@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.
Files changed (81) hide show
  1. package/app/reports/components/report-canvas/report-canvas.component.d.ts +0 -1
  2. package/app/reports/data/report.data.d.ts +8 -12
  3. package/app/reports/export/report-export-collector.service.d.ts +0 -1
  4. package/app/reports/export/report-filter-lines.d.ts +0 -2
  5. package/app/reports/interfaces/report-chat-viewer-state.interface.d.ts +0 -2
  6. package/app/reports/interfaces/report-export-snapshot.interface.d.ts +2 -3
  7. package/app/reports/interfaces/report-saved-filter-changes.interface.d.ts +4 -0
  8. package/app/reports/interfaces/report-saved-filter.interface.d.ts +6 -0
  9. package/app/reports/interfaces/{report-view-config.interface.d.ts → report-state-snapshot.interface.d.ts} +1 -2
  10. package/app/reports/interfaces/report-viewer-feature.type.d.ts +1 -1
  11. package/app/reports/report-chat-viewer-state.d.ts +3 -3
  12. package/app/reports/report-saved-filters.d.ts +3 -0
  13. package/app/reports/report-state.d.ts +15 -0
  14. package/app/reports/services/report-filter-state.service.d.ts +9 -25
  15. package/app/reports/tile-data-state.d.ts +5 -5
  16. package/app/reports/views/report/fs-ai-report.component.d.ts +12 -5
  17. package/esm2022/app/reports/canvas-landing-page.mjs +3 -3
  18. package/esm2022/app/reports/components/component-list/component-list.component.mjs +3 -3
  19. package/esm2022/app/reports/components/report-canvas/report-canvas.component.mjs +8 -12
  20. package/esm2022/app/reports/components/report-component/report-component.component.mjs +25 -30
  21. package/esm2022/app/reports/data/report.data.mjs +24 -41
  22. package/esm2022/app/reports/export/report-export-collector.service.mjs +11 -18
  23. package/esm2022/app/reports/export/report-filter-lines.mjs +5 -15
  24. package/esm2022/app/reports/filter-settings-rules.mjs +2 -2
  25. package/esm2022/app/reports/interfaces/canvas-landing-input.interface.mjs +1 -1
  26. package/esm2022/app/reports/interfaces/report-chat-viewer-state.interface.mjs +1 -1
  27. package/esm2022/app/reports/interfaces/report-export-snapshot.interface.mjs +1 -1
  28. package/esm2022/app/reports/interfaces/report-saved-filter-changes.interface.mjs +2 -0
  29. package/esm2022/app/reports/interfaces/report-saved-filter.interface.mjs +2 -0
  30. package/esm2022/app/reports/interfaces/report-state-snapshot.interface.mjs +2 -0
  31. package/esm2022/app/reports/interfaces/report-temporary-state.interface.mjs +1 -1
  32. package/esm2022/app/reports/interfaces/report-tile-state.interface.mjs +1 -1
  33. package/esm2022/app/reports/interfaces/report-viewer-feature.type.mjs +1 -1
  34. package/esm2022/app/reports/interfaces/report.interface.mjs +1 -1
  35. package/esm2022/app/reports/mark-click.mjs +2 -2
  36. package/esm2022/app/reports/report-chat-viewer-state.mjs +3 -3
  37. package/esm2022/app/reports/report-date-presets.mjs +2 -2
  38. package/esm2022/app/reports/report-saved-filters.mjs +92 -0
  39. package/esm2022/app/reports/report-state.mjs +169 -0
  40. package/esm2022/app/reports/report-viewer-features.mjs +2 -4
  41. package/esm2022/app/reports/services/report-filter-state.service.mjs +83 -310
  42. package/esm2022/app/reports/tile-data-state.mjs +4 -4
  43. package/esm2022/app/reports/tile-loads.mjs +5 -6
  44. package/esm2022/app/reports/views/report/fs-ai-report.component.mjs +192 -102
  45. package/esm2022/app/reports/views/report/report.component.mjs +14 -16
  46. package/esm2022/public_api.mjs +4 -8
  47. package/fesm2022/{firestitch-report-echarts-CyHkFToO.mjs → firestitch-report-echarts-B0RWUjR8.mjs} +2 -2
  48. package/fesm2022/{firestitch-report-echarts-CyHkFToO.mjs.map → firestitch-report-echarts-B0RWUjR8.mjs.map} +1 -1
  49. package/fesm2022/{firestitch-report-firestitch-report-DftB7M1o.mjs → firestitch-report-firestitch-report-CJW0lLdW.mjs} +480 -1450
  50. package/fesm2022/firestitch-report-firestitch-report-CJW0lLdW.mjs.map +1 -0
  51. package/fesm2022/firestitch-report.mjs +1 -1
  52. package/package.json +1 -1
  53. package/public_api.d.ts +3 -7
  54. package/app/reports/components/report-view-picker/report-view-picker.component.d.ts +0 -21
  55. package/app/reports/dialogs/report-view/report-view-dialog.component.d.ts +0 -13
  56. package/app/reports/interfaces/report-view-create.interface.d.ts +0 -7
  57. package/app/reports/interfaces/report-view-deleted.interface.d.ts +0 -4
  58. package/app/reports/interfaces/report-view-dialog-data.interface.d.ts +0 -7
  59. package/app/reports/interfaces/report-view-dropped.interface.d.ts +0 -5
  60. package/app/reports/interfaces/report-view-menu-item.interface.d.ts +0 -10
  61. package/app/reports/interfaces/report-view-summary.interface.d.ts +0 -11
  62. package/app/reports/interfaces/report-view.interface.d.ts +0 -7
  63. package/app/reports/interfaces/report-views.interface.d.ts +0 -7
  64. package/app/reports/report-view-config.d.ts +0 -34
  65. package/app/reports/report-view-menu.d.ts +0 -15
  66. package/app/reports/services/report-view.service.d.ts +0 -39
  67. package/esm2022/app/reports/components/report-view-picker/report-view-picker.component.mjs +0 -115
  68. package/esm2022/app/reports/dialogs/report-view/report-view-dialog.component.mjs +0 -52
  69. package/esm2022/app/reports/interfaces/report-view-config.interface.mjs +0 -2
  70. package/esm2022/app/reports/interfaces/report-view-create.interface.mjs +0 -2
  71. package/esm2022/app/reports/interfaces/report-view-deleted.interface.mjs +0 -2
  72. package/esm2022/app/reports/interfaces/report-view-dialog-data.interface.mjs +0 -2
  73. package/esm2022/app/reports/interfaces/report-view-dropped.interface.mjs +0 -2
  74. package/esm2022/app/reports/interfaces/report-view-menu-item.interface.mjs +0 -2
  75. package/esm2022/app/reports/interfaces/report-view-summary.interface.mjs +0 -2
  76. package/esm2022/app/reports/interfaces/report-view.interface.mjs +0 -2
  77. package/esm2022/app/reports/interfaces/report-views.interface.mjs +0 -2
  78. package/esm2022/app/reports/report-view-config.mjs +0 -587
  79. package/esm2022/app/reports/report-view-menu.mjs +0 -119
  80. package/esm2022/app/reports/services/report-view.service.mjs +0 -218
  81. 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==