public void NamesListNotInList()
        {
            // Arrange
            var namesList = new NamesList(Directory.GetCurrentDirectory(), "en", false, null);

            // Act
            var exists = namesList.GetNames().Contains("JonesASDFLKJCKJXFLKJSLDKFJASDF");

            // Assert
            Assert.IsFalse(exists);
        }
        public void NamesListRemove()
        {
            // Arrange
            var namesList = new NamesList(Directory.GetCurrentDirectory(), "en", false, null);
            namesList.Add("Jones123");

            // Act
            namesList.Remove("Jones123");

            // Assert
            Assert.IsFalse(namesList.GetNames().Contains("Jones123"));
        }
        public void NamesListIsInNamesEtcMultiWordList()
        {
            // Arrange
            var namesList = new NamesList(Directory.GetCurrentDirectory(), "en", false, null);

            // Act
            namesList.Add("Charlie Parker123");
            var exists = namesList.IsInNamesEtcMultiWordList("This is Charlie Parker123!", "Charlie Parker123");

            // Assert
            Assert.IsTrue(exists);
        }
        public void NamesListAddMultiWord()
        {
            // Arrange
            var namesList = new NamesList(Directory.GetCurrentDirectory(), "en", false, null);

            // Act
            namesList.Add("Charlie Parker123");
            var exists = namesList.GetMultiNames().Contains("Charlie Parker123");

            // Assert
            Assert.IsTrue(exists);
        }
Example #5
0
        internal void FixCasing(Subtitle subtitle, string language)
        {
            var namesList = new NamesList(Configuration.DictionariesFolder, language, Configuration.Settings.WordLists.UseOnlineNamesEtc, Configuration.Settings.WordLists.NamesEtcUrl);
            var namesEtc = namesList.GetAllNames();

            // Longer names must be first
            namesEtc.Sort((s1, s2) => s2.Length.CompareTo(s1.Length));

            string lastLine = string.Empty;
            foreach (Paragraph p in subtitle.Paragraphs)
            {
                p.Text = FixCasing(p.Text, lastLine, namesEtc);

                // fix casing of English alone i to I
                if (radioButtonNormal.Checked && language.StartsWith("en", StringComparison.Ordinal))
                {
                    p.Text = FixEnglishAloneILowerToUpper(p.Text);
                }

                lastLine = p.Text;
            }
        }
