HTML Diff
2 added 1 removed
Original 2026-01-01
Modified 2026-02-26
1 <p><strong>Разработчики часто неверно понимают концепцию передачи состояния представления (REST). Большинство ошибок связаны с трактовкой архитектурного ограничения HATEOAS. В этой статье мы разберем популярные заблуждения, связанные с REST, и подробно остановимся на HATEOAS. В конце текста на примере имитации конечного автомата - кухонного тостера - рассмотрим, как гипермедиа может использоваться в REST API для управления состояниями.</strong></p>
1 <p><strong>Разработчики часто неверно понимают концепцию передачи состояния представления (REST). Большинство ошибок связаны с трактовкой архитектурного ограничения HATEOAS. В этой статье мы разберем популярные заблуждения, связанные с REST, и подробно остановимся на HATEOAS. В конце текста на примере имитации конечного автомата - кухонного тостера - рассмотрим, как гипермедиа может использоваться в REST API для управления состояниями.</strong></p>
2 <p><em>Примечание: Это адаптированный перевод статьи<a>Designing a True REST State Machine</a>Билла Доррфельда, технического журналиста и специалиста по API. Повествование ведётся от лица автора оригинала.</em></p>
2 <p><em>Примечание: Это адаптированный перевод статьи<a>Designing a True REST State Machine</a>Билла Доррфельда, технического журналиста и специалиста по API. Повествование ведётся от лица автора оригинала.</em></p>
3 <h2>Содержание</h2>
3 <h2>Содержание</h2>
4 <ul><li><a>История REST и гипермедиа</a></li>
4 <ul><li><a>История REST и гипермедиа</a></li>
5 <li><a>Что такое REST</a></li>
5 <li><a>Что такое REST</a></li>
6 <li><a>Пример конечного автомата: IoT-тостер</a></li>
6 <li><a>Пример конечного автомата: IoT-тостер</a></li>
7 <li><a>Заключение</a></li>
7 <li><a>Заключение</a></li>
8 - </ul><p>Концепция гипермедиа сформировалась в 1941 году, когда аргентинский писатель Хорхе Луис Борхес написал "Сад расходящихся тропок" - рассказ, в котором страницы текста ссылаются друг на друга. Вероятно, это первый в истории пример гипертекста (<em>на самом деле<a>впервые</a>гипертекст использовался в романе Джеймса Джойса "Улисс", - прим. редакции</em>). Сейчас в массовой культуре есть множество примеров реляционных связей - от сюжета видеоигры<a>Bioshock</a>до серии детских романов-ужасов Роберта Стайна<a>Goosebumps</a>, - но во времена Борхеса такой прием был беспрецедентным.</p>
8 + </ul><h2>История REST и гипермедиа</h2>
 
