Система управления контентом CAIRO

Как начать работать

Виктор Грищенко


Содержание

1. Подготовка
2. Создание информационной структуры
2.1. Создание типа сущности "Новость"
2.2. Создание типа сущности "Лента новостей"
2.3. Создание корневой сущности
3. Создание общедоступного веб-интерфейса
3.1. Настройка
3.2. Создание страницы списка новостей
3.3. Создание страницы новости

Список иллюстраций

1. Форма создания типа сущности
2. Форма создания точки вложения

Список таблиц

1. Виртуальные хосты, используемые в примере
2. Параметры сущности "Новость"

Аннотация

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

Для создания информационного ресурса необходимо иметь возможность создавать виртуальные хосты и базы данных, а также иметь возможность работать с файлами на сервере. Одна установленная версия системы может поддерживать несколько ресурсов различного масштаба и сложности. Далее подробно рассматривается пример создания ленты новостей. Этот пример позволит продемонстрировать основные возможности системы и подходы, используемые при создании веб-ресурсов на базе Cairo.

Важно

В случае, если используется демонстрационная версия Cairo или версия для разработчика, то адреса всех веб-ресурсов, разрабатываемых на базе платформы Cairo, должны иметь суффикс доменного имени ".cairo" (например, "www.sample.cairo"). Если же используется базовая версия Cairo, то может возникнуть необходимость получить лицензию на дополнительный ресурс. Подробнее об этом написано в документе "Система управления контентом CAIRO: Активация системы и получение лицензий на дополнительные ресурсы данных".

1. Подготовка

В тестовом примере будут использоваться два виртуальных хоста. Один для системы администрирования, другой - для общедоступного веб-интерфейса. Параметры виртуальных хостов описаны в таблице.

Таблица 1. Виртуальные хосты, используемые в примере

Адрес хостаКаталог Document RootОписание
www.sample.cairo/var/www/www.sample.cairoСайт, на котором будет выведена создаваемая лента новостей.
admin.sample.cairo/var/www/admin.sample.cairoСистема администрирования.

Настройки, указанные в таблице, приведены в качестве примера. В настройках сервера необходимо указать путь, по которому установлена Cairo на конкретном сервере.

На данном этапе подразумевается, что в системе установлен интерфейс администратора Cairo. Необходимо добавить в него новый ресурс. Для этого создадим новую базу данных sample и импортируем в нее файл /dump/cairo-dummy.sql, который входит в дистрибутив системы. Добавим в файл /etc/login.ini раздел с описанием параметров ресурса:

[Sample]
dbhost = localhost
dbuser = cairo
dbpasswd = some_password
dbname = sample
dbcharset =
dbversion = <Версия сервера БД>
authhost = admin.sample.cairo
basedir = /var/www/admin.sample.cairo
uploaddir = /var/www/www.sample.cairo/var/uploaded
cachedir =  /var/www/www.sample.cairo/var/cache
frmtext_files = /var/frmtext-files
httphost = www.sample.cairo
locale = ru_RU.CP1251
auth_user =
auth_group =

Важно

В файле /etc/login.ini приведенные параметры ресурса следует заменить на те, которые соответствуют реальному серверу.

2. Создание информационной структуры

В данном руководстве будет создан простейший информационный ресурс - "Лента новостей", поэтому его структура будет содержать всего два типа сущностей: "Новость" и "Лента новостей". Тип сущности "Лента новостей" имеет одно поле - "Название". Тип сущности "Новость" включает следующие поля:

  • Дата добавления;

  • Заголовок;

  • Изображение;

  • Аннотация;

  • Полный текст.

2.1. Создание типа сущности "Новость"

Для получения доступа к интерфейсу администратора Cairo необходимо авторизироваться. Откройте в браузере URL http://admin.sample.cairo/. В появившейся форме авторизации следует ввести следующие данные:

Имя пользователя: root

Пароль: admin

В выпадающем списке "Ресурс" выбирается название ресурса. После авторизации откроется стартовая страница веб-интерфейса.

