Iodide: интерактивный научный редактор от Mozilla

Автор оригинала: Brendan Colloran
  • Перевод

Изучение аттрактора Лоренца, а затем редактирование кода в Iodide

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

Но на сегодняшний день очень немногие научные инструменты используют полный коммуникационный потенциал современных браузеров. Результаты дата-майнинга не очень удобно просматривать в браузере. Поэтому сегодня Mozilla представляет Iodide — экспериментальный инструмент, который помогает учёным составлять красивые интерактивные документы с использованием веб-технологий, всё в рамках итеративного рабочего процесса, который многим знаком.

Это не просто среда программирования для создания интерактивных документов в браузере. Iodide пытается помочь в рабочем процессе, связывая редактор и предпросмотр. Это отличается от стиля IDE, которая выдаёт презентационные документы типа pdf (они затем отделяются от исходного кода). И отличается от стиля блокнотов с ячейками, которые смешивают код и элементы презентации. В Iodide вы видите и документ, который выглядит так, как вы хотите, и лёгкий доступ к базовому коду и среде редактирования.

Iodide пока в альфа-версии, но в интернет-индустрии принято говорить: «Если вас не смущает первая версия вашего продукта, вы опоздали с запуском». Поэтому мы решили сделать очень ранний запуск в надежде получить отзывы от сообщества. У нас есть демо, которое вы можете попробовать прямо сейчас, но там ещё много недоработок (пожалуйста, не используйте эту альфу для важной работы!). Надеемся, что вы закроете глаза на косяки и поймёте ценность самой концепции, а ваши отзывы помогут понять, в каком направлении нам двигаться дальше.

Как мы пришли к Iodide


Наука о данных в Mozilla


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

Наука о данных предполагает написание большого количества кода, но в отличие от традиционной разработки ПО наша цель — отвечать на вопросы, а не создавать программное обеспечение. Это обычно сводится к созданию некоего отчёта — документа, диаграмм или интерактивной визуализации данных. Как и все, мы в Mozilla изучаем свои данные с помощью фантастических современных инструментов, таких как Jupyter и R-Studio. Но когда приходит время делиться результатами, мы обычно не можем просто передать «заказчику» блокнот Jupyter или сценарий R, поэтому часто приходится копировать ключевые цифры и сводную статистику в документ Google.

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


Полезный рабочий цикл в науке о данных

Почему в науке так мало веба?


На этом фоне в конце 2017 года я начал проект по интерактивной визуализации данных в Mozilla. В наши дни вы можете создавать такие визуализации с помощью отличных библиотек на Python, R и Julia, но для моего проекта требовалось перейти на Javascript. Это означало выход из привычного окружения науки о данных. Современные инструменты веб-разработки невероятно мощны, но чрезвычайно сложные. Против своего желания мне пришлось создавать полноценную цепочку инструментов Javascript для сборки с горячей перезагрузкой модулей, но всё равно невозможно было найти нормальный редактор, который генерирует чистые, читаемые веб-документы в живом, итеративном рабочем процессе.

Я начал задаваться вопросом, почему нет такого инструмента — почему нет аналога Jupyter для интерактивных веб-документов — и пришёл к размышлениям, почему почти никто не использует Javascript для научных вычислений. Кажется, на это есть три важные причины:

  1. Сам Javascript в научных кругах имеет противоречивую репутацию как медленный и неудобный язык.
  2. Не так много библиотек научных вычислений работают в браузере или поддерживают Javascript.
  3. Я обнаружил дефицит научных инструментов для программирования с поддержкой быстрых итераций и прямым доступом к презентационным возможностям браузера.

Это очень большие проблемы. Но работа в браузере имеет некоторые реальные преимущества для такой «коммуникативной» науки о данных, которой мы занимаемся в Mozilla. Конечно, самое большое преимущество в том, что у браузера самый передовой и хорошо поддерживаемый набор технологий визуализации данных: от DOM до WebGL, Canvas и WebVR.

