@firestitch/report 18.8.0 → 18.9.0
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/app/reports/components/component-text/component-text.component.d.ts +47 -2
- package/app/reports/components/component-text/value-embed.plugin.d.ts +67 -0
- package/app/reports/components/report-canvas/report-canvas.component.d.ts +34 -9
- package/app/reports/components/report-component/report-component.component.d.ts +10 -1
- package/app/reports/data/report.data.d.ts +2 -1
- package/app/reports/dialogs/component-settings/component-settings.component.d.ts +8 -0
- package/app/reports/enums/report-value-formula.enum.d.ts +6 -0
- package/app/reports/export/report-export-collector.service.d.ts +24 -0
- package/app/reports/export/report-export.service.d.ts +3 -1
- package/app/reports/export/report-pdf.service.d.ts +18 -2
- package/app/reports/export/report-pptx.service.d.ts +15 -2
- package/app/reports/export/report-text-layout.service.d.ts +35 -0
- package/app/reports/format.d.ts +5 -1
- package/app/reports/interfaces/report.interface.d.ts +22 -3
- package/app/reports/layout.d.ts +2 -0
- package/app/reports/services/report-filter-state.service.d.ts +1 -1
- package/app/reports/text.d.ts +50 -0
- package/app/reports/theme/palette.d.ts +2 -0
- package/app/reports/values.d.ts +17 -0
- package/esm2022/app/reports/components/component-text/component-text.component.mjs +213 -16
- package/esm2022/app/reports/components/component-text/value-embed.plugin.mjs +484 -0
- package/esm2022/app/reports/components/report-canvas/report-canvas.component.mjs +260 -34
- package/esm2022/app/reports/components/report-component/report-component.component.mjs +65 -19
- package/esm2022/app/reports/data/report.data.mjs +19 -1
- package/esm2022/app/reports/dialogs/component-settings/component-settings.component.mjs +134 -23
- package/esm2022/app/reports/enums/report-value-formula.enum.mjs +14 -0
- package/esm2022/app/reports/export/report-export-collector.service.mjs +170 -44
- package/esm2022/app/reports/export/report-export.service.mjs +57 -19
- package/esm2022/app/reports/export/report-pdf.service.mjs +339 -96
- package/esm2022/app/reports/export/report-pptx.service.mjs +316 -88
- package/esm2022/app/reports/export/report-text-layout.service.mjs +241 -0
- package/esm2022/app/reports/format.mjs +41 -10
- package/esm2022/app/reports/interfaces/report.interface.mjs +1 -1
- package/esm2022/app/reports/kpi-card.mjs +19 -6
- package/esm2022/app/reports/layout.mjs +11 -1
- package/esm2022/app/reports/option-builder.mjs +18 -5
- package/esm2022/app/reports/output-notes.mjs +57 -11
- package/esm2022/app/reports/services/report-filter-state.service.mjs +19 -10
- package/esm2022/app/reports/text.mjs +293 -85
- package/esm2022/app/reports/theme/palette.mjs +7 -2
- package/esm2022/app/reports/values.mjs +183 -0
- package/esm2022/app/reports/views/report/fs-ai-report.component.mjs +4 -1
- package/esm2022/app/reports/views/report/report.component.mjs +4 -1
- package/esm2022/public_api.mjs +2 -1
- package/fesm2022/{firestitch-report-echarts-qCBE3LqM.mjs → firestitch-report-echarts-DBMOHmBF.mjs} +2 -2
- package/fesm2022/{firestitch-report-echarts-qCBE3LqM.mjs.map → firestitch-report-echarts-DBMOHmBF.mjs.map} +1 -1
- package/fesm2022/{firestitch-report-firestitch-report-DbsWbE-j.mjs → firestitch-report-firestitch-report-CqbXT1gh.mjs} +3492 -1028
- package/fesm2022/firestitch-report-firestitch-report-CqbXT1gh.mjs.map +1 -0
- package/fesm2022/firestitch-report.mjs +1 -1
- package/package.json +1 -1
- package/public_api.d.ts +1 -0
- package/fesm2022/firestitch-report-firestitch-report-DbsWbE-j.mjs.map +0 -1
|
@@ -0,0 +1,484 @@
|
|
|
1
|
+
import { Plugin } from '@firestitch/html-editor';
|
|
2
|
+
import { VALUE_TOKEN_PATTERN, valueText, valueToken } from '../../text';
|
|
3
|
+
// How a value chip is marked in the editor. The names follow the embeds of
|
|
4
|
+
// @firestitch/markdown-editor. Attributes rather than a class: the report keeps
|
|
5
|
+
// Froala on inline styles (useClasses: false), and a chip never reaches storage
|
|
6
|
+
// anyway — it turns back into its {{value.key}} token on the way out.
|
|
7
|
+
const TYPE_ATTRIBUTE = 'data-embed-type';
|
|
8
|
+
const KEY_ATTRIBUTE = 'data-embed-key';
|
|
9
|
+
const MISSING_ATTRIBUTE = 'data-embed-missing';
|
|
10
|
+
const CHIP_SELECTOR = `[${KEY_ATTRIBUTE}]`;
|
|
11
|
+
const VALUE_TYPE = 'value';
|
|
12
|
+
// The page a copy came from, on the clipboard beside its text: values belong
|
|
13
|
+
// to their page, so a value pasted onto another one doesn't come with it.
|
|
14
|
+
const SCOPE_TYPE = 'application/x-fs-report-value-scope';
|
|
15
|
+
// What Froala must keep on a chip when it cleans html it is handed.
|
|
16
|
+
export const VALUE_EMBED_ATTRIBUTES = [TYPE_ATTRIBUTE, KEY_ATTRIBUTE, MISSING_ATTRIBUTE, 'contenteditable'];
|
|
17
|
+
// A brief ring around the chips an edit was stopped at.
|
|
18
|
+
const FLASH = [{ boxShadow: '0 0 0 2px #e15759' }, { boxShadow: '0 0 0 2px transparent' }];
|
|
19
|
+
const FLASH_MS = 700;
|
|
20
|
+
// Commands that would build what the server rewrites (ReportTextHtml): a table
|
|
21
|
+
// is kept only between paragraphs, and a cell holds words and values only.
|
|
22
|
+
const TABLE_INSERT_COMMANDS = ['insertTable', 'tableInsert'];
|
|
23
|
+
const NO_TABLE_INSIDE = 'li, td, th';
|
|
24
|
+
const CELL_COMMANDS = ['formatUL', 'formatOL', 'paragraphFormat'];
|
|
25
|
+
const CELL = 'td, th';
|
|
26
|
+
// Undo and redo restore a step; they remove nothing of their own.
|
|
27
|
+
const HISTORY_COMMANDS = ['undo', 'redo'];
|
|
28
|
+
// Keys that, pressed alone, edit nothing.
|
|
29
|
+
const MODIFIER_KEYS = ['Shift', 'Control', 'Alt', 'AltGraph', 'Meta'];
|
|
30
|
+
// The cells of a table selected as cells (Froala's own marking).
|
|
31
|
+
const SELECTED_CELL = '.fr-selected-cell';
|
|
32
|
+
// Live values inside a text block's editor.
|
|
33
|
+
//
|
|
34
|
+
// Stored html carries a value as a {{value.key}} token. While editing, each
|
|
35
|
+
// token is a chip: one character to the cursor, labeled with the value, and
|
|
36
|
+
// reporting a click. Froala's html.get hands back tokens again, so the draft
|
|
37
|
+
// and the saved html never hold a chip.
|
|
38
|
+
//
|
|
39
|
+
// A chip can't be deleted by editing: Backspace or Delete beside it, and any
|
|
40
|
+
// deleting, typing over, cutting, pasting over or dragging of a selection that
|
|
41
|
+
// holds one, is stopped and reported. It is taken out on purpose by selecting
|
|
42
|
+
// it and pressing Delete, then taking the stopped selection's
|
|
43
|
+
// removeSelection(); a value that was deleted leaves through removeKey().
|
|
44
|
+
//
|
|
45
|
+
// A table is the exception: deleting a row, a column or the table, or
|
|
46
|
+
// emptying several selected cells, goes through with the chips in it, and is
|
|
47
|
+
// reported as removed() when it took a value's last chip, with the undo that
|
|
48
|
+
// brings them back.
|
|
49
|
+
export class ValueEmbedPlugin extends Plugin {
|
|
50
|
+
// The editor this plugin serves; null until it is built, and after it is gone.
|
|
51
|
+
_editor = null;
|
|
52
|
+
// Set while a deliberate removal runs, so the guards let it through.
|
|
53
|
+
_removing = false;
|
|
54
|
+
// Listeners on the editable element, captured so each runs before Froala's
|
|
55
|
+
// own handler for the same event.
|
|
56
|
+
_domListeners = [];
|
|
57
|
+
// The page the paste under way was copied on ('' when not from a block).
|
|
58
|
+
_pasteScope = '';
|
|
59
|
+
// How many chips each key had as the command under way started; null for
|
|
60
|
+
// one that removes nothing of its own (undo, redo).
|
|
61
|
+
_before = null;
|
|
62
|
+
constructor(config) {
|
|
63
|
+
super();
|
|
64
|
+
this.config = config;
|
|
65
|
+
}
|
|
66
|
+
initialize() {
|
|
67
|
+
if (!this.config.host().contains(this.editor.el)) {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
const editor = this.editor;
|
|
71
|
+
const el = editor.el;
|
|
72
|
+
this._editor = editor;
|
|
73
|
+
editor.events.on('html.set', () => this._toChips());
|
|
74
|
+
editor.events.on('paste.after', () => this._toChips(true));
|
|
75
|
+
this._watchCommands(editor);
|
|
76
|
+
editor.events.on('html.get', (html) => this._toTokens(html));
|
|
77
|
+
// First in Froala's chain, so its own Backspace handling never runs on a
|
|
78
|
+
// stopped key.
|
|
79
|
+
editor.events.on('keydown', (event) => this._onKeydown(event), true);
|
|
80
|
+
editor.events.on('paste.before', (event) => {
|
|
81
|
+
this._pasteScope = event?.clipboardData?.getData(SCOPE_TYPE) ?? '';
|
|
82
|
+
return this._guardSelection(event);
|
|
83
|
+
});
|
|
84
|
+
// A press on a chip opens its popover; Froala's floating toolbar, which
|
|
85
|
+
// pops up on any press in the text and sits above every overlay, stays
|
|
86
|
+
// away for it.
|
|
87
|
+
editor.events.on('toolbar.show', (event) => (this._onChip(event) ? false : undefined), true);
|
|
88
|
+
// Only while it is still this editor: reopening a block builds the next
|
|
89
|
+
// one before the last is torn down.
|
|
90
|
+
editor.events.on('destroy', () => {
|
|
91
|
+
if (this._editor === editor) {
|
|
92
|
+
this.destroy();
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
this._domListeners = [
|
|
96
|
+
['beforeinput', (event) => this._onBeforeInput(event)],
|
|
97
|
+
['cut', (event) => this._guardSelection(event)],
|
|
98
|
+
['dragstart', (event) => this._guardSelection(event)],
|
|
99
|
+
['copy', (event) => this._onCopy(event)],
|
|
100
|
+
['click', (event) => this._onClick(event)],
|
|
101
|
+
];
|
|
102
|
+
this._domListeners.forEach(([name, listener]) => el.addEventListener(name, listener, true));
|
|
103
|
+
this._toChips();
|
|
104
|
+
}
|
|
105
|
+
destroy() {
|
|
106
|
+
const el = this._editor?.el;
|
|
107
|
+
this._domListeners.forEach(([name, listener]) => el?.removeEventListener(name, listener, true));
|
|
108
|
+
this._domListeners = [];
|
|
109
|
+
this._editor = null;
|
|
110
|
+
}
|
|
111
|
+
// Relabel every chip: the values arrived or changed, or names were toggled.
|
|
112
|
+
refresh() {
|
|
113
|
+
this._chips().forEach((chip) => this._label(chip));
|
|
114
|
+
}
|
|
115
|
+
// Put Froala's floating toolbar and a table's popup away, when either is
|
|
116
|
+
// already up as a chip's popover opens: they sit above every overlay.
|
|
117
|
+
hideToolbar() {
|
|
118
|
+
this._editor?.toolbar.hide();
|
|
119
|
+
this._editor?.popups.hide('table.edit');
|
|
120
|
+
}
|
|
121
|
+
// The editor's own undo of the last step: what puts back the chips an edit
|
|
122
|
+
// took out.
|
|
123
|
+
undo() {
|
|
124
|
+
this._editor?.commands.undo();
|
|
125
|
+
}
|
|
126
|
+
// Take a value out of the text, wherever it appears — it was deleted.
|
|
127
|
+
removeKey(key) {
|
|
128
|
+
this._chips()
|
|
129
|
+
.filter((chip) => chip.getAttribute(KEY_ATTRIBUTE) === key)
|
|
130
|
+
.forEach((chip) => this.remove(chip));
|
|
131
|
+
}
|
|
132
|
+
// Take one chip out of the text.
|
|
133
|
+
remove(chip) {
|
|
134
|
+
if (!this._editor?.el.contains(chip)) {
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
// The cursor goes back where the chip was — whatever asked for the
|
|
138
|
+
// removal (a dialog, a popover) took the focus, and without it an Undo
|
|
139
|
+
// straight after would never reach the editor.
|
|
140
|
+
const caret = document.createRange();
|
|
141
|
+
caret.setStartBefore(chip);
|
|
142
|
+
caret.collapse(true);
|
|
143
|
+
this._editor.undo.saveStep();
|
|
144
|
+
chip.remove();
|
|
145
|
+
this._editor.el.focus();
|
|
146
|
+
const selection = this._selection();
|
|
147
|
+
selection.removeAllRanges();
|
|
148
|
+
selection.addRange(caret);
|
|
149
|
+
this._changed();
|
|
150
|
+
}
|
|
151
|
+
_chips() {
|
|
152
|
+
return this._editor
|
|
153
|
+
? Array.from(this._editor.el.querySelectorAll(CHIP_SELECTOR))
|
|
154
|
+
: [];
|
|
155
|
+
}
|
|
156
|
+
// How many chips each key has in the block.
|
|
157
|
+
_chipCounts() {
|
|
158
|
+
const counts = new Map();
|
|
159
|
+
this._chips().forEach((chip) => {
|
|
160
|
+
const key = chip.getAttribute(KEY_ATTRIBUTE);
|
|
161
|
+
counts.set(key, (counts.get(key) ?? 0) + 1);
|
|
162
|
+
});
|
|
163
|
+
return counts;
|
|
164
|
+
}
|
|
165
|
+
// Tell the host when an edit took the last chip of some key out of the
|
|
166
|
+
// block, given the counts from before it.
|
|
167
|
+
_reportRemoved(before) {
|
|
168
|
+
if (!before || !this._editor) {
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
const after = this._chipCounts();
|
|
172
|
+
if ([...before.keys()].some((key) => !after.has(key))) {
|
|
173
|
+
this.config.removed({
|
|
174
|
+
before: [...before.keys()],
|
|
175
|
+
after: [...after.keys()],
|
|
176
|
+
undo: () => this.undo(),
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
// A toolbar command sees tokens, not chips: Clear formatting unwraps every
|
|
181
|
+
// span, a chip included, which would leave a typed number behind. Around a
|
|
182
|
+
// token it formats plain text, and the chip comes back inside whatever
|
|
183
|
+
// formatting the token was given.
|
|
184
|
+
_watchCommands(editor) {
|
|
185
|
+
editor.events.on('commands.before', (command) => this._onCommandBefore(command));
|
|
186
|
+
editor.events.on('commands.after', () => {
|
|
187
|
+
this._toChips();
|
|
188
|
+
this._reportRemoved(this._before);
|
|
189
|
+
this._before = null;
|
|
190
|
+
});
|
|
191
|
+
// Undo and redo restore a step as Froala saved it: the one before a
|
|
192
|
+
// command holds tokens, as the command saw them. Neither fires
|
|
193
|
+
// commands.after: Froala's commands.undo() — Ctrl+Z, and undo() here —
|
|
194
|
+
// runs the undo directly.
|
|
195
|
+
editor.events.on('commands.undo', () => this._toChips());
|
|
196
|
+
editor.events.on('commands.redo', () => this._toChips());
|
|
197
|
+
}
|
|
198
|
+
// Every command starts a new edit. One that would build what the server
|
|
199
|
+
// rewrites is refused (returning false cancels it); any other runs on
|
|
200
|
+
// tokens, its chip counts kept to see what it removed.
|
|
201
|
+
_onCommandBefore(command) {
|
|
202
|
+
this.config.changed();
|
|
203
|
+
if (TABLE_INSERT_COMMANDS.includes(command) && this._caretIn(NO_TABLE_INSIDE)) {
|
|
204
|
+
this.config.refused('A table goes between paragraphs, never inside a list or another table.');
|
|
205
|
+
return false;
|
|
206
|
+
}
|
|
207
|
+
if (CELL_COMMANDS.includes(command) && this._caretIn(CELL)) {
|
|
208
|
+
this.config.refused('A table cell holds words and values; a list or a heading goes outside the table.');
|
|
209
|
+
return false;
|
|
210
|
+
}
|
|
211
|
+
this._before = HISTORY_COMMANDS.includes(command) ? null : this._chipCounts();
|
|
212
|
+
this._toTokenText();
|
|
213
|
+
}
|
|
214
|
+
// Whether the caret sits inside an element of this editor that `selector`
|
|
215
|
+
// matches.
|
|
216
|
+
_caretIn(selector) {
|
|
217
|
+
const container = this._editor.selection.element()?.closest?.(selector) ?? null;
|
|
218
|
+
return !!container && this._editor.el.contains(container);
|
|
219
|
+
}
|
|
220
|
+
// Turn every {{value.key}} token in the editor's text into a chip. For a
|
|
221
|
+
// paste, a token only stays when it was copied on this page and the page has
|
|
222
|
+
// the value; otherwise it goes, and just the text around it is pasted.
|
|
223
|
+
_toChips(pasted = false) {
|
|
224
|
+
const el = this._editor?.el;
|
|
225
|
+
if (!el) {
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
const walker = document.createTreeWalker(el, NodeFilter.SHOW_TEXT);
|
|
229
|
+
const texts = [];
|
|
230
|
+
while (walker.nextNode()) {
|
|
231
|
+
const text = walker.currentNode;
|
|
232
|
+
if (text.data.includes('{{') && !text.parentElement?.closest(CHIP_SELECTOR)) {
|
|
233
|
+
texts.push(text);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
texts.forEach((text) => this._splitText(text, pasted));
|
|
237
|
+
}
|
|
238
|
+
_keepsPasted(key) {
|
|
239
|
+
return this._pasteScope === this.config.scope() && !!this.config.values()[key];
|
|
240
|
+
}
|
|
241
|
+
_splitText(text, pasted) {
|
|
242
|
+
const matches = Array.from(text.data.matchAll(VALUE_TOKEN_PATTERN));
|
|
243
|
+
if (!matches.length) {
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
// Only non-empty text around the chips, so a selection counted in child
|
|
247
|
+
// nodes keeps its place.
|
|
248
|
+
const fragment = document.createDocumentFragment();
|
|
249
|
+
const appendText = (value) => {
|
|
250
|
+
if (value) {
|
|
251
|
+
fragment.append(value);
|
|
252
|
+
}
|
|
253
|
+
};
|
|
254
|
+
let consumed = 0;
|
|
255
|
+
matches.forEach((match) => {
|
|
256
|
+
const key = match[1].toLowerCase();
|
|
257
|
+
appendText(text.data.slice(consumed, match.index));
|
|
258
|
+
if (!pasted || this._keepsPasted(key)) {
|
|
259
|
+
fragment.append(this._createChip(key));
|
|
260
|
+
}
|
|
261
|
+
consumed = match.index + match[0].length;
|
|
262
|
+
});
|
|
263
|
+
appendText(text.data.slice(consumed));
|
|
264
|
+
text.replaceWith(fragment);
|
|
265
|
+
}
|
|
266
|
+
// Every chip in the editor back to its token, as text.
|
|
267
|
+
_toTokenText() {
|
|
268
|
+
this._chips().forEach((chip) => chip.replaceWith(valueToken(chip.getAttribute(KEY_ATTRIBUTE))));
|
|
269
|
+
}
|
|
270
|
+
_createChip(key) {
|
|
271
|
+
const chip = document.createElement('span');
|
|
272
|
+
chip.setAttribute(TYPE_ATTRIBUTE, VALUE_TYPE);
|
|
273
|
+
chip.setAttribute(KEY_ATTRIBUTE, key);
|
|
274
|
+
chip.setAttribute('contenteditable', 'false');
|
|
275
|
+
this._label(chip);
|
|
276
|
+
return chip;
|
|
277
|
+
}
|
|
278
|
+
// A chip reads as the value does in the viewed block — its number, the
|
|
279
|
+
// ellipsis while that loads, else the em dash — so opening the editor moves
|
|
280
|
+
// no word; or as its name, when names are toggled on. A key with no value on
|
|
281
|
+
// the page reads as the key itself, marked missing.
|
|
282
|
+
_label(chip) {
|
|
283
|
+
const key = chip.getAttribute(KEY_ATTRIBUTE);
|
|
284
|
+
const value = this.config.values()[key];
|
|
285
|
+
chip.textContent = !value
|
|
286
|
+
? key
|
|
287
|
+
: this.config.showNames() ? value.name : valueText(value);
|
|
288
|
+
chip.title = value?.name ?? key;
|
|
289
|
+
chip.toggleAttribute(MISSING_ATTRIBUTE, !value);
|
|
290
|
+
}
|
|
291
|
+
// The html Froala hands out, with every chip back to its token.
|
|
292
|
+
_toTokens(html) {
|
|
293
|
+
if (!html.includes(KEY_ATTRIBUTE)) {
|
|
294
|
+
return html;
|
|
295
|
+
}
|
|
296
|
+
const template = document.createElement('template');
|
|
297
|
+
template.innerHTML = html;
|
|
298
|
+
template.content.querySelectorAll(CHIP_SELECTOR).forEach((chip) => {
|
|
299
|
+
chip.replaceWith(valueToken(chip.getAttribute(KEY_ATTRIBUTE)));
|
|
300
|
+
});
|
|
301
|
+
return template.innerHTML;
|
|
302
|
+
}
|
|
303
|
+
_onKeydown(event) {
|
|
304
|
+
// Any key but a lone modifier starts a new edit.
|
|
305
|
+
if (!MODIFIER_KEYS.includes(event.key)) {
|
|
306
|
+
this.config.changed();
|
|
307
|
+
}
|
|
308
|
+
const deleting = event.key === 'Backspace' || event.key === 'Delete';
|
|
309
|
+
// Deleting across several selected cells goes through, values and all:
|
|
310
|
+
// Froala saves an undo step and empties the cells, and what that took is
|
|
311
|
+
// reported once they are empty.
|
|
312
|
+
if (deleting && this._editor.el.querySelectorAll(SELECTED_CELL).length > 1) {
|
|
313
|
+
const before = this._chipCounts();
|
|
314
|
+
setTimeout(() => this._reportRemoved(before));
|
|
315
|
+
return undefined;
|
|
316
|
+
}
|
|
317
|
+
const range = this._range();
|
|
318
|
+
if (!range) {
|
|
319
|
+
return;
|
|
320
|
+
}
|
|
321
|
+
if (range.collapsed) {
|
|
322
|
+
if (!deleting) {
|
|
323
|
+
return;
|
|
324
|
+
}
|
|
325
|
+
const chip = this._adjacentChip(event.key === 'Backspace', this._granularity(event));
|
|
326
|
+
return chip ? this._block(event, [chip], null) : undefined;
|
|
327
|
+
}
|
|
328
|
+
// A selection is replaced by a deleting key, Enter, a typed character or
|
|
329
|
+
// a cut.
|
|
330
|
+
const typing = event.key.length === 1 && !event.ctrlKey && !event.metaKey;
|
|
331
|
+
const cutting = (event.ctrlKey || event.metaKey) && event.key.toLowerCase() === 'x';
|
|
332
|
+
if (!deleting && !typing && !cutting && event.key !== 'Enter') {
|
|
333
|
+
return;
|
|
334
|
+
}
|
|
335
|
+
const chips = this._chipsIn(range);
|
|
336
|
+
return chips.length ? this._block(event, chips, range) : undefined;
|
|
337
|
+
}
|
|
338
|
+
// The same rule for edits that arrive without a key Froala sees: a phone
|
|
339
|
+
// keyboard, an input method, a spell-check replacement.
|
|
340
|
+
_onBeforeInput(event) {
|
|
341
|
+
const range = this._range();
|
|
342
|
+
if (this._removing || !range) {
|
|
343
|
+
return;
|
|
344
|
+
}
|
|
345
|
+
if (range.collapsed) {
|
|
346
|
+
const backward = event.inputType.endsWith('Backward');
|
|
347
|
+
if (event.inputType.startsWith('delete')) {
|
|
348
|
+
const chip = this._adjacentChip(backward, event.inputType.includes('Word') ? 'word' : 'character');
|
|
349
|
+
if (chip) {
|
|
350
|
+
this._block(event, [chip], null);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
return;
|
|
354
|
+
}
|
|
355
|
+
const chips = this._chipsIn(range);
|
|
356
|
+
if (chips.length) {
|
|
357
|
+
this._block(event, chips, range);
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
// Cut, drag and paste-over: stopped when the selection holds a value.
|
|
361
|
+
_guardSelection(event) {
|
|
362
|
+
const range = this._range();
|
|
363
|
+
if (this._removing || !range || range.collapsed) {
|
|
364
|
+
return;
|
|
365
|
+
}
|
|
366
|
+
const chips = this._chipsIn(range);
|
|
367
|
+
return chips.length ? this._block(event, chips, range) : undefined;
|
|
368
|
+
}
|
|
369
|
+
// Copying a value copies its token, and the page it was copied on, so
|
|
370
|
+
// pasting it back on this page — in this block or another — makes it a chip
|
|
371
|
+
// again.
|
|
372
|
+
_onCopy(event) {
|
|
373
|
+
const range = this._range();
|
|
374
|
+
if (!range || range.collapsed || !this._chipsIn(range).length) {
|
|
375
|
+
return;
|
|
376
|
+
}
|
|
377
|
+
const holder = document.createElement('div');
|
|
378
|
+
holder.append(range.cloneContents());
|
|
379
|
+
holder.querySelectorAll(CHIP_SELECTOR).forEach((chip) => {
|
|
380
|
+
chip.replaceWith(valueToken(chip.getAttribute(KEY_ATTRIBUTE)));
|
|
381
|
+
});
|
|
382
|
+
event.clipboardData.setData('text/plain', this._plainText(holder));
|
|
383
|
+
event.clipboardData.setData('text/html', holder.innerHTML);
|
|
384
|
+
event.clipboardData.setData(SCOPE_TYPE, this.config.scope());
|
|
385
|
+
event.preventDefault();
|
|
386
|
+
}
|
|
387
|
+
// What copied html reads as in plain text: a paragraph on its own lines, a
|
|
388
|
+
// table's cells tab-separated and its rows on lines of their own. That is
|
|
389
|
+
// the browser's innerText, which only text laid out on the page has — so
|
|
390
|
+
// the holder is put offscreen (not hidden: hidden text has none) while it is
|
|
391
|
+
// read.
|
|
392
|
+
_plainText(holder) {
|
|
393
|
+
holder.style.cssText = 'position: fixed; left: -10000px; top: 0';
|
|
394
|
+
document.body.append(holder);
|
|
395
|
+
const text = holder.innerText;
|
|
396
|
+
holder.remove();
|
|
397
|
+
return text;
|
|
398
|
+
}
|
|
399
|
+
_onClick(event) {
|
|
400
|
+
const chip = event.target?.closest?.(CHIP_SELECTOR);
|
|
401
|
+
if (!chip || !this._editor?.el.contains(chip)) {
|
|
402
|
+
return;
|
|
403
|
+
}
|
|
404
|
+
event.preventDefault();
|
|
405
|
+
// A press in a table cell can open the table's popup on mouseup, just
|
|
406
|
+
// before this click; a chip in a cell shows only its own popover.
|
|
407
|
+
this._editor.popups.hide('table.edit');
|
|
408
|
+
this.config.click(chip.getAttribute(KEY_ATTRIBUTE), chip);
|
|
409
|
+
}
|
|
410
|
+
_onChip(event) {
|
|
411
|
+
return !!event?.target?.closest?.(CHIP_SELECTOR);
|
|
412
|
+
}
|
|
413
|
+
_block(event, chips, range) {
|
|
414
|
+
event.preventDefault();
|
|
415
|
+
event.stopPropagation();
|
|
416
|
+
chips.forEach((chip) => chip.animate(FLASH, FLASH_MS));
|
|
417
|
+
this.config.blocked({
|
|
418
|
+
count: chips.length,
|
|
419
|
+
...(range ? { removeSelection: () => this._removeRange(range) } : {}),
|
|
420
|
+
});
|
|
421
|
+
return false;
|
|
422
|
+
}
|
|
423
|
+
_removeRange(range) {
|
|
424
|
+
if (!this._editor) {
|
|
425
|
+
return;
|
|
426
|
+
}
|
|
427
|
+
const selection = this._selection();
|
|
428
|
+
this._editor.el.focus();
|
|
429
|
+
selection.removeAllRanges();
|
|
430
|
+
selection.addRange(range);
|
|
431
|
+
this._editor.undo.saveStep();
|
|
432
|
+
this._removing = true;
|
|
433
|
+
// The browser's own delete, so two paragraphs a selection spans join the
|
|
434
|
+
// way they would for a plain Delete.
|
|
435
|
+
document.execCommand('delete');
|
|
436
|
+
this._removing = false;
|
|
437
|
+
this._changed();
|
|
438
|
+
}
|
|
439
|
+
// An edit made here rather than typed: record it for undo, and tell
|
|
440
|
+
// html-editor so the draft follows.
|
|
441
|
+
_changed() {
|
|
442
|
+
this._editor.undo.saveStep();
|
|
443
|
+
this._editor.events.trigger('contentChanged');
|
|
444
|
+
}
|
|
445
|
+
_selection() {
|
|
446
|
+
return this._editor.el.ownerDocument.getSelection();
|
|
447
|
+
}
|
|
448
|
+
// The selection, when it is inside this editor.
|
|
449
|
+
_range() {
|
|
450
|
+
const selection = this._editor ? this._selection() : null;
|
|
451
|
+
if (!selection?.rangeCount) {
|
|
452
|
+
return null;
|
|
453
|
+
}
|
|
454
|
+
const range = selection.getRangeAt(0);
|
|
455
|
+
return this._editor.el.contains(range.commonAncestorContainer) ? range : null;
|
|
456
|
+
}
|
|
457
|
+
_chipsIn(range) {
|
|
458
|
+
return this._chips().filter((chip) => range.intersectsNode(chip));
|
|
459
|
+
}
|
|
460
|
+
// The chip a collapsed cursor would delete into: stretch the selection by
|
|
461
|
+
// what the key deletes, see what it covers, and put it back. Letting the
|
|
462
|
+
// browser stretch it handles every shape the html takes — a chip inside a
|
|
463
|
+
// bold span, at a line's end, beside an empty text node.
|
|
464
|
+
_adjacentChip(backward, granularity) {
|
|
465
|
+
const selection = this._selection();
|
|
466
|
+
const range = selection.getRangeAt(0).cloneRange();
|
|
467
|
+
selection.modify('extend', backward ? 'backward' : 'forward', granularity);
|
|
468
|
+
const chip = selection.rangeCount
|
|
469
|
+
? this._chipsIn(selection.getRangeAt(0))[0] ?? null
|
|
470
|
+
: null;
|
|
471
|
+
selection.removeAllRanges();
|
|
472
|
+
selection.addRange(range);
|
|
473
|
+
return chip;
|
|
474
|
+
}
|
|
475
|
+
// How far a deleting key reaches: a word with Ctrl/Alt, to the line's start
|
|
476
|
+
// with Cmd on a Mac, one character otherwise.
|
|
477
|
+
_granularity(event) {
|
|
478
|
+
if (event.metaKey) {
|
|
479
|
+
return 'lineboundary';
|
|
480
|
+
}
|
|
481
|
+
return event.ctrlKey || event.altKey ? 'word' : 'character';
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidmFsdWUtZW1iZWQucGx1Z2luLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vc3JjL2FwcC9yZXBvcnRzL2NvbXBvbmVudHMvY29tcG9uZW50LXRleHQvdmFsdWUtZW1iZWQucGx1Z2luLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxNQUFNLEVBQWdCLE1BQU0seUJBQXlCLENBQUM7QUFFL0QsT0FBTyxFQUFhLG1CQUFtQixFQUFFLFNBQVMsRUFBRSxVQUFVLEVBQUUsTUFBTSxZQUFZLENBQUM7QUFHbkYsMkVBQTJFO0FBQzNFLGdGQUFnRjtBQUNoRixnRkFBZ0Y7QUFDaEYsc0VBQXNFO0FBQ3RFLE1BQU0sY0FBYyxHQUFHLGlCQUFpQixDQUFDO0FBQ3pDLE1BQU0sYUFBYSxHQUFHLGdCQUFnQixDQUFDO0FBQ3ZDLE1BQU0saUJBQWlCLEdBQUcsb0JBQW9CLENBQUM7QUFDL0MsTUFBTSxhQUFhLEdBQUcsSUFBSSxhQUFhLEdBQUcsQ0FBQztBQUMzQyxNQUFNLFVBQVUsR0FBRyxPQUFPLENBQUM7QUFFM0IsNkVBQTZFO0FBQzdFLDBFQUEwRTtBQUMxRSxNQUFNLFVBQVUsR0FBRyxxQ0FBcUMsQ0FBQztBQUV6RCxvRUFBb0U7QUFDcEUsTUFBTSxDQUFDLE1BQU0sc0JBQXNCLEdBQUcsQ0FBQyxjQUFjLEVBQUUsYUFBYSxFQUFFLGlCQUFpQixFQUFFLGlCQUFpQixDQUFDLENBQUM7QUFFNUcsd0RBQXdEO0FBQ3hELE1BQU0sS0FBSyxHQUFlLENBQUMsRUFBRSxTQUFTLEVBQUUsbUJBQW1CLEVBQUUsRUFBRSxFQUFFLFNBQVMsRUFBRSx1QkFBdUIsRUFBRSxDQUFDLENBQUM7QUFDdkcsTUFBTSxRQUFRLEdBQUcsR0FBRyxDQUFDO0FBRXJCLCtFQUErRTtBQUMvRSwyRUFBMkU7QUFDM0UsTUFBTSxxQkFBcUIsR0FBRyxDQUFDLGFBQWEsRUFBRSxhQUFhLENBQUMsQ0FBQztBQUM3RCxNQUFNLGVB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USxFQUFFLFFBQVEsQ0FBQyxDQUFDLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQyxTQUFTLEVBQUUsV0FBVyxDQUFDLENBQUM7UUFDM0UsTUFBTSxJQUFJLEdBQUcsU0FBUyxDQUFDLFVBQVU7WUFDL0IsQ0FBQyxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsU0FBUyxDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLElBQUk7WUFDbkQsQ0FBQyxDQUFDLElBQUksQ0FBQztRQUVULFNBQVMsQ0FBQyxlQUFlLEVBQUUsQ0FBQztRQUM1QixTQUFTLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBRTFCLE9BQU8sSUFBSSxDQUFDO0lBQ2QsQ0FBQztJQUVELDRFQUE0RTtJQUM1RSw4Q0FBOEM7SUFDdEMsWUFBWSxDQUFDLEtBQW9CO1FBQ3ZDLElBQUksS0FBSyxDQUFDLE9BQU8sRUFBRSxDQUFDO1lBQ2xCLE9BQU8sY0FBYyxDQUFDO1FBQ3hCLENBQUM7UUFFRCxPQUFPLEtBQUssQ0FBQyxPQUFPLElBQUksS0FBSyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxXQUFXLENBQUM7SUFDOUQsQ0FBQztDQUNGIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgUGx1Z2luLCBQbHVnaW5Db25maWcgfSBmcm9tICdAZmlyZXN0aXRjaC9odG1sLWVkaXRvcic7XG5cbmltcG9ydCB7IFRleHRWYWx1ZSwgVkFMVUVfVE9LRU5fUEFUVEVSTiwgdmFsdWVUZXh0LCB2YWx1ZVRva2VuIH0gZnJvbSAnLi4vLi4vdGV4dCc7XG5cblxuLy8gSG93IGEgdmFsdWUgY2hpcCBpcyBtYXJrZWQgaW4gdGhlIGVkaXRvci4gVGhlIG5hbWVzIGZvbGxvdyB0aGUgZW1iZWRzIG9mXG4vLyBAZmlyZXN0aXRjaC9tYXJrZG93bi1lZGl0b3IuIEF0dHJpYnV0ZXMgcmF0aGVyIHRoYW4gYSBjbGFzczogdGhlIHJlcG9ydCBrZWVwc1xuLy8gRnJvYWxhIG9uIGlubGluZSBzdHlsZXMgKHVzZUNsYXNzZXM6IGZhbHNlKSwgYW5kIGEgY2hpcCBuZXZlciByZWFjaGVzIHN0b3JhZ2Vcbi8vIGFueXdheSDigJQgaXQgdHVybnMgYmFjayBpbnRvIGl0cyB7e3ZhbHVlLmtleX19IHRva2VuIG9uIHRoZSB3YXkgb3V0LlxuY29uc3QgVFlQRV9BVFRSSUJVVEUgPSAnZGF0YS1lbWJlZC10eXBlJztcbmNvbnN0IEtFWV9BVFRSSUJVVEUgPSAnZGF0YS1lbWJlZC1rZXknO1xuY29uc3QgTUlTU0lOR19BVFRSSUJVVEUgPSAnZGF0YS1lbWJlZC1taXNzaW5nJztcbmNvbnN0IENISVBfU0VMRUNUT1IgPSBgWyR7S0VZX0FUVFJJQlVURX1dYDtcbmNvbnN0IFZBTFVFX1RZUEUgPSAndmFsdWUnO1xuXG4vLyBUaGUgcGFnZSBhIGNvcHkgY2FtZSBmcm9tLCBvbiB0aGUgY2xpcGJvYXJkIGJlc2lkZSBpdHMgdGV4dDogdmFsdWVzIGJlbG9uZ1xuLy8gdG8gdGhlaXIgcGFnZSwgc28gYSB2YWx1ZSBwYXN0ZWQgb250byBhbm90aGVyIG9uZSBkb2Vzbid0IGNvbWUgd2l0aCBpdC5cbmNvbnN0IFNDT1BFX1RZUEUgPSAnYXBwbGljYXRpb24veC1mcy1yZXBvcnQtdmFsdWUtc2NvcGUnO1xuXG4vLyBXaGF0IEZyb2FsYSBtdXN0IGtlZXAgb24gYSBjaGlwIHdoZW4gaXQgY2xlYW5zIGh0bWwgaXQgaXMgaGFuZGVkLlxuZXhwb3J0IGNvbnN0IFZBTFVFX0VNQkVEX0FUVFJJQlVURVMgPSBbVFlQRV9BVFRSSUJVVEUsIEtFWV9BVFRSSUJVVEUsIE1JU1NJTkdfQVRUUklCVVRFLCAnY29udGVudGVkaXRhYmxlJ107XG5cbi8vIEEgYnJpZWYgcmluZyBhcm91bmQgdGhlIGNoaXBzIGFuIGVkaXQgd2FzIHN0b3BwZWQgYXQuXG5jb25zdCBGTEFTSDogS2V5ZnJhbWVbXSA9IFt7IGJveFNoYWRvdzogJzAgMCAwIDJweCAjZTE1NzU5JyB9LCB7IGJveFNoYWRvdzogJzAgMCAwIDJweCB0cmFuc3BhcmVudCcgfV07XG5jb25zdCBGTEFTSF9NUyA9IDcwMDtcblxuLy8gQ29tbWFuZHMgdGhhdCB3b3VsZCBidWlsZCB3aGF0IHRoZSBzZXJ2ZXIgcmV3cml0ZXMgKFJlcG9ydFRleHRIdG1sKTogYSB0YWJsZVxuLy8gaXMga2VwdCBvbmx5IGJldHdlZW4gcGFyYWdyYXBocywgYW5kIGEgY2VsbCBob2xkcyB3b3JkcyBhbmQgdmFsdWVzIG9ubHkuXG5jb25zdCBUQUJMRV9JTlNFUlRfQ09NTUFORFMgPSBbJ2luc2VydFRhYmxlJywgJ3RhYmxlSW5zZXJ0J107XG5jb25zdCBOT19UQUJMRV9JTlNJREUgPSAnbGksIHRkLCB0aCc7XG5jb25zdCBDRUxMX0NPTU1BTkRTID0gWydmb3JtYXRVTCcsICdmb3JtYXRPTCcsICdwYXJhZ3JhcGhGb3JtYXQnXTtcbmNvbnN0IENFTEwgPSAndGQsIHRoJztcblxuLy8gVW5kbyBhbmQgcmVkbyByZXN0b3JlIGEgc3RlcDsgdGhleSByZW1vdmUgbm90aGluZyBvZiB0aGVpciBvd24uXG5jb25zdCBISVNUT1JZX0NPTU1BTkRTID0gWyd1bmRvJywgJ3JlZG8nXTtcblxuLy8gS2V5cyB0aGF0LCBwcmVzc2VkIGFsb25lLCBlZGl0IG5vdGhpbmcuXG5jb25zdCBNT0RJRklFUl9LRVlTID0gWydTaGlmdCcsICdDb250cm9sJywgJ0FsdCcsICdBbHRHcmFwaCcsICdNZXRhJ107XG5cbi8vIFRoZSBjZWxscyBvZiBhIHRhYmxlIHNlbGVjdGVkIGFzIGNlbGxzIChGcm9hbGEncyBvd24gbWFya2luZykuXG5jb25zdCBTRUxFQ1RFRF9DRUxMID0gJy5mci1zZWxlY3RlZC1jZWxsJztcblxuLy8gQW4gZWRpdCB0aGF0IHdvdWxkIGhhdmUgcmVtb3ZlZCB2YWx1ZXMsIGFuZCB3YXMgc3RvcHBlZC5cbmV4cG9ydCBpbnRlcmZhY2UgVmFsdWVFbWJlZEJsb2NrIHtcbiAgY291bnQ6IG51bWJlcjtcbiAgLy8gUHJlc2VudCB3aGVuIHRoZSBlZGl0IHdhcyBvbiBhIHNlbGVjdGlvbjogcmVtb3ZlcyB0aGUgc2VsZWN0aW9uLCB2YWx1ZXNcbiAgLy8gYW5kIGFsbCDigJQgdGhlIGRlbGliZXJhdGUgd2F5IHRocm91Z2guXG4gIHJlbW92ZVNlbGVjdGlvbj86ICgpID0+IHZvaWQ7XG59XG5cbi8vIEFuIGVkaXQgdGhhdCB0b29rIHRoZSBsYXN0IGNoaXAgb2Ygc29tZSB2YWx1ZXMgb3V0IG9mIHRoZSBibG9jazogZGVsZXRpbmdcbi8vIGEgcm93LCBhIGNvbHVtbiBvciBhIHRhYmxlLCBvciBlbXB0eWluZyBjZWxscy4gQWxsb3dlZCwgdmFsdWVzIGFuZCBhbGwuXG5leHBvcnQgaW50ZXJmYWNlIFZhbHVlRW1iZWRSZW1vdmFsIHtcbiAgLy8gVGhlIGtleXMgdGhlIGJsb2NrJ3MgY2hpcHMgbmFtZWQgYmVmb3JlIHRoZSBlZGl0LCBhbmQgYWZ0ZXIgaXQuXG4gIGJlZm9yZTogc3RyaW5nW107XG4gIGFmdGVyOiBzdHJpbmdbXTtcbiAgLy8gVGhlIGVkaXRvcidzIG93biB1bmRvLCB3aGljaCBicmluZ3MgdGhlIGNoaXBzIGJhY2suXG4gIHVuZG86ICgpID0+IHZvaWQ7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgVmFsdWVFbWJlZFBsdWdpbkNvbmZpZyBleHRlbmRzIFBsdWdpbkNvbmZpZyB7XG4gIC8vIFRoZSBlbGVtZW50IHRoZSBlZGl0b3Igc2l0cyBpbi4gaHRtbC1lZGl0b3IgcmVnaXN0ZXJzIGEgcGx1Z2luIHdpdGggRnJvYWxhXG4gIC8vIGdsb2JhbGx5LCBzbyBGcm9hbGEgaGFuZHMgaXQgZXZlcnkgZWRpdG9yIGJ1aWx0IGFmdGVyd2FyZHM7IGl0IHdvcmtzIG9ubHlcbiAgLy8gZm9yIHRoZSBvbmUgaW5zaWRlIHRoaXMgZWxlbWVudC5cbiAgaG9zdDogKCkgPT4gSFRNTEVsZW1lbnQ7XG4gIC8vIFRoZSBwYWdlJ3MgdmFsdWVzLCBieSBrZXkuIE9uZSB3aG9zZSBudW1iZXIgaXMgc3RpbGwgb24gaXRzIHdheSBpcyBsaXN0ZWRcbiAgLy8gd2l0aCBsb2FkaW5nOiB0cnVlOyBhIGtleSBub3QgbGlzdGVkIGlzIG5vIHZhbHVlIG9mIHRoZSBwYWdlLlxuICB2YWx1ZXM6ICgpID0+IFJlY29yZDxzdHJpbmcsIFRleHRWYWx1ZT47XG4gIC8vIFRoZSBwYWdlIHRoZSBibG9jaydzIHZhbHVlcyBiZWxvbmcgdG8uXG4gIHNjb3BlOiAoKSA9PiBzdHJpbmc7XG4gIC8vIExhYmVsIGNoaXBzIHdpdGggdGhlIHZhbHVlJ3MgbmFtZSBpbnN0ZWFkIG9mIGl0cyBudW1iZXIuXG4gIHNob3dOYW1lczogKCkgPT4gYm9vbGVhbjtcbiAgY2xpY2s6IChrZXk6IHN0cmluZywgY2hpcDogSFRNTEVsZW1lbnQpID0+IHZvaWQ7XG4gIGJsb2NrZWQ6IChibG9jazogVmFsdWVFbWJlZEJsb2NrKSA9PiB2b2lkO1xuICByZW1vdmVkOiAocmVtb3ZhbDogVmFsdWVFbWJlZFJlbW92YWwpID0+IHZvaWQ7XG4gIC8vIEEga2V5IHdhcyBwcmVzc2VkIG9yIGEgY29tbWFuZCBpcyBhYm91dCB0byBydW46IHdoYXQgd2FzIHNhaWQgYWJvdXQgdGhlXG4gIC8vIGxhc3QgZWRpdCBubyBsb25nZXIgYXBwbGllcy5cbiAgY2hhbmdlZDogKCkgPT4gdm9pZDtcbiAgLy8gQSBjb21tYW5kIHdhcyByZWZ1c2VkLCBhbmQgd2h5LlxuICByZWZ1c2VkOiAodGV4dDogc3RyaW5nKSA9PiB2b2lkO1xufVxuXG4vLyBMaXZlIHZhbHVlcyBpbnNpZGUgYSB0ZXh0IGJsb2NrJ3MgZWRpdG9yLlxuLy9cbi8vIFN0b3JlZCBodG1sIGNhcnJpZXMgYSB2YWx1ZSBhcyBhIHt7dmFsdWUua2V5fX0gdG9rZW4uIFdoaWxlIGVkaXRpbmcsIGVhY2hcbi8vIHRva2VuIGlzIGEgY2hpcDogb25lIGNoYXJhY3RlciB0byB0aGUgY3Vyc29yLCBsYWJlbGVkIHdpdGggdGhlIHZhbHVlLCBhbmRcbi8vIHJlcG9ydGluZyBhIGNsaWNrLiBGcm9hbGEncyBodG1sLmdldCBoYW5kcyBiYWNrIHRva2VucyBhZ2Fpbiwgc28gdGhlIGRyYWZ0XG4vLyBhbmQgdGhlIHNhdmVkIGh0bWwgbmV2ZXIgaG9sZCBhIGNoaXAuXG4vL1xuLy8gQSBjaGlwIGNhbid0IGJlIGRlbGV0ZWQgYnkgZWRpdGluZzogQmFja3NwYWNlIG9yIERlbGV0ZSBiZXNpZGUgaXQsIGFuZCBhbnlcbi8vIGRlbGV0aW5nLCB0eXBpbmcgb3ZlciwgY3V0dGluZywgcGFzdGluZyBvdmVyIG9yIGRyYWdnaW5nIG9mIGEgc2VsZWN0aW9uIHRoYXRcbi8vIGhvbGRzIG9uZSwgaXMgc3RvcHBlZCBhbmQgcmVwb3J0ZWQuIEl0IGlzIHRha2VuIG91dCBvbiBwdXJwb3NlIGJ5IHNlbGVjdGluZ1xuLy8gaXQgYW5kIHByZXNzaW5nIERlbGV0ZSwgdGhlbiB0YWtpbmcgdGhlIHN0b3BwZWQgc2VsZWN0aW9uJ3Ncbi8vIHJlbW92ZVNlbGVjdGlvbigpOyBhIHZhbHVlIHRoYXQgd2FzIGRlbGV0ZWQgbGVhdmVzIHRocm91Z2ggcmVtb3ZlS2V5KCkuXG4vL1xuLy8gQSB0YWJsZSBpcyB0aGUgZXhjZXB0aW9uOiBkZWxldGluZyBhIHJvdywgYSBjb2x1bW4gb3IgdGhlIHRhYmxlLCBvclxuLy8gZW1wdHlpbmcgc2V2ZXJhbCBzZWxlY3RlZCBjZWxscywgZ29lcyB0aHJvdWdoIHdpdGggdGhlIGNoaXBzIGluIGl0LCBhbmQgaXNcbi8vIHJlcG9ydGVkIGFzIHJlbW92ZWQoKSB3aGVuIGl0IHRvb2sgYSB2YWx1ZSdzIGxhc3QgY2hpcCwgd2l0aCB0aGUgdW5kbyB0aGF0XG4vLyBicmluZ3MgdGhlbSBiYWNrLlxuZXhwb3J0IGNsYXNzIFZhbHVlRW1iZWRQbHVnaW4gZXh0ZW5kcyBQbHVnaW4ge1xuXG4gIC8vIFRoZSBiYXNlIGNsYXNzJ3MgY29uZmlnLCB0eXBlZCBmb3IgdGhpcyBwbHVnaW4uXG4gIHB1YmxpYyBkZWNsYXJlIGNvbmZpZzogVmFsdWVFbWJlZFBsdWdpbkNvbmZpZztcblxuICAvLyBUaGUgZWRpdG9yIHRoaXMgcGx1Z2luIHNlcnZlczsgbnVsbCB1bnRpbCBpdCBpcyBidWlsdCwgYW5kIGFmdGVyIGl0IGlzIGdvbmUuXG4gIHByaXZhdGUgX2VkaXRvcjogYW55ID0gbnVsbDtcbiAgLy8gU2V0IHdoaWxlIGEgZGVsaWJlcmF0ZSByZW1vdmFsIHJ1bnMsIHNvIHRoZSBndWFyZHMgbGV0IGl0IHRocm91Z2guXG4gIHByaXZhdGUgX3JlbW92aW5nID0gZmFsc2U7XG4gIC8vIExpc3RlbmVycyBvbiB0aGUgZWRpdGFibGUgZWxlbWVudCwgY2FwdHVyZWQgc28gZWFjaCBydW5zIGJlZm9yZSBGcm9hbGEnc1xuICAvLyBvd24gaGFuZGxlciBmb3IgdGhlIHNhbWUgZXZlbnQuXG4gIHByaXZhdGUgX2RvbUxpc3RlbmVyczogW3N0cmluZywgRXZlbnRMaXN0ZW5lcl1bXSA9IFtdO1xuICAvLyBUaGUgcGFnZSB0aGUgcGFzdGUgdW5kZXIgd2F5IHdhcyBjb3BpZWQgb24gKCcnIHdoZW4gbm90IGZyb20gYSBibG9jaykuXG4gIHByaXZhdGUgX3Bhc3RlU2NvcGUgPSAnJztcbiAgLy8gSG93IG1hbnkgY2hpcHMgZWFjaCBrZXkgaGFkIGFzIHRoZSBjb21tYW5kIHVuZGVyIHdheSBzdGFydGVkOyBudWxsIGZvclxuICAvLyBvbmUgdGhhdCByZW1vdmVzIG5vdGhpbmcgb2YgaXRzIG93biAodW5kbywgcmVkbykuXG4gIHByaXZhdGUgX2JlZm9yZTogTWFwPHN0cmluZywgbnVtYmVyPiB8IG51bGwgPSBudWxsO1xuXG4gIGNvbnN0cnVjdG9yKGNvbmZpZzogVmFsdWVFbWJlZFBsdWdpbkNvbmZpZykge1xuICAgIHN1cGVyKCk7XG4gICAgdGhpcy5jb25maWcgPSBjb25maWc7XG4gIH1cblxuICBwdWJsaWMgaW5pdGlhbGl6ZSgpOiB2b2lkIHtcbiAgICBpZiAoIXRoaXMuY29uZmlnLmhvc3QoKS5jb250YWlucyh0aGlzLmVkaXRvci5lbCkpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBjb25zdCBlZGl0b3IgPSB0aGlzLmVkaXRvcjtcbiAgICBjb25zdCBlbDogSFRNTEVsZW1lbnQgPSBlZGl0b3IuZWw7XG4gICAgdGhpcy5fZWRpdG9yID0gZWRpdG9yO1xuXG4gICAgZWRpdG9yLmV2ZW50cy5vbignaHRtbC5zZXQnLCAoKSA9PiB0aGlzLl90b0NoaXBzKCkpO1xuICAgIGVkaXRvci5ldmVudHMub24oJ3Bhc3RlLmFmdGVyJywgKCkgPT4gdGhpcy5fdG9DaGlwcyh0cnVlKSk7XG4gICAgdGhpcy5fd2F0Y2hDb21tYW5kcyhlZGl0b3IpO1xuICAgIGVkaXRvci5ldmVudHMub24oJ2h0bWwuZ2V0JywgKGh0bWw6IHN0cmluZykgPT4gdGhpcy5fdG9Ub2tlbnMoaHRtbCkpO1xuICAgIC8vIEZpcnN0IGluIEZyb2FsYSdzIGNoYWluLCBzbyBpdHMgb3duIEJhY2tzcGFjZSBoYW5kbGluZyBuZXZlciBydW5zIG9uIGFcbiAgICAvLyBzdG9wcGVkIGtleS5cbiAgICBlZGl0b3IuZXZlbnRzLm9uKCdrZXlkb3duJywgKGV2ZW50OiBLZXlib2FyZEV2ZW50KSA9PiB0aGlzLl9vbktleWRvd24oZXZlbnQpLCB0cnVlKTtcbiAgICBlZGl0b3IuZXZlbnRzLm9uKCdwYXN0ZS5iZWZvcmUnLCAoZXZlbnQ6IENsaXBib2FyZEV2ZW50KSA9PiB7XG4gICAgICB0aGlzLl9wYXN0ZVNjb3BlID0gZXZlbnQ/LmNsaXBib2FyZERhdGE/LmdldERhdGEoU0NPUEVfVFlQRSkgPz8gJyc7XG5cbiAgICAgIHJldHVybiB0aGlzLl9ndWFyZFNlbGVjdGlvbihldmVudCk7XG4gICAgfSk7XG4gICAgLy8gQSBwcmVzcyBvbiBhIGNoaXAgb3BlbnMgaXRzIHBvcG92ZXI7IEZyb2FsYSdzIGZsb2F0aW5nIHRvb2xiYXIsIHdoaWNoXG4gICAgLy8gcG9wcyB1cCBvbiBhbnkgcHJlc3MgaW4gdGhlIHRleHQgYW5kIHNpdHMgYWJvdmUgZXZlcnkgb3ZlcmxheSwgc3RheXNcbiAgICAvLyBhd2F5IGZvciBpdC5cbiAgICBlZGl0b3IuZXZlbnRzLm9uKCd0b29sYmFyLnNob3cnLCAoZXZlbnQ/OiBFdmVudCkgPT4gKHRoaXMuX29uQ2hpcChldmVudCkgPyBmYWxzZSA6IHVuZGVmaW5lZCksIHRydWUpO1xuICAgIC8vIE9ubHkgd2hpbGUgaXQgaXMgc3RpbGwgdGhpcyBlZGl0b3I6IHJlb3BlbmluZyBhIGJsb2NrIGJ1aWxkcyB0aGUgbmV4dFxuICAgIC8vIG9uZSBiZWZvcmUgdGhlIGxhc3QgaXMgdG9ybiBkb3duLlxuICAgIGVkaXRvci5ldmVudHMub24oJ2Rlc3Ryb3knLCAoKSA9PiB7XG4gICAgICBpZiAodGhpcy5fZWRpdG9yID09PSBlZGl0b3IpIHtcbiAgICAgICAgdGhpcy5kZXN0cm95KCk7XG4gICAgICB9XG4gICAgfSk7XG5cbiAgICB0aGlzLl9kb21MaXN0ZW5lcnMgPSBbXG4gICAgICBbJ2JlZm9yZWlucHV0JywgKGV2ZW50KSA9PiB0aGlzLl9vbkJlZm9yZUlucHV0KGV2ZW50IGFzIElucHV0RXZlbnQpXSxcbiAgICAgIFsnY3V0JywgKGV2ZW50KSA9PiB0aGlzLl9ndWFyZFNlbGVjdGlvbihldmVudCldLFxuICAgICAgWydkcmFnc3RhcnQnLCAoZXZlbnQpID0+IHRoaXMuX2d1YXJkU2VsZWN0aW9uKGV2ZW50KV0sXG4gICAgICBbJ2NvcHknLCAoZXZlbnQpID0+IHRoaXMuX29uQ29weShldmVudCBhcyBDbGlwYm9hcmRFdmVudCldLFxuICAgICAgWydjbGljaycsIChldmVudCkgPT4gdGhpcy5fb25DbGljayhldmVudCBhcyBNb3VzZUV2ZW50KV0sXG4gICAgXTtcbiAgICB0aGlzLl9kb21MaXN0ZW5lcnMuZm9yRWFjaCgoW25hbWUsIGxpc3RlbmVyXSkgPT4gZWwuYWRkRXZlbnRMaXN0ZW5lcihuYW1lLCBsaXN0ZW5lciwgdHJ1ZSkpO1xuXG4gICAgdGhpcy5fdG9DaGlwcygpO1xuICB9XG5cbiAgcHVibGljIGRlc3Ryb3koKTogdm9pZCB7XG4gICAgY29uc3QgZWw6IEhUTUxFbGVtZW50IHwgdW5kZWZpbmVkID0gdGhpcy5fZWRpdG9yPy5lbDtcbiAgICB0aGlzLl9kb21MaXN0ZW5lcnMuZm9yRWFjaCgoW25hbWUsIGxpc3RlbmVyXSkgPT4gZWw/LnJlbW92ZUV2ZW50TGlzdGVuZXIobmFtZSwgbGlzdGVuZXIsIHRydWUpKTtcbiAgICB0aGlzLl9kb21MaXN0ZW5lcnMgPSBbXTtcbiAgICB0aGlzLl9lZGl0b3IgPSBudWxsO1xuICB9XG5cbiAgLy8gUmVsYWJlbCBldmVyeSBjaGlwOiB0aGUgdmFsdWVzIGFycml2ZWQgb3IgY2hhbmdlZCwgb3IgbmFtZXMgd2VyZSB0b2dnbGVkLlxuICBwdWJsaWMgcmVmcmVzaCgpOiB2b2lkIHtcbiAgICB0aGlzLl9jaGlwcygpLmZvckVhY2goKGNoaXApID0+IHRoaXMuX2xhYmVsKGNoaXApKTtcbiAgfVxuXG4gIC8vIFB1dCBGcm9hbGEncyBmbG9hdGluZyB0b29sYmFyIGFuZCBhIHRhYmxlJ3MgcG9wdXAgYXdheSwgd2hlbiBlaXRoZXIgaXNcbiAgLy8gYWxyZWFkeSB1cCBhcyBhIGNoaXAncyBwb3BvdmVyIG9wZW5zOiB0aGV5IHNpdCBhYm92ZSBldmVyeSBvdmVybGF5LlxuICBwdWJsaWMgaGlkZVRvb2xiYXIoKTogdm9pZCB7XG4gICAgdGhpcy5fZWRpdG9yPy50b29sYmFyLmhpZGUoKTtcbiAgICB0aGlzLl9lZGl0b3I/LnBvcHVwcy5oaWRlKCd0YWJsZS5lZGl0Jyk7XG4gIH1cblxuICAvLyBUaGUgZWRpdG9yJ3Mgb3duIHVuZG8gb2YgdGhlIGxhc3Qgc3RlcDogd2hhdCBwdXRzIGJhY2sgdGhlIGNoaXBzIGFuIGVkaXRcbiAgLy8gdG9vayBvdXQuXG4gIHB1YmxpYyB1bmRvKCk6IHZvaWQge1xuICAgIHRoaXMuX2VkaXRvcj8uY29tbWFuZHMudW5kbygpO1xuICB9XG5cbiAgLy8gVGFrZSBhIHZhbHVlIG91dCBvZiB0aGUgdGV4dCwgd2hlcmV2ZXIgaXQgYXBwZWFycyDigJQgaXQgd2FzIGRlbGV0ZWQuXG4gIHB1YmxpYyByZW1vdmVLZXkoa2V5OiBzdHJpbmcpOiB2b2lkIHtcbiAgICB0aGlzLl9jaGlwcygpXG4gICAgICAuZmlsdGVyKChjaGlwKSA9PiBjaGlwLmdldEF0dHJpYnV0ZShLRVlfQVRUUklCVVRFKSA9PT0ga2V5KVxuICAgICAgLmZvckVhY2goKGNoaXApID0+IHRoaXMucmVtb3ZlKGNoaXApKTtcbiAgfVxuXG4gIC8vIFRha2Ugb25lIGNoaXAgb3V0IG9mIHRoZSB0ZXh0LlxuICBwdWJsaWMgcmVtb3ZlKGNoaXA6IEhUTUxFbGVtZW50KTogdm9pZCB7XG4gICAgaWYgKCF0aGlzLl9lZGl0b3I/LmVsLmNvbnRhaW5zKGNoaXApKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgLy8gVGhlIGN1cnNvciBnb2VzIGJhY2sgd2hlcmUgdGhlIGNoaXAgd2FzIOKAlCB3aGF0ZXZlciBhc2tlZCBmb3IgdGhlXG4gICAgLy8gcmVtb3ZhbCAoYSBkaWFsb2csIGEgcG9wb3ZlcikgdG9vayB0aGUgZm9jdXMsIGFuZCB3aXRob3V0IGl0IGFuIFVuZG9cbiAgICAvLyBzdHJhaWdodCBhZnRlciB3b3VsZCBuZXZlciByZWFjaCB0aGUgZWRpdG9yLlxuICAgIGNvbnN0IGNhcmV0ID0gZG9jdW1lbnQuY3JlYXRlUmFuZ2UoKTtcbiAgICBjYXJldC5zZXRTdGFydEJlZm9yZShjaGlwKTtcbiAgICBjYXJldC5jb2xsYXBzZSh0cnVlKTtcblxuICAgIHRoaXMuX2VkaXRvci51bmRvLnNhdmVTdGVwKCk7XG4gICAgY2hpcC5yZW1vdmUoKTtcbiAgICB0aGlzLl9lZGl0b3IuZWwuZm9jdXMoKTtcbiAgICBjb25zdCBzZWxlY3Rpb24gPSB0aGlzLl9zZWxlY3Rpb24oKTtcbiAgICBzZWxlY3Rpb24ucmVtb3ZlQWxsUmFuZ2VzKCk7XG4gICAgc2VsZWN0aW9uLmFkZFJhbmdlKGNhcmV0KTtcbiAgICB0aGlzLl9jaGFuZ2VkKCk7XG4gIH1cblxuICBwcml2YXRlIF9jaGlwcygpOiBIVE1MRWxlbWVudFtdIHtcbiAgICByZXR1cm4gdGhpcy5fZWRpdG9yXG4gICAgICA/IEFycmF5LmZyb20odGhpcy5fZWRpdG9yLmVsLnF1ZXJ5U2VsZWN0b3JBbGwoQ0hJUF9TRUxFQ1RPUikpXG4gICAgICA6IFtdO1xuICB9XG5cbiAgLy8gSG93IG1hbnkgY2hpcHMgZWFjaCBrZXkgaGFzIGluIHRoZSBibG9jay5cbiAgcHJpdmF0ZSBfY2hpcENvdW50cygpOiBNYXA8c3RyaW5nLCBudW1iZXI+IHtcbiAgICBjb25zdCBjb3VudHMgPSBuZXcgTWFwPHN0cmluZywgbnVtYmVyPigpO1xuICAgIHRoaXMuX2NoaXBzKCkuZm9yRWFjaCgoY2hpcCkgPT4ge1xuICAgICAgY29uc3Qga2V5ID0gY2hpcC5nZXRBdHRyaWJ1dGUoS0VZX0FUVFJJQlVURSk7XG4gICAgICBjb3VudHMuc2V0KGtleSwgKGNvdW50cy5nZXQoa2V5KSA/PyAwKSArIDEpO1xuICAgIH0pO1xuXG4gICAgcmV0dXJuIGNvdW50cztcbiAgfVxuXG4gIC8vIFRlbGwgdGhlIGhvc3Qgd2hlbiBhbiBlZGl0IHRvb2sgdGhlIGxhc3QgY2hpcCBvZiBzb21lIGtleSBvdXQgb2YgdGhlXG4gIC8vIGJsb2NrLCBnaXZlbiB0aGUgY291bnRzIGZyb20gYmVmb3JlIGl0LlxuICBwcml2YXRlIF9yZXBvcnRSZW1vdmVkKGJlZm9yZTogTWFwPHN0cmluZywgbnVtYmVyPiB8IG51bGwpOiB2b2lkIHtcbiAgICBpZiAoIWJlZm9yZSB8fCAhdGhpcy5fZWRpdG9yKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgY29uc3QgYWZ0ZXIgPSB0aGlzLl9jaGlwQ291bnRzKCk7XG4gICAgaWYgKFsuLi5iZWZvcmUua2V5cygpXS5zb21lKChrZXkpID0+ICFhZnRlci5oYXMoa2V5KSkpIHtcbiAgICAgIHRoaXMuY29uZmlnLnJlbW92ZWQoe1xuICAgICAgICBiZWZvcmU6IFsuLi5iZWZvcmUua2V5cygpXSxcbiAgICAgICAgYWZ0ZXI6IFsuLi5hZnRlci5rZXlzKCldLFxuICAgICAgICB1bmRvOiAoKSA9PiB0aGlzLnVuZG8oKSxcbiAgICAgIH0pO1xuICAgIH1cbiAgfVxuXG4gIC8vIEEgdG9vbGJhciBjb21tYW5kIHNlZXMgdG9rZW5zLCBub3QgY2hpcHM6IENsZWFyIGZvcm1hdHRpbmcgdW53cmFwcyBldmVyeVxuICAvLyBzcGFuLCBhIGNoaXAgaW5jbHVkZWQsIHdoaWNoIHdvdWxkIGxlYXZlIGEgdHlwZWQgbnVtYmVyIGJlaGluZC4gQXJvdW5kIGFcbiAgLy8gdG9rZW4gaXQgZm9ybWF0cyBwbGFpbiB0ZXh0LCBhbmQgdGhlIGNoaXAgY29tZXMgYmFjayBpbnNpZGUgd2hhdGV2ZXJcbiAgLy8gZm9ybWF0dGluZyB0aGUgdG9rZW4gd2FzIGdpdmVuLlxuICBwcml2YXRlIF93YXRjaENvbW1hbmRzKGVkaXRvcjogYW55KTogdm9pZCB7XG4gICAgZWRpdG9yLmV2ZW50cy5vbignY29tbWFuZHMuYmVmb3JlJywgKGNvbW1hbmQ6IHN0cmluZykgPT4gdGhpcy5fb25Db21tYW5kQmVmb3JlKGNvbW1hbmQpKTtcbiAgICBlZGl0b3IuZXZlbnRzLm9uKCdjb21tYW5kcy5hZnRlcicsICgpID0+IHtcbiAgICAgIHRoaXMuX3RvQ2hpcHMoKTtcbiAgICAgIHRoaXMuX3JlcG9ydFJlbW92ZWQodGhpcy5fYmVmb3JlKTtcbiAgICAgIHRoaXMuX2JlZm9yZSA9IG51bGw7XG4gICAgfSk7XG4gICAgLy8gVW5kbyBhbmQgcmVkbyByZXN0b3JlIGEgc3RlcCBhcyBGcm9hbGEgc2F2ZWQgaXQ6IHRoZSBvbmUgYmVmb3JlIGFcbiAgICAvLyBjb21tYW5kIGhvbGRzIHRva2VucywgYXMgdGhlIGNvbW1hbmQgc2F3IHRoZW0uIE5laXRoZXIgZmlyZXNcbiAgICAvLyBjb21tYW5kcy5hZnRlcjogRnJvYWxhJ3MgY29tbWFuZHMudW5kbygpIOKAlCBDdHJsK1osIGFuZCB1bmRvKCkgaGVyZSDigJRcbiAgICAvLyBydW5zIHRoZSB1bmRvIGRpcmVjdGx5LlxuICAgIGVkaXRvci5ldmVudHMub24oJ2NvbW1hbmRzLnVuZG8nLCAoKSA9PiB0aGlzLl90b0NoaXBzKCkpO1xuICAgIGVkaXRvci5ldmVudHMub24oJ2NvbW1hbmRzLnJlZG8nLCAoKSA9PiB0aGlzLl90b0NoaXBzKCkpO1xuICB9XG5cbiAgLy8gRXZlcnkgY29tbWFuZCBzdGFydHMgYSBuZXcgZWRpdC4gT25lIHRoYXQgd291bGQgYnVpbGQgd2hhdCB0aGUgc2VydmVyXG4gIC8vIHJld3JpdGVzIGlzIHJlZnVzZWQgKHJldHVybmluZyBmYWxzZSBjYW5jZWxzIGl0KTsgYW55IG90aGVyIHJ1bnMgb25cbiAgLy8gdG9rZW5zLCBpdHMgY2hpcCBjb3VudHMga2VwdCB0byBzZWUgd2hhdCBpdCByZW1vdmVkLlxuICBwcml2YXRlIF9vbkNvbW1hbmRCZWZvcmUoY29tbWFuZDogc3RyaW5nKTogZmFsc2UgfCB2b2lkIHtcbiAgICB0aGlzLmNvbmZpZy5jaGFuZ2VkKCk7XG5cbiAgICBpZiAoVEFCTEVfSU5TRVJUX0NPTU1BTkRTLmluY2x1ZGVzKGNvbW1hbmQpICYmIHRoaXMuX2NhcmV0SW4oTk9fVEFCTEVfSU5TSURFKSkge1xuICAgICAgdGhpcy5jb25maWcucmVmdXNlZCgnQSB0YWJsZSBnb2VzIGJldHdlZW4gcGFyYWdyYXBocywgbmV2ZXIgaW5zaWRlIGEgbGlzdCBvciBhbm90aGVyIHRhYmxlLicpO1xuXG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuXG4gICAgaWYgKENFTExfQ09NTUFORFMuaW5jbHVkZXMoY29tbWFuZCkgJiYgdGhpcy5fY2FyZXRJbihDRUxMKSkge1xuICAgICAgdGhpcy5jb25maWcucmVmdXNlZCgnQSB0YWJsZSBjZWxsIGhvbGRzIHdvcmRzIGFuZCB2YWx1ZXM7IGEgbGlzdCBvciBhIGhlYWRpbmcgZ29lcyBvdXRzaWRlIHRoZSB0YWJsZS4nKTtcblxuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cblxuICAgIHRoaXMuX2JlZm9yZSA9IEhJU1RPUllfQ09NTUFORFMuaW5jbHVkZXMoY29tbWFuZCkgPyBudWxsIDogdGhpcy5fY2hpcENvdW50cygpO1xuICAgIHRoaXMuX3RvVG9rZW5UZXh0KCk7XG4gIH1cblxuICAvLyBXaGV0aGVyIHRoZSBjYXJldCBzaXRzIGluc2lkZSBhbiBlbGVtZW50IG9mIHRoaXMgZWRpdG9yIHRoYXQgYHNlbGVjdG9yYFxuICAvLyBtYXRjaGVzLlxuICBwcml2YXRlIF9jYXJldEluKHNlbGVjdG9yOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgICBjb25zdCBjb250YWluZXI6IEVsZW1lbnQgfCBudWxsID0gdGhpcy5fZWRpdG9yLnNlbGVjdGlvbi5lbGVtZW50KCk/LmNsb3Nlc3Q/LihzZWxlY3RvcikgPz8gbnVsbDtcblxuICAgIHJldHVybiAhIWNvbnRhaW5lciAmJiB0aGlzLl9lZGl0b3IuZWwuY29udGFpbnMoY29udGFpbmVyKTtcbiAgfVxuXG4gIC8vIFR1cm4gZXZlcnkge3t2YWx1ZS5rZXl9fSB0b2tlbiBpbiB0aGUgZWRpdG9yJ3MgdGV4dCBpbnRvIGEgY2hpcC4gRm9yIGFcbiAgLy8gcGFzdGUsIGEgdG9rZW4gb25seSBzdGF5cyB3aGVuIGl0IHdhcyBjb3BpZWQgb24gdGhpcyBwYWdlIGFuZCB0aGUgcGFnZSBoYXNcbiAgLy8gdGhlIHZhbHVlOyBvdGhlcndpc2UgaXQgZ29lcywgYW5kIGp1c3QgdGhlIHRleHQgYXJvdW5kIGl0IGlzIHBhc3RlZC5cbiAgcHJpdmF0ZSBfdG9DaGlwcyhwYXN0ZWQgPSBmYWxzZSk6IHZvaWQge1xuICAgIGNvbnN0IGVsOiBIVE1MRWxlbWVudCB8IHVuZGVmaW5lZCA9IHRoaXMuX2VkaXRvcj8uZWw7XG4gICAgaWYgKCFlbCkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGNvbnN0IHdhbGtlciA9IGRvY3VtZW50LmNyZWF0ZVRyZWVXYWxrZXIoZWwsIE5vZGVGaWx0ZXIuU0hPV19URVhUKTtcbiAgICBjb25zdCB0ZXh0czogVGV4dFtdID0gW107XG4gICAgd2hpbGUgKHdhbGtlci5uZXh0Tm9kZSgpKSB7XG4gICAgICBjb25zdCB0ZXh0ID0gd2Fsa2VyLmN1cnJlbnROb2RlIGFzIFRleHQ7XG4gICAgICBpZiAodGV4dC5kYXRhLmluY2x1ZGVzKCd7eycpICYmICF0ZXh0LnBhcmVudEVsZW1lbnQ/LmNsb3Nlc3QoQ0hJUF9TRUxFQ1RPUikpIHtcbiAgICAgICAgdGV4dHMucHVzaCh0ZXh0KTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICB0ZXh0cy5mb3JFYWNoKCh0ZXh0KSA9PiB0aGlzLl9zcGxpdFRleHQodGV4dCwgcGFzdGVkKSk7XG4gIH1cblxuICBwcml2YXRlIF9rZWVwc1Bhc3RlZChrZXk6IHN0cmluZyk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLl9wYXN0ZVNjb3BlID09PSB0aGlzLmNvbmZpZy5zY29wZSgpICYmICEhdGhpcy5jb25maWcudmFsdWVzKClba2V5XTtcbiAgfVxuXG4gIHByaXZhdGUgX3NwbGl0VGV4dCh0ZXh0OiBUZXh0LCBwYXN0ZWQ6IGJvb2xlYW4pOiB2b2lkIHtcbiAgICBjb25zdCBtYXRjaGVzID0gQXJyYXkuZnJvbSh0ZXh0LmRhdGEubWF0Y2hBbGwoVkFMVUVfVE9LRU5fUEFUVEVSTikpO1xuICAgIGlmICghbWF0Y2hlcy5sZW5ndGgpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICAvLyBPbmx5IG5vbi1lbXB0eSB0ZXh0IGFyb3VuZCB0aGUgY2hpcHMsIHNvIGEgc2VsZWN0aW9uIGNvdW50ZWQgaW4gY2hpbGRcbiAgICAvLyBub2RlcyBrZWVwcyBpdHMgcGxhY2UuXG4gICAgY29uc3QgZnJhZ21lbnQgPSBkb2N1bWVudC5jcmVhdGVEb2N1bWVudEZyYWdtZW50KCk7XG4gICAgY29uc3QgYXBwZW5kVGV4dCA9ICh2YWx1ZTogc3RyaW5nKSA9PiB7XG4gICAgICBpZiAodmFsdWUpIHtcbiAgICAgICAgZnJhZ21lbnQuYXBwZW5kKHZhbHVlKTtcbiAgICAgIH1cbiAgICB9O1xuICAgIGxldCBjb25zdW1lZCA9IDA7XG4gICAgbWF0Y2hlcy5mb3JFYWNoKChtYXRjaCkgPT4ge1xuICAgICAgY29uc3Qga2V5ID0gbWF0Y2hbMV0udG9Mb3dlckNhc2UoKTtcbiAgICAgIGFwcGVuZFRleHQodGV4dC5kYXRhLnNsaWNlKGNvbnN1bWVkLCBtYXRjaC5pbmRleCkpO1xuICAgICAgaWYgKCFwYXN0ZWQgfHwgdGhpcy5fa2VlcHNQYXN0ZWQoa2V5KSkge1xuICAgICAgICBmcmFnbWVudC5hcHBlbmQodGhpcy5fY3JlYXRlQ2hpcChrZXkpKTtcbiAgICAgIH1cbiAgICAgIGNvbnN1bWVkID0gbWF0Y2guaW5kZXggKyBtYXRjaFswXS5sZW5ndGg7XG4gICAgfSk7XG4gICAgYXBwZW5kVGV4dCh0ZXh0LmRhdGEuc2xpY2UoY29uc3VtZWQpKTtcblxuICAgIHRleHQucmVwbGFjZVdpdGgoZnJhZ21lbnQpO1xuICB9XG5cbiAgLy8gRXZlcnkgY2hpcCBpbiB0aGUgZWRpdG9yIGJhY2sgdG8gaXRzIHRva2VuLCBhcyB0ZXh0LlxuICBwcml2YXRlIF90b1Rva2VuVGV4dCgpOiB2b2lkIHtcbiAgICB0aGlzLl9jaGlwcygpLmZvckVhY2goKGNoaXApID0+IGNoaXAucmVwbGFjZVdpdGgodmFsdWVUb2tlbihjaGlwLmdldEF0dHJpYnV0ZShLRVlfQVRUUklCVVRFKSkpKTtcbiAgfVxuXG4gIHByaXZhdGUgX2NyZWF0ZUNoaXAoa2V5OiBzdHJpbmcpOiBIVE1MRWxlbWVudCB7XG4gICAgY29uc3QgY2hpcCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ3NwYW4nKTtcbiAgICBjaGlwLnNldEF0dHJpYnV0ZShUWVBFX0FUVFJJQlVURSwgVkFMVUVfVFlQRSk7XG4gICAgY2hpcC5zZXRBdHRyaWJ1dGUoS0VZX0FUVFJJQlVURSwga2V5KTtcbiAgICBjaGlwLnNldEF0dHJpYnV0ZSgnY29udGVudGVkaXRhYmxlJywgJ2ZhbHNlJyk7XG4gICAgdGhpcy5fbGFiZWwoY2hpcCk7XG5cbiAgICByZXR1cm4gY2hpcDtcbiAgfVxuXG4gIC8vIEEgY2hpcCByZWFkcyBhcyB0aGUgdmFsdWUgZG9lcyBpbiB0aGUgdmlld2VkIGJsb2NrIOKAlCBpdHMgbnVtYmVyLCB0aGVcbiAgLy8gZWxsaXBzaXMgd2hpbGUgdGhhdCBsb2FkcywgZWxzZSB0aGUgZW0gZGFzaCDigJQgc28gb3BlbmluZyB0aGUgZWRpdG9yIG1vdmVzXG4gIC8vIG5vIHdvcmQ7IG9yIGFzIGl0cyBuYW1lLCB3aGVuIG5hbWVzIGFyZSB0b2dnbGVkIG9uLiBBIGtleSB3aXRoIG5vIHZhbHVlIG9uXG4gIC8vIHRoZSBwYWdlIHJlYWRzIGFzIHRoZSBrZXkgaXRzZWxmLCBtYXJrZWQgbWlzc2luZy5cbiAgcHJpdmF0ZSBfbGFiZWwoY2hpcDogSFRNTEVsZW1lbnQpOiB2b2lkIHtcbiAgICBjb25zdCBrZXkgPSBjaGlwLmdldEF0dHJpYnV0ZShLRVlfQVRUUklCVVRFKTtcbiAgICBjb25zdCB2YWx1ZSA9IHRoaXMuY29uZmlnLnZhbHVlcygpW2tleV07XG5cbiAgICBjaGlwLnRleHRDb250ZW50ID0gIXZhbHVlXG4gICAgICA/IGtleVxuICAgICAgOiB0aGlzLmNvbmZpZy5zaG93TmFtZXMoKSA/IHZhbHVlLm5hbWUgOiB2YWx1ZVRleHQodmFsdWUpO1xuICAgIGNoaXAudGl0bGUgPSB2YWx1ZT8ubmFtZSA/PyBrZXk7XG4gICAgY2hpcC50b2dnbGVBdHRyaWJ1dGUoTUlTU0lOR19BVFRSSUJVVEUsICF2YWx1ZSk7XG4gIH1cblxuICAvLyBUaGUgaHRtbCBGcm9hbGEgaGFuZHMgb3V0LCB3aXRoIGV2ZXJ5IGNoaXAgYmFjayB0byBpdHMgdG9rZW4uXG4gIHByaXZhdGUgX3RvVG9rZW5zKGh0bWw6IHN0cmluZyk6IHN0cmluZyB7XG4gICAgaWYgKCFodG1sLmluY2x1ZGVzKEtFWV9BVFRSSUJVVEUpKSB7XG4gICAgICByZXR1cm4gaHRtbDtcbiAgICB9XG5cbiAgICBjb25zdCB0ZW1wbGF0ZSA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ3RlbXBsYXRlJyk7XG4gICAgdGVtcGxhdGUuaW5uZXJIVE1MID0gaHRtbDtcbiAgICB0ZW1wbGF0ZS5jb250ZW50LnF1ZXJ5U2VsZWN0b3JBbGwoQ0hJUF9TRUxFQ1RPUikuZm9yRWFjaCgoY2hpcCkgPT4ge1xuICAgICAgY2hpcC5yZXBsYWNlV2l0aCh2YWx1ZVRva2VuKGNoaXAuZ2V0QXR0cmlidXRlKEtFWV9BVFRSSUJVVEUpKSk7XG4gICAgfSk7XG5cbiAgICByZXR1cm4gdGVtcGxhdGUuaW5uZXJIVE1MO1xuICB9XG5cbiAgcHJpdmF0ZSBfb25LZXlkb3duKGV2ZW50OiBLZXlib2FyZEV2ZW50KTogYm9vbGVhbiB8IHZvaWQge1xuICAgIC8vIEFueSBrZXkgYnV0IGEgbG9uZSBtb2RpZmllciBzdGFydHMgYSBuZXcgZWRpdC5cbiAgICBpZiAoIU1PRElGSUVSX0tFWVMuaW5jbHVkZXMoZXZlbnQua2V5KSkge1xuICAgICAgdGhpcy5jb25maWcuY2hhbmdlZCgpO1xuICAgIH1cblxuICAgIGNvbnN0IGRlbGV0aW5nID0gZXZlbnQua2V5ID09PSAnQmFja3NwYWNlJyB8fCBldmVudC5rZXkgPT09ICdEZWxldGUnO1xuXG4gICAgLy8gRGVsZXRpbmcgYWNyb3NzIHNldmVyYWwgc2VsZWN0ZWQgY2VsbHMgZ29lcyB0aHJvdWdoLCB2YWx1ZXMgYW5kIGFsbDpcbiAgICAvLyBGcm9hbGEgc2F2ZXMgYW4gdW5kbyBzdGVwIGFuZCBlbXB0aWVzIHRoZSBjZWxscywgYW5kIHdoYXQgdGhhdCB0b29rIGlzXG4gICAgLy8gcmVwb3J0ZWQgb25jZSB0aGV5IGFyZSBlbXB0eS5cbiAgICBpZiAoZGVsZXRpbmcgJiYgdGhpcy5fZWRpdG9yLmVsLnF1ZXJ5U2VsZWN0b3JBbGwoU0VMRUNURURfQ0VMTCkubGVuZ3RoID4gMSkge1xuICAgICAgY29uc3QgYmVmb3JlID0gdGhpcy5fY2hpcENvdW50cygpO1xuICAgICAgc2V0VGltZW91dCgoKSA9PiB0aGlzLl9yZXBvcnRSZW1vdmVkKGJlZm9yZSkpO1xuXG4gICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgIH1cblxuICAgIGNvbnN0IHJhbmdlID0gdGhpcy5fcmFuZ2UoKTtcbiAgICBpZiAoIXJhbmdlKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKHJhbmdlLmNvbGxhcHNlZCkge1xuICAgICAgaWYgKCFkZWxldGluZykge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGNoaXAgPSB0aGlzLl9hZGphY2VudENoaXAoZXZlbnQua2V5ID09PSAnQmFja3NwYWNlJywgdGhpcy5fZ3JhbnVsYXJpdHkoZXZlbnQpKTtcblxuICAgICAgcmV0dXJuIGNoaXAgPyB0aGlzLl9ibG9jayhldmVudCwgW2NoaXBdLCBudWxsKSA6IHVuZGVmaW5lZDtcbiAgICB9XG5cbiAgICAvLyBBIHNlbGVjdGlvbiBpcyByZXBsYWNlZCBieSBhIGRlbGV0aW5nIGtleSwgRW50ZXIsIGEgdHlwZWQgY2hhcmFjdGVyIG9yXG4gICAgLy8gYSBjdXQuXG4gICAgY29uc3QgdHlwaW5nID0gZXZlbnQua2V5Lmxlbmd0aCA9PT0gMSAmJiAhZXZlbnQuY3RybEtleSAmJiAhZXZlbnQubWV0YUtleTtcbiAgICBjb25zdCBjdXR0aW5nID0gKGV2ZW50LmN0cmxLZXkgfHwgZXZlbnQubWV0YUtleSkgJiYgZXZlbnQua2V5LnRvTG93ZXJDYXNlKCkgPT09ICd4JztcbiAgICBpZiAoIWRlbGV0aW5nICYmICF0eXBpbmcgJiYgIWN1dHRpbmcgJiYgZXZlbnQua2V5ICE9PSAnRW50ZXInKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgY29uc3QgY2hpcHMgPSB0aGlzLl9jaGlwc0luKHJhbmdlKTtcblxuICAgIHJldHVybiBjaGlwcy5sZW5ndGggPyB0aGlzLl9ibG9jayhldmVudCwgY2hpcHMsIHJhbmdlKSA6IHVuZGVmaW5lZDtcbiAgfVxuXG4gIC8vIFRoZSBzYW1lIHJ1bGUgZm9yIGVkaXRzIHRoYXQgYXJyaXZlIHdpdGhvdXQgYSBrZXkgRnJvYWxhIHNlZXM6IGEgcGhvbmVcbiAgLy8ga2V5Ym9hcmQsIGFuIGlucHV0IG1ldGhvZCwgYSBzcGVsbC1jaGVjayByZXBsYWNlbWVudC5cbiAgcHJpdmF0ZSBfb25CZWZvcmVJbnB1dChldmVudDogSW5wdXRFdmVudCk6IHZvaWQge1xuICAgIGNvbnN0IHJhbmdlID0gdGhpcy5fcmFuZ2UoKTtcbiAgICBpZiAodGhpcy5fcmVtb3ZpbmcgfHwgIXJhbmdlKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKHJhbmdlLmNvbGxhcHNlZCkge1xuICAgICAgY29uc3QgYmFja3dhcmQgPSBldmVudC5pbnB1dFR5cGUuZW5kc1dpdGgoJ0JhY2t3YXJkJyk7XG4gICAgICBpZiAoZXZlbnQuaW5wdXRUeXBlLnN0YXJ0c1dpdGgoJ2RlbGV0ZScpKSB7XG4gICAgICAgIGNvbnN0IGNoaXAgPSB0aGlzLl9hZGphY2VudENoaXAoYmFja3dhcmQsIGV2ZW50LmlucHV0VHlwZS5pbmNsdWRlcygnV29yZCcpID8gJ3dvcmQnIDogJ2NoYXJhY3RlcicpO1xuICAgICAgICBpZiAoY2hpcCkge1xuICAgICAgICAgIHRoaXMuX2Jsb2NrKGV2ZW50LCBbY2hpcF0sIG51bGwpO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBjb25zdCBjaGlwcyA9IHRoaXMuX2NoaXBzSW4ocmFuZ2UpO1xuICAgIGlmIChjaGlwcy5sZW5ndGgpIHtcbiAgICAgIHRoaXMuX2Jsb2NrKGV2ZW50LCBjaGlwcywgcmFuZ2UpO1xuICAgIH1cbiAgfVxuXG4gIC8vIEN1dCwgZHJhZyBhbmQgcGFzdGUtb3Zlcjogc3RvcHBlZCB3aGVuIHRoZSBzZWxlY3Rpb24gaG9sZHMgYSB2YWx1ZS5cbiAgcHJpdmF0ZSBfZ3VhcmRTZWxlY3Rpb24oZXZlbnQ6IEV2ZW50KTogYm9vbGVhbiB8IHZvaWQge1xuICAgIGNvbnN0IHJhbmdlID0gdGhpcy5fcmFuZ2UoKTtcbiAgICBpZiAodGhpcy5fcmVtb3ZpbmcgfHwgIXJhbmdlIHx8IHJhbmdlLmNvbGxhcHNlZCkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGNvbnN0IGNoaXBzID0gdGhpcy5fY2hpcHNJbihyYW5nZSk7XG5cbiAgICByZXR1cm4gY2hpcHMubGVuZ3RoID8gdGhpcy5fYmxvY2soZXZlbnQsIGNoaXBzLCByYW5nZSkgOiB1bmRlZmluZWQ7XG4gIH1cblxuICAvLyBDb3B5aW5nIGEgdmFsdWUgY29waWVzIGl0cyB0b2tlbiwgYW5kIHRoZSBwYWdlIGl0IHdhcyBjb3BpZWQgb24sIHNvXG4gIC8vIHBhc3RpbmcgaXQgYmFjayBvbiB0aGlzIHBhZ2Ug4oCUIGluIHRoaXMgYmxvY2sgb3IgYW5vdGhlciDigJQgbWFrZXMgaXQgYSBjaGlwXG4gIC8vIGFnYWluLlxuICBwcml2YXRlIF9vbkNvcHkoZXZlbnQ6IENsaXBib2FyZEV2ZW50KTogdm9pZCB7XG4gICAgY29uc3QgcmFuZ2UgPSB0aGlzLl9yYW5nZSgpO1xuICAgIGlmICghcmFuZ2UgfHwgcmFuZ2UuY29sbGFwc2VkIHx8ICF0aGlzLl9jaGlwc0luKHJhbmdlKS5sZW5ndGgpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBjb25zdCBob2xkZXIgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdkaXYnKTtcbiAgICBob2xkZXIuYXBwZW5kKHJhbmdlLmNsb25lQ29udGVudHMoKSk7XG4gICAgaG9sZGVyLnF1ZXJ5U2VsZWN0b3JBbGwoQ0hJUF9TRUxFQ1RPUikuZm9yRWFjaCgoY2hpcCkgPT4ge1xuICAgICAgY2hpcC5yZXBsYWNlV2l0aCh2YWx1ZVRva2VuKGNoaXAuZ2V0QXR0cmlidXRlKEtFWV9BVFRSSUJVVEUpKSk7XG4gICAgfSk7XG5cbiAgICBldmVudC5jbGlwYm9hcmREYXRhLnNldERhdGEoJ3RleHQvcGxhaW4nLCB0aGlzLl9wbGFpblRleHQoaG9sZGVyKSk7XG4gICAgZXZlbnQuY2xpcGJvYXJkRGF0YS5zZXREYXRhKCd0ZXh0L2h0bWwnLCBob2xkZXIuaW5uZXJIVE1MKTtcbiAgICBldmVudC5jbGlwYm9hcmREYXRhLnNldERhdGEoU0NPUEVfVFlQRSwgdGhpcy5jb25maWcuc2NvcGUoKSk7XG4gICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgfVxuXG4gIC8vIFdoYXQgY29waWVkIGh0bWwgcmVhZHMgYXMgaW4gcGxhaW4gdGV4dDogYSBwYXJhZ3JhcGggb24gaXRzIG93biBsaW5lcywgYVxuICAvLyB0YWJsZSdzIGNlbGxzIHRhYi1zZXBhcmF0ZWQgYW5kIGl0cyByb3dzIG9uIGxpbmVzIG9mIHRoZWlyIG93bi4gVGhhdCBpc1xuICAvLyB0aGUgYnJvd3NlcidzIGlubmVyVGV4dCwgd2hpY2ggb25seSB0ZXh0IGxhaWQgb3V0IG9uIHRoZSBwYWdlIGhhcyDigJQgc29cbiAgLy8gdGhlIGhvbGRlciBpcyBwdXQgb2Zmc2NyZWVuIChub3QgaGlkZGVuOiBoaWRkZW4gdGV4dCBoYXMgbm9uZSkgd2hpbGUgaXQgaXNcbiAgLy8gcmVhZC5cbiAgcHJpdmF0ZSBfcGxhaW5UZXh0KGhvbGRlcjogSFRNTEVsZW1lbnQpOiBzdHJpbmcge1xuICAgIGhvbGRlci5zdHlsZS5jc3NUZXh0ID0gJ3Bvc2l0aW9uOiBmaXhlZDsgbGVmdDogLTEwMDAwcHg7IHRvcDogMCc7XG4gICAgZG9jdW1lbnQuYm9keS5hcHBlbmQoaG9sZGVyKTtcbiAgICBjb25zdCB0ZXh0ID0gaG9sZGVyLmlubmVyVGV4dDtcbiAgICBob2xkZXIucmVtb3ZlKCk7XG5cbiAgICByZXR1cm4gdGV4dDtcbiAgfVxuXG4gIHByaXZhdGUgX29uQ2xpY2soZXZlbnQ6IE1vdXNlRXZlbnQpOiB2b2lkIHtcbiAgICBjb25zdCBjaGlwID0gKGV2ZW50LnRhcmdldCBhcyBFbGVtZW50KT8uY2xvc2VzdD8uKENISVBfU0VMRUNUT1IpIGFzIEhUTUxFbGVtZW50IHwgbnVsbDtcbiAgICBpZiAoIWNoaXAgfHwgIXRoaXMuX2VkaXRvcj8uZWwuY29udGFpbnMoY2hpcCkpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgIC8vIEEgcHJlc3MgaW4gYSB0YWJsZSBjZWxsIGNhbiBvcGVuIHRoZSB0YWJsZSdzIHBvcHVwIG9uIG1vdXNldXAsIGp1c3RcbiAgICAvLyBiZWZvcmUgdGhpcyBjbGljazsgYSBjaGlwIGluIGEgY2VsbCBzaG93cyBvbmx5IGl0cyBvd24gcG9wb3Zlci5cbiAgICB0aGlzLl9lZGl0b3IucG9wdXBzLmhpZGUoJ3RhYmxlLmVkaXQnKTtcbiAgICB0aGlzLmNvbmZpZy5jbGljayhjaGlwLmdldEF0dHJpYnV0ZShLRVlfQVRUUklCVVRFKSwgY2hpcCk7XG4gIH1cblxuICBwcml2YXRlIF9vbkNoaXAoZXZlbnQ/OiBFdmVudCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiAhIShldmVudD8udGFyZ2V0IGFzIEVsZW1lbnQgfCB1bmRlZmluZWQpPy5jbG9zZXN0Py4oQ0hJUF9TRUxFQ1RPUik7XG4gIH1cblxuICBwcml2YXRlIF9ibG9jayhldmVudDogRXZlbnQsIGNoaXBzOiBIVE1MRWxlbWVudFtdLCByYW5nZTogUmFuZ2UgfCBudWxsKTogZmFsc2Uge1xuICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgZXZlbnQuc3RvcFByb3BhZ2F0aW9uKCk7XG4gICAgY2hpcHMuZm9yRWFjaCgoY2hpcCkgPT4gY2hpcC5hbmltYXRlKEZMQVNILCBGTEFTSF9NUykpO1xuXG4gICAgdGhpcy5jb25maWcuYmxvY2tlZCh7XG4gICAgICBjb3VudDogY2hpcHMubGVuZ3RoLFxuICAgICAgLi4uKHJhbmdlID8geyByZW1vdmVTZWxlY3Rpb246ICgpID0+IHRoaXMuX3JlbW92ZVJhbmdlKHJhbmdlKSB9IDoge30pLFxuICAgIH0pO1xuXG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG5cbiAgcHJpdmF0ZSBfcmVtb3ZlUmFuZ2UocmFuZ2U6IFJhbmdlKTogdm9pZCB7XG4gICAgaWYgKCF0aGlzLl9lZGl0b3IpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBjb25zdCBzZWxlY3Rpb24gPSB0aGlzLl9zZWxlY3Rpb24oKTtcbiAgICB0aGlzLl9lZGl0b3IuZWwuZm9jdXMoKTtcbiAgICBzZWxlY3Rpb24ucmVtb3ZlQWxsUmFuZ2VzKCk7XG4gICAgc2VsZWN0aW9uLmFkZFJhbmdlKHJhbmdlKTtcblxuICAgIHRoaXMuX2VkaXRvci51bmRvLnNhdmVTdGVwKCk7XG4gICAgdGhpcy5fcmVtb3ZpbmcgPSB0cnVlO1xuICAgIC8vIFRoZSBicm93c2VyJ3Mgb3duIGRlbGV0ZSwgc28gdHdvIHBhcmFncmFwaHMgYSBzZWxlY3Rpb24gc3BhbnMgam9pbiB0aGVcbiAgICAvLyB3YXkgdGhleSB3b3VsZCBmb3IgYSBwbGFpbiBEZWxldGUuXG4gICAgZG9jdW1lbnQuZXhlY0NvbW1hbmQoJ2RlbGV0ZScpO1xuICAgIHRoaXMuX3JlbW92aW5nID0gZmFsc2U7XG4gICAgdGhpcy5fY2hhbmdlZCgpO1xuICB9XG5cbiAgLy8gQW4gZWRpdCBtYWRlIGhlcmUgcmF0aGVyIHRoYW4gdHlwZWQ6IHJlY29yZCBpdCBmb3IgdW5kbywgYW5kIHRlbGxcbiAgLy8gaHRtbC1lZGl0b3Igc28gdGhlIGRyYWZ0IGZvbGxvd3MuXG4gIHByaXZhdGUgX2NoYW5nZWQoKTogdm9pZCB7XG4gICAgdGhpcy5fZWRpdG9yLnVuZG8uc2F2ZVN0ZXAoKTtcbiAgICB0aGlzLl9lZGl0b3IuZXZlbnRzLnRyaWdnZXIoJ2NvbnRlbnRDaGFuZ2VkJyk7XG4gIH1cblxuICBwcml2YXRlIF9zZWxlY3Rpb24oKTogU2VsZWN0aW9uIHtcbiAgICByZXR1cm4gdGhpcy5fZWRpdG9yLmVsLm93bmVyRG9jdW1lbnQuZ2V0U2VsZWN0aW9uKCk7XG4gIH1cblxuICAvLyBUaGUgc2VsZWN0aW9uLCB3aGVuIGl0IGlzIGluc2lkZSB0aGlzIGVkaXRvci5cbiAgcHJpdmF0ZSBfcmFuZ2UoKTogUmFuZ2UgfCBudWxsIHtcbiAgICBjb25zdCBzZWxlY3Rpb24gPSB0aGlzLl9lZGl0b3IgPyB0aGlzLl9zZWxlY3Rpb24oKSA6IG51bGw7XG4gICAgaWYgKCFzZWxlY3Rpb24/LnJhbmdlQ291bnQpIHtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cblxuICAgIGNvbnN0IHJhbmdlID0gc2VsZWN0aW9uLmdldFJhbmdlQXQoMCk7XG5cbiAgICByZXR1cm4gdGhpcy5fZWRpdG9yLmVsLmNvbnRhaW5zKHJhbmdlLmNvbW1vbkFuY2VzdG9yQ29udGFpbmVyKSA/IHJhbmdlIDogbnVsbDtcbiAgfVxuXG4gIHByaXZhdGUgX2NoaXBzSW4ocmFuZ2U6IFJhbmdlKTogSFRNTEVsZW1lbnRbXSB7XG4gICAgcmV0dXJuIHRoaXMuX2NoaXBzKCkuZmlsdGVyKChjaGlwKSA9PiByYW5nZS5pbnRlcnNlY3RzTm9kZShjaGlwKSk7XG4gIH1cblxuICAvLyBUaGUgY2hpcCBhIGNvbGxhcHNlZCBjdXJzb3Igd291bGQgZGVsZXRlIGludG86IHN0cmV0Y2ggdGhlIHNlbGVjdGlvbiBieVxuICAvLyB3aGF0IHRoZSBrZXkgZGVsZXRlcywgc2VlIHdoYXQgaXQgY292ZXJzLCBhbmQgcHV0IGl0IGJhY2suIExldHRpbmcgdGhlXG4gIC8vIGJyb3dzZXIgc3RyZXRjaCBpdCBoYW5kbGVzIGV2ZXJ5IHNoYXBlIHRoZSBodG1sIHRha2VzIOKAlCBhIGNoaXAgaW5zaWRlIGFcbiAgLy8gYm9sZCBzcGFuLCBhdCBhIGxpbmUncyBlbmQsIGJlc2lkZSBhbiBlbXB0eSB0ZXh0IG5vZGUuXG4gIHByaXZhdGUgX2FkamFjZW50Q2hpcChiYWNrd2FyZDogYm9vbGVhbiwgZ3JhbnVsYXJpdHk6IHN0cmluZyk6IEhUTUxFbGVtZW50IHwgbnVsbCB7XG4gICAgY29uc3Qgc2VsZWN0aW9uID0gdGhpcy5fc2VsZWN0aW9uKCk7XG4gICAgY29uc3QgcmFuZ2UgPSBzZWxlY3Rpb24uZ2V0UmFuZ2VBdCgwKS5jbG9uZVJhbmdlKCk7XG5cbiAgICBzZWxlY3Rpb24ubW9kaWZ5KCdleHRlbmQnLCBiYWNrd2FyZCA/ICdiYWNrd2FyZCcgOiAnZm9yd2FyZCcsIGdyYW51bGFyaXR5KTtcbiAgICBjb25zdCBjaGlwID0gc2VsZWN0aW9uLnJhbmdlQ291bnRcbiAgICAgID8gdGhpcy5fY2hpcHNJbihzZWxlY3Rpb24uZ2V0UmFuZ2VBdCgwKSlbMF0gPz8gbnVsbFxuICAgICAgOiBudWxsO1xuXG4gICAgc2VsZWN0aW9uLnJlbW92ZUFsbFJhbmdlcygpO1xuICAgIHNlbGVjdGlvbi5hZGRSYW5nZShyYW5nZSk7XG5cbiAgICByZXR1cm4gY2hpcDtcbiAgfVxuXG4gIC8vIEhvdyBmYXIgYSBkZWxldGluZyBrZXkgcmVhY2hlczogYSB3b3JkIHdpdGggQ3RybC9BbHQsIHRvIHRoZSBsaW5lJ3Mgc3RhcnRcbiAgLy8gd2l0aCBDbWQgb24gYSBNYWMsIG9uZSBjaGFyYWN0ZXIgb3RoZXJ3aXNlLlxuICBwcml2YXRlIF9ncmFudWxhcml0eShldmVudDogS2V5Ym9hcmRFdmVudCk6IHN0cmluZyB7XG4gICAgaWYgKGV2ZW50Lm1ldGFLZXkpIHtcbiAgICAgIHJldHVybiAnbGluZWJvdW5kYXJ5JztcbiAgICB9XG5cbiAgICByZXR1cm4gZXZlbnQuY3RybEtleSB8fCBldmVudC5hbHRLZXkgPyAnd29yZCcgOiAnY2hhcmFjdGVyJztcbiAgfVxufVxuIl19
|