@firestitch/report 18.10.0 → 18.10.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 (44) hide show
  1. package/app/reports/data/report.data.d.ts +3 -5
  2. package/app/reports/dialogs/report-settings/report-settings.component.d.ts +30 -2
  3. package/app/reports/filter-settings-rules.d.ts +4 -0
  4. package/app/reports/interfaces/report-filter-group-changes.interface.d.ts +7 -0
  5. package/app/reports/interfaces/report.interface.d.ts +1 -14
  6. package/app/reports/report-filter-items.d.ts +2 -8
  7. package/app/reports/report-view-config.d.ts +1 -3
  8. package/app/reports/services/report-filter-state.service.d.ts +5 -14
  9. package/app/reports/services/report-view.service.d.ts +1 -13
  10. package/app/reports/views/report/fs-ai-report.component.d.ts +2 -8
  11. package/esm2022/app/reports/canvas-landing-page.mjs +7 -6
  12. package/esm2022/app/reports/components/component-list/component-list.component.mjs +5 -5
  13. package/esm2022/app/reports/components/report-canvas/report-canvas.component.mjs +13 -12
  14. package/esm2022/app/reports/components/report-component/report-component.component.mjs +9 -9
  15. package/esm2022/app/reports/data/report.data.mjs +8 -5
  16. package/esm2022/app/reports/dialogs/report-settings/report-settings.component.mjs +169 -21
  17. package/esm2022/app/reports/filter-settings-rules.mjs +8 -1
  18. package/esm2022/app/reports/interfaces/canvas-landing-input.interface.mjs +1 -1
  19. package/esm2022/app/reports/interfaces/report-filter-group-changes.interface.mjs +2 -0
  20. package/esm2022/app/reports/interfaces/report-temporary-state.interface.mjs +1 -1
  21. package/esm2022/app/reports/interfaces/report-view-config.interface.mjs +1 -1
  22. package/esm2022/app/reports/interfaces/report.interface.mjs +1 -1
  23. package/esm2022/app/reports/report-date-presets.mjs +2 -2
  24. package/esm2022/app/reports/report-filter-items.mjs +25 -105
  25. package/esm2022/app/reports/report-view-config.mjs +6 -116
  26. package/esm2022/app/reports/services/report-filter-state.service.mjs +92 -269
  27. package/esm2022/app/reports/services/report-view.service.mjs +25 -165
  28. package/esm2022/app/reports/views/report/fs-ai-report.component.mjs +56 -120
  29. package/esm2022/app/reports/views/report/report.component.mjs +11 -8
  30. package/fesm2022/{firestitch-report-echarts-UBg8Wlhd.mjs → firestitch-report-echarts-DHEH_K_q.mjs} +2 -2
  31. package/fesm2022/{firestitch-report-echarts-UBg8Wlhd.mjs.map → firestitch-report-echarts-DHEH_K_q.mjs.map} +1 -1
  32. package/fesm2022/{firestitch-report-firestitch-report-B1keNrcK.mjs → firestitch-report-firestitch-report-ZcHTnNKq.mjs} +454 -1470
  33. package/fesm2022/firestitch-report-firestitch-report-ZcHTnNKq.mjs.map +1 -0
  34. package/fesm2022/firestitch-report.mjs +1 -1
  35. package/package.json +1 -1
  36. package/app/reports/interfaces/report-url-link.interface.d.ts +0 -4
  37. package/app/reports/interfaces/report-url-value-name.type.d.ts +0 -1
  38. package/app/reports/interfaces/report-url-write.interface.d.ts +0 -4
  39. package/app/reports/report-url-state.d.ts +0 -36
  40. package/esm2022/app/reports/interfaces/report-url-link.interface.mjs +0 -2
  41. package/esm2022/app/reports/interfaces/report-url-value-name.type.mjs +0 -2
  42. package/esm2022/app/reports/interfaces/report-url-write.interface.mjs +0 -2
  43. package/esm2022/app/reports/report-url-state.mjs +0 -677
  44. package/fesm2022/firestitch-report-firestitch-report-B1keNrcK.mjs.map +0 -1