Example #6
0
        private void ButtonOkClick(object sender, EventArgs e)
        {
            if (string.IsNullOrWhiteSpace(textBoxAddName.Text))
            {
                return;
            }

            NewName = textBoxAddName.Text.RemoveControlCharacters().Trim();
            string languageName = null;
            _language = Configuration.Settings.Language.Main;

            if (!string.IsNullOrEmpty(Configuration.Settings.General.SpellCheckLanguage))
            {
                languageName = Configuration.Settings.General.SpellCheckLanguage;
            }
            else
            {
                List<string> list = Utilities.GetDictionaryLanguages();
                if (list.Count > 0)
                {
                    string name = list[0];
                    int start = name.LastIndexOf('[');
                    int end = name.LastIndexOf(']');
                    if (start > 0 && end > start)
                    {
                        start++;
                        name = name.Substring(start, end - start);
                        languageName = name;
                    }
                    else
                    {
                        MessageBox.Show(string.Format(_language.InvalidLanguageNameX, name));
                        return;
                    }
                }
            }

            languageName = LanguageAutoDetect.AutoDetectLanguageName(languageName, _subtitle);
            if (comboBoxDictionaries.Items.Count > 0)
            {
                string name = comboBoxDictionaries.SelectedItem.ToString();
                int start = name.LastIndexOf('[');
                int end = name.LastIndexOf(']');
                if (start >= 0 && end > start)
                {
                    start++;
                    name = name.Substring(start, end - start);
                    languageName = name;
                }
            }

            if (string.IsNullOrEmpty(languageName))
                languageName = "en_US";

            var namesList = new NamesList(Configuration.DictionariesFolder, languageName, Configuration.Settings.WordLists.UseOnlineNamesEtc, Configuration.Settings.WordLists.NamesEtcUrl);
            if (namesList.Add(textBoxAddName.Text))
                DialogResult = DialogResult.OK;
            else
                DialogResult = DialogResult.Cancel;
        }
        public SpellCheckWordLists(string dictionaryFolder, string languageName, IDoSpell doSpell)
        {
            if (languageName == null)
                throw new NullReferenceException("languageName");
            if (doSpell == null)
                throw new NullReferenceException("doSpell");

            _languageName = languageName;
            _doSpell = doSpell;
            _namesList = new NamesList(Configuration.DictionariesFolder, languageName, Configuration.Settings.WordLists.UseOnlineNamesEtc, Configuration.Settings.WordLists.NamesEtcUrl);
            _namesEtcList = _namesList.GetNames();
            var namesEtcMultiWordList = _namesList.GetMultiNames();

            foreach (string namesItem in _namesEtcList)
                _namesEtcListUppercase.Add(namesItem.ToUpper());

            if (languageName.StartsWith("en_", StringComparison.OrdinalIgnoreCase))
            {
                foreach (string namesItem in _namesEtcList)
                {
                    if (!namesItem.EndsWith('s'))
                    {
                        _namesEtcListWithApostrophe.Add(namesItem + "'s");
                        _namesEtcListWithApostrophe.Add(namesItem + "’s");
                    }
                    else if (!namesItem.EndsWith('\''))
                    {
                        _namesEtcListWithApostrophe.Add(namesItem + "'");
                    }
                }
            }

            _userWordList = new List<string>();
            _userPhraseList = new List<string>();
            if (File.Exists(dictionaryFolder + languageName + "_user.xml"))
            {
                var userWordDictionary = new XmlDocument();
                userWordDictionary.Load(dictionaryFolder + languageName + "_user.xml");
                if (userWordDictionary.DocumentElement != null)
                {
                    var xmlNodeList = userWordDictionary.DocumentElement.SelectNodes("word");
                    if (xmlNodeList != null)
                    {
                        foreach (XmlNode node in xmlNodeList)
                        {
                            string word = node.InnerText.Trim().ToLower();
                            if (word.Contains(' '))
                                _userPhraseList.Add(word);
                            else
                                _userWordList.Add(word);
                        }
                    }
                }
            }

            // Add names/userdic with "." or " " or "-"
            _wordsWithDashesOrPeriods = new List<string>();
            _wordsWithDashesOrPeriods.AddRange(namesEtcMultiWordList);
            foreach (string name in _namesEtcList)
            {
                if (name.Contains(PeriodAndDash))
                    _wordsWithDashesOrPeriods.Add(name);
            }
            foreach (string word in _userWordList)
            {
                if (word.Contains(PeriodAndDash))
                    _wordsWithDashesOrPeriods.Add(word);
            }
            _wordsWithDashesOrPeriods.AddRange(_userPhraseList);
        }
        public bool AddName(string word)
        {
            if (word == null || word.Length <= 1 || _namesEtcList.Contains(word))
                return false;

            _namesEtcList.Add(word);
            _namesEtcListUppercase.Add(word.ToUpper());
            if (_languageName.StartsWith("en_", StringComparison.Ordinal) && !word.EndsWith('s'))
            {
                _namesEtcList.Add(word + "s");
                _namesEtcListUppercase.Add(word.ToUpper() + "S");
            }
            if (!word.EndsWith('s'))
            {
                _namesEtcListWithApostrophe.Add(word + "'s");
                _namesEtcListUppercase.Add(word.ToUpper() + "'S");
            }
            if (!word.EndsWith('\''))
                _namesEtcListWithApostrophe.Add(word + "'");

            var namesList = new NamesList(Configuration.DictionariesFolder, _languageName, Configuration.Settings.WordLists.UseOnlineNamesEtc, Configuration.Settings.WordLists.NamesEtcUrl);
            namesList.Add(word);
            return true;
        }
Example #9
0
        private void MakeSureNamesListIsLoaded()
        {
            if (_namesEtcList == null)
            {
                _namesEtcList = new List<string>();
                string languageTwoLetterCode = Utilities.AutoDetectGoogleLanguage(Subtitle);

                // Will contains both one word names and multi names
                var namesList = new NamesList(Configuration.DictionariesFolder, languageTwoLetterCode, Configuration.Settings.WordLists.UseOnlineNamesEtc, Configuration.Settings.WordLists.NamesEtcUrl);
                _namesEtcList = namesList.GetAllNames();
            }
        }
