@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.
- package/app/reports/data/report.data.d.ts +3 -5
- package/app/reports/dialogs/report-settings/report-settings.component.d.ts +30 -2
- package/app/reports/filter-settings-rules.d.ts +4 -0
- package/app/reports/interfaces/report-filter-group-changes.interface.d.ts +7 -0
- package/app/reports/interfaces/report.interface.d.ts +1 -14
- package/app/reports/report-filter-items.d.ts +2 -8
- package/app/reports/report-view-config.d.ts +1 -3
- package/app/reports/services/report-filter-state.service.d.ts +5 -14
- package/app/reports/services/report-view.service.d.ts +1 -13
- package/app/reports/views/report/fs-ai-report.component.d.ts +2 -8
- package/esm2022/app/reports/canvas-landing-page.mjs +7 -6
- package/esm2022/app/reports/components/component-list/component-list.component.mjs +5 -5
- package/esm2022/app/reports/components/report-canvas/report-canvas.component.mjs +13 -12
- package/esm2022/app/reports/components/report-component/report-component.component.mjs +9 -9
- package/esm2022/app/reports/data/report.data.mjs +8 -5
- package/esm2022/app/reports/dialogs/report-settings/report-settings.component.mjs +169 -21
- package/esm2022/app/reports/filter-settings-rules.mjs +8 -1
- package/esm2022/app/reports/interfaces/canvas-landing-input.interface.mjs +1 -1
- package/esm2022/app/reports/interfaces/report-filter-group-changes.interface.mjs +2 -0
- package/esm2022/app/reports/interfaces/report-temporary-state.interface.mjs +1 -1
- package/esm2022/app/reports/interfaces/report-view-config.interface.mjs +1 -1
- package/esm2022/app/reports/interfaces/report.interface.mjs +1 -1
- package/esm2022/app/reports/report-date-presets.mjs +2 -2
- package/esm2022/app/reports/report-filter-items.mjs +25 -105
- package/esm2022/app/reports/report-view-config.mjs +6 -116
- package/esm2022/app/reports/services/report-filter-state.service.mjs +92 -269
- package/esm2022/app/reports/services/report-view.service.mjs +25 -165
- package/esm2022/app/reports/views/report/fs-ai-report.component.mjs +56 -120
- package/esm2022/app/reports/views/report/report.component.mjs +11 -8
- package/fesm2022/{firestitch-report-echarts-UBg8Wlhd.mjs → firestitch-report-echarts-DHEH_K_q.mjs} +2 -2
- package/fesm2022/{firestitch-report-echarts-UBg8Wlhd.mjs.map → firestitch-report-echarts-DHEH_K_q.mjs.map} +1 -1
- package/fesm2022/{firestitch-report-firestitch-report-B1keNrcK.mjs → firestitch-report-firestitch-report-ZcHTnNKq.mjs} +454 -1470
- package/fesm2022/firestitch-report-firestitch-report-ZcHTnNKq.mjs.map +1 -0
- package/fesm2022/firestitch-report.mjs +1 -1
- package/package.json +1 -1
- package/app/reports/interfaces/report-url-link.interface.d.ts +0 -4
- package/app/reports/interfaces/report-url-value-name.type.d.ts +0 -1
- package/app/reports/interfaces/report-url-write.interface.d.ts +0 -4
- package/app/reports/report-url-state.d.ts +0 -36
- package/esm2022/app/reports/interfaces/report-url-link.interface.mjs +0 -2
- package/esm2022/app/reports/interfaces/report-url-value-name.type.mjs +0 -2
- package/esm2022/app/reports/interfaces/report-url-write.interface.mjs +0 -2
- package/esm2022/app/reports/report-url-state.mjs +0 -677
- 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®ion=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
|