Разработка любого нового ресурса начинается с пункта меню "Управление структурой данных". Нажав на него, можно получить доступ к модулю управления типами сущностей. Здесь можно создавать новые типы, редактировать старые и организовывать связи между ними.

Перейдите в раздел "Управление структурой данных" и нажмите на кнопку "Добавить тип". Появившаяся форма позволяет определить основные параметры нового типа. Заполните поля формы в соответствии с рисунком ниже.

Рисунок 1. Форма создания типа сущности

Форма создания типа сущности

После создания типа сущности выводится страница этого типа. Теперь определим набор полей новости. Нажав на кнопку "Добавить поле", переходим на форму добавления поля.

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

Таблица 2. Параметры сущности "Новость"

Псевдоним поляДатаЗаголовокИзображениеАннотацияПолный текст
Имя поляnews_datetitleimagetopicnews_text
Тип поляdatestringimagetextfrmtext
Формат поля    ZvenoSimple
Значение по умолчаниюtime()    
Важность поляобязательноеобязательноенеобязательноеобязательноенеобязательное
Может выводится в спискеДаДаДаДаНет
В списке по умолчаниюДаДаДаНетНет
Тип сортировкиПо убыванию    
Входит в заголовокНетДаНетНетНет

Подробнее о параметрах полей можно узнать в документах: "Система управления контентом CAIRO: Руководство разработчика" и "Система управления контентом CAIRO: Справочное руководство по API".

2.2. Создание типа сущности "Лента новостей"

Определив все поля сущности "Новость", перейдем к созданию ленты новостей. Для этого снова воспользуйтесь ссылкой "Управление структурой данных" и нажмите на кнопку "Добавить тип".

Тип "Лента новостей" создадим с именем таблицы "class_news_line". Обязательно отметьте флаг "Появляется в главном меню". Этот флаг указывает, что ссылки на страницы сущностей типа "Лента новостей" будут доступны в главном меню раздела "Управление данными".

Теперь создадим для типа сущностей "Лента новостей" обязательное строковое (string) поле "Название" с именем в таблице "title". Не забудьте установить флаг вхождения данного поля в заголовок сущности.

В результате система содержит два типа сущностей, которые пока не связаны друг с другом. Для завершения процесса создания структуры данных демонстрационного ресурса осталось установить связь между ними, а именно указать, что лента новостей может содержать новости. Для этого заходим на страницу типа "Лента новостей" и нажимаем на кнопку "Добавить тип" в блоке "Допустимые для вложения типы". Заполните поля формы в соответствии с рисунком ниже.

Рисунок 2. Форма создания точки вложения

Форма создания точки вложения

Теперь сущности типа "Новость" могут вкладываться в сущности типа "Лента новостей". Другими словами, в тип сущности "Лента новостей" была добавлена точка вложения "Новости" .

2.3. Создание корневой сущности

На данном этапе уже определены типы сущностей ресурса и связи между ними. Теперь создадим первый экземпляр типа "Лента новостей".

Для создания ленты новостей необходимо перейти на страницу типа сущности "Лента новостей" и нажать на кнопку "Добавить корневую сущность". В появившейся форме введите название ленты новостей, например "Новости мира CMS", и сохраните данные. Так как при создании типа "Лента новостей" было указано, что сущности этого типа могут появляться в главном меню, то ленты новостей, являющиеся корневыми сущностями, будут доступны через пункт меню "Управление данными".

Подсказка

Если необходимо создать дополнительные ленты новостей, то это можно сделать, воспользовавшись кнопкой "Добавить корневую сущность" на странице типа "Лента новостей". Все ленты новостей появятся в меню "Управление данными".

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

3. Создание общедоступного веб-интерфейса

В предыдущем разделе была создана информационная структура веб-ресурса. Ниже будет описан процесс создания сайта, предназначенного для вывода данных, добавленных через интерфейс администратора Cairo. Для этого нам понадобится архив cairo-project-x.x.x.tar.bz2, который входит в дистрибутив системы.

Создадим ресурс, состоящий из двух скриптов. Первый будет выводить список новостей, а второй - страницу новости. Для получения информации о новостях будем использовать классы, предоставляемые платформой Cairo.

3.1. Настройка

