воскресенье, 31 октября 2010 г.

Jdoc создание шаблонов

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

jdoc statements

jdoc statements are included in every Joomla template and indicate where the output from other parts of Joomla or its extensions should be positioned in the overall web page. A typical jdoc statement looks like this: <jdoc:include type="component" /> See the jdoc statements article for more information.

Contents

 [hide]

jdoc:include

The <jdoc:include /> statement is a Joomla! template's method of displaying content specific to the page being viewed. There are various <jdoc:include />statements, each returning a different part of a Joomla! page.

The type attribute

The type attribute specifies the type of content to be rendered in place of the <jdoc:include /> element. For example, the <jdoc:include type="head" />statement uses the type attribute head (type="head"). (Note: Jdoc expressions require double quotes around attributes, and won't work with single quotes.)

Component

<jdoc:include type="component" />
This element should only appear once in the <body> element of the Template to render the main content of the page with respect to the current page being viewed.

Head

<jdoc:include type="head" />
This element should only appear once in the <head> element of the Template to render the content of the style, script and meta elements associated with the current page.

Installation

<jdoc:include type="installation" />
This element is only used within the Joomla! Installer template and of no particular use in a Front-end or Back-end template. It's somewhat the equivalent to the 'component' type, rendering the main content of an installation step.

Message

<jdoc:include type="message" />
This element should only appear once in the <body> element of the Template to render system and error messages that occurred in the request.
CSS styles for system messages can be found in templates\system\css\system.css

Module

<jdoc:include type="module" name="breadcrumbs" title="Breadcrumbs" />
<jdoc:include type="module" name="mainmenu" title="Main Menu" />
This element renders a single module given by the name and title attributes: name should match module type (mod_breadcrumbs and mod_menu in the examples above) while title should be the module name of the desired module. The module in question must be published and accessible by the current user in order to become visible. Additional attributes can be provided to control the layout and appearance of the module, if supported.

Modules

Modules are rendered on a page using one of the following code examples. The modules are separated into different areas of a template using template positions set in the templatedetails.xml file. Using the jdoc:include's name="[template position name]" attribute, the various modules in their respective positions can be called, rendered, and styled separately. Additional attributes can be provided to control the layout and appearance of modules, if supported.
Below are some examples of module statements with module positions used frequently by Joomla! theme developers.
<jdoc:include type="modules" name="debug" />
<jdoc:include type="modules" name="icon" />
<jdoc:include type="modules" name="left" style="rounded" />
<jdoc:include type="modules" name="left" style="xhtml" />
<jdoc:include type="modules" name="right" style="xhtml" />
<jdoc:include type="modules" name="status"  />
<jdoc:include type="modules" name="syndicate" />
<jdoc:include type="modules" name="title" />
<jdoc:include type="modules" name="toolbar" />
<jdoc:include type="modules" name="top" />
<jdoc:include type="modules" name="top" style="xhtml" />
<jdoc:include type="modules" name="user1" style="xhtml" />
<jdoc:include type="modules" name="user2" style="xhtml" />
<jdoc:include type="modules" name="user3" />
<jdoc:include type="modules" name="user4" />
Note: The name="user3" module position is normally (by default) used for the top menu.

The style attribute

The optional style="" attribute is available for the module and modules types of <jdoc:include /> statements. The attribute value refers to the chrome style used to wrap the output generated by the Module. If no style is provided, a value of "none" is used by default.
Template designers may add additional chrome names as described in Applying custom module chrome.

Создаём сайт под Joomla=) Фотогалерея Phoca Gallery

