Как сделать свой браузер на основе chromium
Создатели утверждают, что браузер Хромиум способен обеспечить пользователей быстрым, надежным и максимально безопасным серфингом интернета. Чтобы узнать о многочисленных преимуществах веб-проводника, стоит хорошенько его изучить.
Почему стоит выбрать браузер хромиум
Многих пользователь притягивает данный обозреватель, ведь он имеет массу положительных качеств. Кроме того, именно chromium стал основой для создания многочисленных аналогичных программ. Разработчики регулярно выпускают новые версии веб-проводника , что позволяет улучшать функционал браузера, делая его еще удобней и безопасней.
Среди многочисленных особенностей стоит отметить:
- Скорость работы;
- Надежность и безопасность;
- Поддерживает веб-спецификацию;
- Существует возможность расширить функционал;
- Синхронизация;
- Допускается подключение модулей.
Создатели Chromium отлично потрудились над его безопасностью, уделив ей особое внимание. Для обеспечения максимальной защитой, веб-обозреватель создан на модели «песочницы», что позволяет ограничить простор для различного рода атак. Стоит отметить, что такая защита имеется только у официальных версий, поэтому скачивать приложение стоит с сайта разработчиков. Все пароли, личные данные, конфиденциальная информация надежно защищены, украсть их вредоносные ПО и мошенники не смогут.
Так как программа довольно-таки легкая, установить ее можно не только на мощные машины, но слабые устройства. Работает обозреватель, не давая сбоев, а главное обеспечивает высокой скоростью открытия интернет-страниц.
Чем отличаются Google Chrome и браузер Хромиум
Большинство пользователей уверены, что два данных продукта одинаковые, просто пользователи их по-разному называют. Мнение такое ошибочное, ведь хромиум и хром два различных браузера.
Chrome – обозреватель, созданный компанией гугл, на основе chromium. Является полностью закрытым проектом. В момент установки программы загружается Google Update, позволяющий ей проводить автоматическое обновление.
Chromium – открытый проект, разрешающий использовать исходный код. Отсутствует автоматическое обновление, работу приходится проводить вручную. Не имеет таких полезных плагинов, как Flash и PDF Viewer. Не поддерживает кодек mp3.
Хром и хромиум тесно связаны между собой, но при этом являются разными продуктами. У хромиума имеются определенные функции и возможности, которых нет в хроме. Так как browser google chrome создавался на базе chromium, интерфейс у двух программ практически одинаковый, поэтому разобраться в работе приложения будет просто.
Браузер хромиум скачать можно на официальном сайте компании. Достаточно открыть главную страницу и нажать на «download». Если решите воспользоваться сторонними сайтами, обратите внимание на скачиваемую версию и язык интерфейса. Устанавливается приложение на компьютеры с операционной системой windows и linux.
Обычные пользователи редко используют данный веб-проводник для постоянного серфинга интернета. Ему отдают предпочтения разработчики и программисты. Но даже несмотря на то, что он менее популярен, браузер способен обеспечить быстрой, стабильной работой и отличной безопасностью.
Chromium Embedded Framework (CEF) — это проект с открытыми исходными кодами, созданный в 2008 году как элемент управления Web browser, работающий на базе Chromium от Google.
На данный момент это довольно мощный инструмент для разработки настольных приложений, со списком решений, использующих этот контрол можно ознакомиться здесь. Но достаточно сказать, что его используют такие широко известные продукты, как Evernote и Steam.
- CEF позволяет создать свои обработчики протоколов, таким образом, реализовать свой «закрытый» алгоритм шифрования (да-
да, несчастные пользователи старого Internet Explorer и корпоративных web-решений, долой ActiveX). Этим же можно воспользоваться, чтобы подгружать данные из статических ресурсов программы - CEF позволяет делать обертку над нативными функциями в пространстве объектов виртуальной машины Javascript. Ресурсоемкие операции по обработке больших массивов данных можно переложить на более строгие и быстрые языки программирования
- CEF позволяет обрабатывать события навигации, скачивания файлов и так далее
А теперь о грустном
Знакомьтесь, CefSharp
- Создание неограниченного числа компонентов класса WebView
- Обработка событий по загрузке страницы, события навигации
- Собственные обработчики протоколов.
- Внедрение js-кода во время выполнения страницы
- Создание глобальных [native code] объектов со статическими методами
Первое знакомство
Три главные вещи, которые нужны для работы — это локальный обработчик протокола, глобальный объект и тот объект, который будет у нас управлять фреймворком.
Локальный обработчик протокола
Реализуется пара классов: фабрика (реализует интерфейс CefSharp.ISchemeHandlerFactory) и, собственно, сам обработчик (реализующий интерфейс CefSharp.ISchemeHandler).
С первым все понятно:
Второй не будет сложнее:
Для того, чтобы подключить js-файл приложения, можно воспользоваться методом GetStream или GetString класса ResourceManager. Из плюсов — исходный код вашего приложения будет находиться внутри .exe или .dll файла. Из минусов — при изменении js-кода придется каждый раз заново компилировать приложение.
С ним еще проще — это обычный объект, содержащий методы и поля. Один минус — на весь проект у Вас будет по одному экземпляру каждого такого класса.
Инициализация CEF
Я решил сделать класс наследником ApplicationContext. Для оконного отображения WinForms запускается быстрее, и нет необходимости тянуть за собой WPF
На этом, собственно и все. Можно создавать форму, добавлять в нее компонент WebView и работать как душе угодно.
Если Вы дочитали до этого места, то Вы — терпеливый человек и я благодарен Вам.
Но нам этого мало
Как я уже отмечал ранее, в CefSharp есть некоторые недостатки. Например, нельзя связать компонент WebView с формой, его содержащую. Для этого родился некоторого рода жестокий костыль, который я представлю на обозрение публики.
Дабы не захламлять статью лоскутами кода, я приведу некоторые выдержки из листинга.
1 Новый класс Window, наследуемый от Form
2 Объект-мост общих вызовов
Внимательный читатель заметит неладное: вместо нормальных объектов CefSharp позволяет обмениваться только простыми типами, такими как int, double, bool, string. Но в реальной жизни обычно, как раз, наоборот. Поэтому данный костыль использует упаковку/распаковку данных в JSON. Решение неидеальное, затрачивается множество времени зря, но таковы данные ограничения библиотеки.
Поскольку DataContractJsonSerializer работает только с определенными типами, его использовать проблематично. Поэтому в проекте был использован 100% managed парсер. Тоже костыль.
Сегодня я предлагаю посмотреть как можно подрихтовать исходники chromium-а, собрать свой вариант браузера и подтянуть это добро в electron. Эта статья — пробный шар, какая то часть ее позже перекочует в документацию проекта который, я надеюсь, смогу раскачать и сделать популярным, но об этом потом.
Идея вокруг которой крутится эта статья (и надеюсь многие другие, которые последуют) — простая до безобразия. Примерно как идея ноды — "а давайте прикрутим к v8 свой эвент луп и будем писать сервера на js". Хорошая идея, число хейтеров подтверждает. Или идея — "а давайте прикрутим спереди браузер, сзади — ноду и будем писать на этом кросс-платформенные приложения для десктопов". Это очень хорошая идея, число хейтеров подтверждает.
Моя идея хорошо вписывается в этот строй — а давайте выкинем все лишнее из хромиума, притащим этот огрызок в электрон, выкинем все лишнее из электрона что бы от него (электрона) ничего не осталось, да так что бы хейтерам было нечего ненавидеть и что бы они ненавидели нас за это. Хм. Хорошая идея, чем дольше над ней думаю тем больше мне она нравится.
Проблема каждой хорошей идеи — реализация. Естественно сразу после того как мне пришла в голову эта идея я с шашкой наголо бросился на исходники хромиума. Гм. Хромиум не просто большой. Он огромен. Он огромен как операционная система. Потому что он и является операционной системой. А последнее время он даже этого не скрывает и трасформируется в Chromium OS. Так вот, он огромен настолько что даже выкидывать код из него — не так просто как может показаться на первый взгляд. Но на второй взгляд и с нанадцатой попытки на самом деле можно освоить и это. Так что давайте возьмем себя в руки, уймем дрожь в коленках и приступим наконец уже.
Саму идею мы конечно реализовывать не будем, статья о гораздо более маленьком шаге — внести минимальные правки в chromium, собрать его, подтянуть это добро в electron и собрать электрон. Все. Но по пути я буду периодически отвлекаться от того что мы делаем на то зачем (в будущем) это нужно.
В приниципе если мы это пробросим в chromium то и нода для electron не нужна и ее можно выкинуть. Ок.
Мысль была простой — насколько возможно одиночке разобраться в сорцах хромиума, выкинуть что то ненужное и при этом не поломать что то нужное. И я пошел проверять эту гипотезу.
Давайте приступим. Для начала давайте убедимся что мы можем собрать chromium с сорцов. Тут никакого rocket science, все делаем по инструкции. Я собирал под мак поэтому пользовался этой инструкцией. Если вы под другой осью то стоит начать отсюда.
Не буду пересказывать содержимое этого документа, если мы собираем с оригинальной репы без переключений веток то все должно пройти гладко. Единственное что могу добавить — если вы ставили/обновляли XCode то после этого стоит его еще и запустить — он что то у себя там доставляет при старте. У меня был момент когда до этого телодвижения сборка не собиралась, после собралась (что то то ли с либами то ли с хедерами) и это было не xcodebuild -license (см. в самом конце упомянутой инструкции)
После того как вы установили depots_tools вся последовательность действий сводится к:
Консервативные пользователи которых раздражает хипстерский интерфейс вима могут проделать то же самое в vi, выбор за вами.
После этого остается только сделать
и дождаться завершения сборки.
Поскольку просто рассказывать что было сделано, приводить тут команды шелла и скриншоты результата — это скучно, тупо и никому не нужно, по пути я буду немного рассказывать о чем я думал когда это делал и немного про внутренности хромиума и электрона, что бы у вас образовался какой то фундамент если вдруг захотите сделать что то подобное но другое.
Так вот. Маленький кусочек большой картины. Если мы разматываем что-то, что проброшено в js, то есть какая то сущность к которой мы из js имеем доступ, то скорее всего это что-то прикручено в blink и проброшено в v8. Blink — это рендерер, то что занимается отрисовкой DOM на вашем экране, v8 — это js движок. У вменяемых программистов конечно же возникает картинка в которой blink сидит отдельно, имеет доступ к DOM (и CSSOM — тут, немножко тут, CSS Typed Object Model) и занимается отрисовкой, v8 занимается вычислениями и все такое. Так вот. Нет. Код писали не благородные лесные эльфы-крестоностцы, как можно было бы ожидать, а вполне себе обычные люди, в трудных ситуациях идущие на компромиссы. А с учетом размеров проекта — идти на компромиссы приходилось часто, так что будьте готовы удивляться. Сам по себе код обычно легко читаем, надо отдать должное. Но вот архитектурные решения и размазанность этого кода по проекту первое время удивляют.
Blink у нас лежит в third_party директории и у неискушенного читателя может сложиться впечатление что он автономен и выступает в роли зависимости, что то вроде npm-пакета в node_modules, но нет. Blink является практически неотъемлимой частью chromium, многое знает об его устройстве и не стесняется делать импорты из chromium-а что для порядочной зависимости является абсурдом. Не будем умничать, тут так принято (хотя да, и эти люди запрещают мне ковыряться в . ). Что бы понять насколько blink прирос мясом к chromium можно взглянуть например сюда или сюда.
(by the way, тут сидит народ из JetBrains, вопрос к ним — а есть какой то рецепт завести chroimium в Clion на обычной машинке а не выкованной высшими эльфами из Гандолина? И что бы два раза не вставать — а он mojom пережевывает?)
Ок. Идем в third_party/blink/renderer/platform/loader/cors/ и в cors.cc видим
Собираем по новой:
В этот раз все пройдет гораздо быстрее, вместо 50 000 артефактов собираться будет пара тысяч (сейчас точно не помню сколько было конкретно в этом случае, но обычно если mojom не трогали и никого не выкидывали [функции/методы/классы] редко более 5-7 тысяч артефактов пересобирается).
Запускаем chromium и скармливаем ему какой нибудь html типа
И дрожащей от нетерпения рукой открываем консоль в браузере. Ну что, обломались? Я вот тоже так же обломался. Ладно, не буду томить, вот коммит который делает работу. Тут кстати прикольная фича, я могу показать этот же коммит но в репе chromium-а, вот смотрите, не уверен как к этому относиться так что пофигу. Но сдается мне что король голый а форк не настоящий, но это потом, на тему автономности я планирую отдельную статью.
Ну а поскольку интрига сорвана давайте уже воспользуемся готовым результатом.
Естественно я уже выложил все в репе, вот тут, нам нужна ветка without/restricted-headers
Не торопитесь делать git clone . Если вы собирали хромиум по инструкции то сама репа у вас уже есть, она лежит в chromium/src . Для того что бы пролить в нее ветки с моей репы достаточно сделать
после этого делаем git remote -v и убеждаемся что форк прописан в репе, должно быть что то вроде:
Отлично. Git прекрасный инструмент для распределенной работы и мы еще поговорим об этом позже. А пока что нас интересует ветка without/restricted-headers .
Делаем git fetch gonzazoid , это прольет в локальную репу все изменения форка. После переключимся в нужную ветку: git checkout without/restricted-headers . Либо можно сделать git pull в текущую ветку но тут есть ньюансы.
Если вы собирали с main то собирали вы скорее всего другую версию хромиума, не ту с которой отбранчевалась ветка without/restricted-headers . А значит (с большой вероятностью) сборка не заработает. Потому что нужно:
Это долго и нудно. Но это стоит держать в голове. Однако когда вы переключаетесь между ветками которые отбранчевались с одного и того же коммита после переключения не только не надо делать gclient sync, но и не надо трогать директорию сборки. Нинзя сам разберется какие файлы поменялись, пересоберет объектники и все такое.
Ок, переключились на ветку without/restricted-headers и предположим что собрали ее. Скармливаем вышеупомянутый html и видим в консоли что то вроде:
Да, мы можем выставлять эти хедеры и хромимум даже бровью не ведет. Чудненько.
Но как браузер такая сборка не особа полезна (хромиум как браузер вообще не особо, частенько oh-snap-ает, на видео хостингах вообще бесполезен из за своего набора кодеков и все такое)
Но вот если мы это притащим в электрон, то там это может пригодиться.
Ок. Собираем электрон. (IRL вы еще захотите сохранить свои изменения, запушить их и повесить на коммит тег, но так как это учебная статья и я все уже сделал — то этот момент пока опускаем)
Знакомство со сборкой электрона стоит начать отсюда. После сборки chromium-а там почти все для вас будет знакомо. В сухом остатке:
Тут обратите внимание на строку
Если вы после сборки электрона в этой же сессии терминала пойдете собирать chromium то CHROMIUM_BUILDTOOLS_PATH будет указывать на build tools электрона. А когда вы снесете электрон из за того что у вас не хватает места то CHROMIUM_BUILDTOOLS_PATH будет указывать в никуда. Соотв. к сборке chromium-a (если вы решили вдруг пересобрать его ПОСЛЕ сборки электрона) добавляется этот же шаг — перед генерацией сборки делаем
в директории сорцов chromium-а.
Вернемся к электрону.
Структура директорий будет такая же как и у chromium, потому что в src у вас сейчас лежит на самом деле хромиум. Просто в его код добавилась директория electron в которой и лежит репа электрона. Ок. Запускаем сборку:
Опять же, если мы не чудили и все делали по инструкции то скорее всего все соберется. А вот как бы нам теперь электрону подсунуть свой chromium?
Побродив по сорцам находим в корне проекта /DEPS файл. И видим в нем строки:
Скорее всего нам сюда. Дальше в этом же файле видим:
Это мы удачно зашли.
Смотрим как это используется (в этом же файле)
остается только прописать тег который мы повесили на наш коммит в chromium:
Тут небольшое отступление. Версия chromium-а важна. Электрон пользуется chromium-ом не через Chromium Embedded а довольно агрессивно лезет в потроха и применяет свой набор патчей. Соответственно просто так взять и поменять версию chromium-а в сборке электрона как правило не получится — нужно танцевать от той сборки chromium-а на которую рассчитывает electron.
То есть в нашем случае нам нужна не последняя версия chromium в main а конкретно 98.0.4706.0. Если вы повторяете самостоятельно все шаги в статье — не расстраивайтесь. Можно сделать git stash, отбранчеваться от нужного тега и сделать git stash apply. Либо, если вы уже закоммитили — отбранчеваться от нужного тега и сделать git cherry-pick нужного коммита. Я в свое время начал эксперименты с отключения cookie вот в этой ветке отбранчевавшись от main, и когда дело дошло до электрона пожалел о своей беспечности. Но cherry-pick и за два вечера перенес порядка 80 коммитов в нужную ветку, ничего страшного.
Ок. Вернемся к сборке электрона. Наши коммиты в chromium-е вылиты на github, потеганы, конфиг электрона поправлен и мы готовы собирать. Но мы поменяли версию chromium-а и надо бы обновить все дерево сорцов и перегенерить план сборки.
Вот тут у меня довольно не проработанная часть. Я на самом деле сделал форк electron-а, завел свою ветку, закоммитил в ней изменения, вылил на github и запустил сборку вот так:
Поскольку директория src/electron и есть репа электрона, наверняка то же самое можно сделать локально, без выливания изменений на github, в инструкции по сборке электрона даже описывают это но я просто пока еще с этим не разбирался. Если кто пройдет этот путь короче — you are very welcome! Делитесь опытом, я обновлю статью.
Так. Сборка. Запускаем
И довольно быстро падаем с ошибкой про LLVM. Почему? Потому что chromium_git используется не только электроном но и самим chromium для сборки, он пытается сходить по тому урлу что мы ему дали и выкачать оттуда llvm (похоже что подрихтованный под этот проект иначе что бы ему не сходить по урлу самого LLVM) а так как там где мы ему указали LLVM нет — он падает.
Это очередной звоночек на тему автономности и опенсорсности, но пока просто запоминаем это и идем дальше.
Очевидно что нам придется оставить chromium_git в покое а менять значение в самой сборке урла:
И вот теперь то оно наконец то соберется. Ну наконец то! Помните тот html что мы ваяли для проверки в chromium? Вспоминаем его путь и делаем:
Открываем консоль в электроне и видим ту же картину что и на скриншоте выше. Отлично!
После этого запускаем
И увидим что то вроде:
Что то из этого уже работает, что то еще нет, все интересное только начинается!
Отдельной статьей будет объяснение того зачем я это все делаю и как я вижу как электрон можно сделать стройным как Снегурочку, но поскольку это уже будет «Я пиарюсь» — если вы хотите это продолжение — поддержите кармой.
Все. Новостей на сегодня больше нет, с вами был Тимур, хорошего настроения!
Как насчет создания веб-браузера для вашей компании или настраиваемого браузера для читателей блога – или, если уж на то пошло, даже одного для себя! MakeMyBrowser – это бесплатный веб-сервис, который позволяет вам создать свой собственный настраиваемый браузер для вашей компании, друзей, семьи или просто кого-либо. Персонализированные браузеры, созданные с помощью MakeMyBrowser, основаны на хроме и поддерживают все расширения Chrome.
Создайте персонализированный браузер с MakeMyBrowser
Теперь добавьте закладки в свой браузер, чтобы пользователи могли легко переходить на ваш сайт и иметь к нему легкий доступ. Вы можете добавлять настраиваемые закладки и даже настраивать домашнюю страницу браузера. Более того, если вы не хотите добавлять закладки вручную, вы можете экспортировать их из своего Google Chrome, который вы в настоящий момент используете.
Теперь третий и последний шаг – выбор подходящей темы. Есть много вариантов, доступных для выбора.
Выберите подходящую тему для вашего браузера и нажмите «Готово», а затем кнопку «Загрузить».
Теперь загрузите созданный вами браузер и установите его, как любое другое простое приложение. Программа установки загрузит некоторые файлы из Интернета, поэтому для установки браузера вам необходимо подключение к Интернету. После установки вы можете пользоваться своим персональным браузером и даже распространять его среди своих друзей, семьи, читателей блогов или своих коллег.
Браузер выглядит потрясающе, и каждая функция выглядит великолепно. Самое приятное то, что он основан на такой сильной платформе, как Chromium. Я могу установить тысячи расширений на свой собственный браузер без каких-либо проблем. Платформа быстрая, плавная и гибкая.
Если вы издатель или блогер, MakeMyBrowser предлагает вам что-то особенное. Существует специальный раздел для издателей, который позволяет вам создать персональный браузер для ваших читателей и увеличить трафик на ваш блог. Ваш персональный браузер постоянно напоминает вашим пользователям о посещении вашего сайта. Это потрясающая маркетинговая стратегия, которая может помочь вам увеличить трафик и привлечь читателей к вашему блогу. Вы можете просто зарегистрироваться в качестве блогера и создать персональный браузер для своих читателей.
Обновление: сайт, похоже, был закрыт. Спасибо Дискоданк.
Задумывались ли вы когда-нибудь о создании собственного браузера? На самом деле попробовать себя в разработке программного обеспечения довольно легко, и для этого даже не потребуется больших знаний в программировании. Сегодня мы попробуем сделать первый шаг на пути к становлению гуру разработки. Возможно вас заинтересует этот процесс, и вы захотите углубиться сильнее.
Установка и обновления
Для начала вам необходимо скачать и установить Visual Studio Community Edition от Microsoft, который к слову абсолютно бесплатен. Эта среда разработки может показаться вам довольно громоздкой, но она содержит множество готовых шаблонов, в том числе и веб браузер, который нам так необходим.
Создаем собственный веб браузер
После развертывания всех необходимых компонентов, Visual Studio запустится автоматически. Первым делом вам предложат подключиться к различным службам для разработчиков, но в нашем случае такой необходимости нет. Выбираем пункт Не сейчас! Возможно, позже , выбираем понравившуюся тему оформления и наконец запускаем Visual Studio.
После того как Visual Studio будет запущен вы увидите рабочую область, которая разделена на две части. В левой части отображается пустая форма нашего проекта, а в правой части находится панель свойств, где мы сможем изменять размер и отступы элементов. Сейчас в левой части необходимо открыть меню Панель элементов , в разделе Стандартные элементы управления выбираем WebBrowser и щелкаем на пустое окно в нашей форме.
Создание элементов меню
Для создания элементов управления нам нужно снова воспользоваться Панелью элементов . Найдите там элемент Button и перетащите в верхнюю часть окна. Всего нам понадобиться 5 кнопок. Их цвет и форму можно будет изменить позже, в разделе свойства. Также нам нужна строка адреса – перетащите их из панели элементов TextBox в нашу форму.
Расставьте кнопки и текстовое поле так, как вам будет удобно. Visual Studio позволяет с лёгкостью сделать это симметрично и на одинаковом расстоянии. Сейчас нам необходимо немного изменить размеры содержимого, чтобы элементы управления не перекрывали веб страницу.
Для этого щелкните левой клавишей мыши на пустом поле нашей формы, а затем нажмите на небольшой треугольник в правом верхнем углу и выберете пункт Открепить в родительском контейнере . Теперь просто потяните за верхний белый квадрат вниз так, чтобы содержимое нашего браузера находилось под элементами управления.
Стоит разобраться, что мы только что написали. Первым делом мы обращаемся к нашему веб браузеру – как только мы перетащили элемент WebBrowser из панели в форму, мы создали элемент с именем webBrowser1. В программе может использоваться множество различных элементов и каждому из них задается имя по умолчанию и порядковый номер.
Теперь давайте разберемся со строкой поиска. Для нее значение будет следующим:
Начало здесь ровно такое же, как и раньше – мы просто обращаемся к нашему браузеру. Затем идет функция перейти ( Navigate ) на определенный адрес, у которой в скобках указаны параметры. В качестве параметров у нас опять же элемент тестовая строка с номером 1 ( textBox1 ) и текст из нее ( Text ) от которого мы передаем функции Navigate. Эту же функцию следует задать нашей пятой кнопке. Так мы пусть и повторим действие, зато будем уверены, если что-то пойдет не так, то сможем повторить процесс.
Запускаем наш браузер
Настало время запустить наш браузер. Для этого достаточно нажать кнопку Пуск в меню сверху. Спустя некоторое время вы увидите наш скромный веб обозреватель и сможете открыть в нем любую веб страницу. Если у вас что-то не получилось, то в первую очередь проверьте знак ; в конце строки. Сохраните свой браузер нажав иконку в виде дискеты, в левом верхнем углу и при следующем запуске окружения разработки у вас уже будут все инструменты под рукой.
Заключение
Сегодня мы рассмотрели один из самых простых вариантов применения Microsoft Visual Studio. Если, вам понравилось исследовать разработку программного обеспечения, то попробуйте изучить пособие Microsoft.
Создаете вы свой проект или только готовитесь к этому – просто поделитесь с нами в комментариях. Возможно именно наш скромный браузер вдохновит вас на нечто большее.
Читайте также: