@firestitch/report 18.6.1 → 18.8.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.
Files changed (97) hide show
  1. package/app/reports/components/component-chart/component-chart.component.d.ts +6 -7
  2. package/app/reports/components/component-kpi/component-kpi.component.d.ts +17 -9
  3. package/app/reports/components/component-kpi/components/sparkline/sparkline.component.d.ts +8 -0
  4. package/app/reports/components/component-list/component-list.component.d.ts +39 -10
  5. package/app/reports/components/component-note/component-note.component.d.ts +12 -0
  6. package/app/reports/components/report-canvas/report-canvas.component.d.ts +0 -10
  7. package/app/reports/components/report-component/report-component.component.d.ts +5 -12
  8. package/app/reports/data/report.data.d.ts +2 -3
  9. package/app/reports/dialogs/component-settings/component-settings.component.d.ts +34 -2
  10. package/app/reports/dialogs/list-columns/list-columns.component.d.ts +23 -0
  11. package/app/reports/dialogs/report-settings/report-locale-patch.d.ts +5 -0
  12. package/app/reports/dialogs/report-settings/report-settings.component.d.ts +20 -2
  13. package/app/reports/enums/report-change-polarity.enum.d.ts +5 -0
  14. package/app/reports/enums/report-chart-color.enum.d.ts +12 -0
  15. package/app/reports/enums/report-chart-data-labels.enum.d.ts +6 -0
  16. package/app/reports/enums/report-chart-date-label.enum.d.ts +5 -0
  17. package/app/reports/enums/report-chart-line-style.enum.d.ts +5 -0
  18. package/app/reports/enums/report-chart-mark-stat.enum.d.ts +6 -0
  19. package/app/reports/enums/report-kpi-trend.enum.d.ts +5 -0
  20. package/app/reports/enums/report-list-column-format.enum.d.ts +6 -0
  21. package/app/reports/enums/report-number-units.enum.d.ts +6 -0
  22. package/app/reports/enums/report-value-format.enum.d.ts +5 -0
  23. package/app/reports/export/offscreen-chart.d.ts +2 -2
  24. package/app/reports/export/report-export-collector.service.d.ts +37 -8
  25. package/app/reports/export/report-pdf.service.d.ts +6 -0
  26. package/app/reports/export/report-pptx.service.d.ts +24 -0
  27. package/app/reports/format.d.ts +64 -3
  28. package/app/reports/interfaces/report-chat-viewer-filter.interface.d.ts +2 -0
  29. package/app/reports/interfaces/report.interface.d.ts +205 -14
  30. package/app/reports/kpi-card.d.ts +48 -0
  31. package/app/reports/layout.d.ts +0 -9
  32. package/app/reports/list-config.d.ts +16 -0
  33. package/app/reports/option-builder.d.ts +76 -9
  34. package/app/reports/output-notes.d.ts +14 -0
  35. package/app/reports/pipes/report-date.pipe.d.ts +2 -1
  36. package/app/reports/pipes/report-number.pipe.d.ts +8 -0
  37. package/app/reports/pipes/report-output.pipe.d.ts +10 -0
  38. package/app/reports/report-filter-items.d.ts +5 -2
  39. package/app/reports/report-url-state.d.ts +4 -0
  40. package/app/reports/services/report-filter-state.service.d.ts +27 -2
  41. package/app/reports/theme/palette.d.ts +6 -0
  42. package/app/reports/theme/typography.d.ts +2 -0
  43. package/esm2022/app/reports/components/component-chart/component-chart.component.mjs +23 -20
  44. package/esm2022/app/reports/components/component-kpi/component-kpi.component.mjs +56 -29
  45. package/esm2022/app/reports/components/component-kpi/components/sparkline/sparkline.component.mjs +19 -0
  46. package/esm2022/app/reports/components/component-list/component-list.component.mjs +218 -32
  47. package/esm2022/app/reports/components/component-note/component-note.component.mjs +30 -0
  48. package/esm2022/app/reports/components/report-canvas/report-canvas.component.mjs +7 -61
  49. package/esm2022/app/reports/components/report-component/report-component.component.mjs +99 -100
  50. package/esm2022/app/reports/data/report.data.mjs +20 -7
  51. package/esm2022/app/reports/dialogs/component-settings/component-settings.component.mjs +133 -13
  52. package/esm2022/app/reports/dialogs/list-columns/list-columns.component.mjs +56 -0
  53. package/esm2022/app/reports/dialogs/report-settings/report-locale-patch.mjs +13 -0
  54. package/esm2022/app/reports/dialogs/report-settings/report-settings.component.mjs +138 -20
  55. package/esm2022/app/reports/enums/report-change-polarity.enum.mjs +11 -0
  56. package/esm2022/app/reports/enums/report-chart-color.enum.mjs +19 -0
  57. package/esm2022/app/reports/enums/report-chart-data-labels.enum.mjs +13 -0
  58. package/esm2022/app/reports/enums/report-chart-date-label.enum.mjs +13 -0
  59. package/esm2022/app/reports/enums/report-chart-line-style.enum.mjs +12 -0
  60. package/esm2022/app/reports/enums/report-chart-mark-stat.enum.mjs +12 -0
  61. package/esm2022/app/reports/enums/report-kpi-trend.enum.mjs +10 -0
  62. package/esm2022/app/reports/enums/report-list-column-format.enum.mjs +14 -0
  63. package/esm2022/app/reports/enums/report-number-units.enum.mjs +14 -0
  64. package/esm2022/app/reports/enums/report-value-format.enum.mjs +13 -0
  65. package/esm2022/app/reports/export/offscreen-chart.mjs +5 -4
  66. package/esm2022/app/reports/export/report-export-collector.service.mjs +186 -40
  67. package/esm2022/app/reports/export/report-pdf.service.mjs +332 -67
  68. package/esm2022/app/reports/export/report-pptx.service.mjs +765 -106
  69. package/esm2022/app/reports/format.mjs +917 -57
  70. package/esm2022/app/reports/interfaces/report-chat-viewer-filter.interface.mjs +1 -1
  71. package/esm2022/app/reports/interfaces/report.interface.mjs +1 -1
  72. package/esm2022/app/reports/kpi-card.mjs +174 -0
  73. package/esm2022/app/reports/layout.mjs +1 -46
  74. package/esm2022/app/reports/list-config.mjs +106 -0
  75. package/esm2022/app/reports/option-builder.mjs +1457 -117
  76. package/esm2022/app/reports/output-notes.mjs +158 -0
  77. package/esm2022/app/reports/pipes/report-date.pipe.mjs +7 -6
  78. package/esm2022/app/reports/pipes/report-number.pipe.mjs +25 -0
  79. package/esm2022/app/reports/pipes/report-output.pipe.mjs +28 -0
  80. package/esm2022/app/reports/report-filter-items.mjs +28 -3
  81. package/esm2022/app/reports/report-url-state.mjs +56 -15
  82. package/esm2022/app/reports/services/report-filter-state.service.mjs +274 -22
  83. package/esm2022/app/reports/theme/echarts.mjs +8 -2
  84. package/esm2022/app/reports/theme/palette.mjs +35 -1
  85. package/esm2022/app/reports/theme/typography.mjs +8 -1
  86. package/esm2022/app/reports/views/report/fs-ai-report.component.mjs +2 -2
  87. package/esm2022/app/reports/views/report/report.component.mjs +3 -4
  88. package/esm2022/public_api.mjs +10 -1
  89. package/fesm2022/{firestitch-report-echarts-Djtmaxj1.mjs → firestitch-report-echarts-qCBE3LqM.mjs} +9 -3
  90. package/fesm2022/firestitch-report-echarts-qCBE3LqM.mjs.map +1 -0
  91. package/fesm2022/{firestitch-report-firestitch-report-D3zseBZc.mjs → firestitch-report-firestitch-report-DbsWbE-j.mjs} +5523 -875
  92. package/fesm2022/firestitch-report-firestitch-report-DbsWbE-j.mjs.map +1 -0
  93. package/fesm2022/firestitch-report.mjs +1 -1
  94. package/package.json +1 -1
  95. package/public_api.d.ts +9 -0
  96. package/fesm2022/firestitch-report-echarts-Djtmaxj1.mjs.map +0 -1
  97. package/fesm2022/firestitch-report-firestitch-report-D3zseBZc.mjs.map +0 -1
@@ -1,55 +1,620 @@
1
- import { format, isValid, parseISO } from 'date-fns';
1
+ import { isValid, parseISO } from 'date-fns';
2
2
  import { formatInTimeZone, toZonedTime } from 'date-fns-tz';
