@firestitch/report 18.9.0 → 18.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/app/reports/anchor-at-point.d.ts +14 -0
- package/app/reports/canvas-landing-page.d.ts +2 -0
- package/app/reports/components/component-chart/component-chart.component.d.ts +18 -2
- package/app/reports/components/component-kpi/component-kpi.component.d.ts +4 -1
- package/app/reports/components/report-canvas/report-canvas.component.d.ts +3 -0
- package/app/reports/components/report-component/report-component.component.d.ts +35 -1
- package/app/reports/components/report-view-picker/report-view-picker.component.d.ts +21 -0
- package/app/reports/data/report.data.d.ts +17 -2
- package/app/reports/dialogs/component-settings/component-settings.component.d.ts +18 -3
- package/app/reports/dialogs/report-settings/report-settings.component.d.ts +15 -6
- package/app/reports/dialogs/report-view/report-view-dialog.component.d.ts +13 -0
- package/app/reports/drill-crumbs.d.ts +12 -0
- package/app/reports/export/report-export-collector.service.d.ts +13 -4
- package/app/reports/export/report-filter-lines.d.ts +18 -0
- package/app/reports/filter-settings-rules.d.ts +33 -0
- package/app/reports/format.d.ts +0 -1
- package/app/reports/interfaces/canvas-landing-input.interface.d.ts +8 -0
- package/app/reports/interfaces/component-data-applied.interface.d.ts +13 -0
- package/app/reports/interfaces/component-data-drill.interface.d.ts +22 -0
- package/app/reports/interfaces/filter-bar-placement.type.d.ts +1 -0
- package/app/reports/interfaces/filter-component-toggle-state.interface.d.ts +4 -0
- package/app/reports/interfaces/filter-settings-option.interface.d.ts +4 -0
- package/app/reports/interfaces/filter-type-select-state.interface.d.ts +5 -0
- package/app/reports/interfaces/report-chart-hit.interface.d.ts +5 -0
- package/app/reports/interfaces/report-chat-viewer-cross-filter-field.interface.d.ts +4 -0
- package/app/reports/interfaces/report-chat-viewer-cross-filter.interface.d.ts +7 -0
- package/app/reports/interfaces/report-chat-viewer-detail.interface.d.ts +4 -0
- package/app/reports/interfaces/report-chat-viewer-drill-step.interface.d.ts +5 -0
- package/app/reports/interfaces/report-chat-viewer-drill.interface.d.ts +5 -0
- package/app/reports/interfaces/report-chat-viewer-filter.interface.d.ts +3 -0
- package/app/reports/interfaces/report-chat-viewer-selection.interface.d.ts +5 -0
- package/app/reports/interfaces/report-chat-viewer-state.interface.d.ts +12 -0
- package/app/reports/interfaces/report-drill-crumb.interface.d.ts +6 -0
- package/app/reports/interfaces/report-drill-refusal.type.d.ts +1 -0
- package/app/reports/interfaces/report-drill-step.interface.d.ts +5 -0
- package/app/reports/interfaces/report-export-line-kind.type.d.ts +1 -0
- package/app/reports/interfaces/report-export-line.interface.d.ts +8 -0
- package/app/reports/interfaces/report-export-lines-input.interface.d.ts +9 -0
- package/app/reports/interfaces/report-export-snapshot.interface.d.ts +15 -0
- package/app/reports/interfaces/report-filter-line-context.interface.d.ts +8 -0
- package/app/reports/interfaces/report-filter-line-form.type.d.ts +1 -0
- package/app/reports/interfaces/report-filter-match.type.d.ts +1 -0
- package/app/reports/interfaces/report-filter-option-pair.interface.d.ts +4 -0
- package/app/reports/interfaces/report-filter-options-ask.interface.d.ts +6 -0
- package/app/reports/interfaces/report-filter-options-list.interface.d.ts +7 -0
- package/app/reports/interfaces/report-filter-options-request.interface.d.ts +6 -0
- package/app/reports/interfaces/report-filter-options-stream.interface.d.ts +11 -0
- package/app/reports/interfaces/report-filter-options.interface.d.ts +7 -0
- package/app/reports/interfaces/report-filter-skip.type.d.ts +1 -0
- package/app/reports/interfaces/report-mark-action.type.d.ts +1 -0
- package/app/reports/interfaces/report-mark-click.interface.d.ts +13 -0
- package/app/reports/interfaces/report-mark-context.interface.d.ts +6 -0
- package/app/reports/interfaces/report-mark-decision.interface.d.ts +6 -0
- package/app/reports/interfaces/report-mark-event.interface.d.ts +11 -0
- package/app/reports/interfaces/report-mark-point.interface.d.ts +8 -0
- package/app/reports/interfaces/report-temporary-state.interface.d.ts +4 -0
- package/app/reports/interfaces/report-tile-state.interface.d.ts +8 -0
- package/app/reports/interfaces/report-url-link.interface.d.ts +4 -0
- package/app/reports/interfaces/report-url-value-name.type.d.ts +1 -0
- package/app/reports/interfaces/report-url-write.interface.d.ts +4 -0
- package/app/reports/interfaces/report-view-config.interface.d.ts +11 -0
- package/app/reports/interfaces/report-view-create.interface.d.ts +7 -0
- package/app/reports/interfaces/report-view-deleted.interface.d.ts +4 -0
- package/app/reports/interfaces/report-view-dialog-data.interface.d.ts +7 -0
- package/app/reports/interfaces/report-view-dropped.interface.d.ts +5 -0
- package/app/reports/interfaces/report-view-menu-item.interface.d.ts +10 -0
- package/app/reports/interfaces/report-view-summary.interface.d.ts +11 -0
- package/app/reports/interfaces/report-view.interface.d.ts +7 -0
- package/app/reports/interfaces/report-viewer-feature.type.d.ts +1 -0
- package/app/reports/interfaces/report-views.interface.d.ts +7 -0
- package/app/reports/interfaces/report.interface.d.ts +27 -3
- package/app/reports/interfaces/tile-load-result.interface.d.ts +4 -0
- package/app/reports/mark-click.d.ts +20 -0
- package/app/reports/option-builder.d.ts +12 -1
- package/app/reports/report-chat-viewer-state.d.ts +8 -0
- package/app/reports/report-date-presets.d.ts +2 -0
- package/app/reports/report-filter-items.d.ts +27 -22
- package/app/reports/report-tile.d.ts +2 -0
- package/app/reports/report-url-state.d.ts +27 -10
- package/app/reports/report-view-config.d.ts +36 -0
- package/app/reports/report-view-menu.d.ts +15 -0
- package/app/reports/report-viewer-features.d.ts +5 -0
- package/app/reports/services/report-filter-options.service.d.ts +26 -0
- package/app/reports/services/report-filter-state.service.d.ts +64 -1
- package/app/reports/services/report-view.service.d.ts +51 -0
- package/app/reports/tile-data-state.d.ts +7 -0
- package/app/reports/tile-loads.d.ts +4 -0
- package/app/reports/views/report/fs-ai-report.component.d.ts +9 -1
- package/app/reports/views/report/report.component.d.ts +6 -0
- package/esm2022/app/reports/anchor-at-point.mjs +49 -0
- package/esm2022/app/reports/canvas-landing-page.mjs +25 -0
- package/esm2022/app/reports/components/component-chart/component-chart.component.mjs +97 -5
- package/esm2022/app/reports/components/component-kpi/component-kpi.component.mjs +11 -4
- package/esm2022/app/reports/components/component-list/component-list.component.mjs +7 -1
- package/esm2022/app/reports/components/report-canvas/report-canvas.component.mjs +47 -32
- package/esm2022/app/reports/components/report-component/report-component.component.mjs +257 -61
- package/esm2022/app/reports/components/report-view-picker/report-view-picker.component.mjs +115 -0
- package/esm2022/app/reports/data/report.data.mjs +87 -10
- package/esm2022/app/reports/dialogs/component-settings/component-settings.component.mjs +106 -51
- package/esm2022/app/reports/dialogs/report-settings/report-settings.component.mjs +86 -90
- package/esm2022/app/reports/dialogs/report-view/report-view-dialog.component.mjs +52 -0
- package/esm2022/app/reports/drill-crumbs.mjs +73 -0
- package/esm2022/app/reports/export/report-export-collector.service.mjs +187 -117
- package/esm2022/app/reports/export/report-filter-lines.mjs +235 -0
- package/esm2022/app/reports/export/report-pdf.service.mjs +12 -7
- package/esm2022/app/reports/export/report-pptx.service.mjs +18 -14
- package/esm2022/app/reports/filter-settings-rules.mjs +283 -0
- package/esm2022/app/reports/format.mjs +2 -22
- package/esm2022/app/reports/interfaces/canvas-landing-input.interface.mjs +2 -0
- package/esm2022/app/reports/interfaces/component-data-applied.interface.mjs +2 -0
- package/esm2022/app/reports/interfaces/component-data-drill.interface.mjs +2 -0
- package/esm2022/app/reports/interfaces/filter-bar-placement.type.mjs +2 -0
- package/esm2022/app/reports/interfaces/filter-component-toggle-state.interface.mjs +2 -0
- package/esm2022/app/reports/interfaces/filter-settings-option.interface.mjs +2 -0
- package/esm2022/app/reports/interfaces/filter-type-select-state.interface.mjs +2 -0
- package/esm2022/app/reports/interfaces/report-chart-hit.interface.mjs +2 -0
- package/esm2022/app/reports/interfaces/report-chat-viewer-cross-filter-field.interface.mjs +2 -0
- package/esm2022/app/reports/interfaces/report-chat-viewer-cross-filter.interface.mjs +2 -0
- package/esm2022/app/reports/interfaces/report-chat-viewer-detail.interface.mjs +2 -0
- package/esm2022/app/reports/interfaces/report-chat-viewer-drill-step.interface.mjs +2 -0
- package/esm2022/app/reports/interfaces/report-chat-viewer-drill.interface.mjs +2 -0
- package/esm2022/app/reports/interfaces/report-chat-viewer-filter.interface.mjs +1 -1
- package/esm2022/app/reports/interfaces/report-chat-viewer-selection.interface.mjs +2 -0
- package/esm2022/app/reports/interfaces/report-chat-viewer-state.interface.mjs +1 -1
- package/esm2022/app/reports/interfaces/report-drill-crumb.interface.mjs +2 -0
- package/esm2022/app/reports/interfaces/report-drill-refusal.type.mjs +2 -0
- package/esm2022/app/reports/interfaces/report-drill-step.interface.mjs +2 -0
- package/esm2022/app/reports/interfaces/report-export-line-kind.type.mjs +2 -0
- package/esm2022/app/reports/interfaces/report-export-line.interface.mjs +2 -0
- package/esm2022/app/reports/interfaces/report-export-lines-input.interface.mjs +2 -0
- package/esm2022/app/reports/interfaces/report-export-snapshot.interface.mjs +2 -0
- package/esm2022/app/reports/interfaces/report-filter-line-context.interface.mjs +2 -0
- package/esm2022/app/reports/interfaces/report-filter-line-form.type.mjs +2 -0
- package/esm2022/app/reports/interfaces/report-filter-match.type.mjs +2 -0
- package/esm2022/app/reports/interfaces/report-filter-option-pair.interface.mjs +2 -0
- package/esm2022/app/reports/interfaces/report-filter-options-ask.interface.mjs +2 -0
- package/esm2022/app/reports/interfaces/report-filter-options-list.interface.mjs +2 -0
- package/esm2022/app/reports/interfaces/report-filter-options-request.interface.mjs +2 -0
- package/esm2022/app/reports/interfaces/report-filter-options-stream.interface.mjs +2 -0
- package/esm2022/app/reports/interfaces/report-filter-options.interface.mjs +2 -0
- package/esm2022/app/reports/interfaces/report-filter-skip.type.mjs +2 -0
- package/esm2022/app/reports/interfaces/report-mark-action.type.mjs +2 -0
- package/esm2022/app/reports/interfaces/report-mark-click.interface.mjs +2 -0
- package/esm2022/app/reports/interfaces/report-mark-context.interface.mjs +2 -0
- package/esm2022/app/reports/interfaces/report-mark-decision.interface.mjs +2 -0
- package/esm2022/app/reports/interfaces/report-mark-event.interface.mjs +2 -0
- package/esm2022/app/reports/interfaces/report-mark-point.interface.mjs +2 -0
- package/esm2022/app/reports/interfaces/report-temporary-state.interface.mjs +2 -0
- package/esm2022/app/reports/interfaces/report-tile-state.interface.mjs +2 -0
- package/esm2022/app/reports/interfaces/report-url-link.interface.mjs +2 -0
- package/esm2022/app/reports/interfaces/report-url-value-name.type.mjs +2 -0
- package/esm2022/app/reports/interfaces/report-url-write.interface.mjs +2 -0
- package/esm2022/app/reports/interfaces/report-view-config.interface.mjs +2 -0
- package/esm2022/app/reports/interfaces/report-view-create.interface.mjs +2 -0
- package/esm2022/app/reports/interfaces/report-view-deleted.interface.mjs +2 -0
- package/esm2022/app/reports/interfaces/report-view-dialog-data.interface.mjs +2 -0
- package/esm2022/app/reports/interfaces/report-view-dropped.interface.mjs +2 -0
- package/esm2022/app/reports/interfaces/report-view-menu-item.interface.mjs +2 -0
- package/esm2022/app/reports/interfaces/report-view-summary.interface.mjs +2 -0
- package/esm2022/app/reports/interfaces/report-view.interface.mjs +2 -0
- package/esm2022/app/reports/interfaces/report-viewer-feature.type.mjs +2 -0
- package/esm2022/app/reports/interfaces/report-views.interface.mjs +2 -0
- package/esm2022/app/reports/interfaces/report.interface.mjs +1 -1
- package/esm2022/app/reports/interfaces/tile-load-result.interface.mjs +2 -0
- package/esm2022/app/reports/mark-click.mjs +193 -0
- package/esm2022/app/reports/option-builder.mjs +159 -15
- package/esm2022/app/reports/report-chat-viewer-state.mjs +34 -0
- package/esm2022/app/reports/report-date-presets.mjs +18 -0
- package/esm2022/app/reports/report-filter-items.mjs +343 -72
- package/esm2022/app/reports/report-tile.mjs +12 -0
- package/esm2022/app/reports/report-url-state.mjs +596 -108
- package/esm2022/app/reports/report-view-config.mjs +697 -0
- package/esm2022/app/reports/report-view-menu.mjs +119 -0
- package/esm2022/app/reports/report-viewer-features.mjs +42 -0
- package/esm2022/app/reports/services/report-filter-options.service.mjs +238 -0
- package/esm2022/app/reports/services/report-filter-state.service.mjs +697 -62
- package/esm2022/app/reports/services/report-view.service.mjs +358 -0
- package/esm2022/app/reports/tile-data-state.mjs +127 -0
- package/esm2022/app/reports/tile-loads.mjs +38 -0
- package/esm2022/app/reports/views/report/fs-ai-report.component.mjs +177 -46
- package/esm2022/app/reports/views/report/report.component.mjs +103 -23
- package/esm2022/public_api.mjs +23 -1
- package/fesm2022/{firestitch-report-echarts-DBMOHmBF.mjs → firestitch-report-echarts-UBg8Wlhd.mjs} +2 -2
- package/fesm2022/{firestitch-report-echarts-DBMOHmBF.mjs.map → firestitch-report-echarts-UBg8Wlhd.mjs.map} +1 -1
- package/fesm2022/{firestitch-report-firestitch-report-CqbXT1gh.mjs → firestitch-report-firestitch-report-B1keNrcK.mjs} +9063 -4272
- package/fesm2022/firestitch-report-firestitch-report-B1keNrcK.mjs.map +1 -0
- package/fesm2022/firestitch-report.mjs +1 -1
- package/package.json +1 -1
- package/public_api.d.ts +22 -0
- package/fesm2022/firestitch-report-firestitch-report-CqbXT1gh.mjs.map +0 -1
|
@@ -0,0 +1,697 @@
|
|
|
1
|
+
import { GRANULARITY_OPTIONS, } from './interfaces/report.interface';
|
|
2
|
+
import { dateBoundString, dateFromBound } from './report-filter-items';
|
|
3
|
+
// The version this viewer writes and reads.
|
|
4
|
+
export const REPORT_VIEW_CONFIG_VERSION = 1;
|
|
5
|
+
// The caps of a view document, the server's.
|
|
6
|
+
export const VIEW_CONFIG_MAX_BYTES = 32 * 1024;
|
|
7
|
+
export const VIEW_CONFIG_MAX_GROUPS = 100;
|
|
8
|
+
export const VIEW_CONFIG_MAX_TILES = 200;
|
|
9
|
+
export const GROUP_VALUE_MAX_PICKS = 500;
|
|
10
|
+
export const DRILL_MAX_DEPTH = 5;
|
|
11
|
+
// Every relative range name the server knows, in its enum's order. A record
|
|
12
|
+
// rather than a list, so the build fails when ReportRelativeRange gains a
|
|
13
|
+
// name this misses.
|
|
14
|
+
const RELATIVE_RANGES = {
|
|
15
|
+
thisWeek: true,
|
|
16
|
+
lastWeek: true,
|
|
17
|
+
last7Days: true,
|
|
18
|
+
last30Days: true,
|
|
19
|
+
last3Months: true,
|
|
20
|
+
last6Months: true,
|
|
21
|
+
last12Months: true,
|
|
22
|
+
thisMonth: true,
|
|
23
|
+
thisQuarter: true,
|
|
24
|
+
thisYear: true,
|
|
25
|
+
yearToDate: true,
|
|
26
|
+
};
|
|
27
|
+
// The same names as a list, in the server enum's order (the record's key
|
|
28
|
+
// order): the order the date picker offers them in.
|
|
29
|
+
export const RELATIVE_RANGE_NAMES = Object.keys(RELATIVE_RANGES);
|
|
30
|
+
// The keys a group value may hold, by its group's type.
|
|
31
|
+
const GROUP_VALUE_KEYS = {
|
|
32
|
+
dateRange: ['relative', 'start', 'end'],
|
|
33
|
+
select: ['values', 'excludeValues'],
|
|
34
|
+
keyword: ['value'],
|
|
35
|
+
numberRange: ['min', 'max'],
|
|
36
|
+
};
|
|
37
|
+
// The keys of a view document and of a tile state this viewer reads. Any
|
|
38
|
+
// other key is kept as it was.
|
|
39
|
+
const VIEW_CONFIG_KEYS = ['v', 'pageId', 'groupBy', 'match', 'groups', 'tiles'];
|
|
40
|
+
const TILE_STATE_KEYS = ['sort', 'search', 'hidden', 'drill'];
|
|
41
|
+
const DAY_PATTERN = /^(\d{4})-(\d{2})-(\d{2})$/;
|
|
42
|
+
// A number as text: what a masked input or a link sends.
|
|
43
|
+
const NUMBER_PATTERN = /^[+-]?(?:\d+(?:\.\d*)?|\.\d+)(?:e[+-]?\d+)?$/i;
|
|
44
|
+
const ID_KEY_PATTERN = /^[1-9]\d*$/;
|
|
45
|
+
// Whether a name is a relative range the server resolves.
|
|
46
|
+
export function isRelativeRange(name) {
|
|
47
|
+
return typeof name === 'string' && Object.prototype.hasOwnProperty.call(RELATIVE_RANGES, name);
|
|
48
|
+
}
|
|
49
|
+
export function isChartGranularity(value) {
|
|
50
|
+
return GRANULARITY_OPTIONS.some((option) => option.value === value);
|
|
51
|
+
}
|
|
52
|
+
// Whether text is a real calendar day written 'yyyy-MM-dd' (no 2026-02-30).
|
|
53
|
+
export function isCalendarDay(text) {
|
|
54
|
+
const parts = DAY_PATTERN.exec(text);
|
|
55
|
+
if (!parts) {
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
const [year, month, day] = parts.slice(1).map(Number);
|
|
59
|
+
const date = new Date(Date.UTC(year, month - 1, day));
|
|
60
|
+
return date.getUTCFullYear() === year && date.getUTCMonth() === month - 1 && date.getUTCDate() === day;
|
|
61
|
+
}
|
|
62
|
+
// A number written as text (a link's range end, a masked input's value), or
|
|
63
|
+
// null when the text is not one finite number.
|
|
64
|
+
export function numberFromText(text) {
|
|
65
|
+
const number = NUMBER_PATTERN.test(text) ? Number(text) : NaN;
|
|
66
|
+
return Number.isFinite(number) ? number : null;
|
|
67
|
+
}
|
|
68
|
+
// A group value read for a group of `type`, on its way to being stored: only
|
|
69
|
+
// the parts that hold something. Throws, naming what is wrong, when a key
|
|
70
|
+
// does not belong to the type or a part breaks its type's rule.
|
|
71
|
+
export function groupValueFromArray(value, type) {
|
|
72
|
+
requireGroupKeys(value, type);
|
|
73
|
+
switch (type) {
|
|
74
|
+
case 'dateRange':
|
|
75
|
+
return dateRangeValue(value);
|
|
76
|
+
case 'select':
|
|
77
|
+
return selectValue(value);
|
|
78
|
+
case 'numberRange':
|
|
79
|
+
return numberRangeValue(value);
|
|
80
|
+
default:
|
|
81
|
+
return keywordValue(value);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
// A group value read back (a saved view, a link) for a group of `type`: what
|
|
85
|
+
// groupValueFromArray gives, or null when it would refuse it.
|
|
86
|
+
export function groupValueFromStored(value, type) {
|
|
87
|
+
if (!isPlainObject(value)) {
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
try {
|
|
91
|
+
return groupValueFromArray(value, type);
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
// A view document read for storing or applying. Throws when it is not a
|
|
98
|
+
// version 1 document, breaks a cap or holds a malformed known key.
|
|
99
|
+
export function viewConfigFromArray(input) {
|
|
100
|
+
const doc = requireObject(input, 'A view config must be an object.');
|
|
101
|
+
requireSize(doc);
|
|
102
|
+
requireVersion(doc.v);
|
|
103
|
+
const config = { v: REPORT_VIEW_CONFIG_VERSION, ...otherKeys(doc, VIEW_CONFIG_KEYS) };
|
|
104
|
+
const pageId = optionalId(doc.pageId, 'pageId must be a page id.');
|
|
105
|
+
if (pageId !== null) {
|
|
106
|
+
config.pageId = pageId;
|
|
107
|
+
}
|
|
108
|
+
if (isSet(doc.groupBy)) {
|
|
109
|
+
config.groupBy = requireGranularity(doc.groupBy, 'groupBy must be a time grain.');
|
|
110
|
+
}
|
|
111
|
+
if (isSet(doc.match)) {
|
|
112
|
+
config.match = requireMatch(doc.match);
|
|
113
|
+
}
|
|
114
|
+
if (isSet(doc.groups)) {
|
|
115
|
+
config.groups = viewGroups(doc.groups);
|
|
116
|
+
}
|
|
117
|
+
if (isSet(doc.tiles)) {
|
|
118
|
+
config.tiles = viewTiles(doc.tiles);
|
|
119
|
+
}
|
|
120
|
+
return config;
|
|
121
|
+
}
|
|
122
|
+
// A group's value as a view or a link stores it, read for the keys its
|
|
123
|
+
// group's type owns, or null when it holds nothing. A date range that still
|
|
124
|
+
// carries its relative preset is stored as that preset whatever today is: the
|
|
125
|
+
// viewer did not edit it, so a view saved after midnight with the page still
|
|
126
|
+
// open keeps rolling.
|
|
127
|
+
export function toStoredGroupValue(type, value) {
|
|
128
|
+
if (!value) {
|
|
129
|
+
return null;
|
|
130
|
+
}
|
|
131
|
+
switch (type) {
|
|
132
|
+
case 'dateRange':
|
|
133
|
+
return isRelativeRange(value.preset)
|
|
134
|
+
? { relative: value.preset }
|
|
135
|
+
: storedOrNull({ start: dateBoundString(value.start), end: dateBoundString(value.end) });
|
|
136
|
+
case 'select': {
|
|
137
|
+
const excludeValues = keptPicks(value.excludeValues);
|
|
138
|
+
return storedOrNull(excludeValues ? { excludeValues } : { values: keptPicks(value.values) });
|
|
139
|
+
}
|
|
140
|
+
case 'numberRange':
|
|
141
|
+
return storedOrNull({ min: finiteNumber(value.min), max: finiteNumber(value.max) });
|
|
142
|
+
default:
|
|
143
|
+
return storedOrNull({ value: value.value?.trim() || undefined });
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
// A group value in its stored shape as the value the bars and the requests
|
|
147
|
+
// read: a relative preset as today's days in the report's zone, carrying its
|
|
148
|
+
// name; fixed days as dates; any other value as it is. Null when it holds
|
|
149
|
+
// nothing, or names a preset `resolveRelative` does not know.
|
|
150
|
+
export function toLiveGroupValue(type, stored, resolveRelative) {
|
|
151
|
+
if (!stored || holdsNothing(stored)) {
|
|
152
|
+
return null;
|
|
153
|
+
}
|
|
154
|
+
if (type !== 'dateRange') {
|
|
155
|
+
return { ...stored };
|
|
156
|
+
}
|
|
157
|
+
if (stored.relative) {
|
|
158
|
+
const range = resolveRelative(stored.relative);
|
|
159
|
+
return range ? { start: range.start, end: range.end, preset: stored.relative } : null;
|
|
160
|
+
}
|
|
161
|
+
return { start: dateFromBound(stored.start), end: dateFromBound(stored.end) };
|
|
162
|
+
}
|
|
163
|
+
// Whether the screen's state differs from the view it opened on. `current`
|
|
164
|
+
// is a snapshot, so it holds every group the report has; a group only `base`
|
|
165
|
+
// holds is one the report no longer has, and is not compared. A group `base`
|
|
166
|
+
// does not hold was added after the view was saved: it is compared with its
|
|
167
|
+
// value in `authored` (the report's defaults), so leaving it at its default
|
|
168
|
+
// changes nothing. The page is not compared (moving to another page does not
|
|
169
|
+
// edit a view), and neither are keys this viewer does not know. Picks are
|
|
170
|
+
// compared in any order.
|
|
171
|
+
export function viewDiffers(base, current, authored = null) {
|
|
172
|
+
return (base.match ?? 'all') !== (current.match ?? 'all')
|
|
173
|
+
|| (base.groupBy ?? null) !== (current.groupBy ?? null)
|
|
174
|
+
|| groupsDiffer(base, current, authored)
|
|
175
|
+
|| tilesDiffer(base.tiles ?? {}, current.tiles ?? {});
|
|
176
|
+
}
|
|
177
|
+
// Whether two stored group values are the same filter, as viewDiffers reads
|
|
178
|
+
// a group: picks in any order, text trimmed, an empty value read as none.
|
|
179
|
+
export function sameStoredGroupValue(a, b) {
|
|
180
|
+
return storedValueKey(a) === storedValueKey(b);
|
|
181
|
+
}
|
|
182
|
+
// A drill path kept to what a tile can carry: its steps up to the first that
|
|
183
|
+
// is not a time level with a plain value (the steps before it are kept), at
|
|
184
|
+
// most DRILL_MAX_DEPTH of them.
|
|
185
|
+
export function cleanDrillPath(path) {
|
|
186
|
+
const kept = [];
|
|
187
|
+
for (const step of path ?? []) {
|
|
188
|
+
if (!isPlainObject(step) || !isChartGranularity(step.level) || !isDrillValue(step.value)
|
|
189
|
+
|| kept.length === DRILL_MAX_DEPTH) {
|
|
190
|
+
break;
|
|
191
|
+
}
|
|
192
|
+
kept.push({ level: step.level, value: step.value });
|
|
193
|
+
}
|
|
194
|
+
return kept;
|
|
195
|
+
}
|
|
196
|
+
// Whether two drill paths are the same steps. A value is compared as text,
|
|
197
|
+
// so 2026 and '2026' are the same step.
|
|
198
|
+
export function sameDrillPath(a, b) {
|
|
199
|
+
return drillKey(a) === drillKey(b);
|
|
200
|
+
}
|
|
201
|
+
// What a link must carry for the screen (`current`, a snapshot) to open on
|
|
202
|
+
// `base`: only what differs from it. A group `base` does not hold is read
|
|
203
|
+
// against `authored`, as viewDiffers reads it. A key that went back to its
|
|
204
|
+
// authored state where `base` holds another is written as that state where
|
|
205
|
+
// a link can say it: a group's value (an empty value clears it) and a list's
|
|
206
|
+
// sort (its authored first term, `authoredSort`). The match back to 'all',
|
|
207
|
+
// the authored grain, an empty search, no hidden columns, a chart's top and
|
|
208
|
+
// a list with no authored sort cannot be said on top of a base, so the
|
|
209
|
+
// result is null and the caller writes the full diff from the authored
|
|
210
|
+
// defaults instead, which can always be said. The page is never part of it
|
|
211
|
+
// (the host writes its own key).
|
|
212
|
+
export function viewConfigDiff(base, current, authored, authoredSort) {
|
|
213
|
+
const diff = { v: REPORT_VIEW_CONFIG_VERSION };
|
|
214
|
+
if ((base.match ?? 'all') !== (current.match ?? 'all')) {
|
|
215
|
+
if (current.match !== 'any') {
|
|
216
|
+
return null;
|
|
217
|
+
}
|
|
218
|
+
diff.match = 'any';
|
|
219
|
+
}
|
|
220
|
+
if ((base.groupBy ?? null) !== (current.groupBy ?? null)) {
|
|
221
|
+
if (!current.groupBy) {
|
|
222
|
+
return null;
|
|
223
|
+
}
|
|
224
|
+
diff.groupBy = current.groupBy;
|
|
225
|
+
}
|
|
226
|
+
const groups = changedGroups(base, current, authored);
|
|
227
|
+
if (Object.keys(groups).length) {
|
|
228
|
+
diff.groups = groups;
|
|
229
|
+
}
|
|
230
|
+
const tiles = changedTiles(base.tiles ?? {}, current.tiles ?? {}, authoredSort);
|
|
231
|
+
if (!tiles) {
|
|
232
|
+
return null;
|
|
233
|
+
}
|
|
234
|
+
if (Object.keys(tiles).length) {
|
|
235
|
+
diff.tiles = tiles;
|
|
236
|
+
}
|
|
237
|
+
return diff;
|
|
238
|
+
}
|
|
239
|
+
// A view's config to save: the screen (`screen`, a snapshot), with the keys
|
|
240
|
+
// this viewer does not know kept from the stored document (`stored`), at the
|
|
241
|
+
// top and in each tile. They are never read here, and saving must not lose
|
|
242
|
+
// them.
|
|
243
|
+
export function withStoredKeys(stored, screen) {
|
|
244
|
+
if (!stored) {
|
|
245
|
+
return screen;
|
|
246
|
+
}
|
|
247
|
+
const tiles = { ...screen.tiles };
|
|
248
|
+
Object.entries(stored.tiles ?? {}).forEach(([componentId, tile]) => {
|
|
249
|
+
const kept = isPlainObject(tile) ? otherKeys(tile, TILE_STATE_KEYS) : {};
|
|
250
|
+
if (Object.keys(kept).length) {
|
|
251
|
+
tiles[Number(componentId)] = { ...kept, ...tiles[Number(componentId)] };
|
|
252
|
+
}
|
|
253
|
+
});
|
|
254
|
+
const config = { ...otherKeys(stored, VIEW_CONFIG_KEYS), ...screen };
|
|
255
|
+
delete config.tiles;
|
|
256
|
+
return Object.keys(tiles).length ? { ...config, tiles } : config;
|
|
257
|
+
}
|
|
258
|
+
// How many settings of a saved view no longer apply because the report
|
|
259
|
+
// changed: what the server left out when it read the view (`dropped`), and
|
|
260
|
+
// what the viewer could not apply (`applied` is the view as it applied, the
|
|
261
|
+
// state service's base): a group value that no longer fits its group, and a
|
|
262
|
+
// list sort, search or hidden columns, or a chart's drill path, its tile can
|
|
263
|
+
// no longer take (a list column gone, a chart turned into a list).
|
|
264
|
+
export function viewDroppedCount(view, applied) {
|
|
265
|
+
const dropped = view.dropped;
|
|
266
|
+
const groups = Object.entries(view.config?.groups ?? {})
|
|
267
|
+
.filter(([groupId, value]) => value !== null && !Object.prototype.hasOwnProperty.call(applied.groups ?? {}, groupId))
|
|
268
|
+
.length;
|
|
269
|
+
const tiles = Object.entries(view.config?.tiles ?? {})
|
|
270
|
+
.reduce((count, [componentId, tile]) => count + tileKeysLost(tile, applied.tiles?.[Number(componentId)]), 0);
|
|
271
|
+
return (dropped?.groups?.length ?? 0) + (dropped?.tiles?.length ?? 0) + (dropped?.page ? 1 : 0) + groups + tiles;
|
|
272
|
+
}
|
|
273
|
+
// The note a view opens with when some of its settings no longer apply, or
|
|
274
|
+
// null when every setting applies. Only a viewer who may change the view
|
|
275
|
+
// (`canChange`) is told to save it.
|
|
276
|
+
export function viewDroppedMessage(count, canChange = true) {
|
|
277
|
+
if (count < 1) {
|
|
278
|
+
return null;
|
|
279
|
+
}
|
|
280
|
+
const note = count === 1
|
|
281
|
+
? '1 setting in this view no longer applies, because the report changed.'
|
|
282
|
+
: `${count} settings in this view no longer apply, because the report changed.`;
|
|
283
|
+
return canChange ? `${note} Save changes to update the view.` : note;
|
|
284
|
+
}
|
|
285
|
+
// Shown when a link names a view the viewer cannot open (deleted, or another
|
|
286
|
+
// person's own view): the link's other settings apply on the report's
|
|
287
|
+
// defaults.
|
|
288
|
+
export const VIEW_NOT_AVAILABLE_MESSAGE = 'The view in this link is not available.';
|
|
289
|
+
// The open view as a chat turn names it: its id, and whether the screen
|
|
290
|
+
// differs from it. Both are left out while no view is open.
|
|
291
|
+
export function chatViewFields(openView, viewChanged) {
|
|
292
|
+
return openView ? { viewId: openView.id, viewChanged } : {};
|
|
293
|
+
}
|
|
294
|
+
function groupsDiffer(base, current, authored) {
|
|
295
|
+
return Object.entries(current.groups ?? {}).some(([groupId, value]) => {
|
|
296
|
+
const kept = base.groups && Object.prototype.hasOwnProperty.call(base.groups, groupId)
|
|
297
|
+
? base.groups[Number(groupId)]
|
|
298
|
+
: authored?.groups?.[Number(groupId)];
|
|
299
|
+
return storedValueKey(kept) !== storedValueKey(value);
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
function tilesDiffer(base, current) {
|
|
303
|
+
const ids = new Set([...Object.keys(base), ...Object.keys(current)].map(Number));
|
|
304
|
+
return [...ids].some((componentId) => tileStateKey(base[componentId]) !== tileStateKey(current[componentId]));
|
|
305
|
+
}
|
|
306
|
+
// The groups whose value on screen differs from base's (or, for a group base
|
|
307
|
+
// does not hold, from the authored one), each with the screen's value; null
|
|
308
|
+
// for one that holds nothing.
|
|
309
|
+
function changedGroups(base, current, authored) {
|
|
310
|
+
return Object.fromEntries(Object.entries(current.groups ?? {})
|
|
311
|
+
.filter(([groupId, value]) => {
|
|
312
|
+
const kept = base.groups && Object.prototype.hasOwnProperty.call(base.groups, groupId)
|
|
313
|
+
? base.groups[Number(groupId)]
|
|
314
|
+
: authored?.groups?.[Number(groupId)];
|
|
315
|
+
return storedValueKey(kept) !== storedValueKey(value);
|
|
316
|
+
})
|
|
317
|
+
.map(([groupId, value]) => [groupId, value ?? null]));
|
|
318
|
+
}
|
|
319
|
+
// Each tile's keys that differ from base's, or null when one of them went
|
|
320
|
+
// back to a state a link cannot say (see viewConfigDiff).
|
|
321
|
+
function changedTiles(base, current, authoredSort) {
|
|
322
|
+
const tiles = {};
|
|
323
|
+
const ids = new Set([...Object.keys(base), ...Object.keys(current)].map(Number));
|
|
324
|
+
for (const componentId of ids) {
|
|
325
|
+
const tile = changedTile(base[componentId] ?? {}, current[componentId] ?? {}, () => authoredSort(componentId));
|
|
326
|
+
if (!tile) {
|
|
327
|
+
return null;
|
|
328
|
+
}
|
|
329
|
+
if (Object.keys(tile).length) {
|
|
330
|
+
tiles[componentId] = tile;
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
return tiles;
|
|
334
|
+
}
|
|
335
|
+
// One tile's keys that differ from base's; null when one went back to a
|
|
336
|
+
// state a link cannot say.
|
|
337
|
+
function changedTile(base, current, authoredSort) {
|
|
338
|
+
const tile = {};
|
|
339
|
+
if (sortKey(base.sort) !== sortKey(current.sort)) {
|
|
340
|
+
const sort = current.sort?.column ? current.sort : authoredSort();
|
|
341
|
+
if (!sort) {
|
|
342
|
+
return null;
|
|
343
|
+
}
|
|
344
|
+
tile.sort = { ...sort };
|
|
345
|
+
}
|
|
346
|
+
if ((base.search ?? '') !== (current.search ?? '')) {
|
|
347
|
+
if (!current.search) {
|
|
348
|
+
return null;
|
|
349
|
+
}
|
|
350
|
+
tile.search = current.search;
|
|
351
|
+
}
|
|
352
|
+
if (sortedNames(base.hidden) !== sortedNames(current.hidden)) {
|
|
353
|
+
if (!current.hidden?.length) {
|
|
354
|
+
return null;
|
|
355
|
+
}
|
|
356
|
+
tile.hidden = [...current.hidden];
|
|
357
|
+
}
|
|
358
|
+
if (drillKey(base.drill) !== drillKey(current.drill)) {
|
|
359
|
+
if (!current.drill?.length) {
|
|
360
|
+
return null;
|
|
361
|
+
}
|
|
362
|
+
tile.drill = current.drill.map((step) => ({ ...step }));
|
|
363
|
+
}
|
|
364
|
+
return tile;
|
|
365
|
+
}
|
|
366
|
+
// How many keys of a stored tile state the tile, as it applied, lost: a
|
|
367
|
+
// sort, a search or a drill path it no longer has, and hidden columns it
|
|
368
|
+
// kept fewer of.
|
|
369
|
+
function tileKeysLost(stored, applied) {
|
|
370
|
+
if (!stored) {
|
|
371
|
+
return 0;
|
|
372
|
+
}
|
|
373
|
+
return [
|
|
374
|
+
!!stored.sort?.column && !applied?.sort?.column,
|
|
375
|
+
!!stored.search && !applied?.search,
|
|
376
|
+
(stored.hidden?.length ?? 0) > (applied?.hidden?.length ?? 0),
|
|
377
|
+
(stored.drill?.length ?? 0) > 0 && !applied?.drill?.length,
|
|
378
|
+
].filter(Boolean).length;
|
|
379
|
+
}
|
|
380
|
+
// A list sort as text; no direction reads as ascending, the way a list
|
|
381
|
+
// applies it.
|
|
382
|
+
function sortKey(sort) {
|
|
383
|
+
return sort?.column ? JSON.stringify([sort.column, sort.direction ?? 'asc']) : '';
|
|
384
|
+
}
|
|
385
|
+
function sortedNames(names) {
|
|
386
|
+
return JSON.stringify([...(names ?? [])].sort());
|
|
387
|
+
}
|
|
388
|
+
// One text for a stored group value, the same for every way of writing the
|
|
389
|
+
// same filter: picks in any order, text trimmed, and an empty value read as
|
|
390
|
+
// none.
|
|
391
|
+
function storedValueKey(value) {
|
|
392
|
+
const stored = value ?? {};
|
|
393
|
+
const picks = (list) => [...(keptPicks(list) ?? [])].map(String).sort();
|
|
394
|
+
return JSON.stringify([
|
|
395
|
+
stored.relative ?? null,
|
|
396
|
+
stored.start?.slice(0, 10) ?? null,
|
|
397
|
+
stored.end?.slice(0, 10) ?? null,
|
|
398
|
+
picks(stored.values),
|
|
399
|
+
picks(stored.excludeValues),
|
|
400
|
+
(stored.value ?? '').trim(),
|
|
401
|
+
finiteNumber(stored.min) ?? null,
|
|
402
|
+
finiteNumber(stored.max) ?? null,
|
|
403
|
+
]);
|
|
404
|
+
}
|
|
405
|
+
// One text for a tile's state, over the keys this viewer reads. No direction
|
|
406
|
+
// reads as ascending, the way a list applies it.
|
|
407
|
+
function tileStateKey(tile) {
|
|
408
|
+
return JSON.stringify([
|
|
409
|
+
tile?.sort?.column ? [tile.sort.column, tile.sort.direction ?? 'asc'] : null,
|
|
410
|
+
tile?.search ?? '',
|
|
411
|
+
[...(tile?.hidden ?? [])].sort(),
|
|
412
|
+
drillKey(tile?.drill),
|
|
413
|
+
]);
|
|
414
|
+
}
|
|
415
|
+
function drillKey(path) {
|
|
416
|
+
return JSON.stringify((path ?? [])
|
|
417
|
+
.map((step) => [step.level, step.value === null || step.value === undefined ? null : String(step.value)]));
|
|
418
|
+
}
|
|
419
|
+
// The picks of a list with blanks (null, '') left out, or undefined when none
|
|
420
|
+
// is left.
|
|
421
|
+
function keptPicks(list) {
|
|
422
|
+
const kept = (list ?? []).filter((pick) => isSet(pick) && pick !== '');
|
|
423
|
+
return kept.length ? kept : undefined;
|
|
424
|
+
}
|
|
425
|
+
// A range end as a number. A masked input sends its number as text, so
|
|
426
|
+
// numeric text is read as its number, as boundPart reads it.
|
|
427
|
+
export function finiteNumber(value) {
|
|
428
|
+
const number = typeof value === 'string' ? numberFromText(value.trim()) : value;
|
|
429
|
+
return typeof number === 'number' && Number.isFinite(number) ? number : undefined;
|
|
430
|
+
}
|
|
431
|
+
// Whether a stored value reads the same as no value at all.
|
|
432
|
+
function holdsNothing(stored) {
|
|
433
|
+
return storedValueKey(stored) === storedValueKey(null);
|
|
434
|
+
}
|
|
435
|
+
// Only the parts that hold something, or null when none does.
|
|
436
|
+
function storedOrNull(value) {
|
|
437
|
+
const stored = compact(value);
|
|
438
|
+
return Object.keys(stored).length ? stored : null;
|
|
439
|
+
}
|
|
440
|
+
function requireGroupKeys(value, type) {
|
|
441
|
+
const allowed = GROUP_VALUE_KEYS[type] ?? GROUP_VALUE_KEYS.keyword;
|
|
442
|
+
const unknown = Object.keys(value).filter((key) => !allowed.includes(key));
|
|
443
|
+
if (unknown.length) {
|
|
444
|
+
throw new Error(`A ${type} default takes ${allowed.join(', ')} — not ${unknown.join(', ')}.`);
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
// A relative range, or fixed days; never both.
|
|
448
|
+
function dateRangeValue(value) {
|
|
449
|
+
const relative = textPart(value, 'relative');
|
|
450
|
+
const start = dayPart(value, 'start');
|
|
451
|
+
const end = dayPart(value, 'end');
|
|
452
|
+
if (relative === '') {
|
|
453
|
+
return compact({ start, end });
|
|
454
|
+
}
|
|
455
|
+
if (start !== null || end !== null) {
|
|
456
|
+
throw new Error('A dateRange default is either a relative preset or a fixed start/end, not both.');
|
|
457
|
+
}
|
|
458
|
+
if (!isRelativeRange(relative)) {
|
|
459
|
+
throw new Error(`relative must be one of: ${Object.keys(RELATIVE_RANGES).join(', ')}.`);
|
|
460
|
+
}
|
|
461
|
+
return { relative };
|
|
462
|
+
}
|
|
463
|
+
// The values to keep or the values to leave out; never both.
|
|
464
|
+
function selectValue(value) {
|
|
465
|
+
const values = pickList(value, 'values');
|
|
466
|
+
const excludeValues = pickList(value, 'excludeValues');
|
|
467
|
+
if (values !== null && excludeValues !== null) {
|
|
468
|
+
throw new Error('A select default either keeps values or leaves out exclude_values, not both.');
|
|
469
|
+
}
|
|
470
|
+
return compact({ values, excludeValues });
|
|
471
|
+
}
|
|
472
|
+
function keywordValue(value) {
|
|
473
|
+
const text = textPart(value, 'value');
|
|
474
|
+
return text !== '' ? { value: text } : {};
|
|
475
|
+
}
|
|
476
|
+
// Either end may be open; 0 is an end like any other.
|
|
477
|
+
function numberRangeValue(value) {
|
|
478
|
+
const min = boundPart(value, 'min');
|
|
479
|
+
const max = boundPart(value, 'max');
|
|
480
|
+
if (min !== null && max !== null && min > max) {
|
|
481
|
+
throw new Error(`min (${min}) is above max (${max}).`);
|
|
482
|
+
}
|
|
483
|
+
return compact({ min, max });
|
|
484
|
+
}
|
|
485
|
+
// The text `key` holds, trimmed, or '' when absent. A number is read as its
|
|
486
|
+
// text; any other kind is refused.
|
|
487
|
+
function textPart(value, key) {
|
|
488
|
+
const text = value[key];
|
|
489
|
+
if (text === undefined || text === null) {
|
|
490
|
+
return '';
|
|
491
|
+
}
|
|
492
|
+
if (typeof text !== 'string' && typeof text !== 'number') {
|
|
493
|
+
throw new Error(`${key} must be text.`);
|
|
494
|
+
}
|
|
495
|
+
return String(text).trim();
|
|
496
|
+
}
|
|
497
|
+
// A calendar-day bound: its first ten characters must be a real day.
|
|
498
|
+
function dayPart(value, key) {
|
|
499
|
+
const text = textPart(value, key);
|
|
500
|
+
if (text === '') {
|
|
501
|
+
return null;
|
|
502
|
+
}
|
|
503
|
+
const day = text.slice(0, 10);
|
|
504
|
+
if (!isCalendarDay(day)) {
|
|
505
|
+
throw new Error(`${key} must be a yyyy-MM-dd day.`);
|
|
506
|
+
}
|
|
507
|
+
return day;
|
|
508
|
+
}
|
|
509
|
+
// The picks of `key` with blanks (null, '') dropped, or null when none is
|
|
510
|
+
// left. A lone pick is a list of one; a pick that is a list or an object is
|
|
511
|
+
// refused.
|
|
512
|
+
function pickList(value, key) {
|
|
513
|
+
const raw = value[key] ?? [];
|
|
514
|
+
const picks = Array.isArray(raw) ? raw : [raw];
|
|
515
|
+
if (picks.some((pick) => isSet(pick) && !isScalar(pick))) {
|
|
516
|
+
throw new Error(`Each pick in ${key} must be a plain value, not a list.`);
|
|
517
|
+
}
|
|
518
|
+
const kept = picks.filter((pick) => isSet(pick) && pick !== '');
|
|
519
|
+
return kept.length ? kept : null;
|
|
520
|
+
}
|
|
521
|
+
// One end of a number range: null when absent or blank, else a finite number
|
|
522
|
+
// (numeric text is read as its number).
|
|
523
|
+
function boundPart(value, key) {
|
|
524
|
+
const raw = typeof value[key] === 'string' ? value[key].trim() : value[key];
|
|
525
|
+
if (!isSet(raw) || raw === '') {
|
|
526
|
+
return null;
|
|
527
|
+
}
|
|
528
|
+
const bound = typeof raw === 'string' ? numberFromText(raw) : raw;
|
|
529
|
+
if (typeof bound !== 'number' || !Number.isFinite(bound)) {
|
|
530
|
+
throw new Error(`${key} must be a finite number.`);
|
|
531
|
+
}
|
|
532
|
+
return bound;
|
|
533
|
+
}
|
|
534
|
+
function requireSize(doc) {
|
|
535
|
+
if (new TextEncoder().encode(JSON.stringify(doc)).length > VIEW_CONFIG_MAX_BYTES) {
|
|
536
|
+
throw new Error('A view config is over 32 KB.');
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
function requireVersion(version) {
|
|
540
|
+
if (!isSet(version)) {
|
|
541
|
+
throw new Error('A view config needs its version (v).');
|
|
542
|
+
}
|
|
543
|
+
if (version !== REPORT_VIEW_CONFIG_VERSION) {
|
|
544
|
+
throw new Error(`This viewer reads view config version ${REPORT_VIEW_CONFIG_VERSION} only.`);
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
function requireMatch(match) {
|
|
548
|
+
if (match !== 'all' && match !== 'any') {
|
|
549
|
+
throw new Error('match must be all or any.');
|
|
550
|
+
}
|
|
551
|
+
return match;
|
|
552
|
+
}
|
|
553
|
+
// Group id -> value. A value no group type could hold is dropped whole.
|
|
554
|
+
function viewGroups(raw) {
|
|
555
|
+
const entries = Object.entries(requireObject(raw, 'groups must map group ids to values.'));
|
|
556
|
+
if (entries.length > VIEW_CONFIG_MAX_GROUPS) {
|
|
557
|
+
throw new Error(`A view holds at most ${VIEW_CONFIG_MAX_GROUPS} groups.`);
|
|
558
|
+
}
|
|
559
|
+
const groups = {};
|
|
560
|
+
entries.forEach(([key, value]) => {
|
|
561
|
+
const id = requireIdKey(key, 'groups');
|
|
562
|
+
requirePickCount(value);
|
|
563
|
+
const kept = value === null ? null : storedGroupValue(value);
|
|
564
|
+
if (kept !== undefined) {
|
|
565
|
+
groups[id] = kept;
|
|
566
|
+
}
|
|
567
|
+
});
|
|
568
|
+
return groups;
|
|
569
|
+
}
|
|
570
|
+
// A stored group value, read for the one type its keys belong to (an empty
|
|
571
|
+
// value fits every type), or undefined when it fits none.
|
|
572
|
+
function storedGroupValue(value) {
|
|
573
|
+
if (!isPlainObject(value)) {
|
|
574
|
+
return undefined;
|
|
575
|
+
}
|
|
576
|
+
const keys = Object.keys(value);
|
|
577
|
+
const type = Object.keys(GROUP_VALUE_KEYS)
|
|
578
|
+
.find((candidate) => keys.every((key) => GROUP_VALUE_KEYS[candidate].includes(key)));
|
|
579
|
+
return type ? (groupValueFromStored(value, type) ?? undefined) : undefined;
|
|
580
|
+
}
|
|
581
|
+
function requirePickCount(value) {
|
|
582
|
+
const lists = isPlainObject(value) ? [value.values, value.excludeValues] : [];
|
|
583
|
+
if (lists.some((list) => Array.isArray(list) && list.length > GROUP_VALUE_MAX_PICKS)) {
|
|
584
|
+
throw new Error(`A group value holds at most ${GROUP_VALUE_MAX_PICKS} values.`);
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
// Component id -> tile state.
|
|
588
|
+
function viewTiles(raw) {
|
|
589
|
+
const entries = Object.entries(requireObject(raw, 'tiles must map component ids to tile states.'));
|
|
590
|
+
if (entries.length > VIEW_CONFIG_MAX_TILES) {
|
|
591
|
+
throw new Error(`A view holds at most ${VIEW_CONFIG_MAX_TILES} tiles.`);
|
|
592
|
+
}
|
|
593
|
+
const tiles = {};
|
|
594
|
+
entries.forEach(([key, value]) => {
|
|
595
|
+
tiles[requireIdKey(key, 'tiles')] = viewTile(value);
|
|
596
|
+
});
|
|
597
|
+
return tiles;
|
|
598
|
+
}
|
|
599
|
+
function viewTile(raw) {
|
|
600
|
+
const tile = requireObject(raw, 'A tile state must be an object.');
|
|
601
|
+
const state = otherKeys(tile, TILE_STATE_KEYS);
|
|
602
|
+
if (isSet(tile.sort)) {
|
|
603
|
+
state.sort = viewSort(tile.sort);
|
|
604
|
+
}
|
|
605
|
+
if (isSet(tile.search)) {
|
|
606
|
+
state.search = requireString(tile.search, 'search must be text.');
|
|
607
|
+
}
|
|
608
|
+
if (isSet(tile.hidden)) {
|
|
609
|
+
state.hidden = viewHidden(tile.hidden);
|
|
610
|
+
}
|
|
611
|
+
if (isSet(tile.drill)) {
|
|
612
|
+
state.drill = viewDrill(tile.drill);
|
|
613
|
+
}
|
|
614
|
+
return state;
|
|
615
|
+
}
|
|
616
|
+
function viewSort(raw) {
|
|
617
|
+
const sort = requireObject(raw, 'sort must be a column and a direction.');
|
|
618
|
+
const column = requireString(sort.column, 'sort must name a column.');
|
|
619
|
+
if (column === '' || (isSet(sort.direction) && sort.direction !== 'asc' && sort.direction !== 'desc')) {
|
|
620
|
+
throw new Error('sort must be a column and a direction.');
|
|
621
|
+
}
|
|
622
|
+
return sort.direction ? { column, direction: sort.direction } : { column };
|
|
623
|
+
}
|
|
624
|
+
function viewHidden(raw) {
|
|
625
|
+
if (!Array.isArray(raw) || raw.some((name) => typeof name !== 'string')) {
|
|
626
|
+
throw new Error('hidden must list column names.');
|
|
627
|
+
}
|
|
628
|
+
return [...raw];
|
|
629
|
+
}
|
|
630
|
+
function viewDrill(raw) {
|
|
631
|
+
if (!Array.isArray(raw)) {
|
|
632
|
+
throw new Error('drill must list steps.');
|
|
633
|
+
}
|
|
634
|
+
if (raw.length > DRILL_MAX_DEPTH) {
|
|
635
|
+
throw new Error(`A drill path holds at most ${DRILL_MAX_DEPTH} steps.`);
|
|
636
|
+
}
|
|
637
|
+
return raw.map((step) => {
|
|
638
|
+
if (!isPlainObject(step) || !isChartGranularity(step.level) || !isDrillValue(step.value)) {
|
|
639
|
+
throw new Error('A drill step needs a time level and a value.');
|
|
640
|
+
}
|
|
641
|
+
return { level: step.level, value: step.value };
|
|
642
|
+
});
|
|
643
|
+
}
|
|
644
|
+
function isDrillValue(value) {
|
|
645
|
+
return value === null || typeof value === 'string' || typeof value === 'number';
|
|
646
|
+
}
|
|
647
|
+
// The keys of `source` that are not in `known`, as they were.
|
|
648
|
+
function otherKeys(source, known) {
|
|
649
|
+
return Object.fromEntries(Object.entries(source).filter(([key]) => !known.includes(key)));
|
|
650
|
+
}
|
|
651
|
+
function optionalId(raw, refusal) {
|
|
652
|
+
if (!isSet(raw)) {
|
|
653
|
+
return null;
|
|
654
|
+
}
|
|
655
|
+
if (!Number.isInteger(raw) || raw < 1) {
|
|
656
|
+
throw new Error(refusal);
|
|
657
|
+
}
|
|
658
|
+
return raw;
|
|
659
|
+
}
|
|
660
|
+
function requireIdKey(key, where) {
|
|
661
|
+
if (!ID_KEY_PATTERN.test(key)) {
|
|
662
|
+
throw new Error(`${where} are keyed by id, not by '${key}'.`);
|
|
663
|
+
}
|
|
664
|
+
return Number(key);
|
|
665
|
+
}
|
|
666
|
+
function requireGranularity(raw, refusal) {
|
|
667
|
+
if (!isChartGranularity(raw)) {
|
|
668
|
+
throw new Error(refusal);
|
|
669
|
+
}
|
|
670
|
+
return raw;
|
|
671
|
+
}
|
|
672
|
+
function requireString(raw, refusal) {
|
|
673
|
+
if (typeof raw !== 'string') {
|
|
674
|
+
throw new Error(refusal);
|
|
675
|
+
}
|
|
676
|
+
return raw;
|
|
677
|
+
}
|
|
678
|
+
function requireObject(raw, refusal) {
|
|
679
|
+
if (!isPlainObject(raw)) {
|
|
680
|
+
throw new Error(refusal);
|
|
681
|
+
}
|
|
682
|
+
return raw;
|
|
683
|
+
}
|
|
684
|
+
function isSet(value) {
|
|
685
|
+
return value !== undefined && value !== null;
|
|
686
|
+
}
|
|
687
|
+
function isPlainObject(value) {
|
|
688
|
+
return value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
689
|
+
}
|
|
690
|
+
function isScalar(value) {
|
|
691
|
+
return typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean';
|
|
692
|
+
}
|
|
693
|
+
// Only the parts that hold something.
|
|
694
|
+
function compact(value) {
|
|
695
|
+
return Object.fromEntries(Object.entries(value).filter(([, part]) => isSet(part)));
|
|
696
|
+
}
|
|
697
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVwb3J0LXZpZXctY29uZmlnLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL2FwcC9yZXBvcnRzL3JlcG9ydC12aWV3LWNvbmZpZy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUEwQkEsT0FBTyxFQUlMLG1CQUFtQixHQUlwQixNQUFNLCtCQUErQixDQUFDO0FBQ3ZDLE9BQU8sRUFBRSxlQUFlLEVBQUUsYUFBYSxFQUFFLE1BQU0sdUJBQXVCLENBQUM7QUFHdkUsNENBQTRDO0FBQzVDLE1BQU0sQ0FBQyxNQUFNLDBCQUEwQixHQUFHLENBQUMsQ0FBQztBQUU1Qyw2Q0FBNkM7QUFDN0MsTUFBTSxDQUFDLE1BQU0scUJBQXFCLEdBQUcsRUFBRSxHQUFHLElBQUksQ0FBQztBQUMvQyxNQUFNLENBQUMsTUFBTSxzQkFBc0IsR0FBRyxHQUFHLENBQUM7QUFDMUMsTUFBTSxDQUFDLE1BQU0scUJBQXFCLEdBQUcsR0FBRyxDQUFDO0FBQ3pDLE1BQU0sQ0FBQyxNQUFNLHFCQUFxQixHQUFHLEdBQUcsQ0FBQztBQUN6QyxNQUFNLENBQUMsTUFBTSxlQUFlLEdBQUcsQ0FBQyxDQUFDO0FBRWpDLDRFQUE0RTtBQUM1RSwwRUFBMEU7QUFDMUUsb0JBQW9CO0FBQ3BCLE1BQU0sZUFBZSxHQUFzQztJQUN6RCxRQUFRLEVBQUUsSUFBSTtJQUNkLFFBQVEsRUFBRSxJQUFJO0lBQ2QsU0FBUyxFQUFFLElBQUk7SUFDZixVQUFVLEVBQUUsSUFBSTtJQUNoQixXQUFXLEVBQUUsSUFBSTtJQUNqQixXQUFXLEVBQUUsSUFBSTtJQUNqQixZQUFZLEVBQUUsSUFBSTtJQUNsQixTQUFTLEVBQUUsSUFBSTtJQUNmLFdBQVcsRUFBRSxJQUFJO0lBQ2pCLFFBQVEsRUFBRSxJQUFJO0lBQ2QsVUFBVSxFQUFFLElBQUk7Q0FDakIsQ0FBQztBQUVGLHlFQUF5RTtBQUN6RSxvREFBb0Q7QUFDcEQsTUFBTSxDQUFDLE1BQU0sb0JBQW9CLEdBQUcsTUFBTSxD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QztBQUM5RSxDQUFDO0FBRUQsU0FBUyxRQUFRLENBQUMsS0FBYztJQUM5QixPQUFPLE9BQU8sS0FBSyxLQUFLLFFBQVEsSUFBSSxPQUFPLEtBQUssS0FBSyxRQUFRLElBQUksT0FBTyxLQUFLLEtBQUssU0FBUyxDQUFDO0FBQzlGLENBQUM7QUFFRCxzQ0FBc0M7QUFDdEMsU0FBUyxPQUFPLENBQUMsS0FBOEI7SUFDN0MsT0FBTyxNQUFNLENBQUMsV0FBVyxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxFQUFFLElBQUksQ0FBQyxFQUFFLEVBQUUsQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBdUIsQ0FBQztBQUMzRyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gVGhlIHZpZXdlcidzIGR1cmFibGUgc3RhdGUgYXMgb25lIGRvY3VtZW50IChSZXBvcnRWaWV3Q29uZmlnLCB2ZXJzaW9uIDEpOiBhXG4vLyBzYXZlZCB2aWV3J3MgY29uZmlnLCBhbmQgd2hhdCBhIHJlcG9ydCBsaW5rIGNhcnJpZXMgKHJlcG9ydC11cmwtc3RhdGUudHMpLlxuLy8gUHVyZSwgc28gdGhlIG5vZGUgaGFybmVzcyBydW5zIGl0IGFnYWluc3QgdGhlIHNlcnZlcidzIG93biBjYXNlIHRhYmxlOiB0aGVcbi8vIHJ1bGVzIGJlbG93IG1pcnJvciB0aGUgc2VydmVyJ3MgUmVwb3J0Vmlld0NvbmZpZyBhbmQgUmVwb3J0RmlsdGVyR3JvdXBWYWx1ZVxuLy8gRFRPcywgYW5kIHRoZSB0d28gbXVzdCBhZ3JlZSBvbiBldmVyeSBjYXNlLlxuLy9cbi8vIC0gQSBncm91cCB2YWx1ZSB0YWtlcyB0aGUga2V5cyBpdHMgZ3JvdXAncyB0eXBlIG93bnMgKGdyb3VwVmFsdWVGcm9tQXJyYXkpLlxuLy8gICBPbmUgd3JpdHRlbiBpbiBhIHNoYXBlIHRoYXQgZG9lcyBub3QgZml0IGlzIHJlZnVzZWQsIG5hbWluZyB3aGF0IGlzXG4vLyAgIHdyb25nOyBvbmUgcmVhZCBiYWNrIHRoYXQgZG9lcyBub3QgZml0IGlzIGRyb3BwZWQgd2hvbGUsIG5ldmVyIGFwcGxpZWQgaW5cbi8vICAgcGFydCAoZ3JvdXBWYWx1ZUZyb21TdG9yZWQpLlxuLy8gLSBBIGRvY3VtZW50ICh2aWV3Q29uZmlnRnJvbUFycmF5KSBpcyByZWZ1c2VkIHdoZW4gaXQgaXMgbm90IG9uZSwgYnJlYWtzIGFcbi8vICAgY2FwIG9yIGhvbGRzIGEgbWFsZm9ybWVkIGtub3duIGtleS4gS2V5cyB0aGlzIHZpZXdlciBkb2VzIG5vdCBrbm93LCBhdFxuLy8gICB0aGUgdG9wIGFuZCBpbiBhIHRpbGUsIGFyZSBrZXB0IGFzIHRoZXkgd2VyZSBhbmQgbmV2ZXIgcmVhZC4gQSBncm91cFxuLy8gICB2YWx1ZSB0aGF0IG5vIGdyb3VwIHR5cGUgY291bGQgaG9sZCBpcyBkcm9wcGVkIHdob2xlLlxuLy8gLSBUaGUgdmlld2VyJ3Mgc3RhdGUgc2VydmljZSB0dXJucyBpdHMgdmFsdWVzIGludG8gdGhpcyBzaGFwZSBhbmQgYmFja1xuLy8gICAodG9TdG9yZWRHcm91cFZhbHVlLCB0b0xpdmVHcm91cFZhbHVlKSwgYW5kIGFza3Mgdmlld0RpZmZlcnMgd2hldGhlciB0aGVcbi8vICAgc2NyZWVuIHN0aWxsIHNob3dzIHRoZSBvcGVuIHZpZXcuXG4vLyAtIFRoZSB2aWV3IHNlcnZpY2UgKFJlcG9ydFZpZXdTZXJ2aWNlKSB3cml0ZXMgYSBsaW5rIGFzIHZpZXdDb25maWdEaWZmLFxuLy8gICBzYXZlcyBhIHZpZXcgdGhyb3VnaCB3aXRoU3RvcmVkS2V5cyBhbmQgY291bnRzIHdoYXQgYSB2aWV3IGxvc3QgdGhyb3VnaFxuLy8gICB2aWV3RHJvcHBlZENvdW50OyB0aGUgY2hhdCBuYW1lcyB0aGUgb3BlbiB2aWV3IHRocm91Z2ggY2hhdFZpZXdGaWVsZHMuXG5pbXBvcnQgeyBSZXBvcnRDaGF0Vmlld2VyU3RhdGUgfSBmcm9tICcuL2ludGVyZmFjZXMvcmVwb3J0LWNoYXQtdmlld2VyLXN0YXRlLmludGVyZmFjZSc7XG5pbXBvcnQgeyBSZXBvcnREcmlsbFN0ZXAgfSBmcm9tICcuL2ludGVyZmFjZXMvcmVwb3J0LWRyaWxsLXN0ZXAuaW50ZXJmYWNlJztcbmltcG9ydCB7IFJlcG9ydFRpbGVTdGF0ZSB9IGZyb20gJy4vaW50ZXJmYWNlcy9yZXBvcnQtdGlsZS1zdGF0ZS5pbnRlcmZhY2UnO1xuaW1wb3J0IHsgUmVwb3J0Vmlld0NvbmZpZyB9IGZyb20gJy4vaW50ZXJmYWNlcy9yZXBvcnQtdmlldy1jb25maWcuaW50ZXJmYWNlJztcbmltcG9ydCB7IFJlcG9ydFZpZXdTdW1tYXJ5IH0gZnJvbSAnLi9pbnRlcmZhY2VzL3JlcG9ydC12aWV3LXN1bW1hcnkuaW50ZXJmYWNlJztcbmltcG9ydCB7IFJlcG9ydFZpZXcgfSBmcm9tICcuL2ludGVyZmFjZXMvcmVwb3J0LXZpZXcuaW50ZXJmYWNlJztcbmltcG9ydCB7XG4gIENoYXJ0R3JhbnVsYXJpdHksXG4gIEZpbHRlckdyb3VwRGVmYXVsdCxcbiAgRmlsdGVyR3JvdXBWYWx1ZSxcbiAgR1JBTlVMQVJJVFlfT1BUSU9OUyxcbiAgUmVwb3J0RmlsdGVyVHlwZSxcbiAgUmVwb3J0UmVsYXRpdmVSYW5nZSxcbiAgUmVwb3J0U29ydCxcbn0gZnJvbSAnLi9pbnRlcmZhY2VzL3JlcG9ydC5pbnRlcmZhY2UnO1xuaW1wb3J0IHsgZGF0ZUJvdW5kU3RyaW5nLCBkYXRlRnJvbUJvdW5kIH0gZnJvbSAnLi9yZXBvcnQtZmlsdGVyLWl0ZW1zJztcblxuXG4vLyBUaGUgdmVyc2lvbiB0aGlzIHZpZXdlciB3cml0ZXMgYW5kIHJlYWRzLlxuZXhwb3J0IGNvbnN0IFJFUE9SVF9WSUVXX0NPTkZJR19WRVJTSU9OID0gMTtcblxuLy8gVGhlIGNhcHMgb2YgYSB2aWV3IGRvY3VtZW50LCB0aGUgc2VydmVyJ3MuXG5leHBvcnQgY29uc3QgVklFV19DT05GSUdfTUFYX0JZVEVTID0gMzIgKiAxMDI0O1xuZXhwb3J0IGNvbnN0IFZJRVdfQ09ORklHX01BWF9HUk9VUFMgPSAxMDA7XG5leHBvcnQgY29uc3QgVklFV19DT05GSUdfTUFYX1RJTEVTID0gMjAwO1xuZXhwb3J0IGNvbnN0IEdST1VQX1ZBTFVFX01BWF9QSUNLUyA9IDUwMDtcbmV4cG9ydCBjb25zdCBEUklMTF9NQVhfREVQVEggPSA1O1xuXG4vLyBFdmVyeSByZWxhdGl2ZSByYW5nZSBuYW1lIHRoZSBzZXJ2ZXIga25vd3MsIGluIGl0cyBlbnVtJ3Mgb3JkZXIuIEEgcmVjb3JkXG4vLyByYXRoZXIgdGhhbiBhIGxpc3QsIHNvIHRoZSBidWlsZCBmYWlscyB3aGVuIFJlcG9ydFJlbGF0aXZlUmFuZ2UgZ2FpbnMgYVxuLy8gbmFtZSB0aGlzIG1pc3Nlcy5cbmNvbnN0IFJFTEFUSVZFX1JBTkdFUzogUmVjb3JkPFJlcG9ydFJlbGF0aXZlUmFuZ2UsIHRydWU+ID0ge1xuICB0aGlzV2VlazogdHJ1ZSxcbiAgbGFzdFdlZWs6IHRydWUsXG4gIGxhc3Q3RGF5czogdHJ1ZSxcbiAgbGFzdDMwRGF5czogdHJ1ZSxcbiAgbGFzdDNNb250aHM6IHRydWUsXG4gIGxhc3Q2TW9udGhzOiB0cnVlLFxuICBsYXN0MTJNb250aHM6IHRydWUsXG4gIHRoaXNNb250aDogdHJ1ZSxcbiAgdGhpc1F1YXJ0ZXI6IHRydWUsXG4gIHRoaXNZZWFyOiB0cnVlLFxuICB5ZWFyVG9EYXRlOiB0cnVlLFxufTtcblxuLy8gVGhlIHNhbWUgbmFtZXMgYXMgYSBsaXN0LCBpbiB0aGUgc2VydmVyIGVudW0ncyBvcmRlciAodGhlIHJlY29yZCdzIGtleVxuLy8gb3JkZXIpOiB0aGUgb3JkZXIgdGhlIGRhdGUgcGlja2VyIG9mZmVycyB0aGVtIGluLlxuZXhwb3J0IGNvbnN0IFJFTEFUSVZFX1JBTkdFX05BTUVTID0gT2JqZWN0LmtleXMoUkVMQVRJVkVfUkFOR0VTKSBhcyBSZXBvcnRSZWxhdGl2ZVJhbmdlW107XG5cbi8vIFRoZSBrZXlzIGEgZ3JvdXAgdmFsdWUgbWF5IGhvbGQsIGJ5IGl0cyBncm91cCdzIHR5cGUuXG5jb25zdCBHUk9VUF9WQUxVRV9LRVlTOiBSZWNvcmQ8UmVwb3J0RmlsdGVyVHlwZSwgcmVhZG9ubHkgKGtleW9mIEZpbHRlckdyb3VwRGVmYXVsdClbXT4gPSB7XG4gIGRhdGVSYW5nZTogWydyZWxhdGl2ZScsICdzdGFydCcsICdlbmQnXSxcbiAgc2VsZWN0OiBbJ3ZhbHVlcycsICdleGNsdWRlVmFsdWVzJ10sXG4gIGtleXdvcmQ6IFsndmFsdWUnXSxcbiAgbnVtYmVyUmFuZ2U6IFsnbWluJywgJ21heCddLFxufTtcblxuLy8gVGhlIGtleXMgb2YgYSB2aWV3IGRvY3VtZW50IGFuZCBvZiBhIHRpbGUgc3RhdGUgdGhpcyB2aWV3ZXIgcmVhZHMuIEFueVxuLy8gb3RoZXIga2V5IGlzIGtlcHQgYXMgaXQgd2FzLlxuY29uc3QgVklFV19DT05GSUdfS0VZUyA9IFsndicsICdwYWdlSWQnLCAnZ3JvdXBCeScsICdtYXRjaCcsICdncm91cHMnLCAndGlsZXMnXTtcbmNvbnN0IFRJTEVfU1RBVEVfS0VZUyA9IFsnc29ydCcsICdzZWFyY2gnLCAnaGlkZGVuJywgJ2RyaWxsJ107XG5cbmNvbnN0IERBWV9QQVRURVJOID0gL14oXFxkezR9KS0oXFxkezJ9KS0oXFxkezJ9KSQvO1xuXG4vLyBBIG51bWJlciBhcyB0ZXh0OiB3aGF0IGEgbWFza2VkIGlucHV0IG9yIGEgbGluayBzZW5kcy5cbmNvbnN0IE5VTUJFUl9QQVRURVJOID0gL15bKy1dPyg/OlxcZCsoPzpcXC5cXGQqKT98XFwuXFxkKykoPzplWystXT9cXGQrKT8kL2k7XG5cbmNvbnN0IElEX0tFWV9QQVRURVJOID0gL15bMS05XVxcZCokLztcblxuXG4vLyBXaGV0aGVyIGEgbmFtZSBpcyBhIHJlbGF0aXZlIHJhbmdlIHRoZSBzZXJ2ZXIgcmVzb2x2ZXMuXG5leHBvcnQgZnVuY3Rpb24gaXNSZWxhdGl2ZVJhbmdlKG5hbWU6IHVua25vd24pOiBuYW1lIGlzIFJlcG9ydFJlbGF0aXZlUmFuZ2Uge1xuICByZXR1cm4gdHlwZW9mIG5hbWUgPT09ICdzdHJpbmcnICYmIE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChSRUxBVElWRV9SQU5HRVMsIG5hbWUpO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gaXNDaGFydEdyYW51bGFyaXR5KHZhbHVlOiB1bmtub3duKTogdmFsdWUgaXMgQ2hhcnRHcmFudWxhcml0eSB7XG4gIHJldHVybiBHUkFOVUxBUklUWV9PUFRJT05TLnNvbWUoKG9wdGlvbikgPT4gb3B0aW9uLnZhbHVlID09PSB2YWx1ZSk7XG59XG5cbi8vIFdoZXRoZXIgdGV4dCBpcyBhIHJlYWwgY2FsZW5kYXIgZGF5IHdyaXR0ZW4gJ3l5eXktTU0tZGQnIChubyAyMDI2LTAyLTMwKS5cbmV4cG9ydCBmdW5jdGlvbiBpc0NhbGVuZGFyRGF5KHRleHQ6IHN0cmluZyk6IGJvb2xlYW4ge1xuICBjb25zdCBwYXJ0cyA9IERBWV9QQVRURVJOLmV4ZWModGV4dCk7XG4gIGlmICghcGFydHMpIHtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cblxuICBjb25zdCBbeWVhciwgbW9udGgsIGRheV0gPSBwYXJ0cy5zbGljZSgxKS5tYXAoTnVtYmVyKTtcbiAgY29uc3QgZGF0ZSA9IG5ldyBEYXRlKERhdGUuVVRDKHllYXIsIG1vbnRoIC0gMSwgZGF5KSk7XG5cbiAgcmV0dXJuIGRhdGUuZ2V0VVRDRnVsbFllYXIoKSA9PT0geWVhciAmJiBkYXRlLmdldFVUQ01vbnRoKCkgPT09IG1vbnRoIC0gMSAmJiBkYXRlLmdldFVUQ0RhdGUoKSA9PT0gZGF5O1xufVxuXG4vLyBBIG51bWJlciB3cml0dGVuIGFzIHRleHQgKGEgbGluaydzIHJhbmdlIGVuZCwgYSBtYXNrZWQgaW5wdXQncyB2YWx1ZSksIG9yXG4vLyBudWxsIHdoZW4gdGhlIHRleHQgaXMgbm90IG9uZSBmaW5pdGUgbnVtYmVyLlxuZXhwb3J0IGZ1bmN0aW9uIG51bWJlckZyb21UZXh0KHRleHQ6IHN0cmluZyk6IG51bWJlciB8IG51bGwge1xuICBjb25zdCBudW1iZXIgPSBOVU1CRVJfUEFUVEVSTi50ZXN0KHRleHQpID8gTnVtYmVyKHRleHQpIDogTmFOO1xuXG4gIHJldHVybiBOdW1iZXIuaXNGaW5pdGUobnVtYmVyKSA/IG51bWJlciA6IG51bGw7XG59XG5cbi8vIEEgZ3JvdXAgdmFsdWUgcmVhZCBmb3IgYSBncm91cCBvZiBgdHlwZWAsIG9uIGl0cyB3YXkgdG8gYmVpbmcgc3RvcmVkOiBvbmx5XG4vLyB0aGUgcGFydHMgdGhhdCBob2xkIHNvbWV0aGluZy4gVGhyb3dzLCBuYW1pbmcgd2hhdCBpcyB3cm9uZywgd2hlbiBhIGtleVxuLy8gZG9lcyBub3QgYmVsb25nIHRvIHRoZSB0eXBlIG9yIGEgcGFydCBicmVha3MgaXRzIHR5cGUncyBydWxlLlxuZXhwb3J0IGZ1bmN0aW9uIGdyb3VwVmFsdWVGcm9tQXJyYXkodmFsdWU6IFJlY29yZDxzdHJpbmcsIHVua25vd24+LCB0eXBlOiBSZXBvcnRGaWx0ZXJUeXBlKTogRmlsdGVyR3JvdXBEZWZhdWx0IHtcbiAgcmVxdWlyZUdyb3VwS2V5cyh2YWx1ZSwgdHlwZSk7XG5cbiAgc3dpdGNoICh0eXBlKSB7XG4gICAgY2FzZSAnZGF0ZVJhbmdlJzpcbiAgICAgIHJldHVybiBkYXRlUmFuZ2VWYWx1ZSh2YWx1ZSk7XG5cbiAgICBjYXNlICdzZWxlY3QnOlxuICAgICAgcmV0dXJuIHNlbGVjdFZhbHVlKHZhbHVlKTtcblxuICAgIGNhc2UgJ251bWJlclJhbmdlJzpcbiAgICAgIHJldHVybiBudW1iZXJSYW5nZVZhbHVlKHZhbHVlKTtcblxuICAgIGRlZmF1bHQ6XG4gICAgICByZXR1cm4ga2V5d29yZFZhbHVlKHZhbHVlKTtcbiAgfVxufVxuXG4vLyBBIGdyb3VwIHZhbHVlIHJlYWQgYmFjayAoYSBzYXZlZCB2aWV3LCBhIGxpbmspIGZvciBhIGdyb3VwIG9mIGB0eXBlYDogd2hhdFxuLy8gZ3JvdXBWYWx1ZUZyb21BcnJheSBnaXZlcywgb3IgbnVsbCB3aGVuIGl0IHdvdWxkIHJlZnVzZSBpdC5cbmV4cG9ydCBmdW5jdGlvbiBncm91cFZhbHVlRnJvbVN0b3JlZCh2YWx1ZTogdW5rbm93biwgdHlwZTogUmVwb3J0RmlsdGVyVHlwZSk6IEZpbHRlckdyb3VwRGVmYXVsdCB8IG51bGwge1xuICBpZiAoIWlzUGxhaW5PYmplY3QodmFsdWUpKSB7XG4gICAgcmV0dXJuIG51bGw7XG4gIH1cblxuICB0cnkge1xuICAgIHJldHVybiBncm91cFZhbHVlRnJvbUFycmF5KHZhbHVlLCB0eXBlKTtcbiAgfSBjYXRjaCB7XG4gICAgcmV0dXJuIG51bGw7XG4gIH1cbn1cblxuLy8gQSB2aWV3IGRvY3VtZW50IHJlYWQgZm9yIHN0b3Jpbmcgb3IgYXBwbHlpbmcuIFRocm93cyB3aGVuIGl0IGlzIG5vdCBhXG4vLyB2ZXJzaW9uIDEgZG9jdW1lbnQsIGJyZWFrcyBhIGNhcCBvciBob2xkcyBhIG1hbGZvcm1lZCBrbm93biBrZXkuXG5leHBvcnQgZnVuY3Rpb24gdmlld0NvbmZpZ0Zyb21BcnJheShpbnB1dDogdW5rbm93bik6IFJlcG9ydFZpZXdDb25maWcge1xuICBjb25zdCBkb2MgPSByZXF1aXJlT2JqZWN0KGlucHV0LCAnQSB2aWV3IGNvbmZpZyBtdXN0IGJlIGFuIG9iamVjdC4nKTtcbiAgcmVxdWlyZVNpemUoZG9jKTtcbiAgcmVxdWlyZVZlcnNpb24oZG9jLnYpO1xuXG4gIGNvbnN0IGNvbmZpZyA9IHsgdjogUkVQT1JUX1ZJRVdfQ09ORklHX1ZFUlNJT04sIC4uLm90aGVyS2V5cyhkb2MsIFZJRVdfQ09ORklHX0tFWVMpIH0gYXMgUmVwb3J0Vmlld0NvbmZpZztcbiAgY29uc3QgcGFnZUlkID0gb3B0aW9uYWxJZChkb2MucGFnZUlkLCAncGFnZUlkIG11c3QgYmUgYSBwYWdlIGlkLicpO1xuICBpZiAocGFnZUlkICE9PSBudWxsKSB7XG4gICAgY29uZmlnLnBhZ2VJZCA9IHBhZ2VJZDtcbiAgfVxuXG4gIGlmIChpc1NldChkb2MuZ3JvdXBCeSkpIHtcbiAgICBjb25maWcuZ3JvdXBCeSA9IHJlcXVpcmVHcmFudWxhcml0eShkb2MuZ3JvdXBCeSwgJ2dyb3VwQnkgbXVzdCBiZSBhIHRpbWUgZ3JhaW4uJyk7XG4gIH1cblxuICBpZiAoaXNTZXQoZG9jLm1hdGNoKSkge1xuICAgIGNvbmZpZy5tYXRjaCA9IHJlcXVpcmVNYXRjaChkb2MubWF0Y2gpO1xuICB9XG5cbiAgaWYgKGlzU2V0KGRvYy5ncm91cHMpKSB7XG4gICAgY29uZmlnLmdyb3VwcyA9IHZpZXdHcm91cHMoZG9jLmdyb3Vwcyk7XG4gIH1cblxuICBpZiAoaXNTZXQoZG9jLnRpbGVzKSkge1xuICAgIGNvbmZpZy50aWxlcyA9IHZpZXdUaWxlcyhkb2MudGlsZXMpO1xuICB9XG5cbiAgcmV0dXJuIGNvbmZpZztcbn1cblxuLy8gQSBncm91cCdzIHZhbHVlIGFzIGEgdmlldyBvciBhIGxpbmsgc3RvcmVzIGl0LCByZWFkIGZvciB0aGUga2V5cyBpdHNcbi8vIGdyb3VwJ3MgdHlwZSBvd25zLCBvciBudWxsIHdoZW4gaXQgaG9sZHMgbm90aGluZy4gQSBkYXRlIHJhbmdlIHRoYXQgc3RpbGxcbi8vIGNhcnJpZXMgaXRzIHJlbGF0aXZlIHByZXNldCBpcyBzdG9yZWQgYXMgdGhhdCBwcmVzZXQgd2hhdGV2ZXIgdG9kYXkgaXM6IHRoZVxuLy8gdmlld2VyIGRpZCBub3QgZWRpdCBpdCwgc28gYSB2aWV3IHNhdmVkIGFmdGVyIG1pZG5pZ2h0IHdpdGggdGhlIHBhZ2Ugc3RpbGxcbi8vIG9wZW4ga2VlcHMgcm9sbGluZy5cbmV4cG9ydCBmdW5jdGlvbiB0b1N0b3JlZEdyb3VwVmFsdWUoXG4gIHR5cGU6IFJlcG9ydEZpbHRlclR5cGUsXG4gIHZhbHVlOiBGaWx0ZXJHcm91cFZhbHVlIHwgbnVsbCB8IHVuZGVmaW5lZCxcbik6IEZpbHRlckdyb3VwRGVmYXVsdCB8IG51bGwge1xuICBpZiAoIXZhbHVlKSB7XG4gICAgcmV0dXJuIG51bGw7XG4gIH1cblxuICBzd2l0Y2ggKHR5cGUpIHtcbiAgICBjYXNlICdkYXRlUmFuZ2UnOlxuICAgICAgcmV0dXJuIGlzUmVsYXRpdmVSYW5nZSh2YWx1ZS5wcmVzZXQpXG4gICAgICAgID8geyByZWxhdGl2ZTogdmFsdWUucHJlc2V0IH1cbiAgICAgICAgOiBzdG9yZWRPck51bGwoeyBzdGFydDogZGF0ZUJvdW5kU3RyaW5nKHZhbHVlLnN0YXJ0KSwgZW5kOiBkYXRlQm91bmRTdHJpbmcodmFsdWUuZW5kKSB9KTtcblxuICAgIGNhc2UgJ3NlbGVjdCc6IHtcbiAgICAgIGNvbnN0IGV4Y2x1ZGVWYWx1ZXMgPSBrZXB0UGlja3ModmFsdWUuZXhjbHVkZVZhbHVlcyk7XG5cbiAgICAgIHJldHVybiBzdG9yZWRPck51bGwoZXhjbHVkZVZhbHVlcyA/IHsgZXhjbHVkZVZhbHVlcyB9IDogeyB2YWx1ZXM6IGtlcHRQaWNrcyh2YWx1ZS52YWx1ZXMpIH0pO1xuICAgIH1cblxuICAgIGNhc2UgJ251bWJlclJhbmdlJzpcbiAgICAgIHJldHVybiBzdG9yZWRPck51bGwoeyBtaW46IGZpbml0ZU51bWJlcih2YWx1ZS5taW4pLCBtYXg6IGZpbml0ZU51bWJlcih2YWx1ZS5tYXgpIH0pO1xuXG4gICAgZGVmYXVsdDpcbiAgICAgIHJldHVybiBzdG9yZWRPck51bGwoeyB2YWx1ZTogdmFsdWUudmFsdWU/LnRyaW0oKSB8fCB1bmRlZmluZWQgfSk7XG4gIH1cbn1cblxuLy8gQSBncm91cCB2YWx1ZSBpbiBpdHMgc3RvcmVkIHNoYXBlIGFzIHRoZSB2YWx1ZSB0aGUgYmFycyBhbmQgdGhlIHJlcXVlc3RzXG4vLyByZWFkOiBhIHJlbGF0aXZlIHByZXNldCBhcyB0b2RheSdzIGRheXMgaW4gdGhlIHJlcG9ydCdzIHpvbmUsIGNhcnJ5aW5nIGl0c1xuLy8gbmFtZTsgZml4ZWQgZGF5cyBhcyBkYXRlczsgYW55IG90aGVyIHZhbHVlIGFzIGl0IGlzLiBOdWxsIHdoZW4gaXQgaG9sZHNcbi8vIG5vdGhpbmcsIG9yIG5hbWVzIGEgcHJlc2V0IGByZXNvbHZlUmVsYXRpdmVgIGRvZXMgbm90IGtub3cuXG5leHBvcnQgZnVuY3Rpb24gdG9MaXZlR3JvdXBWYWx1ZShcbiAgdHlwZTogUmVwb3J0RmlsdGVyVHlwZSxcbiAgc3RvcmVkOiBGaWx0ZXJHcm91cERlZmF1bHQgfCBudWxsIHwgdW5kZWZpbmVkLFxuICByZXNvbHZlUmVsYXRpdmU6IChuYW1lOiBzdHJpbmcpID0+IHsgc3RhcnQ6IERhdGU7IGVuZDogRGF0ZSB9IHwgbnVsbCxcbik6IEZpbHRlckdyb3VwVmFsdWUgfCBudWxsIHtcbiAgaWYgKCFzdG9yZWQgfHwgaG9sZHNOb3RoaW5nKHN0b3JlZCkpIHtcbiAgICByZXR1cm4gbnVsbDtcbiAgfVxuXG4gIGlmICh0eXBlICE9PSAnZGF0ZVJhbmdlJykge1xuICAgIHJldHVybiB7IC4uLnN0b3JlZCB9O1xuICB9XG5cbiAgaWYgKHN0b3JlZC5yZWxhdGl2ZSkge1xuICAgIGNvbnN0IHJhbmdlID0gcmVzb2x2ZVJlbGF0aXZlKHN0b3JlZC5yZWxhdGl2ZSk7XG5cbiAgICByZXR1cm4gcmFuZ2UgPyB7IHN0YXJ0OiByYW5nZS5zdGFydCwgZW5kOiByYW5nZS5lbmQsIHByZXNldDogc3RvcmVkLnJlbGF0aXZlIH0gOiBudWxsO1xuICB9XG5cbiAgcmV0dXJuIHsgc3RhcnQ6IGRhdGVGcm9tQm91bmQoc3RvcmVkLnN0YXJ0KSwgZW5kOiBkYXRlRnJvbUJvdW5kKHN0b3JlZC5lbmQpIH07XG59XG5cbi8vIFdoZXRoZXIgdGhlIHNjcmVlbidzIHN0YXRlIGRpZmZlcnMgZnJvbSB0aGUgdmlldyBpdCBvcGVuZWQgb24uIGBjdXJyZW50YFxuLy8gaXMgYSBzbmFwc2hvdCwgc28gaXQgaG9sZHMgZXZlcnkgZ3JvdXAgdGhlIHJlcG9ydCBoYXM7IGEgZ3JvdXAgb25seSBgYmFzZWBcbi8vIGhvbGRzIGlzIG9uZSB0aGUgcmVwb3J0IG5vIGxvbmdlciBoYXMsIGFuZCBpcyBub3QgY29tcGFyZWQuIEEgZ3JvdXAgYGJhc2VgXG4vLyBkb2VzIG5vdCBob2xkIHdhcyBhZGRlZCBhZnRlciB0aGUgdmlldyB3YXMgc2F2ZWQ6IGl0IGlzIGNvbXBhcmVkIHdpdGggaXRzXG4vLyB2YWx1ZSBpbiBgYXV0aG9yZWRgICh0aGUgcmVwb3J0J3MgZGVmYXVsdHMpLCBzbyBsZWF2aW5nIGl0IGF0IGl0cyBkZWZhdWx0XG4vLyBjaGFuZ2VzIG5vdGhpbmcuIFRoZSBwYWdlIGlzIG5vdCBjb21wYXJlZCAobW92aW5nIHRvIGFub3RoZXIgcGFnZSBkb2VzIG5vdFxuLy8gZWRpdCBhIHZpZXcpLCBhbmQgbmVpdGhlciBhcmUga2V5cyB0aGlzIHZpZXdlciBkb2VzIG5vdCBrbm93LiBQaWNrcyBhcmVcbi8vIGNvbXBhcmVkIGluIGFueSBvcmRlci5cbmV4cG9ydCBmdW5jdGlvbiB2aWV3RGlmZmVycyhcbiAgYmFzZTogUmVwb3J0Vmlld0NvbmZpZyxcbiAgY3VycmVudDogUmVwb3J0Vmlld0NvbmZpZyxcbiAgYXV0aG9yZWQ6IFJlcG9ydFZpZXdDb25maWcgfCBudWxsID0gbnVsbCxcbik6IGJvb2xlYW4ge1xuICByZXR1cm4gKGJhc2UubWF0Y2ggPz8gJ2FsbCcpICE9PSAoY3VycmVudC5tYXRjaCA/PyAnYWxsJylcbiAgICB8fCAoYmFzZS5ncm91cEJ5ID8/IG51bGwpICE9PSAoY3VycmVudC5ncm91cEJ5ID8/IG51bGwpXG4gICAgfHwgZ3JvdXBzRGlmZmVyKGJhc2UsIGN1cnJlbnQsIGF1dGhvcmVkKVxuICAgIHx8IHRpbGVzRGlmZmVyKGJhc2UudGlsZXMgPz8ge30sIGN1cnJlbnQudGlsZXMgPz8ge30pO1xufVxuXG4vLyBXaGV0aGVyIHR3byBzdG9yZWQgZ3JvdXAgdmFsdWVzIGFyZSB0aGUgc2FtZSBmaWx0ZXIsIGFzIHZpZXdEaWZmZXJzIHJlYWRzXG4vLyBhIGdyb3VwOiBwaWNrcyBpbiBhbnkgb3JkZXIsIHRleHQgdHJpbW1lZCwgYW4gZW1wdHkgdmFsdWUgcmVhZCBhcyBub25lLlxuZXhwb3J0IGZ1bmN0aW9uIHNhbWVTdG9yZWRHcm91cFZhbHVlKFxuICBhOiBGaWx0ZXJHcm91cERlZmF1bHQgfCBudWxsIHwgdW5kZWZpbmVkLFxuICBiOiBGaWx0ZXJHcm91cERlZmF1bHQgfCBudWxsIHwgdW5kZWZpbmVkLFxuKTogYm9vbGVhbiB7XG4gIHJldHVybiBzdG9yZWRWYWx1ZUtleShhKSA9PT0gc3RvcmVkVmFsdWVLZXkoYik7XG59XG5cbi8vIEEgZHJpbGwgcGF0aCBrZXB0IHRvIHdoYXQgYSB0aWxlIGNhbiBjYXJyeTogaXRzIHN0ZXBzIHVwIHRvIHRoZSBmaXJzdCB0aGF0XG4vLyBpcyBub3QgYSB0aW1lIGxldmVsIHdpdGggYSBwbGFpbiB2YWx1ZSAodGhlIHN0ZXBzIGJlZm9yZSBpdCBhcmUga2VwdCksIGF0XG4vLyBtb3N0IERSSUxMX01BWF9ERVBUSCBvZiB0aGVtLlxuZXhwb3J0IGZ1bmN0aW9uIGNsZWFuRHJpbGxQYXRoKHBhdGg6IHJlYWRvbmx5IHVua25vd25bXSB8IG51bGwgfCB1bmRlZmluZWQpOiBSZXBvcnREcmlsbFN0ZXBbXSB7XG4gIGNvbnN0IGtlcHQ6IFJlcG9ydERyaWxsU3RlcFtdID0gW107XG5cbiAgZm9yIChjb25zdCBzdGVwIG9mIHBhdGggPz8gW10pIHtcbiAgICBpZiAoIWlzUGxhaW5PYmplY3Qoc3RlcCkgfHwgIWlzQ2hhcnRHcmFudWxhcml0eShzdGVwLmxldmVsKSB8fCAhaXNEcmlsbFZhbHVlKHN0ZXAudmFsdWUpXG4gICAgICB8fCBrZXB0Lmxlbmd0aCA9PT0gRFJJTExfTUFYX0RFUFRIKSB7XG4gICAgICBicmVhaztcbiAgICB9XG5cbiAgICBrZXB0LnB1c2goeyBsZXZlbDogc3RlcC5sZXZlbCwgdmFsdWU6IHN0ZXAudmFsdWUgfSk7XG4gIH1cblxuICByZXR1cm4ga2VwdDtcbn1cblxuLy8gV2hldGhlciB0d28gZHJpbGwgcGF0aHMgYXJlIHRoZSBzYW1lIHN0ZXBzLiBBIHZhbHVlIGlzIGNvbXBhcmVkIGFzIHRleHQsXG4vLyBzbyAyMDI2IGFuZCAnMjAyNicgYXJlIHRoZSBzYW1lIHN0ZXAuXG5leHBvcnQgZnVuY3Rpb24gc2FtZURyaWxsUGF0aChcbiAgYTogcmVhZG9ubHkgUmVwb3J0RHJpbGxTdGVwW10gfCBudWxsIHwgdW5kZWZpbmVkLFxuICBiOiByZWFkb25seSBSZXBvcnREcmlsbFN0ZXBbXSB8IG51bGwgfCB1bmRlZmluZWQsXG4pOiBib29sZWFuIHtcbiAgcmV0dXJuIGRyaWxsS2V5KGEpID09PSBkcmlsbEtleShiKTtcbn1cblxuLy8gV2hhdCBhIGxpbmsgbXVzdCBjYXJyeSBmb3IgdGhlIHNjcmVlbiAoYGN1cnJlbnRgLCBhIHNuYXBzaG90KSB0byBvcGVuIG9uXG4vLyBgYmFzZWA6IG9ubHkgd2hhdCBkaWZmZXJzIGZyb20gaXQuIEEgZ3JvdXAgYGJhc2VgIGRvZXMgbm90IGhvbGQgaXMgcmVhZFxuLy8gYWdhaW5zdCBgYXV0aG9yZWRgLCBhcyB2aWV3RGlmZmVycyByZWFkcyBpdC4gQSBrZXkgdGhhdCB3ZW50IGJhY2sgdG8gaXRzXG4vLyBhdXRob3JlZCBzdGF0ZSB3aGVyZSBgYmFzZWAgaG9sZHMgYW5vdGhlciBpcyB3cml0dGVuIGFzIHRoYXQgc3RhdGUgd2hlcmVcbi8vIGEgbGluayBjYW4gc2F5IGl0OiBhIGdyb3VwJ3MgdmFsdWUgKGFuIGVtcHR5IHZhbHVlIGNsZWFycyBpdCkgYW5kIGEgbGlzdCdzXG4vLyBzb3J0IChpdHMgYXV0aG9yZWQgZmlyc3QgdGVybSwgYGF1dGhvcmVkU29ydGApLiBUaGUgbWF0Y2ggYmFjayB0byAnYWxsJyxcbi8vIHRoZSBhdXRob3JlZCBncmFpbiwgYW4gZW1wdHkgc2VhcmNoLCBubyBoaWRkZW4gY29sdW1ucywgYSBjaGFydCdzIHRvcCBhbmRcbi8vIGEgbGlzdCB3aXRoIG5vIGF1dGhvcmVkIHNvcnQgY2Fubm90IGJlIHNhaWQgb24gdG9wIG9mIGEgYmFzZSwgc28gdGhlXG4vLyByZXN1bHQgaXMgbnVsbCBhbmQgdGhlIGNhbGxlciB3cml0ZXMgdGhlIGZ1bGwgZGlmZiBmcm9tIHRoZSBhdXRob3JlZFxuLy8gZGVmYXVsdHMgaW5zdGVhZCwgd2hpY2ggY2FuIGFsd2F5cyBiZSBzYWlkLiBUaGUgcGFnZSBpcyBuZXZlciBwYXJ0IG9mIGl0XG4vLyAodGhlIGhvc3Qgd3JpdGVzIGl0cyBvd24ga2V5KS5cbmV4cG9ydCBmdW5jdGlvbiB2aWV3Q29uZmlnRGlmZihcbiAgYmFzZTogUmVwb3J0Vmlld0NvbmZpZyxcbiAgY3VycmVudDogUmVwb3J0Vmlld0NvbmZpZyxcbiAgYXV0aG9yZWQ6IFJlcG9ydFZpZXdDb25maWcgfCBudWxsLFxuICBhdXRob3JlZFNvcnQ6IChjb21wb25lbnRJZDogbnVtYmVyKSA9PiBSZXBvcnRTb3J0IHwgbnVsbCxcbik6IFJlcG9ydFZpZXdDb25maWcgfCBudWxsIHtcbiAgY29uc3QgZGlmZjogUmVwb3J0Vmlld0NvbmZpZyA9IHsgdjogUkVQT1JUX1ZJRVdfQ09ORklHX1ZFUlNJT04gfTtcblxuICBpZiAoKGJhc2UubWF0Y2ggPz8gJ2FsbCcpICE9PSAoY3VycmVudC5tYXRjaCA/PyAnYWxsJykpIHtcbiAgICBpZiAoY3VycmVudC5tYXRjaCAhPT0gJ2FueScpIHtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cblxuICAgIGRpZmYubWF0Y2ggPSAnYW55JztcbiAgfVxuXG4gIGlmICgoYmFzZS5ncm91cEJ5ID8/IG51bGwpICE9PSAoY3VycmVudC5ncm91cEJ5ID8/IG51bGwpKSB7XG4gICAgaWYgKCFjdXJyZW50Lmdyb3VwQnkpIHtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cblxuICAgIGRpZmYuZ3JvdXBCeSA9IGN1cnJlbnQuZ3JvdXBCeTtcbiAgfVxuXG4gIGNvbnN0IGdyb3VwcyA9IGNoYW5nZWRHcm91cHMoYmFzZSwgY3VycmVudCwgYXV0aG9yZWQpO1xuICBpZiAoT2JqZWN0LmtleXMoZ3JvdXBzKS5sZW5ndGgpIHtcbiAgICBkaWZmLmdyb3VwcyA9IGdyb3VwcztcbiAgfVxuXG4gIGNvbnN0IHRpbGVzID0gY2hhbmdlZFRpbGVzKGJhc2UudGlsZXMgPz8ge30sIGN1cnJlbnQudGlsZXMgPz8ge30sIGF1dGhvcmVkU29ydCk7XG4gIGlmICghdGlsZXMpIHtcbiAgICByZXR1cm4gbnVsbDtcbiAgfVxuXG4gIGlmIChPYmplY3Qua2V5cyh0aWxlcykubGVuZ3RoKSB7XG4gICAgZGlmZi50aWxlcyA9IHRpbGVzO1xuICB9XG5cbiAgcmV0dXJuIGRpZmY7XG59XG5cbi8vIEEgdmlldydzIGNvbmZpZyB0byBzYXZlOiB0aGUgc2NyZWVuIChgc2NyZWVuYCwgYSBzbmFwc2hvdCksIHdpdGggdGhlIGtleXNcbi8vIHRoaXMgdmlld2VyIGRvZXMgbm90IGtub3cga2VwdCBmcm9tIHRoZSBzdG9yZWQgZG9jdW1lbnQgKGBzdG9yZWRgKSwgYXQgdGhlXG4vLyB0b3AgYW5kIGluIGVhY2ggdGlsZS4gVGhleSBhcmUgbmV2ZXIgcmVhZCBoZXJlLCBhbmQgc2F2aW5nIG11c3Qgbm90IGxvc2Vcbi8vIHRoZW0uXG5leHBvcnQgZnVuY3Rpb24gd2l0aFN0b3JlZEtleXMoc3RvcmVkOiBSZXBvcnRWaWV3Q29uZmlnIHwgbnVsbCB8IHVuZGVmaW5lZCwgc2NyZWVuOiBSZXBvcnRWaWV3Q29uZmlnKTogUmVwb3J0Vmlld0NvbmZpZyB7XG4gIGlmICghc3RvcmVkKSB7XG4gICAgcmV0dXJuIHNjcmVlbjtcbiAgfVxuXG4gIGNvbnN0IHRpbGVzOiBSZWNvcmQ8bnVtYmVyLCBSZXBvcnRUaWxlU3RhdGU+ID0geyAuLi5zY3JlZW4udGlsZXMgfTtcblxuICBPYmplY3QuZW50cmllcyhzdG9yZWQudGlsZXMgPz8ge30pLmZvckVhY2goKFtjb21wb25lbnRJZCwgdGlsZV0pID0+IHtcbiAgICBjb25zdCBrZXB0ID0gaXNQbGFpbk9iamVjdCh0aWxlKSA/IG90aGVyS2V5cyh0aWxlLCBUSUxFX1NUQVRFX0tFWVMpIDoge307XG5cbiAgICBpZiAoT2JqZWN0LmtleXMoa2VwdCkubGVuZ3RoKSB7XG4gICAgICB0aWxlc1tOdW1iZXIoY29tcG9uZW50SWQpXSA9IHsgLi4ua2VwdCwgLi4udGlsZXNbTnVtYmVyKGNvbXBvbmVudElkKV0gfTtcbiAgICB9XG4gIH0pO1xuXG4gIGNvbnN0IGNvbmZpZzogUmVwb3J0Vmlld0NvbmZpZyA9IHsgLi4ub3RoZXJLZXlzKHN0b3JlZCBhcyB1bmtub3duIGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+LCBWSUVXX0NPTkZJR19LRVlTKSwgLi4uc2NyZWVuIH07XG4gIGRlbGV0ZSBjb25maWcudGlsZXM7XG5cbiAgcmV0dXJuIE9iamVjdC5rZXlzKHRpbGVzKS5sZW5ndGggPyB7IC4uLmNvbmZpZywgdGlsZXMgfSA6IGNvbmZpZztcbn1cblxuLy8gSG93IG1hbnkgc2V0dGluZ3Mgb2YgYSBzYXZlZCB2aWV3IG5vIGxvbmdlciBhcHBseSBiZWNhdXNlIHRoZSByZXBvcnRcbi8vIGNoYW5nZWQ6IHdoYXQgdGhlIHNlcnZlciBsZWZ0IG91dCB3aGVuIGl0IHJlYWQgdGhlIHZpZXcgKGBkcm9wcGVkYCksIGFuZFxuLy8gd2hhdCB0aGUgdmlld2VyIGNvdWxkIG5vdCBhcHBseSAoYGFwcGxpZWRgIGlzIHRoZSB2aWV3IGFzIGl0IGFwcGxpZWQsIHRoZVxuLy8gc3RhdGUgc2VydmljZSdzIGJhc2UpOiBhIGdyb3VwIHZhbHVlIHRoYXQgbm8gbG9uZ2VyIGZpdHMgaXRzIGdyb3VwLCBhbmQgYVxuLy8gbGlzdCBzb3J0LCBzZWFyY2ggb3IgaGlkZGVuIGNvbHVtbnMsIG9yIGEgY2hhcnQncyBkcmlsbCBwYXRoLCBpdHMgdGlsZSBjYW5cbi8vIG5vIGxvbmdlciB0YWtlIChhIGxpc3QgY29sdW1uIGdvbmUsIGEgY2hhcnQgdHVybmVkIGludG8gYSBsaXN0KS5cbmV4cG9ydCBmdW5jdGlvbiB2aWV3RHJvcHBlZENvdW50KHZpZXc6IFBpY2s8UmVwb3J0VmlldywgJ2NvbmZpZycgfCAnZHJvcHBlZCc+LCBhcHBsaWVkOiBSZXBvcnRWaWV3Q29uZmlnKTogbnVtYmVyIHtcbiAgY29uc3QgZHJvcHBlZCA9IHZpZXcuZHJvcHBlZDtcbiAgY29uc3QgZ3JvdXBzID0gT2JqZWN0LmVudHJpZXModmlldy5jb25maWc/Lmdyb3VwcyA/PyB7fSlcbiAgICAuZmlsdGVyKChbZ3JvdXBJZCwgdmFsdWVdKSA9PiB2YWx1ZSAhPT0gbnVsbCAmJiAhT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKGFwcGxpZWQuZ3JvdXBzID8/IHt9LCBncm91cElkKSlcbiAgICAubGVuZ3RoO1xuICBjb25zdCB0aWxlcyA9IE9iamVjdC5lbnRyaWVzKHZpZXcuY29uZmlnPy50aWxlcyA/PyB7fSlcbiAgICAucmVkdWNlKChjb3VudCwgW2NvbXBvbmVudElkLCB0aWxlXSkgPT4gY291bnQgKyB0aWxlS2V5c0xvc3QodGlsZSwgYXBwbGllZC50aWxlcz8uW051bWJlcihjb21wb25lbnRJZCldKSwgMCk7XG5cbiAgcmV0dXJuIChkcm9wcGVkPy5ncm91cHM/Lmxlbmd0aCA/PyAwKSArIChkcm9wcGVkPy50aWxlcz8ubGVuZ3RoID8/IDApICsgKGRyb3BwZWQ/LnBhZ2UgPyAxIDogMCkgKyBncm91cHMgKyB0aWxlcztcbn1cblxuLy8gVGhlIG5vdGUgYSB2aWV3IG9wZW5zIHdpdGggd2hlbiBzb21lIG9mIGl0cyBzZXR0aW5ncyBubyBsb25nZXIgYXBwbHksIG9yXG4vLyBudWxsIHdoZW4gZXZlcnkgc2V0dGluZyBhcHBsaWVzLiBPbmx5IGEgdmlld2VyIHdobyBtYXkgY2hhbmdlIHRoZSB2aWV3XG4vLyAoYGNhbkNoYW5nZWApIGlzIHRvbGQgdG8gc2F2ZSBpdC5cbmV4cG9ydCBmdW5jdGlvbiB2aWV3RHJvcHBlZE1lc3NhZ2UoY291bnQ6IG51bWJlciwgY2FuQ2hhbmdlID0gdHJ1ZSk6IHN0cmluZyB8IG51bGwge1xuICBpZiAoY291bnQgPCAxKSB7XG4gICAgcmV0dXJuIG51bGw7XG4gIH1cblxuICBjb25zdCBub3RlID0gY291bnQgPT09IDFcbiAgICA/ICcxIHNldHRpbmcgaW4gdGhpcyB2aWV3IG5vIGxvbmdlciBhcHBsaWVzLCBiZWNhdXNlIHRoZSByZXBvcnQgY2hhbmdlZC4nXG4gICAgOiBgJHtjb3VudH0gc2V0dGluZ3MgaW4gdGhpcyB2aWV3IG5vIGxvbmdlciBhcHBseSwgYmVjYXVzZSB0aGUgcmVwb3J0IGNoYW5nZWQuYDtcblxuICByZXR1cm4gY2FuQ2hhbmdlID8gYCR7bm90ZX0gU2F2ZSBjaGFuZ2VzIHRvIHVwZGF0ZSB0aGUgdmlldy5gIDogbm90ZTtcbn1cblxuLy8gU2hvd24gd2hlbiBhIGxpbmsgbmFtZXMgYSB2aWV3IHRoZSB2aWV3ZXIgY2Fubm90IG9wZW4gKGRlbGV0ZWQsIG9yIGFub3RoZXJcbi8vIHBlcnNvbidzIG93biB2aWV3KTogdGhlIGxpbmsncyBvdGhlciBzZXR0aW5ncyBhcHBseSBvbiB0aGUgcmVwb3J0J3Ncbi8vIGRlZmF1bHRzLlxuZXhwb3J0IGNvbnN0IFZJRVdfTk9UX0FWQUlMQUJMRV9NRVNTQUdFID0gJ1RoZSB2aWV3IGluIHRoaXMgbGluayBpcyBub3QgYXZhaWxhYmxlLic7XG5cbi8vIFRoZSBvcGVuIHZpZXcgYXMgYSBjaGF0IHR1cm4gbmFtZXMgaXQ6IGl0cyBpZCwgYW5kIHdoZXRoZXIgdGhlIHNjcmVlblxuLy8gZGlmZmVycyBmcm9tIGl0LiBCb3RoIGFyZSBsZWZ0IG91dCB3aGlsZSBubyB2aWV3IGlzIG9wZW4uXG5leHBvcnQgZnVuY3Rpb24gY2hhdFZpZXdGaWVsZHMoXG4gIG9wZW5WaWV3OiBQaWNrPFJlcG9ydFZpZXdTdW1tYXJ5LCAnaWQnPiB8IG51bGwsXG4gIHZpZXdDaGFuZ2VkOiBib29sZWFuLFxuKTogUGljazxSZXBvcnRDaGF0Vmlld2VyU3RhdGUsICd2aWV3SWQnIHwgJ3ZpZXdDaGFuZ2VkJz4ge1xuICByZXR1cm4gb3BlblZpZXcgPyB7IHZpZXdJZDogb3BlblZpZXcuaWQsIHZpZXdDaGFuZ2VkIH0gOiB7fTtcbn1cblxuZnVuY3Rpb24gZ3JvdXBzRGlmZmVyKGJhc2U6IFJlcG9ydFZpZXdDb25maWcsIGN1cnJlbnQ6IFJlcG9ydFZpZXdDb25maWcsIGF1dGhvcmVkOiBSZXBvcnRWaWV3Q29uZmlnIHwgbnVsbCk6IGJvb2xlYW4ge1xuICByZXR1cm4gT2JqZWN0LmVudHJpZXMoY3VycmVudC5ncm91cHMgPz8ge30pLnNvbWUoKFtncm91cElkLCB2YWx1ZV0pID0+IHtcbiAgICBjb25zdCBrZXB0ID0gYmFzZS5ncm91cHMgJiYgT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKGJhc2UuZ3JvdXBzLCBncm91cElkKVxuICAgICAgPyBiYXNlLmdyb3Vwc1tOdW1iZXIoZ3JvdXBJZCldXG4gICAgICA6IGF1dGhvcmVkPy5ncm91cHM/LltOdW1iZXIoZ3JvdXBJZCldO1xuXG4gICAgcmV0dXJuIHN0b3JlZFZhbHVlS2V5KGtlcHQpICE9PSBzdG9yZWRWYWx1ZUtleSh2YWx1ZSk7XG4gIH0pO1xufVxuXG5mdW5jdGlvbiB0aWxlc0RpZmZlcihiYXNlOiBSZWNvcmQ8bnVtYmVyLCBSZXBvcnRUaWxlU3RhdGU+LCBjdXJyZW50OiBSZWNvcmQ8bnVtYmVyLCBSZXBvcnRUaWxlU3RhdGU+KTogYm9vbGVhbiB7XG4gIGNvbnN0IGlkcyA9IG5ldyBTZXQoWy4uLk9iamVjdC5rZXlzKGJhc2UpLCAuLi5PYmplY3Qua2V5cyhjdXJyZW50KV0ubWFwKE51bWJlcikpO1xuXG4gIHJldHVybiBbLi4uaWRzXS5zb21lKChjb21wb25lbnRJZCkgPT4gdGlsZVN0YXRlS2V5KGJhc2VbY29tcG9uZW50SWRdKSAhPT0gdGlsZVN0YXRlS2V5KGN1cnJlbnRbY29tcG9uZW50SWRdKSk7XG59XG5cbi8vIFRoZSBncm91cHMgd2hvc2UgdmFsdWUgb24gc2NyZWVuIGRpZmZlcnMgZnJvbSBiYXNlJ3MgKG9yLCBmb3IgYSBncm91cCBiYXNlXG4vLyBkb2VzIG5vdCBob2xkLCBmcm9tIHRoZSBhdXRob3JlZCBvbmUpLCBlYWNoIHdpdGggdGhlIHNjcmVlbidzIHZhbHVlOyBudWxsXG4vLyBmb3Igb25lIHRoYXQgaG9sZHMgbm90aGluZy5cbmZ1bmN0aW9uIGNoYW5nZWRHcm91cHMoXG4gIGJhc2U6IFJlcG9ydFZpZXdDb25maWcsXG4gIGN1cnJlbnQ6IFJlcG9ydFZpZXdDb25maWcsXG4gIGF1dGhvcmVkOiBSZXBvcnRWaWV3Q29uZmlnIHwgbnVsbCxcbik6IFJlY29yZDxudW1iZXIsIEZpbHRlckdyb3VwRGVmYXVsdCB8IG51bGw+IHtcbiAgcmV0dXJuIE9iamVjdC5mcm9tRW50cmllcyhPYmplY3QuZW50cmllcyhjdXJyZW50Lmdyb3VwcyA/PyB7fSlcbiAgICAuZmlsdGVyKChbZ3JvdXBJZCwgdmFsdWVdKSA9PiB7XG4gICAgICBjb25zdCBrZXB0ID0gYmFzZS5ncm91cHMgJiYgT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKGJhc2UuZ3JvdXBzLCBncm91cElkKVxuICAgICAgICA/IGJhc2UuZ3JvdXBzW051bWJlcihncm91cElkKV1cbiAgICAgICAgOiBhdXRob3JlZD8uZ3JvdXBzPy5bTnVtYmVyKGdyb3VwSWQpXTtcblxuICAgICAgcmV0dXJuIHN0b3JlZFZhbHVlS2V5KGtlcHQpICE9PSBzdG9yZWRWYWx1ZUtleSh2YWx1ZSk7XG4gICAgfSlcbiAgICAubWFwKChbZ3JvdXBJZCwgdmFsdWVdKSA9PiBbZ3JvdXBJZCwgdmFsdWUgPz8gbnVsbF0pKTtcbn1cblxuLy8gRWFjaCB0aWxlJ3Mga2V5cyB0aGF0IGRpZmZlciBmcm9tIGJhc2Uncywgb3IgbnVsbCB3aGVuIG9uZSBvZiB0aGVtIHdlbnRcbi8vIGJhY2sgdG8gYSBzdGF0ZSBhIGxpbmsgY2Fubm90IHNheSAoc2VlIHZpZXdDb25maWdEaWZmKS5cbmZ1bmN0aW9uIGNoYW5nZWRUaWxlcyhcbiAgYmFzZTogUmVjb3JkPG51bWJlciwgUmVwb3J0VGlsZVN0YXRlPixcbiAgY3VycmVudDogUmVjb3JkPG51bWJlciwgUmVwb3J0VGlsZVN0YXRlPixcbiAgYXV0aG9yZWRTb3J0OiAoY29tcG9uZW50SWQ6IG51bWJlcikgPT4gUmVwb3J0U29ydCB8IG51bGwsXG4pOiBSZWNvcmQ8bnVtYmVyLCBSZXBvcnRUaWxlU3RhdGU+IHwgbnVsbCB7XG4gIGNvbnN0IHRpbGVzOiBSZWNvcmQ8bnVtYmVyLCBSZXBvcnRUaWxlU3RhdGU+ID0ge307XG4gIGNvbnN0IGlkcyA9IG5ldyBTZXQoWy4uLk9iamVjdC5rZXlzKGJhc2UpLCAuLi5PYmplY3Qua2V5cyhjdXJyZW50KV0ubWFwKE51bWJlcikpO1xuXG4gIGZvciAoY29uc3QgY29tcG9uZW50SWQgb2YgaWRzKSB7XG4gICAgY29uc3QgdGlsZSA9IGNoYW5nZWRUaWxlKGJhc2VbY29tcG9uZW50SWRdID8/IHt9LCBjdXJyZW50W2NvbXBvbmVudElkXSA/PyB7fSwgKCkgPT4gYXV0aG9yZWRTb3J0KGNvbXBvbmVudElkKSk7XG5cbiAgICBpZiAoIXRpbGUpIHtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cblxuICAgIGlmIChPYmplY3Qua2V5cyh0aWxlKS5sZW5ndGgpIHtcbiAgICAgIHRpbGVzW2NvbXBvbmVudElkXSA9IHRpbGU7XG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIHRpbGVzO1xufVxuXG4vLyBPbmUgdGlsZSdzIGtleXMgdGhhdCBkaWZmZXIgZnJvbSBiYXNlJ3M7IG51bGwgd2hlbiBvbmUgd2VudCBiYWNrIHRvIGFcbi8vIHN0YXRlIGEgbGluayBjYW5ub3Qgc2F5LlxuZnVuY3Rpb24gY2hhbmdlZFRpbGUoXG4gIGJhc2U6IFJlcG9ydFRpbGVTdGF0ZSxcbiAgY3VycmVudDogUmVwb3J0VGlsZVN0YXRlLFxuICBhdXRob3JlZFNvcnQ6ICgpID0+IFJlcG9ydFNvcnQgfCBudWxsLFxuKTogUmVwb3J0VGlsZVN0YXRlIHwgbnVsbCB7XG4gIGNvbnN0IHRpbGU6IFJlcG9ydFRpbGVTdGF0ZSA9IHt9O1xuXG4gIGlmIChzb3J0S2V5KGJhc2Uuc29ydCkgIT09IHNvcnRLZXkoY3VycmVudC5zb3J0KSkge1xuICAgIGNvbnN0IHNvcnQgPSBjdXJyZW50LnNvcnQ/LmNvbHVtbiA/IGN1cnJlbnQuc29ydCA6IGF1dGhvcmVkU29ydCgpO1xuICAgIGlmICghc29ydCkge1xuICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuXG4gICAgdGlsZS5zb3J0ID0geyAuLi5zb3J0IH07XG4gIH1cblxuICBpZiAoKGJhc2Uuc2VhcmNoID8/ICcnKSAhPT0gKGN1cnJlbnQuc2VhcmNoID8/ICcnKSkge1xuICAgIGlmICghY3VycmVudC5zZWFyY2gpIHtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cblxuICAgIHRpbGUuc2VhcmNoID0gY3VycmVudC5zZWFyY2g7XG4gIH1cblxuICBpZiAoc29ydGVkTmFtZXMoYmFzZS5oaWRkZW4pICE9PSBzb3J0ZWROYW1lcyhjdXJyZW50LmhpZGRlbikpIHtcbiAgICBpZiAoIWN1cnJlbnQuaGlkZGVuPy5sZW5ndGgpIHtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cblxuICAgIHRpbGUuaGlkZGVuID0gWy4uLmN1cnJlbnQuaGlkZGVuXTtcbiAgfVxuXG4gIGlmIChkcmlsbEtleShiYXNlLmRyaWxsKSAhPT0gZHJpbGxLZXkoY3VycmVudC5kcmlsbCkpIHtcbiAgICBpZiAoIWN1cnJlbnQuZHJpbGw/Lmxlbmd0aCkge1xuICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuXG4gICAgdGlsZS5kcmlsbCA9IGN1cnJlbnQuZHJpbGwubWFwKChzdGVwKSA9PiAoeyAuLi5zdGVwIH0pKTtcbiAgfVxuXG4gIHJldHVybiB0aWxlO1xufVxuXG4vLyBIb3cgbWFueSBrZXlzIG9mIGEgc3RvcmVkIHRpbGUgc3RhdGUgdGhlIHRpbGUsIGFzIGl0IGFwcGxpZWQsIGxvc3Q6IGFcbi8vIHNvcnQsIGEgc2VhcmNoIG9yIGEgZHJpbGwgcGF0aCBpdCBubyBsb25nZXIgaGFzLCBhbmQgaGlkZGVuIGNvbHVtbnMgaXRcbi8vIGtlcHQgZmV3ZXIgb2YuXG5mdW5jdGlvbiB0aWxlS2V5c0xvc3Qoc3RvcmVkOiBSZXBvcnRUaWxlU3RhdGUgfCB1bmRlZmluZWQsIGFwcGxpZWQ6IFJlcG9ydFRpbGVTdGF0ZSB8IHVuZGVmaW5lZCk6IG51bWJlciB7XG4gIGlmICghc3RvcmVkKSB7XG4gICAgcmV0dXJuIDA7XG4gIH1cblxuICByZXR1cm4gW1xuICAgICEhc3RvcmVkLnNvcnQ/LmNvbHVtbiAmJiAhYXBwbGllZD8uc29ydD8uY29sdW1uLFxuICAgICEhc3RvcmVkLnNlYXJjaCAmJiAhYXBwbGllZD8uc2VhcmNoLFxuICAgIChzdG9yZWQuaGlkZGVuPy5sZW5ndGggPz8gMCkgPiAoYXBwbGllZD8uaGlkZGVuPy5sZW5ndGggPz8gMCksXG4gICAgKHN0b3JlZC5kcmlsbD8ubGVuZ3RoID8/IDApID4gMCAmJiAhYXBwbGllZD8uZHJpbGw/Lmxlbmd0aCxcbiAgXS5maWx0ZXIoQm9vbGVhbikubGVuZ3RoO1xufVxuXG4vLyBBIGxpc3Qgc29ydCBhcyB0ZXh0OyBubyBkaXJlY3Rpb24gcmVhZHMgYXMgYXNjZW5kaW5nLCB0aGUgd2F5IGEgbGlzdFxuLy8gYXBwbGllcyBpdC5cbmZ1bmN0aW9uIHNvcnRLZXkoc29ydDogUmVwb3J0U29ydCB8IHVuZGVmaW5lZCk6IHN0cmluZyB7XG4gIHJldHVybiBzb3J0Py5jb2x1bW4gPyBKU09OLnN0cmluZ2lmeShbc29ydC5jb2x1bW4sIHNvcnQuZGlyZWN0aW9uID8/ICdhc2MnXSkgOiAnJztcbn1cblxuZnVuY3Rpb24gc29ydGVkTmFtZXMobmFtZXM6IHJlYWRvbmx5IHN0cmluZ1tdIHwgdW5kZWZpbmVkKTogc3RyaW5nIHtcbiAgcmV0dXJuIEpTT04uc3RyaW5naWZ5KFsuLi4obmFtZXMgPz8gW10pXS5zb3J0KCkpO1xufVxuXG4vLyBPbmUgdGV4dCBmb3IgYSBzdG9yZWQgZ3JvdXAgdmFsdWUsIHRoZSBzYW1lIGZvciBldmVyeSB3YXkgb2Ygd3JpdGluZyB0aGVcbi8vIHNhbWUgZmlsdGVyOiBwaWNrcyBpbiBhbnkgb3JkZXIsIHRleHQgdHJpbW1lZCwgYW5kIGFuIGVtcHR5IHZhbHVlIHJlYWQgYXNcbi8vIG5vbmUuXG5mdW5jdGlvbiBzdG9yZWRWYWx1ZUtleSh2YWx1ZTogRmlsdGVyR3JvdXBEZWZhdWx0IHwgbnVsbCB8IHVuZGVmaW5lZCk6IHN0cmluZyB7XG4gIGNvbnN0IHN0b3JlZCA9IHZhbHVlID8/IHt9O1xuICBjb25zdCBwaWNrcyA9IChsaXN0OiB1bmtub3duW10gfCB1bmRlZmluZWQpID0+IFsuLi4oa2VwdFBpY2tzKGxpc3QpID8/IFtdKV0ubWFwKFN0cmluZykuc29ydCgpO1xuXG4gIHJldHVybiBKU09OLnN0cmluZ2lmeShbXG4gICAgc3RvcmVkLnJlbGF0aXZlID8/IG51bGwsXG4gICAgc3RvcmVkLnN0YXJ0Py5zbGljZSgwLCAxMCkgPz8gbnVsbCxcbiAgICBzdG9yZWQuZW5kPy5zbGljZSgwLCAxMCkgPz8gbnVsbCxcbiAgICBwaWNrcyhzdG9yZWQudmFsdWVzKSxcbiAgICBwaWNrcyhzdG9yZWQuZXhjbHVkZVZhbHVlcyksXG4gICAgKHN0b3JlZC52YWx1ZSA/PyAnJykudHJpbSgpLFxuICAgIGZpbml0ZU51bWJlcihzdG9yZWQubWluKSA/PyBudWxsLFxuICAgIGZpbml0ZU51bWJlcihzdG9yZWQubWF4KSA/PyBudWxsLFxuICBdKTtcbn1cblxuLy8gT25lIHRleHQgZm9yIGEgdGlsZSdzIHN0YXRlLCBvdmVyIHRoZSBrZXlzIHRoaXMgdmlld2VyIHJlYWRzLiBObyBkaXJlY3Rpb25cbi8vIHJlYWRzIGFzIGFzY2VuZGluZywgdGhlIHdheSBhIGxpc3QgYXBwbGllcyBpdC5cbmZ1bmN0aW9uIHRpbGVTdGF0ZUtleSh0aWxlOiBSZXBvcnRUaWxlU3RhdGUgfCB1bmRlZmluZWQpOiBzdHJpbmcge1xuICByZXR1cm4gSlNPTi5zdHJpbmdpZnkoW1xuICAgIHRpbGU/LnNvcnQ/LmNvbHVtbiA/IFt0aWxlLnNvcnQuY29sdW1uLCB0aWxlLnNvcnQuZGlyZWN0aW9uID8/ICdhc2MnXSA6IG51bGwsXG4gICAgdGlsZT8uc2VhcmNoID8/ICcnLFxuICAgIFsuLi4odGlsZT8uaGlkZGVuID8/IFtdKV0uc29ydCgpLFxuICAgIGRyaWxsS2V5KHRpbGU/LmRyaWxsKSxcbiAgXSk7XG59XG5cbmZ1bmN0aW9uIGRyaWxsS2V5KHBhdGg6IHJlYWRvbmx5IFJlcG9ydERyaWxsU3RlcFtdIHwgbnVsbCB8IHVuZGVmaW5lZCk6IHN0cmluZyB7XG4gIHJldHVybiBKU09OLnN0cmluZ2lmeSgocGF0aCA/PyBbXSlcbiAgICAubWFwKChzdGVwKSA9PiBbc3RlcC5sZXZlbCwgc3RlcC52YWx1ZSA9PT0gbnVsbCB8fCBzdGVwLnZhbHVlID09PSB1bmRlZmluZWQgPyBudWxsIDogU3RyaW5nKHN0ZXAudmFsdWUpXSkpO1xufVxuXG4vLyBUaGUgcGlja3Mgb2YgYSBsaXN0IHdpdGggYmxhbmtzIChudWxsLCAnJykgbGVmdCBvdXQsIG9yIHVuZGVmaW5lZCB3aGVuIG5vbmVcbi8vIGlzIGxlZnQuXG5mdW5jdGlvbiBrZXB0UGlja3MobGlzdDogdW5rbm93bltdIHwgbnVsbCB8IHVuZGVmaW5lZCk6IHVua25vd25bXSB8IHVuZGVmaW5lZCB7XG4gIGNvbnN0IGtlcHQgPSAobGlzdCA/PyBbXSkuZmlsdGVyKChwaWNrKSA9PiBpc1NldChwaWNrKSAmJiBwaWNrICE9PSAnJyk7XG5cbiAgcmV0dXJuIGtlcHQubGVuZ3RoID8ga2VwdCA6IHVuZGVmaW5lZDtcbn1cblxuLy8gQSByYW5nZSBlbmQgYXMgYSBudW1iZXIuIEEgbWFza2VkIGlucHV0IHNlbmRzIGl0cyBudW1iZXIgYXMgdGV4dCwgc29cbi8vIG51bWVyaWMgdGV4dCBpcyByZWFkIGFzIGl0cyBudW1iZXIsIGFzIGJvdW5kUGFydCByZWFkcyBpdC5cbmV4cG9ydCBmdW5jdGlvbiBmaW5pdGVOdW1iZXIodmFsdWU6IHVua25vd24pOiBudW1iZXIgfCB1bmRlZmluZWQge1xuICBjb25zdCBudW1iZXIgPSB0eXBlb2YgdmFsdWUgPT09ICdzdHJpbmcnID8gbnVtYmVyRnJvbVRleHQodmFsdWUudHJpbSgpKSA6IHZhbHVlO1xuXG4gIHJldHVybiB0eXBlb2YgbnVtYmVyID09PSAnbnVtYmVyJyAmJiBOdW1iZXIuaXNGaW5pdGUobnVtYmVyKSA/IG51bWJlciA6IHVuZGVmaW5lZDtcbn1cblxuLy8gV2hldGhlciBhIHN0b3JlZCB2YWx1ZSByZWFkcyB0aGUgc2FtZSBhcyBubyB2YWx1ZSBhdCBhbGwuXG5mdW5jdGlvbiBob2xkc05vdGhpbmcoc3RvcmVkOiBGaWx0ZXJHcm91cERlZmF1bHQpOiBib29sZWFuIHtcbiAgcmV0dXJuIHN0b3JlZFZhbHVlS2V5KHN0b3JlZCkgPT09IHN0b3JlZFZhbHVlS2V5KG51bGwpO1xufVxuXG4vLyBPbmx5IHRoZSBwYXJ0cyB0aGF0IGhvbGQgc29tZXRoaW5nLCBvciBudWxsIHdoZW4gbm9uZSBkb2VzLlxuZnVuY3Rpb24gc3RvcmVkT3JOdWxsKHZhbHVlOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPik6IEZpbHRlckdyb3VwRGVmYXVsdCB8IG51bGwge1xuICBjb25zdCBzdG9yZWQgPSBjb21wYWN0KHZhbHVlKTtcblxuICByZXR1cm4gT2JqZWN0LmtleXMoc3RvcmVkKS5sZW5ndGggPyBzdG9yZWQgOiBudWxsO1xufVxuXG5mdW5jdGlvbiByZXF1aXJlR3JvdXBLZXlzKHZhbHVlOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiwgdHlwZTogUmVwb3J0RmlsdGVyVHlwZSk6IHZvaWQge1xuICBjb25zdCBhbGxvd2VkOiByZWFkb25seSBzdHJpbmdbXSA9IEdST1VQX1ZBTFVFX0tFWVNbdHlwZV0gPz8gR1JPVVBfVkFMVUVfS0VZUy5rZXl3b3JkO1xuICBjb25zdCB1bmtub3duID0gT2JqZWN0LmtleXModmFsdWUpLmZpbHRlcigoa2V5KSA9PiAhYWxsb3dlZC5pbmNsdWRlcyhrZXkpKTtcblxuICBpZiAodW5rbm93bi5sZW5ndGgpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYEEgJHt0eXBlfSBkZWZhdWx0IHRha2VzICR7YWxsb3dlZC5qb2luKCcsICcpfSDigJQgbm90ICR7dW5rbm93bi5qb2luKCcsICcpfS5gKTtcbiAgfVxufVxuXG4vLyBBIHJlbGF0aXZlIHJhbmdlLCBvciBmaXhlZCBkYXlzOyBuZXZlciBib3RoLlxuZnVuY3Rpb24gZGF0ZVJhbmdlVmFsdWUodmFsdWU6IFJlY29yZDxzdHJpbmcsIHVua25vd24+KTogRmlsdGVyR3JvdXBEZWZhdWx0IHtcbiAgY29uc3QgcmVsYXRpdmUgPSB0ZXh0UGFydCh2YWx1ZSwgJ3JlbGF0aXZlJyk7XG4gIGNvbnN0IHN0YXJ0ID0gZGF5UGFydCh2YWx1ZSwgJ3N0YXJ0Jyk7XG4gIGNvbnN0IGVuZCA9IGRheVBhcnQodmFsdWUsICdlbmQnKTtcblxuICBpZiAocmVsYXRpdmUgPT09ICcnKSB7XG4gICAgcmV0dXJuIGNvbXBhY3QoeyBzdGFydCwgZW5kIH0pO1xuICB9XG5cbiAgaWYgKHN0YXJ0ICE9PSBudWxsIHx8IGVuZCAhPT0gbnVsbCkge1xuICAgIHRocm93IG5ldyBFcnJvcignQSBkYXRlUmFuZ2UgZGVmYXVsdCBpcyBlaXRoZXIgYSByZWxhdGl2ZSBwcmVzZXQgb3IgYSBmaXhlZCBzdGFydC9lbmQsIG5vdCBib3RoLicpO1xuICB9XG5cbiAgaWYgKCFpc1JlbGF0aXZlUmFuZ2UocmVsYXRpdmUpKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGByZWxhdGl2ZSBtdXN0IGJlIG9uZSBvZjogJHtPYmplY3Qua2V5cyhSRUxBVElWRV9SQU5HRVMpLmpvaW4oJywgJyl9LmApO1xuICB9XG5cbiAgcmV0dXJuIHsgcmVsYXRpdmUgfTtcbn1cblxuLy8gVGhlIHZhbHVlcyB0byBrZWVwIG9yIHRoZSB2YWx1ZXMgdG8gbGVhdmUgb3V0OyBuZXZlciBib3RoLlxuZnVuY3Rpb24gc2VsZWN0VmFsdWUodmFsdWU6IFJlY29yZDxzdHJpbmcsIHVua25vd24+KTogRmlsdGVyR3JvdXBEZWZhdWx0IHtcbiAgY29uc3QgdmFsdWVzID0gcGlja0xpc3QodmFsdWUsICd2YWx1ZXMnKTtcbiAgY29uc3QgZXhjbHVkZVZhbHVlcyA9IHBpY2tMaXN0KHZhbHVlLCAnZXhjbHVkZVZhbHVlcycpO1xuXG4gIGlmICh2YWx1ZXMgIT09IG51bGwgJiYgZXhjbHVkZVZhbHVlcyAhPT0gbnVsbCkge1xuICAgIHRocm93IG5ldyBFcnJvcignQSBzZWxlY3QgZGVmYXVsdCBlaXRoZXIga2VlcHMgdmFsdWVzIG9yIGxlYXZlcyBvdXQgZXhjbHVkZV92YWx1ZXMsIG5vdCBib3RoLicpO1xuICB9XG5cbiAgcmV0dXJuIGNvbXBhY3QoeyB2YWx1ZXMsIGV4Y2x1ZGVWYWx1ZXMgfSk7XG59XG5cbmZ1bmN0aW9uIGtleXdvcmRWYWx1ZSh2YWx1ZTogUmVjb3JkPHN0cmluZywgdW5rbm93bj4pOiBGaWx0ZXJHcm91cERlZmF1bHQge1xuICBjb25zdCB0ZXh0ID0gdGV4dFBhcnQodmFsdWUsICd2YWx1ZScpO1xuXG4gIHJldHVybiB0ZXh0ICE9PSAnJyA/IHsgdmFsdWU6IHRleHQgfSA6IHt9O1xufVxuXG4vLyBFaXRoZXIgZW5kIG1heSBiZSBvcGVuOyAwIGlzIGFuIGVuZCBsaWtlIGFueSBvdGhlci5cbmZ1bmN0aW9uIG51bWJlclJhbmdlVmFsdWUodmFsdWU6IFJlY29yZDxzdHJpbmcsIHVua25vd24+KTogRmlsdGVyR3JvdXBEZWZhdWx0IHtcbiAgY29uc3QgbWluID0gYm91bmRQYXJ0KHZhbHVlLCAnbWluJyk7XG4gIGNvbnN0IG1heCA9IGJvdW5kUGFydCh2YWx1ZSwgJ21heCcpO1xuXG4gIGlmIChtaW4gIT09IG51bGwgJiYgbWF4ICE9PSBudWxsICYmIG1pbiA+IG1heCkge1xuICAgIHRocm93IG5ldyBFcnJvcihgbWluICgke21pbn0pIGlzIGFib3ZlIG1heCAoJHttYXh9KS5gKTtcbiAgfVxuXG4gIHJldHVybiBjb21wYWN0KHsgbWluLCBtYXggfSk7XG59XG5cbi8vIFRoZSB0ZXh0IGBrZXlgIGhvbGRzLCB0cmltbWVkLCBvciAnJyB3aGVuIGFic2VudC4gQSBudW1iZXIgaXMgcmVhZCBhcyBpdHNcbi8vIHRleHQ7IGFueSBvdGhlciBraW5kIGlzIHJlZnVzZWQuXG5mdW5jdGlvbiB0ZXh0UGFydCh2YWx1ZTogUmVjb3JkPHN0cmluZywgdW5rbm93bj4sIGtleTogc3RyaW5nKTogc3RyaW5nIHtcbiAgY29uc3QgdGV4dCA9IHZhbHVlW2tleV07XG4gIGlmICh0ZXh0ID09PSB1bmRlZmluZWQgfHwgdGV4dCA9PT0gbnVsbCkge1xuICAgIHJldHVybiAnJztcbiAgfVxuXG4gIGlmICh0eXBlb2YgdGV4dCAhPT0gJ3N0cmluZycgJiYgdHlwZW9mIHRleHQgIT09ICdudW1iZXInKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGAke2tleX0gbXVzdCBiZSB0ZXh0LmApO1xuICB9XG5cbiAgcmV0dXJuIFN0cmluZyh0ZXh0KS50cmltKCk7XG59XG5cbi8vIEEgY2FsZW5kYXItZGF5IGJvdW5kOiBpdHMgZmlyc3QgdGVuIGNoYXJhY3RlcnMgbXVzdCBiZSBhIHJlYWwgZGF5LlxuZnVuY3Rpb24gZGF5UGFydCh2YWx1ZTogUmVjb3JkPHN0cmluZywgdW5rbm93bj4sIGtleTogc3RyaW5nKTogc3RyaW5nIHwgbnVsbCB7XG4gIGNvbnN0IHRleHQgPSB0ZXh0UGFydCh2YWx1ZSwga2V5KTtcbiAgaWYgKHRleHQgPT09ICcnKSB7XG4gICAgcmV0dXJuIG51bGw7XG4gIH1cblxuICBjb25zdCBkYXkgPSB0ZXh0LnNsaWNlKDAsIDEwKTtcbiAgaWYgKCFpc0NhbGVuZGFyRGF5KGRheSkpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYCR7a2V5fSBtdXN0IGJlIGEgeXl5eS1NTS1kZCBkYXkuYCk7XG4gIH1cblxuICByZXR1cm4gZGF5O1xufVxuXG4vLyBUaGUgcGlja3Mgb2YgYGtleWAgd2l0aCBibGFua3MgKG51bGwsICcnKSBkcm9wcGVkLCBvciBudWxsIHdoZW4gbm9uZSBpc1xuLy8gbGVmdC4gQSBsb25lIHBpY2sgaXMgYSBsaXN0IG9mIG9uZTsgYSBwaWNrIHRoYXQgaXMgYSBsaXN0IG9yIGFuIG9iamVjdCBpc1xuLy8gcmVmdXNlZC5cbmZ1bmN0aW9uIHBpY2tMaXN0KHZhbHVlOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiwga2V5OiBzdHJpbmcpOiB1bmtub3duW10gfCBudWxsIHtcbiAgY29uc3QgcmF3ID0gdmFsdWVba2V5XSA/PyBbXTtcbiAgY29uc3QgcGlja3M6IHVua25vd25bXSA9IEFycmF5LmlzQXJyYXkocmF3KSA/IHJhdyA6IFtyYXddO1xuXG4gIGlmIChwaWNrcy5zb21lKChwaWNrKSA9PiBpc1NldChwaWNrKSAmJiAhaXNTY2FsYXIocGljaykpKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBFYWNoIHBpY2sgaW4gJHtrZXl9IG11c3QgYmUgYSBwbGFpbiB2YWx1ZSwgbm90IGEgbGlzdC5gKTtcbiAgfVxuXG4gIGNvbnN0IGtlcHQgPSBwaWNrcy5maWx0ZXIoKHBpY2spID0+IGlzU2V0KHBpY2spICYmIHBpY2sgIT09ICcnKTtcblxuICByZXR1cm4ga2VwdC5sZW5ndGggPyBrZXB0IDogbnVsbDtcbn1cblxuLy8gT25lIGVuZCBvZiBhIG51bWJlciByYW5nZTogbnVsbCB3aGVuIGFic2VudCBvciBibGFuaywgZWxzZSBhIGZpbml0ZSBudW1iZXJcbi8vIChudW1lcmljIHRleHQgaXMgcmVhZCBhcyBpdHMgbnVtYmVyKS5cbmZ1bmN0aW9uIGJvdW5kUGFydCh2YWx1ZTogUmVjb3JkPHN0cmluZywgdW5rbm93bj4sIGtleTogc3RyaW5nKTogbnVtYmVyIHwgbnVsbCB7XG4gIGNvbnN0IHJhdyA9IHR5cGVvZiB2YWx1ZVtrZXldID09PSAnc3RyaW5nJyA/ICh2YWx1ZVtrZXldIGFzIHN0cmluZykudHJpbSgpIDogdmFsdWVba2V5XTtcbiAgaWYgKCFpc1NldChyYXcpIHx8IHJhdyA9PT0gJycpIHtcbiAgICByZXR1cm4gbnVsbDtcbiAgfVxuXG4gIGNvbnN0IGJvdW5kID0gdHlwZW9mIHJhdyA9PT0gJ3N0cmluZycgPyBudW1iZXJGcm9tVGV4dChyYXcpIDogcmF3O1xuICBpZiAodHlwZW9mIGJvdW5kICE9PSAnbnVtYmVyJyB8fCAhTnVtYmVyLmlzRmluaXRlKGJvdW5kKSkge1xuICAgIHRocm93IG5ldyBFcnJvcihgJHtrZXl9IG11c3QgYmUgYSBmaW5pdGUgbnVtYmVyLmApO1xuICB9XG5cbiAgcmV0dXJuIGJvdW5kO1xufVxuXG5mdW5jdGlvbiByZXF1aXJlU2l6ZShkb2M6IFJlY29yZDxzdHJpbmcsIHVua25vd24+KTogdm9pZCB7XG4gIGlmIChuZXcgVGV4dEVuY29kZXIoKS5lbmNvZGUoSlNPTi5zdHJpbmdpZnkoZG9jKSkubGVuZ3RoID4gVklFV19DT05GSUdfTUFYX0JZVEVTKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdBIHZpZXcgY29uZmlnIGlzIG92ZXIgMzIgS0IuJyk7XG4gIH1cbn1cblxuZnVuY3Rpb24gcmVxdWlyZVZlcnNpb24odmVyc2lvbjogdW5rbm93bik6IHZvaWQge1xuICBpZiAoIWlzU2V0KHZlcnNpb24pKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdBIHZpZXcgY29uZmlnIG5lZWRzIGl0cyB2ZXJzaW9uICh2KS4nKTtcbiAgfVxuXG4gIGlmICh2ZXJzaW9uICE9PSBSRVBPUlRfVklFV19DT05GSUdfVkVSU0lPTikge1xuICAgIHRocm93IG5ldyBFcnJvcihgVGhpcyB2aWV3ZXIgcmVhZHMgdmlldyBjb25maWcgdmVyc2lvbiAke1JFUE9SVF9WSUVXX0NPTkZJR19WRVJTSU9OfSBvbmx5LmApO1xuICB9XG59XG5cbmZ1bmN0aW9uIHJlcXVpcmVNYXRjaChtYXRjaDogdW5rbm93bik6IFJlcG9ydFZpZXdDb25maWdbJ21hdGNoJ10ge1xuICBpZiAobWF0Y2ggIT09ICdhbGwnICYmIG1hdGNoICE9PSAnYW55Jykge1xuICAgIHRocm93IG5ldyBFcnJvcignbWF0Y2ggbXVzdCBiZSBhbGwgb3IgYW55LicpO1xuICB9XG5cbiAgcmV0dXJuIG1hdGNoO1xufVxuXG4vLyBHcm91cCBpZCAtPiB2YWx1ZS4gQSB2YWx1ZSBubyBncm91cCB0eXBlIGNvdWxkIGhvbGQgaXMgZHJvcHBlZCB3aG9sZS5cbmZ1bmN0aW9uIHZpZXdHcm91cHMocmF3OiB1bmtub3duKTogUmVjb3JkPG51bWJlciwgRmlsdGVyR3JvdXBEZWZhdWx0IHwgbnVsbD4ge1xuICBjb25zdCBlbnRyaWVzID0gT2JqZWN0LmVudHJpZXMocmVxdWlyZU9iamVjdChyYXcsICdncm91cHMgbXVzdCBtYXAgZ3JvdXAgaWRzIHRvIHZhbHVlcy4nKSk7XG4gIGlmIChlbnRyaWVzLmxlbmd0aCA+IFZJRVdfQ09ORklHX01BWF9HUk9VUFMpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYEEgdmlldyBob2xkcyBhdCBtb3N0ICR7VklFV19DT05GSUdfTUFYX0dST1VQU30gZ3JvdXBzLmApO1xuICB9XG5cbiAgY29uc3QgZ3JvdXBzOiBSZWNvcmQ8bnVtYmVyLCBGaWx0ZXJHcm91cERlZmF1bHQgfCBudWxsPiA9IHt9O1xuICBlbnRyaWVzLmZvckVhY2goKFtrZXksIHZhbHVlXSkgPT4ge1xuICAgIGNvbnN0IGlkID0gcmVxdWlyZUlkS2V5KGtleSwgJ2dyb3VwcycpO1xuICAgIHJlcXVpcmVQaWNrQ291bnQodmFsdWUpO1xuICAgIGNvbnN0IGtlcHQgPSB2YWx1ZSA9PT0gbnVsbCA/IG51bGwgOiBzdG9yZWRHcm91cFZhbHVlKHZhbHVlKTtcblxuICAgIGlmIChrZXB0ICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIGdyb3Vwc1tpZF0gPSBrZXB0O1xuICAgIH1cbiAgfSk7XG5cbiAgcmV0dXJuIGdyb3Vwcztcbn1cblxuLy8gQSBzdG9yZWQgZ3JvdXAgdmFsdWUsIHJlYWQgZm9yIHRoZSBvbmUgdHlwZSBpdHMga2V5cyBiZWxvbmcgdG8gKGFuIGVtcHR5XG4vLyB2YWx1ZSBmaXRzIGV2ZXJ5IHR5cGUpLCBvciB1bmRlZmluZWQgd2hlbiBpdCBmaXRzIG5vbmUuXG5mdW5jdGlvbiBzdG9yZWRHcm91cFZhbHVlKHZhbHVlOiB1bmtub3duKTogRmlsdGVyR3JvdXBEZWZhdWx0IHwgdW5kZWZpbmVkIHtcbiAgaWYgKCFpc1BsYWluT2JqZWN0KHZhbHVlKSkge1xuICAgIHJldHVybiB1bmRlZmluZWQ7XG4gIH1cblxuICBjb25zdCBrZXlzID0gT2JqZWN0LmtleXModmFsdWUpO1xuICBjb25zdCB0eXBlID0gKE9iamVjdC5rZXlzKEdST1VQX1ZBTFVFX0tFWVMpIGFzIFJlcG9ydEZpbHRlclR5cGVbXSlcbiAgICAuZmluZCgoY2FuZGlkYXRlKSA9PiBrZXlzLmV2ZXJ5KChrZXkpID0+IChHUk9VUF9WQUxVRV9LRVlTW2NhbmRpZGF0ZV0gYXMgcmVhZG9ubHkgc3RyaW5nW10pLmluY2x1ZGVzKGtleSkpKTtcblxuICByZXR1cm4gdHlwZSA/IChncm91cFZhbHVlRnJvbVN0b3JlZCh2YWx1ZSwgdHlwZSkgPz8gdW5kZWZpbmVkKSA6IHVuZGVmaW5lZDtcbn1cblxuZnVuY3Rpb24gcmVxdWlyZVBpY2tDb3VudCh2YWx1ZTogdW5rbm93bik6IHZvaWQge1xuICBjb25zdCBsaXN0cyA9IGlzUGxhaW5PYmplY3QodmFsdWUpID8gW3ZhbHVlLnZhbHVlcywgdmFsdWUuZXhjbHVkZVZhbHVlc10gOiBbXTtcblxuICBpZiAobGlzdHMuc29tZSgobGlzdCkgPT4gQXJyYXkuaXNBcnJheShsaXN0KSAmJiBsaXN0Lmxlbmd0aCA+IEdST1VQX1ZBTFVFX01BWF9QSUNLUykpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYEEgZ3JvdXAgdmFsdWUgaG9sZHMgYXQgbW9zdCAke0dST1VQX1ZBTFVFX01BWF9QSUNLU30gdmFsdWVzLmApO1xuICB9XG59XG5cbi8vIENvbXBvbmVudCBpZCAtPiB0aWxlIHN0YXRlLlxuZnVuY3Rpb24gdmlld1RpbGVzKHJhdzogdW5rbm93bik6IFJlY29yZDxudW1iZXIsIFJlcG9ydFRpbGVTdGF0ZT4ge1xuICBjb25zdCBlbnRyaWVzID0gT2JqZWN0LmVudHJpZXMocmVxdWlyZU9iamVjdChyYXcsICd0aWxlcyBtdXN0IG1hcCBjb21wb25lbnQgaWRzIHRvIHRpbGUgc3RhdGVzLicpKTtcbiAgaWYgKGVudHJpZXMubGVuZ3RoID4gVklFV19DT05GSUdfTUFYX1RJTEVTKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBBIHZpZXcgaG9sZHMgYXQgbW9zdCAke1ZJRVdfQ09ORklHX01BWF9USUxFU30gdGlsZXMuYCk7XG4gIH1cblxuICBjb25zdCB0aWxlczogUmVjb3JkPG51bWJlciwgUmVwb3J0VGlsZVN0YXRlPiA9IHt9O1xuICBlbnRyaWVzLmZvckVhY2goKFtrZXksIHZhbHVlXSkgPT4ge1xuICAgIHRpbGVzW3JlcXVpcmVJZEtleShrZXksICd0aWxlcycpXSA9IHZpZXdUaWxlKHZhbHVlKTtcbiAgfSk7XG5cbiAgcmV0dXJuIHRpbGVzO1xufVxuXG5mdW5jdGlvbiB2aWV3VGlsZShyYXc6IHVua25vd24pOiBSZXBvcnRUaWxlU3RhdGUge1xuICBjb25zdCB0aWxlID0gcmVxdWlyZU9iamVjdChyYXcsICdBIHRpbGUgc3RhdGUgbXVzdCBiZSBhbiBvYmplY3QuJyk7XG4gIGNvbnN0IHN0YXRlID0gb3RoZXJLZXlzKHRpbGUsIFRJTEVfU1RBVEVfS0VZUykgYXMgUmVwb3J0VGlsZVN0YXRlO1xuXG4gIGlmIChpc1NldCh0aWxlLnNvcnQpKSB7XG4gICAgc3RhdGUuc29ydCA9IHZpZXdTb3J0KHRpbGUuc29ydCk7XG4gIH1cblxuICBpZiAoaXNTZXQodGlsZS5zZWFyY2gpKSB7XG4gICAgc3RhdGUuc2VhcmNoID0gcmVxdWlyZVN0cmluZyh0aWxlLnNlYXJjaCwgJ3NlYXJjaCBtdXN0IGJlIHRleHQuJyk7XG4gIH1cblxuICBpZiAoaXNTZXQodGlsZS5oaWRkZW4pKSB7XG4gICAgc3RhdGUuaGlkZGVuID0gdmlld0hpZGRlbih0aWxlLmhpZGRlbik7XG4gIH1cblxuICBpZiAoaXNTZXQodGlsZS5kcmlsbCkpIHtcbiAgICBzdGF0ZS5kcmlsbCA9IHZpZXdEcmlsbCh0aWxlLmRyaWxsKTtcbiAgfVxuXG4gIHJldHVybiBzdGF0ZTtcbn1cblxuZnVuY3Rpb24gdmlld1NvcnQocmF3OiB1bmtub3duKTogUmVwb3J0U29ydCB7XG4gIGNvbnN0IHNvcnQgPSByZXF1aXJlT2JqZWN0KHJhdywgJ3NvcnQgbXVzdCBiZSBhIGNvbHVtbiBhbmQgYSBkaXJlY3Rpb24uJyk7XG4gIGNvbnN0IGNvbHVtbiA9IHJlcXVpcmVTdHJpbmcoc29ydC5jb2x1bW4sICdzb3J0IG11c3QgbmFtZSBhIGNvbHVtbi4nKTtcbiAgaWYgKGNvbHVtbiA9PT0gJycgfHwgKGlzU2V0KHNvcnQuZGlyZWN0aW9uKSAmJiBzb3J0LmRpcmVjdGlvbiAhPT0gJ2FzYycgJiYgc29ydC5kaXJlY3Rpb24gIT09ICdkZXNjJykpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ3NvcnQgbXVzdCBiZSBhIGNvbHVtbiBhbmQgYSBkaXJlY3Rpb24uJyk7XG4gIH1cblxuICByZXR1cm4gc29ydC5kaXJlY3Rpb24gPyB7IGNvbHVtbiwgZGlyZWN0aW9uOiBzb3J0LmRpcmVjdGlvbiBhcyBSZXBvcnRTb3J0WydkaXJlY3Rpb24nXSB9IDogeyBjb2x1bW4gfTtcbn1cblxuZnVuY3Rpb24gdmlld0hpZGRlbihyYXc6IHVua25vd24pOiBzdHJpbmdbXSB7XG4gIGlmICghQXJyYXkuaXNBcnJheShyYXcpIHx8IHJhdy5zb21lKChuYW1lKSA9PiB0eXBlb2YgbmFtZSAhPT0gJ3N0cmluZycpKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdoaWRkZW4gbXVzdCBsaXN0IGNvbHVtbiBuYW1lcy4nKTtcbiAgfVxuXG4gIHJldHVybiBbLi4ucmF3XTtcbn1cblxuZnVuY3Rpb24gdmlld0RyaWxsKHJhdzogdW5rbm93bik6IFJlcG9ydERyaWxsU3RlcFtdIHtcbiAgaWYgKCFBcnJheS5pc0FycmF5KHJhdykpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ2RyaWxsIG11c3QgbGlzdCBzdGVwcy4nKTtcbiAgfVxuXG4gIGlmIChyYXcubGVuZ3RoID4gRFJJTExfTUFYX0RFUFRIKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBBIGRyaWxsIHBhdGggaG9sZHMgYXQgbW9zdCAke0RSSUxMX01BWF9ERVBUSH0gc3RlcHMuYCk7XG4gIH1cblxuICByZXR1cm4gcmF3Lm1hcCgoc3RlcDogdW5rbm93bikgPT4ge1xuICAgIGlmICghaXNQbGFpbk9iamVjdChzdGVwKSB8fCAhaXNDaGFydEdyYW51bGFyaXR5KHN0ZXAubGV2ZWwpIHx8ICFpc0RyaWxsVmFsdWUoc3RlcC52YWx1ZSkpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignQSBkcmlsbCBzdGVwIG5lZWRzIGEgdGltZSBsZXZlbCBhbmQgYSB2YWx1ZS4nKTtcbiAgICB9XG5cbiAgICByZXR1cm4geyBsZXZlbDogc3RlcC5sZXZlbCwgdmFsdWU6IHN0ZXAudmFsdWUgfTtcbiAgfSk7XG59XG5cbmZ1bmN0aW9uIGlzRHJpbGxWYWx1ZSh2YWx1ZTogdW5rbm93bik6IHZhbHVlIGlzIFJlcG9ydERyaWxsU3RlcFsndmFsdWUnXSB7XG4gIHJldHVybiB2YWx1ZSA9PT0gbnVsbCB8fCB0eXBlb2YgdmFsdWUgPT09ICdzdHJpbmcnIHx8IHR5cGVvZiB2YWx1ZSA9PT0gJ251bWJlcic7XG59XG5cbi8vIFRoZSBrZXlzIG9mIGBzb3VyY2VgIHRoYXQgYXJlIG5vdCBpbiBga25vd25gLCBhcyB0aGV5IHdlcmUuXG5mdW5jdGlvbiBvdGhlcktleXMoc291cmNlOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiwga25vd246IHJlYWRvbmx5IHN0cmluZ1tdKTogUmVjb3JkPHN0cmluZywgdW5rbm93bj4ge1xuICByZXR1cm4gT2JqZWN0LmZyb21FbnRyaWVzKE9iamVjdC5lbnRyaWVzKHNvdXJjZSkuZmlsdGVyKChba2V5XSkgPT4gIWtub3duLmluY2x1ZGVzKGtleSkpKTtcbn1cblxuZnVuY3Rpb24gb3B0aW9uYWxJZChyYXc6IHVua25vd24sIHJlZnVzYWw6IHN0cmluZyk6IG51bWJlciB8IG51bGwge1xuICBpZiAoIWlzU2V0KHJhdykpIHtcbiAgICByZXR1cm4gbnVsbDtcbiAgfVxuXG4gIGlmICghTnVtYmVyLmlzSW50ZWdlcihyYXcpIHx8IChyYXcgYXMgbnVtYmVyKSA8IDEpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IocmVmdXNhbCk7XG4gIH1cblxuICByZXR1cm4gcmF3IGFzIG51bWJlcjtcbn1cblxuZnVuY3Rpb24gcmVxdWlyZUlkS2V5KGtleTogc3RyaW5nLCB3aGVyZTogc3RyaW5nKTogbnVtYmVyIHtcbiAgaWYgKCFJRF9LRVlfUEFUVEVSTi50ZXN0KGtleSkpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYCR7d2hlcmV9IGFyZSBrZXllZCBieSBpZCwgbm90IGJ5ICcke2tleX0nLmApO1xuICB9XG5cbiAgcmV0dXJuIE51bWJlcihrZXkpO1xufVxuXG5mdW5jdGlvbiByZXF1aXJlR3JhbnVsYXJpdHkocmF3OiB1bmtub3duLCByZWZ1c2FsOiBzdHJpbmcpOiBDaGFydEdyYW51bGFyaXR5IHtcbiAgaWYgKCFpc0NoYXJ0R3JhbnVsYXJpdHkocmF3KSkge1xuICAgIHRocm93IG5ldyBFcnJvcihyZWZ1c2FsKTtcbiAgfVxuXG4gIHJldHVybiByYXc7XG59XG5cbmZ1bmN0aW9uIHJlcXVpcmVTdHJpbmcocmF3OiB1bmtub3duLCByZWZ1c2FsOiBzdHJpbmcpOiBzdHJpbmcge1xuICBpZiAodHlwZW9mIHJhdyAhPT0gJ3N0cmluZycpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IocmVmdXNhbCk7XG4gIH1cblxuICByZXR1cm4gcmF3O1xufVxuXG5mdW5jdGlvbiByZXF1aXJlT2JqZWN0KHJhdzogdW5rbm93biwgcmVmdXNhbDogc3RyaW5nKTogUmVjb3JkPHN0cmluZywgdW5rbm93bj4ge1xuICBpZiAoIWlzUGxhaW5PYmplY3QocmF3KSkge1xuICAgIHRocm93IG5ldyBFcnJvcihyZWZ1c2FsKTtcbiAgfVxuXG4gIHJldHVybiByYXc7XG59XG5cbmZ1bmN0aW9uIGlzU2V0KHZhbHVlOiB1bmtub3duKTogYm9vbGVhbiB7XG4gIHJldHVybiB2YWx1ZSAhPT0gdW5kZWZpbmVkICYmIHZhbHVlICE9PSBudWxsO1xufVxuXG5mdW5jdGlvbiBpc1BsYWluT2JqZWN0KHZhbHVlOiB1bmtub3duKTogdmFsdWUgaXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj4ge1xuICByZXR1cm4gdmFsdWUgIT09IG51bGwgJiYgdHlwZW9mIHZhbHVlID09PSAnb2JqZWN0JyAmJiAhQXJyYXkuaXNBcnJheSh2YWx1ZSk7XG59XG5cbmZ1bmN0aW9uIGlzU2NhbGFyKHZhbHVlOiB1bmtub3duKTogYm9vbGVhbiB7XG4gIHJldHVybiB0eXBlb2YgdmFsdWUgPT09ICdzdHJpbmcnIHx8IHR5cGVvZiB2YWx1ZSA9PT0gJ251bWJlcicgfHwgdHlwZW9mIHZhbHVlID09PSAnYm9vbGVhbic7XG59XG5cbi8vIE9ubHkgdGhlIHBhcnRzIHRoYXQgaG9sZCBzb21ldGhpbmcuXG5mdW5jdGlvbiBjb21wYWN0KHZhbHVlOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPik6IEZpbHRlckdyb3VwRGVmYXVsdCB7XG4gIHJldHVybiBPYmplY3QuZnJvbUVudHJpZXMoT2JqZWN0LmVudHJpZXModmFsdWUpLmZpbHRlcigoWywgcGFydF0pID0+IGlzU2V0KHBhcnQpKSkgYXMgRmlsdGVyR3JvdXBEZWZhdWx0O1xufVxuIl19
|