Ужас.. хэллуин... гугл меня ещё не проиндексировал(( Я то думал он сайты с blogspot быстро индексирует, ведь я не хочу заниматься добавлением в каталоги....у меня всё тихо.. поспал два часа, теперь попишу 15 минут блог, пойду прогуляюсь. Надеюсь, хоть развеюсь, а то аж как-то грустно).

Вообщем, необходимо сперва поставить задачу. Допустим у меня есть на сайте eventlist, переведённый. Первое, что меня заинтересовало, после того, как я поиграл с этим интересным компонентом, это как же добавить фотоотчёты. Ну, для начала необходим хороший компонент для хранения фоток. Идём на extensions.joomla.org. Пойду пока попразную хэллуин))
.......................................................................
утро.. болит голова)) ща напишу))....
.......................................................................
Нужен компонент, который будет хранить множество фотоальбомов. Я остановился на Phoca Gallery. На их сайте и вправду множество файлов, помогающих настроить этот компонент. Есть даже файл с русификацией. Надеюсь этот компонент подойдёт. Скачиваем сам компонент, его плагин для работы с JComments, и русификацию. Идём в панель администратора-расширения-установить-устанавливаем компонент(файлы русификации просто компируем в папки administrator/language/ru-RU и /language/ru-RU). Полазив по меню, обнаружил, что можно создавать категории и подкатегории.. Это очень здорово, ведь именно такой компонент и нужен был мне, сейчас попробуйте создать категорию и в неё напихать фоток... Пока всё, что мне не понравилось - это то, что у меня не загружается несколько фотографий сразу... Надеюсь вы поиграли с компонентом и разобрались как с ним управляться... Теперь перейдём к интересному. Я хочу, чтобы на странице каждого клуба (в eventlist) появлялось несколько фоток, которые сохранила для меня Phoca Gallery для этого клуба. Думаю для этого нужно использовать какой-нибудь плагин. (При вводе в редакторе некой строки будут выводиться картинки). Такой плагин я нашёл на их же сайте. Phoca Gallery Plugin Docs - тут хорошо описано как использовать этот плагин, хоть и на английском. Т.е. для того, чтобы отобразить 5 фотографий на странице клуба(или события) мне нужно для начала включить этот плагин в менеджере плагинов, затем использовать его в описании клуба таким образом: {phocagallery view=category|categoryid=1|limitcount=5}
Не правда ли просто? Джумла рулит)) Поигравшись с параметром detail, пришел к выводу, что самые красивые эффекты это 3 и 6, т.е.


{phocagallery view=category|categoryid=1|limitcount=5|displaydownload=0|displayname=0|detail=3}
{phocagallery view=category|categoryid=1|limitcount=5|displaydownload=0|displayname=0|detail=6}


Однако, если использовать detail=0, то в быстром просмотре можно увидеть не только 5 фоток, представленных на странице, а все фотографии, входящие в категорию. Мне лучше использовать значение 0, а красоту я наведу с помощью тем.. 

суббота, 30 октября 2010 г.

Создаем сайт под Joomla=). Переводим компонент

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

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

Пока с дизайном ещё не разобрались, приступим непосредственно к созданию ПО.
Для начала, я думаю необходимо поискать готовые расширения (а вдруг повезёт и ничего писать не понадобится) Для тех кто не в курсе - самый большой источник расширений для joomla http://extensions.joomla.org/


Первым самым полезным для меня компонентом оказался EventList . установив его, я понял, что основная архитектура полностью проработана именно в нём. Мне необходимо лишь перевести его на русский язык, да и изменить стиль(может несколько представлений добавить). Я залез в первый попавшийся шаблон этого компонента и решил узнать, как же выводят текст в joomla. Интересно, что выводят его примерно так:
echo JText::_( 'CITY' ).':';


Я полез по документации joomla, ничего не понял, полез в исходники. Из-за возможности отладки кода в функции достаточно много. Смысл такой. JText вызывает метод из JLanguage, который загружает ini файлы с языками, которые находятся в папке language/ru-Ru (Для русского языка). Т.е., если мы вызываем в нашем компоненте echo JText::_('CITY');, а в ini файле с нужным именем прописано (в нашем случае ru-RU.com_eventlist.ini) есть строчка CITY=Город, то вместо City нам выведет город. Если же оно не нашло нужной строки, то выведет City (заглавная буква только первая). Вот так-то всё просто =)). Не знаю насколько быстро работает такой метод, но он очень удобный. Займусь переводом, после чего выложу все файлы.


По окончании пользовательской части, обнаружилось, что при просмотре деталей мероприятия в подзаголовке Клуб в графе информации о клубе всё равно пишется Venue. Дело было в файле components/com_eventlist/views/details/tmpl/default.php на строке 149 (к моменту вашего прочтения номер может измениться, или ошибка может быть исправлена):


