Определение токсичных комментариев на русском языке

zlv3pvzhnlzikkdgmgc2odlwulk.gif


Сегодня социальные сети превратились в одну из главных коммуникационных платформ как в онлайне, так и реальной жизни. Свобода выражения разных точек зрения, в том числе токсичных, агрессивных и оскорбительных комментариев может иметь долговременные негативные последствия для мнений людей и социальной сплочённости. Поэтому одной из важнейших задач современного общества является разработка средств автоматического определения токсичной информации в интернете для уменьшения негативных последствий.

В этой статье описывается решение этой задачи для русского языка. В качестве источника данных мы использовали анонимно опубликованный на Kaggle набор данных, дополнительно проверив качество аннотации. Для создания классифицирующей модели мы сделали тонкую настройку двух версий Multilingual Universal Sentence Encoder, Bidirectional Encoder Representations from Transformers и ruBERT. Настроенная модель ruBERT показала F1 = 92,20%, это был лучший результат классификации. Мы выложили в открытый доступ обученные модели и примеры кода.

1. Введение


Сегодня задача определения токсичных комментариев хорошо решается с помощью продвинутых методик глубокого обучения [1], [35]. Хотя в некоторых работах прямо исследуется тема обнаружения оскорблений, токсичных и ненавистнических высказываний на русском языке [2], [8], [17], в открытом доступе есть лишь один набор данных с русскоязычными токсичными комментариями [5]. Он был опубликован на Kaggle без каких-либо пояснений о процессе аннотирования, так что для академических и практических целей он может быть ненадёжен без дополнительного глубокого изучения.

Эта статья посвящена автоматическому определению токсичных комментариев на русском языке. Для этой задачи мы проверили аннотирование набора данных Russian Language Toxic Comments Dataset [5]. Затем создали классифицирующую модель на основе тонкой настройки предварительно обученной многоязычной версий Multilingual Universal Sentence Encoder (M-USE) [48], Bidirectional Encoder Representations from Transformers (M-BERT) [13] и ruBERT [22]. Самая точная модель ruBERT-Toxic показала F1 = 92,20% в задаче бинарной классификации токсичных комментариев. Полученные модели M-BERT и M-USE вы можете скачать с github.

Структура статьи следующая. В разделе 2 мы кратко описываем другие работы по этой теме, а также имеющиеся русскоязычные наборы данных. В разделе 3 мы даём общий обзор набора Russian Language Toxic Comments Dataset и описываем процесс проверки его аннотирования. В разделе 4 мы описываем доработку языковых моделей под задачу классификации текстов. В разделе 5 мы описываем эксперимент по классификации. И в заключение рассказываем о производительности нашей системы и направлениях будущих исследований.

2. Другие работы по теме


В отношении разных источников данных проведены объемные работы по обнаружению токсичных комментариев. Например, Prabowo с коллегами применяли для обнаружения ненавистнических и оскорбительных высказываний в индонезийском Twitter алгоритм наивной байесовой классификации (NB), метод опорных векторов (SVM) и классификатор на основе ансамбля деревьев принятия решений (RFDT) [34]. Экспериментальные результаты показали точность 68,43% у иерархического подхода с признаками словарных униграмм и у SVM-модели. В работе коллектива под руководством Founta [15] для классификации токсичных текстов предложена нейросеть глубокого обучения на основе GRU с предварительно обученными GloVe-эмбеддингами. Модель показала высокую точность на пяти наборах данных, с AUC в диапазоне от 92% до 98%.

Обнаружению токсичных, ненавистнических и оскорбительных комментариев посвящают всё больше семинаров и соревнований. Например, HatEval и OffensEval на SemEval-2019; HASOC на FIRE-2019; Shared Task on the Identification of Offensive Language на GermEval-2019 и GermEval-2018; TRAC на COLING-2018. Модели, используемые в задачах, варьируются от традиционного машинного обучения (например, SVM и логистическая регрессия) до глубокого обучения (RNN, LSTM, GRU, CNN, CapsNet, включая механизм внимания [45], [49], а также передовые модели вроде ELMo [31], BERT [13] и USE [9], [48]). Значительное количество коллективов, добившихся хороших результатов [18], [24], [27], [28], [30], [36], [38], использовало эмбеддинги из перечисленных предварительно обученных языковых моделей. Поскольку представления из предварительно обученных моделей продемонстрировали в классификации высокие результаты, их широко использовали в последующих исследованиях. Например, сотрудники Университета Лотарингии провели многоклассовую двоичную классификацию Twitter-сообщений с помощью двух подходов: обучив DNN-классификатор с предварительно обученными словарными эмбеддингами, и тщательно настроенную предварительно обученную модель BERT [14]. Второй подход показал значительно лучшие результаты по сравнению с CNN и двунаправленными LSTM-нейросетями на основе FastText-эмбеддингов.

