create or replace package PKG_P8PANELS_VISUAL as
  /* Константы - типы данных */
  SDATA_TYPE_STR            constant PKG_STD.TSTRING := 'STR';  -- Тип данных "строка"
  SDATA_TYPE_NUMB           constant PKG_STD.TSTRING := 'NUMB'; -- Тип данных "число"
  SDATA_TYPE_DATE           constant PKG_STD.TSTRING := 'DATE'; -- Тип данных "дата"
  
  /* Константы - направление сортировки */
  SORDER_DIRECTION_ASC      constant PKG_STD.TSTRING := 'ASC';  -- По возрастанию
  SORDER_DIRECTION_DESC     constant PKG_STD.TSTRING := 'DESC'; -- По убыванию
  
  /* Константы - масштаб диаграммы Ганта */
  NGANTT_ZOOM_QUARTER_DAY   constant PKG_STD.TNUMBER := 0; -- Четверть дня
  NGANTT_ZOOM_HALF_DAY      constant PKG_STD.TNUMBER := 1; -- Пол дня
  NGANTT_ZOOM_DAY           constant PKG_STD.TNUMBER := 2; -- День
  NGANTT_ZOOM_WEEK          constant PKG_STD.TNUMBER := 3; -- Неделя
  NGANTT_ZOOM_MONTH         constant PKG_STD.TNUMBER := 4; -- Месяц
  
  /* Константы - масштаб циклограммы */
  NCYCLOGRAM_ZOOM_MIN       constant PKG_STD.TLNUMBER := 0.2; -- Минимальный (0.2 от исходного)
  NCYCLOGRAM_ZOOM_TINY      constant PKG_STD.TLNUMBER := 0.4; -- Мелкий (0.4 от исходного)
  NCYCLOGRAM_ZOOM_SMALL     constant PKG_STD.TLNUMBER := 0.7; -- Уменьшенный (0.7 от исходного)
  NCYCLOGRAM_ZOOM_DEFAULT   constant PKG_STD.TLNUMBER := 1;   -- Исходный
  NCYCLOGRAM_ZOOM_LARGE     constant PKG_STD.TLNUMBER := 1.5; -- Увеличенный (1.5 от исходного)
  NCYCLOGRAM_ZOOM_HUGE      constant PKG_STD.TLNUMBER := 2;   -- Большой (2 от исходного)
  NCYCLOGRAM_ZOOM_MAX       constant PKG_STD.TLNUMBER := 2.5; -- Максимальный (2.5 от исходного)
  
  /* Константы - тип графика */
  SCHART_TYPE_BAR           constant PKG_STD.TSTRING := 'bar';      -- Столбчатая
  SCHART_TYPE_LINE          constant PKG_STD.TSTRING := 'line';     -- Линейная
  SCHART_TYPE_PIE           constant PKG_STD.TSTRING := 'pie';      -- Круговая
  SCHART_TYPE_DOUGHNUT      constant PKG_STD.TSTRING := 'doughnut'; -- Кольцевая
  /* Константы - расположение легенды графика */  
  SCHART_LGND_POS_LEFT      constant PKG_STD.TSTRING := 'left';   -- Слева
  SCHART_LGND_POS_RIGHT     constant PKG_STD.TSTRING := 'right';  -- Справа
  SCHART_LGND_POS_TOP       constant PKG_STD.TSTRING := 'top';    -- Наверху
  SCHART_LGND_POS_BOTTOM    constant PKG_STD.TSTRING := 'bottom'; -- Внизу
  
  /* Константы - циклограмма */
  NCYCLOGRAM_GROUP_DEF_WIDTH  constant PKG_STD.TNUMBER := 100; -- Высота заголовка группы (по умолчанию)
  NCYCLOGRAM_GROUP_DEF_HEIGHT constant PKG_STD.TNUMBER := 42;  -- Ширина заголовка группы (по умолчанию)
  NCYCLOGRAM_LINE_HEIGHT      constant PKG_STD.TNUMBER := 20;  -- Высота строк циклограммы
  /* Типы данных - значение колонки таблицы данных */
  type TDG_COL_VAL is record
  (
    SVALUE                  PKG_STD.TLSTRING, -- Значение (строка)
    NVALUE                  PKG_STD.TLNUMBER, -- Значение (число)
    DVALUE                  PKG_STD.TLDATE    -- Значение (дата)
  );
  
  /* Типы данных - коллекция значений колонки таблицы данных */
  type TDG_COL_VALS is table of TDG_COL_VAL;
 
  /* Типы данных - описатель колонки таблицы данных */
  type TDG_COL_DEF is record
  (
    SNAME                   PKG_STD.TSTRING, -- Наименование
    SCAPTION                PKG_STD.TSTRING, -- Заголовок
    SDATA_TYPE              PKG_STD.TSTRING, -- Тип данных (см. константы SDATA_TYPE_*)
    SCOND_FROM              PKG_STD.TSTRING, -- Наименование нижней границы условия отбора
    SCOND_TO                PKG_STD.TSTRING, -- Наименование верхней границы условия отбора
    BVISIBLE                boolean,         -- Разрешить отображение
    BORDER                  boolean,         -- Разрешить сортировку
    BFILTER                 boolean,         -- Разрешить отбор
    RCOL_VALS               TDG_COL_VALS,    -- Предопределённые значения
    SHINT                   PKG_STD.TSTRING, -- Текст всплывающей подсказки
    SPARENT                 PKG_STD.TSTRING, -- Наименование родительской колонки
    BEXPANDABLE             boolean,         -- Разрешить сокрытие/отображение дочерних колонок
    BEXPANDED               boolean,         -- Отобразить/скрыть дочерние колонки
    NWIDTH                  PKG_STD.TNUMBER  -- Ширина колонки (обязательно для фиксированных)
  );
  
  /* Типы данных - коллекция описателей колонок таблицы данных */
  type TDG_COL_DEFS is table of TDG_COL_DEF;
  
  /* Типы данных - колонка */
  type TDG_COL is record
  (
    SNAME                   PKG_STD.TSTRING, -- Наименование
    RCOL_VAL                TDG_COL_VAL      -- Значение
  );
  /* Типы данных - коллекция колонок */
  type TDG_COLS is table of TDG_COL;
  
  /* Типы данных - строка */
  type TDG_ROW is record
  (
    SGROUP                  PKG_STD.TSTRING, -- Наименование группы
    RCOLS                   TDG_COLS         -- Колонки
  );
  
  /* Типы данных - коллекция строк */
  type TDG_ROWS is table of TDG_ROW;
  /* Типы данных - группа */
  type TDG_GROUP is record
  (
    SNAME                   PKG_STD.TSTRING, -- Наименование
    SCAPTION                PKG_STD.TSTRING, -- Заголовок
    BEXPANDABLE             boolean,         -- Разрешить сокрытие/отображение дочерних 
    BEXPANDED               boolean          -- Отобразить/скрыть дочерние
  );
  
  /* Типы данных - коллекция групп */
  type TDG_GROUPS is table of TDG_GROUP;
  
  /* Типы данных - таблица данных */
  type TDG is record
  (
    BFIXED_HEADER           boolean,         -- Зафиксировать заголовок
    NFIXED_COLUMNS          PKG_STD.TNUMBER, -- Количество фиксированных колонок
    RCOL_DEFS               TDG_COL_DEFS,    -- Описание колонок
    RGROUPS                 TDG_GROUPS,      -- Описание групп
    RROWS                   TDG_ROWS         -- Данные строк
  );
  
  /* Типы данных - фильтр */
  type TDG_FILTER is record
  (
    SNAME                   PKG_STD.TSTRING, -- Наименование
    SFROM                   PKG_STD.TSTRING, -- Значение "с"
    STO                     PKG_STD.TSTRING  -- Значение "по"
  );
  
  /* Типы данных - коллекция фильтров */
  type TDG_FILTERS is table of TDG_FILTER;
  
  /* Типы данных - сортировка */
  type TDG_ORDER is record
  (
    SNAME                   PKG_STD.TSTRING, -- Наименование
    SDIRECTION              PKG_STD.TSTRING  -- Направление (см. константы SORDER_DIRECTION_*)
  );
  
  /* Типы данных - коллекция сортировок */
  type TDG_ORDERS is table of TDG_ORDER;
  
  /* Типы данных - описание атрибута задачи для диаграммы Ганта */
  type TGANTT_TASK_ATTR is record
  (
    SNAME                   PKG_STD.TSTRING, -- Наименование
    SCAPTION                PKG_STD.TSTRING, -- Заголовок
    BVISIBLE                boolean          -- Разрешить отображение
  );
  
  /* Типы данных - коллекция описаний атрибутов задачи для диаграммы Ганта */
  type TGANTT_TASK_ATTRS is table of TGANTT_TASK_ATTR;
  /* Типы данных - значение атрибута задачи для диаграммы Ганта */
  type TGANTT_TASK_ATTR_VAL is record
  (
    SNAME                   PKG_STD.TSTRING, -- Наименование
    SVALUE                  PKG_STD.TSTRING  -- Значение
  );
  
  /* Типы данных - коллекция значений атрибутов задачи для диаграммы Ганта */
  type TGANTT_TASK_ATTR_VALS is table of TGANTT_TASK_ATTR_VAL;
  
  /* Типы данных - коллекция ссылок на предшествующие задачи для диаграммы Ганта */
  type TGANTT_TASK_DEPENDENCIES is table of PKG_STD.TREF;
  
  /* Тип данных - задача для диаграммы Ганта */
  type TGANTT_TASK is record
  (
    NRN                     PKG_STD.TREF,                    -- Рег. номер
    SNUMB                   PKG_STD.TSTRING,                 -- Номер
    SCAPTION                PKG_STD.TSTRING,                 -- Заголовок
    SNAME                   PKG_STD.TSTRING,                 -- Наименование
    DSTART                  PKG_STD.TLDATE,                  -- Дата начала
    DEND                    PKG_STD.TLDATE,                  -- Дата окончания
    NPROGRESS               PKG_STD.TLNUMBER := null,        -- Прогресс (% готовности) задачи (null - не определен)
    SBG_COLOR               PKG_STD.TSTRING := null,         -- Цвет заливки задачи (null - использовать цвет по умолчанию из стилей, формат - HTML-цвет, #RRGGBBAA)
    STEXT_COLOR             PKG_STD.TSTRING := null,         -- Цвет текста заголовка задачи (null - использовать цвет по умолчанию из стилей, формат - HTML-цвет, #RRGGBBAA)
    SBG_PROGRESS_COLOR      PKG_STD.TSTRING := null,         -- Цвет заливки прогресса (null - использовать цвет по умолчанию из стилей, формат - HTML-цвет, #RRGGBBAA)
    BREAD_ONLY              boolean := null,                 -- Сроки и прогресс задачи только для чтения (null - как указано в описании диаграммы)
    BREAD_ONLY_DATES        boolean := null,                 -- Сроки задачи только для чтения (null - как указано в описании диаграммы)
    BREAD_ONLY_PROGRESS     boolean := null,                 -- Прогресс задачи только для чтения (null - как указано в описании диаграммы)
    RATTR_VALS              TGANTT_TASK_ATTR_VALS := null,   -- Значения дополнительных атрбутов (null - дополнительные атрибуты не определены)
    RDEPENDENCIES           TGANTT_TASK_DEPENDENCIES := null -- Список предшествующих задач
  );
  
  /* Тип данных - коллекция задач диаграммы Ганта */
  type TGANTT_TASKS is table of TGANTT_TASK;
  
  /* Тип данных - описание цвета задач диаграммы Ганта */
  type TGANTT_TASK_COLOR is record
  (
    SBG_COLOR               PKG_STD.TSTRING := null, -- Цвет заливки задачи (формат - HTML-цвет, #RRGGBBAA)
    STEXT_COLOR             PKG_STD.TSTRING := null, -- Цвет текста заголовка задачи (формат - HTML-цвет, #RRGGBBAA)
    SBG_PROGRESS_COLOR      PKG_STD.TSTRING := null, -- Цвет заливки прогресса (формат - HTML-цвет, #RRGGBBAA)
    SDESC                   PKG_STD.TSTRING          -- Описание
  );
  
  /* Тип данных - коллекция описаний цветов задач диаграммы Ганта */
  type TGANTT_TASK_COLORS is table of TGANTT_TASK_COLOR;
  
  /* Типы данных - диаграмма Ганта */
  type TGANTT is record
  (
    STITLE                  PKG_STD.TSTRING := null,             -- Заголовок (null - не отображать)
    NZOOM                   PKG_STD.TNUMBER := NGANTT_ZOOM_WEEK, -- Текущий масштаб (см. константы NGANTT_ZOOM_*)
    BZOOM_BAR               boolean := true,                     -- Обображать панель масштабирования
    BREAD_ONLY              boolean := false,                    -- Сроки и прогресс задач только для чтения
    BREAD_ONLY_DATES        boolean := false,                    -- Сроки задач только для чтения
    BREAD_ONLY_PROGRESS     boolean := false,                    -- Прогресс задач только для чтения
    RTASK_ATTRS             TGANTT_TASK_ATTRS,                   -- Описание атрибутов карточки задачи
    RTASK_COLORS            TGANTT_TASK_COLORS,                  -- Описание цветов задач
    RTASKS                  TGANTT_TASKS                         -- Список задач
  );
  
  /* Типы данных - значение атрибута элемента данных графика */
  type TCHART_DATASET_ITEM_ATTR_VAL is record
  (
    SNAME                   PKG_STD.TSTRING, -- Наименование
    SVALUE                  PKG_STD.TSTRING  -- Значение
  );
  
  /* Типы данных - коллекция значений атрибутов элемента данных графика */
  type TCHART_DATASET_ITEM_ATTR_VALS is table of TCHART_DATASET_ITEM_ATTR_VAL;  
  
  /* Тип данных - элемент данных графика */
  type TCHART_DATASET_ITEM is record
  (
    NVALUE                  PKG_STD.TLNUMBER,                     -- Значение элемента данных, отображаемое на графике
    RATTR_VALS              TCHART_DATASET_ITEM_ATTR_VALS := null -- Значения дополнительных атрбутов (null - дополнительные атрибуты не определены)
  );
  
  /* Тип данных - коллекция элементов данных */
  type TCHART_DATASET_ITEMS is table of TCHART_DATASET_ITEM;
  
  /* Тип данных - набор данных графика */
  type TCHART_DATASET is record
  (
    SCAPTION                PKG_STD.TSTRING,         -- Заголовок
    SBORDER_COLOR           PKG_STD.TSTRING := null, -- Цвет границы элемента данных на графике (null - использовать цвет по умолчанию из стилей, формат - HTML-цвет, #RRGGBBAA)
    SBG_COLOR               PKG_STD.TSTRING := null, -- Цвет заливки элемента данных на графике (null - использовать цвет по умолчанию из стилей, формат - HTML-цвет, #RRGGBBAA)
    RITEMS                  TCHART_DATASET_ITEMS     -- Элементы данных
  );
  
  /* Тип данных - коллекция наборов данных графика */
  type TCHART_DATASETS is table of TCHART_DATASET;
  
  /* Тип данных - коллекция меток данных графика */
  type TCHART_LABELS is table of PKG_STD.TSTRING;
  
  /* Типы данных - график */
  type TCHART is record
  (
    STYPE                   PKG_STD.TSTRING,         -- Тип (см. константы SCHART_TYPE_*)
    STITLE                  PKG_STD.TSTRING := null, -- Заголовок (null - не отображать)
    SLGND_POS               PKG_STD.TSTRING := null, -- Расположение легенды (null - не отображать, см. константы SCHART_LGND_POS_*)
    RLABELS                 TCHART_LABELS,           -- Метки значений
    RDATASETS               TCHART_DATASETS          -- Наборы данных
  );
  
  /* Типы данных - описание атрибута задачи для циклограммы */
  type TCYCLOGRAM_TASK_ATTR is record
  (
    SNAME                   PKG_STD.TSTRING, -- Наименование
    SCAPTION                PKG_STD.TSTRING, -- Заголовок
    BVISIBLE                boolean          -- Разрешить отображение
  );
  
  /* Типы данных - коллекция описаний атрибутов задачи для циклограммы */
  type TCYCLOGRAM_TASK_ATTRS is table of TCYCLOGRAM_TASK_ATTR;
  /* Типы данных - значение атрибута задачи для циклограммы */
  type TCYCLOGRAM_TASK_ATTR_VAL is record
  (
    SNAME                   PKG_STD.TSTRING, -- Наименование
    SVALUE                  PKG_STD.TSTRING  -- Значение
  );
  
  /* Типы данных - коллекция значений атрибутов задачи для циклограммы */
  type TCYCLOGRAM_TASK_ATTR_VALS is table of TCYCLOGRAM_TASK_ATTR_VAL;
  
  /* Типы данных - колонка циклограммы */
  type TCYCLOGRAM_COLUMN is record 
  (
    SNAME                   PKG_STD.TSTRING, -- Наименование колонки
    NSTART                  PKG_STD.TNUMBER, -- Позиция начала колонки
    NEND                    PKG_STD.TNUMBER  -- Позиция конца колонки
  );
  
  /* Типы данных - коллекция колонок циклограммы */
  type TCYCLOGRAM_COLUMNS is table of TCYCLOGRAM_COLUMN;
  
  /* Типы данных - строки циклограммы */
  type TCYCLOGRAM_TASK is record
  (
    NRN                     PKG_STD.TREF,                     -- Рег. номер
    SCAPTION                PKG_STD.TSTRING,                  -- Заголовок
    SNAME                   PKG_STD.TSTRING,                  -- Наименование
    NLINE_NUMB              PKG_STD.TNUMBER,                  -- Номер строки
    NSTART                  PKG_STD.TNUMBER,                  -- Позиция начала задачи
    NEND                    PKG_STD.TNUMBER,                  -- Позиция конца задачи
    SGROUP                  PKG_STD.TSTRING,                  -- Наименование группы
    SBG_COLOR               PKG_STD.TSTRING := null,          -- Цвет заливки задачи (null - использовать цвет по умолчанию из стилей, формат - HTML-цвет, #RRGGBBAA)
    STEXT_COLOR             PKG_STD.TSTRING := null,          -- Цвет текста заголовка задачи (null - использовать цвет по умолчанию из стилей, формат - HTML-цвет, #RRGGBBAA)
    SHIGHLIGHT_COLOR        PKG_STD.TSTRING := null,          -- Цвет при наведении (null - использовать цвет по умолчанию из стилей, формат - HTML-цвет, #RRGGBBAA)
    RATTR_VALS              TCYCLOGRAM_TASK_ATTR_VALS := null -- Значения дополнительных атрбутов (null - дополнительные атрибуты не определены)
  );
  
  /* Типы данных - коллекция строк циклограммы */
  type TCYCLOGRAM_TASKS is table of TCYCLOGRAM_TASK;
  
  /* Типы данных - группа строк циклограммы */
  type TCYCLOGRAM_GROUP is record
  (
    SNAME                   PKG_STD.TSTRING,        -- Имя группы
    BHEADER_VISIBLE         boolean,                -- Признак отображения заголовка группы
    NHEADER_HEIGHT          PKG_STD.TNUMBER,        -- Высота заголовка группы
    NHEADER_WIDTH           PKG_STD.TNUMBER,        -- Ширина заголовка группы
    SHIGHLIGHT_COLOR        PKG_STD.TSTRING := null -- Цвет при наведении (null - использовать цвет по умолчанию из стилей, формат - HTML-цвет, #RRGGBBAA)
  );
  
  /* Типы данных - коллекция групп строк циклограммы */
  type TCYCLOGRAM_GROUPS is table of TCYCLOGRAM_GROUP;
  
  /* Типы данных - циклограмма */
  type TCYCLOGRAM is record
  (
    STITLE                  PKG_STD.TSTRING,                            -- Заголовок (null - не отображать)
    NLINE_HEIGHT            PKG_STD.TLNUMBER,                           -- Высота строк
    NZOOM                   PKG_STD.TNUMBER := NCYCLOGRAM_ZOOM_DEFAULT, -- Текущий масштаб (см. константы NCYCLOGRAM_ZOOM_*)
    BZOOM_BAR               boolean := true,                            -- Обображать панель масштабирования
    RCOLUMNS                TCYCLOGRAM_COLUMNS,                         -- Коллекция колонок циклограммы
    RGROUPS                 TCYCLOGRAM_GROUPS,                          -- Коллекция групп строк циклограммы
    RTASKS                  TCYCLOGRAM_TASKS,                           -- Коллекция строк циклограммы
    RTASK_ATTRS             TCYCLOGRAM_TASK_ATTRS                       -- Описание атрибутов карточки задачи
  );
  
  /* Расчет диапаона выдаваемых записей */
  procedure UTL_ROWS_LIMITS_CALC
  (
    NPAGE_NUMBER            in number,  -- Номер страницы (игнорируется при NPAGE_SIZE=0)
    NPAGE_SIZE              in number,  -- Количество записей на странице (0 - все)
    NROW_FROM               out number, -- Нижняя граница диапазона
    NROW_TO                 out number  -- Верхняя граница диапазона
  );
  
  /* Формирование наименования условия отбора для нижней границы */
  function UTL_COND_NAME_MAKE_FROM
  (
    SNAME                   in varchar2 -- Наименование колонки
  ) return                  varchar2;   -- Результат
  
  /* Формирование наименования условия отбора для верхней границы */
  function UTL_COND_NAME_MAKE_TO
  (
    SNAME                   in varchar2 -- Наименование колонки
  ) return                  varchar2;   -- Результат
  
  /* Добавление значения в коллекцию */
  procedure TDG_COL_VALS_ADD
  (
    RCOL_VALS               in out nocopy TDG_COL_VALS, -- Коллекция значений
    SVALUE                  in varchar2 := null,        -- Значение (строка)
    NVALUE                  in number := null,          -- Значение (число)
    DVALUE                  in date := null,            -- Значение (дата)
    BCLEAR                  in boolean := false         -- Флаг очистки коллекции (false - не очищать, true - очистить коллекцию перед добавлением)
  );
  
  /* Формирование строки */
  function TDG_ROW_MAKE
  (
    SGROUP                  in varchar2 := null -- Наименование группы
  ) return                  TDG_ROW;            -- Результат работы
  
  /* Добавление колонки к строке */
  procedure TDG_ROW_ADD_COL
  (
    RROW                    in out nocopy TDG_ROW, -- Строка
    SNAME                   in varchar2,           -- Наименование колонки
    SVALUE                  in varchar2 := null,   -- Значение (строка)
    NVALUE                  in number := null,     -- Значение (число)
    DVALUE                  in date := null,       -- Значение (дата)
    BCLEAR                  in boolean := false    -- Флаг очистки коллекции (false - не очищать, true - очистить коллекцию перед добавлением)
  );
  
  /* Добавление строковой колонки к строке из курсора динамического запроса */
  procedure TDG_ROW_ADD_CUR_COLS
  (
    RROW                    in out nocopy TDG_ROW, -- Строка
    SNAME                   in varchar2,           -- Наименование колонки
    ICURSOR                 in integer,            -- Курсор
    NPOSITION               in number,             -- Номер колонки в курсоре
    BCLEAR                  in boolean := false    -- Флаг очистки коллекции (false - не очищать, true - очистить коллекцию перед добавлением)
  );
  
  /* Добавление числовой колонки к строке из курсора динамического запроса */
  procedure TDG_ROW_ADD_CUR_COLN
  (
    RROW                    in out nocopy TDG_ROW, -- Строка
    SNAME                   in varchar2,           -- Наименование колонки
    ICURSOR                 in integer,            -- Курсор
    NPOSITION               in number,             -- Номер колонки в курсоре
    BCLEAR                  in boolean := false    -- Флаг очистки коллекции (false - не очищать, true - очистить коллекцию перед добавлением)
  );
  /* Добавление колонки типа "дата" к строке из курсора динамического запроса */
  procedure TDG_ROW_ADD_CUR_COLD
  (
    RROW                    in out nocopy TDG_ROW, -- Строка
    SNAME                   in varchar2,           -- Наименование колонки
    ICURSOR                 in integer,            -- Курсор
    NPOSITION               in number,             -- Номер колонки в курсоре
    BCLEAR                  in boolean := false    -- Флаг очистки коллекции (false - не очищать, true - очистить коллекцию перед добавлением)
  );
  
  /* Формирование таблицы данных */
  function TDG_MAKE
  (
    BFIXED_HEADER           in boolean := false, -- Зафиксировать заголовок
    NFIXED_COLUMNS          in number := 0       -- Количество фиксированных колонок
  ) return                  TDG;                 -- Результат работы
  
  /* Поиск описания колонки в таблице данных по наименованию */
  function TDG_FIND_COL_DEF
  (
    RDATA_GRID              in TDG,      -- Описание таблицы данных
    SNAME                   in varchar2  -- Наименование колонки
  ) return                  TDG_COL_DEF; -- Найденное описание (null - если не нашли)
  
  /* Добавление описания колонки к таблице данных */
  procedure TDG_ADD_COL_DEF
  (
    RDATA_GRID              in out nocopy TDG,             -- Описание таблицы данных
    SNAME                   in varchar2,                   -- Наименование колонки
    SCAPTION                in varchar2,                   -- Заголовок колонки
    SDATA_TYPE              in varchar2 := SDATA_TYPE_STR, -- Тип данных колонки (см. константы SDATA_TYPE_*)
    SCOND_FROM              in varchar2 := null,           -- Наименование нижней границы условия отбора (null - используется UTL_COND_NAME_MAKE_FROM)
    SCOND_TO                in varchar2 := null,           -- Наименование верхней границы условия отбора (null - используется UTL_COND_NAME_MAKE_TO)
    BVISIBLE                in boolean := true,            -- Разрешить отображение
    BORDER                  in boolean := false,           -- Разрешить сортировку по колонке
    BFILTER                 in boolean := false,           -- Разрешить отбор по колонке
    RCOL_VALS               in TDG_COL_VALS := null,       -- Предопределённые значения колонки
    SHINT                   in varchar2 := null,           -- Текст всплывающей подсказки
    SPARENT                 in varchar2 := null,           -- Наименование родительской колонки
    BEXPANDABLE             in boolean := false,           -- Разрешить сокрытие/отображение дочерних колонок
    BEXPANDED               in boolean := true,            -- Отобразить/скрыть дочерние колонки
    NWIDTH                  in number := null,             -- Ширина колонки (обязательно для фиксированных)
    BCLEAR                  in boolean := false            -- Флаг очистки коллекции описаний колонок таблицы данных (false - не очищать, true - очистить коллекцию перед добавлением)
  );
  
  /* Добавление описания группы к таблице данных */
  procedure TDG_ADD_GROUP
  (
    RDATA_GRID              in out nocopy TDG,   -- Описание таблицы данных
    SNAME                   in varchar2,         -- Наименование группы
    SCAPTION                in varchar2,         -- Заголовок группы
    BEXPANDABLE             in boolean := false, -- Разрешить сокрытие/отображение дочерних
    BEXPANDED               in boolean := true,  -- Отобразить/скрыть дочерние
    BCLEAR                  in boolean := false  -- Флаг очистки коллекции описаний групп таблицы данных (false - не очищать, true - очистить коллекцию перед добавлением)
  );
  
  /* Добавление описания колонки к таблице данных */
  procedure TDG_ADD_ROW
  (
    RDATA_GRID              in out nocopy TDG,  -- Описание таблицы данных
    RROW                    in TDG_ROW,         -- Строка
    BCLEAR                  in boolean := false -- Флаг очистки коллекции строк таблицы данных (false - не очищать, true - очистить коллекцию перед добавлением)
  );
  /* Сериализация таблицы данных */
  function TDG_TO_XML
  (
    RDATA_GRID              in TDG,        -- Описание таблицы данных
    NINCLUDE_DEF            in number := 1 -- Включить описание колонок (0 - нет, 1 - да)
  ) return                  clob;          -- XML-описание
  
  /* Конвертация значений фильтра в число */
  procedure TDG_FILTER_TO_NUMBER
  (
    RFILTER                 in TDG_FILTER, -- Фильтр
    NFROM                   out number,    -- Значение нижней границы диапазона
    NTO                     out number     -- Значение верхней границы диапазона
  );
  /* Конвертация значений фильтра в дату */
  procedure TDG_FILTER_TO_DATE
  (
    RFILTER                 in TDG_FILTER, -- Фильтр
    DFROM                   out date,      -- Значение нижней границы диапазона
    DTO                     out date       -- Значение верхней границы диапазона
  );
  
  /* Поиск фильтра в коллекции */
  function TDG_FILTERS_FIND
  (
    RFILTERS                in TDG_FILTERS, -- Коллекция фильтров
    SNAME                   in varchar2     -- Наименование
  ) return                  TDG_FILTER;     -- Найденный фильтр (null - если не нашли)
  
  /* Десериализация фильтров */
  function TDG_FILTERS_FROM_XML
  (
    CFILTERS                in clob      -- Сериализованное представление фильтров (BASE64(ИМЯЗНАЧЕНИЕЗНАЧЕНИЕ...))
  ) return                  TDG_FILTERS; -- Результат работы
  /* Применение параметров фильтрации в запросе */
  procedure TDG_FILTERS_SET_QUERY
  (
    NIDENT                  in number,         -- Идентификатор отбора
    NCOMPANY                in number,         -- Рег. номер организации
    NPARENT                 in number := null, -- Рег. номер родителя
    SUNIT                   in varchar2,       -- Код раздела
    SPROCEDURE              in varchar2,       -- Наименование серверной процедуры отбора
    RDATA_GRID              in TDG,            -- Описание таблицы данных
    RFILTERS                in TDG_FILTERS     -- Коллекция фильтров
  );
  
  /* Десериализация сортировок */
  function TDG_ORDERS_FROM_XML
  (
    CORDERS                 in clob     -- Сериализованное представление сотрировок (BASE64(ИМЯASC/DESC...))
  ) return                  TDG_ORDERS; -- Результат работы
  /* Применение параметров сортировки в запросе */
  procedure TDG_ORDERS_SET_QUERY
  (
    RDATA_GRID              in TDG,            -- Описание таблицы
    RORDERS                 in TDG_ORDERS,     -- Коллекция сортировок
    SPATTERN                in varchar2,       -- Шаблон для подстановки условий отбора в запрос
    CSQL                    in out nocopy clob -- Буфер запроса
  );
  
  /* Формирование задачи для диаграммы Ганта */
  function TGANTT_TASK_MAKE
  (
    NRN                     in number,           -- Рег. номер
    SNUMB                   in varchar2,         -- Номер
    SCAPTION                in varchar2,         -- Заголовок
    SNAME                   in varchar2,         -- Наименование    
    DSTART                  in date,             -- Дата начала
    DEND                    in date,             -- Дата окончания
    NPROGRESS               in number := null,   -- Прогресс (% готовности) задачи (null - не определен)
    SBG_COLOR               in varchar2 := null, -- Цвет заливки задачи (null - использовать цвет по умолчанию из стилей, формат - HTML-цвет, #RRGGBBAA)
    STEXT_COLOR             in varchar2 := null, -- Цвет текста заголовка задачи (null - использовать цвет по умолчанию из стилей, формат - HTML-цвет, #RRGGBBAA)
    SBG_PROGRESS_COLOR      in varchar2 := null, -- Цвет заливки прогресса (null - использовать цвет по умолчанию из стилей, формат - HTML-цвет, #RRGGBBAA)
    BREAD_ONLY              in boolean := null,  -- Сроки и прогресс задачи только для чтения (null - как указано в описании диаграммы)
    BREAD_ONLY_DATES        in boolean := null,  -- Сроки задачи только для чтения (null - как указано в описании диаграммы)
    BREAD_ONLY_PROGRESS     in boolean := null   -- Прогресс задачи только для чтения (null - как указано в описании диаграммы)
  ) return                  TGANTT_TASK;         -- Результат работы
  
  /* Добавление значения атрибута к задаче диаграммы Ганта */
  procedure TGANTT_TASK_ADD_ATTR_VAL
  (
    RGANTT                  in TGANTT,                 -- Описание диаграммы
    RTASK                   in out nocopy TGANTT_TASK, -- Описание задачи
    SNAME                   in varchar2,               -- Наименование
    SVALUE                  in varchar2,               -- Значение
    BCLEAR                  in boolean := false        -- Флаг очистки коллекции значений атрибутов (false - не очищать, true - очистить коллекцию перед добавлением)
  );
  
  /* Добавление предшествующей задачи к задаче диаграммы Ганта */
  procedure TGANTT_TASK_ADD_DEPENDENCY
  (
    RTASK                   in out nocopy TGANTT_TASK, -- Описание задачи
    NDEPENDENCY             in number,                 -- Рег. номер предшествующей задачи
    BCLEAR                  in boolean := false        -- Флаг очистки коллекции предшествущих задач (false - не очищать, true - очистить коллекцию перед добавлением)
  );
  
  /* Формирование диаграммы Ганта */
  function TGANTT_MAKE
  (
    STITLE                  in varchar2 := null,           -- Заголовок (null - не отображать)
    NZOOM                   in number := NGANTT_ZOOM_WEEK, -- Текущий масштаб (см. константы NGANTT_ZOOM_*)
    BZOOM_BAR               in boolean := true,            -- Обображать панель масштабирования
    BREAD_ONLY              in boolean := false,           -- Сроки и прогресс задач только для чтения
    BREAD_ONLY_DATES        in boolean := false,           -- Сроки задач только для чтения
    BREAD_ONLY_PROGRESS     in boolean := false            -- Прогресс задач только для чтения
  ) return                  TGANTT;                        -- Результат работы
  
  /* Добавление описания атрибута карточки задачи диаграммы Ганта */
  procedure TGANTT_ADD_TASK_ATTR
  (
    RGANTT                  in out nocopy TGANTT, -- Описание диаграммы Ганта
    SNAME                   in varchar2,          -- Наименование
    SCAPTION                in varchar2,          -- Заголовок
    BVISIBLE                boolean := true,      -- Разрешить отображение
    BCLEAR                  in boolean := false   -- Флаг очистки коллекции атрибутов (false - не очищать, true - очистить коллекцию перед добавлением)
  );
  /* Добавление описания цвета задачи диаграммы Ганта */
  procedure TGANTT_ADD_TASK_COLOR
  (
    RGANTT                  in out nocopy TGANTT, -- Описание диаграммы Ганта
    SBG_COLOR               in varchar2 := null,  -- Цвет заливки задачи (формат - HTML-цвет, #RRGGBBAA)
    STEXT_COLOR             in varchar2 := null,  -- Цвет текста заголовка задачи (формат - HTML-цвет, #RRGGBBAA)
    SBG_PROGRESS_COLOR      in varchar2 := null,  -- Цвет заливки прогресса (формат - HTML-цвет, #RRGGBBAA)
    SDESC                   in varchar2,          -- Описание
    BCLEAR                  in boolean := false   -- Флаг очистки коллекции цветов (false - не очищать, true - очистить коллекцию перед добавлением)
  );
  /* Добавление задачи к диаграмме Ганта */
  procedure TGANTT_ADD_TASK
  (
    RGANTT                  in out nocopy TGANTT, -- Описание диаграммы Ганта
    RTASK                   in TGANTT_TASK,       -- Задача
    BCLEAR                  in boolean := false   -- Флаг очистки коллекции задач диаграммы (false - не очищать, true - очистить коллекцию перед добавлением)
  );
  
  /* Сериализация диаграммы Ганта */
  function TGANTT_TO_XML
  (
    RGANTT                  in TGANTT,     -- Описание диаграммы Ганта
    NINCLUDE_DEF            in number := 1 -- Включить описание заголовка (0 - нет, 1 - да)
  ) return                  clob;          -- XML-описание
  /* Добавление дополнительного атрибута элемента данных графика */
  procedure TCHART_DATASET_ITM_ATTR_VL_ADD
  (
    RATTR_VALS              in out nocopy TCHART_DATASET_ITEM_ATTR_VALS, -- Коллекция дополнительных атрибутов элемента данных графика
    SNAME                   PKG_STD.TSTRING,                             -- Наименование
    SVALUE                  PKG_STD.TSTRING,                             -- Значение
    BCLEAR                  in boolean := false                          -- Флаг очистки коллекции дополнительных атрибутов элемента данных (false - не очищать, true - очистить коллекцию перед добавлением)
  );
  /* Формирование набора данных графика */
  function TCHART_DATASET_MAKE
  (
    SCAPTION                in varchar2,         -- Заголовок
    SBORDER_COLOR           in varchar2 := null, -- Цвет границы элемента данных на графике (null - использовать цвет по умолчанию из стилей, формат - HTML-цвет, #RRGGBBAA)
    SBG_COLOR               in varchar2 := null  -- Цвет заливки элемента данных на графике (null - использовать цвет по умолчанию из стилей, формат - HTML-цвет, #RRGGBBAA)
  ) return                  TCHART_DATASET;      -- Результат работы
  /* Добавление элемента в набор данных графика */
  procedure TCHART_DATASET_ADD_ITEM
  (
    RDATASET                in out nocopy TCHART_DATASET,             -- Описание набора данных графика
    NVALUE                  in number,                                -- Значение элемента данных, отображаемое на графике
    RATTR_VALS              in TCHART_DATASET_ITEM_ATTR_VALS := null, -- Значения дополнительных атрбутов (null - дополнительные атрибуты не определены)
    BCLEAR                  in boolean := false                       -- Флаг очистки коллекции элементов набора данных (false - не очищать, true - очистить коллекцию перед добавлением)
  );
  /* Формирование графика */
  function TCHART_MAKE
  (
    STYPE                   in varchar2,         -- Тип (см. константы SCHART_TYPE_*)
    STITLE                  in varchar2 := null, -- Заголовок (null - не отображать)
    SLGND_POS               in varchar2 := null  -- Расположение легенды (null - не отображать, см. константы SCHART_LGND_POS_*)
  ) return                  TCHART;              -- Результат работы
  /* Добавление метки значения графика */
  procedure TCHART_ADD_LABEL
  (
    RCHART                  in out nocopy TCHART, -- Описание графика
    SLABEL                  in varchar2,          -- Метка значения
    BCLEAR                  in boolean := false   -- Флаг очистки коллекции меток (false - не очищать, true - очистить коллекцию перед добавлением)
  );
  /* Добавление набора данных графика */
  procedure TCHART_ADD_DATASET
  (
    RCHART                  in out nocopy TCHART, -- Описание графика
    RDATASET                in TCHART_DATASET,    -- Набор данных
    BCLEAR                  in boolean := false   -- Флаг очистки коллекции наборов данных (false - не очищать, true - очистить коллекцию перед добавлением)
  );
  /* Сериализация графика */
  function TCHART_TO_XML
  (
    RCHART                  in TCHART,     -- Описание графика
    NINCLUDE_DEF            in number := 1 -- Включить описание заголовка (0 - нет, 1 - да)
  ) return                  clob;          -- XML-описание
  
  /* Формирование задачи циклограммы */
  function TCYCLOGRAM_TASK_MAKE
  (
    NRN                     in number,           -- Рег. номер записи
    SCAPTION                in varchar2,         -- Заголовок
    SNAME                   in varchar2,         -- Наименование
    NLINE_NUMB              in number,           -- Номер строки
    NSTART                  in number,           -- Позиция начала задачи
    NEND                    in number,           -- Позиция конца задачи
    SGROUP                  in varchar2 := null, -- Наименование группы
    SBG_COLOR               in varchar2 := null, -- Цвет заливки задачи (null - использовать цвет по умолчанию из стилей, формат - HTML-цвет, #RRGGBBAA)
    STEXT_COLOR             in varchar2 := null, -- Цвет текста заголовка задачи (null - использовать цвет по умолчанию из стилей, формат - HTML-цвет, #RRGGBBAA)
    SHIGHLIGHT_COLOR        in varchar2 := null  -- Цвет при наведении (null - использовать цвет по умолчанию из стилей, формат - HTML-цвет, #RRGGBBAA)
  ) return                  TCYCLOGRAM_TASK;     -- Результат работы
  
  /* Добавление значения атрибута к задаче циклограммы */
  procedure TCYCLOGRAM_TASK_ADD_ATTR_VAL
  (
    RCYCLOGRAM              in TCYCLOGRAM,                 -- Описание циклограммы
    RTASK                   in out nocopy TCYCLOGRAM_TASK, -- Описание задачи
    SNAME                   in varchar2,                   -- Наименование
    SVALUE                  in varchar2,                   -- Значение
    BCLEAR                  in boolean := false            -- Флаг очистки коллекции значений атрибутов (false - не очищать, true - очистить коллекцию перед добавлением)
  );
  
  /* Формирование циклограммы */
  function TCYCLOGRAM_MAKE
  (
    STITLE                  in varchar2,                          -- Заголовок (null - не отображать)
    NLINE_HEIGHT            in number := NCYCLOGRAM_LINE_HEIGHT,  -- Высота строк
    NZOOM                   in number := NCYCLOGRAM_ZOOM_DEFAULT, -- Текущий масштаб (см. константы NCYCLOGRAM_ZOOM_*)
    BZOOM_BAR               in boolean := true                    -- Обображать панель масштабирования
  ) return                  TCYCLOGRAM;                           -- Результат работы
  
  /* Добавление колонки в циклограмму */
  procedure TCYCLOGRAM_ADD_COLUMN
  (
    RCYCLOGRAM              in out nocopy TCYCLOGRAM, -- Описание циклограммы
    SNAME                   in varchar2,              -- Заголовок колонки
    NSTART                  in number,                -- Позиция начала колонки
    NEND                    in number,                -- Позиция конца колонки
    BCLEAR                  in boolean := false       -- Флаг очистки коллекции колонок циклограммы (false - не очищать, true - очистить коллекцию перед добавлением)
  );
  
  /* Добавление группы в циклограмму */
  procedure TCYCLOGRAM_ADD_GROUP
  (
    RCYCLOGRAM              in out nocopy TCYCLOGRAM,                 -- Описание циклограммы
    SNAME                   in varchar2,                              -- Имя группы
    BHEADER_VISIBLE         in boolean := true,                       -- Признак отображения заголовка группы
    NHEADER_HEIGHT          in number := NCYCLOGRAM_GROUP_DEF_HEIGHT, -- Высота заголовка группы
    NHEADER_WIDTH           in number := NCYCLOGRAM_GROUP_DEF_WIDTH,  -- Ширина заголовка группы
    SHIGHLIGHT_COLOR        in varchar2 := null,                      -- Цвет при наведении (null - использовать цвет по умолчанию из стилей, формат - HTML-цвет, #RRGGBBAA)
    BCLEAR                  in boolean := false                       -- Флаг очистки коллекции групп (false - не очищать, true - очистить коллекцию перед добавлением)
  );
  
  /* Добавление задачи в циклограммы */
  procedure TCYCLOGRAM_ADD_TASK
  (
    RCYCLOGRAM              in out nocopy TCYCLOGRAM, -- Описание циклограммы
    RTASK                   in TCYCLOGRAM_TASK,       -- Задача циклограммы
    BCLEAR                  in boolean := false       -- Флаг очистки коллекции задач (false - не очищать, true - очистить коллекцию перед добавлением)
  );
  
  /* Добавление описания атрибута задачи циклограммы */
  procedure TCYCLOGRAM_ADD_TASK_ATTR
  (
    RCYCLOGRAM              in out nocopy TCYCLOGRAM, -- Описание циклограммы
    SNAME                   in varchar2,              -- Наименование
    SCAPTION                in varchar2,              -- Заголовок
    BVISIBLE                boolean := true,          -- Разрешить отображение
    BCLEAR                  in boolean := false       -- Флаг очистки коллекции атрибутов (false - не очищать, true - очистить коллекцию перед добавлением)
  );
  
  /* Сериализация циклограммы */
  function TCYCLOGRAM_TO_XML
  (
    RCYCLOGRAM              in TCYCLOGRAM, -- Описание циклограммы
    NINCLUDE_DEF            in number := 1 -- Включить описание колонок (0 - нет, 1 - да)
  ) return                  clob;          -- XML-описание
end PKG_P8PANELS_VISUAL;
/
create or replace package body PKG_P8PANELS_VISUAL as
  /* Константы - тэги запросов */
  SRQ_TAG_XROOT               constant PKG_STD.TSTRING := 'XROOT';     -- Тэг для корня данных запроса
  SRQ_TAG_XFILTERS            constant PKG_STD.TSTRING := 'filters';   -- Тэг для строк данных
  SRQ_TAG_XORDERS             constant PKG_STD.TSTRING := 'orders';    -- Тэг для описания колонок
  SRQ_TAG_SNAME               constant PKG_STD.TSTRING := 'name';      -- Тэг для наименования
  SRQ_TAG_SDIRECTION          constant PKG_STD.TSTRING := 'direction'; -- Тэг для направления
  SRQ_TAG_SFROM               constant PKG_STD.TSTRING := 'from';      -- Тэг для значения "с"
  SRQ_TAG_STO                 constant PKG_STD.TSTRING := 'to';        -- Тэг для значения "по"
  /* Константы - тэги ответов */
  SRESP_TAG_XDATA             constant PKG_STD.TSTRING := 'XDATA';        -- Тэг для корня описания данных
  SRESP_TAG_XCHART            constant PKG_STD.TSTRING := 'XCHART';       -- Тэг для описания графика
  SRESP_TAG_XDATA_GRID        constant PKG_STD.TSTRING := 'XDATA_GRID';   -- Тэг для описания таблицы данных
  SRESP_TAG_XCYCLOGRAM        constant PKG_STD.TSTRING := 'XCYCLOGRAM';   -- Тэг для описания циклограммы
  SRESP_TAG_XGANTT            constant PKG_STD.TSTRING := 'XGANTT';       -- Тэг для описания диаграммы Ганта
  
  /* Константы - атрибуты ответов (универсальные) */
  SRESP_ATTR_NAME             constant PKG_STD.TSTRING := 'name';           -- Атрибут для наименования
  SRESP_ATTR_CAPTION          constant PKG_STD.TSTRING := 'caption';        -- Атрибут для подписи
  SRESP_ATTR_DATA_TYPE        constant PKG_STD.TSTRING := 'dataType';       -- Атрибут для типа данных
  SRESP_ATTR_VISIBLE          constant PKG_STD.TSTRING := 'visible';        -- Атрибут для флага видимости
  SRESP_ATTR_TITLE            constant PKG_STD.TSTRING := 'title';          -- Атрибут для заголовка
  SRESP_ATTR_ZOOM             constant PKG_STD.TSTRING := 'zoom';           -- Атрибут для масштаба
  SRESP_ATTR_ID               constant PKG_STD.TSTRING := 'id';             -- Атрибут для идентификатора
  SRESP_ATTR_START            constant PKG_STD.TSTRING := 'start';          -- Атрибут для даты начала
  SRESP_ATTR_END              constant PKG_STD.TSTRING := 'end';            -- Атрибут для даты окончания
  SRESP_ATTR_RN               constant PKG_STD.TSTRING := 'rn';             -- Атрибут для рег. номера
  SRESP_ATTR_NUMB             constant PKG_STD.TSTRING := 'numb';           -- Атрибут для номера
  SRESP_ATTR_FULL_NAME        constant PKG_STD.TSTRING := 'fullName';       -- Атрибут для полного наименования
  SRESP_ATTR_DESC             constant PKG_STD.TSTRING := 'desc';           -- Атрибут для описания
  SRESP_ATTR_TYPE             constant PKG_STD.TSTRING := 'type';           -- Атрибут для типа
  SRESP_ATTR_HINT             constant PKG_STD.TSTRING := 'hint';           -- Атрибут для подсказки
  SRESP_ATTR_GROUP_NAME       constant PKG_STD.TSTRING := 'groupName';      -- Атрибут для наименования группы
  SRESP_ATTR_PARENT           constant PKG_STD.TSTRING := 'parent';         -- Атрибут для ссылки на родителя
  SRESP_ATTR_EXPANDABLE       constant PKG_STD.TSTRING := 'expandable';     -- Атрибут для доступности действия сокрытия/отображения
  SRESP_ATTR_EXPANDED         constant PKG_STD.TSTRING := 'expanded';       -- Атрибут для флага сокрытия/отображения
  SRESP_ATTR_FIXED_HEADER     constant PKG_STD.TSTRING := 'fixedHeader';    -- Атрибут для флага фиксации заголовка
  SRESP_ATTR_FIXED_COLUMNS    constant PKG_STD.TSTRING := 'fixedColumns';   -- Атрибут для количества фиксированных колонок
  SRESP_ATTR_WIDTH            constant PKG_STD.TSTRING := 'width';          -- Атрибут для ширины
  SRESP_ATTR_HEIGHT           constant PKG_STD.TSTRING := 'height';         -- Атрибут для высоты
  SRESP_ATTR_COLUMNS          constant PKG_STD.TSTRING := 'columns';        -- Атрибут для колонок
  SRESP_ATTR_TASKS            constant PKG_STD.TSTRING := 'tasks';          -- Атрибут для задач
  SRESP_ATTR_HL_COLOR         constant PKG_STD.TSTRING := 'highlightColor'; -- Атрибут для цвета подсветки
  SRESP_ATTR_ZOOM_BAR         constant PKG_STD.TSTRING := 'zoomBar';        -- Атрибут для флага отображения панели масштаба
  SRESP_ATTR_ROWS             constant PKG_STD.TSTRING := 'rows';           -- Атрибут для строк данных
  SRESP_ATTR_COLUMNS_DEF      constant PKG_STD.TSTRING := 'columnsDef';     -- Атрибут для описания колонок
  SRESP_ATTR_GROUPS           constant PKG_STD.TSTRING := 'groups';         -- Атрибут для описания групп
  
  /* Константы - атрибуты ответов (таблица данных) */
  SRESP_ATTR_DT_ORDER         constant PKG_STD.TSTRING := 'order';  -- Атрибут для флага сортировки
  SRESP_ATTR_DT_FILTER        constant PKG_STD.TSTRING := 'filter'; -- Атрибут для флага отбора
  SRESP_ATTR_DT_COLUMN_VALUES constant PKG_STD.TSTRING := 'values'; -- Атрибут для предопределённых значений
  /* Константы - атрибуты ответов (диаграмма Ганта) */  
  SRESP_ATTR_TASK_PROGRESS     constant PKG_STD.TSTRING := 'progress';         -- Атрибут для прогресса задачи
  SRESP_ATTR_TASK_DEPS         constant PKG_STD.TSTRING := 'dependencies';     -- Атрибут для зависимостей задачи
  SRESP_ATTR_TASK_RO           constant PKG_STD.TSTRING := 'readOnly';         -- Атрибут для флага задачи "только для чтения"
  SRESP_ATTR_TASK_RO_PRGRS     constant PKG_STD.TSTRING := 'readOnlyProgress'; -- Атрибут для флага задачи "прогресс только для чтения"
  SRESP_ATTR_TASK_RO_DATES     constant PKG_STD.TSTRING := 'readOnlyDates';    -- Атрибут для флага задачи "даты только для чтения"
  SRESP_ATTR_TASK_BG_COLOR     constant PKG_STD.TSTRING := 'bgColor';          -- Атрибут для цвета заголовка задачи
  SRESP_ATTR_TASK_TEXT_COLOR   constant PKG_STD.TSTRING := 'textColor';        -- Атрибут для цвета текста задачи
  SRESP_ATTR_TASK_BG_PRG_COLOR constant PKG_STD.TSTRING := 'bgProgressColor';  -- Атрибут для цвета прогресса задачи
  SRESP_ATTR_TASK_ATTRIBUTES   constant PKG_STD.TSTRING := 'taskAttributes';   -- Атрибут для коллекции атрибутов задачи
  SRESP_ATTR_TASK_COLORS       constant PKG_STD.TSTRING := 'taskColors';       -- Атрибут для коллекции цветов задачи
  /* Константы - атрибуты ответов (графики) */  
  SRESP_ATTR_CHART_LGND_POS   constant PKG_STD.TSTRING := 'legendPosition';  -- Атрибут для места размешения легенды графика
  SRESP_ATTR_CHART_LABELS     constant PKG_STD.TSTRING := 'labels';          -- Атрибут для меток графика
  SRESP_ATTR_CHART_DATASETS   constant PKG_STD.TSTRING := 'datasets';        -- Атрибут для наборов данных графика
  SRESP_ATTR_CHART_DS_LABEL   constant PKG_STD.TSTRING := 'label';           -- Атрибут для метки набора данных графика
  SRESP_ATTR_CHART_DS_BR_CLR  constant PKG_STD.TSTRING := 'borderColor';     -- Атрибут для цвета границы элемента набора данных графика
  SRESP_ATTR_CHART_DS_BG_CLR  constant PKG_STD.TSTRING := 'backgroundColor'; -- Атрибут для цвета заливки элемента набора данных графика
  SRESP_ATTR_CHART_DS_DATA    constant PKG_STD.TSTRING := 'data';            -- Атрибут для коллекции значений элементов набора данных
  SRESP_ATTR_CHART_DS_ITEMS   constant PKG_STD.TSTRING := 'items';           -- Атрибут для коллекции элементов набора данных
  SRESP_ATTR_CHART_DS_I_VAL   constant PKG_STD.TSTRING := 'value';           -- Атрибут для значения элемента набора данных
  
  /* Константы - атрибуты ответов (циклограмма) */
  SRESP_ATTR_CG_TASK_LINE     constant PKG_STD.TSTRING := 'lineNumb';   -- Атрибут для номера строки (по оси Y)
  SRESP_ATTR_CG_LINE_HEIGHT   constant PKG_STD.TSTRING := 'lineHeight'; -- Атрибут для высоты строк 
  
  /* Константы - параметры условий отбора */
  SCOND_FROM_POSTFIX          constant PKG_STD.TSTRING := 'From'; -- Постфикс наименования нижней границы условия отбора
  SCOND_TO_POSTFIX            constant PKG_STD.TSTRING := 'To';   -- Постфикс наименования верхней границы условия отбора
  /* Расчет диапаона выдаваемых записей */
  procedure UTL_ROWS_LIMITS_CALC
  (
    NPAGE_NUMBER            in number,  -- Номер страницы (игнорируется при NPAGE_SIZE=0)
    NPAGE_SIZE              in number,  -- Количество записей на странице (0 - все)
    NROW_FROM               out number, -- Нижняя граница диапазона
    NROW_TO                 out number  -- Верхняя граница диапазона
  )
  is
  begin
    if (COALESCE(NPAGE_SIZE, 0) <= 0)
    then
      NROW_FROM := 1;
      NROW_TO   := 1000000000;
    else
      NROW_FROM := COALESCE(NPAGE_NUMBER, 1) * NPAGE_SIZE - NPAGE_SIZE + 1;
      NROW_TO   := COALESCE(NPAGE_NUMBER, 1) * NPAGE_SIZE;
    end if;
  end UTL_ROWS_LIMITS_CALC;
  
  /* Формирование наименования условия отбора для нижней границы */
  function UTL_COND_NAME_MAKE_FROM
  (
    SNAME                   in varchar2 -- Наименование колонки
  ) return                  varchar2    -- Результат
  is
  begin
    return SNAME || SCOND_FROM_POSTFIX;
  end UTL_COND_NAME_MAKE_FROM;
  /* Формирование наименования условия отбора для верхней границы */
  function UTL_COND_NAME_MAKE_TO
  (
    SNAME                   in varchar2 -- Наименование колонки
  ) return                  varchar2    -- Результат
  is
  begin
    return SNAME || SCOND_TO_POSTFIX;
  end UTL_COND_NAME_MAKE_TO;
  
  /* Формирование значения */
  function TDG_COL_VAL_MAKE
  (
    SVALUE                  in varchar2, -- Значение (строка)
    NVALUE                  in number,   -- Значение (число)
    DVALUE                  in date      -- Значение (дата)
  ) return                  TDG_COL_VAL  -- Результат работы
  is
    RRES                    TDG_COL_VAL; -- Буфер для результата
  begin
    /* Формируем объект */
    RRES.SVALUE := SVALUE;
    RRES.NVALUE := NVALUE;
    RRES.DVALUE := DVALUE;
    /* Возвращаем результат */
    return RRES;
  end TDG_COL_VAL_MAKE;
  /* Добавление значения в коллекцию */
  procedure TDG_COL_VALS_ADD
  (
    RCOL_VALS               in out nocopy TDG_COL_VALS, -- Коллекция значений
    SVALUE                  in varchar2 := null,        -- Значение (строка)
    NVALUE                  in number := null,          -- Значение (число)
    DVALUE                  in date := null,            -- Значение (дата)
    BCLEAR                  in boolean := false         -- Флаг очистки коллекции (false - не очищать, true - очистить коллекцию перед добавлением)
  )
  is
  begin
    /* Инициализируем коллекцию если необходимо */
    if ((RCOL_VALS is null) or (BCLEAR)) then
      RCOL_VALS := TDG_COL_VALS();
    end if;
    /* Добавляем элемент */
    RCOL_VALS.EXTEND();
    RCOL_VALS(RCOL_VALS.LAST) := TDG_COL_VAL_MAKE(SVALUE => SVALUE, NVALUE => NVALUE, DVALUE => DVALUE);
  end TDG_COL_VALS_ADD;
  
  /* Формирование описания колонки */
  function TDG_COL_DEF_MAKE
  (
    SNAME                   in varchar2,                   -- Наименование
    SCAPTION                in varchar2,                   -- Заголовок
    SDATA_TYPE              in varchar2 := SDATA_TYPE_STR, -- Тип данных (см. константы SDATA_TYPE_*)
    SCOND_FROM              in varchar2 := null,           -- Наименование нижней границы условия отбора (null - используется UTL_COND_NAME_MAKE_FROM)
    SCOND_TO                in varchar2 := null,           -- Наименование верхней границы условия отбора (null - используется UTL_COND_NAME_MAKE_TO)
    BVISIBLE                in boolean := true,            -- Разрешить отображение
    BORDER                  in boolean := false,           -- Разрешить сортировку
    BFILTER                 in boolean := false,           -- Разрешить отбор
    RCOL_VALS               in TDG_COL_VALS := null,       -- Предопределённые значения
    SHINT                   in varchar2 := null,           -- Текст всплывающей подсказки
    SPARENT                 in varchar2 := null,           -- Наименование родительской колонки
    BEXPANDABLE             in boolean := false,           -- Разрешить сокрытие/отображение дочерних колонок
    BEXPANDED               in boolean := true,            -- Отобразить/скрыть дочерние колонки
    NWIDTH                  in number := null              -- Ширина колонки (обязательно для фиксированных)
  ) return                  TDG_COL_DEF                    -- Результат работы
  is
    RRES                    TDG_COL_DEF;                   -- Буфер для результата
  begin
    /* Формируем объект */
    RRES.SNAME       := SNAME;
    RRES.SCAPTION    := SCAPTION;
    RRES.SDATA_TYPE  := COALESCE(SDATA_TYPE, SDATA_TYPE_STR);
    RRES.SCOND_FROM  := COALESCE(SCOND_FROM, UTL_COND_NAME_MAKE_FROM(SNAME => SNAME));
    RRES.SCOND_TO    := COALESCE(SCOND_TO, UTL_COND_NAME_MAKE_TO(SNAME => SNAME));
    RRES.BVISIBLE    := COALESCE(BVISIBLE, true);
    RRES.BORDER      := COALESCE(BORDER, false);
    RRES.BFILTER     := COALESCE(BFILTER, false);
    RRES.RCOL_VALS   := COALESCE(RCOL_VALS, TDG_COL_VALS());
    RRES.SHINT       := SHINT;
    RRES.SPARENT     := SPARENT;
    RRES.BEXPANDABLE := COALESCE(BEXPANDABLE, false);
    RRES.BEXPANDED   := COALESCE(BEXPANDED, true);
    RRES.NWIDTH      := NWIDTH;
    /* Возвращаем результат */
    return RRES;
  end TDG_COL_DEF_MAKE;
  
  /* Добавление описания колонки в коллекцию */
  procedure TDG_COL_DEFS_ADD
  (
    RCOL_DEFS               in out nocopy TDG_COL_DEFS,    -- Коллекция описаний колонок
    SNAME                   in varchar2,                   -- Наименование
    SCAPTION                in varchar2,                   -- Заголовок
    SDATA_TYPE              in varchar2 := SDATA_TYPE_STR, -- Тип данных (см. константы SDATA_TYPE_*)
    SCOND_FROM              in varchar2 := null,           -- Наименование нижней границы условия отбора (null - используется UTL_COND_NAME_MAKE_FROM)
    SCOND_TO                in varchar2 := null,           -- Наименование верхней границы условия отбора (null - используется UTL_COND_NAME_MAKE_TO)
    BVISIBLE                in boolean := true,            -- Разрешить отображение
    BORDER                  in boolean := false,           -- Разрешить сортировку
    BFILTER                 in boolean := false,           -- Разрешить отбор
    RCOL_VALS               in TDG_COL_VALS := null,       -- Предопределённые значения
    SHINT                   in varchar2 := null,           -- Текст всплывающей подсказки
    SPARENT                 in varchar2 := null,           -- Наименование родительской колонки
    BEXPANDABLE             in boolean := false,           -- Разрешить сокрытие/отображение дочерних колонок
    BEXPANDED               in boolean := true,            -- Отобразить/скрыть дочерние колонки
    NWIDTH                  in number := null,             -- Ширина колонки (обязательно для фиксированных)
    BCLEAR                  in boolean := false            -- Флаг очистки коллекции (false - не очищать, true - очистить коллекцию перед добавлением)
  )
  is
  begin
    /* Инициализируем коллекцию если необходимо */
    if ((RCOL_DEFS is null) or (BCLEAR)) then
      RCOL_DEFS := TDG_COL_DEFS();
    end if;
    /* Добавляем элемент */
    RCOL_DEFS.EXTEND();
    RCOL_DEFS(RCOL_DEFS.LAST) := TDG_COL_DEF_MAKE(SNAME       => SNAME,
                                                  SCAPTION    => SCAPTION,
                                                  SDATA_TYPE  => SDATA_TYPE,
                                                  SCOND_FROM  => SCOND_FROM,
                                                  SCOND_TO    => SCOND_TO,
                                                  BVISIBLE    => BVISIBLE,
                                                  BORDER      => BORDER,
                                                  BFILTER     => BFILTER,
                                                  RCOL_VALS   => RCOL_VALS,
                                                  SHINT       => SHINT,
                                                  SPARENT     => SPARENT,
                                                  BEXPANDABLE => BEXPANDABLE,
                                                  BEXPANDED   => BEXPANDED,
                                                  NWIDTH      => NWIDTH);
  end TDG_COL_DEFS_ADD;
  
  /* Поиск описания колонки по наименованию */
  function TDG_COL_DEFS_FIND
  (
    RCOL_DEFS               in TDG_COL_DEFS, -- Описание колонок таблицы данных
    SNAME                   in varchar2      -- Наименование
  ) return                  TDG_COL_DEF      -- Найденное описание (null - если не нашли)
  is
  begin
    /* Обходим колонки из коллекции описаний */
    if ((RCOL_DEFS is not null) and (RCOL_DEFS.COUNT > 0)) then
      for I in RCOL_DEFS.FIRST .. RCOL_DEFS.LAST
      loop
        if (RCOL_DEFS(I).SNAME = SNAME) then
          return RCOL_DEFS(I);
        end if;
      end loop;
    end if;
    /* Ничего не нашли */
    return null;
  end TDG_COL_DEFS_FIND;
  
  /* Сериализация описания колонок таблицы данных */
  procedure TDG_COL_DEFS_TO_XML
  (
    RCOL_DEFS               in TDG_COL_DEFS -- Описание колонок таблицы данных
  )
  is    
  begin
    /* Обходим колонки из коллекции */
    if ((RCOL_DEFS is not null) and (RCOL_DEFS.COUNT > 0)) then
      for I in RCOL_DEFS.FIRST .. RCOL_DEFS.LAST
      loop
        /* Открываем описание колонки */
        PKG_XFAST.DOWN_NODE(SNAME => SRESP_ATTR_COLUMNS_DEF);
        /* Атрибуты колонки */
        PKG_XFAST.ATTR(SNAME => SRESP_ATTR_NAME, SVALUE => RCOL_DEFS(I).SNAME);
        PKG_XFAST.ATTR(SNAME => SRESP_ATTR_CAPTION, SVALUE => RCOL_DEFS(I).SCAPTION);
        PKG_XFAST.ATTR(SNAME => SRESP_ATTR_DATA_TYPE, SVALUE => RCOL_DEFS(I).SDATA_TYPE);
        PKG_XFAST.ATTR(SNAME => SRESP_ATTR_VISIBLE, BVALUE => RCOL_DEFS(I).BVISIBLE);
        PKG_XFAST.ATTR(SNAME => SRESP_ATTR_DT_ORDER, BVALUE => RCOL_DEFS(I).BORDER);
        PKG_XFAST.ATTR(SNAME => SRESP_ATTR_DT_FILTER, BVALUE => RCOL_DEFS(I).BFILTER);
        PKG_XFAST.ATTR(SNAME => SRESP_ATTR_HINT, SVALUE => RCOL_DEFS(I).SHINT);
        PKG_XFAST.ATTR(SNAME => SRESP_ATTR_PARENT, SVALUE => RCOL_DEFS(I).SPARENT);
        PKG_XFAST.ATTR(SNAME => SRESP_ATTR_EXPANDABLE, BVALUE => RCOL_DEFS(I).BEXPANDABLE);
        PKG_XFAST.ATTR(SNAME => SRESP_ATTR_EXPANDED, BVALUE => RCOL_DEFS(I).BEXPANDED);
        if (RCOL_DEFS(I).NWIDTH is not null) then
          PKG_XFAST.ATTR(SNAME => SRESP_ATTR_WIDTH, NVALUE => RCOL_DEFS(I).NWIDTH);
        end if;
        /* Предопределённые значения */
        if (RCOL_DEFS(I).RCOL_VALS is not null) and (RCOL_DEFS(I).RCOL_VALS.COUNT > 0) then
          for V in RCOL_DEFS(I).RCOL_VALS.FIRST .. RCOL_DEFS(I).RCOL_VALS.LAST
          loop
            /* Открываем описание предопределённого значения */
            PKG_XFAST.DOWN_NODE(SNAME => SRESP_ATTR_DT_COLUMN_VALUES);
            /* Значение */
            case RCOL_DEFS(I).SDATA_TYPE
              when SDATA_TYPE_STR then
                PKG_XFAST.VALUE(SVALUE => RCOL_DEFS(I).RCOL_VALS(V).SVALUE);
              when SDATA_TYPE_NUMB then
                PKG_XFAST.VALUE(NVALUE => RCOL_DEFS(I).RCOL_VALS(V).NVALUE);
              when SDATA_TYPE_DATE then
                PKG_XFAST.VALUE(DVALUE => RCOL_DEFS(I).RCOL_VALS(V).DVALUE);
              else
                P_EXCEPTION(0,
                            'Описание колонки "%s" таблицы данных содержит неподдерживаемый тип данных ("%s").',
                            COALESCE(RCOL_DEFS(I).SNAME, '<НЕ ОПРЕДЕЛЕНА>'),
                            COALESCE(RCOL_DEFS(I).SDATA_TYPE, '<НЕ ОПРЕДЕЛЁН>'));
            end case;
            /* Закрываем описание предопределённого значения */
            PKG_XFAST.UP();
          end loop;
        end if;
        /* Закрываем описание колонки */
        PKG_XFAST.UP();
      end loop;
    end if;
  end TDG_COL_DEFS_TO_XML;
  
  /* Формирование колонки */
  function TDG_COL_MAKE
  (
    SNAME                   in varchar2,         -- Наименование колонки
    SVALUE                  in varchar2 := null, -- Значение (строка)
    NVALUE                  in number := null,   -- Значение (число)
    DVALUE                  in date := null      -- Значение (дата)
  ) return                  TDG_COL              -- Результат работы
  is
    RRES                    TDG_COL;             -- Буфер для результата
  begin
    /* Формируем объект */
    RRES.SNAME    := SNAME;
    RRES.RCOL_VAL := TDG_COL_VAL_MAKE(SVALUE => SVALUE, NVALUE => NVALUE, DVALUE => DVALUE);
    /* Возвращаем результат */
    return RRES;
  end TDG_COL_MAKE;
  
  /* Добавление колонки в коллекцию */
  procedure TDG_COLS_ADD
  (
    RCOLS                   in out nocopy TDG_COLS, -- Коллекция колонок
    SNAME                   in varchar2,            -- Наименование колонки
    SVALUE                  in varchar2 := null,    -- Значение (строка)
    NVALUE                  in number := null,      -- Значение (число)
    DVALUE                  in date := null,        -- Значение (дата)
    BCLEAR                  in boolean := false     -- Флаг очистки коллекции (false - не очищать, true - очистить коллекцию перед добавлением)
  )
  is
  begin
    /* Инициализируем коллекцию если необходимо */
    if ((RCOLS is null) or (BCLEAR)) then
      RCOLS := TDG_COLS();
    end if;
    /* Добавляем элемент */
    RCOLS.EXTEND();
    RCOLS(RCOLS.LAST) := TDG_COL_MAKE(SNAME => SNAME, SVALUE => SVALUE, NVALUE => NVALUE, DVALUE => DVALUE);
  end TDG_COLS_ADD;
  
  /* Формирование описания группы */
  function TDG_GROUP_MAKE
  (
    SNAME                   in varchar2,        -- Наименование
    SCAPTION                in varchar2,        -- Заголовок
    BEXPANDABLE             in boolean := true, -- Разрешить сокрытие/отображение дочерних
    BEXPANDED               in boolean := true  -- Отобразить/скрыть дочерние
  ) return                  TDG_GROUP           -- Результат работы
  is
    RRES                    TDG_GROUP;          -- Буфер для результата
  begin
    /* Формируем объект */
    RRES.SNAME       := SNAME;
    RRES.SCAPTION    := SCAPTION;
    RRES.BEXPANDABLE := COALESCE(BEXPANDABLE, true);
    RRES.BEXPANDED   := COALESCE(BEXPANDED, true);
    /* Возвращаем результат */
    return RRES;
  end TDG_GROUP_MAKE;
  
  /* Добавление описания группы в коллекцию */
  procedure TDG_GROUPS_ADD
  (
    RGROUPS                 in out nocopy TDG_GROUPS, -- Коллекция описаний колонок
    SNAME                   in varchar2,              -- Наименование
    SCAPTION                in varchar2,              -- Заголовок
    BEXPANDABLE             in boolean := false,      -- Разрешить сокрытие/отображение дочерних
    BEXPANDED               in boolean := true,       -- Отобразить/скрыть дочерние
    BCLEAR                  in boolean := false       -- Флаг очистки коллекции (false - не очищать, true - очистить коллекцию перед добавлением)
  )
  is
    BFND                    boolean := false;         -- Флаг наличия группы в коллекции
  begin
    /* Инициализируем коллекцию если необходимо */
    if ((RGROUPS is null) or (BCLEAR)) then
      RGROUPS := TDG_GROUPS();
    end if;
    /* Проверим наличие */
    if (RGROUPS.COUNT > 0) then
      for I in RGROUPS.FIRST .. RGROUPS.LAST
      loop
        if (RGROUPS(I).SNAME = SNAME) then
          /* Элемент найден - обновим */
          BFND := true;
          RGROUPS(I) := TDG_GROUP_MAKE(SNAME       => SNAME,
                                       SCAPTION    => SCAPTION,
                                       BEXPANDABLE => BEXPANDABLE,
                                       BEXPANDED   => BEXPANDED);
          exit;
        end if;
      end loop;
    end if;
    /* Добавляем элемент если такого нет */
    if (not BFND) then
      RGROUPS.EXTEND();
      RGROUPS(RGROUPS.LAST) := TDG_GROUP_MAKE(SNAME       => SNAME,
                                              SCAPTION    => SCAPTION,
                                              BEXPANDABLE => BEXPANDABLE,
                                              BEXPANDED   => BEXPANDED);
    end if;
  end TDG_GROUPS_ADD;
  
  /* Сериализация описания групп таблицы данных */
  procedure TDG_GROUPS_TO_XML
  (
    RGROUPS                 in TDG_GROUPS  -- Описание групп таблицы данных
  )
  is    
  begin
    /* Обходим группы из коллекции */
    if ((RGROUPS is not null) and (RGROUPS.COUNT > 0)) then
      for I in RGROUPS.FIRST .. RGROUPS.LAST
      loop
        /* Открываем описание группы */
        PKG_XFAST.DOWN_NODE(SNAME => SRESP_ATTR_GROUPS);
        /* Атрибуты группы */
        PKG_XFAST.ATTR(SNAME => SRESP_ATTR_NAME, SVALUE => RGROUPS(I).SNAME);
        PKG_XFAST.ATTR(SNAME => SRESP_ATTR_CAPTION, SVALUE => RGROUPS(I).SCAPTION);
        PKG_XFAST.ATTR(SNAME => SRESP_ATTR_EXPANDABLE, BVALUE => RGROUPS(I).BEXPANDABLE);
        PKG_XFAST.ATTR(SNAME => SRESP_ATTR_EXPANDED, BVALUE => RGROUPS(I).BEXPANDED);
        /* Закрываем описание группы */
        PKG_XFAST.UP();
      end loop;
    end if;
  end TDG_GROUPS_TO_XML;
  
  /* Формирование строки */
  function TDG_ROW_MAKE
  (
    SGROUP                  in varchar2 := null -- Наименование группы
  )
  return                    TDG_ROW             -- Результат работы
  is
    RRES                    TDG_ROW;            -- Буфер для результата
  begin
    /* Формируем объект */
    RRES.SGROUP := SGROUP;
    RRES.RCOLS  := TDG_COLS();
    /* Возвращаем результат */
    return RRES;
  end TDG_ROW_MAKE;
  
  /* Добавление колонки к строке */
  procedure TDG_ROW_ADD_COL
  (
    RROW                    in out nocopy TDG_ROW, -- Строка
    SNAME                   in varchar2,           -- Наименование колонки
    SVALUE                  in varchar2 := null,   -- Значение (строка)
    NVALUE                  in number := null,     -- Значение (число)
    DVALUE                  in date := null,       -- Значение (дата)
    BCLEAR                  in boolean := false    -- Флаг очистки коллекции (false - не очищать, true - очистить коллекцию перед добавлением)
  )
  is
  begin
    /* Сформируем колонку и добавим её к коллекции колонок строки */
    TDG_COLS_ADD(RCOLS  => RROW.RCOLS,
                 SNAME  => SNAME,
                 SVALUE => SVALUE,
                 NVALUE => NVALUE,
                 DVALUE => DVALUE,
                 BCLEAR => BCLEAR);
  end TDG_ROW_ADD_COL;
  
  /* Добавление строковой колонки к строке из курсора динамического запроса */
  procedure TDG_ROW_ADD_CUR_COLS
  (
    RROW                    in out nocopy TDG_ROW, -- Строка
    SNAME                   in varchar2,           -- Наименование колонки
    ICURSOR                 in integer,            -- Курсор
    NPOSITION               in number,             -- Номер колонки в курсоре
    BCLEAR                  in boolean := false    -- Флаг очистки коллекции (false - не очищать, true - очистить коллекцию перед добавлением)
  )
  is
    SVALUE                  PKG_STD.TLSTRING;      -- Буфер для значения курсора
  begin
    /* Читаем данные из курсора */
    PKG_SQL_DML.COLUMN_VALUE_STR(ICURSOR => ICURSOR, IPOSITION => NPOSITION, SVALUE => SVALUE);
    /* Сформируем колонку и добавим её к коллекции колонок строки */
    TDG_COLS_ADD(RCOLS  => RROW.RCOLS,
                 SNAME  => SNAME,
                 SVALUE => SVALUE,
                 NVALUE => null,
                 DVALUE => null,
                 BCLEAR => BCLEAR);
  end TDG_ROW_ADD_CUR_COLS;
  /* Добавление числовой колонки к строке из курсора динамического запроса */
  procedure TDG_ROW_ADD_CUR_COLN
  (
    RROW                    in out nocopy TDG_ROW, -- Строка
    SNAME                   in varchar2,           -- Наименование колонки
    ICURSOR                 in integer,            -- Курсор
    NPOSITION               in number,             -- Номер колонки в курсоре
    BCLEAR                  in boolean := false    -- Флаг очистки коллекции (false - не очищать, true - очистить коллекцию перед добавлением)
  )
  is
    NVALUE                  PKG_STD.TLNUMBER;      -- Буфер для значения курсора
  begin
    /* Читаем данные из курсора */
    PKG_SQL_DML.COLUMN_VALUE_NUM(ICURSOR => ICURSOR, IPOSITION => NPOSITION, NVALUE => NVALUE);
    /* Сформируем колонку и добавим её к коллекции колонок строки */
    TDG_COLS_ADD(RCOLS  => RROW.RCOLS,
                 SNAME  => SNAME,
                 SVALUE => null,
                 NVALUE => NVALUE,
                 DVALUE => null,
                 BCLEAR => BCLEAR);
  end TDG_ROW_ADD_CUR_COLN;
  
  /* Добавление колонки типа "дата" к строке из курсора динамического запроса */
  procedure TDG_ROW_ADD_CUR_COLD
  (
    RROW                    in out nocopy TDG_ROW, -- Строка
    SNAME                   in varchar2,           -- Наименование колонки
    ICURSOR                 in integer,            -- Курсор
    NPOSITION               in number,             -- Номер колонки в курсоре
    BCLEAR                  in boolean := false    -- Флаг очистки коллекции (false - не очищать, true - очистить коллекцию перед добавлением)
  )
  is
    DVALUE                  PKG_STD.TLDATE;        -- Буфер для значения курсора
  begin
    /* Читаем данные из курсора */
    PKG_SQL_DML.COLUMN_VALUE_DATE(ICURSOR => ICURSOR, IPOSITION => NPOSITION, DVALUE => DVALUE);
    /* Сформируем колонку и добавим её к коллекции колонок строки */
    TDG_COLS_ADD(RCOLS  => RROW.RCOLS,
                 SNAME  => SNAME,
                 SVALUE => null,
                 NVALUE => null,
                 DVALUE => DVALUE,
                 BCLEAR => BCLEAR);
  end TDG_ROW_ADD_CUR_COLD;
  
  /* Сериализация строки данных таблицы данных */
  procedure TDG_ROWS_TO_XML
  (
    RCOL_DEFS               in TDG_COL_DEFS, -- Описание колонок таблицы данных
    RROWS                   in TDG_ROWS      -- Строки таблицы данных
  )
  is  
    RCOL_DEF                TDG_COL_DEF;     -- Описание текущей сериализуемой колонки
  begin
    /* Обходим строки из коллекции */
    if ((RROWS is not null) and (RROWS.COUNT > 0)) then
      for I in RROWS.FIRST .. RROWS.LAST
      loop
        /* Открываем строку */
        PKG_XFAST.DOWN_NODE(SNAME => SRESP_ATTR_ROWS);
        /* Если указана группа - добавим её */
        if (RROWS(I).SGROUP is not null) then
          PKG_XFAST.ATTR(SNAME => SRESP_ATTR_GROUP_NAME, SVALUE => RROWS(I).SGROUP);
        end if;
        /* Обходим колонки строки */
        if ((RROWS(I).RCOLS is not null) and (RROWS(I).RCOLS.COUNT > 0)) then
          for J in RROWS(I).RCOLS.FIRST .. RROWS(I).RCOLS.LAST
          loop
            /* Найдём описание колонки */
            RCOL_DEF := TDG_COL_DEFS_FIND(RCOL_DEFS => RCOL_DEFS, SNAME => RROWS(I).RCOLS(J).SNAME);
            if (RCOL_DEF.SNAME is null) then
              P_EXCEPTION(0,
                          'Описание колонки "%s" таблицы данных не определено.',
                          RROWS(I).RCOLS(J).SNAME);
            end if;
            /* Добавлением значение колонки как атрибут строки */
            case RCOL_DEF.SDATA_TYPE
              when SDATA_TYPE_STR then
                PKG_XFAST.ATTR(SNAME => RROWS(I).RCOLS(J).SNAME, SVALUE => RROWS(I).RCOLS(J).RCOL_VAL.SVALUE);
              when SDATA_TYPE_NUMB then
                PKG_XFAST.ATTR(SNAME => RROWS(I).RCOLS(J).SNAME, NVALUE => RROWS(I).RCOLS(J).RCOL_VAL.NVALUE);
              when SDATA_TYPE_DATE then
                PKG_XFAST.ATTR(SNAME => RROWS(I).RCOLS(J).SNAME, DVALUE => RROWS(I).RCOLS(J).RCOL_VAL.DVALUE);
              else
                P_EXCEPTION(0,
                            'Описание колонки "%s" таблицы данных содержит неподдерживаемый тип данных ("%s").',
                            RCOL_DEFS(I).SNAME,
                            COALESCE(RCOL_DEFS(I).SDATA_TYPE, '<НЕ ОПРЕДЕЛЁН>'));
            end case;
          end loop;
        end if;
        /* Закрываем строку */
        PKG_XFAST.UP();
      end loop;
    end if;
  end TDG_ROWS_TO_XML;
  
  /* Формирование таблицы данных */
  function TDG_MAKE
  (
    BFIXED_HEADER           in boolean := false, -- Зафиксировать заголовок
    NFIXED_COLUMNS          in number := 0       -- Количество фиксированных колонок
  ) return                  TDG                  -- Результат работы
  is
    RRES                    TDG;                 -- Буфер для результата
  begin
    /* Формируем объект */
    RRES.BFIXED_HEADER  := COALESCE(BFIXED_HEADER, false);
    RRES.NFIXED_COLUMNS := COALESCE(NFIXED_COLUMNS, 0);
    RRES.RCOL_DEFS      := TDG_COL_DEFS();
    RRES.RGROUPS        := TDG_GROUPS();
    RRES.RROWS          := TDG_ROWS();
    /* Возвращаем результат */
    return RRES;
  end TDG_MAKE;
  
  /* Поиск описания колонки в таблице данных по наименованию */
  function TDG_FIND_COL_DEF
  (
    RDATA_GRID              in TDG,     -- Описание таблицы данных
    SNAME                   in varchar2 -- Наименование колонки
  ) return                  TDG_COL_DEF -- Найденное описание (null - если не нашли)
  is
  begin
    return TDG_COL_DEFS_FIND(RCOL_DEFS => RDATA_GRID.RCOL_DEFS, SNAME => SNAME);
  end TDG_FIND_COL_DEF;
  
  /* Добавление описания колонки к таблице данных */
  procedure TDG_ADD_COL_DEF
  (
    RDATA_GRID              in out nocopy TDG,             -- Описание таблицы данных
    SNAME                   in varchar2,                   -- Наименование колонки
    SCAPTION                in varchar2,                   -- Заголовок колонки
    SDATA_TYPE              in varchar2 := SDATA_TYPE_STR, -- Тип данных колонки (см. константы SDATA_TYPE_*)
    SCOND_FROM              in varchar2 := null,           -- Наименование нижней границы условия отбора (null - используется UTL_COND_NAME_MAKE_FROM)
    SCOND_TO                in varchar2 := null,           -- Наименование верхней границы условия отбора (null - используется UTL_COND_NAME_MAKE_TO)
    BVISIBLE                in boolean := true,            -- Разрешить отображение
    BORDER                  in boolean := false,           -- Разрешить сортировку по колонке
    BFILTER                 in boolean := false,           -- Разрешить отбор по колонке
    RCOL_VALS               in TDG_COL_VALS := null,       -- Предопределённые значения колонки
    SHINT                   in varchar2 := null,           -- Текст всплывающей подсказки
    SPARENT                 in varchar2 := null,           -- Наименование родительской колонки
    BEXPANDABLE             in boolean := false,           -- Разрешить сокрытие/отображение дочерних колонок
    BEXPANDED               in boolean := true,            -- Отобразить/скрыть дочерние колонки
    NWIDTH                  in number := null,             -- Ширина колонки (обязательно для фиксированных)    
    BCLEAR                  in boolean := false            -- Флаг очистки коллекции описаний колонок таблицы данных (false - не очищать, true - очистить коллекцию перед добавлением)
  )
  is
  begin
    /* Формируем описание и добавляем в коллекцию таблицы данных */
    TDG_COL_DEFS_ADD(RCOL_DEFS   => RDATA_GRID.RCOL_DEFS,
                     SNAME       => SNAME,
                     SCAPTION    => SCAPTION,
                     SDATA_TYPE  => SDATA_TYPE,
                     SCOND_FROM  => SCOND_FROM,
                     SCOND_TO    => SCOND_TO,
                     BVISIBLE    => BVISIBLE,
                     BORDER      => BORDER,
                     BFILTER     => BFILTER,
                     RCOL_VALS   => RCOL_VALS,
                     SHINT       => SHINT,
                     SPARENT     => SPARENT,
                     BEXPANDABLE => BEXPANDABLE,
                     BEXPANDED   => BEXPANDED,
                     NWIDTH      => NWIDTH,
                     BCLEAR      => BCLEAR);
  end TDG_ADD_COL_DEF;
  
  /* Добавление описания группы к таблице данных */
  procedure TDG_ADD_GROUP
  (
    RDATA_GRID              in out nocopy TDG,   -- Описание таблицы данных
    SNAME                   in varchar2,         -- Наименование группы
    SCAPTION                in varchar2,         -- Заголовок группы
    BEXPANDABLE             in boolean := false, -- Разрешить сокрытие/отображение дочерних
    BEXPANDED               in boolean := true,  -- Отобразить/скрыть дочерние
    BCLEAR                  in boolean := false  -- Флаг очистки коллекции описаний групп таблицы данных (false - не очищать, true - очистить коллекцию перед добавлением)
  )
  is
  begin
    /* Формируем описание и добавляем в коллекцию таблицы данных */
    TDG_GROUPS_ADD(RGROUPS     => RDATA_GRID.RGROUPS,
                   SNAME       => SNAME,
                   SCAPTION    => SCAPTION,
                   BEXPANDABLE => BEXPANDABLE,
                   BEXPANDED   => BEXPANDED,
                   BCLEAR      => BCLEAR);
  end TDG_ADD_GROUP;
  
  /* Добавление описания колонки к таблице данных */
  procedure TDG_ADD_ROW
  (
    RDATA_GRID              in out nocopy TDG,  -- Описание таблицы данных
    RROW                    in TDG_ROW,         -- Строка
    BCLEAR                  in boolean := false -- Флаг очистки коллекции строк таблицы данных (false - не очищать, true - очистить коллекцию перед добавлением)
  )
  is
  begin
    /* Инициализируем коллекцию если необходимо */
    if ((RDATA_GRID.RROWS is null) or (BCLEAR)) then
      RDATA_GRID.RROWS := TDG_ROWS();
    end if;
    /* Добавляем элемент */
    RDATA_GRID.RROWS.EXTEND();
    RDATA_GRID.RROWS(RDATA_GRID.RROWS.LAST) := RROW;
  end TDG_ADD_ROW;
  
  /* Сериализация описания таблицы данных */
  procedure TDG_DEF_TO_XML
  (
    RDATA_GRID                  in TDG  -- Описание таблицы данных
  )
  is    
  begin
    /* Cтатические атрибуты заголовка */
    PKG_XFAST.ATTR(SNAME => SRESP_ATTR_FIXED_HEADER, BVALUE => RDATA_GRID.BFIXED_HEADER);
    PKG_XFAST.ATTR(SNAME => SRESP_ATTR_FIXED_COLUMNS, NVALUE => RDATA_GRID.NFIXED_COLUMNS);
  end TDG_DEF_TO_XML;
  
  /* Сериализация таблицы данных */
  function TDG_TO_XML
  (
    RDATA_GRID              in TDG,        -- Описание таблицы данных
    NINCLUDE_DEF            in number := 1 -- Включить описание колонок (0 - нет, 1 - да)
  ) return                  clob           -- XML-описание
  is
    CRES                    clob;          -- Буфер для результата
  begin
    /* Начинаем формирование XML */
    PKG_XFAST.PROLOGUE(ITYPE => PKG_XFAST.CONTENT_);
    /* Открываем корень */
    PKG_XFAST.DOWN_NODE(SNAME => SRESP_TAG_XDATA);
    /* Открываем таблицу данных */
    PKG_XFAST.DOWN_NODE(SNAME => SRESP_TAG_XDATA_GRID);
    /* Формируем описание таблицы данных */
    TDG_DEF_TO_XML(RDATA_GRID => RDATA_GRID);
    /* Если необходимо включить описание колонок */
    if (NINCLUDE_DEF = 1) then
      TDG_COL_DEFS_TO_XML(RCOL_DEFS => RDATA_GRID.RCOL_DEFS);
    end if;
    /* Формируем описание групп */
    TDG_GROUPS_TO_XML(RGROUPS => RDATA_GRID.RGROUPS);
    /* Формируем описание строк */
    TDG_ROWS_TO_XML(RCOL_DEFS => RDATA_GRID.RCOL_DEFS, RROWS => RDATA_GRID.RROWS);
    /* Закрываем таблицу данных */
    PKG_XFAST.UP();
    /* Закрываем корень */
    PKG_XFAST.UP();
    /* Сериализуем */
    CRES := PKG_XFAST.SERIALIZE_TO_CLOB();
    /* Завершаем формирование XML */
    PKG_XFAST.EPILOGUE();
    /* Возвращаем полученное */
    return CRES;
  exception
    when others then
      /* Завершаем формирование XML */
      PKG_XFAST.EPILOGUE();
      /* Вернем ошибку */
      PKG_STATE.DIAGNOSTICS_STACKED();
      P_EXCEPTION(0, PKG_STATE.SQL_ERRM());
  end TDG_TO_XML;
  
  /* Конвертация значений фильтра в число */
  procedure TDG_FILTER_TO_NUMBER
  (
    RFILTER                 in TDG_FILTER, -- Фильтр
    NFROM                   out number,    -- Значение нижней границы диапазона
    NTO                     out number     -- Значение верхней границы диапазона
  )
  is
  begin
    /* Нижняя граница диапазона */
    if (RFILTER.SFROM is not null) then
      begin
        NFROM := PKG_P8PANELS_BASE.UTL_S2N(SVALUE => RFILTER.SFROM);
      exception
        when others then
          P_EXCEPTION(0,
                      'Неверный формат числа (%s) в указанной нижней границе диапазона фильтра.',
                      RFILTER.SFROM);
      end;
    end if;
    /* Верхняя граница диапазона */    
    if (RFILTER.STO is not null) then
      begin
        NTO := PKG_P8PANELS_BASE.UTL_S2N(SVALUE => RFILTER.STO);
      exception
        when others then
          P_EXCEPTION(0,
                      'Неверный формат числа (%s) в указанной верхней границе диапазона фильтра.',
                      RFILTER.STO);
      end;
    end if;
  end TDG_FILTER_TO_NUMBER;
  
  /* Конвертация значений фильтра в дату */
  procedure TDG_FILTER_TO_DATE
  (
    RFILTER                 in TDG_FILTER, -- Фильтр
    DFROM                   out date,      -- Значение нижней границы диапазона
    DTO                     out date       -- Значение верхней границы диапазона
  )
  is
  begin
    /* Нижняя граница диапазона */
    if (RFILTER.SFROM is not null) then
      begin
        DFROM := PKG_P8PANELS_BASE.UTL_S2D(SVALUE => RFILTER.SFROM);
      exception
        when others then
          P_EXCEPTION(0,
                      'Неверный формат даты (%s) в указанной нижней границе диапазона фильтра.',
                      RFILTER.SFROM);
      end;
    end if;
    /* Верхняя граница диапазона */
    if (RFILTER.STO is not null) then
      begin
        DTO := PKG_P8PANELS_BASE.UTL_S2D(SVALUE => RFILTER.STO);
      exception
        when others then
          P_EXCEPTION(0,
                      'Неверный формат даты (%s) в указанной верхней границе диапазона фильтра.',
                      RFILTER.STO);
      end;
    end if;
  end TDG_FILTER_TO_DATE;
  /* Формирование фильтра */
  function TDG_FILTER_MAKE
  (
    SNAME                   in varchar2, -- Наименование
    SFROM                   in varchar2, -- Значение "с"
    STO                     in varchar2  -- Значение "по"
  ) return                  TDG_FILTER   -- Результат работы
  is
    RRES                    TDG_FILTER;  -- Буфер для результата
  begin
    /* Формируем объект */
    RRES.SNAME := SNAME;
    RRES.SFROM := SFROM;
    RRES.STO   := STO;
    /* Возвращаем результат */
    return RRES;
  end TDG_FILTER_MAKE;
  
  /* Поиск фильтра в коллекции */
  function TDG_FILTERS_FIND
  (
    RFILTERS                in TDG_FILTERS, -- Коллекция фильтров
    SNAME                   in varchar2     -- Наименование
  ) return                  TDG_FILTER      -- Найденный фильтр (null - если не нашли)
  is
  begin
    /* Обходим фильтры из коллекции */
    if ((RFILTERS is not null) and (RFILTERS.COUNT > 0)) then
      for I in RFILTERS.FIRST .. RFILTERS.LAST
      loop
        if (RFILTERS(I).SNAME = SNAME) then
          return RFILTERS(I);
        end if;
      end loop;
    end if;
    /* Ничего не нашли */
    return null;
  end TDG_FILTERS_FIND;
  
  /* Десериализация фильтров */
  function TDG_FILTERS_FROM_XML
  (
    CFILTERS                in clob              -- Сериализованное представление фильтров (BASE64(ИМЯЗНАЧЕНИЕЗНАЧЕНИЕ...))
  ) return                  TDG_FILTERS          -- Результат работы
  is
    RFILTERS                TDG_FILTERS;         -- Буфер для результата работы
    XDOC                    PKG_XPATH.TDOCUMENT; -- Документ XML
    XROOT                   PKG_XPATH.TNODE;     -- Корень документа XML
    XNODE                   PKG_XPATH.TNODE;     -- Буфер узла документа
    XNODES                  PKG_XPATH.TNODES;    -- Буфер коллекции узлов документа
  begin
    /* Вернём выходную коллекцию */
    RFILTERS := TDG_FILTERS();
    /* Разбираем XML */
    XDOC := PKG_XPATH.PARSE_FROM_CLOB(LCXML => '<' || SRQ_TAG_XROOT || '>' ||
                                               BLOB2CLOB(LBDATA   => BASE64_DECODE(LCSRCE => CFILTERS),
                                                         SCHARSET => PKG_CHARSET.CHARSET_UTF_()) || '' ||
                                               SRQ_TAG_XROOT || '>');
    /* Считываем корневой узел */
    XROOT := PKG_XPATH.ROOT_NODE(RDOCUMENT => XDOC);
    /* Считывание списка записей */
    XNODES := PKG_XPATH.LIST_NODES(RPARENT_NODE => XROOT, SPATTERN => '/' || SRQ_TAG_XROOT || '/' || SRQ_TAG_XFILTERS);
    /* Цикл по списку записией */
    for I in 1 .. PKG_XPATH.COUNT_NODES(RNODES => XNODES)
    loop
      /* Считаем элемент по его номеру */
      XNODE := PKG_XPATH.ITEM_NODE(RNODES => XNODES, INUMBER => I);
      /* Добавим его в коллекцию */
      RFILTERS.EXTEND();
      RFILTERS(RFILTERS.LAST) := TDG_FILTER_MAKE(SNAME => PKG_XPATH.VALUE(RNODE => XNODE, SPATTERN => SRQ_TAG_SNAME),
                                                 SFROM => PKG_XPATH.VALUE(RNODE => XNODE, SPATTERN => SRQ_TAG_SFROM),
                                                 STO   => PKG_XPATH.VALUE(RNODE => XNODE, SPATTERN => SRQ_TAG_STO));
    end loop;
    /* Освободим документ */
    PKG_XPATH.FREE(RDOCUMENT => XDOC);
    /* Вернём результат */
    return RFILTERS;
  exception
    when others then
      /* Освободим документ */
      PKG_XPATH.FREE(RDOCUMENT => XDOC);
      /* Вернем ошибку */
      PKG_STATE.DIAGNOSTICS_STACKED();
      P_EXCEPTION(0, PKG_STATE.SQL_ERRM());
  end TDG_FILTERS_FROM_XML;
  
  /* Применение параметров фильтрации в запросе */
  procedure TDG_FILTERS_SET_QUERY
  (
    NIDENT                  in number,         -- Идентификатор отбора
    NCOMPANY                in number,         -- Рег. номер организации
    NPARENT                 in number := null, -- Рег. номер родителя
    SUNIT                   in varchar2,       -- Код раздела
    SPROCEDURE              in varchar2,       -- Наименование серверной процедуры отбора
    RDATA_GRID              in TDG,            -- Описание таблицы данных
    RFILTERS                in TDG_FILTERS     -- Коллекция фильтров
  )
  is
    RCOL_DEF                TDG_COL_DEF;       -- Описание текущей фильтруемой колонки
    BENUM                   boolean;           -- Флаг начиличия перечисляемых значений
    NFROM                   PKG_STD.TLNUMBER;  -- Буфер для верхней границы диапазона отбора чисел
    NTO                     PKG_STD.TLNUMBER;  -- Буфер для нижней границы диапазона отбора чисел
    DFROM                   PKG_STD.TLDATE;    -- Буфер для верхней границы диапазона отбора дат
    DTO                     PKG_STD.TLDATE;    -- Буфер для нижней границы диапазона отбора дат
  begin
    /* Формирование условий отбора - Пролог */
    PKG_COND_BROKER.PROLOGUE(IMODE => PKG_COND_BROKER.MODE_SMART_, NIDENT => NIDENT);
    /* Формирование условий отбора - Установка процедуры серверного отбора */
    PKG_COND_BROKER.SET_PROCEDURE(SPROCEDURE_NAME => SPROCEDURE);
    /* Формирование условий отбора - Установка раздела */
    PKG_COND_BROKER.SET_UNIT(SUNITCODE => SUNIT);
    /* Формирование условий отбора - Установка организации */
    PKG_COND_BROKER.SET_COMPANY(NCOMPANY => NCOMPANY);
    /* Формирование условий отбора - Установка родителя */
    if (NPARENT is not null) then
      PKG_COND_BROKER.SET_PARENT(NPARENT => NPARENT);
    end if;
    /* Обходим фильтр, если задан */
    if ((RFILTERS is not null) and (RFILTERS.COUNT > 0)) then
      for I in RFILTERS.FIRST .. RFILTERS.LAST
      loop
        /* Найдем фильтруемую колонку в описании */
        RCOL_DEF := TDG_COL_DEFS_FIND(RCOL_DEFS => RDATA_GRID.RCOL_DEFS, SNAME => RFILTERS(I).SNAME);
        if (RCOL_DEF.SNAME is not null) then
          /* Определимся с наличием перечисляемых значений */
          if ((RCOL_DEF.RCOL_VALS is not null) and (RCOL_DEF.RCOL_VALS.COUNT > 0)) then
            BENUM := true;
          else
            BENUM := false;
          end if;
          /* Установим для неё условие отобра согласно типу данных */
          case RCOL_DEF.SDATA_TYPE
            when SDATA_TYPE_STR then
              begin
                if (BENUM) then
                  PKG_COND_BROKER.SET_CONDITION_ESTR(SCONDITION_NAME   => RCOL_DEF.SCOND_FROM,
                                                     SCONDITION_ESTR   => RFILTERS(I).SFROM,
                                                     ICASE_INSENSITIVE => 1);
                else
                  PKG_COND_BROKER.SET_CONDITION_STR(SCONDITION_NAME   => RCOL_DEF.SCOND_FROM,
                                                    SCONDITION_VALUE  => RFILTERS(I).SFROM,
                                                    ICASE_INSENSITIVE => 1);
                end if;
              end;
            when SDATA_TYPE_NUMB then
              begin
                if (BENUM) then
                  PKG_COND_BROKER.SET_CONDITION_ENUM(SCONDITION_NAME => RCOL_DEF.SCOND_FROM,
                                                     SCONDITION_ENUM => RFILTERS(I).SFROM);
                else
                  TDG_FILTER_TO_NUMBER(RFILTER => RFILTERS(I), NFROM => NFROM, NTO => NTO);
                  if (NFROM is not null) then
                    PKG_COND_BROKER.SET_CONDITION_NUM(SCONDITION_NAME  => RCOL_DEF.SCOND_FROM,
                                                      NCONDITION_VALUE => NFROM);
                  end if;
                  if (NTO is not null) then
                    PKG_COND_BROKER.SET_CONDITION_NUM(SCONDITION_NAME => RCOL_DEF.SCOND_TO, NCONDITION_VALUE => NTO);
                  end if;
                end if;
              end;
            when SDATA_TYPE_DATE then
              begin
                if (BENUM) then
                  PKG_COND_BROKER.SET_CONDITION_EDATE(SCONDITION_NAME  => RCOL_DEF.SCOND_FROM,
                                                      SCONDITION_EDATE => RFILTERS(I).SFROM);
                else
                  TDG_FILTER_TO_DATE(RFILTER => RFILTERS(I), DFROM => DFROM, DTO => DTO);
                  if (DFROM is not null) then
                    PKG_COND_BROKER.SET_CONDITION_DATE(SCONDITION_NAME  => RCOL_DEF.SCOND_FROM,
                                                       DCONDITION_VALUE => DFROM);
                  end if;
                  if (DTO is not null) then
                    PKG_COND_BROKER.SET_CONDITION_DATE(SCONDITION_NAME => RCOL_DEF.SCOND_TO, DCONDITION_VALUE => DTO);
                  end if;
                end if;
              end;
            else
              P_EXCEPTION(0,
                          'Описание колонки "%s" таблицы данных содержит неподдерживаемый тип данных ("%s").',
                          RCOL_DEF.SNAME,
                          COALESCE(RCOL_DEF.SDATA_TYPE, '<НЕ ОПРЕДЕЛЁН>'));
          end case;
        end if;
      end loop;
    end if;
    /* Формирование условий отбора - Эпилог */
    PKG_COND_BROKER.EPILOGUE();
  end TDG_FILTERS_SET_QUERY;
  
  /* Формирование сортировки */
  function TDG_ORDER_MAKE
  (
    SNAME                   in varchar2, -- Наименование
    SDIRECTION              in varchar2  -- Направление (см. константы SORDER_DIRECTION_*)
  ) return                  TDG_ORDER    -- Результат работы
  is
    RRES                    TDG_ORDER;   -- Буфер для результата
  begin
    /* Формируем объект */
    RRES.SNAME      := SNAME;
    RRES.SDIRECTION := SDIRECTION;
    /* Возвращаем результат */
    return RRES;
  end TDG_ORDER_MAKE;
  
  /* Десериализация сортировок */
  function TDG_ORDERS_FROM_XML
  (
    CORDERS                 in clob              -- Сериализованное представление сотрировок (BASE64(ИМЯASC/DESC...))
  ) return                  TDG_ORDERS           -- Результат работы
  is
    RORDERS                 TDG_ORDERS;          -- Буфер для результата работы
    XDOC                    PKG_XPATH.TDOCUMENT; -- Документ XML
    XROOT                   PKG_XPATH.TNODE;     -- Корень документа XML
    XNODE                   PKG_XPATH.TNODE;     -- Буфер узла документа
    XNODES                  PKG_XPATH.TNODES;    -- Буфер коллекции узлов документа
  begin
    /* Инициализируем выходную коллекцию */
    RORDERS := TDG_ORDERS();
    /* Разбираем XML */
    XDOC := PKG_XPATH.PARSE_FROM_CLOB(LCXML => '<' || SRQ_TAG_XROOT || '>' ||
                                               BLOB2CLOB(LBDATA   => BASE64_DECODE(LCSRCE => CORDERS),
                                                         SCHARSET => PKG_CHARSET.CHARSET_UTF_()) || '' ||
                                               SRQ_TAG_XROOT || '>');
    /* Считываем корневой узел */
    XROOT := PKG_XPATH.ROOT_NODE(RDOCUMENT => XDOC);
    /* Считывание списка записей */
    XNODES := PKG_XPATH.LIST_NODES(RPARENT_NODE => XROOT, SPATTERN => '/' || SRQ_TAG_XROOT || '/' || SRQ_TAG_XORDERS);
    /* Цикл по списку записией */
    for I in 1 .. PKG_XPATH.COUNT_NODES(RNODES => XNODES)
    loop
      /* Считаем элемент по его номеру */
      XNODE := PKG_XPATH.ITEM_NODE(RNODES => XNODES, INUMBER => I);
      /* Добавим его в коллекцию */
      RORDERS.EXTEND();
      RORDERS(RORDERS.LAST) := TDG_ORDER_MAKE(SNAME      => PKG_XPATH.VALUE(RNODE => XNODE, SPATTERN => SRQ_TAG_SNAME),
                                              SDIRECTION => PKG_XPATH.VALUE(RNODE    => XNODE,
                                                                            SPATTERN => SRQ_TAG_SDIRECTION));
    end loop;
    /* Освободим документ */
    PKG_XPATH.FREE(RDOCUMENT => XDOC);
    /* Вернём результат */
    return RORDERS;
  exception
    when others then
      /* Освободим документ */
      PKG_XPATH.FREE(RDOCUMENT => XDOC);
      /* Вернем ошибку */
      PKG_STATE.DIAGNOSTICS_STACKED();
      P_EXCEPTION(0, PKG_STATE.SQL_ERRM());
  end TDG_ORDERS_FROM_XML;
  
  /* Применение параметров сортировки в запросе */
  procedure TDG_ORDERS_SET_QUERY
  (
    RDATA_GRID              in TDG,             -- Описание таблицы
    RORDERS                 in TDG_ORDERS,      -- Коллекция сортировок
    SPATTERN                in varchar2,        -- Шаблон для подстановки условий отбора в запрос    
    CSQL                    in out nocopy clob  -- Буфер запроса
  )
  is
    CSQL_ORDERS             clob;               -- Буфер для условий сортировки в запросе
  begin
    /* Если сортировка задана */
    if ((RORDERS is not null) and (RORDERS.COUNT > 0)) then
      CSQL_ORDERS := ' order by ';
      for I in RORDERS.FIRST .. RORDERS.LAST
      loop
        /* Перед добавлением в запрос - обязательная проверка, чтобы избежать SQL-инъекций */
        if ((TDG_COL_DEFS_FIND(RCOL_DEFS => RDATA_GRID.RCOL_DEFS, SNAME => RORDERS(I).SNAME).SNAME is not null) and
           (RORDERS(I).SDIRECTION in (SORDER_DIRECTION_ASC, SORDER_DIRECTION_DESC))) then
          CSQL_ORDERS := CSQL_ORDERS || RORDERS(I).SNAME || ' ' || RORDERS(I).SDIRECTION;
          if (I < RORDERS.LAST) then
            CSQL_ORDERS := CSQL_ORDERS || ', ';
          end if;
        end if;
      end loop;
    end if;
    CSQL := replace(CSQL, SPATTERN, CSQL_ORDERS);
  end TDG_ORDERS_SET_QUERY;
  
  /* Проверка корректности наименования дополнительного атрибута задачи диаграммы Ганта */
  procedure TGANTT_TASK_ATTR_NAME_CHECK
  (
    SNAME                   in varchar2 -- Наименование
  )
  is
  begin
    if (SNAME in (SRESP_ATTR_ID,
                  SRESP_ATTR_RN,
                  SRESP_ATTR_NUMB,
                  SRESP_ATTR_CAPTION,
                  SRESP_ATTR_FULL_NAME,
                  SRESP_ATTR_START,
                  SRESP_ATTR_END,
                  SRESP_ATTR_TASK_PROGRESS,
                  SRESP_ATTR_TASK_BG_COLOR,
                  SRESP_ATTR_TASK_TEXT_COLOR,                  
                  SRESP_ATTR_TASK_RO,
                  SRESP_ATTR_TASK_RO_PRGRS,
                  SRESP_ATTR_TASK_RO_DATES,
                  SRESP_ATTR_TASK_DEPS)) then
      P_EXCEPTION(0,
                  'Наименование атрибута "%s" является зарезервированным.',
                  SNAME);
    end if;
  end TGANTT_TASK_ATTR_NAME_CHECK;
  
  /* Поиск атрибута задачи диаграммы Ганта по наименованию */
  function TGANTT_TASK_ATTR_FIND
  (
    RTASK_ATTRS             in TGANTT_TASK_ATTRS, -- Описание атрибутов задачи диаграммы Ганта
    SNAME                   in varchar2           -- Наименование
  ) return                  TGANTT_TASK_ATTR      -- Найденное описание (null - если не нашли)
  is
  begin
    /* Обходим атрибуты из описания */
    if ((RTASK_ATTRS is not null) and (RTASK_ATTRS.COUNT > 0)) then
      for I in RTASK_ATTRS.FIRST .. RTASK_ATTRS.LAST
      loop
        if (RTASK_ATTRS(I).SNAME = SNAME) then
          return RTASK_ATTRS(I);
        end if;
      end loop;
    end if;
    /* Ничего не нашли */
    return null;
  end TGANTT_TASK_ATTR_FIND;
  
  /* Поиск цвета задачи диаграммы Ганта по параметрам */
  function TGANTT_TASK_COLOR_FIND
  (
    RTASK_COLORS            in TGANTT_TASK_COLORS, -- Описание цветов задачи диаграммы Ганта
    SBG_COLOR               in varchar2 := null,   -- Цвет заливки задачи (формат - HTML-цвет, #RRGGBBAA)
    STEXT_COLOR             in varchar2 := null,   -- Цвет текста заголовка задачи (формат - HTML-цвет, #RRGGBBAA)
    SBG_PROGRESS_COLOR      in varchar2 := null    -- Цвет заливки прогресса (формат - HTML-цвет, #RRGGBBAA)
  ) return                  TGANTT_TASK_COLOR      -- Найденное описание цвета (null - если не нашли)
  is
  begin
    /* Обходим цвета из описания */
    if ((RTASK_COLORS is not null) and (RTASK_COLORS.COUNT > 0)) then
      for I in RTASK_COLORS.FIRST .. RTASK_COLORS.LAST
      loop
        if ((CMP_VC2(V1 => RTASK_COLORS(I).SBG_COLOR, V2 => SBG_COLOR) = 1) and
           (CMP_VC2(V1 => RTASK_COLORS(I).STEXT_COLOR, V2 => STEXT_COLOR) = 1) and
           (CMP_VC2(V1 => RTASK_COLORS(I).SBG_PROGRESS_COLOR, V2 => SBG_PROGRESS_COLOR) = 1)) 
            then
          return RTASK_COLORS(I);
        end if;
      end loop;
    end if;
    /* Ничего не нашли */
    return null;
  end TGANTT_TASK_COLOR_FIND;
  
  /* Формирование задачи для диаграммы Ганта */
  function TGANTT_TASK_MAKE
  (
    NRN                     in number,           -- Рег. номер
    SNUMB                   in varchar2,         -- Номер
    SCAPTION                in varchar2,         -- Заголовок
    SNAME                   in varchar2,         -- Наименование
    DSTART                  in date,             -- Дата начала
    DEND                    in date,             -- Дата окончания
    NPROGRESS               in number := null,   -- Прогресс (% готовности) задачи (null - не определен)
    SBG_COLOR               in varchar2 := null, -- Цвет заливки задачи (null - использовать цвет по умолчанию из стилей, формат - HTML-цвет, #RRGGBBAA)
    STEXT_COLOR             in varchar2 := null, -- Цвет текста заголовка задачи (null - использовать цвет по умолчанию из стилей, формат - HTML-цвет, #RRGGBBAA)
    SBG_PROGRESS_COLOR      in varchar2 := null, -- Цвет заливки прогресса (null - использовать цвет по умолчанию из стилей, формат - HTML-цвет, #RRGGBBAA)
    BREAD_ONLY              in boolean := null,  -- Сроки и прогресс задачи только для чтения (null - как указано в описании диаграммы)
    BREAD_ONLY_DATES        in boolean := null,  -- Сроки задачи только для чтения (null - как указано в описании диаграммы)
    BREAD_ONLY_PROGRESS     in boolean := null   -- Прогресс задачи только для чтения (null - как указано в описании диаграммы)
  ) return                  TGANTT_TASK          -- Результат работы
  is
    RRES                    TGANTT_TASK;         -- Буфер для результата
  begin
    /* Проверим параметры */
    if ((NRN is null) or (SNUMB is null) or (SCAPTION is null) or (SNAME is null) or (DSTART is null) or (DEND is null)) then
      P_EXCEPTION(0,
                  'Регистрационный номер, номер, заголовок, наименование, даты начала и окончания являются обязательными при создании задачи для диаграммы Ганта.');
    end if;
    if ((NPROGRESS is not null) and (not (NPROGRESS between 0 and 100))) then
      P_EXCEPTION(0, 'Прогресс задачи должен быть значением от 0 до 100');
    end if;
    /* Формируем объект */
    RRES.NRN                 := NRN;
    RRES.SNUMB               := SNUMB;
    RRES.SCAPTION            := SCAPTION;
    RRES.SNAME               := SNAME;
    RRES.DSTART              := DSTART;
    RRES.DEND                := DEND;
    RRES.NPROGRESS           := NPROGRESS;
    RRES.SBG_COLOR           := SBG_COLOR;
    RRES.STEXT_COLOR         := STEXT_COLOR;
    RRES.SBG_PROGRESS_COLOR  := SBG_PROGRESS_COLOR;
    RRES.BREAD_ONLY          := BREAD_ONLY;
    RRES.BREAD_ONLY_DATES    := BREAD_ONLY_DATES;
    RRES.BREAD_ONLY_PROGRESS := BREAD_ONLY_PROGRESS;
    RRES.RATTR_VALS          := TGANTT_TASK_ATTR_VALS();
    RRES.RDEPENDENCIES       := TGANTT_TASK_DEPENDENCIES();
    /* Возвращаем результат */
    return RRES;
  end TGANTT_TASK_MAKE;
  
  /* Добавление значения атрибута к задаче диаграммы Ганта */
  procedure TGANTT_TASK_ADD_ATTR_VAL
  (
    RGANTT                  in TGANTT,                 -- Описание диаграммы
    RTASK                   in out nocopy TGANTT_TASK, -- Описание задачи
    SNAME                   in varchar2,               -- Наименование
    SVALUE                  in varchar2,               -- Значение
    BCLEAR                  in boolean := false        -- Флаг очистки коллекции значений атрибутов (false - не очищать, true - очистить коллекцию перед добавлением)
  )
  is
  begin
    /* Проверим наименование */
    TGANTT_TASK_ATTR_NAME_CHECK(SNAME => SNAME);
    /* Проверим, что такой атрибут зарегистрирован */
    if (TGANTT_TASK_ATTR_FIND(RTASK_ATTRS => RGANTT.RTASK_ATTRS, SNAME => SNAME).SNAME is null) then
      P_EXCEPTION(0,
                  'Атрибут "%s" задачи диаграммы Ганта не зарегистрирован.',
                  SNAME);
    end if;
    /* Инициализируем коллекцию если необходимо */
    if ((RTASK.RATTR_VALS is null) or (BCLEAR)) then
      RTASK.RATTR_VALS := TGANTT_TASK_ATTR_VALS();
    end if;
    /* Добавляем элемент */
    RTASK.RATTR_VALS.EXTEND();
    RTASK.RATTR_VALS(RTASK.RATTR_VALS.LAST).SNAME := SNAME;
    RTASK.RATTR_VALS(RTASK.RATTR_VALS.LAST).SVALUE := SVALUE;
  end TGANTT_TASK_ADD_ATTR_VAL;
  
  /* Добавление предшествующей задачи к задаче диаграммы Ганта */
  procedure TGANTT_TASK_ADD_DEPENDENCY
  (
    RTASK                   in out nocopy TGANTT_TASK, -- Описание задачи
    NDEPENDENCY             in number,                 -- Рег. номер предшествующей задачи
    BCLEAR                  in boolean := false        -- Флаг очистки коллекции предшествущих задач (false - не очищать, true - очистить коллекцию перед добавлением)
  )
  is
  begin
    /* Инициализируем коллекцию если необходимо */
    if ((RTASK.RDEPENDENCIES is null) or (BCLEAR)) then
      RTASK.RDEPENDENCIES := TGANTT_TASK_DEPENDENCIES();
    end if;
    /* Добавляем элемент */
    RTASK.RDEPENDENCIES.EXTEND();
    RTASK.RDEPENDENCIES(RTASK.RDEPENDENCIES.LAST) := NDEPENDENCY;
  end TGANTT_TASK_ADD_DEPENDENCY;
  
  /* Сериализация описания задач диаграммы Ганта */
  procedure TGANTT_TASKS_TO_XML
  (
    RTASKS                  in TGANTT_TASKS   -- Коллекция задач диаграммы Ганта
  )
  is    
  begin
    /* Обходим задачи из коллекции */
    if ((RTASKS is not null) and (RTASKS.COUNT > 0)) then
      for I in RTASKS.FIRST .. RTASKS.LAST
      loop
        /* Открываем строку */
        PKG_XFAST.DOWN_NODE(SNAME => SRESP_ATTR_TASKS);
        /* Статические тарибуты */
        PKG_XFAST.ATTR(SNAME => SRESP_ATTR_ID, SVALUE => 'taskId' || RTASKS(I).NRN);
        PKG_XFAST.ATTR(SNAME => SRESP_ATTR_RN, NVALUE => RTASKS(I).NRN);
        PKG_XFAST.ATTR(SNAME => SRESP_ATTR_NUMB, SVALUE => RTASKS(I).SNUMB);
        PKG_XFAST.ATTR(SNAME => SRESP_ATTR_NAME, SVALUE => RTASKS(I).SCAPTION);
        PKG_XFAST.ATTR(SNAME => SRESP_ATTR_FULL_NAME, SVALUE => RTASKS(I).SNAME);
        PKG_XFAST.ATTR(SNAME => SRESP_ATTR_START, DVALUE => RTASKS(I).DSTART);
        PKG_XFAST.ATTR(SNAME => SRESP_ATTR_END, DVALUE => RTASKS(I).DEND);
        if (RTASKS(I).NPROGRESS is not null) then
          PKG_XFAST.ATTR(SNAME => SRESP_ATTR_TASK_PROGRESS, NVALUE => RTASKS(I).NPROGRESS);
        end if;
        if (RTASKS(I).SBG_COLOR is not null) then
          PKG_XFAST.ATTR(SNAME => SRESP_ATTR_TASK_BG_COLOR, SVALUE => RTASKS(I).SBG_COLOR);
        end if;
        if (RTASKS(I).STEXT_COLOR is not null) then
          PKG_XFAST.ATTR(SNAME => SRESP_ATTR_TASK_TEXT_COLOR, SVALUE => RTASKS(I).STEXT_COLOR);
        end if;
        if (RTASKS(I).SBG_PROGRESS_COLOR is not null) then
          PKG_XFAST.ATTR(SNAME => SRESP_ATTR_TASK_BG_PRG_COLOR, SVALUE => RTASKS(I).SBG_PROGRESS_COLOR);
        end if;
        if (RTASKS(I).BREAD_ONLY is not null) then
          PKG_XFAST.ATTR(SNAME => SRESP_ATTR_TASK_RO, BVALUE => RTASKS(I).BREAD_ONLY);
        end if;
        if (RTASKS(I).BREAD_ONLY_DATES is not null) then
          PKG_XFAST.ATTR(SNAME => SRESP_ATTR_TASK_RO_DATES, BVALUE => RTASKS(I).BREAD_ONLY_DATES);
        end if;
        if (RTASKS(I).BREAD_ONLY_PROGRESS is not null) then
          PKG_XFAST.ATTR(SNAME => SRESP_ATTR_TASK_RO_PRGRS, BVALUE => RTASKS(I).BREAD_ONLY_PROGRESS);
        end if;
        /* Динамические атрибуты */
        if ((RTASKS(I).RATTR_VALS is not null) and (RTASKS(I).RATTR_VALS.COUNT > 0)) then
          for J in RTASKS(I).RATTR_VALS.FIRST .. RTASKS(I).RATTR_VALS.LAST
          loop
            PKG_XFAST.ATTR(SNAME => RTASKS(I).RATTR_VALS(J).SNAME, SVALUE => RTASKS(I).RATTR_VALS(J).SVALUE);
          end loop;
        end if;
        /* Зависимости */
        if ((RTASKS(I).RDEPENDENCIES is not null) and (RTASKS(I).RDEPENDENCIES.COUNT > 0)) then
          for J in RTASKS(I).RDEPENDENCIES.FIRST .. RTASKS(I).RDEPENDENCIES.LAST
          loop
            PKG_XFAST.DOWN_NODE(SNAME => SRESP_ATTR_TASK_DEPS);
            PKG_XFAST.VALUE(SVALUE => 'taskId' || TO_CHAR(RTASKS(I).RDEPENDENCIES(J)));
            PKG_XFAST.UP();
          end loop;
        end if;
        /* Закрываем задачу */
        PKG_XFAST.UP();
      end loop;
    end if;
  end TGANTT_TASKS_TO_XML;
  /* Формирование диаграммы Ганта */
  function TGANTT_MAKE
  (
    STITLE                  in varchar2 := null,           -- Заголовок (null - не отображать)
    NZOOM                   in number := NGANTT_ZOOM_WEEK, -- Текущий масштаб (см. константы NGANTT_ZOOM_*)
    BZOOM_BAR               in boolean := true,            -- Обображать панель масштабирования
    BREAD_ONLY              in boolean := false,           -- Сроки и прогресс задач только для чтения
    BREAD_ONLY_DATES        in boolean := false,           -- Сроки задач только для чтения
    BREAD_ONLY_PROGRESS     in boolean := false            -- Прогресс задач только для чтения
  ) return                  TGANTT                         -- Результат работы
  is
    RRES                    TGANTT;                        -- Буфер для результата
  begin
    /* Формируем объект */
    RRES.STITLE              := STITLE;
    RRES.NZOOM               := COALESCE(NZOOM, NGANTT_ZOOM_WEEK);
    RRES.BZOOM_BAR           := COALESCE(BZOOM_BAR, true);
    RRES.BREAD_ONLY          := COALESCE(BREAD_ONLY, false);
    RRES.BREAD_ONLY_DATES    := COALESCE(BREAD_ONLY_DATES, false);
    RRES.BREAD_ONLY_PROGRESS := COALESCE(BREAD_ONLY_PROGRESS, false);
    RRES.RTASK_ATTRS         := TGANTT_TASK_ATTRS();
    RRES.RTASK_COLORS        := TGANTT_TASK_COLORS();
    RRES.RTASKS              := TGANTT_TASKS();
    /* Возвращаем результат */
    return RRES;
  end TGANTT_MAKE;
  
  /* Добавление описания атрибута карточки задачи диаграммы Ганта */
  procedure TGANTT_ADD_TASK_ATTR
  (
    RGANTT                  in out nocopy TGANTT, -- Описание диаграммы Ганта
    SNAME                   in varchar2,          -- Наименование
    SCAPTION                in varchar2,          -- Заголовок
    BVISIBLE                boolean := true,      -- Разрешить отображение
    BCLEAR                  in boolean := false   -- Флаг очистки коллекции атрибутов (false - не очищать, true - очистить коллекцию перед добавлением)
  )
  is
  begin
    /* Проверим наименование */
    TGANTT_TASK_ATTR_NAME_CHECK(SNAME => SNAME);
    /* Проверим, что такого ещё нет */
    if (TGANTT_TASK_ATTR_FIND(RTASK_ATTRS => RGANTT.RTASK_ATTRS, SNAME => SNAME).SNAME is not null) then
      P_EXCEPTION(0,
                  'Атрибут "%s" задачи диаграммы Ганта уже зарегистрирован.',
                  SNAME);
    end if;
    /* Инициализируем коллекцию если необходимо */
    if ((RGANTT.RTASK_ATTRS is null) or (BCLEAR)) then
      RGANTT.RTASK_ATTRS := TGANTT_TASK_ATTRS();
    end if;
    /* Добавляем элемент */
    RGANTT.RTASK_ATTRS.EXTEND();
    RGANTT.RTASK_ATTRS(RGANTT.RTASK_ATTRS.LAST).SNAME := SNAME;
    RGANTT.RTASK_ATTRS(RGANTT.RTASK_ATTRS.LAST).SCAPTION := SCAPTION;
    RGANTT.RTASK_ATTRS(RGANTT.RTASK_ATTRS.LAST).BVISIBLE := BVISIBLE;
  end TGANTT_ADD_TASK_ATTR;
  /* Добавление описания цвета задачи диаграммы Ганта */
  procedure TGANTT_ADD_TASK_COLOR
  (
    RGANTT                  in out nocopy TGANTT, -- Описание диаграммы Ганта
    SBG_COLOR               in varchar2 := null,  -- Цвет заливки задачи (формат - HTML-цвет, #RRGGBBAA)
    STEXT_COLOR             in varchar2 := null,  -- Цвет текста заголовка задачи (формат - HTML-цвет, #RRGGBBAA)
    SBG_PROGRESS_COLOR      in varchar2 := null,  -- Цвет заливки прогресса (формат - HTML-цвет, #RRGGBBAA)
    SDESC                   in varchar2,          -- Описание
    BCLEAR                  in boolean := false   -- Флаг очистки коллекции цветов (false - не очищать, true - очистить коллекцию перед добавлением)
  )
  is
  begin
    /* Проверим параметры */
    if ((SBG_COLOR is null) and (STEXT_COLOR is null) and (SBG_PROGRESS_COLOR is null)) then
      P_EXCEPTION(0,
                  'Должен быть указан цвет заливки или цвет текста задачи, или цвет заливки прогресса.');
    end if;
    if (SDESC is null) then
      P_EXCEPTION(0, 'Описание цвета должно быть задано.');
    end if;
    /* Проверим, что такого ещё нет */
    if (TGANTT_TASK_COLOR_FIND(RTASK_COLORS => RGANTT.RTASK_COLORS, SBG_COLOR => SBG_COLOR, STEXT_COLOR => STEXT_COLOR, SBG_PROGRESS_COLOR => SBG_PROGRESS_COLOR)
       .SDESC is not null) then
      P_EXCEPTION(0,
                  'Такое описание цвета для задачи диаграммы Ганта уже зарегистрировано.');
    end if;
    /* Инициализируем коллекцию если необходимо */
    if ((RGANTT.RTASK_COLORS is null) or (BCLEAR)) then
      RGANTT.RTASK_COLORS := TGANTT_TASK_COLORS();
    end if;
    /* Добавляем элемент */
    RGANTT.RTASK_COLORS.EXTEND();
    RGANTT.RTASK_COLORS(RGANTT.RTASK_COLORS.LAST).SBG_COLOR := SBG_COLOR;
    RGANTT.RTASK_COLORS(RGANTT.RTASK_COLORS.LAST).STEXT_COLOR := STEXT_COLOR;
    RGANTT.RTASK_COLORS(RGANTT.RTASK_COLORS.LAST).SBG_PROGRESS_COLOR := SBG_PROGRESS_COLOR;
    RGANTT.RTASK_COLORS(RGANTT.RTASK_COLORS.LAST).SDESC := SDESC;
  end TGANTT_ADD_TASK_COLOR;
  /* Добавление задачи к диаграмме Ганта */
  procedure TGANTT_ADD_TASK
  (
    RGANTT                  in out nocopy TGANTT, -- Описание диаграммы Ганта
    RTASK                   in TGANTT_TASK,       -- Задача
    BCLEAR                  in boolean := false   -- Флаг очистки коллекции задач диаграммы (false - не очищать, true - очистить коллекцию перед добавлением)
  )
  is
  begin
    /* Инициализируем коллекцию если необходимо */
    if ((RGANTT.RTASKS is null) or (BCLEAR)) then
      RGANTT.RTASKS := TGANTT_TASKS();
    end if;
    /* Добавляем элемент */
    RGANTT.RTASKS.EXTEND();
    RGANTT.RTASKS(RGANTT.RTASKS.LAST) := RTASK;
  end TGANTT_ADD_TASK;
  
  /* Сериализация описания заголовка диаграммы Ганта */
  procedure TGANTT_DEF_TO_XML
  (
    RGANTT                  in TGANTT   -- Описание диаграммы Ганта
  )
  is    
  begin
    /* Cтатические атрибуты заголовка */
    PKG_XFAST.ATTR(SNAME => SRESP_ATTR_TITLE, SVALUE => RGANTT.STITLE);
    PKG_XFAST.ATTR(SNAME => SRESP_ATTR_ZOOM, NVALUE => RGANTT.NZOOM);
    PKG_XFAST.ATTR(SNAME => SRESP_ATTR_ZOOM_BAR, BVALUE => RGANTT.BZOOM_BAR);
    PKG_XFAST.ATTR(SNAME => SRESP_ATTR_TASK_RO, BVALUE => RGANTT.BREAD_ONLY);
    PKG_XFAST.ATTR(SNAME => SRESP_ATTR_TASK_RO_DATES, BVALUE => RGANTT.BREAD_ONLY_DATES);
    PKG_XFAST.ATTR(SNAME => SRESP_ATTR_TASK_RO_PRGRS, BVALUE => RGANTT.BREAD_ONLY_PROGRESS);
    /* Если есть динамические атрибуты */
    if ((RGANTT.RTASK_ATTRS is not null) and (RGANTT.RTASK_ATTRS.COUNT > 0)) then
      /* Обходим динамические атрибуты задачи */
      for I in RGANTT.RTASK_ATTRS.FIRST .. RGANTT.RTASK_ATTRS.LAST
      loop
        /* Открываем динамический атрибут задачи */
        PKG_XFAST.DOWN_NODE(SNAME => SRESP_ATTR_TASK_ATTRIBUTES);
        /* Наполняем его атрибутами */
        PKG_XFAST.ATTR(SNAME => SRESP_ATTR_NAME, SVALUE => RGANTT.RTASK_ATTRS(I).SNAME);
        PKG_XFAST.ATTR(SNAME => SRESP_ATTR_CAPTION, SVALUE => RGANTT.RTASK_ATTRS(I).SCAPTION);
        PKG_XFAST.ATTR(SNAME => SRESP_ATTR_VISIBLE, BVALUE => RGANTT.RTASK_ATTRS(I).BVISIBLE);
        /* Закрываем динамический атрибут задачи */
        PKG_XFAST.UP();
      end loop;
    end if;
    /* Если есть описание цветов */
    if ((RGANTT.RTASK_COLORS is not null) and (RGANTT.RTASK_COLORS.COUNT > 0)) then
      /* Обходим описание цветов задачи */
      for I in RGANTT.RTASK_COLORS.FIRST .. RGANTT.RTASK_COLORS.LAST
      loop
        /* Открываем описание цвета задачи */
        PKG_XFAST.DOWN_NODE(SNAME => SRESP_ATTR_TASK_COLORS);
        /* Наполняем его атрибутами */
        if (RGANTT.RTASK_COLORS(I).SBG_COLOR is not null) then
          PKG_XFAST.ATTR(SNAME => SRESP_ATTR_TASK_BG_COLOR, SVALUE => RGANTT.RTASK_COLORS(I).SBG_COLOR);
        end if;
        if (RGANTT.RTASK_COLORS(I).STEXT_COLOR is not null) then
          PKG_XFAST.ATTR(SNAME => SRESP_ATTR_TASK_TEXT_COLOR, SVALUE => RGANTT.RTASK_COLORS(I).STEXT_COLOR);
        end if;
        if (RGANTT.RTASK_COLORS(I).SBG_PROGRESS_COLOR is not null) then
          PKG_XFAST.ATTR(SNAME => SRESP_ATTR_TASK_BG_PRG_COLOR, SVALUE => RGANTT.RTASK_COLORS(I).SBG_PROGRESS_COLOR);
        end if;
        PKG_XFAST.ATTR(SNAME => SRESP_ATTR_DESC, SVALUE => RGANTT.RTASK_COLORS(I).SDESC);
        /* Закрываем описание цвета задачи */
        PKG_XFAST.UP();
      end loop;
    end if;
  end TGANTT_DEF_TO_XML;
  
  /* Сериализация диаграммы Ганта */
  function TGANTT_TO_XML
  (
    RGANTT                  in TGANTT,     -- Описание диаграммы Ганта
    NINCLUDE_DEF            in number := 1 -- Включить описание заголовка (0 - нет, 1 - да)
  ) return                  clob           -- XML-описание
  is
    CRES                    clob;          -- Буфер для результата
  begin
    /* Начинаем формирование XML */
    PKG_XFAST.PROLOGUE(ITYPE => PKG_XFAST.CONTENT_);
    /* Открываем корень */
    PKG_XFAST.DOWN_NODE(SNAME => SRESP_TAG_XDATA);
    /* Открываем диаграмму Ганта */
    PKG_XFAST.DOWN_NODE(SNAME => SRESP_TAG_XGANTT);
    /* Если необходимо включить описание колонок */
    if (NINCLUDE_DEF = 1) then
      TGANTT_DEF_TO_XML(RGANTT => RGANTT);
    end if;
    /* Формируем описание задач */
    TGANTT_TASKS_TO_XML(RTASKS => RGANTT.RTASKS);
    /* Закрываем диаграмму Ганта */
    PKG_XFAST.UP();
    /* Закрываем корень */
    PKG_XFAST.UP();
    /* Сериализуем */
    CRES := PKG_XFAST.SERIALIZE_TO_CLOB();
    /* Завершаем формирование XML */
    PKG_XFAST.EPILOGUE();
    /* Возвращаем полученное */
    return CRES;
  exception
    when others then
      /* Завершаем формирование XML */
      PKG_XFAST.EPILOGUE();
      /* Вернем ошибку */
      PKG_STATE.DIAGNOSTICS_STACKED();
      P_EXCEPTION(0, PKG_STATE.SQL_ERRM());
  end TGANTT_TO_XML;
  
  /* Проверка корректности наименования дополнительного атрибута элемента данных графика */
  procedure TCHART_DATASET_ITEM_ATTR_NM_CH
  (
    SNAME                   in varchar2 -- Наименование
  )
  is
  begin
    if (SNAME in (SRESP_ATTR_CHART_DS_I_VAL)) then
      P_EXCEPTION(0,
                  'Наименование атрибута "%s" является зарезервированным.',
                  SNAME);
    end if;
  end TCHART_DATASET_ITEM_ATTR_NM_CH;
  
  /* Сериализация меток графика */
  procedure TCHART_LABELS_TO_XML
  (
    RLABELS                 in TCHART_LABELS -- Описание диаграммы Ганта
  )
  is    
  begin
    /* Если есть метки */
    if ((RLABELS is not null) and (RLABELS.COUNT > 0)) then
      /* Обходим метки */
      for I in RLABELS.FIRST .. RLABELS.LAST
      loop
        /* Открываем описание метки */
        PKG_XFAST.DOWN_NODE(SNAME => SRESP_ATTR_CHART_LABELS);
        /* Добавляем значение */
        PKG_XFAST.VALUE(SVALUE => RLABELS(I));
        /* Закрываем описание метки */
        PKG_XFAST.UP();
      end loop;
    end if;
  end TCHART_LABELS_TO_XML;
  
  /* Добавление дополнительного атрибута элемента данных графика */
  procedure TCHART_DATASET_ITM_ATTR_VL_ADD
  (
    RATTR_VALS              in out nocopy TCHART_DATASET_ITEM_ATTR_VALS, -- Коллекция дополнительных атрибутов элемента данных графика
    SNAME                   PKG_STD.TSTRING,                             -- Наименование
    SVALUE                  PKG_STD.TSTRING,                             -- Значение
    BCLEAR                  in boolean := false                          -- Флаг очистки коллекции дополнительных атрибутов элемента данных (false - не очищать, true - очистить коллекцию перед добавлением)
  )
  is
  begin
    /* Проверим корректность наименования */
    TCHART_DATASET_ITEM_ATTR_NM_CH(SNAME => SNAME);
    /* Инициализируем коллекцию если необходимо */
    if ((RATTR_VALS is null) or (BCLEAR)) then
      RATTR_VALS := TCHART_DATASET_ITEM_ATTR_VALS();
    end if;
    /* Добавляем элемент */
    RATTR_VALS.EXTEND();
    RATTR_VALS(RATTR_VALS.LAST).SNAME := SNAME;
    RATTR_VALS(RATTR_VALS.LAST).SVALUE := SVALUE;
  end TCHART_DATASET_ITM_ATTR_VL_ADD;
  
  /* Формирование набора данных графика */
  function TCHART_DATASET_MAKE
  (
    SCAPTION                in varchar2,         -- Заголовок
    SBORDER_COLOR           in varchar2 := null, -- Цвет границы элемента данных на графике (null - использовать цвет по умолчанию из стилей, формат - HTML-цвет, #RRGGBBAA)
    SBG_COLOR               in varchar2 := null  -- Цвет заливки элемента данных на графике (null - использовать цвет по умолчанию из стилей, формат - HTML-цвет, #RRGGBBAA)
  ) return                  TCHART_DATASET       -- Результат работы
  is
    RRES                    TCHART_DATASET;      -- Буфер для результата
  begin
    /* Формируем объект */
    RRES.SCAPTION      := SCAPTION;
    RRES.SBORDER_COLOR := SBORDER_COLOR;
    RRES.SBG_COLOR     := SBG_COLOR;
    RRES.RITEMS        := TCHART_DATASET_ITEMS();
    /* Возвращаем результат */
    return RRES;
  end TCHART_DATASET_MAKE;
  
  /* Добавление элемента в набор данных графика */
  procedure TCHART_DATASET_ADD_ITEM
  (
    RDATASET                in out nocopy TCHART_DATASET,             -- Описание набора данных графика
    NVALUE                  in number,                                -- Значение элемента данных, отображаемое на графике
    RATTR_VALS              in TCHART_DATASET_ITEM_ATTR_VALS := null, -- Значения дополнительных атрбутов (null - дополнительные атрибуты не определены)
    BCLEAR                  in boolean := false                       -- Флаг очистки коллекции элементов набора данных (false - не очищать, true - очистить коллекцию перед добавлением)
  )
  is
  begin
    /* Инициализируем коллекцию если необходимо */
    if ((RDATASET.RITEMS is null) or (BCLEAR)) then
      RDATASET.RITEMS := TCHART_DATASET_ITEMS();
    end if;
    /* Добавляем элемент */
    RDATASET.RITEMS.EXTEND();
    RDATASET.RITEMS(RDATASET.RITEMS.LAST).NVALUE := NVALUE;
    RDATASET.RITEMS(RDATASET.RITEMS.LAST).RATTR_VALS := RATTR_VALS;
  end TCHART_DATASET_ADD_ITEM;
  
  /* Сериализация коллекции наборов данных графика */
  procedure TCHART_DATASETS_TO_XML
  (
    RDATASETS               in TCHART_DATASETS -- Наборы данных графика
  )
  is
  begin
    /* Если есть наборы данных */
    if ((RDATASETS is not null) and (RDATASETS.COUNT > 0)) then
      /* Обходим наборы данных */
      for I in RDATASETS.FIRST .. RDATASETS.LAST
      loop
        /* Открываем набор данных */
        PKG_XFAST.DOWN_NODE(SNAME => SRESP_ATTR_CHART_DATASETS);
        /* Добавляем статические атрибуты */
        PKG_XFAST.ATTR(SNAME => SRESP_ATTR_CHART_DS_LABEL, SVALUE => RDATASETS(I).SCAPTION);
        if (RDATASETS(I).SBORDER_COLOR is not null) then
          PKG_XFAST.ATTR(SNAME => SRESP_ATTR_CHART_DS_BR_CLR, SVALUE => RDATASETS(I).SBORDER_COLOR);
        end if;
        if (RDATASETS(I).SBG_COLOR is not null) then
          PKG_XFAST.ATTR(SNAME => SRESP_ATTR_CHART_DS_BG_CLR, SVALUE => RDATASETS(I).SBG_COLOR);
        end if;
        /* Если в наборе данных есть элементы */
        if ((RDATASETS(I).RITEMS is not null) and (RDATASETS(I).RITEMS.COUNT > 0)) then
          /* Обходим элементы набора данных для формирования отображаемых значений */
          for J in RDATASETS(I).RITEMS.FIRST .. RDATASETS(I).RITEMS.LAST
          loop
            /* Открываем значение элемента набора данных */
            PKG_XFAST.DOWN_NODE(SNAME => SRESP_ATTR_CHART_DS_DATA);
            /* Формируем значение элемента */
            PKG_XFAST.VALUE(NVALUE => RDATASETS(I).RITEMS(J).NVALUE);
            /* Закрываем значение элемента набора данных */
            PKG_XFAST.UP();
          end loop;
          /* Обходим элементы набора данных для формирования из самих */
          for J in RDATASETS(I).RITEMS.FIRST .. RDATASETS(I).RITEMS.LAST
          loop
            /* Открываем элемент набора данных */
            PKG_XFAST.DOWN_NODE(SNAME => SRESP_ATTR_CHART_DS_ITEMS);
            /* Добавляем статические атрибуты */
            PKG_XFAST.ATTR(SNAME => SRESP_ATTR_CHART_DS_I_VAL, NVALUE => RDATASETS(I).RITEMS(J).NVALUE);
            /* Добавляем дополнительные атрибуты */
            if ((RDATASETS(I).RITEMS(J).RATTR_VALS is not null) and (RDATASETS(I).RITEMS(J).RATTR_VALS.COUNT > 0)) then
              for K in RDATASETS(I).RITEMS(J).RATTR_VALS.FIRST .. RDATASETS(I).RITEMS(J).RATTR_VALS.LAST
              loop
                PKG_XFAST.ATTR(SNAME  => RDATASETS(I).RITEMS(J).RATTR_VALS(K).SNAME,
                               SVALUE => RDATASETS(I).RITEMS(J).RATTR_VALS(K).SVALUE);
              end loop;
            end if;
            /* Закрываем элемент набора данных */
            PKG_XFAST.UP();
          end loop;
        end if;
        /* Закрываем набор данных */
        PKG_XFAST.UP();
      end loop;
    end if;
  end TCHART_DATASETS_TO_XML;
  
  /* Формирование графика */
  function TCHART_MAKE
  (
    STYPE                   in varchar2,         -- Тип (см. константы SCHART_TYPE_*)
    STITLE                  in varchar2 := null, -- Заголовок (null - не отображать)
    SLGND_POS               in varchar2 := null  -- Расположение легенды (null - не отображать, см. константы SCHART_LGND_POS_*)
  ) return                  TCHART               -- Результат работы
  is
    RRES                    TCHART;              -- Буфер для результата
  begin
    /* Формируем объект */
    RRES.STYPE     := STYPE;
    RRES.STITLE    := STITLE;
    RRES.SLGND_POS := SLGND_POS;
    RRES.RLABELS   := TCHART_LABELS();
    RRES.RDATASETS := TCHART_DATASETS();
    /* Возвращаем результат */
    return RRES;
  end TCHART_MAKE;
  
  /* Добавление метки значения графика */
  procedure TCHART_ADD_LABEL
  (
    RCHART                  in out nocopy TCHART, -- Описание графика
    SLABEL                  in varchar2,          -- Метка значения
    BCLEAR                  in boolean := false   -- Флаг очистки коллекции меток (false - не очищать, true - очистить коллекцию перед добавлением)
  )
  is
  begin
    /* Инициализируем коллекцию если необходимо */
    if ((RCHART.RLABELS is null) or (BCLEAR)) then
      RCHART.RLABELS := TCHART_LABELS();
    end if;
    /* Добавляем элемент */
    RCHART.RLABELS.EXTEND();
    RCHART.RLABELS(RCHART.RLABELS.LAST) := SLABEL;
  end TCHART_ADD_LABEL;
  
  /* Добавление набора данных графика */
  procedure TCHART_ADD_DATASET
  (
    RCHART                  in out nocopy TCHART, -- Описание графика
    RDATASET                in TCHART_DATASET,    -- Набор данных
    BCLEAR                  in boolean := false   -- Флаг очистки коллекции наборов данных (false - не очищать, true - очистить коллекцию перед добавлением)
  )
  is
  begin
    /* Инициализируем коллекцию если необходимо */
    if ((RCHART.RDATASETS is null) or (BCLEAR)) then
      RCHART.RDATASETS := TCHART_DATASETS();
    end if;
    /* Добавляем элемент */
    RCHART.RDATASETS.EXTEND();
    RCHART.RDATASETS(RCHART.RDATASETS.LAST) := RDATASET;
  end TCHART_ADD_DATASET;
  
  /* Сериализация описания заголовка графика */
  procedure TCHART_DEF_TO_XML
  (
    RCHART                  in TCHART   -- Описание графика
  )
  is    
  begin
    /* Cтатические атрибуты заголовка */
    PKG_XFAST.ATTR(SNAME => SRESP_ATTR_TYPE, SVALUE => RCHART.STYPE);
    PKG_XFAST.ATTR(SNAME => SRESP_ATTR_TITLE, SVALUE => RCHART.STITLE);
    PKG_XFAST.ATTR(SNAME => SRESP_ATTR_CHART_LGND_POS, SVALUE => RCHART.SLGND_POS);
  end TCHART_DEF_TO_XML;
  
  /* Сериализация графика */
  function TCHART_TO_XML
  (
    RCHART                  in TCHART,     -- Описание графика
    NINCLUDE_DEF            in number := 1 -- Включить описание заголовка (0 - нет, 1 - да)
  ) return                  clob           -- XML-описание
  is
    CRES                    clob;          -- Буфер для результата
  begin
    /* Начинаем формирование XML */
    PKG_XFAST.PROLOGUE(ITYPE => PKG_XFAST.CONTENT_);
    /* Открываем корень */
    PKG_XFAST.DOWN_NODE(SNAME => SRESP_TAG_XDATA);
    /* Открываем график */
    PKG_XFAST.DOWN_NODE(SNAME => SRESP_TAG_XCHART);
    /* Если необходимо включить описание колонок */
    if (NINCLUDE_DEF = 1) then
      TCHART_DEF_TO_XML(RCHART => RCHART);
    end if;
    /* Формируем описание меток */
    TCHART_LABELS_TO_XML(RLABELS => RCHART.RLABELS);
    /* Формируем описание наборов данных */
    TCHART_DATASETS_TO_XML(RDATASETS => RCHART.RDATASETS);
    /* Закрываем график */
    PKG_XFAST.UP();
    /* Закрываем корень */
    PKG_XFAST.UP();
    /* Сериализуем */
    CRES := PKG_XFAST.SERIALIZE_TO_CLOB();
    /* Завершаем формирование XML */
    PKG_XFAST.EPILOGUE();
    /* Возвращаем полученное */
    return CRES;
  exception
    when others then
      /* Завершаем формирование XML */
      PKG_XFAST.EPILOGUE();
      /* Вернем ошибку */
      PKG_STATE.DIAGNOSTICS_STACKED();
      P_EXCEPTION(0, PKG_STATE.SQL_ERRM());
  end TCHART_TO_XML;
  
  /* Формирование колонки циклограммы */
  function TCYCLOGRAM_COLUMN_MAKE
  (
    SNAME                   in varchar2,       -- Заголовок колонки
    NSTART                  in number,         -- Позиция начала колонки
    NEND                    in number          -- Позиция конца колонки
  ) return                  TCYCLOGRAM_COLUMN  -- Результат работы
  is
    RRES                    TCYCLOGRAM_COLUMN; -- Буфер для результата
  begin
    /* Формируем объект */
    RRES.SNAME  := SNAME;
    RRES.NSTART := NSTART;
    RRES.NEND   := NEND;
    /* Возвращаем результат */
    return RRES;
  end TCYCLOGRAM_COLUMN_MAKE;
  
  /* Добавление колонки циклограммы в коллекцию */
  procedure TCYCLOGRAM_COLUMNS_ADD
  (
    RCOLUMNS                in out nocopy TCYCLOGRAM_COLUMNS, -- Коллекция колонок циклограммы
    SNAME                   in varchar2,                      -- Наименование колонки
    NSTART                  in number,                        -- Позиция начала колонки
    NEND                    in number,                        -- Позиция конца колонки
    BCLEAR                  in boolean := false               -- Флаг очистки коллекции колонок (false - не очищать, true - очистить коллекцию перед добавлением)
  )
  is
  begin
    /* Инициализируем коллекцию если необходимо */
    if ((RCOLUMNS is null) or (BCLEAR)) then
      RCOLUMNS := TCYCLOGRAM_COLUMNS();
    end if;
    /* Добавляем элемент */
    RCOLUMNS.EXTEND();
    RCOLUMNS(RCOLUMNS.LAST) := TCYCLOGRAM_COLUMN_MAKE(SNAME => SNAME, NSTART => NSTART, NEND => NEND);
  end TCYCLOGRAM_COLUMNS_ADD;
  
  /* Формирование группы циклограммы */
  function TCYCLOGRAM_GROUP_MAKE
  (
    SNAME                   in varchar2,                              -- Имя группы
    BHEADER_VISIBLE         in boolean := true,                       -- Признак отображения заголовка группы
    NHEADER_HEIGHT          in number := NCYCLOGRAM_GROUP_DEF_HEIGHT, -- Высота заголовка группы
    NHEADER_WIDTH           in number := NCYCLOGRAM_GROUP_DEF_WIDTH,  -- Ширина заголовка группы
    SHIGHLIGHT_COLOR        in varchar2 := null                       -- Цвет при наведении (null - использовать цвет по умолчанию из стилей, формат - HTML-цвет, #RRGGBBAA)
  ) return                  TCYCLOGRAM_GROUP                          -- Результат работы
  is
    RRES                    TCYCLOGRAM_GROUP;                         -- Буфер для результата
  begin
    /* Формируем объект */
    RRES.SNAME            := SNAME;
    RRES.BHEADER_VISIBLE  := BHEADER_VISIBLE;
    RRES.NHEADER_HEIGHT   := NHEADER_HEIGHT;
    RRES.NHEADER_WIDTH    := NHEADER_WIDTH;
    RRES.SHIGHLIGHT_COLOR := SHIGHLIGHT_COLOR;
    /* Возвращаем результат */
    return RRES;
  end TCYCLOGRAM_GROUP_MAKE;
  
  /* Поиск группы циклограммы по наименованию */
  function TCYCLOGRAM_GROUP_FIND
  (
    RGROUPS                 in TCYCLOGRAM_GROUPS, -- Описание групп циклограммы
    SNAME                   in varchar2           -- Наименование
  ) return                  TCYCLOGRAM_GROUP      -- Найденное описание группы (null - если не нашли)
  is
  begin
    /* Обходим группы из описания */
    if ((RGROUPS is not null) and (RGROUPS.COUNT > 0)) then
      for I in RGROUPS.FIRST .. RGROUPS.LAST
      loop
        if (RGROUPS(I).SNAME = SNAME) then
          return RGROUPS(I);
        end if;
      end loop;
    end if;
    /* Ничего не нашли */
    return null;
  end TCYCLOGRAM_GROUP_FIND;
  
  /* Сериализация описания групп циклограммы */
  procedure TCYCLOGRAM_GROUPS_TO_XML
  (
    RGROUPS                  in TCYCLOGRAM_GROUPS -- Коллекция групп циклограммы
  )
  is    
  begin
    /* Обходим группы из коллекции */
    if ((RGROUPS is not null) and (RGROUPS.COUNT > 0)) then
      for I in RGROUPS.FIRST .. RGROUPS.LAST
      loop
        /* Открываем описание группы */
        PKG_XFAST.DOWN_NODE(SNAME => SRESP_ATTR_GROUPS);
        /* Атрибуты группы */
        PKG_XFAST.ATTR(SNAME => SRESP_ATTR_NAME, SVALUE => RGROUPS(I).SNAME);
        PKG_XFAST.ATTR(SNAME => SRESP_ATTR_VISIBLE, BVALUE => RGROUPS(I).BHEADER_VISIBLE);
        PKG_XFAST.ATTR(SNAME => SRESP_ATTR_HEIGHT, NVALUE => RGROUPS(I).NHEADER_HEIGHT);
        PKG_XFAST.ATTR(SNAME => SRESP_ATTR_WIDTH, NVALUE => RGROUPS(I).NHEADER_WIDTH);
        if (RGROUPS(I).SHIGHLIGHT_COLOR is not null) then
          PKG_XFAST.ATTR(SNAME => SRESP_ATTR_HL_COLOR, SVALUE => RGROUPS(I).SHIGHLIGHT_COLOR);
        end if;
        /* Закрываем описание группы */
        PKG_XFAST.UP();
      end loop;
    end if;
  end TCYCLOGRAM_GROUPS_TO_XML;
  
  /* Проверка наличия группы в циклограмме */
  function TCYCLOGRAM_TASK_GROUP_CHECK
  (
    RGROUPS                 in TCYCLOGRAM_GROUPS, -- Описание групп циклограммы
    SNAME                   in varchar2           -- Наименование
  ) return                  TCYCLOGRAM_GROUP      -- Найденное описание группы (null - если не нашли)
  is
  begin
    /* Обходим группы из описания */
    if ((RGROUPS is not null) and (RGROUPS.COUNT > 0)) then
      for I in RGROUPS.FIRST .. RGROUPS.LAST
      loop
        if (RGROUPS(I).SNAME = SNAME) then
          return RGROUPS(I);
        end if;
      end loop;
    end if;
    /* Ничего не нашли */
    return null;
  end TCYCLOGRAM_TASK_GROUP_CHECK;
  
  /* Формирование задачи циклограммы */
  function TCYCLOGRAM_TASK_MAKE
  (
    NRN                     in number,           -- Рег. номер записи
    SCAPTION                in varchar2,         -- Заголовок
    SNAME                   in varchar2,         -- Наименование
    NLINE_NUMB              in number,           -- Номер строки
    NSTART                  in number,           -- Позиция начала задачи
    NEND                    in number,           -- Позиция конца задачи
    SGROUP                  in varchar2 := null, -- Наименование группы
    SBG_COLOR               in varchar2 := null, -- Цвет заливки задачи (null - использовать цвет по умолчанию из стилей, формат - HTML-цвет, #RRGGBBAA)
    STEXT_COLOR             in varchar2 := null, -- Цвет текста заголовка задачи (null - использовать цвет по умолчанию из стилей, формат - HTML-цвет, #RRGGBBAA)
    SHIGHLIGHT_COLOR        in varchar2 := null  -- Цвет при наведении (null - использовать цвет по умолчанию из стилей, формат - HTML-цвет, #RRGGBBAA)
  ) return                  TCYCLOGRAM_TASK      -- Результат работы
  is
    RRES                    TCYCLOGRAM_TASK;     -- Буфер для результата
  begin
    /* Формируем объект */
    RRES.NRN              := NRN;
    RRES.SCAPTION         := SCAPTION;
    RRES.SNAME            := SNAME;
    RRES.NLINE_NUMB       := NLINE_NUMB;
    RRES.NSTART           := NSTART;
    RRES.NEND             := NEND;
    RRES.SGROUP           := SGROUP;
    RRES.SBG_COLOR        := SBG_COLOR;
    RRES.STEXT_COLOR      := STEXT_COLOR;
    RRES.SHIGHLIGHT_COLOR := SHIGHLIGHT_COLOR;
    /* Возвращаем результат */
    return RRES;
  end TCYCLOGRAM_TASK_MAKE;
  
  /* Проверка корректности наименования дополнительного атрибута задачи циклограммы */
  procedure TCYCLOGRAM_TASK_ATTR_NAME_CH
  (
    SNAME                   in varchar2 -- Наименование
  )
  is
  begin
    if (SNAME in (SRESP_ATTR_ID,
                  SRESP_ATTR_RN,
                  SRESP_ATTR_CAPTION,
                  SRESP_ATTR_FULL_NAME,
                  SRESP_ATTR_START,
                  SRESP_ATTR_END,
                  SRESP_ATTR_CG_TASK_LINE,
                  SRESP_ATTR_GROUP_NAME,
                  SRESP_ATTR_TASK_BG_COLOR,
                  SRESP_ATTR_TASK_TEXT_COLOR,
                  SRESP_ATTR_HL_COLOR)) then
      P_EXCEPTION(0,
                  'Наименование атрибута "%s" является зарезервированным.',
                  SNAME);
    end if;
  end TCYCLOGRAM_TASK_ATTR_NAME_CH;
  
  /* Поиск атрибута задачи циклограммы по наименованию */
  function TCYCLOGRAM_TASK_ATTR_FIND
  (
    RTASK_ATTRS             in TCYCLOGRAM_TASK_ATTRS, -- Описание атрибутов задачи циклограммы
    SNAME                   in varchar2               -- Наименование
  ) return                  TCYCLOGRAM_TASK_ATTR      -- Найденное описание (null - если не нашли)
  is
  begin
    /* Обходим атрибуты из описания */
    if ((RTASK_ATTRS is not null) and (RTASK_ATTRS.COUNT > 0)) then
      for I in RTASK_ATTRS.FIRST .. RTASK_ATTRS.LAST
      loop
        if (RTASK_ATTRS(I).SNAME = SNAME) then
          return RTASK_ATTRS(I);
        end if;
      end loop;
    end if;
    /* Ничего не нашли */
    return null;
  end TCYCLOGRAM_TASK_ATTR_FIND;
  
  /* Добавление значения атрибута к задаче циклограммы */
  procedure TCYCLOGRAM_TASK_ADD_ATTR_VAL
  (
    RCYCLOGRAM              in TCYCLOGRAM,                 -- Описание циклограммы
    RTASK                   in out nocopy TCYCLOGRAM_TASK, -- Описание задачи
    SNAME                   in varchar2,                   -- Наименование
    SVALUE                  in varchar2,                   -- Значение
    BCLEAR                  in boolean := false            -- Флаг очистки коллекции значений атрибутов (false - не очищать, true - очистить коллекцию перед добавлением)
  )
  is
  begin
    /* Проверим наименование */
    TCYCLOGRAM_TASK_ATTR_NAME_CH(SNAME => SNAME);
    /* Проверим, что такой атрибут зарегистрирован */
    if (TCYCLOGRAM_TASK_ATTR_FIND(RTASK_ATTRS => RCYCLOGRAM.RTASK_ATTRS, SNAME => SNAME).SNAME is null) then
      P_EXCEPTION(0,
                  'Атрибут "%s" задачи циклограммы не зарегистрирован.',
                  SNAME);
    end if;
    /* Инициализируем коллекцию если необходимо */
    if ((RTASK.RATTR_VALS is null) or (BCLEAR)) then
      RTASK.RATTR_VALS := TCYCLOGRAM_TASK_ATTR_VALS();
    end if;
    /* Добавляем элемент */
    RTASK.RATTR_VALS.EXTEND();
    RTASK.RATTR_VALS(RTASK.RATTR_VALS.LAST).SNAME := SNAME;
    RTASK.RATTR_VALS(RTASK.RATTR_VALS.LAST).SVALUE := SVALUE;
  end TCYCLOGRAM_TASK_ADD_ATTR_VAL;
  
  /* Сериализация описания задач группы циклограммы */
  procedure TCYCLOGRAM_TASKS_TO_XML
  (
    RTASKS                  in TCYCLOGRAM_TASKS -- Коллекция задач группы циклограммы
  )
  is
  begin
    /* Обходим задачи из коллекции */
    if ((RTASKS is not null) and (RTASKS.COUNT > 0)) then
      for I in RTASKS.FIRST .. RTASKS.LAST
      loop
        /* Открываем строку */
        PKG_XFAST.DOWN_NODE(SNAME => SRESP_ATTR_TASKS);
        /* Статические тарибуты */
        PKG_XFAST.ATTR(SNAME => SRESP_ATTR_ID, SVALUE => 'taskId' || RTASKS(I).NRN);
        PKG_XFAST.ATTR(SNAME => SRESP_ATTR_RN, NVALUE => RTASKS(I).NRN);
        PKG_XFAST.ATTR(SNAME => SRESP_ATTR_NAME, SVALUE => RTASKS(I).SCAPTION);
        PKG_XFAST.ATTR(SNAME => SRESP_ATTR_FULL_NAME, SVALUE => RTASKS(I).SNAME);
        PKG_XFAST.ATTR(SNAME => SRESP_ATTR_CG_TASK_LINE, NVALUE => RTASKS(I).NLINE_NUMB);
        PKG_XFAST.ATTR(SNAME => SRESP_ATTR_START, NVALUE => RTASKS(I).NSTART);
        PKG_XFAST.ATTR(SNAME => SRESP_ATTR_END, NVALUE => RTASKS(I).NEND);
        if (RTASKS(I).SGROUP is not null) then
          PKG_XFAST.ATTR(SNAME => SRESP_ATTR_GROUP_NAME, SVALUE => RTASKS(I).SGROUP);
        end if;
        if (RTASKS(I).SBG_COLOR is not null) then
          PKG_XFAST.ATTR(SNAME => SRESP_ATTR_TASK_BG_COLOR, SVALUE => RTASKS(I).SBG_COLOR);
        end if;
        if (RTASKS(I).STEXT_COLOR is not null) then
          PKG_XFAST.ATTR(SNAME => SRESP_ATTR_TASK_TEXT_COLOR, SVALUE => RTASKS(I).STEXT_COLOR);
        end if;
        if (RTASKS(I).SHIGHLIGHT_COLOR is not null) then
          PKG_XFAST.ATTR(SNAME => SRESP_ATTR_HL_COLOR, SVALUE => RTASKS(I).SHIGHLIGHT_COLOR);
        end if;
        /* Динамические атрибуты */
        if ((RTASKS(I).RATTR_VALS is not null) and (RTASKS(I).RATTR_VALS.COUNT > 0)) then
          for J in RTASKS(I).RATTR_VALS.FIRST .. RTASKS(I).RATTR_VALS.LAST
          loop
            PKG_XFAST.ATTR(SNAME => RTASKS(I).RATTR_VALS(J).SNAME, SVALUE => RTASKS(I).RATTR_VALS(J).SVALUE);
          end loop;
        end if;
        /* Закрываем задачу */
        PKG_XFAST.UP();
      end loop;
    end if;
  end TCYCLOGRAM_TASKS_TO_XML;
  
  /* Формирование циклограммы */
  function TCYCLOGRAM_MAKE
  (
    STITLE                  in varchar2,                          -- Заголовок (null - не отображать)
    NLINE_HEIGHT            in number := NCYCLOGRAM_LINE_HEIGHT,  -- Высота строк
    NZOOM                   in number := NCYCLOGRAM_ZOOM_DEFAULT, -- Текущий масштаб (см. константы NCYCLOGRAM_ZOOM_*)
    BZOOM_BAR               in boolean := true                    -- Обображать панель масштабирования
  ) return                  TCYCLOGRAM                            -- Результат работы
  is
    RRES                    TCYCLOGRAM;                           -- Буфер для результата
  begin
    /* Формируем объект */
    RRES.STITLE       := STITLE;
    RRES.NLINE_HEIGHT := NLINE_HEIGHT;
    RRES.NZOOM        := NZOOM;
    RRES.BZOOM_BAR    := BZOOM_BAR;
    /* Возвращаем результат */
    return RRES;
  end TCYCLOGRAM_MAKE;
  
  /* Добавление колонки в циклограмму */
  procedure TCYCLOGRAM_ADD_COLUMN
  (
    RCYCLOGRAM              in out nocopy TCYCLOGRAM, -- Описание циклограммы
    SNAME                   in varchar2,              -- Заголовок колонки
    NSTART                  in number,                -- Позиция начала колонки
    NEND                    in number,                -- Позиция конца колонки
    BCLEAR                  in boolean := false       -- Флаг очистки коллекции колонок (false - не очищать, true - очистить коллекцию перед добавлением)
  )
  is
  begin
    /* Формируем описание и добавляем в коллекцию колонок */
    TCYCLOGRAM_COLUMNS_ADD(RCOLUMNS => RCYCLOGRAM.RCOLUMNS,
                           SNAME    => SNAME,
                           NSTART   => NSTART,
                           NEND     => NEND,
                           BCLEAR   => BCLEAR);
  end TCYCLOGRAM_ADD_COLUMN;
  
  /* Добавление группы в циклограмму */
  procedure TCYCLOGRAM_ADD_GROUP
  (
    RCYCLOGRAM              in out nocopy TCYCLOGRAM,                 -- Описание циклограммы
    SNAME                   in varchar2,                              -- Имя группы
    BHEADER_VISIBLE         in boolean := true,                       -- Признак отображения заголовка группы
    NHEADER_HEIGHT          in number := NCYCLOGRAM_GROUP_DEF_HEIGHT, -- Высота заголовка группы
    NHEADER_WIDTH           in number := NCYCLOGRAM_GROUP_DEF_WIDTH,  -- Ширина заголовка группы
    SHIGHLIGHT_COLOR        in varchar2 := null,                      -- Цвет при наведении (null - использовать цвет по умолчанию из стилей, формат - HTML-цвет, #RRGGBBAA)
    BCLEAR                  in boolean := false                       -- Флаг очистки коллекции групп (false - не очищать, true - очистить коллекцию перед добавлением)
  )
  is
  begin
    /* Проверяем наличие группы в циклограмме */
    if (TCYCLOGRAM_GROUP_FIND(RGROUPS => RCYCLOGRAM.RGROUPS, SNAME => SNAME).SNAME is null) then
      /* Инициализируем коллекцию если необходимо */
      if ((RCYCLOGRAM.RGROUPS is null) or (BCLEAR)) then
        RCYCLOGRAM.RGROUPS := TCYCLOGRAM_GROUPS();
      end if;
      /* Добавляем элемент */
      RCYCLOGRAM.RGROUPS.EXTEND();
      RCYCLOGRAM.RGROUPS(RCYCLOGRAM.RGROUPS.LAST) := TCYCLOGRAM_GROUP_MAKE(SNAME            => SNAME,
                                                                           BHEADER_VISIBLE  => BHEADER_VISIBLE,
                                                                           NHEADER_HEIGHT   => NHEADER_HEIGHT,
                                                                           NHEADER_WIDTH    => NHEADER_WIDTH,
                                                                           SHIGHLIGHT_COLOR => SHIGHLIGHT_COLOR);
    end if;
  end TCYCLOGRAM_ADD_GROUP;
  
  /* Добавление задачи в циклограммы */
  procedure TCYCLOGRAM_ADD_TASK
  (
    RCYCLOGRAM              in out nocopy TCYCLOGRAM, -- Описание циклограммы
    RTASK                   in TCYCLOGRAM_TASK,       -- Задача циклограммы
    BCLEAR                  in boolean := false       -- Флаг очистки коллекции задач (false - не очищать, true - очистить коллекцию перед добавлением)
  )
  is
  begin
    /* Инициализируем коллекцию если необходимо */
    if ((RCYCLOGRAM.RTASKS is null) or (BCLEAR)) then
      RCYCLOGRAM.RTASKS := TCYCLOGRAM_TASKS();
    end if;
    /* Если у задачи указана группа */
    if (RTASK.SGROUP is not null) then
      /* Проверяем наличие группы в циклограмме */
      if (TCYCLOGRAM_GROUP_FIND(RGROUPS => RCYCLOGRAM.RGROUPS, SNAME => RTASK.SGROUP).SNAME is null) then
        P_EXCEPTION(0, 'Группа "%s" циклограммы не зарегистрирована.', RTASK.SGROUP);
      end if;
    end if;
    /* Добавляем элемент */
    RCYCLOGRAM.RTASKS.EXTEND();
    RCYCLOGRAM.RTASKS(RCYCLOGRAM.RTASKS.LAST) := RTASK;
  end TCYCLOGRAM_ADD_TASK;
  
  /* Добавление описания атрибута задачи циклограммы */
  procedure TCYCLOGRAM_ADD_TASK_ATTR
  (
    RCYCLOGRAM              in out nocopy TCYCLOGRAM, -- Описание циклограммы
    SNAME                   in varchar2,              -- Наименование
    SCAPTION                in varchar2,              -- Заголовок
    BVISIBLE                boolean := true,          -- Разрешить отображение
    BCLEAR                  in boolean := false       -- Флаг очистки коллекции атрибутов (false - не очищать, true - очистить коллекцию перед добавлением)
  )
  is
  begin
    /* Проверим наименование */
    TCYCLOGRAM_TASK_ATTR_NAME_CH(SNAME => SNAME);
    /* Проверим, что такого ещё нет */
    if (TCYCLOGRAM_TASK_ATTR_FIND(RTASK_ATTRS => RCYCLOGRAM.RTASK_ATTRS, SNAME => SNAME).SNAME is not null) then
      P_EXCEPTION(0,
                  'Атрибут "%s" задачи циклограммы уже зарегистрирован.',
                  SNAME);
    end if;
    /* Инициализируем коллекцию если необходимо */
    if ((RCYCLOGRAM.RTASK_ATTRS is null) or (BCLEAR)) then
      RCYCLOGRAM.RTASK_ATTRS := TCYCLOGRAM_TASK_ATTRS();
    end if;
    /* Добавляем элемент */
    RCYCLOGRAM.RTASK_ATTRS.EXTEND();
    RCYCLOGRAM.RTASK_ATTRS(RCYCLOGRAM.RTASK_ATTRS.LAST).SNAME := SNAME;
    RCYCLOGRAM.RTASK_ATTRS(RCYCLOGRAM.RTASK_ATTRS.LAST).SCAPTION := SCAPTION;
    RCYCLOGRAM.RTASK_ATTRS(RCYCLOGRAM.RTASK_ATTRS.LAST).BVISIBLE := BVISIBLE;
  end TCYCLOGRAM_ADD_TASK_ATTR;
  
  /* Сериализация описания циклограммы */
  procedure TCYCLOGRAM_DEF_TO_XML
  (
    RCYCLOGRAM              in TCYCLOGRAM -- Описание циклограммы
  )
  is    
  begin
    /* Cтатические атрибуты заголовка */
    PKG_XFAST.ATTR(SNAME => SRESP_ATTR_TITLE, SVALUE => RCYCLOGRAM.STITLE);
    PKG_XFAST.ATTR(SNAME => SRESP_ATTR_CG_LINE_HEIGHT, NVALUE => RCYCLOGRAM.NLINE_HEIGHT);
    PKG_XFAST.ATTR(SNAME => SRESP_ATTR_ZOOM, NVALUE => RCYCLOGRAM.NZOOM);
    PKG_XFAST.ATTR(SNAME => SRESP_ATTR_ZOOM_BAR, BVALUE => RCYCLOGRAM.BZOOM_BAR);
    /* Если есть динамические атрибуты */
    if ((RCYCLOGRAM.RTASK_ATTRS is not null) and (RCYCLOGRAM.RTASK_ATTRS.COUNT > 0)) then
      /* Обходим динамические атрибуты задачи */
      for I in RCYCLOGRAM.RTASK_ATTRS.FIRST .. RCYCLOGRAM.RTASK_ATTRS.LAST
      loop
        /* Открываем динамический атрибут задачи */
        PKG_XFAST.DOWN_NODE(SNAME => SRESP_ATTR_TASK_ATTRIBUTES);
        /* Наполняем его атрибутами */
        PKG_XFAST.ATTR(SNAME => SRESP_ATTR_NAME, SVALUE => RCYCLOGRAM.RTASK_ATTRS(I).SNAME);
        PKG_XFAST.ATTR(SNAME => SRESP_ATTR_CAPTION, SVALUE => RCYCLOGRAM.RTASK_ATTRS(I).SCAPTION);
        PKG_XFAST.ATTR(SNAME => SRESP_ATTR_VISIBLE, BVALUE => RCYCLOGRAM.RTASK_ATTRS(I).BVISIBLE);
        /* Закрываем динамический атрибут задачи */
        PKG_XFAST.UP();
      end loop;
    end if;
    /* Обходим колонки циклограммы */
    if ((RCYCLOGRAM.RCOLUMNS is not null) and (RCYCLOGRAM.RCOLUMNS.COUNT > 0)) then
      for I in RCYCLOGRAM.RCOLUMNS.FIRST .. RCYCLOGRAM.RCOLUMNS.LAST
      loop
        /* Открываем описание колонки */
        PKG_XFAST.DOWN_NODE(SNAME => SRESP_ATTR_COLUMNS);
        /* Атрибуты колонки */
        PKG_XFAST.ATTR(SNAME => SRESP_ATTR_NAME, SVALUE => RCYCLOGRAM.RCOLUMNS(I).SNAME);
        PKG_XFAST.ATTR(SNAME => SRESP_ATTR_START, NVALUE => RCYCLOGRAM.RCOLUMNS(I).NSTART);
        PKG_XFAST.ATTR(SNAME => SRESP_ATTR_END, NVALUE => RCYCLOGRAM.RCOLUMNS(I).NEND);
        /* Закрываем описание колонки */
        PKG_XFAST.UP();
      end loop;
    end if;
  end TCYCLOGRAM_DEF_TO_XML;
  
  /* Сериализация циклограммы */
  function TCYCLOGRAM_TO_XML
  (
    RCYCLOGRAM              in TCYCLOGRAM, -- Описание циклограммы
    NINCLUDE_DEF            in number := 1 -- Включить описание колонок (0 - нет, 1 - да)
  ) return                  clob           -- XML-описание
  is
    CRES                    clob;          -- Буфер для результата
  begin
    /* Начинаем формирование XML */
    PKG_XFAST.PROLOGUE(ITYPE => PKG_XFAST.CONTENT_);
    /* Открываем корень */
    PKG_XFAST.DOWN_NODE(SNAME => SRESP_TAG_XDATA);
    /* Открываем циклограмму */
    PKG_XFAST.DOWN_NODE(SNAME => SRESP_TAG_XCYCLOGRAM);
    /* Если необходимо включить описание циклограммы */
    if (NINCLUDE_DEF = 1) then
      TCYCLOGRAM_DEF_TO_XML(RCYCLOGRAM => RCYCLOGRAM);
    end if;
    /* Формируем описание групп циклограммы */
    TCYCLOGRAM_GROUPS_TO_XML(RGROUPS => RCYCLOGRAM.RGROUPS);
    /* Описываем задачи */
    TCYCLOGRAM_TASKS_TO_XML(RTASKS => RCYCLOGRAM.RTASKS);
    /* Закрываем циклограмму */
    PKG_XFAST.UP();
    /* Закрываем корень */
    PKG_XFAST.UP();
    /* Сериализуем */
    CRES := PKG_XFAST.SERIALIZE_TO_CLOB();
    /* Завершаем формирование XML */
    PKG_XFAST.EPILOGUE();
    /* Возвращаем полученное */
    return CRES;
  exception
    when others then
      /* Завершаем формирование XML */
      PKG_XFAST.EPILOGUE();
      /* Вернем ошибку */
      PKG_STATE.DIAGNOSTICS_STACKED();
      P_EXCEPTION(0, PKG_STATE.SQL_ERRM());
  end TCYCLOGRAM_TO_XML;
  
end PKG_P8PANELS_VISUAL;
/