Example #10
0
        private void ButtonRemoveNameEtcClick(object sender, EventArgs e)
        {
            if (listBoxNamesEtc.SelectedIndices.Count == 0)
                return;

            string language = GetCurrentWordListLanguage();
            int index = listBoxNamesEtc.SelectedIndex;
            string text = listBoxNamesEtc.Items[index].ToString();
            int itemsToRemoveCount = listBoxNamesEtc.SelectedIndices.Count;
            if (!string.IsNullOrEmpty(language) && index >= 0)
            {
                DialogResult result;
                if (itemsToRemoveCount == 1)
                    result = MessageBox.Show(string.Format(Configuration.Settings.Language.Settings.RemoveX, text), "Subtitle Edit", MessageBoxButtons.YesNo);
                else
                    result = MessageBox.Show(string.Format(Configuration.Settings.Language.Main.DeleteXLinesPrompt, itemsToRemoveCount), "Subtitle Edit", MessageBoxButtons.YesNo);
                if (result == DialogResult.Yes)
                {
                    int removeCount = 0;
                    var namesList = new NamesList(Configuration.DictionariesFolder, language, Configuration.Settings.WordLists.UseOnlineNamesEtc, Configuration.Settings.WordLists.NamesEtcUrl);
                    for (int idx = listBoxNamesEtc.SelectedIndices.Count - 1; idx >= 0; idx--)
                    {
                        index = listBoxNamesEtc.SelectedIndices[idx];
                        text = listBoxNamesEtc.Items[index].ToString();
                        namesList.Remove(text);
                        removeCount++;
                        listBoxNamesEtc.Items.RemoveAt(index);
                    }

                    if (removeCount > 0)
                    {
                        LoadNamesEtc(language, true); // reload

                        if (index < listBoxNamesEtc.Items.Count)
                            listBoxNamesEtc.SelectedIndex = index;
                        else if (listBoxNamesEtc.Items.Count > 0)
                            listBoxNamesEtc.SelectedIndex = index - 1;
                        listBoxNamesEtc.Focus();

                        buttonRemoveNameEtc.Enabled = false;
                        return;
                    }

                    if (removeCount < itemsToRemoveCount && Configuration.Settings.WordLists.UseOnlineNamesEtc && !string.IsNullOrEmpty(Configuration.Settings.WordLists.NamesEtcUrl))
                    {
                        MessageBox.Show(Configuration.Settings.Language.Settings.CannotUpdateNamesEtcOnline);
                        return;
                    }

                    if (removeCount == 0)
                        MessageBox.Show(Configuration.Settings.Language.Settings.WordNotFound);
                }
            }
        }
Example #11
0
 private void ButtonAddNamesEtcClick(object sender, EventArgs e)
 {
     string language = GetCurrentWordListLanguage();
     string text = textBoxNameEtc.Text.RemoveControlCharacters().Trim();
     if (!string.IsNullOrEmpty(language) && text.Length > 1 && !_wordListNamesEtc.Contains(text))
     {
         var namesList = new NamesList(Configuration.DictionariesFolder, language, Configuration.Settings.WordLists.UseOnlineNamesEtc, Configuration.Settings.WordLists.NamesEtcUrl);
         namesList.Add(text);
         LoadNamesEtc(language, true);
         labelStatus.Text = string.Format(Configuration.Settings.Language.Settings.WordAddedX, text);
         textBoxNameEtc.Text = string.Empty;
         textBoxNameEtc.Focus();
         for (int i = 0; i < listBoxNamesEtc.Items.Count; i++)
         {
             if (listBoxNamesEtc.Items[i].ToString() == text)
             {
                 listBoxNamesEtc.SelectedIndex = i;
                 int top = i - 5;
                 if (top < 0)
                     top = 0;
                 listBoxNamesEtc.TopIndex = top;
                 break;
             }
         }
     }
     else
     {
         MessageBox.Show(Configuration.Settings.Language.Settings.WordAlreadyExists);
     }
 }