Хотя изучению токсичного и агрессивного поведения в русскоязычных соцсетях посвящено значительное количество исследований [7], [33], [41], их автоматической классификации уделено не так много внимания. Для определения агрессивности в англо- и русскоязычных текстах Гордеев использовал свёрточные нейросети и классификатор на основе случайного леса (RFC) [17]. Набор сообщений, аннотированных как агрессивные, содержал около 1000 сообщений на русском и примерно столько же на английском, однако он не выложен в общий доступ. Обученная CNN-модель показала точность двоичной классификации русскоязычных текстов 66,68%. На основе этих результатов авторы пришли к выводу, что свёрточные нейросети и подходы на основе глубокого обучения более перспективны для определения агрессивных текстов. Андрузяк с соавторами предложил вероятностный подход без учителя с исходным словарём для классифицирования оскорбительных комментариев на YouTube, написанных на украинском и русском [2]. Авторы опубликовал вручную размеченный набор данных из 2000 комментариев, однако он содержит тексты на русском и украинском, поэтому его нельзя напрямую использовать для исследований русскоязычного текста.

Несколько недавних исследований посвящены автоматическому определению отношения к мигрантам и этническим группам в русскоязычных соцсетях, в том числе определение нападок на основе идентичности. Бодрунова с соавторами изучила 363 000 русскоязычных публикаций в LiveJournal на тему отношения к переселенцам из постсоветских республик в сравнении с другими нациями [8]. Выяснилось, что в русскоязычных блогах мигранты не становились причиной значительных дискуссий и не подвергались худшему отношению. При этом к представителям северокавказских и центральноазиатских национальностей относятся совершенно по-разному. Группа исследователей под руководством Бессуднова выяснила, что русские традиционно относятся враждебнее к выходцам с Кавказа и Средней Азии; в то же время, в целом принимают украинцев и молдаван как потенциальных соседей [6]. А согласно выводам коллектива под руководством Кольцовой, отношение к представителям среднеазиатских национальностей и украинцам самое негативное [19]. Хотя некоторые академические исследования были посвящены определению токсичных, оскорбительных и ненавистнических высказываний, ни одни из авторов не выложили в открытый доступ свои русскоязычные наборы данных. Насколько нам известно, Russian Language Toxic Comments Dataset [5] — единственный набор русскоязычных токсичных комментариев в открытом доступе. Однако его опубликовали на Kaggle без описания процесса создания и аннотирования, так что без подробного изучения его не рекомендуется использовать в академических и практических проектах.

Поскольку определению токсичных русскоязычных комментариев посвящено мало исследований, мы решили оценить работу моделей глубокого обучения на Russian Language Toxic Comments Dataset [5]. Нам неизвестны исследования по классификации на основе этого источника данных. Модели Multilingual BERT и Multilingual USE — одни из самых распространённых и успешных в недавних исследовательских работах. И только они официально поддерживают русский язык. Мы решили использовать тонкую настройку в качестве подхода с переносом обучения, потому что в свежих исследованиях это давало наилучшие результаты классификации [13], [22], [43], [48].

3. Набор данных со токсичными комментариями


Набор Russian Language Toxic Comments Dataset [5] представляет собой коллекцию аннотированных комментариев с сайтов Двач и Пикабу. Он опубликован на Kaggle в 2019-м и содержит 14 412 комментариев, из которых 4 826 помечены как токсичные, а 9 586 — как нетоксичные. Средняя длина комментария 175 символов, минимальная — 21, максимальная — 7 403.

Для проверки качества аннотирования мы вручную проаннотировали часть комментариев, и сравнили с исходными метками с помощью inter-annotator agreement. Мы решили считать имеющиеся аннотации корректными при достижении значительного или высокого уровня inter-annotator agreement.

