From cf76c805199ce142116ed749c09ed9d20410cd48 Mon Sep 17 00:00:00 2001 From: Dollerino Date: Wed, 23 Oct 2024 16:30:05 +0300 Subject: [PATCH] =?UTF-8?q?=D0=A6=D0=98=D0=A2=D0=9A-904=20-=20=D0=94=D0=BE?= =?UTF-8?q?=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=20=D0=BA=D0=BE=D0=BC=D0=BF?= =?UTF-8?q?=D0=BE=D0=BD=D0=B5=D0=BD=D1=82=20"=D0=A6=D0=B8=D0=BA=D0=BB?= =?UTF-8?q?=D0=BE=D0=B3=D1=80=D0=B0=D0=BC=D0=BC=D0=B0"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 497 +++++++++++++++++++ app/components/p8p_cyclogram.js | 819 ++++++++++++++++++++++++++++++++ app/config_wrapper.js | 9 + app/panels/samples/cyclogram.js | 302 ++++++++++++ app/panels/samples/samples.js | 4 +- db/P8PNL_SMPL_CYCLOGRAM.sql | 18 + db/PKG_P8PANELS_SAMPLES.pck | 553 +++++++++++++++++++++ docs/img/72.png | Bin 0 -> 44588 bytes docs/img/73.png | Bin 0 -> 59174 bytes 9 files changed, 2201 insertions(+), 1 deletion(-) create mode 100644 app/components/p8p_cyclogram.js create mode 100644 app/panels/samples/cyclogram.js create mode 100644 db/P8PNL_SMPL_CYCLOGRAM.sql create mode 100644 docs/img/72.png create mode 100644 docs/img/73.png diff --git a/README.md b/README.md index c6a6461..58cc08f 100644 --- a/README.md +++ b/README.md @@ -2366,6 +2366,503 @@ const Svg = ({ title }) => { Полные актуальные исходные коды примера можно увидеть в "app/panels/samples/svg.js" данного репозитория соответственно. +##### Циклограмма "P8PCyclogram" + +Компонент предназначен для отображения данных в виде циклограммы. Поддерживается: + +- Группировка задач с отображением описания группы при наведении +- Форматирование цвета заливки задачи, текста задачи и цвета при наведении на задачу/группу +- Дополнение задачи произвольными учётными атрибутами +- Диалоговый редактор задачи, отображающий её дополнительные атрибуты с возможностью настройки их форматирования +- Отображение произвольного пользовательского диалога в качестве карточки задачи/редактора задачи +- Масштабирование визуального представления + +![Пример P8PGantt](docs/img/72.png) +![Пример P8PGantt](docs/img/73.png) + +**Подключение** + +Клиентская часть циклограммы реализована в компоненте `P8PCyclogram`, объявленном в "app/components/p8p_cyclogram". Для использования компонента на панели его необходимо импортировать: + +``` +import { P8PCyclogram } from "../../components/p8p_cyclogram"; + +const MyPanel = () => { + return ( +
+ +
+ ); +} +``` + +**Свойства** + +`containerStyle` - необязательный, объект, стили, которые будут применены к компонету `div`, являющемуся контейнером циклограммы\ +`lineHeight` - необязательный, число, высота строки в пикселях (по умолчанию 20)\ +`title` - необязательный, строка, заголовок циклограммы (если не указан - не отображается)\ +`titleStyle` - необязательный, объект, стили, которые будут применены к компонету `Typography` заголовка циклограммы\ +`onTitleClick` - необязательный, функция, будет вызвана при нажатии пользователем на заголовок (если указана - заголовок формируется в виде гиперссылки), сигнатура функции `f()`, результат функции не интерпретируется\ +`zoomBar` - необязательный, логический, признак отображения панели управления масштабом (по умолчанию - не отображается)\ +`zoom` - необязательный, число, масштаб циклограммы\ +`columns` - обязательный, массив, колонки, отображаемые на циклограмме, должен состоять из объектов вида `{name: <НАИМЕНОВАНИЕ>, start: <ПОЗИЦИЯ_НАЧАЛА_КОЛОНКИ>, end: <ПОЗИЦИЯ_ОКОНЧАНИЯ_КОЛОНКИ>}` (см. константу `P8P_CYCLOGRAM_COLUMN_SHAPE` в коде компонента)\ +`columnRenderer` - необязательный, функция формирования представления колонки (если не указана - отображение по умолчанию). Сигнатура функции: `f({column})`. Будет вызвана для каждой колонки циклограммы, в функцию будет передан объект, в поле `column` которого будет содержаться описание текущей генерируемой колонки (элемент массива `columns`, см. выше описание полей). Должна возвращать значение или React-компонент.\ +`groups` - необязательный, массив, группы задач, которые отображаются на циклограмме, должен состоять из объектов вида `{name: <НАИМЕНОВАНИЕ>, height: <ВЫСОТА_ОТОБРАЖЕНИЯ_ГРУППЫ>, width: <ШИРИНА_ОТОБРАЖЕНИЯ_ГРУППЫ>, visible: <ПРИЗНАК_ОТОБРАЖЕНИЯ_ГРУППЫ>}` (см. константу `P8P_CYCLOGRAM_GROUP_SHAPE` в коде компонента). Группа отображается только при наведении на соответствующую задачу, которая относится к данной группе.\ +`groupHeaderRenderer` - необязательный, функция формирования представления всплывающей информации о группе (если не указана - отображение по умолчанию). Сигнатура функции: `f({group})`. Будет вызвана для каждой группы циклограммы, в функцию будет передан объект, в поле `group` которого будет содержаться описание текущей генерируемой группы (элемент массив `groups`, см. выше описание полей). Должна возвращать значение или React-компонент.\ +`tasks` - обязательный, массив, задачи, отображаемые на циклограмме, должен состоять из объектов вида `{id: <УНИКАЛЬНЫЙ_ИДЕНТИФИКАТОР>, rn: <ССЫЛКА_НА_ЗАПИСЬ_В_СИСТЕМЕ>, name: <НАИМЕНОВАНИЕ>, fullName: <ПОЛНОЕ_НАИМЕНОВАНИЕ>, lineNumb: <НОМЕР_СТРОКИ_ЗАДАЧИ>, start: <ПОЗИЦИЯ_НАЧАЛА_ЗАДАЧИ>, end: <ПОЗИЦИЯ_ОКОНЧАНИЯ_ЗАДАЧИ>, group: <НАИМЕНОВАНИЕ_ГРУППЫ>, bgColor: <ЦВЕТ_ЗАЛИВКИ>, textColor: <ЦВЕТ_ТЕКСТА>, highlightColor: <ЦВЕТ_НАВЕДЕНИЯ>, [<ИМЯ_ДОПОЛНИТЕЛЬНОГО_АТРИБУТА1>:<ЗНАЧЕНИЕ1>, <ИМЯ_ДОПОЛНИТЕЛЬНОГО_АТРИБУТА2>:<ЗНАЧЕНИЕ2>,...]}` (см. константу `P8P_CYCLOGRAM_TASK_SHAPE` в коде компонента).\ +`taskRenderer` - необязательный, функция формирования представления задачи на циклограмме (если не указана - отображение по умолчанию). Сигнатура функции: `f({task, taskHeight, taskWidth})`. Будет вызвана для каждой задачи циклограммы, в функцию будет передан объект, в поле `task` которого будет содержаться описание текущей генерируемой задаче (элемент массив `tasks`, см. выше описание полей), в поле `taskHeight` описание высоты задачи, в поле `taskWidth` описание ширины задачи. Должна возвращать объект вида `{taskStyle: <СТИЛИ_ДЛЯ_ЭЛЕМЕНТА_ЗАДАЧИ>, taskProps: <СВОЙСТВА_ДЛЯ_ЭЛЕМЕНТА_ЗАДАЧИ>, data: <ЗНАЧЕНИЕ_ИЛИ_КОМПОНЕНТ_React_ДЛЯ_СОДЕРЖИМОГО_ЭЛЕМЕНТА_ЗАДАЧИ>}` или `undefined`, если для задачи не предполагается специального представления.\ +`taskAttributes` - необязательный, массив, состав (не значения) дополнительных атрибутутов задач, должен состоять из объектов вида `{name: <ИМЯ_ДОПОЛНИТЕЛЬНОГО_АТРИБУТА>, caption: <ЗАГОЛОВОК_ДОПОЛНИТЕЛЬНОГО_АТРИБУТА>, visible: <ПРИЗНАК_ОТОБРАЖЕНИЯ_ДОПОЛНИТЕЛЬНОГО_АТРИБУТА - true|false>}` (см. константу `P8P_CYCLOGRAM_TASK_ATTRIBUTE_SHAPE` в коде компонента)\ +`taskAttributeRenderer` - необязательный, функция, если указана - будет вызвана при отображении диалога редактора здачи, результат функции будет применён для отображения области дополнительных атрибутов задачи в диалоге редактора, если не указана - дополнительные атрибуты будут отображены с форматированием по умолчанию. Сигнатура функции - `f({task, attribute})`, в функцию будет передан объект в поле `task`, которого, будет содержаться описание задачи для которой отображается редактор (элемент массива `tasks`, см. выше описание полей), в поле `attribute` - описание дополнительного атрибута формируемого в диалоге редактора (элемент массива `taskAttributes`, см. выше описание полей). Должна возвращать значение или React-компонент.\ +`taskDialogRenderer` - необязательный, функция, если указана - будет вызвана до отображения диалога редактора задачи. Результат функции будет показан в качестве содержимого диалога редактора, вместо типовой формы. Сигнатура функции - `f({task, taskAttributes, close})`, в функцию будет передан объект в поле `task`, которого, будет содержаться описание задачи для которой отображается редактор (элемент массива `tasks`, см. выше описание полей), в поле `taskAttributes` - массив `taskAttributes` (см. выше описание полей), описывающий состав полей задачи, в поле `close` - функция закрытия диалога задачи, может быть вызвана возвращаемым Reac-компонентом для сокрытия диалога. Должна возвращать значение или React-компонент.\ +`noDataFoundText` - обязательный, строка, текст для отображения ошибки об отсутствии данных\ +`nameTaskEditorCaption` - обязательный, строка, подпись стандартного атрибута `name` в диалоге редактора задачи\ +`okTaskEditorBtnCaption` - обязательный, строка, подпись кнопки "ОК" диалога редактора задачи\ +`cancelTaskEditorBtnCaption` - обязательный, строка, подпись кнопки "ОТМЕНА" диалога редактора задачи + +Некоторые параметры циклограммы вынесены в свойства компонента `P8PCyclogram` для минимизации его связи с фреймворком и поддержания возможности стороннего использования (например, свойства `noDataFoundText`, `okTaskEditorBtnCaption`, `cancelTaskEditorBtnCaption` и т.п.) . Тем не менее, в настройках фреймворка и его окружении уже есть реализации для данных свойств. Например, в "app.text.js" уже содержатся объявления типовых констант для текстов подписей кнопок и пунктов меню. Поэтому, в "app/config_wrapper.js" для привязки свойств `P8PCyclogram` к контексту фреймворка реализованы специальные декораторы и объекты-шаблоны, облегчающие подключение экземпляра `P8PCyclogram` к панели и снимающие с разработчика необходимость указывать некоторые из перечисленных выше обязательных свойств. В предложенном ниже примере, из модуля "config_wrapper" в панель импортируется объект `P8P_CYCLOGRAM_CONFIG_PROPS`, который уже содержт преднастроенное описание свойств `noDataFoundText`,`nameTaskEditorCaption`, `okTaskEditorBtnCaption` и `cancelTaskEditorBtnCaption`, полученное из окружения фреймворка. Таким образом, прикладной разработчик может не указывать их значения при использовании `P8PCyclogram` (если по каким-то причинам не хочет их переопределить, конечно). + +``` +import { P8PCyclogram } from "../../components/p8p_cyclogram"; +import { P8P_CYCLOGRAM_CONFIG_PROPS } from "../../config_wrapper"; + +const MyPanel = () => { + return ( +
+ +
+ ); +} +``` + +**API на сервере БД** + +Компонент `P8PCyclogram` требует от разработчика передачи данных в определённом формате. С целью снижения трудозатрат на приведение собранных хранимым объектом данных Системы к форматам, потребляемым `P8PCyclogram`, реализован специальный API на стороне сервера БД. + +Для циклограммы это (см. детальные описания программных интерфейсов в пакете `PKG_P8PANELS_VISUAL`): +`PKG_P8PANELS_VISUAL.TCYCLOGRAM_MAKE` - функция, инициализация циклограммы, возвращает объект для хранения её описания\ +`PKG_P8PANELS_VISUAL.TCYCLOGRAM_ADD_TASK_ATTR` - процедура, добавляет, к указанному объекту описания циклограммы, описатель дополнительного атрибута задачи\ +`PKG_P8PANELS_VISUAL.TCYCLOGRAM_TASK_MAKE` - функция, инициализирует и возвращает объект для описания задачи в циклограмме (поставщик данных для `TCYCLOGRAM_ADD_TASK`)\ +`PKG_P8PANELS_VISUAL.TCYCLOGRAM_TASK_ADD_ATTR_VAL` - процедура, добавляет, к указанному объекту описания задачи, значение дополнительного атрибута\ +`PKG_P8PANELS_VISUAL.TCYCLOGRAM_ADD_COLUMN` - процедура, добавляет, к указанному объекту описания циклограммы, новую колонку\ +`PKG_P8PANELS_VISUAL.TCYCLOGRAM_ADD_GROUP` - процедура, добавляет, к указанному объекту описания циклограммы, новую группу\ +`PKG_P8PANELS_VISUAL.TCYCLOGRAM_ADD_TASK` - процедура, добавляет, к указанному объекту описания циклограммы, новую задачу, ранее описанную через `TCYCLOGRAM_TASK_MAKE`\ +`PKG_P8PANELS_VISUAL.TCYCLOGRAM_TO_XML` - функция, производит сериализацию объекта, описывающего циклограмму, в специальный XML-формат, корректно интерпретируемый клиентским компонентом `P8PCyclogram` при передаче в WEB-приложение + +**Пример** + +Код на стороне сервера БД (хранимая процедура в клиентском пакете `PKG_P8PANELS_SAMPLES`, требует наличия таблицы `P8PNL_SMPL_CYCLOGRAM`, см. "db/P8PNL_SMPL_CYCLOGRAM.sql"): + +``` + procedure CYCLOGRAM + ( + NIDENT in number, -- Идентификатор процесса + COUT out clob -- Сериализованные данные для циклограммы + ) + is + CG PKG_P8PANELS_VISUAL.TCYCLOGRAM; -- Описание циклограммы + RTASK PKG_P8PANELS_VISUAL.TCYCLOGRAM_TASK; -- Описание задачи циклограммы + NLINE_NUMB PKG_STD.TNUMBER := 0; -- Номер строки + NLINE_NUMB_TMP PKG_STD.TNUMBER := 0; -- Номер строки (буфер) + DTASK_DATE_START PKG_STD.TLDATE; -- Дата начала этапа + DTASK_DATE_END PKG_STD.TLDATE; -- Дата окончания этапа + NTASK_START PKG_STD.TNUMBER := 0; -- Позиция начала этапа + NTASK_END PKG_STD.TNUMBER := 0; -- Позиция окончания этапа + STASK_NAME PKG_STD.TSTRING; -- Наименование задачи + SCOLOR_WHITE PKG_STD.TSTRING := 'white'; -- Цвет - белый + SBG_TASK_COLOR_W_GRP PKG_STD.TSTRING := '#6bc982'; -- Цвет задачи с группой + SHL_TASK_COLOR_W_GRP PKG_STD.TSTRING := '#7dd592'; -- Цвет наведения задачи с группой + SBG_TASK_COLOR_WO_GRP PKG_STD.TSTRING := '#e36d6d'; -- Цвет задачи без группы + STEXT_COLOR_TASK_WO_GRP PKG_STD.TSTRING := '#e5e5e5'; -- Цвет текста задачи без группы + SBG_TASK_COLOR_GRP PKG_STD.TSTRING := 'cadetblue'; -- Цвет групповой задачи + SHL_TASK_COLOR_GRP PKG_STD.TSTRING := '#6fadaf'; -- Цвет наведения групповой задачи + + /* Считывание значений группирующей задачи */ + procedure GROUP_TASK_GET + ( + NIDENT in number, -- Идентификатор процесса + NGROUP in number := null, -- Рег. номер группы + NFLAG_WO_GROUP in number := 0, -- Признак отбора задач без групп (0 - нет, 1 - да) + DTASK_DATE_START out date, -- Дата начала этапа + DTASK_DATE_END out date, -- Дата окончания этапа + NTASK_START out number, -- Позиция начала этапа + NTASK_END out number -- Позиция окончания этапа + ) + is + begin + ... + end GROUP_TASK_GET; + begin + /* Инициализируем циклограмму */ + CG := PKG_P8PANELS_VISUAL.TCYCLOGRAM_MAKE(STITLE => 'Задачи на ' || TO_CHAR(EXTRACT(year from sysdate)) || ' год'); + /* Добавляем атрибуты */ + PKG_P8PANELS_VISUAL.TCYCLOGRAM_ADD_TASK_ATTR(RCYCLOGRAM => CG, + SNAME => 'ddate_start', + SCAPTION => 'Дата начала', + BVISIBLE => true, + BCLEAR => true); + PKG_P8PANELS_VISUAL.TCYCLOGRAM_ADD_TASK_ATTR(RCYCLOGRAM => CG, + SNAME => 'ddate_end', + SCAPTION => 'Дата окончания', + BVISIBLE => true); + PKG_P8PANELS_VISUAL.TCYCLOGRAM_ADD_TASK_ATTR(RCYCLOGRAM => CG, + SNAME => 'type', + SCAPTION => 'Тип', + BVISIBLE => false); + /* Обходим колонки */ + for CLMN in (select T.NAME, + T.POS_START, + T.POS_END + from P8PNL_SMPL_CYCLOGRAM T + where T.IDENT = NIDENT + and T.TYPE = 0) + loop + /* Добавляем колонку */ + PKG_P8PANELS_VISUAL.TCYCLOGRAM_ADD_COLUMN(RCYCLOGRAM => CG, + SNAME => CLMN.NAME, + NSTART => CLMN.POS_START, + NEND => CLMN.POS_END); + end loop; + /* Считываем значения для задач проекта */ + GROUP_TASK_GET(NIDENT => NIDENT, + NFLAG_WO_GROUP => 0, + DTASK_DATE_START => DTASK_DATE_START, + DTASK_DATE_END => DTASK_DATE_END, + NTASK_START => NTASK_START, + NTASK_END => NTASK_END); + /* Формируем задачу (этап) */ + RTASK := PKG_P8PANELS_VISUAL.TCYCLOGRAM_TASK_MAKE(NRN => 1, + SCAPTION => 'Задачи проекта', + SNAME => 'Задачи проекта', + NLINE_NUMB => NLINE_NUMB, + NSTART => NTASK_START, + NEND => NTASK_END, + SBG_COLOR => SCOLOR_WHITE); + /* Добавляем атрибуты */ + PKG_P8PANELS_VISUAL.TCYCLOGRAM_TASK_ADD_ATTR_VAL(RCYCLOGRAM => CG, + RTASK => RTASK, + SNAME => 'ddate_start', + SVALUE => PKG_XCONVERT.DATE_TO_XML(DVALUE => DTASK_DATE_START), + BCLEAR => true); + PKG_P8PANELS_VISUAL.TCYCLOGRAM_TASK_ADD_ATTR_VAL(RCYCLOGRAM => CG, + RTASK => RTASK, + SNAME => 'ddate_end', + SVALUE => PKG_XCONVERT.DATE_TO_XML(DVALUE => DTASK_DATE_END)); + PKG_P8PANELS_VISUAL.TCYCLOGRAM_TASK_ADD_ATTR_VAL(RCYCLOGRAM => CG, RTASK => RTASK, SNAME => 'type', SVALUE => 0); + /* Добавляем задачу в циклограмму */ + PKG_P8PANELS_VISUAL.TCYCLOGRAM_ADD_TASK(RCYCLOGRAM => CG, RTASK => RTASK); + /* Указываем следующую строку */ + NLINE_NUMB := NLINE_NUMB + 1; + /* Обходим группы */ + for GRP in (select T.RN, + T.NAME, + ROWNUM RNUM + from P8PNL_SMPL_CYCLOGRAM T + where T.IDENT = NIDENT + and T.TYPE = 1 + order by T.RN asc) + loop + ... + /* Добавляем группу */ + PKG_P8PANELS_VISUAL.TCYCLOGRAM_ADD_GROUP(RCYCLOGRAM => CG, + SNAME => GRP.NAME, + NHEADER_HEIGHT => 30, + NHEADER_WIDTH => 200); + /* Считываем значения этапа группы */ + GROUP_TASK_GET(NIDENT => NIDENT, + NGROUP => GRP.RN, + DTASK_DATE_START => DTASK_DATE_START, + DTASK_DATE_END => DTASK_DATE_END, + NTASK_START => NTASK_START, + NTASK_END => NTASK_END); + /* Формируем задачу (этап) */ + RTASK := PKG_P8PANELS_VISUAL.TCYCLOGRAM_TASK_MAKE(NRN => GRP.RN, + SCAPTION => 'Этап ' || TO_CHAR(GRP.RNUM), + SNAME => 'Этап ' || TO_CHAR(GRP.RNUM), + NLINE_NUMB => NLINE_NUMB, + NSTART => NTASK_START, + NEND => NTASK_END, + SBG_COLOR => SBG_TASK_COLOR_GRP, + STEXT_COLOR => SCOLOR_WHITE, + SHIGHLIGHT_COLOR => SHL_TASK_COLOR_GRP); + /* Добавляем атрибуты */ + PKG_P8PANELS_VISUAL.TCYCLOGRAM_TASK_ADD_ATTR_VAL(RCYCLOGRAM => CG, + RTASK => RTASK, + SNAME => 'ddate_start', + SVALUE => PKG_XCONVERT.DATE_TO_XML(DVALUE => DTASK_DATE_START), + BCLEAR => true); + PKG_P8PANELS_VISUAL.TCYCLOGRAM_TASK_ADD_ATTR_VAL(RCYCLOGRAM => CG, + RTASK => RTASK, + SNAME => 'ddate_end', + SVALUE => PKG_XCONVERT.DATE_TO_XML(DVALUE => DTASK_DATE_END)); + PKG_P8PANELS_VISUAL.TCYCLOGRAM_TASK_ADD_ATTR_VAL(RCYCLOGRAM => CG, RTASK => RTASK, SNAME => 'type', SVALUE => 1); + /* Добавляем задачу в циклограмму */ + PKG_P8PANELS_VISUAL.TCYCLOGRAM_ADD_TASK(RCYCLOGRAM => CG, RTASK => RTASK); + /* Обходим задачи группы */ + for TASK in (select T.RN, + T.NAME, + T.POS_START, + T.POS_END, + T.DATE_FROM, + T.DATE_TO, + ROWNUM RNUM + from P8PNL_SMPL_CYCLOGRAM T + where T.IDENT = NIDENT + and T.TYPE = 2 + and T.TASK_GROUP = GRP.RN) + loop + ... + end loop; + /* Указываем следующую строку */ + NLINE_NUMB := NLINE_NUMB + 1; + end loop; + /* Указываем следующую строку */ + NLINE_NUMB := NLINE_NUMB + 1; + /* Считываем значения для обособленных задач */ + GROUP_TASK_GET(NIDENT => NIDENT, + NFLAG_WO_GROUP => 1, + DTASK_DATE_START => DTASK_DATE_START, + DTASK_DATE_END => DTASK_DATE_END, + NTASK_START => NTASK_START, + NTASK_END => NTASK_END); + /* Формируем задачу (этап) */ + RTASK := PKG_P8PANELS_VISUAL.TCYCLOGRAM_TASK_MAKE(NRN => 1, + SCAPTION => 'Обособленные задачи', + SNAME => 'Обособленные задачи', + NLINE_NUMB => NLINE_NUMB, + NSTART => NTASK_START, + NEND => NTASK_END, + SBG_COLOR => SCOLOR_WHITE); + /* Добавляем атрибуты */ + PKG_P8PANELS_VISUAL.TCYCLOGRAM_TASK_ADD_ATTR_VAL(RCYCLOGRAM => CG, + RTASK => RTASK, + SNAME => 'ddate_start', + SVALUE => PKG_XCONVERT.DATE_TO_XML(DVALUE => DTASK_DATE_START), + BCLEAR => true); + PKG_P8PANELS_VISUAL.TCYCLOGRAM_TASK_ADD_ATTR_VAL(RCYCLOGRAM => CG, + RTASK => RTASK, + SNAME => 'ddate_end', + SVALUE => PKG_XCONVERT.DATE_TO_XML(DVALUE => DTASK_DATE_END)); + PKG_P8PANELS_VISUAL.TCYCLOGRAM_TASK_ADD_ATTR_VAL(RCYCLOGRAM => CG, RTASK => RTASK, SNAME => 'type', SVALUE => 0); + /* Добавляем задачу в циклограмму */ + PKG_P8PANELS_VISUAL.TCYCLOGRAM_ADD_TASK(RCYCLOGRAM => CG, RTASK => RTASK); + /* Указываем следующую строку */ + NLINE_NUMB := NLINE_NUMB + 1; + /* Цикл по обособленным задачам */ + for REC in (select T.RN, + T.NAME, + T.POS_START, + T.POS_END, + T.DATE_FROM, + T.DATE_TO, + ROWNUM RNUM + from P8PNL_SMPL_CYCLOGRAM T + where T.IDENT = NIDENT + and T.TYPE = 2 + and T.TASK_GROUP is null) + loop + ... + end loop; + /* Формируем список */ + COUT := PKG_P8PANELS_VISUAL.TCYCLOGRAM_TO_XML(RCYCLOGRAM => CG); + end CYCLOGRAM; +``` + +Код панели на стороне клиента (WEB-приложения): + +``` +/* + Парус 8 - Панели мониторинга - Примеры для разработчиков + Пример: Циклограмма "P8PCyclogram" +*/ + +//--------------------- +//Подключение библиотек +//--------------------- + +import React, { useState, useContext, useCallback, useEffect } from "react"; //Классы React +import PropTypes from "prop-types"; //Контроль свойств компонента +import { + Typography, + Grid, + Button, + Box, + DialogContent, + List, + ListItem, + ListItemText, + Divider, + TextField, + DialogActions, + Stack, + Icon +} from "@mui/material"; //Интерфейсные элементы +import { formatDateJSONDateOnly, formatDateRF } from "../../core/utils"; //Вспомогательные функции +import { APP_BAR_HEIGHT } from "../../components/p8p_app_workspace"; //Заголовок страницы +import { P8PCyclogram } from "../../components/p8p_cyclogram"; //Циклограмма +import { P8P_CYCLOGRAM_CONFIG_PROPS } from "../../config_wrapper"; //Подключение компонентов к настройкам приложения +import { BackEndСtx } from "../../context/backend"; //Контекст взаимодействия с сервером + +//--------- +//Константы +//--------- + +//Отступ контейнера страницы от заголовка +const CONTAINER_PADDING_TOP = "20px"; + +//Высота заголовка страницы +const TITLE_HEIGHT = "47px"; + +//Высота строк +const LINE_HEIGHT = 30; + +//Стили +const STYLES = { + CONTAINER: { textAlign: "center", paddingTop: CONTAINER_PADDING_TOP }, + TITLE: { paddingBottom: "15px", height: TITLE_HEIGHT }, + GANTT_CONTAINER: { + height: `calc(100vh - ${APP_BAR_HEIGHT} - ${TITLE_HEIGHT} - ${CONTAINER_PADDING_TOP})`, + width: "100vw", + paddingTop: "5px" + }, + TASK_EDITOR_CONTENT: { minWidth: 400, overflowX: "auto" }, + TASK_EDITOR_LIST: { width: "100%", minWidth: 300, maxWidth: 700, bgcolor: "background.paper" }, + GROUP_HEADER: height => ({ + border: "1px solid", + backgroundColor: "#ecf8fb", + height: height, + borderRadius: "10px", + display: "flex", + alignItems: "center", + justifyContent: "space-around" + }) +}; + +//--------------------------------------------- +//Вспомогательные функции форматирования данных +//--------------------------------------------- + +//Диалог открытия задачи +const CustomTaskDialog = ({ task, ident, handleReload, close }) => { + ... +}; + +//Контроль свойств - Диалог открытия задачи +CustomTaskDialog.propTypes = { + task: PropTypes.object.isRequired, + ident: PropTypes.number.isRequired, + handleReload: PropTypes.func.isRequired, + close: PropTypes.func.isRequired +}; + +//Заголовок группы +const CustomGroupHeader = ({ group }) => { + ... +}; + +//Контроль свойств - Заголовок группы +CustomGroupHeader.propTypes = { + group: PropTypes.object.isRequired +}; + +//Отображение задачи +const taskRenderer = ({ task }) => { + ... +}; + +//----------- +//Тело модуля +//----------- + +//Пример: Циклограмма "P8PCyclogram" +const Cyclogram = ({ title }) => { + //Собственное состояние + const [state, setState] = useState({ + init: false, + dataLoaded: false, + reload: true, + ident: null + }); + + //Подключение к контексту взаимодействия с сервером + const { executeStored } = useContext(BackEndСtx); + + //При необходимости перезагрузки + const handleReload = () => { + setState(pv => ({ ...pv, reload: true })); + }; + + //При необходимости обновить данные таблицы + useEffect(() => { + //Загрузка данных циклограммы с сервера + const loadData = async () => { + const data = await executeStored({ + stored: "PKG_P8PANELS_SAMPLES.CYCLOGRAM", + args: { NIDENT: state.ident }, + attributeValueProcessor: (name, val) => + name === "name" ? undefined : ["ddate_start", "ddate_end"].includes(name) ? formatDateJSONDateOnly(val) : val, + respArg: "COUT" + }); + setState(pv => ({ ...pv, dataLoaded: true, ...data.XCYCLOGRAM, reload: false })); + }; + //Если указан идентификатор и требуется перезагрузить + if (state.ident && state.reload) loadData(); + }, [state.ident, state.reload, executeStored]); + + //При подключении компонента к странице + useEffect(() => { + //Инициализация данных циклограммы + const initData = async () => { + const data = await executeStored({ stored: "PKG_P8PANELS_SAMPLES.CYCLOGRAM_INIT", args: { NIDENT: state.ident } }); + setState(pv => ({ ...pv, init: true, ident: data.NIDENT, reload: true })); + }; + //Если требуется проинициализировать + if (!state.init) { + initData(); + } + }, [executeStored, state.ident, state.init]); + + return ( + +
+ + {title} + + + + {state.dataLoaded ? ( + ( + + )} + taskRenderer={prms => taskRenderer(prms)} + groupHeaderRenderer={prms => } + /> + ) : null} + + +
+
+ ); +}; + +//Контроль свойств - Пример: Циклограмма "P8PCyclogram" +Cyclogram.propTypes = { + title: PropTypes.string.isRequired +}; + +//---------------- +//Интерфейс модуля +//---------------- + +export { Cyclogram }; +``` + +Полные актуальные исходные коды примеров можно увидеть в "db/PKG_P8PANELS_SAMPLES.pck" и "app/panels/samples/cyclogram.js" данного репозитория соответственно. + ### Ограничения дизайна пользовательского интерфейса Фреймворк позволяет реализовать любые пользовательские интерфейсы, вёрстка которых не противоречит возможностям современного HTML. Тем не менее, при разработке пользовательских интерфейсов панелей важно придерживаться предложенных ниже правил. Это позволит создавать их в едином ключе и упростит работу конечного пользователя при их освоении. diff --git a/app/components/p8p_cyclogram.js b/app/components/p8p_cyclogram.js new file mode 100644 index 0000000..08a4866 --- /dev/null +++ b/app/components/p8p_cyclogram.js @@ -0,0 +1,819 @@ +/* + Парус 8 - Панели мониторинга + Компонент: Циклограмма +*/ + +//--------------------- +//Подключение библиотек +//--------------------- + +import React, { useEffect, useState, useRef } from "react"; //Классы React +import PropTypes from "prop-types"; //Контроль свойств компонента +import { + Box, + Typography, + Dialog, + DialogActions, + DialogContent, + Button, + List, + ListItem, + ListItemText, + Link, + Divider, + IconButton, + Icon +} from "@mui/material"; //Интерфейсные компоненты +import { P8PAppInlineError } from "./p8p_app_message"; //Встраиваемое сообщение об ошибке +import { hasValue } from "../core/utils"; //Вспомогательный функции + +//--------- +//Константы +//--------- + +//Уровни масштаба +const P8P_CYCLOGRAM_ZOOM = [0.2, 0.4, 0.7, 1, 1.5, 2, 2.5]; + +//Параметры элементов циклограммы +const NDEFAULT_LINE_HEIGHT = 20; +const NDEFAULT_HEADER_HEIGHT = 35; + +//Высота заголовка +const TITLE_HEIGHT = "44px"; + +//Высота панели масштабирования +const ZOOM_HEIGHT = "56px"; + +//Стили +const STYLES = { + CYCLOGRAM_TITLE: { height: TITLE_HEIGHT }, + CYCLOGRAM_ZOOM: { height: ZOOM_HEIGHT }, + HEADER_COLUMN: { + fontSize: "12px", + textOverflow: "ellipsis", + overflow: "hidden", + whiteSpace: "pre", + textAlign: "center", + lineHeight: "3", + padding: "0px 5px" + }, + CYCLOGRAM_BOX: (noData, title, zoomBar) => ({ + position: "relative", + overflow: "auto", + padding: "0px 8px", + height: `calc(100% - ${zoomBar ? ZOOM_HEIGHT : "0px"} - ${title ? TITLE_HEIGHT : "0px"})`, + display: noData ? "none" : "" + }), + GRID_ROW: index => (index % 2 === 0 ? { backgroundColor: "#ffffff" } : { backgroundColor: "#f5f5f5" }), + GROUP_HEADER_BOX: { + border: "1px solid", + backgroundColor: "#ebebeb", + display: "flex", + alignItems: "center", + justifyContent: "center" + }, + GROUP_HEADER: { + fontSize: "14px", + textAlign: "center", + wordWrap: "break-word" + }, + TASK_EDITOR_CONTENT: { minWidth: 400, overflowX: "auto" }, + TASK_EDITOR_LIST: { width: "100%", minWidth: 300, maxWidth: 700, bgcolor: "background.paper" }, + TASK_BOX: (lineHeight, bgColor, textColor, highlightColor) => ({ + display: "flex", + alignItems: "center", + backgroundColor: bgColor ? bgColor : "#b4b9bf", + ...(textColor ? { color: textColor } : {}), + height: lineHeight, + "&:hover": { + ...(highlightColor + ? { backgroundColor: `${highlightColor} !important`, filter: "brightness(1) !important" } + : { filter: "brightness(1.25) !important" }), + cursor: "pointer !important" + } + }), + TASK: lineHeight => { + const availableLines = Math.floor(lineHeight / 18); + return { + width: "100%", + fontSize: "12px", + overflowWrap: "break-word", + wordBreak: "break-all", + overflow: "hidden", + textOverflow: "ellipsis", + display: "-webkit-box", + lineHeight: "18px", + maxHeight: lineHeight, + WebkitLineClamp: availableLines < 1 ? 1 : availableLines, + WebkitBoxOrient: "vertical" + }; + } +}; + +//Структура колонки +const P8P_CYCLOGRAM_COLUMN_SHAPE = PropTypes.shape({ + name: PropTypes.string.isRequired, + start: PropTypes.number.isRequired, + end: PropTypes.number.isRequired +}); + +//Структура группы +const P8P_CYCLOGRAM_GROUP_SHAPE = PropTypes.shape({ + name: PropTypes.string.isRequired, + height: PropTypes.number.isRequired, + width: PropTypes.number.isRequired, + visible: PropTypes.bool.isRequired +}); + +//Структура задачи +const P8P_CYCLOGRAM_TASK_SHAPE = PropTypes.shape({ + id: PropTypes.string.isRequired, + rn: PropTypes.number.isRequired, + name: PropTypes.string.isRequired, + fullName: PropTypes.string.isRequired, + lineNumb: PropTypes.number.isRequired, + start: PropTypes.number.isRequired, + end: PropTypes.number.isRequired, + group: PropTypes.string, + bgColor: PropTypes.string, + textColor: PropTypes.string, + highlightColor: PropTypes.string +}); + +//Структура динамического атрибута задачи +const P8P_CYCLOGRAM_TASK_ATTRIBUTE_SHAPE = PropTypes.shape({ + name: PropTypes.string.isRequired, + caption: PropTypes.string.isRequired, + visible: PropTypes.bool.isRequired +}); + +//-------------------------------- +//Вспомогательные классы и функции +//-------------------------------- + +//Определение сдвига для максимальной ширины колонок +const getShift = (columns, currentColumnsMaxWidth, maxCyclogramWidth) => { + //Определяем доступное пространство для расширения + let maxWidthDiff = maxCyclogramWidth - currentColumnsMaxWidth; + //Инициализируем значение сдвига + let shift = 1; + //Если доступно больше ширины и есть пространство для расширения + if (maxCyclogramWidth > currentColumnsMaxWidth && maxCyclogramWidth - maxWidthDiff > columns.length) { + //Определяем доступный сдвиг колонок + shift = maxCyclogramWidth / currentColumnsMaxWidth; + } + //Возвращаем сдвиг + return shift; +}; + +//Формирование стилей для группы +const getGroupStyles = (indexGrp, highlightColor) => { + return `.main .TaskGrp${indexGrp}:hover .TaskGrp${indexGrp} { + ${highlightColor ? `background: ${highlightColor};` : `filter: brightness(1.15);`} + } + .main:has(.TaskGrp${indexGrp}:hover) .TaskGrpHeader${indexGrp} { + display: block; + } + `; + //cursor: pointer; +}; + +//Фон строк таблицы +const P8PCyclogramRowsGrid = ({ rows, maxWidth, lineHeight }) => { + return ( + + {rows.map((el, index) => ( + + + + ))} + + ); +}; + +//Контроль свойств - Фон строк таблицы +P8PCyclogramRowsGrid.propTypes = { + rows: PropTypes.array.isRequired, + maxWidth: PropTypes.number.isRequired, + lineHeight: PropTypes.number.isRequired +}; + +//Линии строк таблицы +const P8PCyclogramRowsLines = ({ rows, maxWidth, lineHeight }) => { + return ( + + {rows.map((el, index) => ( + + ))} + + ); +}; + +//Контроль свойств - Линии строк таблицы +P8PCyclogramRowsLines.propTypes = { + rows: PropTypes.array.isRequired, + maxWidth: PropTypes.number.isRequired, + lineHeight: PropTypes.number.isRequired +}; + +//Линии колонок таблицы +const P8PCyclogramColumnsLines = ({ columns, shift, y1, y2 }) => { + //Инициализируем старт текущей колонки + let prevColumnEnd = 0; + return ( + + {columns.map((column, index) => { + //Аккумулируем окончание последней колонки с учетом сдвига + prevColumnEnd = index !== 0 ? prevColumnEnd + (columns[index - 1].end - columns[index - 1].start) * shift : 0; + return ; + })} + + + ); +}; + +//Контроль свойств - Линии колонок таблицы +P8PCyclogramColumnsLines.propTypes = { + columns: PropTypes.array.isRequired, + shift: PropTypes.number.isRequired, + y1: PropTypes.number.isRequired, + y2: PropTypes.number.isRequired +}; + +//Фон таблицы циклограммы +const P8PCyclogramGrid = ({ tasks, columns, shift, maxWidth, maxHeight, lineHeight }) => { + //Формируем массив строк исходя из максимального значения строки задачи + const rows = Array.from(Array(Math.max(...tasks.map(o => o.lineNumb)) + 1).keys()); + return ( + + + + + + + ); +}; + +//Контроль свойств - Фон таблицы циклограммы +P8PCyclogramGrid.propTypes = { + tasks: PropTypes.array.isRequired, + columns: PropTypes.array.isRequired, + shift: PropTypes.number.isRequired, + maxWidth: PropTypes.number.isRequired, + maxHeight: PropTypes.number.isRequired, + lineHeight: PropTypes.number.isRequired +}; + +//Колонка заголовка циклограммы +const P8PCyclogramHeaderColumn = ({ column, start, shift, columnRenderer }) => { + //Рассчитываем ширину колонки + const columnWidth = column.end - column.start; + //Формируем собственное отображение, если требуется + const customView = columnRenderer ? columnRenderer({ column }) : null; + return ( + <> + + {customView ? ( + customView + ) : ( + + {column.name} + + )} + + + ); +}; + +//Контроль свойств - Колонка заголовка циклограммы +P8PCyclogramHeaderColumn.propTypes = { + column: PropTypes.object.isRequired, + start: PropTypes.number.isRequired, + shift: PropTypes.number.isRequired, + maxHeight: PropTypes.number.isRequired, + lastElement: PropTypes.bool, + columnRenderer: PropTypes.func +}; + +//Заголовок циклограммы +const P8PCyclogramHeader = ({ columns, shift, maxWidth, maxHeight, columnRenderer, headerBlock }) => { + //Инициализируем старт текущей колонки + let prevColumnEnd = 0; + return ( + + + {columns.map((column, index) => { + //Аккумулируем окончание последней колонки с учетом сдвига + prevColumnEnd = index !== 0 ? prevColumnEnd + (columns[index - 1].end - columns[index - 1].start) * shift : 0; + return ( + + ); + })} + + + + + ); +}; + +//Контроль свойств - Заголовок циклограммы +P8PCyclogramHeader.propTypes = { + columns: PropTypes.array.isRequired, + shift: PropTypes.number.isRequired, + maxWidth: PropTypes.number.isRequired, + maxHeight: PropTypes.number.isRequired, + columnRenderer: PropTypes.func, + headerBlock: PropTypes.object +}; + +//Задача циклограммы +const P8PCyclogramTask = ({ task, indexGrp, shift, lineHeight, openTaskEditor, taskRenderer }) => { + //Рассчитываем ширину задачи + const width = task.end !== 0 ? (task.end - task.start) * shift : 0; + //Формируем собственное отображение, если требуется + const customView = taskRenderer ? taskRenderer({ task, taskHeight: lineHeight, taskWidth: width }) || {} : {}; + return ( + + openTaskEditor(task)} + > + {customView.data ? ( + customView.data + ) : ( + + {task.name} + + )} + + + ); +}; + +//Контроль свойств - Группы циклограммы +P8PCyclogramTask.propTypes = { + task: PropTypes.object.isRequired, + indexGrp: PropTypes.number, + shift: PropTypes.number.isRequired, + lineHeight: PropTypes.number.isRequired, + openTaskEditor: PropTypes.func.isRequired, + taskRenderer: PropTypes.func +}; + +//Основная информация циклограммы +const P8PCyclogramMain = ({ + columns, + groups, + tasks, + shift, + lineHeight, + maxWidth, + maxHeight, + openTaskEditor, + groupHeaderRenderer, + taskRenderer, + columnRenderer, + headerBlock +}) => { + //Инициализируем коллекцию тасков с группами + const tasksWithGroup = tasks.filter(task => hasValue(task.groupName)); + //Инициализируем коллекцию тасков без групп + const tasksWithoutGroup = tasks.filter(task => !hasValue(task.groupName)); + //Инициализируем коллекцию отображаемых групп + const visibleGroups = groups ? groups.filter(group => group.visible) : []; + return ( + + + {visibleGroups.length !== 0 + ? visibleGroups.map((grp, indexGrp) => { + //Считываем задачи группы + let groupTasks = tasksWithGroup.filter(task => task.groupName === grp.name); + //Если по данной группе нет тасков - ничего не выводим + if (groupTasks.length === 0) { + return null; + } + return ( + + {groupTasks.map((task, index) => ( + + ))} + + + ); + }) + : null} + + {tasksWithoutGroup.map((task, index) => { + return ( + + ); + })} + + + + {visibleGroups.length !== 0 ? ( + + {visibleGroups.map((grp, indexGrp) => { + //Инициализируем параметры группы + let defaultView = null; + let customView = null; + let groupHeaderX = 0; + let groupHeaderY = 0; + let groupTasks = tasksWithGroup.filter(task => task.groupName === grp.name); + //Если по данной группе нет тасков - ничего не выводим + if (groupTasks.length === 0) { + return null; + } + //Если требуется отображать заголовок группы + if (grp.visible) { + //Формируем отображение по умолчанию + defaultView = ( + + {grp.name} + + ); + //Формируем собственное отображение, если требуется + customView = groupHeaderRenderer ? groupHeaderRenderer({ group: grp }) : null; + //Рассчитываем координаты заголовка группы + groupHeaderX = Math.min(...groupTasks.map(o => o.start)) * shift; + groupHeaderY = NDEFAULT_HEADER_HEIGHT + Math.min(...groupTasks.map(o => o.lineNumb)) * lineHeight - grp.height - 5; + } + return ( + + {customView ? customView : defaultView} + + ); + })} + + ) : null} + + ); +}; + +//Контроль свойств - Основная информация циклограммы +P8PCyclogramMain.propTypes = { + columns: PropTypes.array.isRequired, + groups: PropTypes.array, + tasks: PropTypes.array.isRequired, + shift: PropTypes.number.isRequired, + lineHeight: PropTypes.number.isRequired, + maxWidth: PropTypes.number.isRequired, + maxHeight: PropTypes.number.isRequired, + openTaskEditor: PropTypes.func.isRequired, + groupHeaderRenderer: PropTypes.func, + taskRenderer: PropTypes.func, + columnRenderer: PropTypes.func, + headerBlock: PropTypes.object +}; + +//Редактор задачи +const P8PCyclogramTaskEditor = ({ + task, + taskAttributes, + onOk, + onCancel, + taskAttributeRenderer, + taskDialogRenderer, + nameCaption, + okBtnCaption, + cancelBtnCaption +}) => { + //Собственное состояние + const [state, setState] = useState({ + start: task.start, + end: task.end + }); + + //Отображаемые атрибуты + const dispTaskAttributes = + Array.isArray(taskAttributes) && taskAttributes.length > 0 ? taskAttributes.filter(attr => attr.visible && hasValue(task[attr.name])) : []; + + //При сохранении + const handleOk = () => (onOk && state.start && state.end ? onOk() : null); + + //При отмене + const handleCancel = () => (onCancel ? onCancel() : null); + + //Генерация содержимого + return ( + + {taskDialogRenderer ? ( + taskDialogRenderer({ task, taskAttributes, close: handleCancel }) + ) : ( + <> + + + + + + {dispTaskAttributes.length > 0 ? : null} + {dispTaskAttributes.length > 0 + ? dispTaskAttributes.map((attr, i) => { + const defaultView = task[attr.name]; + const customView = taskAttributeRenderer ? taskAttributeRenderer({ task, attribute: attr }) : null; + return ( + + + + + {i < dispTaskAttributes.length - 1 ? : null} + + ); + }) + : null} + + + + + + + + )} + + ); +}; + +//Контроль свойств - Редактор задачи +P8PCyclogramTaskEditor.propTypes = { + task: P8P_CYCLOGRAM_TASK_SHAPE, + taskAttributes: PropTypes.arrayOf(P8P_CYCLOGRAM_TASK_ATTRIBUTE_SHAPE), + onOk: PropTypes.func, + onCancel: PropTypes.func, + taskAttributeRenderer: PropTypes.func, + taskDialogRenderer: PropTypes.func, + nameCaption: PropTypes.string.isRequired, + okBtnCaption: PropTypes.string.isRequired, + cancelBtnCaption: PropTypes.string.isRequired +}; + +//Циклограмма +const P8PCyclogram = ({ + containerStyle, + lineHeight, + title, + titleStyle, + onTitleClick, + zoomBar, + zoom, + columns, + columnRenderer, + groups, + groupHeaderRenderer, + tasks, + taskRenderer, + taskAttributes, + taskAttributeRenderer, + taskDialogRenderer, + noDataFoundText, + nameTaskEditorCaption, + okTaskEditorBtnCaption, + cancelTaskEditorBtnCaption +}) => { + //Хук основного блока (для последующего определения доступной ширины) + const mainBlock = useRef(null); + //Хук для заголовка таблицы + const headerBlock = useRef(null); + //Собственное состояние + const [state, setState] = useState({ + noData: true, + loaded: false, + lineHeight: NDEFAULT_LINE_HEIGHT, + maxWidth: 0, + maxHeight: 0, + shift: 0, + zoom: P8P_CYCLOGRAM_ZOOM.includes(zoom) ? zoom : 1, + tasks: [], + editTask: null + }); + + //Обновление масштаба циклограммы + const handleZoomChange = direction => { + //Считываем текущий индекс + const currentIndex = P8P_CYCLOGRAM_ZOOM.indexOf(state.zoom); + setState(pv => ({ + ...pv, + zoom: + currentIndex + direction !== P8P_CYCLOGRAM_ZOOM.length && currentIndex + direction !== -1 + ? P8P_CYCLOGRAM_ZOOM[currentIndex + direction] + : pv.zoom + })); + }; + + //Открытие редактора задачи + const openTaskEditor = task => setState(pv => ({ ...pv, editTask: { ...task } })); + + //При сохранении задачи в редакторе + const handleTaskEditorSave = () => { + setState(pv => ({ ...pv, editTask: null })); + }; + + //При закрытии редактора задачи без сохранения + const handleTaskEditorCancel = () => setState(pv => ({ ...pv, editTask: null })); + + //При скролле блока + const handleScroll = e => { + //Изменяем позицию заголовка таблицы относительно скролла + headerBlock.current.setAttribute("transform", "translate(0," + e.currentTarget.scrollTop + ")"); + }; + + //При изменении данных + useEffect(() => { + //Если есть колонки и задачи + if (Array.isArray(columns) && columns.length > 0 && Array.isArray(tasks) && tasks.length > 0) { + //Определяем текущую максимальную ширину колонок + let currentColumnsMaxWidth = Math.max(...columns.map(o => o.end)); + //Определяем доступный сдвиг для ширины колонок (16 - паддинг по бокам) + let columnShift = getShift(columns, currentColumnsMaxWidth, mainBlock.current.offsetWidth - 16) * state.zoom; + //Устанавливаем значения исходя из колонок/задач + setState(pv => ({ + ...pv, + loaded: true, + lineHeight: lineHeight ? lineHeight : NDEFAULT_LINE_HEIGHT, + maxWidth: columnShift !== 0 ? currentColumnsMaxWidth * columnShift : currentColumnsMaxWidth, + maxHeight: NDEFAULT_HEADER_HEIGHT + (Math.max(...tasks.map(o => o.lineNumb)) + 1) * (lineHeight ? lineHeight : NDEFAULT_LINE_HEIGHT), + shift: columnShift, + tasks: tasks, + noData: false + })); + } else { + //Устанавливаем значения исходя из колонок/задач + setState(pv => ({ + ...pv, + noData: true + })); + } + }, [columns, lineHeight, state.zoom, tasks]); + + //Генерация содержимого + return ( + <> +
+ {state.noData ? : null} + {state.loaded ? ( + <> + {title ? ( + + {onTitleClick ? ( + onTitleClick()}> + {title} + + ) : ( + title + )} + + ) : null} + {zoomBar ? ( + + handleZoomChange(1)} + disabled={state.zoom == P8P_CYCLOGRAM_ZOOM[P8P_CYCLOGRAM_ZOOM.length - 1]} + > + zoom_in + + handleZoomChange(-1)} disabled={state.zoom == P8P_CYCLOGRAM_ZOOM[0]}> + zoom_out + + + ) : null} + + + + + + + + ) : null} + {state.editTask ? ( + + ) : null} +
+ + ); +}; + +//Контроль свойств - Циклограмма +P8PCyclogram.propTypes = { + containerStyle: PropTypes.object, + lineHeight: PropTypes.number, + title: PropTypes.string, + titleStyle: PropTypes.object, + onTitleClick: PropTypes.func, + zoomBar: PropTypes.bool, + zoom: PropTypes.number, + columns: PropTypes.arrayOf(P8P_CYCLOGRAM_COLUMN_SHAPE).isRequired, + columnRenderer: PropTypes.func, + groups: PropTypes.arrayOf(P8P_CYCLOGRAM_GROUP_SHAPE), + groupHeaderRenderer: PropTypes.func, + tasks: PropTypes.arrayOf(P8P_CYCLOGRAM_TASK_SHAPE).isRequired, + taskRenderer: PropTypes.func, + taskAttributes: PropTypes.arrayOf(P8P_CYCLOGRAM_TASK_ATTRIBUTE_SHAPE), + taskAttributeRenderer: PropTypes.func, + taskDialogRenderer: PropTypes.func, + noDataFoundText: PropTypes.string.isRequired, + nameTaskEditorCaption: PropTypes.string.isRequired, + okTaskEditorBtnCaption: PropTypes.string.isRequired, + cancelTaskEditorBtnCaption: PropTypes.string.isRequired +}; + +//---------------- +//Интерфейс модуля +//---------------- + +export { P8PCyclogram }; diff --git a/app/config_wrapper.js b/app/config_wrapper.js index 4372f0f..808b6a7 100644 --- a/app/config_wrapper.js +++ b/app/config_wrapper.js @@ -76,6 +76,14 @@ const P8P_GANTT_CONFIG_PROPS = { cancelTaskEditorBtnCaption: BUTTONS.CANCEL }; +//Конфигурируемые свойства "Циклограммы" (P8PCyclogram) +const P8P_CYCLOGRAM_CONFIG_PROPS = { + noDataFoundText: TEXTS.NO_DATA_FOUND, + nameTaskEditorCaption: CAPTIONS.NAME, + okTaskEditorBtnCaption: BUTTONS.OK, + cancelTaskEditorBtnCaption: BUTTONS.CANCEL +}; + //----------------------- //Вспомогательные функции //----------------------- @@ -132,6 +140,7 @@ export { P8P_DATA_GRID_SIZE, P8P_DATA_GRID_FILTER_SHAPE, P8P_GANTT_CONFIG_PROPS, + P8P_CYCLOGRAM_CONFIG_PROPS, P8P_GANTT_TASK_SHAPE, P8P_GANTT_TASK_ATTRIBUTE_SHAPE, P8P_GANTT_TASK_COLOR_SHAPE, diff --git a/app/panels/samples/cyclogram.js b/app/panels/samples/cyclogram.js new file mode 100644 index 0000000..8517d78 --- /dev/null +++ b/app/panels/samples/cyclogram.js @@ -0,0 +1,302 @@ +/* + Парус 8 - Панели мониторинга - Примеры для разработчиков + Пример: Циклограмма "P8PCyclogram" +*/ + +//--------------------- +//Подключение библиотек +//--------------------- + +import React, { useState, useContext, useCallback, useEffect } from "react"; //Классы React +import PropTypes from "prop-types"; //Контроль свойств компонента +import { + Typography, + Grid, + Button, + Box, + DialogContent, + List, + ListItem, + ListItemText, + Divider, + TextField, + DialogActions, + Stack, + Icon +} from "@mui/material"; //Интерфейсные элементы +import { formatDateJSONDateOnly, formatDateRF } from "../../core/utils"; //Вспомогательные функции +import { APP_BAR_HEIGHT } from "../../components/p8p_app_workspace"; //Заголовок страницы +import { P8PCyclogram } from "../../components/p8p_cyclogram"; //Циклограмма +import { P8P_CYCLOGRAM_CONFIG_PROPS } from "../../config_wrapper"; //Подключение компонентов к настройкам приложения +import { BackEndСtx } from "../../context/backend"; //Контекст взаимодействия с сервером + +//--------- +//Константы +//--------- + +//Отступ контейнера страницы от заголовка +const CONTAINER_PADDING_TOP = "20px"; + +//Высота заголовка страницы +const TITLE_HEIGHT = "47px"; + +//Высота строк +const LINE_HEIGHT = 30; + +//Стили +const STYLES = { + CONTAINER: { textAlign: "center", paddingTop: CONTAINER_PADDING_TOP }, + TITLE: { paddingBottom: "15px", height: TITLE_HEIGHT }, + GANTT_CONTAINER: { + height: `calc(100vh - ${APP_BAR_HEIGHT} - ${TITLE_HEIGHT} - ${CONTAINER_PADDING_TOP})`, + width: "100vw", + paddingTop: "5px" + }, + TASK_EDITOR_CONTENT: { minWidth: 400, overflowX: "auto" }, + TASK_EDITOR_LIST: { width: "100%", minWidth: 300, maxWidth: 700, bgcolor: "background.paper" }, + GROUP_HEADER: height => ({ + border: "1px solid", + backgroundColor: "#ecf8fb", + height: height, + borderRadius: "10px", + display: "flex", + alignItems: "center", + justifyContent: "space-around" + }) +}; + +//--------------------------------------------- +//Вспомогательные функции форматирования данных +//--------------------------------------------- + +//Диалог открытия задачи +const CustomTaskDialog = ({ task, ident, handleReload, close }) => { + //Собственное состояние + const [taskDates, setTaskDates] = useState({ start: task.ddate_start, end: task.ddate_end }); + + //Тип проекта + const textType = task.type === 0 ? "Задачи проекта" : task.type === 1 ? "Этап проекта" : "Работа проекта"; + + //Подключение к контексту взаимодействия с сервером + const { executeStored } = useContext(BackEndСtx); + + //Изменение дат задачи + const changeDates = useCallback(async () => { + //Изменяем даты задачи + await executeStored({ + stored: "PKG_P8PANELS_SAMPLES.CYCLOGRAM_TASK_MODIFY", + args: { + NIDENT: ident, + NRN: task.rn, + SDATE_FROM: formatDateRF(taskDates.start), + SDATE_TO: formatDateRF(taskDates.end) + } + }); + handleReload(); + close(); + }, [close, executeStored, handleReload, ident, task.rn, taskDates.end, taskDates.start]); + + //При нажатии OK + const handleOk = () => { + //Изменяем даты задачи + changeDates(); + }; + + return ( + <> + + + + + + + + setTaskDates(pv => ({ ...pv, start: e.target.value }))} + variant="standard" + size="small" + margin="normal" + > + } + /> + + + + setTaskDates(pv => ({ ...pv, end: e.target.value }))} + variant="standard" + size="small" + margin="normal" + > + } + /> + + + + + {task.type === 0 ? "description" : task.type === 1 ? "check" : "work_outline"} + {textType} + + } + /> + + + + + + + + + ); +}; + +//Контроль свойств - Диалог открытия задачи +CustomTaskDialog.propTypes = { + task: PropTypes.object.isRequired, + ident: PropTypes.number.isRequired, + handleReload: PropTypes.func.isRequired, + close: PropTypes.func.isRequired +}; + +//Заголовок группы +const CustomGroupHeader = ({ group }) => { + return ( + + {group.name} + + ); +}; + +//Контроль свойств - Заголовок группы +CustomGroupHeader.propTypes = { + group: PropTypes.object.isRequired +}; + +//Отображение задачи +const taskRenderer = ({ task }) => { + //Если это задачи проекта + if (task.type === 0) { + return { + taskStyle: { border: "3px solid #ebe058" } + }; + } +}; + +//----------- +//Тело модуля +//----------- + +//Пример: Циклограмма "P8PCyclogram" +const Cyclogram = ({ title }) => { + //Собственное состояние + const [state, setState] = useState({ + init: false, + dataLoaded: false, + reload: true, + ident: null + }); + + //Подключение к контексту взаимодействия с сервером + const { executeStored } = useContext(BackEndСtx); + + //При необходимости перезагрузки + const handleReload = () => { + setState(pv => ({ ...pv, reload: true })); + }; + + //При необходимости обновить данные таблицы + useEffect(() => { + //Загрузка данных циклограммы с сервера + const loadData = async () => { + const data = await executeStored({ + stored: "PKG_P8PANELS_SAMPLES.CYCLOGRAM", + args: { NIDENT: state.ident }, + attributeValueProcessor: (name, val) => + name === "name" ? undefined : ["ddate_start", "ddate_end"].includes(name) ? formatDateJSONDateOnly(val) : val, + respArg: "COUT" + }); + setState(pv => ({ ...pv, dataLoaded: true, ...data.XCYCLOGRAM, reload: false })); + }; + //Если указан идентификатор и требуется перезагрузить + if (state.ident && state.reload) loadData(); + }, [state.ident, state.reload, executeStored]); + + //При подключении компонента к странице + useEffect(() => { + //Инициализация данных циклограммы + const initData = async () => { + const data = await executeStored({ stored: "PKG_P8PANELS_SAMPLES.CYCLOGRAM_INIT", args: { NIDENT: state.ident } }); + setState(pv => ({ ...pv, init: true, ident: data.NIDENT, reload: true })); + }; + //Если требуется проинициализировать + if (!state.init) { + initData(); + } + }, [executeStored, state.ident, state.init]); + + return ( + +
+ + {title} + + + + {state.dataLoaded ? ( + ( + + )} + taskRenderer={prms => taskRenderer(prms)} + groupHeaderRenderer={prms => } + /> + ) : null} + + +
+
+ ); +}; + +//Контроль свойств - Пример: Циклограмма "P8PCyclogram" +Cyclogram.propTypes = { + title: PropTypes.string.isRequired +}; + +//---------------- +//Интерфейс модуля +//---------------- + +export { Cyclogram }; diff --git a/app/panels/samples/samples.js b/app/panels/samples/samples.js index cbf8df8..3746450 100644 --- a/app/panels/samples/samples.js +++ b/app/panels/samples/samples.js @@ -18,6 +18,7 @@ import { DataGrid } from "./data_grid"; //Пример: Таблица данн import { Chart } from "./chart"; //Пример: Графики "P8PChart" import { Gantt } from "./gantt"; //Пример: Диаграмма Ганта "P8PGantt" import { Svg } from "./svg"; //Пример: Интерактивные изображения "P8PSVG" +import { Cyclogram } from "./cyclogram"; //Пример: Циклограмма "P8PCyclogram" //--------- //Константы @@ -32,7 +33,8 @@ const MODES = { DATAGRID: { name: "DATAGRID", caption: 'Таблица данных "P8PDataGrid"', component: DataGrid }, CHART: { name: "CHART", caption: 'Графики "P8PChart"', component: Chart }, GANTT: { name: "GANTT", caption: 'Диаграмма Ганта "P8PGantt"', component: Gantt }, - SVG: { name: "SVG", caption: 'Интерактивные изображения "P8PSVG"', component: Svg } + SVG: { name: "SVG", caption: 'Интерактивные изображения "P8PSVG"', component: Svg }, + CYCLOGRAM: { name: "CYCLOGRAM", caption: 'Циклограмма "P8PCyclogram"', component: Cyclogram } }; //Стили diff --git a/db/P8PNL_SMPL_CYCLOGRAM.sql b/db/P8PNL_SMPL_CYCLOGRAM.sql new file mode 100644 index 0000000..3c16eff --- /dev/null +++ b/db/P8PNL_SMPL_CYCLOGRAM.sql @@ -0,0 +1,18 @@ +/* + Парус 8 - Панели мониторинга - Примеры + Буфер для циклограммы +*/ +create table P8PNL_SMPL_CYCLOGRAM +( + RN number( 17 ) not null, + IDENT number( 17 ) not null, + TYPE number( 1 ) not null, + NAME varchar2( 200 ) not null, + POS_START number( 17 ) default null, + POS_END number( 17 ) default null, + DATE_FROM date default null, + DATE_TO date default null, + TASK_GROUP number( 17 ) default null, + constraint C_P8PNL_SMPL_CYCLOGRAM_RN_PK primary key (RN), + constraint C_P8PNL_SMPL_CYCLOGRAM_TP_VAL check (TYPE in (0, 1, 2)) +); diff --git a/db/PKG_P8PANELS_SAMPLES.pck b/db/PKG_P8PANELS_SAMPLES.pck index 1f7e228..74e7101 100644 --- a/db/PKG_P8PANELS_SAMPLES.pck +++ b/db/PKG_P8PANELS_SAMPLES.pck @@ -59,10 +59,35 @@ create or replace package PKG_P8PANELS_SAMPLES as DDATE_TO in date -- Дата окончания задачи ); + /* Инициализация буфера данных для диаграммы Ганта */ + procedure CYCLOGRAM_INIT + ( + NIDENT in out number -- Идентификатор буфера сформированных данных (null - сгенерировать новый, !null - удалить старые данные и пересоздать с указанным идентификатором) + ); + + /* Сбор данных для отображения циклограммы */ + procedure CYCLOGRAM + ( + NIDENT in number, -- Идентификатор процесса + COUT out clob -- Сериализованные данные для циклограммы + ); + + /* Изменение задачи циклограммы */ + procedure CYCLOGRAM_TASK_MODIFY + ( + NIDENT in number, -- Идентификатор буфера + NRN in number, -- Рег. номер записи + SDATE_FROM in varchar2, -- Дата начала (в строковом представлении) + SDATE_TO in varchar2 -- Дата окончания (в строковом представлении) + ); + end PKG_P8PANELS_SAMPLES; / create or replace package body PKG_P8PANELS_SAMPLES as + /* Константы для циклограммы */ + NCG_MULTIPLIER constant PKG_STD.TNUMBER := 5; -- Множитель для ширины отображения + /* Получение списка контрагентов */ procedure AGNLIST_GET ( @@ -205,6 +230,7 @@ create or replace package body PKG_P8PANELS_SAMPLES as NCONTACT_METHOD => null, SMF_ID => null, SOKOGU => null, + NJURPERS_SUBDIV => null, NRN => NRN); end AGNLIST_INSERT; @@ -666,6 +692,533 @@ create or replace package body PKG_P8PANELS_SAMPLES as DDATE_TO => TRUNC(DDATE_TO)); end loop; end GANTT_MODIFY; + + /* Очистка буфера данных для циклограммы */ + procedure CYCLOGRAM_BASE_CLEAN + ( + NIDENT in number -- Идентификатор буфера + ) + is + begin + /* Удалим из буфера всё с указанным идентификатором */ + delete from P8PNL_SMPL_CYCLOGRAM T where T.IDENT = NIDENT; + end CYCLOGRAM_BASE_CLEAN; + + /* Добавление данных в буфер циклограммы */ + procedure CYCLOGRAM_BASE_INSERT + ( + NIDENT in number, -- Идентификатор буфера + NTYPE in number, -- Тип (0 - колонка, 1 - группа, 2 - задача) + SNAME in varchar2, -- Наименование + NPOS_START in number := null, -- Позиция начала элемента + NPOS_END in number := null, -- Позиция окончания элемента + DDATE_FROM in date := null, -- Дата начала + DDATE_TO in date := null, -- Дата окончания + NTASK_GROUP in number := null, -- Рег. номер группы + NRN out number -- Рег. номер записи + ) + is + begin + /* Генерируем рег. номер записи */ + NRN := GEN_ID(); + /* Добавим запись */ + insert into P8PNL_SMPL_CYCLOGRAM + (RN, IDENT, type, name, POS_START, POS_END, DATE_FROM, DATE_TO, TASK_GROUP) + values + (NRN, NIDENT, NTYPE, SNAME, NPOS_START, NPOS_END, DDATE_FROM, DDATE_TO, NTASK_GROUP); + end CYCLOGRAM_BASE_INSERT; + + /* Исправление данных в буфере циклограммы */ + procedure CYCLOGRAM_BASE_UPDATE + ( + NIDENT in number, -- Идентификатор буфера + NRN in number, -- Рег. номер записи + NTYPE in number, -- Тип задачи (0 - этап/веха, 1 - работа) + SNAME in varchar2, -- Наименование + NPOS_START in number, -- Позиция начала + NPOS_END in number, -- Позиция окончания + DDATE_FROM in date, -- Дата начала + DDATE_TO in date, -- Дата окончания + NTASK_GROUP in number -- Рег. номер группы + ) + is + begin + /* Изменим запись */ + update P8PNL_SMPL_CYCLOGRAM T + set T.TYPE = NTYPE, + T.NAME = SNAME, + T.POS_START = NPOS_START, + T.POS_END = NPOS_END, + T.DATE_FROM = DDATE_FROM, + T.DATE_TO = DDATE_TO, + T.TASK_GROUP = NTASK_GROUP + where T.RN = NRN + and T.IDENT = NIDENT; + end CYCLOGRAM_BASE_UPDATE; + + /* Инициализация буфера данных для диаграммы Ганта */ + procedure CYCLOGRAM_INIT + ( + NIDENT in out number -- Идентификатор буфера сформированных данных (null - сгенерировать новый, !null - удалить старые данные и пересоздать с указанным идентификатором) + ) + is + NYEAR PKG_STD.TNUMBER; -- Текущий год + DCYCLOGRAM_START PKG_STD.TLDATE; -- Дата начала циклограммы + DMONTH_CUR PKG_STD.TLDATE; -- Текущий месяц (для расчетов) + DMONTH_START PKG_STD.TLDATE; -- Начало месяца (для расчетов) + DMONTH_END PKG_STD.TLDATE; -- Окончание месяца (для расчетов) + NMONTH_DAYS PKG_STD.TNUMBER; -- Количество дней месяца + NSTART PKG_STD.TNUMBER := 0; -- Позиция начала элемента + NEND PKG_STD.TNUMBER := 0; -- Позиция окончания элемента + NGROUP PKG_STD.TNUMBER; -- Рег. номер группы + NDUMMY PKG_STD.TNUMBER; -- Буфер для рег. номера + NMONTH PKG_STD.TNUMBER; -- Месяц даты + + /* Инициализация группы */ + procedure INIT_GROUP + ( + NIDENT in number, -- Идентификатор буфера + DDATE in date, -- Текущая обрабатываемая дата + NRN in out number -- Рег. номер группы + ) + is + NMONTH PKG_STD.TNUMBER; -- Месяц даты + begin + /* Считываем текущий месяц */ + NMONTH := D_MONTH(DDATE => DDATE); + /* Исходим от даты (формируем группу на начало каждого квартала) */ + case NMONTH + /* Первый квартал */ + when 1 then + /* Добавляем группу */ + CYCLOGRAM_BASE_INSERT(NIDENT => NIDENT, NTYPE => 1, SNAME => 'I группа', NRN => NRN); + /* Второй квартал */ + when 4 then + /* Добавляем группу */ + CYCLOGRAM_BASE_INSERT(NIDENT => NIDENT, NTYPE => 1, SNAME => 'II группа', NRN => NRN); + /* Третий квартал */ + when 7 then + /* Добавляем группу */ + CYCLOGRAM_BASE_INSERT(NIDENT => NIDENT, NTYPE => 1, SNAME => 'III группа', NRN => NRN); + /* Четвертый квартал */ + when 10 then + /* ДОбавляем группу */ + CYCLOGRAM_BASE_INSERT(NIDENT => NIDENT, NTYPE => 1, SNAME => 'IV группа', NRN => NRN); + else + null; + end case; + end INIT_GROUP; + begin + /* Удаляем старые данные из буфера */ + if (NIDENT is not null) then + CYCLOGRAM_BASE_CLEAN(NIDENT => NIDENT); + else + /* Илиформируем новый идентификатор, если не задан */ + NIDENT := GEN_IDENT(); + end if; + /* Фиксируем текущий год */ + NYEAR := EXTRACT(year from sysdate); + /* Фиксируем дату начала циклограммы */ + DCYCLOGRAM_START := TO_DATE('01.01.' || NYEAR, 'dd.mm.yyyy'); + /* Добавляем колонки и групповые задачи (месяцы года) */ + for I in 0 .. 11 + loop + /* Рассчитываем текущий месяц */ + DMONTH_CUR := ADD_MONTHS(DCYCLOGRAM_START, I); + /* Считываем первый и последний день месяца */ + P_FIRST_LAST_DAY(DCALCDATE => DMONTH_CUR, DBGNDATE => DMONTH_START, DENDDATE => DMONTH_END); + /* Рассчитываем количество дней месяца */ + NMONTH_DAYS := DMONTH_END - DMONTH_START + 1; + /* Рассчитываем позицию окончания элемента */ + NEND := NSTART + (NMONTH_DAYS * NCG_MULTIPLIER); + /* Определяем номер месяца */ + NMONTH := D_MONTH(DDATE => DMONTH_CUR); + /* Добавляем колонку в таблицу */ + CYCLOGRAM_BASE_INSERT(NIDENT => NIDENT, + NTYPE => 0, + SNAME => TO_CHAR(NMONTH), + NPOS_START => NSTART, + NPOS_END => NEND, + NRN => NDUMMY); + /* Инициализируем группу */ + INIT_GROUP(NIDENT => NIDENT, DDATE => DMONTH_CUR, NRN => NGROUP); + /* Добавляем задачу */ + CYCLOGRAM_BASE_INSERT(NIDENT => NIDENT, + NTYPE => 2, + SNAME => 'Работа ' || TO_CHAR(I + 1), + NPOS_START => NSTART, + NPOS_END => NEND, + DDATE_FROM => DMONTH_START, + DDATE_TO => DMONTH_END, + NTASK_GROUP => NGROUP, + NRN => NDUMMY); + /* Если это февраль, май, август или ноябрь - добавляем особосбленную задачу */ + if (NMONTH in (2, 5, 8, 11)) then + /* Добавляем обособленную задачу */ + CYCLOGRAM_BASE_INSERT(NIDENT => NIDENT, + NTYPE => 2, + SNAME => 'Обособленная работа ' || NMONTH, + NPOS_START => NSTART, + NPOS_END => NEND, + DDATE_FROM => DMONTH_START, + DDATE_TO => DMONTH_END, + NRN => NDUMMY); + end if; + /* Рассчитываем начало следующего месяца */ + NSTART := NEND; + end loop; + end CYCLOGRAM_INIT; + + /* Сбор данных для отображения циклограммы */ + procedure CYCLOGRAM + ( + NIDENT in number, -- Идентификатор процесса + COUT out clob -- Сериализованные данные для циклограммы + ) + is + CG PKG_P8PANELS_VISUAL.TCYCLOGRAM; -- Описание циклограммы + RTASK PKG_P8PANELS_VISUAL.TCYCLOGRAM_TASK; -- Описание задачи циклограммы + NLINE_NUMB PKG_STD.TNUMBER := 0; -- Номер строки + NLINE_NUMB_TMP PKG_STD.TNUMBER := 0; -- Номер строки (буфер) + DTASK_DATE_START PKG_STD.TLDATE; -- Дата начала этапа + DTASK_DATE_END PKG_STD.TLDATE; -- Дата окончания этапа + NTASK_START PKG_STD.TNUMBER := 0; -- Позиция начала этапа + NTASK_END PKG_STD.TNUMBER := 0; -- Позиция окончания этапа + STASK_NAME PKG_STD.TSTRING; -- Наименование задачи + SCOLOR_WHITE PKG_STD.TSTRING := 'white'; -- Цвет - белый + SBG_TASK_COLOR_W_GRP PKG_STD.TSTRING := '#6bc982'; -- Цвет задачи с группой + SHL_TASK_COLOR_W_GRP PKG_STD.TSTRING := '#7dd592'; -- Цвет наведения задачи с группой + SBG_TASK_COLOR_WO_GRP PKG_STD.TSTRING := '#e36d6d'; -- Цвет задачи без группы + STEXT_COLOR_TASK_WO_GRP PKG_STD.TSTRING := '#e5e5e5'; -- Цвет текста задачи без группы + SBG_TASK_COLOR_GRP PKG_STD.TSTRING := 'cadetblue'; -- Цвет групповой задачи + SHL_TASK_COLOR_GRP PKG_STD.TSTRING := '#6fadaf'; -- Цвет наведения групповой задачи + + /* Считывание значений группирующей задачи */ + procedure GROUP_TASK_GET + ( + NIDENT in number, -- Идентификатор процесса + NGROUP in number := null, -- Рег. номер группы + NFLAG_WO_GROUP in number := 0, -- Признак отбора задач без групп (0 - нет, 1 - да) + DTASK_DATE_START out date, -- Дата начала этапа + DTASK_DATE_END out date, -- Дата окончания этапа + NTASK_START out number, -- Позиция начала этапа + NTASK_END out number -- Позиция окончания этапа + ) + is + begin + /* Считываем начало и окончание этапа */ + begin + select min(T.DATE_FROM), + max(T.DATE_TO), + min(T.POS_START), + max(T.POS_END) + into DTASK_DATE_START, + DTASK_DATE_END, + NTASK_START, + NTASK_END + from P8PNL_SMPL_CYCLOGRAM T + where T.IDENT = NIDENT + and (((NFLAG_WO_GROUP = 1) and (T.TASK_GROUP is null)) or ((NFLAG_WO_GROUP = 0) and (T.TASK_GROUP is not null))) + and ((NGROUP is null) or ((NGROUP is not null) and (T.TASK_GROUP = NGROUP))) + and T.TYPE = 2; + end; + end GROUP_TASK_GET; + begin + /* Инициализируем циклограмму */ + CG := PKG_P8PANELS_VISUAL.TCYCLOGRAM_MAKE(STITLE => 'Задачи на ' || TO_CHAR(EXTRACT(year from sysdate)) || ' год'); + /* Добавляем атрибуты */ + PKG_P8PANELS_VISUAL.TCYCLOGRAM_ADD_TASK_ATTR(RCYCLOGRAM => CG, + SNAME => 'ddate_start', + SCAPTION => 'Дата начала', + BVISIBLE => true, + BCLEAR => true); + PKG_P8PANELS_VISUAL.TCYCLOGRAM_ADD_TASK_ATTR(RCYCLOGRAM => CG, + SNAME => 'ddate_end', + SCAPTION => 'Дата окончания', + BVISIBLE => true); + PKG_P8PANELS_VISUAL.TCYCLOGRAM_ADD_TASK_ATTR(RCYCLOGRAM => CG, + SNAME => 'type', + SCAPTION => 'Тип', + BVISIBLE => false); + /* Обходим колонки */ + for CLMN in (select T.NAME, + T.POS_START, + T.POS_END + from P8PNL_SMPL_CYCLOGRAM T + where T.IDENT = NIDENT + and T.TYPE = 0) + loop + /* Добавляем колонку */ + PKG_P8PANELS_VISUAL.TCYCLOGRAM_ADD_COLUMN(RCYCLOGRAM => CG, + SNAME => CLMN.NAME, + NSTART => CLMN.POS_START, + NEND => CLMN.POS_END); + end loop; + /* Считываем значения для задач проекта */ + GROUP_TASK_GET(NIDENT => NIDENT, + NFLAG_WO_GROUP => 0, + DTASK_DATE_START => DTASK_DATE_START, + DTASK_DATE_END => DTASK_DATE_END, + NTASK_START => NTASK_START, + NTASK_END => NTASK_END); + /* Формируем задачу (этап) */ + RTASK := PKG_P8PANELS_VISUAL.TCYCLOGRAM_TASK_MAKE(NRN => 1, + SCAPTION => 'Задачи проекта', + SNAME => 'Задачи проекта', + NLINE_NUMB => NLINE_NUMB, + NSTART => NTASK_START, + NEND => NTASK_END, + SBG_COLOR => SCOLOR_WHITE); + /* Добавляем атрибуты */ + PKG_P8PANELS_VISUAL.TCYCLOGRAM_TASK_ADD_ATTR_VAL(RCYCLOGRAM => CG, + RTASK => RTASK, + SNAME => 'ddate_start', + SVALUE => PKG_XCONVERT.DATE_TO_XML(DVALUE => DTASK_DATE_START), + BCLEAR => true); + PKG_P8PANELS_VISUAL.TCYCLOGRAM_TASK_ADD_ATTR_VAL(RCYCLOGRAM => CG, + RTASK => RTASK, + SNAME => 'ddate_end', + SVALUE => PKG_XCONVERT.DATE_TO_XML(DVALUE => DTASK_DATE_END)); + PKG_P8PANELS_VISUAL.TCYCLOGRAM_TASK_ADD_ATTR_VAL(RCYCLOGRAM => CG, RTASK => RTASK, SNAME => 'type', SVALUE => 0); + /* Добавляем задачу в циклограмму */ + PKG_P8PANELS_VISUAL.TCYCLOGRAM_ADD_TASK(RCYCLOGRAM => CG, RTASK => RTASK); + /* Указываем следующую строку */ + NLINE_NUMB := NLINE_NUMB + 1; + /* Обходим группы */ + for GRP in (select T.RN, + T.NAME, + ROWNUM RNUM + from P8PNL_SMPL_CYCLOGRAM T + where T.IDENT = NIDENT + and T.TYPE = 1 + order by T.RN asc) + loop + /* Если это вторая группа - сохраним номер строки */ + if (GRP.RNUM = 2) then + NLINE_NUMB_TMP := NLINE_NUMB; + end if; + /* Если это третья группа - вернемся на уровень второй группы */ + if (GRP.RNUM = 3) then + NLINE_NUMB := NLINE_NUMB_TMP; + end if; + /* Добавляем группу */ + PKG_P8PANELS_VISUAL.TCYCLOGRAM_ADD_GROUP(RCYCLOGRAM => CG, + SNAME => GRP.NAME, + NHEADER_HEIGHT => 30, + NHEADER_WIDTH => 200); + /* Считываем значения этапа группы */ + GROUP_TASK_GET(NIDENT => NIDENT, + NGROUP => GRP.RN, + DTASK_DATE_START => DTASK_DATE_START, + DTASK_DATE_END => DTASK_DATE_END, + NTASK_START => NTASK_START, + NTASK_END => NTASK_END); + /* Формируем задачу (этап) */ + RTASK := PKG_P8PANELS_VISUAL.TCYCLOGRAM_TASK_MAKE(NRN => GRP.RN, + SCAPTION => 'Этап ' || TO_CHAR(GRP.RNUM), + SNAME => 'Этап ' || TO_CHAR(GRP.RNUM), + NLINE_NUMB => NLINE_NUMB, + NSTART => NTASK_START, + NEND => NTASK_END, + SBG_COLOR => SBG_TASK_COLOR_GRP, + STEXT_COLOR => SCOLOR_WHITE, + SHIGHLIGHT_COLOR => SHL_TASK_COLOR_GRP); + /* Добавляем атрибуты */ + PKG_P8PANELS_VISUAL.TCYCLOGRAM_TASK_ADD_ATTR_VAL(RCYCLOGRAM => CG, + RTASK => RTASK, + SNAME => 'ddate_start', + SVALUE => PKG_XCONVERT.DATE_TO_XML(DVALUE => DTASK_DATE_START), + BCLEAR => true); + PKG_P8PANELS_VISUAL.TCYCLOGRAM_TASK_ADD_ATTR_VAL(RCYCLOGRAM => CG, + RTASK => RTASK, + SNAME => 'ddate_end', + SVALUE => PKG_XCONVERT.DATE_TO_XML(DVALUE => DTASK_DATE_END)); + PKG_P8PANELS_VISUAL.TCYCLOGRAM_TASK_ADD_ATTR_VAL(RCYCLOGRAM => CG, RTASK => RTASK, SNAME => 'type', SVALUE => 1); + /* Добавляем задачу в циклограмму */ + PKG_P8PANELS_VISUAL.TCYCLOGRAM_ADD_TASK(RCYCLOGRAM => CG, RTASK => RTASK); + /* Обходим задачи группы */ + for TASK in (select T.RN, + T.NAME, + T.POS_START, + T.POS_END, + T.DATE_FROM, + T.DATE_TO, + ROWNUM RNUM + from P8PNL_SMPL_CYCLOGRAM T + where T.IDENT = NIDENT + and T.TYPE = 2 + and T.TASK_GROUP = GRP.RN) + loop + /* Указываем следующую строку */ + NLINE_NUMB := NLINE_NUMB + 1; + /* Формируем наименование задачи */ + STASK_NAME := 'Работа ' || TO_CHAR(TASK.RNUM) || ' этапа ' || TO_CHAR(GRP.RNUM); + /* Формируем задачу */ + RTASK := PKG_P8PANELS_VISUAL.TCYCLOGRAM_TASK_MAKE(NRN => TASK.RN, + SCAPTION => STASK_NAME, + SNAME => STASK_NAME, + NLINE_NUMB => NLINE_NUMB, + NSTART => TASK.POS_START, + NEND => TASK.POS_END, + SGROUP => GRP.NAME, + SBG_COLOR => SBG_TASK_COLOR_W_GRP, + STEXT_COLOR => SCOLOR_WHITE, + SHIGHLIGHT_COLOR => SHL_TASK_COLOR_W_GRP); + /* Добавляем атрибуты */ + PKG_P8PANELS_VISUAL.TCYCLOGRAM_TASK_ADD_ATTR_VAL(RCYCLOGRAM => CG, + RTASK => RTASK, + SNAME => 'ddate_start', + SVALUE => PKG_XCONVERT.DATE_TO_XML(DVALUE => TASK.DATE_FROM), + BCLEAR => true); + PKG_P8PANELS_VISUAL.TCYCLOGRAM_TASK_ADD_ATTR_VAL(RCYCLOGRAM => CG, + RTASK => RTASK, + SNAME => 'ddate_end', + SVALUE => PKG_XCONVERT.DATE_TO_XML(DVALUE => TASK.DATE_TO)); + PKG_P8PANELS_VISUAL.TCYCLOGRAM_TASK_ADD_ATTR_VAL(RCYCLOGRAM => CG, + RTASK => RTASK, + SNAME => 'type', + SVALUE => 2); + /* Добавляем задачу в циклограмму */ + PKG_P8PANELS_VISUAL.TCYCLOGRAM_ADD_TASK(RCYCLOGRAM => CG, RTASK => RTASK); + end loop; + /* Указываем следующую строку */ + NLINE_NUMB := NLINE_NUMB + 1; + end loop; + /* Указываем следующую строку */ + NLINE_NUMB := NLINE_NUMB + 1; + /* Считываем значения для обособленных задач */ + GROUP_TASK_GET(NIDENT => NIDENT, + NFLAG_WO_GROUP => 1, + DTASK_DATE_START => DTASK_DATE_START, + DTASK_DATE_END => DTASK_DATE_END, + NTASK_START => NTASK_START, + NTASK_END => NTASK_END); + /* Формируем задачу (этап) */ + RTASK := PKG_P8PANELS_VISUAL.TCYCLOGRAM_TASK_MAKE(NRN => 1, + SCAPTION => 'Обособленные задачи', + SNAME => 'Обособленные задачи', + NLINE_NUMB => NLINE_NUMB, + NSTART => NTASK_START, + NEND => NTASK_END, + SBG_COLOR => SCOLOR_WHITE); + /* Добавляем атрибуты */ + PKG_P8PANELS_VISUAL.TCYCLOGRAM_TASK_ADD_ATTR_VAL(RCYCLOGRAM => CG, + RTASK => RTASK, + SNAME => 'ddate_start', + SVALUE => PKG_XCONVERT.DATE_TO_XML(DVALUE => DTASK_DATE_START), + BCLEAR => true); + PKG_P8PANELS_VISUAL.TCYCLOGRAM_TASK_ADD_ATTR_VAL(RCYCLOGRAM => CG, + RTASK => RTASK, + SNAME => 'ddate_end', + SVALUE => PKG_XCONVERT.DATE_TO_XML(DVALUE => DTASK_DATE_END)); + PKG_P8PANELS_VISUAL.TCYCLOGRAM_TASK_ADD_ATTR_VAL(RCYCLOGRAM => CG, RTASK => RTASK, SNAME => 'type', SVALUE => 0); + /* Добавляем задачу в циклограмму */ + PKG_P8PANELS_VISUAL.TCYCLOGRAM_ADD_TASK(RCYCLOGRAM => CG, RTASK => RTASK); + /* Указываем следующую строку */ + NLINE_NUMB := NLINE_NUMB + 1; + /* Цикл по обособленным задачам */ + for REC in (select T.RN, + T.NAME, + T.POS_START, + T.POS_END, + T.DATE_FROM, + T.DATE_TO, + ROWNUM RNUM + from P8PNL_SMPL_CYCLOGRAM T + where T.IDENT = NIDENT + and T.TYPE = 2 + and T.TASK_GROUP is null) + loop + /* Формируем наименование задачи */ + STASK_NAME := 'Работа ' || TO_CHAR(REC.RNUM) || ' без этапа '; + /* Формируем задачу */ + RTASK := PKG_P8PANELS_VISUAL.TCYCLOGRAM_TASK_MAKE(NRN => REC.RN, + SCAPTION => STASK_NAME, + SNAME => STASK_NAME, + NLINE_NUMB => NLINE_NUMB, + NSTART => REC.POS_START, + NEND => REC.POS_END, + SBG_COLOR => SBG_TASK_COLOR_WO_GRP, + STEXT_COLOR => STEXT_COLOR_TASK_WO_GRP); + /* Добавляем атрибуты */ + PKG_P8PANELS_VISUAL.TCYCLOGRAM_TASK_ADD_ATTR_VAL(RCYCLOGRAM => CG, + RTASK => RTASK, + SNAME => 'ddate_start', + SVALUE => PKG_XCONVERT.DATE_TO_XML(DVALUE => REC.DATE_FROM), + BCLEAR => true); + PKG_P8PANELS_VISUAL.TCYCLOGRAM_TASK_ADD_ATTR_VAL(RCYCLOGRAM => CG, + RTASK => RTASK, + SNAME => 'ddate_end', + SVALUE => PKG_XCONVERT.DATE_TO_XML(DVALUE => REC.DATE_TO)); + PKG_P8PANELS_VISUAL.TCYCLOGRAM_TASK_ADD_ATTR_VAL(RCYCLOGRAM => CG, RTASK => RTASK, SNAME => 'type', SVALUE => 2); + /* Добавляем задачу в циклограмму */ + PKG_P8PANELS_VISUAL.TCYCLOGRAM_ADD_TASK(RCYCLOGRAM => CG, RTASK => RTASK); + end loop; + /* Формируем список */ + COUT := PKG_P8PANELS_VISUAL.TCYCLOGRAM_TO_XML(RCYCLOGRAM => CG); + end CYCLOGRAM; + + /* Изменение задачи циклограммы */ + procedure CYCLOGRAM_TASK_MODIFY + ( + NIDENT in number, -- Идентификатор буфера + NRN in number, -- Рег. номер записи + SDATE_FROM in varchar2, -- Дата начала (в строковом представлении) + SDATE_TO in varchar2 -- Дата окончания (в строковом представлении) + ) + is + DDATE_FROM PKG_STD.TLDATE; -- Дата начала + DDATE_TO PKG_STD.TLDATE; -- Дата окончания + NYEAR PKG_STD.TNUMBER; -- Текущий год + DCYCLOGRAM_START PKG_STD.TLDATE; -- Дата начала циклограммы + NSTART PKG_STD.TNUMBER; -- Позиция начала элемента + NEND PKG_STD.TNUMBER; -- Позиция окончания элемента + begin + /* Фиксируем текущий год */ + NYEAR := EXTRACT(year from sysdate); + /* Переводим даты */ + DDATE_FROM := TO_DATE(SDATE_FROM, 'dd.mm.yyyy'); + DDATE_TO := TO_DATE(SDATE_TO, 'dd.mm.yyyy'); + /* Если дата начала выходит за границы года */ + if (D_YEAR(DDATE => DDATE_FROM) <> NYEAR) then + P_EXCEPTION(0, + 'Дата начала задачи выходит за границы текущего года (%s).', + NYEAR); + end if; + /* Если дата окончания выходит за границы года */ + if (D_YEAR(DDATE => DDATE_TO) <> NYEAR) then + P_EXCEPTION(0, + 'Дата окончания задачи выходит за границы текущего года (%s).', + NYEAR); + end if; + /* Дата окончания не может быть меньше даты начала */ + if (DDATE_TO < DDATE_FROM) then + P_EXCEPTION(0, 'Дата окончания не может быть меньше даты начала.'); + end if; + /* Фиксируем дату начала циклограммы */ + DCYCLOGRAM_START := TO_DATE('01.01.' || NYEAR, 'dd.mm.yyyy'); + /* Рассчитываем новую позицию начала */ + NSTART := (DDATE_FROM - DCYCLOGRAM_START) * NCG_MULTIPLIER; + /* Рассчитываем новую позицию окончания */ + NEND := NSTART + ((DDATE_TO - DDATE_FROM + 1) * NCG_MULTIPLIER); + /* Считываем запись */ + for REC in (select T.* + from P8PNL_SMPL_CYCLOGRAM T + where T.RN = NRN + and T.IDENT = NIDENT) + loop + /* Обновляем запись циклограммы */ + CYCLOGRAM_BASE_UPDATE(NIDENT => REC.IDENT, + NRN => REC.RN, + NTYPE => REC.TYPE, + SNAME => REC.NAME, + NPOS_START => NSTART, + NPOS_END => NEND, + DDATE_FROM => DDATE_FROM, + DDATE_TO => DDATE_TO, + NTASK_GROUP => REC.TASK_GROUP); + end loop; + end CYCLOGRAM_TASK_MODIFY; end PKG_P8PANELS_SAMPLES; / diff --git a/docs/img/72.png b/docs/img/72.png new file mode 100644 index 0000000000000000000000000000000000000000..2235039dc6c9edda2557a682e61ecfb227ef834a GIT binary patch literal 44588 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 literal 0 HcmV?d00001 diff --git a/docs/img/73.png b/docs/img/73.png new file mode 100644 index 0000000000000000000000000000000000000000..9a4cacfb88e65b1d566829a1e71b6f8cbfbfa1ca GIT binary patch literal 59174 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