Размышляя о трудностях в коммуникации, упомянутых выше, мне пришло в голову ещё одно потенциальное преимущество: в браузере конечный документ не обязательно отделять от инструмента, который его создал. Я хотел сделать инструмент для итеративной научной работы с веб-документами (веб-приложение с конкретной функциональностью)… и многие наши инструменты были по сути веб-приложениями. Для этих маленьких веб-приложений-документов, почему бы не связать документ с редактором?

Таким образом, читатели без технической подготовки могут просматривать красивый документ, а учёный мгновенно переключается в режим исходного кода. Более того, поскольку вычисления происходят в JS-движке браузера, учёный может сразу начать эксперименты с кодом. И всё это без подключения к удалённым вычислительным ресурсам или установки какого-либо программного обеспечения.

Появление Iodide


Я начал обсуждать с коллегами потенциальные плюсы и минусы научных вычислений в браузере, и в ходе бесед мы отметили другие интересные тенденции.

Внутри Mozilla выходило много интересных демонстраций на WebAssembly, новой платформе для запуска в браузере кода, написанного на языках, отличных от Javascript. WebAssembly позволяет запускать программы с невероятной скоростью, в некоторых случаях близко к нативным бинарникам. На WASM без проблем работают ресурсоёмкие процессы, даже целые 3D-игровые движки. В принципе, можно скомпилировать лучшие в мире библиотеки численных вычислений C и C++ для WebAssembly, обернуть их в эргономичные API JS, как это делает проект SciPy для Python. В конце концов, такие проекты уже существуют.


WebAssembly позволяет запускать код в браузере почти без накладных расходов

Мы также заметили, что сообщество Javascript готово вводить новый синтаксис, если это помогает людям более эффективно решать свои проблемы. Возможно, стоит попытаться эмулировать некоторые из ключевых синтаксических элементов, которые делают численное программирование более понятным и гибким в MATLAB, Julia и Python — это матричное умножение, многомерная нарезка, операции трансляции массива (broadcast array) и так далее. И снова мы обнаружили, что многие согласны с нами.

Все эти предпосылки приводят к вопросу: насколько веб-платформа подходит для научных вычислений? Как минимум, она способна помочь в коммуникациях в тех процессах, с которыми мы сталкиваемся в Mozilla (и с которыми сталкиваются многие в индустрии и академических кругах). С постоянно улучшающимся ядром Javascript и возможностью добавления синтаксических расширений для численного программирования, возможно, сам JS станет более привлекательным для ученых. Казалось, WebAssembly позволяет использовать серьёзные научные библиотеки. Третья ножка стула — веб-окружение для создания научных документов. На этом последнем элементе мы сосредоточили свои эксперименты, которые привели нас к Iodide.

Анатомия Iodide


Iodide — это инструмент, который обеспечивает учёным знакомый рабочий процесс для создания великолепных интерактивных документов, используя всю мощь веб-платформы. Работа построена в виде «отчётов» — по сути, это веб-страница, которую вы заполняете своим контентом. Плюс некоторые инструменты для итеративного изучения данных и изменения отчёта, чтобы создать финальный документ. Как только он готов, можете отправить ссылку непосредственно на него. Если коллеги и сотрудники хотят просмотреть код, то одним щелчком мыши переключаются в режим исследования. Если хотят поэкспериментировать с кодом и использовать его в качестве основы для своей работы, то ещё одним щелчком делается форк.

Дальше мы расскажем о некоторых экспериментальных идеях, как сделать этот рабочий процесс более гибким.

Режим отчёта и режим исследования


Iodide стремится в одном месте увязать исследование, объяснение и сотрудничество. Центральное место здесь занимает способность перемещаться между красивым отчётом и полезной средой для итеративного исследования с научными вычислениями.

При создании нового блокнота Iodide вы попадаете в режим исследования (Explore View). Это набор панелей, включая редактор для написания кода, консоль для просмотра выходных данных, средство просмотра рабочей области для изучения переменных, созданных во время сеанса, и панель «Предварительный просмотр отчёта».