Сначала мы вручную разметили 3000 комментариев и сравнили полученные метки классов с исходными. Аннотации составляли русскоязычные участники краудсорсинговой платформы Яндекс.Толока, которая уже использовалась в нескольких академических исследованиях русскоязычных текстов [10], [29], [32], [44]. В качестве руководства по разметке мы пользовались инструкциями по распознаванию токсичности с дополнительными атрибутами, которые применялись на соревновании Jigsaw Toxic Comment Classification Challenge. Аннотаторов попросили определять токсичность в текстах, уровень которой нужно было указать для каждого комментария. Чтобы повысить точность разметки и ограничить возможность обмана мы воспользовались такой методикой:

  • Присваивали аннотаторам уровень на основе их ответов на контрольные задания и банили тех, кто даёт некорректные ответы.
  • Ограничивали доступ к заданиям тем, кто отвечает слишком быстро.
  • Ограничивали доступ к заданиям тем, не вводит правильную капчу несколько раз подряд.


Каждый комментарий размечался 3–8 аннотаторами с применением методики динамического перекрытия. Результаты агрегировали по методу Dawid-Skene [12] на основе рекомендаций Яндекс.Толоки. Аннотаторы продемонстрировали высокий уровень inter-annotator agreement, альфа-коэффициент Криппендорфа был равен 0,81. А каппа-коэффициент Коэна между исходной и нашей агрегированной метками был равен 0,68, что соответствует значительному уровню inter-annotator agreement [11]. Поэтому мы решили считать разметку набора данных корректной, особенно с учётом возможных различий в инструкциях по аннотированию.

4. Модели машинного обучения


4.1. Подходы с исходным уровнем


В качестве подходов с исходным уровнем мы взяли один базовый подход на основе машинного обучения и один современный подход на основе нейросетей. В обоих случаях мы провели предварительную подготовку: заменили URL и ники ключевыми словами, убрали знаки пунктуации и заменили прописные буквы на строчные.

Сначала мы применили модель Multinomial Naive Bayes (MNB), которая хорошо себя показала в задачах по классификации текстов [16], [40]. Для создания модели мы взяли Bag-of-Words и векторизацию TF-IDF. Второй моделью стала нейросеть двунаправленной долгой краткосрочной памяти (Bidirectional Long Short-Term Memory (BiLSTM)). Для слоя эмбеддинга мы предварительно обучили эмбеддинги Word2Vec (dim = 300) [25] на основе коллекции русскоязычных Twitter-сообщений из RuTweetCorp [37]. И поверх эмбеддингов Word2Vec мы добавили два слоя Bidirectional LSTM. Затем добавили скрытый полносвязный слой и сигмоидный выходной слой. Для уменьшения переобучения мы добавили в нейросеть слои регуляризации с гауссовым шумом и слои исключения (Dropout). Мы воспользовались оптимизатором Адама с исходной скоростью обучения 0,001 и категориальной двоичной кросс-энтропией в качестве функции потерь. Модель обучали с фиксированными эмбеддингами в течение 10 эпох. Мы пробовали разблокировать эмбеддинги в разных эпохах с одновременным уменьшением скорости обучения, но результаты оказались хуже. Вероятно, причина была в размере обучающего набора [4].

4.2. Модель BERT


Сейчас официально доступны две версии многоязычной модели BERTBASE, но использовать официально рекомендуется только Cased-версию. BERTBASE берёт последовательность из не более чем 512 токенов и выдаёт её представление. Токенизация выполняется с помощью WordPiece [46] с предварительной нормализацией текста и пунктуационным разделением. Исследователи из МФТИ обучили BERTBASE Cased и опубликовали ruBERT — модель для русского языка [22]. Мы использовали обе модели — Multilingual BERTBASE Cased и ruBERT, которые содержат 12 последовательных блоков преобразования, имеют скрытый размер 768, содержат 12 блоков self-attention head и 110 млн параметров. Этап тонкой настройки выполнялся с рекомендованными параметрами из работы [43] и официального репозитория: три эпохи обучения, 10% этапов прогрева, максимальная длина последовательности 128, размер пакета 32, скорость обучения 5e-5.

4.3. Модель MUSE


