tool-dom-ang15 0.0.0-stage → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,3 +1,181 @@
1
- # Temporary Holding Version
2
-
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
1
+ # DOM Playground (`lib-tool-dom-ang15`)
2
+
3
+ Демонстрационный Angular-компонент, показывающий работу трёх сервисов для манипуляции DOM:
4
+
5
+ - **`DomElement`** — создание, вставка, удаление и поиск элементов;
6
+ - **`DomClass`** — управление CSS-классами, включая генерацию утилит отступов `margin/padding`;
7
+ - **`DomStyle`** — работа с инлайн-стилями элемента.
8
+
9
+ Компонент представляет собой интерактивную «песочницу» с кнопками для вызова каждого метода и журналом операций.
10
+
11
+ ---
12
+
13
+ ## Содержание
14
+
15
+ - [Установка и запуск](#установка-и-запуск)
16
+ - [Структура](#структура)
17
+ - [Разметка (HTML)](#разметка-html)
18
+ - [Компонент (TS)](#компонент-ts)
19
+ - [Демонстрации по сервисам](#демонстрации-по-сервисам)
20
+ - [DomElement](#domelement)
21
+ - [DomClass](#domclass)
22
+ - [DomStyle](#domstyle)
23
+ - [Утилиты и сброс](#утилиты-и-сброс)
24
+ - [Логирование](#логирование)
25
+
26
+ ---
27
+
28
+ ## Установка и запуск
29
+
30
+ Компонент предполагает наличие зависимостей:
31
+
32
+ ```ts
33
+ import { DomClass } from './dom/dom-class';
34
+ import { DomElement } from './dom/dom-element';
35
+ import { DomStyle } from './dom/dom-style';
36
+ import { green } from 'tool-log';
37
+ ```
38
+
39
+ Селектор компонента: `lib-tool-dom-ang15`.
40
+
41
+ ```html
42
+ <lib-tool-dom-ang15></lib-tool-dom-ang15>
43
+ ```
44
+
45
+ ---
46
+
47
+ ## Структура
48
+
49
+ ```
50
+ tool-dom-ang15/
51
+ ├── tool-dom-ang15.component.ts # логика песочницы
52
+ ├── tool-dom-ang15.component.html # шаблон (панели + лог)
53
+ ├── tool-dom-ang15.component.scss # стили
54
+ └── dom/
55
+ ├── dom-element.ts # сервис DomElement
56
+ ├── dom-class.ts # сервис DomClass
57
+ └── dom-style.ts # сервис DomStyle
58
+ ```
59
+
60
+ ---
61
+
62
+ ## Разметка (HTML)
63
+
64
+ Шаблон состоит из двух колонок:
65
+
66
+ **Левая колонка** — песочница и группы кнопок:
67
+
68
+ - `#sandbox` — корневой контейнер, к которому применяется `addClassMarginPadding`;
69
+ - `#target` — целевой элемент для классов и стилей;
70
+ - `#dynamicHost` — контейнер для динамически создаваемых элементов;
71
+ - три группы кнопок: **DomElement**, **DomClass**, **DomStyle**;
72
+ - кнопки **Reset All** и **Clear Log**.
73
+
74
+ **Правая колонка** — журнал операций (`logHtml`), выводится через `*ngFor`, с плейсхолдером при пустом логе.
75
+
76
+ ---
77
+
78
+ ## Компонент (TS)
79
+
80
+ Реализует `OnInit` и `AfterViewInit`.
81
+
82
+ **ViewChild-ссылки:**
83
+
84
+ | Ссылка | Назначение |
85
+ |---|---|
86
+ | `sandboxRef` | корень для генерации утилит отступов |
87
+ | `targetRef` | целевой элемент для классов/стилей |
88
+ | `dynamicHostRef` | хост динамических элементов |
89
+
90
+ **Публичные поля:**
91
+
92
+ - `logHtml: string[]` — массив строк лога;
93
+ - `dom: DomElement`, `cls: DomClass`, `style: DomStyle` — экземпляры сервисов.
94
+
95
+ **Инициализация (`ngOnInit`):**
96
+
97
+ ```ts
98
+ this.dom = new DomElement(this.document);
99
+ this.cls = new DomClass(this.document);
100
+ this.style = new DomStyle();
101
+ ```
102
+
103
+ `DOCUMENT` внедряется через `@Inject(DOCUMENT)`.
104
+
105
+ ---
106
+
107
+ ## Демонстрации по сервисам
108
+
109
+ ### DomElement
110
+
111
+ | Метод | Демо | Что делает |
112
+ |---|---|---|
113
+ | `createElement(tag, class)` | `demoCreateElement()` | создаёт `<div class="created-box">` и добавляет в `#dynamicHost` |
114
+ | `elementCreate(host, tag, mode, text, class, event, handler)` | `demoElementCreate()` | создаёт `<button>` с обработчиком `click` |
115
+ | `elementAdd(host, mode, class, event, handler, el)` | `demoElementAdd()` | вставляет `<span>` через `insertBefore`, вешает `mouseenter` |
116
+ | `elementRemove(host, el)` | `demoElementRemove()` | удаляет последний дочерний элемент |
117
+ | `elementGet(selector)` | `demoElementGet()` | асинхронно ждёт появления `.appears-later` (создаётся через 1 с) |
118
+ | `getElementByDataAttribute(attr, value?)` | `demoGetByDataAttr()` | ищет по `data-id`, затем уточняет по значению |
119
+ | `getCoordinates(el)` | `demoGetCoordinates()` | возвращает `{top, left, width, height}` |
120
+ | `elementGetParent(el)` | `demoGetParent()` | родительский узел |
121
+ | `elementsGetSiblingAll(el)` | `demoSiblingsAll()` | все соседи |
122
+ | `elementGetSiblingNext(el)` | `demoSiblingsNext()` | следующий сосед |
123
+ | `elementGetSiblingPrevious(el)` | `demoSiblingsPrevious()` | предыдущий узел (включая текстовые) |
124
+ | `elementGetChildren(el)` | `demoGetChildren()` | дочерние элементы |
125
+
126
+ ### DomClass
127
+
128
+ | Метод | Демо | Что делает |
129
+ |---|---|---|
130
+ | `hasClass(el, cls)` | `demoHasClass()` | проверяет наличие `demo-active` |
131
+ | `addClass(el, cls)` | `demoAddClass()` | добавляет `demo-active` |
132
+ | `addClasses(el, list)` | `demoAddClasses()` | массово добавляет `demo-a`, `demo-b`, `demo-c` |
133
+ | `addClassMarginPadding(rootRef, values)` | `demoAddClassMarginPadding()` | генерирует `.evo-{m\|p}{t\|r\|b\|l}-{1..5}` и применяет `evo-mt-2`, `evo-pl-3` |
134
+ | `deleteClassMarginPadding()` | `demoDeleteClassMarginPadding()` | удаляет `<style data-dynamic-style>` |
135
+ | `removeClass(el, cls)` | `demoRemoveClass()` | удаляет `demo-active` |
136
+ | `toggleClass(el, cls, force?)` | `demoToggleClass()` / `demoToggleForce()` | переключает класс (в т.ч. с `force=true`) |
137
+ | `getClasses(el)` | `demoGetClasses()` | возвращает список классов |
138
+ | `clearClasses(el)` | `demoClearClasses()` | удаляет все классы |
139
+
140
+ ### DomStyle
141
+
142
+ | Метод | Демо | Что делает |
143
+ |---|---|---|
144
+ | `applyStyleProperty(el, prop, value)` | `demoApplyStyle()` | задаёт `background-color` и `border` |
145
+ | `getStyle(el, prop)` | `demoGetStyle()` | читает `background-color` |
146
+ | `removeStyle(el, prop)` | `demoRemoveStyle()` | удаляет `background-color` |
147
+
148
+ ---
149
+
150
+ ## Утилиты и сброс
151
+
152
+ **`resetAll()`** — полный сброс состояния песочницы:
153
+
154
+ 1. `clearClasses(target)` — снять все классы;
155
+ 2. удалить инлайн-стили (`removeAttribute('style')`);
156
+ 3. очистить `#dynamicHost`;
157
+ 4. `deleteClassMarginPadding()` — убрать динамический `<style>`;
158
+ 5. обнулить `_createdCounter`.
159
+
160
+ **`clearLog()`** — очищает `logHtml`.
161
+
162
+ ---
163
+
164
+ ## Логирование
165
+
166
+ Внутренний метод `_log(message)`:
167
+
168
+ - добавляет запись с временной меткой в начало `logHtml` (`unshift`);
169
+ - ограничивает массив 200 элементами;
170
+ - дублирует сообщение в `console.log`.
171
+
172
+ Каждое демо-действие пишет в лог результат: имя метода, аргументы и итог (например, количество найденных элементов, значение класса, координаты).
173
+
174
+ ---
175
+
176
+ ## Примечания
177
+
178
+ - `DomClass` и `DomElement` принимают `Document` в конструкторе (для тестируемости и SSR-совместимости).
179
+ - `DomStyle` не требует `Document` — работает напрямую со `style` элемента.
180
+ - Генерация утилит отступов (`addClassMarginPadding`) опирается на CSS-переменные `--evo1..5`, ожидаемые в глобальных стилях проекта.
181
+ - Для асинхронного поиска `elementGet` использует повторные попытки, что позволяет дождаться появления элемента в DOM.
@@ -0,0 +1,198 @@
1
+ import { __decorate, __param } from "tslib";
2
+ import { Inject } from '@angular/core';
3
+ import { DOCUMENT } from "@angular/common";
4
+ import { DomElement } from "./dom-element";
5
+ /**
6
+ * Класс для работы с классами DOM
7
+ */
8
+ let DomClass = class DomClass {
9
+ constructor(document) {
10
+ this.document = document;
11
+ this.dom = new DomElement(this.document);
12
+ }
13
+ //region Управление классами
14
+ /**
15
+ * Проверяет наличие класса у элемента
16
+ *
17
+ * @param {HTMLElement} element - Элемент
18
+ * @param {string} className - Класс
19
+ *
20
+ * @returns {boolean} true, если класс присутствует
21
+ */
22
+ hasClass(element, className) {
23
+ return !!(className && element?.classList.contains(className));
24
+ }
25
+ /**
26
+ * Добавляет класс элементу
27
+ *
28
+ * @param {HTMLElement} element - Элемент
29
+ * @param {string} className - Класс
30
+ *
31
+ * @returns {boolean} true, если класс добавили
32
+ */
33
+ addClass(element, className) {
34
+ if (className && element && 'classList' in element) {
35
+ element.classList.add(className);
36
+ return true;
37
+ }
38
+ return false;
39
+ }
40
+ /**
41
+ * Массовое добавление CSS-классов
42
+ *
43
+ * @param {HTMLElement} element - Элемент
44
+ * @param classNames - Массив названий CSS-классов для добавления
45
+ */
46
+ addClasses(element, classNames) {
47
+ if (!element || !classNames || classNames.length === 0) {
48
+ return;
49
+ }
50
+ classNames.forEach(className => {
51
+ if (className && className.trim() !== '') {
52
+ this.addClass(element, className.trim());
53
+ }
54
+ });
55
+ }
56
+ /**
57
+ * Создает CSS-классы для margin и padding на основе переменных --evo{n}.
58
+ * Классы генерируются для всех направлений (top, right, bottom, left).
59
+ *
60
+ * @param elementRef - Элемент для которого будут создаваться классы.
61
+ * @param {number[]} arrVars - Значения для генерации классов.
62
+ *
63
+ */
64
+ addClassMarginPadding(elementRef, arrVars = []) {
65
+ const root = this.dom.elementGetParent(elementRef.nativeElement);
66
+ if (!root) {
67
+ console.error('Root element not found');
68
+ return;
69
+ }
70
+ const properties = ['m', 'p']; // margin, padding
71
+ const directions = ['t', 'r', 'b', 'l']; // top, right, bottom, left
72
+ let style = this.document.querySelector('style[data-dynamic-style]');
73
+ if (!style) {
74
+ style = this.document.createElement('style');
75
+ style.setAttribute('data-dynamic-style', '');
76
+ root.appendChild(style);
77
+ }
78
+ let cssContent = '';
79
+ // Добавляем классы для arrVars (если массив не пустой)
80
+ if (arrVars && arrVars.length > 0) {
81
+ arrVars.forEach(value => {
82
+ properties.forEach(prop => {
83
+ directions.forEach(dir => {
84
+ const className = `.evo-${prop}${dir}-${value}`;
85
+ const cssProperty = prop === 'm' ? 'margin' : 'padding';
86
+ const cssDirection = this._getCssDirection(dir);
87
+ cssContent += `${className} { ${cssProperty}-${cssDirection}: var(--evo${value}); }\n`;
88
+ });
89
+ });
90
+ });
91
+ }
92
+ style.textContent = cssContent;
93
+ }
94
+ /**
95
+ * Удаление всех классов созданных в addClassMarginPadding (<style data-dynamic-style="">)
96
+ * @see {@link addClassMarginPadding} - Создает CSS-классы для margin и padding на основе переменных --evo{n}.
97
+ */
98
+ deleteClassMarginPadding() {
99
+ this.document.querySelector('style[data-dynamic-style]')?.remove();
100
+ }
101
+ /**
102
+ * Удаляет класс у элемента
103
+ *
104
+ * @param {HTMLElement} element - Элемент
105
+ * @param {string} className - Класс
106
+ *
107
+ * @returns {boolean} true, если класс был удален
108
+ */
109
+ removeClass(element, className) {
110
+ if (className && element && 'classList' in element) {
111
+ element.classList.remove(className);
112
+ return true;
113
+ }
114
+ return false;
115
+ }
116
+ /**
117
+ * Переключает CSS-класс у корневого элемента
118
+ *
119
+ * @param {HTMLElement} element - Элемент
120
+ * @param className - Название CSS-класса для переключения
121
+ * @param force - Принудительно установить или удалить класс (true - добавить, false - удалить)
122
+ */
123
+ toggleClass(element, className, force) {
124
+ if (!element || !className) {
125
+ return;
126
+ }
127
+ const trimmedClassName = className.trim();
128
+ if (force !== undefined) {
129
+ if (force) {
130
+ this.addClass(element, trimmedClassName);
131
+ }
132
+ else {
133
+ this.removeClass(element, trimmedClassName);
134
+ }
135
+ }
136
+ else {
137
+ // Переключаем на основе текущего состояния
138
+ if (this.hasClass(element, trimmedClassName)) {
139
+ this.removeClass(element, trimmedClassName);
140
+ }
141
+ else {
142
+ this.addClass(element, trimmedClassName);
143
+ }
144
+ }
145
+ }
146
+ /**
147
+ * Возвращает массив всех CSS-классов корневого элемента
148
+ *
149
+ * @param {HTMLElement} element - Элемент
150
+ *
151
+ * @returns Массив названий CSS-классов
152
+ */
153
+ getClasses(element) {
154
+ if (element) {
155
+ // Получаем актуальные классы с элемента
156
+ return Array.from(element.classList);
157
+ }
158
+ return [];
159
+ }
160
+ /**
161
+ * Удаляет все CSS-классы у корневого элемента и очищает кэш
162
+ *
163
+ * @param {HTMLElement} element - Элемент
164
+ */
165
+ clearClasses(element) {
166
+ // Удаляем все классы с элемента
167
+ if (element) {
168
+ element.className = '';
169
+ }
170
+ }
171
+ //endregion
172
+ //region Приватные методы
173
+ /**
174
+ * Преобразует сокращенное направление (t, r, b, l) в полное название CSS-свойства.
175
+ *
176
+ * @param {string} dir - Сокращенное направление (t, r, b, l).
177
+ * @returns {string} Полное название направления (top, right, bottom, left).
178
+ */
179
+ _getCssDirection(dir) {
180
+ switch (dir) {
181
+ case 't':
182
+ return 'top';
183
+ case 'r':
184
+ return 'right';
185
+ case 'b':
186
+ return 'bottom';
187
+ case 'l':
188
+ return 'left';
189
+ default:
190
+ return '';
191
+ }
192
+ }
193
+ };
194
+ DomClass = __decorate([
195
+ __param(0, Inject(DOCUMENT))
196
+ ], DomClass);
197
+ export { DomClass };
198
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZG9tLWNsYXNzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvdG9vbC1kb20tYW5nMTUvc3JjL2xpYi9kb20vZG9tLWNsYXNzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQSxPQUFPLEVBQWEsTUFBTSxFQUFDLE1BQU0sZUFBZSxDQUFDO0FBQ2pELE9BQU8sRUFBQyxRQUFRLEVBQUMsTUFBTSxpQkFBaUIsQ0FBQztBQUN6QyxPQUFPLEVBQUMsVUFBVSxFQUFDLE1BQU0sZUFBZSxDQUFDO0FBRXpDOztHQUVHO0FBQ0ksSUFBTSxRQUFRLEdBQWQsTUFBTSxRQUFRO0lBR2pCLFlBQzZCLFFBQWtCO1FBQWxCLGFBQVEsR0FBUixRQUFRLENBQVU7UUFFM0MsSUFBSSxDQUFDLEdBQUcsR0FBRyxJQUFJLFVBQVUsQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUE7SUFDNUMsQ0FBQztJQUVELDRCQUE0QjtJQUM1Qjs7Ozs7OztPQU9HO0lBQ0gsUUFBUSxDQUFDLE9BQW9CLEVBQUUsU0FBaUI7UUFDNUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxTQUFTLElBQUksT0FBTyxFQUFFLFNBQVMsQ0FBQyxRQUFRLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQztJQUNuRSxDQUFDO0lBRUQ7Ozs7Ozs7T0FPRztJQUNILFFBQVEsQ0FBQyxPQUEyQixFQUFFLFNBQWlCO1FBQ25ELElBQUksU0FBUyxJQUFJLE9BQU8sSUFBSSxXQUFXLElBQUksT0FBTyxFQUFFO1lBQ2hELE9BQU8sQ0FBQyxTQUFTLENBQUMsR0FBRyxDQUFDLFNBQVMsQ0FBQyxDQUFDO1lBRWpDLE9BQU8sSUFBSSxDQUFDO1NBQ2Y7UUFFRCxPQUFPLEtBQUssQ0FBQztJQUNqQixDQUFDO0lBRUQ7Ozs7O09BS0c7SUFDSCxVQUFVLENBQUMsT0FBMkIsRUFBRSxVQUFvQjtRQUN4RCxJQUFJLENBQUMsT0FBTyxJQUFJLENBQUMsVUFBVSxJQUFJLFVBQVUsQ0FB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QUNKLE9BQU8sS0FBSyxDQUFDO1lBQ2pCLEtBQUssR0FBRztnQkFDSixPQUFPLE9BQU8sQ0FBQztZQUNuQixLQUFLLEdBQUc7Z0JBQ0osT0FBTyxRQUFRLENBQUM7WUFDcEIsS0FBSyxHQUFHO2dCQUNKLE9BQU8sTUFBTSxDQUFDO1lBQ2xCO2dCQUNJLE9BQU8sRUFBRSxDQUFDO1NBQ2pCO0lBQ0wsQ0FBQztDQUdKLENBQUE7QUF0TlksUUFBUTtJQUlaLFdBQUEsTUFBTSxDQUFDLFFBQVEsQ0FBQyxDQUFBO0dBSlosUUFBUSxDQXNOcEI7U0F0TlksUUFBUSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7RWxlbWVudFJlZiwgSW5qZWN0fSBmcm9tICdAYW5ndWxhci9jb3JlJztcclxuaW1wb3J0IHtET0NVTUVOVH0gZnJvbSBcIkBhbmd1bGFyL2NvbW1vblwiO1xyXG5pbXBvcnQge0RvbUVsZW1lbnR9IGZyb20gXCIuL2RvbS1lbGVtZW50XCI7XHJcblxyXG4vKipcclxuICog0JrQu9Cw0YHRgSDQtNC70Y8g0YDQsNCx0L7RgtGLINGBINC60LvQsNGB0YHQsNC80LggRE9NXHJcbiAqL1xyXG5leHBvcnQgY2xhc3MgRG9tQ2xhc3Mge1xyXG4gICAgcHVibGljIGRvbTogRG9tRWxlbWVudDtcclxuXHJcbiAgICBjb25zdHJ1Y3RvcihcclxuICAgICAgICBASW5qZWN0KERPQ1VNRU5UKSBwdWJsaWMgZG9jdW1lbnQ6IERvY3VtZW50LFxyXG4gICAgKSB7XHJcbiAgICAgICAgdGhpcy5kb20gPSBuZXcgRG9tRWxlbWVudCh0aGlzLmRvY3VtZW50KVxyXG4gICAgfVxyXG5cclxuICAgIC8vcmVnaW9uINCj0L/RgNCw0LLQu9C10L3QuNC1INC60LvQsNGB0YHQsNC80LhcclxuICAgIC8qKlxyXG4gICAgICog0J/RgNC+0LLQtdGA0Y/QtdGCINC90LDQu9C40YfQuNC1INC60LvQsNGB0YHQsCDRgyDRjdC70LXQvNC10L3RgtCwXHJcbiAgICAgKlxyXG4gICAgICogQHBhcmFtIHtIVE1MRWxlbWVudH0gZWxlbWVudCAtINCt0LvQtdC80LXQvdGCXHJcbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gY2xhc3NOYW1lIC0g0JrQu9Cw0YHRgVxyXG4gICAgICpcclxuICAgICAqIEByZXR1cm5zIHtib29sZWFufSB0cnVlLCDQtdGB0LvQuCDQutC70LDRgdGBINC/0YDQuNGB0YPRgtGB0YLQstGD0LXRglxyXG4gICAgICovXHJcbiAgICBoYXNDbGFzcyhlbGVtZW50OiBIVE1MRWxlbWVudCwgY2xhc3NOYW1lOiBzdHJpbmcpOiBib29sZWFuIHtcclxuICAgICAgICByZXR1cm4gISEoY2xhc3NOYW1lICYmIGVsZW1lbnQ/LmNsYXNzTGlzdC5jb250YWlucyhjbGFzc05hbWUpKTtcclxuICAgIH1cclxuXHJcbiAgICAvKipcclxuICAgICAqINCU0L7QsdCw0LLQu9GP0LXRgiDQutC70LDRgdGBINGN0LvQtdC80LXQvdGC0YNcclxuICAgICAqXHJcbiAgICAgKiBAcGFyYW0ge0hUTUxFbGVtZW50fSBlbGVtZW50IC0g0K3Qu9C10LzQtdC90YJcclxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBjbGFzc05hbWUgLSDQmtC70LDRgdGBXHJcbiAgICAgKlxyXG4gICAgICogQHJldHVybnMge2Jvb2xlYW59IHRydWUsINC10YHQu9C4INC60LvQsNGB0YEg0LTQvtCx0LDQstC40LvQuFxyXG4gICAgICovXHJcbiAgICBhZGRDbGFzcyhlbGVtZW50OiBIVE1MRWxlbWVudCB8IG51bGwsIGNsYXNzTmFtZTogc3RyaW5nKTogYm9vbGVhbiB7XHJcbiAgICAgICAgaWYgKGNsYXNzTmFtZSAmJiBlbGVtZW50ICYmICdjbGFzc0xpc3QnIGluIGVsZW1lbnQpIHtcclxuICAgICAgICAgICAgZWxlbWVudC5jbGFzc0xpc3QuYWRkKGNsYXNzTmFtZSk7XHJcblxyXG4gICAgICAgICAgICByZXR1cm4gdHJ1ZTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIHJldHVybiBmYWxzZTtcclxuICAgIH1cclxuXHJcbiAgICAvKipcclxuICAgICAqINCc0LDRgdGB0L7QstC+0LUg0LTQvtCx0LDQstC70LXQvdC40LUgQ1NTLdC60LvQsNGB0YHQvtCyXHJcbiAgICAgKlxyXG4gICAgICogQHBhcmFtIHtIVE1MRWxlbWVudH0gZWxlbWVudCAtINCt0LvQtdC80LXQvdGCXHJcbiAgICAgKiBAcGFyYW0gY2xhc3NOYW1lcyAtINCc0LDRgdGB0LjQsiDQvdCw0LfQstCw0L3QuNC5IENTUy3QutC70LDRgdGB0L7QsiDQtNC70Y8g0LTQvtCx0LDQstC70LXQvdC40Y9cclxuICAgICAqL1xyXG4gICAgYWRkQ2xhc3NlcyhlbGVtZW50OiBIVE1MRWxlbWVudCB8IG51bGwsIGNsYXNzTmFtZXM6IHN0cmluZ1tdKTogdm9pZCB7XHJcbiAgICAgICAgaWYgKCFlbGVtZW50IHx8ICFjbGFzc05hbWVzIHx8IGNsYXNzTmFtZXMubGVuZ3RoID09PSAwKSB7XHJcbiAgICAgICAgICAgIHJldHVybjtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIGNsYXNzTmFtZXMuZm9yRWFjaChjbGFzc05hbWUgPT4ge1xyXG4gICAgICAgICAgICBpZiAoY2xhc3NOYW1lICYmIGNsYXNzTmFtZS50cmltKCkgIT09ICcnKSB7XHJcbiAgICAgICAgICAgICAgICB0aGlzLmFkZENsYXNzKGVsZW1lbnQsIGNsYXNzTmFtZS50cmltKCkpO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgfSk7XHJcbiAgICB9XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiDQodC+0LfQtNCw0LXRgiBDU1Mt0LrQu9Cw0YHRgdGLINC00LvRjyBtYXJnaW4g0LggcGFkZGluZyDQvdCwINC+0YHQvdC+0LLQtSDQv9C10YDQtdC80LXQvdC90YvRhSAtLWV2b3tufS5cclxuICAgICAqINCa0LvQsNGB0YHRiyDQs9C10L3QtdGA0LjRgNGD0Y7RgtGB0Y8g0LTQu9GPINCy0YHQtdGFINC90LDQv9GA0LDQstC70LXQvdC40LkgKHRvcCwgcmlnaHQsIGJvdHRvbSwgbGVmdCkuXHJcbiAgICAgKlxyXG4gICAgICogQHBhcmFtIGVsZW1lbnRSZWYgLSDQrdC70LXQvNC10L3RgiDQtNC70Y8g0LrQvtGC0L7RgNC+0LPQviDQsdGD0LTRg9GCINGB0L7Qt9C00LDQstCw0YLRjNGB0Y8g0LrQu9Cw0YHRgdGLLlxyXG4gICAgICogQHBhcmFtIHtudW1iZXJbXX0gYXJyVmFycyAtINCX0L3QsNGH0LXQvdC40Y8g0LTQu9GPINCz0LXQvdC10YDQsNGG0LjQuCDQutC70LDRgdGB0L7Qsi5cclxuICAgICAqXHJcbiAgICAgKi9cclxuICAgIGFkZENsYXNzTWFyZ2luUGFkZGluZyhlbGVtZW50UmVmOiBFbGVtZW50UmVmPEhUTUxFbGVtZW50PiwgYXJyVmFyczogbnVtYmVyW10gPSBbXSk6IHZvaWQge1xyXG4gICAgICAgIGNvbnN0IHJvb3QgPSB0aGlzLmRvbS5lbGVtZW50R2V0UGFyZW50KGVsZW1lbnRSZWYubmF0aXZlRWxlbWVudCk7XHJcblxyXG4gICAgICAgIGlmICghcm9vdCkge1xyXG4gICAgICAgICAgICBjb25zb2xlLmVycm9yKCdSb290IGVsZW1lbnQgbm90IGZvdW5kJyk7XHJcbiAgICAgICAgICAgIHJldHVybjtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIGNvbnN0IHByb3BlcnRpZXMgPSBbJ20nLCAncCddOyAvLyBtYXJnaW4sIHBhZGRpbmdcclxuICAgICAgICBjb25zdCBkaXJlY3Rpb25zID0gWyd0JywgJ3InLCAnYicsICdsJ107IC8vIHRvcCwgcmlnaHQsIGJvdHRvbSwgbGVmdFxyXG4gICAgICAgIGxldCBzdHlsZSA9IHRoaXMuZG9jdW1lbnQucXVlcnlTZWxlY3Rvcignc3R5bGVbZGF0YS1keW5hbWljLXN0eWxlXScpO1xyXG5cclxuICAgICAgICBpZiAoIXN0eWxlKSB7XHJcbiAgICAgICAgICAgIHN0eWxlID0gdGhpcy5kb2N1bWVudC5jcmVhdGVFbGVtZW50KCdzdHlsZScpO1xyXG4gICAgICAgICAgICBzdHlsZS5zZXRBdHRyaWJ1dGUoJ2RhdGEtZHluYW1pYy1zdHlsZScsICcnKTtcclxuICAgICAgICAgICAgcm9vdC5hcHBlbmRDaGlsZChzdHlsZSk7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICBsZXQgY3NzQ29udGVudCA9ICcnO1xyXG5cclxuICAgICAgICAvLyDQlNC+0LHQsNCy0LvRj9C10Lwg0LrQu9Cw0YHRgdGLINC00LvRjyBhcnJWYXJzICjQtdGB0LvQuCDQvNCw0YHRgdC40LIg0L3QtSDQv9GD0YHRgtC+0LkpXHJcbiAgICAgICAgaWYgKGFyclZhcnMgJiYgYXJyVmFycy5sZW5ndGggPiAwKSB7XHJcbiAgICAgICAgICAgIGFyclZhcnMuZm9yRWFjaCh2YWx1ZSA9PiB7XHJcbiAgICAgICAgICAgICAgICBwcm9wZXJ0aWVzLmZvckVhY2gocHJvcCA9PiB7XHJcbiAgICAgICAgICAgICAgICAgICAgZGlyZWN0aW9ucy5mb3JFYWNoKGRpciA9PiB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IGNsYXNzTmFtZSA9IGAuZXZvLSR7cHJvcH0ke2Rpcn0tJHt2YWx1ZX1gO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBjc3NQcm9wZXJ0eSA9IHByb3AgPT09ICdtJyA/ICdtYXJnaW4nIDogJ3BhZGRpbmcnO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBjc3NEaXJlY3Rpb24gPSB0aGlzLl9nZXRDc3NEaXJlY3Rpb24oZGlyKTtcclxuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGNzc0NvbnRlbnQgKz0gYCR7Y2xhc3NOYW1lfSB7ICR7Y3NzUHJvcGVydHl9LSR7Y3NzRGlyZWN0aW9ufTogdmFyKC0tZXZvJHt2YWx1ZX0pOyB9XFxuYDtcclxuICAgICAgICAgICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgICAgIH0pO1xyXG4gICAgICAgICAgICB9KTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIHN0eWxlLnRleHRDb250ZW50ID0gY3NzQ29udGVudDtcclxuICAgIH1cclxuXHJcbiAgICAvKipcclxuICAgICAqINCj0LTQsNC70LXQvdC40LUg0LLRgdC10YUg0LrQu9Cw0YHRgdC+0LIg0YHQvtC30LTQsNC90L3Ri9GFINCyIGFkZENsYXNzTWFyZ2luUGFkZGluZyAoPHN0eWxlIGRhdGEtZHluYW1pYy1zdHlsZT1cIlwiPilcclxuICAgICAqICBAc2VlIHtAbGluayBhZGRDbGFzc01hcmdpblBhZGRpbmd9IC0g0KHQvtC30LTQsNC10YIgQ1NTLdC60LvQsNGB0YHRiyDQtNC70Y8gbWFyZ2luINC4IHBhZGRpbmcg0L3QsCDQvtGB0L3QvtCy0LUg0L/QtdGA0LXQvNC10L3QvdGL0YUgLS1ldm97bn0uXHJcbiAgICAgKi9cclxuICAgIGRlbGV0ZUNsYXNzTWFyZ2luUGFkZGluZygpOiB2b2lkIHtcclxuICAgICAgICB0aGlzLmRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJ3N0eWxlW2RhdGEtZHluYW1pYy1zdHlsZV0nKT8ucmVtb3ZlKCk7XHJcbiAgICB9XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiDQo9C00LDQu9GP0LXRgiDQutC70LDRgdGBINGDINGN0LvQtdC80LXQvdGC0LBcclxuICAgICAqXHJcbiAgICAgKiBAcGFyYW0ge0hUTUxFbGVtZW50fSBlbGVtZW50IC0g0K3Qu9C10LzQtdC90YJcclxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBjbGFzc05hbWUgLSDQmtC70LDRgdGBXHJcbiAgICAgKlxyXG4gICAgICogQHJldHVybnMge2Jvb2xlYW59IHRydWUsINC10YHQu9C4INC60LvQsNGB0YEg0LHRi9C7INGD0LTQsNC70LXQvVxyXG4gICAgICovXHJcbiAgICByZW1vdmVDbGFzcyhlbGVtZW50OiBIVE1MRWxlbWVudCB8IG51bGwsIGNsYXNzTmFtZTogc3RyaW5nKTogYm9vbGVhbiB7XHJcbiAgICAgICAgaWYgKGNsYXNzTmFtZSAmJiBlbGVtZW50ICYmICdjbGFzc0xpc3QnIGluIGVsZW1lbnQpIHtcclxuICAgICAgICAgICAgZWxlbWVudC5jbGFzc0xpc3QucmVtb3ZlKGNsYXNzTmFtZSk7XHJcblxyXG4gICAgICAgICAgICByZXR1cm4gdHJ1ZTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIHJldHVybiBmYWxzZTtcclxuICAgIH1cclxuXHJcbiAgICAvKipcclxuICAgICAqINCf0LXRgNC10LrQu9GO0YfQsNC10YIgQ1NTLdC60LvQsNGB0YEg0YMg0LrQvtGA0L3QtdCy0L7Qs9C+INGN0LvQtdC80LXQvdGC0LBcclxuICAgICAqXHJcbiAgICAgKiBAcGFyYW0ge0hUTUxFbGVtZW50fSBlbGVtZW50IC0g0K3Qu9C10LzQtdC90YJcclxuICAgICAqIEBwYXJhbSBjbGFzc05hbWUgLSDQndCw0LfQstCw0L3QuNC1IENTUy3QutC70LDRgdGB0LAg0LTQu9GPINC/0LXRgNC10LrQu9GO0YfQtdC90LjRj1xyXG4gICAgICogQHBhcmFtIGZvcmNlIC0g0J/RgNC40L3Rg9C00LjRgtC10LvRjNC90L4g0YPRgdGC0LDQvdC+0LLQuNGC0Ywg0LjQu9C4INGD0LTQsNC70LjRgtGMINC60LvQsNGB0YEgKHRydWUgLSDQtNC+0LHQsNCy0LjRgtGMLCBmYWxzZSAtINGD0LTQsNC70LjRgtGMKVxyXG4gICAgICovXHJcbiAgICB0b2dnbGVDbGFzcyhlbGVtZW50OiBIVE1MRWxlbWVudCB8IG51bGwsIGNsYXNzTmFtZTogc3RyaW5nLCBmb3JjZT86IGJvb2xlYW4pOiB2b2lkIHtcclxuICAgICAgICBpZiAoIWVsZW1lbnQgfHwgIWNsYXNzTmFtZSkge1xyXG4gICAgICAgICAgICByZXR1cm47XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICBjb25zdCB0cmltbWVkQ2xhc3NOYW1lID0gY2xhc3NOYW1lLnRyaW0oKTtcclxuXHJcbiAgICAgICAgaWYgKGZvcmNlICE9PSB1bmRlZmluZWQpIHtcclxuICAgICAgICAgICAgaWYgKGZvcmNlKSB7XHJcbiAgICAgICAgICAgICAgICB0aGlzLmFkZENsYXNzKGVsZW1lbnQsIHRyaW1tZWRDbGFzc05hbWUpO1xyXG4gICAgICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICAgICAgdGhpcy5yZW1vdmVDbGFzcyhlbGVtZW50LCB0cmltbWVkQ2xhc3NOYW1lKTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgIC8vINCf0LXRgNC10LrQu9GO0YfQsNC10Lwg0L3QsCDQvtGB0L3QvtCy0LUg0YLQtdC60YPRidC10LPQviDRgdC+0YHRgtC+0Y/QvdC40Y9cclxuICAgICAgICAgICAgaWYgKHRoaXMuaGFzQ2xhc3MoZWxlbWVudCwgdHJpbW1lZENsYXNzTmFtZSkpIHtcclxuICAgICAgICAgICAgICAgIHRoaXMucmVtb3ZlQ2xhc3MoZWxlbWVudCwgdHJpbW1lZENsYXNzTmFtZSk7XHJcbiAgICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgICAgICB0aGlzLmFkZENsYXNzKGVsZW1lbnQsIHRyaW1tZWRDbGFzc05hbWUpO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8qKlxyXG4gICAgICog0JLQvtC30LLRgNCw0YnQsNC10YIg0LzQsNGB0YHQuNCyINCy0YHQtdGFIENTUy3QutC70LDRgdGB0L7QsiDQutC+0YDQvdC10LLQvtCz0L4g0Y3Qu9C10LzQtdC90YLQsFxyXG4gICAgICpcclxuICAgICAqIEBwYXJhbSB7SFRNTEVsZW1lbnR9IGVsZW1lbnQgLSDQrdC70LXQvNC10L3RglxyXG4gICAgICpcclxuICAgICAqIEByZXR1cm5zINCc0LDRgdGB0LjQsiDQvdCw0LfQstCw0L3QuNC5IENTUy3QutC70LDRgdGB0L7QslxyXG4gICAgICovXHJcbiAgICBnZXRDbGFzc2VzKGVsZW1lbnQ6IEhUTUxFbGVtZW50IHwgbnVsbCk6IHN0cmluZ1tdIHtcclxuICAgICAgICBpZiAoZWxlbWVudCkge1xyXG4gICAgICAgICAgICAvLyDQn9C+0LvRg9GH0LDQtdC8INCw0LrRgtGD0LDQu9GM0L3Ri9C1INC60LvQsNGB0YHRiyDRgSDRjdC70LXQvNC10L3RgtCwXHJcbiAgICAgICAgICAgIHJldHVybiBBcnJheS5mcm9tKGVsZW1lbnQuY2xhc3NMaXN0KTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIHJldHVybiBbXTtcclxuICAgIH1cclxuXHJcbiAgICAvKipcclxuICAgICAqINCj0LTQsNC70Y/QtdGCINCy0YHQtSBDU1Mt0LrQu9Cw0YHRgdGLINGDINC60L7RgNC90LXQstC+0LPQviDRjdC70LXQvNC10L3RgtCwINC4INC+0YfQuNGJ0LDQtdGCINC60Y3RiFxyXG4gICAgICpcclxuICAgICAqIEBwYXJhbSB7SFRNTEVsZW1lbnR9IGVsZW1lbnQgLSDQrdC70LXQvNC10L3RglxyXG4gICAgICovXHJcbiAgICBjbGVhckNsYXNzZXMoZWxlbWVudDogSFRNTEVsZW1lbnQgfCBudWxsKTogdm9pZCB7XHJcbiAgICAgICAgLy8g0KPQtNCw0LvRj9C10Lwg0LLRgdC1INC60LvQsNGB0YHRiyDRgSDRjdC70LXQvNC10L3RgtCwXHJcbiAgICAgICAgaWYgKGVsZW1lbnQpIHtcclxuICAgICAgICAgICAgZWxlbWVudC5jbGFzc05hbWUgPSAnJztcclxuICAgICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLy9lbmRyZWdpb25cclxuXHJcbiAgICAvL3JlZ2lvbiDQn9GA0LjQstCw0YLQvdGL0LUg0LzQtdGC0L7QtNGLXHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiDQn9GA0LXQvtCx0YDQsNC30YPQtdGCINGB0L7QutGA0LDRidC10L3QvdC+0LUg0L3QsNC/0YDQsNCy0LvQtdC90LjQtSAodCwgciwgYiwgbCkg0LIg0L/QvtC70L3QvtC1INC90LDQt9Cy0LDQvdC40LUgQ1NTLdGB0LLQvtC50YHRgtCy0LAuXHJcbiAgICAgKlxyXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IGRpciAtINCh0L7QutGA0LDRidC10L3QvdC+0LUg0L3QsNC/0YDQsNCy0LvQtdC90LjQtSAodCwgciwgYiwgbCkuXHJcbiAgICAgKiBAcmV0dXJucyB7c3RyaW5nfSDQn9C+0LvQvdC+0LUg0L3QsNC30LLQsNC90LjQtSDQvdCw0L/RgNCw0LLQu9C10L3QuNGPICh0b3AsIHJpZ2h0LCBib3R0b20sIGxlZnQpLlxyXG4gICAgICovXHJcbiAgICBwcml2YXRlIF9nZXRDc3NEaXJlY3Rpb24oZGlyOiBzdHJpbmcpOiBzdHJpbmcge1xyXG4gICAgICAgIHN3aXRjaCAoZGlyKSB7XHJcbiAgICAgICAgICAgIGNhc2UgJ3QnOlxyXG4gICAgICAgICAgICAgICAgcmV0dXJuICd0b3AnO1xyXG4gICAgICAgICAgICBjYXNlICdyJzpcclxuICAgICAgICAgICAgICAgIHJldHVybiAncmlnaHQnO1xyXG4gICAgICAgICAgICBjYXNlICdiJzpcclxuICAgICAgICAgICAgICAgIHJldHVybiAnYm90dG9tJztcclxuICAgICAgICAgICAgY2FzZSAnbCc6XHJcbiAgICAgICAgICAgICAgICByZXR1cm4gJ2xlZnQnO1xyXG4gICAgICAgICAgICBkZWZhdWx0OlxyXG4gICAgICAgICAgICAgICAgcmV0dXJuICcnO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvL2VuZHJlZ2lvblxyXG59XHJcbiJdfQ==