<dt class="venue"><?php echo $this->elsettings->locationname.':'; ?></dt> 


Т.е. , видимо, существуют несколько различных типов заведений (клубы, рестораны и т.д.). Поэтому просто изменяем строку на:


<dt class="venue"><?php echo JText::_($this->elsettings->locationname).':'; ?></dt>


Допустим, вы как и я переводите какой-либо компонент.. тогда придётся переводить и его администраторскую часть.. всё тоже самое.. всё также, только в папке administrator/language создаём опять же файл ru-RU.com_eventlist


Перевод сделал, можете посмотреть на результат. Перевод не полный, но вполне исчерпывающий.. Чёрт, нельзя в блоге файлы публиковать. Публикую в 
Google Documents, придётся авторизоваться.. Успехов с переводами ;)

понедельник, 25 октября 2010 г.

Создадим самый простой компонент. Часть 4. Заключительная

Вот мы и подошли к концу создания самого простого компонента). Неожиданно, но всё это дело растянулось на 4 части.. хм.. Могло бы и на 5, если быть честным =)) Ну что же, мы имеем компонент, который выводит строки из БД. Осталось сделать только, чтобы эти самые строки мы могли добавлять из пользовательского интерфейса. Не будем делать админскую часть, возможность удаления, редактирования. Сроки жмут =)) Начнём

Первым делом мы должны создать шаблон формы.
/components/com_counter/views/counter/tmpl/default_form.php

<? defined('_JEXEC') or die('доступ запрещен'); ?>
<form method="post" action="index.php?option=com_counter&task=add">
ADD; <input type="text" name="new_comment" />
<input type="submit"  />
</form>
Простенький шаблон. Обычная форма. ссылка index.php?option=com_counter&task=add означает, что мы передаём нашему компоненту данные с заданием add...

Теперь в зависимости от того, авторизован пользователь или нет мы должны показать эту форму или наоборот
Изменим немного представление
/components/com_counter/views/counter/view.html.php

<?php
defined('_JEXEC') or die();
jimport( 'joomla.application.component.view');
class CounterViewCounter extends JView
{
function display ($tpl = null)
{
$user = &JFactory::getUser(); //получаем данные текущего пользователя
$model = &$this->getModel();
$rows = $model->getComments();
foreach($rows as $list)
{
$this->assignRef('username', $model->getUserName($list->user_id));
$this->assignRef('list', $list);
parent::display($tpl);
}
if(!$user->guest) parent::display('form'); // если пользователь не гость, то показать шаблон form
}
}
?>

В представление добавилось всего две строчки. Следует заметить, что когда мы передаём методу parent::display('xxx'); какое-то название, то joomla будет искать шаблон в папке tml(которая находится в той же папке, что и представление), но будет искать не xxx.php, а default_xxx.php

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

Чтобы компонент и вправду был завершен, нам нужно в контроллере реализовать функцию add
/component/com_counter/controller.php


<?
defined('_JEXEC') or die();
jimport('joomla.application.component.controller');

class CounterController extends JController
{
function __construct()
{
parent::__construct();
$this->registerTask('add','add');
$this->registerTask('show','show');
}
function add()
{
$user = &JFactory::getUser();
if(!$user->guest)
{
JTable::addIncludePath(JPATH_ADMINISTRATOR.DS.'components'.DS.'com_counter'.DS.'tables');
$row = &JTable::getInstance('counter', 'Table');

$row->user_id = $user->id;
$row->content = JRequest::getVar('new_comment');
if (!$row->store()) {
 JError::raiseError(500, $row->getError());
}
} else echo "Forbidden";
$this->show();
}
function show()
{
parent::display();
}
function display()
{
parent::display();
}
}
?>

Рассмотрим метод add(). Для начала мы проверяем авторизован ли пользователь. Если авторизован, то позволяем ему добавить комментарий. Методы сохранения данных в таблицу могут быть различны, но хотелось испробовать недавно выученный JTable. в шаге 2 мы создавали класс нашей таблицы, который расширял JTable. в этом шаге я решил его использовать. Все известные переменные мы заполнили инфой. Переменные, которые остались установлены в null JTable игнорирует в запросах вставки. Итак, использовать класс для сохранения информации мне понравилось =) Шаги закончены, осталось жуткое послевкусие писанины и ощущение того, что везде всё написано бездарно. Не огорчайся читатель, просто не обращай внимания =)