В качестве входных данных Multilingual USETrans берёт последовательность из не более чем 100 токенов, а Multilingual USECNN — из не более чем 256 токенов. Для всех поддерживаемых языков используется токенизация SentencePiece [20]. Мы применяли предварительно обученную Multilingual USETrans, которая поддерживает 16 языков, включая русский, содержит энкодер-преобразователь с 6 слоями преобразования, 8 блоков attention head, имеет размер фильтра 2048, скрытый размер 512. Также мы применяли предварительно обученную Multilingual USECNN, которая поддерживает 16 языков, включая русский, содержит CNN-энкодер с двумя CNN-слоями, фильтр шириной (1, 2, 3, 5), имеет размер фильтра. Для обеих моделей мы использовали рекомендованные параметры со страницы TensorFlow Hub: 100 эпох обучения, размер пакета 32, скорость обучения 3e-4.

5. Эксперимент


Мы сравнили подходы с исходным уровнем и подходы с переносом обучения:

  • классификатор Multinomial Naive Bayes;
  • нейросеть Bidirectional Long Short-Term Memory (BiLSTM);
  • многоязычную версию Bidirectional Encoder Representations from Transformers (M-BERT);
  • ruBERT;
  • две версии Multilingual Universal Sentence Encoder (M-USE).


Качество классификации обученных моделей на тестовом наборе (20%) приведена в таблице. Все настроенные языковые модели превысили исходные уровни по точности, recall и мере F1. ruBERT показала F1 = 92,20%, это лучший результат.

Двоичная классификация токсичных русскоязычных комментариев:


6. Заключение


В этой статье мы использовали две тонко настроенные версии модели Multilingual Universal Sentence Encoder [48], модель Multilingual Bidirectional Encoder Representations from Transformers [13] и ruBERT [22] для определения токсичных русскоязычных комментариев. Настроенная ruBERTToxic показала F1 = 92,20%, это лучший результат классификации.

Полученные модели M-BERT и M-USE доступны на github.

Литературные источники