Example #12
0
        private void LoadNamesEtc(string language, bool reloadListBox)
        {
            var task = Task.Factory.StartNew(() =>
            {
                // names etc
                var namesList = new NamesList(Configuration.DictionariesFolder, language, Configuration.Settings.WordLists.UseOnlineNamesEtc, Configuration.Settings.WordLists.NamesEtcUrl);
                _wordListNamesEtc = namesList.GetAllNames();
                _wordListNamesEtc.Sort();
                return _wordListNamesEtc;
            });

            if (reloadListBox)
            {
                // reload the listbox on a continuation ui thead
                var uiContext = TaskScheduler.FromCurrentSynchronizationContext();
                task.ContinueWith(originalTask =>
                {
                    listBoxNamesEtc.BeginUpdate();
                    listBoxNamesEtc.Items.Clear();
                    foreach (var name in originalTask.Result)
                    {
                        listBoxNamesEtc.Items.Add(name);
                    }
                    listBoxNamesEtc.EndUpdate();
                }, uiContext);
            }
        }
Example #13
0
        private void LoadDictionaries(string dictionaryFolder, string dictionary)
        {
            _changeAllDictionary = new Dictionary<string, string>();
            _skipAllList = new List<string>();
            _namesList = new NamesList(Configuration.DictionariesFolder, _languageName, Configuration.Settings.WordLists.UseOnlineNamesEtc, Configuration.Settings.WordLists.NamesEtcUrl);
            _namesEtcList = _namesList.GetNames();
            _namesEtcMultiWordList = _namesList.GetMultiNames();

            foreach (string namesItem in _namesEtcList)
                _namesEtcListUppercase.Add(namesItem.ToUpper());

            if (_languageName.StartsWith("en_", StringComparison.OrdinalIgnoreCase))
            {
                foreach (string namesItem in _namesEtcList)
                {
                    if (!namesItem.EndsWith('s'))
                    {
                        _namesEtcListWithApostrophe.Add(namesItem + "'s");
                        _namesEtcListWithApostrophe.Add(namesItem + "’s");
                    }
                    else if (!namesItem.EndsWith('\''))
                    {
                        _namesEtcListWithApostrophe.Add(namesItem + "'");
                    }
                }
            }

            _userWordList = new List<string>();
            _userPhraseList = new List<string>();
            if (File.Exists(dictionaryFolder + _languageName + "_user.xml"))
            {
                var userWordDictionary = new XmlDocument();
                userWordDictionary.Load(dictionaryFolder + _languageName + "_user.xml");
                foreach (XmlNode node in userWordDictionary.DocumentElement.SelectNodes("word"))
                {
                    string word = node.InnerText.Trim().ToLower();
                    if (word.Contains(' '))
                        _userPhraseList.Add(word);
                    else
                        _userWordList.Add(word);
                }
            }

            // Add names/userdic with "." or " " or "-"
            _wordsWithDashesOrPeriods = new List<string>();
            _wordsWithDashesOrPeriods.AddRange(_namesEtcMultiWordList);
            foreach (string name in _namesEtcList)
            {
                if (name.Contains(new[] { '.', '-' }))
                    _wordsWithDashesOrPeriods.Add(name);
            }
            foreach (string word in _userWordList)
            {
                if (word.Contains(new[] { '.', '-' }))
                    _wordsWithDashesOrPeriods.Add(word);
            }
            _wordsWithDashesOrPeriods.AddRange(_userPhraseList);

            _changeAllDictionary = new Dictionary<string, string>();
            LoadHunspell(dictionary);
        }