_(zY9gS{P+(iR?|q_zWAj&_S8!4Ob` zgqOC1`hNxZ!S^Xdq3Ssi+gczUNr(J(fTEu-U~GF#&j!G#0#G+~v0m{mZVcxtf=U^P zgaZEZA>0E2sSQxx6Tn1J+1JS#!TEGGc1tm;@A4hT80-C2(SX22Yb(y?R zPdElS2U*?z394Bs*d19AN9q9sQ;FxhMK9Fi-?Kn;W}m!QhdqIgl$3UUxXAn10aP$Qs_k4{ROk4c(_ayj_;_*U9n z0!znNN9u#>>$b;*Wd&gZ+lw_|^lX0G+t$pkCP5w2^b3n^>-e|05Ix9$?%X@x zQo~7WXnSfjaje8J_Y7Y`9=2<(TI^s9Q)bLVB zWw2a8Y#prfFbTMzY?JInif{$0WoMObHZS;hkLEDBAD`KOByX{h0}LtzwkFioYH3@y zVjj$H%u>Q)t~bkJ)=sJy%pQ2-^Av3K_nfU#mB5`g(P$Pl^#LWAc)%u-iHS)XE|H`T zT*Ydqzc#hBcubxx{rq2lMgAKhQPHlrZJ_S{dsRZ8w+Ij=>~+liaI_$Ce@%NK z;AV?wM=9{(^E;5-s22PejMY&hlGqsH)wv z8p9d!M}-wL8!-Qd`><>6j4^KoX8-9y&nWWj#$>Xgj!p!lJd59v5_aVr{d@y^(7E7& z?|vwvP|g6XQRpqGhZvfPM-*zixs^bAr?Rk;dHLP@PpcD9v73;4bH7_N#IzR!wpT4O zw9Q7)U#7WnwZvIhLcYD&>fK=HKfG5njQH)_Hz~@EKtTF-;!(3`<_nGZ%Wzv;*<~`^ zEUo{rhQRsFeIMuZI1%`Blm5%hWq>78-Ce zw8lEam@5TL%3G^cqeDe)C}}G`9Asmg>n(JL8wMXuLPid*Ks&P=_p3#InIQ48oBHEVwm z+9F&(Smi&zx4W<>)9?g$zCCPOxo_H_&h)-?GvLIqpjb-kzpYDwvHxeOkI;qM@PTSzhXccxB`0SAAk5 zNzM-qAEOdvZuJL10ushxj5wK4a5MaoC`o-5T9CrXakfcrobP~wF6YCGld{1_OlmRf zzyLE`6|w5dT;h zI%_=yX3of-8Cd&V-zIQvkJ4zYpVs^(CIA|Zo@w9ll0pN>;6G;?-Tan|&82b8YKzXP zsgs$`s(?RYPgM&@wz?q@rCV21`b?DE1sCkKhk{Q<%C~`ezzniec;b9jf=9_Ekcgmh0I=EfFQE|gF5CJubHX8OC$Fc-`q*egjR9&+ z?i<5_H2Z&{-2ZN|wWgxzSXEV3MH@UQDQ3Pu39}QOZ_Y=XAda)lky(Bu50FbUx3Vkd z5+pJBC)5)GY7MK~s|N(t&WtB@%x4|{fajz@gWw5Q5}?zeP^O=$PVcK7)dg7dUc~`O z(0}{0+)t9~^wA^i(t0;pLS>4*s)1B4@s}ocbgreNSe{o#+wH0gryPrsyvnau!*z`~ z)rMhPX`biviksI4iw8K|#v@)_m{ruh!1#w0AX2iTphtI>^v8do16c5P2G5&Gi?oFTC~r}Bapj}xTswhR8+yV`zMfB)g0u8#!Od$1Kj95s;5`o==esKghVV}&)%RqD5H z9lG6)7A%XZ5^Z1`sj<(Myzeuj<0=;vaJ5C}R#i3;Xkt-v6jBVw`$r1^V`U4~Z~Fm$ zQWYJ4-p9XCB|uRf(D8rXo^eAD7O?HD7Z*C$o-%lHt~I~X2d2W>LUvdC zqOGA@e<3}FMiX@Wp{)MjGig%mchozHinfS4mv~9<2q9IkS(}%yB(C1{5fuyi?mb=w zAG+|5{Me}xkxh;6!860lvbwR8-|*s7yr9F6}n#6sx-D8`F^5#Wy_q;=IM{7t_Q@Oc3%vx!ScBq)ey;;b3M~79WVh0)?|+WQoX_;MQ!2q09BzfAU=R`t6U79-53fhkH?b5wi!;VL zru}!|Pl(73H$24$q4BJioX&_e(7HISMH#xNH=BAmdR6cN+n>`i5G6{5J8# zx;IfTbBOR9mrJTme(A(I<2n7|+}1&lY1TwZ6`Rhk#29wr}{eaVJ{GOWM(1Ox+HZxVzNtxd^gJGyNRfmgRG0kH#acImd?Z&2ONCgge>(UsGzSILg z4FplX;&l03#k1iRU9MUtVa_C(b?=JgJV4CknXud(;&i&m;Ap7JpV*%soXr{)ajHM; zBmCOu4i-S=ZhqI(D0z3c;f@gckEKM zdA(*nn&MkZjg=8!JdA$u_m>6dy$bV6u05lzqc}G-!>Y%HS9$Sqz3WWeqxcB9UbB}< zJejKZ$1tw3pE|rADrHIJ&Q;=AVObc|afY(!nmH@h2%}7|umaEWfs@XqD^~Fx^;+)| zAHkvxIrVRP;IUg$R8wbuEiuct^K=f@d(I{xkXY!uhBqNj>zEs+BoO+b2tj$UcrLB4;6={JwfY1px~)7bOR z>|W@~dKyegqZei8rHEIeM`Jc9l`jtAJ-M^;F|!>U|Ee{?+BLewO6YMK>TvlvmZE$- zV;u4-@})ZAB^`p5z9-sc3OOIOf1Lq^!+W42OwCUufq<9Pw9T%a8OhHpZeo} z!Y%(s+;I`geQ2BCW&yog6!5ix1d#N)y5XwvKNt0%PM&|(x24X4fQEtg3q^CgTMJ&m z+G`g+;9RW^o)qv8TWaH9x@agTm!^2v%uOIvI(PjaQ%aDzP~VK7E$jlRe&;mme|!)g z#6cANjeTLS4xpyG)5GQSfS1}9h?WC0Kx5$06u~VBCtcwJKXw%fZqz-YXprIq6!5$} zJcKyFsf~psj|#T{#d{9~RUM-RK+I@?H)t49kiP;jjn2=?{5Raq{1-n!+SyV^RJlf_ zkO9=M>zkO&7JxJa3UoNM%e$r4)R;0TY!`#)%nwC$6}*V|zK5on&G_99?+IoS|+dQG6> za|QT)z*~UWOpT!JF)q{xCPTZ<3>9Zy@EQe}`frSJciUKNfpr-VVxZ9cn$YLEaU&uM zIb}?i1G;J&B9Yp76RzNpvIBh038@>wgnT)2GgL&{wzVh9u7a*rhikLri5Q5?senq( zr;`7*u*MonbC5!Syr`lVLik&T=02Gwklx^Zl`ah~H%paXg@x6!rRkkm!1r-yesqht zq|0j&G!qTNx1Bq{4ei&_o$bCg%^D$!%cS}=9V2TaHXv9EoI4b*BtSdr zac%VyqN1b6W58QexCu#HoP^)ut;#h}KKSD14xM=M##0gpEUSkvKPp20#+bmpX<4Hk zl+0FFYTD?(W=Vj%p8xMF7`D9{Lzllvng1vzp|G4@ zKd0#u$-zv{yEgqRE!x;>yZHFLvI^@`31T;&tenNPI-E}yF8&TV{qnfZ_~F`U5k(J? z2z~RaYxx?t-faN^OUMPXoL)hsw5YhyVhVFK*?ld0WidV>HuL!skOp+umH)+uhrA>E#t~H zNY{wf*>2LJ*hg!@#Cr0lhJ$#94tca0KKhtnXD0{3KuBFS6dYE5yWDZy z0HP%CfpOdMuH1Pj59F`qmY1)t9)S=@dCn++L`j0jgNAV_%sBfX}00)U%k z9!vr*SU4l=#CvNX48Xw1y-<3^ZIg0GdlbB|yjPzVGDaouZBOo_+@Yr~Uk5p8&Vt}0 z_fv%_CLhrO*vVz27y@nwD3Ub?#2xH;JV-DyswjY9WLT{)STEu;Aru)8m~)%D z^ZRc=+~)}wHD3bM+0=z=sC^gf^eg!3IgVTDUt)YLrhFUo*UL+r_)9I%4jUiBdM{c- zDFS4zSr$!@+*w%p^)Ps3wkEX3*&|4u6IGK*U66VV$TBMQV8CQ@ltU&15_4$$zi2w+ukHu%`KegK1hM zUnmij2uUKgmp>u8vefx5UUcPb`PLK}{qp5#p${x0V5duAClc~&VPH5_zqL8Hq*y?m zU*zFY1~hv*K%5umJ`MA%NzLs_IQFK1*ji}U(Y3Nlt>($i$ar7Hm0u6=W%Q&KFtTYR zMzakx_IhlAjJl}>fEnSyZZRoM4<|?f_hHT_;d?(UlOxwyY?Gg@#eGq4q|4n&R^Rmr zdP*K?fA}-Rh!JrSq&B{%fri{%ZTU(s+q}-gs}oXRYFZK%g5`LBCD+t&rPlOxXv?i~ zF1?K^>?G~JCHld+e!QUpp)q$4e1NvT$B(HiGHe{TKyvT^Eme)>neGxB0vZLRPI-W# zuF!)lK45o3eZG0p9spSyqi(<z#95VI0W7qw8Ny1`b@VEa-F`NO4dEz{>lDb! zU9K^CZ8h?O`F(4WoQX@_Mpo$_kO0^LPfvyR~&3AXU%q%WNo**y|D=}&S~TVw&TNfwuFkSAE^DyuYLegB8dWaC0k`a)j>Avwm~%| zC_!&5;qHN#9FcOuo)#lN8YPh+Do2)p1EHKxKe<#MJMyN_D%I7_a_rIB)QSuJ{$)QC zUCu^7d5)4pbNpO^F&S(3s=NI9py*$Xo{My{zkE(SQULH}VPR=U0?berZg4V` ziaU9u)fWBz?R?LJGjy<{>{CBfp5UxYjNYd;o-<@FxK!&E%7~p@r(< zRiW%b4Nn0_?Dr1`xniyI#lb`Y$9Nl$dmDEoF?=R|mx-6vr%|79*XtY1X*bLR5O zbm-T#Y%Tr5&~WDVFVPXe7NZE(L zE6#f?eN)*1u4AwHcd)A0u0v&WsM2|D(gOmFYvWykYdBAtUj*(1)}|C*h;6 z#h-+)ZTBM%oR&A;{yaJv_9$QD)a>@;W9+krftU~y$<0>%fyshv#i|ry)9|Prt)F7E zoYSKQL2EMx+cseJ88_t|Dy-Ob&Vb^5YDT%9_GSfb#0I(HFZ-Bz6cC@9u{eN)y8S@u z%?^IWjcNm9ekQu}8fd96F=cnHLVCg#SP{9)z@q!vKGVjq3_qFVhaQ_zh0@X|-_pso zgJQ5&A8`RZysF8_2)L5Hq^{Vyy`Bqu35txd~Blklqj=S->EAS zg`w-cb0j>kan%mInN(Why-hggdj&GX?yg$w5q;VPLKfGU)XOGMf>FZ(WtUGeIXcEb z-s52AfjfrgOEB=HK}fLY@ZmX=M$0L-8$HxQ^4{N57|VO5#7IP2;L_Guzwr0Ti^fl_ z4gIlXplU&#n+XBYN@|eH?rjXv>ez$1-rg(59MkJ9PNHwYUo@_z7jUFJX;KwxWivKp z89D}9$MnBLs*1JC53=(r5kzvc~%S|s=Pu#dfPd?;#b1IlGAGb$0uf6@4W zgAFkOHk;tmL@G&71@rp3uv7B>m7>Mpfms>_N%f$;vbQs|3AWk`Zz1PtLfh;r*i@z= z6P~WKqvZtf{Ehi;jK?PWvc(d@2%NST*;*PK8+^VzI*E3@2y^WsEz^O`f6eB!H5zr~ zMo7E$>90S!BPoxsU-&|OminF%C^Ybtl*iL~EZ=LJiWJ(yyq4xvjEr)FCjyEimA#Z&ZpkiyW^}eUyJOt z^xK>AF-1GOReU5q+;(G4ikRDmSLZI~lymjvn9(=% z|2W~>`pZg1Pg*+xavU`+Pg?_4x1-W+Oe|>EAEXjjb92}X3F1SXi3GMBZ+yr0YJL!9xLIAuskHr0va)42XX$5PLpCv#G$hgp+h9dFKWZI$8%c|Wre zj@o^{7snbqF*jW{G1l*E8Jzca@Ke@H(nX(u7h*=rWz+B7Y<YWc; z*;h;6ITRAVFtU|Ryg$^&DPv^Zpbyg{3Upx^K{InT)vxAn2DQsp<+-2hAo#H@>*Vy( zu3{8WdqT zjujwwFT_ITs=N3+z89<8sQ~zj$^-^0O2oL`ZC|`YLaCVZsAC(KjENxwFi>fHjYwD7 zp^NVEzcG7MunWONh>p4p)7@094lC$L+i5BLJI|K?x(!BKV?+}%&f{73n*{R_`r9g` zCSS=T_OFT>a+~s`j`tc`?iJ}9@bV+j&w(*)Zg*`#$HybMncp!mE`}rW`9XqghwSj1 zO~_?dn0Y+!kyr!jBv~PcucDiCGAd9p>a$i_&sq@)A5RUp4e2ndAeD~UEl$5tnvQ=N zk&170c8>V%4?E_RM3a5GxXVWY+xWhsWIe;*=VrPA7#HqL!ZYgM-w<(9(9eJWzWeIU zn9hiZ=vP{~72x_h&-v-SdR>%;Zn&RFZ(zQ}8=c&nM@g>(C*I|d;)Z7@v%D=kH25i| zc%8BRl9|k%@(Bh3y}c|Eat=}v%?$5%tu*@3mX2EO=)>2HP^_x7>I6p3oBuSQ%`g7K z7axiplF`Mi890;rZT$3DUMsk!>F_W{Fku3&1@1j#O)||5ATZ#$DcWhkvIGu%+w^58 zM_8_5%X+gtUFXXjbn9ij|CFN{+v|xt-ffy9Q867UHsTE_=~;z0T!~L^g+=oZSGU1J|y`rjeVvddaO}(dIUpmq-)%_WYK6Y}CUW;^K+! zv2VW*g`*T@0u(UxpE$E=13VtkWgm4&#C=q0(w?;nplp%8$x0pya*q-DJ-)kRN+|iv zp8(|1N1pee-+lO8q?G6lo)=u|n)9{t?A^=LHY}uQPLO{JdYlV~?C(VkTKCU>&wwY4p49pSkbc?<*M z^YxhBPQ~eE{uby)l*OxPGpPtHQai&fwsSPgJ?m`>HlN zn=r7OmXzq&pS;dW&GX;M&bNAU?w6v-Z;q>0kVKwMv*yB_&0t<HK z^wd{vZkT+jl=!IYX7b3q#*C!ShUb|6FQla0pC-96G25xXx#R|Co_gB*p+ZHlSq_1t zfzN+u)63RdrLDR`oGLibta?k&pz%hA@%pHhP(b3TvQ5i z`hVfgE`Hgo@ZzCxk3tO-_7a=!xIY<`R5^X@G}`^pgM&hR`Gtj}zST1aITs2W^N|dAkZ{zKIhfr#NDsEf>#T2LR|Uv#0jn7Q~MEQ6cjnvj{G9yyH8VtQXD!Q zjs@?p?GzN^Pp|!)2=`dur_k@ec$MDz*OW-1zWj^1{y%!VsWelelfvL38RrXMQFMs^ zn~&Ez=lziVs<@+Lzs=ru0?zaM$&>vnpA>9dHUiV-YTT=F<&7-p7lHNdVcY#@P0Fkc z*=;;q(*8f*-aD$Pb?Y0An=L2`*bt@aw$KD@w9sWM0zwc3q(%g!gb+$-fdmy1MFEwj zw1AY*L3&Nxuo0=DCXfW!fRqr5Ktf3%+{HfUJ?DI9+&jj1?;ZE9KZHS+S#!;2mftg< zSuUrtA`hypSi?#}5Wo2g4B*|dRS1f~QqhJDN0FkmG?5UFzU)81eKX6C-CMWhEUl9q zIEyQ#_LGC*$cZ=F-s?bP$A%S6YH8`!NXPPgt{ggzpt*|dVw!t0 z`W}g-YxRrrk~RdIHg0or(1Y5Z&}t$jNFu_6Z-}}%t~G{XPoCXi)tY>n6yRCxR=*JT zaF7ELJxM+l;>9wxt8@(#kG?{!>dLTfydYSeTr7XD40}VMJbS%UHi(<_j4a!J`?}CMuW1b7RpT@zH%n-M7jilzUIZ%RIs%gm{EY ze}A*hA#8oU#y>8V;9O`TX(@#px(qM-FGAnzFYJ8n6cd#4z=_}N<`w83W%jeQi|P3V z`cstd%Wu!jZ#qCk528L8@W_Cb+yow7V(VFYC6%oOUM&G`h~pg zL3^?iHhe$@%{(V%t)Qy89&O^!sQVdn629~5nYO)vy#l+5$IiFHAzfU;%6cVV_C)64czjZ#xQr)_ z=G7jC_HERJvRm0|)je;ho0PGxno-!;s*cydBMnCRd+p+2knY~T8V;#x3moi|U{+&; z#6zDpqexeE?)vVnE%_Sl`40{K5y%`mAJ{$s$Gn@ZxnvSJ)t#k++0vy_XeZ`8_=D%Df;?vA?YW zy01@<$7^98MICP_RKv#3_$TAbV4+OCNkV^7{nxJ(MAK>u!(A=R@#^OSCbKp#l`vyOS6$Cfrx39M%bu|#%5i=N}YCN1`|O^ zyXx%Th)caw=N!t;YNgKf$KN!hI0^_VFL`~bb;Q$jV*GoBiQ5z8`(bS5UqMVEz<}s} z+PZl{7xDR7^q`=mH>70D;|RHSS9V2#y2&OKBe!zSe@@ekiU)8#tOmx3Cz1F2F&YHIS96cpc zw2Nn)L4ND@jaVFtcuCclui@al^G2BSs58`fA!o9eL|)!LB>iE!OU zX}|H%Dfc~Q494s%sBdqdD$5q!D-bG$Yrjd?;o>@FuCgxTteRISbG4gKPI?wYpp!^pp?TEeYkUfnXl+9jlhabAxFhW^>fp2Rf zNjA`k;7qsT^g*nuQ<+2e>Y3JsrJ+;88h)L}!n@-IMahpU+f}!i#X9|t@^!NZbOU|> zUJv^76B(Ei0CRT_p9IO7EZuX5%@-S0Wsyh&aeMNRtgy&|jV0K`AEqzkT|c<$XSkqV z!8~4LDkp(_-c5fX);IP1h+;XA%4p-@z$Dl39(|?VI-F^ICit-LiK!3t58W5&Ajk6?VjN_R*+pjNi;Vjpif_Oqll0Ylgg0BI zxP4K;Sld_Yy&6QQQY-mW1zs{yS*S}-9U9jeeWYTc+uT%=d4;_;uee)XBCH+%3rH@u zR~ne8IBm-d8jAufVE(mSa4Rwi7%bTaC>=`V|H2v1KlRj98GjEB@sa@bS!$ujCV?-Q zaRw|`;j36#P-fY*EgxvO6|fS>NfaV?dl_l~)_66g)Gaxg# zJpq&%xbMVGAwi0Cp!uVx0QnARK4kx{7^5I7dJ{lrB*@zlOl&MnW7v7 zCGL}!01TJtiycbt)_4TMd4qK4E|y8BHw#+c%4P68#Ybo8fRGV>U|eT>w{K$Wv&fQ2TLrSaIKp#3*xxdHqfXqsP%BZanQb4Zx zEwn>P?Ev*4s9AV_sShVE+)G-wlrE8P#;1BWyv6}=$8}J78fdflO8`yqd-|%g6O0^-fb`kqRGn}P ztf>hLOfGteMx(`lDZD`Q86fr9BzozWlpKV-cD$}7kFY|46&)1MTFW3lu25@?Q zUhr>s){#vup0E@K>g?Lfu#_lQ*;7hwYrOR9=5ksE55S&${}lQ&ReEvLzsHppBE{rX zWZs*~pBC(**A-unTzeVv&{U}9MX*52#r2EHfTFD5i<&{&2m9UWqW|&n$J5x0$@-463Am4b>nvfKeYU8(^{#$B z&+(41j+v|9f1_)5JUe@Tyu7%oT$~pU^iofV8`P{9PdF)csx$e4T-t*x0@YFf#IkU= zaFFipNK-chFt($~rYj{%R(88CY;Dluu*AkO!LF2B?b=$hcr#l+{_Tp(xtq#Pgl9&d z9asV=fy&-UC;l@3tb&JlWY|M&Uh#p{b0P3|W|w~m_{&z=8(BGko_0o71^dpS zd47uU0FNZUTid}7=GD6=Th1$}_nn-IhfrSBxuDEs96v0a#}E(c<HD)P}Q4Cy|7{QwRjujUA##Ix7u3q7l|Zb3e}v`J47(D~gG4YkKUm=cYQ$?@Is zVTG4JNryeh7GF?sxGWEmO_v=MTaEa#FI^L)PX}UL&MLSKAD?Q`+|IG8xaarvvi(V9 z^S#-_{)R$7PZ`I%XzBf%KX(BBL`nl1Ynf&0USJASml#HB*OiWC4-KsY%TG6%`StxG2lLMB~ubGu#w>}T9HPD(`9 z=}f;q^neHGO86}9G0%CYpO=0Z3Z=c6Db`EzY4&n=|LJd-Y!X#Ds|OA@lL-fSHl*@T z>wnEXLb4su5KCBu%7;X0Smy8Bx5km5Zh3SBckqkYT7SfKxpWvQS>}~Z&x#J~HZEYJ z1p-ffW?qf-N#TWkSnb$paP(B)VaXi!=m^vMa??=o=)sOK8`qrd)qFT}rr+UARYxC< zM)STXna^8&Bda8ydi|*IK9tgPvdvqr{(Rfavf;X|^l-z`r&)=fU(wPx7a}kJs z)d_I*!SsF3d{=fO;OoC-0zxN^LRu#lcoTQiE`^F!n*dI7;ci z7Q%8#<$?RT&m*A70i#4?K#EU`)%E**sW`EA%BbsuqnkSa@UZniIV6;R_M^FK9~N@Okm#^s+-+k z&b)1fH)p-5yD9`%uvZ$K84So7j9;%R*2}AU%*y_oOhAEwS}g0r)I4?~>s zbwzo|E8}+DrS(fX2Ti}>q(SqD3cwM_A(yY@nc&2SWcM zuoob(GiS&`+DIuu`m9vaV8~#|0R2O(JPQf2RS&ST2r4Zq3jXaEKwS&bW9shjt4nV& zlungB%gTAD6w>^_z9Oul^q69jv{_hI)wy&>IUSVHe=XN=I$TEUt6A^Uh&7j)uEL@R z_+rh-&QsA!c@I$q6}t!K?vt8z<4)f`1 zQCWYh2{{{-$s;#P?=Flt*K`f#OTxxS_;cmc z0(z5?_E}+uk)=}UmK_bCOv1mMpH~0N50LbP^K70~=-sfO@UilUfahII5We@12Y3N@o=x7+7W83b`a-lICXv zP9Z2whehr~fNUPoHr`v&!~4BObja8pLH-%YH{ALuI|K9Y*4`MV=|8`6nsFc0ciUkp zA<07VlR;O9tg%(tcWjtAK|ISo>oCa7o>YHBJyCyq0Ez=lp7nREqP0x8xq3*&3%_&) zA<(Oz|Ks&-J@iq(<E`oj{{E0Sr@-eFiL)hOKaK{{##V}JtWTllu0z8pNCYG z2+NBMRIHtnPtFOOnZ3R8P5tQKU?&4W+5Ggoe9H1r8EA3rtr;UNb&EpB!yzrw^|{*p z2SG>^>)yuPwHK($wFEg4K)+``@F((tkmCQNnT5G34|*+>3?tW)3UNbVU^tM7k}&E0 z(iLmvh2l$TW&2hGUmzNBdSywe;93-RFST;#%$kIri@%}O67Z6es8h0yh`n?g-QlU1> zC|pbShipA!l81y@PoxskHajS7Ac)-`NgZblEP`-f8oV$rl#lV{xqPaKl0SGi~$uvy;_pZzt z7)XpU1%m9XJe8q->BrAwwa;4gNW&YOMH$PQhbR)O zf(AF7V{~d~BC`GgqD3QA=6%!V`z@PG1akSbIwgLkFFrCf=wi+3eKP-tJ-o}9e|oom zdk`LTKJHYY)u&K146HWt?;da$`PKbviEr8clB z{+C@Dr@aJohGHJDU!Tb+myKB$E_@akc}q@9_XIxL+SJauoOfnQ{N+Bp7li;~CDgfa zDw%q1`R=&i3pT$Au$AcqlP}|p=y%aJA@cPKpr^6_GVkat0bx{UZZ?GQv+7>JKi1An zz=lVmjbfYi>@2UB8UKGsjOSBun~lWut<}gEI}(5kpBDrB3&(IxxYyuUXD_SrO;u z#^41UF0f5E%kHFWMrn2wWLGTQH3dCg=mc+G#>FnUOYCp^nMX0N&S=F-Dd}6Yl2wL2 zNu8aIdM*FvA1pDFaqGJ@Mmm$Pcj-UPd-8m@bXL|qzh8h{atE#2puD4?Ot<~WSo1wM z4Z2=MSixaXpH@ZhACY;z^PV9fUE*Ji`}4k<=C4aX3#=;VF9XLifZaAT>Ch9Ui0dcU++5RN9)Ns%Q zXqg)@*8oD=jGc8$TTKiO(E%W}iqBtP|3Nlm+->@u&F)_p_M=Fk%w$USz%stH|6BUD zl?I1}qZA2Bc)<|OZB}vGEqQUTbTkmQ9-FisgT~N~u9~2h_ZtltzS*G_jSB0Q?M0qO z1A#5A*uPK3n93%`-nEhOkm^CVm{-5?##R+L2aPHiZ%}A9d?UJ4ued$eY7=%*?FijK z%H_tlxO+!G-=xmsyek>rb^Xg>vmw+Q$mb?v8W*`KzgL!^x9&79*Vc|W7&}n%WmTM! z`Uw?ukH#fn;+5D+FePI`iBLjR~ zFV&rKiKwX4BNfSfl!UV<;U71Gh)+VbOUoD&C7nnrM_jR@oWBh^;X6g@#Ap zmTN_J!o&Vlw7dD$G(!~5igiO&NnMeeY_;XCzZsmG9{#a0%^#YtEUuHuFjv?wMFGzG zdTLzPMN_pg_rzmkBoUR^aW6aC<1We_>P_#DCG{-nz)@H0Q6d6EQ(26zSPI@yY2uk2yWV7*=J=gNt zCsgmUFG1UWD}Kg$ul-!z9arnL$}tbcf05fahrpGee;PJ^R_U_x&4+cl6L|O=1&2|u zN+P!$pz(Mpr`sfOTC1yMG{vi@;&SM)ufJDL#!HVg&i-*}&O&9hzdYd;0`j(t^Q}0W z2uP}zG=ADk!z;&Tka7nG<_4!uCpkQiQJ*@Ky8fM?+6TymUW5P>^5f!?4+GT^tG)I} ztS}%Z&AGihq*H}(DmQR^cZ1QTSlLBm#xqvFBywV+6Y9tRaQ32XSugrR$-O&@t$Tc0ejWBMJ`)??%oJFn6o-#qGWh%>z8B|yXo^6;0bo(DoE5Rk*X^9tv}B`x!|Ts9S`2ovkhFiE~ef+ z4DP%mIiPIgdQ*O)KwxwS4IswCjhRQ^FbK?zY@ ztpL7iFXjCyW7yzT@8>3tBo}s|b*ecdruwGcdPcCi>Oh{<&C#00zI>y2g?f&xSQxEw zhnzN>9#m6}p6n714T*=J(HW5VRQ21;ou29&5Sn+;j(vo>^=LpG{ME_FN=ntCr%h^s zu;HNxAizZdmzmQAH$vxSrQq(<-my}|k!q4;ePjQuqy`lU)A5_SN98ij?HJ*9d80K~ zP@PE`YNMA&?xteyMri%)GlvbFyxL>uHTgU@aG<-xYRYj(h^hbmU=^pN?zE4C-K zcuDM`390T;iG+XV#CpQx8Jd-ZUlRIfn83Mo#0off*E&;F%Dw6uPQrP5`l^{B5H@3~ zaRC4c0cN?l1e zXU}MGaw2x1I)zdit$B#h7VjY_#Fpmb9IH+>%~0+RpBlf4Ns4g{kK3IL0?c@f9h_!} z@Ci`)C?M)~BX6l(+Is*RXFF7if6k!P4|(r6WSfNVdIa|UoL}G3Qc|o;RO#AdT_}Ok zlG+y`s`X33Q|eSz)~_1g4K>cGCE@uUcV_qaA6&PWTYA!{&h0YkN|B~AAR44^%8Oq_ zlC`{h;lFA=pIW( zK}muwr@@)OmZvfIW0gnlyeg0$8v}g;Os=YV$%{{jS}@mujRxq8Ul#)}(1H)|3!9vC zYisf-g=cQ`HJ9&=GhnD=f>P7BXVtlfWim-WSu*=K{TrQR5>vy>7i7iGYPXNKSg7PX z0VwM4>wh~#rLzaCLr``chXAdvlyBbr^L!?FsMj`d>{!&_-}4mM#{T`wf9A3X|Lf>a zTkyc}7dN6LHI(e&duTrG84laK&2NcYPXyqYp*>%JdY$9vfjX7XK&*vv2|(Qc_lW!7 zOrOc5?QE~xP0#EC1t+Zw48}B&Ap}HLzBC7o2}d<31`WwR$zGUxH`qWd_K2v~uKX=l zruAb-l7>&7Jfl;q`g&~f%RipPU$*gXQLCKf>9*4HDq&3J+-iVRQOW=78ztfepU@r1 z-};j@Hm+7Wd58Kdj_gE_uDKNl7$>B>hB=S^ukV|Qplml)kB1^|Dr+ND!U|^uvB#uO zC#9;8{cved>RV~4URZ{Nw)ITx#E||KRsXbJ-Q}^5YU(cY8*m;FQ=xf=qBi%a^1Md( zX-&_PI4uUaIlKEwcl1f>H02N|zfQE#aSezw*jr{)on<~}%qzTcHuvR|a;rCNwa+mg zX&hS|mHrG_dD&e-`{LYVrSOHsqK4Hsoj-X6XZqu3Ltu6ZC+1J1F8L=yn$9JWq!A(t{7XB-Dl$XR4prP3Px4rUvFP zXoB8;63y+!0kw=A({%Ux*?{FU;(x8x!BK%(8mAi-RGmI(obk4!2Hcaj^M2X*we;bm z5@V8GDW-|>D7JzmJ%({vO0EabHJt1%wIs3cX3xBQ>z__Jo@B>q8ogUP{=VnQrjBQc z9QAsq-vX|X_RN2bG1YsCsO?e0*r+@Cj+(?<+oQC&W_SNE&y(ICVUdM{+eYp%p!)-q zuaa2^n?52oR^1u!qWO89`?VKuE8WDpM4}CVeq4#7^s3y%M z0C6YiIEs4~Hs(oc2#Ku5|LBZCvQC@3Xr4%G1zO_)ky4YzC={i&TRdPpwL{Go(8Ya+&(Rqo~;AK+P z^sS`IR7yVS=Le0m3V|~!jnn1BiDR>-?ksQMJaTzZtSly~JAizt_W7L3x8v|Sm0v)G zKu@dWQmafMBaF~0o>Ri=nCYMXrs4l2-a&e4Xv;*+$tMBITdz7uin%}MG1o<+)U~zA zqVoX`#11XXq>={~#xr@wQp=w{X3*b0r>fB4QK=>|q-l-hXvsxW!SRauGn&<%OA!os zull)Ih|R{suqN8!7TV$VB|nu~?(ukqAg?C;bbI^irNsa-<#m~^$m#c(qsKsI=;lSr z$JE(UvFR~3`AQGB^B9m?psPGI!up^m##G{yoCjMin+$B_grB6yFAJPnjFDXG784(r z)S!uVHT!;$N*S*IIo>?$*=gkka2iRqr=)DE7UL*SInjDzeK&)M?|fb5(|L*`KSI#OJ}C5jD4UNWiifz zzT0EUUaUb<11aEXr4Rg95E3WZ;P^7-DL1QEIb?ThP>^gWdTq4%(+RAna{c(gA@cpy zd9XkGOa58Dk4u!<@p}w=TyL|-Whqy6vh?7ls6V^^Yo37bA4l6rgJ;`-zKk5~8F(tu ze{nS_b;?S|BX94Bc>R5EJA-?1l3i2@%!PCLs$z`mQVRsaC-)-L|IzV%xw+|fMv>z#c`Xs{4+ zPzrc`fE_0+-xJuN+HnnMv+Pc`p;l5^J-i&qpsn>4mC#Xz9&M6eyVSzeSn7}ZT>L}W zwBKf)KSI~KH@wW33Whn@&KpFg{{{%dXKIaCRm|tj3x& zp?|tz8d96JG7b6oS>vah$$f$UzdZ22^I^@rfr`wM)%_Nzz~%Yt|5rZ$-%tE^2ChsH zP+(Q#JzCKQOl$WjDJk*23DD3N`om9M3}_VzR6)1wql1TlU`RO(E&zKdpv9reqp^m7 z8laSw*K7Y~Sb%Rh0_jh3(&CosVb?V35>)1?jHj z!bA!CnZi%CUCE^mt0#a8y?-PD0yq9MC73D8)&nY}*v}8JErFk)OeM1kt8hJj(9>~K za@7F~oN0BIeiR${1k@*1prqmQ{g{{zMl&2ptnVwLr{w8uj`j6Ds+StCd9Ne&cMo8Y znX?}eP9qiG7vGgFVA2%k5%-ovAYgh* z0i*ZS={Z3VlpVF(l$fzk!0~}i?0^1zKmI8LM*AACGT-QJr`)Z*;aNE&R@;6}7oG_R z3L8N(moWQ{V1EtTn|Z=v9$fh{VZWQLwx3`cZd3at5j}}j%7i?)okcA0=xD)BjcoXJ zkr410$;N&j)&8(u%J4>n@m^02f?B83A2_7X-j~ht1NwMcOVSy`~E8%lRieH@-hRN(ef?RQowy~S*xMM-a3NWdI}T#6)9_Q=b&c13eDOxC3$Y;`q#<~jM3 z%l3}|;~Av5H)l|4Q7e4!zKH5bTQxL%O-(>dyM;@1!~a!^&E93*tS^;WdJ~8R=GwAl z=$s56horck#_w?I7j5n0vJuQnhWA5af(PF+8Ol#pb*0=B@eF9s=|Idas{6}R2$1Ed z9FBzEmyN2%kYoo=rTkJc0b_>=ebW{dq9*u36W>85EGbLcU)|HH-RoclU>2qa+ZBo- z?VB|^4pOx-yc0SDUvIhVP$nk!7I3A#+oiqlwf7KZ+wVhrdTR`%ns5#p#w+a~A|VaV z0bfF6bbhSuRZk$AH>A_TQpR@LC#qp~di5*BKB)wE?3`T$HP(e{L=cJ|w(iwLYaeC| z`x;8s_Vos&wQ%PHzzZWMZ)_6xSowE3+gVXkt`j@skVT!+CK3d!`+jk!`wfxR^5Xps zW!)ItJDu{xrponm8d^?+Ln&JW@ zcLOoA>ZvzF3Zayp9bPHSY=;4QE3${kIUp9`j=W|$r?8-Fl*N9&J6NmI{5Zx~WV^3W zI0nykQ4hdyXSybsW!P~s>%DmnzT1uPQ$R|P4&HPbCZ?(T&vrMuX**51a412T`LfD} ziTb&XRP^4}9CGJQ7H7GN=iA$LY5}8ND~L9Qc&Cs0C?uvr!$sls>w4|?sIaverL7-? z2C?=(Fgkmj(1|KU_|k8%@#-6eEwCbp>VPVjYrXMoo!gO&9<(E}oW?-mTv+lfIXhtC zp~_Lo$9!)kQ&$M{s3I|+{*48m_vPsRr!fiRL>A0?lvkAu%Z1mkZjxuAxF4`BL^3x> z^XDyVnZ`Go{?J8Lh+Fv&$ zu{aIabx4m3cN)B-GvZUH;f~_j+2TvyGMzseM?dx^dGl-brX6{rNFl61kT zQQ5C76Q$JF2)f!w=t>KWe>d#B>kUD z6_B_u0Av`t-tNe0Y;E>HdbM!fIi+lF?M|v|_sA-DD_>gz+FWW2nI33Unaz{1Ul1X z>v|%~W5eAEPK1D_0l40(4P4KnVl0Z~!Cw|tV>xq6%VtF+aq!xqGUJgu5;%uacpg#2 zX4NTuvMDKmX7vreew(aPIZ)Z#dS0u3&q-@?S0dI@E&MVu)G0IopJawreB2RueB7E^ zi;!;|>rtD37dY2*Yw3QKWBMl3@yyjnPthw>=xQ0!C#bkZJ#Zt-V2hQ1A#?Z8j8PAR z!B{G2m#Ua-HE7rzJigJ_9JD34D6fS0l5Nj<;C5??^&%e1V3=UTt5^KT@MU(*EmCvJ zMH%a>DYqK?QA3y&ZWlJpZgg>+b5h!b#j0L}f0337{SLH>s})RN$J*8W2?6J2J4nlY za?D3x1-y{@`T{YPR_(uf12S?=I&F$`p8YGnjrD98YdF3#FPgcIo;RSUm2&mxq4Vs- z#T6OuIWn08^t6~Md()7Yf6t0=eiUJ)<3l(kv2$VaI!E&EH zHIS;K3L>crsIgPn#ffQ*6jVzz^<&?HD8Y)Esf2R2^HGK+4h zYiSjc9a6@8p?G8#!l3dAvEwa7GN@-b!xX?Aq&gS9Mskr^lY8lON5Mho zJ@9Znci35IYz~SWEmcbDEz`bVA;}uNd@o~xjJ1bag+JKzZE)*n{M^#tWN%cqvd#vC zF);(|-KV3~Iz3Xvc6)6t!_V9#QWmCWIo)xD+0>)Gb2oHyTR_E?eI-=R8|FmQ4XL1{ zzTg&($9XDw&Y||i1Akl#Ebb}`qr~z#K+QHc<8eLZ5o6l&j+_!d_A!Mq;!vnEZBJ`= ztJO*;|BuqWo?(1={%%vt7}X?bGjK9MaAsicB+EBh5p{W@YzY5y_b#FA_g$z~`pK3o z$DZtoD%qPOCv#fDx5kD`r`1V{yOT=0+0*2PR2zw7&H3PKXqJZch&3J^86zQ5aNQ0 zVvu2prSP!t%1qhio>i7{8FL01R*g{Qu9Phf<1*;b@MhD`^(_{8#47CWX3)~tPnElj zlHjFyZ%v+bpIwxrNZA}$V=Cbxdkc4IK(+qli}5p}!TfjLMr)(3smEs2H_>~4)lSr= z2J|!XSTF)IY_{%5f};8P;v;^+N57nsKxkc;Zl%S{-i9{*NzUG#sP~V8Vkzv~r6uy* z>~+PpI1YSFH0~~LQ&kwV_JwaPPNZ=6t)zy^9_m3+Gap!Ke&?JmmJ&bC7ak}=(52?} zBbud{_(RC!yY-akp@exBiPKsesc{0XHy62bd+DN*BY~1a!cFG}ELda#qo;mV`5dsYle_tHz}t`Upgs`nv%{3_x{YO*qc@ya zs)=>7X+p!}E!*oKr=d$kEUJvYo4h8Tx)Po7(f;R;YRW2_GuLZYG9r*AaThQPTn2m{NAK|E%Ov zS#5*%{A(c=>=y?_z%Ku;7K;x#UA)sE3CRe|j1x(;*w)?6upkCU5b%XM*Mh&l`#|L^ z4E8d~DsWuQ=EzCNDw*4)M$q=D|G^O14kI*PW(%Bf*t5D4u0p_CqgU))Hz7>RSXILG zSYS__(&p~*9%0FwYNF?kvnGLRu!`l@HT#gITJ{A4$WV*Phhu#0jLr5oS;LLH^XkY zMpJP!U8gzRZ1+cZr0ztrSyhG&JEaa9OK&E&GFFI1;ptxC?dd;7Low40VQ9x^thxGf z%511M^V$Rv#eN-yCfKo}Ha^$A!X_< z^QxWdqnTJ^HXrZJa@O2*76_s_U{=+0(T?ZRlGXm>K^c3$B57NO%ikV<5RkgoiQPhe zec&kJG1e3|ZleG4XaM5rS-dA&j`JxFPbN#{d+Wp{E7MJ~A)hQU+&OJ;`LWl=3=7+l z*}8}LriGymH2ub^N@JZrE%jmc5Z+NlkTuuZQ5RevVqK{rtF@%DcI}zu{!Rk!`+()J9ac^J+0yD)8KRt`%OdgDylk6%~dGh9YYP}803Vx(>6gyZgoaPffatO!0u)796H zGg?q5ZiNW?NSnkY6`?&EkvnUuG~bZ$7T*l06oB}4PvKzdGAS8{II^aPCVj+jrf9l+ zzq*GyxZOa@!8zg8_bTyPvwS@EVQW(b+okCm)Drz{f@pw1M4Cz2@2vTY{g^! z@53G1S3A2t*GO7VitMPoc%*%vy;`0Or98&fy@}n*dAlR3r#+FLVCpXo!=A>?CF`r5 z6;VP^^2@S*FEe;`vWNNWbM0&WutGAFQ>K#t#y40?nNs=(XsimD(U|Y$ek9wVvF5Lu zm2*MnmUa&-zE($$!6THM(0bR4UA2BI5_>Y%6cun9uw~aws>9KRAH>h0S0j709jQ5{ zzX$8k!|EE~(Xp3FUK*j0D=NAXfC-nt&I)%=J%|*MPyR#DBoM-1CRzFgG zyqYiIw7w0xC3AgPNO3!*nd5Pzuqppk97DnUnUKP=1T|!aYQK(>+mno%sEBEkGg~K zIPmi4jne5d!RHJ8uo6~*@v!5Ud$UMGskDaBt*2v7K1BrRD-3=WVPKCg zkIcW8Ty;&5ysp;4noAzbsgUwP7f;xu6A`Ku?7KYe9Ny@gAG4)6tku#c#|c>Yn!e7t zGs_75vxLRG9kh=)Y428pP{To%+c18JAi$dAd*%>s-TrODu5BA#AFTf3l9b57b^3YJ z!KXVirYL0l{g=gCnGPs0RF3;RIAIOF3=E4ylT7p9&p%lSBHY~-t(Ko-#6{xN5}-+n zs7|T;VvZ~?N%s2NRvu-396EQh@t z?o`?68=xAxPzPNAuY!GF@&1MsXHG5r`caDh=F%qg!dH~I@!%%}J5{ZwCq9n0GUtZ( z-2*Jy^x(2=MsR3A_Ucb`5L;S!&BHKqgXmGacQ&DvY^e$>go+4_eMgnr`|VYnD$#M! zPA}_5rmG?SYeR#m-@Sud@|HFg(~u$3^=Om?>(om}>1w4V#9iygq18>1_#vDu%)0F7 zg~5(~Xv`z%ykZ^HNBR>Lu^q9;oEq2g-Vk|@sH-U@`x0t0zMw@v27i^{3=&bs;wRHT z&iG5kX*c)bL+NXZX*9wuI%VbRxw9E&p3;iRVS5W|X`3BK;F)(yBmfIz`gZ(6_>%Vs z4}p8mdDm6;UD*idw(3@y2BQZ*w$Pk}sJu2of4zA-p0|-#`DnC-b8b!TTOZUO>*hz^ zkDH6*ON2sPO&&`cdz~Lb-N6zuqqXgGs>Q1id3saPv?TA!8mpaQnM%f8p1cMDieUmp zdgD;gr~?M8>0jP%`EV_pC~tYA*Z7yhU#&c1{~q*yXxj?XHvd_}m3?%=u$~z3gLyNV z*X9GKaQZ~)krc+snm}__nVp!x#)|`*&BWia`M*v!6|sTYDw`heW{)_+%bnc)z->S6 zLbKMuo4mNUSklqeN$zbjpTNtDWfGqTSQ@ZfP^IOF4nqLrmPIbac|0YAxb1{qr?0Kr zZ=MtV>yXqtIyhITwlX6_U}hL`Nb2E_`e3xo=Tti>DbmS{ouS^68K3(HKermhtf7xa z?yB;hpmSwYf8YN3r!hN4bYK`U^we;T&d-u>#Ta39q~O$j=t5@=Ld>eF7GrqJrWg%u zqlKt^{NtJR=s%^q7#_js%sl548F}~Fm{q;PFpMPfT=USX$&qaq=$6$kc($R8bk5eQ zVXmbR8ez{?dAjV(d=N7(5}#+f9-$_%tnJqKR}JE7)yZU{UnkvdJJh`Tb<-~lVmody z9odlK*UyJYRVnUD-kV-2-S8EC<1TGVG$v#Di^9}&wr~mds58G>g^x@y+Nb%r^b5GL z4Of|}a31E1Hf`1Fd&6!Y`8sI0uaHrR+8Bp$+<%y!U)>SA8*@9rGVUWJ1AG zW18amp-WDjoeFNfPv*qQ!>Xr@#IypNOt2y46WZuR-5I7?MD7G^X0P8d7bMtX!ySgXQ2h3Z>m#vx(hN%pYv!NS_g|O9Lf}@|x0h293(ONl<~;Z}&bQU|wup zyMz85FC*o;4!KHaS>ms<6|)q)?%VlLMaB)H8sfdizSh(ngC`5I!PT+4U7ocK^`ua@ zpM6=rMw6Rw7Bt;ACNXw`88^u79rItN*ElE8;9ORXM6&K=brF?Br{4dzdgPW`y5#Wa zX)8|XsKlFmhdXeSCFQE>z!_yaw&)g*0yy0L-S2Y`pfLOJ?`4}G!lh&v$)dPM*NJ7? z_O-F)FfCib$zaEPt>xs2NZ}$DV^Ah?f+MsyKM{^&(>Q#?Iq8MdlaG7$f7qQJo3-kxVLR&&?C-wyAGS4)ox|61G;B?*x_qA6=bkP*Z6ZhIJfUTrj9jXJnDF6%{Rr z-8PF0T%nYuSt8IFX$ZGzr`#ZhmZX6Ya%+^OiJG(`E`#I>h$sqCl&~hZ1sQsO)YSZ#fA5d4>Z>|`-mlJi&ie_Gfd+d8Xp6BiyfY!QE!q%8V}_#{ zMC7~hY$Be@Pv8uaMbv2Ve%Tu3zMGxBeO_Lk%g~E#wr1)9SyUHN$SOtR+A006dV{Z@ z2d8Nz>RB#EuX4T*R`BgEqWNty?gIp?4@Fl&n1D#g;eT>WlIbzL^M)MX(jdV&ul0$O z-f24C8>i()2c^-_Ll&i2Ig=p;0(+!&QR;RmDY#vJB&d_KZ**1k6i{LgGxf{`fv8;G zj47CfQ9%jC(@wW81dYayQHOXRmDyzz-KFLN`ddcev@NkW>E)ycC}aCPGX9NGdpZGG z;JHIEj%!VqyRMbiw6W5hc99D6Rn1=P;9R`+F7x7Rbh;TZ;p~4dwB9V1OUo z2$*Btoj(|_+hj09Ps>09!7rjZ^#C%H zkF{74t9tV1;R@js7^L39WSG0T&N>j#H&c9=z36=!0CJxn$hoj@Kh$~FDD(I8jt7eu z+@=#x@>!Bi%_~$LX^;xmKP921=JChjXXKErF0;RHQqZV`bcqPL&IIVNYNd%{(LLh| z`=v#df0}kHK;JKi2U<=xBm$qic`9~5$6!`Z#z1b3<9Pi6g7E!kfTTWP@iLCyM_f|; z;`Ec;f-Af>$z3jPtuj82)Qix+lzf5y@N9@3JT}4O*+!aL8zOYZpJy~mI8Vi_@8WYDPmI|1E4N!Siqz?vDsf?=vTYJhK>R^ztvE(0GE+xaF%j^b z?O&HxBeVyxRBZJ@u?lvKw9xBH{w-a>=EI({|ZwfCrl#(h_=1)S5 z?ost9+xYy6p5*KH%Mg20F)1PC2&Xjho{9AavLZq$L^M-@NQL)s-8mYrNF0&P=g?Hz zEoTL?HeH>RSm6@)V*89C+W-$=8R0E#t^{3) z1Nj-yBSfz-WV4p6UG`vI4!8l_Lk%9(MWazNOp!oB2r+ymbpbKef;0;MS6N4nlr6CP zA|5)jl#H)%VSQO<03~SteVVxaX;QBIGlGCJ*r|Om~-gg>B(ZuP?;~_7~L$2 z8N_)j)h8>d#CDS_)~)!4a7-PI1yqJ)bUFMEt+Q2)TdDF%F^_K91uv?%SJH|Rc48_8 zV|sE(j@t>h!Hv)zbg-nJ`C4C(tFpCl-mVm9>5x%0yyI zjOU1-U+NA-GS;Wy=+a|p#6CVSs21@bnaeM@Rp)aCh2JukxUZb7eDPzGAkq(#|E0^c zm29`3L1@*fhG_F&(+tXXaPZE!XN&duJh|1;rRrXd%hVcN`#u{cQFE3RFK zS9RjkCh(EffqM2x)b@>pmtFdqe;Su5N)RfTSD7r7DZ}6PrjdBLByEb1XDxL!r?)>z z#{D)SfBof61Szk9`_}aaLxzK_dq54``e(Omd4og`TD5bDYA9A6p+G_V%7e|+6O}|# zMfp|H39Whh#$0~4X@vt(tFGvH$Zh|FxJUTWt(1}8ElFZ5nW*$Kp5nG*XZo2sJ6nyXNurl*#29`uOnR|?z3>V zY^zu6=9pG;;e0YM1oS^X6Tukl#;_mG{~HVs65ap+ literal 0 HcmV?d00001