Редактирование кода Markdown в режиме исследования Iodide

Нажатием на кнопку Report в правом верхнем углу можно расширить содержимое панели предварительного просмотра на всё окно. Читатели, которые не заинтересованы в технических деталях, могут сосредоточиться на этом представлении документа, не углубляясь в код. Когда читатель заходит по ссылке на отчёт, код запускается автоматически. Для просмотра кода нужно нажать кнопку Explore в правом верхнем углу. Оттуда можно сделать и копию блокнота для собственных исследований.


Переход из режима исследования в режим отчёта

Всякий раз, когда вы делитесь ссылкой на блокнот Iodide, ваш коллега всегда получает доступ к обоим этим представлениям. Чистый, читаемый документ никогда не отделяется от базового кода и среды редактирования.

Живые, интерактивные документы с мощью веб-платформы


Документы Iodide живут в браузере. Это означает постоянную доступность вычислительного движка. Каждый документ — это живой интерактивный отчёт с запущенным кодом. Более того, поскольку вычисление происходит в браузере одновременно с презентацией, нет необходимости вызывать бэкенд языка в другом процессе. Таким образом, интерактивные документы обновляются в режиме реального времени, открывая возможность плавных 3D-визуализаций. Низкая задержка и высокая частота кадров даже соответствуют требованиям VR.


Контрибутор Девин Бейли изучает данные МРТ своего мозга

Совместное использование и воспроизводимость


Опора на веб упрощает ряд элементов рабочего процесса, по сравнению с другими инструментами. Совместное использование реализовано нативно: документ и код доступны по одному URL и не нужно, скажем, вставлять ссылку на скрипт в сносках Google Docs. Вычислительное ядро — это браузер, а библиотеки подгружаются HTTP-запросом, как и любой скрипт — не требуется устанавливать никаких дополнительных языков, библиотек или инструментов. И поскольку браузеры обеспечивают совместимость, блокнот одинаково выглядит на всех компьютерах и ОС.

Для обеспечения совместной работы мы создали довольно простой сервер, где сохраняются блокноты. Есть публичный инстанс iodide.io, чтобы экспериментировать с Iodide и публиковать свои работы. Но можно создать и приватный инстанс за файрволом (мы в Mozilla так и делаем для некоторых внутренних документов). Но важно отметить, что сами блокноты не привязаны к одному серверу Iodide. Если возникнет необходимость, то легко перенести работу на другой сервер или экспортировать блокнот в виде пакета для совместного использования на других сервисах, таких как Netlify или GitHub Pages (подробнее об экспорте пакетов см. ниже в разделе «Что дальше?»). Передача вычислений на сторону клиента позволяет нам сосредоточиться на создании действительно отличной среды для обмена и сотрудничества, без необходимости выделять вычислительные ресурсы в облаке.

Pyodide: научный стек Python в браузере


Когда мы начали думать о том, чтобы сделать веб лучше для учёных, то сосредоточились на способах, которые могут упростить работу с Javascript, таких как компиляция существующих научных библиотек в WebAssembly и их упаковка в простые JS API. Когда мы обрисовали идею разработчикам WebAssembly в Mozilla, они предложили более амбициозную идею: если многие учёные предпочитают Python, то ступите на их поле — скомпилируйте научный стек Python для запуска в WebAssembly.

Мы думали, что это звучит устрашающе, что это будет огромный проект и что он никогда не обеспечит удовлетворительную производительность… но спустя две недели у Майка Дроэттбума была рабочая реализация Python, работающая внутри блокнота Iodide. В течение следующих нескольких месяцев мы добавили Numpy, Pandas и Matplotlib, наиболее используемые модули в научной экосистеме Python. Благодаря помощи Кирилла Смелкова и Романа Юрчака из Nexedi появилась поддержка Scipy и scikit-learn. С тех пор мы продолжаем потихоньку добавлять другие библиотеки.