На самом деле много тем остались не раскрытыми, однако основы освоены. Трубы горят, нужно двигаться быстрее.. Пока некоторые темы отложим до лучших времен

Создадим самый простой компонент. Часть 4. Заключительная

Создадим самый простой компонент. Часть 3. JDatabase, JUser

Вообщем, разобравшись, как joomla работает с данными, я понял, что через обычные запросы. Да-да ничего мудреного тут нет. Ну, может это и к лучшему =). У нас есть класс JDatabase . Надеюсь вы ознакомились с ним по ссылке. Теперь можно переходить к реализации.

у нас немного изменится модель
/component/com_counter/models/counter.php

<?
defined('_JEXEC') or die('доступ запрещен');

class CounterModelCounter extends JModel
{
function getComments( $options=array() )
{
$database = &$this->getDBO();
$database->setQuery("SELECT * FROM #__counter");
$list = $database->loadObjectList();
return $list;
}
}
?>

Тут всё ясно. модель реализует функцию, которая получает ссылку на базу данных, потом шлёт запрос, получает ответ и возвращает его представлению. Интересно, что сейчас я пришел к выводу, что, благодаря модели MVC, joomla не нуждается в заумных классах для работы с БД. Можно больше сказать, что класс JTable во многих случаях избыточен, однако я думаю с его помощью получается информация о пользователях и других полезных данных сайта. ну.. посмотрим

Представление и шаблон пришлось тоже изменить.

Представление
/components/com_counter/views/counter/view.html.php

<?php
defined('_JEXEC') or die();
jimport( 'joomla.application.component.view');
class CounterViewCounter extends JView
{
function display ($tpl = null)
{
$model = &$this->getModel();
$rows = $model->getComments();
foreach($rows as $list)
{
$this->assignRef('list', $list);
parent::display($tpl);
}
}
}
?>

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

Шаблон

/components/com_counter/views/counter/tmpl/default.php
<? echo "<b>".$this->list->user_id."</b>:".$this->list->content; ?><br />

Вот такой простой шаблон. Отображает всего 2 переменные. Теперь встаёт вопрос.. Кто хочет видеть в комментах id пользователя? мы хотим узнать его имя по идентификатору. Конечно, у меня в базе всего один пользователь) но это не проблема для такого заядлого программера как я))).. зарегистрирую ещё одного)

Заметил, что в базе данных пользователь Admin у меня с идентификатором 62, второй пользователь имеет идентификатор 63. Меняю в соответствии с ними записи в БД (чтобы user_id совпадало с этими идентификаторами)

Теперь нам надо подумать как узнать имя пользователя по идентификатору. за эти моменты отвечают классы JUser и JFactory. Нам нужно будет добавить 1 функцию в нашу модель:

Модель
/component/com_counter/models/counter.php
<?
defined('_JEXEC') or die('доступ запрещен');
jimport( 'joomla.database.table.user' );

class CounterModelCounter extends JModel
{
function getUserName($id)
{
$user = &JFactory::getUser($id);
return $user->username;
}
function getComments( $options=array() )
{
$database = &$this->getDBO();
$database->setQuery("SELECT * FROM #__counter");
$list = $database->loadObjectList();
return $list;
}
}
?>

*совершенно не эффективное решение, лучше бы было изменить запрос, который мы посылаем в БД, но мы учимся и использование большего количества классов нам зачтется. Если кто-то зачем-то решит использовать этот простенький компонент в реальных задачах, то прошу вас, измените запрос и просто уберите функцию getUserName. Дело в том, что мы делаем запрос, получаем все комменты. а потом в представлении на каждый комментарий ещё раз делаем запрос, чтобы узнать имя пользователя.

сразу же это вносит мельчайшие изменения в шаблон и представление

