@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.
Files changed (52) hide show
  1. package/app/reports/components/component-text/component-text.component.d.ts +47 -2
  2. package/app/reports/components/component-text/value-embed.plugin.d.ts +67 -0
  3. package/app/reports/components/report-canvas/report-canvas.component.d.ts +34 -9
  4. package/app/reports/components/report-component/report-component.component.d.ts +10 -1
  5. package/app/reports/data/report.data.d.ts +2 -1
  6. package/app/reports/dialogs/component-settings/component-settings.component.d.ts +8 -0
  7. package/app/reports/enums/report-value-formula.enum.d.ts +6 -0
  8. package/app/reports/export/report-export-collector.service.d.ts +24 -0
  9. package/app/reports/export/report-export.service.d.ts +3 -1
  10. package/app/reports/export/report-pdf.service.d.ts +18 -2
  11. package/app/reports/export/report-pptx.service.d.ts +15 -2
  12. package/app/reports/export/report-text-layout.service.d.ts +35 -0
  13. package/app/reports/format.d.ts +5 -1
  14. package/app/reports/interfaces/report.interface.d.ts +22 -3
  15. package/app/reports/layout.d.ts +2 -0
  16. package/app/reports/services/report-filter-state.service.d.ts +1 -1
  17. package/app/reports/text.d.ts +50 -0
  18. package/app/reports/theme/palette.d.ts +2 -0
  19. package/app/reports/values.d.ts +17 -0
  20. package/esm2022/app/reports/components/component-text/component-text.component.mjs +213 -16
  21. package/esm2022/app/reports/components/component-text/value-embed.plugin.mjs +484 -0
  22. package/esm2022/app/reports/components/report-canvas/report-canvas.component.mjs +260 -34
  23. package/esm2022/app/reports/components/report-component/report-component.component.mjs +65 -19
  24. package/esm2022/app/reports/data/report.data.mjs +19 -1
  25. package/esm2022/app/reports/dialogs/component-settings/component-settings.component.mjs +134 -23
  26. package/esm2022/app/reports/enums/report-value-formula.enum.mjs +14 -0
  27. package/esm2022/app/reports/export/report-export-collector.service.mjs +170 -44
  28. package/esm2022/app/reports/export/report-export.service.mjs +57 -19
  29. package/esm2022/app/reports/export/report-pdf.service.mjs +339 -96
  30. package/esm2022/app/reports/export/report-pptx.service.mjs +316 -88
  31. package/esm2022/app/reports/export/report-text-layout.service.mjs +241 -0
  32. package/esm2022/app/reports/format.mjs +41 -10
  33. package/esm2022/app/reports/interfaces/report.interface.mjs +1 -1
  34. package/esm2022/app/reports/kpi-card.mjs +19 -6
  35. package/esm2022/app/reports/layout.mjs +11 -1
  36. package/esm2022/app/reports/option-builder.mjs +18 -5
  37. package/esm2022/app/reports/output-notes.mjs +57 -11
  38. package/esm2022/app/reports/services/report-filter-state.service.mjs +19 -10
  39. package/esm2022/app/reports/text.mjs +293 -85
  40. package/esm2022/app/reports/theme/palette.mjs +7 -2
  41. package/esm2022/app/reports/values.mjs +183 -0
  42. package/esm2022/app/reports/views/report/fs-ai-report.component.mjs +4 -1
  43. package/esm2022/app/reports/views/report/report.component.mjs +4 -1
  44. package/esm2022/public_api.mjs +2 -1
  45. package/fesm2022/{firestitch-report-echarts-qCBE3LqM.mjs → firestitch-report-echarts-DBMOHmBF.mjs} +2 -2
  46. package/fesm2022/{firestitch-report-echarts-qCBE3LqM.mjs.map → firestitch-report-echarts-DBMOHmBF.mjs.map} +1 -1
  47. package/fesm2022/{firestitch-report-firestitch-report-DbsWbE-j.mjs → firestitch-report-firestitch-report-CqbXT1gh.mjs} +3492 -1028
  48. package/fesm2022/firestitch-report-firestitch-report-CqbXT1gh.mjs.map +1 -0
  49. package/fesm2022/firestitch-report.mjs +1 -1
  50. package/package.json +1 -1
  51. package/public_api.d.ts +1 -0
  52. package/fesm2022/firestitch-report-firestitch-report-DbsWbE-j.mjs.map +0 -1