9 + <p>Концепция гипермедиа сформировалась в 1941 году, когда аргентинский писатель Хорхе Луис Борхес написал "Сад расходящихся тропок" - рассказ, в котором страницы текста ссылаются друг на друга. Вероятно, это первый в истории пример гипертекста (<em>на самом деле<a>впервые</a>гипертекст использовался в романе Джеймса Джойса "Улисс", - прим. редакции</em>). Сейчас в массовой культуре есть множество примеров реляционных связей - от сюжета видеоигры<a>Bioshock</a>до серии детских романов-ужасов Роберта Стайна<a>Goosebumps</a>, - но во времена Борхеса такой прием был беспрецедентным.</p>
9 <p><em>Гипермедиа - система организации информации, элементы которой взаимосвязаны и, кроме самого гипертекста, включают в себя видео, картинки, аудио и другие типы контента.</em></p>
10 <p><em>Гипермедиа - система организации информации, элементы которой взаимосвязаны и, кроме самого гипертекста, включают в себя видео, картинки, аудио и другие типы контента.</em></p>
10 <p>Затем произошло несколько событий, которые помогли REST сформироваться в концепцию с четкой структурой:</p>
11 <p>Затем произошло несколько событий, которые помогли REST сформироваться в концепцию с четкой структурой:</p>
11 <ul><li>1963:<a>Тед Нельсон</a>ввел термины гипертекста и гипермедиа.</li>
12 <ul><li>1963:<a>Тед Нельсон</a>ввел термины гипертекста и гипермедиа.</li>
12 <li>1968: Исследователь человеко-машинного интерфейса(Human-Machine Intelligence, HMI) Дуглас Энгельбарт на презентации, которую позже окрестили "матерью всех демонстраций", представил систему NLS - oN-Line System и первую компьютерную мышь. Этот момент можно назвать началом обработки текста в современном виде.</li>
13 <li>1968: Исследователь человеко-машинного интерфейса(Human-Machine Intelligence, HMI) Дуглас Энгельбарт на презентации, которую позже окрестили "матерью всех демонстраций", представил систему NLS - oN-Line System и первую компьютерную мышь. Этот момент можно назвать началом обработки текста в современном виде.</li>
13 <li>1987: Сотрудник Apple Билл Аткинсон создал HyperCard - первую успешную реализацию гипермедиа до появления Всемирной паутины.</li>
14 <li>1987: Сотрудник Apple Билл Аткинсон создал HyperCard - первую успешную реализацию гипермедиа до появления Всемирной паутины.</li>
14 <li>1989: Тим Бернерс-Ли из ЦЕРНа создал<a>Всемирную паутину</a>и представил первую успешную реализацию протокола передачи гипертекста (HTTP) между клиентом и сервером.</li>
15 <li>1989: Тим Бернерс-Ли из ЦЕРНа создал<a>Всемирную паутину</a>и представил первую успешную реализацию протокола передачи гипертекста (HTTP) между клиентом и сервером.</li>
15 <li>2000: Рой Филдинг, соавтор спецификации HTTP и URI, написал докторскую диссертацию<a>"Архитектурные стили и проектирование сетевых архитектур программного обеспечения"</a>, где он описал передачу репрезентативного состояния, или REST. Именно Филдинг считается создателем концепции REST в ее нынешнем виде.</li>
16 <li>2000: Рой Филдинг, соавтор спецификации HTTP и URI, написал докторскую диссертацию<a>"Архитектурные стили и проектирование сетевых архитектур программного обеспечения"</a>, где он описал передачу репрезентативного состояния, или REST. Именно Филдинг считается создателем концепции REST в ее нынешнем виде.</li>
16 </ul><h2>Что такое REST</h2>
17 </ul><h2>Что такое REST</h2>
17 <p>Все технические аспекты, которые определяют REST, трудно раскрыть в виде статьи в блоге - это слишком объемная тема. Поэтому предлагаю пойти от обратного: рассмотреть четыре распространенных заблуждения - они помогут нам понять, чем REST точно не является.</p>
18 <p>Все технические аспекты, которые определяют REST, трудно раскрыть в виде статьи в блоге - это слишком объемная тема. Поэтому предлагаю пойти от обратного: рассмотреть четыре распространенных заблуждения - они помогут нам понять, чем REST точно не является.</p>
18 <h3>Заблуждение №1: REST - это просто CRUD</h3>
19 <h3>Заблуждение №1: REST - это просто CRUD</h3>
19 <p>CRUD - акроним, который обозначает четыре базовые функции при работе с персистентными хранилищами данных: "создание, чтение, редактирование, удаление". CRUD соответствует действиям в SQL, но он плохо соотносится с методами HTTP.</p>
20 <p>CRUD - акроним, который обозначает четыре базовые функции при работе с персистентными хранилищами данных: "создание, чтение, редактирование, удаление". CRUD соответствует действиям в SQL, но он плохо соотносится с методами HTTP.</p>
20 <p>Хотя GET и DELETE в REST и CRUD совпадают, POST, PUT и PATCH отвечают за разные операции. Например, в REST POST означает не только "создать" - это универсальный метод. С его помощью туннелируется весь протокол SOAP при использовании с HTTP.</p>
21 <p>Хотя GET и DELETE в REST и CRUD совпадают, POST, PUT и PATCH отвечают за разные операции. Например, в REST POST означает не только "создать" - это универсальный метод. С его помощью туннелируется весь протокол SOAP при использовании с HTTP.</p>
21 <p>Поскольку HTTP-методы не соответствуют CRUD, теоретик и популяризатор REST Асбьёрн Ульсберг утверждает, что создатели различных API должны подумать, как они могут описывать API иным способом: "Не ограничивайте себя CRUD при разработке REST API. Прочитайте спецификацию и поймите семантику каждого метода, а затем правильно используйте ее".</p>
22 <p>Поскольку HTTP-методы не соответствуют CRUD, теоретик и популяризатор REST Асбьёрн Ульсберг утверждает, что создатели различных API должны подумать, как они могут описывать API иным способом: "Не ограничивайте себя CRUD при разработке REST API. Прочитайте спецификацию и поймите семантику каждого метода, а затем правильно используйте ее".</p>
22 <p>Если перефразировать, смысл этой цитаты сводится к тому, что REST - это стиль архитектуры, а не протокол. Таким образом, ошибочно называть "RESTful" HTTP API с операциями CRUD.</p>
23 <p>Если перефразировать, смысл этой цитаты сводится к тому, что REST - это стиль архитектуры, а не протокол. Таким образом, ошибочно называть "RESTful" HTTP API с операциями CRUD.</p>
23 <h3>Заблуждение №2: некоторые конструкции URI "более RESTful", чем другие</h3>
24 <h3>Заблуждение №2: некоторые конструкции URI "более RESTful", чем другие</h3>
24 <p>Унифицированные идентификаторы ресурсов (URI) - основа концепции REST. Они позволяют определять ресурсы и действия с ними. Однако многие разработчики ошибочно считают, что могут отличить качество построения REST API просто на основе того, как структурирован URI. Проведем эксперимент: сможете ли вы сказать, какой URI "более RESTful"?</p>
25 <p>Унифицированные идентификаторы ресурсов (URI) - основа концепции REST. Они позволяют определять ресурсы и действия с ними. Однако многие разработчики ошибочно считают, что могут отличить качество построения REST API просто на основе того, как структурирован URI. Проведем эксперимент: сможете ли вы сказать, какой URI "более RESTful"?</p>
25 <ol><li><a>http://hexlet.io/authors/contributor?author=doerrfeld</a></li>
26 <ol><li><a>http://hexlet.io/authors/contributor?author=doerrfeld</a></li>
26 <li><a>http://api.hexlet.io/blogpost/getPostById?id=47</a></li>
27 <li><a>http://api.hexlet.io/blogpost/getPostById?id=47</a></li>
27 <li><a>http://api.hexlet.io/blogpost/47/edit-form</a></li>
28 <li><a>http://api.hexlet.io/blogpost/47/edit-form</a></li>
28 <li><a>http://api.hexlet.io/blogpost/47</a></li>
29 <li><a>http://api.hexlet.io/blogpost/47</a></li>
29 <li><a>http://api.hexlet.io/128ndoels-8asdf-12d5-39d3</a></li>
30 <li><a>http://api.hexlet.io/128ndoels-8asdf-12d5-39d3</a></li>
30 </ol><p>Тот факт, что мы указали URI, метод и описание для каждого вызова API, еще не значит, что мы создали REST API - мы просто задокументировали наши URI, как если бы мы задокументировали операции удаленного вызова процедур (RPC). Ульсберг отмечал, что такой подход усложняет работу и лишает сервис гибкости.</p>
31 </ol><p>Тот факт, что мы указали URI, метод и описание для каждого вызова API, еще не значит, что мы создали REST API - мы просто задокументировали наши URI, как если бы мы задокументировали операции удаленного вызова процедур (RPC). Ульсберг отмечал, что такой подход усложняет работу и лишает сервис гибкости.</p>
31 <h3>Заблуждение №3: API-интерфейсам REST нужны версии</h3>
32 <h3>Заблуждение №3: API-интерфейсам REST нужны версии</h3>
32 <p>Представим, что у нас есть таблица базы данных под названием "Referer". После нескольких лет использования мы заметили, что имя базы написано с ошибкой и решили изменить его на "Referrer". Клиенты уже взаимодействуют со старым именем таблицы в своих SQL-операторах, поэтому обновить имя базы будет крайне сложно - прежде придется обновить все клиенты.</p>
33 <p>Представим, что у нас есть таблица базы данных под названием "Referer". После нескольких лет использования мы заметили, что имя базы написано с ошибкой и решили изменить его на "Referrer". Клиенты уже взаимодействуют со старым именем таблицы в своих SQL-операторах, поэтому обновить имя базы будет крайне сложно - прежде придется обновить все клиенты.</p>
33 <p>То же самое с API: если мы решим обновить один из /blogposts/ в URI из примеров, указанных выше, обновления потребуют все клиенты. Это приведет к созданию второй версии - то есть к необходимости обновить документацию и все клиенты. Резюмируя, можно сказать, что строго запрограммированное управление версиями в URI - это боль.</p>
34 <p>То же самое с API: если мы решим обновить один из /blogposts/ в URI из примеров, указанных выше, обновления потребуют все клиенты. Это приведет к созданию второй версии - то есть к необходимости обновить документацию и все клиенты. Резюмируя, можно сказать, что строго запрограммированное управление версиями в URI - это боль.</p>
34 <h3>Заблуждение №4. Гипермедиа необязательна для REST API</h3>
35 <h3>Заблуждение №4. Гипермедиа необязательна для REST API</h3>
35 <p><em>В интервью Майку Амудсену в 2014 году Филдинг сказал следующее: "Гипермедиа как механизм управления состоянием приложения - это ограничение REST. Это не одна из опций и не идеал, к которому нужно стремиться. Гипермедиа - это данность и ограничение. Вы либо принимаете их, либо не занимаетесь REST".</em></p>
36 <p><em>В интервью Майку Амудсену в 2014 году Филдинг сказал следующее: "Гипермедиа как механизм управления состоянием приложения - это ограничение REST. Это не одна из опций и не идеал, к которому нужно стремиться. Гипермедиа - это данность и ограничение. Вы либо принимаете их, либо не занимаетесь REST".</em></p>
36 <p>REST состоит из 6 основных ограничений - так называемых ограничений Филдинга. Он выглядит так:</p>
37 <p>REST состоит из 6 основных ограничений - так называемых ограничений Филдинга. Он выглядит так:</p>
37 <ul><li>Клиент-сервер</li>
38 <ul><li>Клиент-сервер</li>
38 <li>Отсутствие состояния</li>
39 <li>Отсутствие состояния</li>
39 <li>Кэшируемость</li>
40 <li>Кэшируемость</li>
40 <li>Многоуровневая система</li>
41 <li>Многоуровневая система</li>
41 <li>Код по требованию</li>
42 <li>Код по требованию</li>
42 <li>Единообразие интерфейса</li>
43 <li>Единообразие интерфейса</li>
43 </ul><p>При этом последний пункт - "Единообразие интерфейса" - состоит из еще нескольких подпунктов:</p>
44 </ul><p>При этом последний пункт - "Единообразие интерфейса" - состоит из еще нескольких подпунктов:</p>
44 <ol><li>Определение ресурсов</li>
45 <ol><li>Определение ресурсов</li>
45 <li>Управление ресурсами через представление</li>
46 <li>Управление ресурсами через представление</li>
46 <li>Самодостаточные сообщение</li>
47 <li>Самодостаточные сообщение</li>
47 <li>Гипермедиа как механизм управления состоянием приложения (HATEOAS)</li>
48 <li>Гипермедиа как механизм управления состоянием приложения (HATEOAS)</li>
48 </ol><p>Среди них HATEOAS, вероятно, самое важное и уникальное, но наименее понятное условия REST.</p>
49 </ol><p>Среди них HATEOAS, вероятно, самое важное и уникальное, но наименее понятное условия REST.</p>
49 <p><em>По сути, HATEOAS или гипермедиа как механизм управления состоянием, - это подход к описанию ресурсов API. С его помощью можно установить инверсию контроля за ресурсами, которые клиент может вызвать, вместо того, чтобы просто перечислять каждый из них и указывать список функций, которые можно с ними выполнить. Именно благодаря этому сервер может отвечать за состояние ресурса.</em></p>
50 <p><em>По сути, HATEOAS или гипермедиа как механизм управления состоянием, - это подход к описанию ресурсов API. С его помощью можно установить инверсию контроля за ресурсами, которые клиент может вызвать, вместо того, чтобы просто перечислять каждый из них и указывать список функций, которые можно с ними выполнить. Именно благодаря этому сервер может отвечать за состояние ресурса.</em></p>
50 <p>Чтобы лучше понять эту идею, Ульсберг советует воспользоваться методом, предложенным Дональдом Норманом в книге "Дизайн повседневных вещей". Так же, как чашка сделана для того, чтобы ее взяли за ручку и подняли, а кнопка - чтобы быть нажатой, гипермедиа хочет сообщить вам, что делать с тем или иным ресурсом. Гипермедиа - это ссылки и метаданные для операций, которые помогают разработчикам или машинам выполнять дополнительные действия.</p>
51 <p>Чтобы лучше понять эту идею, Ульсберг советует воспользоваться методом, предложенным Дональдом Норманом в книге "Дизайн повседневных вещей". Так же, как чашка сделана для того, чтобы ее взяли за ручку и подняли, а кнопка - чтобы быть нажатой, гипермедиа хочет сообщить вам, что делать с тем или иным ресурсом. Гипермедиа - это ссылки и метаданные для операций, которые помогают разработчикам или машинам выполнять дополнительные действия.</p>
51 <p>Асбьёрн Ульсберг описывает гипермедиа так: "Если вы посмотрите на гипермедиа как на рецепт того, как должен выглядеть следующий запрос, вы поймете, что такое гипермедиа".</p>
52 <p>Асбьёрн Ульсберг описывает гипермедиа так: "Если вы посмотрите на гипермедиа как на рецепт того, как должен выглядеть следующий запрос, вы поймете, что такое гипермедиа".</p>
52 <h2>Пример конечного автомата: IoT-тостер</h2>
53 <h2>Пример конечного автомата: IoT-тостер</h2>
53 <p>Разберем концепцию гипермедиа как механизма состояния приложения на примере простого конечного автомата - тостера, подключенного к интернету вещей (IoT), которым можно управлять через интернет.</p>
54 <p>Разберем концепцию гипермедиа как механизма состояния приложения на примере простого конечного автомата - тостера, подключенного к интернету вещей (IoT), которым можно управлять через интернет.</p>
54 <p>Конечный автомат - это абстрактная модель, которая содержит конечное количество состояний чего-либо. В нашем случае тостер запускается после включения - переходит в состояние нагрева. Затем он достигает верхнего предела температуры и переходит в состояние ожидания, снижая температуру. Этот цикл продолжается до тех пор, пока кусок хлеба не поджарится достаточно хорошо - после этого тостер отключается.</p>
55 <p>Конечный автомат - это абстрактная модель, которая содержит конечное количество состояний чего-либо. В нашем случае тостер запускается после включения - переходит в состояние нагрева. Затем он достигает верхнего предела температуры и переходит в состояние ожидания, снижая температуру. Этот цикл продолжается до тех пор, пока кусок хлеба не поджарится достаточно хорошо - после этого тостер отключается.</p>
55 <p>Как управлять тостером с помощью REST и гипермедиа? Филдинг писал, что каждая страница в сети представляет собой отдельное состояние одного ресурса, которое можно получить с помощью вызова GET (этот процесс показан в таблице выше). То есть вы можете получить какие-либо данные с помощью идентификатора в URI.</p>
56 <p>Как управлять тостером с помощью REST и гипермедиа? Филдинг писал, что каждая страница в сети представляет собой отдельное состояние одного ресурса, которое можно получить с помощью вызова GET (этот процесс показан в таблице выше). То есть вы можете получить какие-либо данные с помощью идентификатора в URI.</p>
56 <p><em>Попробуем сделать это: для начала вызовем наш тостер с помощью GET:</em></p>
57 <p><em>Попробуем сделать это: для начала вызовем наш тостер с помощью GET:</em></p>
57 <p>Ответ будет выглядеть примерно так:</p>
58 <p>Ответ будет выглядеть примерно так:</p>
58 <p>В ответе содержится идентификатор, который показывает, с каким ресурсом мы работаем. Следом отображается текущее состояние ресурса, а ниже - список возможных операций, которые с ним можно совершить.</p>
59 <p>В ответе содержится идентификатор, который показывает, с каким ресурсом мы работаем. Следом отображается текущее состояние ресурса, а ниже - список возможных операций, которые с ним можно совершить.</p>
59 <p>Теперь попробуем изменить состояние тостера. Для этого отправим HTTP-запрос PUT:</p>
60 <p>Теперь попробуем изменить состояние тостера. Для этого отправим HTTP-запрос PUT:</p>
60 <p>Ответ будет выглядеть примерно так:</p>
61 <p>Ответ будет выглядеть примерно так:</p>
61 <p>Хорошо, теперь мы включили тостер. Однако в ответе видно, что его мощность по-прежнему на нуле - он все еще не нагревается. Попробуем вызвать изменение мощности:</p>
62 <p>Хорошо, теперь мы включили тостер. Однако в ответе видно, что его мощность по-прежнему на нуле - он все еще не нагревается. Попробуем вызвать изменение мощности:</p>
62 <p>Мы увеличили мощность - теперь в ответе видно, что тостер нагревается.</p>
63 <p>Мы увеличили мощность - теперь в ответе видно, что тостер нагревается.</p>
63 <p>Теперь мы можем перевести тостер в режим ожидания и снова увеличить мощность. Однако вместо этого отправим еще один вызов GET на идентификатор устройства:</p>
64 <p>Теперь мы можем перевести тостер в режим ожидания и снова увеличить мощность. Однако вместо этого отправим еще один вызов GET на идентификатор устройства:</p>
64 <p>С момента нашего последнего запроса тостер перешел в состояние ожидания. В ответе видно, что мы все еще можем отключить его или отрегулировать температуру, усилив мощность нагрева.</p>
65 <p>С момента нашего последнего запроса тостер перешел в состояние ожидания. В ответе видно, что мы все еще можем отключить его или отрегулировать температуру, усилив мощность нагрева.</p>
65 <p>Если подождать еще несколько минут, следующий запрос к конечному автомату, скорее всего, приведет его к состоянию "выключение" или "выключено" - то есть в то состояние, с которого мы начинали.</p>
66 <p>Если подождать еще несколько минут, следующий запрос к конечному автомату, скорее всего, приведет его к состоянию "выключение" или "выключено" - то есть в то состояние, с которого мы начинали.</p>
66 <h2>Заключение</h2>
67 <h2>Заключение</h2>
67 <p>Сеть функционирует как набор идей, связанных друг с другом гипертекстом. Ульсберг считает, что веб-API должны имитировать этот принцип, а важным аспектом в реализации API является гипермедиа. Для тех, кто только начинает работать с REST, создание HATEOAS-совместимого API - это огромный шаг вперед по сравнению с API-интерфейсами в стиле RPC.</p>
68 <p>Сеть функционирует как набор идей, связанных друг с другом гипертекстом. Ульсберг считает, что веб-API должны имитировать этот принцип, а важным аспектом в реализации API является гипермедиа. Для тех, кто только начинает работать с REST, создание HATEOAS-совместимого API - это огромный шаг вперед по сравнению с API-интерфейсами в стиле RPC.</p>
68 <p>"Если вы используете гипермедиа, вы можете добавлять отношения, ссылки и операции к ресурсам, не нарушая работу существующих клиентов, и наделяя новых клиентов новыми функциями", - писал Ульсберг.</p>
69 <p>"Если вы используете гипермедиа, вы можете добавлять отношения, ссылки и операции к ресурсам, не нарушая работу существующих клиентов, и наделяя новых клиентов новыми функциями", - писал Ульсберг.</p>
69 <p>Такой подход подразумевает переосмысление традиционного подхода к управлению версиями. Мнения Ульсберга и Филдинга в этом вопросе сходятся: управление версиями в REST - плохая идея. Когда вы в последний раз видели номер версии на веб-сайте? HTML не требует контроля версий, и JSON тоже в нем не нуждается.</p>
70 <p>Такой подход подразумевает переосмысление традиционного подхода к управлению версиями. Мнения Ульсберга и Филдинга в этом вопросе сходятся: управление версиями в REST - плохая идея. Когда вы в последний раз видели номер версии на веб-сайте? HTML не требует контроля версий, и JSON тоже в нем не нуждается.</p>
70 <p>Уделяя больше внимания ресурсам как конечному автомату, мы можем сообщать потребителям текущее состояние, с помощью которого мы совершаем операции. Такой подход снижает степень связанности и в бизнес-доменах, где состояние приложения состоит из множества сложных и взаимозависимых факторов, и значительно упрощает работу клиента. Именно в этом сила REST и гипермедиа.</p>
71 <p>Уделяя больше внимания ресурсам как конечному автомату, мы можем сообщать потребителям текущее состояние, с помощью которого мы совершаем операции. Такой подход снижает степень связанности и в бизнес-доменах, где состояние приложения состоит из множества сложных и взаимозависимых факторов, и значительно упрощает работу клиента. Именно в этом сила REST и гипермедиа.</p>