Представление
/components/com_counter/views/counter/view.html.php
<?php 
defined('_JEXEC') or die();
jimport( 'joomla.application.component.view');  
class CounterViewCounter extends JView 
{ 
function display ($tpl = null) 
{ 
$model = &$this->getModel();
$rows = $model->getComments();
foreach($rows as $list)
{
$this->assignRef('username', $model->getUserName($list->user_id));
$this->assignRef('list', $list);
parent::display($tpl);
}
} 
} 
?>


Шаблон
/components/com_counter/views/counter/tmpl/default.php
<? echo "<b>".$this->username."</b>:".$this->list->content; ?><br />

Можно сделать ссылку на пользователя в месте, где стоит его имя, которая будет оказан переходить на его профиль, но в стандартной комплектации joomla вроде нет модуля профиля пользователя. Вообщем это тема не этой лекции.

воскресенье, 24 октября 2010 г.

Работа с БД Joomla-docs

Нашел интересную статейку, однако лежит он в разделе программирования для joomla 1.0..
Ну что же.. читаем, думаем


Общая информация

При старте Joomla в числе прочих, создается объект класса database (исходники класса лежат в /includes/database.php), позволяющий Joomla работать с базой данных – выбирать данные и изменять их. Исторически сложилось, что данный класс лишь обертка над myslq_* функциями, пусть и очень удобная.

[править]

Префикс таблиц в Joomla

Так как Joomla изначально создавалась для учета реальных требований хостинга, то в ней заложен функционал доступа к таблицам, согласно их префиксу. Т.е. если ваш тарифный план на хостинге дает вам возможность использовать одну лишь базу данных MySQL, а вы хотите поставить, например две Joomla или какой-либо дополнительный скрипт, названия таблиц которого совпадают с некоторыми таблицами в Joomla, то это можно реализовать при помощи префикса таблиц.
Сам префикс задается еще при установке и чаще всего представляет собой нечто вроде “jos_” (JOS расшифровывается как Joomla Open Source) и записывается в файл конфигурации configuration.php.
Конечно, при работе с базой данных можно считывать эту переменную и каждый раз приписывать ее к именам таблиц в SQL-запросах, но намного удобнее использовать механизм, встроенный в Joomla, а именно макроподстановку #__ (знак решетки и два подчеркивания). В классе database данный символ будет заменен на текущий префикс таблиц, с которым работает Joomla. Например, если при установке вы оставили префикс пустым, то он и будет заменен на пустую строку, и названия таблиц будут самыми читабельными: users, session.

[править]

Методы класса database

  • setQuery - один из самых часто используемых методов. Нужен для того, что бы объект записал запрос в свою внутреннюю переменную и заменил префикс на тот, который записан в файле конфигурации.
  • query - используется для исполнения запроса, не возвращающего никаких данных. Например, вставки или удаления строк из таблицы по некоторому условию.
  • loadObjectList - используется для выборки массива объектов представляющих собой наследники stdClass с именами полей совпадающих с именами столбцов в таблице.
  • loadResultArray - загрузка массива результатов. Удобно при выборке одной колонки, а не нескольких.
  • loadResult - загрузка одного поля. Т.е. мы знаем что результат будет только один.

Примеры использования:
  • Загрузка списка пользователей

$database->setQuery("SELECT * FROM #__users");
$list = $database->loadObjectList();
 
foreach($list as $user) {
 
    echo $user->name;
}

В результате мы увидим на экране имена всех пользователей на сайте. Отмечу, что для некоторых людей, ранее работавших с другими CMS и их слоями абстракции от БД, такой подход может оказаться немного странным. Они могли привыкнуть в цикле производить выборку данных и в этом же цикле с ними что-то делать, а здесь цикл выборки спрятан от глаз программиста, он сразу работает с данными. Надо просто привыкнуть, и позволить такие рутинные функции делать самой Joomla, а в цикле уже манипулировать данными, а не функциями выборки этих данных.
  • Загрузка ID-статей из определенного раздела

$database->setQuery("SELECT id FROM #__content WHERE section_id=1");
$ids = $database->loadResultArray();
echo implode(',',$ids);//выведет нечто вроде "1,2,3,4,5,6"

  • Загрузка email текущего пользователя

