@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,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==
|