private static void GenerateControlFile(List <CharacterVerse> allCv)
        {
            int versionNumber = ControlCharacterVerseData.Singleton.ControlFileVersion + 1;

            allCv.Sort(CharacterVerse.ReferenceComparison);
            var sb = new StringBuilder();

            sb.Append("Control File Version\t").Append(versionNumber).Append("\tGenerated\t").Append(DateTime.Now.ToString("R")).Append(Environment.NewLine);
            sb.Append(CharacterVerse.AllTabDelimited(allCv));
            File.WriteAllText(Path.Combine(kBaseDirForRealOutput, "CharacterVerse.txt"), sb.ToString());
        }
        static List <CharacterVerse> FindAliases(List <CharacterVerse> characterVerses)
        {
            characterVerses.Sort(CharacterVerse.CharacterComparison);
            File.WriteAllText(Path.Combine(kBaseDirForHelperOutput, "CharacterVerse_SortCharacter.txt"), CharacterVerse.AllTabDelimited(characterVerses));

            var characters = new Dictionary <string, HashSet <string> >();

            foreach (var cv in characterVerses)
            {
                HashSet <string> idSet;
                if (characters.TryGetValue(cv.Character, out idSet))
                {
                    idSet.Add(cv.CharacterId);
                }
                else
                {
                    characters.Add(cv.Character, new HashSet <string> {
                        cv.CharacterId
                    });
                }
            }
            var multiCharacters = new Dictionary <string, HashSet <string> >();

            foreach (var ch in characters)
            {
                if (ch.Value.Count > 1)
                {
                    multiCharacters.Add(ch.Key, ch.Value);
                }
            }
            File.WriteAllText(Path.Combine(kBaseDirForHelperOutput, "MultipleCharacter.txt"), TabDelimited(multiCharacters));
            if (multiCharacters.Count > 0)
            {
                MessageBox.Show("Two or more numerical character IDs have the same character name.\n" +
                                "See MultipleCharacter.txt for the character IDs in question.");
            }

            characterVerses.Sort(CharacterVerse.CharacterIdComparison);
            File.WriteAllText(Path.Combine(kBaseDirForHelperOutput, "CharacterVerse_SortCharacterId.txt"), CharacterVerse.AllTabDelimited(characterVerses));

            var characterIds       = new Dictionary <string, HashSet <string> >();
            var uniqueCharacterIds = new HashSet <string>();

            foreach (var cv in characterVerses)
            {
                uniqueCharacterIds.Add(cv.CharacterId);
                HashSet <string> idSet;
                if (characterIds.TryGetValue(cv.CharacterId, out idSet))
                {
                    idSet.Add(cv.Character);
                }
                else
                {
                    characterIds.Add(cv.CharacterId, new HashSet <string> {
                        cv.Character
                    });
                }
            }
            var multiCharacterIds = new Dictionary <string, HashSet <string> >();

            foreach (var ch in characterIds)
            {
                if (ch.Value.Count > 1)
                {
                    multiCharacterIds.Add(ch.Key, ch.Value);
                }
            }
            File.WriteAllText(Path.Combine(kBaseDirForHelperOutput, "MultipleCharacterId.txt"), TabDelimited(multiCharacterIds));
            if (multiCharacterIds.Count > 0)
            {
                MessageBox.Show("Two or more characters have the same numerical character ID.\n" +
                                "One way to resolve this is by making them aliases in AliasUtil.cs.\n" +
                                "See MultipleCharacterId.txt or MultipleCharacterId_Extra.txt for the characters in question.");
            }

            ProcessUniqueIds(uniqueCharacterIds);

            ProcessHelpfulVersionOfMultipleCharacterId(multiCharacterIds, characterVerses);

            return(characterVerses);
        }
        static List <CharacterVerse> ProcessJimFiles()
        {
            var allCv  = CharacterVerse.All();
            var allCci = CharacterCharacterId.All();

            var cvNotFound = new List <CharacterVerse>();
            var cciFound   = new List <CharacterCharacterId>();

            foreach (CharacterVerse cv in allCv)
            {
                bool found = false;
                foreach (CharacterCharacterId cci in allCci)
                {
                    if (cv.CharacterAndDelivery.Equals(cci.Character))
                    {
                        cv.CharacterId   = cci.CharacterId;
                        cv.VoiceTalentId = cci.VoiceTalentId;
                        cciFound.Add(cci);
                        found = true;
                        break;
                    }
                }
                if (!found)
                {
                    cvNotFound.Add(cv);
                }

                SetAlias(cv);

                if (DialogueQuotesReferences.Contains(cv.Book, cv.Chapter, cv.Verse))
                {
                    cv.IsDialogue = true;
                }
            }

            Directory.CreateDirectory(kBaseDirForHelperOutput);
            File.WriteAllText(Path.Combine(kBaseDirForHelperOutput, "CharacterCharacterId_notFullyProcessed.txt"), CharacterCharacterId.AllTabDilimited(allCci));
            allCci.RemoveAll(cciFound.Contains);

            GenerateControlFile(allCv);
            GenerateCharacterIdMap(allCv);

            File.WriteAllText(Path.Combine(kBaseDirForHelperOutput, "cvNotFound.txt"), CharacterVerse.AllTabDelimited(cvNotFound));
            File.WriteAllText(Path.Combine(kBaseDirForHelperOutput, "cciNotFound.txt"), CharacterCharacterId.AllTabDilimited(allCci));

            return(allCv);
        }