Настройка параметров веб-ресурса аналогична настройке интерфейса администратора Cairo (см. документ "Система управления контентом CAIRO: Установка и настройка"). В настройках каталогов необходимо прописать те же параметры, что и для универсального интерфейса администратора, за исключением параметров general.basedir, general.tmpdir, general.skindir, general.etcdir, general.cachedir и general.uploaddir, которым присваиваются адреса соответствующих каталогов. Кроме того, в дополнительном разделе database определяются параметры базы данных. В результате файл /etc/core.ini должен выглядеть следующим образом:

;#############################################################################
;## Общие настройки системы
;#############################################################################
[general]
; Каталог, в который установлена система
general.basedir = /var/www/www.sample.cairo

; Каталог временных файлов
general.tmpdir = /var/www/www.sample.cairo/tmp

; Каталог библиотек
general.libdir = /var/www/admin.sample.cairo/usr/lib

; Каталог ядра системы
general.coredir = /var/www/admin.sample.cairo/core

; Каталог, содержащий модули
general.moddir = /var/www/admin.sample.cairo/usr/modules

; Каталог, содержащий классы полей
general.fieldsdir = /var/www/admin.sample.cairo/usr/fields

; Каталог, содержащий альтернативные классы сущностей
general.entdir = /var/www/admin.sample.cairo/usr/entities

; Каталог, содержащий темы оформления
general.skindir = /var/www/www.sample.cairo/usr/skins

; Каталог Элементов управления
general.widgetdir = /var/www/admin.sample.cairo/usr/widgets

; Каталог, содержащий Javascript
; Используется путь относительно корня ресурса, так как
; JavaScript используется только в шаблонах
general.jsdir = /usr/javascript

; Каталог настроек
general.etcdir = /var/www/www.sample.cairo/etc

; Каталог кэша
general.cachedir = /var/www/www.sample.cairo/var/cache

; Каталог загруженных на сервер файлов
general.uploaddir = /var/www/www.sample.cairo/var/uploaded

; Текущий скин
general.skin = default

; Пути поиска файлов (одной строкой)
general.paths = /var/www/admin.sample.cairo/core,/var/www/admin.sample.cairo/usr/lib,
/var/www/admin.sample.cairo/usr/modules,/var/www/admin.sample.cairo/usr/modules,
/var/www/admin.sample.cairo/usr/fields,/var/www/admin.sample.cairo/usr/widgets

; Часовой пояс клиента
general.gmt.client = +0200


;#############################################################################
;## Настройки интернационализации
;#############################################################################
[locale]
; Язык локали по умолчанию
locale.LANG = ru_RU.CP1251


;#############################################################################
;## Настройки режима отладки
;#############################################################################
[debug]

; Показывать ли ошибки PHP
debug.show_php_errors = on

; Вывод статистики после генерации страницы
debug.show_stat = off

; Выводить ли расширенную статистику по SQL-запросам
debug.sql_stat = off

; Выводить ли ошибки, если они появились при генерации страницы
debug.show_runtime_errors = on


;#############################################################################
;## Настройки изображений
;#############################################################################
[image]

; Ширина эскизов изображений
image.thumb_width = 76

; Высота эскизов изображений.
; Если установить значение 0, то высота будет вычисляться автоматически
image.thumb_height = 0

; Способ, которым будут создаваться уменьшенные копии изображений
; Допускаются два значения:
; - ImageMagic
; - GD
; По умолчанию используется GD
image.thumb_handler = GD

; Версия GD
; Необходимо заполнить только в случае, если используется
; библиотека GD
image.gd_ver = 1.6.2

; Путь к ImageMagick'у
image.convert =


;#############################################################################
;## Настройки файлов
;#############################################################################

; Ширина иконок файлов
file.icon_width = 16

; Высота иконок файлов.
file.icon_height = 16


;#############################################################################
;## Настройки электронной почты
;#############################################################################
[mail]
mail.host = localhost
mail.from = "robot@sample.cairo"
mail.webmaster = "admin@sample.cairo"


;#############################################################################
;## Настройки базы данных
;#############################################################################
[database]
database.host    = localhost
database.user    = cairo
database.passwd  = some_password
database.name    = sample
database.charset =
database.version =



