@firestitch/report 18.10.2 → 18.11.1
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/report-canvas/report-canvas.component.d.ts +0 -1
- package/app/reports/data/report.data.d.ts +8 -12
- package/app/reports/export/report-export-collector.service.d.ts +0 -1
- package/app/reports/export/report-filter-lines.d.ts +0 -2
- package/app/reports/interfaces/report-chat-viewer-state.interface.d.ts +0 -2
- package/app/reports/interfaces/report-export-snapshot.interface.d.ts +2 -3
- package/app/reports/interfaces/report-saved-filter-changes.interface.d.ts +4 -0
- package/app/reports/interfaces/report-saved-filter.interface.d.ts +6 -0
- package/app/reports/interfaces/{report-view-config.interface.d.ts → report-state-snapshot.interface.d.ts} +1 -2
- package/app/reports/interfaces/report-viewer-feature.type.d.ts +1 -1
- package/app/reports/report-chat-viewer-state.d.ts +3 -3
- package/app/reports/report-saved-filters.d.ts +3 -0
- package/app/reports/report-state.d.ts +15 -0
- package/app/reports/services/report-filter-state.service.d.ts +9 -25
- package/app/reports/tile-data-state.d.ts +5 -5
- package/app/reports/views/report/fs-ai-report.component.d.ts +12 -5
- package/esm2022/app/reports/canvas-landing-page.mjs +3 -3
- package/esm2022/app/reports/components/component-list/component-list.component.mjs +3 -3
- package/esm2022/app/reports/components/report-canvas/report-canvas.component.mjs +8 -12
- package/esm2022/app/reports/components/report-component/report-component.component.mjs +25 -30
- package/esm2022/app/reports/data/report.data.mjs +24 -41
- package/esm2022/app/reports/export/report-export-collector.service.mjs +11 -18
- package/esm2022/app/reports/export/report-filter-lines.mjs +5 -15
- package/esm2022/app/reports/filter-settings-rules.mjs +2 -2
- package/esm2022/app/reports/interfaces/canvas-landing-input.interface.mjs +1 -1
- package/esm2022/app/reports/interfaces/report-chat-viewer-state.interface.mjs +1 -1
- package/esm2022/app/reports/interfaces/report-export-snapshot.interface.mjs +1 -1
- package/esm2022/app/reports/interfaces/report-saved-filter-changes.interface.mjs +2 -0
- package/esm2022/app/reports/interfaces/report-saved-filter.interface.mjs +2 -0
- package/esm2022/app/reports/interfaces/report-state-snapshot.interface.mjs +2 -0
- package/esm2022/app/reports/interfaces/report-temporary-state.interface.mjs +1 -1
- package/esm2022/app/reports/interfaces/report-tile-state.interface.mjs +1 -1
- package/esm2022/app/reports/interfaces/report-viewer-feature.type.mjs +1 -1
- package/esm2022/app/reports/interfaces/report.interface.mjs +1 -1
- package/esm2022/app/reports/mark-click.mjs +2 -2
- package/esm2022/app/reports/report-chat-viewer-state.mjs +3 -3
- package/esm2022/app/reports/report-date-presets.mjs +2 -2
- package/esm2022/app/reports/report-saved-filters.mjs +92 -0
- package/esm2022/app/reports/report-state.mjs +169 -0
- package/esm2022/app/reports/report-viewer-features.mjs +2 -4
- package/esm2022/app/reports/services/report-filter-state.service.mjs +83 -310
- package/esm2022/app/reports/tile-data-state.mjs +4 -4
- package/esm2022/app/reports/tile-loads.mjs +5 -6
- package/esm2022/app/reports/views/report/fs-ai-report.component.mjs +192 -102
- package/esm2022/app/reports/views/report/report.component.mjs +14 -16
- package/esm2022/public_api.mjs +4 -8
- package/fesm2022/{firestitch-report-echarts-CyHkFToO.mjs → firestitch-report-echarts-B0RWUjR8.mjs} +2 -2
- package/fesm2022/{firestitch-report-echarts-CyHkFToO.mjs.map → firestitch-report-echarts-B0RWUjR8.mjs.map} +1 -1
- package/fesm2022/{firestitch-report-firestitch-report-DftB7M1o.mjs → firestitch-report-firestitch-report-CJW0lLdW.mjs} +480 -1450
- package/fesm2022/firestitch-report-firestitch-report-CJW0lLdW.mjs.map +1 -0
- package/fesm2022/firestitch-report.mjs +1 -1
- package/package.json +1 -1
- package/public_api.d.ts +3 -7
- package/app/reports/components/report-view-picker/report-view-picker.component.d.ts +0 -21
- package/app/reports/dialogs/report-view/report-view-dialog.component.d.ts +0 -13
- package/app/reports/interfaces/report-view-create.interface.d.ts +0 -7
- package/app/reports/interfaces/report-view-deleted.interface.d.ts +0 -4
- package/app/reports/interfaces/report-view-dialog-data.interface.d.ts +0 -7
- package/app/reports/interfaces/report-view-dropped.interface.d.ts +0 -5
- package/app/reports/interfaces/report-view-menu-item.interface.d.ts +0 -10
- package/app/reports/interfaces/report-view-summary.interface.d.ts +0 -11
- package/app/reports/interfaces/report-view.interface.d.ts +0 -7
- package/app/reports/interfaces/report-views.interface.d.ts +0 -7
- package/app/reports/report-view-config.d.ts +0 -34
- package/app/reports/report-view-menu.d.ts +0 -15
- package/app/reports/services/report-view.service.d.ts +0 -39
- package/esm2022/app/reports/components/report-view-picker/report-view-picker.component.mjs +0 -115
- package/esm2022/app/reports/dialogs/report-view/report-view-dialog.component.mjs +0 -52
- package/esm2022/app/reports/interfaces/report-view-config.interface.mjs +0 -2
- package/esm2022/app/reports/interfaces/report-view-create.interface.mjs +0 -2
- package/esm2022/app/reports/interfaces/report-view-deleted.interface.mjs +0 -2
- package/esm2022/app/reports/interfaces/report-view-dialog-data.interface.mjs +0 -2
- package/esm2022/app/reports/interfaces/report-view-dropped.interface.mjs +0 -2
- package/esm2022/app/reports/interfaces/report-view-menu-item.interface.mjs +0 -2
- package/esm2022/app/reports/interfaces/report-view-summary.interface.mjs +0 -2
- package/esm2022/app/reports/interfaces/report-view.interface.mjs +0 -2
- package/esm2022/app/reports/interfaces/report-views.interface.mjs +0 -2
- package/esm2022/app/reports/report-view-config.mjs +0 -587
- package/esm2022/app/reports/report-view-menu.mjs +0 -119
- package/esm2022/app/reports/services/report-view.service.mjs +0 -218
- package/fesm2022/firestitch-report-firestitch-report-DftB7M1o.mjs.map +0 -1
|
@@ -1,587 +0,0 @@
|
|
|
1
|
-
import { GRANULARITY_OPTIONS, } from './interfaces/report.interface';
|
|
2
|
-
import { dateBoundString, dateFromBound } from './report-filter-items';
|
|
3
|
-
// The version this viewer writes and reads.
|
|
4
|
-
export const REPORT_VIEW_CONFIG_VERSION = 1;
|
|
5
|
-
// The caps of a view document, the server's.
|
|
6
|
-
export const VIEW_CONFIG_MAX_BYTES = 32 * 1024;
|
|
7
|
-
export const VIEW_CONFIG_MAX_GROUPS = 100;
|
|
8
|
-
export const VIEW_CONFIG_MAX_TILES = 200;
|
|
9
|
-
export const GROUP_VALUE_MAX_PICKS = 500;
|
|
10
|
-
export const DRILL_MAX_DEPTH = 5;
|
|
11
|
-
// Every relative range name the server knows, in its enum's order. A record
|
|
12
|
-
// rather than a list, so the build fails when ReportRelativeRange gains a
|
|
13
|
-
// name this misses.
|
|
14
|
-
const RELATIVE_RANGES = {
|
|
15
|
-
thisWeek: true,
|
|
16
|
-
lastWeek: true,
|
|
17
|
-
last7Days: true,
|
|
18
|
-
last30Days: true,
|
|
19
|
-
last3Months: true,
|
|
20
|
-
last6Months: true,
|
|
21
|
-
last12Months: true,
|
|
22
|
-
thisMonth: true,
|
|
23
|
-
thisQuarter: true,
|
|
24
|
-
thisYear: true,
|
|
25
|
-
yearToDate: true,
|
|
26
|
-
};
|
|
27
|
-
// The same names as a list, in the server enum's order (the record's key
|
|
28
|
-
// order): the order the date picker offers them in.
|
|
29
|
-
export const RELATIVE_RANGE_NAMES = Object.keys(RELATIVE_RANGES);
|
|
30
|
-
// The keys a group value may hold, by its group's type.
|
|
31
|
-
const GROUP_VALUE_KEYS = {
|
|
32
|
-
dateRange: ['relative', 'start', 'end'],
|
|
33
|
-
select: ['values', 'excludeValues'],
|
|
34
|
-
keyword: ['value'],
|
|
35
|
-
numberRange: ['min', 'max'],
|
|
36
|
-
};
|
|
37
|
-
// The keys of a view document and of a tile state this viewer reads. Any
|
|
38
|
-
// other key is kept as it was.
|
|
39
|
-
const VIEW_CONFIG_KEYS = ['v', 'pageId', 'groupBy', 'match', 'groups', 'tiles'];
|
|
40
|
-
const TILE_STATE_KEYS = ['sort', 'search', 'hidden', 'drill'];
|
|
41
|
-
const DAY_PATTERN = /^(\d{4})-(\d{2})-(\d{2})$/;
|
|
42
|
-
// A number as text: what a masked input sends.
|
|
43
|
-
const NUMBER_PATTERN = /^[+-]?(?:\d+(?:\.\d*)?|\.\d+)(?:e[+-]?\d+)?$/i;
|
|
44
|
-
const ID_KEY_PATTERN = /^[1-9]\d*$/;
|
|
45
|
-
// Whether a name is a relative range the server resolves.
|
|
46
|
-
export function isRelativeRange(name) {
|
|
47
|
-
return typeof name === 'string' && Object.prototype.hasOwnProperty.call(RELATIVE_RANGES, name);
|
|
48
|
-
}
|
|
49
|
-
export function isChartGranularity(value) {
|
|
50
|
-
return GRANULARITY_OPTIONS.some((option) => option.value === value);
|
|
51
|
-
}
|
|
52
|
-
// Whether text is a real calendar day written 'yyyy-MM-dd' (no 2026-02-30).
|
|
53
|
-
export function isCalendarDay(text) {
|
|
54
|
-
const parts = DAY_PATTERN.exec(text);
|
|
55
|
-
if (!parts) {
|
|
56
|
-
return false;
|
|
57
|
-
}
|
|
58
|
-
const [year, month, day] = parts.slice(1).map(Number);
|
|
59
|
-
const date = new Date(Date.UTC(year, month - 1, day));
|
|
60
|
-
return date.getUTCFullYear() === year && date.getUTCMonth() === month - 1 && date.getUTCDate() === day;
|
|
61
|
-
}
|
|
62
|
-
// A number written as text (a masked input's value), or null when the text
|
|
63
|
-
// is not one finite number.
|
|
64
|
-
export function numberFromText(text) {
|
|
65
|
-
const number = NUMBER_PATTERN.test(text) ? Number(text) : NaN;
|
|
66
|
-
return Number.isFinite(number) ? number : null;
|
|
67
|
-
}
|
|
68
|
-
// A group value read for a group of `type`, on its way to being stored: only
|
|
69
|
-
// the parts that hold something. Throws, naming what is wrong, when a key
|
|
70
|
-
// does not belong to the type or a part breaks its type's rule.
|
|
71
|
-
export function groupValueFromArray(value, type) {
|
|
72
|
-
requireGroupKeys(value, type);
|
|
73
|
-
switch (type) {
|
|
74
|
-
case 'dateRange':
|
|
75
|
-
return dateRangeValue(value);
|
|
76
|
-
case 'select':
|
|
77
|
-
return selectValue(value);
|
|
78
|
-
case 'numberRange':
|
|
79
|
-
return numberRangeValue(value);
|
|
80
|
-
default:
|
|
81
|
-
return keywordValue(value);
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
// A group value read back (a saved view) for a group of `type`: what
|
|
85
|
-
// groupValueFromArray gives, or null when it would refuse it.
|
|
86
|
-
export function groupValueFromStored(value, type) {
|
|
87
|
-
if (!isPlainObject(value)) {
|
|
88
|
-
return null;
|
|
89
|
-
}
|
|
90
|
-
try {
|
|
91
|
-
return groupValueFromArray(value, type);
|
|
92
|
-
}
|
|
93
|
-
catch {
|
|
94
|
-
return null;
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
// A view document read for storing or applying. Throws when it is not a
|
|
98
|
-
// version 1 document, breaks a cap or holds a malformed known key.
|
|
99
|
-
export function viewConfigFromArray(input) {
|
|
100
|
-
const doc = requireObject(input, 'A view config must be an object.');
|
|
101
|
-
requireSize(doc);
|
|
102
|
-
requireVersion(doc.v);
|
|
103
|
-
const config = { v: REPORT_VIEW_CONFIG_VERSION, ...otherKeys(doc, VIEW_CONFIG_KEYS) };
|
|
104
|
-
const pageId = optionalId(doc.pageId, 'pageId must be a page id.');
|
|
105
|
-
if (pageId !== null) {
|
|
106
|
-
config.pageId = pageId;
|
|
107
|
-
}
|
|
108
|
-
if (isSet(doc.groupBy)) {
|
|
109
|
-
config.groupBy = requireGranularity(doc.groupBy, 'groupBy must be a time grain.');
|
|
110
|
-
}
|
|
111
|
-
if (isSet(doc.match)) {
|
|
112
|
-
config.match = requireMatch(doc.match);
|
|
113
|
-
}
|
|
114
|
-
if (isSet(doc.groups)) {
|
|
115
|
-
config.groups = viewGroups(doc.groups);
|
|
116
|
-
}
|
|
117
|
-
if (isSet(doc.tiles)) {
|
|
118
|
-
config.tiles = viewTiles(doc.tiles);
|
|
119
|
-
}
|
|
120
|
-
return config;
|
|
121
|
-
}
|
|
122
|
-
// A group's value as a view stores it, read for the keys its
|
|
123
|
-
// group's type owns, or null when it holds nothing. A date range that still
|
|
124
|
-
// carries its relative preset is stored as that preset whatever today is: the
|
|
125
|
-
// viewer did not edit it, so a view saved after midnight with the page still
|
|
126
|
-
// open keeps rolling.
|
|
127
|
-
export function toStoredGroupValue(type, value) {
|
|
128
|
-
if (!value) {
|
|
129
|
-
return null;
|
|
130
|
-
}
|
|
131
|
-
switch (type) {
|
|
132
|
-
case 'dateRange':
|
|
133
|
-
return isRelativeRange(value.preset)
|
|
134
|
-
? { relative: value.preset }
|
|
135
|
-
: storedOrNull({ start: dateBoundString(value.start), end: dateBoundString(value.end) });
|
|
136
|
-
case 'select': {
|
|
137
|
-
const excludeValues = keptPicks(value.excludeValues);
|
|
138
|
-
return storedOrNull(excludeValues ? { excludeValues } : { values: keptPicks(value.values) });
|
|
139
|
-
}
|
|
140
|
-
case 'numberRange':
|
|
141
|
-
return storedOrNull({ min: finiteNumber(value.min), max: finiteNumber(value.max) });
|
|
142
|
-
default:
|
|
143
|
-
return storedOrNull({ value: value.value?.trim() || undefined });
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
// A group value in its stored shape as the value the bars and the requests
|
|
147
|
-
// read: a relative preset as today's days in the report's zone, carrying its
|
|
148
|
-
// name; fixed days as dates; any other value as it is. Null when it holds
|
|
149
|
-
// nothing, or names a preset `resolveRelative` does not know.
|
|
150
|
-
export function toLiveGroupValue(type, stored, resolveRelative) {
|
|
151
|
-
if (!stored || holdsNothing(stored)) {
|
|
152
|
-
return null;
|
|
153
|
-
}
|
|
154
|
-
if (type !== 'dateRange') {
|
|
155
|
-
return { ...stored };
|
|
156
|
-
}
|
|
157
|
-
if (stored.relative) {
|
|
158
|
-
const range = resolveRelative(stored.relative);
|
|
159
|
-
return range ? { start: range.start, end: range.end, preset: stored.relative } : null;
|
|
160
|
-
}
|
|
161
|
-
return { start: dateFromBound(stored.start), end: dateFromBound(stored.end) };
|
|
162
|
-
}
|
|
163
|
-
// Whether the screen's state differs from the view it opened on. `current`
|
|
164
|
-
// is a snapshot, so it holds every group the report has; a group only `base`
|
|
165
|
-
// holds is one the report no longer has, and is not compared. A group `base`
|
|
166
|
-
// does not hold was added after the view was saved: it is compared with its
|
|
167
|
-
// value in `authored` (the report's defaults), so leaving it at its default
|
|
168
|
-
// changes nothing. The page is not compared (moving to another page does not
|
|
169
|
-
// edit a view), and neither are keys this viewer does not know. Picks are
|
|
170
|
-
// compared in any order.
|
|
171
|
-
export function viewDiffers(base, current, authored = null) {
|
|
172
|
-
return (base.match ?? 'all') !== (current.match ?? 'all')
|
|
173
|
-
|| (base.groupBy ?? null) !== (current.groupBy ?? null)
|
|
174
|
-
|| groupsDiffer(base, current, authored)
|
|
175
|
-
|| tilesDiffer(base.tiles ?? {}, current.tiles ?? {});
|
|
176
|
-
}
|
|
177
|
-
// Whether two stored group values are the same filter, as viewDiffers reads
|
|
178
|
-
// a group: picks in any order, text trimmed, an empty value read as none.
|
|
179
|
-
export function sameStoredGroupValue(a, b) {
|
|
180
|
-
return storedValueKey(a) === storedValueKey(b);
|
|
181
|
-
}
|
|
182
|
-
// A drill path kept to what a tile can carry: its steps up to the first that
|
|
183
|
-
// is not a time level with a plain value (the steps before it are kept), at
|
|
184
|
-
// most DRILL_MAX_DEPTH of them.
|
|
185
|
-
export function cleanDrillPath(path) {
|
|
186
|
-
const kept = [];
|
|
187
|
-
for (const step of path ?? []) {
|
|
188
|
-
if (!isPlainObject(step) || !isChartGranularity(step.level) || !isDrillValue(step.value)
|
|
189
|
-
|| kept.length === DRILL_MAX_DEPTH) {
|
|
190
|
-
break;
|
|
191
|
-
}
|
|
192
|
-
kept.push({ level: step.level, value: step.value });
|
|
193
|
-
}
|
|
194
|
-
return kept;
|
|
195
|
-
}
|
|
196
|
-
// Whether two drill paths are the same steps. A value is compared as text,
|
|
197
|
-
// so 2026 and '2026' are the same step.
|
|
198
|
-
export function sameDrillPath(a, b) {
|
|
199
|
-
return drillKey(a) === drillKey(b);
|
|
200
|
-
}
|
|
201
|
-
// A view's config to save: the screen (`screen`, a snapshot), with the keys
|
|
202
|
-
// this viewer does not know kept from the stored document (`stored`), at the
|
|
203
|
-
// top and in each tile. They are never read here, and saving must not lose
|
|
204
|
-
// them.
|
|
205
|
-
export function withStoredKeys(stored, screen) {
|
|
206
|
-
if (!stored) {
|
|
207
|
-
return screen;
|
|
208
|
-
}
|
|
209
|
-
const tiles = { ...screen.tiles };
|
|
210
|
-
Object.entries(stored.tiles ?? {}).forEach(([componentId, tile]) => {
|
|
211
|
-
const kept = isPlainObject(tile) ? otherKeys(tile, TILE_STATE_KEYS) : {};
|
|
212
|
-
if (Object.keys(kept).length) {
|
|
213
|
-
tiles[Number(componentId)] = { ...kept, ...tiles[Number(componentId)] };
|
|
214
|
-
}
|
|
215
|
-
});
|
|
216
|
-
const config = { ...otherKeys(stored, VIEW_CONFIG_KEYS), ...screen };
|
|
217
|
-
delete config.tiles;
|
|
218
|
-
return Object.keys(tiles).length ? { ...config, tiles } : config;
|
|
219
|
-
}
|
|
220
|
-
// How many settings of a saved view no longer apply because the report
|
|
221
|
-
// changed: what the server left out when it read the view (`dropped`), and
|
|
222
|
-
// what the viewer could not apply (`applied` is the view as it applied, the
|
|
223
|
-
// state service's base): a group value that no longer fits its group, and a
|
|
224
|
-
// list sort, search or hidden columns, or a chart's drill path, its tile can
|
|
225
|
-
// no longer take (a list column gone, a chart turned into a list).
|
|
226
|
-
export function viewDroppedCount(view, applied) {
|
|
227
|
-
const dropped = view.dropped;
|
|
228
|
-
const groups = Object.entries(view.config?.groups ?? {})
|
|
229
|
-
.filter(([groupId, value]) => value !== null && !Object.prototype.hasOwnProperty.call(applied.groups ?? {}, groupId))
|
|
230
|
-
.length;
|
|
231
|
-
const tiles = Object.entries(view.config?.tiles ?? {})
|
|
232
|
-
.reduce((count, [componentId, tile]) => count + tileKeysLost(tile, applied.tiles?.[Number(componentId)]), 0);
|
|
233
|
-
return (dropped?.groups?.length ?? 0) + (dropped?.tiles?.length ?? 0) + (dropped?.page ? 1 : 0) + groups + tiles;
|
|
234
|
-
}
|
|
235
|
-
// The note a view opens with when some of its settings no longer apply, or
|
|
236
|
-
// null when every setting applies. Only a viewer who may change the view
|
|
237
|
-
// (`canChange`) is told to save it.
|
|
238
|
-
export function viewDroppedMessage(count, canChange = true) {
|
|
239
|
-
if (count < 1) {
|
|
240
|
-
return null;
|
|
241
|
-
}
|
|
242
|
-
const note = count === 1
|
|
243
|
-
? '1 setting in this view no longer applies, because the report changed.'
|
|
244
|
-
: `${count} settings in this view no longer apply, because the report changed.`;
|
|
245
|
-
return canChange ? `${note} Save changes to update the view.` : note;
|
|
246
|
-
}
|
|
247
|
-
// The open view as a chat turn names it: its id, and whether the screen
|
|
248
|
-
// differs from it. Both are left out while no view is open.
|
|
249
|
-
export function chatViewFields(openView, viewChanged) {
|
|
250
|
-
return openView ? { viewId: openView.id, viewChanged } : {};
|
|
251
|
-
}
|
|
252
|
-
function groupsDiffer(base, current, authored) {
|
|
253
|
-
return Object.entries(current.groups ?? {}).some(([groupId, value]) => {
|
|
254
|
-
const kept = base.groups && Object.prototype.hasOwnProperty.call(base.groups, groupId)
|
|
255
|
-
? base.groups[Number(groupId)]
|
|
256
|
-
: authored?.groups?.[Number(groupId)];
|
|
257
|
-
return storedValueKey(kept) !== storedValueKey(value);
|
|
258
|
-
});
|
|
259
|
-
}
|
|
260
|
-
function tilesDiffer(base, current) {
|
|
261
|
-
const ids = new Set([...Object.keys(base), ...Object.keys(current)].map(Number));
|
|
262
|
-
return [...ids].some((componentId) => tileStateKey(base[componentId]) !== tileStateKey(current[componentId]));
|
|
263
|
-
}
|
|
264
|
-
// How many keys of a stored tile state the tile, as it applied, lost: a
|
|
265
|
-
// sort, a search or a drill path it no longer has, and hidden columns it
|
|
266
|
-
// kept fewer of.
|
|
267
|
-
function tileKeysLost(stored, applied) {
|
|
268
|
-
if (!stored) {
|
|
269
|
-
return 0;
|
|
270
|
-
}
|
|
271
|
-
return [
|
|
272
|
-
!!stored.sort?.column && !applied?.sort?.column,
|
|
273
|
-
!!stored.search && !applied?.search,
|
|
274
|
-
(stored.hidden?.length ?? 0) > (applied?.hidden?.length ?? 0),
|
|
275
|
-
(stored.drill?.length ?? 0) > 0 && !applied?.drill?.length,
|
|
276
|
-
].filter(Boolean).length;
|
|
277
|
-
}
|
|
278
|
-
// One text for a stored group value, the same for every way of writing the
|
|
279
|
-
// same filter: picks in any order, text trimmed, and an empty value read as
|
|
280
|
-
// none.
|
|
281
|
-
function storedValueKey(value) {
|
|
282
|
-
const stored = value ?? {};
|
|
283
|
-
const picks = (list) => [...(keptPicks(list) ?? [])].map(String).sort();
|
|
284
|
-
return JSON.stringify([
|
|
285
|
-
stored.relative ?? null,
|
|
286
|
-
stored.start?.slice(0, 10) ?? null,
|
|
287
|
-
stored.end?.slice(0, 10) ?? null,
|
|
288
|
-
picks(stored.values),
|
|
289
|
-
picks(stored.excludeValues),
|
|
290
|
-
(stored.value ?? '').trim(),
|
|
291
|
-
finiteNumber(stored.min) ?? null,
|
|
292
|
-
finiteNumber(stored.max) ?? null,
|
|
293
|
-
]);
|
|
294
|
-
}
|
|
295
|
-
// One text for a tile's state, over the keys this viewer reads. No direction
|
|
296
|
-
// reads as ascending, the way a list applies it.
|
|
297
|
-
function tileStateKey(tile) {
|
|
298
|
-
return JSON.stringify([
|
|
299
|
-
tile?.sort?.column ? [tile.sort.column, tile.sort.direction ?? 'asc'] : null,
|
|
300
|
-
tile?.search ?? '',
|
|
301
|
-
[...(tile?.hidden ?? [])].sort(),
|
|
302
|
-
drillKey(tile?.drill),
|
|
303
|
-
]);
|
|
304
|
-
}
|
|
305
|
-
function drillKey(path) {
|
|
306
|
-
return JSON.stringify((path ?? [])
|
|
307
|
-
.map((step) => [step.level, step.value === null || step.value === undefined ? null : String(step.value)]));
|
|
308
|
-
}
|
|
309
|
-
// The picks of a list with blanks (null, '') left out, or undefined when none
|
|
310
|
-
// is left.
|
|
311
|
-
function keptPicks(list) {
|
|
312
|
-
const kept = (list ?? []).filter((pick) => isSet(pick) && pick !== '');
|
|
313
|
-
return kept.length ? kept : undefined;
|
|
314
|
-
}
|
|
315
|
-
// A range end as a number. A masked input sends its number as text, so
|
|
316
|
-
// numeric text is read as its number, as boundPart reads it.
|
|
317
|
-
export function finiteNumber(value) {
|
|
318
|
-
const number = typeof value === 'string' ? numberFromText(value.trim()) : value;
|
|
319
|
-
return typeof number === 'number' && Number.isFinite(number) ? number : undefined;
|
|
320
|
-
}
|
|
321
|
-
// Whether a stored value reads the same as no value at all.
|
|
322
|
-
function holdsNothing(stored) {
|
|
323
|
-
return storedValueKey(stored) === storedValueKey(null);
|
|
324
|
-
}
|
|
325
|
-
// Only the parts that hold something, or null when none does.
|
|
326
|
-
function storedOrNull(value) {
|
|
327
|
-
const stored = compact(value);
|
|
328
|
-
return Object.keys(stored).length ? stored : null;
|
|
329
|
-
}
|
|
330
|
-
function requireGroupKeys(value, type) {
|
|
331
|
-
const allowed = GROUP_VALUE_KEYS[type] ?? GROUP_VALUE_KEYS.keyword;
|
|
332
|
-
const unknown = Object.keys(value).filter((key) => !allowed.includes(key));
|
|
333
|
-
if (unknown.length) {
|
|
334
|
-
throw new Error(`A ${type} default takes ${allowed.join(', ')} — not ${unknown.join(', ')}.`);
|
|
335
|
-
}
|
|
336
|
-
}
|
|
337
|
-
// A relative range, or fixed days; never both.
|
|
338
|
-
function dateRangeValue(value) {
|
|
339
|
-
const relative = textPart(value, 'relative');
|
|
340
|
-
const start = dayPart(value, 'start');
|
|
341
|
-
const end = dayPart(value, 'end');
|
|
342
|
-
if (relative === '') {
|
|
343
|
-
return compact({ start, end });
|
|
344
|
-
}
|
|
345
|
-
if (start !== null || end !== null) {
|
|
346
|
-
throw new Error('A dateRange default is either a relative preset or a fixed start/end, not both.');
|
|
347
|
-
}
|
|
348
|
-
if (!isRelativeRange(relative)) {
|
|
349
|
-
throw new Error(`relative must be one of: ${Object.keys(RELATIVE_RANGES).join(', ')}.`);
|
|
350
|
-
}
|
|
351
|
-
return { relative };
|
|
352
|
-
}
|
|
353
|
-
// The values to keep or the values to leave out; never both.
|
|
354
|
-
function selectValue(value) {
|
|
355
|
-
const values = pickList(value, 'values');
|
|
356
|
-
const excludeValues = pickList(value, 'excludeValues');
|
|
357
|
-
if (values !== null && excludeValues !== null) {
|
|
358
|
-
throw new Error('A select default either keeps values or leaves out exclude_values, not both.');
|
|
359
|
-
}
|
|
360
|
-
return compact({ values, excludeValues });
|
|
361
|
-
}
|
|
362
|
-
function keywordValue(value) {
|
|
363
|
-
const text = textPart(value, 'value');
|
|
364
|
-
return text !== '' ? { value: text } : {};
|
|
365
|
-
}
|
|
366
|
-
// Either end may be open; 0 is an end like any other.
|
|
367
|
-
function numberRangeValue(value) {
|
|
368
|
-
const min = boundPart(value, 'min');
|
|
369
|
-
const max = boundPart(value, 'max');
|
|
370
|
-
if (min !== null && max !== null && min > max) {
|
|
371
|
-
throw new Error(`min (${min}) is above max (${max}).`);
|
|
372
|
-
}
|
|
373
|
-
return compact({ min, max });
|
|
374
|
-
}
|
|
375
|
-
// The text `key` holds, trimmed, or '' when absent. A number is read as its
|
|
376
|
-
// text; any other kind is refused.
|
|
377
|
-
function textPart(value, key) {
|
|
378
|
-
const text = value[key];
|
|
379
|
-
if (text === undefined || text === null) {
|
|
380
|
-
return '';
|
|
381
|
-
}
|
|
382
|
-
if (typeof text !== 'string' && typeof text !== 'number') {
|
|
383
|
-
throw new Error(`${key} must be text.`);
|
|
384
|
-
}
|
|
385
|
-
return String(text).trim();
|
|
386
|
-
}
|
|
387
|
-
// A calendar-day bound: its first ten characters must be a real day.
|
|
388
|
-
function dayPart(value, key) {
|
|
389
|
-
const text = textPart(value, key);
|
|
390
|
-
if (text === '') {
|
|
391
|
-
return null;
|
|
392
|
-
}
|
|
393
|
-
const day = text.slice(0, 10);
|
|
394
|
-
if (!isCalendarDay(day)) {
|
|
395
|
-
throw new Error(`${key} must be a yyyy-MM-dd day.`);
|
|
396
|
-
}
|
|
397
|
-
return day;
|
|
398
|
-
}
|
|
399
|
-
// The picks of `key` with blanks (null, '') dropped, or null when none is
|
|
400
|
-
// left. A lone pick is a list of one; a pick that is a list or an object is
|
|
401
|
-
// refused.
|
|
402
|
-
function pickList(value, key) {
|
|
403
|
-
const raw = value[key] ?? [];
|
|
404
|
-
const picks = Array.isArray(raw) ? raw : [raw];
|
|
405
|
-
if (picks.some((pick) => isSet(pick) && !isScalar(pick))) {
|
|
406
|
-
throw new Error(`Each pick in ${key} must be a plain value, not a list.`);
|
|
407
|
-
}
|
|
408
|
-
const kept = picks.filter((pick) => isSet(pick) && pick !== '');
|
|
409
|
-
return kept.length ? kept : null;
|
|
410
|
-
}
|
|
411
|
-
// One end of a number range: null when absent or blank, else a finite number
|
|
412
|
-
// (numeric text is read as its number).
|
|
413
|
-
function boundPart(value, key) {
|
|
414
|
-
const raw = typeof value[key] === 'string' ? value[key].trim() : value[key];
|
|
415
|
-
if (!isSet(raw) || raw === '') {
|
|
416
|
-
return null;
|
|
417
|
-
}
|
|
418
|
-
const bound = typeof raw === 'string' ? numberFromText(raw) : raw;
|
|
419
|
-
if (typeof bound !== 'number' || !Number.isFinite(bound)) {
|
|
420
|
-
throw new Error(`${key} must be a finite number.`);
|
|
421
|
-
}
|
|
422
|
-
return bound;
|
|
423
|
-
}
|
|
424
|
-
function requireSize(doc) {
|
|
425
|
-
if (new TextEncoder().encode(JSON.stringify(doc)).length > VIEW_CONFIG_MAX_BYTES) {
|
|
426
|
-
throw new Error('A view config is over 32 KB.');
|
|
427
|
-
}
|
|
428
|
-
}
|
|
429
|
-
function requireVersion(version) {
|
|
430
|
-
if (!isSet(version)) {
|
|
431
|
-
throw new Error('A view config needs its version (v).');
|
|
432
|
-
}
|
|
433
|
-
if (version !== REPORT_VIEW_CONFIG_VERSION) {
|
|
434
|
-
throw new Error(`This viewer reads view config version ${REPORT_VIEW_CONFIG_VERSION} only.`);
|
|
435
|
-
}
|
|
436
|
-
}
|
|
437
|
-
function requireMatch(match) {
|
|
438
|
-
if (match !== 'all' && match !== 'any') {
|
|
439
|
-
throw new Error('match must be all or any.');
|
|
440
|
-
}
|
|
441
|
-
return match;
|
|
442
|
-
}
|
|
443
|
-
// Group id -> value. A value no group type could hold is dropped whole.
|
|
444
|
-
function viewGroups(raw) {
|
|
445
|
-
const entries = Object.entries(requireObject(raw, 'groups must map group ids to values.'));
|
|
446
|
-
if (entries.length > VIEW_CONFIG_MAX_GROUPS) {
|
|
447
|
-
throw new Error(`A view holds at most ${VIEW_CONFIG_MAX_GROUPS} groups.`);
|
|
448
|
-
}
|
|
449
|
-
const groups = {};
|
|
450
|
-
entries.forEach(([key, value]) => {
|
|
451
|
-
const id = requireIdKey(key, 'groups');
|
|
452
|
-
requirePickCount(value);
|
|
453
|
-
const kept = value === null ? null : storedGroupValue(value);
|
|
454
|
-
if (kept !== undefined) {
|
|
455
|
-
groups[id] = kept;
|
|
456
|
-
}
|
|
457
|
-
});
|
|
458
|
-
return groups;
|
|
459
|
-
}
|
|
460
|
-
// A stored group value, read for the one type its keys belong to (an empty
|
|
461
|
-
// value fits every type), or undefined when it fits none.
|
|
462
|
-
function storedGroupValue(value) {
|
|
463
|
-
if (!isPlainObject(value)) {
|
|
464
|
-
return undefined;
|
|
465
|
-
}
|
|
466
|
-
const keys = Object.keys(value);
|
|
467
|
-
const type = Object.keys(GROUP_VALUE_KEYS)
|
|
468
|
-
.find((candidate) => keys.every((key) => GROUP_VALUE_KEYS[candidate].includes(key)));
|
|
469
|
-
return type ? (groupValueFromStored(value, type) ?? undefined) : undefined;
|
|
470
|
-
}
|
|
471
|
-
function requirePickCount(value) {
|
|
472
|
-
const lists = isPlainObject(value) ? [value.values, value.excludeValues] : [];
|
|
473
|
-
if (lists.some((list) => Array.isArray(list) && list.length > GROUP_VALUE_MAX_PICKS)) {
|
|
474
|
-
throw new Error(`A group value holds at most ${GROUP_VALUE_MAX_PICKS} values.`);
|
|
475
|
-
}
|
|
476
|
-
}
|
|
477
|
-
// Component id -> tile state.
|
|
478
|
-
function viewTiles(raw) {
|
|
479
|
-
const entries = Object.entries(requireObject(raw, 'tiles must map component ids to tile states.'));
|
|
480
|
-
if (entries.length > VIEW_CONFIG_MAX_TILES) {
|
|
481
|
-
throw new Error(`A view holds at most ${VIEW_CONFIG_MAX_TILES} tiles.`);
|
|
482
|
-
}
|
|
483
|
-
const tiles = {};
|
|
484
|
-
entries.forEach(([key, value]) => {
|
|
485
|
-
tiles[requireIdKey(key, 'tiles')] = viewTile(value);
|
|
486
|
-
});
|
|
487
|
-
return tiles;
|
|
488
|
-
}
|
|
489
|
-
function viewTile(raw) {
|
|
490
|
-
const tile = requireObject(raw, 'A tile state must be an object.');
|
|
491
|
-
const state = otherKeys(tile, TILE_STATE_KEYS);
|
|
492
|
-
if (isSet(tile.sort)) {
|
|
493
|
-
state.sort = viewSort(tile.sort);
|
|
494
|
-
}
|
|
495
|
-
if (isSet(tile.search)) {
|
|
496
|
-
state.search = requireString(tile.search, 'search must be text.');
|
|
497
|
-
}
|
|
498
|
-
if (isSet(tile.hidden)) {
|
|
499
|
-
state.hidden = viewHidden(tile.hidden);
|
|
500
|
-
}
|
|
501
|
-
if (isSet(tile.drill)) {
|
|
502
|
-
state.drill = viewDrill(tile.drill);
|
|
503
|
-
}
|
|
504
|
-
return state;
|
|
505
|
-
}
|
|
506
|
-
function viewSort(raw) {
|
|
507
|
-
const sort = requireObject(raw, 'sort must be a column and a direction.');
|
|
508
|
-
const column = requireString(sort.column, 'sort must name a column.');
|
|
509
|
-
if (column === '' || (isSet(sort.direction) && sort.direction !== 'asc' && sort.direction !== 'desc')) {
|
|
510
|
-
throw new Error('sort must be a column and a direction.');
|
|
511
|
-
}
|
|
512
|
-
return sort.direction ? { column, direction: sort.direction } : { column };
|
|
513
|
-
}
|
|
514
|
-
function viewHidden(raw) {
|
|
515
|
-
if (!Array.isArray(raw) || raw.some((name) => typeof name !== 'string')) {
|
|
516
|
-
throw new Error('hidden must list column names.');
|
|
517
|
-
}
|
|
518
|
-
return [...raw];
|
|
519
|
-
}
|
|
520
|
-
function viewDrill(raw) {
|
|
521
|
-
if (!Array.isArray(raw)) {
|
|
522
|
-
throw new Error('drill must list steps.');
|
|
523
|
-
}
|
|
524
|
-
if (raw.length > DRILL_MAX_DEPTH) {
|
|
525
|
-
throw new Error(`A drill path holds at most ${DRILL_MAX_DEPTH} steps.`);
|
|
526
|
-
}
|
|
527
|
-
return raw.map((step) => {
|
|
528
|
-
if (!isPlainObject(step) || !isChartGranularity(step.level) || !isDrillValue(step.value)) {
|
|
529
|
-
throw new Error('A drill step needs a time level and a value.');
|
|
530
|
-
}
|
|
531
|
-
return { level: step.level, value: step.value };
|
|
532
|
-
});
|
|
533
|
-
}
|
|
534
|
-
function isDrillValue(value) {
|
|
535
|
-
return value === null || typeof value === 'string' || typeof value === 'number';
|
|
536
|
-
}
|
|
537
|
-
// The keys of `source` that are not in `known`, as they were.
|
|
538
|
-
function otherKeys(source, known) {
|
|
539
|
-
return Object.fromEntries(Object.entries(source).filter(([key]) => !known.includes(key)));
|
|
540
|
-
}
|
|
541
|
-
function optionalId(raw, refusal) {
|
|
542
|
-
if (!isSet(raw)) {
|
|
543
|
-
return null;
|
|
544
|
-
}
|
|
545
|
-
if (!Number.isInteger(raw) || raw < 1) {
|
|
546
|
-
throw new Error(refusal);
|
|
547
|
-
}
|
|
548
|
-
return raw;
|
|
549
|
-
}
|
|
550
|
-
function requireIdKey(key, where) {
|
|
551
|
-
if (!ID_KEY_PATTERN.test(key)) {
|
|
552
|
-
throw new Error(`${where} are keyed by id, not by '${key}'.`);
|
|
553
|
-
}
|
|
554
|
-
return Number(key);
|
|
555
|
-
}
|
|
556
|
-
function requireGranularity(raw, refusal) {
|
|
557
|
-
if (!isChartGranularity(raw)) {
|
|
558
|
-
throw new Error(refusal);
|
|
559
|
-
}
|
|
560
|
-
return raw;
|
|
561
|
-
}
|
|
562
|
-
function requireString(raw, refusal) {
|
|
563
|
-
if (typeof raw !== 'string') {
|
|
564
|
-
throw new Error(refusal);
|
|
565
|
-
}
|
|
566
|
-
return raw;
|
|
567
|
-
}
|
|
568
|
-
function requireObject(raw, refusal) {
|
|
569
|
-
if (!isPlainObject(raw)) {
|
|
570
|
-
throw new Error(refusal);
|
|
571
|
-
}
|
|
572
|
-
return raw;
|
|
573
|
-
}
|
|
574
|
-
function isSet(value) {
|
|
575
|
-
return value !== undefined && value !== null;
|
|
576
|
-
}
|
|
577
|
-
function isPlainObject(value) {
|
|
578
|
-
return value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
579
|
-
}
|
|
580
|
-
function isScalar(value) {
|
|
581
|
-
return typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean';
|
|
582
|
-
}
|
|
583
|
-
// Only the parts that hold something.
|
|
584
|
-
function compact(value) {
|
|
585
|
-
return Object.fromEntries(Object.entries(value).filter(([, part]) => isSet(part)));
|
|
586
|
-
}
|
|
587
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVwb3J0LXZpZXctY29uZmlnLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL2FwcC9yZXBvcnRzL3JlcG9ydC12aWV3LWNvbmZpZy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUEwQkEsT0FBTyxFQUlMLG1CQUFtQixHQUlwQixNQUFNLCtCQUErQixDQUFDO0FBQ3ZDLE9BQU8sRUFBRSxlQUFlLEVBQUUsYUFBYSxFQUFFLE1BQU0sdUJBQXVCLENBQUM7QUFHdkUsNENBQTRDO0FBQzVDLE1BQU0sQ0FBQyxNQUFNLDBCQUEwQixHQUFHLENBQUMsQ0FBQztBQUU1Qyw2Q0FBNkM7QUFDN0MsTUFBTSxDQUFDLE1BQU0scUJBQXFCLEdBQUcsRUFBRSxHQUFHLElBQUksQ0FBQztBQUMvQyxNQUFNLENBQUMsTUFBTSxzQkFBc0IsR0FBRyxHQUFHLENBQUM7QUFDMUMsTUFBTSxDQUFDLE1BQU0scUJBQXFCLEdBQUcsR0FBRyxDQUFDO0FBQ3pDLE1BQU0sQ0FBQyxNQUFNLHFCQUFxQixHQUFHLEdBQUcsQ0FBQztBQUN6QyxNQUFNLENBQUMsTUFBTSxlQUFlLEdBQUcsQ0FBQyxDQUFDO0FBRWpDLDRFQUE0RTtBQUM1RSwwRUFBMEU7QUFDMUUsb0JBQW9CO0FBQ3BCLE1BQU0sZUFBZSxHQUFzQztJQUN6RCxRQUFRLEVBQUUsSUFBSTtJQUNkLFFBQVEsRUFBRSxJQUFJO0lBQ2QsU0FBUyxFQUFFLElBQUk7SUFDZixVQUFVLEVBQUUsSUFBSTtJQUNoQixXQUFXLEVBQUUsSUFBSTtJQUNqQixXQUFXLEVBQUUsSUFBSTtJQUNqQixZQUFZLEVBQUUsSUFBSTtJQUNsQixTQUFTLEVBQUUsSUFBSTtJQUNmLFdBQVcsRUFBRSxJQUFJO0lBQ2pCLFFBQVEsRUFBRSxJQUFJO0lBQ2QsVUFBVSxFQUFFLElBQUk7Q0FDakIsQ0FBQztBQUVGLHlFQUF5RTtBQUN6RSxvREFBb0Q7QUFDcEQsTUFBTSxDQUFDLE1BQU0sb0JBQW9CLEdBQUcsTUFBTSxD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QUMsR0FBWSxFQUFFLE9BQWU7SUFDbEQsSUFBSSxDQUFDLGFBQWEsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDO1FBQ3hCLE1BQU0sSUFBSSxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUM7SUFDM0IsQ0FBQztJQUVELE9BQU8sR0FBRyxDQUFDO0FBQ2IsQ0FBQztBQUVELFNBQVMsS0FBSyxDQUFDLEtBQWM7SUFDM0IsT0FBTyxLQUFLLEtBQUssU0FBUyxJQUFJLEtBQUssS0FBSyxJQUFJLENBQUM7QUFDL0MsQ0FBQztBQUVELFNBQVMsYUFBYSxDQUFDLEtBQWM7SUFDbkMsT0FBTyxLQUFLLEtBQUssSUFBSSxJQUFJLE9BQU8sS0FBSyxLQUFLLFFBQVEsSUFBSSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLENBQUM7QUFDOUUsQ0FBQztBQUVELFNBQVMsUUFBUSxDQUFDLEtBQWM7SUFDOUIsT0FBTyxPQUFPLEtBQUssS0FBSyxRQUFRLElBQUksT0FBTyxLQUFLLEtBQUssUUFBUSxJQUFJLE9BQU8sS0FBSyxLQUFLLFNBQVMsQ0FBQztBQUM5RixDQUFDO0FBRUQsc0NBQXNDO0FBQ3RDLFNBQVMsT0FBTyxDQUFDLEtBQThCO0lBQzdDLE9BQU8sTUFBTSxDQUFDLFdBQVcsQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBRSxJQUFJLENBQUMsRUFBRSxFQUFFLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQXVCLENBQUM7QUFDM0csQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8vIFRoZSB2aWV3ZXIncyBkdXJhYmxlIHN0YXRlIGFzIG9uZSBkb2N1bWVudCAoUmVwb3J0Vmlld0NvbmZpZywgdmVyc2lvbiAxKTogYVxuLy8gc2F2ZWQgdmlldydzIGNvbmZpZy5cbi8vIFB1cmUsIHNvIHRoZSBub2RlIGhhcm5lc3MgcnVucyBpdCBhZ2FpbnN0IHRoZSBzZXJ2ZXIncyBvd24gY2FzZSB0YWJsZTogdGhlXG4vLyBydWxlcyBiZWxvdyBtaXJyb3IgdGhlIHNlcnZlcidzIFJlcG9ydFZpZXdDb25maWcgYW5kIFJlcG9ydEZpbHRlckdyb3VwVmFsdWVcbi8vIERUT3MsIGFuZCB0aGUgdHdvIG11c3QgYWdyZWUgb24gZXZlcnkgY2FzZS5cbi8vXG4vLyAtIEEgZ3JvdXAgdmFsdWUgdGFrZXMgdGhlIGtleXMgaXRzIGdyb3VwJ3MgdHlwZSBvd25zIChncm91cFZhbHVlRnJvbUFycmF5KS5cbi8vICAgT25lIHdyaXR0ZW4gaW4gYSBzaGFwZSB0aGF0IGRvZXMgbm90IGZpdCBpcyByZWZ1c2VkLCBuYW1pbmcgd2hhdCBpc1xuLy8gICB3cm9uZzsgb25lIHJlYWQgYmFjayB0aGF0IGRvZXMgbm90IGZpdCBpcyBkcm9wcGVkIHdob2xlLCBuZXZlciBhcHBsaWVkIGluXG4vLyAgIHBhcnQgKGdyb3VwVmFsdWVGcm9tU3RvcmVkKS5cbi8vIC0gQSBkb2N1bWVudCAodmlld0NvbmZpZ0Zyb21BcnJheSkgaXMgcmVmdXNlZCB3aGVuIGl0IGlzIG5vdCBvbmUsIGJyZWFrcyBhXG4vLyAgIGNhcCBvciBob2xkcyBhIG1hbGZvcm1lZCBrbm93biBrZXkuIEtleXMgdGhpcyB2aWV3ZXIgZG9lcyBub3Qga25vdywgYXRcbi8vICAgdGhlIHRvcCBhbmQgaW4gYSB0aWxlLCBhcmUga2VwdCBhcyB0aGV5IHdlcmUgYW5kIG5ldmVyIHJlYWQuIEEgZ3JvdXBcbi8vICAgdmFsdWUgdGhhdCBubyBncm91cCB0eXBlIGNvdWxkIGhvbGQgaXMgZHJvcHBlZCB3aG9sZS5cbi8vIC0gVGhlIHZpZXdlcidzIHN0YXRlIHNlcnZpY2UgdHVybnMgaXRzIHZhbHVlcyBpbnRvIHRoaXMgc2hhcGUgYW5kIGJhY2tcbi8vICAgKHRvU3RvcmVkR3JvdXBWYWx1ZSwgdG9MaXZlR3JvdXBWYWx1ZSksIGFuZCBhc2tzIHZpZXdEaWZmZXJzIHdoZXRoZXIgdGhlXG4vLyAgIHNjcmVlbiBzdGlsbCBzaG93cyB0aGUgb3BlbiB2aWV3LlxuLy8gLSBUaGUgdmlldyBzZXJ2aWNlIChSZXBvcnRWaWV3U2VydmljZSkgc2F2ZXMgYSB2aWV3IHRocm91Z2ggd2l0aFN0b3JlZEtleXNcbi8vICAgYW5kIGNvdW50cyB3aGF0IGEgdmlldyBsb3N0IHRocm91Z2ggdmlld0Ryb3BwZWRDb3VudDsgdGhlIGNoYXQgbmFtZXMgdGhlXG4vLyAgIG9wZW4gdmlldyB0aHJvdWdoIGNoYXRWaWV3RmllbGRzLlxuaW1wb3J0IHsgUmVwb3J0Q2hhdFZpZXdlclN0YXRlIH0gZnJvbSAnLi9pbnRlcmZhY2VzL3JlcG9ydC1jaGF0LXZpZXdlci1zdGF0ZS5pbnRlcmZhY2UnO1xuaW1wb3J0IHsgUmVwb3J0RHJpbGxTdGVwIH0gZnJvbSAnLi9pbnRlcmZhY2VzL3JlcG9ydC1kcmlsbC1zdGVwLmludGVyZmFjZSc7XG5pbXBvcnQgeyBSZXBvcnRUaWxlU3RhdGUgfSBmcm9tICcuL2ludGVyZmFjZXMvcmVwb3J0LXRpbGUtc3RhdGUuaW50ZXJmYWNlJztcbmltcG9ydCB7IFJlcG9ydFZpZXdDb25maWcgfSBmcm9tICcuL2ludGVyZmFjZXMvcmVwb3J0LXZpZXctY29uZmlnLmludGVyZmFjZSc7XG5pbXBvcnQgeyBSZXBvcnRWaWV3U3VtbWFyeSB9IGZyb20gJy4vaW50ZXJmYWNlcy9yZXBvcnQtdmlldy1zdW1tYXJ5LmludGVyZmFjZSc7XG5pbXBvcnQgeyBSZXBvcnRWaWV3IH0gZnJvbSAnLi9pbnRlcmZhY2VzL3JlcG9ydC12aWV3LmludGVyZmFjZSc7XG5pbXBvcnQge1xuICBDaGFydEdyYW51bGFyaXR5LFxuICBGaWx0ZXJHcm91cERlZmF1bHQsXG4gIEZpbHRlckdyb3VwVmFsdWUsXG4gIEdSQU5VTEFSSVRZX09QVElPTlMsXG4gIFJlcG9ydEZpbHRlclR5cGUsXG4gIFJlcG9ydFJlbGF0aXZlUmFuZ2UsXG4gIFJlcG9ydFNvcnQsXG59IGZyb20gJy4vaW50ZXJmYWNlcy9yZXBvcnQuaW50ZXJmYWNlJztcbmltcG9ydCB7IGRhdGVCb3VuZFN0cmluZywgZGF0ZUZyb21Cb3VuZCB9IGZyb20gJy4vcmVwb3J0LWZpbHRlci1pdGVtcyc7XG5cblxuLy8gVGhlIHZlcnNpb24gdGhpcyB2aWV3ZXIgd3JpdGVzIGFuZCByZWFkcy5cbmV4cG9ydCBjb25zdCBSRVBPUlRfVklFV19DT05GSUdfVkVSU0lPTiA9IDE7XG5cbi8vIFRoZSBjYXBzIG9mIGEgdmlldyBkb2N1bWVudCwgdGhlIHNlcnZlcidzLlxuZXhwb3J0IGNvbnN0IFZJRVdfQ09ORklHX01BWF9CWVRFUyA9IDMyICogMTAyNDtcbmV4cG9ydCBjb25zdCBWSUVXX0NPTkZJR19NQVhfR1JPVVBTID0gMTAwO1xuZXhwb3J0IGNvbnN0IFZJRVdfQ09ORklHX01BWF9USUxFUyA9IDIwMDtcbmV4cG9ydCBjb25zdCBHUk9VUF9WQUxVRV9NQVhfUElDS1MgPSA1MDA7XG5leHBvcnQgY29uc3QgRFJJTExfTUFYX0RFUFRIID0gNTtcblxuLy8gRXZlcnkgcmVsYXRpdmUgcmFuZ2UgbmFtZSB0aGUgc2VydmVyIGtub3dzLCBpbiBpdHMgZW51bSdzIG9yZGVyLiBBIHJlY29yZFxuLy8gcmF0aGVyIHRoYW4gYSBsaXN0LCBzbyB0aGUgYnVpbGQgZmFpbHMgd2hlbiBSZXBvcnRSZWxhdGl2ZVJhbmdlIGdhaW5zIGFcbi8vIG5hbWUgdGhpcyBtaXNzZXMuXG5jb25zdCBSRUxBVElWRV9SQU5HRVM6IFJlY29yZDxSZXBvcnRSZWxhdGl2ZVJhbmdlLCB0cnVlPiA9IHtcbiAgdGhpc1dlZWs6IHRydWUsXG4gIGxhc3RXZWVrOiB0cnVlLFxuICBsYXN0N0RheXM6IHRydWUsXG4gIGxhc3QzMERheXM6IHRydWUsXG4gIGxhc3QzTW9udGhzOiB0cnVlLFxuICBsYXN0Nk1vbnRoczogdHJ1ZSxcbiAgbGFzdDEyTW9udGhzOiB0cnVlLFxuICB0aGlzTW9udGg6IHRydWUsXG4gIHRoaXNRdWFydGVyOiB0cnVlLFxuICB0aGlzWWVhcjogdHJ1ZSxcbiAgeWVhclRvRGF0ZTogdHJ1ZSxcbn07XG5cbi8vIFRoZSBzYW1lIG5hbWVzIGFzIGEgbGlzdCwgaW4gdGhlIHNlcnZlciBlbnVtJ3Mgb3JkZXIgKHRoZSByZWNvcmQncyBrZXlcbi8vIG9yZGVyKTogdGhlIG9yZGVyIHRoZSBkYXRlIHBpY2tlciBvZmZlcnMgdGhlbSBpbi5cbmV4cG9ydCBjb25zdCBSRUxBVElWRV9SQU5HRV9OQU1FUyA9IE9iamVjdC5rZXlzKFJFTEFUSVZFX1JBTkdFUykgYXMgUmVwb3J0UmVsYXRpdmVSYW5nZVtdO1xuXG4vLyBUaGUga2V5cyBhIGdyb3VwIHZhbHVlIG1heSBob2xkLCBieSBpdHMgZ3JvdXAncyB0eXBlLlxuY29uc3QgR1JPVVBfVkFMVUVfS0VZUzogUmVjb3JkPFJlcG9ydEZpbHRlclR5cGUsIHJlYWRvbmx5IChrZXlvZiBGaWx0ZXJHcm91cERlZmF1bHQpW10+ID0ge1xuICBkYXRlUmFuZ2U6IFsncmVsYXRpdmUnLCAnc3RhcnQnLCAnZW5kJ10sXG4gIHNlbGVjdDogWyd2YWx1ZXMnLCAnZXhjbHVkZVZhbHVlcyddLFxuICBrZXl3b3JkOiBbJ3ZhbHVlJ10sXG4gIG51bWJlclJhbmdlOiBbJ21pbicsICdtYXgnXSxcbn07XG5cbi8vIFRoZSBrZXlzIG9mIGEgdmlldyBkb2N1bWVudCBhbmQgb2YgYSB0aWxlIHN0YXRlIHRoaXMgdmlld2VyIHJlYWRzLiBBbnlcbi8vIG90aGVyIGtleSBpcyBrZXB0IGFzIGl0IHdhcy5cbmNvbnN0IFZJRVdfQ09ORklHX0tFWVMgPSBbJ3YnLCAncGFnZUlkJywgJ2dyb3VwQnknLCAnbWF0Y2gnLCAnZ3JvdXBzJywgJ3RpbGVzJ107XG5jb25zdCBUSUxFX1NUQVRFX0tFWVMgPSBbJ3NvcnQnLCAnc2VhcmNoJywgJ2hpZGRlbicsICdkcmlsbCddO1xuXG5jb25zdCBEQVlfUEFUVEVSTiA9IC9eKFxcZHs0fSktKFxcZHsyfSktKFxcZHsyfSkkLztcblxuLy8gQSBudW1iZXIgYXMgdGV4dDogd2hhdCBhIG1hc2tlZCBpbnB1dCBzZW5kcy5cbmNvbnN0IE5VTUJFUl9QQVRURVJOID0gL15bKy1dPyg/OlxcZCsoPzpcXC5cXGQqKT98XFwuXFxkKykoPzplWystXT9cXGQrKT8kL2k7XG5cbmNvbnN0IElEX0tFWV9QQVRURVJOID0gL15bMS05XVxcZCokLztcblxuXG4vLyBXaGV0aGVyIGEgbmFtZSBpcyBhIHJlbGF0aXZlIHJhbmdlIHRoZSBzZXJ2ZXIgcmVzb2x2ZXMuXG5leHBvcnQgZnVuY3Rpb24gaXNSZWxhdGl2ZVJhbmdlKG5hbWU6IHVua25vd24pOiBuYW1lIGlzIFJlcG9ydFJlbGF0aXZlUmFuZ2Uge1xuICByZXR1cm4gdHlwZW9mIG5hbWUgPT09ICdzdHJpbmcnICYmIE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChSRUxBVElWRV9SQU5HRVMsIG5hbWUpO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gaXNDaGFydEdyYW51bGFyaXR5KHZhbHVlOiB1bmtub3duKTogdmFsdWUgaXMgQ2hhcnRHcmFudWxhcml0eSB7XG4gIHJldHVybiBHUkFOVUxBUklUWV9PUFRJT05TLnNvbWUoKG9wdGlvbikgPT4gb3B0aW9uLnZhbHVlID09PSB2YWx1ZSk7XG59XG5cbi8vIFdoZXRoZXIgdGV4dCBpcyBhIHJlYWwgY2FsZW5kYXIgZGF5IHdyaXR0ZW4gJ3l5eXktTU0tZGQnIChubyAyMDI2LTAyLTMwKS5cbmV4cG9ydCBmdW5jdGlvbiBpc0NhbGVuZGFyRGF5KHRleHQ6IHN0cmluZyk6IGJvb2xlYW4ge1xuICBjb25zdCBwYXJ0cyA9IERBWV9QQVRURVJOLmV4ZWModGV4dCk7XG4gIGlmICghcGFydHMpIHtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cblxuICBjb25zdCBbeWVhciwgbW9udGgsIGRheV0gPSBwYXJ0cy5zbGljZSgxKS5tYXAoTnVtYmVyKTtcbiAgY29uc3QgZGF0ZSA9IG5ldyBEYXRlKERhdGUuVVRDKHllYXIsIG1vbnRoIC0gMSwgZGF5KSk7XG5cbiAgcmV0dXJuIGRhdGUuZ2V0VVRDRnVsbFllYXIoKSA9PT0geWVhciAmJiBkYXRlLmdldFVUQ01vbnRoKCkgPT09IG1vbnRoIC0gMSAmJiBkYXRlLmdldFVUQ0RhdGUoKSA9PT0gZGF5O1xufVxuXG4vLyBBIG51bWJlciB3cml0dGVuIGFzIHRleHQgKGEgbWFza2VkIGlucHV0J3MgdmFsdWUpLCBvciBudWxsIHdoZW4gdGhlIHRleHRcbi8vIGlzIG5vdCBvbmUgZmluaXRlIG51bWJlci5cbmV4cG9ydCBmdW5jdGlvbiBudW1iZXJGcm9tVGV4dCh0ZXh0OiBzdHJpbmcpOiBudW1iZXIgfCBudWxsIHtcbiAgY29uc3QgbnVtYmVyID0gTlVNQkVSX1BBVFRFUk4udGVzdCh0ZXh0KSA/IE51bWJlcih0ZXh0KSA6IE5hTjtcblxuICByZXR1cm4gTnVtYmVyLmlzRmluaXRlKG51bWJlcikgPyBudW1iZXIgOiBudWxsO1xufVxuXG4vLyBBIGdyb3VwIHZhbHVlIHJlYWQgZm9yIGEgZ3JvdXAgb2YgYHR5cGVgLCBvbiBpdHMgd2F5IHRvIGJlaW5nIHN0b3JlZDogb25seVxuLy8gdGhlIHBhcnRzIHRoYXQgaG9sZCBzb21ldGhpbmcuIFRocm93cywgbmFtaW5nIHdoYXQgaXMgd3JvbmcsIHdoZW4gYSBrZXlcbi8vIGRvZXMgbm90IGJlbG9uZyB0byB0aGUgdHlwZSBvciBhIHBhcnQgYnJlYWtzIGl0cyB0eXBlJ3MgcnVsZS5cbmV4cG9ydCBmdW5jdGlvbiBncm91cFZhbHVlRnJvbUFycmF5KHZhbHVlOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiwgdHlwZTogUmVwb3J0RmlsdGVyVHlwZSk6IEZpbHRlckdyb3VwRGVmYXVsdCB7XG4gIHJlcXVpcmVHcm91cEtleXModmFsdWUsIHR5cGUpO1xuXG4gIHN3aXRjaCAodHlwZSkge1xuICAgIGNhc2UgJ2RhdGVSYW5nZSc6XG4gICAgICByZXR1cm4gZGF0ZVJhbmdlVmFsdWUodmFsdWUpO1xuXG4gICAgY2FzZSAnc2VsZWN0JzpcbiAgICAgIHJldHVybiBzZWxlY3RWYWx1ZSh2YWx1ZSk7XG5cbiAgICBjYXNlICdudW1iZXJSYW5nZSc6XG4gICAgICByZXR1cm4gbnVtYmVyUmFuZ2VWYWx1ZSh2YWx1ZSk7XG5cbiAgICBkZWZhdWx0OlxuICAgICAgcmV0dXJuIGtleXdvcmRWYWx1ZSh2YWx1ZSk7XG4gIH1cbn1cblxuLy8gQSBncm91cCB2YWx1ZSByZWFkIGJhY2sgKGEgc2F2ZWQgdmlldykgZm9yIGEgZ3JvdXAgb2YgYHR5cGVgOiB3aGF0XG4vLyBncm91cFZhbHVlRnJvbUFycmF5IGdpdmVzLCBvciBudWxsIHdoZW4gaXQgd291bGQgcmVmdXNlIGl0LlxuZXhwb3J0IGZ1bmN0aW9uIGdyb3VwVmFsdWVGcm9tU3RvcmVkKHZhbHVlOiB1bmtub3duLCB0eXBlOiBSZXBvcnRGaWx0ZXJUeXBlKTogRmlsdGVyR3JvdXBEZWZhdWx0IHwgbnVsbCB7XG4gIGlmICghaXNQbGFpbk9iamVjdCh2YWx1ZSkpIHtcbiAgICByZXR1cm4gbnVsbDtcbiAgfVxuXG4gIHRyeSB7XG4gICAgcmV0dXJuIGdyb3VwVmFsdWVGcm9tQXJyYXkodmFsdWUsIHR5cGUpO1xuICB9IGNhdGNoIHtcbiAgICByZXR1cm4gbnVsbDtcbiAgfVxufVxuXG4vLyBBIHZpZXcgZG9jdW1lbnQgcmVhZCBmb3Igc3RvcmluZyBvciBhcHBseWluZy4gVGhyb3dzIHdoZW4gaXQgaXMgbm90IGFcbi8vIHZlcnNpb24gMSBkb2N1bWVudCwgYnJlYWtzIGEgY2FwIG9yIGhvbGRzIGEgbWFsZm9ybWVkIGtub3duIGtleS5cbmV4cG9ydCBmdW5jdGlvbiB2aWV3Q29uZmlnRnJvbUFycmF5KGlucHV0OiB1bmtub3duKTogUmVwb3J0Vmlld0NvbmZpZyB7XG4gIGNvbnN0IGRvYyA9IHJlcXVpcmVPYmplY3QoaW5wdXQsICdBIHZpZXcgY29uZmlnIG11c3QgYmUgYW4gb2JqZWN0LicpO1xuICByZXF1aXJlU2l6ZShkb2MpO1xuICByZXF1aXJlVmVyc2lvbihkb2Mudik7XG5cbiAgY29uc3QgY29uZmlnID0geyB2OiBSRVBPUlRfVklFV19DT05GSUdfVkVSU0lPTiwgLi4ub3RoZXJLZXlzKGRvYywgVklFV19DT05GSUdfS0VZUykgfSBhcyBSZXBvcnRWaWV3Q29uZmlnO1xuICBjb25zdCBwYWdlSWQgPSBvcHRpb25hbElkKGRvYy5wYWdlSWQsICdwYWdlSWQgbXVzdCBiZSBhIHBhZ2UgaWQuJyk7XG4gIGlmIChwYWdlSWQgIT09IG51bGwpIHtcbiAgICBjb25maWcucGFnZUlkID0gcGFnZUlkO1xuICB9XG5cbiAgaWYgKGlzU2V0KGRvYy5ncm91cEJ5KSkge1xuICAgIGNvbmZpZy5ncm91cEJ5ID0gcmVxdWlyZUdyYW51bGFyaXR5KGRvYy5ncm91cEJ5LCAnZ3JvdXBCeSBtdXN0IGJlIGEgdGltZSBncmFpbi4nKTtcbiAgfVxuXG4gIGlmIChpc1NldChkb2MubWF0Y2gpKSB7XG4gICAgY29uZmlnLm1hdGNoID0gcmVxdWlyZU1hdGNoKGRvYy5tYXRjaCk7XG4gIH1cblxuICBpZiAoaXNTZXQoZG9jLmdyb3VwcykpIHtcbiAgICBjb25maWcuZ3JvdXBzID0gdmlld0dyb3Vwcyhkb2MuZ3JvdXBzKTtcbiAgfVxuXG4gIGlmIChpc1NldChkb2MudGlsZXMpKSB7XG4gICAgY29uZmlnLnRpbGVzID0gdmlld1RpbGVzKGRvYy50aWxlcyk7XG4gIH1cblxuICByZXR1cm4gY29uZmlnO1xufVxuXG4vLyBBIGdyb3VwJ3MgdmFsdWUgYXMgYSB2aWV3IHN0b3JlcyBpdCwgcmVhZCBmb3IgdGhlIGtleXMgaXRzXG4vLyBncm91cCdzIHR5cGUgb3ducywgb3IgbnVsbCB3aGVuIGl0IGhvbGRzIG5vdGhpbmcuIEEgZGF0ZSByYW5nZSB0aGF0IHN0aWxsXG4vLyBjYXJyaWVzIGl0cyByZWxhdGl2ZSBwcmVzZXQgaXMgc3RvcmVkIGFzIHRoYXQgcHJlc2V0IHdoYXRldmVyIHRvZGF5IGlzOiB0aGVcbi8vIHZpZXdlciBkaWQgbm90IGVkaXQgaXQsIHNvIGEgdmlldyBzYXZlZCBhZnRlciBtaWRuaWdodCB3aXRoIHRoZSBwYWdlIHN0aWxsXG4vLyBvcGVuIGtlZXBzIHJvbGxpbmcuXG5leHBvcnQgZnVuY3Rpb24gdG9TdG9yZWRHcm91cFZhbHVlKFxuICB0eXBlOiBSZXBvcnRGaWx0ZXJUeXBlLFxuICB2YWx1ZTogRmlsdGVyR3JvdXBWYWx1ZSB8IG51bGwgfCB1bmRlZmluZWQsXG4pOiBGaWx0ZXJHcm91cERlZmF1bHQgfCBudWxsIHtcbiAgaWYgKCF2YWx1ZSkge1xuICAgIHJldHVybiBudWxsO1xuICB9XG5cbiAgc3dpdGNoICh0eXBlKSB7XG4gICAgY2FzZSAnZGF0ZVJhbmdlJzpcbiAgICAgIHJldHVybiBpc1JlbGF0aXZlUmFuZ2UodmFsdWUucHJlc2V0KVxuICAgICAgICA/IHsgcmVsYXRpdmU6IHZhbHVlLnByZXNldCB9XG4gICAgICAgIDogc3RvcmVkT3JOdWxsKHsgc3RhcnQ6IGRhdGVCb3VuZFN0cmluZyh2YWx1ZS5zdGFydCksIGVuZDogZGF0ZUJvdW5kU3RyaW5nKHZhbHVlLmVuZCkgfSk7XG5cbiAgICBjYXNlICdzZWxlY3QnOiB7XG4gICAgICBjb25zdCBleGNsdWRlVmFsdWVzID0ga2VwdFBpY2tzKHZhbHVlLmV4Y2x1ZGVWYWx1ZXMpO1xuXG4gICAgICByZXR1cm4gc3RvcmVkT3JOdWxsKGV4Y2x1ZGVWYWx1ZXMgPyB7IGV4Y2x1ZGVWYWx1ZXMgfSA6IHsgdmFsdWVzOiBrZXB0UGlja3ModmFsdWUudmFsdWVzKSB9KTtcbiAgICB9XG5cbiAgICBjYXNlICdudW1iZXJSYW5nZSc6XG4gICAgICByZXR1cm4gc3RvcmVkT3JOdWxsKHsgbWluOiBmaW5pdGVOdW1iZXIodmFsdWUubWluKSwgbWF4OiBmaW5pdGVOdW1iZXIodmFsdWUubWF4KSB9KTtcblxuICAgIGRlZmF1bHQ6XG4gICAgICByZXR1cm4gc3RvcmVkT3JOdWxsKHsgdmFsdWU6IHZhbHVlLnZhbHVlPy50cmltKCkgfHwgdW5kZWZpbmVkIH0pO1xuICB9XG59XG5cbi8vIEEgZ3JvdXAgdmFsdWUgaW4gaXRzIHN0b3JlZCBzaGFwZSBhcyB0aGUgdmFsdWUgdGhlIGJhcnMgYW5kIHRoZSByZXF1ZXN0c1xuLy8gcmVhZDogYSByZWxhdGl2ZSBwcmVzZXQgYXMgdG9kYXkncyBkYXlzIGluIHRoZSByZXBvcnQncyB6b25lLCBjYXJyeWluZyBpdHNcbi8vIG5hbWU7IGZpeGVkIGRheXMgYXMgZGF0ZXM7IGFueSBvdGhlciB2YWx1ZSBhcyBpdCBpcy4gTnVsbCB3aGVuIGl0IGhvbGRzXG4vLyBub3RoaW5nLCBvciBuYW1lcyBhIHByZXNldCBgcmVzb2x2ZVJlbGF0aXZlYCBkb2VzIG5vdCBrbm93LlxuZXhwb3J0IGZ1bmN0aW9uIHRvTGl2ZUdyb3VwVmFsdWUoXG4gIHR5cGU6IFJlcG9ydEZpbHRlclR5cGUsXG4gIHN0b3JlZDogRmlsdGVyR3JvdXBEZWZhdWx0IHwgbnVsbCB8IHVuZGVmaW5lZCxcbiAgcmVzb2x2ZVJlbGF0aXZlOiAobmFtZTogc3RyaW5nKSA9PiB7IHN0YXJ0OiBEYXRlOyBlbmQ6IERhdGUgfSB8IG51bGwsXG4pOiBGaWx0ZXJHcm91cFZhbHVlIHwgbnVsbCB7XG4gIGlmICghc3RvcmVkIHx8IGhvbGRzTm90aGluZyhzdG9yZWQpKSB7XG4gICAgcmV0dXJuIG51bGw7XG4gIH1cblxuICBpZiAodHlwZSAhPT0gJ2RhdGVSYW5nZScpIHtcbiAgICByZXR1cm4geyAuLi5zdG9yZWQgfTtcbiAgfVxuXG4gIGlmIChzdG9yZWQucmVsYXRpdmUpIHtcbiAgICBjb25zdCByYW5nZSA9IHJlc29sdmVSZWxhdGl2ZShzdG9yZWQucmVsYXRpdmUpO1xuXG4gICAgcmV0dXJuIHJhbmdlID8geyBzdGFydDogcmFuZ2Uuc3RhcnQsIGVuZDogcmFuZ2UuZW5kLCBwcmVzZXQ6IHN0b3JlZC5yZWxhdGl2ZSB9IDogbnVsbDtcbiAgfVxuXG4gIHJldHVybiB7IHN0YXJ0OiBkYXRlRnJvbUJvdW5kKHN0b3JlZC5zdGFydCksIGVuZDogZGF0ZUZyb21Cb3VuZChzdG9yZWQuZW5kKSB9O1xufVxuXG4vLyBXaGV0aGVyIHRoZSBzY3JlZW4ncyBzdGF0ZSBkaWZmZXJzIGZyb20gdGhlIHZpZXcgaXQgb3BlbmVkIG9uLiBgY3VycmVudGBcbi8vIGlzIGEgc25hcHNob3QsIHNvIGl0IGhvbGRzIGV2ZXJ5IGdyb3VwIHRoZSByZXBvcnQgaGFzOyBhIGdyb3VwIG9ubHkgYGJhc2VgXG4vLyBob2xkcyBpcyBvbmUgdGhlIHJlcG9ydCBubyBsb25nZXIgaGFzLCBhbmQgaXMgbm90IGNvbXBhcmVkLiBBIGdyb3VwIGBiYXNlYFxuLy8gZG9lcyBub3QgaG9sZCB3YXMgYWRkZWQgYWZ0ZXIgdGhlIHZpZXcgd2FzIHNhdmVkOiBpdCBpcyBjb21wYXJlZCB3aXRoIGl0c1xuLy8gdmFsdWUgaW4gYGF1dGhvcmVkYCAodGhlIHJlcG9ydCdzIGRlZmF1bHRzKSwgc28gbGVhdmluZyBpdCBhdCBpdHMgZGVmYXVsdFxuLy8gY2hhbmdlcyBub3RoaW5nLiBUaGUgcGFnZSBpcyBub3QgY29tcGFyZWQgKG1vdmluZyB0byBhbm90aGVyIHBhZ2UgZG9lcyBub3Rcbi8vIGVkaXQgYSB2aWV3KSwgYW5kIG5laXRoZXIgYXJlIGtleXMgdGhpcyB2aWV3ZXIgZG9lcyBub3Qga25vdy4gUGlja3MgYXJlXG4vLyBjb21wYXJlZCBpbiBhbnkgb3JkZXIuXG5leHBvcnQgZnVuY3Rpb24gdmlld0RpZmZlcnMoXG4gIGJhc2U6IFJlcG9ydFZpZXdDb25maWcsXG4gIGN1cnJlbnQ6IFJlcG9ydFZpZXdDb25maWcsXG4gIGF1dGhvcmVkOiBSZXBvcnRWaWV3Q29uZmlnIHwgbnVsbCA9IG51bGwsXG4pOiBib29sZWFuIHtcbiAgcmV0dXJuIChiYXNlLm1hdGNoID8/ICdhbGwnKSAhPT0gKGN1cnJlbnQubWF0Y2ggPz8gJ2FsbCcpXG4gICAgfHwgKGJhc2UuZ3JvdXBCeSA/PyBudWxsKSAhPT0gKGN1cnJlbnQuZ3JvdXBCeSA/PyBudWxsKVxuICAgIHx8IGdyb3Vwc0RpZmZlcihiYXNlLCBjdXJyZW50LCBhdXRob3JlZClcbiAgICB8fCB0aWxlc0RpZmZlcihiYXNlLnRpbGVzID8/IHt9LCBjdXJyZW50LnRpbGVzID8/IHt9KTtcbn1cblxuLy8gV2hldGhlciB0d28gc3RvcmVkIGdyb3VwIHZhbHVlcyBhcmUgdGhlIHNhbWUgZmlsdGVyLCBhcyB2aWV3RGlmZmVycyByZWFkc1xuLy8gYSBncm91cDogcGlja3MgaW4gYW55IG9yZGVyLCB0ZXh0IHRyaW1tZWQsIGFuIGVtcHR5IHZhbHVlIHJlYWQgYXMgbm9uZS5cbmV4cG9ydCBmdW5jdGlvbiBzYW1lU3RvcmVkR3JvdXBWYWx1ZShcbiAgYTogRmlsdGVyR3JvdXBEZWZhdWx0IHwgbnVsbCB8IHVuZGVmaW5lZCxcbiAgYjogRmlsdGVyR3JvdXBEZWZhdWx0IHwgbnVsbCB8IHVuZGVmaW5lZCxcbik6IGJvb2xlYW4ge1xuICByZXR1cm4gc3RvcmVkVmFsdWVLZXkoYSkgPT09IHN0b3JlZFZhbHVlS2V5KGIpO1xufVxuXG4vLyBBIGRyaWxsIHBhdGgga2VwdCB0byB3aGF0IGEgdGlsZSBjYW4gY2Fycnk6IGl0cyBzdGVwcyB1cCB0byB0aGUgZmlyc3QgdGhhdFxuLy8gaXMgbm90IGEgdGltZSBsZXZlbCB3aXRoIGEgcGxhaW4gdmFsdWUgKHRoZSBzdGVwcyBiZWZvcmUgaXQgYXJlIGtlcHQpLCBhdFxuLy8gbW9zdCBEUklMTF9NQVhfREVQVEggb2YgdGhlbS5cbmV4cG9ydCBmdW5jdGlvbiBjbGVhbkRyaWxsUGF0aChwYXRoOiByZWFkb25seSB1bmtub3duW10gfCBudWxsIHwgdW5kZWZpbmVkKTogUmVwb3J0RHJpbGxTdGVwW10ge1xuICBjb25zdCBrZXB0OiBSZXBvcnREcmlsbFN0ZXBbXSA9IFtdO1xuXG4gIGZvciAoY29uc3Qgc3RlcCBvZiBwYXRoID8/IFtdKSB7XG4gICAgaWYgKCFpc1BsYWluT2JqZWN0KHN0ZXApIHx8ICFpc0NoYXJ0R3JhbnVsYXJpdHkoc3RlcC5sZXZlbCkgfHwgIWlzRHJpbGxWYWx1ZShzdGVwLnZhbHVlKVxuICAgICAgfHwga2VwdC5sZW5ndGggPT09IERSSUxMX01BWF9ERVBUSCkge1xuICAgICAgYnJlYWs7XG4gICAgfVxuXG4gICAga2VwdC5wdXNoKHsgbGV2ZWw6IHN0ZXAubGV2ZWwsIHZhbHVlOiBzdGVwLnZhbHVlIH0pO1xuICB9XG5cbiAgcmV0dXJuIGtlcHQ7XG59XG5cbi8vIFdoZXRoZXIgdHdvIGRyaWxsIHBhdGhzIGFyZSB0aGUgc2FtZSBzdGVwcy4gQSB2YWx1ZSBpcyBjb21wYXJlZCBhcyB0ZXh0LFxuLy8gc28gMjAyNiBhbmQgJzIwMjYnIGFyZSB0aGUgc2FtZSBzdGVwLlxuZXhwb3J0IGZ1bmN0aW9uIHNhbWVEcmlsbFBhdGgoXG4gIGE6IHJlYWRvbmx5IFJlcG9ydERyaWxsU3RlcFtdIHwgbnVsbCB8IHVuZGVmaW5lZCxcbiAgYjogcmVhZG9ubHkgUmVwb3J0RHJpbGxTdGVwW10gfCBudWxsIHwgdW5kZWZpbmVkLFxuKTogYm9vbGVhbiB7XG4gIHJldHVybiBkcmlsbEtleShhKSA9PT0gZHJpbGxLZXkoYik7XG59XG5cbi8vIEEgdmlldydzIGNvbmZpZyB0byBzYXZlOiB0aGUgc2NyZWVuIChgc2NyZWVuYCwgYSBzbmFwc2hvdCksIHdpdGggdGhlIGtleXNcbi8vIHRoaXMgdmlld2VyIGRvZXMgbm90IGtub3cga2VwdCBmcm9tIHRoZSBzdG9yZWQgZG9jdW1lbnQgKGBzdG9yZWRgKSwgYXQgdGhlXG4vLyB0b3AgYW5kIGluIGVhY2ggdGlsZS4gVGhleSBhcmUgbmV2ZXIgcmVhZCBoZXJlLCBhbmQgc2F2aW5nIG11c3Qgbm90IGxvc2Vcbi8vIHRoZW0uXG5leHBvcnQgZnVuY3Rpb24gd2l0aFN0b3JlZEtleXMoc3RvcmVkOiBSZXBvcnRWaWV3Q29uZmlnIHwgbnVsbCB8IHVuZGVmaW5lZCwgc2NyZWVuOiBSZXBvcnRWaWV3Q29uZmlnKTogUmVwb3J0Vmlld0NvbmZpZyB7XG4gIGlmICghc3RvcmVkKSB7XG4gICAgcmV0dXJuIHNjcmVlbjtcbiAgfVxuXG4gIGNvbnN0IHRpbGVzOiBSZWNvcmQ8bnVtYmVyLCBSZXBvcnRUaWxlU3RhdGU+ID0geyAuLi5zY3JlZW4udGlsZXMgfTtcblxuICBPYmplY3QuZW50cmllcyhzdG9yZWQudGlsZXMgPz8ge30pLmZvckVhY2goKFtjb21wb25lbnRJZCwgdGlsZV0pID0+IHtcbiAgICBjb25zdCBrZXB0ID0gaXNQbGFpbk9iamVjdCh0aWxlKSA/IG90aGVyS2V5cyh0aWxlLCBUSUxFX1NUQVRFX0tFWVMpIDoge307XG5cbiAgICBpZiAoT2JqZWN0LmtleXMoa2VwdCkubGVuZ3RoKSB7XG4gICAgICB0aWxlc1tOdW1iZXIoY29tcG9uZW50SWQpXSA9IHsgLi4ua2VwdCwgLi4udGlsZXNbTnVtYmVyKGNvbXBvbmVudElkKV0gfTtcbiAgICB9XG4gIH0pO1xuXG4gIGNvbnN0IGNvbmZpZzogUmVwb3J0Vmlld0NvbmZpZyA9IHsgLi4ub3RoZXJLZXlzKHN0b3JlZCBhcyB1bmtub3duIGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+LCBWSUVXX0NPTkZJR19LRVlTKSwgLi4uc2NyZWVuIH07XG4gIGRlbGV0ZSBjb25maWcudGlsZXM7XG5cbiAgcmV0dXJuIE9iamVjdC5rZXlzKHRpbGVzKS5sZW5ndGggPyB7IC4uLmNvbmZpZywgdGlsZXMgfSA6IGNvbmZpZztcbn1cblxuLy8gSG93IG1hbnkgc2V0dGluZ3Mgb2YgYSBzYXZlZCB2aWV3IG5vIGxvbmdlciBhcHBseSBiZWNhdXNlIHRoZSByZXBvcnRcbi8vIGNoYW5nZWQ6IHdoYXQgdGhlIHNlcnZlciBsZWZ0IG91dCB3aGVuIGl0IHJlYWQgdGhlIHZpZXcgKGBkcm9wcGVkYCksIGFuZFxuLy8gd2hhdCB0aGUgdmlld2VyIGNvdWxkIG5vdCBhcHBseSAoYGFwcGxpZWRgIGlzIHRoZSB2aWV3IGFzIGl0IGFwcGxpZWQsIHRoZVxuLy8gc3RhdGUgc2VydmljZSdzIGJhc2UpOiBhIGdyb3VwIHZhbHVlIHRoYXQgbm8gbG9uZ2VyIGZpdHMgaXRzIGdyb3VwLCBhbmQgYVxuLy8gbGlzdCBzb3J0LCBzZWFyY2ggb3IgaGlkZGVuIGNvbHVtbnMsIG9yIGEgY2hhcnQncyBkcmlsbCBwYXRoLCBpdHMgdGlsZSBjYW5cbi8vIG5vIGxvbmdlciB0YWtlIChhIGxpc3QgY29sdW1uIGdvbmUsIGEgY2hhcnQgdHVybmVkIGludG8gYSBsaXN0KS5cbmV4cG9ydCBmdW5jdGlvbiB2aWV3RHJvcHBlZENvdW50KHZpZXc6IFBpY2s8UmVwb3J0VmlldywgJ2NvbmZpZycgfCAnZHJvcHBlZCc+LCBhcHBsaWVkOiBSZXBvcnRWaWV3Q29uZmlnKTogbnVtYmVyIHtcbiAgY29uc3QgZHJvcHBlZCA9IHZpZXcuZHJvcHBlZDtcbiAgY29uc3QgZ3JvdXBzID0gT2JqZWN0LmVudHJpZXModmlldy5jb25maWc/Lmdyb3VwcyA/PyB7fSlcbiAgICAuZmlsdGVyKChbZ3JvdXBJZCwgdmFsdWVdKSA9PiB2YWx1ZSAhPT0gbnVsbCAmJiAhT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKGFwcGxpZWQuZ3JvdXBzID8/IHt9LCBncm91cElkKSlcbiAgICAubGVuZ3RoO1xuICBjb25zdCB0aWxlcyA9IE9iamVjdC5lbnRyaWVzKHZpZXcuY29uZmlnPy50aWxlcyA/PyB7fSlcbiAgICAucmVkdWNlKChjb3VudCwgW2NvbXBvbmVudElkLCB0aWxlXSkgPT4gY291bnQgKyB0aWxlS2V5c0xvc3QodGlsZSwgYXBwbGllZC50aWxlcz8uW051bWJlcihjb21wb25lbnRJZCldKSwgMCk7XG5cbiAgcmV0dXJuIChkcm9wcGVkPy5ncm91cHM/Lmxlbmd0aCA/PyAwKSArIChkcm9wcGVkPy50aWxlcz8ubGVuZ3RoID8/IDApICsgKGRyb3BwZWQ/LnBhZ2UgPyAxIDogMCkgKyBncm91cHMgKyB0aWxlcztcbn1cblxuLy8gVGhlIG5vdGUgYSB2aWV3IG9wZW5zIHdpdGggd2hlbiBzb21lIG9mIGl0cyBzZXR0aW5ncyBubyBsb25nZXIgYXBwbHksIG9yXG4vLyBudWxsIHdoZW4gZXZlcnkgc2V0dGluZyBhcHBsaWVzLiBPbmx5IGEgdmlld2VyIHdobyBtYXkgY2hhbmdlIHRoZSB2aWV3XG4vLyAoYGNhbkNoYW5nZWApIGlzIHRvbGQgdG8gc2F2ZSBpdC5cbmV4cG9ydCBmdW5jdGlvbiB2aWV3RHJvcHBlZE1lc3NhZ2UoY291bnQ6IG51bWJlciwgY2FuQ2hhbmdlID0gdHJ1ZSk6IHN0cmluZyB8IG51bGwge1xuICBpZiAoY291bnQgPCAxKSB7XG4gICAgcmV0dXJuIG51bGw7XG4gIH1cblxuICBjb25zdCBub3RlID0gY291bnQgPT09IDFcbiAgICA/ICcxIHNldHRpbmcgaW4gdGhpcyB2aWV3IG5vIGxvbmdlciBhcHBsaWVzLCBiZWNhdXNlIHRoZSByZXBvcnQgY2hhbmdlZC4nXG4gICAgOiBgJHtjb3VudH0gc2V0dGluZ3MgaW4gdGhpcyB2aWV3IG5vIGxvbmdlciBhcHBseSwgYmVjYXVzZSB0aGUgcmVwb3J0IGNoYW5nZWQuYDtcblxuICByZXR1cm4gY2FuQ2hhbmdlID8gYCR7bm90ZX0gU2F2ZSBjaGFuZ2VzIHRvIHVwZGF0ZSB0aGUgdmlldy5gIDogbm90ZTtcbn1cblxuLy8gVGhlIG9wZW4gdmlldyBhcyBhIGNoYXQgdHVybiBuYW1lcyBpdDogaXRzIGlkLCBhbmQgd2hldGhlciB0aGUgc2NyZWVuXG4vLyBkaWZmZXJzIGZyb20gaXQuIEJvdGggYXJlIGxlZnQgb3V0IHdoaWxlIG5vIHZpZXcgaXMgb3Blbi5cbmV4cG9ydCBmdW5jdGlvbiBjaGF0Vmlld0ZpZWxkcyhcbiAgb3BlblZpZXc6IFBpY2s8UmVwb3J0Vmlld1N1bW1hcnksICdpZCc+IHwgbnVsbCxcbiAgdmlld0NoYW5nZWQ6IGJvb2xlYW4sXG4pOiBQaWNrPFJlcG9ydENoYXRWaWV3ZXJTdGF0ZSwgJ3ZpZXdJZCcgfCAndmlld0NoYW5nZWQnPiB7XG4gIHJldHVybiBvcGVuVmlldyA/IHsgdmlld0lkOiBvcGVuVmlldy5pZCwgdmlld0NoYW5nZWQgfSA6IHt9O1xufVxuXG5mdW5jdGlvbiBncm91cHNEaWZmZXIoYmFzZTogUmVwb3J0Vmlld0NvbmZpZywgY3VycmVudDogUmVwb3J0Vmlld0NvbmZpZywgYXV0aG9yZWQ6IFJlcG9ydFZpZXdDb25maWcgfCBudWxsKTogYm9vbGVhbiB7XG4gIHJldHVybiBPYmplY3QuZW50cmllcyhjdXJyZW50Lmdyb3VwcyA/PyB7fSkuc29tZSgoW2dyb3VwSWQsIHZhbHVlXSkgPT4ge1xuICAgIGNvbnN0IGtlcHQgPSBiYXNlLmdyb3VwcyAmJiBPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwoYmFzZS5ncm91cHMsIGdyb3VwSWQpXG4gICAgICA/IGJhc2UuZ3JvdXBzW051bWJlcihncm91cElkKV1cbiAgICAgIDogYXV0aG9yZWQ/Lmdyb3Vwcz8uW051bWJlcihncm91cElkKV07XG5cbiAgICByZXR1cm4gc3RvcmVkVmFsdWVLZXkoa2VwdCkgIT09IHN0b3JlZFZhbHVlS2V5KHZhbHVlKTtcbiAgfSk7XG59XG5cbmZ1bmN0aW9uIHRpbGVzRGlmZmVyKGJhc2U6IFJlY29yZDxudW1iZXIsIFJlcG9ydFRpbGVTdGF0ZT4sIGN1cnJlbnQ6IFJlY29yZDxudW1iZXIsIFJlcG9ydFRpbGVTdGF0ZT4pOiBib29sZWFuIHtcbiAgY29uc3QgaWRzID0gbmV3IFNldChbLi4uT2JqZWN0LmtleXMoYmFzZSksIC4uLk9iamVjdC5rZXlzKGN1cnJlbnQpXS5tYXAoTnVtYmVyKSk7XG5cbiAgcmV0dXJuIFsuLi5pZHNdLnNvbWUoKGNvbXBvbmVudElkKSA9PiB0aWxlU3RhdGVLZXkoYmFzZVtjb21wb25lbnRJZF0pICE9PSB0aWxlU3RhdGVLZXkoY3VycmVudFtjb21wb25lbnRJZF0pKTtcbn1cblxuLy8gSG93IG1hbnkga2V5cyBvZiBhIHN0b3JlZCB0aWxlIHN0YXRlIHRoZSB0aWxlLCBhcyBpdCBhcHBsaWVkLCBsb3N0OiBhXG4vLyBzb3J0LCBhIHNlYXJjaCBvciBhIGRyaWxsIHBhdGggaXQgbm8gbG9uZ2VyIGhhcywgYW5kIGhpZGRlbiBjb2x1bW5zIGl0XG4vLyBrZXB0IGZld2VyIG9mLlxuZnVuY3Rpb24gdGlsZUtleXNMb3N0KHN0b3JlZDogUmVwb3J0VGlsZVN0YXRlIHwgdW5kZWZpbmVkLCBhcHBsaWVkOiBSZXBvcnRUaWxlU3RhdGUgfCB1bmRlZmluZWQpOiBudW1iZXIge1xuICBpZiAoIXN0b3JlZCkge1xuICAgIHJldHVybiAwO1xuICB9XG5cbiAgcmV0dXJuIFtcbiAgICAhIXN0b3JlZC5zb3J0Py5jb2x1bW4gJiYgIWFwcGxpZWQ/LnNvcnQ/LmNvbHVtbixcbiAgICAhIXN0b3JlZC5zZWFyY2ggJiYgIWFwcGxpZWQ/LnNlYXJjaCxcbiAgICAoc3RvcmVkLmhpZGRlbj8ubGVuZ3RoID8/IDApID4gKGFwcGxpZWQ/LmhpZGRlbj8ubGVuZ3RoID8/IDApLFxuICAgIChzdG9yZWQuZHJpbGw/Lmxlbmd0aCA/PyAwKSA+IDAgJiYgIWFwcGxpZWQ/LmRyaWxsPy5sZW5ndGgsXG4gIF0uZmlsdGVyKEJvb2xlYW4pLmxlbmd0aDtcbn1cblxuLy8gT25lIHRleHQgZm9yIGEgc3RvcmVkIGdyb3VwIHZhbHVlLCB0aGUgc2FtZSBmb3IgZXZlcnkgd2F5IG9mIHdyaXRpbmcgdGhlXG4vLyBzYW1lIGZpbHRlcjogcGlja3MgaW4gYW55IG9yZGVyLCB0ZXh0IHRyaW1tZWQsIGFuZCBhbiBlbXB0eSB2YWx1ZSByZWFkIGFzXG4vLyBub25lLlxuZnVuY3Rpb24gc3RvcmVkVmFsdWVLZXkodmFsdWU6IEZpbHRlckdyb3VwRGVmYXVsdCB8IG51bGwgfCB1bmRlZmluZWQpOiBzdHJpbmcge1xuICBjb25zdCBzdG9yZWQgPSB2YWx1ZSA/PyB7fTtcbiAgY29uc3QgcGlja3MgPSAobGlzdDogdW5rbm93bltdIHwgdW5kZWZpbmVkKSA9PiBbLi4uKGtlcHRQaWNrcyhsaXN0KSA/PyBbXSldLm1hcChTdHJpbmcpLnNvcnQoKTtcblxuICByZXR1cm4gSlNPTi5zdHJpbmdpZnkoW1xuICAgIHN0b3JlZC5yZWxhdGl2ZSA/PyBudWxsLFxuICAgIHN0b3JlZC5zdGFydD8uc2xpY2UoMCwgMTApID8/IG51bGwsXG4gICAgc3RvcmVkLmVuZD8uc2xpY2UoMCwgMTApID8/IG51bGwsXG4gICAgcGlja3Moc3RvcmVkLnZhbHVlcyksXG4gICAgcGlja3Moc3RvcmVkLmV4Y2x1ZGVWYWx1ZXMpLFxuICAgIChzdG9yZWQudmFsdWUgPz8gJycpLnRyaW0oKSxcbiAgICBmaW5pdGVOdW1iZXIoc3RvcmVkLm1pbikgPz8gbnVsbCxcbiAgICBmaW5pdGVOdW1iZXIoc3RvcmVkLm1heCkgPz8gbnVsbCxcbiAgXSk7XG59XG5cbi8vIE9uZSB0ZXh0IGZvciBhIHRpbGUncyBzdGF0ZSwgb3ZlciB0aGUga2V5cyB0aGlzIHZpZXdlciByZWFkcy4gTm8gZGlyZWN0aW9uXG4vLyByZWFkcyBhcyBhc2NlbmRpbmcsIHRoZSB3YXkgYSBsaXN0IGFwcGxpZXMgaXQuXG5mdW5jdGlvbiB0aWxlU3RhdGVLZXkodGlsZTogUmVwb3J0VGlsZVN0YXRlIHwgdW5kZWZpbmVkKTogc3RyaW5nIHtcbiAgcmV0dXJuIEpTT04uc3RyaW5naWZ5KFtcbiAgICB0aWxlPy5zb3J0Py5jb2x1bW4gPyBbdGlsZS5zb3J0LmNvbHVtbiwgdGlsZS5zb3J0LmRpcmVjdGlvbiA/PyAnYXNjJ10gOiBudWxsLFxuICAgIHRpbGU/LnNlYXJjaCA/PyAnJyxcbiAgICBbLi4uKHRpbGU/LmhpZGRlbiA/PyBbXSldLnNvcnQoKSxcbiAgICBkcmlsbEtleSh0aWxlPy5kcmlsbCksXG4gIF0pO1xufVxuXG5mdW5jdGlvbiBkcmlsbEtleShwYXRoOiByZWFkb25seSBSZXBvcnREcmlsbFN0ZXBbXSB8IG51bGwgfCB1bmRlZmluZWQpOiBzdHJpbmcge1xuICByZXR1cm4gSlNPTi5zdHJpbmdpZnkoKHBhdGggPz8gW10pXG4gICAgLm1hcCgoc3RlcCkgPT4gW3N0ZXAubGV2ZWwsIHN0ZXAudmFsdWUgPT09IG51bGwgfHwgc3RlcC52YWx1ZSA9PT0gdW5kZWZpbmVkID8gbnVsbCA6IFN0cmluZyhzdGVwLnZhbHVlKV0pKTtcbn1cblxuLy8gVGhlIHBpY2tzIG9mIGEgbGlzdCB3aXRoIGJsYW5rcyAobnVsbCwgJycpIGxlZnQgb3V0LCBvciB1bmRlZmluZWQgd2hlbiBub25lXG4vLyBpcyBsZWZ0LlxuZnVuY3Rpb24ga2VwdFBpY2tzKGxpc3Q6IHVua25vd25bXSB8IG51bGwgfCB1bmRlZmluZWQpOiB1bmtub3duW10gfCB1bmRlZmluZWQge1xuICBjb25zdCBrZXB0ID0gKGxpc3QgPz8gW10pLmZpbHRlcigocGljaykgPT4gaXNTZXQocGljaykgJiYgcGljayAhPT0gJycpO1xuXG4gIHJldHVybiBrZXB0Lmxlbmd0aCA/IGtlcHQgOiB1bmRlZmluZWQ7XG59XG5cbi8vIEEgcmFuZ2UgZW5kIGFzIGEgbnVtYmVyLiBBIG1hc2tlZCBpbnB1dCBzZW5kcyBpdHMgbnVtYmVyIGFzIHRleHQsIHNvXG4vLyBudW1lcmljIHRleHQgaXMgcmVhZCBhcyBpdHMgbnVtYmVyLCBhcyBib3VuZFBhcnQgcmVhZHMgaXQuXG5leHBvcnQgZnVuY3Rpb24gZmluaXRlTnVtYmVyKHZhbHVlOiB1bmtub3duKTogbnVtYmVyIHwgdW5kZWZpbmVkIHtcbiAgY29uc3QgbnVtYmVyID0gdHlwZW9mIHZhbHVlID09PSAnc3RyaW5nJyA/IG51bWJlckZyb21UZXh0KHZhbHVlLnRyaW0oKSkgOiB2YWx1ZTtcblxuICByZXR1cm4gdHlwZW9mIG51bWJlciA9PT0gJ251bWJlcicgJiYgTnVtYmVyLmlzRmluaXRlKG51bWJlcikgPyBudW1iZXIgOiB1bmRlZmluZWQ7XG59XG5cbi8vIFdoZXRoZXIgYSBzdG9yZWQgdmFsdWUgcmVhZHMgdGhlIHNhbWUgYXMgbm8gdmFsdWUgYXQgYWxsLlxuZnVuY3Rpb24gaG9sZHNOb3RoaW5nKHN0b3JlZDogRmlsdGVyR3JvdXBEZWZhdWx0KTogYm9vbGVhbiB7XG4gIHJldHVybiBzdG9yZWRWYWx1ZUtleShzdG9yZWQpID09PSBzdG9yZWRWYWx1ZUtleShudWxsKTtcbn1cblxuLy8gT25seSB0aGUgcGFydHMgdGhhdCBob2xkIHNvbWV0aGluZywgb3IgbnVsbCB3aGVuIG5vbmUgZG9lcy5cbmZ1bmN0aW9uIHN0b3JlZE9yTnVsbCh2YWx1ZTogUmVjb3JkPHN0cmluZywgdW5rbm93bj4pOiBGaWx0ZXJHcm91cERlZmF1bHQgfCBudWxsIHtcbiAgY29uc3Qgc3RvcmVkID0gY29tcGFjdCh2YWx1ZSk7XG5cbiAgcmV0dXJuIE9iamVjdC5rZXlzKHN0b3JlZCkubGVuZ3RoID8gc3RvcmVkIDogbnVsbDtcbn1cblxuZnVuY3Rpb24gcmVxdWlyZUdyb3VwS2V5cyh2YWx1ZTogUmVjb3JkPHN0cmluZywgdW5rbm93bj4sIHR5cGU6IFJlcG9ydEZpbHRlclR5cGUpOiB2b2lkIHtcbiAgY29uc3QgYWxsb3dlZDogcmVhZG9ubHkgc3RyaW5nW10gPSBHUk9VUF9WQUxVRV9LRVlTW3R5cGVdID8/IEdST1VQX1ZBTFVFX0tFWVMua2V5d29yZDtcbiAgY29uc3QgdW5rbm93biA9IE9iamVjdC5rZXlzKHZhbHVlKS5maWx0ZXIoKGtleSkgPT4gIWFsbG93ZWQuaW5jbHVkZXMoa2V5KSk7XG5cbiAgaWYgKHVua25vd24ubGVuZ3RoKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBBICR7dHlwZX0gZGVmYXVsdCB0YWtlcyAke2FsbG93ZWQuam9pbignLCAnKX0g4oCUIG5vdCAke3Vua25vd24uam9pbignLCAnKX0uYCk7XG4gIH1cbn1cblxuLy8gQSByZWxhdGl2ZSByYW5nZSwgb3IgZml4ZWQgZGF5czsgbmV2ZXIgYm90aC5cbmZ1bmN0aW9uIGRhdGVSYW5nZVZhbHVlKHZhbHVlOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPik6IEZpbHRlckdyb3VwRGVmYXVsdCB7XG4gIGNvbnN0IHJlbGF0aXZlID0gdGV4dFBhcnQodmFsdWUsICdyZWxhdGl2ZScpO1xuICBjb25zdCBzdGFydCA9IGRheVBhcnQodmFsdWUsICdzdGFydCcpO1xuICBjb25zdCBlbmQgPSBkYXlQYXJ0KHZhbHVlLCAnZW5kJyk7XG5cbiAgaWYgKHJlbGF0aXZlID09PSAnJykge1xuICAgIHJldHVybiBjb21wYWN0KHsgc3RhcnQsIGVuZCB9KTtcbiAgfVxuXG4gIGlmIChzdGFydCAhPT0gbnVsbCB8fCBlbmQgIT09IG51bGwpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ0EgZGF0ZVJhbmdlIGRlZmF1bHQgaXMgZWl0aGVyIGEgcmVsYXRpdmUgcHJlc2V0IG9yIGEgZml4ZWQgc3RhcnQvZW5kLCBub3QgYm90aC4nKTtcbiAgfVxuXG4gIGlmICghaXNSZWxhdGl2ZVJhbmdlKHJlbGF0aXZlKSkge1xuICAgIHRocm93IG5ldyBFcnJvcihgcmVsYXRpdmUgbXVzdCBiZSBvbmUgb2Y6ICR7T2JqZWN0LmtleXMoUkVMQVRJVkVfUkFOR0VTKS5qb2luKCcsICcpfS5gKTtcbiAgfVxuXG4gIHJldHVybiB7IHJlbGF0aXZlIH07XG59XG5cbi8vIFRoZSB2YWx1ZXMgdG8ga2VlcCBvciB0aGUgdmFsdWVzIHRvIGxlYXZlIG91dDsgbmV2ZXIgYm90aC5cbmZ1bmN0aW9uIHNlbGVjdFZhbHVlKHZhbHVlOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPik6IEZpbHRlckdyb3VwRGVmYXVsdCB7XG4gIGNvbnN0IHZhbHVlcyA9IHBpY2tMaXN0KHZhbHVlLCAndmFsdWVzJyk7XG4gIGNvbnN0IGV4Y2x1ZGVWYWx1ZXMgPSBwaWNrTGlzdCh2YWx1ZSwgJ2V4Y2x1ZGVWYWx1ZXMnKTtcblxuICBpZiAodmFsdWVzICE9PSBudWxsICYmIGV4Y2x1ZGVWYWx1ZXMgIT09IG51bGwpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ0Egc2VsZWN0IGRlZmF1bHQgZWl0aGVyIGtlZXBzIHZhbHVlcyBvciBsZWF2ZXMgb3V0IGV4Y2x1ZGVfdmFsdWVzLCBub3QgYm90aC4nKTtcbiAgfVxuXG4gIHJldHVybiBjb21wYWN0KHsgdmFsdWVzLCBleGNsdWRlVmFsdWVzIH0pO1xufVxuXG5mdW5jdGlvbiBrZXl3b3JkVmFsdWUodmFsdWU6IFJlY29yZDxzdHJpbmcsIHVua25vd24+KTogRmlsdGVyR3JvdXBEZWZhdWx0IHtcbiAgY29uc3QgdGV4dCA9IHRleHRQYXJ0KHZhbHVlLCAndmFsdWUnKTtcblxuICByZXR1cm4gdGV4dCAhPT0gJycgPyB7IHZhbHVlOiB0ZXh0IH0gOiB7fTtcbn1cblxuLy8gRWl0aGVyIGVuZCBtYXkgYmUgb3BlbjsgMCBpcyBhbiBlbmQgbGlrZSBhbnkgb3RoZXIuXG5mdW5jdGlvbiBudW1iZXJSYW5nZVZhbHVlKHZhbHVlOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPik6IEZpbHRlckdyb3VwRGVmYXVsdCB7XG4gIGNvbnN0IG1pbiA9IGJvdW5kUGFydCh2YWx1ZSwgJ21pbicpO1xuICBjb25zdCBtYXggPSBib3VuZFBhcnQodmFsdWUsICdtYXgnKTtcblxuICBpZiAobWluICE9PSBudWxsICYmIG1heCAhPT0gbnVsbCAmJiBtaW4gPiBtYXgpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYG1pbiAoJHttaW59KSBpcyBhYm92ZSBtYXggKCR7bWF4fSkuYCk7XG4gIH1cblxuICByZXR1cm4gY29tcGFjdCh7IG1pbiwgbWF4IH0pO1xufVxuXG4vLyBUaGUgdGV4dCBga2V5YCBob2xkcywgdHJpbW1lZCwgb3IgJycgd2hlbiBhYnNlbnQuIEEgbnVtYmVyIGlzIHJlYWQgYXMgaXRzXG4vLyB0ZXh0OyBhbnkgb3RoZXIga2luZCBpcyByZWZ1c2VkLlxuZnVuY3Rpb24gdGV4dFBhcnQodmFsdWU6IFJlY29yZDxzdHJpbmcsIHVua25vd24+LCBrZXk6IHN0cmluZyk6IHN0cmluZyB7XG4gIGNvbnN0IHRleHQgPSB2YWx1ZVtrZXldO1xuICBpZiAodGV4dCA9PT0gdW5kZWZpbmVkIHx8IHRleHQgPT09IG51bGwpIHtcbiAgICByZXR1cm4gJyc7XG4gIH1cblxuICBpZiAodHlwZW9mIHRleHQgIT09ICdzdHJpbmcnICYmIHR5cGVvZiB0ZXh0ICE9PSAnbnVtYmVyJykge1xuICAgIHRocm93IG5ldyBFcnJvcihgJHtrZXl9IG11c3QgYmUgdGV4dC5gKTtcbiAgfVxuXG4gIHJldHVybiBTdHJpbmcodGV4dCkudHJpbSgpO1xufVxuXG4vLyBBIGNhbGVuZGFyLWRheSBib3VuZDogaXRzIGZpcnN0IHRlbiBjaGFyYWN0ZXJzIG11c3QgYmUgYSByZWFsIGRheS5cbmZ1bmN0aW9uIGRheVBhcnQodmFsdWU6IFJlY29yZDxzdHJpbmcsIHVua25vd24+LCBrZXk6IHN0cmluZyk6IHN0cmluZyB8IG51bGwge1xuICBjb25zdCB0ZXh0ID0gdGV4dFBhcnQodmFsdWUsIGtleSk7XG4gIGlmICh0ZXh0ID09PSAnJykge1xuICAgIHJldHVybiBudWxsO1xuICB9XG5cbiAgY29uc3QgZGF5ID0gdGV4dC5zbGljZSgwLCAxMCk7XG4gIGlmICghaXNDYWxlbmRhckRheShkYXkpKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGAke2tleX0gbXVzdCBiZSBhIHl5eXktTU0tZGQgZGF5LmApO1xuICB9XG5cbiAgcmV0dXJuIGRheTtcbn1cblxuLy8gVGhlIHBpY2tzIG9mIGBrZXlgIHdpdGggYmxhbmtzIChudWxsLCAnJykgZHJvcHBlZCwgb3IgbnVsbCB3aGVuIG5vbmUgaXNcbi8vIGxlZnQuIEEgbG9uZSBwaWNrIGlzIGEgbGlzdCBvZiBvbmU7IGEgcGljayB0aGF0IGlzIGEgbGlzdCBvciBhbiBvYmplY3QgaXNcbi8vIHJlZnVzZWQuXG5mdW5jdGlvbiBwaWNrTGlzdCh2YWx1ZTogUmVjb3JkPHN0cmluZywgdW5rbm93bj4sIGtleTogc3RyaW5nKTogdW5rbm93bltdIHwgbnVsbCB7XG4gIGNvbnN0IHJhdyA9IHZhbHVlW2tleV0gPz8gW107XG4gIGNvbnN0IHBpY2tzOiB1bmtub3duW10gPSBBcnJheS5pc0FycmF5KHJhdykgPyByYXcgOiBbcmF3XTtcblxuICBpZiAocGlja3Muc29tZSgocGljaykgPT4gaXNTZXQocGljaykgJiYgIWlzU2NhbGFyKHBpY2spKSkge1xuICAgIHRocm93IG5ldyBFcnJvcihgRWFjaCBwaWNrIGluICR7a2V5fSBtdXN0IGJlIGEgcGxhaW4gdmFsdWUsIG5vdCBhIGxpc3QuYCk7XG4gIH1cblxuICBjb25zdCBrZXB0ID0gcGlja3MuZmlsdGVyKChwaWNrKSA9PiBpc1NldChwaWNrKSAmJiBwaWNrICE9PSAnJyk7XG5cbiAgcmV0dXJuIGtlcHQubGVuZ3RoID8ga2VwdCA6IG51bGw7XG59XG5cbi8vIE9uZSBlbmQgb2YgYSBudW1iZXIgcmFuZ2U6IG51bGwgd2hlbiBhYnNlbnQgb3IgYmxhbmssIGVsc2UgYSBmaW5pdGUgbnVtYmVyXG4vLyAobnVtZXJpYyB0ZXh0IGlzIHJlYWQgYXMgaXRzIG51bWJlcikuXG5mdW5jdGlvbiBib3VuZFBhcnQodmFsdWU6IFJlY29yZDxzdHJpbmcsIHVua25vd24+LCBrZXk6IHN0cmluZyk6IG51bWJlciB8IG51bGwge1xuICBjb25zdCByYXcgPSB0eXBlb2YgdmFsdWVba2V5XSA9PT0gJ3N0cmluZycgPyAodmFsdWVba2V5XSBhcyBzdHJpbmcpLnRyaW0oKSA6IHZhbHVlW2tleV07XG4gIGlmICghaXNTZXQocmF3KSB8fCByYXcgPT09ICcnKSB7XG4gICAgcmV0dXJuIG51bGw7XG4gIH1cblxuICBjb25zdCBib3VuZCA9IHR5cGVvZiByYXcgPT09ICdzdHJpbmcnID8gbnVtYmVyRnJvbVRleHQocmF3KSA6IHJhdztcbiAgaWYgKHR5cGVvZiBib3VuZCAhPT0gJ251bWJlcicgfHwgIU51bWJlci5pc0Zpbml0ZShib3VuZCkpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYCR7a2V5fSBtdXN0IGJlIGEgZmluaXRlIG51bWJlci5gKTtcbiAgfVxuXG4gIHJldHVybiBib3VuZDtcbn1cblxuZnVuY3Rpb24gcmVxdWlyZVNpemUoZG9jOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPik6IHZvaWQge1xuICBpZiAobmV3IFRleHRFbmNvZGVyKCkuZW5jb2RlKEpTT04uc3RyaW5naWZ5KGRvYykpLmxlbmd0aCA+IFZJRVdfQ09ORklHX01BWF9CWVRFUykge1xuICAgIHRocm93IG5ldyBFcnJvcignQSB2aWV3IGNvbmZpZyBpcyBvdmVyIDMyIEtCLicpO1xuICB9XG59XG5cbmZ1bmN0aW9uIHJlcXVpcmVWZXJzaW9uKHZlcnNpb246IHVua25vd24pOiB2b2lkIHtcbiAgaWYgKCFpc1NldCh2ZXJzaW9uKSkge1xuICAgIHRocm93IG5ldyBFcnJvcignQSB2aWV3IGNvbmZpZyBuZWVkcyBpdHMgdmVyc2lvbiAodikuJyk7XG4gIH1cblxuICBpZiAodmVyc2lvbiAhPT0gUkVQT1JUX1ZJRVdfQ09ORklHX1ZFUlNJT04pIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYFRoaXMgdmlld2VyIHJlYWRzIHZpZXcgY29uZmlnIHZlcnNpb24gJHtSRVBPUlRfVklFV19DT05GSUdfVkVSU0lPTn0gb25seS5gKTtcbiAgfVxufVxuXG5mdW5jdGlvbiByZXF1aXJlTWF0Y2gobWF0Y2g6IHVua25vd24pOiBSZXBvcnRWaWV3Q29uZmlnWydtYXRjaCddIHtcbiAgaWYgKG1hdGNoICE9PSAnYWxsJyAmJiBtYXRjaCAhPT0gJ2FueScpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ21hdGNoIG11c3QgYmUgYWxsIG9yIGFueS4nKTtcbiAgfVxuXG4gIHJldHVybiBtYXRjaDtcbn1cblxuLy8gR3JvdXAgaWQgLT4gdmFsdWUuIEEgdmFsdWUgbm8gZ3JvdXAgdHlwZSBjb3VsZCBob2xkIGlzIGRyb3BwZWQgd2hvbGUuXG5mdW5jdGlvbiB2aWV3R3JvdXBzKHJhdzogdW5rbm93bik6IFJlY29yZDxudW1iZXIsIEZpbHRlckdyb3VwRGVmYXVsdCB8IG51bGw+IHtcbiAgY29uc3QgZW50cmllcyA9IE9iamVjdC5lbnRyaWVzKHJlcXVpcmVPYmplY3QocmF3LCAnZ3JvdXBzIG11c3QgbWFwIGdyb3VwIGlkcyB0byB2YWx1ZXMuJykpO1xuICBpZiAoZW50cmllcy5sZW5ndGggPiBWSUVXX0NPTkZJR19NQVhfR1JPVVBTKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBBIHZpZXcgaG9sZHMgYXQgbW9zdCAke1ZJRVdfQ09ORklHX01BWF9HUk9VUFN9IGdyb3Vwcy5gKTtcbiAgfVxuXG4gIGNvbnN0IGdyb3VwczogUmVjb3JkPG51bWJlciwgRmlsdGVyR3JvdXBEZWZhdWx0IHwgbnVsbD4gPSB7fTtcbiAgZW50cmllcy5mb3JFYWNoKChba2V5LCB2YWx1ZV0pID0+IHtcbiAgICBjb25zdCBpZCA9IHJlcXVpcmVJZEtleShrZXksICdncm91cHMnKTtcbiAgICByZXF1aXJlUGlja0NvdW50KHZhbHVlKTtcbiAgICBjb25zdCBrZXB0ID0gdmFsdWUgPT09IG51bGwgPyBudWxsIDogc3RvcmVkR3JvdXBWYWx1ZSh2YWx1ZSk7XG5cbiAgICBpZiAoa2VwdCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICBncm91cHNbaWRdID0ga2VwdDtcbiAgICB9XG4gIH0pO1xuXG4gIHJldHVybiBncm91cHM7XG59XG5cbi8vIEEgc3RvcmVkIGdyb3VwIHZhbHVlLCByZWFkIGZvciB0aGUgb25lIHR5cGUgaXRzIGtleXMgYmVsb25nIHRvIChhbiBlbXB0eVxuLy8gdmFsdWUgZml0cyBldmVyeSB0eXBlKSwgb3IgdW5kZWZpbmVkIHdoZW4gaXQgZml0cyBub25lLlxuZnVuY3Rpb24gc3RvcmVkR3JvdXBWYWx1ZSh2YWx1ZTogdW5rbm93bik6IEZpbHRlckdyb3VwRGVmYXVsdCB8IHVuZGVmaW5lZCB7XG4gIGlmICghaXNQbGFpbk9iamVjdCh2YWx1ZSkpIHtcbiAgICByZXR1cm4gdW5kZWZpbmVkO1xuICB9XG5cbiAgY29uc3Qga2V5cyA9IE9iamVjdC5rZXlzKHZhbHVlKTtcbiAgY29uc3QgdHlwZSA9IChPYmplY3Qua2V5cyhHUk9VUF9WQUxVRV9LRVlTKSBhcyBSZXBvcnRGaWx0ZXJUeXBlW10pXG4gICAgLmZpbmQoKGNhbmRpZGF0ZSkgPT4ga2V5cy5ldmVyeSgoa2V5KSA9PiAoR1JPVVBfVkFMVUVfS0VZU1tjYW5kaWRhdGVdIGFzIHJlYWRvbmx5IHN0cmluZ1tdKS5pbmNsdWRlcyhrZXkpKSk7XG5cbiAgcmV0dXJuIHR5cGUgPyAoZ3JvdXBWYWx1ZUZyb21TdG9yZWQodmFsdWUsIHR5cGUpID8/IHVuZGVmaW5lZCkgOiB1bmRlZmluZWQ7XG59XG5cbmZ1bmN0aW9uIHJlcXVpcmVQaWNrQ291bnQodmFsdWU6IHVua25vd24pOiB2b2lkIHtcbiAgY29uc3QgbGlzdHMgPSBpc1BsYWluT2JqZWN0KHZhbHVlKSA/IFt2YWx1ZS52YWx1ZXMsIHZhbHVlLmV4Y2x1ZGVWYWx1ZXNdIDogW107XG5cbiAgaWYgKGxpc3RzLnNvbWUoKGxpc3QpID0+IEFycmF5LmlzQXJyYXkobGlzdCkgJiYgbGlzdC5sZW5ndGggPiBHUk9VUF9WQUxVRV9NQVhfUElDS1MpKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBBIGdyb3VwIHZhbHVlIGhvbGRzIGF0IG1vc3QgJHtHUk9VUF9WQUxVRV9NQVhfUElDS1N9IHZhbHVlcy5gKTtcbiAgfVxufVxuXG4vLyBDb21wb25lbnQgaWQgLT4gdGlsZSBzdGF0ZS5cbmZ1bmN0aW9uIHZpZXdUaWxlcyhyYXc6IHVua25vd24pOiBSZWNvcmQ8bnVtYmVyLCBSZXBvcnRUaWxlU3RhdGU+IHtcbiAgY29uc3QgZW50cmllcyA9IE9iamVjdC5lbnRyaWVzKHJlcXVpcmVPYmplY3QocmF3LCAndGlsZXMgbXVzdCBtYXAgY29tcG9uZW50IGlkcyB0byB0aWxlIHN0YXRlcy4nKSk7XG4gIGlmIChlbnRyaWVzLmxlbmd0aCA+IFZJRVdfQ09ORklHX01BWF9USUxFUykge1xuICAgIHRocm93IG5ldyBFcnJvcihgQSB2aWV3IGhvbGRzIGF0IG1vc3QgJHtWSUVXX0NPTkZJR19NQVhfVElMRVN9IHRpbGVzLmApO1xuICB9XG5cbiAgY29uc3QgdGlsZXM6IFJlY29yZDxudW1iZXIsIFJlcG9ydFRpbGVTdGF0ZT4gPSB7fTtcbiAgZW50cmllcy5mb3JFYWNoKChba2V5LCB2YWx1ZV0pID0+IHtcbiAgICB0aWxlc1tyZXF1aXJlSWRLZXkoa2V5LCAndGlsZXMnKV0gPSB2aWV3VGlsZSh2YWx1ZSk7XG4gIH0pO1xuXG4gIHJldHVybiB0aWxlcztcbn1cblxuZnVuY3Rpb24gdmlld1RpbGUocmF3OiB1bmtub3duKTogUmVwb3J0VGlsZVN0YXRlIHtcbiAgY29uc3QgdGlsZSA9IHJlcXVpcmVPYmplY3QocmF3LCAnQSB0aWxlIHN0YXRlIG11c3QgYmUgYW4gb2JqZWN0LicpO1xuICBjb25zdCBzdGF0ZSA9IG90aGVyS2V5cyh0aWxlLCBUSUxFX1NUQVRFX0tFWVMpIGFzIFJlcG9ydFRpbGVTdGF0ZTtcblxuICBpZiAoaXNTZXQodGlsZS5zb3J0KSkge1xuICAgIHN0YXRlLnNvcnQgPSB2aWV3U29ydCh0aWxlLnNvcnQpO1xuICB9XG5cbiAgaWYgKGlzU2V0KHRpbGUuc2VhcmNoKSkge1xuICAgIHN0YXRlLnNlYXJjaCA9IHJlcXVpcmVTdHJpbmcodGlsZS5zZWFyY2gsICdzZWFyY2ggbXVzdCBiZSB0ZXh0LicpO1xuICB9XG5cbiAgaWYgKGlzU2V0KHRpbGUuaGlkZGVuKSkge1xuICAgIHN0YXRlLmhpZGRlbiA9IHZpZXdIaWRkZW4odGlsZS5oaWRkZW4pO1xuICB9XG5cbiAgaWYgKGlzU2V0KHRpbGUuZHJpbGwpKSB7XG4gICAgc3RhdGUuZHJpbGwgPSB2aWV3RHJpbGwodGlsZS5kcmlsbCk7XG4gIH1cblxuICByZXR1cm4gc3RhdGU7XG59XG5cbmZ1bmN0aW9uIHZpZXdTb3J0KHJhdzogdW5rbm93bik6IFJlcG9ydFNvcnQge1xuICBjb25zdCBzb3J0ID0gcmVxdWlyZU9iamVjdChyYXcsICdzb3J0IG11c3QgYmUgYSBjb2x1bW4gYW5kIGEgZGlyZWN0aW9uLicpO1xuICBjb25zdCBjb2x1bW4gPSByZXF1aXJlU3RyaW5nKHNvcnQuY29sdW1uLCAnc29ydCBtdXN0IG5hbWUgYSBjb2x1bW4uJyk7XG4gIGlmIChjb2x1bW4gPT09ICcnIHx8IChpc1NldChzb3J0LmRpcmVjdGlvbikgJiYgc29ydC5kaXJlY3Rpb24gIT09ICdhc2MnICYmIHNvcnQuZGlyZWN0aW9uICE9PSAnZGVzYycpKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdzb3J0IG11c3QgYmUgYSBjb2x1bW4gYW5kIGEgZGlyZWN0aW9uLicpO1xuICB9XG5cbiAgcmV0dXJuIHNvcnQuZGlyZWN0aW9uID8geyBjb2x1bW4sIGRpcmVjdGlvbjogc29ydC5kaXJlY3Rpb24gYXMgUmVwb3J0U29ydFsnZGlyZWN0aW9uJ10gfSA6IHsgY29sdW1uIH07XG59XG5cbmZ1bmN0aW9uIHZpZXdIaWRkZW4ocmF3OiB1bmtub3duKTogc3RyaW5nW10ge1xuICBpZiAoIUFycmF5LmlzQXJyYXkocmF3KSB8fCByYXcuc29tZSgobmFtZSkgPT4gdHlwZW9mIG5hbWUgIT09ICdzdHJpbmcnKSkge1xuICAgIHRocm93IG5ldyBFcnJvcignaGlkZGVuIG11c3QgbGlzdCBjb2x1bW4gbmFtZXMuJyk7XG4gIH1cblxuICByZXR1cm4gWy4uLnJhd107XG59XG5cbmZ1bmN0aW9uIHZpZXdEcmlsbChyYXc6IHVua25vd24pOiBSZXBvcnREcmlsbFN0ZXBbXSB7XG4gIGlmICghQXJyYXkuaXNBcnJheShyYXcpKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdkcmlsbCBtdXN0IGxpc3Qgc3RlcHMuJyk7XG4gIH1cblxuICBpZiAocmF3Lmxlbmd0aCA+IERSSUxMX01BWF9ERVBUSCkge1xuICAgIHRocm93IG5ldyBFcnJvcihgQSBkcmlsbCBwYXRoIGhvbGRzIGF0IG1vc3QgJHtEUklMTF9NQVhfREVQVEh9IHN0ZXBzLmApO1xuICB9XG5cbiAgcmV0dXJuIHJhdy5tYXAoKHN0ZXA6IHVua25vd24pID0+IHtcbiAgICBpZiAoIWlzUGxhaW5PYmplY3Qoc3RlcCkgfHwgIWlzQ2hhcnRHcmFudWxhcml0eShzdGVwLmxldmVsKSB8fCAhaXNEcmlsbFZhbHVlKHN0ZXAudmFsdWUpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0EgZHJpbGwgc3RlcCBuZWVkcyBhIHRpbWUgbGV2ZWwgYW5kIGEgdmFsdWUuJyk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHsgbGV2ZWw6IHN0ZXAubGV2ZWwsIHZhbHVlOiBzdGVwLnZhbHVlIH07XG4gIH0pO1xufVxuXG5mdW5jdGlvbiBpc0RyaWxsVmFsdWUodmFsdWU6IHVua25vd24pOiB2YWx1ZSBpcyBSZXBvcnREcmlsbFN0ZXBbJ3ZhbHVlJ10ge1xuICByZXR1cm4gdmFsdWUgPT09IG51bGwgfHwgdHlwZW9mIHZhbHVlID09PSAnc3RyaW5nJyB8fCB0eXBlb2YgdmFsdWUgPT09ICdudW1iZXInO1xufVxuXG4vLyBUaGUga2V5cyBvZiBgc291cmNlYCB0aGF0IGFyZSBub3QgaW4gYGtub3duYCwgYXMgdGhleSB3ZXJlLlxuZnVuY3Rpb24gb3RoZXJLZXlzKHNvdXJjZTogUmVjb3JkPHN0cmluZywgdW5rbm93bj4sIGtub3duOiByZWFkb25seSBzdHJpbmdbXSk6IFJlY29yZDxzdHJpbmcsIHVua25vd24+IHtcbiAgcmV0dXJuIE9iamVjdC5mcm9tRW50cmllcyhPYmplY3QuZW50cmllcyhzb3VyY2UpLmZpbHRlcigoW2tleV0pID0+ICFrbm93bi5pbmNsdWRlcyhrZXkpKSk7XG59XG5cbmZ1bmN0aW9uIG9wdGlvbmFsSWQocmF3OiB1bmtub3duLCByZWZ1c2FsOiBzdHJpbmcpOiBudW1iZXIgfCBudWxsIHtcbiAgaWYgKCFpc1NldChyYXcpKSB7XG4gICAgcmV0dXJuIG51bGw7XG4gIH1cblxuICBpZiAoIU51bWJlci5pc0ludGVnZXIocmF3KSB8fCAocmF3IGFzIG51bWJlcikgPCAxKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKHJlZnVzYWwpO1xuICB9XG5cbiAgcmV0dXJuIHJhdyBhcyBudW1iZXI7XG59XG5cbmZ1bmN0aW9uIHJlcXVpcmVJZEtleShrZXk6IHN0cmluZywgd2hlcmU6IHN0cmluZyk6IG51bWJlciB7XG4gIGlmICghSURfS0VZX1BBVFRFUk4udGVzdChrZXkpKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGAke3doZXJlfSBhcmUga2V5ZWQgYnkgaWQsIG5vdCBieSAnJHtrZXl9Jy5gKTtcbiAgfVxuXG4gIHJldHVybiBOdW1iZXIoa2V5KTtcbn1cblxuZnVuY3Rpb24gcmVxdWlyZUdyYW51bGFyaXR5KHJhdzogdW5rbm93biwgcmVmdXNhbDogc3RyaW5nKTogQ2hhcnRHcmFudWxhcml0eSB7XG4gIGlmICghaXNDaGFydEdyYW51bGFyaXR5KHJhdykpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IocmVmdXNhbCk7XG4gIH1cblxuICByZXR1cm4gcmF3O1xufVxuXG5mdW5jdGlvbiByZXF1aXJlU3RyaW5nKHJhdzogdW5rbm93biwgcmVmdXNhbDogc3RyaW5nKTogc3RyaW5nIHtcbiAgaWYgKHR5cGVvZiByYXcgIT09ICdzdHJpbmcnKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKHJlZnVzYWwpO1xuICB9XG5cbiAgcmV0dXJuIHJhdztcbn1cblxuZnVuY3Rpb24gcmVxdWlyZU9iamVjdChyYXc6IHVua25vd24sIHJlZnVzYWw6IHN0cmluZyk6IFJlY29yZDxzdHJpbmcsIHVua25vd24+IHtcbiAgaWYgKCFpc1BsYWluT2JqZWN0KHJhdykpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IocmVmdXNhbCk7XG4gIH1cblxuICByZXR1cm4gcmF3O1xufVxuXG5mdW5jdGlvbiBpc1NldCh2YWx1ZTogdW5rbm93bik6IGJvb2xlYW4ge1xuICByZXR1cm4gdmFsdWUgIT09IHVuZGVmaW5lZCAmJiB2YWx1ZSAhPT0gbnVsbDtcbn1cblxuZnVuY3Rpb24gaXNQbGFpbk9iamVjdCh2YWx1ZTogdW5rbm93bik6IHZhbHVlIGlzIFJlY29yZDxzdHJpbmcsIHVua25vd24+IHtcbiAgcmV0dXJuIHZhbHVlICE9PSBudWxsICYmIHR5cGVvZiB2YWx1ZSA9PT0gJ29iamVjdCcgJiYgIUFycmF5LmlzQXJyYXkodmFsdWUpO1xufVxuXG5mdW5jdGlvbiBpc1NjYWxhcih2YWx1ZTogdW5rbm93bik6IGJvb2xlYW4ge1xuICByZXR1cm4gdHlwZW9mIHZhbHVlID09PSAnc3RyaW5nJyB8fCB0eXBlb2YgdmFsdWUgPT09ICdudW1iZXInIHx8IHR5cGVvZiB2YWx1ZSA9PT0gJ2Jvb2xlYW4nO1xufVxuXG4vLyBPbmx5IHRoZSBwYXJ0cyB0aGF0IGhvbGQgc29tZXRoaW5nLlxuZnVuY3Rpb24gY29tcGFjdCh2YWx1ZTogUmVjb3JkPHN0cmluZywgdW5rbm93bj4pOiBGaWx0ZXJHcm91cERlZmF1bHQge1xuICByZXR1cm4gT2JqZWN0LmZyb21FbnRyaWVzKE9iamVjdC5lbnRyaWVzKHZhbHVlKS5maWx0ZXIoKFssIHBhcnRdKSA9PiBpc1NldChwYXJ0KSkpIGFzIEZpbHRlckdyb3VwRGVmYXVsdDtcbn1cbiJdfQ==
|