Запуск интерпретатора Python внутри виртуальной машины Javascript добавляет накладные расходы к производительности, но они удивительно маленькие. По сравнению с нативным кодом, в наших тестах код выполняется в 1-12 раз медленнее в Firefox и в 1-16 раз медленнее в Chrome. Опыт показывает, что производительности вполне достаточно для комфортных интерактивных исследований.


Matplotlib в браузере поддерживает интерактивные функции, недоступные в статических средах

Перенос Python в браузер создаёт волшебные рабочие процессы. Например, вы можете импортировать и обработать данные в Python, а затем получить доступ к результирующим объектам из Javascript (в большинстве случаев преобразование происходит автоматически), чтобы отобразить их с помощью JS-библиотек, таких как d3. Ещё более волшебным образом вы получаете доступ к API браузера из кода Python, например, для манипуляции DOM без использования Javascript.

Конечно, о Pyodide можно рассказать гораздо больше и он заслуживает отдельной статьи — мы рассмотрим его более подробно в следующем месяце.

JSMD (JavaScript MarkDown)


Также как Jupyter и режим R-Markdown в R, редактор Iodide позволяет свободно чередовать код и заметки, разбивая код на куски, которые изменяются и запускаются как отдельные единицы. Наша реализация этой идеи соответствует реализации R Markdown и «режиму ячеек» в MATLAB: вместо явно основанного на ячейках интерфейса содержимое блокнота Iodide — это просто текстовый документ, который использует специальный синтаксис для разграничения определенных типов ячеек. Мы называем такой текстовый формат JSMD.

По образцу MATLAB, фрагменты кода начинаются знаками %%, за которыми следует строка, указывающая язык. В настоящее время мы поддерживаем фрагменты, содержащие Javascript, CSS, Markdown (и HTML), Python, специальный фрагмент 'fetch', который упрощает загрузку ресурсов, и плагины, расширяющие функциональность Iodide путём добавления новых типов ячеек.

Мы нашли этот формат весьма удобным. Он упрощает использование текстовых инструментов, таких как diff viewer и ваш собственный любимый текстовый редактор. Вы можете выполнять стандартные текстовые операции (вырезать/копировать/вставить) без необходимости изучать команды управления ячейками. Для более подробной информации см. документацию по JSMD.

Что дальше?


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

Расширенные функции совместной работы


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

Теперь мы рассматриваем ещё три большие функции:

  1. Треды комментариев в стиле Google Docs.
  2. Возможность предлагать изменения в чужом блокноте через механизм fork/merge, как в GitHub.
  3. Одновременное редактирование блокнотов, как в Google Docs.

На данный момент мы расставляем приоритеты примерно в таком порядке, но если вы решите их расставить иначе или у вас есть другие предложения, не стесняйтесь сообщить об этом!

Больше языков!


Мы обсуждали с сообществами R и Julia возможность компиляции этих языков в WebAssembly, чтобы использовать их в Iodide и других браузерных проектах. На первый взгляд, это выполнимо, но реализация будет немного сложнее, чем для Python. Как и в Python, открываются некоторые интересные рабочие процессы: например, вы можете применить статистические модели в R или решить дифференциальные уравнения в Julia, а затем отобразить результаты с помощью API браузера. Если вы занимаетесь этими языками, пожалуйста, дайте знать — в частности, мы хотим получить помощь от экспертов по FORTRAN и LLVM.

Экспорт блокнотов


Ранние версии Iodide были автономными запускаемыми HTML-файлами, которые включали как код JSMD, используемый в анализе, так и код JS для запуска самого Iodide, но мы отошли от этой архитектуры. Более поздние эксперименты убедили нас, что преимущества совместной работы с сервером Iodide перевешивают преимущества управления файлами в локальной системе. Тем не менее, эти эксперименты показали, что можно сделать автономный исполняемый блокнот Iodide, добавив код Iodide вместе с любыми данными и используемыми библиотеками в один большой HTML-файл. Он может получиться большим, но будет полезен как идеально воспроизводимый и архивируемый снимок.