;#############################################################################
;## Настройки интерфейса
;#############################################################################
webface.title = ""

; Страницы будут сжиматься
webface.gzip = on

; Кэшировать ли данные на стороне клиента
webface.cache.client = on

Подробнее о назначении настроек можно прочитать в документе "Система управления контентом CAIRO: Файлы конфигурации".

3.2. Создание страницы списка новостей

Страница списка новостей строится на основе класса CEntityList, который позволяет получать список сущностей. Для простоты будем выводить простой список без использования постраничности, календарей и другой функциональности, присущей новостным лентам.

В каталоге /var/www/www.sample.cairo/bin уже есть файл home.php. На него ссылается корень сайта. Весь код, относящийся к выводу списка сущностей, будет реализован именно в нем.

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

  1. // Подключаем ядро
  2. require_once($_SERVER['DOCUMENT_ROOT'].'/etc/init.php');
  3.  
  4. // Подключаем "Список сущностей"
  5. require_once($_CONFIG['general.coredir'].'/centitylist.php');

Через веб-интерфейс администратора Cairo получаем информацию об идентификаторе типа сущности "Новость" и идентификаторе связи новостной ленты и новости. Подробнее о том, какую служебную информацию и каким образом можно получить через интерфейс администратора Cairo смотрите в документе "Система управления контентом CAIRO: Интерфейс администратора". Если информация о типах сущностей вводилась в порядке, соответствующем описанному в данном руководстве, то оба идентификатора будут равны "1". Используя эту информацию, получаем список новостей.

В списке будет выводиться заголовок новости, изображение, дата, и аннотация. Перечень этих полей указан в первом параметре метода get_list(). Затем необходимо сформировать массив полей, выводимых в списке и ассоциативный массив новостей.

  1.     // идентификатор подтипа "Новость"
  2.     define("ETID_NEWS", 1);
  3.  
  4.     // Идентификатор связи "Новость в ленте новостей"
  5.     define("ETACID_NEWS", 1);
  6.  
  7.     // Получаем список новостей
  8.     if (!$o_news_list = CEntityList::create(0, ETID_NEWS, CENTITYLIST_RT_ASSOC)) {
  9.         CCore::error_push(CError::create("Ошибка создания списка новостей",
  10.                                          __FILE__,
  11.                                          __LINE__,
  12.                                          "",
  13.                                          ""));
  14.         break;
  15.     }
  16.  
  17.     // Делаем запрос к БД
  18.     if (!$o_news_list->get_list(
  19.                         "entities.entid, news_date, title, topic, image, image_realname",
  20.                         "",
  21.                         "ent_accept.etacid = ?etacid",
  22.                         "",
  23.                         "",
  24.                         "news_date DESC",
  25.                         "",
  26.                         CENTITYLIST_COUNT_NONE,
  27.                         array("etacid" => ETACID_NEWS)) ) {
  28.         CCore::error_push(CError::create("Ошибка получения списка новостей",
  29.                                          __FILE__,
  30.                                          __LINE__,
  31.                                          "",
  32.                                          ""));
  33.         break;
  34.     }

Далее формируем массив, который будет содержать только ту информацию о новостях, которая будет выводиться на странице.

  1. $ar_news = array();
  2.     for($i_len=sizeof($o_news_list->items), $i=0; $i<$i_len; $i++) {
  3.         $ar_news[] = array(
  4.             "entid"          => $o_news_list->items[$i]["entid"],
  5.             "date"           => $o_news_list->items[$i]["news_date"],
  6.             "title"          => $o_news_list->items[$i]["title"],
  7.             "topic"          => $o_news_list->items[$i]["topic"],
  8.             "image"          => $o_news_list->items[$i]["image"],
  9.             "image_realname" => $o_news_list->items[$i]["image_realname"],
  10.             "url"            => "/bin/news.php?id=".$o_news_list->items[$i]["entid"],
  11.         );
  12.     }