Example #14
0
        public void DoAction(SpellCheckAction action)
        {
            switch (action)
            {
                case SpellCheckAction.Change:
                    _noOfChangedWords++;
                    _mainWindow.CorrectWord(_prefix + ChangeWord + _postfix, _currentParagraph, _prefix + _currentWord + _postfix, ref _firstChange, _wordsIndex);
                    break;
                case SpellCheckAction.ChangeAll:
                    _noOfChangedWords++;
                    if (!_changeAllDictionary.ContainsKey(_currentWord))
                        _changeAllDictionary.Add(_currentWord, ChangeWord);
                    _mainWindow.CorrectWord(_prefix + ChangeWord + _postfix, _currentParagraph, _prefix + _currentWord + _postfix, ref _firstChange, -1);
                    break;
                case SpellCheckAction.Skip:
                    _noOfSkippedWords++;
                    break;
                case SpellCheckAction.SkipAll:
                    _noOfSkippedWords++;
                    _skipAllList.Add(ChangeWord.ToUpper());
                    if (ChangeWord.EndsWith('\'') || ChangeWord.StartsWith('\''))
                        _skipAllList.Add(ChangeWord.ToUpper().Trim('\''));
                    break;
                case SpellCheckAction.AddToDictionary:
                    if (_userWordList.IndexOf(ChangeWord) < 0)
                    {
                        _noOfAddedWords++;
                        string s = ChangeWord.Trim().ToLower();
                        if (s.Contains(' '))
                            _userPhraseList.Add(s);
                        else
                            _userWordList.Add(s);
                        Utilities.AddToUserDictionary(s, _languageName);
                    }
                    break;
                case SpellCheckAction.AddToNamesEtc:
                    if (ChangeWord.Length > 1 && !_namesEtcList.Contains(ChangeWord))
                    {
                        _namesEtcList.Add(ChangeWord);
                        _namesEtcListUppercase.Add(ChangeWord.ToUpper());
                        if (_languageName.StartsWith("en_", StringComparison.Ordinal) && !ChangeWord.EndsWith('s'))
                        {
                            _namesEtcList.Add(ChangeWord + "s");
                            _namesEtcListUppercase.Add(ChangeWord.ToUpper() + "S");
                        }
                        if (!ChangeWord.EndsWith('s'))
                        {
                            _namesEtcListWithApostrophe.Add(ChangeWord + "'s");
                            _namesEtcListUppercase.Add(ChangeWord.ToUpper() + "'S");
                        }
                        if (!ChangeWord.EndsWith('\''))
                            _namesEtcListWithApostrophe.Add(ChangeWord + "'");

                        var namesList = new NamesList(Configuration.DictionariesFolder, _languageName, Configuration.Settings.WordLists.UseOnlineNamesEtc, Configuration.Settings.WordLists.NamesEtcUrl);
                        namesList.Add(ChangeWord);
                    }
                    break;
                case SpellCheckAction.ChangeWholeText:
                    _mainWindow.ShowStatus(string.Format(Configuration.Settings.Language.Main.SpellCheckChangedXToY, _currentParagraph.Text.Replace(Environment.NewLine, " "), ChangeWholeText.Replace(Environment.NewLine, " ")));
                    _currentParagraph.Text = ChangeWholeText;
                    _mainWindow.ChangeWholeTextMainPart(ref _noOfChangedWords, ref _firstChange, _currentIndex, _currentParagraph);

                    break;
            }
            labelActionInfo.Text = string.Empty;
            PrepareNextWord();
            CheckActions();
        }
        private void FindAllNames()
        {
            string language = LanguageAutoDetect.AutoDetectLanguageName("en_US", _subtitle);
            if (string.IsNullOrEmpty(language))
                language = "en_US";

            var namesList = new NamesList(Configuration.DictionariesFolder, language, Configuration.Settings.WordLists.UseOnlineNamesEtc, Configuration.Settings.WordLists.NamesEtcUrl);

            // Will contains both one word names and multi names
            var namesEtcList = namesList.GetAllNames();

            if (language.StartsWith("en", StringComparison.Ordinal))
            {
                namesEtcList.Remove("Black");
                namesEtcList.Remove("Bill");
                namesEtcList.Remove("Long");
                namesEtcList.Remove("Don");
            }

            var sb = new StringBuilder();
            foreach (Paragraph p in _subtitle.Paragraphs)
                sb.AppendLine(p.Text);
            string text = HtmlUtil.RemoveHtmlTags(sb.ToString());
            string textToLower = text.ToLower();
            listViewNames.BeginUpdate();
            foreach (string name in namesEtcList)
            {
                int startIndex = textToLower.IndexOf(name.ToLower(), StringComparison.Ordinal);
                if (startIndex >= 0)
                {
                    while (startIndex >= 0 && startIndex < text.Length &&
                           textToLower.Substring(startIndex).Contains(name.ToLower()) && name.Length > 1 && name != name.ToLower())
                    {
                        bool startOk = (startIndex == 0) || (text[startIndex - 1] == ' ') || (text[startIndex - 1] == '-') ||
                                       (text[startIndex - 1] == '"') || (text[startIndex - 1] == '\'') || (text[startIndex - 1] == '>') ||
                                       (Environment.NewLine.EndsWith(text[startIndex - 1].ToString(CultureInfo.InvariantCulture)));

                        if (startOk)
                        {
                            int end = startIndex + name.Length;
                            bool endOk = end <= text.Length;
                            if (endOk)
                                endOk = end == text.Length || ExpectedEndChars.Contains(text[end]);

                            if (endOk && text.Substring(startIndex, name.Length) != name) // do not add names where casing already is correct
                            {
                                if (!_usedNames.Contains(name))
                                {
                                    _usedNames.Add(name);
                                    AddToListViewNames(name);
                                    break; // break while
                                }
                            }
                        }

                        startIndex = textToLower.IndexOf(name.ToLower(), startIndex + 2, StringComparison.Ordinal);
                    }
                }
            }
            listViewNames.EndUpdate();
            groupBoxNames.Text = string.Format(Configuration.Settings.Language.ChangeCasingNames.NamesFoundInSubtitleX, listViewNames.Items.Count);
        }
