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 +181 -3
- package/esm2020/lib/dom/dom-class.mjs +198 -0
- package/esm2020/lib/dom/dom-element.mjs +299 -0
- package/esm2020/lib/dom/dom-style.mjs +31 -0
- package/esm2020/lib/dom/dom.interface.mjs +2 -0
- package/esm2020/lib/tool-dom-ang15.component.mjs +237 -0
- package/esm2020/lib/tool-dom-ang15.module.mjs +20 -0
- package/esm2020/lib/tool-dom-ang15.service.mjs +15 -0
- package/esm2020/public-api.mjs +7 -0
- package/esm2020/tool-dom-ang15.mjs +5 -0
- package/fesm2015/tool-dom-ang15.mjs +804 -0
- package/fesm2015/tool-dom-ang15.mjs.map +1 -0
- package/fesm2020/tool-dom-ang15.mjs +794 -0
- package/fesm2020/tool-dom-ang15.mjs.map +1 -0
- package/index.d.ts +5 -0
- package/lib/dom/dom-class.d.ts +87 -0
- package/lib/dom/dom-element.d.ts +186 -0
- package/lib/dom/dom-style.d.ts +8 -0
- package/lib/dom/dom.interface.d.ts +8 -0
- package/lib/tool-dom-ang15.component.d.ts +83 -0
- package/lib/tool-dom-ang15.module.d.ts +8 -0
- package/lib/tool-dom-ang15.service.d.ts +6 -0
- package/package.json +30 -3
- package/public-api.d.ts +3 -0
package/README.md
CHANGED
|
@@ -1,3 +1,181 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
3
|
-
|
|
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==
|