@@ -0,0 +1,241 @@
1
+ import { ApplicationRef, EnvironmentInjector, Injectable, Injector, afterNextRender, createComponent, inject, } from '@angular/core';
2
+ import { ComponentTextComponent } from '../components/component-text/component-text.component';
3
+ import { PX_PER_INCH } from '../components/report-canvas/report-canvas.component';
4
+ import { componentPaddingCss } from '../layout';
5
+ import { fillTextTokens, parseTable, splitAtTables } from '../text';
6
+ import * as i0 from "@angular/core";
7
+ // How far past the bottom of its box a block may reach and still fit: two
8
+ // pixels, so the rounding of the last line's edge never counts as overflow.
9
+ // The deck keeps a table's row on the same terms.
10
+ export const OVERFLOW_SLACK = 2 / PX_PER_INCH;
11
+ // Where the canvas puts each part of a text block, for the exports. A
12
+ // browser wraps the words and sizes a table's columns by its own layout, which
13
+ // neither jsPDF nor PowerPoint reproduces. So the block is rendered offscreen
14
+ // with the canvas's own component, at the canvas's 96px per inch and unscaled,
15
+ // and the exports place what they draw where it sat: a table at its top, in
16
+ // its column widths and row heights, and the words between tables at theirs.
17
+ // It also tells whether the block runs past the bottom of its box.
18
+ //
19
+ // Provided beside the export services, so the block renders under the same
20
+ // injector the canvas's blocks do.
21
+ export class ReportTextLayoutService {
22
+ _appRef = inject(ApplicationRef);
23
+ _environmentInjector = inject(EnvironmentInjector);
24
+ _injector = inject(Injector);
25
+ _layouts = new Map();
26
+ // A block is measured once per size, padding and filled html: an export that
27
+ // draws it twice, or a second export with the same numbers, reads the same
28
+ // layout, which nothing changes.
29
+ async measure(component, tokens) {
30
+ const html = component.config?.html ?? '';
31
+ const key = [
32
+ component.id,
33
+ component.w,
34
+ component.h,
35
+ JSON.stringify(component.config?.padding ?? null),
36
+ fillTextTokens(html, tokens),
37
+ ].join('|');
38
+ let layout = this._layouts.get(key);
39
+ if (!layout) {
40
+ layout = this._render(component, html, tokens);
41
+ this._layouts.set(key, layout);
42
+ // A measure that failed is tried again next time.
43
+ layout.catch(() => this._layouts.delete(key));
44
+ }
45
+ return layout;
46
+ }
47
+ async _render(component, html, tokens) {
48
+ const text = createComponent(ComponentTextComponent, {
49
+ environmentInjector: this._environmentInjector,
50
+ elementInjector: this._injector,
51
+ });
52
+ const box = blockBox(component, text.location.nativeElement);
53
+ try {
54
+ text.setInput('html', html);
55
+ text.setInput('tokens', tokens);
56
+ text.setInput('editing', false);
57
+ document.body.append(box);
58
+ await this._rendered(text);
59
+ // Laid out first, so a font the words ask for is loading by the time
60
+ // fonts.ready is read.
61
+ box.getBoundingClientRect();
62
+ await document.fonts.ready;
63
+ return measureBlock(text.location.nativeElement.querySelector('.text-content'));
64
+ }
65
+ finally {
66
+ // Destroying the block also takes it off the application.
67
+ text.destroy();
68
+ box.remove();
69
+ }
70
+ }
71
+ // The block is rendered by the application's own change detection, as any
72
+ // view attached to it: its inputs mark it for the next render, which draws
73
+ // it before the callback runs. Not whenStable(): that also waits out
74
+ // whatever else the host app has under way (its requests and, under
75
+ // zone.js, its timers), and never resolves while a timer repeats.
76
+ _rendered(text) {
77
+ return new Promise((resolve) => {
78
+ afterNextRender(() => resolve(), { injector: this._environmentInjector });
79
+ this._appRef.attachView(text.hostView);
80
+ });
81
+ }
82
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ReportTextLayoutService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
83
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ReportTextLayoutService });
84
+ }
85
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ReportTextLayoutService, decorators: [{
86
+ type: Injectable
87
+ }] });
88
+ // The block's box as the canvas draws it (the component box): its size, a
89
+ // 1px border and the block's padding (componentPaddingCss) around a body the
90
+ // text fills. Fixed far off to the left, and hidden, so it is never seen.
91
+ function blockBox(component, text) {
92
+ const box = document.createElement('div');
93
+ const body = document.createElement('div');
94
+ Object.assign(box.style, {
95
+ position: 'fixed',
96
+ left: '-10000px',
97
+ top: '0',
98
+ visibility: 'hidden',
99
+ width: `${component.w * PX_PER_INCH}px`,
100
+ height: `${component.h * PX_PER_INCH}px`,
101
+ boxSizing: 'border-box',
102
+ border: '1px solid transparent',
103
+ padding: componentPaddingCss(component),
104
+ });
105
+ body.style.height = '100%';
106
+ body.append(text);
107
+ box.append(body);
108
+ return box;
109
+ }
110
+ // Split the rendered block at its tables, as textBlocks splits the same html,
111
+ // so the nth segment is the nth text part and the nth table the nth table
112
+ // part. How far the block reaches is the bottom of its last part that draws
113
+ // anything.
114
+ function measureBlock(content) {
115
+ const box = content.getBoundingClientRect();
116
+ const parts = splitAtTables(content);
117
+ const segments = [];
118
+ const tables = [];
119
+ let usedHeight = 0;
120
+ parts.forEach((part, index) => {
121
+ if (Array.isArray(part)) {
122
+ const segment = measureSegment(drawnNodes(part, index === parts.length - 1), box);
123
+ segments.push(segment);
124
+ usedHeight = segment?.bottom ?? usedHeight;
125
+ }
126
+ else {
127
+ const table = measureTable(part, box);
128
+ tables.push(table);
129
+ usedHeight = table.top + table.height;
130
+ }
131
+ });
132
+ const contentHeight = inches(box.height);
133
+ return {
134
+ contentWidth: inches(box.width),
135
+ contentHeight,
136
+ usedHeight,
137
+ overflow: usedHeight > contentHeight + OVERFLOW_SLACK,
138
+ segments,
139
+ tables,
140
+ };
141
+ }
142
+ // The nodes of a run between tables that the exports draw. Whitespace between
143
+ // blocks draws nothing anywhere. A blank line at the start of a block is
144
+ // drawn, on the canvas and by textBlocks alike, but textBlocks drops the blank
145
+ // lines at the very end of a block, so they are not measured either: a
146
+ // trailing empty paragraph never makes a block overflow.
147
+ function drawnNodes(nodes, blockEnd) {
148
+ const skipsLast = blockEnd ? isBlank : isVoid;
149
+ let start = 0;
150
+ let end = nodes.length;
151
+ while (start < end && isVoid(nodes[start])) {
152
+ start++;
153
+ }
154
+ while (end > start && skipsLast(nodes[end - 1])) {
155
+ end--;
156
+ }
157
+ const drawn = nodes.slice(start, end);
158
+ if (blockEnd && drawn.length) {
159
+ trimBlankLines(drawn[drawn.length - 1]);
160
+ }
161
+ return drawn;
162
+ }
163
+ // Take the blank lines off the end of the block's last node, as textBlocks
164
+ // drops them: the elements that hold no text after its last words, down its
165
+ // last children — the <br>s of <p>b<br><br></p>, a list's empty last item.
166
+ // Whitespace is passed over and left, so a paragraph never turns into an
167
+ // empty one, which the canvas draws as a line. The block is the measure's own
168
+ // copy, thrown away once measured, and nothing above what is taken off moves.
169
+ function trimBlankLines(node) {
170
+ let child = node.lastChild;
171
+ while (child && isBlank(child)) {
172
+ const previous = child.previousSibling;
173
+ if (!isVoid(child)) {
174
+ child.remove();
175
+ }
176
+ child = previous;
177
+ }
178
+ if (child) {
179
+ trimBlankLines(child);
180
+ }
181
+ }
182
+ // Whitespace between blocks, or a comment.
183
+ function isVoid(node) {
184
+ return node.nodeType === Node.TEXT_NODE
185
+ ? !/[^ \t\n\r\f]/.test(node.textContent ?? '')
186
+ : node.nodeType !== Node.ELEMENT_NODE;
187
+ }
188
+ // A node that draws no words: whitespace, or an element with no text in it,
189
+ // such as the empty line <p><br></p>.
190
+ function isBlank(node) {
191
+ return isVoid(node) || !node.textContent;
192
+ }
193
+ // From before its first node to after its last. null for a run that draws
194
+ // nothing.
195
+ function measureSegment(nodes, box) {
196
+ if (!nodes.length) {
197
+ return null;
198
+ }
199
+ const range = document.createRange();
200
+ range.setStartBefore(nodes[0]);
201
+ range.setEndAfter(nodes[nodes.length - 1]);
202
+ const rect = range.getBoundingClientRect();
203
+ return { top: inches(rect.top - box.top), bottom: inches(rect.bottom - box.top) };
204
+ }
205
+ function measureTable(table, box) {
206
+ const rect = table.getBoundingClientRect();
207
+ return {
208
+ top: inches(rect.top - box.top),
209
+ left: inches(rect.left - box.left),
210
+ width: inches(rect.width),
211
+ height: inches(rect.height),
212
+ rowHeights: Array.from(table.rows, (row) => inches(row.getBoundingClientRect().height)),
213
+ columnWidths: columnWidths(table, rect.width).map(inches),
214
+ };
215
+ }
216
+ // A grid column is as wide as a cell that spans only it. A column that only
217
+ // spanning cells cross shares what the others leave of the table's width, and
218
+ // all of them are scaled to add up to it exactly. The cells come in the same
219
+ // order as the grid's (parseTable reads the same rows), so the nth cell of a
220
+ // row is the nth cell of that grid row.
221
+ function columnWidths(table, width) {
222
+ const grid = parseTable(table);
223
+ const widths = Array.from({ length: grid.columns }, () => null);
224
+ grid.rows.forEach((row, rowIndex) => row.cells.forEach((cell, cellIndex) => {
225
+ if (cell.colSpan === 1 && widths[cell.column] === null) {
226
+ widths[cell.column] = table.rows[rowIndex].cells[cellIndex].getBoundingClientRect().width;
227
+ }
228
+ }));
229
+ const known = widths.filter((value) => value !== null);
230
+ const share = Math.max(0, width - sum(known)) / Math.max(1, widths.length - known.length);
231
+ const filled = widths.map((value) => value ?? share);
232
+ const total = sum(filled);
233
+ return filled.map((value) => total ? value * width / total : width / filled.length);
234
+ }
235
+ function sum(values) {
236
+ return values.reduce((total, value) => total + value, 0);
237
+ }
238
+ function inches(pixels) {
239
+ return pixels / PX_PER_INCH;
240
+ }
241
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVwb3J0LXRleHQtbGF5b3V0LnNlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9zcmMvYXBwL3JlcG9ydHMvZXhwb3J0L3JlcG9ydC10ZXh0LWxheW91dC5zZXJ2aWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFDTCxjQUFjLEVBQWdCLG1CQUFtQixFQUFFLFVBQVUsRUFBRSxRQUFRLEVBQUUsZUFBZSxFQUFFLGVBQWUsRUFBRSxNQUFNLEdBQ2xILE1BQU0sZUFBZSxDQUFDO0FBRXZCLE9BQU8sRUFBRSxzQkFBc0IsRUFBRSxNQUFNLHVEQUF1RCxDQUFDO0FBQy9GLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxxREFBcUQsQ0FBQztBQUVsRixPQUFPLEVBQUUsbUJBQW1CLEVBQUUsTUFBTSxXQUFXLENBQUM7QUFDaEQsT0FBTyxFQUFvQixjQUFjLEVBQUUsVUFBVSxFQUFFLGFBQWEsRUFBRSxNQUFNLFNBQVMsQ0FBQzs7QUF5Q3RGLDBFQUEwRTtBQUMxRSw0RUFBNEU7QUFDNUUsa0RBQWtEO0FBQ2xELE1BQU0sQ0FBQyxNQUFNLGNBQWMsR0FBRyxDQUFDLEdBQUcsV0FBVyxDQUFDO0FBRTlDLHNFQUFzRTtBQUN0RSwrRUFBK0U7QUFDL0UsOEVBQThFO0FBQzlFLCtFQUErRTtBQUMvRSw0RUFBNEU7QUFDNUUsNkVBQTZFO0FBQzdFLG1FQUFtRTtBQUNuRSxFQUFFO0FBQ0YsMkVBQTJFO0FBQzNFLG1DQUFtQztBQUVuQyxNQUFNLE9BQU8sdUJBQXVCO0lBRWpCLE9BQU8sR0FBRyxNQUFNLENBQUMsY0FBYyxDQUFDLENBQUM7SUFDakMsb0JBQW9CLEdBQUcsTUFBTSxDQUFDLG1CQUFtQixDQUFDLENBQUM7SUFDbkQsU0FBUyxHQUFHLE1BQU0sQ0FBQyxRQUFRLENBQUMsQ0FBQztJQUM3QixRQUFRLEdBQUcsSUFBSSxHQUFHLEVBQW9DLENBQUM7SUFFeEUsNkVBQTZFO0lBQzdFLDJFQUEy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QUMsQ0FBQyxLQUFLLEdBQUcsS0FBSyxHQUFHLEtBQUssQ0FBQyxDQUFDLENBQUMsS0FBSyxHQUFHLE1BQU0sQ0FBQyxNQUFNLENBQUMsQ0FBQztBQUN0RixDQUFDO0FBRUQsU0FBUyxHQUFHLENBQUMsTUFBZ0I7SUFDM0IsT0FBTyxNQUFNLENBQUMsTUFBTSxDQUFDLENBQUMsS0FBSyxFQUFFLEtBQUssRUFBRSxFQUFFLENBQUMsS0FBSyxHQUFHLEtBQUssRUFBRSxDQUFDLENBQUMsQ0FBQztBQUMzRCxDQUFDO0FBRUQsU0FBUyxNQUFNLENBQUMsTUFBYztJQUM1QixPQUFPLE1BQU0sR0FBRyxXQUFXLENBQUM7QUFDOUIsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XG4gIEFwcGxpY2F0aW9uUmVmLCBDb21wb25lbnRSZWYsIEVudmlyb25tZW50SW5qZWN0b3IsIEluamVjdGFibGUsIEluamVjdG9yLCBhZnRlck5leHRSZW5kZXIsIGNyZWF0ZUNvbXBvbmVudCwgaW5qZWN0LFxufSBmcm9tICdAYW5ndWxhci9jb3JlJztcblxuaW1wb3J0IHsgQ29tcG9uZW50VGV4dENvbXBvbmVudCB9IGZyb20gJy4uL2NvbXBvbmVudHMvY29tcG9uZW50LXRleHQvY29tcG9uZW50LXRleHQuY29tcG9uZW50JztcbmltcG9ydCB7IFBYX1BFUl9JTkNIIH0gZnJvbSAnLi4vY29tcG9uZW50cy9yZXBvcnQtY2FudmFzL3JlcG9ydC1jYW52YXMuY29tcG9uZW50JztcbmltcG9ydCB7IFJlcG9ydENvbXBvbmVudCB9IGZyb20gJy4uL2ludGVyZmFjZXMvcmVwb3J0LmludGVyZmFjZSc7XG5pbXBvcnQgeyBjb21wb25lbnRQYWRkaW5nQ3NzIH0gZnJvbSAnLi4vbGF5b3V0JztcbmltcG9ydCB7IFRleHRUb2tlbkNvbnRleHQsIGZpbGxUZXh0VG9rZW5zLCBwYXJzZVRhYmxlLCBzcGxpdEF0VGFibGVzIH0gZnJvbSAnLi4vdGV4dCc7XG5cblxuLy8gV2hlcmUgYSBzdHJldGNoIG9mIGEgYmxvY2sncyB3b3JkcyBzaXRzOiB0aGUgdG9wIG9mIGl0cyBmaXJzdCBsaW5lIGFuZCB0aGVcbi8vIGJvdHRvbSBvZiBpdHMgbGFzdC5cbmV4cG9ydCBpbnRlcmZhY2UgVGV4dFNlZ21lbnRMYXlvdXQge1xuICB0b3A6IG51bWJlcjtcbiAgYm90dG9tOiBudW1iZXI7XG59XG5cbi8vIFdoZXJlIGEgdGFibGUgc2l0cyBpbiBpdHMgYmxvY2ssIGFuZCBob3cgdGFsbCBpdHMgcm93cyBhbmQgaG93IHdpZGUgaXRzXG4vLyBjb2x1bW5zIGFyZS5cbmV4cG9ydCBpbnRlcmZhY2UgVGV4dFRhYmxlTGF5b3V0IHtcbiAgdG9wOiBudW1iZXI7XG4gIGxlZnQ6IG51bWJlcjtcbiAgd2lkdGg6IG51bWJlcjtcbiAgaGVpZ2h0OiBudW1iZXI7XG4gIC8vIEEgcm93J3MgaGVpZ2h0LCBpbiB0aGUgb3JkZXIgdGV4dEJsb2NrcyBsaXN0cyB0aGUgcm93czogdGhlIGhlYWQgZmlyc3QgYW5kXG4gIC8vIHRoZSBmb290IGxhc3QuXG4gIHJvd0hlaWdodHM6IG51bWJlcltdO1xuICAvLyBBIGdyaWQgY29sdW1uJ3Mgd2lkdGggKHRhYmxlR3JpZCksIGxlZnQgdG8gcmlnaHQuIFRvZ2V0aGVyIHRoZXkgYXJlIHRoZVxuICAvLyB0YWJsZSdzIHdpZHRoLlxuICBjb2x1bW5XaWR0aHM6IG51bWJlcltdO1xufVxuXG4vLyBBIHRleHQgYmxvY2sgYXMgdGhlIGNhbnZhcyBsYXlzIGl0IG91dC4gRXZlcnl0aGluZyBpcyBpbiBpbmNoZXMsIG1lYXN1cmVkXG4vLyBmcm9tIHRoZSB0b3AgbGVmdCBvZiB0aGUgYmxvY2sncyBjb250ZW50IGJveCAoaW5zaWRlIGl0cyBwYWRkaW5nKS5cbmV4cG9ydCBpbnRlcmZhY2UgVGV4dEJsb2NrTGF5b3V0IHtcbiAgY29udGVudFdpZHRoOiBudW1iZXI7XG4gIGNvbnRlbnRIZWlnaHQ6IG51bWJlcjtcbiAgLy8gSG93IGZhciBkb3duIHRoZSBibG9jaydzIHdvcmRzIGFuZCB0YWJsZXMgcmVhY2guXG4gIHVzZWRIZWlnaHQ6IG51bWJlcjtcbiAgLy8gVGhleSByZWFjaCBwYXN0IHRoZSBib3R0b20gb2YgdGhlIGJveCwgd2hlcmUgdGhlIGNhbnZhcyBjdXRzIHRoZW0gb2ZmLlxuICBvdmVyZmxvdzogYm9vbGVhbjtcbiAgLy8gT25lIHBlciB0ZXh0IHBhcnQgb2YgdGV4dEJsb2NrcywgaW4gb3JkZXI6IG51bGwgZm9yIGEgcGFydCB0aGF0IGRyYXdzXG4gIC8vIG5vdGhpbmcuXG4gIHNlZ21lbnRzOiAoVGV4dFNlZ21lbnRMYXlvdXQgfCBudWxsKVtdO1xuICAvLyBPbmUgcGVyIHRhYmxlIHBhcnQgb2YgdGV4dEJsb2NrcywgaW4gb3JkZXIuXG4gIHRhYmxlczogVGV4dFRhYmxlTGF5b3V0W107XG59XG5cbi8vIEhvdyBmYXIgcGFzdCB0aGUgYm90dG9tIG9mIGl0cyBib3ggYSBibG9jayBtYXkgcmVhY2ggYW5kIHN0aWxsIGZpdDogdHdvXG4vLyBwaXhlbHMsIHNvIHRoZSByb3VuZGluZyBvZiB0aGUgbGFzdCBsaW5lJ3MgZWRnZSBuZXZlciBjb3VudHMgYXMgb3ZlcmZsb3cuXG4vLyBUaGUgZGVjayBrZWVwcyBhIHRhYmxlJ3Mgcm93IG9uIHRoZSBzYW1lIHRlcm1zLlxuZXhwb3J0IGNvbnN0IE9WRVJGTE9XX1NMQUNLID0gMiAvIFBYX1BFUl9JTkNIO1xuXG4vLyBXaGVyZSB0aGUgY2FudmFzIHB1dHMgZWFjaCBwYXJ0IG9mIGEgdGV4dCBibG9jaywgZm9yIHRoZSBleHBvcnRzLiBBXG4vLyBicm93c2VyIHdyYXBzIHRoZSB3b3JkcyBhbmQgc2l6ZXMgYSB0YWJsZSdzIGNvbHVtbnMgYnkgaXRzIG93biBsYXlvdXQsIHdoaWNoXG4vLyBuZWl0aGVyIGpzUERGIG5vciBQb3dlclBvaW50IHJlcHJvZHVjZXMuIFNvIHRoZSBibG9jayBpcyByZW5kZXJlZCBvZmZzY3JlZW5cbi8vIHdpdGggdGhlIGNhbnZhcydzIG93biBjb21wb25lbnQsIGF0IHRoZSBjYW52YXMncyA5NnB4IHBlciBpbmNoIGFuZCB1bnNjYWxlZCxcbi8vIGFuZCB0aGUgZXhwb3J0cyBwbGFjZSB3aGF0IHRoZXkgZHJhdyB3aGVyZSBpdCBzYXQ6IGEgdGFibGUgYXQgaXRzIHRvcCwgaW5cbi8vIGl0cyBjb2x1bW4gd2lkdGhzIGFuZCByb3cgaGVpZ2h0cywgYW5kIHRoZSB3b3JkcyBiZXR3ZWVuIHRhYmxlcyBhdCB0aGVpcnMuXG4vLyBJdCBhbHNvIHRlbGxzIHdoZXRoZXIgdGhlIGJsb2NrIHJ1bnMgcGFzdCB0aGUgYm90dG9tIG9mIGl0cyBib3guXG4vL1xuLy8gUHJvdmlkZWQgYmVzaWRlIHRoZSBleHBvcnQgc2VydmljZXMsIHNvIHRoZSBibG9jayByZW5kZXJzIHVuZGVyIHRoZSBzYW1lXG4vLyBpbmplY3RvciB0aGUgY2FudmFzJ3MgYmxvY2tzIGRvLlxuQEluamVjdGFibGUoKVxuZXhwb3J0IGNsYXNzIFJlcG9ydFRleHRMYXlvdXRTZXJ2aWNlIHtcblxuICBwcml2YXRlIHJlYWRvbmx5IF9hcHBSZWYgPSBpbmplY3QoQXBwbGljYXRpb25SZWYpO1xuICBwcml2YXRlIHJlYWRvbmx5IF9lbnZpcm9ubWVudEluamVjdG9yID0gaW5qZWN0KEVudmlyb25tZW50SW5qZWN0b3IpO1xuICBwcml2YXRlIHJlYWRvbmx5IF9pbmplY3RvciA9IGluamVjdChJbmplY3Rvcik7XG4gIHByaXZhdGUgcmVhZG9ubHkgX2xheW91dHMgPSBuZXcgTWFwPHN0cmluZywgUHJvbWlzZTxUZXh0QmxvY2tMYXlvdXQ+PigpO1xuXG4gIC8vIEEgYmxvY2sgaXMgbWVhc3VyZWQgb25jZSBwZXIgc2l6ZSwgcGFkZGluZyBhbmQgZmlsbGVkIGh0bWw6IGFuIGV4cG9ydCB0aGF0XG4gIC8vIGRyYXdzIGl0IHR3aWNlLCBvciBhIHNlY29uZCBleHBvcnQgd2l0aCB0aGUgc2FtZSBudW1iZXJzLCByZWFkcyB0aGUgc2FtZVxuICAvLyBsYXlvdXQsIHdoaWNoIG5vdGhpbmcgY2hhbmdlcy5cbiAgcHVibGljIGFzeW5jIG1lYXN1cmUoY29tcG9uZW50OiBSZXBvcnRDb21wb25lbnQsIHRva2VuczogVGV4dFRva2VuQ29udGV4dCk6IFByb21pc2U8VGV4dEJsb2NrTGF5b3V0PiB7XG4gICAgY29uc3QgaHRtbCA9IGNvbXBvbmVudC5jb25maWc/Lmh0bWwgPz8gJyc7XG4gICAgY29uc3Qga2V5ID0gW1xuICAgICAgY29tcG9uZW50LmlkLFxuICAgICAgY29tcG9uZW50LncsXG4gICAgICBjb21wb25lbnQuaCxcbiAgICAgIEpTT04uc3RyaW5naWZ5KGNvbXBvbmVudC5jb25maWc/LnBhZGRpbmcgPz8gbnVsbCksXG4gICAgICBmaWxsVGV4dFRva2VucyhodG1sLCB0b2tlbnMpLFxuICAgIF0uam9pbignfCcpO1xuXG4gICAgbGV0IGxheW91dCA9IHRoaXMuX2xheW91dHMuZ2V0KGtleSk7XG4gICAgaWYgKCFsYXlvdXQpIHtcbiAgICAgIGxheW91dCA9IHRoaXMuX3JlbmRlcihjb21wb25lbnQsIGh0bWwsIHRva2Vucyk7XG4gICAgICB0aGlzLl9sYXlvdXRzLnNldChrZXksIGxheW91dCk7XG4gICAgICAvLyBBIG1lYXN1cmUgdGhhdCBmYWlsZWQgaXMgdHJpZWQgYWdhaW4gbmV4dCB0aW1lLlxuICAgICAgbGF5b3V0LmNhdGNoKCgpID0+IHRoaXMuX2xheW91dHMuZGVsZXRlKGtleSkpO1xuICAgIH1cblxuICAgIHJldHVybiBsYXlvdXQ7XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIF9yZW5kZXIoY29tcG9uZW50OiBSZXBvcnRDb21wb25lbnQsIGh0bWw6IHN0cmluZywgdG9rZW5zOiBUZXh0VG9rZW5Db250ZXh0KTogUHJvbWlzZTxUZXh0QmxvY2tMYXlvdXQ+IHtcbiAgICBjb25zdCB0ZXh0ID0gY3JlYXRlQ29tcG9uZW50KENvbXBvbmVudFRleHRDb21wb25lbnQsIHtcbiAgICAgIGVudmlyb25tZW50SW5qZWN0b3I6IHRoaXMuX2Vudmlyb25tZW50SW5qZWN0b3IsXG4gICAgICBlbGVtZW50SW5qZWN0b3I6IHRoaXMuX2luamVjdG9yLFxuICAgIH0pO1xuICAgIGNvbnN0IGJveCA9IGJsb2NrQm94KGNvbXBvbmVudCwgdGV4dC5sb2NhdGlvbi5uYXRpdmVFbGVtZW50KTtcblxuICAgIHRyeSB7XG4gICAgICB0ZXh0LnNldElucHV0KCdodG1sJywgaHRtbCk7XG4gICAgICB0ZXh0LnNldElucHV0KCd0b2tlbnMnLCB0b2tlbnMpO1xuICAgICAgdGV4dC5zZXRJbnB1dCgnZWRpdGluZycsIGZhbHNlKTtcbiAgICAgIGRvY3VtZW50LmJvZHkuYXBwZW5kKGJveCk7XG4gICAgICBhd2FpdCB0aGlzLl9yZW5kZXJlZCh0ZXh0KTtcbiAgICAgIC8vIExhaWQgb3V0IGZpcnN0LCBzbyBhIGZvbnQgdGhlIHdvcmRzIGFzayBmb3IgaXMgbG9hZGluZyBieSB0aGUgdGltZVxuICAgICAgLy8gZm9udHMucmVhZHkgaXMgcmVhZC5cbiAgICAgIGJveC5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtcbiAgICAgIGF3YWl0IGRvY3VtZW50LmZvbnRzLnJlYWR5O1xuXG4gICAgICByZXR1cm4gbWVhc3VyZUJsb2NrKHRleHQubG9jYXRpb24ubmF0aXZlRWxlbWVudC5xdWVyeVNlbGVjdG9yKCcudGV4dC1jb250ZW50JykpO1xuICAgIH0gZmluYWxseSB7XG4gICAgICAvLyBEZXN0cm95aW5nIHRoZSBibG9jayBhbHNvIHRha2VzIGl0IG9mZiB0aGUgYXBwbGljYXRpb24uXG4gICAgICB0ZXh0LmRlc3Ryb3koKTtcbiAgICAgIGJveC5yZW1vdmUoKTtcbiAgICB9XG4gIH1cblxuICAvLyBUaGUgYmxvY2sgaXMgcmVuZGVyZWQgYnkgdGhlIGFwcGxpY2F0aW9uJ3Mgb3duIGNoYW5nZSBkZXRlY3Rpb24sIGFzIGFueVxuICAvLyB2aWV3IGF0dGFjaGVkIHRvIGl0OiBpdHMgaW5wdXRzIG1hcmsgaXQgZm9yIHRoZSBuZXh0IHJlbmRlciwgd2hpY2ggZHJhd3NcbiAgLy8gaXQgYmVmb3JlIHRoZSBjYWxsYmFjayBydW5zLiBOb3Qgd2hlblN0YWJsZSgpOiB0aGF0IGFsc28gd2FpdHMgb3V0XG4gIC8vIHdoYXRldmVyIGVsc2UgdGhlIGhvc3QgYXBwIGhhcyB1bmRlciB3YXkgKGl0cyByZXF1ZXN0cyBhbmQsIHVuZGVyXG4gIC8vIHpvbmUuanMsIGl0cyB0aW1lcnMpLCBhbmQgbmV2ZXIgcmVzb2x2ZXMgd2hpbGUgYSB0aW1lciByZXBlYXRzLlxuICBwcml2YXRlIF9yZW5kZXJlZCh0ZXh0OiBDb21wb25lbnRSZWY8Q29tcG9uZW50VGV4dENvbXBvbmVudD4pOiBQcm9taXNlPHZvaWQ+IHtcbiAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUpID0+IHtcbiAgICAgIGFmdGVyTmV4dFJlbmRlcigoKSA9PiByZXNvbHZlKCksIHsgaW5qZWN0b3I6IHRoaXMuX2Vudmlyb25tZW50SW5qZWN0b3IgfSk7XG4gICAgICB0aGlzLl9hcHBSZWYuYXR0YWNoVmlldyh0ZXh0Lmhvc3RWaWV3KTtcbiAgICB9KTtcbiAgfVxufVxuXG4vLyBUaGUgYmxvY2sncyBib3ggYXMgdGhlIGNhbnZhcyBkcmF3cyBpdCAodGhlIGNvbXBvbmVudCBib3gpOiBpdHMgc2l6ZSwgYVxuLy8gMXB4IGJvcmRlciBhbmQgdGhlIGJsb2NrJ3MgcGFkZGluZyAoY29tcG9uZW50UGFkZGluZ0NzcykgYXJvdW5kIGEgYm9keSB0aGVcbi8vIHRleHQgZmlsbHMuIEZpeGVkIGZhciBvZmYgdG8gdGhlIGxlZnQsIGFuZCBoaWRkZW4sIHNvIGl0IGlzIG5ldmVyIHNlZW4uXG5mdW5jdGlvbiBibG9ja0JveChjb21wb25lbnQ6IFJlcG9ydENvbXBvbmVudCwgdGV4dDogSFRNTEVsZW1lbnQpOiBIVE1MRWxlbWVudCB7XG4gIGNvbnN0IGJveCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2RpdicpO1xuICBjb25zdCBib2R5ID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnZGl2Jyk7XG5cbiAgT2JqZWN0LmFzc2lnbihib3guc3R5bGUsIHtcbiAgICBwb3NpdGlvbjogJ2ZpeGVkJyxcbiAgICBsZWZ0OiAnLTEwMDAwcHgnLFxuICAgIHRvcDogJzAnLFxuICAgIHZpc2liaWxpdHk6ICdoaWRkZW4nLFxuICAgIHdpZHRoOiBgJHtjb21wb25lbnQudyAqIFBYX1BFUl9JTkNIfXB4YCxcbiAgICBoZWlnaHQ6IGAke2NvbXBvbmVudC5oICogUFhfUEVSX0lOQ0h9cHhgLFxuICAgIGJveFNpemluZzogJ2JvcmRlci1ib3gnLFxuICAgIGJvcmRlcjogJzFweCBzb2xpZCB0cmFuc3BhcmVudCcsXG4gICAgcGFkZGluZzogY29tcG9uZW50UGFkZGluZ0Nzcyhjb21wb25lbnQpLFxuICB9KTtcbiAgYm9keS5zdHlsZS5oZWlnaHQgPSAnMTAwJSc7XG4gIGJvZHkuYXBwZW5kKHRleHQpO1xuICBib3guYXBwZW5kKGJvZHkpO1xuXG4gIHJldHVybiBib3g7XG59XG5cbi8vIFNwbGl0IHRoZSByZW5kZXJlZCBibG9jayBhdCBpdHMgdGFibGVzLCBhcyB0ZXh0QmxvY2tzIHNwbGl0cyB0aGUgc2FtZSBodG1sLFxuLy8gc28gdGhlIG50aCBzZWdtZW50IGlzIHRoZSBudGggdGV4dCBwYXJ0IGFuZCB0aGUgbnRoIHRhYmxlIHRoZSBudGggdGFibGVcbi8vIHBhcnQuIEhvdyBmYXIgdGhlIGJsb2NrIHJlYWNoZXMgaXMgdGhlIGJvdHRvbSBvZiBpdHMgbGFzdCBwYXJ0IHRoYXQgZHJhd3Ncbi8vIGFueXRoaW5nLlxuZnVuY3Rpb24gbWVhc3VyZUJsb2NrKGNvbnRlbnQ6IEhUTUxFbGVtZW50KTogVGV4dEJsb2NrTGF5b3V0IHtcbiAgY29uc3QgYm94ID0gY29udGVudC5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtcbiAgY29uc3QgcGFydHMgPSBzcGxpdEF0VGFibGVzKGNvbnRlbnQpO1xuICBjb25zdCBzZWdtZW50czogKFRleHRTZWdtZW50TGF5b3V0IHwgbnVsbClbXSA9IFtdO1xuICBjb25zdCB0YWJsZXM6IFRleHRUYWJsZUxheW91dFtdID0gW107XG4gIGxldCB1c2VkSGVpZ2h0ID0gMDtcblxuICBwYXJ0cy5mb3JFYWNoKChwYXJ0LCBpbmRleCkgPT4ge1xuICAgIGlmIChBcnJheS5pc0FycmF5KHBhcnQpKSB7XG4gICAgICBjb25zdCBzZWdtZW50ID0gbWVhc3VyZVNlZ21lbnQoZHJhd25Ob2RlcyhwYXJ0LCBpbmRleCA9PT0gcGFydHMubGVuZ3RoIC0gMSksIGJveCk7XG4gICAgICBzZWdtZW50cy5wdXNoKHNlZ21lbnQpO1xuICAgICAgdXNlZEhlaWdodCA9IHNlZ21lbnQ/LmJvdHRvbSA/PyB1c2VkSGVpZ2h0O1xuICAgIH0gZWxzZSB7XG4gICAgICBjb25zdCB0YWJsZSA9IG1lYXN1cmVUYWJsZShwYXJ0LCBib3gpO1xuICAgICAgdGFibGVzLnB1c2godGFibGUpO1xuICAgICAgdXNlZEhlaWdodCA9IHRhYmxlLnRvcCArIHRhYmxlLmhlaWdodDtcbiAgICB9XG4gIH0pO1xuXG4gIGNvbnN0IGNvbnRlbnRIZWlnaHQgPSBpbmNoZXMoYm94LmhlaWdodCk7XG5cbiAgcmV0dXJuIHtcbiAgICBjb250ZW50V2lkdGg6IGluY2hlcyhib3gud2lkdGgpLFxuICAgIGNvbnRlbnRIZWlnaHQsXG4gICAgdXNlZEhlaWdodCxcbiAgICBvdmVyZmxvdzogdXNlZEhlaWdodCA+IGNvbnRlbnRIZWlnaHQgKyBPVkVSRkxPV19TTEFDSyxcbiAgICBzZWdtZW50cyxcbiAgICB0YWJsZXMsXG4gIH07XG59XG5cbi8vIFRoZSBub2RlcyBvZiBhIHJ1biBiZXR3ZWVuIHRhYmxlcyB0aGF0IHRoZSBleHBvcnRzIGRyYXcuIFdoaXRlc3BhY2UgYmV0d2VlblxuLy8gYmxvY2tzIGRyYXdzIG5vdGhpbmcgYW55d2hlcmUuIEEgYmxhbmsgbGluZSBhdCB0aGUgc3RhcnQgb2YgYSBibG9jayBpc1xuLy8gZHJhd24sIG9uIHRoZSBjYW52YXMgYW5kIGJ5IHRleHRCbG9ja3MgYWxpa2UsIGJ1dCB0ZXh0QmxvY2tzIGRyb3BzIHRoZSBibGFua1xuLy8gbGluZXMgYXQgdGhlIHZlcnkgZW5kIG9mIGEgYmxvY2ssIHNvIHRoZXkgYXJlIG5vdCBtZWFzdXJlZCBlaXRoZXI6IGFcbi8vIHRyYWlsaW5nIGVtcHR5IHBhcmFncmFwaCBuZXZlciBtYWtlcyBhIGJsb2NrIG92ZXJmbG93LlxuZnVuY3Rpb24gZHJhd25Ob2Rlcyhub2RlczogTm9kZVtdLCBibG9ja0VuZDogYm9vbGVhbik6IE5vZGVbXSB7XG4gIGNvbnN0IHNraXBzTGFzdCA9IGJsb2NrRW5kID8gaXNCbGFuayA6IGlzVm9pZDtcbiAgbGV0IHN0YXJ0ID0gMDtcbiAgbGV0IGVuZCA9IG5vZGVzLmxlbmd0aDtcblxuICB3aGlsZSAoc3RhcnQgPCBlbmQgJiYgaXNWb2lkKG5vZGVzW3N0YXJ0XSkpIHtcbiAgICBzdGFydCsrO1xuICB9XG4gIHdoaWxlIChlbmQgPiBzdGFydCAmJiBza2lwc0xhc3Qobm9kZXNbZW5kIC0gMV0pKSB7XG4gICAgZW5kLS07XG4gIH1cblxuICBjb25zdCBkcmF3biA9IG5vZGVzLnNsaWNlKHN0YXJ0LCBlbmQpO1xuICBpZiAoYmxvY2tFbmQgJiYgZHJhd24ubGVuZ3RoKSB7XG4gICAgdHJpbUJsYW5rTGluZXMoZHJhd25bZHJhd24ubGVuZ3RoIC0gMV0pO1xuICB9XG5cbiAgcmV0dXJuIGRyYXduO1xufVxuXG4vLyBUYWtlIHRoZSBibGFuayBsaW5lcyBvZmYgdGhlIGVuZCBvZiB0aGUgYmxvY2sncyBsYXN0IG5vZGUsIGFzIHRleHRCbG9ja3Ncbi8vIGRyb3BzIHRoZW06IHRoZSBlbGVtZW50cyB0aGF0IGhvbGQgbm8gdGV4dCBhZnRlciBpdHMgbGFzdCB3b3JkcywgZG93biBpdHNcbi8vIGxhc3QgY2hpbGRyZW4g4oCUIHRoZSA8YnI+cyBvZiA8cD5iPGJyPjxicj48L3A+LCBhIGxpc3QncyBlbXB0eSBsYXN0IGl0ZW0uXG4vLyBXaGl0ZXNwYWNlIGlzIHBhc3NlZCBvdmVyIGFuZCBsZWZ0LCBzbyBhIHBhcmFncmFwaCBuZXZlciB0dXJucyBpbnRvIGFuXG4vLyBlbXB0eSBvbmUsIHdoaWNoIHRoZSBjYW52YXMgZHJhd3MgYXMgYSBsaW5lLiBUaGUgYmxvY2sgaXMgdGhlIG1lYXN1cmUncyBvd25cbi8vIGNvcHksIHRocm93biBhd2F5IG9uY2UgbWVhc3VyZWQsIGFuZCBub3RoaW5nIGFib3ZlIHdoYXQgaXMgdGFrZW4gb2ZmIG1vdmVzLlxuZnVuY3Rpb24gdHJpbUJsYW5rTGluZXMobm9kZTogTm9kZSk6IHZvaWQge1xuICBsZXQgY2hpbGQgPSBub2RlLmxhc3RDaGlsZDtcbiAgd2hpbGUgKGNoaWxkICYmIGlzQmxhbmsoY2hpbGQpKSB7XG4gICAgY29uc3QgcHJldmlvdXMgPSBjaGlsZC5wcmV2aW91c1NpYmxpbmc7XG4gICAgaWYgKCFpc1ZvaWQoY2hpbGQpKSB7XG4gICAgICBjaGlsZC5yZW1vdmUoKTtcbiAgICB9XG4gICAgY2hpbGQgPSBwcmV2aW91cztcbiAgfVxuXG4gIGlmIChjaGlsZCkge1xuICAgIHRyaW1CbGFua0xpbmVzKGNoaWxkKTtcbiAgfVxufVxuXG4vLyBXaGl0ZXNwYWNlIGJldHdlZW4gYmxvY2tzLCBvciBhIGNvbW1lbnQuXG5mdW5jdGlvbiBpc1ZvaWQobm9kZTogTm9kZSk6IGJvb2xlYW4ge1xuICByZXR1cm4gbm9kZS5ub2RlVHlwZSA9PT0gTm9kZS5URVhUX05PREVcbiAgICA/ICEvW14gXFx0XFxuXFxyXFxmXS8udGVzdChub2RlLnRleHRDb250ZW50ID8/ICcnKVxuICAgIDogbm9kZS5ub2RlVHlwZSAhPT0gTm9kZS5FTEVNRU5UX05PREU7XG59XG5cbi8vIEEgbm9kZSB0aGF0IGRyYXdzIG5vIHdvcmRzOiB3aGl0ZXNwYWNlLCBvciBhbiBlbGVtZW50IHdpdGggbm8gdGV4dCBpbiBpdCxcbi8vIHN1Y2ggYXMgdGhlIGVtcHR5IGxpbmUgPHA+PGJyPjwvcD4uXG5mdW5jdGlvbiBpc0JsYW5rKG5vZGU6IE5vZGUpOiBib29sZWFuIHtcbiAgcmV0dXJuIGlzVm9pZChub2RlKSB8fCAhbm9kZS50ZXh0Q29udGVudDtcbn1cblxuLy8gRnJvbSBiZWZvcmUgaXRzIGZpcnN0IG5vZGUgdG8gYWZ0ZXIgaXRzIGxhc3QuIG51bGwgZm9yIGEgcnVuIHRoYXQgZHJhd3Ncbi8vIG5vdGhpbmcuXG5mdW5jdGlvbiBtZWFzdXJlU2VnbWVudChub2RlczogTm9kZVtdLCBib3g6IERPTVJlY3QpOiBUZXh0U2VnbWVudExheW91dCB8IG51bGwge1xuICBpZiAoIW5vZGVzLmxlbmd0aCkge1xuICAgIHJldHVybiBudWxsO1xuICB9XG5cbiAgY29uc3QgcmFuZ2UgPSBkb2N1bWVudC5jcmVhdGVSYW5nZSgpO1xuICByYW5nZS5zZXRTdGFydEJlZm9yZShub2Rlc1swXSk7XG4gIHJhbmdlLnNldEVuZEFmdGVyKG5vZGVzW25vZGVzLmxlbmd0aCAtIDFdKTtcbiAgY29uc3QgcmVjdCA9IHJhbmdlLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xuXG4gIHJldHVybiB7IHRvcDogaW5jaGVzKHJlY3QudG9wIC0gYm94LnRvcCksIGJvdHRvbTogaW5jaGVzKHJlY3QuYm90dG9tIC0gYm94LnRvcCkgfTtcbn1cblxuZnVuY3Rpb24gbWVhc3VyZVRhYmxlKHRhYmxlOiBIVE1MVGFibGVFbGVtZW50LCBib3g6IERPTVJlY3QpOiBUZXh0VGFibGVMYXlvdXQge1xuICBjb25zdCByZWN0ID0gdGFibGUuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XG5cbiAgcmV0dXJuIHtcbiAgICB0b3A6IGluY2hlcyhyZWN0LnRvcCAtIGJveC50b3ApLFxuICAgIGxlZnQ6IGluY2hlcyhyZWN0LmxlZnQgLSBib3gubGVmdCksXG4gICAgd2lkdGg6IGluY2hlcyhyZWN0LndpZHRoKSxcbiAgICBoZWlnaHQ6IGluY2hlcyhyZWN0LmhlaWdodCksXG4gICAgcm93SGVpZ2h0czogQXJyYXkuZnJvbSh0YWJsZS5yb3dzLCAocm93KSA9PiBpbmNoZXMocm93LmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpLmhlaWdodCkpLFxuICAgIGNvbHVtbldpZHRoczogY29sdW1uV2lkdGhzKHRhYmxlLCByZWN0LndpZHRoKS5tYXAoaW5jaGVzKSxcbiAgfTtcbn1cblxuLy8gQSBncmlkIGNvbHVtbiBpcyBhcyB3aWRlIGFzIGEgY2VsbCB0aGF0IHNwYW5zIG9ubHkgaXQuIEEgY29sdW1uIHRoYXQgb25seVxuLy8gc3Bhbm5pbmcgY2VsbHMgY3Jvc3Mgc2hhcmVzIHdoYXQgdGhlIG90aGVycyBsZWF2ZSBvZiB0aGUgdGFibGUncyB3aWR0aCwgYW5kXG4vLyBhbGwgb2YgdGhlbSBhcmUgc2NhbGVkIHRvIGFkZCB1cCB0byBpdCBleGFjdGx5LiBUaGUgY2VsbHMgY29tZSBpbiB0aGUgc2FtZVxuLy8gb3JkZXIgYXMgdGhlIGdyaWQncyAocGFyc2VUYWJsZSByZWFkcyB0aGUgc2FtZSByb3dzKSwgc28gdGhlIG50aCBjZWxsIG9mIGFcbi8vIHJvdyBpcyB0aGUgbnRoIGNlbGwgb2YgdGhhdCBncmlkIHJvdy5cbmZ1bmN0aW9uIGNvbHVtbldpZHRocyh0YWJsZTogSFRNTFRhYmxlRWxlbWVudCwgd2lkdGg6IG51bWJlcik6IG51bWJlcltdIHtcbiAgY29uc3QgZ3JpZCA9IHBhcnNlVGFibGUodGFibGUpO1xuICBjb25zdCB3aWR0aHM6IChudW1iZXIgfCBudWxsKVtdID0gQXJyYXkuZnJvbSh7IGxlbmd0aDogZ3JpZC5jb2x1bW5zIH0sICgpID0+IG51bGwpO1xuXG4gIGdyaWQucm93cy5mb3JFYWNoKChyb3csIHJvd0luZGV4KSA9PiByb3cuY2VsbHMuZm9yRWFjaCgoY2VsbCwgY2VsbEluZGV4KSA9PiB7XG4gICAgaWYgKGNlbGwuY29sU3BhbiA9PT0gMSAmJiB3aWR0aHNbY2VsbC5jb2x1bW5dID09PSBudWxsKSB7XG4gICAgICB3aWR0aHNbY2VsbC5jb2x1bW5dID0gdGFibGUucm93c1tyb3dJbmRleF0uY2VsbHNbY2VsbEluZGV4XS5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKS53aWR0aDtcbiAgICB9XG4gIH0pKTtcblxuICBjb25zdCBrbm93biA9IHdpZHRocy5maWx0ZXIoKHZhbHVlKTogdmFsdWUgaXMgbnVtYmVyID0+IHZhbHVlICE9PSBudWxsKTtcbiAgY29uc3Qgc2hhcmUgPSBNYXRoLm1heCgwLCB3aWR0aCAtIHN1bShrbm93bikpIC8gTWF0aC5tYXgoMSwgd2lkdGhzLmxlbmd0aCAtIGtub3duLmxlbmd0aCk7XG4gIGNvbnN0IGZpbGxlZCA9IHdpZHRocy5tYXAoKHZhbHVlKSA9PiB2YWx1ZSA/PyBzaGFyZSk7XG4gIGNvbnN0IHRvdGFsID0gc3VtKGZpbGxlZCk7XG5cbiAgcmV0dXJuIGZpbGxlZC5tYXAoKHZhbHVlKSA9PiB0b3RhbCA/IHZhbHVlICogd2lkdGggLyB0b3RhbCA6IHdpZHRoIC8gZmlsbGVkLmxlbmd0aCk7XG59XG5cbmZ1bmN0aW9uIHN1bSh2YWx1ZXM6IG51bWJlcltdKTogbnVtYmVyIHtcbiAgcmV0dXJuIHZhbHVlcy5yZWR1Y2UoKHRvdGFsLCB2YWx1ZSkgPT4gdG90YWwgKyB2YWx1ZSwgMCk7XG59XG5cbmZ1bmN0aW9uIGluY2hlcyhwaXhlbHM6IG51bWJlcik6IG51bWJlciB7XG4gIHJldHVybiBwaXhlbHMgLyBQWF9QRVJfSU5DSDtcbn1cbiJdfQ==