Список
  1. Aken, B. van et al.: Challenges for toxic comment classification: An in-depth error analysis. In: Proceedings of the 2nd workshop on abusive language online (ALW2). pp. 33–42. Association for Computational Linguistics, Brussels, Belgium (2018).
  2. Andrusyak, B. et al.: Detection of abusive speech for mixed sociolects of russian and ukrainian languages. In: The 12th workshop on recent advances in slavonic natural languages processing, RASLAN 2018, karlova studanka, czech republic, december 7–9, 2018. pp. 77–84 (2018).
  3. Basile, V. et al.: SemEval-2019 task 5: Multilingual detection of hate speech against immigrants and women in twitter. In: Proceedings of the 13th international workshop on semantic evaluation. pp. 54–63. Association for Computational Linguistics, Minneapolis, Minnesota, USA (2019).
  4. Baziotis, C. et al.: DataStories at SemEval-2017 task 4: Deep LSTM with attention for message-level and topic-based sentiment analysis. In: Proceedings of the 11th international workshop on semantic evaluation (SemEval-2017). pp. 747–754. Association for Computational Linguistics, Vancouver, Canada (2017).
  5. Belchikov, A.: Russian language toxic comments, https://www.kaggle.com/ blackmoon/russian-language-toxic-comments.
  6. Bessudnov, A., Shcherbak, A.: Ethnic discrimination in multi-ethnic societies: Evidence from russia. European Sociological Review. (2019).
  7. Biryukova, E.V. et al.: READER«S comment in on-line magazine as a genre of internet discourse (by the material of the german and russian languages). Philological Sciences. Issues of Theory and Practice. 12, 1, 79–82 (2018).
  8. Bodrunova, S.S. et al.: Who«s bad? Attitudes toward resettlers from the post-soviet south versus other nations in the russian blogosphere. International Journal of Communication. 11, 23 (2017).
  9. Cer, D.M. et al.: Universal sentence encoder. ArXiv. abs/1803.11175, (2018).
  10. Chernyak, E. et al.: Char-rnn for word stress detection in east slavic languages. CoRR. abs/1906.04082, (2019).
  11. Cohen, J.: A coefficient of agreement for nominal scales. Educational and psychological measurement. 20, 1, 37–46 (1960).
  12. Dawid, A. P., Skene, A. M.: Maximum likelihood estimation of observer errorrates using the em algorithm. Journal of the Royal Statistical Society: Series C (Applied Statistics). 28, 1, 20–28 (1979).
  13. Devlin, J. et al.: BERT: Pre-training of deep bidirectional transformers for language understanding. In: Proceedings of the 2019 conference of the north American chapter of the association for computational linguistics: Human language technologies, volume 1 (long and short papers). pp. 4171–4186. Association for Computational Linguistics, Minneapolis, Minnesota (2019).
  14. d«Sa, A.G. et al.: BERT and fastText embeddings for automatic detection of toxic speech. In: SIIE 2020-information systems and economic intelligence. (2020).
  15. Founta, A.M. et al.: A unified deep learning architecture for abuse detection. In: Proceedings of the 10th acm conference on web science. pp. 105–114. Association for Computing Machinery, New York, NY, USA (2019).
  16. Frank, E., Bouckaert, R.: Naive bayes for text classification with unbalanced classes. In: Fürnkranz, J. et al. (eds.) Knowledge discovery in databases: PKDD 2006. pp. 503–510. Springer Berlin Heidelberg, Berlin, Heidelberg (2006).
  17. Gordeev, D.: Detecting state of aggression in sentences using cnn. In: International conference on speech and computer. pp. 240–245. Springer (2016).
  18. Indurthi, V. et al.: FERMI at SemEval-2019 task 5: Using sentence embeddings to identify hate speech against immigrants and women in twitter. In: Proceedings of the 13th international workshop on semantic evaluation. pp. 70–74. Association for Computational Linguistics, Minneapolis, Minnesota, USA (2019).
  19. Koltsova, O. et al.: FINDING and analyzing judgements on ethnicity in the russian-language social media. AoIR Selected Papers of Internet Research. (2017).
  20. Kudo, T., Richardson, J.: SentencePiece: A simple and language independent subword tokenizer and detokenizer for neural text processing. In: Proceedings of the 2018 conference on empirical methods in natural language processing: System demonstrations. pp. 66–71. Association for Computational Linguistics, Brussels, Belgium (2018).
  21. Kumar, R. et al. eds: Proceedings of the first workshop on trolling, aggression and cyberbullying (TRAC-2018). Association for Computational Linguistics, Santa Fe, New Mexico, USA (2018).
  22. Kuratov, Y., Arkhipov, M.: Adaptation of deep bidirectional multilingual transformers for Russian language. In: Computational Linguistics and Intellectual Technologies: Papers from the Annual International Conference «Dialogue». pp. 333–340. RSUH, Moscow, Russia (2019).
  23. Lenhart, A. et al.: Online harassment, digital abuse, and cyberstalking in america. Data; Society Research Institute (2016).
  24. Liu, P. et al.: NULI at SemEval-2019 task 6: Transfer learning for offensive language detection using bidirectional transformers. In: Proceedings of the 13th international workshop on semantic evaluation. pp. 87–91. Association for Computational Linguistics, Minneapolis, Minnesota, USA (2019).
  25. Mikolov, T. et al.: Distributed representations of words and phrases and their compositionality. In: Proceedings of the 26th international conference on neural information processing systems—volume 2. pp. 3111–3119. Curran Associates Inc., Red Hook, NY, USA (2013).
  26. Mishra, P. et al.: Abusive language detection with graph convolutional networks. In: Proceedings of the 2019 conference of the north american chapter of the association for computational linguistics: Human language technologies, volume 1 (long and short papers). pp. 2145–2150 (2019).
  27. Mishra, S., Mishra, S.: 3Idiots at HASOC 2019: Fine-tuning transformer neural networks for hate speech identification in indo-european languages. In: Working notes of FIRE 2019—forum for information retrieval evaluation, kolkata, india, december 12–15, 2019. pp. 208–213 (2019).
  28. Nikolov, A., Radivchev, V.: Nikolov-radivchev at SemEval-2019 task 6: Offensive tweet classification with BERT and ensembles. In: Proceedings of the 13th international workshop on semantic evaluation. pp. 691–695. Association for Computational Linguistics, Minneapolis, Minnesota, USA (2019).
  29. Panchenko, A. et al.: RUSSE»2018: A Shared Task on Word Sense Induction for the Russian Language. In: Computational Linguistics and Intellectual Technologies: Papers from the Annual International Conference «Dialogue». pp. 547–564. RSUH, Moscow, Russia (2018).
  30. Paraschiv, A., Cercel, D.-C.: UPB at germeval-2019 task 2: BERT-based offensive language classification of german tweets. In: Preliminary proceedings of the 15th conference on natural language processing (konvens 2019). Erlangen, germany: German society for computational linguistics & language technology. pp. 396–402 (2019).
  31. Peters, M. et al.: Deep contextualized word representations. In: Proceedings of the 2018 conference of the north American chapter of the association for computational linguistics: Human language technologies, volume 1 (long papers). pp. 2227–2237. Association for Computational Linguistics, New Orleans, Louisiana (2018).
  32. Ponomareva, M. et al.: Automated word stress detection in Russian. In: Proceedings of the first workshop on subword and character level models in NLP. pp. 31–35. Association for Computational Linguistics, Copenhagen, Denmark (2017).
  33. Potapova, R., Komalova, L.: Lexico-semantical indices of «deprivation–aggression» modality correlation in social network discourse. In: International conference on speech and computer. pp. 493–502. Springer (2017).
  34. Prabowo, F.A. et al.: Hierarchical multi-label classification to identify hate speech and abusive language on indonesian twitter. In: 2019 6th international conference on information technology, computer and electrical engineering (icitacee). pp. 1–5 (2019).
  35. Risch, J., Krestel, R.: Toxic comment detection in online discussions. In: Deep learning-based approaches for sentiment analysis. pp. 85–109. Springer (2020).
  36. Risch, J. et al.: HpiDEDIS at germeval 2019: Offensive language identification using a german bert model. In: Preliminary proceedings of the 15th conference on natural language processing (konvens 2019). Erlangen, germany: German society for computational linguistics & language technology. pp. 403–408 (2019).
  37. Rubtsova, Y.: A method for development and analysis of short text corpus for the review classification task. Proceedings of conferences Digital Libraries: Advanced Methods and Technologies, Digital Collections (RCDL»2013). Pp. 269–275 (2013).
  38. Ruiter, D. et al.: LSV-uds at HASOC 2019: The problem of defining hate. In: Working notes of FIRE 2019—forum for information retrieval evaluation, kolkata, india, december 12–15, 2019. pp. 263–270 (2019).
  39. Sambasivan, N. et al.: «They don«t leave us alone anywhere we go»: Gender and digital abuse in south asia. In: Proceedings of the 2019 chi conference on human factors in computing systems. Association for Computing Machinery, New York, NY, USA (2019).
  40. Sang-Bum Kim et al.: Some effective techniques for naive bayes text classification. IEEE Transactions on Knowledge and Data Engineering. 18, 11, 1457–1466 (2006).
  41. Shkapenko, T., Vertelova, I.: Hate speech markers in internet comments to translated articles from polish media. Political Linguistics. 70, 4, Pages 104–111 (2018).
  42. Strus, J.M. et al.: Overview of germeval task 2, 2019 shared task on the identification of offensive language. Presented at the (2019).
  43. Sun, C. et al.: How to fine-tune bert for text classification? In: Sun, M. et al. (eds.) Chinese computational linguistics. pp. 194–206. Springer International Publishing, Cham (2019).
  44. Ustalov, D., Igushkin, S.: Sense inventory alignment using lexical substitutions and crowdsourcing. In: 2016 international fruct conference on intelligence, social media and web (ismw fruct). (2016).
  45. Vaswani, A. et al.: Attention is all you need. In: Proceedings of the 31st international conference on neural information processing systems. pp. 6000–6010. Curran Associates Inc., Red Hook, NY, USA (2017).
  46. Wu, Y. et al.: Google«s neural machine translation system: Bridging the gap between human and machine translation. arXiv preprint arXiv:1609.08144. (2016).
  47. Yang, F. et al.: Exploring deep multimodal fusion of text and photo for hate speech classification. In: Proceedings of the third workshop on abusive language online. pp. 11–18. Association for Computational Linguistics, Florence, Italy (2019).
  48. Yang, Y. et al.: Multilingual universal sentence encoder for semantic retrieval. CoRR. abs/1907.04307, (2019).
  49. Yang, Z. et al.: Hierarchical attention networks for document classification. In: Proceedings of the 2016 conference of the north American chapter of the association for computational linguistics: Human language technologies. pp. 1480–1489. pp. Association for Computational Linguistics, San Diego, California (2016).

© Habrahabr.ru