Example #16
0
        private void LoadSpellingDictionariesViaDictionaryFileName(string threeLetterIsoLanguageName, CultureInfo culture, string dictionaryFileName, bool resetSkipList)
        {
            _fiveLetterWordListLanguageName = Path.GetFileNameWithoutExtension(dictionaryFileName);
            if (_fiveLetterWordListLanguageName.Length > 5)
                _fiveLetterWordListLanguageName = _fiveLetterWordListLanguageName.Substring(0, 5);
            string dictionary = Utilities.DictionaryFolder + _fiveLetterWordListLanguageName;
            if (resetSkipList)
            {
                _wordSkipList = new HashSet<string> { Configuration.Settings.Tools.MusicSymbol, "*", "%", "#", "+", "$" };
            }

            // Load names etc list (names/noise words)
            _namesList = new NamesList(Configuration.DictionariesFolder, _fiveLetterWordListLanguageName, Configuration.Settings.WordLists.UseOnlineNamesEtc, Configuration.Settings.WordLists.NamesEtcUrl);
            _namesEtcList = _namesList.GetNames();
            _namesEtcMultiWordList = _namesList.GetMultiNames();
            _namesEtcListUppercase = new HashSet<string>();
            foreach (string name in _namesEtcList)
                _namesEtcListUppercase.Add(name.ToUpper());

            _namesEtcListWithApostrophe = new HashSet<string>();
            if (threeLetterIsoLanguageName.Equals("eng", StringComparison.OrdinalIgnoreCase))
            {
                foreach (string namesItem in _namesEtcList)
                {
                    if (!namesItem.EndsWith('s'))
                        _namesEtcListWithApostrophe.Add(namesItem + "'s");
                    else
                        _namesEtcListWithApostrophe.Add(namesItem + "'");
                }
            }

            // Load user words
            _userWordList = new HashSet<string>();
            _userWordListXmlFileName = Utilities.LoadUserWordList(_userWordList, _fiveLetterWordListLanguageName);

            // Find abbreviations
            _abbreviationList = new HashSet<string>();
            foreach (string name in _namesEtcList)
            {
                if (name.EndsWith('.'))
                    _abbreviationList.Add(name);
            }
            if (threeLetterIsoLanguageName.Equals("eng", StringComparison.OrdinalIgnoreCase))
            {
                if (!_abbreviationList.Contains("a.m."))
                    _abbreviationList.Add("a.m.");
                if (!_abbreviationList.Contains("p.m."))
                    _abbreviationList.Add("p.m.");
                if (!_abbreviationList.Contains("o.r."))
                    _abbreviationList.Add("o.r.");
            }

            foreach (string name in _userWordList)
            {
                if (name.EndsWith('.'))
                    _abbreviationList.Add(name);
            }

            // Load Hunspell spell checker
            try
            {
                if (!File.Exists(dictionary + ".dic"))
                {
                    var fileMatches = Directory.GetFiles(Utilities.DictionaryFolder, _fiveLetterWordListLanguageName + "*.dic");
                    if (fileMatches.Length > 0)
                        dictionary = fileMatches[0].Substring(0, fileMatches[0].Length - 4);
                }
                if (_hunspell != null)
                    _hunspell.Dispose();
                _hunspell = Hunspell.GetHunspell(dictionary);
                IsDictionaryLoaded = true;
                _spellCheckDictionaryName = dictionary;
                DictionaryCulture = culture;
            }
            catch
            {
                IsDictionaryLoaded = false;
            }
        }