В результате весь скрипт получения списка новостей будет выглядеть следующим образом:

  1. <?php
  2. /**
  3. * Главная страница
  4. */
  5.  
  6. // Подключаем ядро
  7. require_once($_SERVER['DOCUMENT_ROOT'].'/etc/init.php');
  8.  
  9. // Подключаем "Список сущностей"
  10. require_once($_CONFIG['general.coredir'].'/centitylist.php');
  11.  
  12. do {
  13.  
  14.     // идентификатор подтипа "Новость"
  15.     define("ETID_NEWS", 1);
  16.  
  17.     // Идентификатор связи "Новость в ленте новостей"
  18.     define("ETACID_NEWS", 1);
  19.  
  20.     // Получаем список новостей
  21.     if (!$o_news_list = CEntityList::create(0, ETID_NEWS, CENTITYLIST_RT_ASSOC)) {
  22.         CCore::error_push(CError::create("Ошибка создания списка новостей",
  23.                                          __FILE__,
  24.                                          __LINE__,
  25.                                          "",
  26.                                          ""));
  27.         break;
  28.     }
  29.  
  30.     if (!$o_news_list->get_list(
  31.                         "entities.entid, news_date, title, topic, image, image_realname",
  32.                         "",
  33.                         "ent_accept.etacid = ?etacid",
  34.                         "",
  35.                         "",
  36.                         "news_date DESC",
  37.                         "",
  38.                         CENTITYLIST_COUNT_NONE,
  39.                         array("etacid" => ETACID_NEWS)) ) {
  40.         CCore::error_push(CError::create("Ошибка получения списка новостей",
  41.                                          __FILE__,
  42.                                          __LINE__,
  43.                                          "",
  44.                                          ""));
  45.         break;
  46.     }
  47.  
  48.     $ar_news = array();
  49.     for($i_len=sizeof($o_news_list->items), $i=0; $i<$i_len; $i++) {
  50.         $ar_news[] = array(
  51.             "entid"          => $o_news_list->items[$i]["entid"],
  52.             "date"           => $o_news_list->items[$i]["news_date"],
  53.             "title"          => $o_news_list->items[$i]["title"],
  54.             "topic"          => $o_news_list->items[$i]["topic"],
  55.             "image"          => $o_news_list->items[$i]["image"],
  56.             "image_realname" => $o_news_list->items[$i]["image_realname"],
  57.             "url"            => "/bin/news.php?id=".$o_news_list->items[$i]["entid"],
  58.         );
  59.     }
  60.  
  61.     $_PAGE_TITLE = "Список новостей";
  62.     include($_CONFIG["general.tpldir"]."/bin/main.tpl.php");
  63.     exit;
  64.  
  65. } while (false);
  66.  
  67. include($_CONFIG['general.basedir'].'/bin/error.php');
  68. ?>

Теперь остается только подключить шаблон страницы. Шаблон представляет собой HTML-файл со вставками PHP-кода. При желании, можно использовать любой имеющийся шаблонизатор, платформа Cairo не налагает ограничений на используемую систему шаблонизации.

  1. <html>
  2. <head>
  3.     <title><?=htmlspecialchars($_PAGE_TITLE)?></title>
  4.     <meta HTTP-EQUIV="Content-type" content="text/html; charset=windows-1251">
  5. </head>
  6. <body>
  7. <?if (empty($ar_news)) {?>
  8. Нет новостей в ленте
  9. <?}else{?>
  10. <table border="0" cellspacing="0" cellpadding="5">
  11. <?foreach($ar_news as $new) {?>
  12. <tr>
  13. <td><?
  14. if (!empty($new['image'])) {
  15.     ?><img src="/thumbnails/<?=
  16.                           htmlspecialchars($new["entid"])
  17.                       ?>/image/80x0/<?=
  18.                           htmlspecialchars($new["image_realname"])
  19.                       ?>" width="80"><?
  20. }
  21. ?></td>
  22. <td><a href="<?=$new['url']?>"><b><?=htmlspecialchars($new['title'])?></b></a><br><br>
  23. <?=nl2br(htmlspecialchars($new['topic']))?></td>
  24. </tr>
  25. <?}?>
  26. </table>
  27. <?}?>
  28. </body>
  29. </html>

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