Браузерное расширение Iodide для текстовых редакторов


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

Отзывы и помощь приветствуются!


Мы не пытаемся решить все проблемы научных данных и научных вычислений, а Iodide не универсальное решение. Если вам нужно обрабатывать терабайты данных на кластерах GPU, вряд ли Iodide вам чем-то поможет. Если вы публикуете статьи журнала и вам просто нужно написать документ в LaTeX, то есть лучшие инструменты. Если вам не нравится сама идея переносить всё в браузер, нет проблем — существует множество действительно удивительных инструментов, которые вы можете использовать для науки, и мы благодарны вам за это! Мы не хотим менять чьи-то привычки, а многим учёным не нужны веб-ориентированные коммуникации. Супер! Делайте, как вам удобно!

Но от учёных, которые делают или хотят делать контент для интернета, хотелось бы услышать, какие инструменты вам необходимы в работе!

Пожалуйста, зайдите на iodide.io, попробуйте этот инструмент и оставьте отзыв (но опять же: имейте в виду, что проект находится в альфа-версии — пожалуйста, не используйте его ни для какой критической работы, и помните, что в альфе всё может измениться). Можете заполнить небольшую анкету, также приветствуются тикеты и баг-репорты на Github. Запросы функций и общие мысли оставляйте в нашей группе Google или в Gitter.

Если хотите принять участие в создании Iodide, исходный код опубликован на Github. Iodide затрагивает широкий спектр программных дисциплин: от разработки современных интерфейсов и научных вычислений до компиляции и транспиляции, поэтому здесь много интересного!
Поддержать автора
Поделиться публикацией