@@ -1,677 +0,0 @@
1
- import { iso8601 } from '@firestitch/date';
2
- import { getExcludeName } from '@firestitch/filter';
3
- import { parseISO } from 'date-fns';
4
- import { FORMAT_PARAM, GROUP_BY_ITEM, MATCH_ITEM, PERSONAL_VIEW_PARAM, VIEW_PARAM, dateBoundString, groupParamKeys, itemRangeName, } from './report-filter-items';
5
- import { DRILL_MAX_DEPTH, GROUP_VALUE_MAX_PICKS, REPORT_VIEW_CONFIG_VERSION, isCalendarDay, isChartGranularity, numberFromText, toStoredGroupValue, } from './report-view-config';
6
- // The report viewer's state in its URL: a pure codec. It knows the report's
7
- // filter groups only to name their keys; ReportFilterStateService decides
8
- // WHAT is carried (only values that differ from the link's base) and checks
9
- // what is read back against the report; this file only turns values into
10
- // query params and back. Each value below is as the codec writes it; the
11
- // router percent-encodes it again in the address bar.
12
- //
13
- // ?page=7&groupBy=week&region=3:North,5:East&excludeStatus=2:Refunded
14
- // &shippedFrom=2026-01-01T00:00:00-05:00&shippedTo=2026-01-31T00:00:00-05:00
15
- // &unitsMin=0&unitsMax=50&s31=-create_date&q31=north
16
- // &h31=notes,total&d44=year:2026-01-01,quarter:2026-07-01&match=any&rv=12&rf=2
17
- //
18
- // A filter group is written under its fs-filter item's own query keys, so
19
- // the bar and the link have one syntax. <key> is the group's key, the
20
- // camelCase of its label ('Region' -> region; groupParamKeys in
21
- // report-filter-items.ts, which also says what a clash falls back to:
22
- // region12).
23
- // - A select: <key>=value:name,... for the values it keeps and
24
- // exclude<Key>=value:name,... for the values it leaves out. This is
25
- // fs-filter's own syntax: ',' between picks, ':' between a value and its
26
- // name, and a ',', ':' or '\' inside either one escaped with '\'. The name
27
- // is the one the chip showed when the link was written, and is left off
28
- // while the viewer has not seen it. Only the value is read back: names come
29
- // from the option list, so a renamed option shows its new name.
30
- // - A number range: <key>Min and <key>Max, either one open.
31
- // - A date range: <key>From and <key>To in fs-filter's date format (the
32
- // day's local midnight with its offset, 2026-01-01T00:00:00-05:00), either
33
- // one open. Only the day is read back, so a link opens on the same days in
34
- // every zone. A link never names a preset: a date picker preset only sets
35
- // the days, and a rolling range (a report's relative default) is not written
36
- // while it is the link's base, and is written as its days when it must be
37
- // (the caller turns it into days first; see groupValueParams).
38
- // - A keyword: <key>=text.
39
- // An empty value is an explicit clear of a group that has a default: <key>=
40
- // for a select or a keyword, both ends empty for a range.
41
- // The other keys:
42
- // - s<componentId>: a list's sort column, '-' prefixed when descending.
43
- // - q<componentId>: the text in a list's search box.
44
- // - h<componentId>: the columns a viewer hid on a list (encodeColumnList).
45
- // - d<componentId>: a chart's drill path, 'level:value' steps (each part
46
- // percent-encoded) joined by ','.
47
- // - groupBy: the group-by grain (GROUP_BY_ITEM).
48
- // - match=any: the groups combine with any (absent = all).
49
- // - rv: the shared view the state is a diff from. rpv: the open personal
50
- // view, a label only, never a base.
51
- // - rf=2: the format every link this viewer writes carries.
52
- // A key this codec does not know is ignored and left in the URL as it is.
53
- // The page key is the host's (FsAiReportComponent.pageQueryParam) and is
54
- // written beside these, never by this codec. The cross-filter and the rows
55
- // panel are never in the URL.
56
- //
57
- // The keys the codec owns: the tile keys, groupBy, match, rv, rpv, rf, and
58
- // every key a group of the open report is written under. A write removes an
59
- // owned key it no longer carries, so a host must not keep its own state
60
- // under one. A group key comes from a label, so a host param named like one
61
- // (a group labeled 'Status' owns status and excludeStatus) is the codec's.
62
- // Only the default page key, 'page', is kept off the groups.
63
- // The keys of the views and the format. Declared beside the filter items,
64
- // which keep a group key off them (declaring them here would make the two
65
- // files import each other); re-exported so every codec constant can be
66
- // imported from the codec.
67
- export { FORMAT_PARAM, PERSONAL_VIEW_PARAM, VIEW_PARAM } from './report-filter-items';
68
- // The prefix of a list's sort key.
69
- export const LIST_SORT_PARAM_PREFIX = 's';
70
- // The prefix of a list's search key.
71
- export const LIST_SEARCH_PARAM_PREFIX = 'q';
72
- // The prefix of a list's hidden-columns key.
73
- export const LIST_HIDDEN_PARAM_PREFIX = 'h';
74
- // The prefix of a chart's drill-path key.
75
- export const DRILL_PARAM_PREFIX = 'd';
76
- // The match's key: the report bar's Match item's own name.
77
- export const MATCH_PARAM = MATCH_ITEM;
78
- // The format a link this viewer writes carries.
79
- export const URL_FORMAT = 2;
80
- // Between a drill step's level and its value.
81
- export const DRILL_STEP_SEPARATOR = ':';
82
- // Between a select's picks, and between a pick's value and its name
83
- // (fs-filter's AutoCompleteChips syntax).
84
- export const PICK_SEPARATOR = ',';
85
- export const PICK_NAME_SEPARATOR = ':';
86
- // Before a ',', ':' or '\' that is part of a pick's value or name.
87
- const PICK_ESCAPE = '\\';
88
- // The most characters the codec's params may take in a link (the host's own
89
- // path and params are not counted).
90
- export const REPORT_URL_MAX_LENGTH = 2000;
91
- // Shown once when a link left group values out (ReportUrlWrite.tooLong).
92
- export const URL_TOO_LONG_MESSAGE = 'This filter is too long for a link; save a view to share it.';
93
- const MATCH_ANY = 'any';
94
- // The prefixes of the tile keys this codec owns, each followed by an id.
95
- const OWNED_PREFIXES = [LIST_SORT_PARAM_PREFIX, LIST_SEARCH_PARAM_PREFIX, LIST_HIDDEN_PARAM_PREFIX, DRILL_PARAM_PREFIX];
96
- // The keys this codec owns that carry no id and do not depend on the report.
97
- const OWNED_KEYS = [GROUP_BY_ITEM, MATCH_PARAM, VIEW_PARAM, PERSONAL_VIEW_PARAM, FORMAT_PARAM];
98
- // A key of one of the prefixes above, followed by its id.
99
- const ID_PARAM = new RegExp(`^([${OWNED_PREFIXES.join('')}])(\\d+)$`);
100
- // A key this codec owns whatever the report: a list's sort, search or hidden
101
- // columns; a chart's drill path; the grain, the match, the two views and the
102
- // format. The groups' keys are owned too (see the top of this file).
103
- export const OWNED_PARAM = new RegExp(`^(?:[${OWNED_PREFIXES.join('')}]\\d+|${OWNED_KEYS.join('|')})$`);
104
- // A link's day: 'yyyy-MM-dd', alone or as the start of fs-filter's date
105
- // format ('T' and a time and offset after it).
106
- const LINK_DAY = /^(\d{4}-\d{2}-\d{2})(?:T.*)?$/;
107
- // The viewer-state params of a URL: the groups' values in their stored shape
108
- // (null for a group the link clears; read as paramsToViewConfig reads them),
109
- // the rest as raw strings. Keys this codec does not own are ignored.
110
- // `groups` is every filter group of the report.
111
- export function readReportUrlParams(params, groups) {
112
- const listSorts = new Map();
113
- const listSearches = new Map();
114
- const listHidden = new Map();
115
- // Each prefix read here names the map its keys go to; a prefix with no
116
- // entry is never read as some other kind of state.
117
- const byPrefix = {
118
- [LIST_SORT_PARAM_PREFIX]: listSorts,
119
- [LIST_SEARCH_PARAM_PREFIX]: listSearches,
120
- [LIST_HIDDEN_PARAM_PREFIX]: listHidden,
121
- };
122
- const query = {};
123
- for (const key of params.keys) {
124
- query[key] = params.get(key) ?? '';
125
- const owned = ID_PARAM.exec(key);
126
- if (owned) {
127
- byPrefix[owned[1]]?.set(Number(owned[2]), params.get(key) ?? '');
128
- }
129
- }
130
- return {
131
- groups: readGroupParams(query, groups),
132
- listSorts, listSearches, listHidden,
133
- groupBy: params.get(GROUP_BY_ITEM),
134
- };
135
- }
136
- // The viewer state a link carries, as a view config: its group values (read
137
- // by each group's type, so a group the report does not have is skipped), the
138
- // grain, the match and each tile's sort, search, hidden columns and drill
139
- // path. A param that is unusable is left out. Whether a tile's component and
140
- // a list's columns exist is the caller's check. `groups` is every filter
141
- // group of the report.
142
- export function paramsToViewConfig(params, groups) {
143
- const config = { v: REPORT_VIEW_CONFIG_VERSION };
144
- const groupBy = paramText(params[GROUP_BY_ITEM]);
145
- if (isChartGranularity(groupBy)) {
146
- config.groupBy = groupBy;
147
- }
148
- if (paramText(params[MATCH_PARAM]) === MATCH_ANY) {
149
- config.match = MATCH_ANY;
150
- }
151
- readGroupParams(params, groups).forEach((value, groupId) => {
152
- config.groups = { ...config.groups, [groupId]: value };
153
- });
154
- Object.keys(params).forEach((key) => {
155
- const owned = ID_PARAM.exec(key);
156
- const raw = paramText(params[key]);
157
- if (owned && raw !== null) {
158
- readTileParam(config, owned[1], Number(owned[2]), raw);
159
- }
160
- });
161
- return config;
162
- }
163
- // The params that make a link carry `config`, the views it names, and rf=2.
164
- // Each group is written under its keys among `groups` (every filter group of
165
- // the report); a group the report no longer has is left out. `name` names a
166
- // select's values. Past REPORT_URL_MAX_LENGTH the longest group values are
167
- // left out (those groups then open at the link's base) and tooLong is set.
168
- export function viewConfigToParams(config, groups, link = {}, name = () => null) {
169
- const params = {};
170
- const keys = groupParamKeys(groups);
171
- const types = new Map(groups.map((group) => [group.id, group.type]));
172
- const groupParams = new Set();
173
- if (config.groupBy) {
174
- params[GROUP_BY_ITEM] = config.groupBy;
175
- }
176
- Object.entries(config.groups ?? {}).forEach(([id, value]) => {
177
- const groupId = Number(id);
178
- const key = keys.get(groupId);
179
- if (key) {
180
- const written = groupValueParams(types.get(groupId), key, value, (pick) => name(groupId, pick));
181
- Object.assign(params, written);
182
- Object.keys(written).forEach((param) => groupParams.add(param));
183
- }
184
- });
185
- Object.entries(config.tiles ?? {}).forEach(([componentId, tile]) => {
186
- Object.assign(params, tileParams(Number(componentId), tile));
187
- });
188
- if (config.match === MATCH_ANY) {
189
- params[MATCH_PARAM] = MATCH_ANY;
190
- }
191
- if (link.viewId) {
192
- params[VIEW_PARAM] = String(link.viewId);
193
- }
194
- if (link.personalViewId) {
195
- params[PERSONAL_VIEW_PARAM] = String(link.personalViewId);
196
- }
197
- return capReportParams(withFormat(params), groupParams);
198
- }
199
- // The views a link names, each a positive id or null.
200
- export function readReportUrlLink(params) {
201
- return {
202
- viewId: positiveId(paramText(params[VIEW_PARAM])),
203
- personalViewId: positiveId(paramText(params[PERSONAL_VIEW_PARAM])),
204
- };
205
- }
206
- // Whether a link carries viewer state of its own, so it opens on that state
207
- // rather than on a default view: any owned key but the format marker and the
208
- // personal view, which is a label only. `groups` is every filter group of
209
- // the report.
210
- export function hasReportUrlState(params, groups) {
211
- const groupKeys = ownedGroupKeys(groups);
212
- return Object.keys(params).some((key) => ID_PARAM.test(key) || groupKeys.has(key)
213
- || key === GROUP_BY_ITEM || key === MATCH_PARAM || key === VIEW_PARAM);
214
- }
215
- // Every owned key `current` carries, set to null: under the router's 'merge'
216
- // handling, a write spread over these removes the keys it no longer carries.
217
- // Keys this codec does not own are left alone. `groups` is every filter
218
- // group of the report.
219
- export function reportParamsToClear(current, groups) {
220
- const groupKeys = ownedGroupKeys(groups);
221
- const params = {};
222
- for (const key of current.keys) {
223
- if (OWNED_PARAM.test(key) || groupKeys.has(key)) {
224
- params[key] = null;
225
- }
226
- }
227
- return params;
228
- }
229
- // The names the select picks in `current` (the URL as it is) carry, so a
230
- // write can keep a name the viewer's lists have not named yet. Only a write
231
- // reads these: what the chips show comes from the lists.
232
- export function urlValueNames(current, groups) {
233
- const keys = groupParamKeys(groups);
234
- const names = new Map();
235
- groups
236
- .filter((group) => group.type === 'select')
237
- .forEach((group) => {
238
- const key = keys.get(group.id);
239
- const picks = [current.get(key), current.get(getExcludeName(key))]
240
- .flatMap((raw) => (raw ? decodePickList(raw) : []))
241
- .filter((pick) => pick.name !== null);
242
- names.set(group.id, new Map(picks.map((pick) => [pick.value, pick.name])));
243
- });
244
- return (groupId, value) => names.get(groupId)?.get(String(value)) ?? null;
245
- }
246
- // A list's hidden column names as one param value. A name is a query's output
247
- // alias, which can hold a comma, so each is percent-encoded before the join.
248
- export function encodeColumnList(names) {
249
- return names.map((name) => encodeURIComponent(name)).join(',');
250
- }
251
- // The column names of a hidden-columns param, in its order. Empty items are
252
- // dropped, and an item that does not decode (a hand-edited '%') is kept as
253
- // written. Whether a name is a column of the list is the caller's check.
254
- export function decodeColumnList(raw) {
255
- return raw.split(',')
256
- .filter((item) => item !== '')
257
- .map(decodeItem);
258
- }
259
- // A group's value in its stored shape as the link's params under the group's
260
- // key (see the top of this file): days, then a select's values left out, then
261
- // its values kept, then a number range, then keyword text. null (a cleared
262
- // group), or a value that holds nothing, is the group's keys, empty. A
263
- // relative range with no days is not written at all: a link carries days, and
264
- // only the caller has the report's zone and clock to give them
265
- // (ReportViewService). `name` names a select's value.
266
- export function groupValueParams(type, key, value, name = () => null) {
267
- if (!value) {
268
- return clearParams(type, key);
269
- }
270
- if (value.start || value.end) {
271
- return rangeParams(type, key, ['from', 'to'], [linkDayText(value.start), linkDayText(value.end)]);
272
- }
273
- if (value.excludeValues?.length) {
274
- return { [getExcludeName(key)]: encodePicks(value.excludeValues, name) };
275
- }
276
- if (value.values) {
277
- return { [key]: encodePicks(value.values, name) };
278
- }
279
- if (isNumberEnd(value.min) || isNumberEnd(value.max)) {
280
- return rangeParams(type, key, ['min', 'max'], [numberEndText(value.min), numberEndText(value.max)]);
281
- }
282
- if (value.relative) {
283
- return {};
284
- }
285
- return value.value ? { [key]: value.value } : clearParams(type, key);
286
- }
287
- export function encodeSort(sort) {
288
- return `${sort.direction === 'desc' ? '-' : ''}${sort.column}`;
289
- }
290
- // A list sort read back from its URL param, or null when it names no column.
291
- // Whether the column is one the list can sort by is the caller's check.
292
- export function decodeSort(raw) {
293
- const descending = raw.startsWith('-');
294
- const column = descending ? raw.slice(1) : raw;
295
- return column
296
- ? { column, direction: descending ? 'desc' : 'asc' }
297
- : null;
298
- }
299
- // A drill path as its URL param. A step with no value writes its level only.
300
- export function encodeDrillPath(path) {
301
- return path
302
- .map((step) => (step.value === null || step.value === undefined
303
- ? encodeURIComponent(step.level)
304
- : `${encodeURIComponent(step.level)}${DRILL_STEP_SEPARATOR}${encodeURIComponent(String(step.value))}`))
305
- .join(',');
306
- }
307
- // A drill path read back from its URL param: its steps up to the first that
308
- // is not a time level (the steps before it are kept), at most DRILL_MAX_DEPTH
309
- // of them. Values come back as text. Whether the path fits the chart is the
310
- // server's check (it applies the longest valid prefix).
311
- export function decodeDrillPath(raw) {
312
- const path = [];
313
- for (const item of raw.split(',')) {
314
- const step = decodeDrillStep(item);
315
- if (!step || path.length === DRILL_MAX_DEPTH) {
316
- break;
317
- }
318
- path.push(step);
319
- }
320
- return path;
321
- }
322
- // The query params that make the URL carry `snapshot`: every snapshot key is
323
- // set, and each owned key that `current` carries but the snapshot does not is
324
- // set to null, which removes it under the router's 'merge' handling. Keys
325
- // this codec does not own are left alone. Each group is written under its
326
- // keys among `groups` (every filter group of the report). A select's value
327
- // is named by `name`, else by the name `current` carries for it. A date range
328
- // is written as the days on screen, never as a preset name.
329
- export function buildReportUrlParams(snapshot, current, groups, name = () => null) {
330
- const params = {};
331
- const keys = groupParamKeys(groups);
332
- const types = new Map(groups.map((group) => [group.id, group.type]));
333
- const currentName = urlValueNames(current, groups);
334
- snapshot.groups.forEach((value, groupId) => {
335
- const key = keys.get(groupId);
336
- if (key) {
337
- const type = types.get(groupId);
338
- const named = (pick) => name(groupId, pick) ?? currentName(groupId, pick);
339
- const days = value ? { ...value, preset: undefined } : value;
340
- Object.assign(params, groupValueParams(type, key, toStoredGroupValue(type, days), named));
341
- }
342
- });
343
- snapshot.listSorts.forEach((sort, componentId) => {
344
- params[`${LIST_SORT_PARAM_PREFIX}${componentId}`] = encodeSort(sort);
345
- });
346
- // The text as typed: the router percent-encodes it in the URL.
347
- snapshot.listSearches.forEach((search, componentId) => {
348
- params[`${LIST_SEARCH_PARAM_PREFIX}${componentId}`] = search;
349
- });
350
- snapshot.listHidden.forEach((names, componentId) => {
351
- params[`${LIST_HIDDEN_PARAM_PREFIX}${componentId}`] = encodeColumnList(names);
352
- });
353
- if (snapshot.frequency) {
354
- params[GROUP_BY_ITEM] = snapshot.frequency;
355
- }
356
- return { ...reportParamsToClear(current, groups), ...withFormat(params) };
357
- }
358
- // `params` with the format marker, when it carries anything.
359
- function withFormat(params) {
360
- return Object.keys(params).length ? { ...params, [FORMAT_PARAM]: String(URL_FORMAT) } : params;
361
- }
362
- // Each group's value a link carries, in its stored shape, by group id (null
363
- // for a group the link clears). A group with no usable param is left out.
364
- function readGroupParams(params, groups) {
365
- const keys = groupParamKeys(groups);
366
- const values = new Map();
367
- for (const group of groups) {
368
- const value = readGroupParam(params, group.type, keys.get(group.id));
369
- if (value !== undefined) {
370
- values.set(group.id, value);
371
- }
372
- }
373
- return values;
374
- }
375
- // One group's value in a link, read from the keys of its type. null is a
376
- // clear; undefined is no usable value.
377
- function readGroupParam(params, type, key) {
378
- switch (type) {
379
- case 'select':
380
- return readSelect(params, key);
381
- case 'dateRange':
382
- return readDateRange(params, key);
383
- case 'numberRange':
384
- return readNumberRange(params, key);
385
- case 'keyword':
386
- return readKeyword(params[key]);
387
- default:
388
- return undefined;
389
- }
390
- }
391
- // A select's values kept (<key>), else its values left out (exclude<Key>).
392
- function readSelect(params, key) {
393
- const kept = paramText(params[key]);
394
- if (kept !== null) {
395
- return kept === '' ? null : decodePicks(kept, 'values');
396
- }
397
- const excluded = paramText(params[getExcludeName(key)]);
398
- if (excluded !== null) {
399
- return excluded === '' ? null : decodePicks(excluded, 'excludeValues');
400
- }
401
- return undefined;
402
- }
403
- // A date range's days (<key>From, <key>To), each a real calendar day,
404
- // either one open but not both.
405
- function readDateRange(params, key) {
406
- const ends = readRangeEnds(params, key, ['from', 'to']);
407
- if (!ends) {
408
- return ends === null ? null : undefined;
409
- }
410
- const [start, end] = ends.map(linkDay);
411
- if (start === undefined || end === undefined) {
412
- return undefined;
413
- }
414
- return compactRange(start, end, 'start', 'end');
415
- }
416
- // A number range's ends (<key>Min, <key>Max), each a finite number, either
417
- // one open but not both, and min not above max.
418
- function readNumberRange(params, key) {
419
- const ends = readRangeEnds(params, key, ['min', 'max']);
420
- if (!ends) {
421
- return ends === null ? null : undefined;
422
- }
423
- const [min, max] = ends.map((end) => (end === '' ? null : numberFromText(end)));
424
- if ((ends[0] !== '' && min === null) || (ends[1] !== '' && max === null) || (min !== null && max !== null && min > max)) {
425
- return undefined;
426
- }
427
- return compactRange(min, max, 'min', 'max');
428
- }
429
- // A keyword's text. Blank text is unusable.
430
- function readKeyword(raw) {
431
- const text = paramText(raw);
432
- if (text === null) {
433
- return undefined;
434
- }
435
- if (text === '') {
436
- return null;
437
- }
438
- return text.trim() ? { value: text } : undefined;
439
- }
440
- // A range's two ends as written ('' for one the link leaves open):
441
- // undefined when the link carries neither key, null when every one it
442
- // carries is empty (a clear).
443
- function readRangeEnds(params, key, ends) {
444
- const [low, high] = ends.map((end) => paramText(params[itemRangeName(key, end)]));
445
- if (low === null && high === null) {
446
- return undefined;
447
- }
448
- return low || high ? [low ?? '', high ?? ''] : null;
449
- }
450
- // The params of a range's ends, the ones it sets only; with neither one
451
- // usable, the group's clear.
452
- function rangeParams(type, key, ends, texts) {
453
- const params = {};
454
- ends.forEach((end, index) => {
455
- if (texts[index]) {
456
- params[itemRangeName(key, end)] = texts[index];
457
- }
458
- });
459
- return Object.keys(params).length ? params : clearParams(type, key);
460
- }
461
- // The params of a cleared group: its keys, empty.
462
- function clearParams(type, key) {
463
- switch (type) {
464
- case 'dateRange':
465
- return { [itemRangeName(key, 'from')]: '', [itemRangeName(key, 'to')]: '' };
466
- case 'numberRange':
467
- return { [itemRangeName(key, 'min')]: '', [itemRangeName(key, 'max')]: '' };
468
- default:
469
- return { [key]: '' };
470
- }
471
- }
472
- // A stored day in fs-filter's date format: its local midnight with the
473
- // offset, '' when there is no real day.
474
- function linkDayText(bound) {
475
- const day = dateBoundString(bound);
476
- return day && isCalendarDay(day) ? iso8601(parseISO(day)) : '';
477
- }
478
- // The day of a link's date end: null when the end is open (''), undefined
479
- // when it is not a real calendar day.
480
- function linkDay(text) {
481
- if (text === '') {
482
- return null;
483
- }
484
- const day = LINK_DAY.exec(text)?.[1];
485
- return day && isCalendarDay(day) ? day : undefined;
486
- }
487
- // The keys a link carries the groups' values under, by each group's type.
488
- function ownedGroupKeys(groups) {
489
- const keys = groupParamKeys(groups);
490
- return new Set(groups.flatMap((group) => {
491
- const key = keys.get(group.id);
492
- switch (group.type) {
493
- case 'select':
494
- return [key, getExcludeName(key)];
495
- case 'dateRange':
496
- return [itemRangeName(key, 'from'), itemRangeName(key, 'to')];
497
- case 'numberRange':
498
- return [itemRangeName(key, 'min'), itemRangeName(key, 'max')];
499
- default:
500
- return [key];
501
- }
502
- }));
503
- }
504
- // One id-keyed param of a tile read into `config`.
505
- function readTileParam(config, prefix, id, raw) {
506
- switch (prefix) {
507
- case LIST_SORT_PARAM_PREFIX:
508
- setTileState(config, id, 'sort', decodeSort(raw));
509
- break;
510
- case LIST_SEARCH_PARAM_PREFIX:
511
- setTileState(config, id, 'search', raw || null);
512
- break;
513
- case LIST_HIDDEN_PARAM_PREFIX:
514
- setTileState(config, id, 'hidden', nonEmpty(decodeColumnList(raw)));
515
- break;
516
- default:
517
- setTileState(config, id, 'drill', nonEmpty(decodeDrillPath(raw)));
518
- }
519
- }
520
- // Sets one key of a tile's state, creating the tile, unless there is nothing
521
- // to set.
522
- function setTileState(config, componentId, key, value) {
523
- if (value === null) {
524
- return;
525
- }
526
- config.tiles = { ...config.tiles, [componentId]: { ...config.tiles?.[componentId], [key]: value } };
527
- }
528
- // The params of one tile's state.
529
- function tileParams(componentId, tile) {
530
- const params = {};
531
- if (tile.sort?.column) {
532
- params[`${LIST_SORT_PARAM_PREFIX}${componentId}`] = encodeSort(tile.sort);
533
- }
534
- // The text as typed: the router percent-encodes it in the URL.
535
- if (tile.search) {
536
- params[`${LIST_SEARCH_PARAM_PREFIX}${componentId}`] = tile.search;
537
- }
538
- if (tile.hidden?.length) {
539
- params[`${LIST_HIDDEN_PARAM_PREFIX}${componentId}`] = encodeColumnList(tile.hidden);
540
- }
541
- if (tile.drill?.length) {
542
- params[`${DRILL_PARAM_PREFIX}${componentId}`] = encodeDrillPath(tile.drill);
543
- }
544
- return params;
545
- }
546
- // `params` within REPORT_URL_MAX_LENGTH: past it, group values (the params
547
- // named in `groupParams`) are left out, longest first, until the rest fits.
548
- function capReportParams(params, groupParams) {
549
- if (queryLength(params) <= REPORT_URL_MAX_LENGTH) {
550
- return { params, tooLong: false };
551
- }
552
- const kept = { ...params };
553
- const groupKeys = Object.keys(kept)
554
- .filter((key) => groupParams.has(key))
555
- .sort((a, b) => queryText(kept[b]).length - queryText(kept[a]).length);
556
- for (const key of groupKeys) {
557
- if (queryLength(kept) <= REPORT_URL_MAX_LENGTH) {
558
- break;
559
- }
560
- delete kept[key];
561
- }
562
- return { params: kept, tooLong: true };
563
- }
564
- // The length of `params` as the router writes them in a query string.
565
- function queryLength(params) {
566
- return Object.entries(params)
567
- .map(([key, value]) => `${queryText(key)}=${queryText(value)}`)
568
- .join('&')
569
- .length;
570
- }
571
- // Text as the router writes it in a query string (its query encoding):
572
- // percent-encoded, with '@', ':', '$', ',' and ';' left as they are.
573
- function queryText(text) {
574
- return encodeURIComponent(text)
575
- .replace(/%40/g, '@')
576
- .replace(/%3A/gi, ':')
577
- .replace(/%24/g, '$')
578
- .replace(/%2C/gi, ',')
579
- .replace(/%3B/gi, ';');
580
- }
581
- // A param's text: a repeated key gives its first value.
582
- function paramText(value) {
583
- const first = Array.isArray(value) ? value[0] : value;
584
- return typeof first === 'string' || typeof first === 'number' ? String(first) : null;
585
- }
586
- function positiveId(raw) {
587
- return raw !== null && /^[1-9]\d*$/.test(raw) ? Number(raw) : null;
588
- }
589
- function nonEmpty(list) {
590
- return list.length ? list : null;
591
- }
592
- // An item of a list param, percent-decoded; one that does not decode (a
593
- // hand-edited '%') is kept as written.
594
- function decodeItem(item) {
595
- try {
596
- return decodeURIComponent(item);
597
- }
598
- catch {
599
- return item;
600
- }
601
- }
602
- // Select picks as one param value: value:name for each, the name left off
603
- // when `name` does not know it, blanks left out.
604
- function encodePicks(picks, name) {
605
- return picks
606
- .filter((pick) => typeof pick === 'string' || typeof pick === 'number' || typeof pick === 'boolean')
607
- .filter((pick) => String(pick) !== '')
608
- .map((pick) => {
609
- const named = name(pick);
610
- return named ? `${escapePick(String(pick))}${PICK_NAME_SEPARATOR}${escapePick(named)}` : escapePick(String(pick));
611
- })
612
- .join(PICK_SEPARATOR);
613
- }
614
- // A pick's value or name with each ',', ':' and '\' in it escaped.
615
- function escapePick(text) {
616
- return text.replace(/[\\,:]/g, (char) => `${PICK_ESCAPE}${char}`);
617
- }
618
- // The picks of a param written as encodePicks writes them, in order: each
619
- // value and its name (null when the pick has none).
620
- function decodePickList(raw) {
621
- const picks = [];
622
- let parts = [''];
623
- let escaped = false;
624
- const endPick = () => picks.push({ value: parts[0], name: parts.length > 1 ? parts[1] : null });
625
- for (const char of raw) {
626
- if (escaped) {
627
- parts[parts.length - 1] += char;
628
- escaped = false;
629
- }
630
- else if (char === PICK_ESCAPE) {
631
- escaped = true;
632
- }
633
- else if (char === PICK_NAME_SEPARATOR && parts.length === 1) {
634
- parts.push('');
635
- }
636
- else if (char === PICK_SEPARATOR) {
637
- endPick();
638
- parts = [''];
639
- }
640
- else {
641
- parts[parts.length - 1] += char;
642
- }
643
- }
644
- endPick();
645
- return picks;
646
- }
647
- // A select's values, kept or left out, read from its param, or undefined
648
- // when there are none or too many.
649
- function decodePicks(raw, as) {
650
- const picks = decodePickList(raw)
651
- .map((pick) => pick.value)
652
- .filter((value) => value !== '');
653
- return picks.length && picks.length <= GROUP_VALUE_MAX_PICKS ? { [as]: picks } : undefined;
654
- }
655
- // A range's set ends under their keys.
656
- function compactRange(low, high, lowKey, highKey) {
657
- return {
658
- ...(low !== null ? { [lowKey]: low } : {}),
659
- ...(high !== null ? { [highKey]: high } : {}),
660
- };
661
- }
662
- function isNumberEnd(end) {
663
- return typeof end === 'number' && Number.isFinite(end);
664
- }
665
- function numberEndText(end) {
666
- return isNumberEnd(end) ? String(end) : '';
667
- }
668
- // One 'level:value' step, or null when its level is not a time grain.
669
- function decodeDrillStep(item) {
670
- const at = item.indexOf(DRILL_STEP_SEPARATOR);
671
- const level = decodeItem(at < 0 ? item : item.slice(0, at));
672
- if (!isChartGranularity(level)) {
673
- return null;
674
- }
675
- return { level, value: at < 0 ? null : decodeItem(item.slice(at + 1)) };
676
- }
677
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVwb3J0LXVybC1zdGF0ZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9hcHAvcmVwb3J0cy9yZXBvcnQtdXJsLXN0YXRlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUVBLE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQztBQUMzQyxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFFcEQsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLFVBQVUsQ0FBQztBQVlwQyxPQUFPLEVBQ0wsWUFBWSxFQUFFLGFBQWEsRUFBZ0IsVUFBVSxFQUFFLG1CQUFtQixFQUFFLFVBQVUsRUFDdEYsZUFBZSxFQUFFLGNBQWMsRUFBRSxhQUFhLEdBQy9DLE1BQU0sdUJBQXVCLENBQUM7QUFDL0IsT0FBTyxFQUNMLGVBQWUsRUFBRSxxQkFBcUIsRUFBRSwwQkFBMEIsRUFBRSxhQUFhLEVBQUUsa0JBQWtCLEVBQ3JHLGNBQWMsRUFBRSxrQkFBa0IsR0FDbkMsTUFBTSxzQkFBc0IsQ0FBQztBQUc5Qiw0RUFBNEU7QUFDNUUsMEVBQTBFO0FBQzFFLDRFQUE0RTtBQUM1RSx5RUFBeUU7QUFDekUseUVBQXlFO0FBQ3pFLHNEQUFzRDtBQUN0RCxFQUFFO0FBQ0Ysd0VBQXdFO0FBQ3hFLGdGQUFnRjtBQUNoRix3REFBd0Q7QUFDeEQsa0ZBQWtGO0FBQ2xGLEVBQUU7QUFDRiwwRUFBMEU7QUFDMUUsc0VBQXNFO0FBQ3RFLGdFQUFnRTtBQUNoRSxzRUFBc0U7QUFDdEUsYUFBYTtBQUNiLCtEQUErRDtBQUMvRCxzRUFBc0U7QUFDdEUsMkVBQTJFO0FBQzNFLDZFQUE2RTtBQUM3RSwwRUFBMEU7QUFDMUUsOEVBQThFO0FBQzlFLGtFQUFrRTtBQUNsRSw0REFBNEQ7QUFDNUQsd0VBQXdFO0FBQ3hFLDZFQUE2RTtBQUM3RSw2RUFBNkU7QUFDN0UsNEVBQTRFO0FBQzVFLCtFQUErRTtBQUMvRSw0RUFBNEU7QUFDNUUs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QUFDLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztLQUM5QyxDQUFDO0FBQ0osQ0FBQztBQUVELFNBQVMsV0FBVyxDQUFDLEdBQVk7SUFDL0IsT0FBTyxPQUFPLEdBQUcsS0FBSyxRQUFRLElBQUksTUFBTSxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsQ0FBQztBQUN6RCxDQUFDO0FBRUQsU0FBUyxhQUFhLENBQUMsR0FBWTtJQUNqQyxPQUFPLFdBQVcsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUM7QUFDN0MsQ0FBQztBQUVELHNFQUFzRTtBQUN0RSxTQUFTLGVBQWUsQ0FBQyxJQUFZO0lBQ25DLE1BQU0sRUFBRSxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsb0JBQW9CLENBQUMsQ0FBQztJQUM5QyxNQUFNLEtBQUssR0FBRyxVQUFVLENBQUMsRUFBRSxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDO0lBRTVELElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDO1FBQy9CLE9BQU8sSUFBSSxDQUFDO0lBQ2QsQ0FBQztJQUVELE9BQU8sRUFBRSxLQUFLLEVBQUUsS0FBSyxFQUFFLEVBQUUsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsRUFBRSxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztBQUMxRSxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgUGFyYW1NYXAsIFBhcmFtcyB9IGZyb20gJ0Bhbmd1bGFyL3JvdXRlcic7XG5cbmltcG9ydCB7IGlzbzg2MDEgfSBmcm9tICdAZmlyZXN0aXRjaC9kYXRlJztcbmltcG9ydCB7IGdldEV4Y2x1ZGVOYW1lIH0gZnJvbSAnQGZpcmVzdGl0Y2gvZmlsdGVyJztcblxuaW1wb3J0IHsgcGFyc2VJU08gfSBmcm9tICdkYXRlLWZucyc7XG5cbmltcG9ydCB7IFJlcG9ydERyaWxsU3RlcCB9IGZyb20gJy4vaW50ZXJmYWNlcy9yZXBvcnQtZHJpbGwtc3RlcC5pbnRlcmZhY2UnO1xuaW1wb3J0IHsgUmVwb3J0RmlsdGVyTWF0Y2ggfSBmcm9tICcuL2ludGVyZmFjZXMvcmVwb3J0LWZpbHRlci1tYXRjaC50eXBlJztcbmltcG9ydCB7IFJlcG9ydFRpbGVTdGF0ZSB9IGZyb20gJy4vaW50ZXJmYWNlcy9yZXBvcnQtdGlsZS1zdGF0ZS5pbnRlcmZhY2UnO1xuaW1wb3J0IHsgUmVwb3J0VXJsTGluayB9IGZyb20gJy4vaW50ZXJmYWNlcy9yZXBvcnQtdXJsLWxpbmsuaW50ZXJmYWNlJztcbmltcG9ydCB7IFJlcG9ydFVybFZhbHVlTmFtZSB9IGZyb20gJy4vaW50ZXJmYWNlcy9yZXBvcnQtdXJsLXZhbHVlLW5hbWUudHlwZSc7XG5pbXBvcnQgeyBSZXBvcnRVcmxXcml0ZSB9IGZyb20gJy4vaW50ZXJmYWNlcy9yZXBvcnQtdXJsLXdyaXRlLmludGVyZmFjZSc7XG5pbXBvcnQgeyBSZXBvcnRWaWV3Q29uZmlnIH0gZnJvbSAnLi9pbnRlcmZhY2VzL3JlcG9ydC12aWV3LWNvbmZpZy5pbnRlcmZhY2UnO1xuaW1wb3J0IHtcbiAgRmlsdGVyR3JvdXBEZWZhdWx0LCBSZXBvcnRGaWx0ZXJHcm91cCwgUmVwb3J0RmlsdGVyVHlwZSwgUmVwb3J0U29ydCwgUmVwb3J0VXJsUGFyYW1zLCBSZXBvcnRVcmxTbmFwc2hvdCxcbn0gZnJvbSAnLi9pbnRlcmZhY2VzL3JlcG9ydC5pbnRlcmZhY2UnO1xuaW1wb3J0IHtcbiAgRk9STUFUX1BBUkFNLCBHUk9VUF9CWV9JVEVNLCBJdGVtUmFuZ2VFbmQsIE1BVENIX0lURU0sIFBFUlNPTkFMX1ZJRVdfUEFSQU0sIFZJRVdfUEFSQU0sXG4gIGRhdGVCb3VuZFN0cmluZywgZ3JvdXBQYXJhbUtleXMsIGl0ZW1SYW5nZU5hbWUsXG59IGZyb20gJy4vcmVwb3J0LWZpbHRlci1pdGVtcyc7XG5pbXBvcnQge1xuICBEUklMTF9NQVhfREVQVEgsIEdST1VQX1ZBTFVFX01BWF9QSUNLUywgUkVQT1JUX1ZJRVdfQ09ORklHX1ZFUlNJT04sIGlzQ2FsZW5kYXJEYXksIGlzQ2hhcnRHcmFudWxhcml0eSxcbiAgbnVtYmVyRnJvbVRleHQsIHRvU3RvcmVkR3JvdXBWYWx1ZSxcbn0gZnJvbSAnLi9yZXBvcnQtdmlldy1jb25maWcnO1xuXG5cbi8vIFRoZSByZXBvcnQgdmlld2VyJ3Mgc3RhdGUgaW4gaXRzIFVSTDogYSBwdXJlIGNvZGVjLiBJdCBrbm93cyB0aGUgcmVwb3J0J3Ncbi8vIGZpbHRlciBncm91cHMgb25seSB0byBuYW1lIHRoZWlyIGtleXM7IFJlcG9ydEZpbHRlclN0YXRlU2VydmljZSBkZWNpZGVzXG4vLyBXSEFUIGlzIGNhcnJpZWQgKG9ubHkgdmFsdWVzIHRoYXQgZGlmZmVyIGZyb20gdGhlIGxpbmsncyBiYXNlKSBhbmQgY2hlY2tzXG4vLyB3aGF0IGlzIHJlYWQgYmFjayBhZ2FpbnN0IHRoZSByZXBvcnQ7IHRoaXMgZmlsZSBvbmx5IHR1cm5zIHZhbHVlcyBpbnRvXG4vLyBxdWVyeSBwYXJhbXMgYW5kIGJhY2suIEVhY2ggdmFsdWUgYmVsb3cgaXMgYXMgdGhlIGNvZGVjIHdyaXRlcyBpdDsgdGhlXG4vLyByb3V0ZXIgcGVyY2VudC1lbmNvZGVzIGl0IGFnYWluIGluIHRoZSBhZGRyZXNzIGJhci5cbi8vXG4vLyAgID9wYWdlPTcmZ3JvdXBCeT13ZWVrJnJlZ2lvbj0zOk5vcnRoLDU6RWFzdCZleGNsdWRlU3RhdHVzPTI6UmVmdW5kZWRcbi8vICAgICZzaGlwcGVkRnJvbT0yMDI2LTAxLTAxVDAwOjAwOjAwLTA1OjAwJnNoaXBwZWRUbz0yMDI2LTAxLTMxVDAwOjAwOjAwLTA1OjAwXG4vLyAgICAmdW5pdHNNaW49MCZ1bml0c01heD01MCZzMzE9LWNyZWF0ZV9kYXRlJnEzMT1ub3J0aFxuLy8gICAgJmgzMT1ub3Rlcyx0b3RhbCZkNDQ9eWVhcjoyMDI2LTAxLTAxLHF1YXJ0ZXI6MjAyNi0wNy0wMSZtYXRjaD1hbnkmcnY9MTImcmY9MlxuLy9cbi8vIEEgZmlsdGVyIGdyb3VwIGlzIHdyaXR0ZW4gdW5kZXIgaXRzIGZzLWZpbHRlciBpdGVtJ3Mgb3duIHF1ZXJ5IGtleXMsIHNvXG4vLyB0aGUgYmFyIGFuZCB0aGUgbGluayBoYXZlIG9uZSBzeW50YXguIDxrZXk+IGlzIHRoZSBncm91cCdzIGtleSwgdGhlXG4vLyBjYW1lbENhc2Ugb2YgaXRzIGxhYmVsICgnUmVnaW9uJyAtPiByZWdpb247IGdyb3VwUGFyYW1LZXlzIGluXG4vLyByZXBvcnQtZmlsdGVyLWl0ZW1zLnRzLCB3aGljaCBhbHNvIHNheXMgd2hhdCBhIGNsYXNoIGZhbGxzIGJhY2sgdG86XG4vLyByZWdpb24xMikuXG4vLyAtIEEgc2VsZWN0OiA8a2V5Pj12YWx1ZTpuYW1lLC4uLiBmb3IgdGhlIHZhbHVlcyBpdCBrZWVwcyBhbmRcbi8vICAgZXhjbHVkZTxLZXk+PXZhbHVlOm5hbWUsLi4uIGZvciB0aGUgdmFsdWVzIGl0IGxlYXZlcyBvdXQuIFRoaXMgaXNcbi8vICAgZnMtZmlsdGVyJ3Mgb3duIHN5bnRheDogJywnIGJldHdlZW4gcGlja3MsICc6JyBiZXR3ZWVuIGEgdmFsdWUgYW5kIGl0c1xuLy8gICBuYW1lLCBhbmQgYSAnLCcsICc6JyBvciAnXFwnIGluc2lkZSBlaXRoZXIgb25lIGVzY2FwZWQgd2l0aCAnXFwnLiBUaGUgbmFtZVxuLy8gICBpcyB0aGUgb25lIHRoZSBjaGlwIHNob3dlZCB3aGVuIHRoZSBsaW5rIHdhcyB3cml0dGVuLCBhbmQgaXMgbGVmdCBvZmZcbi8vICAgd2hpbGUgdGhlIHZpZXdlciBoYXMgbm90IHNlZW4gaXQuIE9ubHkgdGhlIHZhbHVlIGlzIHJlYWQgYmFjazogbmFtZXMgY29tZVxuLy8gICBmcm9tIHRoZSBvcHRpb24gbGlzdCwgc28gYSByZW5hbWVkIG9wdGlvbiBzaG93cyBpdHMgbmV3IG5hbWUuXG4vLyAtIEEgbnVtYmVyIHJhbmdlOiA8a2V5Pk1pbiBhbmQgPGtleT5NYXgsIGVpdGhlciBvbmUgb3Blbi5cbi8vIC0gQSBkYXRlIHJhbmdlOiA8a2V5PkZyb20gYW5kIDxrZXk+VG8gaW4gZnMtZmlsdGVyJ3MgZGF0ZSBmb3JtYXQgKHRoZVxuLy8gICBkYXkncyBsb2NhbCBtaWRuaWdodCB3aXRoIGl0cyBvZmZzZXQsIDIwMjYtMDEtMDFUMDA6MDA6MDAtMDU6MDApLCBlaXRoZXJcbi8vICAgb25lIG9wZW4uIE9ubHkgdGhlIGRheSBpcyByZWFkIGJhY2ssIHNvIGEgbGluayBvcGVucyBvbiB0aGUgc2FtZSBkYXlzIGluXG4vLyAgIGV2ZXJ5IHpvbmUuIEEgbGluayBuZXZlciBuYW1lcyBhIHByZXNldDogYSBkYXRlIHBpY2tlciBwcmVzZXQgb25seSBzZXRzXG4vLyAgIHRoZSBkYXlzLCBhbmQgYSByb2xsaW5nIHJhbmdlIChhIHJlcG9ydCdzIHJlbGF0aXZlIGRlZmF1bHQpIGlzIG5vdCB3cml0dGVuXG4vLyAgIHdoaWxlIGl0IGlzIHRoZSBsaW5rJ3MgYmFzZSwgYW5kIGlzIHdyaXR0ZW4gYXMgaXRzIGRheXMgd2hlbiBpdCBtdXN0IGJlXG4vLyAgICh0aGUgY2FsbGVyIHR1cm5zIGl0IGludG8gZGF5cyBmaXJzdDsgc2VlIGdyb3VwVmFsdWVQYXJhbXMpLlxuLy8gLSBBIGtleXdvcmQ6IDxrZXk+PXRleHQuXG4vLyBBbiBlbXB0eSB2YWx1ZSBpcyBhbiBleHBsaWNpdCBjbGVhciBvZiBhIGdyb3VwIHRoYXQgaGFzIGEgZGVmYXVsdDogPGtleT49XG4vLyBmb3IgYSBzZWxlY3Qgb3IgYSBrZXl3b3JkLCBib3RoIGVuZHMgZW1wdHkgZm9yIGEgcmFuZ2UuXG4vLyBUaGUgb3RoZXIga2V5czpcbi8vIC0gczxjb21wb25lbnRJZD46IGEgbGlzdCdzIHNvcnQgY29sdW1uLCAnLScgcHJlZml4ZWQgd2hlbiBkZXNjZW5kaW5nLlxuLy8gLSBxPGNvbXBvbmVudElkPjogdGhlIHRleHQgaW4gYSBsaXN0J3Mgc2VhcmNoIGJveC5cbi8vIC0gaDxjb21wb25lbnRJZD46IHRoZSBjb2x1bW5zIGEgdmlld2VyIGhpZCBvbiBhIGxpc3QgKGVuY29kZUNvbHVtbkxpc3QpLlxuLy8gLSBkPGNvbXBvbmVudElkPjogYSBjaGFydCdzIGRyaWxsIHBhdGgsICdsZXZlbDp2YWx1ZScgc3RlcHMgKGVhY2ggcGFydFxuLy8gICBwZXJjZW50LWVuY29kZWQpIGpvaW5lZCBieSAnLCcuXG4vLyAtIGdyb3VwQnk6IHRoZSBncm91cC1ieSBncmFpbiAoR1JPVVBfQllfSVRFTSkuXG4vLyAtIG1hdGNoPWFueTogdGhlIGdyb3VwcyBjb21iaW5lIHdpdGggYW55IChhYnNlbnQgPSBhbGwpLlxuLy8gLSBydjogdGhlIHNoYXJlZCB2aWV3IHRoZSBzdGF0ZSBpcyBhIGRpZmYgZnJvbS4gcnB2OiB0aGUgb3BlbiBwZXJzb25hbFxuLy8gICB2aWV3LCBhIGxhYmVsIG9ubHksIG5ldmVyIGEgYmFzZS5cbi8vIC0gcmY9MjogdGhlIGZvcm1hdCBldmVyeSBsaW5rIHRoaXMgdmlld2VyIHdyaXRlcyBjYXJyaWVzLlxuLy8gQSBrZXkgdGhpcyBjb2RlYyBkb2VzIG5vdCBrbm93IGlzIGlnbm9yZWQgYW5kIGxlZnQgaW4gdGhlIFVSTCBhcyBpdCBpcy5cbi8vIFRoZSBwYWdlIGtleSBpcyB0aGUgaG9zdCdzIChGc0FpUmVwb3J0Q29tcG9uZW50LnBhZ2VRdWVyeVBhcmFtKSBhbmQgaXNcbi8vIHdyaXR0ZW4gYmVzaWRlIHRoZXNlLCBuZXZlciBieSB0aGlzIGNvZGVjLiBUaGUgY3Jvc3MtZmlsdGVyIGFuZCB0aGUgcm93c1xuLy8gcGFuZWwgYXJlIG5ldmVyIGluIHRoZSBVUkwuXG4vL1xuLy8gVGhlIGtleXMgdGhlIGNvZGVjIG93bnM6IHRoZSB0aWxlIGtleXMsIGdyb3VwQnksIG1hdGNoLCBydiwgcnB2LCByZiwgYW5kXG4vLyBldmVyeSBrZXkgYSBncm91cCBvZiB0aGUgb3BlbiByZXBvcnQgaXMgd3JpdHRlbiB1bmRlci4gQSB3cml0ZSByZW1vdmVzIGFuXG4vLyBvd25lZCBrZXkgaXQgbm8gbG9uZ2VyIGNhcnJpZXMsIHNvIGEgaG9zdCBtdXN0IG5vdCBrZWVwIGl0cyBvd24gc3RhdGVcbi8vIHVuZGVyIG9uZS4gQSBncm91cCBrZXkgY29tZXMgZnJvbSBhIGxhYmVsLCBzbyBhIGhvc3QgcGFyYW0gbmFtZWQgbGlrZSBvbmVcbi8vIChhIGdyb3VwIGxhYmVsZWQgJ1N0YXR1cycgb3ducyBzdGF0dXMgYW5kIGV4Y2x1ZGVTdGF0dXMpIGlzIHRoZSBjb2RlYydzLlxuLy8gT25seSB0aGUgZGVmYXVsdCBwYWdlIGtleSwgJ3BhZ2UnLCBpcyBrZXB0IG9mZiB0aGUgZ3JvdXBzLlxuXG4vLyBUaGUga2V5cyBvZiB0aGUgdmlld3MgYW5kIHRoZSBmb3JtYXQuIERlY2xhcmVkIGJlc2lkZSB0aGUgZmlsdGVyIGl0ZW1zLFxuLy8gd2hpY2gga2VlcCBhIGdyb3VwIGtleSBvZmYgdGhlbSAoZGVjbGFyaW5nIHRoZW0gaGVyZSB3b3VsZCBtYWtlIHRoZSB0d29cbi8vIGZpbGVzIGltcG9ydCBlYWNoIG90aGVyKTsgcmUtZXhwb3J0ZWQgc28gZXZlcnkgY29kZWMgY29uc3RhbnQgY2FuIGJlXG4vLyBpbXBvcnRlZCBmcm9tIHRoZSBjb2RlYy5cbmV4cG9ydCB7IEZPUk1BVF9QQVJBTSwgUEVSU09OQUxfVklFV19QQVJBTSwgVklFV19QQVJBTSB9IGZyb20gJy4vcmVwb3J0LWZpbHRlci1pdGVtcyc7XG5cbi8vIFRoZSBwcmVmaXggb2YgYSBsaXN0J3Mgc29ydCBrZXkuXG5leHBvcnQgY29uc3QgTElTVF9TT1JUX1BBUkFNX1BSRUZJWCA9ICdzJztcblxuLy8gVGhlIHByZWZpeCBvZiBhIGxpc3QncyBzZWFyY2gga2V5LlxuZXhwb3J0IGNvbnN0IExJU1RfU0VBUkNIX1BBUkFNX1BSRUZJWCA9ICdxJztcblxuLy8gVGhlIHByZWZpeCBvZiBhIGxpc3QncyBoaWRkZW4tY29sdW1ucyBrZXkuXG5leHBvcnQgY29uc3QgTElTVF9ISURERU5fUEFSQU1fUFJFRklYID0gJ2gnO1xuXG4vLyBUaGUgcHJlZml4IG9mIGEgY2hhcnQncyBkcmlsbC1wYXRoIGtleS5cbmV4cG9ydCBjb25zdCBEUklMTF9QQVJBTV9QUkVGSVggPSAnZCc7XG5cbi8vIFRoZSBtYXRjaCdzIGtleTogdGhlIHJlcG9ydCBiYXIncyBNYXRjaCBpdGVtJ3Mgb3duIG5hbWUuXG5leHBvcnQgY29uc3QgTUFUQ0hfUEFSQU0gPSBNQVRDSF9JVEVNO1xuXG4vLyBUaGUgZm9ybWF0IGEgbGluayB0aGlzIHZpZXdlciB3cml0ZXMgY2Fycmllcy5cbmV4cG9ydCBjb25zdCBVUkxfRk9STUFUID0gMjtcblxuLy8gQmV0d2VlbiBhIGRyaWxsIHN0ZXAncyBsZXZlbCBhbmQgaXRzIHZhbHVlLlxuZXhwb3J0IGNvbnN0IERSSUxMX1NURVBfU0VQQVJBVE9SID0gJzonO1xuXG4vLyBCZXR3ZWVuIGEgc2VsZWN0J3MgcGlja3MsIGFuZCBiZXR3ZWVuIGEgcGljaydzIHZhbHVlIGFuZCBpdHMgbmFtZVxuLy8gKGZzLWZpbHRlcidzIEF1dG9Db21wbGV0ZUNoaXBzIHN5bnRheCkuXG5leHBvcnQgY29uc3QgUElDS19TRVBBUkFUT1IgPSAnLCc7XG5leHBvcnQgY29uc3QgUElDS19OQU1FX1NFUEFSQVRPUiA9ICc6JztcblxuLy8gQmVmb3JlIGEgJywnLCAnOicgb3IgJ1xcJyB0aGF0IGlzIHBhcnQgb2YgYSBwaWNrJ3MgdmFsdWUgb3IgbmFtZS5cbmNvbnN0IFBJQ0tfRVNDQVBFID0gJ1xcXFwnO1xuXG4vLyBUaGUgbW9zdCBjaGFyYWN0ZXJzIHRoZSBjb2RlYydzIHBhcmFtcyBtYXkgdGFrZSBpbiBhIGxpbmsgKHRoZSBob3N0J3Mgb3duXG4vLyBwYXRoIGFuZCBwYXJhbXMgYXJlIG5vdCBjb3VudGVkKS5cbmV4cG9ydCBjb25zdCBSRVBPUlRfVVJMX01BWF9MRU5HVEggPSAyMDAwO1xuXG4vLyBTaG93biBvbmNlIHdoZW4gYSBsaW5rIGxlZnQgZ3JvdXAgdmFsdWVzIG91dCAoUmVwb3J0VXJsV3JpdGUudG9vTG9uZykuXG5leHBvcnQgY29uc3QgVVJMX1RPT19MT05HX01FU1NBR0UgPSAnVGhpcyBmaWx0ZXIgaXMgdG9vIGxvbmcgZm9yIGEgbGluazsgc2F2ZSBhIHZpZXcgdG8gc2hhcmUgaXQuJztcblxuY29uc3QgTUFUQ0hfQU5ZOiBSZXBvcnRGaWx0ZXJNYXRjaCA9ICdhbnknO1xuXG4vLyBUaGUgcHJlZml4ZXMgb2YgdGhlIHRpbGUga2V5cyB0aGlzIGNvZGVjIG93bnMsIGVhY2ggZm9sbG93ZWQgYnkgYW4gaWQuXG5jb25zdCBPV05FRF9QUkVGSVhFUyA9IFtMSVNUX1NPUlRfUEFSQU1fUFJFRklYLCBMSVNUX1NFQVJDSF9QQVJBTV9QUkVGSVgsIExJU1RfSElEREVOX1BBUkFNX1BSRUZJWCwgRFJJTExfUEFSQU1fUFJFRklYXTtcblxuLy8gVGhlIGtleXMgdGhpcyBjb2RlYyBvd25zIHRoYXQgY2Fycnkgbm8gaWQgYW5kIGRvIG5vdCBkZXBlbmQgb24gdGhlIHJlcG9ydC5cbmNvbnN0IE9XTkVEX0tFWVMgPSBbR1JPVVBfQllfSVRFTSwgTUFUQ0hfUEFSQU0sIFZJRVdfUEFSQU0sIFBFUlNPTkFMX1ZJRVdfUEFSQU0sIEZPUk1BVF9QQVJBTV07XG5cbi8vIEEga2V5IG9mIG9uZSBvZiB0aGUgcHJlZml4ZXMgYWJvdmUsIGZvbGxvd2VkIGJ5IGl0cyBpZC5cbmNvbnN0IElEX1BBUkFNID0gbmV3IFJlZ0V4cChgXihbJHtPV05FRF9QUkVGSVhFUy5qb2luKCcnKX1dKShcXFxcZCspJGApO1xuXG4vLyBBIGtleSB0aGlzIGNvZGVjIG93bnMgd2hhdGV2ZXIgdGhlIHJlcG9ydDogYSBsaXN0J3Mgc29ydCwgc2VhcmNoIG9yIGhpZGRlblxuLy8gY29sdW1uczsgYSBjaGFydCdzIGRyaWxsIHBhdGg7IHRoZSBncmFpbiwgdGhlIG1hdGNoLCB0aGUgdHdvIHZpZXdzIGFuZCB0aGVcbi8vIGZvcm1hdC4gVGhlIGdyb3Vwcycga2V5cyBhcmUgb3duZWQgdG9vIChzZWUgdGhlIHRvcCBvZiB0aGlzIGZpbGUpLlxuZXhwb3J0IGNvbnN0IE9XTkVEX1BBUkFNID0gbmV3IFJlZ0V4cChgXig/Olske09XTkVEX1BSRUZJWEVTLmpvaW4oJycpfV1cXFxcZCt8JHtPV05FRF9LRVlTLmpvaW4oJ3wnKX0pJGApO1xuXG4vLyBBIGxpbmsncyBkYXk6ICd5eXl5LU1NLWRkJywgYWxvbmUgb3IgYXMgdGhlIHN0YXJ0IG9mIGZzLWZpbHRlcidzIGRhdGVcbi8vIGZvcm1hdCAoJ1QnIGFuZCBhIHRpbWUgYW5kIG9mZnNldCBhZnRlciBpdCkuXG5jb25zdCBMSU5LX0RBWSA9IC9eKFxcZHs0fS1cXGR7Mn0tXFxkezJ9KSg/OlQuKik/JC87XG5cbnR5cGUgVXJsR3JvdXAgPSBQaWNrPFJlcG9ydEZpbHRlckdyb3VwLCAnaWQnIHwgJ3R5cGUnIHwgJ2xhYmVsJyB8ICdmaWx0ZXJzJz47XG5cbi8vIFRoZSB2aWV3ZXItc3RhdGUgcGFyYW1zIG9mIGEgVVJMOiB0aGUgZ3JvdXBzJyB2YWx1ZXMgaW4gdGhlaXIgc3RvcmVkIHNoYXBlXG4vLyAobnVsbCBmb3IgYSBncm91cCB0aGUgbGluayBjbGVhcnM7IHJlYWQgYXMgcGFyYW1zVG9WaWV3Q29uZmlnIHJlYWRzIHRoZW0pLFxuLy8gdGhlIHJlc3QgYXMgcmF3IHN0cmluZ3MuIEtleXMgdGhpcyBjb2RlYyBkb2VzIG5vdCBvd24gYXJlIGlnbm9yZWQuXG4vLyBgZ3JvdXBzYCBpcyBldmVyeSBmaWx0ZXIgZ3JvdXAgb2YgdGhlIHJlcG9ydC5cbmV4cG9ydCBmdW5jdGlvbiByZWFkUmVwb3J0VXJsUGFyYW1zKHBhcmFtczogUGFyYW1NYXAsIGdyb3VwczogcmVhZG9ubHkgVXJsR3JvdXBbXSk6IFJlcG9ydFVybFBhcmFtcyB7XG4gIGNvbnN0IGxpc3RTb3J0cyA9IG5ldyBNYXA8bnVtYmVyLCBzdHJpbmc+KCk7XG4gIGNvbnN0IGxpc3RTZWFyY2hlcyA9IG5ldyBNYXA8bnVtYmVyLCBzdHJpbmc+KCk7XG4gIGNvbnN0IGxpc3RIaWRkZW4gPSBuZXcgTWFwPG51bWJlciwgc3RyaW5nPigpO1xuICAvLyBFYWNoIHByZWZpeCByZWFkIGhlcmUgbmFtZXMgdGhlIG1hcCBpdHMga2V5cyBnbyB0bzsgYSBwcmVmaXggd2l0aCBub1xuICAvLyBlbnRyeSBpcyBuZXZlciByZWFkIGFzIHNvbWUgb3RoZXIga2luZCBvZiBzdGF0ZS5cbiAgY29uc3QgYnlQcmVmaXg6IFJlY29yZDxzdHJpbmcsIE1hcDxudW1iZXIsIHN0cmluZz4+ID0ge1xuICAgIFtMSVNUX1NPUlRfUEFSQU1fUFJFRklYXTogbGlzdFNvcnRzLFxuICAgIFtMSVNUX1NFQVJDSF9QQVJBTV9QUkVGSVhdOiBsaXN0U2VhcmNoZXMsXG4gICAgW0xJU1RfSElEREVOX1BBUkFNX1BSRUZJWF06IGxpc3RIaWRkZW4sXG4gIH07XG4gIGNvbnN0IHF1ZXJ5OiBQYXJhbXMgPSB7fTtcblxuICBmb3IgKGNvbnN0IGtleSBvZiBwYXJhbXMua2V5cykge1xuICAgIHF1ZXJ5W2tleV0gPSBwYXJhbXMuZ2V0KGtleSkgPz8gJyc7XG4gICAgY29uc3Qgb3duZWQgPSBJRF9QQVJBTS5leGVjKGtleSk7XG4gICAgaWYgKG93bmVkKSB7XG4gICAgICBieVByZWZpeFtvd25lZFsxXV0/LnNldChOdW1iZXIob3duZWRbMl0pLCBwYXJhbXMuZ2V0KGtleSkgPz8gJycpO1xuICAgIH1cbiAgfVxuXG4gIHJldHVybiB7XG4gICAgZ3JvdXBzOiByZWFkR3JvdXBQYXJhbXMocXVlcnksIGdyb3VwcyksXG4gICAgbGlzdFNvcnRzLCBsaXN0U2VhcmNoZXMsIGxpc3RIaWRkZW4sXG4gICAgZ3JvdXBCeTogcGFyYW1zLmdldChHUk9VUF9CWV9JVEVNKSxcbiAgfTtcbn1cblxuLy8gVGhlIHZpZXdlciBzdGF0ZSBhIGxpbmsgY2FycmllcywgYXMgYSB2aWV3IGNvbmZpZzogaXRzIGdyb3VwIHZhbHVlcyAocmVhZFxuLy8gYnkgZWFjaCBncm91cCdzIHR5cGUsIHNvIGEgZ3JvdXAgdGhlIHJlcG9ydCBkb2VzIG5vdCBoYXZlIGlzIHNraXBwZWQpLCB0aGVcbi8vIGdyYWluLCB0aGUgbWF0Y2ggYW5kIGVhY2ggdGlsZSdzIHNvcnQsIHNlYXJjaCwgaGlkZGVuIGNvbHVtbnMgYW5kIGRyaWxsXG4vLyBwYXRoLiBBIHBhcmFtIHRoYXQgaXMgdW51c2FibGUgaXMgbGVmdCBvdXQuIFdoZXRoZXIgYSB0aWxlJ3MgY29tcG9uZW50IGFuZFxuLy8gYSBsaXN0J3MgY29sdW1ucyBleGlzdCBpcyB0aGUgY2FsbGVyJ3MgY2hlY2suIGBncm91cHNgIGlzIGV2ZXJ5IGZpbHRlclxuLy8gZ3JvdXAgb2YgdGhlIHJlcG9ydC5cbmV4cG9ydCBmdW5jdGlvbiBwYXJhbXNUb1ZpZXdDb25maWcocGFyYW1zOiBQYXJhbXMsIGdyb3VwczogcmVhZG9ubHkgVXJsR3JvdXBbXSk6IFJlcG9ydFZpZXdDb25maWcge1xuICBjb25zdCBjb25maWc6IFJlcG9ydFZpZXdDb25maWcgPSB7IHY6IFJFUE9SVF9WSUVXX0NPTkZJR19WRVJTSU9OIH07XG5cbiAgY29uc3QgZ3JvdXBCeSA9IHBhcmFtVGV4dChwYXJhbXNbR1JPVVBfQllfSVRFTV0pO1xuICBpZiAoaXNDaGFydEdyYW51bGFyaXR5KGdyb3VwQnkpKSB7XG4gICAgY29uZmlnLmdyb3VwQnkgPSBncm91cEJ5O1xuICB9XG5cbiAgaWYgKHBhcmFtVGV4dChwYXJhbXNbTUFUQ0hfUEFSQU1dKSA9PT0gTUFUQ0hfQU5ZKSB7XG4gICAgY29uZmlnLm1hdGNoID0gTUFUQ0hfQU5ZO1xuICB9XG5cbiAgcmVhZEdyb3VwUGFyYW1zKHBhcmFtcywgZ3JvdXBzKS5mb3JFYWNoKCh2YWx1ZSwgZ3JvdXBJZCkgPT4ge1xuICAgIGNvbmZpZy5ncm91cHMgPSB7IC4uLmNvbmZpZy5ncm91cHMsIFtncm91cElkXTogdmFsdWUgfTtcbiAgfSk7XG5cbiAgT2JqZWN0LmtleXMocGFyYW1zKS5mb3JFYWNoKChrZXkpID0+IHtcbiAgICBjb25zdCBvd25lZCA9IElEX1BBUkFNLmV4ZWMoa2V5KTtcbiAgICBjb25zdCByYXcgPSBwYXJhbVRleHQocGFyYW1zW2tleV0pO1xuXG4gICAgaWYgKG93bmVkICYmIHJhdyAhPT0gbnVsbCkge1xuICAgICAgcmVhZFRpbGVQYXJhbShjb25maWcsIG93bmVkWzFdLCBOdW1iZXIob3duZWRbMl0pLCByYXcpO1xuICAgIH1cbiAgfSk7XG5cbiAgcmV0dXJuIGNvbmZpZztcbn1cblxuLy8gVGhlIHBhcmFtcyB0aGF0IG1ha2UgYSBsaW5rIGNhcnJ5IGBjb25maWdgLCB0aGUgdmlld3MgaXQgbmFtZXMsIGFuZCByZj0yLlxuLy8gRWFjaCBncm91cCBpcyB3cml0dGVuIHVuZGVyIGl0cyBrZXlzIGFtb25nIGBncm91cHNgIChldmVyeSBmaWx0ZXIgZ3JvdXAgb2Zcbi8vIHRoZSByZXBvcnQpOyBhIGdyb3VwIHRoZSByZXBvcnQgbm8gbG9uZ2VyIGhhcyBpcyBsZWZ0IG91dC4gYG5hbWVgIG5hbWVzIGFcbi8vIHNlbGVjdCdzIHZhbHVlcy4gUGFzdCBSRVBPUlRfVVJMX01BWF9MRU5HVEggdGhlIGxvbmdlc3QgZ3JvdXAgdmFsdWVzIGFyZVxuLy8gbGVmdCBvdXQgKHRob3NlIGdyb3VwcyB0aGVuIG9wZW4gYXQgdGhlIGxpbmsncyBiYXNlKSBhbmQgdG9vTG9uZyBpcyBzZXQuXG5leHBvcnQgZnVuY3Rpb24gdmlld0NvbmZpZ1RvUGFyYW1zKFxuICBjb25maWc6IFJlcG9ydFZpZXdDb25maWcsXG4gIGdyb3VwczogcmVhZG9ubHkgVXJsR3JvdXBbXSxcbiAgbGluazogUmVwb3J0VXJsTGluayA9IHt9LFxuICBuYW1lOiBSZXBvcnRVcmxWYWx1ZU5hbWUgPSAoKSA9PiBudWxsLFxuKTogUmVwb3J0VXJsV3JpdGUge1xuICBjb25zdCBwYXJhbXM6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4gPSB7fTtcbiAgY29uc3Qga2V5cyA9IGdyb3VwUGFyYW1LZXlzKGdyb3Vwcyk7XG4gIGNvbnN0IHR5cGVzID0gbmV3IE1hcChncm91cHMubWFwKChncm91cCkgPT4gW2dyb3VwLmlkLCBncm91cC50eXBlXSkpO1xuICBjb25zdCBncm91cFBhcmFtcyA9IG5ldyBTZXQ8c3RyaW5nPigpO1xuXG4gIGlmIChjb25maWcuZ3JvdXBCeSkge1xuICAgIHBhcmFtc1tHUk9VUF9CWV9JVEVNXSA9IGNvbmZpZy5ncm91cEJ5O1xuICB9XG5cbiAgT2JqZWN0LmVudHJpZXMoY29uZmlnLmdyb3VwcyA/PyB7fSkuZm9yRWFjaCgoW2lkLCB2YWx1ZV0pID0+IHtcbiAgICBjb25zdCBncm91cElkID0gTnVtYmVyKGlkKTtcbiAgICBjb25zdCBrZXkgPSBrZXlzLmdldChncm91cElkKTtcbiAgICBpZiAoa2V5KSB7XG4gICAgICBjb25zdCB3cml0dGVuID0gZ3JvdXBWYWx1ZVBhcmFtcyh0eXBlcy5nZXQoZ3JvdXBJZCksIGtleSwgdmFsdWUsIChwaWNrKSA9PiBuYW1lKGdyb3VwSWQsIHBpY2spKTtcbiAgICAgIE9iamVjdC5hc3NpZ24ocGFyYW1zLCB3cml0dGVuKTtcbiAgICAgIE9iamVjdC5rZXlzKHdyaXR0ZW4pLmZvckVhY2goKHBhcmFtKSA9PiBncm91cFBhcmFtcy5hZGQocGFyYW0pKTtcbiAgICB9XG4gIH0pO1xuXG4gIE9iamVjdC5lbnRyaWVzKGNvbmZpZy50aWxlcyA/PyB7fSkuZm9yRWFjaCgoW2NvbXBvbmVudElkLCB0aWxlXSkgPT4ge1xuICAgIE9iamVjdC5hc3NpZ24ocGFyYW1zLCB0aWxlUGFyYW1zKE51bWJlcihjb21wb25lbnRJZCksIHRpbGUpKTtcbiAgfSk7XG5cbiAgaWYgKGNvbmZpZy5tYXRjaCA9PT0gTUFUQ0hfQU5ZKSB7XG4gICAgcGFyYW1zW01BVENIX1BBUkFNXSA9IE1BVENIX0FOWTtcbiAgfVxuXG4gIGlmIChsaW5rLnZpZXdJZCkge1xuICAgIHBhcmFtc1tWSUVXX1BBUkFNXSA9IFN0cmluZyhsaW5rLnZpZXdJZCk7XG4gIH1cblxuICBpZiAobGluay5wZXJzb25hbFZpZXdJZCkge1xuICAgIHBhcmFtc1tQRVJTT05BTF9WSUVXX1BBUkFNXSA9IFN0cmluZyhsaW5rLnBlcnNvbmFsVmlld0lkKTtcbiAgfVxuXG4gIHJldHVybiBjYXBSZXBvcnRQYXJhbXMod2l0aEZvcm1hdChwYXJhbXMpLCBncm91cFBhcmFtcyk7XG59XG5cbi8vIFRoZSB2aWV3cyBhIGxpbmsgbmFtZXMsIGVhY2ggYSBwb3NpdGl2ZSBpZCBvciBudWxsLlxuZXhwb3J0IGZ1bmN0aW9uIHJlYWRSZXBvcnRVcmxMaW5rKHBhcmFtczogUGFyYW1zKTogUmVwb3J0VXJsTGluayB7XG4gIHJldHVybiB7XG4gICAgdmlld0lkOiBwb3NpdGl2ZUlkKHBhcmFtVGV4dChwYXJhbXNbVklFV19QQVJBTV0pKSxcbiAgICBwZXJzb25hbFZpZXdJZDogcG9zaXRpdmVJZChwYXJhbVRleHQocGFyYW1zW1BFUlNPTkFMX1ZJRVdfUEFSQU1dKSksXG4gIH07XG59XG5cbi8vIFdoZXRoZXIgYSBsaW5rIGNhcnJpZXMgdmlld2VyIHN0YXRlIG9mIGl0cyBvd24sIHNvIGl0IG9wZW5zIG9uIHRoYXQgc3RhdGVcbi8vIHJhdGhlciB0aGFuIG9uIGEgZGVmYXVsdCB2aWV3OiBhbnkgb3duZWQga2V5IGJ1dCB0aGUgZm9ybWF0IG1hcmtlciBhbmQgdGhlXG4vLyBwZXJzb25hbCB2aWV3LCB3aGljaCBpcyBhIGxhYmVsIG9ubHkuIGBncm91cHNgIGlzIGV2ZXJ5IGZpbHRlciBncm91cCBvZlxuLy8gdGhlIHJlcG9ydC5cbmV4cG9ydCBmdW5jdGlvbiBoYXNSZXBvcnRVcmxTdGF0ZShwYXJhbXM6IFBhcmFtcywgZ3JvdXBzOiByZWFkb25seSBVcmxHcm91cFtdKTogYm9vbGVhbiB7XG4gIGNvbnN0IGdyb3VwS2V5cyA9IG93bmVkR3JvdXBLZXlzKGdyb3Vwcyk7XG5cbiAgcmV0dXJuIE9iamVjdC5rZXlzKHBhcmFtcykuc29tZSgoa2V5KSA9PiBJRF9QQVJBTS50ZXN0KGtleSkgfHwgZ3JvdXBLZXlzLmhhcyhrZXkpXG4gICAgfHwga2V5ID09PSBHUk9VUF9CWV9JVEVNIHx8IGtleSA9PT0gTUFUQ0hfUEFSQU0gfHwga2V5ID09PSBWSUVXX1BBUkFNKTtcbn1cblxuLy8gRXZlcnkgb3duZWQga2V5IGBjdXJyZW50YCBjYXJyaWVzLCBzZXQgdG8gbnVsbDogdW5kZXIgdGhlIHJvdXRlcidzICdtZXJnZSdcbi8vIGhhbmRsaW5nLCBhIHdyaXRlIHNwcmVhZCBvdmVyIHRoZXNlIHJlbW92ZXMgdGhlIGtleXMgaXQgbm8gbG9uZ2VyIGNhcnJpZXMuXG4vLyBLZXlzIHRoaXMgY29kZWMgZG9lcyBub3Qgb3duIGFyZSBsZWZ0IGFsb25lLiBgZ3JvdXBzYCBpcyBldmVyeSBmaWx0ZXJcbi8vIGdyb3VwIG9mIHRoZSByZXBvcnQuXG5leHBvcnQgZnVuY3Rpb24gcmVwb3J0UGFyYW1zVG9DbGVhcihjdXJyZW50OiBQYXJhbU1hcCwgZ3JvdXBzOiByZWFkb25seSBVcmxHcm91cFtdKTogUGFyYW1zIHtcbiAgY29uc3QgZ3JvdXBLZXlzID0gb3duZWRHcm91cEtleXMoZ3JvdXBzKTtcbiAgY29uc3QgcGFyYW1zOiBQYXJhbXMgPSB7fTtcblxuICBmb3IgKGNvbnN0IGtleSBvZiBjdXJyZW50LmtleXMpIHtcbiAgICBpZiAoT1dORURfUEFSQU0udGVzdChrZXkpIHx8IGdyb3VwS2V5cy5oYXMoa2V5KSkge1xuICAgICAgcGFyYW1zW2tleV0gPSBudWxsO1xuICAgIH1cbiAgfVxuXG4gIHJldHVybiBwYXJhbXM7XG59XG5cbi8vIFRoZSBuYW1lcyB0aGUgc2VsZWN0IHBpY2tzIGluIGBjdXJyZW50YCAodGhlIFVSTCBhcyBpdCBpcykgY2FycnksIHNvIGFcbi8vIHdyaXRlIGNhbiBrZWVwIGEgbmFtZSB0aGUgdmlld2VyJ3MgbGlzdHMgaGF2ZSBub3QgbmFtZWQgeWV0LiBPbmx5IGEgd3JpdGVcbi8vIHJlYWRzIHRoZXNlOiB3aGF0IHRoZSBjaGlwcyBzaG93IGNvbWVzIGZyb20gdGhlIGxpc3RzLlxuZXhwb3J0IGZ1bmN0aW9uIHVybFZhbHVlTmFtZXMoY3VycmVudDogUGFyYW1NYXAsIGdyb3VwczogcmVhZG9ubHkgVXJsR3JvdXBbXSk6IFJlcG9ydFVybFZhbHVlTmFtZSB7XG4gIGNvbnN0IGtleXMgPSBncm91cFBhcmFtS2V5cyhncm91cHMpO1xuICBjb25zdCBuYW1lcyA9IG5ldyBNYXA8bnVtYmVyLCBNYXA8c3RyaW5nLCBzdHJpbmc+PigpO1xuXG4gIGdyb3Vwc1xuICAgIC5maWx0ZXIoKGdyb3VwKSA9PiBncm91cC50eXBlID09PSAnc2VsZWN0JylcbiAgICAuZm9yRWFjaCgoZ3JvdXApID0+IHtcbiAgICAgIGNvbnN0IGtleSA9IGtleXMuZ2V0KGdyb3VwLmlkKTtcbiAgICAgIGNvbnN0IHBpY2tzID0gW2N1cnJlbnQuZ2V0KGtleSksIGN1cnJlbnQuZ2V0KGdldEV4Y2x1ZGVOYW1lKGtleSkpXVxuICAgICAgICAuZmxhdE1hcCgocmF3KSA9PiAocmF3ID8gZGVjb2RlUGlja0xpc3QocmF3KSA6IFtdKSlcbiAgICAgICAgLmZpbHRlcigocGljaykgPT4gcGljay5uYW1lICE9PSBudWxsKTtcblxuICAgICAgbmFtZXMuc2V0KGdyb3VwLmlkLCBuZXcgTWFwKHBpY2tzLm1hcCgocGljaykgPT4gW3BpY2sudmFsdWUsIHBpY2submFtZV0pKSk7XG4gICAgfSk7XG5cbiAgcmV0dXJuIChncm91cElkLCB2YWx1ZSkgPT4gbmFtZXMuZ2V0KGdyb3VwSWQpPy5nZXQoU3RyaW5nKHZhbHVlKSkgPz8gbnVsbDtcbn1cblxuLy8gQSBsaXN0J3MgaGlkZGVuIGNvbHVtbiBuYW1lcyBhcyBvbmUgcGFyYW0gdmFsdWUuIEEgbmFtZSBpcyBhIHF1ZXJ5J3Mgb3V0cHV0XG4vLyBhbGlhcywgd2hpY2ggY2FuIGhvbGQgYSBjb21tYSwgc28gZWFjaCBpcyBwZXJjZW50LWVuY29kZWQgYmVmb3JlIHRoZSBqb2luLlxuZXhwb3J0IGZ1bmN0aW9uIGVuY29kZUNvbHVtbkxpc3QobmFtZXM6IHJlYWRvbmx5IHN0cmluZ1tdKTogc3RyaW5nIHtcbiAgcmV0dXJuIG5hbWVzLm1hcCgobmFtZSkgPT4gZW5jb2RlVVJJQ29tcG9uZW50KG5hbWUpKS5qb2luKCcsJyk7XG59XG5cbi8vIFRoZSBjb2x1bW4gbmFtZXMgb2YgYSBoaWRkZW4tY29sdW1ucyBwYXJhbSwgaW4gaXRzIG9yZGVyLiBFbXB0eSBpdGVtcyBhcmVcbi8vIGRyb3BwZWQsIGFuZCBhbiBpdGVtIHRoYXQgZG9lcyBub3QgZGVjb2RlIChhIGhhbmQtZWRpdGVkICclJykgaXMga2VwdCBhc1xuLy8gd3JpdHRlbi4gV2hldGhlciBhIG5hbWUgaXMgYSBjb2x1bW4gb2YgdGhlIGxpc3QgaXMgdGhlIGNhbGxlcidzIGNoZWNrLlxuZXhwb3J0IGZ1bmN0aW9uIGRlY29kZUNvbHVtbkxpc3QocmF3OiBzdHJpbmcpOiBzdHJpbmdbXSB7XG4gIHJldHVybiByYXcuc3BsaXQoJywnKVxuICAgIC5maWx0ZXIoKGl0ZW0pID0+IGl0ZW0gIT09ICcnKVxuICAgIC5tYXAoZGVjb2RlSXRlbSk7XG59XG5cbi8vIEEgZ3JvdXAncyB2YWx1ZSBpbiBpdHMgc3RvcmVkIHNoYXBlIGFzIHRoZSBsaW5rJ3MgcGFyYW1zIHVuZGVyIHRoZSBncm91cCdzXG4vLyBrZXkgKHNlZSB0aGUgdG9wIG9mIHRoaXMgZmlsZSk6IGRheXMsIHRoZW4gYSBzZWxlY3QncyB2YWx1ZXMgbGVmdCBvdXQsIHRoZW5cbi8vIGl0cyB2YWx1ZXMga2VwdCwgdGhlbiBhIG51bWJlciByYW5nZSwgdGhlbiBrZXl3b3JkIHRleHQuIG51bGwgKGEgY2xlYXJlZFxuLy8gZ3JvdXApLCBvciBhIHZhbHVlIHRoYXQgaG9sZHMgbm90aGluZywgaXMgdGhlIGdyb3VwJ3Mga2V5cywgZW1wdHkuIEFcbi8vIHJlbGF0aXZlIHJhbmdlIHdpdGggbm8gZGF5cyBpcyBub3Qgd3JpdHRlbiBhdCBhbGw6IGEgbGluayBjYXJyaWVzIGRheXMsIGFuZFxuLy8gb25seSB0aGUgY2FsbGVyIGhhcyB0aGUgcmVwb3J0J3Mgem9uZSBhbmQgY2xvY2sgdG8gZ2l2ZSB0aGVtXG4vLyAoUmVwb3J0Vmlld1NlcnZpY2UpLiBgbmFtZWAgbmFtZXMgYSBzZWxlY3QncyB2YWx1ZS5cbmV4cG9ydCBmdW5jdGlvbiBncm91cFZhbHVlUGFyYW1zKFxuICB0eXBlOiBSZXBvcnRGaWx0ZXJUeXBlIHwgdW5kZWZpbmVkLFxuICBrZXk6IHN0cmluZyxcbiAgdmFsdWU6IEZpbHRlckdyb3VwRGVmYXVsdCB8IG51bGwsXG4gIG5hbWU6ICh2YWx1ZTogdW5rbm93bikgPT4gc3RyaW5nIHwgbnVsbCA9ICgpID0+IG51bGwsXG4pOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+IHtcbiAgaWYgKCF2YWx1ZSkge1xuICAgIHJldHVybiBjbGVhclBhcmFtcyh0eXBlLCBrZXkpO1xuICB9XG5cbiAgaWYgKHZhbHVlLnN0YXJ0IHx8IHZhbHVlLmVuZCkge1xuICAgIHJldHVybiByYW5nZVBhcmFtcyh0eXBlLCBrZXksIFsnZnJvbScsICd0byddLCBbbGlua0RheVRleHQodmFsdWUuc3RhcnQpLCBsaW5rRGF5VGV4dCh2YWx1ZS5lbmQpXSk7XG4gIH1cblxuICBpZiAodmFsdWUuZXhjbHVkZVZhbHVlcz8ubGVuZ3RoKSB7XG4gICAgcmV0dXJuIHsgW2dldEV4Y2x1ZGVOYW1lKGtleSldOiBlbmNvZGVQaWNrcyh2YWx1ZS5leGNsdWRlVmFsdWVzLCBuYW1lKSB9O1xuICB9XG5cbiAgaWYgKHZhbHVlLnZhbHVlcykge1xuICAgIHJldHVybiB7IFtrZXldOiBlbmNvZGVQaWNrcyh2YWx1ZS52YWx1ZXMsIG5hbWUpIH07XG4gIH1cblxuICBpZiAoaXNOdW1iZXJFbmQodmFsdWUubWluKSB8fCBpc051bWJlckVuZCh2YWx1ZS5tYXgpKSB7XG4gICAgcmV0dXJuIHJhbmdlUGFyYW1zKHR5cGUsIGtleSwgWydtaW4nLCAnbWF4J10sIFtudW1iZXJFbmRUZXh0KHZhbHVlLm1pbiksIG51bWJlckVuZFRleHQodmFsdWUubWF4KV0pO1xuICB9XG5cbiAgaWYgKHZhbHVlLnJlbGF0aXZlKSB7XG4gICAgcmV0dXJuIHt9O1xuICB9XG5cbiAgcmV0dXJuIHZhbHVlLnZhbHVlID8geyBba2V5XTogdmFsdWUudmFsdWUgfSA6IGNsZWFyUGFyYW1zKHR5cGUsIGtleSk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBlbmNvZGVTb3J0KHNvcnQ6IFJlcG9ydFNvcnQpOiBzdHJpbmcge1xuICByZXR1cm4gYCR7c29ydC5kaXJlY3Rpb24gPT09ICdkZXNjJyA/ICctJyA6ICcnfSR7c29ydC5jb2x1bW59YDtcbn1cblxuLy8gQSBsaXN0IHNvcnQgcmVhZCBiYWNrIGZyb20gaXRzIFVSTCBwYXJhbSwgb3IgbnVsbCB3aGVuIGl0IG5hbWVzIG5vIGNvbHVtbi5cbi8vIFdoZXRoZXIgdGhlIGNvbHVtbiBpcyBvbmUgdGhlIGxpc3QgY2FuIHNvcnQgYnkgaXMgdGhlIGNhbGxlcidzIGNoZWNrLlxuZXhwb3J0IGZ1bmN0aW9uIGRlY29kZVNvcnQocmF3OiBzdHJpbmcpOiBSZXBvcnRTb3J0IHwgbnVsbCB7XG4gIGNvbnN0IGRlc2NlbmRpbmcgPSByYXcuc3RhcnRzV2l0aCgnLScpO1xuICBjb25zdCBjb2x1bW4gPSBkZXNjZW5kaW5nID8gcmF3LnNsaWNlKDEpIDogcmF3O1xuXG4gIHJldHVybiBjb2x1bW5cbiAgICA/IHsgY29sdW1uLCBkaXJlY3Rpb246IGRlc2NlbmRpbmcgPyAnZGVzYycgOiAnYXNjJyB9XG4gICAgOiBudWxsO1xufVxuXG4vLyBBIGRyaWxsIHBhdGggYXMgaXRzIFVSTCBwYXJhbS4gQSBzdGVwIHdpdGggbm8gdmFsdWUgd3JpdGVzIGl0cyBsZXZlbCBvbmx5LlxuZXhwb3J0IGZ1bmN0aW9uIGVuY29kZURyaWxsUGF0aChwYXRoOiByZWFkb25seSBSZXBvcnREcmlsbFN0ZXBbXSk6IHN0cmluZyB7XG4gIHJldHVybiBwYXRoXG4gICAgLm1hcCgoc3RlcCkgPT4gKHN0ZXAudmFsdWUgPT09IG51bGwgfHwgc3RlcC52YWx1ZSA9PT0gdW5kZWZpbmVkXG4gICAgICA/IGVuY29kZVVSSUNvbXBvbmVudChzdGVwLmxldmVsKVxuICAgICAgOiBgJHtlbmNvZGVVUklDb21wb25lbnQoc3RlcC5sZXZlbCl9JHtEUklMTF9TVEVQX1NFUEFSQVRPUn0ke2VuY29kZVVSSUNvbXBvbmVudChTdHJpbmcoc3RlcC52YWx1ZSkpfWApKVxuICAgIC5qb2luKCcsJyk7XG59XG5cbi8vIEEgZHJpbGwgcGF0aCByZWFkIGJhY2sgZnJvbSBpdHMgVVJMIHBhcmFtOiBpdHMgc3RlcHMgdXAgdG8gdGhlIGZpcnN0IHRoYXRcbi8vIGlzIG5vdCBhIHRpbWUgbGV2ZWwgKHRoZSBzdGVwcyBiZWZvcmUgaXQgYXJlIGtlcHQpLCBhdCBtb3N0IERSSUxMX01BWF9ERVBUSFxuLy8gb2YgdGhlbS4gVmFsdWVzIGNvbWUgYmFjayBhcyB0ZXh0LiBXaGV0aGVyIHRoZSBwYXRoIGZpdHMgdGhlIGNoYXJ0IGlzIHRoZVxuLy8gc2VydmVyJ3MgY2hlY2sgKGl0IGFwcGxpZXMgdGhlIGxvbmdlc3QgdmFsaWQgcHJlZml4KS5cbmV4cG9ydCBmdW5jdGlvbiBkZWNvZGVEcmlsbFBhdGgocmF3OiBzdHJpbmcpOiBSZXBvcnREcmlsbFN0ZXBbXSB7XG4gIGNvbnN0IHBhdGg6IFJlcG9ydERyaWxsU3RlcFtdID0gW107XG5cbiAgZm9yIChjb25zdCBpdGVtIG9mIHJhdy5zcGxpdCgnLCcpKSB7XG4gICAgY29uc3Qgc3RlcCA9IGRlY29kZURyaWxsU3RlcChpdGVtKTtcbiAgICBpZiAoIXN0ZXAgfHwgcGF0aC5sZW5ndGggPT09IERSSUxMX01BWF9ERVBUSCkge1xuICAgICAgYnJlYWs7XG4gICAgfVxuXG4gICAgcGF0aC5wdXNoKHN0ZXApO1xuICB9XG5cbiAgcmV0dXJuIHBhdGg7XG59XG5cbi8vIFRoZSBxdWVyeSBwYXJhbXMgdGhhdCBtYWtlIHRoZSBVUkwgY2FycnkgYHNuYXBzaG90YDogZXZlcnkgc25hcHNob3Qga2V5IGlzXG4vLyBzZXQsIGFuZCBlYWNoIG93bmVkIGtleSB0aGF0IGBjdXJyZW50YCBjYXJyaWVzIGJ1dCB0aGUgc25hcHNob3QgZG9lcyBub3QgaXNcbi8vIHNldCB0byBudWxsLCB3aGljaCByZW1vdmVzIGl0IHVuZGVyIHRoZSByb3V0ZXIncyAnbWVyZ2UnIGhhbmRsaW5nLiBLZXlzXG4vLyB0aGlzIGNvZGVjIGRvZXMgbm90IG93biBhcmUgbGVmdCBhbG9uZS4gRWFjaCBncm91cCBpcyB3cml0dGVuIHVuZGVyIGl0c1xuLy8ga2V5cyBhbW9uZyBgZ3JvdXBzYCAoZXZlcnkgZmlsdGVyIGdyb3VwIG9mIHRoZSByZXBvcnQpLiBBIHNlbGVjdCdzIHZhbHVlXG4vLyBpcyBuYW1lZCBieSBgbmFtZWAsIGVsc2UgYnkgdGhlIG5hbWUgYGN1cnJlbnRgIGNhcnJpZXMgZm9yIGl0LiBBIGRhdGUgcmFuZ2Vcbi8vIGlzIHdyaXR0ZW4gYXMgdGhlIGRheXMgb24gc2NyZWVuLCBuZXZlciBhcyBhIHByZXNldCBuYW1lLlxuZXhwb3J0IGZ1bmN0aW9uIGJ1aWxkUmVwb3J0VXJsUGFyYW1zKFxuICBzbmFwc2hvdDogUmVwb3J0VXJsU25hcHNob3QsXG4gIGN1cnJlbnQ6IFBhcmFtTWFwLFxuICBncm91cHM6IHJlYWRvbmx5IFVybEdyb3VwW10sXG4gIG5hbWU6IFJlcG9ydFVybFZhbHVlTmFtZSA9ICgpID0+IG51bGwsXG4pOiBQYXJhbXMge1xuICBjb25zdCBwYXJhbXM6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4gPSB7fTtcbiAgY29uc3Qga2V5cyA9IGdyb3VwUGFyYW1LZXlzKGdyb3Vwcyk7XG4gIGNvbnN0IHR5cGVzID0gbmV3IE1hcChncm91cHMubWFwKChncm91cCkgPT4gW2dyb3VwLmlkLCBncm91cC50eXBlXSkpO1xuICBjb25zdCBjdXJyZW50TmFtZSA9IHVybFZhbHVlTmFtZXMoY3VycmVudCwgZ3JvdXBzKTtcblxuICBzbmFwc2hvdC5ncm91cHMuZm9yRWFjaCgodmFsdWUsIGdyb3VwSWQpID0+IHtcbiAgICBjb25zdCBrZXkgPSBrZXlzLmdldChncm91cElkKTtcbiAgICBpZiAoa2V5KSB7XG4gICAgICBjb25zdCB0eXBlID0gdHlwZXMuZ2V0KGdyb3VwSWQpO1xuICAgICAgY29uc3QgbmFtZWQgPSAocGljazogdW5rbm93bikgPT4gbmFtZShncm91cElkLCBwaWNrKSA/PyBjdXJyZW50TmFtZShncm91cElkLCBwaWNrKTtcbiAgICAgIGNvbnN0IGRheXMgPSB2YWx1ZSA/IHsgLi4udmFsdWUsIHByZXNldDogdW5kZWZpbmVkIH0gOiB2YWx1ZTtcbiAgICAgIE9iamVjdC5hc3NpZ24ocGFyYW1zLCBncm91cFZhbHVlUGFyYW1zKHR5cGUsIGtleSwgdG9TdG9yZWRHcm91cFZhbHVlKHR5cGUsIGRheXMpLCBuYW1lZCkpO1xuICAgIH1cbiAgfSk7XG5cbiAgc25hcHNob3QubGlzdFNvcnRzLmZvckVhY2goKHNvcnQsIGNvbXBvbmVudElkKSA9PiB7XG4gICAgcGFyYW1zW2Ake0xJU1RfU09SVF9QQVJBTV9QUkVGSVh9JHtjb21wb25lbnRJZH1gXSA9IGVuY29kZVNvcnQoc29ydCk7XG4gIH0pO1xuXG4gIC8vIFRoZSB0ZXh0IGFzIHR5cGVkOiB0aGUgcm91dGVyIHBlcmNlbnQtZW5jb2RlcyBpdCBpbiB0aGUgVVJMLlxuICBzbmFwc2hvdC5saXN0U2VhcmNoZXMuZm9yRWFjaCgoc2VhcmNoLCBjb21wb25lbnRJZCkgPT4ge1xuICAgIHBhcmFtc1tgJHtMSVNUX1NFQVJDSF9QQVJBTV9QUkVGSVh9JHtjb21wb25lbnRJZH1gXSA9IHNlYXJjaDtcbiAgfSk7XG5cbiAgc25hcHNob3QubGlzdEhpZGRlbi5mb3JFYWNoKChuYW1lcywgY29tcG9uZW50SWQpID0+IHtcbiAgICBwYXJhbXNbYCR7TElTVF9ISURERU5fUEFSQU1fUFJFRklYfSR7Y29tcG9uZW50SWR9YF0gPSBlbmNvZGVDb2x1bW5MaXN0KG5hbWVzKTtcbiAgfSk7XG5cbiAgaWYgKHNuYXBzaG90LmZyZXF1ZW5jeSkge1xuICAgIHBhcmFtc1tHUk9VUF9CWV9JVEVNXSA9IHNuYXBzaG90LmZyZXF1ZW5jeTtcbiAgfVxuXG4gIHJldHVybiB7IC4uLnJlcG9ydFBhcmFtc1RvQ2xlYXIoY3VycmVudCwgZ3JvdXBzKSwgLi4ud2l0aEZvcm1hdChwYXJhbXMpIH07XG59XG5cbi8vIGBwYXJhbXNgIHdpdGggdGhlIGZvcm1hdCBtYXJrZXIsIHdoZW4gaXQgY2FycmllcyBhbnl0aGluZy5cbmZ1bmN0aW9uIHdpdGhGb3JtYXQocGFyYW1zOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+KTogUmVjb3JkPHN0cmluZywgc3RyaW5nPiB7XG4gIHJldHVybiBPYmplY3Qua2V5cyhwYXJhbXMpLmxlbmd0aCA/IHsgLi4ucGFyYW1zLCBbRk9STUFUX1BBUkFNXTogU3RyaW5nKFVSTF9GT1JNQVQpIH0gOiBwYXJhbXM7XG59XG5cbi8vIEVhY2ggZ3JvdXAncyB2YWx1ZSBhIGxpbmsgY2FycmllcywgaW4gaXRzIHN0b3JlZCBzaGFwZSwgYnkgZ3JvdXAgaWQgKG51bGxcbi8vIGZvciBhIGdyb3VwIHRoZSBsaW5rIGNsZWFycykuIEEgZ3JvdXAgd2l0aCBubyB1c2FibGUgcGFyYW0gaXMgbGVmdCBvdXQuXG5mdW5jdGlvbiByZWFkR3JvdXBQYXJhbXMocGFyYW1zOiBQYXJhbXMsIGdyb3VwczogcmVhZG9ubHkgVXJsR3JvdXBbXSk6IE1hcDxudW1iZXIsIEZpbHRlckdyb3VwRGVmYXVsdCB8IG51bGw+IHtcbiAgY29uc3Qga2V5cyA9IGdyb3VwUGFyYW1LZXlzKGdyb3Vwcyk7XG4gIGNvbnN0IHZhbHVlcyA9IG5ldyBNYXA8bnVtYmVyLCBGaWx0ZXJHcm91cERlZmF1bHQgfCBudWxsPigpO1xuXG4gIGZvciAoY29uc3QgZ3JvdXAgb2YgZ3JvdXBzKSB7XG4gICAgY29uc3QgdmFsdWUgPSByZWFkR3JvdXBQYXJhbShwYXJhbXMsIGdyb3VwLnR5cGUsIGtleXMuZ2V0KGdyb3VwLmlkKSk7XG4gICAgaWYgKHZhbHVlICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIHZhbHVlcy5zZXQoZ3JvdXAuaWQsIHZhbHVlKTtcbiAgICB9XG4gIH1cblxuICByZXR1cm4gdmFsdWVzO1xufVxuXG4vLyBPbmUgZ3JvdXAncyB2YWx1ZSBpbiBhIGxpbmssIHJlYWQgZnJvbSB0aGUga2V5cyBvZiBpdHMgdHlwZS4gbnVsbCBpcyBhXG4vLyBjbGVhcjsgdW5kZWZpbmVkIGlzIG5vIHVzYWJsZSB2YWx1ZS5cbmZ1bmN0aW9uIHJlYWRHcm91cFBhcmFtKHBhcmFtczogUGFyYW1zLCB0eXBlOiBSZXBvcnRGaWx0ZXJUeXBlLCBrZXk6IHN0cmluZyk6IEZpbHRlckdyb3VwRGVmYXVsdCB8IG51bGwgfCB1bmRlZmluZWQge1xuICBzd2l0Y2ggKHR5cGUpIHtcbiAgICBjYXNlICdzZWxlY3QnOlxuICAgICAgcmV0dXJuIHJlYWRTZWxlY3QocGFyYW1zLCBrZXkpO1xuXG4gICAgY2FzZSAnZGF0ZVJhbmdlJzpcbiAgICAgIHJldHVybiByZWFkRGF0ZVJhbmdlKHBhcmFtcywga2V5KTtcblxuICAgIGNhc2UgJ251bWJlclJhbmdlJzpcbiAgICAgIHJldHVybiByZWFkTnVtYmVyUmFuZ2UocGFyYW1zLCBrZXkpO1xuXG4gICAgY2FzZSAna2V5d29yZCc6XG4gICAgICByZXR1cm4gcmVhZEtleXdvcmQocGFyYW1zW2tleV0pO1xuXG4gICAgZGVmYXVsdDpcbiAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gIH1cbn1cblxuLy8gQSBzZWxlY3QncyB2YWx1ZXMga2VwdCAoPGtleT4pLCBlbHNlIGl0cyB2YWx1ZXMgbGVmdCBvdXQgKGV4Y2x1ZGU8S2V5PikuXG5mdW5jdGlvbiByZWFkU2VsZWN0KHBhcmFtczogUGFyYW1zLCBrZXk6IHN0cmluZyk6IEZpbHRlckdyb3VwRGVmYXVsdCB8IG51bGwgfCB1bmRlZmluZWQge1xuICBjb25zdCBrZXB0ID0gcGFyYW1UZXh0KHBhcmFtc1trZXldKTtcbiAgaWYgKGtlcHQgIT09IG51bGwpIHtcbiAgICByZXR1cm4ga2VwdCA9PT0gJycgPyBudWxsIDogZGVjb2RlUGlja3Moa2VwdCwgJ3ZhbHVlcycpO1xuICB9XG5cbiAgY29uc3QgZXhjbHVkZWQgPSBwYXJhbVRleHQocGFyYW1zW2dldEV4Y2x1ZGVOYW1lKGtleSldKTtcbiAgaWYgKGV4Y2x1ZGVkICE9PSBudWxsKSB7XG4gICAgcmV0dXJuIGV4Y2x1ZGVkID09PSAnJyA/IG51bGwgOiBkZWNvZGVQaWNrcyhleGNsdWRlZCwgJ2V4Y2x1ZGVWYWx1ZXMnKTtcbiAgfVxuXG4gIHJldHVybiB1bmRlZmluZWQ7XG59XG5cbi8vIEEgZGF0ZSByYW5nZSdzIGRheXMgKDxrZXk+RnJvbSwgPGtleT5UbyksIGVhY2ggYSByZWFsIGNhbGVuZGFyIGRheSxcbi8vIGVpdGhlciBvbmUgb3BlbiBidXQgbm90IGJvdGguXG5mdW5jdGlvbiByZWFkRGF0ZVJhbmdlKHBhcmFtczogUGFyYW1zLCBrZXk6IHN0cmluZyk6IEZpbHRlckdyb3VwRGVmYXVsdCB8IG51bGwgfCB1bmRlZmluZWQge1xuICBjb25zdCBlbmRzID0gcmVhZFJhbmdlRW5kcyhwYXJhbXMsIGtleSwgWydmcm9tJywgJ3RvJ10pO1xuICBpZiAoIWVuZHMpIHtcbiAgICByZXR1cm4gZW5kcyA9PT0gbnVsbCA/IG51bGwgOiB1bmRlZmluZWQ7XG4gIH1cblxuICBjb25zdCBbc3RhcnQsIGVuZF0gPSBlbmRzLm1hcChsaW5rRGF5KTtcbiAgaWYgKHN0YXJ0ID09PSB1bmRlZmluZWQgfHwgZW5kID09PSB1bmRlZmluZWQpIHtcbiAgICByZXR1cm4gdW5kZWZpbmVkO1xuICB9XG5cbiAgcmV0dXJuIGNvbXBhY3RSYW5nZShzdGFydCwgZW5kLCAnc3RhcnQnLCAnZW5kJyk7XG59XG5cbi8vIEEgbnVtYmVyIHJhbmdlJ3MgZW5kcyAoPGtleT5NaW4sIDxrZXk+TWF4KSwgZWFjaCBhIGZpbml0ZSBudW1iZXIsIGVpdGhlclxuLy8gb25lIG9wZW4gYnV0IG5vdCBib3RoLCBhbmQgbWluIG5vdCBhYm92ZSBtYXguXG5mdW5jdGlvbiByZWFkTnVtYmVyUmFuZ2UocGFyYW1zOiBQYXJhbXMsIGtleTogc3RyaW5nKTogRmlsdGVyR3JvdXBEZWZhdWx0IHwgbnVsbCB8IHVuZGVmaW5lZCB7XG4gIGNvbnN0IGVuZHMgPSByZWFkUmFuZ2VFbmRzKHBhcmFtcywga2V5LCBbJ21pbicsICdtYXgnXSk7XG4gIGlmICghZW5kcykge1xuICAgIHJldHVybiBlbmRzID09PSBudWxsID8gbnVsbCA6IHVuZGVmaW5lZDtcbiAgfVxuXG4gIGNvbnN0IFttaW4sIG1heF0gPSBlbmRzLm1hcCgoZW5kKSA9PiAoZW5kID09PSAnJyA/IG51bGwgOiBudW1iZXJGcm9tVGV4dChlbmQpKSk7XG4gIGlmICgoZW5kc1swXSAhPT0gJycgJiYgbWluID09PSBudWxsKSB8fCAoZW5kc1sxXSAhPT0gJycgJiYgbWF4ID09PSBudWxsKSB8fCAobWluICE9PSBudWxsICYmIG1heCAhPT0gbnVsbCAmJiBtaW4gPiBtYXgpKSB7XG4gICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgfVxuXG4gIHJldHVybiBjb21wYWN0UmFuZ2UobWluLCBtYXgsICdtaW4nLCAnbWF4Jyk7XG59XG5cbi8vIEEga2V5d29yZCdzIHRleHQuIEJsYW5rIHRleHQgaXMgdW51c2FibGUuXG5mdW5jdGlvbiByZWFkS2V5d29yZChyYXc6IHVua25vd24pOiBGaWx0ZXJHcm91cERlZmF1bHQgfCBudWxsIHwgdW5kZWZpbmVkIHtcbiAgY29uc3QgdGV4dCA9IHBhcmFtVGV4dChyYXcpO1xuICBpZiAodGV4dCA9PT0gbnVsbCkge1xuICAgIHJldHVybiB1bmRlZmluZWQ7XG4gIH1cblxuICBpZiAodGV4dCA9PT0gJycpIHtcbiAgICByZXR1cm4gbnVsbDtcbiAgfVxuXG4gIHJldHVybiB0ZXh0LnRyaW0oKSA/IHsgdmFsdWU6IHRleHQgfSA6IHVuZGVmaW5lZDtcbn1cblxuLy8gQSByYW5nZSdzIHR3byBlbmRzIGFzIHdyaXR0ZW4gKCcnIGZvciBvbmUgdGhlIGxpbmsgbGVhdmVzIG9wZW4pOlxuLy8gdW5kZWZpbmVkIHdoZW4gdGhlIGxpbmsgY2FycmllcyBuZWl0aGVyIGtleSwgbnVsbCB3aGVuIGV2ZXJ5IG9uZSBpdFxuLy8gY2FycmllcyBpcyBlbXB0eSAoYSBjbGVhcikuXG5mdW5jdGlvbiByZWFkUmFuZ2VFbmRzKFxuICBwYXJhbXM6IFBhcmFtcyxcbiAga2V5OiBzdHJpbmcsXG4gIGVuZHM6IFtJdGVtUmFuZ2VFbmQsIEl0ZW1SYW5nZUVuZF0sXG4pOiBbc3RyaW5nLCBzdHJpbmddIHwgbnVsbCB8IHVuZGVmaW5lZCB7XG4gIGNvbnN0IFtsb3csIGhpZ2hdID0gZW5kcy5tYXAoKGVuZCkgPT4gcGFyYW1UZXh0KHBhcmFtc1tpdGVtUmFuZ2VOYW1lKGtleSwgZW5kKV0pKTtcbiAgaWYgKGxvdyA9PT0gbnVsbCAmJiBoaWdoID09PSBudWxsKSB7XG4gICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgfVxuXG4gIHJldHVybiBsb3cgfHwgaGlnaCA/IFtsb3cgPz8gJycsIGhpZ2ggPz8gJyddIDogbnVsbDtcbn1cblxuLy8gVGhlIHBhcmFtcyBvZiBhIHJhbmdlJ3MgZW5kcywgdGhlIG9uZXMgaXQgc2V0cyBvbmx5OyB3aXRoIG5laXRoZXIgb25lXG4vLyB1c2FibGUsIHRoZSBncm91cCdzIGNsZWFyLlxuZnVuY3Rpb24gcmFuZ2VQYXJhbXMoXG4gIHR5cGU6IFJlcG9ydEZpbHRlclR5cGUgfCB1bmRlZmluZWQsXG4gIGtleTogc3RyaW5nLFxuICBlbmRzOiBbSXRlbVJhbmdlRW5kLCBJdGVtUmFuZ2VFbmRdLFxuICB0ZXh0czogW3N0cmluZywgc3RyaW5nXSxcbik6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4ge1xuICBjb25zdCBwYXJhbXM6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4gPSB7fTtcbiAgZW5kcy5mb3JFYWNoKChlbmQsIGluZGV4KSA9PiB7XG4gICAgaWYgKHRleHRzW2luZGV4XSkge1xuICAgICAgcGFyYW1zW2l0ZW1SYW5nZU5hbWUoa2V5LCBlbmQpXSA9IHRleHRzW2luZGV4XTtcbiAgICB9XG4gIH0pO1xuXG4gIHJldHVybiBPYmplY3Qua2V5cyhwYXJhbXMpLmxlbmd0aCA/IHBhcmFtcyA6IGNsZWFyUGFyYW1zKHR5cGUsIGtleSk7XG59XG5cbi8vIFRoZSBwYXJhbXMgb2YgYSBjbGVhcmVkIGdyb3VwOiBpdHMga2V5cywgZW1wdHkuXG5mdW5jdGlvbiBjbGVhclBhcmFtcyh0eXBlOiBSZXBvcnRGaWx0ZXJUeXBlIHwgdW5kZWZpbmVkLCBrZXk6IHN0cmluZyk6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4ge1xuICBzd2l0Y2ggKHR5cGUpIHtcbiAgICBjYXNlICdkYXRlUmFuZ2UnOlxuICAgICAgcmV0dXJuIHsgW2l0ZW1SYW5nZU5hbWUoa2V5LCAnZnJvbScpXTogJycsIFtpdGVtUmFuZ2VOYW1lKGtleSwgJ3RvJyldOiAnJyB9O1xuXG4gICAgY2FzZSAnbnVtYmVyUmFuZ2UnOlxuICAgICAgcmV0dXJuIHsgW2l0ZW1SYW5nZU5hbWUoa2V5LCAnbWluJyldOiAnJywgW2l0ZW1SYW5nZU5hbWUoa2V5LCAnbWF4JyldOiAnJyB9O1xuXG4gICAgZGVmYXVsdDpcbiAgICAgIHJldHVybiB7IFtrZXldOiAnJyB9O1xuICB9XG59XG5cbi8vIEEgc3RvcmVkIGRheSBpbiBmcy1maWx0ZXIncyBkYXRlIGZvcm1hdDogaXRzIGxvY2FsIG1pZG5pZ2h0IHdpdGggdGhlXG4vLyBvZmZzZXQsICcnIHdoZW4gdGhlcmUgaXMgbm8gcmVhbCBkYXkuXG5mdW5jdGlvbiBsaW5rRGF5VGV4dChib3VuZDogc3RyaW5nIHwgdW5kZWZpbmVkKTogc3RyaW5nIHtcbiAgY29uc3QgZGF5ID0gZGF0ZUJvdW5kU3RyaW5nKGJvdW5kKTtcblxuICByZXR1cm4gZGF5ICYmIGlzQ2FsZW5kYXJEYXkoZGF5KSA/IGlzbzg2MDEocGFyc2VJU08oZGF5KSkgOiAnJztcbn1cblxuLy8gVGhlIGRheSBvZiBhIGxpbmsncyBkYXRlIGVuZDogbnVsbCB3aGVuIHRoZSBlbmQgaXMgb3BlbiAoJycpLCB1bmRlZmluZWRcbi8vIHdoZW4gaXQgaXMgbm90IGEgcmVhbCBjYWxlbmRhciBkYXkuXG5mdW5jdGlvbiBsaW5rRGF5KHRleHQ6IHN0cmluZyk6IHN0cmluZyB8IG51bGwgfCB1bmRlZmluZWQge1xuICBpZiAodGV4dCA9PT0gJycpIHtcbiAgICByZXR1cm4gbnVsbDtcbiAgfVxuXG4gIGNvbnN0IGRheSA9IExJTktfREFZLmV4ZWModGV4dCk/LlsxXTtcblxuICByZXR1cm4gZGF5ICYmIGlzQ2FsZW5kYXJEYXkoZGF5KSA/IGRheSA6IHVuZGVmaW5lZDtcbn1cblxuLy8gVGhlIGtleXMgYSBsaW5rIGNhcnJpZXMgdGhlIGdyb3VwcycgdmFsdWVzIHVuZGVyLCBieSBlYWNoIGdyb3VwJ3MgdHlwZS5cbmZ1bmN0aW9uIG93bmVkR3JvdXBLZXlzKGdyb3VwczogcmVhZG9ubHkgVXJsR3JvdXBbXSk6IFNldDxzdHJpbmc+IHtcbiAgY29uc3Qga2V5cyA9IGdyb3VwUGFyYW1LZXlzKGdyb3Vwcyk7XG5cbiAgcmV0dXJuIG5ldyBTZXQoZ3JvdXBzLmZsYXRNYXAoKGdyb3VwKSA9PiB7XG4gICAgY29uc3Qga2V5ID0ga2V5cy5nZXQoZ3JvdXAuaWQpO1xuXG4gICAgc3dpdGNoIChncm91cC50eXBlKSB7XG4gICAgICBjYXNlICdzZWxlY3QnOlxuICAgICAgICByZXR1cm4gW2tleSwgZ2V0RXhjbHVkZU5hbWUoa2V5KV07XG5cbiAgICAgIGNhc2UgJ2RhdGVSYW5nZSc6XG4gICAgICAgIHJldHVybiBbaXRlbVJhbmdlTmFtZShrZXksICdmcm9tJyksIGl0ZW1SYW5nZU5hbWUoa2V5LCAndG8nKV07XG5cbiAgICAgIGNhc2UgJ251bWJlclJhbmdlJzpcbiAgICAgICAgcmV0dXJuIFtpdGVtUmFuZ2VOYW1lKGtleSwgJ21pbicpLCBpdGVtUmFuZ2VOYW1lKGtleSwgJ21heCcpXTtcblxuICAgICAgZGVmYXVsdDpcbiAgICAgICAgcmV0dXJuIFtrZXldO1xuICAgIH1cbiAgfSkpO1xufVxuXG4vLyBPbmUgaWQta2V5ZWQgcGFyYW0gb2YgYSB0aWxlIHJlYWQgaW50byBgY29uZmlnYC5cbmZ1bmN0aW9uIHJlYWRUaWxlUGFyYW0oXG4gIGNvbmZpZzogUmVwb3J0Vmlld0NvbmZpZyxcbiAgcHJlZml4OiBzdHJpbmcsXG4gIGlkOiBudW1iZXIsXG4gIHJhdzogc3RyaW5nLFxuKTogdm9pZCB7XG4gIHN3aXRjaCAocHJlZml4KSB7XG4gICAgY2FzZSBMSVNUX1NPUlRfUEFSQU1fUFJFRklYOlxuICAgICAgc2V0VGlsZVN0YXRlKGNvbmZpZywgaWQsICdzb3J0JywgZGVjb2RlU29ydChyYXcpKTtcbiAgICAgIGJyZWFrO1xuXG4gICAgY2FzZSBMSVNUX1NFQVJDSF9QQVJBTV9QUkVGSVg6XG4gICAgICBzZXRUaWxlU3RhdGUoY29uZmlnLCBpZCwgJ3NlYXJjaCcsIHJhdyB8fCBudWxsKTtcbiAgICAgIGJyZWFrO1xuXG4gICAgY2FzZSBMSVNUX0hJRERFTl9QQVJBTV9QUkVGSVg6XG4gICAgICBzZXRUaWxlU3RhdGUoY29uZmlnLCBpZCwgJ2hpZGRlbicsIG5vbkVtcHR5KGRlY29kZUNvbHVtbkxpc3QocmF3KSkpO1xuICAgICAgYnJlYWs7XG5cbiAgICBkZWZhdWx0OlxuICAgICAgc2V0VGlsZVN0YXRlKGNvbmZpZywgaWQsICdkcmlsbCcsIG5vbkVtcHR5KGRlY29kZURyaWxsUGF0aChyYXcpKSk7XG4gIH1cbn1cblxuLy8gU2V0cyBvbmUga2V5IG9mIGEgdGlsZSdzIHN0YXRlLCBjcmVhdGluZyB0aGUgdGlsZSwgdW5sZXNzIHRoZXJlIGlzIG5vdGhpbmdcbi8vIHRvIHNldC5cbmZ1bmN0aW9uIHNldFRpbGVTdGF0ZTxLIGV4dGVuZHMga2V5b2YgUmVwb3J0VGlsZVN0YXRlPihcbiAgY29uZmlnOiBSZXBvcnRWaWV3Q29uZmlnLFxuICBjb21wb25lbnRJZDogbnVtYmVyLFxuICBrZXk6IEssXG4gIHZhbHVlOiBSZXBvcnRUaWxlU3RhdGVbS10gfCBudWxsLFxuKTogdm9pZCB7XG4gIGlmICh2YWx1ZSA9PT0gbnVsbCkge1xuICAgIHJldHVybjtcbiAgfVxuXG4gIGNvbmZpZy50aWxlcyA9IHsgLi4uY29uZmlnLnRpbGVzLCBbY29tcG9uZW50SWRdOiB7IC4uLmNvbmZpZy50aWxlcz8uW2NvbXBvbmVudElkXSwgW2tleV06IHZhbHVlIH0gfTtcbn1cblxuLy8gVGhlIHBhcmFtcyBvZiBvbmUgdGlsZSdzIHN0YXRlLlxuZnVuY3Rpb24gdGlsZVBhcmFtcyhjb21wb25lbnRJZDogbnVtYmVyLCB0aWxlOiBSZXBvcnRUaWxlU3RhdGUpOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+IHtcbiAgY29uc3QgcGFyYW1zOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+ID0ge307XG5cbiAgaWYgKHRpbGUuc29ydD8uY29sdW1uKSB7XG4gICAgcGFyYW1zW2Ake0xJU1RfU09SVF9QQVJBTV9QUkVGSVh9JHtjb21wb25lbnRJZH1gXSA9IGVuY29kZVNvcnQodGlsZS5zb3J0KTtcbiAgfVxuXG4gIC8vIFRoZSB0ZXh0IGFzIHR5cGVkOiB0aGUgcm91dGVyIHBlcmNlbnQtZW5jb2RlcyBpdCBpbiB0aGUgVVJMLlxuICBpZiAodGlsZS5zZWFyY2gpIHtcbiAgICBwYXJhbXNbYCR7TElTVF9TRUFSQ0hfUEFSQU1fUFJFRklYfSR7Y29tcG9uZW50SWR9YF0gPSB0aWxlLnNlYXJjaDtcbiAgfVxuXG4gIGlmICh0aWxlLmhpZGRlbj8ubGVuZ3RoKSB7XG4gICAgcGFyYW1zW2Ake0xJU1RfSElEREVOX1BBUkFNX1BSRUZJWH0ke2NvbXBvbmVudElkfWBdID0gZW5jb2RlQ29sdW1uTGlzdCh0aWxlLmhpZGRlbik7XG4gIH1cblxuICBpZiAodGlsZS5kcmlsbD8ubGVuZ3RoKSB7XG4gICAgcGFyYW1zW2Ake0RSSUxMX1BBUkFNX1BSRUZJWH0ke2NvbXBvbmVudElkfWBdID0gZW5jb2RlRHJpbGxQYXRoKHRpbGUuZHJpbGwpO1xuICB9XG5cbiAgcmV0dXJuIHBhcmFtcztcbn1cblxuLy8gYHBhcmFtc2Agd2l0aGluIFJFUE9SVF9VUkxfTUFYX0xFTkdUSDogcGFzdCBpdCwgZ3JvdXAgdmFsdWVzICh0aGUgcGFyYW1zXG4vLyBuYW1lZCBpbiBgZ3JvdXBQYXJhbXNgKSBhcmUgbGVmdCBvdXQsIGxvbmdlc3QgZmlyc3QsIHVudGlsIHRoZSByZXN0IGZpdHMuXG5mdW5jdGlvbiBjYXBSZXBvcnRQYXJhbXMocGFyYW1zOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+LCBncm91cFBhcmFtczogUmVhZG9ubHlTZXQ8c3RyaW5nPik6IFJlcG9ydFVybFdyaXRlIHtcbiAgaWYgKHF1ZXJ5TGVuZ3RoKHBhcmFtcykgPD0gUkVQT1JUX1VSTF9NQVhfTEVOR1RIKSB7XG4gICAgcmV0dXJuIHsgcGFyYW1zLCB0b29Mb25nOiBmYWxzZSB9O1xuICB9XG5cbiAgY29uc3Qga2VwdCA9IHsgLi4ucGFyYW1zIH07XG4gIGNvbnN0IGdyb3VwS2V5cyA9IE9iamVjdC5rZXlzKGtlcHQpXG4gICAgLmZpbHRlcigoa2V5KSA9PiBncm91cFBhcmFtcy5oYXMoa2V5KSlcbiAgICAuc29ydCgoYSwgYikgPT4gcXVlcnlUZXh0KGtlcHRbYl0pLmxlbmd0aCAtIHF1ZXJ5VGV4dChrZXB0W2FdKS5sZW5ndGgpO1xuXG4gIGZvciAoY29uc3Qga2V5IG9mIGdyb3VwS2V5cykge1xuICAgIGlmIChxdWVyeUxlbmd0aChrZXB0KSA8PSBSRVBPUlRfVVJMX01BWF9MRU5HVEgpIHtcbiAgICAgIGJyZWFrO1xuICAgIH1cblxuICAgIGRlbGV0ZSBrZXB0W2tleV07XG4gIH1cblxuICByZXR1cm4geyBwYXJhbXM6IGtlcHQsIHRvb0xvbmc6IHRydWUgfTtcbn1cblxuLy8gVGhlIGxlbmd0aCBvZiBgcGFyYW1zYCBhcyB0aGUgcm91dGVyIHdyaXRlcyB0aGVtIGluIGEgcXVlcnkgc3RyaW5nLlxuZnVuY3Rpb24gcXVlcnlMZW5ndGgocGFyYW1zOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+KTogbnVtYmVyIHtcbiAgcmV0dXJuIE9iamVjdC5lbnRyaWVzKHBhcmFtcylcbiAgICAubWFwKChba2V5LCB2YWx1ZV0pID0+IGAke3F1ZXJ5VGV4dChrZXkpfT0ke3F1ZXJ5VGV4dCh2YWx1ZSl9YClcbiAgICAuam9pbignJicpXG4gICAgLmxlbmd0aDtcbn1cblxuLy8gVGV4dCBhcyB0aGUgcm91dGVyIHdyaXRlcyBpdCBpbiBhIHF1ZXJ5IHN0cmluZyAoaXRzIHF1ZXJ5IGVuY29kaW5nKTpcbi8vIHBlcmNlbnQtZW5jb2RlZCwgd2l0aCAnQCcsICc6JywgJyQnLCAnLCcgYW5kICc7JyBsZWZ0IGFzIHRoZXkgYXJlLlxuZnVuY3Rpb24gcXVlcnlUZXh0KHRleHQ6IHN0cmluZyk6IHN0cmluZyB7XG4gIHJldHVybiBlbmNvZGVVUklDb21wb25lbnQodGV4dClcbiAgICAucmVwbGFjZSgvJTQwL2csICdAJylcbiAgICAucmVwbGFjZSgvJTNBL2dpLCAnOicpXG4gICAgLnJlcGxhY2UoLyUyNC9nLCAnJCcpXG4gICAgLnJlcGxhY2UoLyUyQy9naSwgJywnKVxuICAgIC5yZXBsYWNlKC8lM0IvZ2ksICc7Jyk7XG59XG5cbi8vIEEgcGFyYW0ncyB0ZXh0OiBhIHJlcGVhdGVkIGtleSBnaXZlcyBpdHMgZmlyc3QgdmFsdWUuXG5mdW5jdGlvbiBwYXJhbVRleHQodmFsdWU6IHVua25vd24pOiBzdHJpbmcgfCBudWxsIHtcbiAgY29uc3QgZmlyc3QgPSBBcnJheS5pc0FycmF5KHZhbHVlKSA/IHZhbHVlWzBdIDogdmFsdWU7XG5cbiAgcmV0dXJuIHR5cGVvZiBmaXJzdCA9PT0gJ3N0cmluZycgfHwgdHlwZW9mIGZpcnN0ID09PSAnbnVtYmVyJyA/IFN0cmluZyhmaXJzdCkgOiBudWxsO1xufVxuXG5mdW5jdGlvbiBwb3NpdGl2ZUlkKHJhdzogc3RyaW5nIHwgbnVsbCk6IG51bWJlciB8IG51bGwge1xuICByZXR1cm4gcmF3ICE9PSBudWxsICYmIC9eWzEtOV1cXGQqJC8udGVzdChyYXcpID8gTnVtYmVyKHJhdykgOiBudWxsO1xufVxuXG5mdW5jdGlvbiBub25FbXB0eTxUPihsaXN0OiBUW10pOiBUW10gfCBudWxsIHtcbiAgcmV0dXJuIGxpc3QubGVuZ3RoID8gbGlzdCA6IG51bGw7XG59XG5cbi8vIEFuIGl0ZW0gb2YgYSBsaXN0IHBhcmFtLCBwZXJjZW50LWRlY29kZWQ7IG9uZSB0aGF0IGRvZXMgbm90IGRlY29kZSAoYVxuLy8gaGFuZC1lZGl0ZWQgJyUnKSBpcyBrZXB0IGFzIHdyaXR0ZW4uXG5mdW5jdGlvbiBkZWNvZGVJdGVtKGl0ZW06IHN0cmluZyk6IHN0cmluZyB7XG4gIHRyeSB7XG4gICAgcmV0dXJuIGRlY29kZVVSSUNvbXBvbmVudChpdGVtKTtcbiAgfSBjYXRjaCB7XG4gICAgcmV0dXJuIGl0ZW07XG4gIH1cbn1cblxuLy8gU2VsZWN0IHBpY2tzIGFzIG9uZSBwYXJhbSB2YWx1ZTogdmFsdWU6bmFtZSBmb3IgZWFjaCwgdGhlIG5hbWUgbGVmdCBvZmZcbi8vIHdoZW4gYG5hbWVgIGRvZXMgbm90IGtub3cgaXQsIGJsYW5rcyBsZWZ0IG91dC5cbmZ1bmN0aW9uIGVuY29kZVBpY2tzKHBpY2tzOiByZWFkb25seSB1bmtub3duW10sIG5hbWU6ICh2YWx1ZTogdW5rbm93bikgPT4gc3RyaW5nIHwgbnVsbCk6IHN0cmluZyB7XG4gIHJldHVybiBwaWNrc1xuICAgIC5maWx0ZXIoKHBpY2spID0+IHR5cGVvZiBwaWNrID09PSAnc3RyaW5nJyB8fCB0eXBlb2YgcGljayA9PT0gJ251bWJlcicgfHwgdHlwZW9mIHBpY2sgPT09ICdib29sZWFuJylcbiAgICAuZmlsdGVyKChwaWNrKSA9PiBTdHJpbmcocGljaykgIT09ICcnKVxuICAgIC5tYXAoKHBpY2spID0+IHtcbiAgICAgIGNvbnN0IG5hbWVkID0gbmFtZShwaWNrKTtcblxuICAgICAgcmV0dXJuIG5hbWVkID8gYCR7ZXNjYXBlUGljayhTdHJpbmcocGljaykpfSR7UElDS19OQU1FX1NFUEFSQVRPUn0ke2VzY2FwZVBpY2sobmFtZWQpfWAgOiBlc2NhcGVQaWNrKFN0cmluZyhwaWNrKSk7XG4gICAgfSlcbiAgICAuam9pbihQSUNLX1NFUEFSQVRPUik7XG59XG5cbi8vIEEgcGljaydzIHZhbHVlIG9yIG5hbWUgd2l0aCBlYWNoICcsJywgJzonIGFuZCAnXFwnIGluIGl0IGVzY2FwZWQuXG5mdW5jdGlvbiBlc2NhcGVQaWNrKHRleHQ6IHN0cmluZyk6IHN0cmluZyB7XG4gIHJldHVybiB0ZXh0LnJlcGxhY2UoL1tcXFxcLDpdL2csIChjaGFyKSA9PiBgJHtQSUNLX0VTQ0FQRX0ke2NoYXJ9YCk7XG59XG5cbi8vIFRoZSBwaWNrcyBvZiBhIHBhcmFtIHdyaXR0ZW4gYXMgZW5jb2RlUGlja3Mgd3JpdGVzIHRoZW0sIGluIG9yZGVyOiBlYWNoXG4vLyB2YWx1ZSBhbmQgaXRzIG5hbWUgKG51bGwgd2hlbiB0aGUgcGljayBoYXMgbm9uZSkuXG5mdW5jdGlvbiBkZWNvZGVQaWNrTGlzdChyYXc6IHN0cmluZyk6IHsgdmFsdWU6IHN0cmluZzsgbmFtZTogc3RyaW5nIHwgbnVsbCB9W10ge1xuICBjb25zdCBwaWNrczogeyB2YWx1ZTogc3RyaW5nOyBuYW1lOiBzdHJpbmcgfCBudWxsIH1bXSA9IFtdO1xuICBsZXQgcGFydHM6IHN0cmluZ1tdID0gWycnXTtcbiAgbGV0IGVzY2FwZWQgPSBmYWxzZTtcbiAgY29uc3QgZW5kUGljayA9ICgpID0+IHBpY2tzLnB1c2goeyB2YWx1ZTogcGFydHNbMF0sIG5hbWU6IHBhcnRzLmxlbmd0aCA+IDEgPyBwYXJ0c1sxXSA6IG51bGwgfSk7XG5cbiAgZm9yIChjb25zdCBjaGFyIG9mIHJhdykge1xuICAgIGlmIChlc2NhcGVkKSB7XG4gICAgICBwYXJ0c1twYXJ0cy5sZW5ndGggLSAxXSArPSBjaGFyO1xuICAgICAgZXNjYXBlZCA9IGZhbHNlO1xuICAgIH0gZWxzZSBpZiAoY2hhciA9PT0gUElDS19FU0NBUEUpIHtcbiAgICAgIGVzY2FwZWQgPSB0cnVlO1xuICAgIH0gZWxzZSBpZiAoY2hhciA9PT0gUElDS19OQU1FX1NFUEFSQVRPUiAmJiBwYXJ0cy5sZW5ndGggPT09IDEpIHtcbiAgICAgIHBhcnRzLnB1c2goJycpO1xuICAgIH0gZWxzZSBpZiAoY2hhciA9PT0gUElDS19TRVBBUkFUT1IpIHtcbiAgICAgIGVuZFBpY2soKTtcbiAgICAgIHBhcnRzID0gWycnXTtcbiAgICB9IGVsc2Uge1xuICAgICAgcGFydHNbcGFydHMubGVuZ3RoIC0gMV0gKz0gY2hhcjtcbiAgICB9XG4gIH1cblxuICBlbmRQaWNrKCk7XG5cbiAgcmV0dXJuIHBpY2tzO1xufVxuXG4vLyBBIHNlbGVjdCdzIHZhbHVlcywga2VwdCBvciBsZWZ0IG91dCwgcmVhZCBmcm9tIGl0cyBwYXJhbSwgb3IgdW5kZWZpbmVkXG4vLyB3aGVuIHRoZXJlIGFyZSBub25lIG9yIHRvbyBtYW55LlxuZnVuY3Rpb24gZGVjb2RlUGlja3MocmF3OiBzdHJpbmcsIGFzOiAndmFsdWVzJyB8ICdleGNsdWRlVmFsdWVzJyk6IEZpbHRlckdyb3VwRGVmYXVsdCB8IHVuZGVmaW5lZCB7XG4gIGNvbnN0IHBpY2tzID0gZGVjb2RlUGlja0xpc3QocmF3KVxuICAgIC5tYXAoKHBpY2spID0+IHBpY2sudmFsdWUpXG4gICAgLmZpbHRlcigodmFsdWUpID0+IHZhbHVlICE9PSAnJyk7XG5cbiAgcmV0dXJuIHBpY2tzLmxlbmd0aCAmJiBwaWNrcy5sZW5ndGggPD0gR1JPVVBfVkFMVUVfTUFYX1BJQ0tTID8geyBbYXNdOiBwaWNrcyB9IDogdW5kZWZpbmVkO1xufVxuXG4vLyBBIHJhbmdlJ3Mgc2V0IGVuZHMgdW5kZXIgdGhlaXIga2V5cy5cbmZ1bmN0aW9uIGNvbXBhY3RSYW5nZTxUPihsb3c6IFQgfCBudWxsLCBoaWdoOiBUIHwgbnVsbCwgbG93S2V5OiBzdHJpbmcsIGhpZ2hLZXk6IHN0cmluZyk6IEZpbHRlckdyb3VwRGVmYXVsdCB7XG4gIHJldHVybiB7XG4gICAgLi4uKGxvdyAhPT0gbnVsbCA/IHsgW2xvd0tleV06IGxvdyB9IDoge30pLFxuICAgIC4uLihoaWdoICE9PSBudWxsID8geyBbaGlnaEtleV06IGhpZ2ggfSA6IHt9KSxcbiAgfTtcbn1cblxuZnVuY3Rpb24gaXNOdW1iZXJFbmQoZW5kOiB1bmtub3duKTogZW5kIGlzIG51bWJlciB7XG4gIHJldHVybiB0eXBlb2YgZW5kID09PSAnbnVtYmVyJyAmJiBOdW1iZXIuaXNGaW5pdGUoZW5kKTtcbn1cblxuZnVuY3Rpb24gbnVtYmVyRW5kVGV4dChlbmQ6IHVua25vd24pOiBzdHJpbmcge1xuICByZXR1cm4gaXNOdW1iZXJFbmQoZW5kKSA/IFN0cmluZyhlbmQpIDogJyc7XG59XG5cbi8vIE9uZSAnbGV2ZWw6dmFsdWUnIHN0ZXAsIG9yIG51bGwgd2hlbiBpdHMgbGV2ZWwgaXMgbm90IGEgdGltZSBncmFpbi5cbmZ1bmN0aW9uIGRlY29kZURyaWxsU3RlcChpdGVtOiBzdHJpbmcpOiBSZXBvcnREcmlsbFN0ZXAgfCBudWxsIHtcbiAgY29uc3QgYXQgPSBpdGVtLmluZGV4T2YoRFJJTExfU1RFUF9TRVBBUkFUT1IpO1xuICBjb25zdCBsZXZlbCA9IGRlY29kZUl0ZW0oYXQgPCAwID8gaXRlbSA6IGl0ZW0uc2xpY2UoMCwgYXQpKTtcblxuICBpZiAoIWlzQ2hhcnRHcmFudWxhcml0eShsZXZlbCkpIHtcbiAgICByZXR1cm4gbnVsbDtcbiAgfVxuXG4gIHJldHVybiB7IGxldmVsLCB2YWx1ZTogYXQgPCAwID8gbnVsbCA6IGRlY29kZUl0ZW0oaXRlbS5zbGljZShhdCArIDEpKSB9O1xufVxuIl19