Создание страницы списка новостей завершено. Результат можно увидеть в браузере по адресу http://www.sample.cairo/.

На следующем этапе будет создана страница новости.

3.3. Создание страницы новости

На странице новости будет выводиться заголовок новости, полный текст и изображение новости, если таковое присутствует.

В первую очередь следует создать файл /var/www/www.sample.cairo/bin/news.php. Он будет содержать код, реализующий страницу новости. Для работы с новостями понадобится класс CEntity, который позволяет получать информацию о сущности, используя ее идентификатор.

  1. // Подключаем "Ядро"
  2. require_once($_SERVER['DOCUMENT_ROOT'].'/etc/init.php');
  3. // Подключаем "Сущность"
  4. require_once($_CONFIG['general.coredir'].'/centity.php');
  5.  

Для получения информации о сущности достаточно создать экземпляр класса CEntity с переданным конструктору идентификатором сущности.

  1.     $entid = empty($_GET['id']) ? 0 : (int)$_GET['id'];
  2.  
  3.     // Получаем информацию о сущности
  4.     if (!$o_news = CEntity::create($entid)) {
  5.         CCore::error_push(CError::create("Ошибка создания сущности",
  6.                                          __FILE__,
  7.                                          __LINE__,
  8.                                          "",
  9.                                          ""));
  10.         break;
  11.     }

В целях безопасности скрипт запрещает передавать пустой параметр и проверяет формат переданных данных. После создания сущности объект $o_news содержит все параметры, настройки типа и полей. Далее подключается шаблон для вывода страницы сущности и обрабатываются появившиеся ошибки. Весь скрипт получения информации о новости выглядит следующим образом:

  1. <?php
  2. /**
  3. * Страница новости
  4. */
  5.  
  6. // Подключаем "Ядро"
  7. require_once($_SERVER['DOCUMENT_ROOT'].'/etc/init.php');
  8. // Подключаем "Сущность"
  9. require_once($_CONFIG['general.coredir'].'/centity.php');
  10.  
  11. do {
  12.  
  13.     $entid = empty($_GET['id']) ? 0 : (int)$_GET['id'];
  14.  
  15.     // Получаем информацию о сущности
  16.     if (!$o_news = CEntity::create($entid)) {
  17.         CCore::error_push(CError::create("Ошибка создания сущности",
  18.                                          __FILE__,
  19.                                          __LINE__,
  20.                                          "",
  21.                                          ""));
  22.         break;
  23.     }
  24.  
  25.  
  26.     include
  27.     ($_CONFIG['general.skindir'].'/default/bin/news.tpl.php');
  28.     exit;
  29. } while (false);
  30.  
  31. include($_CONFIG['general.basedir'].'/bin/error.php');
  32. ?>

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

  1. <html>
  2. <head>
  3.     <title><?=htmlspecialchars($o_news->params['title'])?></title>
  4.     <meta HTTP-EQUIV="Content-type" content="text/html; charset=windows-1251">
  5. </head>
  6. <body>
  7. <b><?=htmlspecialchars($o_news->params['title'])?></b><br><br>
  8. <?=$o_news->params['news_text']?></td>
  9.  
  10. <?
  11. if (!empty($o_news->params['image'])) {
  12.     ?><br><br>
  13.     <img src="/files/<?=
  14.         htmlspecialchars($o_news->params['entid'])
  15.     ?>/image/<?=
  16.         htmlspecialchars($o_news->params['image_realname'])
  17.     ?>" width="<?=
  18.         htmlspecialchars($o_news->params['image_width'])
  19.     ?>" height="<?=
  20.         htmlspecialchars($o_news->params['image_height'])
  21.     ?>"><?
  22. }
  23. ?>
  24. </body>
  25. </html>

Если все операции были выполнены правильно, то в результате должна получиться простая лента новостей. Это лишь небольшой пример, показывающий основные принципы работы с платформой Cairo. Возможности примера можно расширить самостоятельно. Так, можно добавить дополнительные ленты новостей и организовать навигацию по ним, модифицировать набор полей новости и т.д. Данная лента новостей может быть использована как часть более крупного ресурса.