Комментарии 20

    +2
    Между тем observablehq.com вышел из беты. У него большая часть тоже opensource, есть поддержка markdown, формул на MathJax, WebGL, WebVR, реактивное вычисление ячеек, также есть возможность совместной работы над одним документом. Единственное, его нельзя развернуть в своей локальной сети. Ну и не планируют поддерживать другие языки кроме JS.
      0
      Очень забавная штука, надо будет как-нибудь попробовать
        0
        Они предложили более амбициозную идею: если многие учёные предпочитают Python, то ступите на их поле

        Это очень, очень трезво и рационально. В научной среде часто если человек начал со STATA то он в ней до пенсии и сидит. Конечно, это не показатель каким профессором надо быть, но гораздо проще упростить жизнь ленивым профессорам и идти им навстречу, чем заставлять переучиться.
        Mozilla, браво.
          0
          Ну, там даже seaborn подключить нельзя. Фи. По сравнению с Google Collab, Kaggle Kernels и локальным использованием Jupyter Notebooks пока как-то очень нишево выглядит.
            0
            блин, как же этим всем научиться пользоваться
              0
              Черт, звучит зажигательно, но я не понимаю как возможно реализовать питон на wasm — если верить документации самой mozilla — сборщик мусора в wasm появится неизвестно когда, многопоточности тоже пока нет — а какой питон без сборки мусора? Тут какое-то шаманство, и скорее реализовано ограниченное подмножество питона, и не на wasm, а простой компиляцией в JS. Поправьте меня если глючу.
              UPD
              Научные библиотеки для питона написаны на С/C++, да хоть тот же TensorFlow, может это их они скомпилировали в wasm? А как тогда быть с питонным кодом, он на лету компилируется в JS? А питоновские потоки не поддерживаются наверное жеж?
                0
                Что мешает скомпилить сам питон в васм, и в нём уже интерпретировать код
                  0
                  Да, это круто, согласен.
                  0

                  Не знаю что там внутри, но чисто с точки зрения банальной эрудиции, в C тоже нет сборщика мусора, но cpython как-то существует.


                  Тредов, собственно, в C тоже нет, только сторонними библиотеками. Но это не так важно как то, что треды в тех рамках, в которых они существуют в питоне (в условиях GIL, то есть concurrency без parallelism) тоже особо ничего не требуют от виртуальной машины. То есть иллюзию тредов можно создать тупо переключениями контекста, просто машина не перестанет от этого быть "однопроцессорной", но и в питоне этого особо нет. А вот когда начинается попытка из питона подёргать сишный код, который разводит параллелизм, то да, тут либо нужны нормальные треды в wasm, либо очень сильно извращаться и тормозить.

                    0
                    Правильно все, поэтому сишный и плюсовый код без GC замечательно компилируется в wasm, где вместо физической памяти используется типизированный массив ArrayBuffer, а код, предполагающий GC, несовместим с wasm (пока), остается только как постом выше товарищ предложил, но это тормоза будут.
                    А треды третьего питона разве не конкурентные, там даже мьютексы есть, все как у взрослых. А у JS многопоточность слабее на порядок.
                      0

                      Попробую ещё раз. Garbage Collection или, скажем, Preemptive Multitasking — это просто такие структуры данных, их можно реализовать на любом языке. Слышать, что какой-то тюринг-полный язык с ними "несовместим", мне крайне странно. Более того, это не такие уж и сложные структуры данных, чтобы париться из-за них, когда ты и так уже реализуешь аж целый интерпретатор питона, который тоже всего лишь структура данных. Параллелизм да — он нечто аппаратное.

                  0
                  Тема очень важная. Много сил потратил на то, чтобы научным работникам объяснить, что эпоха представления моделей и результатов в виде статических публикаций ушла и держится только на консерватизме научной системы.
                  Надеюсь, проект взлетит и станет прототипом многих специализированных инструментов.
                    0
                    А не могли ли бы Вы развернуть эту мысль про статические публикации?
                    +1
                    Автору оригинала, вероятно, стоило сначала посмотреть на Jupyter Notebook, nbconvert или PWeave.
                    p.s. как по мне, это очередная попытка перетянуть на себя одеяло.
                      0

                      Идея по вертикали разделить код и результат довольно удбоная. В Jupyter приходится крутить туда-сюда а чтобы кому-то показать то надо скрывать код. Ну и не хватает фишек IDE и json в гит класть не удобно.

                        0
                        Автодополнение и интеграция с гитом в jupyter notebook имеется в виде плагинов.
                          0

                          А поподробнее? До нормального IDE там ещё далеко.

                            0
                            Hinterland — Автодополнение. единственное, в автодополнении появляются обьекты из тех клеток, которые уже были выполнены (как вариант — все импорты в обьявляются первой клетке, после чего эта клетка запускается чтобы в автодополнении появилось всё, что было импортнуто). Тем не менее, ускоряет работу в разы.
                            github.com/jupyterlab/jupyterlab-git — сам не пользовался, но подозреваю что это то, что нужно для интеграции с git-ом.
                            Variable Inspector — позволяет видеть значения переменных
                            для отладки — pip install ipdb
                            (https://stackoverflow.com/questions/32409629/what-is-the-right-way-to-debug-in-ipython-notebook). Сам тоже не использовал.

                              0

                              Да я про этот минус и имел ввиду: в Jupyter автодополнение только для объектов, которые уже в памяти. Если определяешь функцию в которой пишешь a = ... то автодополнений для методов a не будет. После PyCharm, который очень часто все типы выводит и предлагает автодоплнение ощущения не те. Поэтому в основном весь код пишу в PyCharm а из Jupyter только вызываю функции. В этом плане немного растраивает matplotlib потому что там всё через **kwargs и подсказок нету, каждый раз смотреть доку надо.

                          0

                          Недавно релизнулся PyCharm Pro 2019.
                          В нём как раз реализовали всё так как я себе представлял https://www.youtube.com/watch?v=TIZH4aPSN2E

                      Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                      Самое читаемое