global $my;
$database->setQuery("SELECT email FROM #__users WHERE id='{$my->id}'");
$email = $database->loadResult();

  • Удаление из таблицы

$database->setQuery("DELETE FROM #__xxx WHERE id>20");
$database->query();

  • Вставка данных

$database->setQuery("INSERT INTO #__table (name,value) VALUES ('волк','голодный')");
$database->query();

Если в таблице было создано поле типа AUTO_INCREMENT, то получить идентификатор вновь созданного поля можно при помощи метода insertid, если вызвать его сразу после непосредственной вставки данных.

$new_id = $database->insertid();


[править]

Отладка обращений к базе данных

Порой, во время написания компонента или модуля возникает такая ситуация, что метод loadObjectList возвращает не нужные нам значения, а NULL. Это происходит из-за того, что вы совершили ошибку в синтаксисе SQL-запроса. Для того, что бы узнать ее, вам необходимо вызвать специальный метод, отображающий последнюю ошибку, которая произошла в данном сеансе работы с сервером MySQL.

$database->setQuery(“SELECT * FROM qwerty”);
$list = $database->loadObjectList();
echo $database->stderr();

Если таблицы не существует, то будет выведено сообщение примерно такого вида: “Table 'joomla.qwerty' doesn't exist”. Для других ситуаций ошибки будут другими.

Схема БД Joomla


Источник joomla-docs.ru

Создадим самый простой компонент. Часть 2. БД, JTable, модель

Теперь давайте разберёмся с базой данных. Создадим простую таблицу. Пусть она состоит всего из 3-ёх полей(идентификатор, id пользователя, сообщение).

CREATE TABLE `joomla`.`jos_counter` (




`id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY ,
`user_id` INT NOT NULL ,
`content` VARCHAR( 250 ) NOT NULL
) ENGINE = MYISAM ;

Теперь, когда у нас есть таблица, нам нужна модель, чтобы мы могли отображать данные. Давайте добавим 2-3 записи в таблицу (пока что не будем связывать таблицу с пользователями, поэтому в столбцах пишем то, что захотим)

Давайте создадим файл модели, который будет получать эти данные из таблицы и передавать их представлению. Прежде чем мы это сделаем, мы должны подумать, как же мы будем получать данные из базы данных. Я нактнулся на статью, о создании класса таблицы. В общем я создал
файл в /administrator/components/com_counter/tables/counter.php:

<?
defined('_JEXEC') or die('Доступ запрещен');

class TableCounter extends JTable
{
var $id = null;
var $user_id = null;
var $content = null;

function __construct(&$db)
{
parent::__construct('#_counter', 'id', $db);
}
}
?>

*Про класс JTable написано здесь.

Теперь создадим класс модели, которая получит все записи из таблицы
файл /components/com_counter/models/counter.php


<?
defined('_JEXEC') or die('доступ запрещен');
class CounterModelCounter extends JModel
{
function getComments( $options=array() )
{
JTable::addIncludePath(JPATH_ADMINISTRATOR.DS.'components'.DS.'com_counter'.DS.'tables');
$row = &$this->getTable('counter');
$row->load(1);
return $row;
}
}
?>

Если мы передадим эти данные в представление, которая в свою очередь передаст это шаблону, то мы увидим 1 запись. Нафига нам 1 запись? неужели класс JTable такой бесполезный. Полчаса разбирался с этим классом =/ По крайней мере других методов я не наблюдаю, да и чего ждать от этого класса. Придётся копать класс JDatabase, или просто внедрять свои классы для работы с БД (но это потом, сейчас нужно выучить joomla и написать на на ней заказ)

Код представления:

<?php
defined('_JEXEC') or die();
jimport( 'joomla.application.component.view');
class CounterViewCounter extends JView
{
function display ($tpl = null)
{
$model = &$this->getModel();
$rows = $model->getComments();
$this->assignRef('greeting', $rows->content);
parent::display($tpl);
}
}
?>

Шаблон остался неизменным. Не будем падать духом, в 3-ем шаге мы получим данные любой ценой. будь то хоть mysql_query =))





Создадим самый простой компонент. Часть 4. Заключительная