Design » History » Revision 24
Revision 23 (Никита Давыдовский, 05/03/2012 04:31 PM) → Revision 24/25 (Никита Давыдовский, 05/03/2012 04:33 PM)
h1. Проект архитектуры
{{TOC}}
Модель архитектуры представлена на следующей схеме:
!https://redmine.cs.karelia.ru/attachments/download/83/850px-MS_Arch_mods.png!
h2. Описание уровней архитектуры
*Сетевой уровень (Network layer)* объединяет используемые социальные сервисы и среду передачи данных. В архитектуре представлены сервисы ВКонтакте, Facebook и Flickr. Каждый сервис предоставляет доступ к данным посредством собственного протокола. В настоящий момент в проекте MySocials реализована поддержка протоколов на основе XML и JSON.
*Транспортный уровень (Transport layer)* представляет собой набор библиотек доступа к социальным сервисам (драйверов). Основная задача драйвера - выполнять запросы к сервису для получения или отправки данных. Один запрос к драйверу может быть реализован в виде серии запросов к сервису.
*Промежуточный уровень (Middleware layer)* обеспечивает единый программный интерфейс (MySocials API) доступа к социальным сервисам. API реализован на основе XML. Для более удобной реализации приложений с использованием социальных сервисов реализована Qt библиотека (Core). Библиотека предоставляет набор базовых классов, средства кэширования для автономной работы и объединяет составные запросы.
*Пользовательский уровень (User layer*) объединяет разработанные приложения и плагины.
* Плагины для Qt Messaging Framework (QMF plugins) предоставляют доступ к социальным сервисам аналогично доступу к почтовым сервисам.
* Плагины приложений (Application plugins) реализуют работу с социальными сервисами в различных приложениях. В настоящий момент реализован плагин для Telepathy framework и плагин импорта контактов в адресную книгу Maemo.
* Консольное тестовое приложение (Console application) позволяет проверить работоспособность драйверов и выполнять запросы на основе MySocials API.
* Приложение для просмотра изображений социальных сервисов (Gallery)
* Приложение для работы с социальными сервисами (MySocials)
h2. Описание подсистем
*Ядро (Core)* – Подпрограмма, отвечающая за перенаправление запросов от других модулей к драйверам и наоборот, контроль использования оперативной памяти программой, выполнение повторяющихся задач(проверка сообщений, проверка друзей и т.д.)
Включает в себя:
* Менеджер Событий - модуль, выполняющий через определенный промежуток времени повторяющиеся задача (проверка на новые сообщения и т.д.)
* Модуль перенаправления запросов - модуль, который перенаправляет запросы, полученные от подпрограмм к драйверам
*Драйвер (Driver)* - подпрограмма реализующая взаимодействие с определенным сервисом или их группой
Включает в себя:
* Модуль получения запросов от ядра
* Отправка запросов и получение ответов от сервиса
* Обработка ответа от сервиса
* Модуль отправки ответа ядру
*Интерфейс пользователя (UI)* - Подпрограмма содержащая графический интерфейс пользователя. Содержит функции по выводу информации пользователю, вызывает функции из виджетов. Включает в себя:
Включает в себя:
* Формы с компонентами из виджетов
*Виджеты (Widgets)* - Набор компнентов, содержащих логику работу интерфейса. Виджеты располагаются на уровне конечного приложения. Включают в себя:
* модули(менеджеры) для соединения графического интерфейса и ядра
* модели данных полученные от ядра и методы доступа к ним
* функции обработки событий, поступающих от графического интерфейса
h1. Ядро
!https://redmine.cs.karelia.ru/attachments/download/84/850px-MSCore_Arch.png!
Архитектура ядра
*Структуры данных*
В проекте MySocials для хранения данных используются специальные классы-хранилища. Каждому объекту социальной сети соответствует свой класс. Все классы должны наследоваться от базового класса (Base object), содержащего общие для всех объектов поля и методы.
Поля класса @baseobject@:
<pre>
QString serviceId; // Id сервиса.
QString accountId; // Id аккаунта.
QString ownerId; // Id владельца объекта.
QString objectId; // Id объекта.
QString icon_url; // Путь до иконки объекта.
bool isPrivate; // True если объект имеет ограниченный доступ и не может быть загружен с сервиса.
bool isEmpty; // True если в объекте ничего нет, иначе - false.
</pre>
Методы класса @baseobject@:
<pre>
/* Генерирует имя файла на основе пути и ссылки на объект. */
const QString generateFileName(const QString &path, const QString &obj) const;
</pre>
Поля класса @event@:
<pre>
QString title; // Название события.
QString description; // Описание события.
QString startTime; // Время начала события.
QString endTime; // Время завершения события.
QString updateTime; // Время последнего обновления информации о событии.
QString location; // Географическое место расположения.
QString privacy; // Приватность.
QString creator; // Идентификатор пользователя создавшего событие.
QString icon; // URL иконки события.
QString rsvpStatus; // Статус участия.
</pre>
Методы класса @event@:
<pre>
/* "Упаковать" данные в XML формат. */
QDomElement toQDomElement(QDomDocument& doc) const;
</pre>
<pre>
/* Переопределение предыдущего метода. Во входных параметрах добавлен источник данных. */
static QDomElement toQDomElement(QDomDocument& doc, const Event& src);
</pre>
<pre>
/* Загрузить данные из XML. */
static Event fromQDomElement(const QDomElement& fr, const QString& srvcId, const QString& accountId,
const QString& friendId);
</pre>
h1. Функции
h2. Получение списка событий
*Описание:* Функция, на основе полученных параметров, формирует и отправляет запрос к драйверу и затем получает ответ. После из ответа извлекаются данные и помещаются во внутреннюю структуру данных. После заполнения структура добавляется к списку. По окончании разбора посылается сигнал о том, что события получены.
*Параметры:*
@userId@ - id пользователя чей список нужно получить.
@startTime@ - дата, начиная с которой нужно получить события (строка даты в формате UNIX_timestamp или ISO_8601).
@alsoLoadIcons@ - также загрузить иконки.
*Прототип:*
<pre>
void getEvents(QString userId, QString startTime, bool alsoLoadIcons)
</pre>
h2. Создание события
*Описание:* Функция, на основе полученных параметров, формирует и отправляет запрос к драйверу и затем получает ответ. После из ответа извлекается eventId (id созданного события) и функция посылает сигнал с eventId и статусом транзакции.
*Параметры:*
@title@ - название события.
@description@ - описание события.
@startTime@ - время начала (строка даты в формате UNIX_timestamp или ISO_8601).
@endTime@ - время завершения (строка даты в формате UNIX_timestamp или ISO_8601).
@location@ - место проведения.
@privacy@ - приватность.
*Прототип:*
<pre>
QString createEvent(QString title, QString description, QString startTime, QString endTime, QString location,
QString privacy)
</pre>
h2. Редактирование события
*Описание:* Функция, на основе полученных параметров, формирует и отправляет запрос к драйверу и затем получает ответ. Ответ должен содержать информацию об успехе редактирования (true/false) и эта информация возвращается из функции.
*Параметры:*
@eventId@ - id события которое требуется редактировать.
@title@ - название события.
@description@ - описание события.
@startTime@ - время начала (строка даты в формате UNIX_timestamp или ISO_8601).
@endTime@ - время завершения (строка даты в формате UNIX_timestamp или ISO_8601).
@location@ - место проведения.
@privacy@ - приватность.
*Прототип:*
<pre>
bool editEvent(QString eventId, QString title, QString description, QString startTime, QString endTime,
QString location, QString privacy)
</pre>
h2. Удаление события
*Описание:* Функция, на основе полученных параметров, формирует и отправляет запрос к драйверу и затем получает ответ. Ответ должен содержать информацию об успехе удаления (true/false) и эта информация возвращается из функции. Также функция удаляет информацию о событии из кэша.
*Параметры:*
@eventId@ - id события которое требуется удалить.
*Прототип:*
<pre>
bool deleteEvent(QString eventId)
</pre>
h2. Поиск событий
*Описание:* Функция, на основе поисковой строки, даты и смещения, формирует и отправляет запрос к драйверу и затем получает ответ. После из ответа извлекаются данные и помещаются во внутреннюю структуру данных. После заполнения структура добавляется к списку. По окончании разбора посылается сигнал о том, что события найдены получены.
*Параметры:*
@text@ - поисковый запрос.
@onlyUpcoming@ - флаг, поиск только по грядущим событиям.
@offset@ - смещение (используется для подгрузки событий).
*Прототип:*
<pre>
void searchEvents(QString text, bool onlyUpcoming, int offset);
</pre>
h2. Установка/изменение статуса участия
*Описание:* Функция устанавливает/меняет статус участия пользователя на параметр status, по отношению к событию eventId.
По завершению транзакции отправляет сигнал об успехе/ошибке.
*Параметры:*
@eventId@ - id события по отшению к которому нужно изменить статус.
@status@ - новый статус участия (attending/maybe(unsure)/declined).
*Прототип:*
<pre>
void setRsvpStatus(QString eventId, QString status);
</pre>
h2. Получение списка отметок
*Описание:* Функция получает список отметок места (заданного в параметрах одним из способов).
*Параметры:*
@latitude@ - географическая широта места для которого нужно получить список отметок.
@longitude@ - географическая долгота места для которого нужно получить список отметок.
@placeId@ - идентификатор места (игнорируется если поля широты и долготы не пустые).
@ownerId@ - идентификатор пользователя для котрого нужно получить список (игнорируется если поля широты, долготы и placeId не пустые).
*Прототип:*
<pre>
void getCheckins(QString latitude, QString longitude, QString placeId, QString ownerId, const int type);
</pre>
h2. Поиск места по названию
*Описание:* Функция поиска места по названию в указанной географической локации.
*Параметры:*
@text@ - поисковая строка.
@latitude@ - географическая широта места.
@longitude@ - географическая долгота места.
@radius@ - радиус поиска.
*Прототип:*
<pre>
void searchPlaces(QString text, QString latitude, QString longitude, QString radius);
</pre>
h2. Создание нового места
*Описание:* Функция создания нового места в указанной географической локации. Возвращает идентификатор созданного места.
*Параметры:*
@title@ - название места.
@latitude@ - географическая широта места.
@longitude@ - географическая долгота места.
@type@ - тип места.
@address@ - адрес места.
*Прототип:*
<pre>
QString createPlace(QString title, QString latitude, QString longitude, QString type, QString address);
</pre>
h2. Отметка
*Описание:* Отметиться в заданном месте. Возвращает статус транзакции.
*Параметры:*
@placeId@ - место в котором нужно отметиться.
@title@ - подпись к отметке.
*Прототип:*
<pre>
bool checkIn(QString placeId, QString title);
</pre>
h2. Драйвер
!https://redmine.cs.karelia.ru/attachments/download/85/850px-MSDriver_Arch.png!
Архитектура драйвера
h2. Общий формат запросов и ответов
*Формат запроса:*
<pre>
<Request class="" function = "" noAuthorize="true">
<Params>
</Params>
</Request>
</pre>
_noAuthorize_ - флаг, запрещающий библиотеке вызывать webauth (необязательный параметр, по умолчанию false)
_class_ - класс, к которому относится вызываемая функция
_function_ - имя функции
_Params_ - набор параметров, строго определенный для каждой функции
*Формат ответа:*
<pre>
<Response class="..." function = "..." authorized="true" upload="..." download="...">
<Params>
</Params>
</Response>
</pre>
_authorized_ - флаг, показывающий происходила ли авторизация при выполнении запроса, не устанавливается, если при выполнении запроса возникла ошибка
_upload_ - количество байт отправленных на сервер
_download_ - количество байт полученных с сервера
* "settings":http://oss.fruct.org/wiki/Libvkontakte/xml-data/settings: класс для работы с настройками
* "places":http://oss.fruct.org/wiki/Libvkontakte/xml-data/places: класс для получения данных о местах
* "events":http://oss.fruct.org/wiki/Libvkontakte/xml-data/events: класс для получения данных о событиях
h2. Трассируемость требований
h3. Общие требования
|_.Функциональные требования|
||Приложение Places|Приложение Events|
|*SR.FUSRA.01*(Создание аккаунта)||"Форма _UIEH_8_":https://redmine.cs.karelia.ru/projects/geo-places/wiki/Events-ui-harmattan#%D0%9C%D0%B5%D0%BD%D1%8E-%D0%B4%D0%BE%D0%B1%D0%B0%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F-%D0%B0%D0%BA%D0%BA%D0%B0%D1%83%D0%BD%D1%82%D0%B0-UIEH_8|
|*SR.FUSRA.02*(Настройки сети)||"Форма _UIEH_9_":https://redmine.cs.karelia.ru/projects/geo-places/wiki/Events-ui-harmattan#%D0%A0%D0%B0%D0%B1%D0%BE%D1%82%D0%B0-%D1%81-%D1%81%D0%B5%D1%82%D1%8C%D1%8E-UIEH_9|
|*SR.FUSRA.03*(Выбор аккаунта)|"Форма _UIEH_6_":https://redmine.cs.karelia.ru/projects/geo-places/wiki/Geo-ui-harmattan#%D0%A3%D0%BF%D1%80%D0%B0%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5-%D0%B0%D0%BA%D0%BA%D0%B0%D1%83%D0%BD%D1%82%D0%B0%D0%BC%D0%B8-UIPH_6|"Форма _UIEH_7_":https://redmine.cs.karelia.ru/projects/geo-places/wiki/Events-ui-harmattan#%D0%9C%D0%B5%D0%BD%D1%8E-%D0%B0%D0%BA%D0%BA%D0%B0%D1%83%D0%BD%D1%82%D0%BE%D0%B2-UIEH_7|
h3. Приложение Events
|_.Функциональные требования|\6=.*Интерфейс*|\6=.*Ядро*|
||"_UI_1_":https://redmine.cs.karelia.ru/projects/geo-places/wiki/Events-ui-harmattan#%D0%93%D0%BB%D0%B0%D0%B2%D0%BD%D0%B0%D1%8F-%D1%81%D1%82%D1%80%D0%B0%D0%BD%D0%B8%D1%86%D0%B0-%D0%BA%D0%B0%D0%BB%D0%B5%D0%BD%D0%B4%D0%B0%D1%80%D1%8C-UIEH_1|"_UI_2_":https://redmine.cs.karelia.ru/projects/geo-places/wiki/Events-ui-harmattan#%D0%A1%D0%BE%D0%B7%D0%B4%D0%B0%D0%BD%D0%B8%D0%B5-%D1%81%D0%BE%D0%B1%D1%8B%D1%82%D0%B8%D1%8F-UIEH_2|"_UI_3_":https://redmine.cs.karelia.ru/projects/geo-places/wiki/Events-ui-harmattan#%D0%9F%D0%BE%D0%B8%D1%81%D0%BA-%D1%81%D0%BE%D0%B1%D1%8B%D1%82%D0%B8%D0%B9-UIEH_3|"_UI_5_":https://redmine.cs.karelia.ru/projects/geo-places/wiki/Events-ui-harmattan#%D0%A0%D0%B5%D0%B4%D0%B0%D0%BA%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5-%D1%81%D0%BE%D0%B1%D1%8B%D1%82%D0%B8%D1%8F-%D0%9C%D0%B0%D0%BA%D0%B5%D1%82-UIEH_5|"_UI_6_":https://redmine.cs.karelia.ru/projects/geo-places/wiki/Events-ui-harmattan#%D0%A3%D0%B4%D0%B0%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5-%D1%81%D0%BE%D0%B1%D1%8B%D1%82%D0%B8%D1%8F-%D0%9C%D0%B0%D0%BA%D0%B5%D1%82-UIEH_6|"_UI_4_":https://redmine.cs.karelia.ru/projects/geo-places/wiki/Events-ui-harmattan#%D0%98%D0%BD%D1%84%D0%BE%D1%80%D0%BC%D0%B0%D1%86%D0%B8%D1%8F-%D0%BE-%D1%81%D0%BE%D0%B1%D1%8B%D1%82%D0%B8%D0%B8-UIEH_4|"getEvents":https://redmine.cs.karelia.ru/projects/geo-places/wiki/Design#%D0%9F%D0%BE%D0%BB%D1%83%D1%87%D0%B5%D0%BD%D0%B8%D0%B5-%D1%81%D0%BF%D0%B8%D1%81%D0%BA%D0%B0-%D1%81%D0%BE%D0%B1%D1%8B%D1%82%D0%B8%D0%B9|"createEvent":https://redmine.cs.karelia.ru/projects/geo-places/wiki/Design#%D0%A1%D0%BE%D0%B7%D0%B4%D0%B0%D0%BD%D0%B8%D0%B5-%D1%81%D0%BE%D0%B1%D1%8B%D1%82%D0%B8%D1%8F|"editEvent":https://redmine.cs.karelia.ru/projects/geo-places/wiki/Design#%D0%A0%D0%B5%D0%B4%D0%B0%D0%BA%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5-%D1%81%D0%BE%D0%B1%D1%8B%D1%82%D0%B8%D1%8F|"deleteEvent":https://redmine.cs.karelia.ru/projects/geo-places/wiki/Design#%D0%A3%D0%B4%D0%B0%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5-%D1%81%D0%BE%D0%B1%D1%8B%D1%82%D0%B8%D1%8F|"searchEvent":https://redmine.cs.karelia.ru/projects/geo-places/wiki/Design#%D0%9F%D0%BE%D0%B8%D1%81%D0%BA-%D1%81%D0%BE%D0%B1%D1%8B%D1%82%D0%B8%D0%B9|"setRsvpStatus":https://redmine.cs.karelia.ru/projects/geo-places/wiki/Design#%D0%A3%D1%81%D1%82%D0%B0%D0%BD%D0%BE%D0%B2%D0%BA%D0%B0%D0%B8%D0%B7%D0%BC%D0%B5%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5-%D1%81%D1%82%D0%B0%D1%82%D1%83%D1%81%D0%B0-%D1%83%D1%87%D0%B0%D1%81%D1%82%D0%B8%D1%8F| ||"_UIEH_1_":https://redmine.cs.karelia.ru/projects/geo-places/wiki/Events-ui-harmattan#%D0%93%D0%BB%D0%B0%D0%B2%D0%BD%D0%B0%D1%8F-%D1%81%D1%82%D1%80%D0%B0%D0%BD%D0%B8%D1%86%D0%B0-%D0%BA%D0%B0%D0%BB%D0%B5%D0%BD%D0%B4%D0%B0%D1%80%D1%8C-UIEH_1|"_UIEH_2_":https://redmine.cs.karelia.ru/projects/geo-places/wiki/Events-ui-harmattan#%D0%A1%D0%BE%D0%B7%D0%B4%D0%B0%D0%BD%D0%B8%D0%B5-%D1%81%D0%BE%D0%B1%D1%8B%D1%82%D0%B8%D1%8F-UIEH_2|"_UIEH_3_":https://redmine.cs.karelia.ru/projects/geo-places/wiki/Events-ui-harmattan#%D0%9F%D0%BE%D0%B8%D1%81%D0%BA-%D1%81%D0%BE%D0%B1%D1%8B%D1%82%D0%B8%D0%B9-UIEH_3|"_UIEH_5_":https://redmine.cs.karelia.ru/projects/geo-places/wiki/Events-ui-harmattan#%D0%A0%D0%B5%D0%B4%D0%B0%D0%BA%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5-%D1%81%D0%BE%D0%B1%D1%8B%D1%82%D0%B8%D1%8F-%D0%9C%D0%B0%D0%BA%D0%B5%D1%82-UIEH_5|"_UIEH_6_":https://redmine.cs.karelia.ru/projects/geo-places/wiki/Events-ui-harmattan#%D0%A3%D0%B4%D0%B0%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5-%D1%81%D0%BE%D0%B1%D1%8B%D1%82%D0%B8%D1%8F-%D0%9C%D0%B0%D0%BA%D0%B5%D1%82-UIEH_6|"_UIEH_4_":https://redmine.cs.karelia.ru/projects/geo-places/wiki/Events-ui-harmattan#%D0%98%D0%BD%D1%84%D0%BE%D1%80%D0%BC%D0%B0%D1%86%D0%B8%D1%8F-%D0%BE-%D1%81%D0%BE%D0%B1%D1%8B%D1%82%D0%B8%D0%B8-UIEH_4|"getEvents":https://redmine.cs.karelia.ru/projects/geo-places/wiki/Design#%D0%9F%D0%BE%D0%BB%D1%83%D1%87%D0%B5%D0%BD%D0%B8%D0%B5-%D1%81%D0%BF%D0%B8%D1%81%D0%BA%D0%B0-%D1%81%D0%BE%D0%B1%D1%8B%D1%82%D0%B8%D0%B9|"createEvent":https://redmine.cs.karelia.ru/projects/geo-places/wiki/Design#%D0%A1%D0%BE%D0%B7%D0%B4%D0%B0%D0%BD%D0%B8%D0%B5-%D1%81%D0%BE%D0%B1%D1%8B%D1%82%D0%B8%D1%8F|"editEvent":https://redmine.cs.karelia.ru/projects/geo-places/wiki/Design#%D0%A0%D0%B5%D0%B4%D0%B0%D0%BA%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5-%D1%81%D0%BE%D0%B1%D1%8B%D1%82%D0%B8%D1%8F|"deleteEvent":https://redmine.cs.karelia.ru/projects/geo-places/wiki/Design#%D0%A3%D0%B4%D0%B0%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5-%D1%81%D0%BE%D0%B1%D1%8B%D1%82%D0%B8%D1%8F|"searchEvent":https://redmine.cs.karelia.ru/projects/geo-places/wiki/Design#%D0%9F%D0%BE%D0%B8%D1%81%D0%BA-%D1%81%D0%BE%D0%B1%D1%8B%D1%82%D0%B8%D0%B9|"setRsvpStatus":https://redmine.cs.karelia.ru/projects/geo-places/wiki/Design#%D0%A3%D1%81%D1%82%D0%B0%D0%BD%D0%BE%D0%B2%D0%BA%D0%B0%D0%B8%D0%B7%D0%BC%D0%B5%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5-%D1%81%D1%82%D0%B0%D1%82%D1%83%D1%81%D0%B0-%D1%83%D1%87%D0%B0%D1%81%D1%82%D0%B8%D1%8F|
|*SR.FUSRE.01* (Получение списка событий)|=.+||||||=.+|||||| событий)|=.+||||||+||||||
|*SR.FUSRE.02* (Создание события)||=.+||||||=.+||||| события)||=.+||||||+|||||
|*SR.FUSRE.05* (Поиск событий)|||=.+||||||||=.+|| событий)|||=.+||||||||+||
|*SR.FUSRE.03* (Редактирование события)||||=.(2)+||=.(1)+|||=.+|||| события)||||=.(2)+||=.(1)+|||+||||
|*SR.FUSRE.04* (Удаление события)|||||=.(2)+|=.(1)+||||=.+||| события)|||||=.(2)+|=.(1)+||||+|||
|*SR.FUSRE.05* (Изменение статуса)||||||=.+||||||=.+| статуса)||||||=.+||||||+|
_Примечание: (№) означает последовательность появления форм на экране._
h3. Приложение Places
|_.Функциональные требования|
||=.-|"Форма _UIPH_1_":https://redmine.cs.karelia.ru/projects/geo-places/wiki/Geo-ui-harmattan#%D0%9E%D1%82%D0%BC%D0%B5%D1%82%D0%BA%D0%B8-%D0%BD%D0%B0%D0%B9%D0%B4%D0%B5%D0%BD%D0%BD%D1%8B%D0%B5-%D0%BF%D0%BE%D0%B1%D0%BB%D0%B8%D0%B7%D0%BE%D1%81%D1%82%D0%B8-UIPH_1|=.-|=.-|
|*SR.FUSRP.01*(Поиск места по названию)|||||
|*SR.FUSRP.02*(Получение списка отметок)||=.+|||
|*SR.FUSRP.03*(Создание нового места)|||||
|*SR.FUSRP.04*(Отметка)|||||