3
- // Measure-value formatting shared by the KPI renderer and the exports — the
4
- // config's `format` (number | percent | currency) and `precision` mean the same
5
- // thing on screen, in PowerPoint and in PDF.
6
- // percent takes a 0-1 ratio and shows it as a percentage: 0.3 reads 30%. With
7
- // no precision it shows at most one decimal (0.037 reads 3.7%); a named
8
- // precision counts the decimals of the percentage, not of the ratio, so
9
- // precision 1 shows 0.3 as 30.0%. An older server sends percent values already
10
- // x100 (38.5 for 38.5%); its reports carry no `percentFormat`, and the caller
11
- // passes ratioPercent false so the value is printed as it came, with a % sign.
12
- //
13
- // When the measure names a precision it is pinned as BOTH the minimum and the
14
- // maximum, so a column of rates lines up instead of each value showing however
15
- // many decimals it happens to need. Undefined leaves each format's own default
16
- // alone.
17
- function getFractionDigits(precision) {
18
- return Number.isFinite(precision)
19
- ? { minimumFractionDigits: precision, maximumFractionDigits: precision }
20
- : {};
21
- }
22
- export function formatMeasureValue(value, format, precision, ratioPercent = true) {
23
- if (value === null || value === undefined || value === '') {
24
- return '—';
3
+ import { ReportListColumnFormat } from './enums/report-list-column-format.enum';
4
+ import { ReportNumberUnits } from './enums/report-number-units.enum';
5
+ import { ReportValueFormat } from './enums/report-value-format.enum';
6
+ // What a report reads when the server names no usable locale or currency: an
7
+ // older server that sends neither, or a value this browser's Intl cannot use.
8
+ // Never the browser's own locale, so every viewer of a report sees the same text.
9
+ export const REPORT_FALLBACK_LOCALE = 'en-US';
10
+ export const REPORT_FALLBACK_CURRENCY = 'USD';
11
+ export const DEFAULT_FORMAT_CONTEXT = Object.freeze({
12
+ locale: REPORT_FALLBACK_LOCALE,
13
+ currency: REPORT_FALLBACK_CURRENCY,
14
+ ratioPercent: true,
15
+ });
16
+ const CURRENCY_PATTERN = /^[A-Z]{3}$/;
17
+ // The server's resolved locale as one this browser can format in. A malformed
18
+ // tag ('en_CA') makes supportedLocalesOf throw, and one Intl has no data for
19
+ // ('xx-YY') comes back empty; both read the fallback.
20
+ export function resolveReportLocale(tag) {
21
+ if (!tag) {
22
+ return REPORT_FALLBACK_LOCALE;
23
+ }
24
+ try {
25
+ return Intl.NumberFormat.supportedLocalesOf([tag])[0] ?? REPORT_FALLBACK_LOCALE;
26
+ }
27
+ catch {
28
+ return REPORT_FALLBACK_LOCALE;
29
+ }
30
+ }
31
+ // The server's resolved currency as one Intl can label. The server decides
32
+ // which codes name money; this only guards against a code Intl cannot take at
33
+ // all. It is never checked against the runtime's own currency list, which
34
+ // differs between browsers and leaves out codes the server offers (VEF, MRO),
35
+ // so every viewer labels a report's money the same way.
36
+ export function resolveReportCurrency(code) {
37
+ if (!code || !CURRENCY_PATTERN.test(code)) {
38
+ return REPORT_FALLBACK_CURRENCY;
39
+ }
40
+ try {
41
+ numberFormat(REPORT_FALLBACK_LOCALE, { style: 'currency', currency: code });
42
+ return code;
43
+ }
44
+ catch {
45
+ return REPORT_FALLBACK_CURRENCY;
46
+ }
47
+ }
48
+ // The one place a report's format context is built: the server's effective
49
+ // locale and currency (absent on an older server, which then reads en-US/USD)
50
+ // and whether its percent measures arrive as 0-1 ratios.
51
+ export function resolveFormatContext(report) {
52
+ return {
53
+ locale: resolveReportLocale(report.effectiveLocale),
54
+ currency: resolveReportCurrency(report.effectiveCurrency),
55
+ ratioPercent: report.percentFormat === 'ratio',
56
+ };
57
+ }
58
+ // Building an Intl formatter is far slower than using one, and a chart formats
59
+ // every tick and tooltip value, so each distinct locale + options (+ zone) is
60
+ // built once and reused.
61
+ const NUMBER_FORMATS = new Map();
62
+ const DATE_FORMATS = new Map();
63
+ export function numberFormat(locale, options) {
64
+ const key = `${locale}|${JSON.stringify(options)}`;
65
+ let formatter = NUMBER_FORMATS.get(key);
66
+ if (!formatter) {
67
+ formatter = new Intl.NumberFormat(locale, options);
68
+ NUMBER_FORMATS.set(key, formatter);
69
+ }
70
+ return formatter;
71
+ }
72
+ // No zone formats in the browser's own zone, which is right for a calendar day
73
+ // parsed as local midnight: the day printed is the day stored.
74
+ export function dateFormat(locale, options, timeZone) {
75
+ const key = `${locale}|${JSON.stringify(options)}|${timeZone ?? ''}`;
76
+ let formatter = DATE_FORMATS.get(key);
77
+ if (!formatter) {
78
+ formatter = new Intl.DateTimeFormat(locale, { ...options, timeZone });
79
+ DATE_FORMATS.set(key, formatter);
80
+ }
81
+ return formatter;
82
+ }
83
+ // Number formatting: the one engine behind every numeric slot (a chart
84
+ // measure, a KPI measure, a list column, a cross-tab's cells), so a format
85
+ // means the same thing on screen, in the PDF and in PowerPoint. The data stays
86
+ // raw; only what is shown changes. The rules:
87
+ // - Empty: null, undefined, '', '-' and a non-finite number print the caller's
88
+ // `empty` ('—' unless it names another).
89
+ // - Numeric: a finite number, or a string that spells one plainly ('1234.50',
90
+ // '-3e2'). Anything else ('$1,234', an id with letters, ' ') prints as it
91
+ // came, since a column the SQL already formatted is text.
92
+ // - Styles: number is a plain decimal; currency is the report's currency
93
+ // written in its locale with its symbol (USD reads '$1,235' in en-US and
94
+ // 'US$1,235' in en-CA; EUR reads '1 235 €' in fr-FR); percent takes a 0-1
95
+ // ratio (0.3 reads 30%), or, from an older server that sends percent values
96
+ // already x100, a decimal with a % sign. Precision or units without a format
97
+ // mean number.
98
+ // - Decimals: a precision pins both the minimum and the maximum, so a column
99
+ // of rates lines up. Without one: at most one for a percent and for an
100
+ // abbreviated value (1.2K), whole units for currency, the locale's default
101
+ // for a number.
102
+ // - Units: thousands and millions divide and add a K or M after the digits
103
+ // ('$1.2K', '1,2K $'); auto picks per value by size, and a value that would
104
+ // round to 1000K reads 1M. Units never apply to a percent.
105
+ // - Negatives keep the locale's leading minus. A negative that rounds to zero
106
+ // prints as zero, never '-0'.
107
+ // - Rounding is Intl's, on the digits shown. Every value is written in the
108
+ // context's locale, never the browser's.
109
+ // The most decimals a precision pins: the server's schema bound.
110
+ const MAX_PRECISION = 6;
111
+ // At most one decimal for a percent, and for an abbreviated value (1.2K).
112
+ const PERCENT_DECIMALS = 1;
113
+ const SCALED_DECIMALS = 1;
114
+ // Money shows whole units unless a precision asks for decimals.
115
+ const CURRENCY_DECIMALS = 0;
116
+ // A currency axis whose ticks need decimals shows cents, not tenths.
117
+ const CURRENCY_AXIS_DECIMALS = 2;
118
+ // What a missing value prints unless the caller names its own.
119
+ const EMPTY_VALUE = '—';
120
+ // The tick count a value axis aims for, as ECharts' splitNumber default.
121
+ const AXIS_TICKS = 5;
122
+ // A change's sign: a plus on a positive value, nothing on zero.
123
+ const SIGNED = { signDisplay: 'exceptZero' };
124
+ const NUMERIC_PATTERN = /^\s*[-+]?(\d+\.?\d*|\.\d+)([eE][-+]?\d+)?\s*$/;
125
+ // The formatToParts types that carry a number's digits and separators.
126
+ const NUMBER_PARTS = new Set(['integer', 'group', 'decimal', 'fraction']);
127
+ const DIGIT_PARTS = new Set(['integer', 'fraction']);
128
+ const UNIT_SCALES = new Map([
129
+ [ReportNumberUnits.Thousands, { divisor: 1e3, suffix: 'K', commas: ',' }],
130
+ [ReportNumberUnits.Millions, { divisor: 1e6, suffix: 'M', commas: ',,' }],
131
+ ]);
132
+ // The value as a finite number when it is one or plainly spells one, else
133
+ // null.
134
+ export function toFiniteNumber(value) {
135
+ if (typeof value === 'number') {
136
+ return Number.isFinite(value) ? value : null;
137
+ }
138
+ if (typeof value !== 'string' || !NUMERIC_PATTERN.test(value)) {
139
+ return null;
25
140
  }
26
141
  const numeric = Number(value);
27
- if (!Number.isFinite(numeric)) {
142
+ return Number.isFinite(numeric) ? numeric : null;
143
+ }
144
+ // Whether a slot asks to be formatted at all. A slot without these keys, or a
145
+ // list column whose format is date, keeps its own rendering. Units none is the
146
+ // same as no units key, as it is on the server.
147
+ export function hasNumberFormat(spec) {
148
+ if (!spec || spec.format === ReportListColumnFormat.Date) {
149
+ return false;
150
+ }
151
+ return valueFormat(spec) !== null
152
+ || (spec.precision ?? null) !== null
153
+ || ((spec.units ?? ReportNumberUnits.None) !== ReportNumberUnits.None);
154
+ }
155
+ // The units a value is written in. auto decides by the magnitude: a million
156
+ // and up reads M, a thousand and up K, unless the value would then round to
157
+ // 1000K at these decimals, which reads 1M instead.
158
+ export function resolveUnits(units, magnitude, decimals) {
159
+ switch (units) {
160
+ case ReportNumberUnits.Thousands:
161
+ case ReportNumberUnits.Millions:
162
+ return units;
163
+ case ReportNumberUnits.Auto:
164
+ return autoUnits(Math.abs(magnitude), decimals);
165
+ default:
166
+ return ReportNumberUnits.None;
167
+ }
168
+ }
169
+ function autoUnits(magnitude, decimals) {
170
+ if (magnitude >= 1e6) {
171
+ return ReportNumberUnits.Millions;
172
+ }
173
+ if (magnitude < 1e3) {
174
+ return ReportNumberUnits.None;
175
+ }
176
+ return roundTo(magnitude / 1e3, decimals) >= 1000
177
+ ? ReportNumberUnits.Millions
178
+ : ReportNumberUnits.Thousands;
179
+ }
180
+ // The value rounded as Intl rounds it for display, so the K-to-M promotion
181
+ // agrees with the digits actually shown.
182
+ function roundTo(value, decimals) {
183
+ const digits = clampDecimals(decimals) ?? 0;
184
+ // A fixed locale only so Number() can parse the rounded digits back.
185
+ return Number(numberFormat(REPORT_FALLBACK_LOCALE, {
186
+ useGrouping: false,
187
+ minimumFractionDigits: 0,
188
+ maximumFractionDigits: digits,
189
+ }).format(value));
190
+ }
191
+ // One value, written by the rules above.
192
+ export function formatNumber(value, spec, context, options = {}) {
193
+ if (isEmptyValue(value)) {
194
+ return options.empty ?? EMPTY_VALUE;
195
+ }
196
+ const numeric = toFiniteNumber(value);
197
+ if (numeric === null) {
28
198
  return String(value);
29
199
  }
30
- const fractionDigits = getFractionDigits(precision);
31
- switch (format) {
32
- case 'percent':
33
- if (!ratioPercent) {
34
- return `${new Intl.NumberFormat(undefined, { maximumFractionDigits: 1, ...fractionDigits }).format(numeric)}%`;
35
- }
36
- return new Intl.NumberFormat(undefined, {
37
- style: 'percent',
38
- maximumFractionDigits: 1,
39
- ...fractionDigits,
40
- }).format(numeric);
41
- case 'currency':
42
- return new Intl.NumberFormat(undefined, {
43
- style: 'currency',
44
- currency: 'USD',
45
- // Whole dollars unless the measure asks for decimals — cents were
46
- // unrepresentable before, because this was hardcoded to 0.
47
- maximumFractionDigits: 0,
48
- ...fractionDigits,
49
- }).format(numeric);
200
+ const style = resolveStyle(spec);
201
+ const precision = clampDecimals(spec?.precision);
202
+ const units = style === ReportValueFormat.Percent
203
+ ? ReportNumberUnits.None
204
+ : options.units ?? resolveUnits(spec?.units, numeric, precision ?? SCALED_DECIMALS);
205
+ const scale = UNIT_SCALES.get(units);
206
+ const decimals = clampDecimals(options.decimals) ?? precision;
207
+ const formatter = numberFormat(context.locale, {
208
+ ...styleOptions(style, context, decimals, !!scale),
209
+ ...(options.signed ? SIGNED : {}),
210
+ });
211
+ const text = writeNumber(formatter, (numeric === 0 ? 0 : numeric) / (scale?.divisor ?? 1), scale?.suffix);
212
+ return style === ReportValueFormat.Percent && !context.ratioPercent ? `${text}%` : text;
213
+ }
214
+ function isEmptyValue(value) {
215
+ return value === null
216
+ || value === undefined
217
+ || value === ''
218
+ || value === '-'
219
+ || (typeof value === 'number' && !Number.isFinite(value));
220
+ }
221
+ // The value format a slot names, or null when it names none (or only date).
222
+ function valueFormat(spec) {
223
+ return Object.values(ReportValueFormat).find((format) => format === spec?.format) ?? null;
224
+ }
225
+ function resolveStyle(spec) {
226
+ return valueFormat(spec) ?? ReportValueFormat.Number;
227
+ }
228
+ // A usable decimal count, or null. A stored value outside the schema's bounds
229
+ // is brought inside them rather than thrown on by Intl.
230
+ function clampDecimals(decimals) {
231
+ return typeof decimals === 'number' && Number.isFinite(decimals)
232
+ ? Math.min(MAX_PRECISION, Math.max(0, Math.round(decimals)))
233
+ : null;
234
+ }
235
+ function styleOptions(style, context, decimals, scaled) {
236
+ const fractionDigits = fractionDigitOptions(decimals, defaultDecimals(style, scaled));
237
+ switch (style) {
238
+ case ReportValueFormat.Currency:
239
+ return { ...currencyOptions(context.currency), ...fractionDigits };
240
+ case ReportValueFormat.Percent:
241
+ return context.ratioPercent ? { style: 'percent', ...fractionDigits } : fractionDigits;
242
+ default:
243
+ return fractionDigits;
244
+ }
245
+ }
246
+ function currencyOptions(currency) {
247
+ return { style: 'currency', currency, currencyDisplay: 'symbol' };
248
+ }
249
+ // The most decimals a style shows when nothing pins them; null leaves Intl's
250
+ // own default.
251
+ function defaultDecimals(style, scaled) {
252
+ if (scaled) {
253
+ return SCALED_DECIMALS;
254
+ }
255
+ switch (style) {
256
+ case ReportValueFormat.Percent:
257
+ return PERCENT_DECIMALS;
258
+ case ReportValueFormat.Currency:
259
+ return CURRENCY_DECIMALS;
50
260
  default:
51
- return new Intl.NumberFormat(undefined, fractionDigits).format(numeric);
261
+ return null;
262
+ }
263
+ }
264
+ // Pinned decimals set both bounds. Otherwise a maximum also sets the minimum
265
+ // to zero, so no engine throws on a maximum below a currency's own minimum.
266
+ function fractionDigitOptions(pinned, maximum) {
267
+ if (pinned !== null) {
268
+ return { minimumFractionDigits: pinned, maximumFractionDigits: pinned };
269
+ }
270
+ return maximum === null ? {} : { minimumFractionDigits: 0, maximumFractionDigits: maximum };
271
+ }
272
+ // The formatted value, with the units letter after its digits. A negative
273
+ // whose shown digits are all zero is written as zero, so no '-0' appears.
274
+ function writeNumber(formatter, value, suffix) {
275
+ if (value >= 0 && !suffix) {
276
+ return formatter.format(value);
277
+ }
278
+ const parts = formatter.formatToParts(value);
279
+ if (value < 0 && !hasNonZeroDigit(formatter, parts)) {
280
+ return writeNumber(formatter, 0, suffix);
281
+ }
282
+ if (!suffix) {
283
+ return parts.map((part) => part.value).join('');
284
+ }
285
+ const last = parts.reduce((found, part, index) => NUMBER_PARTS.has(part.type) ? index : found, -1);
286
+ return [
287
+ ...parts.slice(0, last + 1).map((part) => part.value),
288
+ suffix,
289
+ ...parts.slice(last + 1).map((part) => part.value),
290
+ ].join('');
291
+ }
292
+ // Compared with the locale's own zero, so a numbering system other than
293
+ // 0-9 is read correctly.
294
+ function hasNonZeroDigit(formatter, parts) {
295
+ const zero = formatter.formatToParts(0).find((part) => part.type === 'integer')?.value ?? '0';
296
+ return parts.some((part) => DIGIT_PARTS.has(part.type)
297
+ && Array.from(part.value).some((character) => character !== zero));
298
+ }
299
+ // Output values: a column the server marks in ComponentData.outputs (a
300
+ // compared value, a rank, a share) written by what it is. The data stays raw;
301
+ // every number still goes through formatNumber. The rules:
302
+ // - The format: a slot's own explicit format always wins. Otherwise a current,
303
+ // prior or change column takes its source measure's format; a percent change
304
+ // is a percent; a rank is a whole number; a share is a percent to 1 decimal.
305
+ // An own precision or units still applies over those defaults.
306
+ // - Signs: a change and a percent change are signed ('+579', '-31.1%').
307
+ // - Points: a change of a percent-format value, and any share change, is a
308
+ // difference of two rates, so it prints in percentage points, signed and to
309
+ // 1 decimal unless a precision pins others: 0.1 reads '+10.0 pp'.
310
+ // - Missing: a missing prior, or a change or percent change left empty by
311
+ // one, prints '—' titled with the floor ('No baseline: no data before
312
+ // Mar 3, 2026'), or for a rank or a share with the period the row was
313
+ // absent from ('No rank in the prior period'); a percent change over a prior of 0 prints 'n/a' titled
314
+ // 'Prior was 0'. Any other missing value prints '—' (or the caller's empty).
315
+ // - Rank change: prior minus current, so a rise is positive: '▲ 2', '▼ 1',
316
+ // '–' for none, and 'new' for an empty change whose prior rank is missing
317
+ // or not passed (a row always has a current rank, so only the prior lacks).
318
+ // A percent change and a share are 0-1 fractions whatever the report's
319
+ // percentFormat: the server computes them, never a stored value.
320
+ // A missing comparison value prints EMPTY_VALUE whatever the caller's empty.
321
+ const NOT_APPLICABLE_VALUE = 'n/a';
322
+ const NEW_RANK_VALUE = 'new';
323
+ const RANK_UNCHANGED_VALUE = '–';
324
+ const RANK_UP_MARK = '▲';
325
+ const RANK_DOWN_MARK = '▼';
326
+ const POINTS_SUFFIX = 'pp';
327
+ const NO_PRIOR_RANK_TITLE = 'No rank in the prior period';
328
+ const NO_PRIOR_SHARE_TITLE = 'No share in the prior period';
329
+ // Percentage points and a share are written to one decimal unless pinned.
330
+ const POINTS_DECIMALS = 1;
331
+ const SHARE_DECIMALS = 1;
332
+ const RANK_DEFAULT_SPEC = Object.freeze({ format: ReportValueFormat.Number, precision: 0 });
333
+ const SHARE_DEFAULT_SPEC = Object.freeze({
334
+ format: ReportValueFormat.Percent,
335
+ precision: SHARE_DECIMALS,
336
+ });
337
+ const PERCENT_CHANGE_DEFAULT_SPEC = Object.freeze({ format: ReportValueFormat.Percent });
338
+ // One output value, written by the rules above. Without output metadata (a
339
+ // plain measure column, an older server) it is formatNumber with the slot's
340
+ // own format.
341
+ export function formatOutputValue(value, output, spec, context, options = {}) {
342
+ if (!output) {
343
+ return plainOutput(formatNumber(value, spec, context, { empty: options.empty }));
344
+ }
345
+ if (output.kind === 'rank' && output.role === 'change') {
346
+ return formatRankChange(value, spec, context, options);
347
+ }
348
+ const role = output.role;
349
+ const effective = outputFormatSpec(output, spec, options.measureSpec);
350
+ if (isEmptyValue(value)) {
351
+ return missingOutput(output, context, options);
352
+ }
353
+ if (role === 'change' && isPointsChange(output, effective)) {
354
+ return plainOutput(formatPoints(value, output, effective, context));
355
+ }
356
+ const signed = role === 'change' || role === 'percent_change';
357
+ const ratioContext = role === 'percent_change' || output.kind === 'share'
358
+ ? { ...context, ratioPercent: true }
359
+ : context;
360
+ return plainOutput(formatNumber(value, effective, ratioContext, { signed }));
361
+ }
362
+ // The alias of the output that plays `role` in the same lane as `alias`: the
363
+ // same measure and kind, and (for a prior, change or percent change) the same
364
+ // prior lane. A measure compares against one lane only (two compares on one
365
+ // value are two measures), so a current value's lane is whichever one its
366
+ // measure's prior columns carry, lane 2 as readily as lane 1. A change column
367
+ // finds its prior this way to pass as OutputValueOptions.prior. null when the
368
+ // server sends no such column.
369
+ export function laneOutputAlias(outputs, alias, role) {
370
+ const source = outputs?.[alias];
371
+ if (!source) {
372
+ return null;
373
+ }
374
+ const anyLane = source.role === 'current' || source.offset === null;
375
+ const found = Object.entries(outputs ?? {}).find(([, meta]) => meta.measure === source.measure
376
+ && meta.kind === source.kind
377
+ && meta.role === role
378
+ && (role === 'current' || (anyLane ? meta.offset !== null : meta.offset === source.offset)));
379
+ return found ? found[0] : null;
380
+ }
381
+ function plainOutput(text) {
382
+ return { text, title: null };
383
+ }
384
+ // The format an output is written in: the slot's own explicit format, else
385
+ // the default for what it holds, with any own precision or units over it.
386
+ function outputFormatSpec(output, own, measureSpec) {
387
+ if (valueFormat(own) !== null) {
388
+ return own;
389
+ }
390
+ if (output.kind === 'rank') {
391
+ return withOwnDigits(RANK_DEFAULT_SPEC, own);
392
+ }
393
+ if (output.kind === 'share') {
394
+ return withOwnDigits(SHARE_DEFAULT_SPEC, own);
395
+ }
396
+ if (output.role === 'percent_change') {
397
+ return withOwnDigits(PERCENT_CHANGE_DEFAULT_SPEC, own);
398
+ }
399
+ return measureSpec ? withOwnDigits(measureSpec, own) : own ?? null;
400
+ }
401
+ // The base format with the slot's own precision and units over it.
402
+ function withOwnDigits(base, own) {
403
+ return {
404
+ ...base,
405
+ ...((own?.precision ?? null) !== null ? { precision: own.precision } : {}),
406
+ ...((own?.units ?? null) !== null ? { units: own.units } : {}),
407
+ };
408
+ }
409
+ // A change between two rates: a share's, or a percent-format value's.
410
+ function isPointsChange(output, spec) {
411
+ return output.kind === 'share' || resolveStyle(spec) === ReportValueFormat.Percent;
412
+ }
413
+ // A rate change in percentage points. A share and a 0-1 percent are scaled
414
+ // x100; an older server's percent values already are.
415
+ function formatPoints(value, output, spec, context) {
416
+ const numeric = toFiniteNumber(value);
417
+ if (numeric === null) {
418
+ return String(value);
52
419
  }
420
+ const points = output.kind === 'share' || context.ratioPercent ? numeric * 100 : numeric;
421
+ const decimals = clampDecimals(spec?.precision) ?? POINTS_DECIMALS;
422
+ const text = formatNumber(points, { format: ReportValueFormat.Number }, context, { decimals, signed: true });
423
+ return `${text} ${POINTS_SUFFIX}`;
424
+ }
425
+ // A missing output value. A missing prior, or a delta a missing prior left
426
+ // empty, has no baseline; a percent change over a zero prior has none to
427
+ // divide by.
428
+ function missingOutput(output, context, options) {
429
+ const role = output.role;
430
+ if (role === 'prior') {
431
+ return { text: EMPTY_VALUE, title: missingPriorTitle(output, options.floor, context.locale) };
432
+ }
433
+ if (role === 'change' || role === 'percent_change') {
434
+ const prior = options.prior;
435
+ if (role === 'percent_change' && toFiniteNumber(prior) === 0) {
436
+ return { text: NOT_APPLICABLE_VALUE, title: 'Prior was 0' };
437
+ }
438
+ return {
439
+ text: EMPTY_VALUE,
440
+ title: prior !== undefined && isEmptyValue(prior)
441
+ ? missingPriorTitle(output, options.floor, context.locale)
442
+ : null,
443
+ };
444
+ }
445
+ return plainOutput(options.empty ?? EMPTY_VALUE);
446
+ }
447
+ // Why a prior is missing. A value's prior is missing when its window ends
448
+ // before the data starts. A rank's or a share's is missing when the row had
449
+ // no rank or share in the prior period, whatever the floor.
450
+ function missingPriorTitle(output, floor, locale) {
451
+ if (output.kind === 'rank') {
452
+ return NO_PRIOR_RANK_TITLE;
453
+ }
454
+ if (output.kind === 'share') {
455
+ return NO_PRIOR_SHARE_TITLE;
456
+ }
457
+ return noBaselineTitle(floor, locale);
458
+ }
459
+ function noBaselineTitle(floor, locale) {
460
+ const day = floor ? formatDay(floor, locale) : '';
461
+ return day ? `No baseline: no data before ${day}` : 'No baseline';
462
+ }
463
+ // A rank change: prior rank minus current, so moving up is positive.
464
+ function formatRankChange(value, spec, context, options) {
465
+ if (isEmptyValue(value)) {
466
+ return isEmptyValue(options.prior)
467
+ ? { text: NEW_RANK_VALUE, title: NO_PRIOR_RANK_TITLE }
468
+ : plainOutput(EMPTY_VALUE);
469
+ }
470
+ const numeric = toFiniteNumber(value);
471
+ if (numeric === null) {
472
+ return plainOutput(String(value));
473
+ }
474
+ const rankSpec = valueFormat(spec) !== null ? spec : withOwnDigits(RANK_DEFAULT_SPEC, spec);
475
+ const places = formatNumber(Math.abs(numeric), rankSpec, context);
476
+ if (places === formatNumber(0, rankSpec, context)) {
477
+ return plainOutput(RANK_UNCHANGED_VALUE);
478
+ }
479
+ return plainOutput(`${numeric > 0 ? RANK_UP_MARK : RANK_DOWN_MARK} ${places}`);
480
+ }
481
+ // A chart's value axis takes a format only when every measure on it agrees on
482
+ // the style (each measure's format, number when it names none) and at least
483
+ // one of them names a format. The first measure that does gives the axis its
484
+ // precision and units. Otherwise null: the axis keeps its default ticks on
485
+ // screen and in PowerPoint, and each series still formats its own tooltips.
486
+ export function axisNumberFormat(measures) {
487
+ const style = measures.length ? resolveStyle(measures[0]) : null;
488
+ if (style === null || measures.some((measure) => resolveStyle(measure) !== style)) {
489
+ return null;
490
+ }
491
+ const formatted = measures.find((measure) => hasNumberFormat(measure));
492
+ return formatted ? numberFormatSpec(formatted) : null;
493
+ }
494
+ function numberFormatSpec(spec) {
495
+ return {
496
+ ...(spec.format !== undefined ? { format: spec.format } : {}),
497
+ ...(spec.precision !== undefined ? { precision: spec.precision } : {}),
498
+ ...(spec.units !== undefined ? { units: spec.units } : {}),
499
+ };
500
+ }
501
+ // How a chart's value axis writes its ticks: the units decided once from the
502
+ // axis peak, and the decimals the precision pins, else as many as the axis's
503
+ // tick step needs (a percent axis up to 0.12% steps by 0.02%, two decimals).
504
+ // Pinned decimals keep the ticks distinct, and PowerPoint can only pin them.
505
+ export function resolveChartNumberFormat(spec, peak, context) {
506
+ const style = resolveStyle(spec);
507
+ const precision = clampDecimals(spec.precision);
508
+ const units = style === ReportValueFormat.Percent
509
+ ? ReportNumberUnits.None
510
+ : resolveUnits(spec.units, peak, precision ?? SCALED_DECIMALS);
511
+ return { units, decimals: precision ?? axisDecimals(style, units, peak, context) };
512
+ }
513
+ // The decimals the axis's nice tick step needs. A plain, unabbreviated number
514
+ // pins none (null): its ticks keep their own decimals. An unscaled currency
515
+ // axis that needs decimals shows cents, and a K/M axis keeps its step's
516
+ // decimals ('$0.5M', not '$0.50M').
517
+ function axisDecimals(style, units, peak, context) {
518
+ const scale = UNIT_SCALES.get(units);
519
+ if (style === ReportValueFormat.Number && !scale) {
520
+ return null;
521
+ }
522
+ const shownPeak = style === ReportValueFormat.Percent && context.ratioPercent
523
+ ? Math.abs(peak) * 100
524
+ : Math.abs(peak) / (scale?.divisor ?? 1);
525
+ const step = niceStep(shownPeak / AXIS_TICKS);
526
+ const decimals = step > 0 ? clampDecimals(-Math.floor(Math.log10(step))) ?? 0 : 0;
527
+ return style === ReportValueFormat.Currency && decimals > 0 && !scale ? CURRENCY_AXIS_DECIMALS : decimals;
528
+ }
529
+ // ECharts' nice(): the round number (1, 2, 3, 5 or 10 times a power of ten) a
530
+ // rough tick step snaps to.
531
+ function niceStep(rough) {
532
+ if (!(rough > 0) || !Number.isFinite(rough)) {
533
+ return 0;
534
+ }
535
+ const exponent = Math.floor(Math.log10(rough));
536
+ const power = Math.pow(10, exponent);
537
+ const fraction = rough / power;
538
+ let nice = 10;
539
+ if (fraction < 1.5) {
540
+ nice = 1;
541
+ }
542
+ else if (fraction < 2.5) {
543
+ nice = 2;
544
+ }
545
+ else if (fraction < 4) {
546
+ nice = 3;
547
+ }
548
+ else if (fraction < 7) {
549
+ nice = 5;
550
+ }
551
+ return nice * power;
552
+ }
553
+ // PowerPoint's number format code for a formatted value axis, matching the
554
+ // screen's ticks: '#,##0.0%' (percent), '"$"#,##0' (currency),
555
+ // '#,##0.0,"K"' (thousands), '#,##0" $"' (fr-CA currency). A plain number
556
+ // whose decimals are not pinned keeps chartAxisFormatCode's code. The code's
557
+ // separators follow the opening machine's locale; the currency symbol and its
558
+ // side follow the report's.
559
+ export function numberFormatCode(spec, context, chart, series, stacked) {
560
+ const style = resolveStyle(spec);
561
+ const scale = style === ReportValueFormat.Percent ? undefined : UNIT_SCALES.get(chart.units);
562
+ if (style === ReportValueFormat.Number && !scale && chart.decimals === null) {
563
+ return chartAxisFormatCode(series, stacked);
564
+ }
565
+ const decimals = chart.decimals ?? 0;
566
+ const digits = `#,##0${decimals > 0 ? `.${'0'.repeat(decimals)}` : ''}`;
567
+ if (style === ReportValueFormat.Percent) {
568
+ return `${digits}${context.ratioPercent ? '%' : '"%"'}`;
569
+ }
570
+ const scaled = `${digits}${scale?.commas ?? ''}`;
571
+ const unit = scale?.suffix ?? '';
572
+ if (style !== ReportValueFormat.Currency) {
573
+ return unit ? `${scaled}"${unit}"` : scaled;
574
+ }
575
+ const symbol = currencySymbol(context);
576
+ return symbol.prefix
577
+ ? `"${symbol.text}"${scaled}${unit ? `"${unit}"` : ''}`
578
+ : `${scaled}"${unit}${symbol.text}"`;
579
+ }
580
+ const CURRENCY_SYMBOLS = new Map();
581
+ function currencySymbol(context) {
582
+ const key = `${context.locale}|${context.currency}`;
583
+ let symbol = CURRENCY_SYMBOLS.get(key);
584
+ if (!symbol) {
585
+ const parts = numberFormat(context.locale, currencyOptions(context.currency)).formatToParts(1);
586
+ const currency = parts.findIndex((part) => part.type === 'currency');
587
+ const first = parts.findIndex((part) => NUMBER_PARTS.has(part.type));
588
+ const last = parts.reduce((found, part, index) => NUMBER_PARTS.has(part.type) ? index : found, -1);
589
+ const prefix = currency < first;
590
+ const text = (prefix ? parts.slice(Math.max(currency, 0), first) : parts.slice(last + 1))
591
+ .map((part) => part.value)
592
+ .join('')
593
+ .replace(/"/g, '');
594
+ symbol = { prefix, text };
595
+ CURRENCY_SYMBOLS.set(key, symbol);
596
+ }
597
+ return symbol;
598
+ }
599
+ // Every decimal a number has, grouped, in the locale: what ECharts prints by
600
+ // default (its addCommas), but in the report's locale, so a chart's axis and
601
+ // tooltip read like the rest of the report. 1234.5 reads 1,234.5 in en-US and
602
+ // 1 234,5 in fr-CA. A non-numeric string is shown as it came, and anything
603
+ // else non-numeric as '-', as ECharts shows it. As there, an infinite value
604
+ // reads 'Infinity' and negative zero (a tick a float error leaves just below
605
+ // zero) reads '0'.
606
+ const PLAIN_NUMBER = { maximumFractionDigits: 20 };
607
+ export function formatPlainNumber(value, locale) {
608
+ const numeric = typeof value === 'number'
609
+ ? value
610
+ : typeof value === 'string' && value.trim() !== '' ? Number(value) : NaN;
611
+ if (Number.isNaN(numeric)) {
612
+ return typeof value === 'string' ? value : '-';
613
+ }
614
+ if (!Number.isFinite(numeric)) {
615
+ return String(numeric);
616
+ }
617
+ return numberFormat(locale, PLAIN_NUMBER).format(numeric === 0 ? 0 : numeric);
53
618
  }
54
619
  // The axis peak at which a native chart's value axis gains thousands
55
620
  // separators. From here up the ticks are whole numbers in practice; below it
@@ -61,15 +626,19 @@ export const AXIS_SEPARATOR_THRESHOLD = 1000;
61
626
  // (where ticks are whole numbers) gets '#,##0', and a smaller range keeps
62
627
  // 'General' so fractional ticks (0.25, 0.5) are not rounded away.
63
628
  //
64
- // The peak counts a missing value as 0. A stacked chart's peak is its tallest
65
- // stack: the largest sum, per category, of every series' absolute value.
629
+ // The peak is chartValuePeak's.
66
630
  export function chartAxisFormatCode(series, stacked) {
631
+ return chartValuePeak(series, stacked) >= AXIS_SEPARATOR_THRESHOLD ? '#,##0' : 'General';
632
+ }
633
+ // The largest magnitude a chart's value axis has to reach. A missing value
634
+ // counts as 0. A stacked chart's peak is its tallest stack: the largest sum,
635
+ // per category, of every series' absolute value.
636
+ export function chartValuePeak(series, stacked) {
67
637
  const magnitudes = series.map((values) => values.map((value) => Math.abs(value ?? 0)));
68
- const peak = stacked
638
+ return stacked
69
639
  ? Math.max(0, ...(magnitudes[0] ?? []).map((_, index) => magnitudes
70
640
  .reduce((sum, values) => sum + (values[index] ?? 0), 0)))
71
641
  : Math.max(0, ...magnitudes.flat());
72
- return peak >= AXIS_SEPARATOR_THRESHOLD ? '#,##0' : 'General';
73
642
  }
74
643
  // The zone every date in a report is read in. The server resolves it (the
75
644
  // report's own zone, else the application's default reporting zone) and sends
@@ -80,6 +649,52 @@ export function chartAxisFormatCode(series, stacked) {
80
649
  export function resolveReportTimezone(report) {
81
650
  return report.effectiveTimezone ?? report.timezone ?? Intl.DateTimeFormat().resolvedOptions().timeZone;
82
651
  }
652
+ // The date shapes a report writes, each in the report's locale.
653
+ // 'Jan 5, 2026' / '5 janv. 2026': a date cell, a filter bound.
654
+ export const DAY_SHORT = { year: 'numeric', month: 'short', day: 'numeric' };
655
+ // 'January 5, 2026' / '5 janvier 2026': an export cover's date line.
656
+ export const DAY_LONG = { year: 'numeric', month: 'long', day: 'numeric' };
657
+ // 'January' / 'janvier': a monthly period label (its year is added apart).
658
+ export const MONTH_LONG = { month: 'long' };
659
+ // 'January 2026' / 'janvier 2026': a monthly period label written in full.
660
+ export const MONTH_YEAR = { year: 'numeric', month: 'long' };
661
+ // 'Jan 5' / '5 janv.': a daily or weekly period label.
662
+ export const MONTH_DAY = { month: 'short', day: 'numeric' };
663
+ // A date in the locale. With a zone, the day it falls on there; without one,
664
+ // the browser's zone, which keeps a calendar day parsed as local midnight
665
+ // unshifted. It never throws, since a pipe or an export calls it per cell: an
666
+ // invalid Date reads '', a malformed locale ('en_CA') reads the fallback
667
+ // locale, and an unknown zone reads UTC, which still names a real day.
668
+ export function formatLocalDate(date, locale, options, timeZone) {
669
+ if (Number.isNaN(date.getTime())) {
670
+ return '';
671
+ }
672
+ try {
673
+ return writeDate(dateFormat(locale, options, timeZone), date);
674
+ }
675
+ catch {
676
+ return formatFallbackDate(date, resolveReportLocale(locale), options, timeZone);
677
+ }
678
+ }
679
+ function formatFallbackDate(date, locale, options, timeZone) {
680
+ try {
681
+ return writeDate(dateFormat(locale, options, timeZone), date);
682
+ }
683
+ catch {
684
+ return writeDate(dateFormat(locale, options, 'UTC'), date);
685
+ }
686
+ }
687
+ // Intl writes a year below 1000 with only the digits it has ('Jan 1, 1'); a
688
+ // date's year is always written with four ('Jan 1, 0001'), so a sentinel day
689
+ // still reads as a date. Only such a year pays for formatToParts.
690
+ function writeDate(formatter, date) {
691
+ if (date.getUTCFullYear() > 1000) {
692
+ return formatter.format(date);
693
+ }
694
+ return formatter.formatToParts(date)
695
+ .map((part) => part.type === 'year' ? part.value.padStart(4, '0') : part.value)
696
+ .join('');
697
+ }
83
698
  const DATE_ONLY_PATTERN = /^\d{4}-\d{2}-\d{2}$/;
84
699
  const DATE_TIME_PATTERN = /^(\d{4}-\d{2}-\d{2})[ T](\d{2}:\d{2}:\d{2})(\.\d+)?$/;
85
700
  // A report row's date cell as a calendar day in the report's zone.
@@ -95,31 +710,276 @@ const DATE_TIME_PATTERN = /^(\d{4}-\d{2}-\d{2})[ T](\d{2}:\d{2}:\d{2})(\.\d+)?$/
95
710
  // - Anything else is shown as it came, and so is a value that has the shape
96
711
  // but names no real day (a zero date '0000-00-00', or '2026-02-30'): one
97
712
  // bad cell must not throw out of a pipe or abort an export.
98
- export function formatReportDate(value, timezone) {
713
+ // The day is written in the report's locale: 'Jan 5, 2026' in en-US, '5 janv.
714
+ // 2026' in fr-CA.
715
+ export function formatReportDate(value, timezone, locale) {
99
716
  if (value === null || value === undefined || value === '') {
100
717
  return '';
101
718
  }
102
719
  const text = String(value);
103
720
  if (DATE_ONLY_PATTERN.test(text)) {
104
721
  const day = parseISO(text);
105
- return isValid(day) ? format(day, 'MMM d, yyyy') : text;
722
+ return isValid(day) ? formatLocalDate(day, locale, DAY_SHORT) : text;
106
723
  }
107
724
  const dateTime = DATE_TIME_PATTERN.exec(text);
108
725
  if (!dateTime) {
109
726
  return text;
110
727
  }
111
728
  const instant = parseISO(`${dateTime[1]}T${dateTime[2]}Z`);
112
- if (!isValid(instant)) {
113
- return text;
729
+ return isValid(instant) ? formatLocalDate(instant, locale, DAY_SHORT, timezone) : text;
730
+ }
731
+ // The time of day an instant falls at in the report's zone: '2:23 PM' in
732
+ // en-US, '14 h 23' in fr-CA.
733
+ export const TIME_SHORT = { hour: 'numeric', minute: '2-digit' };
734
+ // A window's inclusive days, as the server sends them: 'yyyy-MM-dd' calendar
735
+ // days already in the report's zone. Like a date cell they are read as local
736
+ // midnight and written with NO zone, so a viewer in any zone sees the days
737
+ // sent. Both days: Intl's range in the locale ('Sep 1 – 30, 2026' in en-US,
738
+ // '1–30 sept. 2026' in fr-CA, one date when they are the same day). One day:
739
+ // an open window ('Since Sep 1, 2026', 'Through Sep 30, 2026'). Neither, or
740
+ // days that are not real ones: ''.
741
+ export function formatDayRange(start, end, locale, options = DAY_SHORT) {
742
+ const first = parseDay(start);
743
+ const last = parseDay(end);
744
+ if (first && last) {
745
+ return writeDayRange(first, last, locale, options);
746
+ }
747
+ if (first) {
748
+ return `Since ${formatLocalDate(first, locale, options)}`;
749
+ }
750
+ return last ? `Through ${formatLocalDate(last, locale, options)}` : '';
751
+ }
752
+ // The time a window ending today is cut at: the server's UTC
753
+ // 'yyyy-MM-dd HH:mm:ss' instant, as a time of day in the report's zone. ''
754
+ // for none, or for a value of another shape.
755
+ export function formatThroughTime(through, timezone, locale) {
756
+ const dateTime = through ? DATE_TIME_PATTERN.exec(through) : null;
757
+ const instant = dateTime ? parseISO(`${dateTime[1]}T${dateTime[2]}Z`) : null;
758
+ return instant && isValid(instant) ? formatLocalDate(instant, locale, TIME_SHORT, timezone) : '';
759
+ }
760
+ // A comparison or timeframe window in one line: its days, and the time it is
761
+ // cut at when it ends today on a date-and-time column ('Oct 1 – 2, 2026,
762
+ // until 2:23 PM').
763
+ export function formatDayWindow(meta, timezone, locale) {
764
+ const days = formatDayRange(meta.start, meta.end, locale);
765
+ const time = formatThroughTime(meta.through, timezone, locale);
766
+ return days && time ? `${days}, until ${time}` : days;
767
+ }
768
+ // One 'yyyy-MM-dd' day in the locale, written with no zone: 'Sep 1, 2026'.
769
+ function formatDay(day, locale) {
770
+ const date = parseDay(day);
771
+ return date ? formatLocalDate(date, locale, DAY_SHORT) : '';
772
+ }
773
+ // A 'yyyy-MM-dd' day as local midnight, or null when it is not a real day.
774
+ function parseDay(day) {
775
+ if (!day || !DATE_ONLY_PATTERN.test(day)) {
776
+ return null;
114
777
  }
115
- // An unknown zone makes date-fns-tz throw; UTC still names a real day.
778
+ const date = parseISO(day);
779
+ return isValid(date) ? date : null;
780
+ }
781
+ // Intl's range writes the shared month and year once. A malformed locale
782
+ // reads the fallback; a runtime that cannot write ranges joins two dates.
783
+ function writeDayRange(first, last, locale, options) {
784
+ const [from, to] = first <= last ? [first, last] : [last, first];
785
+ for (const tag of [locale, resolveReportLocale(locale)]) {
786
+ try {
787
+ return dateFormat(tag, options).formatRange(from, to);
788
+ }
789
+ catch {
790
+ // The next locale, then the joined dates.
791
+ }
792
+ }
793
+ return `${formatLocalDate(from, locale, options)} – ${formatLocalDate(to, locale, options)}`;
794
+ }
795
+ // English names for a locale and a currency, for the settings selects. The
796
+ // interface stays English whatever the report's locale: 'fr-CA' reads
797
+ // 'Canadian French', 'CAD' reads 'Canadian Dollar'. A runtime without the
798
+ // names shows the code.
799
+ export function localeName(tag) {
800
+ return displayName('language', tag);
801
+ }
802
+ export function currencyName(code) {
803
+ return displayName('currency', code);
804
+ }
805
+ function displayName(type, code) {
116
806
  try {
117
- return formatInTimeZone(instant, timezone, 'MMM d, yyyy');
807
+ return new Intl.DisplayNames(['en'], { type }).of(code) ?? code;
118
808
  }
119
809
  catch {
120
- return formatInTimeZone(instant, 'UTC', 'MMM d, yyyy');
810
+ return code;
121
811
  }
122
812
  }
813
+ // Comparison, window and KPI wording. The server sends codes and fields,
814
+ // never sentences (a window's description is for the agent and the exports'
815
+ // notes, not the screen); the interface words them here, in English like
816
+ // every other label, with any day written in the report's locale.
817
+ const GRANULARITY_UNITS = {
818
+ day: { one: 'day', many: 'days' },
819
+ week: { one: 'week', many: 'weeks' },
820
+ month: { one: 'month', many: 'months' },
821
+ quarter: { one: 'quarter', many: 'quarters' },
822
+ year: { one: 'year', many: 'years' },
823
+ };
824
+ // What a prior lane is called: always so for a named period, and for the
825
+ // previous period when the server names no unit for it.
826
+ const AGAINST_PHRASES = {
827
+ previous_period: 'previous period',
828
+ previous_week: 'previous week',
829
+ previous_month: 'previous month',
830
+ previous_quarter: 'previous quarter',
831
+ previous_year: 'previous year',
832
+ range: 'custom range',
833
+ };
834
+ // A prior lane's label, from its offset rather than from the measure, so a
835
+ // chart regrouped by the viewer says what it now compares. A named period
836
+ // reads by its name whatever shift carries it ('vs previous quarter' for 3
837
+ // months, 'vs previous year' for 364 days or 52 weeks, 'vs custom range').
838
+ // Only the previous period is worded from its unit and count: 'vs previous
839
+ // week', 'vs previous 3 months', 'vs previous 8 days' (a day-length shift).
840
+ export function comparisonOffsetLabel(offset) {
841
+ return `vs ${offsetPhrase(offset)}`;
842
+ }
843
+ function offsetPhrase(offset) {
844
+ if (offset.against !== 'previous_period' || !offset.unit || !offset.count) {
845
+ return AGAINST_PHRASES[offset.against] ?? AGAINST_PHRASES.previous_period;
846
+ }
847
+ return offset.count === 1
848
+ ? `previous ${GRANULARITY_UNITS[offset.unit].one}`
849
+ : `previous ${offset.count} ${GRANULARITY_UNITS[offset.unit].many}`;
850
+ }
851
+ // One comparison note as a sentence. The comparison, when given, names the
852
+ // period compared with (its first prior lane).
853
+ export function comparisonNoteText(code, comparison) {
854
+ const offset = comparison?.offsets?.[0] ?? null;
855
+ const compared = offset ? `Compared with the ${offsetPhrase(offset)}` : null;
856
+ switch (code) {
857
+ case 'no_window':
858
+ return 'Pick a date range to see the comparison.';
859
+ case 'unit_inferred':
860
+ return compared
861
+ ? `${compared}, judged from the dates picked.`
862
+ : 'The period compared with was judged from the dates picked.';
863
+ case 'window_in_future':
864
+ return 'The date range starts after today, so there is nothing to compare yet.';
865
+ case 'other_date_filter':
866
+ return 'A date filter on another column also applies to both periods.';
867
+ case 'grain_followed':
868
+ return compared
869
+ ? `${compared}, following the grouping picked.`
870
+ : 'The comparison follows the grouping picked.';
871
+ default:
872
+ return '';
873
+ }
874
+ }
875
+ // What a windowed value is: 'Rolling 3-month total', 'Month-to-date total',
876
+ // 'Running total since the start of the data', then its days when the server
877
+ // sends them ('Rolling 7-day average, Sep 24 – 30, 2026'). granularity is the
878
+ // grouping the rows are drawn at (ComponentData.granularity), which names a
879
+ // rolling window authored in periods of the axis.
880
+ export function windowText(meta, locale, granularity) {
881
+ const days = formatDayRange(meta.start, meta.end, locale);
882
+ const phrase = windowPhrase(meta, granularity ?? null);
883
+ return days ? `${phrase}, ${days}` : phrase;
884
+ }
885
+ function windowPhrase(meta, granularity) {
886
+ const value = meta.average ? 'average' : 'total';
887
+ switch (meta.kind) {
888
+ case 'running':
889
+ return meta.fromBeginning ? `Running ${value} since the start of the data` : `Running ${value}`;
890
+ case 'to_date': {
891
+ const reset = meta.resetEvery ? GRANULARITY_UNITS[meta.resetEvery].one : null;
892
+ return reset ? `${capitalize(reset)}-to-date ${value}` : `To-date ${value}`;
893
+ }
894
+ case 'rolling': {
895
+ const unit = meta.unit ?? granularity;
896
+ const span = meta.periods ? `${meta.periods}-${unit ? GRANULARITY_UNITS[unit].one : 'period'} ` : '';
897
+ return `Rolling ${span}${value}`;
898
+ }
899
+ default:
900
+ return capitalize(value);
901
+ }
902
+ }
903
+ // One window note as a sentence.
904
+ export function windowNoteText(code, meta, locale, granularity) {
905
+ switch (code) {
906
+ case 'snapped_start': {
907
+ const start = meta.start ? formatDay(meta.start, locale) : '';
908
+ return start
909
+ ? `The start was moved to ${start}, the start of its period, so the first period is whole.`
910
+ : 'The start was moved to the start of its period, so the first period is whole.';
911
+ }
912
+ case 'span_converted':
913
+ return spanConvertedText(meta, granularity ?? null);
914
+ case 'grain_too_coarse':
915
+ return 'The grouping is coarser than the window, so it has no values at this grouping.';
916
+ case 'equal_grain_plain':
917
+ return 'At this grouping each window is a single period, so the values are the plain ones.';
918
+ case 'own_filter_caps_lead_in':
919
+ return 'The query\'s own date condition starts the window, so earlier rows are not counted.';
920
+ case 'week_by_monday':
921
+ return 'A week that spans two periods counts toward the period its Monday falls in.';
922
+ case 'incomplete_head':
923
+ return 'The first periods are blank because there are not enough earlier rows to fill a whole window.';
924
+ default:
925
+ return '';
926
+ }
927
+ }
928
+ // '3 months are shown as 13 weeks at this grouping.'
929
+ function spanConvertedText(meta, granularity) {
930
+ if (!meta.periods || !meta.unit || !meta.drawnPeriods) {
931
+ return 'The window\'s span was converted to the grouping shown.';
932
+ }
933
+ const authored = unitCount(meta.periods, meta.unit);
934
+ const drawn = granularity
935
+ ? unitCount(meta.drawnPeriods, granularity)
936
+ : `${meta.drawnPeriods} ${meta.drawnPeriods === 1 ? 'period' : 'periods'}`;
937
+ return `${authored} ${meta.periods === 1 ? 'is' : 'are'} shown as ${drawn} at this grouping.`;
938
+ }
939
+ function unitCount(count, unit) {
940
+ return `${count} ${count === 1 ? GRANULARITY_UNITS[unit].one : GRANULARITY_UNITS[unit].many}`;
941
+ }
942
+ // Why a KPI's delta reads as it does, as a sentence. The baseline is named
943
+ // by what the value is compared against: the same period last year for a
944
+ // year-on-year comparison, else the period before.
945
+ export function kpiNoteText(code, against) {
946
+ const baseline = kpiBaselineText(against);
947
+ switch (code) {
948
+ case 'no_prior_data':
949
+ return `No baseline: ${baseline} has no data.`;
950
+ case 'up_from_zero':
951
+ return `New: ${baseline} was 0.`;
952
+ case 'no_change':
953
+ return `No change from ${baseline}.`;
954
+ case 'no_data_either':
955
+ return 'No data in either period.';
956
+ case 'sign_change':
957
+ return 'The value crossed zero, so there is no percent change.';
958
+ default:
959
+ return '';
960
+ }
961
+ }
962
+ // The window a KPI's value is compared with, as a noun phrase. An unknown or
963
+ // missing comparison reads as neutral wording rather than a wrong period.
964
+ function kpiBaselineText(against) {
965
+ switch (against) {
966
+ case 'previous_period':
967
+ return 'the previous period';
968
+ case 'previous_week':
969
+ return 'the previous week';
970
+ case 'previous_month':
971
+ return 'the previous month';
972
+ case 'previous_quarter':
973
+ return 'the previous quarter';
974
+ case 'previous_year':
975
+ return 'the same period last year';
976
+ default:
977
+ return 'the comparison period';
978
+ }
979
+ }
980
+ function capitalize(text) {
981
+ return text.charAt(0).toUpperCase() + text.slice(1);
982
+ }
123
983
  // A short, human label for a zone: its city plus the current abbreviation,
124
984
  // e.g. 'America/New_York' reads 'New York (EDT)'. UTC stays 'UTC', and an
125
985
  // unknown zone is shown as its id. An 'Etc/' zone names no city, and its POSIX
@@ -154,4 +1014,4 @@ export function getZonedNow(timezone) {
154
1014
  return now;
155
1015
  }
156
1016
  }
157
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZm9ybWF0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL2FwcC9yZXBvcnRzL2Zvcm1hdC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsTUFBTSxFQUFFLE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSxVQUFVLENBQUM7QUFDckQsT0FBTyxFQUFFLGdCQUFnQixFQUFFLFdBQVcsRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUs1RCw0RUFBNEU7QUFDNUUsZ0ZBQWdGO0FBQ2hGLDZDQUE2QztBQUU3Qyw4RUFBOEU7QUFDOUUsd0VBQXdFO0FBQ3hFLHdFQUF3RTtBQUN4RSwrRUFBK0U7QUFDL0UsOEVBQThFO0FBQzlFLCtFQUErRTtBQUMvRSxFQUFFO0FBQ0YsOEVBQThFO0FBQzlFLCtFQUErRTtBQUMvRSwrRUFBK0U7QUFDL0UsU0FBUztBQUNULFNBQVMsaUJBQWlCLENBQUMsU0FBa0I7SUFDM0MsT0FBTyxNQUFNLENBQUMsUUFBUSxDQUFDLFNBQVMsQ0FBQztRQUMvQixDQUFDLENBQUMsRUFBRSxxQkFBcUIsRUFBRSxTQUFTLEVBQUUscUJBQXFCLEVBQUUsU0FBUyxFQUFFO1FBQ3hFLENBQUMsQ0FBQyxFQUFFLENBQUM7QUFDVCxDQUFDO0FBRUQsTUFBTSxVQUFVLGtCQUFrQixDQUNoQyxLQUFjLEVBQ2QsTUFBZSxFQUNmLFNBQWtCLEVBQ2xCLFlBQVksR0FBRyxJQUFJO0lBRW5CLElBQUksS0FBSyxLQUFLLElBQUksSUFBSSxLQUFLLEtBQUssU0FBUyxJQUFJLEtBQUssS0FBSyxFQUFFLEVBQUUsQ0FBQztRQUMxRCxPQUFPLEdBQUcsQ0FBQztJQUNiLENBQUM7SUFFRCxNQUFNLE9BQU8sR0FBRyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUM7SUFDOUIsSUFBSSxDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQztRQUM5QixPQUFPLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FB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TUFBTSxHQUFHLEdBQUcsSUFBSSxJQUFJLEVBQUUsQ0FBQztJQUV2QixJQUFJLENBQUM7UUFDSCxNQUFNLEtBQUssR0FBRyxXQUFXLENBQUMsR0FBRyxFQUFFLFFBQVEsQ0FBQyxDQUFDO1FBRXpDLE9BQU8sTUFBTSxDQUFDLEtBQUssQ0FBQyxLQUFLLENBQUMsT0FBTyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUM7SUFDckQsQ0FBQztJQUFDLE1BQU0sQ0FBQztRQUNQLE9BQU8sR0FBRyxDQUFDO0lBQ2IsQ0FBQztBQUNILENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBmb3JtYXQsIGlzVmFsaWQsIHBhcnNlSVNPIH0gZnJvbSAnZGF0ZS1mbnMnO1xuaW1wb3J0IHsgZm9ybWF0SW5UaW1lWm9uZSwgdG9ab25lZFRpbWUgfSBmcm9tICdkYXRlLWZucy10eic7XG5cbmltcG9ydCB7IFJlcG9ydCB9IGZyb20gJy4vaW50ZXJmYWNlcy9yZXBvcnQuaW50ZXJmYWNlJztcblxuXG4vLyBNZWFzdXJlLXZhbHVlIGZvcm1hdHRpbmcgc2hhcmVkIGJ5IHRoZSBLUEkgcmVuZGVyZXIgYW5kIHRoZSBleHBvcnRzIOKAlCB0aGVcbi8vIGNvbmZpZydzIGBmb3JtYXRgIChudW1iZXIgfCBwZXJjZW50IHwgY3VycmVuY3kpIGFuZCBgcHJlY2lzaW9uYCBtZWFuIHRoZSBzYW1lXG4vLyB0aGluZyBvbiBzY3JlZW4sIGluIFBvd2VyUG9pbnQgYW5kIGluIFBERi5cblxuLy8gcGVyY2VudCB0YWtlcyBhIDAtMSByYXRpbyBhbmQgc2hvd3MgaXQgYXMgYSBwZXJjZW50YWdlOiAwLjMgcmVhZHMgMzAlLiBXaXRoXG4vLyBubyBwcmVjaXNpb24gaXQgc2hvd3MgYXQgbW9zdCBvbmUgZGVjaW1hbCAoMC4wMzcgcmVhZHMgMy43JSk7IGEgbmFtZWRcbi8vIHByZWNpc2lvbiBjb3VudHMgdGhlIGRlY2ltYWxzIG9mIHRoZSBwZXJjZW50YWdlLCBub3Qgb2YgdGhlIHJhdGlvLCBzb1xuLy8gcHJlY2lzaW9uIDEgc2hvd3MgMC4zIGFzIDMwLjAlLiBBbiBvbGRlciBzZXJ2ZXIgc2VuZHMgcGVyY2VudCB2YWx1ZXMgYWxyZWFkeVxuLy8geDEwMCAoMzguNSBmb3IgMzguNSUpOyBpdHMgcmVwb3J0cyBjYXJyeSBubyBgcGVyY2VudEZvcm1hdGAsIGFuZCB0aGUgY2FsbGVyXG4vLyBwYXNzZXMgcmF0aW9QZXJjZW50IGZhbHNlIHNvIHRoZSB2YWx1ZSBpcyBwcmludGVkIGFzIGl0IGNhbWUsIHdpdGggYSAlIHNpZ24uXG4vL1xuLy8gV2hlbiB0aGUgbWVhc3VyZSBuYW1lcyBhIHByZWNpc2lvbiBpdCBpcyBwaW5uZWQgYXMgQk9USCB0aGUgbWluaW11bSBhbmQgdGhlXG4vLyBtYXhpbXVtLCBzbyBhIGNvbHVtbiBvZiByYXRlcyBsaW5lcyB1cCBpbnN0ZWFkIG9mIGVhY2ggdmFsdWUgc2hvd2luZyBob3dldmVyXG4vLyBtYW55IGRlY2ltYWxzIGl0IGhhcHBlbnMgdG8gbmVlZC4gVW5kZWZpbmVkIGxlYXZlcyBlYWNoIGZvcm1hdCdzIG93biBkZWZhdWx0XG4vLyBhbG9uZS5cbmZ1bmN0aW9uIGdldEZyYWN0aW9uRGlnaXRzKHByZWNpc2lvbj86IG51bWJlcik6IEludGwuTnVtYmVyRm9ybWF0T3B0aW9ucyB7XG4gIHJldHVybiBOdW1iZXIuaXNGaW5pdGUocHJlY2lzaW9uKVxuICAgID8geyBtaW5pbXVtRnJhY3Rpb25EaWdpdHM6IHByZWNpc2lvbiwgbWF4aW11bUZyYWN0aW9uRGlnaXRzOiBwcmVjaXNpb24gfVxuICAgIDoge307XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBmb3JtYXRNZWFzdXJlVmFsdWUoXG4gIHZhbHVlOiB1bmtub3duLFxuICBmb3JtYXQ/OiBzdHJpbmcsXG4gIHByZWNpc2lvbj86IG51bWJlcixcbiAgcmF0aW9QZXJjZW50ID0gdHJ1ZSxcbik6IHN0cmluZyB7XG4gIGlmICh2YWx1ZSA9PT0gbnVsbCB8fCB2YWx1ZSA9PT0gdW5kZWZpbmVkIHx8IHZhbHVlID09PSAnJykge1xuICAgIHJldHVybiAn4oCUJztcbiAgfVxuXG4gIGNvbnN0IG51bWVyaWMgPSBOdW1iZXIodmFsdWUpO1xuICBpZiAoIU51bWJlci5pc0Zpbml0ZShudW1lcmljKSkge1xuICAgIHJldHVybiBTdHJpbmcodmFsdWUpO1xuICB9XG5cbiAgY29uc3QgZnJhY3Rpb25EaWdpdHMgPSBnZXRGcmFjdGlvbkRpZ2l0cyhwcmVjaXNpb24pO1xuXG4gIHN3aXRjaCAoZm9ybWF0KSB7XG4gICAgY2FzZSAncGVyY2VudCc6XG4gICAgICBpZiAoIXJhdGlvUGVyY2VudCkge1xuICAgICAgICByZXR1cm4gYCR7bmV3IEludGwuTnVtYmVyRm9ybWF0KHVuZGVmaW5lZCwgeyBtYXhpbXVtRnJhY3Rpb25EaWdpdHM6IDEsIC4uLmZyYWN0aW9uRGlnaXRzIH0pLmZvcm1hdChudW1lcmljKX0lYDtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIG5ldyBJbnRsLk51bWJlckZvcm1hdCh1bmRlZmluZWQsIHtcbiAgICAgICAgc3R5bGU6ICdwZXJjZW50JyxcbiAgICAgICAgbWF4aW11bUZyYWN0aW9uRGlnaXRzOiAxLFxuICAgICAgICAuLi5mcmFjdGlvbkRpZ2l0cyxcbiAgICAgIH0pLmZvcm1hdChudW1lcmljKTtcbiAgICBjYXNlICdjdXJyZW5jeSc6XG4gICAgICByZXR1cm4gbmV3IEludGwuTnVtYmVyRm9ybWF0KHVuZGVmaW5lZCwge1xuICAgICAgICBzdHlsZTogJ2N1cnJlbmN5JyxcbiAgICAgICAgY3VycmVuY3k6ICdVU0QnLFxuICAgICAgICAvLyBXaG9sZSBkb2xsYXJzIHVubGVzcyB0aGUgbWVhc3VyZSBhc2tzIGZvciBkZWNpbWFscyDigJQgY2VudHMgd2VyZVxuICAgICAgICAvLyB1bnJlcHJlc2VudGFibGUgYmVmb3JlLCBiZWNhdXNlIHRoaXMgd2FzIGhhcmRjb2RlZCB0byAwLlxuICAgICAgICBtYXhpbXVtRnJhY3Rpb25EaWdpdHM6IDAsXG4gICAgICAgIC4uLmZyYWN0aW9uRGlnaXRzLFxuICAgICAgfSkuZm9ybWF0KG51bWVyaWMpO1xuICAgIGRlZmF1bHQ6XG4gICAgICByZXR1cm4gbmV3IEludGwuTnVtYmVyRm9ybWF0KHVuZGVmaW5lZCwgZnJhY3Rpb25EaWdpdHMpLmZvcm1hdChudW1lcmljKTtcbiAgfVxufVxuXG5cbi8vIFRoZSBheGlzIHBlYWsgYXQgd2hpY2ggYSBuYXRpdmUgY2hhcnQncyB2YWx1ZSBheGlzIGdhaW5zIHRob3VzYW5kc1xuLy8gc2VwYXJhdG9ycy4gRnJvbSBoZXJlIHVwIHRoZSB0aWNrcyBhcmUgd2hvbGUgbnVtYmVycyBpbiBwcmFjdGljZTsgYmVsb3cgaXRcbi8vIG5laXRoZXIgdGhlIHNjcmVlbiBub3IgUG93ZXJQb2ludCdzICdHZW5lcmFsJyBzaG93cyBhIHNlcGFyYXRvci5cbmV4cG9ydCBjb25zdCBBWElTX1NFUEFSQVRPUl9USFJFU0hPTEQgPSAxMDAwO1xuXG4vLyBQb3dlclBvaW50J3MgbnVtYmVyIGZvcm1hdCBmb3IgYSBuYXRpdmUgY2hhcnQncyB2YWx1ZSBheGlzLCBtYXRjaGluZyB3aGF0IHRoZVxuLy8gb24tc2NyZWVuIGF4aXMgcHJpbnRzIGJ5IGRlZmF1bHQ6IHRob3VzYW5kcyBzZXBhcmF0b3JzIHdpdGggZWFjaCB0aWNrJ3Mgb3duXG4vLyBkZWNpbWFscy4gRXhjZWwgaGFzIG5vIFwiR2VuZXJhbCB3aXRoIHNlcGFyYXRvcnNcIiwgc28gYW4gYXhpcyByZWFjaGluZyAxLDAwMFxuLy8gKHdoZXJlIHRpY2tzIGFyZSB3aG9sZSBudW1iZXJzKSBnZXRzICcjLCMjMCcsIGFuZCBhIHNtYWxsZXIgcmFuZ2Uga2VlcHNcbi8vICdHZW5lcmFsJyBzbyBmcmFjdGlvbmFsIHRpY2tzICgwLjI1LCAwLjUpIGFyZSBub3Qgcm91bmRlZCBhd2F5LlxuLy9cbi8vIFRoZSBwZWFrIGNvdW50cyBhIG1pc3NpbmcgdmFsdWUgYXMgMC4gQSBzdGFja2VkIGNoYXJ0J3MgcGVhayBpcyBpdHMgdGFsbGVzdFxuLy8gc3RhY2s6IHRoZSBsYXJnZXN0IHN1bSwgcGVyIGNhdGVnb3J5LCBvZiBldmVyeSBzZXJpZXMnIGFic29sdXRlIHZhbHVlLlxuZXhwb3J0IGZ1bmN0aW9uIGNoYXJ0QXhpc0Zvcm1hdENvZGUoc2VyaWVzOiAobnVtYmVyIHwgbnVsbClbXVtdLCBzdGFja2VkOiBib29sZWFuKTogc3RyaW5nIHtcbiAgY29uc3QgbWFnbml0dWRlcyA9IHNlcmllcy5tYXAoKHZhbHVlcykgPT4gdmFsdWVzLm1hcCgodmFsdWUpID0+IE1hdGguYWJzKHZhbHVlID8/IDApKSk7XG5cbiAgY29uc3QgcGVhayA9IHN0YWNrZWRcbiAgICA/IE1hdGgubWF4KDAsIC4uLihtYWduaXR1ZGVzWzBdID8/IFtdKS5tYXAoKF8sIGluZGV4KSA9PiBtYWduaXR1ZGVzXG4gICAgICAucmVkdWNlKChzdW0sIHZhbHVlcykgPT4gc3VtICsgKHZhbHVlc1tpbmRleF0gPz8gMCksIDApKSlcbiAgICA6IE1hdGgubWF4KDAsIC4uLm1hZ25pdHVkZXMuZmxhdCgpKTtcblxuICByZXR1cm4gcGVhayA+PSBBWElTX1NFUEFSQVRPUl9USFJFU0hPTEQgPyAnIywjIzAnIDogJ0dlbmVyYWwnO1xufVxuXG5cbi8vIFRoZSB6b25lIGV2ZXJ5IGRhdGUgaW4gYSByZXBvcnQgaXMgcmVhZCBpbi4gVGhlIHNlcnZlciByZXNvbHZlcyBpdCAodGhlXG4vLyByZXBvcnQncyBvd24gem9uZSwgZWxzZSB0aGUgYXBwbGljYXRpb24ncyBkZWZhdWx0IHJlcG9ydGluZyB6b25lKSBhbmQgc2VuZHNcbi8vIGl0IGFzIGBlZmZlY3RpdmVUaW1lem9uZWAuIEEgc2VydmVyIHRvbyBvbGQgdG8gc2VuZCB0aGUgZmllbGQgc3RpbGwgdXNlZCBhXG4vLyByZXBvcnQncyBwaW5uZWQgYHRpbWV6b25lYCwgc28gdGhhdCBjb21lcyBuZXh0OyB0aGUgYnJvd3NlcidzIHpvbmUgaXMgdGhlIGxhc3Rcbi8vIGZhbGxiYWNrLiBUaGlzIGlzIHRoZSBvbmUgcGxhY2UgdGhhdCBjaGFpbiBsaXZlcywgc28gZXZlcnkgZGF0ZSB0aGUgdmlld2VyXG4vLyByZW5kZXJzIG9yIHJlc29sdmVzIGFncmVlcyB3aXRoIGV2ZXJ5IG90aGVyLlxuZXhwb3J0IGZ1bmN0aW9uIHJlc29sdmVSZXBvcnRUaW1lem9uZShyZXBvcnQ6IFBpY2s8UmVwb3J0LCAnZWZmZWN0aXZlVGltZXpvbmUnIHwgJ3RpbWV6b25lJz4pOiBzdHJpbmcge1xuICByZXR1cm4gcmVwb3J0LmVmZmVjdGl2ZVRpbWV6b25lID8/IHJlcG9ydC50aW1lem9uZSA/PyBJbnRsLkRhdGVUaW1lRm9ybWF0KCkucmVzb2x2ZWRPcHRpb25zKCkudGltZVpvbmU7XG59XG5cblxuY29uc3QgREFURV9PTkxZX1BBVFRFUk4gPSAvXlxcZHs0fS1cXGR7Mn0tXFxkezJ9JC87XG5jb25zdCBEQVRFX1RJTUVfUEFUVEVSTiA9IC9eKFxcZHs0fS1cXGR7Mn0tXFxkezJ9KVsgVF0oXFxkezJ9OlxcZHsyfTpcXGR7Mn0pKFxcLlxcZCspPyQvO1xuXG4vLyBBIHJlcG9ydCByb3cncyBkYXRlIGNlbGwgYXMgYSBjYWxlbmRhciBkYXkgaW4gdGhlIHJlcG9ydCdzIHpvbmUuXG4vL1xuLy8gUmVwb3J0IHJvd3MgYXJlIHJhdyBkYXRhYmFzZSBzdHJpbmdzLCBub3Qgc2VyaWFsaXplZCBtb2RlbHMsIHNvIHRoZWlyIHNoYXBlXG4vLyBpcyB0aGUgd2lyZSBjb250cmFjdDogYSBEQVRFIGNvbHVtbiBhcnJpdmVzIGFzICdZWVlZLU1NLUREJyBhbmQgYVxuLy8gZGF0ZS1hbmQtdGltZSBjb2x1bW4gYXMgJ1lZWVktTU0tREQgSEg6TU06U1MnIGluIFVUQy4gUmVhZGluZyB0aGF0IHNoYXBlXG4vLyBoZXJlIGRvZXMgbm90IHJlLWRlcml2ZSBhIHNlcnZlciBydWxlOyBpdCBvbmx5IHN0b3BzIHRoZSBicm93c2VyIGd1ZXNzaW5nLlxuLy8gLSBBIGNhbGVuZGFyIGRheSBpcyBuZXZlciBzaGlmdGVkOiBwYXJzZUlTTyByZWFkcyBpdCBhcyBsb2NhbCBtaWRuaWdodCwgc29cbi8vICAgdGhlIGRheSBwcmludGVkIGlzIHRoZSBkYXkgc3RvcmVkLCB3aGF0ZXZlciB0aGUgem9uZS5cbi8vIC0gQW4gaW5zdGFudCBpcyBwaW5uZWQgdG8gVVRDIHdpdGggYW4gZXhwbGljaXQgJ1onLCB0aGVuIHNob3duIGFzIHRoZSBkYXkgaXRcbi8vICAgZmVsbCBvbiBpbiB0aGUgcmVwb3J0J3Mgem9uZSwgdGhlIHNhbWUgZGF5IHRoZSBmaWx0ZXJzIGFuZCB0aW1lIGJ1Y2tldHMgdXNlLlxuLy8gLSBBbnl0aGluZyBlbHNlIGlzIHNob3duIGFzIGl0IGNhbWUsIGFuZCBzbyBpcyBhIHZhbHVlIHRoYXQgaGFzIHRoZSBzaGFwZVxuLy8gICBidXQgbmFtZXMgbm8gcmVhbCBkYXkgKGEgemVybyBkYXRlICcwMDAwLTAwLTAwJywgb3IgJzIwMjYtMDItMzAnKTogb25lXG4vLyAgIGJhZCBjZWxsIG11c3Qgbm90IHRocm93IG91dCBvZiBhIHBpcGUgb3IgYWJvcnQgYW4gZXhwb3J0LlxuZXhwb3J0IGZ1bmN0aW9uIGZvcm1hdFJlcG9ydERhdGUodmFsdWU6IHVua25vd24sIHRpbWV6b25lOiBzdHJpbmcpOiBzdHJpbmcge1xuICBpZiAodmFsdWUgPT09IG51bGwgfHwgdmFsdWUgPT09IHVuZGVmaW5lZCB8fCB2YWx1ZSA9PT0gJycpIHtcbiAgICByZXR1cm4gJyc7XG4gIH1cblxuICBjb25zdCB0ZXh0ID0gU3RyaW5nKHZhbHVlKTtcblxuICBpZiAoREFURV9PTkxZX1BBVFRFUk4udGVzdCh0ZXh0KSkge1xuICAgIGNvbnN0IGRheSA9IHBhcnNlSVNPKHRleHQpO1xuXG4gICAgcmV0dXJuIGlzVmFsaWQoZGF5KSA/IGZvcm1hdChkYXksICdNTU0gZCwgeXl5eScpIDogdGV4dDtcbiAgfVxuXG4gIGNvbnN0IGRhdGVUaW1lID0gREFURV9USU1FX1BBVFRFUk4uZXhlYyh0ZXh0KTtcbiAgaWYgKCFkYXRlVGltZSkge1xuICAgIHJldHVybiB0ZXh0O1xuICB9XG5cbiAgY29uc3QgaW5zdGFudCA9IHBhcnNlSVNPKGAke2RhdGVUaW1lWzFdfVQke2RhdGVUaW1lWzJdfVpgKTtcbiAgaWYgKCFpc1ZhbGlkKGluc3RhbnQpKSB7XG4gICAgcmV0dXJuIHRleHQ7XG4gIH1cblxuICAvLyBBbiB1bmtub3duIHpvbmUgbWFrZXMgZGF0ZS1mbnMtdHogdGhyb3c7IFVUQyBzdGlsbCBuYW1lcyBhIHJlYWwgZGF5LlxuICB0cnkge1xuICAgIHJldHVybiBmb3JtYXRJblRpbWVab25lKGluc3RhbnQsIHRpbWV6b25lLCAnTU1NIGQsIHl5eXknKTtcbiAgfSBjYXRjaCB7XG4gICAgcmV0dXJuIGZvcm1hdEluVGltZVpvbmUoaW5zdGFudCwgJ1VUQycsICdNTU0gZCwgeXl5eScpO1xuICB9XG59XG5cblxuLy8gQSBzaG9ydCwgaHVtYW4gbGFiZWwgZm9yIGEgem9uZTogaXRzIGNpdHkgcGx1cyB0aGUgY3VycmVudCBhYmJyZXZpYXRpb24sXG4vLyBlLmcuICdBbWVyaWNhL05ld19Zb3JrJyByZWFkcyAnTmV3IFlvcmsgKEVEVCknLiBVVEMgc3RheXMgJ1VUQycsIGFuZCBhblxuLy8gdW5rbm93biB6b25lIGlzIHNob3duIGFzIGl0cyBpZC4gQW4gJ0V0Yy8nIHpvbmUgbmFtZXMgbm8gY2l0eSwgYW5kIGl0cyBQT1NJWFxuLy8gc2lnbiBpcyB0aGUgcmV2ZXJzZSBvZiB0aGUgb2Zmc2V0ICgnRXRjL0dNVCs1JyBpcyBHTVQtNSksIHNvIGl0IHJlYWRzIGFzIHRoZVxuLy8gYWJicmV2aWF0aW9uIGFsb25lOiAnRXRjL1VUQycgaXMgJ1VUQycsICdFdGMvR01UKzUnIGlzICdHTVQtNScuXG5leHBvcnQgZnVuY3Rpb24gZ2V0VGltZXpvbmVMYWJlbCh0aW1lem9uZTogc3RyaW5nKTogc3RyaW5nIHtcbiAgaWYgKHRpbWV6b25lID09PSAnVVRDJykge1xuICAgIHJldHVybiB0aW1lem9uZTtcbiAgfVxuXG4gIGNvbnN0IHNlZ21lbnRzID0gdGltZXpvbmUuc3BsaXQoJy8nKTtcblxuICB0cnkge1xuICAgIGNvbnN0IGFiYnJldmlhdGlvbiA9IGZvcm1hdEluVGltZVpvbmUobmV3IERhdGUoKSwgdGltZXpvbmUsICd6enonKTtcblxuICAgIHJldHVybiBzZWdtZW50c1swXSA9PT0gJ0V0YydcbiAgICAgID8gYWJicmV2aWF0aW9uXG4gICAgICA6IGAke3NlZ21lbnRzW3NlZ21lbnRzLmxlbmd0aCAtIDFdLnJlcGxhY2UoL18vZywgJyAnKX0gKCR7YWJicmV2aWF0aW9ufSlgO1xuICB9IGNhdGNoIHtcbiAgICByZXR1cm4gdGltZXpvbmU7XG4gIH1cbn1cblxuXG4vLyBcIk5vd1wiIGFzIGEgRGF0ZSB3aG9zZSBsb2NhbCBmaWVsZHMgcmVhZCB0aGUgd2FsbCBjbG9jayBpbiB0aGUgZ2l2ZW4gem9uZSwgc29cbi8vIGRhdGUtZm5zIGNhbGVuZGFyIGFyaXRobWV0aWMgKHN0YXJ0T2ZXZWVrLCBzdGFydE9mTW9udGgsIC4uLikgYW5kXG4vLyBkYXRlQm91bmRTdHJpbmcoKSBsYW5kIG9uIHRoZSB6b25lJ3MgY2FsZW5kYXIgZGF5IHJhdGhlciB0aGFuIHRoZSBicm93c2VyJ3MuXG4vLyBBbiB1bmtub3duIHpvbmUgZmFsbHMgYmFjayB0byB0aGUgYnJvd3NlcidzIGNsb2NrLlxuZXhwb3J0IGZ1bmN0aW9uIGdldFpvbmVkTm93KHRpbWV6b25lOiBzdHJpbmcpOiBEYXRlIHtcbiAgY29uc3Qgbm93ID0gbmV3IERhdGUoKTtcblxuICB0cnkge1xuICAgIGNvbnN0IHpvbmVkID0gdG9ab25lZFRpbWUobm93LCB0aW1lem9uZSk7XG5cbiAgICByZXR1cm4gTnVtYmVyLmlzTmFOKHpvbmVkLmdldFRpbWUoKSkgPyBub3cgOiB6b25lZDtcbiAgfSBjYXRjaCB7XG4gICAgcmV0dXJuIG5vdztcbiAgfVxufVxuIl19
1017
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZm9ybWF0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL2FwcC9yZXBvcnRzL2Zvcm1hdC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLFVBQVUsQ0FBQztBQUM3QyxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsV0FBVyxFQUFFLE1BQU0sYUFBYSxDQUFDO0FBRTVELE9BQU8sRUFBRSxzQkFBc0IsRUFBRSxNQUFNLHdDQUF3QyxDQUFDO0FBQ2hGLE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxNQUFNLGtDQUFrQyxDQUFDO0FBQ3JFLE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxNQUFNLGtDQUFrQyxDQUFDO0FBcUJyRSw2RUFBNkU7QUFDN0UsOEVBQThFO0FBQzlFLGtGQUFrRjtBQUNsRixNQUFNLENBQUMsTUFBTSxzQkFBc0IsR0FBb0IsT0FBTyxDQUFDO0FBQy9ELE1BQU0sQ0FBQyxNQUFNLHdCQUF3QixHQUF1QixLQUFLLENBQUM7QUFFbEUsTUFBTSxDQUFDLE1BQU0sc0JBQXNCLEdBQWtDLE1BQU0sQ0FBQyxNQUFNLENBQUM7SUFDakYsTUFBTSxFQUFFLHNCQUFzQjtJQUM5QixRQUFRLEVBQUUsd0JBQXdCO0lBQ2xDLFlBQVksRUFBRSxJQUFJO0NBQ25CLENBQUMsQ0FBQztBQUVILE1BQU0sZ0JBQWdCLEdBQUcsWUFBWSxDQUFDO0FBR3RDLDhFQUE4RTtBQUM5RSw2RUFBNkU7QUFDN0Usc0RBQXNEO0FBQ3RELE1BQU0sVUFBVSxtQkFBbUIsQ0FBQyxHQUE4QjtJQUNoRSxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUM7UUFDVCxPQUFPLHNCQUFzQixDQUFDO0lBQ2hDLENBQUM7SUFFRCxJQUFJLENBQUM7UUFDSCxPQUFPLElBQUksQ0FBQyxZQUFZLENBQUMsa0JBQWtCLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLHNCQUFzQixD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LEtBQUssWUFBWSxHQUFHLENBQUM7SUFDOUUsQ0FBQztJQUFDLE1BQU0sQ0FBQztRQUNQLE9BQU8sUUFBUSxDQUFDO0lBQ2xCLENBQUM7QUFDSCxDQUFDO0FBR0QsK0VBQStFO0FBQy9FLG9FQUFvRTtBQUNwRSwrRUFBK0U7QUFDL0UscURBQXFEO0FBQ3JELE1BQU0sVUFBVSxXQUFXLENBQUMsUUFBZ0I7SUFDMUMsTUFBTSxHQUFHLEdBQUcsSUFBSSxJQUFJLEVBQUUsQ0FBQztJQUV2QixJQUFJLENBQUM7UUFDSCxNQUFNLEtBQUssR0FBRyxXQUFXLENBQUMsR0FBRyxFQUFFLFFBQVEsQ0FBQyxDQUFDO1FBRXpDLE9BQU8sTUFBTSxDQUFDLEtBQUssQ0FBQyxLQUFLLENBQUMsT0FBTyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUM7SUFDckQsQ0FBQztJQUFDLE1BQU0sQ0FBQztRQUNQLE9BQU8sR0FBRyxDQUFDO0lBQ2IsQ0FBQztBQUNILENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBpc1ZhbGlkLCBwYXJzZUlTTyB9IGZyb20gJ2RhdGUtZm5zJztcbmltcG9ydCB7IGZvcm1hdEluVGltZVpvbmUsIHRvWm9uZWRUaW1lIH0gZnJvbSAnZGF0ZS1mbnMtdHonO1xuXG5pbXBvcnQgeyBSZXBvcnRMaXN0Q29sdW1uRm9ybWF0IH0gZnJvbSAnLi9lbnVtcy9yZXBvcnQtbGlzdC1jb2x1bW4tZm9ybWF0LmVudW0nO1xuaW1wb3J0IHsgUmVwb3J0TnVtYmVyVW5pdHMgfSBmcm9tICcuL2VudW1zL3JlcG9ydC1udW1iZXItdW5pdHMuZW51bSc7XG5pbXBvcnQgeyBSZXBvcnRWYWx1ZUZvcm1hdCB9IGZyb20gJy4vZW51bXMvcmVwb3J0LXZhbHVlLWZvcm1hdC5lbnVtJztcbmltcG9ydCB7XG4gIENoYXJ0R3JhbnVsYXJpdHksXG4gIENoYXJ0TWVhc3VyZSxcbiAgQ29tcGFyaXNvbkFnYWluc3QsXG4gIENvbXBhcmlzb25Ob3RlQ29kZSxcbiAgQ29tcGFyaXNvbk9mZnNldCxcbiAgQ29tcG9uZW50Q29tcGFyaXNvbixcbiAgS3BpTm90ZUNvZGUsXG4gIE51bWJlckZvcm1hdFNwZWMsXG4gIE91dHB1dE1ldGEsXG4gIE91dHB1dFJvbGUsXG4gIFJlcG9ydCxcbiAgUmVwb3J0Q3VycmVuY3lDb2RlLFxuICBSZXBvcnRGb3JtYXRDb250ZXh0LFxuICBSZXBvcnRMb2NhbGVUYWcsXG4gIFdpbmRvd01ldGEsXG4gIFdpbmRvd05vdGVDb2RlLFxufSBmcm9tICcuL2ludGVyZmFjZXMvcmVwb3J0LmludGVyZmFjZSc7XG5cblxuLy8gV2hhdCBhIHJlcG9ydCByZWFkcyB3aGVuIHRoZSBzZXJ2ZXIgbmFtZXMgbm8gdXNhYmxlIGxvY2FsZSBvciBjdXJyZW5jeTogYW5cbi8vIG9sZGVyIHNlcnZlciB0aGF0IHNlbmRzIG5laXRoZXIsIG9yIGEgdmFsdWUgdGhpcyBicm93c2VyJ3MgSW50bCBjYW5ub3QgdXNlLlxuLy8gTmV2ZXIgdGhlIGJyb3dzZXIncyBvd24gbG9jYWxlLCBzbyBldmVyeSB2aWV3ZXIgb2YgYSByZXBvcnQgc2VlcyB0aGUgc2FtZSB0ZXh0LlxuZXhwb3J0IGNvbnN0IFJFUE9SVF9GQUxMQkFDS19MT0NBTEU6IFJlcG9ydExvY2FsZVRhZyA9ICdlbi1VUyc7XG5leHBvcnQgY29uc3QgUkVQT1JUX0ZBTExCQUNLX0NVUlJFTkNZOiBSZXBvcnRDdXJyZW5jeUNvZGUgPSAnVVNEJztcblxuZXhwb3J0IGNvbnN0IERFRkFVTFRfRk9STUFUX0NPTlRFWFQ6IFJlYWRvbmx5PFJlcG9ydEZvcm1hdENvbnRleHQ+ID0gT2JqZWN0LmZyZWV6ZSh7XG4gIGxvY2FsZTogUkVQT1JUX0ZBTExCQUNLX0xPQ0FMRSxcbiAgY3VycmVuY3k6IFJFUE9SVF9GQUxMQkFDS19DVVJSRU5DWSxcbiAgcmF0aW9QZXJjZW50OiB0cnVlLFxufSk7XG5cbmNvbnN0IENVUlJFTkNZX1BBVFRFUk4gPSAvXltBLVpdezN9JC87XG5cblxuLy8gVGhlIHNlcnZlcidzIHJlc29sdmVkIGxvY2FsZSBhcyBvbmUgdGhpcyBicm93c2VyIGNhbiBmb3JtYXQgaW4uIEEgbWFsZm9ybWVkXG4vLyB0YWcgKCdlbl9DQScpIG1ha2VzIHN1cHBvcnRlZExvY2FsZXNPZiB0aHJvdywgYW5kIG9uZSBJbnRsIGhhcyBubyBkYXRhIGZvclxuLy8gKCd4eC1ZWScpIGNvbWVzIGJhY2sgZW1wdHk7IGJvdGggcmVhZCB0aGUgZmFsbGJhY2suXG5leHBvcnQgZnVuY3Rpb24gcmVzb2x2ZVJlcG9ydExvY2FsZSh0YWc6IHN0cmluZyB8IG51bGwgfCB1bmRlZmluZWQpOiBSZXBvcnRMb2NhbGVUYWcge1xuICBpZiAoIXRhZykge1xuICAgIHJldHVybiBSRVBPUlRfRkFMTEJBQ0tfTE9DQUxFO1xuICB9XG5cbiAgdHJ5IHtcbiAgICByZXR1cm4gSW50bC5OdW1iZXJGb3JtYXQuc3VwcG9ydGVkTG9jYWxlc09mKFt0YWddKVswXSA/PyBSRVBPUlRfRkFMTEJBQ0tfTE9DQUxFO1xuICB9IGNhdGNoIHtcbiAgICByZXR1cm4gUkVQT1JUX0ZBTExCQUNLX0xPQ0FMRTtcbiAgfVxufVxuXG4vLyBUaGUgc2VydmVyJ3MgcmVzb2x2ZWQgY3VycmVuY3kgYXMgb25lIEludGwgY2FuIGxhYmVsLiBUaGUgc2VydmVyIGRlY2lkZXNcbi8vIHdoaWNoIGNvZGVzIG5hbWUgbW9uZXk7IHRoaXMgb25seSBndWFyZHMgYWdhaW5zdCBhIGNvZGUgSW50bCBjYW5ub3QgdGFrZSBhdFxuLy8gYWxsLiBJdCBpcyBuZXZlciBjaGVja2VkIGFnYWluc3QgdGhlIHJ1bnRpbWUncyBvd24gY3VycmVuY3kgbGlzdCwgd2hpY2hcbi8vIGRpZmZlcnMgYmV0d2VlbiBicm93c2VycyBhbmQgbGVhdmVzIG91dCBjb2RlcyB0aGUgc2VydmVyIG9mZmVycyAoVkVGLCBNUk8pLFxuLy8gc28gZXZlcnkgdmlld2VyIGxhYmVscyBhIHJlcG9ydCdzIG1vbmV5IHRoZSBzYW1lIHdheS5cbmV4cG9ydCBmdW5jdGlvbiByZXNvbHZlUmVwb3J0Q3VycmVuY3koY29kZTogc3RyaW5nIHwgbnVsbCB8IHVuZGVmaW5lZCk6IFJlcG9ydEN1cnJlbmN5Q29kZSB7XG4gIGlmICghY29kZSB8fCAhQ1VSUkVOQ1lfUEFUVEVSTi50ZXN0KGNvZGUpKSB7XG4gICAgcmV0dXJuIFJFUE9SVF9GQUxMQkFDS19DVVJSRU5DWTtcbiAgfVxuXG4gIHRyeSB7XG4gICAgbnVtYmVyRm9ybWF0KFJFUE9SVF9GQUxMQkFDS19MT0NBTEUsIHsgc3R5bGU6ICdjdXJyZW5jeScsIGN1cnJlbmN5OiBjb2RlIH0pO1xuXG4gICAgcmV0dXJuIGNvZGU7XG4gIH0gY2F0Y2gge1xuICAgIHJldHVybiBSRVBPUlRfRkFMTEJBQ0tfQ1VSUkVOQ1k7XG4gIH1cbn1cblxuLy8gVGhlIG9uZSBwbGFjZSBhIHJlcG9ydCdzIGZvcm1hdCBjb250ZXh0IGlzIGJ1aWx0OiB0aGUgc2VydmVyJ3MgZWZmZWN0aXZlXG4vLyBsb2NhbGUgYW5kIGN1cnJlbmN5IChhYnNlbnQgb24gYW4gb2xkZXIgc2VydmVyLCB3aGljaCB0aGVuIHJlYWRzIGVuLVVTL1VTRClcbi8vIGFuZCB3aGV0aGVyIGl0cyBwZXJjZW50IG1lYXN1cmVzIGFycml2ZSBhcyAwLTEgcmF0aW9zLlxuZXhwb3J0IGZ1bmN0aW9uIHJlc29sdmVGb3JtYXRDb250ZXh0KFxuICByZXBvcnQ6IFBpY2s8UmVwb3J0LCAnZWZmZWN0aXZlTG9jYWxlJyB8ICdlZmZlY3RpdmVDdXJyZW5jeScgfCAncGVyY2VudEZvcm1hdCc+LFxuKTogUmVwb3J0Rm9ybWF0Q29udGV4dCB7XG4gIHJldHVybiB7XG4gICAgbG9jYWxlOiByZXNvbHZlUmVwb3J0TG9jYWxlKHJlcG9ydC5lZmZlY3RpdmVMb2NhbGUpLFxuICAgIGN1cnJlbmN5OiByZXNvbHZlUmVwb3J0Q3VycmVuY3kocmVwb3J0LmVmZmVjdGl2ZUN1cnJlbmN5KSxcbiAgICByYXRpb1BlcmNlbnQ6IHJlcG9ydC5wZXJjZW50Rm9ybWF0ID09PSAncmF0aW8nLFxuICB9O1xufVxuXG5cbi8vIEJ1aWxkaW5nIGFuIEludGwgZm9ybWF0dGVyIGlzIGZhciBzbG93ZXIgdGhhbiB1c2luZyBvbmUsIGFuZCBhIGNoYXJ0IGZvcm1hdHNcbi8vIGV2ZXJ5IHRpY2sgYW5kIHRvb2x0aXAgdmFsdWUsIHNvIGVhY2ggZGlzdGluY3QgbG9jYWxlICsgb3B0aW9ucyAoKyB6b25lKSBpc1xuLy8gYnVpbHQgb25jZSBhbmQgcmV1c2VkLlxuY29uc3QgTlVNQkVSX0ZPUk1BVFMgPSBuZXcgTWFwPHN0cmluZywgSW50bC5OdW1iZXJGb3JtYXQ+KCk7XG5jb25zdCBEQVRFX0ZPUk1BVFMgPSBuZXcgTWFwPHN0cmluZywgSW50bC5EYXRlVGltZUZvcm1hdD4oKTtcblxuZXhwb3J0IGZ1bmN0aW9uIG51bWJlckZvcm1hdChsb2NhbGU6IHN0cmluZywgb3B0aW9uczogSW50bC5OdW1iZXJGb3JtYXRPcHRpb25zKTogSW50bC5OdW1iZXJGb3JtYXQge1xuICBjb25zdCBrZXkgPSBgJHtsb2NhbGV9fCR7SlNPTi5zdHJpbmdpZnkob3B0aW9ucyl9YDtcbiAgbGV0IGZvcm1hdHRlciA9IE5VTUJFUl9GT1JNQVRTLmdldChrZXkpO1xuXG4gIGlmICghZm9ybWF0dGVyKSB7XG4gICAgZm9ybWF0dGVyID0gbmV3IEludGwuTnVtYmVyRm9ybWF0KGxvY2FsZSwgb3B0aW9ucyk7XG4gICAgTlVNQkVSX0ZPUk1BVFMuc2V0KGtleSwgZm9ybWF0dGVyKTtcbiAgfVxuXG4gIHJldHVybiBmb3JtYXR0ZXI7XG59XG5cbi8vIE5vIHpvbmUgZm9ybWF0cyBpbiB0aGUgYnJvd3NlcidzIG93biB6b25lLCB3aGljaCBpcyByaWdodCBmb3IgYSBjYWxlbmRhciBkYXlcbi8vIHBhcnNlZCBhcyBsb2NhbCBtaWRuaWdodDogdGhlIGRheSBwcmludGVkIGlzIHRoZSBkYXkgc3RvcmVkLlxuZXhwb3J0IGZ1bmN0aW9uIGRhdGVGb3JtYXQoXG4gIGxvY2FsZTogc3RyaW5nLFxuICBvcHRpb25zOiBJbnRsLkRhdGVUaW1lRm9ybWF0T3B0aW9ucyxcbiAgdGltZVpvbmU/OiBzdHJpbmcsXG4pOiBJbnRsLkRhdGVUaW1lRm9ybWF0IHtcbiAgY29uc3Qga2V5ID0gYCR7bG9jYWxlfXwke0pTT04uc3RyaW5naWZ5KG9wdGlvbnMpfXwke3RpbWVab25lID8/ICcnfWA7XG4gIGxldCBmb3JtYXR0ZXIgPSBEQVRFX0ZPUk1BVFMuZ2V0KGtleSk7XG5cbiAgaWYgKCFmb3JtYXR0ZXIpIHtcbiAgICBmb3JtYXR0ZXIgPSBuZXcgSW50bC5EYXRlVGltZUZvcm1hdChsb2NhbGUsIHsgLi4ub3B0aW9ucywgdGltZVpvbmUgfSk7XG4gICAgREFURV9GT1JNQVRTLnNldChrZXksIGZvcm1hdHRlcik7XG4gIH1cblxuICByZXR1cm4gZm9ybWF0dGVyO1xufVxuXG5cbi8vIE51bWJlciBmb3JtYXR0aW5nOiB0aGUgb25lIGVuZ2luZSBiZWhpbmQgZXZlcnkgbnVtZXJpYyBzbG90IChhIGNoYXJ0XG4vLyBtZWFzdXJlLCBhIEtQSSBtZWFzdXJlLCBhIGxpc3QgY29sdW1uLCBhIGNyb3NzLXRhYidzIGNlbGxzKSwgc28gYSBmb3JtYXRcbi8vIG1lYW5zIHRoZSBzYW1lIHRoaW5nIG9uIHNjcmVlbiwgaW4gdGhlIFBERiBhbmQgaW4gUG93ZXJQb2ludC4gVGhlIGRhdGEgc3RheXNcbi8vIHJhdzsgb25seSB3aGF0IGlzIHNob3duIGNoYW5nZXMuIFRoZSBydWxlczpcbi8vIC0gRW1wdHk6IG51bGwsIHVuZGVmaW5lZCwgJycsICctJyBhbmQgYSBub24tZmluaXRlIG51bWJlciBwcmludCB0aGUgY2FsbGVyJ3Ncbi8vICAgYGVtcHR5YCAoJ+KAlCcgdW5sZXNzIGl0IG5hbWVzIGFub3RoZXIpLlxuLy8gLSBOdW1lcmljOiBhIGZpbml0ZSBudW1iZXIsIG9yIGEgc3RyaW5nIHRoYXQgc3BlbGxzIG9uZSBwbGFpbmx5ICgnMTIzNC41MCcsXG4vLyAgICctM2UyJykuIEFueXRoaW5nIGVsc2UgKCckMSwyMzQnLCBhbiBpZCB3aXRoIGxldHRlcnMsICcgJykgcHJpbnRzIGFzIGl0XG4vLyAgIGNhbWUsIHNpbmNlIGEgY29sdW1uIHRoZSBTUUwgYWxyZWFkeSBmb3JtYXR0ZWQgaXMgdGV4dC5cbi8vIC0gU3R5bGVzOiBudW1iZXIgaXMgYSBwbGFpbiBkZWNpbWFsOyBjdXJyZW5jeSBpcyB0aGUgcmVwb3J0J3MgY3VycmVuY3lcbi8vICAgd3JpdHRlbiBpbiBpdHMgbG9jYWxlIHdpdGggaXRzIHN5bWJvbCAoVVNEIHJlYWRzICckMSwyMzUnIGluIGVuLVVTIGFuZFxuLy8gICAnVVMkMSwyMzUnIGluIGVuLUNBOyBFVVIgcmVhZHMgJzEgMjM1IOKCrCcgaW4gZnItRlIpOyBwZXJjZW50IHRha2VzIGEgMC0xXG4vLyAgIHJhdGlvICgwLjMgcmVhZHMgMzAlKSwgb3IsIGZyb20gYW4gb2xkZXIgc2VydmVyIHRoYXQgc2VuZHMgcGVyY2VudCB2YWx1ZXNcbi8vICAgYWxyZWFkeSB4MTAwLCBhIGRlY2ltYWwgd2l0aCBhICUgc2lnbi4gUHJlY2lzaW9uIG9yIHVuaXRzIHdpdGhvdXQgYSBmb3JtYXRcbi8vICAgbWVhbiBudW1iZXIuXG4vLyAtIERlY2ltYWxzOiBhIHByZWNpc2lvbiBwaW5zIGJvdGggdGhlIG1pbmltdW0gYW5kIHRoZSBtYXhpbXVtLCBzbyBhIGNvbHVtblxuLy8gICBvZiByYXRlcyBsaW5lcyB1cC4gV2l0aG91dCBvbmU6IGF0IG1vc3Qgb25lIGZvciBhIHBlcmNlbnQgYW5kIGZvciBhblxuLy8gICBhYmJyZXZpYXRlZCB2YWx1ZSAoMS4ySyksIHdob2xlIHVuaXRzIGZvciBjdXJyZW5jeSwgdGhlIGxvY2FsZSdzIGRlZmF1bHRcbi8vICAgZm9yIGEgbnVtYmVyLlxuLy8gLSBVbml0czogdGhvdXNhbmRzIGFuZCBtaWxsaW9ucyBkaXZpZGUgYW5kIGFkZCBhIEsgb3IgTSBhZnRlciB0aGUgZGlnaXRzXG4vLyAgICgnJDEuMksnLCAnMSwySyAkJyk7IGF1dG8gcGlja3MgcGVyIHZhbHVlIGJ5IHNpemUsIGFuZCBhIHZhbHVlIHRoYXQgd291bGRcbi8vICAgcm91bmQgdG8gMTAwMEsgcmVhZHMgMU0uIFVuaXRzIG5ldmVyIGFwcGx5IHRvIGEgcGVyY2VudC5cbi8vIC0gTmVnYXRpdmVzIGtlZXAgdGhlIGxvY2FsZSdzIGxlYWRpbmcgbWludXMuIEEgbmVnYXRpdmUgdGhhdCByb3VuZHMgdG8gemVyb1xuLy8gICBwcmludHMgYXMgemVybywgbmV2ZXIgJy0wJy5cbi8vIC0gUm91bmRpbmcgaXMgSW50bCdzLCBvbiB0aGUgZGlnaXRzIHNob3duLiBFdmVyeSB2YWx1ZSBpcyB3cml0dGVuIGluIHRoZVxuLy8gICBjb250ZXh0J3MgbG9jYWxlLCBuZXZlciB0aGUgYnJvd3NlcidzLlxuXG4vLyBUaGUgbW9zdCBkZWNpbWFscyBhIHByZWNpc2lvbiBwaW5zOiB0aGUgc2VydmVyJ3Mgc2NoZW1hIGJvdW5kLlxuY29uc3QgTUFYX1BSRUNJU0lPTiA9IDY7XG4vLyBBdCBtb3N0IG9uZSBkZWNpbWFsIGZvciBhIHBlcmNlbnQsIGFuZCBmb3IgYW4gYWJicmV2aWF0ZWQgdmFsdWUgKDEuMkspLlxuY29uc3QgUEVSQ0VOVF9ERUNJTUFMUyA9IDE7XG5jb25zdCBTQ0FMRURfREVDSU1BTFMgPSAxO1xuLy8gTW9uZXkgc2hvd3Mgd2hvbGUgdW5pdHMgdW5sZXNzIGEgcHJlY2lzaW9uIGFza3MgZm9yIGRlY2ltYWxzLlxuY29uc3QgQ1VSUkVOQ1lfREVDSU1BTFMgPSAwO1xuLy8gQSBjdXJyZW5jeSBheGlzIHdob3NlIHRpY2tzIG5lZWQgZGVjaW1hbHMgc2hvd3MgY2VudHMsIG5vdCB0ZW50aHMuXG5jb25zdCBDVVJSRU5DWV9BWElTX0RFQ0lNQUxTID0gMjtcbi8vIFdoYXQgYSBtaXNzaW5nIHZhbHVlIHByaW50cyB1bmxlc3MgdGhlIGNhbGxlciBuYW1lcyBpdHMgb3duLlxuY29uc3QgRU1QVFlfVkFMVUUgPSAn4oCUJztcbi8vIFRoZSB0aWNrIGNvdW50IGEgdmFsdWUgYXhpcyBhaW1zIGZvciwgYXMgRUNoYXJ0cycgc3BsaXROdW1iZXIgZGVmYXVsdC5cbmNvbnN0IEFYSVNfVElDS1MgPSA1O1xuXG4vLyBBIGNoYW5nZSdzIHNpZ246IGEgcGx1cyBvbiBhIHBvc2l0aXZlIHZhbHVlLCBub3RoaW5nIG9uIHplcm8uXG5jb25zdCBTSUdORUQ6IEludGwuTnVtYmVyRm9ybWF0T3B0aW9ucyA9IHsgc2lnbkRpc3BsYXk6ICdleGNlcHRaZXJvJyB9O1xuXG5jb25zdCBOVU1FUklDX1BBVFRFUk4gPSAvXlxccypbLStdPyhcXGQrXFwuP1xcZCp8XFwuXFxkKykoW2VFXVstK10/XFxkKyk/XFxzKiQvO1xuLy8gVGhlIGZvcm1hdFRvUGFydHMgdHlwZXMgdGhhdCBjYXJyeSBhIG51bWJlcidzIGRpZ2l0cyBhbmQgc2VwYXJhdG9ycy5cbmNvbnN0IE5VTUJFUl9QQVJUUyA9IG5ldyBTZXQ8SW50bC5OdW1iZXJGb3JtYXRQYXJ0VHlwZXM+KFsnaW50ZWdlcicsICdncm91cCcsICdkZWNpbWFsJywgJ2ZyYWN0aW9uJ10pO1xuY29uc3QgRElHSVRfUEFSVFMgPSBuZXcgU2V0PEludGwuTnVtYmVyRm9ybWF0UGFydFR5cGVzPihbJ2ludGVnZXInLCAnZnJhY3Rpb24nXSk7XG5cbi8vIEEgbnVtZXJpYyBmb3JtYXQncyB1bml0cyBvbmNlIGRlY2lkZWQ6IGF1dG8gaXMgcmVzb2x2ZWQgdG8gb25lIG9mIHRoZXNlLlxuZXhwb3J0IHR5cGUgUmVzb2x2ZWRVbml0cyA9IFJlcG9ydE51bWJlclVuaXRzLk5vbmUgfCBSZXBvcnROdW1iZXJVbml0cy5UaG91c2FuZHMgfCBSZXBvcnROdW1iZXJVbml0cy5NaWxsaW9ucztcblxuaW50ZXJmYWNlIFVuaXRTY2FsZSB7XG4gIGRpdmlzb3I6IG51bWJlcjtcbiAgc3VmZml4OiBzdHJpbmc7XG4gIC8vIFRoZSBQb3dlclBvaW50L0V4Y2VsIHNjYWxpbmcgY29tbWFzOiBlYWNoIG9uZSBkaXZpZGVzIGJ5IDEsMDAwLlxuICBjb21tYXM6IHN0cmluZztcbn1cblxuY29uc3QgVU5JVF9TQ0FMRVMgPSBuZXcgTWFwPFJlc29sdmVkVW5pdHMsIFVuaXRTY2FsZT4oW1xuICBbUmVwb3J0TnVtYmVyVW5pdHMuVGhvdXNhbmRzLCB7IGRpdmlzb3I6IDFlMywgc3VmZml4OiAnSycsIGNvbW1hczogJywnIH1dLFxuICBbUmVwb3J0TnVtYmVyVW5pdHMuTWlsbGlvbnMsIHsgZGl2aXNvcjogMWU2LCBzdWZmaXg6ICdNJywgY29tbWFzOiAnLCwnIH1dLFxuXSk7XG5cbmV4cG9ydCBpbnRlcmZhY2UgRm9ybWF0TnVtYmVyT3B0aW9ucyB7XG4gIC8vIFdoYXQgYW4gZW1wdHkgdmFsdWUgcHJpbnRzOiAn4oCUJyBmb3IgYSBLUEkgb3IgYSB0b29sdGlwLCAnJyBmb3IgYSBjZWxsLlxuICBlbXB0eT86IHN0cmluZztcbiAgLy8gVW5pdHMgYWxyZWFkeSBkZWNpZGVkIGZvciB0aGUgd2hvbGUgY2hhcnQsIGluIHBsYWNlIG9mIHRoZSBzcGVjJ3Mgb3duLlxuICB1bml0cz86IFJlc29sdmVkVW5pdHM7XG4gIC8vIERlY2ltYWxzIGFscmVhZHkgZGVjaWRlZCBmb3IgdGhlIHdob2xlIGNoYXJ0LCBwaW5uZWQgYXMgbWluIGFuZCBtYXguIG51bGxcbiAgLy8gbGVhdmVzIHRoZSBzcGVjJ3Mgb3duLlxuICBkZWNpbWFscz86IG51bWJlciB8IG51bGw7XG4gIC8vIFdyaXRlcyBhIHBsdXMgYmVmb3JlIGEgcG9zaXRpdmUgdmFsdWUsIGFzIGEgY2hhbmdlIHJlYWRzICgnKzEyJScpLiBaZXJvLFxuICAvLyBhbmQgYSB2YWx1ZSB3aG9zZSBzaG93biBkaWdpdHMgYXJlIGFsbCB6ZXJvLCBzdGF5cyB1bnNpZ25lZC5cbiAgc2lnbmVkPzogYm9vbGVhbjtcbn1cblxuLy8gSG93IGEgY2hhcnQncyB2YWx1ZSBheGlzIHdyaXRlcyBpdHMgdGlja3MsIGRlY2lkZWQgb25jZSBwZXIgY2hhcnQuXG5leHBvcnQgaW50ZXJmYWNlIENoYXJ0TnVtYmVyRm9ybWF0IHtcbiAgdW5pdHM6IFJlc29sdmVkVW5pdHM7XG4gIC8vIFBpbm5lZCBkZWNpbWFscywgb3IgbnVsbCBmb3IgYSBwbGFpbiBudW1iZXIgd2hvc2UgdGlja3Mga2VlcCB0aGVpciBvd24uXG4gIGRlY2ltYWxzOiBudW1iZXIgfCBudWxsO1xufVxuXG4vLyBUaGUgdmFsdWUgYXMgYSBmaW5pdGUgbnVtYmVyIHdoZW4gaXQgaXMgb25lIG9yIHBsYWlubHkgc3BlbGxzIG9uZSwgZWxzZVxuLy8gbnVsbC5cbmV4cG9ydCBmdW5jdGlvbiB0b0Zpbml0ZU51bWJlcih2YWx1ZTogdW5rbm93bik6IG51bWJlciB8IG51bGwge1xuICBpZiAodHlwZW9mIHZhbHVlID09PSAnbnVtYmVyJykge1xuICAgIHJldHVybiBOdW1iZXIuaXNGaW5pdGUodmFsdWUpID8gdmFsdWUgOiBudWxsO1xuICB9XG5cbiAgaWYgKHR5cGVvZiB2YWx1ZSAhPT0gJ3N0cmluZycgfHwgIU5VTUVSSUNfUEFUVEVSTi50ZXN0KHZhbHVlKSkge1xuICAgIHJldHVybiBudWxsO1xuICB9XG5cbiAgY29uc3QgbnVtZXJpYyA9IE51bWJlcih2YWx1ZSk7XG5cbiAgcmV0dXJuIE51bWJlci5pc0Zpbml0ZShudW1lcmljKSA/IG51bWVyaWMgOiBudWxsO1xufVxuXG4vLyBXaGV0aGVyIGEgc2xvdCBhc2tzIHRvIGJlIGZvcm1hdHRlZCBhdCBhbGwuIEEgc2xvdCB3aXRob3V0IHRoZXNlIGtleXMsIG9yIGFcbi8vIGxpc3QgY29sdW1uIHdob3NlIGZvcm1hdCBpcyBkYXRlLCBrZWVwcyBpdHMgb3duIHJlbmRlcmluZy4gVW5pdHMgbm9uZSBpcyB0aGVcbi8vIHNhbWUgYXMgbm8gdW5pdHMga2V5LCBhcyBpdCBpcyBvbiB0aGUgc2VydmVyLlxuZXhwb3J0IGZ1bmN0aW9uIGhhc051bWJlckZvcm1hdChzcGVjPzogTnVtYmVyRm9ybWF0U3BlYyB8IG51bGwpOiBib29sZWFuIHtcbiAgaWYgKCFzcGVjIHx8IHNwZWMuZm9ybWF0ID09PSBSZXBvcnRMaXN0Q29sdW1uRm9ybWF0LkRhdGUpIHtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cblxuICByZXR1cm4gdmFsdWVGb3JtYXQoc3BlYykgIT09IG51bGxcbiAgICB8fCAoc3BlYy5wcmVjaXNpb24gPz8gbnVsbCkgIT09IG51bGxcbiAgICB8fCAoKHNwZWMudW5pdHMgPz8gUmVwb3J0TnVtYmVyVW5pdHMuTm9uZSkgIT09IFJlcG9ydE51bWJlclVuaXRzLk5vbmUpO1xufVxuXG4vLyBUaGUgdW5pdHMgYSB2YWx1ZSBpcyB3cml0dGVuIGluLiBhdXRvIGRlY2lkZXMgYnkgdGhlIG1hZ25pdHVkZTogYSBtaWxsaW9uXG4vLyBhbmQgdXAgcmVhZHMgTSwgYSB0aG91c2FuZCBhbmQgdXAgSywgdW5sZXNzIHRoZSB2YWx1ZSB3b3VsZCB0aGVuIHJvdW5kIHRvXG4vLyAxMDAwSyBhdCB0aGVzZSBkZWNpbWFscywgd2hpY2ggcmVhZHMgMU0gaW5zdGVhZC5cbmV4cG9ydCBmdW5jdGlvbiByZXNvbHZlVW5pdHMoXG4gIHVuaXRzOiBSZXBvcnROdW1iZXJVbml0cyB8IG51bGwgfCB1bmRlZmluZWQsXG4gIG1hZ25pdHVkZTogbnVtYmVyLFxuICBkZWNpbWFsczogbnVtYmVyLFxuKTogUmVzb2x2ZWRVbml0cyB7XG4gIHN3aXRjaCAodW5pdHMpIHtcbiAgICBjYXNlIFJlcG9ydE51bWJlclVuaXRzLlRob3VzYW5kczpcbiAgICBjYXNlIFJlcG9ydE51bWJlclVuaXRzLk1pbGxpb25zOlxuICAgICAgcmV0dXJuIHVuaXRzO1xuICAgIGNhc2UgUmVwb3J0TnVtYmVyVW5pdHMuQXV0bzpcbiAgICAgIHJldHVybiBhdXRvVW5pdHMoTWF0aC5hYnMobWFnbml0dWRlKSwgZGVjaW1hbHMpO1xuICAgIGRlZmF1bHQ6XG4gICAgICByZXR1cm4gUmVwb3J0TnVtYmVyVW5pdHMuTm9uZTtcbiAgfVxufVxuXG5mdW5jdGlvbiBhdXRvVW5pdHMobWFnbml0dWRlOiBudW1iZXIsIGRlY2ltYWxzOiBudW1iZXIpOiBSZXNvbHZlZFVuaXRzIHtcbiAgaWYgKG1hZ25pdHVkZSA+PSAxZTYpIHtcbiAgICByZXR1cm4gUmVwb3J0TnVtYmVyVW5pdHMuTWlsbGlvbnM7XG4gIH1cblxuICBpZiAobWFnbml0dWRlIDwgMWUzKSB7XG4gICAgcmV0dXJuIFJlcG9ydE51bWJlclVuaXRzLk5vbmU7XG4gIH1cblxuICByZXR1cm4gcm91bmRUbyhtYWduaXR1ZGUgLyAxZTMsIGRlY2ltYWxzKSA+PSAxMDAwXG4gICAgPyBSZXBvcnROdW1iZXJVbml0cy5NaWxsaW9uc1xuICAgIDogUmVwb3J0TnVtYmVyVW5pdHMuVGhvdXNhbmRzO1xufVxuXG4vLyBUaGUgdmFsdWUgcm91bmRlZCBhcyBJbnRsIHJvdW5kcyBpdCBmb3IgZGlzcGxheSwgc28gdGhlIEstdG8tTSBwcm9tb3Rpb25cbi8vIGFncmVlcyB3aXRoIHRoZSBkaWdpdHMgYWN0dWFsbHkgc2hvd24uXG5mdW5jdGlvbiByb3VuZFRvKHZhbHVlOiBudW1iZXIsIGRlY2ltYWxzOiBudW1iZXIpOiBudW1iZXIge1xuICBjb25zdCBkaWdpdHMgPSBjbGFtcERlY2ltYWxzKGRlY2ltYWxzKSA/PyAwO1xuXG4gIC8vIEEgZml4ZWQgbG9jYWxlIG9ubHkgc28gTnVtYmVyKCkgY2FuIHBhcnNlIHRoZSByb3VuZGVkIGRpZ2l0cyBiYWNrLlxuICByZXR1cm4gTnVtYmVyKG51bWJlckZvcm1hdChSRVBPUlRfRkFMTEJBQ0tfTE9DQUxFLCB7XG4gICAgdXNlR3JvdXBpbmc6IGZhbHNlLFxuICAgIG1pbmltdW1GcmFjdGlvbkRpZ2l0czogMCxcbiAgICBtYXhpbXVtRnJhY3Rpb25EaWdpdHM6IGRpZ2l0cyxcbiAgfSkuZm9ybWF0KHZhbHVlKSk7XG59XG5cbi8vIE9uZSB2YWx1ZSwgd3JpdHRlbiBieSB0aGUgcnVsZXMgYWJvdmUuXG5leHBvcnQgZnVuY3Rpb24gZm9ybWF0TnVtYmVyKFxuICB2YWx1ZTogdW5rbm93bixcbiAgc3BlYzogTnVtYmVyRm9ybWF0U3BlYyB8IG51bGwgfCB1bmRlZmluZWQsXG4gIGNvbnRleHQ6IFJlcG9ydEZvcm1hdENvbnRleHQsXG4gIG9wdGlvbnM6IEZvcm1hdE51bWJlck9wdGlvbnMgPSB7fSxcbik6IHN0cmluZyB7XG4gIGlmIChpc0VtcHR5VmFsdWUodmFsdWUpKSB7XG4gICAgcmV0dXJuIG9wdGlvbnMuZW1wdHkgPz8gRU1QVFlfVkFMVUU7XG4gIH1cblxuICBjb25zdCBudW1lcmljID0gdG9GaW5pdGVOdW1iZXIodmFsdWUpO1xuICBpZiAobnVtZXJpYyA9PT0gbnVsbCkge1xuICAgIHJldHVybiBTdHJpbmcodmFsdWUpO1xuICB9XG5cbiAgY29uc3Qgc3R5bGUgPSByZXNvbHZlU3R5bGUoc3BlYyk7XG4gIGNvbnN0IHByZWNpc2lvbiA9IGNsYW1wRGVjaW1hbHMoc3BlYz8ucHJlY2lzaW9uKTtcbiAgY29uc3QgdW5pdHMgPSBzdHlsZSA9PT0gUmVwb3J0VmFsdWVGb3JtYXQuUGVyY2VudFxuICAgID8gUmVwb3J0TnVtYmVyVW5pdHMuTm9uZVxuICAgIDogb3B0aW9ucy51bml0cyA/PyByZXNvbHZlVW5pdHMoc3BlYz8udW5pdHMsIG51bWVyaWMsIHByZWNpc2lvbiA/PyBTQ0FMRURfREVDSU1BTFMpO1xuICBjb25zdCBzY2FsZSA9IFVOSVRfU0NBTEVTLmdldCh1bml0cyk7XG4gIGNvbnN0IGRlY2ltYWxzID0gY2xhbXBEZWNpbWFscyhvcHRpb25zLmRlY2ltYWxzKSA/PyBwcmVjaXNpb247XG4gIGNvbnN0IGZvcm1hdHRlciA9IG51bWJlckZvcm1hdChjb250ZXh0LmxvY2FsZSwge1xuICAgIC4uLnN0eWxlT3B0aW9ucyhzdHlsZSwgY29udGV4dCwgZGVjaW1hbHMsICEhc2NhbGUpLFxuICAgIC4uLihvcHRpb25zLnNpZ25lZCA/IFNJR05FRCA6IHt9KSxcbiAgfSk7XG4gIGNvbnN0IHRleHQgPSB3cml0ZU51bWJlcihmb3JtYXR0ZXIsIChudW1lcmljID09PSAwID8gMCA6IG51bWVyaWMpIC8gKHNjYWxlPy5kaXZpc29yID8/IDEpLCBzY2FsZT8uc3VmZml4KTtcblxuICByZXR1cm4gc3R5bGUgPT09IFJlcG9ydFZhbHVlRm9ybWF0LlBlcmNlbnQgJiYgIWNvbnRleHQucmF0aW9QZXJjZW50ID8gYCR7dGV4dH0lYCA6IHRleHQ7XG59XG5cbmZ1bmN0aW9uIGlzRW1wdHlWYWx1ZSh2YWx1ZTogdW5rbm93bik6IGJvb2xlYW4ge1xuICByZXR1cm4gdmFsdWUgPT09IG51bGxcbiAgICB8fCB2YWx1ZSA9PT0gdW5kZWZpbmVkXG4gICAgfHwgdmFsdWUgPT09ICcnXG4gICAgfHwgdmFsdWUgPT09ICctJ1xuICAgIHx8ICh0eXBlb2YgdmFsdWUgPT09ICdudW1iZXInICYmICFOdW1iZXIuaXNGaW5pdGUodmFsdWUpKTtcbn1cblxuLy8gVGhlIHZhbHVlIGZvcm1hdCBhIHNsb3QgbmFtZXMsIG9yIG51bGwgd2hlbiBpdCBuYW1lcyBub25lIChvciBvbmx5IGRhdGUpLlxuZnVuY3Rpb24gdmFsdWVGb3JtYXQoc3BlYzogTnVtYmVyRm9ybWF0U3BlYyB8IG51bGwgfCB1bmRlZmluZWQpOiBSZXBvcnRWYWx1ZUZvcm1hdCB8IG51bGwge1xuICByZXR1cm4gT2JqZWN0LnZhbHVlcyhSZXBvcnRWYWx1ZUZvcm1hdCkuZmluZCgoZm9ybWF0KSA9PiBmb3JtYXQgPT09IHNwZWM/LmZvcm1hdCkgPz8gbnVsbDtcbn1cblxuZnVuY3Rpb24gcmVzb2x2ZVN0eWxlKHNwZWM6IE51bWJlckZvcm1hdFNwZWMgfCBudWxsIHwgdW5kZWZpbmVkKTogUmVwb3J0VmFsdWVGb3JtYXQge1xuICByZXR1cm4gdmFsdWVGb3JtYXQoc3BlYykgPz8gUmVwb3J0VmFsdWVGb3JtYXQuTnVtYmVyO1xufVxuXG4vLyBBIHVzYWJsZSBkZWNpbWFsIGNvdW50LCBvciBudWxsLiBBIHN0b3JlZCB2YWx1ZSBvdXRzaWRlIHRoZSBzY2hlbWEncyBib3VuZHNcbi8vIGlzIGJyb3VnaHQgaW5zaWRlIHRoZW0gcmF0aGVyIHRoYW4gdGhyb3duIG9uIGJ5IEludGwuXG5mdW5jdGlvbiBjbGFtcERlY2ltYWxzKGRlY2ltYWxzOiBudW1iZXIgfCBudWxsIHwgdW5kZWZpbmVkKTogbnVtYmVyIHwgbnVsbCB7XG4gIHJldHVybiB0eXBlb2YgZGVjaW1hbHMgPT09ICdudW1iZXInICYmIE51bWJlci5pc0Zpbml0ZShkZWNpbWFscylcbiAgICA/IE1hdGgubWluKE1BWF9QUkVDSVNJT04sIE1hdGgubWF4KDAsIE1hdGgucm91bmQoZGVjaW1hbHMpKSlcbiAgICA6IG51bGw7XG59XG5cbmZ1bmN0aW9uIHN0eWxlT3B0aW9ucyhcbiAgc3R5bGU6IFJlcG9ydFZhbHVlRm9ybWF0LFxuICBjb250ZXh0OiBSZXBvcnRGb3JtYXRDb250ZXh0LFxuICBkZWNpbWFsczogbnVtYmVyIHwgbnVsbCxcbiAgc2NhbGVkOiBib29sZWFuLFxuKTogSW50bC5OdW1iZXJGb3JtYXRPcHRpb25zIHtcbiAgY29uc3QgZnJhY3Rpb25EaWdpdHMgPSBmcmFjdGlvbkRpZ2l0T3B0aW9ucyhkZWNpbWFscywgZGVmYXVsdERlY2ltYWxzKHN0eWxlLCBzY2FsZWQpKTtcblxuICBzd2l0Y2ggKHN0eWxlKSB7XG4gICAgY2FzZSBSZXBvcnRWYWx1ZUZvcm1hdC5DdXJyZW5jeTpcbiAgICAgIHJldHVybiB7IC4uLmN1cnJlbmN5T3B0aW9ucyhjb250ZXh0LmN1cnJlbmN5KSwgLi4uZnJhY3Rpb25EaWdpdHMgfTtcbiAgICBjYXNlIFJlcG9ydFZhbHVlRm9ybWF0LlBlcmNlbnQ6XG4gICAgICByZXR1cm4gY29udGV4dC5yYXRpb1BlcmNlbnQgPyB7IHN0eWxlOiAncGVyY2VudCcsIC4uLmZyYWN0aW9uRGlnaXRzIH0gOiBmcmFjdGlvbkRpZ2l0cztcbiAgICBkZWZhdWx0OlxuICAgICAgcmV0dXJuIGZyYWN0aW9uRGlnaXRzO1xuICB9XG59XG5cbmZ1bmN0aW9uIGN1cnJlbmN5T3B0aW9ucyhjdXJyZW5jeTogUmVwb3J0Q3VycmVuY3lDb2RlKTogSW50bC5OdW1iZXJGb3JtYXRPcHRpb25zIHtcbiAgcmV0dXJuIHsgc3R5bGU6ICdjdXJyZW5jeScsIGN1cnJlbmN5LCBjdXJyZW5jeURpc3BsYXk6ICdzeW1ib2wnIH07XG59XG5cbi8vIFRoZSBtb3N0IGRlY2ltYWxzIGEgc3R5bGUgc2hvd3Mgd2hlbiBub3RoaW5nIHBpbnMgdGhlbTsgbnVsbCBsZWF2ZXMgSW50bCdzXG4vLyBvd24gZGVmYXVsdC5cbmZ1bmN0aW9uIGRlZmF1bHREZWNpbWFscyhzdHlsZTogUmVwb3J0VmFsdWVGb3JtYXQsIHNjYWxlZDogYm9vbGVhbik6IG51bWJlciB8IG51bGwge1xuICBpZiAoc2NhbGVkKSB7XG4gICAgcmV0dXJuIFNDQUxFRF9ERUNJTUFMUztcbiAgfVxuXG4gIHN3aXRjaCAoc3R5bGUpIHtcbiAgICBjYXNlIFJlcG9ydFZhbHVlRm9ybWF0LlBlcmNlbnQ6XG4gICAgICByZXR1cm4gUEVSQ0VOVF9ERUNJTUFMUztcbiAgICBjYXNlIFJlcG9ydFZhbHVlRm9ybWF0LkN1cnJlbmN5OlxuICAgICAgcmV0dXJuIENVUlJFTkNZX0RFQ0lNQUxTO1xuICAgIGRlZmF1bHQ6XG4gICAgICByZXR1cm4gbnVsbDtcbiAgfVxufVxuXG4vLyBQaW5uZWQgZGVjaW1hbHMgc2V0IGJvdGggYm91bmRzLiBPdGhlcndpc2UgYSBtYXhpbXVtIGFsc28gc2V0cyB0aGUgbWluaW11bVxuLy8gdG8gemVybywgc28gbm8gZW5naW5lIHRocm93cyBvbiBhIG1heGltdW0gYmVsb3cgYSBjdXJyZW5jeSdzIG93biBtaW5pbXVtLlxuZnVuY3Rpb24gZnJhY3Rpb25EaWdpdE9wdGlvbnMocGlubmVkOiBudW1iZXIgfCBudWxsLCBtYXhpbXVtOiBudW1iZXIgfCBudWxsKTogSW50bC5OdW1iZXJGb3JtYXRPcHRpb25zIHtcbiAgaWYgKHBpbm5lZCAhPT0gbnVsbCkge1xuICAgIHJldHVybiB7IG1pbmltdW1GcmFjdGlvbkRpZ2l0czogcGlubmVkLCBtYXhpbXVtRnJhY3Rpb25EaWdpdHM6IHBpbm5lZCB9O1xuICB9XG5cbiAgcmV0dXJuIG1heGltdW0gPT09IG51bGwgPyB7fSA6IHsgbWluaW11bUZyYWN0aW9uRGlnaXRzOiAwLCBtYXhpbXVtRnJhY3Rpb25EaWdpdHM6IG1heGltdW0gfTtcbn1cblxuLy8gVGhlIGZvcm1hdHRlZCB2YWx1ZSwgd2l0aCB0aGUgdW5pdHMgbGV0dGVyIGFmdGVyIGl0cyBkaWdpdHMuIEEgbmVnYXRpdmVcbi8vIHdob3NlIHNob3duIGRpZ2l0cyBhcmUgYWxsIHplcm8gaXMgd3JpdHRlbiBhcyB6ZXJvLCBzbyBubyAnLTAnIGFwcGVhcnMuXG5mdW5jdGlvbiB3cml0ZU51bWJlcihmb3JtYXR0ZXI6IEludGwuTnVtYmVyRm9ybWF0LCB2YWx1ZTogbnVtYmVyLCBzdWZmaXg/OiBzdHJpbmcpOiBzdHJpbmcge1xuICBpZiAodmFsdWUgPj0gMCAmJiAhc3VmZml4KSB7XG4gICAgcmV0dXJuIGZvcm1hdHRlci5mb3JtYXQodmFsdWUpO1xuICB9XG5cbiAgY29uc3QgcGFydHMgPSBmb3JtYXR0ZXIuZm9ybWF0VG9QYXJ0cyh2YWx1ZSk7XG5cbiAgaWYgKHZhbHVlIDwgMCAmJiAhaGFzTm9uWmVyb0RpZ2l0KGZvcm1hdHRlciwgcGFydHMpKSB7XG4gICAgcmV0dXJuIHdyaXRlTnVtYmVyKGZvcm1hdHRlciwgMCwgc3VmZml4KTtcbiAgfVxuXG4gIGlmICghc3VmZml4KSB7XG4gICAgcmV0dXJuIHBhcnRzLm1hcCgocGFydCkgPT4gcGFydC52YWx1ZSkuam9pbignJyk7XG4gIH1cblxuICBjb25zdCBsYXN0ID0gcGFydHMucmVkdWNlKChmb3VuZCwgcGFydCwgaW5kZXgpID0+IE5VTUJFUl9QQVJUUy5oYXMocGFydC50eXBlKSA/IGluZGV4IDogZm91bmQsIC0xKTtcblxuICByZXR1cm4gW1xuICAgIC4uLnBhcnRzLnNsaWNlKDAsIGxhc3QgKyAxKS5tYXAoKHBhcnQpID0+IHBhcnQudmFsdWUpLFxuICAgIHN1ZmZpeCxcbiAgICAuLi5wYXJ0cy5zbGljZShsYXN0ICsgMSkubWFwKChwYXJ0KSA9PiBwYXJ0LnZhbHVlKSxcbiAgXS5qb2luKCcnKTtcbn1cblxuLy8gQ29tcGFyZWQgd2l0aCB0aGUgbG9jYWxlJ3Mgb3duIHplcm8sIHNvIGEgbnVtYmVyaW5nIHN5c3RlbSBvdGhlciB0aGFuXG4vLyAwLTkgaXMgcmVhZCBjb3JyZWN0bHkuXG5mdW5jdGlvbiBoYXNOb25aZXJvRGlnaXQoZm9ybWF0dGVyOiBJbnRsLk51bWJlckZvcm1hdCwgcGFydHM6IEludGwuTnVtYmVyRm9ybWF0UGFydFtdKTogYm9vbGVhbiB7XG4gIGNvbnN0IHplcm8gPSBmb3JtYXR0ZXIuZm9ybWF0VG9QYXJ0cygwKS5maW5kKChwYXJ0KSA9PiBwYXJ0LnR5cGUgPT09ICdpbnRlZ2VyJyk/LnZhbHVlID8/ICcwJztcblxuICByZXR1cm4gcGFydHMuc29tZSgocGFydCkgPT4gRElHSVRfUEFSVFMuaGFzKHBhcnQudHlwZSlcbiAgICAmJiBBcnJheS5mcm9tKHBhcnQudmFsdWUpLnNvbWUoKGNoYXJhY3RlcikgPT4gY2hhcmFjdGVyICE9PSB6ZXJvKSk7XG59XG5cblxuLy8gT3V0cHV0IHZhbHVlczogYSBjb2x1bW4gdGhlIHNlcnZlciBtYXJrcyBpbiBDb21wb25lbnREYXRhLm91dHB1dHMgKGFcbi8vIGNvbXBhcmVkIHZhbHVlLCBhIHJhbmssIGEgc2hhcmUpIHdyaXR0ZW4gYnkgd2hhdCBpdCBpcy4gVGhlIGRhdGEgc3RheXMgcmF3O1xuLy8gZXZlcnkgbnVtYmVyIHN0aWxsIGdvZXMgdGhyb3VnaCBmb3JtYXROdW1iZXIuIFRoZSBydWxlczpcbi8vIC0gVGhlIGZvcm1hdDogYSBzbG90J3Mgb3duIGV4cGxpY2l0IGZvcm1hdCBhbHdheXMgd2lucy4gT3RoZXJ3aXNlIGEgY3VycmVudCxcbi8vICAgcHJpb3Igb3IgY2hhbmdlIGNvbHVtbiB0YWtlcyBpdHMgc291cmNlIG1lYXN1cmUncyBmb3JtYXQ7IGEgcGVyY2VudCBjaGFuZ2Vcbi8vICAgaXMgYSBwZXJjZW50OyBhIHJhbmsgaXMgYSB3aG9sZSBudW1iZXI7IGEgc2hhcmUgaXMgYSBwZXJjZW50IHRvIDEgZGVjaW1hbC5cbi8vICAgQW4gb3duIHByZWNpc2lvbiBvciB1bml0cyBzdGlsbCBhcHBsaWVzIG92ZXIgdGhvc2UgZGVmYXVsdHMuXG4vLyAtIFNpZ25zOiBhIGNoYW5nZSBhbmQgYSBwZXJjZW50IGNoYW5nZSBhcmUgc2lnbmVkICgnKzU3OScsICctMzEuMSUnKS5cbi8vIC0gUG9pbnRzOiBhIGNoYW5nZSBvZiBhIHBlcmNlbnQtZm9ybWF0IHZhbHVlLCBhbmQgYW55IHNoYXJlIGNoYW5nZSwgaXMgYVxuLy8gICBkaWZmZXJlbmNlIG9mIHR3byByYXRlcywgc28gaXQgcHJpbnRzIGluIHBlcmNlbnRhZ2UgcG9pbnRzLCBzaWduZWQgYW5kIHRvXG4vLyAgIDEgZGVjaW1hbCB1bmxlc3MgYSBwcmVjaXNpb24gcGlucyBvdGhlcnM6IDAuMSByZWFkcyAnKzEwLjAgcHAnLlxuLy8gLSBNaXNzaW5nOiBhIG1pc3NpbmcgcHJpb3IsIG9yIGEgY2hhbmdlIG9yIHBlcmNlbnQgY2hhbmdlIGxlZnQgZW1wdHkgYnlcbi8vICAgb25lLCBwcmludHMgJ+KAlCcgdGl0bGVkIHdpdGggdGhlIGZsb29yICgnTm8gYmFzZWxpbmU6IG5vIGRhdGEgYmVmb3JlXG4vLyAgIE1hciAzLCAyMDI2JyksIG9yIGZvciBhIHJhbmsgb3IgYSBzaGFyZSB3aXRoIHRoZSBwZXJpb2QgdGhlIHJvdyB3YXNcbi8vICAgYWJzZW50IGZyb20gKCdObyByYW5rIGluIHRoZSBwcmlvciBwZXJpb2QnKTsgYSBwZXJjZW50IGNoYW5nZSBvdmVyIGEgcHJpb3Igb2YgMCBwcmludHMgJ24vYScgdGl0bGVkXG4vLyAgICdQcmlvciB3YXMgMCcuIEFueSBvdGhlciBtaXNzaW5nIHZhbHVlIHByaW50cyAn4oCUJyAob3IgdGhlIGNhbGxlcidzIGVtcHR5KS5cbi8vIC0gUmFuayBjaGFuZ2U6IHByaW9yIG1pbnVzIGN1cnJlbnQsIHNvIGEgcmlzZSBpcyBwb3NpdGl2ZTogJ+KWsiAyJywgJ+KWvCAxJyxcbi8vICAgJ+KAkycgZm9yIG5vbmUsIGFuZCAnbmV3JyBmb3IgYW4gZW1wdHkgY2hhbmdlIHdob3NlIHByaW9yIHJhbmsgaXMgbWlzc2luZ1xuLy8gICBvciBub3QgcGFzc2VkIChhIHJvdyBhbHdheXMgaGFzIGEgY3VycmVudCByYW5rLCBzbyBvbmx5IHRoZSBwcmlvciBsYWNrcykuXG4vLyBBIHBlcmNlbnQgY2hhbmdlIGFuZCBhIHNoYXJlIGFyZSAwLTEgZnJhY3Rpb25zIHdoYXRldmVyIHRoZSByZXBvcnQnc1xuLy8gcGVyY2VudEZvcm1hdDogdGhlIHNlcnZlciBjb21wdXRlcyB0aGVtLCBuZXZlciBhIHN0b3JlZCB2YWx1ZS5cblxuLy8gQSBtaXNzaW5nIGNvbXBhcmlzb24gdmFsdWUgcHJpbnRzIEVNUFRZX1ZBTFVFIHdoYXRldmVyIHRoZSBjYWxsZXIncyBlbXB0eS5cbmNvbnN0IE5PVF9BUFBMSUNBQkxFX1ZBTFVFID0gJ24vYSc7XG5jb25zdCBORVdfUkFOS19WQUxVRSA9ICduZXcnO1xuY29uc3QgUkFOS19VTkNIQU5HRURfVkFMVUUgPSAn4oCTJztcbmNvbnN0IFJBTktfVVBfTUFSSyA9ICfilrInO1xuY29uc3QgUkFOS19ET1dOX01BUksgPSAn4pa8JztcbmNvbnN0IFBPSU5UU19TVUZGSVggPSAncHAnO1xuY29uc3QgTk9fUFJJT1JfUkFOS19USVRMRSA9ICdObyByYW5rIGluIHRoZSBwcmlvciBwZXJpb2QnO1xuY29uc3QgTk9fUFJJT1JfU0hBUkVfVElUTEUgPSAnTm8gc2hhcmUgaW4gdGhlIHByaW9yIHBlcmlvZCc7XG4vLyBQZXJjZW50YWdlIHBvaW50cyBhbmQgYSBzaGFyZSBhcmUgd3JpdHRlbiB0byBvbmUgZGVjaW1hbCB1bmxlc3MgcGlubmVkLlxuY29uc3QgUE9JTlRTX0RFQ0lNQUxTID0gMTtcbmNvbnN0IFNIQVJFX0RFQ0lNQUxTID0gMTtcblxuY29uc3QgUkFOS19ERUZBVUxUX1NQRUM6IFJlYWRvbmx5PE51bWJlckZvcm1hdFNwZWM+ID0gT2JqZWN0LmZyZWV6ZSh7IGZvcm1hdDogUmVwb3J0VmFsdWVGb3JtYXQuTnVtYmVyLCBwcmVjaXNpb246IDAgfSk7XG5jb25zdCBTSEFSRV9ERUZBVUxUX1NQRUM6IFJlYWRvbmx5PE51bWJlckZvcm1hdFNwZWM+ID0gT2JqZWN0LmZyZWV6ZSh7XG4gIGZvcm1hdDogUmVwb3J0VmFsdWVGb3JtYXQuUGVyY2VudCxcbiAgcHJlY2lzaW9uOiBTSEFSRV9ERUNJTUFMUyxcbn0pO1xuY29uc3QgUEVSQ0VOVF9DSEFOR0VfREVGQVVMVF9TUEVDOiBSZWFkb25seTxOdW1iZXJGb3JtYXRTcGVjPiA9IE9iamVjdC5mcmVlemUoeyBmb3JtYXQ6IFJlcG9ydFZhbHVlRm9ybWF0LlBlcmNlbnQgfSk7XG5cbmV4cG9ydCBpbnRlcmZhY2UgT3V0cHV0VmFsdWVPcHRpb25zIHtcbiAgLy8gVGhlIHNvdXJjZSBtZWFzdXJlJ3MgZm9ybWF0IChPdXRwdXRNZXRhLm1lYXN1cmUncyBzbG90KSwgd2hpY2ggYSBjdXJyZW50LFxuICAvLyBwcmlvciBvciBjaGFuZ2UgY29sdW1uIHRha2VzIHdoZW4gaXRzIG93biBzbG90IG5hbWVzIG5vbmUuXG4gIG1lYXN1cmVTcGVjPzogTnVtYmVyRm9ybWF0U3BlYyB8IG51bGw7XG4gIC8vIFRoZSByb3cncyBwcmlvciB2YWx1ZSBpbiB0aGUgc2FtZSBsYW5lIChzZWUgbGFuZU91dHB1dEFsaWFzKSwgZm9yIGEgY2hhbmdlXG4gIC8vIG9yIGEgcGVyY2VudCBjaGFuZ2U6IGl0IHRlbGxzIGEgbWlzc2luZyBiYXNlbGluZSAoJ+KAlCcpIGZyb20gYSB6ZXJvIG9uZVxuICAvLyAoJ24vYScpLCBhbmQgYSBuZXcgcmFuayBmcm9tIGFuIHVucmFua2VkIHJvdy4gTGVhdmUgaXQgb3V0IHdoZW4gdW5rbm93bi5cbiAgcHJpb3I/OiB1bmtub3duO1xuICAvLyBDb21wb25lbnREYXRhLmNvbXBhcmlzb24uZmxvb3I6IHRoZSBmaXJzdCBkYXkgd2l0aCBkYXRhLCBuYW1lZCBpbiB0aGVcbiAgLy8gbm8tYmFzZWxpbmUgdGl0bGUuXG4gIGZsb29yPzogc3RyaW5nIHwgbnVsbDtcbiAgLy8gV2hhdCBhIG1pc3NpbmcgY3VycmVudCBvciBwbGFpbiB2YWx1ZSBwcmludHMgKCcnIGZvciBhIGNlbGwpLiBBIG1pc3NpbmdcbiAgLy8gY29tcGFyaXNvbiB2YWx1ZSBhbHdheXMgcHJpbnRzICfigJQnLlxuICBlbXB0eT86IHN0cmluZztcbn1cblxuLy8gQW4gb3V0cHV0IHZhbHVlIGFzIHNob3duLCBhbmQgd2h5IGl0IHJlYWRzIHNvIHdoZW4gdGhhdCBpcyBub3Qgb2J2aW91c1xuLy8gKG51bGwgb3RoZXJ3aXNlKTogZm9yIGEgdG9vbHRpcCBvciBhIHRpdGxlIGF0dHJpYnV0ZS5cbmV4cG9ydCBpbnRlcmZhY2UgRm9ybWF0dGVkT3V0cHV0VmFsdWUge1xuICB0ZXh0OiBzdHJpbmc7XG4gIHRpdGxlOiBzdHJpbmcgfCBudWxsO1xufVxuXG4vLyBPbmUgb3V0cHV0IHZhbHVlLCB3cml0dGVuIGJ5IHRoZSBydWxlcyBhYm92ZS4gV2l0aG91dCBvdXRwdXQgbWV0YWRhdGEgKGFcbi8vIHBsYWluIG1lYXN1cmUgY29sdW1uLCBhbiBvbGRlciBzZXJ2ZXIpIGl0IGlzIGZvcm1hdE51bWJlciB3aXRoIHRoZSBzbG90J3Ncbi8vIG93biBmb3JtYXQuXG5leHBvcnQgZnVuY3Rpb24gZm9ybWF0T3V0cHV0VmFsdWUoXG4gIHZhbHVlOiB1bmtub3duLFxuICBvdXRwdXQ6IE91dHB1dE1ldGEgfCBudWxsIHwgdW5kZWZpbmVkLFxuICBzcGVjOiBOdW1iZXJGb3JtYXRTcGVjIHwgbnVsbCB8IHVuZGVmaW5lZCxcbiAgY29udGV4dDogUmVwb3J0Rm9ybWF0Q29udGV4dCxcbiAgb3B0aW9uczogT3V0cHV0VmFsdWVPcHRpb25zID0ge30sXG4pOiBGb3JtYXR0ZWRPdXRwdXRWYWx1ZSB7XG4gIGlmICghb3V0cHV0KSB7XG4gICAgcmV0dXJuIHBsYWluT3V0cHV0KGZvcm1hdE51bWJlcih2YWx1ZSwgc3BlYywgY29udGV4dCwgeyBlbXB0eTogb3B0aW9ucy5lbXB0eSB9KSk7XG4gIH1cblxuICBpZiAob3V0cHV0LmtpbmQgPT09ICdyYW5rJyAmJiBvdXRwdXQucm9sZSA9PT0gJ2NoYW5nZScpIHtcbiAgICByZXR1cm4gZm9ybWF0UmFua0NoYW5nZSh2YWx1ZSwgc3BlYywgY29udGV4dCwgb3B0aW9ucyk7XG4gIH1cblxuICBjb25zdCByb2xlID0gb3V0cHV0LnJvbGU7XG4gIGNvbnN0IGVmZmVjdGl2ZSA9IG91dHB1dEZvcm1hdFNwZWMob3V0cHV0LCBzcGVjLCBvcHRpb25zLm1lYXN1cmVTcGVjKTtcblxuICBpZiAoaXNFbXB0eVZhbHVlKHZhbHVlKSkge1xuICAgIHJldHVybiBtaXNzaW5nT3V0cHV0KG91dHB1dCwgY29udGV4dCwgb3B0aW9ucyk7XG4gIH1cblxuICBpZiAocm9sZSA9PT0gJ2NoYW5nZScgJiYgaXNQb2ludHNDaGFuZ2Uob3V0cHV0LCBlZmZlY3RpdmUpKSB7XG4gICAgcmV0dXJuIHBsYWluT3V0cHV0KGZvcm1hdFBvaW50cyh2YWx1ZSwgb3V0cHV0LCBlZmZlY3RpdmUsIGNvbnRleHQpKTtcbiAgfVxuXG4gIGNvbnN0IHNpZ25lZCA9IHJvbGUgPT09ICdjaGFuZ2UnIHx8IHJvbGUgPT09ICdwZXJjZW50X2NoYW5nZSc7XG4gIGNvbnN0IHJhdGlvQ29udGV4dCA9IHJvbGUgPT09ICdwZXJjZW50X2NoYW5nZScgfHwgb3V0cHV0LmtpbmQgPT09ICdzaGFyZSdcbiAgICA/IHsgLi4uY29udGV4dCwgcmF0aW9QZXJjZW50OiB0cnVlIH1cbiAgICA6IGNvbnRleHQ7XG5cbiAgcmV0dXJuIHBsYWluT3V0cHV0KGZvcm1hdE51bWJlcih2YWx1ZSwgZWZmZWN0aXZlLCByYXRpb0NvbnRleHQsIHsgc2lnbmVkIH0pKTtcbn1cblxuLy8gVGhlIGFsaWFzIG9mIHRoZSBvdXRwdXQgdGhhdCBwbGF5cyBgcm9sZWAgaW4gdGhlIHNhbWUgbGFuZSBhcyBgYWxpYXNgOiB0aGVcbi8vIHNhbWUgbWVhc3VyZSBhbmQga2luZCwgYW5kIChmb3IgYSBwcmlvciwgY2hhbmdlIG9yIHBlcmNlbnQgY2hhbmdlKSB0aGUgc2FtZVxuLy8gcHJpb3IgbGFuZS4gQSBtZWFzdXJlIGNvbXBhcmVzIGFnYWluc3Qgb25lIGxhbmUgb25seSAodHdvIGNvbXBhcmVzIG9uIG9uZVxuLy8gdmFsdWUgYXJlIHR3byBtZWFzdXJlcyksIHNvIGEgY3VycmVudCB2YWx1ZSdzIGxhbmUgaXMgd2hpY2hldmVyIG9uZSBpdHNcbi8vIG1lYXN1cmUncyBwcmlvciBjb2x1bW5zIGNhcnJ5LCBsYW5lIDIgYXMgcmVhZGlseSBhcyBsYW5lIDEuIEEgY2hhbmdlIGNvbHVtblxuLy8gZmluZHMgaXRzIHByaW9yIHRoaXMgd2F5IHRvIHBhc3MgYXMgT3V0cHV0VmFsdWVPcHRpb25zLnByaW9yLiBudWxsIHdoZW4gdGhlXG4vLyBzZXJ2ZXIgc2VuZHMgbm8gc3VjaCBjb2x1bW4uXG5leHBvcnQgZnVuY3Rpb24gbGFuZU91dHB1dEFsaWFzKFxuICBvdXRwdXRzOiBSZWNvcmQ8c3RyaW5nLCBPdXRwdXRNZXRhPiB8IG51bGwgfCB1bmRlZmluZWQsXG4gIGFsaWFzOiBzdHJpbmcsXG4gIHJvbGU6IE91dHB1dFJvbGUsXG4pOiBzdHJpbmcgfCBudWxsIHtcbiAgY29uc3Qgc291cmNlID0gb3V0cHV0cz8uW2FsaWFzXTtcblxuICBpZiAoIXNvdXJjZSkge1xuICAgIHJldHVybiBudWxsO1xuICB9XG5cbiAgY29uc3QgYW55TGFuZSA9IHNvdXJjZS5yb2xlID09PSAnY3VycmVudCcgfHwgc291cmNlLm9mZnNldCA9PT0gbnVsbDtcbiAgY29uc3QgZm91bmQgPSBPYmplY3QuZW50cmllcyhvdXRwdXRzID8/IHt9KS5maW5kKChbLCBtZXRhXSkgPT4gbWV0YS5tZWFzdXJlID09PSBzb3VyY2UubWVhc3VyZVxuICAgICYmIG1ldGEua2luZCA9PT0gc291cmNlLmtpbmRcbiAgICAmJiBtZXRhLnJvbGUgPT09IHJvbGVcbiAgICAmJiAocm9sZSA9PT0gJ2N1cnJlbnQnIHx8IChhbnlMYW5lID8gbWV0YS5vZmZzZXQgIT09IG51bGwgOiBtZXRhLm9mZnNldCA9PT0gc291cmNlLm9mZnNldCkpKTtcblxuICByZXR1cm4gZm91bmQgPyBmb3VuZFswXSA6IG51bGw7XG59XG5cbmZ1bmN0aW9uIHBsYWluT3V0cHV0KHRleHQ6IHN0cmluZyk6IEZvcm1hdHRlZE91dHB1dFZhbHVlIHtcbiAgcmV0dXJuIHsgdGV4dCwgdGl0bGU6IG51bGwgfTtcbn1cblxuLy8gVGhlIGZvcm1hdCBhbiBvdXRwdXQgaXMgd3JpdHRlbiBpbjogdGhlIHNsb3QncyBvd24gZXhwbGljaXQgZm9ybWF0LCBlbHNlXG4vLyB0aGUgZGVmYXVsdCBmb3Igd2hhdCBpdCBob2xkcywgd2l0aCBhbnkgb3duIHByZWNpc2lvbiBvciB1bml0cyBvdmVyIGl0LlxuZnVuY3Rpb24gb3V0cHV0Rm9ybWF0U3BlYyhcbiAgb3V0cHV0OiBPdXRwdXRNZXRhLFxuICBvd246IE51bWJlckZvcm1hdFNwZWMgfCBudWxsIHwgdW5kZWZpbmVkLFxuICBtZWFzdXJlU3BlYzogTnVtYmVyRm9ybWF0U3BlYyB8IG51bGwgfCB1bmRlZmluZWQsXG4pOiBOdW1iZXJGb3JtYXRTcGVjIHwgbnVsbCB7XG4gIGlmICh2YWx1ZUZvcm1hdChvd24pICE9PSBudWxsKSB7XG4gICAgcmV0dXJuIG93bjtcbiAgfVxuXG4gIGlmIChvdXRwdXQua2luZCA9PT0gJ3JhbmsnKSB7XG4gICAgcmV0dXJuIHdpdGhPd25EaWdpdHMoUkFOS19ERUZBVUxUX1NQRUMsIG93bik7XG4gIH1cblxuICBpZiAob3V0cHV0LmtpbmQgPT09ICdzaGFyZScpIHtcbiAgICByZXR1cm4gd2l0aE93bkRpZ2l0cyhTSEFSRV9ERUZBVUxUX1NQRUMsIG93bik7XG4gIH1cblxuICBpZiAob3V0cHV0LnJvbGUgPT09ICdwZXJjZW50X2NoYW5nZScpIHtcbiAgICByZXR1cm4gd2l0aE93bkRpZ2l0cyhQRVJDRU5UX0NIQU5HRV9ERUZBVUxUX1NQRUMsIG93bik7XG4gIH1cblxuICByZXR1cm4gbWVhc3VyZVNwZWMgPyB3aXRoT3duRGlnaXRzKG1lYXN1cmVTcGVjLCBvd24pIDogb3duID8/IG51bGw7XG59XG5cbi8vIFRoZSBiYXNlIGZvcm1hdCB3aXRoIHRoZSBzbG90J3Mgb3duIHByZWNpc2lvbiBhbmQgdW5pdHMgb3ZlciBpdC5cbmZ1bmN0aW9uIHdpdGhPd25EaWdpdHMoYmFzZTogTnVtYmVyRm9ybWF0U3BlYywgb3duOiBOdW1iZXJGb3JtYXRTcGVjIHwgbnVsbCB8IHVuZGVmaW5lZCk6IE51bWJlckZvcm1hdFNwZWMge1xuICByZXR1cm4ge1xuICAgIC4uLmJhc2UsXG4gICAgLi4uKChvd24/LnByZWNpc2lvbiA/PyBudWxsKSAhPT0gbnVsbCA/IHsgcHJlY2lzaW9uOiBvd24ucHJlY2lzaW9uIH0gOiB7fSksXG4gICAgLi4uKChvd24/LnVuaXRzID8/IG51bGwpICE9PSBudWxsID8geyB1bml0czogb3duLnVuaXRzIH0gOiB7fSksXG4gIH07XG59XG5cbi8vIEEgY2hhbmdlIGJldHdlZW4gdHdvIHJhdGVzOiBhIHNoYXJlJ3MsIG9yIGEgcGVyY2VudC1mb3JtYXQgdmFsdWUncy5cbmZ1bmN0aW9uIGlzUG9pbnRzQ2hhbmdlKG91dHB1dDogT3V0cHV0TWV0YSwgc3BlYzogTnVtYmVyRm9ybWF0U3BlYyB8IG51bGwpOiBib29sZWFuIHtcbiAgcmV0dXJuIG91dHB1dC5raW5kID09PSAnc2hhcmUnIHx8IHJlc29sdmVTdHlsZShzcGVjKSA9PT0gUmVwb3J0VmFsdWVGb3JtYXQuUGVyY2VudDtcbn1cblxuLy8gQSByYXRlIGNoYW5nZSBpbiBwZXJjZW50YWdlIHBvaW50cy4gQSBzaGFyZSBhbmQgYSAwLTEgcGVyY2VudCBhcmUgc2NhbGVkXG4vLyB4MTAwOyBhbiBvbGRlciBzZXJ2ZXIncyBwZXJjZW50IHZhbHVlcyBhbHJlYWR5IGFyZS5cbmZ1bmN0aW9uIGZvcm1hdFBvaW50cyhcbiAgdmFsdWU6IHVua25vd24sXG4gIG91dHB1dDogT3V0cHV0TWV0YSxcbiAgc3BlYzogTnVtYmVyRm9ybWF0U3BlYyB8IG51bGwsXG4gIGNvbnRleHQ6IFJlcG9ydEZvcm1hdENvbnRleHQsXG4pOiBzdHJpbmcge1xuICBjb25zdCBudW1lcmljID0gdG9GaW5pdGVOdW1iZXIodmFsdWUpO1xuICBpZiAobnVtZXJpYyA9PT0gbnVsbCkge1xuICAgIHJldHVybiBTdHJpbmcodmFsdWUpO1xuICB9XG5cbiAgY29uc3QgcG9pbnRzID0gb3V0cHV0LmtpbmQgPT09ICdzaGFyZScgfHwgY29udGV4dC5yYXRpb1BlcmNlbnQgPyBudW1lcmljICogMTAwIDogbnVtZXJpYztcbiAgY29uc3QgZGVjaW1hbHMgPSBjbGFtcERlY2ltYWxzKHNwZWM/LnByZWNpc2lvbikgPz8gUE9JTlRTX0RFQ0lNQUxTO1xuICBjb25zdCB0ZXh0ID0gZm9ybWF0TnVtYmVyKHBvaW50cywgeyBmb3JtYXQ6IFJlcG9ydFZhbHVlRm9ybWF0Lk51bWJlciB9LCBjb250ZXh0LCB7IGRlY2ltYWxzLCBzaWduZWQ6IHRydWUgfSk7XG5cbiAgcmV0dXJuIGAke3RleHR9ICR7UE9JTlRTX1NVRkZJWH1gO1xufVxuXG4vLyBBIG1pc3Npbmcgb3V0cHV0IHZhbHVlLiBBIG1pc3NpbmcgcHJpb3IsIG9yIGEgZGVsdGEgYSBtaXNzaW5nIHByaW9yIGxlZnRcbi8vIGVtcHR5LCBoYXMgbm8gYmFzZWxpbmU7IGEgcGVyY2VudCBjaGFuZ2Ugb3ZlciBhIHplcm8gcHJpb3IgaGFzIG5vbmUgdG9cbi8vIGRpdmlkZSBieS5cbmZ1bmN0aW9uIG1pc3NpbmdPdXRwdXQoXG4gIG91dHB1dDogT3V0cHV0TWV0YSxcbiAgY29udGV4dDogUmVwb3J0Rm9ybWF0Q29udGV4dCxcbiAgb3B0aW9uczogT3V0cHV0VmFsdWVPcHRpb25zLFxuKTogRm9ybWF0dGVkT3V0cHV0VmFsdWUge1xuICBjb25zdCByb2xlID0gb3V0cHV0LnJvbGU7XG5cbiAgaWYgKHJvbGUgPT09ICdwcmlvcicpIHtcbiAgICByZXR1cm4geyB0ZXh0OiBFTVBUWV9WQUxVRSwgdGl0bGU6IG1pc3NpbmdQcmlvclRpdGxlKG91dHB1dCwgb3B0aW9ucy5mbG9vciwgY29udGV4dC5sb2NhbGUpIH07XG4gIH1cblxuICBpZiAocm9sZSA9PT0gJ2NoYW5nZScgfHwgcm9sZSA9PT0gJ3BlcmNlbnRfY2hhbmdlJykge1xuICAgIGNvbnN0IHByaW9yID0gb3B0aW9ucy5wcmlvcjtcblxuICAgIGlmIChyb2xlID09PSAncGVyY2VudF9jaGFuZ2UnICYmIHRvRmluaXRlTnVtYmVyKHByaW9yKSA9PT0gMCkge1xuICAgICAgcmV0dXJuIHsgdGV4dDogTk9UX0FQUExJQ0FCTEVfVkFMVUUsIHRpdGxlOiAnUHJpb3Igd2FzIDAnIH07XG4gICAgfVxuXG4gICAgcmV0dXJuIHtcbiAgICAgIHRleHQ6IEVNUFRZX1ZBTFVFLFxuICAgICAgdGl0bGU6IHByaW9yICE9PSB1bmRlZmluZWQgJiYgaXNFbXB0eVZhbHVlKHByaW9yKVxuICAgICAgICA/IG1pc3NpbmdQcmlvclRpdGxlKG91dHB1dCwgb3B0aW9ucy5mbG9vciwgY29udGV4dC5sb2NhbGUpXG4gICAgICAgIDogbnVsbCxcbiAgICB9O1xuICB9XG5cbiAgcmV0dXJuIHBsYWluT3V0cHV0KG9wdGlvbnMuZW1wdHkgPz8gRU1QVFlfVkFMVUUpO1xufVxuXG4vLyBXaHkgYSBwcmlvciBpcyBtaXNzaW5nLiBBIHZhbHVlJ3MgcHJpb3IgaXMgbWlzc2luZyB3aGVuIGl0cyB3aW5kb3cgZW5kc1xuLy8gYmVmb3JlIHRoZSBkYXRhIHN0YXJ0cy4gQSByYW5rJ3Mgb3IgYSBzaGFyZSdzIGlzIG1pc3Npbmcgd2hlbiB0aGUgcm93IGhhZFxuLy8gbm8gcmFuayBvciBzaGFyZSBpbiB0aGUgcHJpb3IgcGVyaW9kLCB3aGF0ZXZlciB0aGUgZmxvb3IuXG5mdW5jdGlvbiBtaXNzaW5nUHJpb3JUaXRsZShcbiAgb3V0cHV0OiBPdXRwdXRNZXRhLFxuICBmbG9vcjogc3RyaW5nIHwgbnVsbCB8IHVuZGVmaW5lZCxcbiAgbG9jYWxlOiBSZXBvcnRMb2NhbGVUYWcsXG4pOiBzdHJpbmcge1xuICBpZiAob3V0cHV0LmtpbmQgPT09ICdyYW5rJykge1xuICAgIHJldHVybiBOT19QUklPUl9SQU5LX1RJVExFO1xuICB9XG5cbiAgaWYgKG91dHB1dC5raW5kID09PSAnc2hhcmUnKSB7XG4gICAgcmV0dXJuIE5PX1BSSU9SX1NIQVJFX1RJVExFO1xuICB9XG5cbiAgcmV0dXJuIG5vQmFzZWxpbmVUaXRsZShmbG9vciwgbG9jYWxlKTtcbn1cblxuZnVuY3Rpb24gbm9CYXNlbGluZVRpdGxlKGZsb29yOiBzdHJpbmcgfCBudWxsIHwgdW5kZWZpbmVkLCBsb2NhbGU6IFJlcG9ydExvY2FsZVRhZyk6IHN0cmluZyB7XG4gIGNvbnN0IGRheSA9IGZsb29yID8gZm9ybWF0RGF5KGZsb29yLCBsb2NhbGUpIDogJyc7XG5cbiAgcmV0dXJuIGRheSA/IGBObyBiYXNlbGluZTogbm8gZGF0YSBiZWZvcmUgJHtkYXl9YCA6ICdObyBiYXNlbGluZSc7XG59XG5cbi8vIEEgcmFuayBjaGFuZ2U6IHByaW9yIHJhbmsgbWludXMgY3VycmVudCwgc28gbW92aW5nIHVwIGlzIHBvc2l0aXZlLlxuZnVuY3Rpb24gZm9ybWF0UmFua0NoYW5nZShcbiAgdmFsdWU6IHVua25vd24sXG4gIHNwZWM6IE51bWJlckZvcm1hdFNwZWMgfCBudWxsIHwgdW5kZWZpbmVkLFxuICBjb250ZXh0OiBSZXBvcnRGb3JtYXRDb250ZXh0LFxuICBvcHRpb25zOiBPdXRwdXRWYWx1ZU9wdGlvbnMsXG4pOiBGb3JtYXR0ZWRPdXRwdXRWYWx1ZSB7XG4gIGlmIChpc0VtcHR5VmFsdWUodmFsdWUpKSB7XG4gICAgcmV0dXJuIGlzRW1wdHlWYWx1ZShvcHRpb25zLnByaW9yKVxuICAgICAgPyB7IHRleHQ6IE5FV19SQU5LX1ZBTFVFLCB0aXRsZTogTk9fUFJJT1JfUkFOS19USVRMRSB9XG4gICAgICA6IHBsYWluT3V0cHV0KEVNUFRZX1ZBTFVFKTtcbiAgfVxuXG4gIGNvbnN0IG51bWVyaWMgPSB0b0Zpbml0ZU51bWJlcih2YWx1ZSk7XG4gIGlmIChudW1lcmljID09PSBudWxsKSB7XG4gICAgcmV0dXJuIHBsYWluT3V0cHV0KFN0cmluZyh2YWx1ZSkpO1xuICB9XG5cbiAgY29uc3QgcmFua1NwZWMgPSB2YWx1ZUZvcm1hdChzcGVjKSAhPT0gbnVsbCA/IHNwZWMgOiB3aXRoT3duRGlnaXRzKFJBTktfREVGQVVMVF9TUEVDLCBzcGVjKTtcbiAgY29uc3QgcGxhY2VzID0gZm9ybWF0TnVtYmVyKE1hdGguYWJzKG51bWVyaWMpLCByYW5rU3BlYywgY29udGV4dCk7XG5cbiAgaWYgKHBsYWNlcyA9PT0gZm9ybWF0TnVtYmVyKDAsIHJhbmtTcGVjLCBjb250ZXh0KSkge1xuICAgIHJldHVybiBwbGFpbk91dHB1dChSQU5LX1VOQ0hBTkdFRF9WQUxVRSk7XG4gIH1cblxuICByZXR1cm4gcGxhaW5PdXRwdXQoYCR7bnVtZXJpYyA+IDAgPyBSQU5LX1VQX01BUksgOiBSQU5LX0RPV05fTUFSS30gJHtwbGFjZXN9YCk7XG59XG5cblxuLy8gQSBjaGFydCdzIHZhbHVlIGF4aXMgdGFrZXMgYSBmb3JtYXQgb25seSB3aGVuIGV2ZXJ5IG1lYXN1cmUgb24gaXQgYWdyZWVzIG9uXG4vLyB0aGUgc3R5bGUgKGVhY2ggbWVhc3VyZSdzIGZvcm1hdCwgbnVtYmVyIHdoZW4gaXQgbmFtZXMgbm9uZSkgYW5kIGF0IGxlYXN0XG4vLyBvbmUgb2YgdGhlbSBuYW1lcyBhIGZvcm1hdC4gVGhlIGZpcnN0IG1lYXN1cmUgdGhhdCBkb2VzIGdpdmVzIHRoZSBheGlzIGl0c1xuLy8gcHJlY2lzaW9uIGFuZCB1bml0cy4gT3RoZXJ3aXNlIG51bGw6IHRoZSBheGlzIGtlZXBzIGl0cyBkZWZhdWx0IHRpY2tzIG9uXG4vLyBzY3JlZW4gYW5kIGluIFBvd2VyUG9pbnQsIGFuZCBlYWNoIHNlcmllcyBzdGlsbCBmb3JtYXRzIGl0cyBvd24gdG9vbHRpcHMuXG5leHBvcnQgZnVuY3Rpb24gYXhpc051bWJlckZvcm1hdChtZWFzdXJlczogQ2hhcnRNZWFzdXJlW10pOiBOdW1iZXJGb3JtYXRTcGVjIHwgbnVsbCB7XG4gIGNvbnN0IHN0eWxlID0gbWVhc3VyZXMubGVuZ3RoID8gcmVzb2x2ZVN0eWxlKG1lYXN1cmVzWzBdKSA6IG51bGw7XG5cbiAgaWYgKHN0eWxlID09PSBudWxsIHx8IG1lYXN1cmVzLnNvbWUoKG1lYXN1cmUpID0+IHJlc29sdmVTdHlsZShtZWFzdXJlKSAhPT0gc3R5bGUpKSB7XG4gICAgcmV0dXJuIG51bGw7XG4gIH1cblxuICBjb25zdCBmb3JtYXR0ZWQgPSBtZWFzdXJlcy5maW5kKChtZWFzdXJlKSA9PiBoYXNOdW1iZXJGb3JtYXQobWVhc3VyZSkpO1xuXG4gIHJldHVybiBmb3JtYXR0ZWQgPyBudW1iZXJGb3JtYXRTcGVjKGZvcm1hdHRlZCkgOiBudWxsO1xufVxuXG5mdW5jdGlvbiBudW1iZXJGb3JtYXRTcGVjKHNwZWM6IE51bWJlckZvcm1hdFNwZWMpOiBOdW1iZXJGb3JtYXRTcGVjIHtcbiAgcmV0dXJuIHtcbiAgICAuLi4oc3BlYy5mb3JtYXQgIT09IHVuZGVmaW5lZCA/IHsgZm9ybWF0OiBzcGVjLmZvcm1hdCB9IDoge30pLFxuICAgIC4uLihzcGVjLnByZWNpc2lvbiAhPT0gdW5kZWZpbmVkID8geyBwcmVjaXNpb246IHNwZWMucHJlY2lzaW9uIH0gOiB7fSksXG4gICAgLi4uKHNwZWMudW5pdHMgIT09IHVuZGVmaW5lZCA/IHsgdW5pdHM6IHNwZWMudW5pdHMgfSA6IHt9KSxcbiAgfTtcbn1cblxuLy8gSG93IGEgY2hhcnQncyB2YWx1ZSBheGlzIHdyaXRlcyBpdHMgdGlja3M6IHRoZSB1bml0cyBkZWNpZGVkIG9uY2UgZnJvbSB0aGVcbi8vIGF4aXMgcGVhaywgYW5kIHRoZSBkZWNpbWFscyB0aGUgcHJlY2lzaW9uIHBpbnMsIGVsc2UgYXMgbWFueSBhcyB0aGUgYXhpcydzXG4vLyB0aWNrIHN0ZXAgbmVlZHMgKGEgcGVyY2VudCBheGlzIHVwIHRvIDAuMTIlIHN0ZXBzIGJ5IDAuMDIlLCB0d28gZGVjaW1hbHMpLlxuLy8gUGlubmVkIGRlY2ltYWxzIGtlZXAgdGhlIHRpY2tzIGRpc3RpbmN0LCBhbmQgUG93ZXJQb2ludCBjYW4gb25seSBwaW4gdGhlbS5cbmV4cG9ydCBmdW5jdGlvbiByZXNvbHZlQ2hhcnROdW1iZXJGb3JtYXQoXG4gIHNwZWM6IE51bWJlckZvcm1hdFNwZWMsXG4gIHBlYWs6IG51bWJlcixcbiAgY29udGV4dDogUmVwb3J0Rm9ybWF0Q29udGV4dCxcbik6IENoYXJ0TnVtYmVyRm9ybWF0IHtcbiAgY29uc3Qgc3R5bGUgPSByZXNvbHZlU3R5bGUoc3BlYyk7XG4gIGNvbnN0IHByZWNpc2lvbiA9IGNsYW1wRGVjaW1hbHMoc3BlYy5wcmVjaXNpb24pO1xuICBjb25zdCB1bml0cyA9IHN0eWxlID09PSBSZXBvcnRWYWx1ZUZvcm1hdC5QZXJjZW50XG4gICAgPyBSZXBvcnROdW1iZXJVbml0cy5Ob25lXG4gICAgOiByZXNvbHZlVW5pdHMoc3BlYy51bml0cywgcGVhaywgcHJlY2lzaW9uID8/IFNDQUxFRF9ERUNJTUFMUyk7XG5cbiAgcmV0dXJuIHsgdW5pdHMsIGRlY2ltYWxzOiBwcmVjaXNpb24gPz8gYXhpc0RlY2ltYWxzKHN0eWxlLCB1bml0cywgcGVhaywgY29udGV4dCkgfTtcbn1cblxuLy8gVGhlIGRlY2ltYWxzIHRoZSBheGlzJ3MgbmljZSB0aWNrIHN0ZXAgbmVlZHMuIEEgcGxhaW4sIHVuYWJicmV2aWF0ZWQgbnVtYmVyXG4vLyBwaW5zIG5vbmUgKG51bGwpOiBpdHMgdGlja3Mga2VlcCB0aGVpciBvd24gZGVjaW1hbHMuIEFuIHVuc2NhbGVkIGN1cnJlbmN5XG4vLyBheGlzIHRoYXQgbmVlZHMgZGVjaW1hbHMgc2hvd3MgY2VudHMsIGFuZCBhIEsvTSBheGlzIGtlZXBzIGl0cyBzdGVwJ3Ncbi8vIGRlY2ltYWxzICgnJDAuNU0nLCBub3QgJyQwLjUwTScpLlxuZnVuY3Rpb24gYXhpc0RlY2ltYWxzKFxuICBzdHlsZTogUmVwb3J0VmFsdWVGb3JtYXQsXG4gIHVuaXRzOiBSZXNvbHZlZFVuaXRzLFxuICBwZWFrOiBudW1iZXIsXG4gIGNvbnRleHQ6IFJlcG9ydEZvcm1hdENvbnRleHQsXG4pOiBudW1iZXIgfCBudWxsIHtcbiAgY29uc3Qgc2NhbGUgPSBVTklUX1NDQUxFUy5nZXQodW5pdHMpO1xuXG4gIGlmIChzdHlsZSA9PT0gUmVwb3J0VmFsdWVGb3JtYXQuTnVtYmVyICYmICFzY2FsZSkge1xuICAgIHJldHVybiBudWxsO1xuICB9XG5cbiAgY29uc3Qgc2hvd25QZWFrID0gc3R5bGUgPT09IFJlcG9ydFZhbHVlRm9ybWF0LlBlcmNlbnQgJiYgY29udGV4dC5yYXRpb1BlcmNlbnRcbiAgICA/IE1hdGguYWJzKHBlYWspICogMTAwXG4gICAgOiBNYXRoLmFicyhwZWFrKSAvIChzY2FsZT8uZGl2aXNvciA/PyAxKTtcbiAgY29uc3Qgc3RlcCA9IG5pY2VTdGVwKHNob3duUGVhayAvIEFYSVNfVElDS1MpO1xuICBjb25zdCBkZWNpbWFscyA9IHN0ZXAgPiAwID8gY2xhbXBEZWNpbWFscygtTWF0aC5mbG9vcihNYXRoLmxvZzEwKHN0ZXApKSkgPz8gMCA6IDA7XG5cbiAgcmV0dXJuIHN0eWxlID09PSBSZXBvcnRWYWx1ZUZvcm1hdC5DdXJyZW5jeSAmJiBkZWNpbWFscyA+IDAgJiYgIXNjYWxlID8gQ1VSUkVOQ1lfQVhJU19ERUNJTUFMUyA6IGRlY2ltYWxzO1xufVxuXG4vLyBFQ2hhcnRzJyBuaWNlKCk6IHRoZSByb3VuZCBudW1iZXIgKDEsIDIsIDMsIDUgb3IgMTAgdGltZXMgYSBwb3dlciBvZiB0ZW4pIGFcbi8vIHJvdWdoIHRpY2sgc3RlcCBzbmFwcyB0by5cbmZ1bmN0aW9uIG5pY2VTdGVwKHJvdWdoOiBudW1iZXIpOiBudW1iZXIge1xuICBpZiAoIShyb3VnaCA+IDApIHx8ICFOdW1iZXIuaXNGaW5pdGUocm91Z2gpKSB7XG4gICAgcmV0dXJuIDA7XG4gIH1cblxuICBjb25zdCBleHBvbmVudCA9IE1hdGguZmxvb3IoTWF0aC5sb2cxMChyb3VnaCkpO1xuICBjb25zdCBwb3dlciA9IE1hdGgucG93KDEwLCBleHBvbmVudCk7XG4gIGNvbnN0IGZyYWN0aW9uID0gcm91Z2ggLyBwb3dlcjtcbiAgbGV0IG5pY2UgPSAxMDtcbiAgaWYgKGZyYWN0aW9uIDwgMS41KSB7XG4gICAgbmljZSA9IDE7XG4gIH0gZWxzZSBpZiAoZnJhY3Rpb24gPCAyLjUpIHtcbiAgICBuaWNlID0gMjtcbiAgfSBlbHNlIGlmIChmcmFjdGlvbiA8IDQpIHtcbiAgICBuaWNlID0gMztcbiAgfSBlbHNlIGlmIChmcmFjdGlvbiA8IDcpIHtcbiAgICBuaWNlID0gNTtcbiAgfVxuXG4gIHJldHVybiBuaWNlICogcG93ZXI7XG59XG5cbi8vIFBvd2VyUG9pbnQncyBudW1iZXIgZm9ybWF0IGNvZGUgZm9yIGEgZm9ybWF0dGVkIHZhbHVlIGF4aXMsIG1hdGNoaW5nIHRoZVxuLy8gc2NyZWVuJ3MgdGlja3M6ICcjLCMjMC4wJScgKHBlcmNlbnQpLCAnXCIkXCIjLCMjMCcgKGN1cnJlbmN5KSxcbi8vICcjLCMjMC4wLFwiS1wiJyAodGhvdXNhbmRzKSwgJyMsIyMwXCIgJFwiJyAoZnItQ0EgY3VycmVuY3kpLiBBIHBsYWluIG51bWJlclxuLy8gd2hvc2UgZGVjaW1hbHMgYXJlIG5vdCBwaW5uZWQga2VlcHMgY2hhcnRBeGlzRm9ybWF0Q29kZSdzIGNvZGUuIFRoZSBjb2RlJ3Ncbi8vIHNlcGFyYXRvcnMgZm9sbG93IHRoZSBvcGVuaW5nIG1hY2hpbmUncyBsb2NhbGU7IHRoZSBjdXJyZW5jeSBzeW1ib2wgYW5kIGl0c1xuLy8gc2lkZSBmb2xsb3cgdGhlIHJlcG9ydCdzLlxuZXhwb3J0IGZ1bmN0aW9uIG51bWJlckZvcm1hdENvZGUoXG4gIHNwZWM6IE51bWJlckZvcm1hdFNwZWMsXG4gIGNvbnRleHQ6IFJlcG9ydEZvcm1hdENvbnRleHQsXG4gIGNoYXJ0OiBDaGFydE51bWJlckZvcm1hdCxcbiAgc2VyaWVzOiAobnVtYmVyIHwgbnVsbClbXVtdLFxuICBzdGFja2VkOiBib29sZWFuLFxuKTogc3RyaW5nIHtcbiAgY29uc3Qgc3R5bGUgPSByZXNvbHZlU3R5bGUoc3BlYyk7XG4gIGNvbnN0IHNjYWxlID0gc3R5bGUgPT09IFJlcG9ydFZhbHVlRm9ybWF0LlBlcmNlbnQgPyB1bmRlZmluZWQgOiBVTklUX1NDQUxFUy5nZXQoY2hhcnQudW5pdHMpO1xuXG4gIGlmIChzdHlsZSA9PT0gUmVwb3J0VmFsdWVGb3JtYXQuTnVtYmVyICYmICFzY2FsZSAmJiBjaGFydC5kZWNpbWFscyA9PT0gbnVsbCkge1xuICAgIHJldHVybiBjaGFydEF4aXNGb3JtYXRDb2RlKHNlcmllcywgc3RhY2tlZCk7XG4gIH1cblxuICBjb25zdCBkZWNpbWFscyA9IGNoYXJ0LmRlY2ltYWxzID8/IDA7XG4gIGNvbnN0IGRpZ2l0cyA9IGAjLCMjMCR7ZGVjaW1hbHMgPiAwID8gYC4keycwJy5yZXBlYXQoZGVjaW1hbHMpfWAgOiAnJ31gO1xuXG4gIGlmIChzdHlsZSA9PT0gUmVwb3J0VmFsdWVGb3JtYXQuUGVyY2VudCkge1xuICAgIHJldHVybiBgJHtkaWdpdHN9JHtjb250ZXh0LnJhdGlvUGVyY2VudCA/ICclJyA6ICdcIiVcIid9YDtcbiAgfVxuXG4gIGNvbnN0IHNjYWxlZCA9IGAke2RpZ2l0c30ke3NjYWxlPy5jb21tYXMgPz8gJyd9YDtcbiAgY29uc3QgdW5pdCA9IHNjYWxlPy5zdWZmaXggPz8gJyc7XG5cbiAgaWYgKHN0eWxlICE9PSBSZXBvcnRWYWx1ZUZvcm1hdC5DdXJyZW5jeSkge1xuICAgIHJldHVybiB1bml0ID8gYCR7c2NhbGVkfVwiJHt1bml0fVwiYCA6IHNjYWxlZDtcbiAgfVxuXG4gIGNvbnN0IHN5bWJvbCA9IGN1cnJlbmN5U3ltYm9sKGNvbnRleHQpO1xuXG4gIHJldHVybiBzeW1ib2wucHJlZml4XG4gICAgPyBgXCIke3N5bWJvbC50ZXh0fVwiJHtzY2FsZWR9JHt1bml0ID8gYFwiJHt1bml0fVwiYCA6ICcnfWBcbiAgICA6IGAke3NjYWxlZH1cIiR7dW5pdH0ke3N5bWJvbC50ZXh0fVwiYDtcbn1cblxuLy8gVGhlIGN1cnJlbmN5IHN5bWJvbCBhcyB0aGUgbG9jYWxlIHdyaXRlcyBpdCBiZXNpZGUgYSBudW1iZXIsIHdpdGggdGhlIHNwYWNlXG4vLyBiZXR3ZWVuIHRoZW0sIGFuZCB3aGljaCBzaWRlIGl0IHNpdHMgb246ICckJyBiZWZvcmUgaW4gZW4tVVMsICcgJCcgYWZ0ZXIgaW5cbi8vIGZyLUNBLiBRdW90ZXMgYXJlIGRyb3BwZWQsIGFzIGEgZm9ybWF0IGNvZGUgY2Fubm90IGhvbGQgdGhlbS5cbmludGVyZmFjZSBDdXJyZW5jeVN5bWJvbCB7XG4gIHByZWZpeDogYm9vbGVhbjtcbiAgdGV4dDogc3RyaW5nO1xufVxuXG5jb25zdCBDVVJSRU5DWV9TWU1CT0xTID0gbmV3IE1hcDxzdHJpbmcsIEN1cnJlbmN5U3ltYm9sPigpO1xuXG5mdW5jdGlvbiBjdXJyZW5jeVN5bWJvbChjb250ZXh0OiBSZXBvcnRGb3JtYXRDb250ZXh0KTogQ3VycmVuY3lTeW1ib2wge1xuICBjb25zdCBrZXkgPSBgJHtjb250ZXh0LmxvY2FsZX18JHtjb250ZXh0LmN1cnJlbmN5fWA7XG4gIGxldCBzeW1ib2wgPSBDVVJSRU5DWV9TWU1CT0xTLmdldChrZXkpO1xuXG4gIGlmICghc3ltYm9sKSB7XG4gICAgY29uc3QgcGFydHMgPSBudW1iZXJGb3JtYXQoY29udGV4dC5sb2NhbGUsIGN1cnJlbmN5T3B0aW9ucyhjb250ZXh0LmN1cnJlbmN5KSkuZm9ybWF0VG9QYXJ0cygxKTtcbiAgICBjb25zdCBjdXJyZW5jeSA9IHBhcnRzLmZpbmRJbmRleCgocGFydCkgPT4gcGFydC50eXBlID09PSAnY3VycmVuY3knKTtcbiAgICBjb25zdCBmaXJzdCA9IHBhcnRzLmZpbmRJbmRleCgocGFydCkgPT4gTlVNQkVSX1BBUlRTLmhhcyhwYXJ0LnR5cGUpKTtcbiAgICBjb25zdCBsYXN0ID0gcGFydHMucmVkdWNlKChmb3VuZCwgcGFydCwgaW5kZXgpID0+IE5VTUJFUl9QQVJUUy5oYXMocGFydC50eXBlKSA/IGluZGV4IDogZm91bmQsIC0xKTtcbiAgICBjb25zdCBwcmVmaXggPSBjdXJyZW5jeSA8IGZpcnN0O1xuICAgIGNvbnN0IHRleHQgPSAocHJlZml4ID8gcGFydHMuc2xpY2UoTWF0aC5tYXgoY3VycmVuY3ksIDApLCBmaXJzdCkgOiBwYXJ0cy5zbGljZShsYXN0ICsgMSkpXG4gICAgICAubWFwKChwYXJ0KSA9PiBwYXJ0LnZhbHVlKVxuICAgICAgLmpvaW4oJycpXG4gICAgICAucmVwbGFjZSgvXCIvZywgJycpO1xuXG4gICAgc3ltYm9sID0geyBwcmVmaXgsIHRleHQgfTtcbiAgICBDVVJSRU5DWV9TWU1CT0xTLnNldChrZXksIHN5bWJvbCk7XG4gIH1cblxuICByZXR1cm4gc3ltYm9sO1xufVxuXG5cbi8vIEV2ZXJ5IGRlY2ltYWwgYSBudW1iZXIgaGFzLCBncm91cGVkLCBpbiB0aGUgbG9jYWxlOiB3aGF0IEVDaGFydHMgcHJpbnRzIGJ5XG4vLyBkZWZhdWx0IChpdHMgYWRkQ29tbWFzKSwgYnV0IGluIHRoZSByZXBvcnQncyBsb2NhbGUsIHNvIGEgY2hhcnQncyBheGlzIGFuZFxuLy8gdG9vbHRpcCByZWFkIGxpa2UgdGhlIHJlc3Qgb2YgdGhlIHJlcG9ydC4gMTIzNC41IHJlYWRzIDEsMjM0LjUgaW4gZW4tVVMgYW5kXG4vLyAxIDIzNCw1IGluIGZyLUNBLiBBIG5vbi1udW1lcmljIHN0cmluZyBpcyBzaG93biBhcyBpdCBjYW1lLCBhbmQgYW55dGhpbmdcbi8vIGVsc2Ugbm9uLW51bWVyaWMgYXMgJy0nLCBhcyBFQ2hhcnRzIHNob3dzIGl0LiBBcyB0aGVyZSwgYW4gaW5maW5pdGUgdmFsdWVcbi8vIHJlYWRzICdJbmZpbml0eScgYW5kIG5lZ2F0aXZlIHplcm8gKGEgdGljayBhIGZsb2F0IGVycm9yIGxlYXZlcyBqdXN0IGJlbG93XG4vLyB6ZXJvKSByZWFkcyAnMCcuXG5jb25zdCBQTEFJTl9OVU1CRVI6IEludGwuTnVtYmVyRm9ybWF0T3B0aW9ucyA9IHsgbWF4aW11bUZyYWN0aW9uRGlnaXRzOiAyMCB9O1xuXG5leHBvcnQgZnVuY3Rpb24gZm9ybWF0UGxhaW5OdW1iZXIodmFsdWU6IHVua25vd24sIGxvY2FsZTogUmVwb3J0TG9jYWxlVGFnKTogc3RyaW5nIHtcbiAgY29uc3QgbnVtZXJpYyA9IHR5cGVvZiB2YWx1ZSA9PT0gJ251bWJlcidcbiAgICA/IHZhbHVlXG4gICAgOiB0eXBlb2YgdmFsdWUgPT09ICdzdHJpbmcnICYmIHZhbHVlLnRyaW0oKSAhPT0gJycgPyBOdW1iZXIodmFsdWUpIDogTmFOO1xuXG4gIGlmIChOdW1iZXIuaXNOYU4obnVtZXJpYykpIHtcbiAgICByZXR1cm4gdHlwZW9mIHZhbHVlID09PSAnc3RyaW5nJyA/IHZhbHVlIDogJy0nO1xuICB9XG5cbiAgaWYgKCFOdW1iZXIuaXNGaW5pdGUobnVtZXJpYykpIHtcbiAgICByZXR1cm4gU3RyaW5nKG51bWVyaWMpO1xuICB9XG5cbiAgcmV0dXJuIG51bWJlckZvcm1hdChsb2NhbGUsIFBMQUlOX05VTUJFUikuZm9ybWF0KG51bWVyaWMgPT09IDAgPyAwIDogbnVtZXJpYyk7XG59XG5cblxuLy8gVGhlIGF4aXMgcGVhayBhdCB3aGljaCBhIG5hdGl2ZSBjaGFydCdzIHZhbHVlIGF4aXMgZ2FpbnMgdGhvdXNhbmRzXG4vLyBzZXBhcmF0b3JzLiBGcm9tIGhlcmUgdXAgdGhlIHRpY2tzIGFyZSB3aG9sZSBudW1iZXJzIGluIHByYWN0aWNlOyBiZWxvdyBpdFxuLy8gbmVpdGhlciB0aGUgc2NyZWVuIG5vciBQb3dlclBvaW50J3MgJ0dlbmVyYWwnIHNob3dzIGEgc2VwYXJhdG9yLlxuZXhwb3J0IGNvbnN0IEFYSVNfU0VQQVJBVE9SX1RIUkVTSE9MRCA9IDEwMDA7XG5cbi8vIFBvd2VyUG9pbnQncyBudW1iZXIgZm9ybWF0IGZvciBhIG5hdGl2ZSBjaGFydCdzIHZhbHVlIGF4aXMsIG1hdGNoaW5nIHdoYXQgdGhlXG4vLyBvbi1zY3JlZW4gYXhpcyBwcmludHMgYnkgZGVmYXVsdDogdGhvdXNhbmRzIHNlcGFyYXRvcnMgd2l0aCBlYWNoIHRpY2sncyBvd25cbi8vIGRlY2ltYWxzLiBFeGNlbCBoYXMgbm8gXCJHZW5lcmFsIHdpdGggc2VwYXJhdG9yc1wiLCBzbyBhbiBheGlzIHJlYWNoaW5nIDEsMDAwXG4vLyAod2hlcmUgdGlja3MgYXJlIHdob2xlIG51bWJlcnMpIGdldHMgJyMsIyMwJywgYW5kIGEgc21hbGxlciByYW5nZSBrZWVwc1xuLy8gJ0dlbmVyYWwnIHNvIGZyYWN0aW9uYWwgdGlja3MgKDAuMjUsIDAuNSkgYXJlIG5vdCByb3VuZGVkIGF3YXkuXG4vL1xuLy8gVGhlIHBlYWsgaXMgY2hhcnRWYWx1ZVBlYWsncy5cbmV4cG9ydCBmdW5jdGlvbiBjaGFydEF4aXNGb3JtYXRDb2RlKHNlcmllczogKG51bWJlciB8IG51bGwpW11bXSwgc3RhY2tlZDogYm9vbGVhbik6IHN0cmluZyB7XG4gIHJldHVybiBjaGFydFZhbHVlUGVhayhzZXJpZXMsIHN0YWNrZWQpID49IEFYSVNfU0VQQVJBVE9SX1RIUkVTSE9MRCA/ICcjLCMjMCcgOiAnR2VuZXJhbCc7XG59XG5cbi8vIFRoZSBsYXJnZXN0IG1hZ25pdHVkZSBhIGNoYXJ0J3MgdmFsdWUgYXhpcyBoYXMgdG8gcmVhY2guIEEgbWlzc2luZyB2YWx1ZVxuLy8gY291bnRzIGFzIDAuIEEgc3RhY2tlZCBjaGFydCdzIHBlYWsgaXMgaXRzIHRhbGxlc3Qgc3RhY2s6IHRoZSBsYXJnZXN0IHN1bSxcbi8vIHBlciBjYXRlZ29yeSwgb2YgZXZlcnkgc2VyaWVzJyBhYnNvbHV0ZSB2YWx1ZS5cbmV4cG9ydCBmdW5jdGlvbiBjaGFydFZhbHVlUGVhayhzZXJpZXM6IChudW1iZXIgfCBudWxsKVtdW10sIHN0YWNrZWQ6IGJvb2xlYW4pOiBudW1iZXIge1xuICBjb25zdCBtYWduaXR1ZGVzID0gc2VyaWVzLm1hcCgodmFsdWVzKSA9PiB2YWx1ZXMubWFwKCh2YWx1ZSkgPT4gTWF0aC5hYnModmFsdWUgPz8gMCkpKTtcblxuICByZXR1cm4gc3RhY2tlZFxuICAgID8gTWF0aC5tYXgoMCwgLi4uKG1hZ25pdHVkZXNbMF0gPz8gW10pLm1hcCgoXywgaW5kZXgpID0+IG1hZ25pdHVkZXNcbiAgICAgIC5yZWR1Y2UoKHN1bSwgdmFsdWVzKSA9PiBzdW0gKyAodmFsdWVzW2luZGV4XSA/PyAwKSwgMCkpKVxuICAgIDogTWF0aC5tYXgoMCwgLi4ubWFnbml0dWRlcy5mbGF0KCkpO1xufVxuXG5cbi8vIFRoZSB6b25lIGV2ZXJ5IGRhdGUgaW4gYSByZXBvcnQgaXMgcmVhZCBpbi4gVGhlIHNlcnZlciByZXNvbHZlcyBpdCAodGhlXG4vLyByZXBvcnQncyBvd24gem9uZSwgZWxzZSB0aGUgYXBwbGljYXRpb24ncyBkZWZhdWx0IHJlcG9ydGluZyB6b25lKSBhbmQgc2VuZHNcbi8vIGl0IGFzIGBlZmZlY3RpdmVUaW1lem9uZWAuIEEgc2VydmVyIHRvbyBvbGQgdG8gc2VuZCB0aGUgZmllbGQgc3RpbGwgdXNlZCBhXG4vLyByZXBvcnQncyBwaW5uZWQgYHRpbWV6b25lYCwgc28gdGhhdCBjb21lcyBuZXh0OyB0aGUgYnJvd3NlcidzIHpvbmUgaXMgdGhlIGxhc3Rcbi8vIGZhbGxiYWNrLiBUaGlzIGlzIHRoZSBvbmUgcGxhY2UgdGhhdCBjaGFpbiBsaXZlcywgc28gZXZlcnkgZGF0ZSB0aGUgdmlld2VyXG4vLyByZW5kZXJzIG9yIHJlc29sdmVzIGFncmVlcyB3aXRoIGV2ZXJ5IG90aGVyLlxuZXhwb3J0IGZ1bmN0aW9uIHJlc29sdmVSZXBvcnRUaW1lem9uZShyZXBvcnQ6IFBpY2s8UmVwb3J0LCAnZWZmZWN0aXZlVGltZXpvbmUnIHwgJ3RpbWV6b25lJz4pOiBzdHJpbmcge1xuICByZXR1cm4gcmVwb3J0LmVmZmVjdGl2ZVRpbWV6b25lID8/IHJlcG9ydC50aW1lem9uZSA/PyBJbnRsLkRhdGVUaW1lRm9ybWF0KCkucmVzb2x2ZWRPcHRpb25zKCkudGltZVpvbmU7XG59XG5cblxuLy8gVGhlIGRhdGUgc2hhcGVzIGEgcmVwb3J0IHdyaXRlcywgZWFjaCBpbiB0aGUgcmVwb3J0J3MgbG9jYWxlLlxuLy8gJ0phbiA1LCAyMDI2JyAvICc1IGphbnYuIDIwMjYnOiBhIGRhdGUgY2VsbCwgYSBmaWx0ZXIgYm91bmQuXG5leHBvcnQgY29uc3QgREFZX1NIT1JUOiBJbnRsLkRhdGVUaW1lRm9ybWF0T3B0aW9ucyA9IHsgeWVhcjogJ251bWVyaWMnLCBtb250aDogJ3Nob3J0JywgZGF5OiAnbnVtZXJpYycgfTtcbi8vICdKYW51YXJ5IDUsIDIwMjYnIC8gJzUgamFudmllciAyMDI2JzogYW4gZXhwb3J0IGNvdmVyJ3MgZGF0ZSBsaW5lLlxuZXhwb3J0IGNvbnN0IERBWV9MT05HOiBJbnRsLkRhdGVUaW1lRm9ybWF0T3B0aW9ucyA9IHsgeWVhcjogJ251bWVyaWMnLCBtb250aDogJ2xvbmcnLCBkYXk6ICdudW1lcmljJyB9O1xuLy8gJ0phbnVhcnknIC8gJ2phbnZpZXInOiBhIG1vbnRobHkgcGVyaW9kIGxhYmVsIChpdHMgeWVhciBpcyBhZGRlZCBhcGFydCkuXG5leHBvcnQgY29uc3QgTU9OVEhfTE9ORzogSW50bC5EYXRlVGltZUZvcm1hdE9wdGlvbnMgPSB7IG1vbnRoOiAnbG9uZycgfTtcbi8vICdKYW51YXJ5IDIwMjYnIC8gJ2phbnZpZXIgMjAyNic6IGEgbW9udGhseSBwZXJpb2QgbGFiZWwgd3JpdHRlbiBpbiBmdWxsLlxuZXhwb3J0IGNvbnN0IE1PTlRIX1lFQVI6IEludGwuRGF0ZVRpbWVGb3JtYXRPcHRpb25zID0geyB5ZWFyOiAnbnVtZXJpYycsIG1vbnRoOiAnbG9uZycgfTtcbi8vICdKYW4gNScgLyAnNSBqYW52Lic6IGEgZGFpbHkgb3Igd2Vla2x5IHBlcmlvZCBsYWJlbC5cbmV4cG9ydCBjb25zdCBNT05USF9EQVk6IEludGwuRGF0ZVRpbWVGb3JtYXRPcHRpb25zID0geyBtb250aDogJ3Nob3J0JywgZGF5OiAnbnVtZXJpYycgfTtcblxuLy8gQSBkYXRlIGluIHRoZSBsb2NhbGUuIFdpdGggYSB6b25lLCB0aGUgZGF5IGl0IGZhbGxzIG9uIHRoZXJlOyB3aXRob3V0IG9uZSxcbi8vIHRoZSBicm93c2VyJ3Mgem9uZSwgd2hpY2gga2VlcHMgYSBjYWxlbmRhciBkYXkgcGFyc2VkIGFzIGxvY2FsIG1pZG5pZ2h0XG4vLyB1bnNoaWZ0ZWQuIEl0IG5ldmVyIHRocm93cywgc2luY2UgYSBwaXBlIG9yIGFuIGV4cG9ydCBjYWxscyBpdCBwZXIgY2VsbDogYW5cbi8vIGludmFsaWQgRGF0ZSByZWFkcyAnJywgYSBtYWxmb3JtZWQgbG9jYWxlICgnZW5fQ0EnKSByZWFkcyB0aGUgZmFsbGJhY2tcbi8vIGxvY2FsZSwgYW5kIGFuIHVua25vd24gem9uZSByZWFkcyBVVEMsIHdoaWNoIHN0aWxsIG5hbWVzIGEgcmVhbCBkYXkuXG5leHBvcnQgZnVuY3Rpb24gZm9ybWF0TG9jYWxEYXRlKFxuICBkYXRlOiBEYXRlLFxuICBsb2NhbGU6IFJlcG9ydExvY2FsZVRhZyxcbiAgb3B0aW9uczogSW50bC5EYXRlVGltZUZvcm1hdE9wdGlvbnMsXG4gIHRpbWVab25lPzogc3RyaW5nLFxuKTogc3RyaW5nIHtcbiAgaWYgKE51bWJlci5pc05hTihkYXRlLmdldFRpbWUoKSkpIHtcbiAgICByZXR1cm4gJyc7XG4gIH1cblxuICB0cnkge1xuICAgIHJldHVybiB3cml0ZURhdGUoZGF0ZUZvcm1hdChsb2NhbGUsIG9wdGlvbnMsIHRpbWVab25lKSwgZGF0ZSk7XG4gIH0gY2F0Y2gge1xuICAgIHJldHVybiBmb3JtYXRGYWxsYmFja0RhdGUoZGF0ZSwgcmVzb2x2ZVJlcG9ydExvY2FsZShsb2NhbGUpLCBvcHRpb25zLCB0aW1lWm9uZSk7XG4gIH1cbn1cblxuZnVuY3Rpb24gZm9ybWF0RmFsbGJhY2tEYXRlKFxuICBkYXRlOiBEYXRlLFxuICBsb2NhbGU6IFJlcG9ydExvY2FsZVRhZyxcbiAgb3B0aW9uczogSW50bC5EYXRlVGltZUZvcm1hdE9wdGlvbnMsXG4gIHRpbWVab25lPzogc3RyaW5nLFxuKTogc3RyaW5nIHtcbiAgdHJ5IHtcbiAgICByZXR1cm4gd3JpdGVEYXRlKGRhdGVGb3JtYXQobG9jYWxlLCBvcHRpb25zLCB0aW1lWm9uZSksIGRhdGUpO1xuICB9IGNhdGNoIHtcbiAgICByZXR1cm4gd3JpdGVEYXRlKGRhdGVGb3JtYXQobG9jYWxlLCBvcHRpb25zLCAnVVRDJyksIGRhdGUpO1xuICB9XG59XG5cbi8vIEludGwgd3JpdGVzIGEgeWVhciBiZWxvdyAxMDAwIHdpdGggb25seSB0aGUgZGlnaXRzIGl0IGhhcyAoJ0phbiAxLCAxJyk7IGFcbi8vIGRhdGUncyB5ZWFyIGlzIGFsd2F5cyB3cml0dGVuIHdpdGggZm91ciAoJ0phbiAxLCAwMDAxJyksIHNvIGEgc2VudGluZWwgZGF5XG4vLyBzdGlsbCByZWFkcyBhcyBhIGRhdGUuIE9ubHkgc3VjaCBhIHllYXIgcGF5cyBmb3IgZm9ybWF0VG9QYXJ0cy5cbmZ1bmN0aW9uIHdyaXRlRGF0ZShmb3JtYXR0ZXI6IEludGwuRGF0ZVRpbWVGb3JtYXQsIGRhdGU6IERhdGUpOiBzdHJpbmcge1xuICBpZiAoZGF0ZS5nZXRVVENGdWxsWWVhcigpID4gMTAwMCkge1xuICAgIHJldHVybiBmb3JtYXR0ZXIuZm9ybWF0KGRhdGUpO1xuICB9XG5cbiAgcmV0dXJuIGZvcm1hdHRlci5mb3JtYXRUb1BhcnRzKGRhdGUpXG4gICAgLm1hcCgocGFydCkgPT4gcGFydC50eXBlID09PSAneWVhcicgPyBwYXJ0LnZhbHVlLnBhZFN0YXJ0KDQsICcwJykgOiBwYXJ0LnZhbHVlKVxuICAgIC5qb2luKCcnKTtcbn1cblxuXG5jb25zdCBEQVRFX09OTFlfUEFUVEVSTiA9IC9eXFxkezR9LVxcZHsyfS1cXGR7Mn0kLztcbmNvbnN0IERBVEVfVElNRV9QQVRURVJOID0gL14oXFxkezR9LVxcZHsyfS1cXGR7Mn0pWyBUXShcXGR7Mn06XFxkezJ9OlxcZHsyfSkoXFwuXFxkKyk/JC87XG5cbi8vIEEgcmVwb3J0IHJvdydzIGRhdGUgY2VsbCBhcyBhIGNhbGVuZGFyIGRheSBpbiB0aGUgcmVwb3J0J3Mgem9uZS5cbi8vXG4vLyBSZXBvcnQgcm93cyBhcmUgcmF3IGRhdGFiYXNlIHN0cmluZ3MsIG5vdCBzZXJpYWxpemVkIG1vZGVscywgc28gdGhlaXIgc2hhcGVcbi8vIGlzIHRoZSB3aXJlIGNvbnRyYWN0OiBhIERBVEUgY29sdW1uIGFycml2ZXMgYXMgJ1lZWVktTU0tREQnIGFuZCBhXG4vLyBkYXRlLWFuZC10aW1lIGNvbHVtbiBhcyAnWVlZWS1NTS1ERCBISDpNTTpTUycgaW4gVVRDLiBSZWFkaW5nIHRoYXQgc2hhcGVcbi8vIGhlcmUgZG9lcyBub3QgcmUtZGVyaXZlIGEgc2VydmVyIHJ1bGU7IGl0IG9ubHkgc3RvcHMgdGhlIGJyb3dzZXIgZ3Vlc3NpbmcuXG4vLyAtIEEgY2FsZW5kYXIgZGF5IGlzIG5ldmVyIHNoaWZ0ZWQ6IHBhcnNlSVNPIHJlYWRzIGl0IGFzIGxvY2FsIG1pZG5pZ2h0LCBzb1xuLy8gICB0aGUgZGF5IHByaW50ZWQgaXMgdGhlIGRheSBzdG9yZWQsIHdoYXRldmVyIHRoZSB6b25lLlxuLy8gLSBBbiBpbnN0YW50IGlzIHBpbm5lZCB0byBVVEMgd2l0aCBhbiBleHBsaWNpdCAnWicsIHRoZW4gc2hvd24gYXMgdGhlIGRheSBpdFxuLy8gICBmZWxsIG9uIGluIHRoZSByZXBvcnQncyB6b25lLCB0aGUgc2FtZSBkYXkgdGhlIGZpbHRlcnMgYW5kIHRpbWUgYnVja2V0cyB1c2UuXG4vLyAtIEFueXRoaW5nIGVsc2UgaXMgc2hvd24gYXMgaXQgY2FtZSwgYW5kIHNvIGlzIGEgdmFsdWUgdGhhdCBoYXMgdGhlIHNoYXBlXG4vLyAgIGJ1dCBuYW1lcyBubyByZWFsIGRheSAoYSB6ZXJvIGRhdGUgJzAwMDAtMDAtMDAnLCBvciAnMjAyNi0wMi0zMCcpOiBvbmVcbi8vICAgYmFkIGNlbGwgbXVzdCBub3QgdGhyb3cgb3V0IG9mIGEgcGlwZSBvciBhYm9ydCBhbiBleHBvcnQuXG4vLyBUaGUgZGF5IGlzIHdyaXR0ZW4gaW4gdGhlIHJlcG9ydCdzIGxvY2FsZTogJ0phbiA1LCAyMDI2JyBpbiBlbi1VUywgJzUgamFudi5cbi8vIDIwMjYnIGluIGZyLUNBLlxuZXhwb3J0IGZ1bmN0aW9uIGZvcm1hdFJlcG9ydERhdGUoXG4gIHZhbHVlOiB1bmtub3duLFxuICB0aW1lem9uZTogc3RyaW5nLFxuICBsb2NhbGU6IFJlcG9ydExvY2FsZVRhZyxcbik6IHN0cmluZyB7XG4gIGlmICh2YWx1ZSA9PT0gbnVsbCB8fCB2YWx1ZSA9PT0gdW5kZWZpbmVkIHx8IHZhbHVlID09PSAnJykge1xuICAgIHJldHVybiAnJztcbiAgfVxuXG4gIGNvbnN0IHRleHQgPSBTdHJpbmcodmFsdWUpO1xuXG4gIGlmIChEQVRFX09OTFlfUEFUVEVSTi50ZXN0KHRleHQpKSB7XG4gICAgY29uc3QgZGF5ID0gcGFyc2VJU08odGV4dCk7XG5cbiAgICByZXR1cm4gaXNWYWxpZChkYXkpID8gZm9ybWF0TG9jYWxEYXRlKGRheSwgbG9jYWxlLCBEQVlfU0hPUlQpIDogdGV4dDtcbiAgfVxuXG4gIGNvbnN0IGRhdGVUaW1lID0gREFURV9USU1FX1BBVFRFUk4uZXhlYyh0ZXh0KTtcbiAgaWYgKCFkYXRlVGltZSkge1xuICAgIHJldHVybiB0ZXh0O1xuICB9XG5cbiAgY29uc3QgaW5zdGFudCA9IHBhcnNlSVNPKGAke2RhdGVUaW1lWzFdfVQke2RhdGVUaW1lWzJdfVpgKTtcblxuICByZXR1cm4gaXNWYWxpZChpbnN0YW50KSA/IGZvcm1hdExvY2FsRGF0ZShpbnN0YW50LCBsb2NhbGUsIERBWV9TSE9SVCwgdGltZXpvbmUpIDogdGV4dDtcbn1cblxuXG4vLyBUaGUgdGltZSBvZiBkYXkgYW4gaW5zdGFudCBmYWxscyBhdCBpbiB0aGUgcmVwb3J0J3Mgem9uZTogJzI6MjMgUE0nIGluXG4vLyBlbi1VUywgJzE0IGggMjMnIGluIGZyLUNBLlxuZXhwb3J0IGNvbnN0IFRJTUVfU0hPUlQ6IEludGwuRGF0ZVRpbWVGb3JtYXRPcHRpb25zID0geyBob3VyOiAnbnVtZXJpYycsIG1pbnV0ZTogJzItZGlnaXQnIH07XG5cbi8vIEEgd2luZG93J3MgaW5jbHVzaXZlIGRheXMsIGFzIHRoZSBzZXJ2ZXIgc2VuZHMgdGhlbTogJ3l5eXktTU0tZGQnIGNhbGVuZGFyXG4vLyBkYXlzIGFscmVhZHkgaW4gdGhlIHJlcG9ydCdzIHpvbmUuIExpa2UgYSBkYXRlIGNlbGwgdGhleSBhcmUgcmVhZCBhcyBsb2NhbFxuLy8gbWlkbmlnaHQgYW5kIHdyaXR0ZW4gd2l0aCBOTyB6b25lLCBzbyBhIHZpZXdlciBpbiBhbnkgem9uZSBzZWVzIHRoZSBkYXlzXG4vLyBzZW50LiBCb3RoIGRheXM6IEludGwncyByYW5nZSBpbiB0aGUgbG9jYWxlICgnU2VwIDEg4oCTIDMwLCAyMDI2JyBpbiBlbi1VUyxcbi8vICcx4oCTMzAgc2VwdC4gMjAyNicgaW4gZnItQ0EsIG9uZSBkYXRlIHdoZW4gdGhleSBhcmUgdGhlIHNhbWUgZGF5KS4gT25lIGRheTpcbi8vIGFuIG9wZW4gd2luZG93ICgnU2luY2UgU2VwIDEsIDIwMjYnLCAnVGhyb3VnaCBTZXAgMzAsIDIwMjYnKS4gTmVpdGhlciwgb3Jcbi8vIGRheXMgdGhhdCBhcmUgbm90IHJlYWwgb25lczogJycuXG5leHBvcnQgZnVuY3Rpb24gZm9ybWF0RGF5UmFuZ2UoXG4gIHN0YXJ0OiBzdHJpbmcgfCBudWxsIHwgdW5kZWZpbmVkLFxuICBlbmQ6IHN0cmluZyB8IG51bGwgfCB1bmRlZmluZWQsXG4gIGxvY2FsZTogUmVwb3J0TG9jYWxlVGFnLFxuICBvcHRpb25zOiBJbnRsLkRhdGVUaW1lRm9ybWF0T3B0aW9ucyA9IERBWV9TSE9SVCxcbik6IHN0cmluZyB7XG4gIGNvbnN0IGZpcnN0ID0gcGFyc2VEYXkoc3RhcnQpO1xuICBjb25zdCBsYXN0ID0gcGFyc2VEYXkoZW5kKTtcblxuICBpZiAoZmlyc3QgJiYgbGFzdCkge1xuICAgIHJldHVybiB3cml0ZURheVJhbmdlKGZpcnN0LCBsYXN0LCBsb2NhbGUsIG9wdGlvbnMpO1xuICB9XG5cbiAgaWYgKGZpcnN0KSB7XG4gICAgcmV0dXJuIGBTaW5jZSAke2Zvcm1hdExvY2FsRGF0ZShmaXJzdCwgbG9jYWxlLCBvcHRpb25zKX1gO1xuICB9XG5cbiAgcmV0dXJuIGxhc3QgPyBgVGhyb3VnaCAke2Zvcm1hdExvY2FsRGF0ZShsYXN0LCBsb2NhbGUsIG9wdGlvbnMpfWAgOiAnJztcbn1cblxuLy8gVGhlIHRpbWUgYSB3aW5kb3cgZW5kaW5nIHRvZGF5IGlzIGN1dCBhdDogdGhlIHNlcnZlcidzIFVUQ1xuLy8gJ3l5eXktTU0tZGQgSEg6bW06c3MnIGluc3RhbnQsIGFzIGEgdGltZSBvZiBkYXkgaW4gdGhlIHJlcG9ydCdzIHpvbmUuICcnXG4vLyBmb3Igbm9uZSwgb3IgZm9yIGEgdmFsdWUgb2YgYW5vdGhlciBzaGFwZS5cbmV4cG9ydCBmdW5jdGlvbiBmb3JtYXRUaHJvdWdoVGltZShcbiAgdGhyb3VnaDogc3RyaW5nIHwgbnVsbCB8IHVuZGVmaW5lZCxcbiAgdGltZXpvbmU6IHN0cmluZyxcbiAgbG9jYWxlOiBSZXBvcnRMb2NhbGVUYWcsXG4pOiBzdHJpbmcge1xuICBjb25zdCBkYXRlVGltZSA9IHRocm91Z2ggPyBEQVRFX1RJTUVfUEFUVEVSTi5leGVjKHRocm91Z2gpIDogbnVsbDtcbiAgY29uc3QgaW5zdGFudCA9IGRhdGVUaW1lID8gcGFyc2VJU08oYCR7ZGF0ZVRpbWVbMV19VCR7ZGF0ZVRpbWVbMl19WmApIDogbnVsbDtcblxuICByZXR1cm4gaW5zdGFudCAmJiBpc1ZhbGlkKGluc3RhbnQpID8gZm9ybWF0TG9jYWxEYXRlKGluc3RhbnQsIGxvY2FsZSwgVElNRV9TSE9SVCwgdGltZXpvbmUpIDogJyc7XG59XG5cbi8vIEEgY29tcGFyaXNvbiBvciB0aW1lZnJhbWUgd2luZG93IGluIG9uZSBsaW5lOiBpdHMgZGF5cywgYW5kIHRoZSB0aW1lIGl0IGlzXG4vLyBjdXQgYXQgd2hlbiBpdCBlbmRzIHRvZGF5IG9uIGEgZGF0ZS1hbmQtdGltZSBjb2x1bW4gKCdPY3QgMSDigJMgMiwgMjAyNixcbi8vIHVudGlsIDI6MjMgUE0nKS5cbmV4cG9ydCBmdW5jdGlvbiBmb3JtYXREYXlXaW5kb3coXG4gIG1ldGE6IHsgc3RhcnQ6IHN0cmluZyB8IG51bGw7IGVuZDogc3RyaW5nIHwgbnVsbDsgdGhyb3VnaD86IHN0cmluZyB8IG51bGwgfSxcbiAgdGltZXpvbmU6IHN0cmluZyxcbiAgbG9jYWxlOiBSZXBvcnRMb2NhbGVUYWcsXG4pOiBzdHJpbmcge1xuICBjb25zdCBkYXlzID0gZm9ybWF0RGF5UmFuZ2UobWV0YS5zdGFydCwgbWV0YS5lbmQsIGxvY2FsZSk7XG4gIGNvbnN0IHRpbWUgPSBmb3JtYXRUaHJvdWdoVGltZShtZXRhLnRocm91Z2gsIHRpbWV6b25lLCBsb2NhbGUpO1xuXG4gIHJldHVybiBkYXlzICYmIHRpbWUgPyBgJHtkYXlzfSwgdW50aWwgJHt0aW1lfWAgOiBkYXlzO1xufVxuXG4vLyBPbmUgJ3l5eXktTU0tZGQnIGRheSBpbiB0aGUgbG9jYWxlLCB3cml0dGVuIHdpdGggbm8gem9uZTogJ1NlcCAxLCAyMDI2Jy5cbmZ1bmN0aW9uIGZvcm1hdERheShkYXk6IHN0cmluZywgbG9jYWxlOiBSZXBvcnRMb2NhbGVUYWcpOiBzdHJpbmcge1xuICBjb25zdCBkYXRlID0gcGFyc2VEYXkoZGF5KTtcblxuICByZXR1cm4gZGF0ZSA/IGZvcm1hdExvY2FsRGF0ZShkYXRlLCBsb2NhbGUsIERBWV9TSE9SVCkgOiAnJztcbn1cblxuLy8gQSAneXl5eS1NTS1kZCcgZGF5IGFzIGxvY2FsIG1pZG5pZ2h0LCBvciBudWxsIHdoZW4gaXQgaXMgbm90IGEgcmVhbCBkYXkuXG5mdW5jdGlvbiBwYXJzZURheShkYXk6IHN0cmluZyB8IG51bGwgfCB1bmRlZmluZWQpOiBEYXRlIHwgbnVsbCB7XG4gIGlmICghZGF5IHx8ICFEQVRFX09OTFlfUEFUVEVSTi50ZXN0KGRheSkpIHtcbiAgICByZXR1cm4gbnVsbDtcbiAgfVxuXG4gIGNvbnN0IGRhdGUgPSBwYXJzZUlTTyhkYXkpO1xuXG4gIHJldHVybiBpc1ZhbGlkKGRhdGUpID8gZGF0ZSA6IG51bGw7XG59XG5cbi8vIEludGwncyByYW5nZSB3cml0ZXMgdGhlIHNoYXJlZCBtb250aCBhbmQgeWVhciBvbmNlLiBBIG1hbGZvcm1lZCBsb2NhbGVcbi8vIHJlYWRzIHRoZSBmYWxsYmFjazsgYSBydW50aW1lIHRoYXQgY2Fubm90IHdyaXRlIHJhbmdlcyBqb2lucyB0d28gZGF0ZXMuXG5mdW5jdGlvbiB3cml0ZURheVJhbmdlKGZpcnN0OiBEYXRlLCBsYXN0OiBEYXRlLCBsb2NhbGU6IFJlcG9ydExvY2FsZVRhZywgb3B0aW9uczogSW50bC5EYXRlVGltZUZvcm1hdE9wdGlvbnMpOiBzdHJpbmcge1xuICBjb25zdCBbZnJvbSwgdG9dID0gZmlyc3QgPD0gbGFzdCA/IFtmaXJzdCwgbGFzdF0gOiBbbGFzdCwgZmlyc3RdO1xuXG4gIGZvciAoY29uc3QgdGFnIG9mIFtsb2NhbGUsIHJlc29sdmVSZXBvcnRMb2NhbGUobG9jYWxlKV0pIHtcbiAgICB0cnkge1xuICAgICAgcmV0dXJuIGRhdGVGb3JtYXQodGFnLCBvcHRpb25zKS5mb3JtYXRSYW5nZShmcm9tLCB0byk7XG4gICAgfSBjYXRjaCB7XG4gICAgICAvLyBUaGUgbmV4dCBsb2NhbGUsIHRoZW4gdGhlIGpvaW5lZCBkYXRlcy5cbiAgICB9XG4gIH1cblxuICByZXR1cm4gYCR7Zm9ybWF0TG9jYWxEYXRlKGZyb20sIGxvY2FsZSwgb3B0aW9ucyl9IOKAkyAke2Zvcm1hdExvY2FsRGF0ZSh0bywgbG9jYWxlLCBvcHRpb25zKX1gO1xufVxuXG5cbi8vIEVuZ2xpc2ggbmFtZXMgZm9yIGEgbG9jYWxlIGFuZCBhIGN1cnJlbmN5LCBmb3IgdGhlIHNldHRpbmdzIHNlbGVjdHMuIFRoZVxuLy8gaW50ZXJmYWNlIHN0YXlzIEVuZ2xpc2ggd2hhdGV2ZXIgdGhlIHJlcG9ydCdzIGxvY2FsZTogJ2ZyLUNBJyByZWFkc1xuLy8gJ0NhbmFkaWFuIEZyZW5jaCcsICdDQUQnIHJlYWRzICdDYW5hZGlhbiBEb2xsYXInLiBBIHJ1bnRpbWUgd2l0aG91dCB0aGVcbi8vIG5hbWVzIHNob3dzIHRoZSBjb2RlLlxuZXhwb3J0IGZ1bmN0aW9uIGxvY2FsZU5hbWUodGFnOiBSZXBvcnRMb2NhbGVUYWcpOiBzdHJpbmcge1xuICByZXR1cm4gZGlzcGxheU5hbWUoJ2xhbmd1YWdlJywgdGFnKTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGN1cnJlbmN5TmFtZShjb2RlOiBSZXBvcnRDdXJyZW5jeUNvZGUpOiBzdHJpbmcge1xuICByZXR1cm4gZGlzcGxheU5hbWUoJ2N1cnJlbmN5JywgY29kZSk7XG59XG5cbmZ1bmN0aW9uIGRpc3BsYXlOYW1lKHR5cGU6ICdsYW5ndWFnZScgfCAnY3VycmVuY3knLCBjb2RlOiBzdHJpbmcpOiBzdHJpbmcge1xuICB0cnkge1xuICAgIHJldHVybiBuZXcgSW50bC5EaXNwbGF5TmFtZXMoWydlbiddLCB7IHR5cGUgfSkub2YoY29kZSkgPz8gY29kZTtcbiAgfSBjYXRjaCB7XG4gICAgcmV0dXJuIGNvZGU7XG4gIH1cbn1cblxuXG4vLyBDb21wYXJpc29uLCB3aW5kb3cgYW5kIEtQSSB3b3JkaW5nLiBUaGUgc2VydmVyIHNlbmRzIGNvZGVzIGFuZCBmaWVsZHMsXG4vLyBuZXZlciBzZW50ZW5jZXMgKGEgd2luZG93J3MgZGVzY3JpcHRpb24gaXMgZm9yIHRoZSBhZ2VudCBhbmQgdGhlIGV4cG9ydHMnXG4vLyBub3Rlcywgbm90IHRoZSBzY3JlZW4pOyB0aGUgaW50ZXJmYWNlIHdvcmRzIHRoZW0gaGVyZSwgaW4gRW5nbGlzaCBsaWtlXG4vLyBldmVyeSBvdGhlciBsYWJlbCwgd2l0aCBhbnkgZGF5IHdyaXR0ZW4gaW4gdGhlIHJlcG9ydCdzIGxvY2FsZS5cblxuY29uc3QgR1JBTlVMQVJJVFlfVU5JVFM6IFJlY29yZDxDaGFydEdyYW51bGFyaXR5LCB7IG9uZTogc3RyaW5nOyBtYW55OiBzdHJpbmcgfT4gPSB7XG4gIGRheTogeyBvbmU6ICdkYXknLCBtYW55OiAnZGF5cycgfSxcbiAgd2VlazogeyBvbmU6ICd3ZWVrJywgbWFueTogJ3dlZWtzJyB9LFxuICBtb250aDogeyBvbmU6ICdtb250aCcsIG1hbnk6ICdtb250aHMnIH0sXG4gIHF1YXJ0ZXI6IHsgb25lOiAncXVhcnRlcicsIG1hbnk6ICdxdWFydGVycycgfSxcbiAgeWVhcjogeyBvbmU6ICd5ZWFyJywgbWFueTogJ3llYXJzJyB9LFxufTtcblxuLy8gV2hhdCBhIHByaW9yIGxhbmUgaXMgY2FsbGVkOiBhbHdheXMgc28gZm9yIGEgbmFtZWQgcGVyaW9kLCBhbmQgZm9yIHRoZVxuLy8gcHJldmlvdXMgcGVyaW9kIHdoZW4gdGhlIHNlcnZlciBuYW1lcyBubyB1bml0IGZvciBpdC5cbmNvbnN0IEFHQUlOU1RfUEhSQVNFUzogUmVjb3JkPENvbXBhcmlzb25BZ2FpbnN0LCBzdHJpbmc+ID0ge1xuICBwcmV2aW91c19wZXJpb2Q6ICdwcmV2aW91cyBwZXJpb2QnLFxuICBwcmV2aW91c193ZWVrOiAncHJldmlvdXMgd2VlaycsXG4gIHByZXZpb3VzX21vbnRoOiAncHJldmlvdXMgbW9udGgnLFxuICBwcmV2aW91c19xdWFydGVyOiAncHJldmlvdXMgcXVhcnRlcicsXG4gIHByZXZpb3VzX3llYXI6ICdwcmV2aW91cyB5ZWFyJyxcbiAgcmFuZ2U6ICdjdXN0b20gcmFuZ2UnLFxufTtcblxuLy8gQSBwcmlvciBsYW5lJ3MgbGFiZWwsIGZyb20gaXRzIG9mZnNldCByYXRoZXIgdGhhbiBmcm9tIHRoZSBtZWFzdXJlLCBzbyBhXG4vLyBjaGFydCByZWdyb3VwZWQgYnkgdGhlIHZpZXdlciBzYXlzIHdoYXQgaXQgbm93IGNvbXBhcmVzLiBBIG5hbWVkIHBlcmlvZFxuLy8gcmVhZHMgYnkgaXRzIG5hbWUgd2hhdGV2ZXIgc2hpZnQgY2FycmllcyBpdCAoJ3ZzIHByZXZpb3VzIHF1YXJ0ZXInIGZvciAzXG4vLyBtb250aHMsICd2cyBwcmV2aW91cyB5ZWFyJyBmb3IgMzY0IGRheXMgb3IgNTIgd2Vla3MsICd2cyBjdXN0b20gcmFuZ2UnKS5cbi8vIE9ubHkgdGhlIHByZXZpb3VzIHBlcmlvZCBpcyB3b3JkZWQgZnJvbSBpdHMgdW5pdCBhbmQgY291bnQ6ICd2cyBwcmV2aW91c1xuLy8gd2VlaycsICd2cyBwcmV2aW91cyAzIG1vbnRocycsICd2cyBwcmV2aW91cyA4IGRheXMnIChhIGRheS1sZW5ndGggc2hpZnQpLlxuZXhwb3J0IGZ1bmN0aW9uIGNvbXBhcmlzb25PZmZzZXRMYWJlbChvZmZzZXQ6IENvbXBhcmlzb25PZmZzZXQpOiBzdHJpbmcge1xuICByZXR1cm4gYHZzICR7b2Zmc2V0UGhyYXNlKG9mZnNldCl9YDtcbn1cblxuZnVuY3Rpb24gb2Zmc2V0UGhyYXNlKG9mZnNldDogQ29tcGFyaXNvbk9mZnNldCk6IHN0cmluZyB7XG4gIGlmIChvZmZzZXQuYWdhaW5zdCAhPT0gJ3ByZXZpb3VzX3BlcmlvZCcgfHwgIW9mZnNldC51bml0IHx8ICFvZmZzZXQuY291bnQpIHtcbiAgICByZXR1cm4gQUdBSU5TVF9QSFJBU0VTW29mZnNldC5hZ2FpbnN0XSA/PyBBR0FJTlNUX1BIUkFTRVMucHJldmlvdXNfcGVyaW9kO1xuICB9XG5cbiAgcmV0dXJuIG9mZnNldC5jb3VudCA9PT0gMVxuICAgID8gYHByZXZpb3VzICR7R1JBTlVMQVJJVFlfVU5JVFNbb2Zmc2V0LnVuaXRdLm9uZX1gXG4gICAgOiBgcHJldmlvdXMgJHtvZmZzZXQuY291bnR9ICR7R1JBTlVMQVJJVFlfVU5JVFNbb2Zmc2V0LnVuaXRdLm1hbnl9YDtcbn1cblxuLy8gT25lIGNvbXBhcmlzb24gbm90ZSBhcyBhIHNlbnRlbmNlLiBUaGUgY29tcGFyaXNvbiwgd2hlbiBnaXZlbiwgbmFtZXMgdGhlXG4vLyBwZXJpb2QgY29tcGFyZWQgd2l0aCAoaXRzIGZpcnN0IHByaW9yIGxhbmUpLlxuZXhwb3J0IGZ1bmN0aW9uIGNvbXBhcmlzb25Ob3RlVGV4dChcbiAgY29kZTogQ29tcGFyaXNvbk5vdGVDb2RlLFxuICBjb21wYXJpc29uPzogQ29tcG9uZW50Q29tcGFyaXNvbiB8IG51bGwsXG4pOiBzdHJpbmcge1xuICBjb25zdCBvZmZzZXQgPSBjb21wYXJpc29uPy5vZmZzZXRzPy5bMF0gPz8gbnVsbDtcbiAgY29uc3QgY29tcGFyZWQgPSBvZmZzZXQgPyBgQ29tcGFyZWQgd2l0aCB0aGUgJHtvZmZzZXRQaHJhc2Uob2Zmc2V0KX1gIDogbnVsbDtcblxuICBzd2l0Y2ggKGNvZGUpIHtcbiAgICBjYXNlICdub193aW5kb3cnOlxuICAgICAgcmV0dXJuICdQaWNrIGEgZGF0ZSByYW5nZSB0byBzZWUgdGhlIGNvbXBhcmlzb24uJztcbiAgICBjYXNlICd1bml0X2luZmVycmVkJzpcbiAgICAgIHJldHVybiBjb21wYXJlZFxuICAgICAgICA/IGAke2NvbXBhcmVkfSwganVkZ2VkIGZyb20gdGhlIGRhdGVzIHBpY2tlZC5gXG4gICAgICAgIDogJ1RoZSBwZXJpb2QgY29tcGFyZWQgd2l0aCB3YXMganVkZ2VkIGZyb20gdGhlIGRhdGVzIHBpY2tlZC4nO1xuICAgIGNhc2UgJ3dpbmRvd19pbl9mdXR1cmUnOlxuICAgICAgcmV0dXJuICdUaGUgZGF0ZSByYW5nZSBzdGFydHMgYWZ0ZXIgdG9kYXksIHNvIHRoZXJlIGlzIG5vdGhpbmcgdG8gY29tcGFyZSB5ZXQuJztcbiAgICBjYXNlICdvdGhlcl9kYXRlX2ZpbHRlcic6XG4gICAgICByZXR1cm4gJ0EgZGF0ZSBmaWx0ZXIgb24gYW5vdGhlciBjb2x1bW4gYWxzbyBhcHBsaWVzIHRvIGJvdGggcGVyaW9kcy4nO1xuICAgIGNhc2UgJ2dyYWluX2ZvbGxvd2VkJzpcbiAgICAgIHJldHVybiBjb21wYXJlZFxuICAgICAgICA/IGAke2NvbXBhcmVkfSwgZm9sbG93aW5nIHRoZSBncm91cGluZyBwaWNrZWQuYFxuICAgICAgICA6ICdUaGUgY29tcGFyaXNvbiBmb2xsb3dzIHRoZSBncm91cGluZyBwaWNrZWQuJztcbiAgICBkZWZhdWx0OlxuICAgICAgcmV0dXJuICcnO1xuICB9XG59XG5cbi8vIFdoYXQgYSB3aW5kb3dlZCB2YWx1ZSBpczogJ1JvbGxpbmcgMy1tb250aCB0b3RhbCcsICdNb250aC10by1kYXRlIHRvdGFsJyxcbi8vICdSdW5uaW5nIHRvdGFsIHNpbmNlIHRoZSBzdGFydCBvZiB0aGUgZGF0YScsIHRoZW4gaXRzIGRheXMgd2hlbiB0aGUgc2VydmVyXG4vLyBzZW5kcyB0aGVtICgnUm9sbGluZyA3LWRheSBhdmVyYWdlLCBTZXAgMjQg4oCTIDMwLCAyMDI2JykuIGdyYW51bGFyaXR5IGlzIHRoZVxuLy8gZ3JvdXBpbmcgdGhlIHJvd3MgYXJlIGRyYXduIGF0IChDb21wb25lbnREYXRhLmdyYW51bGFyaXR5KSwgd2hpY2ggbmFtZXMgYVxuLy8gcm9sbGluZyB3aW5kb3cgYXV0aG9yZWQgaW4gcGVyaW9kcyBvZiB0aGUgYXhpcy5cbmV4cG9ydCBmdW5jdGlvbiB3aW5kb3dUZXh0KFxuICBtZXRhOiBXaW5kb3dNZXRhLFxuICBsb2NhbGU6IFJlcG9ydExvY2FsZVRhZyxcbiAgZ3JhbnVsYXJpdHk/OiBDaGFydEdyYW51bGFyaXR5IHwgbnVsbCxcbik6IHN0cmluZyB7XG4gIGNvbnN0IGRheXMgPSBmb3JtYXREYXlSYW5nZShtZXRhLnN0YXJ0LCBtZXRhLmVuZCwgbG9jYWxlKTtcbiAgY29uc3QgcGhyYXNlID0gd2luZG93UGhyYXNlKG1ldGEsIGdyYW51bGFyaXR5ID8/IG51bGwpO1xuXG4gIHJldHVybiBkYXlzID8gYCR7cGhyYXNlfSwgJHtkYXlzfWAgOiBwaHJhc2U7XG59XG5cbmZ1bmN0aW9uIHdpbmRvd1BocmFzZShtZXRhOiBXaW5kb3dNZXRhLCBncmFudWxhcml0eTogQ2hhcnRHcmFudWxhcml0eSB8IG51bGwpOiBzdHJpbmcge1xuICBjb25zdCB2YWx1ZSA9IG1ldGEuYXZlcmFnZSA/ICdhdmVyYWdlJyA6ICd0b3RhbCc7XG5cbiAgc3dpdGNoIChtZXRhLmtpbmQpIHtcbiAgICBjYXNlICdydW5uaW5nJzpcbiAgICAgIHJldHVybiBtZXRhLmZyb21CZWdpbm5pbmcgPyBgUnVubmluZyAke3ZhbHVlfSBzaW5jZSB0aGUgc3RhcnQgb2YgdGhlIGRhdGFgIDogYFJ1bm5pbmcgJHt2YWx1ZX1gO1xuICAgIGNhc2UgJ3RvX2RhdGUnOiB7XG4gICAgICBjb25zdCByZXNldCA9IG1ldGEucmVzZXRFdmVyeSA/IEdSQU5VTEFSSVRZX1VOSVRTW21ldGEucmVzZXRFdmVyeV0ub25lIDogbnVsbDtcblxuICAgICAgcmV0dXJuIHJlc2V0ID8gYCR7Y2FwaXRhbGl6ZShyZXNldCl9LXRvLWRhdGUgJHt2YWx1ZX1gIDogYFRvLWRhdGUgJHt2YWx1ZX1gO1xuICAgIH1cbiAgICBjYXNlICdyb2xsaW5nJzoge1xuICAgICAgY29uc3QgdW5pdCA9IG1ldGEudW5pdCA/PyBncmFudWxhcml0eTtcbiAgICAgIGNvbnN0IHNwYW4gPSBtZXRhLnBlcmlvZHMgPyBgJHttZXRhLnBlcmlvZHN9LSR7dW5pdCA/IEdSQU5VTEFSSVRZX1VOSVRTW3VuaXRdLm9uZSA6ICdwZXJpb2QnfSBgIDogJyc7XG5cbiAgICAgIHJldHVybiBgUm9sbGluZyAke3NwYW59JHt2YWx1ZX1gO1xuICAgIH1cbiAgICBkZWZhdWx0OlxuICAgICAgcmV0dXJuIGNhcGl0YWxpemUodmFsdWUpO1xuICB9XG59XG5cbi8vIE9uZSB3aW5kb3cgbm90ZSBhcyBhIHNlbnRlbmNlLlxuZXhwb3J0IGZ1bmN0aW9uIHdpbmRvd05vdGVUZXh0KFxuICBjb2RlOiBXaW5kb3dOb3RlQ29kZSxcbiAgbWV0YTogV2luZG93TWV0YSxcbiAgbG9jYWxlOiBSZXBvcnRMb2NhbGVUYWcsXG4gIGdyYW51bGFyaXR5PzogQ2hhcnRHcmFudWxhcml0eSB8IG51bGwsXG4pOiBzdHJpbmcge1xuICBzd2l0Y2ggKGNvZGUpIHtcbiAgICBjYXNlICdzbmFwcGVkX3N0YXJ0Jzoge1xuICAgICAgY29uc3Qgc3RhcnQgPSBtZXRhLnN0YXJ0ID8gZm9ybWF0RGF5KG1ldGEuc3RhcnQsIGxvY2FsZSkgOiAnJztcblxuICAgICAgcmV0dXJuIHN0YXJ0XG4gICAgICAgID8gYFRoZSBzdGFydCB3YXMgbW92ZWQgdG8gJHtzdGFydH0sIHRoZSBzdGFydCBvZiBpdHMgcGVyaW9kLCBzbyB0aGUgZmlyc3QgcGVyaW9kIGlzIHdob2xlLmBcbiAgICAgICAgOiAnVGhlIHN0YXJ0IHdhcyBtb3ZlZCB0byB0aGUgc3RhcnQgb2YgaXRzIHBlcmlvZCwgc28gdGhlIGZpcnN0IHBlcmlvZCBpcyB3aG9sZS4nO1xuICAgIH1cbiAgICBjYXNlICdzcGFuX2NvbnZlcnRlZCc6XG4gICAgICByZXR1cm4gc3BhbkNvbnZlcnRlZFRleHQobWV0YSwgZ3JhbnVsYXJpdHkgPz8gbnVsbCk7XG4gICAgY2FzZSAnZ3JhaW5fdG9vX2NvYXJzZSc6XG4gICAgICByZXR1cm4gJ1RoZSBncm91cGluZyBpcyBjb2Fyc2VyIHRoYW4gdGhlIHdpbmRvdywgc28gaXQgaGFzIG5vIHZhbHVlcyBhdCB0aGlzIGdyb3VwaW5nLic7XG4gICAgY2FzZSAnZXF1YWxfZ3JhaW5fcGxhaW4nOlxuICAgICAgcmV0dXJuICdBdCB0aGlzIGdyb3VwaW5nIGVhY2ggd2luZG93IGlzIGEgc2luZ2xlIHBlcmlvZCwgc28gdGhlIHZhbHVlcyBhcmUgdGhlIHBsYWluIG9uZXMuJztcbiAgICBjYXNlICdvd25fZmlsdGVyX2NhcHNfbGVhZF9pbic6XG4gICAgICByZXR1cm4gJ1RoZSBxdWVyeVxcJ3Mgb3duIGRhdGUgY29uZGl0aW9uIHN0YXJ0cyB0aGUgd2luZG93LCBzbyBlYXJsaWVyIHJvd3MgYXJlIG5vdCBjb3VudGVkLic7XG4gICAgY2FzZSAnd2Vla19ieV9tb25kYXknOlxuICAgICAgcmV0dXJuICdBIHdlZWsgdGhhdCBzcGFucyB0d28gcGVyaW9kcyBjb3VudHMgdG93YXJkIHRoZSBwZXJpb2QgaXRzIE1vbmRheSBmYWxscyBpbi4nO1xuICAgIGNhc2UgJ2luY29tcGxldGVfaGVhZCc6XG4gICAgICByZXR1cm4gJ1RoZSBmaXJzdCBwZXJpb2RzIGFyZSBibGFuayBiZWNhdXNlIHRoZXJlIGFyZSBub3QgZW5vdWdoIGVhcmxpZXIgcm93cyB0byBmaWxsIGEgd2hvbGUgd2luZG93Lic7XG4gICAgZGVmYXVsdDpcbiAgICAgIHJldHVybiAnJztcbiAgfVxufVxuXG4vLyAnMyBtb250aHMgYXJlIHNob3duIGFzIDEzIHdlZWtzIGF0IHRoaXMgZ3JvdXBpbmcuJ1xuZnVuY3Rpb24gc3BhbkNvbnZlcnRlZFRleHQobWV0YTogV2luZG93TWV0YSwgZ3JhbnVsYXJpdHk6IENoYXJ0R3JhbnVsYXJpdHkgfCBudWxsKTogc3RyaW5nIHtcbiAgaWYgKCFtZXRhLnBlcmlvZHMgfHwgIW1ldGEudW5pdCB8fCAhbWV0YS5kcmF3blBlcmlvZHMpIHtcbiAgICByZXR1cm4gJ1RoZSB3aW5kb3dcXCdzIHNwYW4gd2FzIGNvbnZlcnRlZCB0byB0aGUgZ3JvdXBpbmcgc2hvd24uJztcbiAgfVxuXG4gIGNvbnN0IGF1dGhvcmVkID0gdW5pdENvdW50KG1ldGEucGVyaW9kcywgbWV0YS51bml0KTtcbiAgY29uc3QgZHJhd24gPSBncmFudWxhcml0eVxuICAgID8gdW5pdENvdW50KG1ldGEuZHJhd25QZXJpb2RzLCBncmFudWxhcml0eSlcbiAgICA6IGAke21ldGEuZHJhd25QZXJpb2RzfSAke21ldGEuZHJhd25QZXJpb2RzID09PSAxID8gJ3BlcmlvZCcgOiAncGVyaW9kcyd9YDtcblxuICByZXR1cm4gYCR7YXV0aG9yZWR9ICR7bWV0YS5wZXJpb2RzID09PSAxID8gJ2lzJyA6ICdhcmUnfSBzaG93biBhcyAke2RyYXdufSBhdCB0aGlzIGdyb3VwaW5nLmA7XG59XG5cbmZ1bmN0aW9uIHVuaXRDb3VudChjb3VudDogbnVtYmVyLCB1bml0OiBDaGFydEdyYW51bGFyaXR5KTogc3RyaW5nIHtcbiAgcmV0dXJuIGAke2NvdW50fSAke2NvdW50ID09PSAxID8gR1JBTlVMQVJJVFlfVU5JVFNbdW5pdF0ub25lIDogR1JBTlVMQVJJVFlfVU5JVFNbdW5pdF0ubWFueX1gO1xufVxuXG4vLyBXaHkgYSBLUEkncyBkZWx0YSByZWFkcyBhcyBpdCBkb2VzLCBhcyBhIHNlbnRlbmNlLiBUaGUgYmFzZWxpbmUgaXMgbmFtZWRcbi8vIGJ5IHdoYXQgdGhlIHZhbHVlIGlzIGNvbXBhcmVkIGFnYWluc3Q6IHRoZSBzYW1lIHBlcmlvZCBsYXN0IHllYXIgZm9yIGFcbi8vIHllYXItb24teWVhciBjb21wYXJpc29uLCBlbHNlIHRoZSBwZXJpb2QgYmVmb3JlLlxuZXhwb3J0IGZ1bmN0aW9uIGtwaU5vdGVUZXh0KGNvZGU6IEtwaU5vdGVDb2RlLCBhZ2FpbnN0PzogQ29tcGFyaXNvbkFnYWluc3QgfCBudWxsKTogc3RyaW5nIHtcbiAgY29uc3QgYmFzZWxpbmUgPSBrcGlCYXNlbGluZVRleHQoYWdhaW5zdCk7XG5cbiAgc3dpdGNoIChjb2RlKSB7XG4gICAgY2FzZSAnbm9fcHJpb3JfZGF0YSc6XG4gICAgICByZXR1cm4gYE5vIGJhc2VsaW5lOiAke2Jhc2VsaW5lfSBoYXMgbm8gZGF0YS5gO1xuICAgIGNhc2UgJ3VwX2Zyb21femVybyc6XG4gICAgICByZXR1cm4gYE5ldzogJHtiYXNlbGluZX0gd2FzIDAuYDtcbiAgICBjYXNlICdub19jaGFuZ2UnOlxuICAgICAgcmV0dXJuIGBObyBjaGFuZ2UgZnJvbSAke2Jhc2VsaW5lfS5gO1xuICAgIGNhc2UgJ25vX2RhdGFfZWl0aGVyJzpcbiAgICAgIHJldHVybiAnTm8gZGF0YSBpbiBlaXRoZXIgcGVyaW9kLic7XG4gICAgY2FzZSAnc2lnbl9jaGFuZ2UnOlxuICAgICAgcmV0dXJuICdUaGUgdmFsdWUgY3Jvc3NlZCB6ZXJvLCBzbyB0aGVyZSBpcyBubyBwZXJjZW50IGNoYW5nZS4nO1xuICAgIGRlZmF1bHQ6XG4gICAgICByZXR1cm4gJyc7XG4gIH1cbn1cblxuLy8gVGhlIHdpbmRvdyBhIEtQSSdzIHZhbHVlIGlzIGNvbXBhcmVkIHdpdGgsIGFzIGEgbm91biBwaHJhc2UuIEFuIHVua25vd24gb3Jcbi8vIG1pc3NpbmcgY29tcGFyaXNvbiByZWFkcyBhcyBuZXV0cmFsIHdvcmRpbmcgcmF0aGVyIHRoYW4gYSB3cm9uZyBwZXJpb2QuXG5mdW5jdGlvbiBrcGlCYXNlbGluZVRleHQoYWdhaW5zdDogQ29tcGFyaXNvbkFnYWluc3QgfCBudWxsIHwgdW5kZWZpbmVkKTogc3RyaW5nIHtcbiAgc3dpdGNoIChhZ2FpbnN0KSB7XG4gICAgY2FzZSAncHJldmlvdXNfcGVyaW9kJzpcbiAgICAgIHJldHVybiAndGhlIHByZXZpb3VzIHBlcmlvZCc7XG4gICAgY2FzZSAncHJldmlvdXNfd2Vlayc6XG4gICAgICByZXR1cm4gJ3RoZSBwcmV2aW91cyB3ZWVrJztcbiAgICBjYXNlICdwcmV2aW91c19tb250aCc6XG4gICAgICByZXR1cm4gJ3RoZSBwcmV2aW91cyBtb250aCc7XG4gICAgY2FzZSAncHJldmlvdXNfcXVhcnRlcic6XG4gICAgICByZXR1cm4gJ3RoZSBwcmV2aW91cyBxdWFydGVyJztcbiAgICBjYXNlICdwcmV2aW91c195ZWFyJzpcbiAgICAgIHJldHVybiAndGhlIHNhbWUgcGVyaW9kIGxhc3QgeWVhcic7XG4gICAgZGVmYXVsdDpcbiAgICAgIHJldHVybiAndGhlIGNvbXBhcmlzb24gcGVyaW9kJztcbiAgfVxufVxuXG5mdW5jdGlvbiBjYXBpdGFsaXplKHRleHQ6IHN0cmluZyk6IHN0cmluZyB7XG4gIHJldHVybiB0ZXh0LmNoYXJBdCgwKS50b1VwcGVyQ2FzZSgpICsgdGV4dC5zbGljZSgxKTtcbn1cblxuXG4vLyBBIHNob3J0LCBodW1hbiBsYWJlbCBmb3IgYSB6b25lOiBpdHMgY2l0eSBwbHVzIHRoZSBjdXJyZW50IGFiYnJldmlhdGlvbixcbi8vIGUuZy4gJ0FtZXJpY2EvTmV3X1lvcmsnIHJlYWRzICdOZXcgWW9yayAoRURUKScuIFVUQyBzdGF5cyAnVVRDJywgYW5kIGFuXG4vLyB1bmtub3duIHpvbmUgaXMgc2hvd24gYXMgaXRzIGlkLiBBbiAnRXRjLycgem9uZSBuYW1lcyBubyBjaXR5LCBhbmQgaXRzIFBPU0lYXG4vLyBzaWduIGlzIHRoZSByZXZlcnNlIG9mIHRoZSBvZmZzZXQgKCdFdGMvR01UKzUnIGlzIEdNVC01KSwgc28gaXQgcmVhZHMgYXMgdGhlXG4vLyBhYmJyZXZpYXRpb24gYWxvbmU6ICdFdGMvVVRDJyBpcyAnVVRDJywgJ0V0Yy9HTVQrNScgaXMgJ0dNVC01Jy5cbmV4cG9ydCBmdW5jdGlvbiBnZXRUaW1lem9uZUxhYmVsKHRpbWV6b25lOiBzdHJpbmcpOiBzdHJpbmcge1xuICBpZiAodGltZXpvbmUgPT09ICdVVEMnKSB7XG4gICAgcmV0dXJuIHRpbWV6b25lO1xuICB9XG5cbiAgY29uc3Qgc2VnbWVudHMgPSB0aW1lem9uZS5zcGxpdCgnLycpO1xuXG4gIHRyeSB7XG4gICAgY29uc3QgYWJicmV2aWF0aW9uID0gZm9ybWF0SW5UaW1lWm9uZShuZXcgRGF0ZSgpLCB0aW1lem9uZSwgJ3p6eicpO1xuXG4gICAgcmV0dXJuIHNlZ21lbnRzWzBdID09PSAnRXRjJ1xuICAgICAgPyBhYmJyZXZpYXRpb25cbiAgICAgIDogYCR7c2VnbWVudHNbc2VnbWVudHMubGVuZ3RoIC0gMV0ucmVwbGFjZSgvXy9nLCAnICcpfSAoJHthYmJyZXZpYXRpb259KWA7XG4gIH0gY2F0Y2gge1xuICAgIHJldHVybiB0aW1lem9uZTtcbiAgfVxufVxuXG5cbi8vIFwiTm93XCIgYXMgYSBEYXRlIHdob3NlIGxvY2FsIGZpZWxkcyByZWFkIHRoZSB3YWxsIGNsb2NrIGluIHRoZSBnaXZlbiB6b25lLCBzb1xuLy8gZGF0ZS1mbnMgY2FsZW5kYXIgYXJpdGhtZXRpYyAoc3RhcnRPZldlZWssIHN0YXJ0T2ZNb250aCwgLi4uKSBhbmRcbi8vIGRhdGVCb3VuZFN0cmluZygpIGxhbmQgb24gdGhlIHpvbmUncyBjYWxlbmRhciBkYXkgcmF0aGVyIHRoYW4gdGhlIGJyb3dzZXIncy5cbi8vIEFuIHVua25vd24gem9uZSBmYWxscyBiYWNrIHRvIHRoZSBicm93c2VyJ3MgY2xvY2suXG5leHBvcnQgZnVuY3Rpb24gZ2V0Wm9uZWROb3codGltZXpvbmU6IHN0cmluZyk6IERhdGUge1xuICBjb25zdCBub3cgPSBuZXcgRGF0ZSgpO1xuXG4gIHRyeSB7XG4gICAgY29uc3Qgem9uZWQgPSB0b1pvbmVkVGltZShub3csIHRpbWV6b25lKTtcblxuICAgIHJldHVybiBOdW1iZXIuaXNOYU4oem9uZWQuZ2V0VGltZSgpKSA/IG5vdyA6IHpvbmVkO1xuICB9IGNhdGNoIHtcbiAgICByZXR1cm4gbm93O1xuICB9XG59XG4iXX0=