@firestitch/report 18.5.0 → 18.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/app/reports/components/component-kpi/component-kpi.component.d.ts +2 -1
  2. package/app/reports/components/component-list/component-list.component.d.ts +3 -7
  3. package/app/reports/components/report-canvas/report-canvas.component.d.ts +5 -4
  4. package/app/reports/components/report-component/report-component.component.d.ts +7 -6
  5. package/app/reports/components/timezone-select/timezone-select.component.d.ts +4 -6
  6. package/app/reports/consts/report-week.const.d.ts +2 -0
  7. package/app/reports/data/report-ai-chat.data.d.ts +12 -0
  8. package/app/reports/data/report.data.d.ts +3 -3
  9. package/app/reports/dialogs/component-settings/component-settings.component.d.ts +6 -6
  10. package/app/reports/dialogs/report-settings/report-settings.component.d.ts +5 -0
  11. package/app/reports/export/report-export-collector.service.d.ts +14 -2
  12. package/app/reports/export/report-pdf.service.d.ts +14 -1
  13. package/app/reports/export/report-pptx.service.d.ts +2 -1
  14. package/app/reports/format.d.ts +8 -1
  15. package/app/reports/interfaces/report-chat-viewer-filter.interface.d.ts +7 -0
  16. package/app/reports/interfaces/report-chat-viewer-state.interface.d.ts +7 -0
  17. package/app/reports/interfaces/report.interface.d.ts +18 -2
  18. package/app/reports/option-builder.d.ts +2 -1
  19. package/app/reports/pipes/report-date.pipe.d.ts +7 -0
  20. package/app/reports/report-filter-items.d.ts +5 -0
  21. package/app/reports/report-url-state.d.ts +15 -0
  22. package/app/reports/services/report-filter-state.service.d.ts +27 -2
  23. package/app/reports/theme/typography.d.ts +2 -0
  24. package/app/reports/views/report/fs-ai-report.component.d.ts +16 -8
  25. package/app/reports/views/report/report.component.d.ts +6 -6
  26. package/esm2022/app/reports/components/component-kpi/component-kpi.component.mjs +7 -4
  27. package/esm2022/app/reports/components/component-list/component-list.component.mjs +34 -131
  28. package/esm2022/app/reports/components/report-canvas/report-canvas.component.mjs +57 -44
  29. package/esm2022/app/reports/components/report-component/report-component.component.mjs +57 -35
  30. package/esm2022/app/reports/components/timezone-select/timezone-select.component.mjs +23 -23
  31. package/esm2022/app/reports/consts/report-week.const.mjs +7 -0
  32. package/esm2022/app/reports/data/report-ai-chat.data.mjs +25 -0
  33. package/esm2022/app/reports/data/report.data.mjs +22 -9
  34. package/esm2022/app/reports/dialogs/component-settings/component-settings.component.mjs +25 -26
  35. package/esm2022/app/reports/dialogs/global-settings/global-settings.component.mjs +2 -2
  36. package/esm2022/app/reports/dialogs/report-settings/report-settings.component.mjs +38 -13
  37. package/esm2022/app/reports/export/report-export-collector.service.mjs +95 -29
  38. package/esm2022/app/reports/export/report-export.service.mjs +11 -8
  39. package/esm2022/app/reports/export/report-pdf.service.mjs +245 -84
  40. package/esm2022/app/reports/export/report-pptx.service.mjs +64 -48
  41. package/esm2022/app/reports/format.mjs +126 -9
  42. package/esm2022/app/reports/interfaces/report-chat-viewer-filter.interface.mjs +2 -0
  43. package/esm2022/app/reports/interfaces/report-chat-viewer-state.interface.mjs +2 -0
  44. package/esm2022/app/reports/interfaces/report.interface.mjs +1 -1
  45. package/esm2022/app/reports/option-builder.mjs +146 -15
  46. package/esm2022/app/reports/pipes/report-date.pipe.mjs +21 -0
  47. package/esm2022/app/reports/report-filter-items.mjs +42 -10
  48. package/esm2022/app/reports/report-url-state.mjs +148 -0
  49. package/esm2022/app/reports/services/report-filter-state.service.mjs +339 -64
  50. package/esm2022/app/reports/theme/echarts.mjs +6 -5
  51. package/esm2022/app/reports/theme/typography.mjs +6 -0
  52. package/esm2022/app/reports/views/report/fs-ai-report.component.mjs +198 -90
  53. package/esm2022/app/reports/views/report/report.component.mjs +68 -62
  54. package/fesm2022/{firestitch-report-echarts-CtKYuRcT.mjs → firestitch-report-echarts-Djtmaxj1.mjs} +6 -6
  55. package/fesm2022/firestitch-report-echarts-Djtmaxj1.mjs.map +1 -0
  56. package/fesm2022/{firestitch-report-firestitch-report-Df1IXrEs.mjs → firestitch-report-firestitch-report-D3zseBZc.mjs} +1781 -738
  57. package/fesm2022/firestitch-report-firestitch-report-D3zseBZc.mjs.map +1 -0
  58. package/fesm2022/firestitch-report.mjs +1 -1
  59. package/package.json +1 -1
  60. package/app/reports/dialogs/report-settings/report-settings-default.d.ts +0 -2
  61. package/esm2022/app/reports/dialogs/report-settings/report-settings-default.mjs +0 -22
  62. package/fesm2022/firestitch-report-echarts-CtKYuRcT.mjs.map +0 -1
  63. package/fesm2022/firestitch-report-firestitch-report-Df1IXrEs.mjs.map +0 -1
@@ -1,4 +1,4 @@
1
- import { CUSTOM_ELEMENTS_SCHEMA, ChangeDetectionStrategy, ChangeDetectorRef, Component, DestroyRef, ElementRef, NgZone, ViewChild, computed, effect, inject, input, output, signal, } from '@angular/core';
1
+ import { CUSTOM_ELEMENTS_SCHEMA, ChangeDetectionStrategy, Component, DestroyRef, ElementRef, NgZone, ViewChild, computed, effect, inject, input, output, signal, untracked, } from '@angular/core';
2
2
  import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
3
3
  import { ActivatedRoute, Router } from '@angular/router';
4
4
  import { MatButtonModule } from '@angular/material/button';
@@ -8,10 +8,12 @@ import { MatTooltipModule } from '@angular/material/tooltip';
8
8
  import { FsFilterModule } from '@firestitch/filter';
9
9
  import { FsMenuModule } from '@firestitch/menu';
10
10
  import { FsProcess } from '@firestitch/process';
11
- import { takeUntil } from 'rxjs/operators';
11
+ import { Subject, merge } from 'rxjs';
12
+ import { auditTime, switchMap, takeUntil, tap } from 'rxjs/operators';
12
13
  import { provideEchartsCore } from 'ngx-echarts';
13
- import { FsAiChatComponent } from '@firestitch/ai';
14
+ import { FsAiChatComponent, FsAiChatData } from '@firestitch/ai';
14
15
  import { ReportCanvasComponent } from '../../components/report-canvas/report-canvas.component';
16
+ import { ReportAiChatData } from '../../data/report-ai-chat.data';
15
17
  import { ReportData } from '../../data/report.data';
16
18
  import { ComponentSettingsComponent } from '../../dialogs/component-settings/component-settings.component';
17
19
  import { ReportSettingsComponent } from '../../dialogs/report-settings/report-settings.component';
@@ -19,7 +21,9 @@ import { ReportExportCollectorService } from '../../export/report-export-collect
19
21
  import { ReportExportService } from '../../export/report-export.service';
20
22
  import { ReportPdfService } from '../../export/report-pdf.service';
21
23
  import { ReportPptxService } from '../../export/report-pptx.service';
24
+ import { getTimezoneLabel } from '../../format';
22
25
  import { GROUP_BY_ITEM, filterItemForGroup, groupByFilterItem, groupBySignature, groupValuesFromQuery, isGranularityOffered, } from '../../report-filter-items';
26
+ import { buildReportUrlParams, readReportUrlParams } from '../../report-url-state';
23
27
  import { ReportFilterStateService, defaultSignature } from '../../services/report-filter-state.service';
24
28
  import * as i0 from "@angular/core";
25
29
  import * as i1 from "@firestitch/filter";
@@ -29,7 +33,8 @@ import * as i4 from "@angular/material/icon";
29
33
  import * as i5 from "@angular/material/tooltip";
30
34
  // A single report: the AI chat on the left, the report canvas on the right,
31
35
  // under an H2 title + settings gear. The host supplies [reportId] (from its
32
- // route) and switches reports by navigating — this component never picks one.
36
+ // route) and switches reports through its own routes — this component never
37
+ // picks one.
33
38
  export class FsAiReportComponent {
34
39
  // The report this view is focused on — supplied by the host from the route.
35
40
  reportId = input(null);
@@ -39,21 +44,35 @@ export class FsAiReportComponent {
39
44
  // default; a host that mounts several reports on one route, or wants no URL
40
45
  // writes at all, sets this to null to turn it off.
41
46
  pageQueryParam = input('page');
47
+ // Whether the viewer's filters, group-by grain and list sorts live in the URL
48
+ // (g<groupId>, groupBy, s<componentId>; see report-url-state.ts), so a
49
+ // refresh or a shared link opens the report as it was seen. On by default; a
50
+ // host that mounts several reports on one route, or uses query keys shaped
51
+ // like g<n> or s<n> itself, turns it off.
52
+ urlState = input(true);
42
53
  // The report was deleted from its settings dialog — the host routes back to
43
54
  // the listing.
44
55
  deleted = output();
45
56
  // The report was renamed (settings, or the agent) — the host can refresh a
46
57
  // breadcrumb / document title.
47
58
  renamed = output();
48
- // The viewer moved to another page. The URL is already updated by then —
49
- // this is for hosts that track the open page for their own reasons.
59
+ // The viewer moved to another page. This view writes the URL itself (right
60
+ // after this fires) — this is for hosts that track the open page for their
61
+ // own reasons.
50
62
  pageChanged = output();
51
- report = null;
52
- editMode = false;
63
+ report = signal(null);
64
+ editMode = signal(false);
65
+ // The toolbar's zone indicator ('New York (EDT)'): the zone every date in
66
+ // this report is filtered and grouped in. Empty when the server is too old
67
+ // to send the effective zone, and the indicator is not shown.
68
+ timezoneLabel = computed(() => {
69
+ const effectiveTimezone = this.report()?.effectiveTimezone;
70
+ return effectiveTimezone ? getTimezoneLabel(effectiveTimezone) : '';
71
+ });
53
72
  // The page the canvas should open on, read from the URL once per report.
54
73
  // Cleared as soon as the canvas reports back, so a later in-app page change
55
74
  // is never fought by a stale value.
56
- pageId = null;
75
+ pageId = signal(null);
57
76
  // The page the chat is bound to: the one on screen. A report conversation
58
77
  // belongs to exactly one page, so this both scopes the conversation list and
59
78
  // becomes the new conversation's page. A signal because it feeds
@@ -83,23 +102,64 @@ export class FsAiReportComponent {
83
102
  });
84
103
  // The report-level filter toolbar (fs-filter). Rebuilt whenever the loaded
85
104
  // report (and thus its groups) changes.
86
- reportFilterConfig;
105
+ reportFilterConfig = signal(null);
106
+ // Gates the toolbar fs-filter so it isn't rendered when there is nothing to
107
+ // put in it — no report-level filters and no group-by control.
108
+ reportHasFilters = computed(() => {
109
+ return this._reportGroups().length > 0 || !!this._groupByItem();
110
+ });
111
+ // fs-filter reads its config only once (at init). The template keys the
112
+ // toolbar fs-filter on this signature so it's recreated (and re-reads the
113
+ // rebuilt config) whenever the report-level filter set changes.
114
+ reportFilterKey = computed(() => {
115
+ return [
116
+ // The effective zone is part of it too: a zone change re-resolves relative
117
+ // presets, and the bar must be recreated to show the new days.
118
+ this._filterState.timezone(),
119
+ // The stored default is part of the signature: saving a new default in report
120
+ // settings rebuilds the config, but without a key change fs-filter keeps
121
+ // rendering the values it was created with until a full page reload.
122
+ groupBySignature(this.report()),
123
+ ...this._reportGroups().map((group) => `${group.id}:${group.level}:${group.label}:${defaultSignature(group)}`),
124
+ ].join('|');
125
+ });
87
126
  _split;
88
127
  _chatPanel;
89
128
  // Only the canvas knows which page is on screen, and a page-scoped export
90
129
  // has to ask it.
91
130
  _canvas;
92
131
  _reportData = inject(ReportData);
132
+ _reportAiChatData = inject(ReportAiChatData);
93
133
  _router = inject(Router);
94
134
  _route = inject(ActivatedRoute);
95
135
  _filterState = inject(ReportFilterStateService);
96
136
  _exportService = inject(ReportExportService);
137
+ _collector = inject(ReportExportCollectorService);
97
138
  _process = inject(FsProcess);
98
139
  _dialog = inject(MatDialog);
99
140
  _destroyRef = inject(DestroyRef);
100
- _cdRef = inject(ChangeDetectorRef);
101
141
  _zone = inject(NgZone);
142
+ // The report whose URL state has been read. The URL is read only on a
143
+ // report's first load; a reload after a chat or dialog edit keeps the state
144
+ // in memory, which is newer than anything the URL holds.
145
+ _restoredReportId = null;
146
+ // Whether the canvas has reported the open page for this report. Until it
147
+ // has, the page param in the URL is the deep link still being honored, and
148
+ // the URL writer leaves it alone.
149
+ _pageReported = false;
150
+ // The canvas moved to another page. Merged into the single URL writer.
151
+ _pageWrite$ = new Subject();
102
152
  constructor() {
153
+ // Each chat turn carries what the viewer has on screen. Only the function
154
+ // is set here; it is called when a turn is sent.
155
+ this._reportAiChatData.turnData = () => ({ viewerState: this._chatViewerState() });
156
+ // The ONE writer of this view's query params. Page moves and viewer-state
157
+ // changes both funnel here, and auditTime(0) folds a burst (a bar re-sets
158
+ // every group it shows) into a single write. Every write carries the whole
159
+ // state, so a write that supersedes another loses nothing.
160
+ merge(this._filterState.urlChanges(), this._pageWrite$)
161
+ .pipe(auditTime(0), tap(() => this._writeUrl()), takeUntilDestroyed(this._destroyRef))
162
+ .subscribe();
103
163
  // Point the shared data gateway at the configured base first (before any
104
164
  // load below reads it).
105
165
  effect(() => {
@@ -108,27 +168,35 @@ export class FsAiReportComponent {
108
168
  // (Re)load whenever the host switches the report id.
109
169
  effect(() => {
110
170
  const reportId = this.reportId();
111
- this.editMode = false;
112
- // A new report's pages are not this report's pages — drop the binding
113
- // until its canvas says which page it landed on.
114
- this.chatPageId.set(null);
115
171
  // Seed the open page from the URL for this report. Read per load rather
116
172
  // than once at construction: the host may swap reports on the same route,
117
173
  // and each arrival carries its own ?page=.
118
- this.pageId = this._pageIdFromUrl();
119
- if (reportId != null) {
120
- this._loadReport(reportId);
121
- }
122
- else {
123
- this.report = null;
124
- this._buildReportConfig();
125
- this._cdRef.markForCheck();
126
- }
174
+ const pageId = this._pageIdFromUrl();
175
+ // Only the report id and the page param re-run this. The view state below
176
+ // is written here and read by the config build, so it stays untracked.
177
+ untracked(() => {
178
+ this.editMode.set(false);
179
+ // A new report's pages are not this report's pages — drop the binding
180
+ // until its canvas says which page it landed on.
181
+ this.chatPageId.set(null);
182
+ this.pageId.set(pageId);
183
+ this._pageReported = false;
184
+ if (reportId != null) {
185
+ this._loadReport(reportId);
186
+ }
187
+ else {
188
+ // Forget the restored report, so a host that comes back to it reads
189
+ // the URL again.
190
+ this._restoredReportId = null;
191
+ this.report.set(null);
192
+ this._buildReportConfig();
193
+ }
194
+ });
127
195
  });
128
196
  this._buildReportConfig();
129
197
  }
130
198
  toggleEditMode() {
131
- this.editMode = !this.editMode;
199
+ this.editMode.update((editMode) => !editMode);
132
200
  }
133
201
  // The edit tools live in this toolbar, but the canvas owns what they act on
134
202
  // (the active page, the header/footer bands, which layer is live).
@@ -144,12 +212,13 @@ export class FsAiReportComponent {
144
212
  // Report settings — name, page size, orientation, layout mode, delete. The
145
213
  // dialog performs the delete itself; we react to what it reports back.
146
214
  reportSettings() {
147
- if (!this.report) {
215
+ const report = this.report();
216
+ if (!report) {
148
217
  return;
149
218
  }
150
- const reportId = this.report.id;
219
+ const reportId = report.id;
151
220
  this._dialog.open(ReportSettingsComponent, {
152
- data: { report: this.report },
221
+ data: { report },
153
222
  width: '460px',
154
223
  })
155
224
  .afterClosed()
@@ -167,12 +236,13 @@ export class FsAiReportComponent {
167
236
  // Component settings — title, exact geometry, and the diagnostic views
168
237
  // (SQL, config, filter wiring).
169
238
  componentSettings(component) {
170
- if (!this.report) {
239
+ const report = this.report();
240
+ if (!report) {
171
241
  return;
172
242
  }
173
- const reportId = this.report.id;
243
+ const reportId = report.id;
174
244
  const dialogRef = this._dialog.open(ComponentSettingsComponent, {
175
- data: { report: this.report, component },
245
+ data: { report, component },
176
246
  width: '640px',
177
247
  });
178
248
  // Filter add/remove/level changes persist immediately inside the dialog (no
@@ -208,58 +278,58 @@ export class FsAiReportComponent {
208
278
  });
209
279
  }
210
280
  // The canvas moved to another page: reflect it in the URL so a refresh or a
211
- // shared link comes back here. replaceUrl keeps paging out of the browser
212
- // history — Back should leave the report, not walk every page visited.
281
+ // shared link comes back here (the write itself is _writeUrl's).
213
282
  onCanvasPageChanged(pageId) {
214
283
  // The deep link has been consumed; from here the canvas owns the page.
215
- this.pageId = null;
284
+ this.pageId.set(null);
216
285
  this.chatPageId.set(pageId);
286
+ this._pageReported = true;
217
287
  this.pageChanged.emit(pageId);
218
- const param = this.pageQueryParam();
219
- if (!param) {
220
- return;
221
- }
222
- this._router.navigate([], {
223
- relativeTo: this._route,
224
- queryParams: { [param]: pageId },
225
- queryParamsHandling: 'merge',
226
- replaceUrl: true,
227
- });
288
+ this._pageWrite$.next();
228
289
  }
229
290
  // The canvas changed the report's structure (added a page) — re-fetch so the
230
291
  // new page renders; the canvas lands the view on it.
231
292
  onCanvasReportChanged() {
232
- if (this.report) {
233
- this._loadReport(this.report.id);
293
+ const report = this.report();
294
+ if (report) {
295
+ this._loadReport(report.id);
234
296
  }
235
297
  }
236
298
  // Export the report to PowerPoint, entirely client-side (native editable
237
299
  // charts; page = slide). The dock shows progress until the file saves.
238
300
  exportPowerpoint() {
239
- if (!this.report) {
301
+ const report = this.report();
302
+ if (!report) {
240
303
  return;
241
304
  }
242
- this._process.run('Exporting PowerPoint', this._exportService.powerpoint(this.report));
305
+ this._process.run('Exporting PowerPoint', this._exportService.powerpoint(report));
243
306
  }
244
307
  // Export to PDF, entirely client-side (offscreen ECharts at 3×; page = PDF page).
245
308
  exportPdf() {
246
- if (!this.report) {
309
+ const report = this.report();
310
+ if (!report) {
247
311
  return;
248
312
  }
249
- this._process.run('Exporting PDF', this._exportService.pdf(this.report));
313
+ this._process.run('Exporting PDF', this._exportService.pdf(report));
250
314
  }
251
- // The raw data behind the whole report in one action: the server exports every
252
- // component's full filtered dataset and zips one CSV per component, foldered
253
- // by page. `thisPage` narrows it to the page the canvas is showing. Unlike the
254
- // PDF/PowerPoint exports this is entirely server-side — nothing is collected
255
- // in the browser, so it is not capped by what a slide can hold.
315
+ // The whole report as files in one action: the server writes one CSV per
316
+ // component, each what the screen shows (a chart or KPI as drawn, at the
317
+ // viewer's group-by grain; a list in full), and zips them foldered by page
318
+ // with an Export Notes.txt that records the filters as the bar reads them.
319
+ // Lists use their saved default sort; a header click is carried only by a
320
+ // component's own CSV export. `thisPage` narrows it to the page the canvas is
321
+ // showing. Unlike the PDF/PowerPoint exports the files are written
322
+ // server-side, so they are not capped by what a slide can hold.
256
323
  exportData(thisPage = false) {
257
- const report = this.report;
324
+ const report = this.report();
258
325
  if (!report) {
259
326
  return;
260
327
  }
261
328
  const pageId = thisPage ? this._canvas?.activePage?.id ?? null : null;
262
- this._process.download('Exporting data', this._reportData.exportReport(report.id, this._filterState.resolveForReport(report, pageId), pageId));
329
+ const filters = this._filterState.resolveForReport(report, pageId);
330
+ const frequency = this._filterState.frequency();
331
+ this._process.download('Exporting data', this._collector.getFilterSummary(report)
332
+ .pipe(switchMap((lines) => this._reportData.exportReport(report.id, filters, pageId, frequency, lines))));
263
333
  }
264
334
  // React to each chat turn (fs-chat handles the request + persistence); we
265
335
  // only care about the report side effects this context's backend flags.
@@ -297,6 +367,16 @@ export class FsAiReportComponent {
297
367
  handle.addEventListener('pointercancel', end);
298
368
  });
299
369
  }
370
+ // What the viewer has on screen as a chat turn sends it. The canvas
371
+ // selection counts only in edit mode: it is drawn only then, and it is kept
372
+ // (not cleared) when edit mode is left.
373
+ _chatViewerState() {
374
+ return {
375
+ granularity: this._filterState.frequency(),
376
+ selectedComponentId: this.editMode() ? this._canvas?.selectedComponentId() ?? null : null,
377
+ filters: this._filterState.viewerFilters(),
378
+ };
379
+ }
300
380
  _resizeTo(clientX) {
301
381
  const rect = this._split.nativeElement.getBoundingClientRect();
302
382
  if (rect.width === 0) {
@@ -316,50 +396,67 @@ export class FsAiReportComponent {
316
396
  const pageId = Number(this._route.snapshot.queryParamMap.get(param));
317
397
  return Number.isFinite(pageId) && pageId > 0 ? pageId : null;
318
398
  }
399
+ // Writes the open page and the viewer state into the URL in one go. Only
400
+ // the keys this view owns are touched ('merge'), and replaceUrl keeps the
401
+ // writes out of the browser history: Back leaves the report rather than
402
+ // walking every page and filter visited.
403
+ _writeUrl() {
404
+ const report = this.report();
405
+ // A report still on screen while the host's next one loads must not write
406
+ // its state over the new report's URL.
407
+ if (!report || report.id !== this.reportId()) {
408
+ return;
409
+ }
410
+ const queryParams = this.urlState()
411
+ ? buildReportUrlParams(this._filterState.urlSnapshot(report), this._route.snapshot.queryParamMap)
412
+ : {};
413
+ const pageParam = this.pageQueryParam();
414
+ if (pageParam && this._pageReported) {
415
+ queryParams[pageParam] = this.chatPageId();
416
+ }
417
+ if (!Object.keys(queryParams).length) {
418
+ return;
419
+ }
420
+ this._router.navigate([], {
421
+ relativeTo: this._route,
422
+ queryParams,
423
+ queryParamsHandling: 'merge',
424
+ replaceUrl: true,
425
+ });
426
+ }
319
427
  _loadReport(reportId, emitRenamed = false) {
320
428
  this._reportData.get(reportId)
321
429
  .pipe(takeUntilDestroyed(this._destroyRef))
322
430
  .subscribe((report) => {
323
- this.report = report;
324
- this._filterState.init(report);
431
+ // The URL is read once per report, on its first load; every later load
432
+ // keeps the state in memory.
433
+ const restore = this.urlState() && reportId !== this._restoredReportId
434
+ ? readReportUrlParams(this._route.snapshot.queryParamMap)
435
+ : null;
436
+ this._restoredReportId = reportId;
437
+ this.report.set(report);
438
+ this._filterState.init(report, restore);
325
439
  this._buildReportConfig();
326
440
  if (emitRenamed) {
327
441
  this.renamed.emit(report);
328
442
  }
329
- this._cdRef.markForCheck();
330
443
  });
331
444
  }
332
445
  // Report-level filter groups in their saved order — the ones that render in
333
446
  // the toolbar (component-level groups render on their components).
334
447
  _reportGroups() {
335
- return (this.report?.filterGroups ?? [])
448
+ return (this.report()?.filterGroups ?? [])
336
449
  .filter((group) => group.level === 'report' || group.level === 'both')
337
450
  .sort((a, b) => a.order - b.order);
338
451
  }
339
- // Gates the toolbar fs-filter so it isn't rendered when there is nothing to
340
- // put in it — no report-level filters and no group-by control.
341
- get reportHasFilters() {
342
- return this._reportGroups().length > 0 || !!this._groupByItem();
343
- }
344
- // fs-filter reads its config only once (at init). The template keys the
345
- // toolbar fs-filter on this signature so it's recreated (and re-reads the
346
- // rebuilt config) whenever the report-level filter set changes.
347
- get reportFilterKey() {
348
- return [
349
- // The stored default is part of the signature: saving a new default in report
350
- // settings rebuilds the config, but without a key change fs-filter keeps
351
- // rendering the values it was created with until a full page reload.
352
- groupBySignature(this.report),
353
- ...this._reportGroups().map((group) => `${group.id}:${group.level}:${group.label}:${defaultSignature(group)}`),
354
- ].join('|');
355
- }
356
452
  // (Re)build the toolbar fs-filter config — the report-level filter items and
357
453
  // then the group-by control.
358
454
  _buildReportConfig() {
359
- const reportId = this.report?.id ?? null;
455
+ const report = this.report();
456
+ const reportId = report?.id ?? null;
360
457
  // Drop a grain the control no longer offers — the agent can narrow the list
361
458
  // mid-session, and an override the viewer can't see is worse than none.
362
- if (this.report && !isGranularityOffered(this.report, this._filterState.frequency())) {
459
+ if (report && !isGranularityOffered(report, this._filterState.frequency())) {
363
460
  this._filterState.setFrequency(null);
364
461
  }
365
462
  const items = reportId
@@ -373,9 +470,11 @@ export class FsAiReportComponent {
373
470
  if (groupByItem) {
374
471
  items.unshift(groupByItem);
375
472
  }
376
- this.reportFilterConfig = {
377
- // Never touch the URL or persist filter state — report filters are
378
- // session-only, owned by ReportFilterStateService.
473
+ this.reportFilterConfig.set({
474
+ // fs-filter never touches the URL or persists filter state: its keys are
475
+ // not namespaced, it writes outside the router, and it would freeze a
476
+ // rolling range as two dates. ReportFilterStateService owns the values,
477
+ // and _writeUrl is the one writer of the URL.
379
478
  queryParam: false,
380
479
  persist: false,
381
480
  items,
@@ -386,18 +485,19 @@ export class FsAiReportComponent {
386
485
  // Not a filter group — the grain is read straight off the query.
387
486
  this._filterState.setFrequency(query?.[GROUP_BY_ITEM] || null);
388
487
  },
389
- };
488
+ });
390
489
  }
391
490
  // The report's group-by control as an fs-filter item, or null when the report
392
491
  // has none to show. Seeded from the session state so the grain the viewer
393
492
  // picked survives the report being re-fetched after a chat edit.
394
493
  _groupByItem() {
395
- return this.report
396
- ? groupByFilterItem(this.report, this._filterState.frequency())
494
+ const report = this.report();
495
+ return report
496
+ ? groupByFilterItem(report, this._filterState.frequency())
397
497
  : null;
398
498
  }
399
499
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FsAiReportComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
400
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: FsAiReportComponent, isStandalone: true, selector: "fs-ai-report", inputs: { reportId: { classPropertyName: "reportId", publicName: "reportId", isSignal: true, isRequired: false, transformFunction: null }, basePath: { classPropertyName: "basePath", publicName: "basePath", isSignal: true, isRequired: false, transformFunction: null }, pageQueryParam: { classPropertyName: "pageQueryParam", publicName: "pageQueryParam", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { deleted: "deleted", renamed: "renamed", pageChanged: "pageChanged" }, providers: [
500
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: FsAiReportComponent, isStandalone: true, selector: "fs-ai-report", inputs: { reportId: { classPropertyName: "reportId", publicName: "reportId", isSignal: true, isRequired: false, transformFunction: null }, basePath: { classPropertyName: "basePath", publicName: "basePath", isSignal: true, isRequired: false, transformFunction: null }, pageQueryParam: { classPropertyName: "pageQueryParam", publicName: "pageQueryParam", isSignal: true, isRequired: false, transformFunction: null }, urlState: { classPropertyName: "urlState", publicName: "urlState", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { deleted: "deleted", renamed: "renamed", pageChanged: "pageChanged" }, providers: [
401
501
  // Session filter state is per-open-report, not app-global; the export
402
502
  // services resolve filters through it, so they live at the same level.
403
503
  ReportFilterStateService,
@@ -405,9 +505,13 @@ export class FsAiReportComponent {
405
505
  ReportPptxService,
406
506
  ReportPdfService,
407
507
  ReportExportService,
508
+ // fs-ai-chat sits in this template, so it resolves its gateway here: the
509
+ // report one, which adds the viewer's state to each turn it sends.
510
+ ReportAiChatData,
511
+ { provide: FsAiChatData, useExisting: ReportAiChatData },
408
512
  // Tree-shaken ECharts core + the 'report' house theme, loaded lazily.
409
513
  provideEchartsCore({ echarts: () => import('../../theme/echarts').then((module) => module.default) }),
410
- ], viewQueries: [{ propertyName: "_split", first: true, predicate: ["split"], descendants: true, static: true }, { propertyName: "_chatPanel", first: true, predicate: ["chatPanel"], descendants: true, read: ElementRef, static: true }, { propertyName: "_canvas", first: true, predicate: ReportCanvasComponent, descendants: true }], ngImport: i0, template: "<div class=\"fs-ai-report fs-column\">\n\n <div class=\"fs-ai-report__header fs-row.align-center\">\n <h2 class=\"fs-ai-report__title fs-flex\">{{ report?.name }}</h2>\n\n @if (report) {\n <!-- Report-level filters, inline with the toolbar actions. fs-filter\n reads its config once at init, so it's keyed on the filter\n signature: when the report-level filter set changes the block is\n recreated and re-reads the rebuilt config. -->\n @if (reportHasFilters) {\n @for (key of [reportFilterKey]; track key) {\n <fs-filter\n class=\"fs-ai-report__filters\"\n [config]=\"reportFilterConfig\">\n </fs-filter>\n }\n }\n\n <!-- What layout editing can add or switch to, and the way out of it.\n One style for all three \u2014 outlined, icon and text. \"Header & footer\"\n is a toggle: it keeps its label and turns gray while it is on. -->\n @if (editMode) {\n <div class=\"fs-ai-report__edit-tools fs-row.align-center.gap-xs\">\n <button\n mat-stroked-button\n type=\"button\"\n matTooltip=\"Add a block of text\"\n (click)=\"addText()\">\n <mat-icon>title</mat-icon>\n Add text\n </button>\n <button\n mat-stroked-button\n type=\"button\"\n class=\"fs-ai-report__master\"\n [class.active]=\"isMasterMode\"\n [matTooltip]=\"isMasterMode ? 'Back to editing this page' : 'Edit the header and footer shown on every page'\"\n (click)=\"toggleMasterMode()\">\n <mat-icon>web_asset</mat-icon>\n Header & footer\n </button>\n <button\n mat-stroked-button\n type=\"button\"\n (click)=\"toggleEditMode()\">\n <mat-icon>check</mat-icon>\n Done editing\n </button>\n </div>\n }\n\n <!-- One icon for both states: it reads as pressed while editing rather\n than swapping to something else. -->\n <button\n mat-icon-button\n type=\"button\"\n class=\"fs-ai-report__toggle\"\n [class.active]=\"editMode\"\n [matTooltip]=\"editMode ? 'Done editing' : 'Edit layout'\"\n (click)=\"toggleEditMode()\">\n <mat-icon>dashboard_customize</mat-icon>\n </button>\n\n <button\n mat-icon-button\n type=\"button\"\n matTooltip=\"Export\"\n [fsMenuTriggerFor]=\"exportMenu\">\n <mat-icon>download</mat-icon>\n </button>\n <fs-menu #exportMenu>\n <ng-template\n fs-menu-item\n (click)=\"exportPowerpoint()\">\n Export PowerPoint\n </ng-template>\n <ng-template\n fs-menu-item\n (click)=\"exportPdf()\">\n Export PDF\n </ng-template>\n <ng-template\n fs-menu-item\n (click)=\"exportData()\">\n Export Raw Data\n </ng-template>\n @if ((report?.pages?.length ?? 0) > 1) {\n <ng-template\n fs-menu-item\n (click)=\"exportData(true)\">\n Export Raw Data (This Page)\n </ng-template>\n }\n </fs-menu>\n\n <button\n mat-icon-button\n type=\"button\"\n matTooltip=\"Report settings\"\n (click)=\"reportSettings()\">\n <mat-icon>settings</mat-icon>\n </button>\n }\n </div>\n\n <div\n #split\n class=\"fs-ai-report__split fs-row.align-start\">\n <fs-ai-chat\n #chatPanel\n class=\"chat\"\n [basePath]=\"basePath()\"\n [requestData]=\"chatRequestData()\"\n [ready]=\"chatPageId() !== null\"\n (response)=\"onChatResponse($event)\">\n </fs-ai-chat>\n\n <div\n class=\"resizer\"\n (pointerdown)=\"onResizeStart($event)\">\n </div>\n\n <div class=\"viewer fs-flex fs-column\">\n @if (report) {\n <app-report-canvas\n [report]=\"report\"\n [editMode]=\"editMode\"\n [pageId]=\"pageId\"\n (componentSettings)=\"componentSettings($event)\"\n (reportChanged)=\"onCanvasReportChanged()\"\n (pageChanged)=\"onCanvasPageChanged($event)\">\n </app-report-canvas>\n }\n </div>\n </div>\n</div>\n", styles: [".fs-ai-report{height:100%;min-height:500px;display:flex;flex-direction:column}.fs-ai-report__header{flex:0 0 auto;margin-bottom:10px}.fs-ai-report__title{margin:0;min-width:120px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.fs-ai-report__filters{flex:0 1 auto;min-width:0;display:block;margin:0 5px 0 0}.fs-ai-report__filters ::ng-deep .filter-bar-container{align-items:center!important}.fs-ai-report__filters ::ng-deep .mat-mdc-form-field-subscript-wrapper{display:none}.fs-ai-report__toggle.active{background:#e3ecf7;color:var(--brand-primary-color, #2196f3)}.fs-ai-report__master.active{background:#eceff3}.fs-ai-report__edit-tools{margin:0 5px}.fs-ai-report__split{flex:1 1 auto;min-height:0}.fs-ai-report .chat{display:block;flex:0 0 25%;width:100%;height:100%;min-height:400px;min-width:0;border:none}.fs-ai-report .viewer{display:flex;flex-direction:column;min-width:0;height:100%;overflow:hidden}.fs-ai-report .resizer{flex:0 0 11px;align-self:stretch;display:flex;justify-content:center;cursor:col-resize;touch-action:none;-webkit-user-select:none;user-select:none}.fs-ai-report .resizer:before{content:\"\";width:3px;border-radius:3px;background:transparent;transition:background-color .12s ease}.fs-ai-report .resizer:hover:before{background:var(--brand-primary-color)}.fs-ai-report__split.resizing{cursor:col-resize;-webkit-user-select:none;user-select:none}.fs-ai-report__split.resizing .resizer:before{background:var(--brand-primary-color)}.fs-ai-report__split.resizing .chat,.fs-ai-report__split.resizing .viewer{pointer-events:none}\n"], dependencies: [{ kind: "ngmodule", type: FsFilterModule }, { kind: "component", type: i1.FilterComponent, selector: "fs-filter", inputs: ["config"], outputs: ["closed", "opened", "ready"] }, { kind: "ngmodule", type: FsMenuModule }, { kind: "component", type: i2.FsMenuComponent, selector: "fs-menu", inputs: ["class", "buttonClass", "buttonType", "buttonColor"], outputs: ["opened", "closed"] }, { kind: "directive", type: i2.FsMenuItemDirective, selector: "fs-menu-group,[fs-menu-item]" }, { kind: "directive", type: i2.FsMenuTriggerDirective, selector: "[fsMenuTriggerFor]", inputs: ["fsMenuTriggerFor"] }, { kind: "component", type: FsAiChatComponent, selector: "fs-ai-chat", inputs: ["basePath", "requestData", "ready", "introMessage", "showThinking"], outputs: ["response", "showThinkingChange"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i3.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }, { kind: "component", type: i3.MatIconButton, selector: "button[mat-icon-button]", exportAs: ["matButton"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i4.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i5.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "component", type: ReportCanvasComponent, selector: "app-report-canvas", inputs: ["report", "editMode", "pageId"], outputs: ["componentSettings", "reportChanged", "pageChanged"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
514
+ ], viewQueries: [{ propertyName: "_split", first: true, predicate: ["split"], descendants: true, static: true }, { propertyName: "_chatPanel", first: true, predicate: ["chatPanel"], descendants: true, read: ElementRef, static: true }, { propertyName: "_canvas", first: true, predicate: ReportCanvasComponent, descendants: true }], ngImport: i0, template: "<div class=\"fs-ai-report fs-column\">\n\n <div class=\"fs-ai-report__header fs-row.align-center\">\n <h2 class=\"fs-ai-report__title fs-flex\">{{ report()?.name }}</h2>\n\n @if (report()) {\n <!-- Report-level filters, inline with the toolbar actions. fs-filter\n reads its config once at init, so it's keyed on the filter\n signature: when the report-level filter set changes the block is\n recreated and re-reads the rebuilt config. -->\n @if (reportHasFilters()) {\n @for (key of [reportFilterKey()]; track key) {\n <fs-filter\n class=\"fs-ai-report__filters\"\n [config]=\"reportFilterConfig()\">\n </fs-filter>\n }\n }\n\n <!-- What layout editing can add or switch to, and the way out of it.\n One style for all three \u2014 outlined, icon and text. \"Header & footer\"\n is a toggle: it keeps its label and turns gray while it is on. -->\n @if (editMode()) {\n <div class=\"fs-ai-report__edit-tools fs-row.align-center.gap-xs\">\n <button\n mat-stroked-button\n type=\"button\"\n matTooltip=\"Add a block of text\"\n (click)=\"addText()\">\n <mat-icon>title</mat-icon>\n Add text\n </button>\n <button\n mat-stroked-button\n type=\"button\"\n class=\"fs-ai-report__master\"\n [class.active]=\"isMasterMode\"\n [matTooltip]=\"isMasterMode ? 'Back to editing this page' : 'Edit the header and footer shown on every page'\"\n (click)=\"toggleMasterMode()\">\n <mat-icon>web_asset</mat-icon>\n Header & footer\n </button>\n <button\n mat-stroked-button\n type=\"button\"\n (click)=\"toggleEditMode()\">\n <mat-icon>check</mat-icon>\n Done editing\n </button>\n </div>\n }\n\n <!-- The zone every date in this report is filtered and grouped in, the\n same for every viewer. Shown only when the server sends it; a click\n opens Report settings, where it is changed. -->\n @if (report()?.effectiveTimezone; as effectiveTimezone) {\n <button\n mat-button\n type=\"button\"\n class=\"fs-ai-report__timezone\"\n [matTooltip]=\"'Dates are filtered and grouped in ' + effectiveTimezone + ' for everyone. Change it in Report settings.'\"\n (click)=\"reportSettings()\">\n <mat-icon>schedule</mat-icon>\n {{ timezoneLabel() }}\n </button>\n }\n\n <!-- One icon for both states: it reads as pressed while editing rather\n than swapping to something else. -->\n <button\n mat-icon-button\n type=\"button\"\n class=\"fs-ai-report__toggle\"\n [class.active]=\"editMode()\"\n [matTooltip]=\"editMode() ? 'Done editing' : 'Edit layout'\"\n (click)=\"toggleEditMode()\">\n <mat-icon>dashboard_customize</mat-icon>\n </button>\n\n <button\n mat-icon-button\n type=\"button\"\n matTooltip=\"Export\"\n [fsMenuTriggerFor]=\"exportMenu\">\n <mat-icon>download</mat-icon>\n </button>\n <fs-menu #exportMenu>\n <ng-template\n fs-menu-item\n (click)=\"exportPowerpoint()\">\n Export PowerPoint\n </ng-template>\n <ng-template\n fs-menu-item\n (click)=\"exportPdf()\">\n Export PDF\n </ng-template>\n <ng-template\n fs-menu-item\n (click)=\"exportData()\">\n Export Raw Data\n </ng-template>\n @if ((report()?.pages?.length ?? 0) > 1) {\n <ng-template\n fs-menu-item\n (click)=\"exportData(true)\">\n Export Raw Data (This Page)\n </ng-template>\n }\n </fs-menu>\n\n <button\n mat-icon-button\n type=\"button\"\n matTooltip=\"Report settings\"\n (click)=\"reportSettings()\">\n <mat-icon>settings</mat-icon>\n </button>\n }\n </div>\n\n <div\n #split\n class=\"fs-ai-report__split fs-row.align-start\">\n <fs-ai-chat\n #chatPanel\n class=\"chat\"\n [basePath]=\"basePath()\"\n [requestData]=\"chatRequestData()\"\n [ready]=\"chatPageId() !== null\"\n (response)=\"onChatResponse($event)\">\n </fs-ai-chat>\n\n <div\n class=\"resizer\"\n (pointerdown)=\"onResizeStart($event)\">\n </div>\n\n <div class=\"viewer fs-flex fs-column\">\n @if (report()) {\n <app-report-canvas\n [report]=\"report()\"\n [editMode]=\"editMode()\"\n [pageId]=\"pageId()\"\n (componentSettings)=\"componentSettings($event)\"\n (reportChanged)=\"onCanvasReportChanged()\"\n (pageChanged)=\"onCanvasPageChanged($event)\">\n </app-report-canvas>\n }\n </div>\n </div>\n</div>\n", styles: [".fs-ai-report{height:100%;min-height:500px;display:flex;flex-direction:column}.fs-ai-report__header{flex:0 0 auto;margin-bottom:10px}.fs-ai-report__title{margin:0;min-width:120px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.fs-ai-report__filters{flex:0 1 auto;min-width:0;display:block;margin:0 5px 0 0}.fs-ai-report__filters ::ng-deep .filter-bar-container{align-items:center!important}.fs-ai-report__filters ::ng-deep .mat-mdc-form-field-subscript-wrapper{display:none}.fs-ai-report__timezone{--mat-button-text-label-text-color: var(--fs-color-text-muted, light-dark(rgba(0, 0, 0, .54), rgba(255, 255, 255, .6)));color:var(--fs-color-text-muted, light-dark(rgba(0, 0, 0, .54), rgba(255, 255, 255, .6)));white-space:nowrap;flex:0 0 auto}.fs-ai-report__toggle.active{background:#e3ecf7;color:var(--brand-primary-color, #2196f3)}.fs-ai-report__master.active{background:#eceff3}.fs-ai-report__edit-tools{margin:0 5px}.fs-ai-report__split{flex:1 1 auto;min-height:0}.fs-ai-report .chat{display:block;flex:0 0 25%;width:100%;height:100%;min-height:400px;min-width:0;border:none}.fs-ai-report .viewer{display:flex;flex-direction:column;min-width:0;height:100%;overflow:hidden}.fs-ai-report .resizer{flex:0 0 11px;align-self:stretch;display:flex;justify-content:center;cursor:col-resize;touch-action:none;-webkit-user-select:none;user-select:none}.fs-ai-report .resizer:before{content:\"\";width:3px;border-radius:3px;background:transparent;transition:background-color .12s ease}.fs-ai-report .resizer:hover:before{background:var(--brand-primary-color)}.fs-ai-report__split.resizing{cursor:col-resize;-webkit-user-select:none;user-select:none}.fs-ai-report__split.resizing .resizer:before{background:var(--brand-primary-color)}.fs-ai-report__split.resizing .chat,.fs-ai-report__split.resizing .viewer{pointer-events:none}\n"], dependencies: [{ kind: "ngmodule", type: FsFilterModule }, { kind: "component", type: i1.FilterComponent, selector: "fs-filter", inputs: ["config"], outputs: ["closed", "opened", "ready"] }, { kind: "ngmodule", type: FsMenuModule }, { kind: "component", type: i2.FsMenuComponent, selector: "fs-menu", inputs: ["class", "buttonClass", "buttonType", "buttonColor"], outputs: ["opened", "closed"] }, { kind: "directive", type: i2.FsMenuItemDirective, selector: "fs-menu-group,[fs-menu-item]" }, { kind: "directive", type: i2.FsMenuTriggerDirective, selector: "[fsMenuTriggerFor]", inputs: ["fsMenuTriggerFor"] }, { kind: "component", type: FsAiChatComponent, selector: "fs-ai-chat", inputs: ["basePath", "requestData", "ready", "introMessage", "showThinking"], outputs: ["response", "showThinkingChange"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i3.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }, { kind: "component", type: i3.MatIconButton, selector: "button[mat-icon-button]", exportAs: ["matButton"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i4.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i5.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "component", type: ReportCanvasComponent, selector: "app-report-canvas", inputs: ["report", "editMode", "pageId"], outputs: ["componentSettings", "reportChanged", "pageChanged"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
411
515
  }
412
516
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FsAiReportComponent, decorators: [{
413
517
  type: Component,
@@ -419,6 +523,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
419
523
  ReportPptxService,
420
524
  ReportPdfService,
421
525
  ReportExportService,
526
+ // fs-ai-chat sits in this template, so it resolves its gateway here: the
527
+ // report one, which adds the viewer's state to each turn it sends.
528
+ ReportAiChatData,
529
+ { provide: FsAiChatData, useExisting: ReportAiChatData },
422
530
  // Tree-shaken ECharts core + the 'report' house theme, loaded lazily.
423
531
  provideEchartsCore({ echarts: () => import('../../theme/echarts').then((module) => module.default) }),
424
532
  ], imports: [
@@ -429,7 +537,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
429
537
  MatIconModule,
430
538
  MatTooltipModule,
431
539
  ReportCanvasComponent,
432
- ], template: "<div class=\"fs-ai-report fs-column\">\n\n <div class=\"fs-ai-report__header fs-row.align-center\">\n <h2 class=\"fs-ai-report__title fs-flex\">{{ report?.name }}</h2>\n\n @if (report) {\n <!-- Report-level filters, inline with the toolbar actions. fs-filter\n reads its config once at init, so it's keyed on the filter\n signature: when the report-level filter set changes the block is\n recreated and re-reads the rebuilt config. -->\n @if (reportHasFilters) {\n @for (key of [reportFilterKey]; track key) {\n <fs-filter\n class=\"fs-ai-report__filters\"\n [config]=\"reportFilterConfig\">\n </fs-filter>\n }\n }\n\n <!-- What layout editing can add or switch to, and the way out of it.\n One style for all three \u2014 outlined, icon and text. \"Header & footer\"\n is a toggle: it keeps its label and turns gray while it is on. -->\n @if (editMode) {\n <div class=\"fs-ai-report__edit-tools fs-row.align-center.gap-xs\">\n <button\n mat-stroked-button\n type=\"button\"\n matTooltip=\"Add a block of text\"\n (click)=\"addText()\">\n <mat-icon>title</mat-icon>\n Add text\n </button>\n <button\n mat-stroked-button\n type=\"button\"\n class=\"fs-ai-report__master\"\n [class.active]=\"isMasterMode\"\n [matTooltip]=\"isMasterMode ? 'Back to editing this page' : 'Edit the header and footer shown on every page'\"\n (click)=\"toggleMasterMode()\">\n <mat-icon>web_asset</mat-icon>\n Header & footer\n </button>\n <button\n mat-stroked-button\n type=\"button\"\n (click)=\"toggleEditMode()\">\n <mat-icon>check</mat-icon>\n Done editing\n </button>\n </div>\n }\n\n <!-- One icon for both states: it reads as pressed while editing rather\n than swapping to something else. -->\n <button\n mat-icon-button\n type=\"button\"\n class=\"fs-ai-report__toggle\"\n [class.active]=\"editMode\"\n [matTooltip]=\"editMode ? 'Done editing' : 'Edit layout'\"\n (click)=\"toggleEditMode()\">\n <mat-icon>dashboard_customize</mat-icon>\n </button>\n\n <button\n mat-icon-button\n type=\"button\"\n matTooltip=\"Export\"\n [fsMenuTriggerFor]=\"exportMenu\">\n <mat-icon>download</mat-icon>\n </button>\n <fs-menu #exportMenu>\n <ng-template\n fs-menu-item\n (click)=\"exportPowerpoint()\">\n Export PowerPoint\n </ng-template>\n <ng-template\n fs-menu-item\n (click)=\"exportPdf()\">\n Export PDF\n </ng-template>\n <ng-template\n fs-menu-item\n (click)=\"exportData()\">\n Export Raw Data\n </ng-template>\n @if ((report?.pages?.length ?? 0) > 1) {\n <ng-template\n fs-menu-item\n (click)=\"exportData(true)\">\n Export Raw Data (This Page)\n </ng-template>\n }\n </fs-menu>\n\n <button\n mat-icon-button\n type=\"button\"\n matTooltip=\"Report settings\"\n (click)=\"reportSettings()\">\n <mat-icon>settings</mat-icon>\n </button>\n }\n </div>\n\n <div\n #split\n class=\"fs-ai-report__split fs-row.align-start\">\n <fs-ai-chat\n #chatPanel\n class=\"chat\"\n [basePath]=\"basePath()\"\n [requestData]=\"chatRequestData()\"\n [ready]=\"chatPageId() !== null\"\n (response)=\"onChatResponse($event)\">\n </fs-ai-chat>\n\n <div\n class=\"resizer\"\n (pointerdown)=\"onResizeStart($event)\">\n </div>\n\n <div class=\"viewer fs-flex fs-column\">\n @if (report) {\n <app-report-canvas\n [report]=\"report\"\n [editMode]=\"editMode\"\n [pageId]=\"pageId\"\n (componentSettings)=\"componentSettings($event)\"\n (reportChanged)=\"onCanvasReportChanged()\"\n (pageChanged)=\"onCanvasPageChanged($event)\">\n </app-report-canvas>\n }\n </div>\n </div>\n</div>\n", styles: [".fs-ai-report{height:100%;min-height:500px;display:flex;flex-direction:column}.fs-ai-report__header{flex:0 0 auto;margin-bottom:10px}.fs-ai-report__title{margin:0;min-width:120px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.fs-ai-report__filters{flex:0 1 auto;min-width:0;display:block;margin:0 5px 0 0}.fs-ai-report__filters ::ng-deep .filter-bar-container{align-items:center!important}.fs-ai-report__filters ::ng-deep .mat-mdc-form-field-subscript-wrapper{display:none}.fs-ai-report__toggle.active{background:#e3ecf7;color:var(--brand-primary-color, #2196f3)}.fs-ai-report__master.active{background:#eceff3}.fs-ai-report__edit-tools{margin:0 5px}.fs-ai-report__split{flex:1 1 auto;min-height:0}.fs-ai-report .chat{display:block;flex:0 0 25%;width:100%;height:100%;min-height:400px;min-width:0;border:none}.fs-ai-report .viewer{display:flex;flex-direction:column;min-width:0;height:100%;overflow:hidden}.fs-ai-report .resizer{flex:0 0 11px;align-self:stretch;display:flex;justify-content:center;cursor:col-resize;touch-action:none;-webkit-user-select:none;user-select:none}.fs-ai-report .resizer:before{content:\"\";width:3px;border-radius:3px;background:transparent;transition:background-color .12s ease}.fs-ai-report .resizer:hover:before{background:var(--brand-primary-color)}.fs-ai-report__split.resizing{cursor:col-resize;-webkit-user-select:none;user-select:none}.fs-ai-report__split.resizing .resizer:before{background:var(--brand-primary-color)}.fs-ai-report__split.resizing .chat,.fs-ai-report__split.resizing .viewer{pointer-events:none}\n"] }]
540
+ ], template: "<div class=\"fs-ai-report fs-column\">\n\n <div class=\"fs-ai-report__header fs-row.align-center\">\n <h2 class=\"fs-ai-report__title fs-flex\">{{ report()?.name }}</h2>\n\n @if (report()) {\n <!-- Report-level filters, inline with the toolbar actions. fs-filter\n reads its config once at init, so it's keyed on the filter\n signature: when the report-level filter set changes the block is\n recreated and re-reads the rebuilt config. -->\n @if (reportHasFilters()) {\n @for (key of [reportFilterKey()]; track key) {\n <fs-filter\n class=\"fs-ai-report__filters\"\n [config]=\"reportFilterConfig()\">\n </fs-filter>\n }\n }\n\n <!-- What layout editing can add or switch to, and the way out of it.\n One style for all three \u2014 outlined, icon and text. \"Header & footer\"\n is a toggle: it keeps its label and turns gray while it is on. -->\n @if (editMode()) {\n <div class=\"fs-ai-report__edit-tools fs-row.align-center.gap-xs\">\n <button\n mat-stroked-button\n type=\"button\"\n matTooltip=\"Add a block of text\"\n (click)=\"addText()\">\n <mat-icon>title</mat-icon>\n Add text\n </button>\n <button\n mat-stroked-button\n type=\"button\"\n class=\"fs-ai-report__master\"\n [class.active]=\"isMasterMode\"\n [matTooltip]=\"isMasterMode ? 'Back to editing this page' : 'Edit the header and footer shown on every page'\"\n (click)=\"toggleMasterMode()\">\n <mat-icon>web_asset</mat-icon>\n Header & footer\n </button>\n <button\n mat-stroked-button\n type=\"button\"\n (click)=\"toggleEditMode()\">\n <mat-icon>check</mat-icon>\n Done editing\n </button>\n </div>\n }\n\n <!-- The zone every date in this report is filtered and grouped in, the\n same for every viewer. Shown only when the server sends it; a click\n opens Report settings, where it is changed. -->\n @if (report()?.effectiveTimezone; as effectiveTimezone) {\n <button\n mat-button\n type=\"button\"\n class=\"fs-ai-report__timezone\"\n [matTooltip]=\"'Dates are filtered and grouped in ' + effectiveTimezone + ' for everyone. Change it in Report settings.'\"\n (click)=\"reportSettings()\">\n <mat-icon>schedule</mat-icon>\n {{ timezoneLabel() }}\n </button>\n }\n\n <!-- One icon for both states: it reads as pressed while editing rather\n than swapping to something else. -->\n <button\n mat-icon-button\n type=\"button\"\n class=\"fs-ai-report__toggle\"\n [class.active]=\"editMode()\"\n [matTooltip]=\"editMode() ? 'Done editing' : 'Edit layout'\"\n (click)=\"toggleEditMode()\">\n <mat-icon>dashboard_customize</mat-icon>\n </button>\n\n <button\n mat-icon-button\n type=\"button\"\n matTooltip=\"Export\"\n [fsMenuTriggerFor]=\"exportMenu\">\n <mat-icon>download</mat-icon>\n </button>\n <fs-menu #exportMenu>\n <ng-template\n fs-menu-item\n (click)=\"exportPowerpoint()\">\n Export PowerPoint\n </ng-template>\n <ng-template\n fs-menu-item\n (click)=\"exportPdf()\">\n Export PDF\n </ng-template>\n <ng-template\n fs-menu-item\n (click)=\"exportData()\">\n Export Raw Data\n </ng-template>\n @if ((report()?.pages?.length ?? 0) > 1) {\n <ng-template\n fs-menu-item\n (click)=\"exportData(true)\">\n Export Raw Data (This Page)\n </ng-template>\n }\n </fs-menu>\n\n <button\n mat-icon-button\n type=\"button\"\n matTooltip=\"Report settings\"\n (click)=\"reportSettings()\">\n <mat-icon>settings</mat-icon>\n </button>\n }\n </div>\n\n <div\n #split\n class=\"fs-ai-report__split fs-row.align-start\">\n <fs-ai-chat\n #chatPanel\n class=\"chat\"\n [basePath]=\"basePath()\"\n [requestData]=\"chatRequestData()\"\n [ready]=\"chatPageId() !== null\"\n (response)=\"onChatResponse($event)\">\n </fs-ai-chat>\n\n <div\n class=\"resizer\"\n (pointerdown)=\"onResizeStart($event)\">\n </div>\n\n <div class=\"viewer fs-flex fs-column\">\n @if (report()) {\n <app-report-canvas\n [report]=\"report()\"\n [editMode]=\"editMode()\"\n [pageId]=\"pageId()\"\n (componentSettings)=\"componentSettings($event)\"\n (reportChanged)=\"onCanvasReportChanged()\"\n (pageChanged)=\"onCanvasPageChanged($event)\">\n </app-report-canvas>\n }\n </div>\n </div>\n</div>\n", styles: [".fs-ai-report{height:100%;min-height:500px;display:flex;flex-direction:column}.fs-ai-report__header{flex:0 0 auto;margin-bottom:10px}.fs-ai-report__title{margin:0;min-width:120px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.fs-ai-report__filters{flex:0 1 auto;min-width:0;display:block;margin:0 5px 0 0}.fs-ai-report__filters ::ng-deep .filter-bar-container{align-items:center!important}.fs-ai-report__filters ::ng-deep .mat-mdc-form-field-subscript-wrapper{display:none}.fs-ai-report__timezone{--mat-button-text-label-text-color: var(--fs-color-text-muted, light-dark(rgba(0, 0, 0, .54), rgba(255, 255, 255, .6)));color:var(--fs-color-text-muted, light-dark(rgba(0, 0, 0, .54), rgba(255, 255, 255, .6)));white-space:nowrap;flex:0 0 auto}.fs-ai-report__toggle.active{background:#e3ecf7;color:var(--brand-primary-color, #2196f3)}.fs-ai-report__master.active{background:#eceff3}.fs-ai-report__edit-tools{margin:0 5px}.fs-ai-report__split{flex:1 1 auto;min-height:0}.fs-ai-report .chat{display:block;flex:0 0 25%;width:100%;height:100%;min-height:400px;min-width:0;border:none}.fs-ai-report .viewer{display:flex;flex-direction:column;min-width:0;height:100%;overflow:hidden}.fs-ai-report .resizer{flex:0 0 11px;align-self:stretch;display:flex;justify-content:center;cursor:col-resize;touch-action:none;-webkit-user-select:none;user-select:none}.fs-ai-report .resizer:before{content:\"\";width:3px;border-radius:3px;background:transparent;transition:background-color .12s ease}.fs-ai-report .resizer:hover:before{background:var(--brand-primary-color)}.fs-ai-report__split.resizing{cursor:col-resize;-webkit-user-select:none;user-select:none}.fs-ai-report__split.resizing .resizer:before{background:var(--brand-primary-color)}.fs-ai-report__split.resizing .chat,.fs-ai-report__split.resizing .viewer{pointer-events:none}\n"] }]
433
541
  }], ctorParameters: () => [], propDecorators: { _split: [{
434
542
  type: ViewChild,
435
543
  args: ['split', { static: true }]
@@ -440,4 +548,4 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
440
548
  type: ViewChild,
441
549
  args: [ReportCanvasComponent]
442
550
  }] } });
443
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZnMtYWktcmVwb3J0LmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3NyYy9hcHAvcmVwb3J0cy92aWV3cy9yZXBvcnQvZnMtYWktcmVwb3J0LmNvbXBvbmVudC50cyIsIi4uLy4uLy4uLy4uLy4uLy4uL3NyYy9hcHAvcmVwb3J0cy92aWV3cy9yZXBvcnQvZnMtYWktcmVwb3J0LmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFDTCxzQkFBc0IsRUFBRSx1QkFBdUIsRUFBRSxpQkFBaUIsRUFBRSxTQUFTLEVBQzdFLFVBQVUsRUFBRSxVQUFVLEVBQUUsTUFBTSxFQUFFLFNBQVMsRUFBRSxRQUFRLEVBQUUsTUFBTSxFQUFFLE1BQU0sRUFBRSxLQUFLLEVBQUUsTUFBTSxFQUFFLE1BQU0sR0FDM0YsTUFBTSxlQUFlLENBQUM7QUFDdkIsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sNEJBQTRCLENBQUM7QUFDaEUsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUV6RCxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFDM0QsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLDBCQUEwQixDQUFDO0FBQ3JELE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUN2RCxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSwyQkFBMkIsQ0FBQztBQUU3RCxPQUFPLEVBQWdCLGNBQWMsRUFBcUIsTUFBTSxvQkFBb0IsQ0FBQztBQUNyRixPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sa0JBQWtCLENBQUM7QUFDaEQsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBRWhELE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUUzQyxPQUFPLEVBQUUsa0JBQWtCLEVB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YyxtQkFHUCx1QkFBdUIsQ0FBQyxNQUFNLGNBQ25DLElBQUksV0FDUCxDQUFDLHNCQUFzQixDQUFDLGFBQ3RCO3dCQUNULHNFQUFzRTt3QkFDdEUsdUVBQXVFO3dCQUN2RSx3QkFBd0I7d0JBQ3hCLDRCQUE0Qjt3QkFDNUIsaUJBQWlCO3dCQUNqQixnQkFBZ0I7d0JBQ2hCLG1CQUFtQjt3QkFDbkIsc0VBQXNFO3dCQUN0RSxrQkFBa0IsQ0FBQyxFQUFFLE9BQU8sRUFBRSxHQUFHLEVBQUUsQ0FBQyxNQUFNLENBQUMscUJBQXFCLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxNQUFNLEVBQUUsRUFBRSxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsRUFBRSxDQUFDO3FCQUN0RyxXQUNRO3dCQUNQLGNBQWM7d0JBQ2QsWUFBWTt3QkFDWixpQkFBaUI7d0JBQ2pCLGVBQWU7d0JBQ2YsYUFBYTt3QkFDYixnQkFBZ0I7d0JBQ2hCLHFCQUFxQjtxQkFDdEI7d0RBc0VPLE1BQU07c0JBRGIsU0FBUzt1QkFBQyxPQUFPLEVBQUUsRUFBRSxNQUFNLEVBQUUsSUFBSSxFQUFFO2dCQUk1QixVQUFVO3NCQURqQixTQUFTO3VCQUFDLFdBQVcsRUFBRSxFQUFFLE1BQU0sRUFBRSxJQUFJLEVBQUUsSUFBSSxFQUFFLFVBQVUsRUFBRTtnQkFNbEQsT0FBTztzQkFEZCxTQUFTO3VCQUFDLHFCQUFxQiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XHJcbiAgQ1VTVE9NX0VMRU1FTlRTX1NDSEVNQSwgQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3ksIENoYW5nZURldGVjdG9yUmVmLCBDb21wb25lbnQsXHJcbiAgRGVzdHJveVJlZiwgRWxlbWVudFJlZiwgTmdab25lLCBWaWV3Q2hpbGQsIGNvbXB1dGVkLCBlZmZlY3QsIGluamVjdCwgaW5wdXQsIG91dHB1dCwgc2lnbmFsLFxyXG59IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xyXG5pbXBvcnQgeyB0YWtlVW50aWxEZXN0cm95ZWQgfSBmcm9tICdAYW5ndWxhci9jb3JlL3J4anMtaW50ZXJvcCc7XHJcbmltcG9ydCB7IEFjdGl2YXRlZFJvdXRlLCBSb3V0ZXIgfSBmcm9tICdAYW5ndWxhci9yb3V0ZXInO1xyXG5cclxuaW1wb3J0IHsgTWF0QnV0dG9uTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvbWF0ZXJpYWwvYnV0dG9uJztcclxuaW1wb3J0IHsgTWF0RGlhbG9nIH0gZnJvbSAnQGFuZ3VsYXIvbWF0ZXJpYWwvZGlhbG9nJztcclxuaW1wb3J0IHsgTWF0SWNvbk1vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL21hdGVyaWFsL2ljb24nO1xyXG5pbXBvcnQgeyBNYXRUb29sdGlwTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvbWF0ZXJpYWwvdG9vbHRpcCc7XHJcblxyXG5pbXBvcnQgeyBGaWx0ZXJDb25maWcsIEZzRmlsdGVyTW9kdWxlLCBJRmlsdGVyQ29uZmlnSXRlbSB9IGZyb20gJ0BmaXJlc3RpdGNoL2ZpbHRlcic7XHJcbmltcG9ydCB7IEZzTWVudU1vZHVsZSB9IGZyb20gJ0BmaXJlc3RpdGNoL21lbnUnO1xyXG5pbXBvcnQgeyBGc1Byb2Nlc3MgfSBmcm9tICdAZmlyZXN0aXRjaC9wcm9jZXNzJztcclxuXHJcbmltcG9ydCB7IHRha2VVbnRpbCB9IGZyb20gJ3J4anMvb3BlcmF0b3JzJztcclxuXHJcbmltcG9ydCB7IHByb3ZpZGVFY2hhcnRzQ29yZSB9IGZyb20gJ25neC1lY2hhcnRzJztcclxuXHJcbmltcG9ydCB7IEZzQWlDaGF0Q29tcG9uZW50LCBGc0FpQ2hhdFJlc3BvbnNlIH0gZnJvbSAnQGZpcmVzdGl0Y2gvYWknO1xyXG5cclxuaW1wb3J0IHsgUmVwb3J0Q2FudmFzQ29tcG9uZW50IH0gZnJvbSAnLi4vLi4vY29tcG9uZW50cy9yZXBvcnQtY2FudmFzL3JlcG9ydC1jYW52YXMuY29tcG9uZW50JztcclxuaW1wb3J0IHsgUmVwb3J0RGF0YSB9IGZyb20gJy4uLy4uL2RhdGEvcmVwb3J0LmRhdGEnO1xyXG5pbXBvcnQgeyBDb21wb25lbnRTZXR0aW5nc0NvbXBvbmVudCwgQ29tcG9uZW50U2V0dGluZ3NSZXN1bHQgfSBmcm9tICcuLi8uLi9kaWFsb2dzL2NvbXBvbmVudC1zZXR0aW5ncy9jb21wb25lbnQtc2V0dGluZ3MuY29tcG9uZW50JztcclxuaW1wb3J0IHsgUmVwb3J0U2V0dGluZ3NDb21wb25lbnQsIFJlcG9ydFNldHRpbmdzUmVzdWx0IH0gZnJvbSAnLi4vLi4vZGlhbG9ncy9yZXBvcnQtc2V0dGluZ3MvcmVwb3J0LXNldHRpbmdzLmNvbXBvbmVudCc7XHJcbmltcG9ydCB7IFJlcG9ydEV4cG9ydENvbGxlY3RvclNlcnZpY2UgfSBmcm9tICcuLi8uLi9leHBvcnQvcmVwb3J0LWV4cG9ydC1jb2xsZWN0b3Iuc2VydmljZSc7XHJcbmltcG9ydCB7IFJlcG9ydEV4cG9ydFNlcnZpY2UgfSBmcm9tICcuLi8uLi9leHBvcnQvcmVwb3J0LWV4cG9ydC5zZXJ2aWNlJztcclxuaW1wb3J0IHsgUmVwb3J0UGRmU2VydmljZSB9IGZyb20gJy4uLy4uL2V4cG9ydC9yZXBvcnQtcGRmLnNlcnZpY2UnO1xyXG5pbXBvcnQgeyBSZXBvcnRQcHR4U2VydmljZSB9IGZyb20gJy4uLy4uL2V4cG9ydC9yZXBvcnQtcHB0eC5zZXJ2aWNlJztcclxuaW1wb3J0IHtcclxuICBDaGFydEdyYW51bGFyaXR5LCBSZXBvcnQsIFJlcG9ydENoYXRSZXNwb25zZSxcclxuICBSZXBvcnRDb21wb25lbnQgYXMgUmVwb3J0Q29tcG9uZW50TW9kZWwsIFJlcG9ydEZpbHRlckdyb3VwLFxyXG59IGZyb20gJy4uLy4uL2ludGVyZmFjZXMvcmVwb3J0LmludGVyZmFjZSc7XHJcbmltcG9ydCB7XHJcbiAgR1JPVVBfQllfSVRFTSwgZmlsdGVySXRlbUZvckdyb3VwLCBncm91cEJ5RmlsdGVySXRlbSwgZ3JvdXBCeVNpZ25hdHVyZSwgZ3JvdXBWYWx1ZXNGcm9tUXVlcnksXHJcbiAgaXNHcmFudWxhcml0eU9mZmVyZWQsXHJcbn0gZnJvbSAnLi4vLi4vcmVwb3J0LWZpbHRlci1pdGVtcyc7XHJcbmltcG9ydCB7IFJlcG9ydEZpbHRlclN0YXRlU2VydmljZSwgZGVmYXVsdFNpZ25hdHVyZSB9IGZyb20gJy4uLy4uL3NlcnZpY2VzL3JlcG9ydC1maWx0ZXItc3RhdGUuc2VydmljZSc7XHJcblxyXG5cclxuLy8gQSBzaW5nbGUgcmVwb3J0OiB0aGUgQUkgY2hhdCBvbiB0aGUgbGVmdCwgdGhlIHJlcG9ydCBjYW52YXMgb24gdGhlIHJpZ2h0LFxyXG4vLyB1bmRlciBhbiBIMiB0aXRsZSArIHNldHRpbmdzIGdlYXIuIFRoZSBob3N0IHN1cHBsaWVzIFtyZXBvcnRJZF0gKGZyb20gaXRzXHJcbi8vIHJvdXRlKSBhbmQgc3dpdGNoZXMgcmVwb3J0cyBieSBuYXZpZ2F0aW5nIOKAlCB0aGlzIGNvbXBvbmVudCBuZXZlciBwaWNrcyBvbmUuXHJcbkBDb21wb25lbnQoe1xyXG4gIHNlbGVjdG9yOiAnZnMtYWktcmVwb3J0JyxcclxuICB0ZW1wbGF0ZVVybDogJy4vZnMtYWktcmVwb3J0LmNvbXBvbmVudC5odG1sJyxcclxuICBzdHlsZVVybHM6IFsnLi9mcy1haS1yZXBvcnQuY29tcG9uZW50LnNjc3MnXSxcclxuICBjaGFuZ2VEZXRlY3Rpb246IENoYW5nZURldGVjdGlvblN0cmF0ZWd5Lk9uUHVzaCxcclxuICBzdGFuZGFsb25lOiB0cnVlLFxyXG4gIHNjaGVtYXM6IFtDVVNUT01fRUxFTUVOVFNfU0NIRU1BXSxcclxuICBwcm92aWRlcnM6IFtcclxuICAgIC8vIFNlc3Npb24gZmlsdGVyIHN0YXRlIGlzIHBlci1vcGVuLXJlcG9ydCwgbm90IGFwcC1nbG9iYWw7IHRoZSBleHBvcnRcclxuICAgIC8vIHNlcnZpY2VzIHJlc29sdmUgZmlsdGVycyB0aHJvdWdoIGl0LCBzbyB0aGV5IGxpdmUgYXQgdGhlIHNhbWUgbGV2ZWwuXHJcbiAgICBSZXBvcnRGaWx0ZXJTdGF0ZVNlcnZpY2UsXHJcbiAgICBSZXBvcnRFeHBvcnRDb2xsZWN0b3JTZXJ2aWNlLFxyXG4gICAgUmVwb3J0UHB0eFNlcnZpY2UsXHJcbiAgICBSZXBvcnRQZGZTZXJ2aWNlLFxyXG4gICAgUmVwb3J0RXhwb3J0U2VydmljZSxcclxuICAgIC8vIFRyZWUtc2hha2VuIEVDaGFydHMgY29yZSArIHRoZSAncmVwb3J0JyBob3VzZSB0aGVtZSwgbG9hZGVkIGxhemlseS5cclxuICAgIHByb3ZpZGVFY2hhcnRzQ29yZSh7IGVjaGFydHM6ICgpID0+IGltcG9ydCgnLi4vLi4vdGhlbWUvZWNoYXJ0cycpLnRoZW4oKG1vZHVsZSkgPT4gbW9kdWxlLmRlZmF1bHQpIH0pLFxyXG4gIF0sXHJcbiAgaW1wb3J0czogW1xyXG4gICAgRnNGaWx0ZXJNb2R1bGUsXHJcbiAgICBGc01lbnVNb2R1bGUsXHJcbiAgICBGc0FpQ2hhdENvbXBvbmVudCxcclxuICAgIE1hdEJ1dHRvbk1vZHVsZSxcclxuICAgIE1hdEljb25Nb2R1bGUsXHJcbiAgICBNYXRUb29sdGlwTW9kdWxlLFxyXG4gICAgUmVwb3J0Q2FudmFzQ29tcG9uZW50LFxyXG4gIF0sXHJcbn0pXHJcbmV4cG9ydCBjbGFzcyBGc0FpUmVwb3J0Q29tcG9uZW50IHtcclxuXHJcbiAgLy8gVGhlIHJlcG9ydCB0aGlzIHZpZXcgaXMgZm9jdXNlZCBvbiDigJQgc3VwcGxpZWQgYnkgdGhlIGhvc3QgZnJvbSB0aGUgcm91dGUuXHJcbiAgcHVibGljIHJlYWRvbmx5IHJlcG9ydElkID0gaW5wdXQ8bnVtYmVyIHwgbnVsbD4obnVsbCk7XHJcblxyXG4gIC8vIEFQSSBiYXNlIGZvciB0aGUgcmVwb3J0cyArIGNoYXQgZW5kcG9pbnRzOyBvdmVycmlkZSB0byBtb3VudCBlbHNld2hlcmUuXHJcbiAgcHVibGljIHJlYWRvbmx5IGJhc2VQYXRoID0gaW5wdXQ8c3RyaW5nPigncmVwb3J0cycpO1xyXG5cclxuICAvLyBUaGUgcXVlcnkgcGFyYW0gdGhhdCBjYXJyaWVzIHRoZSBvcGVuIHBhZ2UncyBpZC4gRGVlcCBsaW5raW5nIGlzIG9uIGJ5XHJcbiAgLy8gZGVmYXVsdDsgYSBob3N0IHRoYXQgbW91bnRzIHNldmVyYWwgcmVwb3J0cyBvbiBvbmUgcm91dGUsIG9yIHdhbnRzIG5vIFVSTFxyXG4gIC8vIHdyaXRlcyBhdCBhbGwsIHNldHMgdGhpcyB0byBudWxsIHRvIHR1cm4gaXQgb2ZmLlxyXG4gIHB1YmxpYyByZWFkb25seSBwYWdlUXVlcnlQYXJhbSA9IGlucHV0PHN0cmluZyB8IG51bGw+KCdwYWdlJyk7XHJcblxyXG4gIC8vIFRoZSByZXBvcnQgd2FzIGRlbGV0ZWQgZnJvbSBpdHMgc2V0dGluZ3MgZGlhbG9nIOKAlCB0aGUgaG9zdCByb3V0ZXMgYmFjayB0b1xyXG4gIC8vIHRoZSBsaXN0aW5nLlxyXG4gIHB1YmxpYyByZWFkb25seSBkZWxldGVkID0gb3V0cHV0PG51bWJlcj4oKTtcclxuXHJcbiAgLy8gVGhlIHJlcG9ydCB3YXMgcmVuYW1lZCAoc2V0dGluZ3MsIG9yIHRoZSBhZ2VudCkg4oCUIHRoZSBob3N0IGNhbiByZWZyZXNoIGFcclxuICAvLyBicmVhZGNydW1iIC8gZG9jdW1lbnQgdGl0bGUuXHJcbiAgcHVibGljIHJlYWRvbmx5IHJlbmFtZWQgPSBvdXRwdXQ8UmVwb3J0PigpO1xyXG5cclxuICAvLyBUaGUgdmlld2VyIG1vdmVkIHRvIGFub3RoZXIgcGFnZS4gVGhlIFVSTCBpcyBhbHJlYWR5IHVwZGF0ZWQgYnkgdGhlbiDigJRcclxuICAvLyB0aGlzIGlzIGZvciBob3N0cyB0aGF0IHRyYWNrIHRoZSBvcGVuIHBhZ2UgZm9yIHRoZWlyIG93biByZWFzb25zLlxyXG4gIHB1YmxpYyByZWFkb25seSBwYWdlQ2hhbmdlZCA9IG91dHB1dDxudW1iZXIgfCBudWxsPigpO1xyXG5cclxuICBwdWJsaWMgcmVwb3J0OiBSZXBvcnQgfCBudWxsID0gbnVsbDtcclxuICBwdWJsaWMgZWRpdE1vZGUgPSBmYWxzZTtcclxuXHJcbiAgLy8gVGhlIHBhZ2UgdGhlIGNhbnZhcyBzaG91bGQgb3BlbiBvbiwgcmVhZCBmcm9tIHRoZSBVUkwgb25jZSBwZXIgcmVwb3J0LlxyXG4gIC8vIENsZWFyZWQgYXMgc29vbiBhcyB0aGUgY2FudmFzIHJlcG9ydHMgYmFjaywgc28gYSBsYXRlciBpbi1hcHAgcGFnZSBjaGFuZ2VcclxuICAvLyBpcyBuZXZlciBmb3VnaHQgYnkgYSBzdGFsZSB2YWx1ZS5cclxuICBwdWJsaWMgcGFnZUlkOiBudW1iZXIgfCBudWxsID0gbnVsbDtcclxuXHJcbiAgLy8gVGhlIHBhZ2UgdGhlIGNoYXQgaXMgYm91bmQgdG86IHRoZSBvbmUgb24gc2NyZWVuLiBBIHJlcG9ydCBjb252ZXJzYXRpb25cclxuICAvLyBiZWxvbmdzIHRvIGV4YWN0bHkgb25lIHBhZ2UsIHNvIHRoaXMgYm90aCBzY29wZXMgdGhlIGNvbnZlcnNhdGlvbiBsaXN0IGFuZFxyXG4gIC8vIGJlY29tZXMgdGhlIG5ldyBjb252ZXJzYXRpb24ncyBwYWdlLiBBIHNpZ25hbCBiZWNhdXNlIGl0IGZlZWRzXHJcbiAgLy8gW3JlcXVlc3REYXRhXSDigJQgY2hhbmdpbmcgaXQgaXMgd2hhdCByZWxvYWRzIHRoZSBwYW5lbCBvbnRvIHRoZSBuZXcgcGFnZSdzXHJcbiAgLy8gY29udmVyc2F0aW9ucy4gTnVsbCB1bnRpbCB0aGUgY2FudmFzIHJlcG9ydHMgd2hpY2ggcGFnZSBpdCBvcGVuZWQgb24sIHdoaWNoXHJcbiAgLy8ga2VlcHMgdGhlIGNoYXQgZnJvbSBsaXN0aW5nIGFnYWluc3QgYSBwYWdlIGd1ZXNzLlxyXG4gIHB1YmxpYyByZWFkb25seSBjaGF0UGFnZUlkID0gc2lnbmFsPG51bWJlciB8IG51bGw+KG51bGwpO1xyXG5cclxuICAvLyBXaGF0IHRoZSBjaGF0IHNlbmRzIHdpdGggZXZlcnkgY29udmVyc2F0aW9uIGNhbGw6IHRoZSByZXBvcnQsIGFuZCB0aGUgcGFnZVxyXG4gIC8vIGl0IGlzIGJvdW5kIHRvLlxyXG4gIC8vXHJcbiAgLy8gcmVwb3J0UGFnZUlkIGlzIE9NSVRURUQsIG5vdCBzZW50IGFzIG51bGwsIHdoaWxlIHRoZSBvcGVuIHBhZ2UgaXMgdW5rbm93bi5cclxuICAvLyBUaGUgYmFja2VuZCByZWFkcyBhIFBSRVNFTlQgcmVwb3J0UGFnZUlkIG9mIDAvbnVsbCBhcyBcInRoZSByZXBvcnQncyBlYXJsaWVyLFxyXG4gIC8vIHBhZ2UtbGVzcyBjb252ZXJzYXRpb25zXCIsIHNvIHNlbmRpbmcgbnVsbCBiZWZvcmUgdGhlIGNhbnZhcyBoYXMgcmVwb3J0ZWQgaW5cclxuICAvLyB3b3VsZCBhc2sgZm9yIHRoZSB3cm9uZyBsaXN0IOKAlCBhbmQsIHdvcnNlLCB3b3VsZCBiaW5kIGEgY29udmVyc2F0aW9uIHN0YXJ0ZWRcclxuICAvLyBpbiB0aGF0IHdpbmRvdyB0byBubyBwYWdlIGF0IGFsbC5cclxuICAvL1xyXG4gIC8vIFRoZSBjaGF0IGlzIGFsc28gaGVsZCBjbG9zZWQgKFtyZWFkeV0gaW4gdGhlIHRlbXBsYXRlKSB1bnRpbCB0aGUgcGFnZSBpc1xyXG4gIC8vIGtub3duLCBzbyB0aGlzIHBhcnRpYWwgY29udGV4dCBpcyBuZXZlciBhY3R1YWxseSBzZW50OiBvbiBhIGZyZXNoIGxvYWQgdGhlXHJcbiAgLy8gcmVwb3J0IGhhcyB0byBhcnJpdmUgYW5kIHRoZSBjYW52YXMgaGFzIHRvIHJlbmRlciBiZWZvcmUgYW55IHBhZ2UgZXhpc3RzLFxyXG4gIC8vIGFuZCBhIGxpc3QgZmV0Y2hlZCBpbiB0aGF0IHdpbmRvdyB3b3VsZCBiZSB0aGUgd2hvbGUgcmVwb3J0J3MgY29udmVyc2F0aW9uc1xyXG4gIC8vIOKAlCB0aGUgdW5zY29wZWQgbGlzdCwgc2hvd24gYW5kIGF1dG8tc2VsZWN0ZWQgYmVmb3JlIHRoZSByZWFsIG9uZSBsYW5kcy5cclxuICBwdWJsaWMgcmVhZG9ubHkgY2hhdFJlcXVlc3REYXRhID0gY29tcHV0ZWQ8UmVjb3JkPHN0cmluZywgdW5rbm93bj4+KCgpID0+IHtcclxuICAgIGNvbnN0IHJlcG9ydFBhZ2VJZCA9IHRoaXMuY2hhdFBhZ2VJZCgpO1xyXG5cclxuICAgIHJldHVybiByZXBvcnRQYWdlSWQgPT09IG51bGxcclxuICAgICAgPyB7IHJlcG9ydElkOiB0aGlzLnJlcG9ydElkKCkgfVxyXG4gICAgICA6IHsgcmVwb3J0SWQ6IHRoaXMucmVwb3J0SWQoKSwgcmVwb3J0UGFnZUlkIH07XHJcbiAgfSk7XHJcblxyXG4gIC8vIFRoZSByZXBvcnQtbGV2ZWwgZmlsdGVyIHRvb2xiYXIgKGZzLWZpbHRlcikuIFJlYnVpbHQgd2hlbmV2ZXIgdGhlIGxvYWRlZFxyXG4gIC8vIHJlcG9ydCAoYW5kIHRodXMgaXRzIGdyb3VwcykgY2hhbmdlcy5cclxuICBwdWJsaWMgcmVwb3J0RmlsdGVyQ29uZmlnITogRmlsdGVyQ29uZmlnO1xyXG5cclxuICBAVmlld0NoaWxkKCdzcGxpdCcsIHsgc3RhdGljOiB0cnVlIH0pXHJcbiAgcHJpdmF0ZSBfc3BsaXQhOiBFbGVtZW50UmVmPEhUTUxEaXZFbGVtZW50PjtcclxuXHJcbiAgQFZpZXdDaGlsZCgnY2hhdFBhbmVsJywgeyBzdGF0aWM6IHRydWUsIHJlYWQ6IEVsZW1lbnRSZWYgfSlcclxuICBwcml2YXRlIF9jaGF0UGFuZWwhOiBFbGVtZW50UmVmPEhUTUxFbGVtZW50PjtcclxuXHJcbiAgLy8gT25seSB0aGUgY2FudmFzIGtub3dzIHdoaWNoIHBhZ2UgaXMgb24gc2NyZWVuLCBhbmQgYSBwYWdlLXNjb3BlZCBleHBvcnRcclxuICAvLyBoYXMgdG8gYXNrIGl0LlxyXG4gIEBWaWV3Q2hpbGQoUmVwb3J0Q2FudmFzQ29tcG9uZW50KVxyXG4gIHByaXZhdGUgX2NhbnZhcz86IFJlcG9ydENhbnZhc0NvbXBvbmVudDtcclxuXHJcbiAgcHJpdmF0ZSBfcmVwb3J0RGF0YSA9IGluamVjdChSZXBvcnREYXRhKTtcclxuICBwcml2YXRlIF9yb3V0ZXIgPSBpbmplY3QoUm91dGVyKTtcclxuICBwcml2YXRlIF9yb3V0ZSA9IGluamVjdChBY3RpdmF0ZWRSb3V0ZSk7XHJcbiAgcHJpdmF0ZSBfZmlsdGVyU3RhdGUgPSBpbmplY3QoUmVwb3J0RmlsdGVyU3RhdGVTZXJ2aWNlKTtcclxuICBwcml2YXRlIF9leHBvcnRTZXJ2aWNlID0gaW5qZWN0KFJlcG9ydEV4cG9ydFNlcnZpY2UpO1xyXG4gIHByaXZhdGUgX3Byb2Nlc3MgPSBpbmplY3QoRnNQcm9jZXNzKTtcclxuICBwcml2YXRlIF9kaWFsb2cgPSBpbmplY3QoTWF0RGlhbG9nKTtcclxuICBwcml2YXRlIF9kZXN0cm95UmVmID0gaW5qZWN0KERlc3Ryb3lSZWYpO1xyXG4gIHByaXZhdGUgX2NkUmVmID0gaW5qZWN0KENoYW5nZURldGVjdG9yUmVmKTtcclxuICBwcml2YXRlIF96b25lID0gaW5qZWN0KE5nWm9uZSk7XHJcblxyXG4gIGNvbnN0cnVjdG9yKCkge1xyXG4gICAgLy8gUG9pbnQgdGhlIHNoYXJlZCBkYXRhIGdhdGV3YXkgYXQgdGhlIGNvbmZpZ3VyZWQgYmFzZSBmaXJzdCAoYmVmb3JlIGFueVxyXG4gICAgLy8gbG9hZCBiZWxvdyByZWFkcyBpdCkuXHJcbiAgICBlZmZlY3QoKCkgPT4ge1xyXG4gICAgICB0aGlzLl9yZXBvcnREYXRhLmJhc2VQYXRoID0gdGhpcy5iYXNlUGF0aCgpO1xyXG4gICAgfSk7XHJcblxyXG4gICAgLy8gKFJlKWxvYWQgd2hlbmV2ZXIgdGhlIGhvc3Qgc3dpdGNoZXMgdGhlIHJlcG9ydCBpZC5cclxuICAgIGVmZmVjdCgoKSA9PiB7XHJcbiAgICAgIGNvbnN0IHJlcG9ydElkID0gdGhpcy5yZXBvcnRJZCgpO1xyXG4gICAgICB0aGlzLmVkaXRNb2RlID0gZmFsc2U7XHJcblxyXG4gICAgICAvLyBBIG5ldyByZXBvcnQncyBwYWdlcyBhcmUgbm90IHRoaXMgcmVwb3J0J3MgcGFnZXMg4oCUIGRyb3AgdGhlIGJpbmRpbmdcclxuICAgICAgLy8gdW50aWwgaXRzIGNhbnZhcyBzYXlzIHdoaWNoIHBhZ2UgaXQgbGFuZGVkIG9uLlxyXG4gICAgICB0aGlzLmNoYXRQYWdlSWQuc2V0KG51bGwpO1xyXG5cclxuICAgICAgLy8gU2VlZCB0aGUgb3BlbiBwYWdlIGZyb20gdGhlIFVSTCBmb3IgdGhpcyByZXBvcnQuIFJlYWQgcGVyIGxvYWQgcmF0aGVyXHJcbiAgICAgIC8vIHRoYW4gb25jZSBhdCBjb25zdHJ1Y3Rpb246IHRoZSBob3N0IG1heSBzd2FwIHJlcG9ydHMgb24gdGhlIHNhbWUgcm91dGUsXHJcbiAgICAgIC8vIGFuZCBlYWNoIGFycml2YWwgY2FycmllcyBpdHMgb3duID9wYWdlPS5cclxuICAgICAgdGhpcy5wYWdlSWQgPSB0aGlzLl9wYWdlSWRGcm9tVXJsKCk7XHJcblxyXG4gICAgICBpZiAocmVwb3J0SWQgIT0gbnVsbCkge1xyXG4gICAgICAgIHRoaXMuX2xvYWRSZXBvcnQocmVwb3J0SWQpO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIHRoaXMucmVwb3J0ID0gbnVsbDtcclxuICAgICAgICB0aGlzLl9idWlsZFJlcG9ydENvbmZpZygpO1xyXG4gICAgICAgIHRoaXMuX2NkUmVmLm1hcmtGb3JDaGVjaygpO1xyXG4gICAgICB9XHJcbiAgICB9KTtcclxuXHJcbiAgICB0aGlzLl9idWlsZFJlcG9ydENvbmZpZygpO1xyXG4gIH1cclxuXHJcbiAgcHVibGljIHRvZ2dsZUVkaXRNb2RlKCk6IHZvaWQge1xyXG4gICAgdGhpcy5lZGl0TW9kZSA9ICF0aGlzLmVkaXRNb2RlO1xyXG4gIH1cclxuXHJcbiAgLy8gVGhlIGVkaXQgdG9vbHMgbGl2ZSBpbiB0aGlzIHRvb2xiYXIsIGJ1dCB0aGUgY2FudmFzIG93bnMgd2hhdCB0aGV5IGFjdCBvblxyXG4gIC8vICh0aGUgYWN0aXZlIHBhZ2UsIHRoZSBoZWFkZXIvZm9vdGVyIGJhbmRzLCB3aGljaCBsYXllciBpcyBsaXZlKS5cclxuICBwdWJsaWMgZ2V0IGlzTWFzdGVyTW9kZSgpOiBib29sZWFuIHtcclxuICAgIHJldHVybiB0aGlzLl9jYW52YXM/Lm1hc3Rlck1vZGUoKSA/PyBmYWxzZTtcclxuICB9XHJcblxyXG4gIHB1YmxpYyBhZGRUZXh0KCk6IHZvaWQge1xyXG4gICAgdGhpcy5fY2FudmFzPy5hZGRUZXh0KCk7XHJcbiAgfVxyXG5cclxuICBwdWJsaWMgdG9nZ2xlTWFzdGVyTW9kZSgpOiB2b2lkIHtcclxuICAgIHRoaXMuX2NhbnZhcz8udG9nZ2xlTWFzdGVyTW9kZSgpO1xyXG4gIH1cclxuXHJcbiAgLy8gUmVwb3J0IHNldHRpbmdzIOKAlCBuYW1lLCBwYWdlIHNpemUsIG9yaWVudGF0aW9uLCBsYXlvdXQgbW9kZSwgZGVsZXRlLiBUaGVcclxuICAvLyBkaWFsb2cgcGVyZm9ybXMgdGhlIGRlbGV0ZSBpdHNlbGY7IHdlIHJlYWN0IHRvIHdoYXQgaXQgcmVwb3J0cyBiYWNrLlxyXG4gIHB1YmxpYyByZXBvcnRTZXR0aW5ncygpOiB2b2lkIHtcclxuICAgIGlmICghdGhpcy5yZXBvcnQpIHtcclxuICAgICAgcmV0dXJuO1xyXG4gICAgfVxyXG5cclxuICAgIGNvbnN0IHJlcG9ydElkID0gdGhpcy5yZXBvcnQuaWQ7XHJcblxyXG4gICAgdGhpcy5fZGlhbG9nLm9wZW48UmVwb3J0U2V0dGluZ3NDb21wb25lbnQsIHVua25vd24sIFJlcG9ydFNldHRpbmdzUmVzdWx0PihSZXBvcnRTZXR0aW5nc0NvbXBvbmVudCwge1xyXG4gICAgICBkYXRhOiB7IHJlcG9ydDogdGhpcy5yZXBvcnQgfSxcclxuICAgICAgd2lkdGg6ICc0NjBweCcsXHJcbiAgICB9KVxyXG4gICAgICAuYWZ0ZXJDbG9zZWQoKVxyXG4gICAgICAucGlwZSh0YWtlVW50aWxEZXN0cm95ZWQodGhpcy5fZGVzdHJveVJlZikpXHJcbiAgICAgIC5zdWJzY3JpYmUoKHJlc3VsdCkgPT4ge1xyXG4gICAgICAgIGlmIChyZXN1bHQ/LmFjdGlvbiA9PT0gJ2RlbGV0ZWQnKSB7XHJcbiAgICAgICAgICB0aGlzLmRlbGV0ZWQuZW1pdChyZXBvcnRJZCk7XHJcblxyXG4gICAgICAgICAgcmV0dXJuO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgaWYgKHJlc3VsdD8uYWN0aW9uID09PSAnc2F2ZWQnKSB7XHJcbiAgICAgICAgICB0aGlzLl9sb2FkUmVwb3J0KHJlcG9ydElkLCB0cnVlKTtcclxuICAgICAgICB9XHJcbiAgICAgIH0pO1xyXG4gIH1cclxuXHJcbiAgLy8gQ29tcG9uZW50IHNldHRpbmdzIOKAlCB0aXRsZSwgZXhhY3QgZ2VvbWV0cnksIGFuZCB0aGUgZGlhZ25vc3RpYyB2aWV3c1xyXG4gIC8vIChTUUwsIGNvbmZpZywgZmlsdGVyIHdpcmluZykuXHJcbiAgcHVibGljIGNvbXBvbmVudFNldHRpbmdzKGNvbXBvbmVudDogUmVwb3J0Q29tcG9uZW50TW9kZWwpOiB2b2lkIHtcclxuICAgIGlmICghdGhpcy5yZXBvcnQpIHtcclxuICAgICAgcmV0dXJuO1xyXG4gICAgfVxyXG5cclxuICAgIGNvbnN0IHJlcG9ydElkID0gdGhpcy5yZXBvcnQuaWQ7XHJcblxyXG4gICAgY29uc3QgZGlhbG9nUmVmID0gdGhpcy5fZGlhbG9nLm9wZW48Q29tcG9uZW50U2V0dGluZ3NDb21wb25lbnQsIHVua25vd24sIENvbXBvbmVudFNldHRpbmdzUmVzdWx0PihcclxuICAgICAgQ29tcG9uZW50U2V0dGluZ3NDb21wb25lbnQsXHJcbiAgICAgIHtcclxuICAgICAgICBkYXRhOiB7IHJlcG9ydDogdGhpcy5yZXBvcnQsIGNvbXBvbmVudCB9LFxyXG4gICAgICAgIHdpZHRoOiAnNjQwcHgnLFxyXG4gICAgICB9LFxyXG4gICAgKTtcclxuXHJcbiAgICAvLyBGaWx0ZXIgYWRkL3JlbW92ZS9sZXZlbCBjaGFuZ2VzIHBlcnNpc3QgaW1tZWRpYXRlbHkgaW5zaWRlIHRoZSBkaWFsb2cgKG5vXHJcbiAgICAvLyBcInNhdmVcIikgYW5kIGNhbiBsZWF2ZSBpdCBieSBhbiBleGl0IHRoYXQgY2FycmllcyBubyByZXN1bHQsIHNvIHRoZXkgYXJlXHJcbiAgICAvLyBhbm5vdW5jZWQgYXMgdGhleSBsYW5kLiBUaGUgcmVsb2FkIHdhaXRzIGZvciB0aGUgY2xvc2Ugc28gdGhlIGNhbnZhcyBpc24ndFxyXG4gICAgLy8gcmUtcmVuZGVyaW5nIHVuZGVybmVhdGggYW4gb3BlbiBkaWFsb2cuXHJcbiAgICBsZXQgZmlsdGVyc0NoYW5nZWQgPSBmYWxzZTtcclxuICAgIGRpYWxvZ1JlZi5jb21wb25lbnRJbnN0YW5jZS5maWx0ZXJzQ2hhbmdlZFxyXG4gICAgICAucGlwZSh0YWtlVW50aWwoZGlhbG9nUmVmLmFmdGVyQ2xvc2VkKCkpKVxyXG4gICAgICAuc3Vic2NyaWJlKCgpID0+IGZpbHRlcnNDaGFuZ2VkID0gdHJ1ZSk7XHJcblxyXG4gICAgZGlhbG9nUmVmLmFmdGVyQ2xvc2VkKClcclxuICAgICAgLnBpcGUodGFrZVVudGlsRGVzdHJveWVkKHRoaXMuX2Rlc3Ryb3lSZWYpKVxyXG4gICAgICAuc3Vic2NyaWJlKChyZXN1bHQpID0+IHtcclxuICAgICAgICAvLyBUaGUgZGlhbG9nIGNvbmZpcm1zICsgcGVyZm9ybXMgdGhlIGRlbGV0ZSBpdHNlbGYuIFRoZSBjb21wb25lbnQgaXNcclxuICAgICAgICAvLyBnb25lIGZyb20gdGhlIHJlcG9ydCwgc28gcmVsb2FkIHJhdGhlciB0aGFuIHBhdGNoaW5nIGl0IG91dCBsb2NhbGx5IOKAlFxyXG4gICAgICAgIC8vIGl0cyBmaWx0ZXJzIHdlbnQgd2l0aCBpdCwgd2hpY2ggdGhlIHJlcG9ydCBiYXIgaGFzIHRvIGJlIHJlYnVpbHQgZm9yLlxyXG4gICAgICAgIGlmIChyZXN1bHQ/LmRlbGV0ZWQpIHtcclxuICAgICAgICAgIHRoaXMuX2xvYWRSZXBvcnQocmVwb3J0SWQpO1xyXG5cclxuICAgICAgICAgIHJldHVybjtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIFRoZSByZXBvcnQncyBmaWx0ZXIgZ3JvdXBzIGNoYW5nZWQsIHNvIHRoZSByZXBvcnQgYmFyIGFuZCB0aGVcclxuICAgICAgICAvLyBvbi1jb21wb25lbnQgc3RyaXBzIGhhdmUgdG8gYmUgcmVidWlsdCBmcm9tIGEgZnJlc2ggcmVwb3J0LlxyXG4gICAgICAgIGlmIChmaWx0ZXJzQ2hhbmdlZCkge1xyXG4gICAgICAgICAgdGhpcy5fbG9hZFJlcG9ydChyZXBvcnRJZCk7XHJcblxyXG4gICAgICAgICAgcmV0dXJuO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gTm90aGluZyBlbHNlIGluIHRoZSBkaWFsb2cgdG91Y2hlcyB0aGUgcXVlcnkg4oCUIHRpdGxlIGFuZCBwYWRkaW5nIGFyZVxyXG4gICAgICAgIC8vIHByZXNlbnRhdGlvbi4gUmVwYWludCB0aGUgb25lIGNvbXBvbmVudCBpdCB3YXMgb3BlbmVkIGZvciBhbmQgbGVhdmVcclxuICAgICAgICAvLyBldmVyeSBvdGhlciBjb21wb25lbnQncyBkYXRhLCBhbmQgaXRzIHF1ZXJ5LCBhbG9uZS5cclxuICAgICAgICBpZiAocmVzdWx0Py5zZXR0aW5ncykge1xyXG4gICAgICAgICAgdGhpcy5fY2FudmFzPy5hcHBseUNvbXBvbmVudFNldHRpbmdzKGNvbXBvbmVudC5pZCwgcmVzdWx0LnNldHRpbmdzKTtcclxuICAgICAgICB9XHJcbiAgICAgIH0pO1xyXG4gIH1cclxuXHJcbiAgLy8gVGhlIGNhbnZhcyBtb3ZlZCB0byBhbm90aGVyIHBhZ2U6IHJlZmxlY3QgaXQgaW4gdGhlIFVSTCBzbyBhIHJlZnJlc2ggb3IgYVxyXG4gIC8vIHNoYXJlZCBsaW5rIGNvbWVzIGJhY2sgaGVyZS4gcmVwbGFjZVVybCBrZWVwcyBwYWdpbmcgb3V0IG9mIHRoZSBicm93c2VyXHJcbiAgLy8gaGlzdG9yeSDigJQgQmFjayBzaG91bGQgbGVhdmUgdGhlIHJlcG9ydCwgbm90IHdhbGsgZXZlcnkgcGFnZSB2aXNpdGVkLlxyXG4gIHB1YmxpYyBvbkNhbnZhc1BhZ2VDaGFuZ2VkKHBhZ2VJZDogbnVtYmVyIHwgbnVsbCk6IHZvaWQge1xyXG4gICAgLy8gVGhlIGRlZXAgbGluayBoYXMgYmVlbiBjb25zdW1lZDsgZnJvbSBoZXJlIHRoZSBjYW52YXMgb3ducyB0aGUgcGFnZS5cclxuICAgIHRoaXMucGFnZUlkID0gbnVsbDtcclxuICAgIHRoaXMuY2hhdFBhZ2VJZC5zZXQocGFnZUlkKTtcclxuICAgIHRoaXMucGFnZUNoYW5nZWQuZW1pdChwYWdlSWQpO1xyXG5cclxuICAgIGNvbnN0IHBhcmFtID0gdGhpcy5wYWdlUXVlcnlQYXJhbSgpO1xyXG4gICAgaWYgKCFwYXJhbSkge1xyXG4gICAgICByZXR1cm47XHJcbiAgICB9XHJcblxyXG4gICAgdGhpcy5fcm91dGVyLm5hdmlnYXRlKFtdLCB7XHJcbiAgICAgIHJlbGF0aXZlVG86IHRoaXMuX3JvdXRlLFxyXG4gICAgICBxdWVyeVBhcmFtczogeyBbcGFyYW1dOiBwYWdlSWQgfSxcclxuICAgICAgcXVlcnlQYXJhbXNIYW5kbGluZzogJ21lcmdlJyxcclxuICAgICAgcmVwbGFjZVVybDogdHJ1ZSxcclxuICAgIH0pO1xyXG4gIH1cclxuXHJcbiAgLy8gVGhlIGNhbnZhcyBjaGFuZ2VkIHRoZSByZXBvcnQncyBzdHJ1Y3R1cmUgKGFkZGVkIGEgcGFnZSkg4oCUIHJlLWZldGNoIHNvIHRoZVxyXG4gIC8vIG5ldyBwYWdlIHJlbmRlcnM7IHRoZSBjYW52YXMgbGFuZHMgdGhlIHZpZXcgb24gaXQuXHJcbiAgcHVibGljIG9uQ2FudmFzUmVwb3J0Q2hhbmdlZCgpOiB2b2lkIHtcclxuICAgIGlmICh0aGlzLnJlcG9ydCkge1xyXG4gICAgICB0aGlzLl9sb2FkUmVwb3J0KHRoaXMucmVwb3J0LmlkKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIEV4cG9ydCB0aGUgcmVwb3J0IHRvIFBvd2VyUG9pbnQsIGVudGlyZWx5IGNsaWVudC1zaWRlIChuYXRpdmUgZWRpdGFibGVcclxuICAvLyBjaGFydHM7IHBhZ2UgPSBzbGlkZSkuIFRoZSBkb2NrIHNob3dzIHByb2dyZXNzIHVudGlsIHRoZSBmaWxlIHNhdmVzLlxyXG4gIHB1YmxpYyBleHBvcnRQb3dlcnBvaW50KCk6IHZvaWQge1xyXG4gICAgaWYgKCF0aGlzLnJlcG9ydCkge1xyXG4gICAgICByZXR1cm47XHJcbiAgICB9XHJcblxyXG4gICAgdGhpcy5fcHJvY2Vzcy5ydW4oXHJcbiAgICAgICdFeHBvcnRpbmcgUG93ZXJQb2ludCcsXHJcbiAgICAgIHRoaXMuX2V4cG9ydFNlcnZpY2UucG93ZXJwb2ludCh0aGlzLnJlcG9ydCksXHJcbiAgICApO1xyXG4gIH1cclxuXHJcbiAgLy8gRXhwb3J0IHRvIFBERiwgZW50aXJlbHkgY2xpZW50LXNpZGUgKG9mZnNjcmVlbiBFQ2hhcnRzIGF0IDPDlzsgcGFnZSA9IFBERiBwYWdlKS5cclxuICBwdWJsaWMgZXhwb3J0UGRmKCk6IHZvaWQge1xyXG4gICAgaWYgKCF0aGlzLnJlcG9ydCkge1xyXG4gICAgICByZXR1cm47XHJcbiAgICB9XHJcblxyXG4gICAgdGhpcy5fcHJvY2Vzcy5ydW4oXHJcbiAgICAgICdFeHBvcnRpbmcgUERGJyxcclxuICAgICAgdGhpcy5fZXhwb3J0U2VydmljZS5wZGYodGhpcy5yZXBvcnQpLFxyXG4gICAgKTtcclxuICB9XHJcblxyXG4gIC8vIFRoZSByYXcgZGF0YSBiZWhpbmQgdGhlIHdob2xlIHJlcG9ydCBpbiBvbmUgYWN0aW9uOiB0aGUgc2VydmVyIGV4cG9ydHMgZXZlcnlcclxuICAvLyBjb21wb25lbnQncyBmdWxsIGZpbHRlcmVkIGRhdGFzZXQgYW5kIHppcHMgb25lIENTViBwZXIgY29tcG9uZW50LCBmb2xkZXJlZFxyXG4gIC8vIGJ5IHBhZ2UuIGB0aGlzUGFnZWAgbmFycm93cyBpdCB0byB0aGUgcGFnZSB0aGUgY2FudmFzIGlzIHNob3dpbmcuIFVubGlrZSB0aGVcclxuICAvLyBQREYvUG93ZXJQb2ludCBleHBvcnRzIHRoaXMgaXMgZW50aXJlbHkgc2VydmVyLXNpZGUg4oCUIG5vdGhpbmcgaXMgY29sbGVjdGVkXHJcbiAgLy8gaW4gdGhlIGJyb3dzZXIsIHNvIGl0IGlzIG5vdCBjYXBwZWQgYnkgd2hhdCBhIHNsaWRlIGNhbiBob2xkLlxyXG4gIHB1YmxpYyBleHBvcnREYXRhKHRoaXNQYWdlID0gZmFsc2UpOiB2b2lkIHtcclxuICAgIGNvbnN0IHJlcG9ydCA9IHRoaXMucmVwb3J0O1xyXG4gICAgaWYgKCFyZXBvcnQpIHtcclxuICAgICAgcmV0dXJuO1xyXG4gICAgfVxyXG5cclxuICAgIGNvbnN0IHBhZ2VJZCA9IHRoaXNQYWdlID8gdGhpcy5fY2FudmFzPy5hY3RpdmVQYWdlPy5pZCA/PyBudWxsIDogbnVsbDtcclxuXHJcbiAgICB0aGlzLl9wcm9jZXNzLmRvd25sb2FkKFxyXG4gICAgICAnRXhwb3J0aW5nIGRhdGEnLFxyXG4gICAgICB0aGlzLl9yZXBvcnREYXRhLmV4cG9ydFJlcG9ydChyZXBvcnQuaWQsIHRoaXMuX2ZpbHRlclN0YXRlLnJlc29sdmVGb3JSZXBvcnQocmVwb3J0LCBwYWdlSWQpLCBwYWdlSWQpLFxyXG4gICAgKTtcclxuICB9XHJcblxyXG4gIC8vIFJlYWN0IHRvIGVhY2ggY2hhdCB0dXJuIChmcy1jaGF0IGhhbmRsZXMgdGhlIHJlcXVlc3QgKyBwZXJzaXN0ZW5jZSk7IHdlXHJcbiAgLy8gb25seSBjYXJlIGFib3V0IHRoZSByZXBvcnQgc2lkZSBlZmZlY3RzIHRoaXMgY29udGV4dCdzIGJhY2tlbmQgZmxhZ3MuXHJcbiAgcHVibGljIG9uQ2hhdFJlc3BvbnNlKHJlc3BvbnNlOiBGc0FpQ2hhdFJlc3BvbnNlKTogdm9pZCB7XHJcbiAgICBjb25zdCByZXBvcnRJZCA9IHRoaXMucmVwb3J0SWQoKTtcclxuICAgIGlmIChyZXBvcnRJZCA9PSBudWxsKSB7XHJcbiAgICAgIHJldHVybjtcclxuICAgIH1cclxuXHJcbiAgICBjb25zdCByZXBvcnRSZXNwb25zZSA9IHJlc3BvbnNlIGFzIEZzQWlDaGF0UmVzcG9uc2UgJiBSZXBvcnRDaGF0UmVzcG9uc2U7XHJcblxyXG4gICAgLy8gQSBzdHJ1Y3R1cmFsIGNoYW5nZSBvciBhIHJlbmFtZSBib3RoIHJlLWZldGNoIHRoZSByZXBvcnQgKHNlc3Npb24gZmlsdGVyXHJcbiAgICAvLyB2YWx1ZXMgc3Vydml2ZSk7IGEgcmVuYW1lIGFkZGl0aW9uYWxseSBub3RpZmllcyB0aGUgaG9zdCBzbyBpdCBjYW5cclxuICAgIC8vIHJlZnJlc2ggYSBicmVhZGNydW1iIC8gdGl0bGUuXHJcbiAgICBpZiAocmVwb3J0UmVzcG9uc2UucmVwb3J0Q2hhbmdlZCB8fCByZXBvcnRSZXNwb25zZS5yZXBvcnRSZW5hbWVkKSB7XHJcbiAgICAgIHRoaXMuX2xvYWRSZXBvcnQocmVwb3J0SWQsICEhcmVwb3J0UmVzcG9uc2UucmVwb3J0UmVuYW1lZCk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBEcmFnIHRoZSBkaXZpZGVyIGJldHdlZW4gdGhlIGNoYXQgYW5kIGNhbnZhcyBwYW5lcyAocG9pbnRlci1jYXB0dXJlIGxvb3BcclxuICAvLyBvdXRzaWRlIEFuZ3VsYXIpLlxyXG4gIHB1YmxpYyBvblJlc2l6ZVN0YXJ0KGV2ZW50OiBQb2ludGVyRXZlbnQpOiB2b2lkIHtcclxuICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XHJcblxyXG4gICAgY29uc3QgaGFuZGxlID0gZXZlbnQudGFyZ2V0IGFzIEhUTUxFbGVtZW50O1xyXG4gICAgaGFuZGxlLnNldFBvaW50ZXJDYXB0dXJlKGV2ZW50LnBvaW50ZXJJZCk7XHJcbiAgICB0aGlzLl9zcGxpdC5uYXRpdmVFbGVtZW50LmNsYXNzTGlzdC5hZGQoJ3Jlc2l6aW5nJyk7XHJcblxyXG4gICAgdGhpcy5fem9uZS5ydW5PdXRzaWRlQW5ndWxhcigoKSA9PiB7XHJcbiAgICAgIGNvbnN0IG1vdmUgPSAoZTogUG9pbnRlckV2ZW50KSA9PiB0aGlzLl9yZXNpemVUbyhlLmNsaWVudFgpO1xyXG4gICAgICBjb25zdCBlbmQgPSAoKSA9PiB7XHJcbiAgICAgICAgaGFuZGxlLnJlbGVhc2VQb2ludGVyQ2FwdHVyZShldmVudC5wb2ludGVySWQpO1xyXG4gICAgICAgIGhhbmRsZS5yZW1vdmVFdmVudExpc3RlbmVyKCdwb2ludGVybW92ZScsIG1vdmUpO1xyXG4gICAgICAgIGhhbmRsZS5yZW1vdmVFdmVudExpc3RlbmVyKCdwb2ludGVydXAnLCBlbmQpO1xyXG4gICAgICAgIGhhbmRsZS5yZW1vdmVFdmVudExpc3RlbmVyKCdwb2ludGVyY2FuY2VsJywgZW5kKTtcclxuICAgICAgICB0aGlzLl9zcGxpdC5uYXRpdmVFbGVtZW50LmNsYXNzTGlzdC5yZW1vdmUoJ3Jlc2l6aW5nJyk7XHJcbiAgICAgIH07XHJcblxyXG4gICAgICBoYW5kbGUuYWRkRXZlbnRMaXN0ZW5lcigncG9pbnRlcm1vdmUnLCBtb3ZlKTtcclxuICAgICAgaGFuZGxlLmFkZEV2ZW50TGlzdGVuZXIoJ3BvaW50ZXJ1cCcsIGVuZCk7XHJcbiAgICAgIGhhbmRsZS5hZGRFdmVudExpc3RlbmVyKCdwb2ludGVyY2FuY2VsJywgZW5kKTtcclxuICAgIH0pO1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBfcmVzaXplVG8oY2xpZW50WDogbnVtYmVyKTogdm9pZCB7XHJcbiAgICBjb25zdCByZWN0ID0gdGhpcy5fc3BsaXQubmF0aXZlRWxlbWVudC5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtcclxuICAgIGlmIChyZWN0LndpZHRoID09PSAwKSB7XHJcbiAgICAgIHJldHVybjtcclxuICAgIH1cclxuXHJcbiAgICBjb25zdCByYXRpbyA9IChjbGllbnRYIC0gcmVjdC5sZWZ0KSAvIHJlY3Qud2lkdGg7XHJcbiAgICBjb25zdCBjbGFtcGVkID0gTWF0aC5taW4oMC44LCBNYXRoLm1heCgwLjIsIHJhdGlvKSk7XHJcbiAgICB0aGlzLl9jaGF0UGFuZWwubmF0aXZlRWxlbWVudC5zdHlsZS5mbGV4QmFzaXMgPSBgJHtjbGFtcGVkICogMTAwfSVgO1xyXG4gIH1cclxuXHJcbiAgLy8gVGhlIHBhZ2UgaWQgc2l0dGluZyBpbiB0aGUgVVJMIHJpZ2h0IG5vdywgb3IgbnVsbCB3aGVuIGRlZXAgbGlua2luZyBpcyBvZmZcclxuICAvLyBvciB0aGUgdmFsdWUgaXMgbm90IGEgdXNhYmxlIGlkLlxyXG4gIHByaXZhdGUgX3BhZ2VJZEZyb21VcmwoKTogbnVtYmVyIHwgbnVsbCB7XHJcbiAgICBjb25zdCBwYXJhbSA9IHRoaXMucGFnZVF1ZXJ5UGFyYW0oKTtcclxuICAgIGlmICghcGFyYW0pIHtcclxuICAgICAgcmV0dXJuIG51bGw7XHJcbiAgICB9XHJcblxyXG4gICAgY29uc3QgcGFnZUlkID0gTnVtYmVyKHRoaXMuX3JvdXRlLnNuYXBzaG90LnF1ZXJ5UGFyYW1NYXAuZ2V0KHBhcmFtKSk7XHJcblxyXG4gICAgcmV0dXJuIE51bWJlci5pc0Zpbml0ZShwYWdlSWQpICYmIHBhZ2VJZCA+IDAgPyBwYWdlSWQgOiBudWxsO1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBfbG9hZFJlcG9ydChyZXBvcnRJZDogbnVtYmVyLCBlbWl0UmVuYW1lZCA9IGZhbHNlKTogdm9pZCB7XHJcbiAgICB0aGlzLl9yZXBvcnREYXRhLmdldChyZXBvcnRJZClcclxuICAgICAgLnBpcGUodGFrZVVudGlsRGVzdHJveWVkKHRoaXMuX2Rlc3Ryb3lSZWYpKVxyXG4gICAgICAuc3Vic2NyaWJlKChyZXBvcnQ6IFJlcG9ydCkgPT4ge1xyXG4gICAgICAgIHRoaXMucmVwb3J0ID0gcmVwb3J0O1xyXG4gICAgICAgIHRoaXMuX2ZpbHRlclN0YXRlLmluaXQocmVwb3J0KTtcclxuICAgICAgICB0aGlzLl9idWlsZFJlcG9ydENvbmZpZygpO1xyXG5cclxuICAgICAgICBpZiAoZW1pdFJlbmFtZWQpIHtcclxuICAgICAgICAgIHRoaXMucmVuYW1lZC5lbWl0KHJlcG9ydCk7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICB0aGlzLl9jZFJlZi5tYXJrRm9yQ2hlY2soKTtcclxuICAgICAgfSk7XHJcbiAgfVxyXG5cclxuICAvLyBSZXBvcnQtbGV2ZWwgZmlsdGVyIGdyb3VwcyBpbiB0aGVpciBzYXZlZCBvcmRlciDigJQgdGhlIG9uZXMgdGhhdCByZW5kZXIgaW5cclxuICAvLyB0aGUgdG9vbGJhciAoY29tcG9uZW50LWxldmVsIGdyb3VwcyByZW5kZXIgb24gdGhlaXIgY29tcG9uZW50cykuXHJcbiAgcHJpdmF0ZSBfcmVwb3J0R3JvdXBzKCk6IFJlcG9ydEZpbHRlckdyb3VwW10ge1xyXG4gICAgcmV0dXJuICh0aGlzLnJlcG9ydD8uZmlsdGVyR3JvdXBzID8/IFtdKVxyXG4gICAgICAuZmlsdGVyKChncm91cCkgPT4gZ3JvdXAubGV2ZWwgPT09ICdyZXBvcnQnIHx8IGdyb3VwLmxldmVsID09PSAnYm90aCcpXHJcbiAgICAgIC5zb3J0KChhLCBiKSA9PiBhLm9yZGVyIC0gYi5vcmRlcik7XHJcbiAgfVxyXG5cclxuICAvLyBHYXRlcyB0aGUgdG9vbGJhciBmcy1maWx0ZXIgc28gaXQgaXNuJ3QgcmVuZGVyZWQgd2hlbiB0aGVyZSBpcyBub3RoaW5nIHRvXHJcbiAgLy8gcHV0IGluIGl0IOKAlCBubyByZXBvcnQtbGV2ZWwgZmlsdGVycyBhbmQgbm8gZ3JvdXAtYnkgY29udHJvbC5cclxuICBwdWJsaWMgZ2V0IHJlcG9ydEhhc0ZpbHRlcnMoKTogYm9vbGVhbiB7XHJcbiAgICByZXR1cm4gdGhpcy5fcmVwb3J0R3JvdXBzKCkubGVuZ3RoID4gMCB8fCAhIXRoaXMuX2dyb3VwQnlJdGVtKCk7XHJcbiAgfVxyXG5cclxuICAvLyBmcy1maWx0ZXIgcmVhZHMgaXRzIGNvbmZpZyBvbmx5IG9uY2UgKGF0IGluaXQpLiBUaGUgdGVtcGxhdGUga2V5cyB0aGVcclxuICAvLyB0b29sYmFyIGZzLWZpbHRlciBvbiB0aGlzIHNpZ25hdHVyZSBzbyBpdCdzIHJlY3JlYXRlZCAoYW5kIHJlLXJlYWRzIHRoZVxyXG4gIC8vIHJlYnVpbHQgY29uZmlnKSB3aGVuZXZlciB0aGUgcmVwb3J0LWxldmVsIGZpbHRlciBzZXQgY2hhbmdlcy5cclxuICBwdWJsaWMgZ2V0IHJlcG9ydEZpbHRlcktleSgpOiBzdHJpbmcge1xyXG4gICAgcmV0dXJuIFtcclxuICAgICAgLy8gVGhlIHN0b3JlZCBkZWZhdWx0IGlzIHBhcnQgb2YgdGhlIHNpZ25hdHVyZTogc2F2aW5nIGEgbmV3IGRlZmF1bHQgaW4gcmVwb3J0XHJcbiAgICAgIC8vIHNldHRpbmdzIHJlYnVpbGRzIHRoZSBjb25maWcsIGJ1dCB3aXRob3V0IGEga2V5IGNoYW5nZSBmcy1maWx0ZXIga2VlcHNcclxuICAgICAgLy8gcmVuZGVyaW5nIHRoZSB2YWx1ZXMgaXQgd2FzIGNyZWF0ZWQgd2l0aCB1bnRpbCBhIGZ1bGwgcGFnZSByZWxvYWQuXHJcbiAgICAgIGdyb3VwQnlTaWduYXR1cmUodGhpcy5yZXBvcnQpLFxyXG4gICAgICAuLi50aGlzLl9yZXBvcnRHcm91cHMoKS5tYXAoKGdyb3VwKSA9PiBgJHtncm91cC5pZH06JHtncm91cC5sZXZlbH06JHtncm91cC5sYWJlbH06JHtkZWZhdWx0U2lnbmF0dXJlKGdyb3VwKX1gKSxcclxuICAgIF0uam9pbignfCcpO1xyXG4gIH1cclxuXHJcbiAgLy8gKFJlKWJ1aWxkIHRoZSB0b29sYmFyIGZzLWZpbHRlciBjb25maWcg4oCUIHRoZSByZXBvcnQtbGV2ZWwgZmlsdGVyIGl0ZW1zIGFuZFxyXG4gIC8vIHRoZW4gdGhlIGdyb3VwLWJ5IGNvbnRyb2wuXHJcbiAgcHJpdmF0ZSBfYnVpbGRSZXBvcnRDb25maWcoKTogdm9pZCB7XHJcbiAgICBjb25zdCByZXBvcnRJZCA9IHRoaXMucmVwb3J0Py5pZCA/PyBudWxsO1xyXG5cclxuICAgIC8vIERyb3AgYSBncmFpbiB0aGUgY29udHJvbCBubyBsb25nZXIgb2ZmZXJzIOKAlCB0aGUgYWdlbnQgY2FuIG5hcnJvdyB0aGUgbGlzdFxyXG4gICAgLy8gbWlkLXNlc3Npb24sIGFuZCBhbiBvdmVycmlkZSB0aGUgdmlld2VyIGNhbid0IHNlZSBpcyB3b3JzZSB0aGFuIG5vbmUuXHJcbiAgICBpZiAodGhpcy5yZXBvcnQgJiYgIWlzR3JhbnVsYXJpdHlPZmZlcmVkKHRoaXMucmVwb3J0LCB0aGlzLl9maWx0ZXJTdGF0ZS5mcmVxdWVuY3koKSkpIHtcclxuICAgICAgdGhpcy5fZmlsdGVyU3RhdGUuc2V0RnJlcXVlbmN5KG51bGwpO1xyXG4gICAgfVxyXG5cclxuICAgIGNvbnN0IGl0ZW1zID0gcmVwb3J0SWRcclxuICAgICAgPyB0aGlzLl9yZXBvcnRHcm91cHMoKS5tYXAoKGdyb3VwKSA9PlxyXG4gICAgICAgIGZpbHRlckl0ZW1Gb3JHcm91cChncm91cCwgdGhpcy5fcmVwb3J0RGF0YSwgcmVwb3J0SWQsIHRoaXMuX2ZpbHRlclN0YXRlLnZhbHVlKGdyb3VwLmlkKSkpXHJcbiAgICAgIDogW107XHJcblxyXG4gICAgLy8gVGhlIGdyb3VwLWJ5IGNvbnRyb2wgbGVhZHMgdGhlIGJhciwgYWhlYWQgb2YgZXZlcnkgZmlsdGVyOiBpdCBzZXRzIHRoZVxyXG4gICAgLy8gZ3JhaW4gdGhlIHdob2xlIHJlcG9ydCBpcyByZWFkIGF0LCBzbyBpdCBpcyB0aGUgZmlyc3QgdGhpbmcgYSB2aWV3ZXJcclxuICAgIC8vIGRlY2lkZXMuIEl0IGlzIG5vdCBhIGZpbHRlciBncm91cCDigJQgaXQgcmUtYnVja2V0cyByb3dzIHJhdGhlciB0aGFuXHJcbiAgICAvLyBuYXJyb3dpbmcgdGhlbSDigJQgc28gaXQgaXMgcGxhY2VkIGhlcmUgcmF0aGVyIHRoYW4gb3JkZXJlZCBhbW9uZyB0aGVtLlxyXG4gICAgY29uc3QgZ3JvdXBCeUl0ZW0gPSB0aGlzLl9ncm91cEJ5SXRlbSgpO1xyXG4gICAgaWYgKGdyb3VwQnlJdGVtKSB7XHJcbiAgICAgIGl0ZW1zLnVuc2hpZnQoZ3JvdXBCeUl0ZW0pO1xyXG4gICAgfVxyXG5cclxuICAgIHRoaXMucmVwb3J0RmlsdGVyQ29uZmlnID0ge1xyXG4gICAgICAvLyBOZXZlciB0b3VjaCB0aGUgVVJMIG9yIHBlcnNpc3QgZmlsdGVyIHN0YXRlIOKAlCByZXBvcnQgZmlsdGVycyBhcmVcclxuICAgICAgLy8gc2Vzc2lvbi1vbmx5LCBvd25lZCBieSBSZXBvcnRGaWx0ZXJTdGF0ZVNlcnZpY2UuXHJcbiAgICAgIHF1ZXJ5UGFyYW06IGZhbHNlLFxyXG4gICAgICBwZXJzaXN0OiBmYWxzZSxcclxuICAgICAgaXRlbXMsXHJcbiAgICAgIGNoYW5nZTogKHF1ZXJ5KSA9PiB7XHJcbiAgICAgICAgZm9yIChjb25zdCB7IGdyb3VwSWQsIHZhbHVlIH0gb2YgZ3JvdXBWYWx1ZXNGcm9tUXVlcnkocXVlcnkgPz8ge30sIHRoaXMuX3JlcG9ydEdyb3VwcygpKSkge1xyXG4gICAgICAgICAgdGhpcy5fZmlsdGVyU3RhdGUuc2V0VmFsdWUoZ3JvdXBJZCwgdmFsdWUpO1xyXG4gICAgICAgIH1cclxuICAgICAgICAvLyBOb3QgYSBmaWx0ZXIgZ3JvdXAg4oCUIHRoZSBncmFpbiBpcyByZWFkIHN0cmFpZ2h0IG9mZiB0aGUgcXVlcnkuXHJcbiAgICAgICAgdGhpcy5fZmlsdGVyU3RhdGUuc2V0RnJlcXVlbmN5KChxdWVyeT8uW0dST1VQX0JZX0lURU1dIGFzIENoYXJ0R3JhbnVsYXJpdHkpIHx8IG51bGwpO1xyXG4gICAgICB9LFxyXG4gICAgfTtcclxuICB9XHJcblxyXG4gIC8vIFRoZSByZXBvcnQncyBncm91cC1ieSBjb250cm9sIGFzIGFuIGZzLWZpbHRlciBpdGVtLCBvciBudWxsIHdoZW4gdGhlIHJlcG9ydFxyXG4gIC8vIGhhcyBub25lIHRvIHNob3cuIFNlZWRlZCBmcm9tIHRoZSBzZXNzaW9uIHN0YXRlIHNvIHRoZSBncmFpbiB0aGUgdmlld2VyXHJcbiAgLy8gcGlja2VkIHN1cnZpdmVzIHRoZSByZXBvcnQgYmVpbmcgcmUtZmV0Y2hlZCBhZnRlciBhIGNoYXQgZWRpdC5cclxuICBwcml2YXRlIF9ncm91cEJ5SXRlbSgpOiBJRmlsdGVyQ29uZmlnSXRlbSB8IG51bGwge1xyXG4gICAgcmV0dXJuIHRoaXMucmVwb3J0XHJcbiAgICAgID8gZ3JvdXBCeUZpbHRlckl0ZW0odGhpcy5yZXBvcnQsIHRoaXMuX2ZpbHRlclN0YXRlLmZyZXF1ZW5jeSgpKVxyXG4gICAgICA6IG51bGw7XHJcbiAgfVxyXG59XHJcbiIsIjxkaXYgY2xhc3M9XCJmcy1haS1yZXBvcnQgZnMtY29sdW1uXCI+XG5cbiAgPGRpdiBjbGFzcz1cImZzLWFpLXJlcG9ydF9faGVhZGVyIGZzLXJvdy5hbGlnbi1jZW50ZXJcIj5cbiAgICA8aDIgY2xhc3M9XCJmcy1haS1yZXBvcnRfX3RpdGxlIGZzLWZsZXhcIj57eyByZXBvcnQ/Lm5hbWUgfX08L2gyPlxuXG4gICAgQGlmIChyZXBvcnQpIHtcbiAgICAgIDwhLS0gUmVwb3J0LWxldmVsIGZpbHRlcnMsIGlubGluZSB3aXRoIHRoZSB0b29sYmFyIGFjdGlvbnMuIGZzLWZpbHRlclxuICAgICAgICAgICByZWFkcyBpdHMgY29uZmlnIG9uY2UgYXQgaW5pdCwgc28gaXQncyBrZXllZCBvbiB0aGUgZmlsdGVyXG4gICAgICAgICAgIHNpZ25hdHVyZTogd2hlbiB0aGUgcmVwb3J0LWxldmVsIGZpbHRlciBzZXQgY2hhbmdlcyB0aGUgYmxvY2sgaXNcbiAgICAgICAgICAgcmVjcmVhdGVkIGFuZCByZS1yZWFkcyB0aGUgcmVidWlsdCBjb25maWcuIC0tPlxuICAgICAgQGlmIChyZXBvcnRIYXNGaWx0ZXJzKSB7XG4gICAgICAgIEBmb3IgKGtleSBvZiBbcmVwb3J0RmlsdGVyS2V5XTsgdHJhY2sga2V5KSB7XG4gICAgICAgICAgPGZzLWZpbHRlclxuICAgICAgICAgICAgICBjbGFzcz1cImZzLWFpLXJlcG9ydF9fZmlsdGVyc1wiXG4gICAgICAgICAgICAgIFtjb25maWddPVwicmVwb3J0RmlsdGVyQ29uZmlnXCI+XG4gICAgICAgICAgPC9mcy1maWx0ZXI+XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgPCEtLSBXaGF0IGxheW91dCBlZGl0aW5nIGNhbiBhZGQgb3Igc3dpdGNoIHRvLCBhbmQgdGhlIHdheSBvdXQgb2YgaXQuXG4gICAgICAgICAgIE9uZSBzdHlsZSBmb3IgYWxsIHRocmVlIOKAlCBvdXRsaW5lZCwgaWNvbiBhbmQgdGV4dC4gXCJIZWFkZXIgJiBmb290ZXJcIlxuICAgICAgICAgICBpcyBhIHRvZ2dsZTogaXQga2VlcHMgaXRzIGxhYmVsIGFuZCB0dXJucyBncmF5IHdoaWxlIGl0IGlzIG9uLiAtLT5cbiAgICAgIEBpZiAoZWRpdE1vZGUpIHtcbiAgICAgICAgPGRpdiBjbGFzcz1cImZzLWFpLXJlcG9ydF9fZWRpdC10b29scyBmcy1yb3cuYWxpZ24tY2VudGVyLmdhcC14c1wiPlxuICAgICAgICAgIDxidXR0b25cbiAgICAgICAgICAgICAgbWF0LXN0cm9rZWQtYnV0dG9uXG4gICAgICAgICAgICAgIHR5cGU9XCJidXR0b25cIlxuICAgICAgICAgICAgICBtYXRUb29sdGlwPVwiQWRkIGEgYmxvY2sgb2YgdGV4dFwiXG4gICAgICAgICAgICAgIChjbGljayk9XCJhZGRUZXh0KClcIj5cbiAgICAgICAgICAgIDxtYXQtaWNvbj50aXRsZTwvbWF0LWljb24+XG4gICAgICAgICAgICBBZGQgdGV4dFxuICAgICAgICAgIDwvYnV0dG9uPlxuICAgICAgICAgIDxidXR0b25cbiAgICAgICAgICAgICAgbWF0LXN0cm9rZWQtYnV0dG9uXG4gICAgICAgICAgICAgIHR5cGU9XCJidXR0b25cIlxuICAgICAgICAgICAgICBjbGFzcz1cImZzLWFpLXJlcG9ydF9fbWFzdGVyXCJcbiAgICAgICAgICAgICAgW2NsYXNzLmFjdGl2ZV09XCJpc01hc3Rlck1vZGVcIlxuICAgICAgICAgICAgICBbbWF0VG9vbHRpcF09XCJpc01hc3Rlck1vZGUgPyAnQmFjayB0byBlZGl0aW5nIHRoaXMgcGFnZScgOiAnRWRpdCB0aGUgaGVhZGVyIGFuZCBmb290ZXIgc2hvd24gb24gZXZlcnkgcGFnZSdcIlxuICAgICAgICAgICAgICAoY2xpY2spPVwidG9nZ2xlTWFzdGVyTW9kZSgpXCI+XG4gICAgICAgICAgICA8bWF0LWljb24+d2ViX2Fzc2V0PC9tYXQtaWNvbj5cbiAgICAgICAgICAgIEhlYWRlciAmIGZvb3RlclxuICAgICAgICAgIDwvYnV0dG9uPlxuICAgICAgICAgIDxidXR0b25cbiAgICAgICAgICAgICAgbWF0LXN0cm9rZWQtYnV0dG9uXG4gICAgICAgICAgICAgIHR5cGU9XCJidXR0b25cIlxuICAgICAgICAgICAgICAoY2xpY2spPVwidG9nZ2xlRWRpdE1vZGUoKVwiPlxuICAgICAgICAgICAgPG1hdC1pY29uPmNoZWNrPC9tYXQtaWNvbj5cbiAgICAgICAgICAgIERvbmUgZWRpdGluZ1xuICAgICAgICAgIDwvYnV0dG9uPlxuICAgICAgICA8L2Rpdj5cbiAgICAgIH1cblxuICAgICAgPCEtLSBPbmUgaWNvbiBmb3IgYm90aCBzdGF0ZXM6IGl0IHJlYWRzIGFzIHByZXNzZWQgd2hpbGUgZWRpdGluZyByYXRoZXJcbiAgICAgICAgICAgdGhhbiBzd2FwcGluZyB0byBzb21ldGhpbmcgZWxzZS4gLS0+XG4gICAgICA8YnV0dG9uXG4gICAgICAgICAgbWF0LWljb24tYnV0dG9uXG4gICAgICAgICAgdHlwZT1cImJ1dHRvblwiXG4gICAgICAgICAgY2xhc3M9XCJmcy1haS1yZXBvcnRfX3RvZ2dsZVwiXG4gICAgICAgICAgW2NsYXNzLmFjdGl2ZV09XCJlZGl0TW9kZVwiXG4gICAgICAgICAgW21hdFRvb2x0aXBdPVwiZWRpdE1vZGUgPyAnRG9uZSBlZGl0aW5nJyA6ICdFZGl0IGxheW91dCdcIlxuICAgICAgICAgIChjbGljayk9XCJ0b2dnbGVFZGl0TW9kZSgpXCI+XG4gICAgICAgIDxtYXQtaWNvbj5kYXNoYm9hcmRfY3VzdG9taXplPC9tYXQtaWNvbj5cbiAgICAgIDwvYnV0dG9uPlxuXG4gICAgICA8YnV0dG9uXG4gICAgICAgICAgbWF0LWljb24tYnV0dG9uXG4gICAgICAgICAgdHlwZT1cImJ1dHRvblwiXG4gICAgICAgICAgbWF0VG9vbHRpcD1cIkV4cG9ydFwiXG4gICAgICAgICAgW2ZzTWVudVRyaWdnZXJGb3JdPVwiZXhwb3J0TWVudVwiPlxuICAgICAgICA8bWF0LWljb24+ZG93bmxvYWQ8L21hdC1pY29uPlxuICAgICAgPC9idXR0b24+XG4gICAgICA8ZnMtbWVudSAjZXhwb3J0TWVudT5cbiAgICAgICAgPG5nLXRlbXBsYXRlXG4gICAgICAgICAgICBmcy1tZW51LWl0ZW1cbiAgICAgICAgICAgIChjbGljayk9XCJleHBvcnRQb3dlcnBvaW50KClcIj5cbiAgICAgICAgICBFeHBvcnQgUG93ZXJQb2ludFxuICAgICAgICA8L25nLXRlbXBsYXRlPlxuICAgICAgICA8bmctdGVtcGxhdGVcbiAgICAgICAgICAgIGZzLW1lbnUtaXRlbVxuICAgICAgICAgICAgKGNsaWNrKT1cImV4cG9ydFBkZigpXCI+XG4gICAgICAgICAgRXhwb3J0IFBERlxuICAgICAgICA8L25nLXRlbXBsYXRlPlxuICAgICAgICA8bmctdGVtcGxhdGVcbiAgICAgICAgICAgIGZzLW1lbnUtaXRlbVxuICAgICAgICAgICAgKGNsaWNrKT1cImV4cG9ydERhdGEoKVwiPlxuICAgICAgICAgIEV4cG9ydCBSYXcgRGF0YVxuICAgICAgICA8L25nLXRlbXBsYXRlPlxuICAgICAgICBAaWYgKChyZXBvcnQ/LnBhZ2VzPy5sZW5ndGggPz8gMCkgPiAxKSB7XG4gICAgICAgICAgPG5nLXRlbXBsYXRlXG4gICAgICAgICAgICAgIGZzLW1lbnUtaXRlbVxuICAgICAgICAgICAgICAoY2xpY2spPVwiZXhwb3J0RGF0YSh0cnVlKVwiPlxuICAgICAgICAgICAgRXhwb3J0IFJhdyBEYXRhIChUaGlzIFBhZ2UpXG4gICAgICAgICAgPC9uZy10ZW1wbGF0ZT5cbiAgICAgICAgfVxuICAgICAgPC9mcy1tZW51PlxuXG4gICAgICA8YnV0dG9uXG4gICAgICAgICAgbWF0LWljb24tYnV0dG9uXG4gICAgICAgICAgdHlwZT1cImJ1dHRvblwiXG4gICAgICAgICAgbWF0VG9vbHRpcD1cIlJlcG9ydCBzZXR0aW5nc1wiXG4gICAgICAgICAgKGNsaWNrKT1cInJlcG9ydFNldHRpbmdzKClcIj5cbiAgICAgICAgPG1hdC1pY29uPnNldHRpbmdzPC9tYXQtaWNvbj5cbiAgICAgIDwvYnV0dG9uPlxuICAgIH1cbiAgPC9kaXY+XG5cbiAgPGRpdlxuICAgICAgI3NwbGl0XG4gICAgICBjbGFzcz1cImZzLWFpLXJlcG9ydF9fc3BsaXQgZnMtcm93LmFsaWduLXN0YXJ0XCI+XG4gICAgPGZzLWFpLWNoYXRcbiAgICAgICAgI2NoYXRQYW5lbFxuICAgICAgICBjbGFzcz1cImNoYXRcIlxuICAgICAgICBbYmFzZVBhdGhdPVwiYmFzZVBhdGgoKVwiXG4gICAgICAgIFtyZXF1ZXN0RGF0YV09XCJjaGF0UmVxdWVzdERhdGEoKVwiXG4gICAgICAgIFtyZWFkeV09XCJjaGF0UGFnZUlkKCkgIT09IG51bGxcIlxuICAgICAgICAocmVzcG9uc2UpPVwib25DaGF0UmVzcG9uc2UoJGV2ZW50KVwiPlxuICAgIDwvZnMtYWktY2hhdD5cblxuICAgIDxkaXZcbiAgICAgICAgY2xhc3M9XCJyZXNpemVyXCJcbiAgICAgICAgKHBvaW50ZXJkb3duKT1cIm9uUmVzaXplU3RhcnQoJGV2ZW50KVwiPlxuICAgIDwvZGl2PlxuXG4gICAgPGRpdiBjbGFzcz1cInZpZXdlciBmcy1mbGV4IGZzLWNvbHVtblwiPlxuICAgICAgQGlmIChyZXBvcnQpIHtcbiAgICAgICAgPGFwcC1yZXBvcnQtY2FudmFzXG4gICAgICAgICAgICBbcmVwb3J0XT1cInJlcG9ydFwiXG4gICAgICAgICAgICBbZWRpdE1vZGVdPVwiZWRpdE1vZGVcIlxuICAgICAgICAgICAgW3BhZ2VJZF09XCJwYWdlSWRcIlxuICAgICAgICAgICAgKGNvbXBvbmVudFNldHRpbmdzKT1cImNvbXBvbmVudFNldHRpbmdzKCRldmVudClcIlxuICAgICAgICAgICAgKHJlcG9ydENoYW5nZWQpPVwib25DYW52YXNSZXBvcnRDaGFuZ2VkKClcIlxuICAgICAgICAgICAgKHBhZ2VDaGFuZ2VkKT1cIm9uQ2FudmFzUGFnZUNoYW5nZWQoJGV2ZW50KVwiPlxuICAgICAgICA8L2FwcC1yZXBvcnQtY2FudmFzPlxuICAgICAgfVxuICAgIDwvZGl2PlxuICA8L2Rpdj5cbjwvZGl2PlxuIl19
551
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZnMtYWktcmVwb3J0LmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3NyYy9hcHAvcmVwb3J0cy92aWV3cy9yZXBvcnQvZnMtYWktcmVwb3J0LmNvbXBvbmVudC50cyIsIi4uLy4uLy4uLy4uLy4uLy4uL3NyYy9hcHAvcmVwb3J0cy92aWV3cy9yZXBvcnQvZnMtYWktcmVwb3J0LmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFDTCxzQkFBc0IsRUFBRSx1QkFBdUIsRUFBRSxTQUFTLEVBQzFELFVBQVUsRUFBRSxVQUFVLEVBQUUsTUFBTSxFQUFFLFNBQVMsRUFBRSxRQUFRLEVBQUUsTUFBTSxFQUFFLE1BQU0sRUFBRSxLQUFLLEVBQUUsTUFBTSxFQUFFLE1BQU0sRUFBRSxTQUFTLEdBQ3RHLE1BQU0sZUFBZSxDQUFDO0FBQ3ZCLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLDRCQUE0QixDQUFDO0FBQ2hFLE9BQU8sRUFBRSxjQUFjLEVBQVUsTUFBTSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFFakUsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLDBCQUEwQixDQUFDO0FBQzNELE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQUNyRCxPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFDdkQsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sMkJBQTJCLENBQUM7QUFFN0QsT0FBTyxFQUFnQixjQUFjLEVBQXFCLE1BQU0sb0JBQW9CLENBQUM7QUFDckYsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBQ2hELE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQUVoRCxPQUFPLEVBQUUsT0FBTyxFQUFFLEtBQUssRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUN0QyxPQUFPLEVBQUUsU0FB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RUFBRSxPQUFPLEVBQUUsR0FBRyxFQUFFLENBQUMsTUFBTSxDQUFDLHFCQUFxQixDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsTUFBTSxFQUFFLEVBQUUsQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQztxQkFDdEcsV0FDUTt3QkFDUCxjQUFjO3dCQUNkLFlBQVk7d0JBQ1osaUJBQWlCO3dCQUNqQixlQUFlO3dCQUNmLGFBQWE7d0JBQ2IsZ0JBQWdCO3dCQUNoQixxQkFBcUI7cUJBQ3RCO3dEQTZHTyxNQUFNO3NCQURiLFNBQVM7dUJBQUMsT0FBTyxFQUFFLEVBQUUsTUFBTSxFQUFFLElBQUksRUFBRTtnQkFJNUIsVUFBVTtzQkFEakIsU0FBUzt1QkFBQyxXQUFXLEVBQUUsRUFBRSxNQUFNLEVBQUUsSUFBSSxFQUFFLElBQUksRUFBRSxVQUFVLEVBQUU7Z0JBTWxELE9BQU87c0JBRGQsU0FBUzt1QkFBQyxxQkFBcUIiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xuICBDVVNUT01fRUxFTUVOVFNfU0NIRU1BLCBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneSwgQ29tcG9uZW50LFxuICBEZXN0cm95UmVmLCBFbGVtZW50UmVmLCBOZ1pvbmUsIFZpZXdDaGlsZCwgY29tcHV0ZWQsIGVmZmVjdCwgaW5qZWN0LCBpbnB1dCwgb3V0cHV0LCBzaWduYWwsIHVudHJhY2tlZCxcbn0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyB0YWtlVW50aWxEZXN0cm95ZWQgfSBmcm9tICdAYW5ndWxhci9jb3JlL3J4anMtaW50ZXJvcCc7XG5pbXBvcnQgeyBBY3RpdmF0ZWRSb3V0ZSwgUGFyYW1zLCBSb3V0ZXIgfSBmcm9tICdAYW5ndWxhci9yb3V0ZXInO1xuXG5pbXBvcnQgeyBNYXRCdXR0b25Nb2R1bGUgfSBmcm9tICdAYW5ndWxhci9tYXRlcmlhbC9idXR0b24nO1xuaW1wb3J0IHsgTWF0RGlhbG9nIH0gZnJvbSAnQGFuZ3VsYXIvbWF0ZXJpYWwvZGlhbG9nJztcbmltcG9ydCB7IE1hdEljb25Nb2R1bGUgfSBmcm9tICdAYW5ndWxhci9tYXRlcmlhbC9pY29uJztcbmltcG9ydCB7IE1hdFRvb2x0aXBNb2R1bGUgfSBmcm9tICdAYW5ndWxhci9tYXRlcmlhbC90b29sdGlwJztcblxuaW1wb3J0IHsgRmlsdGVyQ29uZmlnLCBGc0ZpbHRlck1vZHVsZSwgSUZpbHRlckNvbmZpZ0l0ZW0gfSBmcm9tICdAZmlyZXN0aXRjaC9maWx0ZXInO1xuaW1wb3J0IHsgRnNNZW51TW9kdWxlIH0gZnJvbSAnQGZpcmVzdGl0Y2gvbWVudSc7XG5pbXBvcnQgeyBGc1Byb2Nlc3MgfSBmcm9tICdAZmlyZXN0aXRjaC9wcm9jZXNzJztcblxuaW1wb3J0IHsgU3ViamVjdCwgbWVyZ2UgfSBmcm9tICdyeGpzJztcbmltcG9ydCB7IGF1ZGl0VGltZSwgc3dpdGNoTWFwLCB0YWtlVW50aWwsIHRhcCB9IGZyb20gJ3J4anMvb3BlcmF0b3JzJztcblxuaW1wb3J0IHsgcHJvdmlkZUVjaGFydHNDb3JlIH0gZnJvbSAnbmd4LWVjaGFydHMnO1xuXG5pbXBvcnQgeyBGc0FpQ2hhdENvbXBvbmVudCwgRnNBaUNoYXREYXRhLCBGc0FpQ2hhdFJlc3BvbnNlIH0gZnJvbSAnQGZpcmVzdGl0Y2gvYWknO1xuXG5pbXBvcnQgeyBSZXBvcnRDYW52YXNDb21wb25lbnQgfSBmcm9tICcuLi8uLi9jb21wb25lbnRzL3JlcG9ydC1jYW52YXMvcmVwb3J0LWNhbnZhcy5jb21wb25lbnQnO1xuaW1wb3J0IHsgUmVwb3J0QWlDaGF0RGF0YSB9IGZyb20gJy4uLy4uL2RhdGEvcmVwb3J0LWFpLWNoYXQuZGF0YSc7XG5pbXBvcnQgeyBSZXBvcnREYXRhIH0gZnJvbSAnLi4vLi4vZGF0YS9yZXBvcnQuZGF0YSc7XG5pbXBvcnQgeyBDb21wb25lbnRTZXR0aW5nc0NvbXBvbmVudCwgQ29tcG9uZW50U2V0dGluZ3NSZXN1bHQgfSBmcm9tICcuLi8uLi9kaWFsb2dzL2NvbXBvbmVudC1zZXR0aW5ncy9jb21wb25lbnQtc2V0dGluZ3MuY29tcG9uZW50JztcbmltcG9ydCB7IFJlcG9ydFNldHRpbmdzQ29tcG9uZW50LCBSZXBvcnRTZXR0aW5nc1Jlc3VsdCB9IGZyb20gJy4uLy4uL2RpYWxvZ3MvcmVwb3J0LXNldHRpbmdzL3JlcG9ydC1zZXR0aW5ncy5jb21wb25lbnQnO1xuaW1wb3J0IHsgUmVwb3J0RXhwb3J0Q29sbGVjdG9yU2VydmljZSB9IGZyb20gJy4uLy4uL2V4cG9ydC9yZXBvcnQtZXhwb3J0LWNvbGxlY3Rvci5zZXJ2aWNlJztcbmltcG9ydCB7IFJlcG9ydEV4cG9ydFNlcnZpY2UgfSBmcm9tICcuLi8uLi9leHBvcnQvcmVwb3J0LWV4cG9ydC5zZXJ2aWNlJztcbmltcG9ydCB7IFJlcG9ydFBkZlNlcnZpY2UgfSBmcm9tICcuLi8uLi9leHBvcnQvcmVwb3J0LXBkZi5zZXJ2aWNlJztcbmltcG9ydCB7IFJlcG9ydFBwdHhTZXJ2aWNlIH0gZnJvbSAnLi4vLi4vZXhwb3J0L3JlcG9ydC1wcHR4LnNlcnZpY2UnO1xuaW1wb3J0IHsgZ2V0VGltZXpvbmVMYWJlbCB9IGZyb20gJy4uLy4uL2Zvcm1hdCc7XG5pbXBvcnQgeyBSZXBvcnRDaGF0Vmlld2VyU3RhdGUgfSBmcm9tICcuLi8uLi9pbnRlcmZhY2VzL3JlcG9ydC1jaGF0LXZpZXdlci1zdGF0ZS5pbnRlcmZhY2UnO1xuaW1wb3J0IHtcbiAgQ2hhcnRHcmFudWxhcml0eSwgUmVwb3J0LCBSZXBvcnRDaGF0UmVzcG9uc2UsXG4gIFJlcG9ydENvbXBvbmVudCBhcyBSZXBvcnRDb21wb25lbnRNb2RlbCwgUmVwb3J0RmlsdGVyR3JvdXAsXG59IGZyb20gJy4uLy4uL2ludGVyZmFjZXMvcmVwb3J0LmludGVyZmFjZSc7XG5pbXBvcnQge1xuICBHUk9VUF9CWV9JVEVNLCBmaWx0ZXJJdGVtRm9yR3JvdXAsIGdyb3VwQnlGaWx0ZXJJdGVtLCBncm91cEJ5U2lnbmF0dXJlLCBncm91cFZhbHVlc0Zyb21RdWVyeSxcbiAgaXNHcmFudWxhcml0eU9mZmVyZWQsXG59IGZyb20gJy4uLy4uL3JlcG9ydC1maWx0ZXItaXRlbXMnO1xuaW1wb3J0IHsgYnVpbGRSZXBvcnRVcmxQYXJhbXMsIHJlYWRSZXBvcnRVcmxQYXJhbXMgfSBmcm9tICcuLi8uLi9yZXBvcnQtdXJsLXN0YXRlJztcbmltcG9ydCB7IFJlcG9ydEZpbHRlclN0YXRlU2VydmljZSwgZGVmYXVsdFNpZ25hdHVyZSB9IGZyb20gJy4uLy4uL3NlcnZpY2VzL3JlcG9ydC1maWx0ZXItc3RhdGUuc2VydmljZSc7XG5cblxuLy8gQSBzaW5nbGUgcmVwb3J0OiB0aGUgQUkgY2hhdCBvbiB0aGUgbGVmdCwgdGhlIHJlcG9ydCBjYW52YXMgb24gdGhlIHJpZ2h0LFxuLy8gdW5kZXIgYW4gSDIgdGl0bGUgKyBzZXR0aW5ncyBnZWFyLiBUaGUgaG9zdCBzdXBwbGllcyBbcmVwb3J0SWRdIChmcm9tIGl0c1xuLy8gcm91dGUpIGFuZCBzd2l0Y2hlcyByZXBvcnRzIHRocm91Z2ggaXRzIG93biByb3V0ZXMg4oCUIHRoaXMgY29tcG9uZW50IG5ldmVyXG4vLyBwaWNrcyBvbmUuXG5AQ29tcG9uZW50KHtcbiAgc2VsZWN0b3I6ICdmcy1haS1yZXBvcnQnLFxuICB0ZW1wbGF0ZVVybDogJy4vZnMtYWktcmVwb3J0LmNvbXBvbmVudC5odG1sJyxcbiAgc3R5bGVVcmxzOiBbJy4vZnMtYWktcmVwb3J0LmNvbXBvbmVudC5zY3NzJ10sXG4gIGNoYW5nZURldGVjdGlvbjogQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3kuT25QdXNoLFxuICBzdGFuZGFsb25lOiB0cnVlLFxuICBzY2hlbWFzOiBbQ1VTVE9NX0VMRU1FTlRTX1NDSEVNQV0sXG4gIHByb3ZpZGVyczogW1xuICAgIC8vIFNlc3Npb24gZmlsdGVyIHN0YXRlIGlzIHBlci1vcGVuLXJlcG9ydCwgbm90IGFwcC1nbG9iYWw7IHRoZSBleHBvcnRcbiAgICAvLyBzZXJ2aWNlcyByZXNvbHZlIGZpbHRlcnMgdGhyb3VnaCBpdCwgc28gdGhleSBsaXZlIGF0IHRoZSBzYW1lIGxldmVsLlxuICAgIFJlcG9ydEZpbHRlclN0YXRlU2VydmljZSxcbiAgICBSZXBvcnRFeHBvcnRDb2xsZWN0b3JTZXJ2aWNlLFxuICAgIFJlcG9ydFBwdHhTZXJ2aWNlLFxuICAgIFJlcG9ydFBkZlNlcnZpY2UsXG4gICAgUmVwb3J0RXhwb3J0U2VydmljZSxcbiAgICAvLyBmcy1haS1jaGF0IHNpdHMgaW4gdGhpcyB0ZW1wbGF0ZSwgc28gaXQgcmVzb2x2ZXMgaXRzIGdhdGV3YXkgaGVyZTogdGhlXG4gICAgLy8gcmVwb3J0IG9uZSwgd2hpY2ggYWRkcyB0aGUgdmlld2VyJ3Mgc3RhdGUgdG8gZWFjaCB0dXJuIGl0IHNlbmRzLlxuICAgIFJlcG9ydEFpQ2hhdERhdGEsXG4gICAgeyBwcm92aWRlOiBGc0FpQ2hhdERhdGEsIHVzZUV4aXN0aW5nOiBSZXBvcnRBaUNoYXREYXRhIH0sXG4gICAgLy8gVHJlZS1zaGFrZW4gRUNoYXJ0cyBjb3JlICsgdGhlICdyZXBvcnQnIGhvdXNlIHRoZW1lLCBsb2FkZWQgbGF6aWx5LlxuICAgIHByb3ZpZGVFY2hhcnRzQ29yZSh7IGVjaGFydHM6ICgpID0+IGltcG9ydCgnLi4vLi4vdGhlbWUvZWNoYXJ0cycpLnRoZW4oKG1vZHVsZSkgPT4gbW9kdWxlLmRlZmF1bHQpIH0pLFxuICBdLFxuICBpbXBvcnRzOiBbXG4gICAgRnNGaWx0ZXJNb2R1bGUsXG4gICAgRnNNZW51TW9kdWxlLFxuICAgIEZzQWlDaGF0Q29tcG9uZW50LFxuICAgIE1hdEJ1dHRvbk1vZHVsZSxcbiAgICBNYXRJY29uTW9kdWxlLFxuICAgIE1hdFRvb2x0aXBNb2R1bGUsXG4gICAgUmVwb3J0Q2FudmFzQ29tcG9uZW50LFxuICBdLFxufSlcbmV4cG9ydCBjbGFzcyBGc0FpUmVwb3J0Q29tcG9uZW50IHtcblxuICAvLyBUaGUgcmVwb3J0IHRoaXMgdmlldyBpcyBmb2N1c2VkIG9uIOKAlCBzdXBwbGllZCBieSB0aGUgaG9zdCBmcm9tIHRoZSByb3V0ZS5cbiAgcHVibGljIHJlYWRvbmx5IHJlcG9ydElkID0gaW5wdXQ8bnVtYmVyIHwgbnVsbD4obnVsbCk7XG5cbiAgLy8gQVBJIGJhc2UgZm9yIHRoZSByZXBvcnRzICsgY2hhdCBlbmRwb2ludHM7IG92ZXJyaWRlIHRvIG1vdW50IGVsc2V3aGVyZS5cbiAgcHVibGljIHJlYWRvbmx5IGJhc2VQYXRoID0gaW5wdXQ8c3RyaW5nPigncmVwb3J0cycpO1xuXG4gIC8vIFRoZSBxdWVyeSBwYXJhbSB0aGF0IGNhcnJpZXMgdGhlIG9wZW4gcGFnZSdzIGlkLiBEZWVwIGxpbmtpbmcgaXMgb24gYnlcbiAgLy8gZGVmYXVsdDsgYSBob3N0IHRoYXQgbW91bnRzIHNldmVyYWwgcmVwb3J0cyBvbiBvbmUgcm91dGUsIG9yIHdhbnRzIG5vIFVSTFxuICAvLyB3cml0ZXMgYXQgYWxsLCBzZXRzIHRoaXMgdG8gbnVsbCB0byB0dXJuIGl0IG9mZi5cbiAgcHVibGljIHJlYWRvbmx5IHBhZ2VRdWVyeVBhcmFtID0gaW5wdXQ8c3RyaW5nIHwgbnVsbD4oJ3BhZ2UnKTtcblxuICAvLyBXaGV0aGVyIHRoZSB2aWV3ZXIncyBmaWx0ZXJzLCBncm91cC1ieSBncmFpbiBhbmQgbGlzdCBzb3J0cyBsaXZlIGluIHRoZSBVUkxcbiAgLy8gKGc8Z3JvdXBJZD4sIGdyb3VwQnksIHM8Y29tcG9uZW50SWQ+OyBzZWUgcmVwb3J0LXVybC1zdGF0ZS50cyksIHNvIGFcbiAgLy8gcmVmcmVzaCBvciBhIHNoYXJlZCBsaW5rIG9wZW5zIHRoZSByZXBvcnQgYXMgaXQgd2FzIHNlZW4uIE9uIGJ5IGRlZmF1bHQ7IGFcbiAgLy8gaG9zdCB0aGF0IG1vdW50cyBzZXZlcmFsIHJlcG9ydHMgb24gb25lIHJvdXRlLCBvciB1c2VzIHF1ZXJ5IGtleXMgc2hhcGVkXG4gIC8vIGxpa2UgZzxuPiBvciBzPG4+IGl0c2VsZiwgdHVybnMgaXQgb2ZmLlxuICBwdWJsaWMgcmVhZG9ubHkgdXJsU3RhdGUgPSBpbnB1dDxib29sZWFuPih0cnVlKTtcblxuICAvLyBUaGUgcmVwb3J0IHdhcyBkZWxldGVkIGZyb20gaXRzIHNldHRpbmdzIGRpYWxvZyDigJQgdGhlIGhvc3Qgcm91dGVzIGJhY2sgdG9cbiAgLy8gdGhlIGxpc3RpbmcuXG4gIHB1YmxpYyByZWFkb25seSBkZWxldGVkID0gb3V0cHV0PG51bWJlcj4oKTtcblxuICAvLyBUaGUgcmVwb3J0IHdhcyByZW5hbWVkIChzZXR0aW5ncywgb3IgdGhlIGFnZW50KSDigJQgdGhlIGhvc3QgY2FuIHJlZnJlc2ggYVxuICAvLyBicmVhZGNydW1iIC8gZG9jdW1lbnQgdGl0bGUuXG4gIHB1YmxpYyByZWFkb25seSByZW5hbWVkID0gb3V0cHV0PFJlcG9ydD4oKTtcblxuICAvLyBUaGUgdmlld2VyIG1vdmVkIHRvIGFub3RoZXIgcGFnZS4gVGhpcyB2aWV3IHdyaXRlcyB0aGUgVVJMIGl0c2VsZiAocmlnaHRcbiAgLy8gYWZ0ZXIgdGhpcyBmaXJlcykg4oCUIHRoaXMgaXMgZm9yIGhvc3RzIHRoYXQgdHJhY2sgdGhlIG9wZW4gcGFnZSBmb3IgdGhlaXJcbiAgLy8gb3duIHJlYXNvbnMuXG4gIHB1YmxpYyByZWFkb25seSBwYWdlQ2hhbmdlZCA9IG91dHB1dDxudW1iZXIgfCBudWxsPigpO1xuXG4gIHB1YmxpYyByZWFkb25seSByZXBvcnQgPSBzaWduYWw8UmVwb3J0IHwgbnVsbD4obnVsbCk7XG4gIHB1YmxpYyByZWFkb25seSBlZGl0TW9kZSA9IHNpZ25hbChmYWxzZSk7XG5cbiAgLy8gVGhlIHRvb2xiYXIncyB6b25lIGluZGljYXRvciAoJ05ldyBZb3JrIChFRFQpJyk6IHRoZSB6b25lIGV2ZXJ5IGRhdGUgaW5cbiAgLy8gdGhpcyByZXBvcnQgaXMgZmlsdGVyZWQgYW5kIGdyb3VwZWQgaW4uIEVtcHR5IHdoZW4gdGhlIHNlcnZlciBpcyB0b28gb2xkXG4gIC8vIHRvIHNlbmQgdGhlIGVmZmVjdGl2ZSB6b25lLCBhbmQgdGhlIGluZGljYXRvciBpcyBub3Qgc2hvd24uXG4gIHB1YmxpYyByZWFkb25seSB0aW1lem9uZUxhYmVsID0gY29tcHV0ZWQoKCkgPT4ge1xuICAgIGNvbnN0IGVmZmVjdGl2ZVRpbWV6b25lID0gdGhpcy5yZXBvcnQoKT8uZWZmZWN0aXZlVGltZXpvbmU7XG5cbiAgICByZXR1cm4gZWZmZWN0aXZlVGltZXpvbmUgPyBnZXRUaW1lem9uZUxhYmVsKGVmZmVjdGl2ZVRpbWV6b25lKSA6ICcnO1xuICB9KTtcblxuICAvLyBUaGUgcGFnZSB0aGUgY2FudmFzIHNob3VsZCBvcGVuIG9uLCByZWFkIGZyb20gdGhlIFVSTCBvbmNlIHBlciByZXBvcnQuXG4gIC8vIENsZWFyZWQgYXMgc29vbiBhcyB0aGUgY2FudmFzIHJlcG9ydHMgYmFjaywgc28gYSBsYXRlciBpbi1hcHAgcGFnZSBjaGFuZ2VcbiAgLy8gaXMgbmV2ZXIgZm91Z2h0IGJ5IGEgc3RhbGUgdmFsdWUuXG4gIHB1YmxpYyByZWFkb25seSBwYWdlSWQgPSBzaWduYWw8bnVtYmVyIHwgbnVsbD4obnVsbCk7XG5cbiAgLy8gVGhlIHBhZ2UgdGhlIGNoYXQgaXMgYm91bmQgdG86IHRoZSBvbmUgb24gc2NyZWVuLiBBIHJlcG9ydCBjb252ZXJzYXRpb25cbiAgLy8gYmVsb25ncyB0byBleGFjdGx5IG9uZSBwYWdlLCBzbyB0aGlzIGJvdGggc2NvcGVzIHRoZSBjb252ZXJzYXRpb24gbGlzdCBhbmRcbiAgLy8gYmVjb21lcyB0aGUgbmV3IGNvbnZlcnNhdGlvbidzIHBhZ2UuIEEgc2lnbmFsIGJlY2F1c2UgaXQgZmVlZHNcbiAgLy8gW3JlcXVlc3REYXRhXSDigJQgY2hhbmdpbmcgaXQgaXMgd2hhdCByZWxvYWRzIHRoZSBwYW5lbCBvbnRvIHRoZSBuZXcgcGFnZSdzXG4gIC8vIGNvbnZlcnNhdGlvbnMuIE51bGwgdW50aWwgdGhlIGNhbnZhcyByZXBvcnRzIHdoaWNoIHBhZ2UgaXQgb3BlbmVkIG9uLCB3aGljaFxuICAvLyBrZWVwcyB0aGUgY2hhdCBmcm9tIGxpc3RpbmcgYWdhaW5zdCBhIHBhZ2UgZ3Vlc3MuXG4gIHB1YmxpYyByZWFkb25seSBjaGF0UGFnZUlkID0gc2lnbmFsPG51bWJlciB8IG51bGw+KG51bGwpO1xuXG4gIC8vIFdoYXQgdGhlIGNoYXQgc2VuZHMgd2l0aCBldmVyeSBjb252ZXJzYXRpb24gY2FsbDogdGhlIHJlcG9ydCwgYW5kIHRoZSBwYWdlXG4gIC8vIGl0IGlzIGJvdW5kIHRvLlxuICAvL1xuICAvLyByZXBvcnRQYWdlSWQgaXMgT01JVFRFRCwgbm90IHNlbnQgYXMgbnVsbCwgd2hpbGUgdGhlIG9wZW4gcGFnZSBpcyB1bmtub3duLlxuICAvLyBUaGUgYmFja2VuZCByZWFkcyBhIFBSRVNFTlQgcmVwb3J0UGFnZUlkIG9mIDAvbnVsbCBhcyBcInRoZSByZXBvcnQncyBlYXJsaWVyLFxuICAvLyBwYWdlLWxlc3MgY29udmVyc2F0aW9uc1wiLCBzbyBzZW5kaW5nIG51bGwgYmVmb3JlIHRoZSBjYW52YXMgaGFzIHJlcG9ydGVkIGluXG4gIC8vIHdvdWxkIGFzayBmb3IgdGhlIHdyb25nIGxpc3Qg4oCUIGFuZCwgd29yc2UsIHdvdWxkIGJpbmQgYSBjb252ZXJzYXRpb24gc3RhcnRlZFxuICAvLyBpbiB0aGF0IHdpbmRvdyB0byBubyBwYWdlIGF0IGFsbC5cbiAgLy9cbiAgLy8gVGhlIGNoYXQgaXMgYWxzbyBoZWxkIGNsb3NlZCAoW3JlYWR5XSBpbiB0aGUgdGVtcGxhdGUpIHVudGlsIHRoZSBwYWdlIGlzXG4gIC8vIGtub3duLCBzbyB0aGlzIHBhcnRpYWwgY29udGV4dCBpcyBuZXZlciBhY3R1YWxseSBzZW50OiBvbiBhIGZyZXNoIGxvYWQgdGhlXG4gIC8vIHJlcG9ydCBoYXMgdG8gYXJyaXZlIGFuZCB0aGUgY2FudmFzIGhhcyB0byByZW5kZXIgYmVmb3JlIGFueSBwYWdlIGV4aXN0cyxcbiAgLy8gYW5kIGEgbGlzdCBmZXRjaGVkIGluIHRoYXQgd2luZG93IHdvdWxkIGJlIHRoZSB3aG9sZSByZXBvcnQncyBjb252ZXJzYXRpb25zXG4gIC8vIOKAlCB0aGUgdW5zY29wZWQgbGlzdCwgc2hvd24gYW5kIGF1dG8tc2VsZWN0ZWQgYmVmb3JlIHRoZSByZWFsIG9uZSBsYW5kcy5cbiAgcHVibGljIHJlYWRvbmx5IGNoYXRSZXF1ZXN0RGF0YSA9IGNvbXB1dGVkPFJlY29yZDxzdHJpbmcsIHVua25vd24+PigoKSA9PiB7XG4gICAgY29uc3QgcmVwb3J0UGFnZUlkID0gdGhpcy5jaGF0UGFnZUlkKCk7XG5cbiAgICByZXR1cm4gcmVwb3J0UGFnZUlkID09PSBudWxsXG4gICAgICA/IHsgcmVwb3J0SWQ6IHRoaXMucmVwb3J0SWQoKSB9XG4gICAgICA6IHsgcmVwb3J0SWQ6IHRoaXMucmVwb3J0SWQoKSwgcmVwb3J0UGFnZUlkIH07XG4gIH0pO1xuXG4gIC8vIFRoZSByZXBvcnQtbGV2ZWwgZmlsdGVyIHRvb2xiYXIgKGZzLWZpbHRlcikuIFJlYnVpbHQgd2hlbmV2ZXIgdGhlIGxvYWRlZFxuICAvLyByZXBvcnQgKGFuZCB0aHVzIGl0cyBncm91cHMpIGNoYW5nZXMuXG4gIHB1YmxpYyByZWFkb25seSByZXBvcnRGaWx0ZXJDb25maWcgPSBzaWduYWw8RmlsdGVyQ29uZmlnIHwgbnVsbD4obnVsbCk7XG5cbiAgLy8gR2F0ZXMgdGhlIHRvb2xiYXIgZnMtZmlsdGVyIHNvIGl0IGlzbid0IHJlbmRlcmVkIHdoZW4gdGhlcmUgaXMgbm90aGluZyB0b1xuICAvLyBwdXQgaW4gaXQg4oCUIG5vIHJlcG9ydC1sZXZlbCBmaWx0ZXJzIGFuZCBubyBncm91cC1ieSBjb250cm9sLlxuICBwdWJsaWMgcmVhZG9ubHkgcmVwb3J0SGFzRmlsdGVycyA9IGNvbXB1dGVkKCgpID0+IHtcbiAgICByZXR1cm4gdGhpcy5fcmVwb3J0R3JvdXBzKCkubGVuZ3RoID4gMCB8fCAhIXRoaXMuX2dyb3VwQnlJdGVtKCk7XG4gIH0pO1xuXG4gIC8vIGZzLWZpbHRlciByZWFkcyBpdHMgY29uZmlnIG9ubHkgb25jZSAoYXQgaW5pdCkuIFRoZSB0ZW1wbGF0ZSBrZXlzIHRoZVxuICAvLyB0b29sYmFyIGZzLWZpbHRlciBvbiB0aGlzIHNpZ25hdHVyZSBzbyBpdCdzIHJlY3JlYXRlZCAoYW5kIHJlLXJlYWRzIHRoZVxuICAvLyByZWJ1aWx0IGNvbmZpZykgd2hlbmV2ZXIgdGhlIHJlcG9ydC1sZXZlbCBmaWx0ZXIgc2V0IGNoYW5nZXMuXG4gIHB1YmxpYyByZWFkb25seSByZXBvcnRGaWx0ZXJLZXkgPSBjb21wdXRlZCgoKSA9PiB7XG4gICAgcmV0dXJuIFtcbiAgICAgIC8vIFRoZSBlZmZlY3RpdmUgem9uZSBpcyBwYXJ0IG9mIGl0IHRvbzogYSB6b25lIGNoYW5nZSByZS1yZXNvbHZlcyByZWxhdGl2ZVxuICAgICAgLy8gcHJlc2V0cywgYW5kIHRoZSBiYXIgbXVzdCBiZSByZWNyZWF0ZWQgdG8gc2hvdyB0aGUgbmV3IGRheXMuXG4gICAgICB0aGlzLl9maWx0ZXJTdGF0ZS50aW1lem9uZSgpLFxuICAgICAgLy8gVGhlIHN0b3JlZCBkZWZhdWx0IGlzIHBhcnQgb2YgdGhlIHNpZ25hdHVyZTogc2F2aW5nIGEgbmV3IGRlZmF1bHQgaW4gcmVwb3J0XG4gICAgICAvLyBzZXR0aW5ncyByZWJ1aWxkcyB0aGUgY29uZmlnLCBidXQgd2l0aG91dCBhIGtleSBjaGFuZ2UgZnMtZmlsdGVyIGtlZXBzXG4gICAgICAvLyByZW5kZXJpbmcgdGhlIHZhbHVlcyBpdCB3YXMgY3JlYXRlZCB3aXRoIHVudGlsIGEgZnVsbCBwYWdlIHJlbG9hZC5cbiAgICAgIGdyb3VwQnlTaWduYXR1cmUodGhpcy5yZXBvcnQoKSksXG4gICAgICAuLi50aGlzLl9yZXBvcnRHcm91cHMoKS5tYXAoKGdyb3VwKSA9PiBgJHtncm91cC5pZH06JHtncm91cC5sZXZlbH06JHtncm91cC5sYWJlbH06JHtkZWZhdWx0U2lnbmF0dXJlKGdyb3VwKX1gKSxcbiAgICBdLmpvaW4oJ3wnKTtcbiAgfSk7XG5cbiAgQFZpZXdDaGlsZCgnc3BsaXQnLCB7IHN0YXRpYzogdHJ1ZSB9KVxuICBwcml2YXRlIF9zcGxpdCE6IEVsZW1lbnRSZWY8SFRNTERpdkVsZW1lbnQ+O1xuXG4gIEBWaWV3Q2hpbGQoJ2NoYXRQYW5lbCcsIHsgc3RhdGljOiB0cnVlLCByZWFkOiBFbGVtZW50UmVmIH0pXG4gIHByaXZhdGUgX2NoYXRQYW5lbCE6IEVsZW1lbnRSZWY8SFRNTEVsZW1lbnQ+O1xuXG4gIC8vIE9ubHkgdGhlIGNhbnZhcyBrbm93cyB3aGljaCBwYWdlIGlzIG9uIHNjcmVlbiwgYW5kIGEgcGFnZS1zY29wZWQgZXhwb3J0XG4gIC8vIGhhcyB0byBhc2sgaXQuXG4gIEBWaWV3Q2hpbGQoUmVwb3J0Q2FudmFzQ29tcG9uZW50KVxuICBwcml2YXRlIF9jYW52YXM/OiBSZXBvcnRDYW52YXNDb21wb25lbnQ7XG5cbiAgcHJpdmF0ZSBfcmVwb3J0RGF0YSA9IGluamVjdChSZXBvcnREYXRhKTtcbiAgcHJpdmF0ZSBfcmVwb3J0QWlDaGF0RGF0YSA9IGluamVjdChSZXBvcnRBaUNoYXREYXRhKTtcbiAgcHJpdmF0ZSBfcm91dGVyID0gaW5qZWN0KFJvdXRlcik7XG4gIHByaXZhdGUgX3JvdXRlID0gaW5qZWN0KEFjdGl2YXRlZFJvdXRlKTtcbiAgcHJpdmF0ZSBfZmlsdGVyU3RhdGUgPSBpbmplY3QoUmVwb3J0RmlsdGVyU3RhdGVTZXJ2aWNlKTtcbiAgcHJpdmF0ZSBfZXhwb3J0U2VydmljZSA9IGluamVjdChSZXBvcnRFeHBvcnRTZXJ2aWNlKTtcbiAgcHJpdmF0ZSBfY29sbGVjdG9yID0gaW5qZWN0KFJlcG9ydEV4cG9ydENvbGxlY3RvclNlcnZpY2UpO1xuICBwcml2YXRlIF9wcm9jZXNzID0gaW5qZWN0KEZzUHJvY2Vzcyk7XG4gIHByaXZhdGUgX2RpYWxvZyA9IGluamVjdChNYXREaWFsb2cpO1xuICBwcml2YXRlIF9kZXN0cm95UmVmID0gaW5qZWN0KERlc3Ryb3lSZWYpO1xuICBwcml2YXRlIF96b25lID0gaW5qZWN0KE5nWm9uZSk7XG5cbiAgLy8gVGhlIHJlcG9ydCB3aG9zZSBVUkwgc3RhdGUgaGFzIGJlZW4gcmVhZC4gVGhlIFVSTCBpcyByZWFkIG9ubHkgb24gYVxuICAvLyByZXBvcnQncyBmaXJzdCBsb2FkOyBhIHJlbG9hZCBhZnRlciBhIGNoYXQgb3IgZGlhbG9nIGVkaXQga2VlcHMgdGhlIHN0YXRlXG4gIC8vIGluIG1lbW9yeSwgd2hpY2ggaXMgbmV3ZXIgdGhhbiBhbnl0aGluZyB0aGUgVVJMIGhvbGRzLlxuICBwcml2YXRlIF9yZXN0b3JlZFJlcG9ydElkOiBudW1iZXIgfCBudWxsID0gbnVsbDtcblxuICAvLyBXaGV0aGVyIHRoZSBjYW52YXMgaGFzIHJlcG9ydGVkIHRoZSBvcGVuIHBhZ2UgZm9yIHRoaXMgcmVwb3J0LiBVbnRpbCBpdFxuICAvLyBoYXMsIHRoZSBwYWdlIHBhcmFtIGluIHRoZSBVUkwgaXMgdGhlIGRlZXAgbGluayBzdGlsbCBiZWluZyBob25vcmVkLCBhbmRcbiAgLy8gdGhlIFVSTCB3cml0ZXIgbGVhdmVzIGl0IGFsb25lLlxuICBwcml2YXRlIF9wYWdlUmVwb3J0ZWQgPSBmYWxzZTtcblxuICAvLyBUaGUgY2FudmFzIG1vdmVkIHRvIGFub3RoZXIgcGFnZS4gTWVyZ2VkIGludG8gdGhlIHNpbmdsZSBVUkwgd3JpdGVyLlxuICBwcml2YXRlIF9wYWdlV3JpdGUkID0gbmV3IFN1YmplY3Q8dm9pZD4oKTtcblxuICBjb25zdHJ1Y3RvcigpIHtcbiAgICAvLyBFYWNoIGNoYXQgdHVybiBjYXJyaWVzIHdoYXQgdGhlIHZpZXdlciBoYXMgb24gc2NyZWVuLiBPbmx5IHRoZSBmdW5jdGlvblxuICAgIC8vIGlzIHNldCBoZXJlOyBpdCBpcyBjYWxsZWQgd2hlbiBhIHR1cm4gaXMgc2VudC5cbiAgICB0aGlzLl9yZXBvcnRBaUNoYXREYXRhLnR1cm5EYXRhID0gKCkgPT4gKHsgdmlld2VyU3RhdGU6IHRoaXMuX2NoYXRWaWV3ZXJTdGF0ZSgpIH0pO1xuXG4gICAgLy8gVGhlIE9ORSB3cml0ZXIgb2YgdGhpcyB2aWV3J3MgcXVlcnkgcGFyYW1zLiBQYWdlIG1vdmVzIGFuZCB2aWV3ZXItc3RhdGVcbiAgICAvLyBjaGFuZ2VzIGJvdGggZnVubmVsIGhlcmUsIGFuZCBhdWRpdFRpbWUoMCkgZm9sZHMgYSBidXJzdCAoYSBiYXIgcmUtc2V0c1xuICAgIC8vIGV2ZXJ5IGdyb3VwIGl0IHNob3dzKSBpbnRvIGEgc2luZ2xlIHdyaXRlLiBFdmVyeSB3cml0ZSBjYXJyaWVzIHRoZSB3aG9sZVxuICAgIC8vIHN0YXRlLCBzbyBhIHdyaXRlIHRoYXQgc3VwZXJzZWRlcyBhbm90aGVyIGxvc2VzIG5vdGhpbmcuXG4gICAgbWVyZ2UodGhpcy5fZmlsdGVyU3RhdGUudXJsQ2hhbmdlcygpLCB0aGlzLl9wYWdlV3JpdGUkKVxuICAgICAgLnBpcGUoXG4gICAgICAgIGF1ZGl0VGltZSgwKSxcbiAgICAgICAgdGFwKCgpID0+IHRoaXMuX3dyaXRlVXJsKCkpLFxuICAgICAgICB0YWtlVW50aWxEZXN0cm95ZWQodGhpcy5fZGVzdHJveVJlZiksXG4gICAgICApXG4gICAgICAuc3Vic2NyaWJlKCk7XG5cbiAgICAvLyBQb2ludCB0aGUgc2hhcmVkIGRhdGEgZ2F0ZXdheSBhdCB0aGUgY29uZmlndXJlZCBiYXNlIGZpcnN0IChiZWZvcmUgYW55XG4gICAgLy8gbG9hZCBiZWxvdyByZWFkcyBpdCkuXG4gICAgZWZmZWN0KCgpID0+IHtcbiAgICAgIHRoaXMuX3JlcG9ydERhdGEuYmFzZVBhdGggPSB0aGlzLmJhc2VQYXRoKCk7XG4gICAgfSk7XG5cbiAgICAvLyAoUmUpbG9hZCB3aGVuZXZlciB0aGUgaG9zdCBzd2l0Y2hlcyB0aGUgcmVwb3J0IGlkLlxuICAgIGVmZmVjdCgoKSA9PiB7XG4gICAgICBjb25zdCByZXBvcnRJZCA9IHRoaXMucmVwb3J0SWQoKTtcblxuICAgICAgLy8gU2VlZCB0aGUgb3BlbiBwYWdlIGZyb20gdGhlIFVSTCBmb3IgdGhpcyByZXBvcnQuIFJlYWQgcGVyIGxvYWQgcmF0aGVyXG4gICAgICAvLyB0aGFuIG9uY2UgYXQgY29uc3RydWN0aW9uOiB0aGUgaG9zdCBtYXkgc3dhcCByZXBvcnRzIG9uIHRoZSBzYW1lIHJvdXRlLFxuICAgICAgLy8gYW5kIGVhY2ggYXJyaXZhbCBjYXJyaWVzIGl0cyBvd24gP3BhZ2U9LlxuICAgICAgY29uc3QgcGFnZUlkID0gdGhpcy5fcGFnZUlkRnJvbVVybCgpO1xuXG4gICAgICAvLyBPbmx5IHRoZSByZXBvcnQgaWQgYW5kIHRoZSBwYWdlIHBhcmFtIHJlLXJ1biB0aGlzLiBUaGUgdmlldyBzdGF0ZSBiZWxvd1xuICAgICAgLy8gaXMgd3JpdHRlbiBoZXJlIGFuZCByZWFkIGJ5IHRoZSBjb25maWcgYnVpbGQsIHNvIGl0IHN0YXlzIHVudHJhY2tlZC5cbiAgICAgIHVudHJhY2tlZCgoKSA9PiB7XG4gICAgICAgIHRoaXMuZWRpdE1vZGUuc2V0KGZhbHNlKTtcblxuICAgICAgICAvLyBBIG5ldyByZXBvcnQncyBwYWdlcyBhcmUgbm90IHRoaXMgcmVwb3J0J3MgcGFnZXMg4oCUIGRyb3AgdGhlIGJpbmRpbmdcbiAgICAgICAgLy8gdW50aWwgaXRzIGNhbnZhcyBzYXlzIHdoaWNoIHBhZ2UgaXQgbGFuZGVkIG9uLlxuICAgICAgICB0aGlzLmNoYXRQYWdlSWQuc2V0KG51bGwpO1xuICAgICAgICB0aGlzLnBhZ2VJZC5zZXQocGFnZUlkKTtcbiAgICAgICAgdGhpcy5fcGFnZVJlcG9ydGVkID0gZmFsc2U7XG5cbiAgICAgICAgaWYgKHJlcG9ydElkICE9IG51bGwpIHtcbiAgICAgICAgICB0aGlzLl9sb2FkUmVwb3J0KHJlcG9ydElkKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAvLyBGb3JnZXQgdGhlIHJlc3RvcmVkIHJlcG9ydCwgc28gYSBob3N0IHRoYXQgY29tZXMgYmFjayB0byBpdCByZWFkc1xuICAgICAgICAgIC8vIHRoZSBVUkwgYWdhaW4uXG4gICAgICAgICAgdGhpcy5fcmVzdG9yZWRSZXBvcnRJZCA9IG51bGw7XG4gICAgICAgICAgdGhpcy5yZXBvcnQuc2V0KG51bGwpO1xuICAgICAgICAgIHRoaXMuX2J1aWxkUmVwb3J0Q29uZmlnKCk7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgIH0pO1xuXG4gICAgdGhpcy5fYnVpbGRSZXBvcnRDb25maWcoKTtcbiAgfVxuXG4gIHB1YmxpYyB0b2dnbGVFZGl0TW9kZSgpOiB2b2lkIHtcbiAgICB0aGlzLmVkaXRNb2RlLnVwZGF0ZSgoZWRpdE1vZGUpID0+ICFlZGl0TW9kZSk7XG4gIH1cblxuICAvLyBUaGUgZWRpdCB0b29scyBsaXZlIGluIHRoaXMgdG9vbGJhciwgYnV0IHRoZSBjYW52YXMgb3ducyB3aGF0IHRoZXkgYWN0IG9uXG4gIC8vICh0aGUgYWN0aXZlIHBhZ2UsIHRoZSBoZWFkZXIvZm9vdGVyIGJhbmRzLCB3aGljaCBsYXllciBpcyBsaXZlKS5cbiAgcHVibGljIGdldCBpc01hc3Rlck1vZGUoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMuX2NhbnZhcz8ubWFzdGVyTW9kZSgpID8/IGZhbHNlO1xuICB9XG5cbiAgcHVibGljIGFkZFRleHQoKTogdm9pZCB7XG4gICAgdGhpcy5fY2FudmFzPy5hZGRUZXh0KCk7XG4gIH1cblxuICBwdWJsaWMgdG9nZ2xlTWFzdGVyTW9kZSgpOiB2b2lkIHtcbiAgICB0aGlzLl9jYW52YXM/LnRvZ2dsZU1hc3Rlck1vZGUoKTtcbiAgfVxuXG4gIC8vIFJlcG9ydCBzZXR0aW5ncyDigJQgbmFtZSwgcGFnZSBzaXplLCBvcmllbnRhdGlvbiwgbGF5b3V0IG1vZGUsIGRlbGV0ZS4gVGhlXG4gIC8vIGRpYWxvZyBwZXJmb3JtcyB0aGUgZGVsZXRlIGl0c2VsZjsgd2UgcmVhY3QgdG8gd2hhdCBpdCByZXBvcnRzIGJhY2suXG4gIHB1YmxpYyByZXBvcnRTZXR0aW5ncygpOiB2b2lkIHtcbiAgICBjb25zdCByZXBvcnQgPSB0aGlzLnJlcG9ydCgpO1xuICAgIGlmICghcmVwb3J0KSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgY29uc3QgcmVwb3J0SWQgPSByZXBvcnQuaWQ7XG5cbiAgICB0aGlzLl9kaWFsb2cub3BlbjxSZXBvcnRTZXR0aW5nc0NvbXBvbmVudCwgdW5rbm93biwgUmVwb3J0U2V0dGluZ3NSZXN1bHQ+KFJlcG9ydFNldHRpbmdzQ29tcG9uZW50LCB7XG4gICAgICBkYXRhOiB7IHJlcG9ydCB9LFxuICAgICAgd2lkdGg6ICc0NjBweCcsXG4gICAgfSlcbiAgICAgIC5hZnRlckNsb3NlZCgpXG4gICAgICAucGlwZSh0YWtlVW50aWxEZXN0cm95ZWQodGhpcy5fZGVzdHJveVJlZikpXG4gICAgICAuc3Vic2NyaWJlKChyZXN1bHQpID0+IHtcbiAgICAgICAgaWYgKHJlc3VsdD8uYWN0aW9uID09PSAnZGVsZXRlZCcpIHtcbiAgICAgICAgICB0aGlzLmRlbGV0ZWQuZW1pdChyZXBvcnRJZCk7XG5cbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBpZiAocmVzdWx0Py5hY3Rpb24gPT09ICdzYXZlZCcpIHtcbiAgICAgICAgICB0aGlzLl9sb2FkUmVwb3J0KHJlcG9ydElkLCB0cnVlKTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gIH1cblxuICAvLyBDb21wb25lbnQgc2V0dGluZ3Mg4oCUIHRpdGxlLCBleGFjdCBnZW9tZXRyeSwgYW5kIHRoZSBkaWFnbm9zdGljIHZpZXdzXG4gIC8vIChTUUwsIGNvbmZpZywgZmlsdGVyIHdpcmluZykuXG4gIHB1YmxpYyBjb21wb25lbnRTZXR0aW5ncyhjb21wb25lbnQ6IFJlcG9ydENvbXBvbmVudE1vZGVsKTogdm9pZCB7XG4gICAgY29uc3QgcmVwb3J0ID0gdGhpcy5yZXBvcnQoKTtcbiAgICBpZiAoIXJlcG9ydCkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGNvbnN0IHJlcG9ydElkID0gcmVwb3J0LmlkO1xuXG4gICAgY29uc3QgZGlhbG9nUmVmID0gdGhpcy5fZGlhbG9nLm9wZW48Q29tcG9uZW50U2V0dGluZ3NDb21wb25lbnQsIHVua25vd24sIENvbXBvbmVudFNldHRpbmdzUmVzdWx0PihcbiAgICAgIENvbXBvbmVudFNldHRpbmdzQ29tcG9uZW50LFxuICAgICAge1xuICAgICAgICBkYXRhOiB7IHJlcG9ydCwgY29tcG9uZW50IH0sXG4gICAgICAgIHdpZHRoOiAnNjQwcHgnLFxuICAgICAgfSxcbiAgICApO1xuXG4gICAgLy8gRmlsdGVyIGFkZC9yZW1vdmUvbGV2ZWwgY2hhbmdlcyBwZXJzaXN0IGltbWVkaWF0ZWx5IGluc2lkZSB0aGUgZGlhbG9nIChub1xuICAgIC8vIFwic2F2ZVwiKSBhbmQgY2FuIGxlYXZlIGl0IGJ5IGFuIGV4aXQgdGhhdCBjYXJyaWVzIG5vIHJlc3VsdCwgc28gdGhleSBhcmVcbiAgICAvLyBhbm5vdW5jZWQgYXMgdGhleSBsYW5kLiBUaGUgcmVsb2FkIHdhaXRzIGZvciB0aGUgY2xvc2Ugc28gdGhlIGNhbnZhcyBpc24ndFxuICAgIC8vIHJlLXJlbmRlcmluZyB1bmRlcm5lYXRoIGFuIG9wZW4gZGlhbG9nLlxuICAgIGxldCBmaWx0ZXJzQ2hhbmdlZCA9IGZhbHNlO1xuICAgIGRpYWxvZ1JlZi5jb21wb25lbnRJbnN0YW5jZS5maWx0ZXJzQ2hhbmdlZFxuICAgICAgLnBpcGUodGFrZVVudGlsKGRpYWxvZ1JlZi5hZnRlckNsb3NlZCgpKSlcbiAgICAgIC5zdWJzY3JpYmUoKCkgPT4gZmlsdGVyc0NoYW5nZWQgPSB0cnVlKTtcblxuICAgIGRpYWxvZ1JlZi5hZnRlckNsb3NlZCgpXG4gICAgICAucGlwZSh0YWtlVW50aWxEZXN0cm95ZWQodGhpcy5fZGVzdHJveVJlZikpXG4gICAgICAuc3Vic2NyaWJlKChyZXN1bHQpID0+IHtcbiAgICAgICAgLy8gVGhlIGRpYWxvZyBjb25maXJtcyArIHBlcmZvcm1zIHRoZSBkZWxldGUgaXRzZWxmLiBUaGUgY29tcG9uZW50IGlzXG4gICAgICAgIC8vIGdvbmUgZnJvbSB0aGUgcmVwb3J0LCBzbyByZWxvYWQgcmF0aGVyIHRoYW4gcGF0Y2hpbmcgaXQgb3V0IGxvY2FsbHkg4oCUXG4gICAgICAgIC8vIGl0cyBmaWx0ZXJzIHdlbnQgd2l0aCBpdCwgd2hpY2ggdGhlIHJlcG9ydCBiYXIgaGFzIHRvIGJlIHJlYnVpbHQgZm9yLlxuICAgICAgICBpZiAocmVzdWx0Py5kZWxldGVkKSB7XG4gICAgICAgICAgdGhpcy5fbG9hZFJlcG9ydChyZXBvcnRJZCk7XG5cbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICAvLyBUaGUgcmVwb3J0J3MgZmlsdGVyIGdyb3VwcyBjaGFuZ2VkLCBzbyB0aGUgcmVwb3J0IGJhciBhbmQgdGhlXG4gICAgICAgIC8vIG9uLWNvbXBvbmVudCBzdHJpcHMgaGF2ZSB0byBiZSByZWJ1aWx0IGZyb20gYSBmcmVzaCByZXBvcnQuXG4gICAgICAgIGlmIChmaWx0ZXJzQ2hhbmdlZCkge1xuICAgICAgICAgIHRoaXMuX2xvYWRSZXBvcnQocmVwb3J0SWQpO1xuXG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gTm90aGluZyBlbHNlIGluIHRoZSBkaWFsb2cgdG91Y2hlcyB0aGUgcXVlcnkg4oCUIHRpdGxlIGFuZCBwYWRkaW5nIGFyZVxuICAgICAgICAvLyBwcmVzZW50YXRpb24uIFJlcGFpbnQgdGhlIG9uZSBjb21wb25lbnQgaXQgd2FzIG9wZW5lZCBmb3IgYW5kIGxlYXZlXG4gICAgICAgIC8vIGV2ZXJ5IG90aGVyIGNvbXBvbmVudCdzIGRhdGEsIGFuZCBpdHMgcXVlcnksIGFsb25lLlxuICAgICAgICBpZiAocmVzdWx0Py5zZXR0aW5ncykge1xuICAgICAgICAgIHRoaXMuX2NhbnZhcz8uYXBwbHlDb21wb25lbnRTZXR0aW5ncyhjb21wb25lbnQuaWQsIHJlc3VsdC5zZXR0aW5ncyk7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICB9XG5cbiAgLy8gVGhlIGNhbnZhcyBtb3ZlZCB0byBhbm90aGVyIHBhZ2U6IHJlZmxlY3QgaXQgaW4gdGhlIFVSTCBzbyBhIHJlZnJlc2ggb3IgYVxuICAvLyBzaGFyZWQgbGluayBjb21lcyBiYWNrIGhlcmUgKHRoZSB3cml0ZSBpdHNlbGYgaXMgX3dyaXRlVXJsJ3MpLlxuICBwdWJsaWMgb25DYW52YXNQYWdlQ2hhbmdlZChwYWdlSWQ6IG51bWJlciB8IG51bGwpOiB2b2lkIHtcbiAgICAvLyBUaGUgZGVlcCBsaW5rIGhhcyBiZWVuIGNvbnN1bWVkOyBmcm9tIGhlcmUgdGhlIGNhbnZhcyBvd25zIHRoZSBwYWdlLlxuICAgIHRoaXMucGFnZUlkLnNldChudWxsKTtcbiAgICB0aGlzLmNoYXRQYWdlSWQuc2V0KHBhZ2VJZCk7XG4gICAgdGhpcy5fcGFnZVJlcG9ydGVkID0gdHJ1ZTtcbiAgICB0aGlzLnBhZ2VDaGFuZ2VkLmVtaXQocGFnZUlkKTtcbiAgICB0aGlzLl9wYWdlV3JpdGUkLm5leHQoKTtcbiAgfVxuXG4gIC8vIFRoZSBjYW52YXMgY2hhbmdlZCB0aGUgcmVwb3J0J3Mgc3RydWN0dXJlIChhZGRlZCBhIHBhZ2UpIOKAlCByZS1mZXRjaCBzbyB0aGVcbiAgLy8gbmV3IHBhZ2UgcmVuZGVyczsgdGhlIGNhbnZhcyBsYW5kcyB0aGUgdmlldyBvbiBpdC5cbiAgcHVibGljIG9uQ2FudmFzUmVwb3J0Q2hhbmdlZCgpOiB2b2lkIHtcbiAgICBjb25zdCByZXBvcnQgPSB0aGlzLnJlcG9ydCgpO1xuICAgIGlmIChyZXBvcnQpIHtcbiAgICAgIHRoaXMuX2xvYWRSZXBvcnQocmVwb3J0LmlkKTtcbiAgICB9XG4gIH1cblxuICAvLyBFeHBvcnQgdGhlIHJlcG9ydCB0byBQb3dlclBvaW50LCBlbnRpcmVseSBjbGllbnQtc2lkZSAobmF0aXZlIGVkaXRhYmxlXG4gIC8vIGNoYXJ0czsgcGFnZSA9IHNsaWRlKS4gVGhlIGRvY2sgc2hvd3MgcHJvZ3Jlc3MgdW50aWwgdGhlIGZpbGUgc2F2ZXMuXG4gIHB1YmxpYyBleHBvcnRQb3dlcnBvaW50KCk6IHZvaWQge1xuICAgIGNvbnN0IHJlcG9ydCA9IHRoaXMucmVwb3J0KCk7XG4gICAgaWYgKCFyZXBvcnQpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICB0aGlzLl9wcm9jZXNzLnJ1bihcbiAgICAgICdFeHBvcnRpbmcgUG93ZXJQb2ludCcsXG4gICAgICB0aGlzLl9leHBvcnRTZXJ2aWNlLnBvd2VycG9pbnQocmVwb3J0KSxcbiAgICApO1xuICB9XG5cbiAgLy8gRXhwb3J0IHRvIFBERiwgZW50aXJlbHkgY2xpZW50LXNpZGUgKG9mZnNjcmVlbiBFQ2hhcnRzIGF0IDPDlzsgcGFnZSA9IFBERiBwYWdlKS5cbiAgcHVibGljIGV4cG9ydFBkZigpOiB2b2lkIHtcbiAgICBjb25zdCByZXBvcnQgPSB0aGlzLnJlcG9ydCgpO1xuICAgIGlmICghcmVwb3J0KSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgdGhpcy5fcHJvY2Vzcy5ydW4oXG4gICAgICAnRXhwb3J0aW5nIFBERicsXG4gICAgICB0aGlzLl9leHBvcnRTZXJ2aWNlLnBkZihyZXBvcnQpLFxuICAgICk7XG4gIH1cblxuICAvLyBUaGUgd2hvbGUgcmVwb3J0IGFzIGZpbGVzIGluIG9uZSBhY3Rpb246IHRoZSBzZXJ2ZXIgd3JpdGVzIG9uZSBDU1YgcGVyXG4gIC8vIGNvbXBvbmVudCwgZWFjaCB3aGF0IHRoZSBzY3JlZW4gc2hvd3MgKGEgY2hhcnQgb3IgS1BJIGFzIGRyYXduLCBhdCB0aGVcbiAgLy8gdmlld2VyJ3MgZ3JvdXAtYnkgZ3JhaW47IGEgbGlzdCBpbiBmdWxsKSwgYW5kIHppcHMgdGhlbSBmb2xkZXJlZCBieSBwYWdlXG4gIC8vIHdpdGggYW4gRXhwb3J0IE5vdGVzLnR4dCB0aGF0IHJlY29yZHMgdGhlIGZpbHRlcnMgYXMgdGhlIGJhciByZWFkcyB0aGVtLlxuICAvLyBMaXN0cyB1c2UgdGhlaXIgc2F2ZWQgZGVmYXVsdCBzb3J0OyBhIGhlYWRlciBjbGljayBpcyBjYXJyaWVkIG9ubHkgYnkgYVxuICAvLyBjb21wb25lbnQncyBvd24gQ1NWIGV4cG9ydC4gYHRoaXNQYWdlYCBuYXJyb3dzIGl0IHRvIHRoZSBwYWdlIHRoZSBjYW52YXMgaXNcbiAgLy8gc2hvd2luZy4gVW5saWtlIHRoZSBQREYvUG93ZXJQb2ludCBleHBvcnRzIHRoZSBmaWxlcyBhcmUgd3JpdHRlblxuICAvLyBzZXJ2ZXItc2lkZSwgc28gdGhleSBhcmUgbm90IGNhcHBlZCBieSB3aGF0IGEgc2xpZGUgY2FuIGhvbGQuXG4gIHB1YmxpYyBleHBvcnREYXRhKHRoaXNQYWdlID0gZmFsc2UpOiB2b2lkIHtcbiAgICBjb25zdCByZXBvcnQgPSB0aGlzLnJlcG9ydCgpO1xuICAgIGlmICghcmVwb3J0KSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgY29uc3QgcGFnZUlkID0gdGhpc1BhZ2UgPyB0aGlzLl9jYW52YXM/LmFjdGl2ZVBhZ2U/LmlkID8/IG51bGwgOiBudWxsO1xuICAgIGNvbnN0IGZpbHRlcnMgPSB0aGlzLl9maWx0ZXJTdGF0ZS5yZXNvbHZlRm9yUmVwb3J0KHJlcG9ydCwgcGFnZUlkKTtcbiAgICBjb25zdCBmcmVxdWVuY3kgPSB0aGlzLl9maWx0ZXJTdGF0ZS5mcmVxdWVuY3koKTtcblxuICAgIHRoaXMuX3Byb2Nlc3MuZG93bmxvYWQoXG4gICAgICAnRXhwb3J0aW5nIGRhdGEnLFxuICAgICAgdGhpcy5fY29sbGVjdG9yLmdldEZpbHRlclN1bW1hcnkocmVwb3J0KVxuICAgICAgICAucGlwZShcbiAgICAgICAgICBzd2l0Y2hNYXAoKGxpbmVzKSA9PiB0aGlzLl9yZXBvcnREYXRhLmV4cG9ydFJlcG9ydChcbiAgICAgICAgICAgIHJlcG9ydC5pZCxcbiAgICAgICAgICAgIGZpbHRlcnMsXG4gICAgICAgICAgICBwYWdlSWQsXG4gICAgICAgICAgICBmcmVxdWVuY3ksXG4gICAgICAgICAgICBsaW5lcyxcbiAgICAgICAgICApKSxcbiAgICAgICAgKSxcbiAgICApO1xuICB9XG5cbiAgLy8gUmVhY3QgdG8gZWFjaCBjaGF0IHR1cm4gKGZzLWNoYXQgaGFuZGxlcyB0aGUgcmVxdWVzdCArIHBlcnNpc3RlbmNlKTsgd2VcbiAgLy8gb25seSBjYXJlIGFib3V0IHRoZSByZXBvcnQgc2lkZSBlZmZlY3RzIHRoaXMgY29udGV4dCdzIGJhY2tlbmQgZmxhZ3MuXG4gIHB1YmxpYyBvbkNoYXRSZXNwb25zZShyZXNwb25zZTogRnNBaUNoYXRSZXNwb25zZSk6IHZvaWQge1xuICAgIGNvbnN0IHJlcG9ydElkID0gdGhpcy5yZXBvcnRJZCgpO1xuICAgIGlmIChyZXBvcnRJZCA9PSBudWxsKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgY29uc3QgcmVwb3J0UmVzcG9uc2UgPSByZXNwb25zZSBhcyBGc0FpQ2hhdFJlc3BvbnNlICYgUmVwb3J0Q2hhdFJlc3BvbnNlO1xuXG4gICAgLy8gQSBzdHJ1Y3R1cmFsIGNoYW5nZSBvciBhIHJlbmFtZSBib3RoIHJlLWZldGNoIHRoZSByZXBvcnQgKHNlc3Npb24gZmlsdGVyXG4gICAgLy8gdmFsdWVzIHN1cnZpdmUpOyBhIHJlbmFtZSBhZGRpdGlvbmFsbHkgbm90aWZpZXMgdGhlIGhvc3Qgc28gaXQgY2FuXG4gICAgLy8gcmVmcmVzaCBhIGJyZWFkY3J1bWIgLyB0aXRsZS5cbiAgICBpZiAocmVwb3J0UmVzcG9uc2UucmVwb3J0Q2hhbmdlZCB8fCByZXBvcnRSZXNwb25zZS5yZXBvcnRSZW5hbWVkKSB7XG4gICAgICB0aGlzLl9sb2FkUmVwb3J0KHJlcG9ydElkLCAhIXJlcG9ydFJlc3BvbnNlLnJlcG9ydFJlbmFtZWQpO1xuICAgIH1cbiAgfVxuXG4gIC8vIERyYWcgdGhlIGRpdmlkZXIgYmV0d2VlbiB0aGUgY2hhdCBhbmQgY2FudmFzIHBhbmVzIChwb2ludGVyLWNhcHR1cmUgbG9vcFxuICAvLyBvdXRzaWRlIEFuZ3VsYXIpLlxuICBwdWJsaWMgb25SZXNpemVTdGFydChldmVudDogUG9pbnRlckV2ZW50KTogdm9pZCB7XG4gICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcblxuICAgIGNvbnN0IGhhbmRsZSA9IGV2ZW50LnRhcmdldCBhcyBIVE1MRWxlbWVudDtcbiAgICBoYW5kbGUuc2V0UG9pbnRlckNhcHR1cmUoZXZlbnQucG9pbnRlcklkKTtcbiAgICB0aGlzLl9zcGxpdC5uYXRpdmVFbGVtZW50LmNsYXNzTGlzdC5hZGQoJ3Jlc2l6aW5nJyk7XG5cbiAgICB0aGlzLl96b25lLnJ1bk91dHNpZGVBbmd1bGFyKCgpID0+IHtcbiAgICAgIGNvbnN0IG1vdmUgPSAoZTogUG9pbnRlckV2ZW50KSA9PiB0aGlzLl9yZXNpemVUbyhlLmNsaWVudFgpO1xuICAgICAgY29uc3QgZW5kID0gKCkgPT4ge1xuICAgICAgICBoYW5kbGUucmVsZWFzZVBvaW50ZXJDYXB0dXJlKGV2ZW50LnBvaW50ZXJJZCk7XG4gICAgICAgIGhhbmRsZS5yZW1vdmVFdmVudExpc3RlbmVyKCdwb2ludGVybW92ZScsIG1vdmUpO1xuICAgICAgICBoYW5kbGUucmVtb3ZlRXZlbnRMaXN0ZW5lcigncG9pbnRlcnVwJywgZW5kKTtcbiAgICAgICAgaGFuZGxlLnJlbW92ZUV2ZW50TGlzdGVuZXIoJ3BvaW50ZXJjYW5jZWwnLCBlbmQpO1xuICAgICAgICB0aGlzLl9zcGxpdC5uYXRpdmVFbGVtZW50LmNsYXNzTGlzdC5yZW1vdmUoJ3Jlc2l6aW5nJyk7XG4gICAgICB9O1xuXG4gICAgICBoYW5kbGUuYWRkRXZlbnRMaXN0ZW5lcigncG9pbnRlcm1vdmUnLCBtb3ZlKTtcbiAgICAgIGhhbmRsZS5hZGRFdmVudExpc3RlbmVyKCdwb2ludGVydXAnLCBlbmQpO1xuICAgICAgaGFuZGxlLmFkZEV2ZW50TGlzdGVuZXIoJ3BvaW50ZXJjYW5jZWwnLCBlbmQpO1xuICAgIH0pO1xuICB9XG5cbiAgLy8gV2hhdCB0aGUgdmlld2VyIGhhcyBvbiBzY3JlZW4gYXMgYSBjaGF0IHR1cm4gc2VuZHMgaXQuIFRoZSBjYW52YXNcbiAgLy8gc2VsZWN0aW9uIGNvdW50cyBvbmx5IGluIGVkaXQgbW9kZTogaXQgaXMgZHJhd24gb25seSB0aGVuLCBhbmQgaXQgaXMga2VwdFxuICAvLyAobm90IGNsZWFyZWQpIHdoZW4gZWRpdCBtb2RlIGlzIGxlZnQuXG4gIHByaXZhdGUgX2NoYXRWaWV3ZXJTdGF0ZSgpOiBSZXBvcnRDaGF0Vmlld2VyU3RhdGUge1xuICAgIHJldHVybiB7XG4gICAgICBncmFudWxhcml0eTogdGhpcy5fZmlsdGVyU3RhdGUuZnJlcXVlbmN5KCksXG4gICAgICBzZWxlY3RlZENvbXBvbmVudElkOiB0aGlzLmVkaXRNb2RlKCkgPyB0aGlzLl9jYW52YXM/LnNlbGVjdGVkQ29tcG9uZW50SWQoKSA/PyBudWxsIDogbnVsbCxcbiAgICAgIGZpbHRlcnM6IHRoaXMuX2ZpbHRlclN0YXRlLnZpZXdlckZpbHRlcnMoKSxcbiAgICB9O1xuICB9XG5cbiAgcHJpdmF0ZSBfcmVzaXplVG8oY2xpZW50WDogbnVtYmVyKTogdm9pZCB7XG4gICAgY29uc3QgcmVjdCA9IHRoaXMuX3NwbGl0Lm5hdGl2ZUVsZW1lbnQuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XG4gICAgaWYgKHJlY3Qud2lkdGggPT09IDApIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBjb25zdCByYXRpbyA9IChjbGllbnRYIC0gcmVjdC5sZWZ0KSAvIHJlY3Qud2lkdGg7XG4gICAgY29uc3QgY2xhbXBlZCA9IE1hdGgubWluKDAuOCwgTWF0aC5tYXgoMC4yLCByYXRpbykpO1xuICAgIHRoaXMuX2NoYXRQYW5lbC5uYXRpdmVFbGVtZW50LnN0eWxlLmZsZXhCYXNpcyA9IGAke2NsYW1wZWQgKiAxMDB9JWA7XG4gIH1cblxuICAvLyBUaGUgcGFnZSBpZCBzaXR0aW5nIGluIHRoZSBVUkwgcmlnaHQgbm93LCBvciBudWxsIHdoZW4gZGVlcCBsaW5raW5nIGlzIG9mZlxuICAvLyBvciB0aGUgdmFsdWUgaXMgbm90IGEgdXNhYmxlIGlkLlxuICBwcml2YXRlIF9wYWdlSWRGcm9tVXJsKCk6IG51bWJlciB8IG51bGwge1xuICAgIGNvbnN0IHBhcmFtID0gdGhpcy5wYWdlUXVlcnlQYXJhbSgpO1xuICAgIGlmICghcGFyYW0pIHtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cblxuICAgIGNvbnN0IHBhZ2VJZCA9IE51bWJlcih0aGlzLl9yb3V0ZS5zbmFwc2hvdC5xdWVyeVBhcmFtTWFwLmdldChwYXJhbSkpO1xuXG4gICAgcmV0dXJuIE51bWJlci5pc0Zpbml0ZShwYWdlSWQpICYmIHBhZ2VJZCA+IDAgPyBwYWdlSWQgOiBudWxsO1xuICB9XG5cbiAgLy8gV3JpdGVzIHRoZSBvcGVuIHBhZ2UgYW5kIHRoZSB2aWV3ZXIgc3RhdGUgaW50byB0aGUgVVJMIGluIG9uZSBnby4gT25seVxuICAvLyB0aGUga2V5cyB0aGlzIHZpZXcgb3ducyBhcmUgdG91Y2hlZCAoJ21lcmdlJyksIGFuZCByZXBsYWNlVXJsIGtlZXBzIHRoZVxuICAvLyB3cml0ZXMgb3V0IG9mIHRoZSBicm93c2VyIGhpc3Rvcnk6IEJhY2sgbGVhdmVzIHRoZSByZXBvcnQgcmF0aGVyIHRoYW5cbiAgLy8gd2Fsa2luZyBldmVyeSBwYWdlIGFuZCBmaWx0ZXIgdmlzaXRlZC5cbiAgcHJpdmF0ZSBfd3JpdGVVcmwoKTogdm9pZCB7XG4gICAgY29uc3QgcmVwb3J0ID0gdGhpcy5yZXBvcnQoKTtcblxuICAgIC8vIEEgcmVwb3J0IHN0aWxsIG9uIHNjcmVlbiB3aGlsZSB0aGUgaG9zdCdzIG5leHQgb25lIGxvYWRzIG11c3Qgbm90IHdyaXRlXG4gICAgLy8gaXRzIHN0YXRlIG92ZXIgdGhlIG5ldyByZXBvcnQncyBVUkwuXG4gICAgaWYgKCFyZXBvcnQgfHwgcmVwb3J0LmlkICE9PSB0aGlzLnJlcG9ydElkKCkpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBjb25zdCBxdWVyeVBhcmFtczogUGFyYW1zID0gdGhpcy51cmxTdGF0ZSgpXG4gICAgICA/IGJ1aWxkUmVwb3J0VXJsUGFyYW1zKHRoaXMuX2ZpbHRlclN0YXRlLnVybFNuYXBzaG90KHJlcG9ydCksIHRoaXMuX3JvdXRlLnNuYXBzaG90LnF1ZXJ5UGFyYW1NYXApXG4gICAgICA6IHt9O1xuXG4gICAgY29uc3QgcGFnZVBhcmFtID0gdGhpcy5wYWdlUXVlcnlQYXJhbSgpO1xuICAgIGlmIChwYWdlUGFyYW0gJiYgdGhpcy5fcGFnZVJlcG9ydGVkKSB7XG4gICAgICBxdWVyeVBhcmFtc1twYWdlUGFyYW1dID0gdGhpcy5jaGF0UGFnZUlkKCk7XG4gICAgfVxuXG4gICAgaWYgKCFPYmplY3Qua2V5cyhxdWVyeVBhcmFtcykubGVuZ3RoKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgdGhpcy5fcm91dGVyLm5hdmlnYXRlKFtdLCB7XG4gICAgICByZWxhdGl2ZVRvOiB0aGlzLl9yb3V0ZSxcbiAgICAgIHF1ZXJ5UGFyYW1zLFxuICAgICAgcXVlcnlQYXJhbXNIYW5kbGluZzogJ21lcmdlJyxcbiAgICAgIHJlcGxhY2VVcmw6IHRydWUsXG4gICAgfSk7XG4gIH1cblxuICBwcml2YXRlIF9sb2FkUmVwb3J0KHJlcG9ydElkOiBudW1iZXIsIGVtaXRSZW5hbWVkID0gZmFsc2UpOiB2b2lkIHtcbiAgICB0aGlzLl9yZXBvcnREYXRhLmdldChyZXBvcnRJZClcbiAgICAgIC5waXBlKHRha2VVbnRpbERlc3Ryb3llZCh0aGlzLl9kZXN0cm95UmVmKSlcbiAgICAgIC5zdWJzY3JpYmUoKHJlcG9ydDogUmVwb3J0KSA9PiB7XG4gICAgICAgIC8vIFRoZSBVUkwgaXMgcmVhZCBvbmNlIHBlciByZXBvcnQsIG9uIGl0cyBmaXJzdCBsb2FkOyBldmVyeSBsYXRlciBsb2FkXG4gICAgICAgIC8vIGtlZXBzIHRoZSBzdGF0ZSBpbiBtZW1vcnkuXG4gICAgICAgIGNvbnN0IHJlc3RvcmUgPSB0aGlzLnVybFN0YXRlKCkgJiYgcmVwb3J0SWQgIT09IHRoaXMuX3Jlc3RvcmVkUmVwb3J0SWRcbiAgICAgICAgICA/IHJlYWRSZXBvcnRVcmxQYXJhbXModGhpcy5fcm91dGUuc25hcHNob3QucXVlcnlQYXJhbU1hcClcbiAgICAgICAgICA6IG51bGw7XG4gICAgICAgIHRoaXMuX3Jlc3RvcmVkUmVwb3J0SWQgPSByZXBvcnRJZDtcblxuICAgICAgICB0aGlzLnJlcG9ydC5zZXQocmVwb3J0KTtcbiAgICAgICAgdGhpcy5fZmlsdGVyU3RhdGUuaW5pdChyZXBvcnQsIHJlc3RvcmUpO1xuICAgICAgICB0aGlzLl9idWlsZFJlcG9ydENvbmZpZygpO1xuXG4gICAgICAgIGlmIChlbWl0UmVuYW1lZCkge1xuICAgICAgICAgIHRoaXMucmVuYW1lZC5lbWl0KHJlcG9ydCk7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICB9XG5cbiAgLy8gUmVwb3J0LWxldmVsIGZpbHRlciBncm91cHMgaW4gdGhlaXIgc2F2ZWQgb3JkZXIg4oCUIHRoZSBvbmVzIHRoYXQgcmVuZGVyIGluXG4gIC8vIHRoZSB0b29sYmFyIChjb21wb25lbnQtbGV2ZWwgZ3JvdXBzIHJlbmRlciBvbiB0aGVpciBjb21wb25lbnRzKS5cbiAgcHJpdmF0ZSBfcmVwb3J0R3JvdXBzKCk6IFJlcG9ydEZpbHRlckdyb3VwW10ge1xuICAgIHJldHVybiAodGhpcy5yZXBvcnQoKT8uZmlsdGVyR3JvdXBzID8/IFtdKVxuICAgICAgLmZpbHRlcigoZ3JvdXApID0+IGdyb3VwLmxldmVsID09PSAncmVwb3J0JyB8fCBncm91cC5sZXZlbCA9PT0gJ2JvdGgnKVxuICAgICAgLnNvcnQoKGEsIGIpID0+IGEub3JkZXIgLSBiLm9yZGVyKTtcbiAgfVxuXG4gIC8vIChSZSlidWlsZCB0aGUgdG9vbGJhciBmcy1maWx0ZXIgY29uZmlnIOKAlCB0aGUgcmVwb3J0LWxldmVsIGZpbHRlciBpdGVtcyBhbmRcbiAgLy8gdGhlbiB0aGUgZ3JvdXAtYnkgY29udHJvbC5cbiAgcHJpdmF0ZSBfYnVpbGRSZXBvcnRDb25maWcoKTogdm9pZCB7XG4gICAgY29uc3QgcmVwb3J0ID0gdGhpcy5yZXBvcnQoKTtcbiAgICBjb25zdCByZXBvcnRJZCA9IHJlcG9ydD8uaWQgPz8gbnVsbDtcblxuICAgIC8vIERyb3AgYSBncmFpbiB0aGUgY29udHJvbCBubyBsb25nZXIgb2ZmZXJzIOKAlCB0aGUgYWdlbnQgY2FuIG5hcnJvdyB0aGUgbGlzdFxuICAgIC8vIG1pZC1zZXNzaW9uLCBhbmQgYW4gb3ZlcnJpZGUgdGhlIHZpZXdlciBjYW4ndCBzZWUgaXMgd29yc2UgdGhhbiBub25lLlxuICAgIGlmIChyZXBvcnQgJiYgIWlzR3JhbnVsYXJpdHlPZmZlcmVkKHJlcG9ydCwgdGhpcy5fZmlsdGVyU3RhdGUuZnJlcXVlbmN5KCkpKSB7XG4gICAgICB0aGlzLl9maWx0ZXJTdGF0ZS5zZXRGcmVxdWVuY3kobnVsbCk7XG4gICAgfVxuXG4gICAgY29uc3QgaXRlbXMgPSByZXBvcnRJZFxuICAgICAgPyB0aGlzLl9yZXBvcnRHcm91cHMoKS5tYXAoKGdyb3VwKSA9PlxuICAgICAgICBmaWx0ZXJJdGVtRm9yR3JvdXAoZ3JvdXAsIHRoaXMuX3JlcG9ydERhdGEsIHJlcG9ydElkLCB0aGlzLl9maWx0ZXJTdGF0ZS52YWx1ZShncm91cC5pZCkpKVxuICAgICAgOiBbXTtcblxuICAgIC8vIFRoZSBncm91cC1ieSBjb250cm9sIGxlYWRzIHRoZSBiYXIsIGFoZWFkIG9mIGV2ZXJ5IGZpbHRlcjogaXQgc2V0cyB0aGVcbiAgICAvLyBncmFpbiB0aGUgd2hvbGUgcmVwb3J0IGlzIHJlYWQgYXQsIHNvIGl0IGlzIHRoZSBmaXJzdCB0aGluZyBhIHZpZXdlclxuICAgIC8vIGRlY2lkZXMuIEl0IGlzIG5vdCBhIGZpbHRlciBncm91cCDigJQgaXQgcmUtYnVja2V0cyByb3dzIHJhdGhlciB0aGFuXG4gICAgLy8gbmFycm93aW5nIHRoZW0g4oCUIHNvIGl0IGlzIHBsYWNlZCBoZXJlIHJhdGhlciB0aGFuIG9yZGVyZWQgYW1vbmcgdGhlbS5cbiAgICBjb25zdCBncm91cEJ5SXRlbSA9IHRoaXMuX2dyb3VwQnlJdGVtKCk7XG4gICAgaWYgKGdyb3VwQnlJdGVtKSB7XG4gICAgICBpdGVtcy51bnNoaWZ0KGdyb3VwQnlJdGVtKTtcbiAgICB9XG5cbiAgICB0aGlzLnJlcG9ydEZpbHRlckNvbmZpZy5zZXQoe1xuICAgICAgLy8gZnMtZmlsdGVyIG5ldmVyIHRvdWNoZXMgdGhlIFVSTCBvciBwZXJzaXN0cyBmaWx0ZXIgc3RhdGU6IGl0cyBrZXlzIGFyZVxuICAgICAgLy8gbm90IG5hbWVzcGFjZWQsIGl0IHdyaXRlcyBvdXRzaWRlIHRoZSByb3V0ZXIsIGFuZCBpdCB3b3VsZCBmcmVlemUgYVxuICAgICAgLy8gcm9sbGluZyByYW5nZSBhcyB0d28gZGF0ZXMuIFJlcG9ydEZpbHRlclN0YXRlU2VydmljZSBvd25zIHRoZSB2YWx1ZXMsXG4gICAgICAvLyBhbmQgX3dyaXRlVXJsIGlzIHRoZSBvbmUgd3JpdGVyIG9mIHRoZSBVUkwuXG4gICAgICBxdWVyeVBhcmFtOiBmYWxzZSxcbiAgICAgIHBlcnNpc3Q6IGZhbHNlLFxuICAgICAgaXRlbXMsXG4gICAgICBjaGFuZ2U6IChxdWVyeSkgPT4ge1xuICAgICAgICBmb3IgKGNvbnN0IHsgZ3JvdXBJZCwgdmFsdWUgfSBvZiBncm91cFZhbHVlc0Zyb21RdWVyeShxdWVyeSA/PyB7fSwgdGhpcy5fcmVwb3J0R3JvdXBzKCkpKSB7XG4gICAgICAgICAgdGhpcy5fZmlsdGVyU3RhdGUuc2V0VmFsdWUoZ3JvdXBJZCwgdmFsdWUpO1xuICAgICAgICB9XG4gICAgICAgIC8vIE5vdCBhIGZpbHRlciBncm91cCDigJQgdGhlIGdyYWluIGlzIHJlYWQgc3RyYWlnaHQgb2ZmIHRoZSBxdWVyeS5cbiAgICAgICAgdGhpcy5fZmlsdGVyU3RhdGUuc2V0RnJlcXVlbmN5KChxdWVyeT8uW0dST1VQX0JZX0lURU1dIGFzIENoYXJ0R3JhbnVsYXJpdHkpIHx8IG51bGwpO1xuICAgICAgfSxcbiAgICB9KTtcbiAgfVxuXG4gIC8vIFRoZSByZXBvcnQncyBncm91cC1ieSBjb250cm9sIGFzIGFuIGZzLWZpbHRlciBpdGVtLCBvciBudWxsIHdoZW4gdGhlIHJlcG9ydFxuICAvLyBoYXMgbm9uZSB0byBzaG93LiBTZWVkZWQgZnJvbSB0aGUgc2Vzc2lvbiBzdGF0ZSBzbyB0aGUgZ3JhaW4gdGhlIHZpZXdlclxuICAvLyBwaWNrZWQgc3Vydml2ZXMgdGhlIHJlcG9ydCBiZWluZyByZS1mZXRjaGVkIGFmdGVyIGEgY2hhdCBlZGl0LlxuICBwcml2YXRlIF9ncm91cEJ5SXRlbSgpOiBJRmlsdGVyQ29uZmlnSXRlbSB8IG51bGwge1xuICAgIGNvbnN0IHJlcG9ydCA9IHRoaXMucmVwb3J0KCk7XG5cbiAgICByZXR1cm4gcmVwb3J0XG4gICAgICA/IGdyb3VwQnlGaWx0ZXJJdGVtKHJlcG9ydCwgdGhpcy5fZmlsdGVyU3RhdGUuZnJlcXVlbmN5KCkpXG4gICAgICA6IG51bGw7XG4gIH1cbn1cbiIsIjxkaXYgY2xhc3M9XCJmcy1haS1yZXBvcnQgZnMtY29sdW1uXCI+XG5cbiAgPGRpdiBjbGFzcz1cImZzLWFpLXJlcG9ydF9faGVhZGVyIGZzLXJvdy5hbGlnbi1jZW50ZXJcIj5cbiAgICA8aDIgY2xhc3M9XCJmcy1haS1yZXBvcnRfX3RpdGxlIGZzLWZsZXhcIj57eyByZXBvcnQoKT8ubmFtZSB9fTwvaDI+XG5cbiAgICBAaWYgKHJlcG9ydCgpKSB7XG4gICAgICA8IS0tIFJlcG9ydC1sZXZlbCBmaWx0ZXJzLCBpbmxpbmUgd2l0aCB0aGUgdG9vbGJhciBhY3Rpb25zLiBmcy1maWx0ZXJcbiAgICAgICAgICAgcmVhZHMgaXRzIGNvbmZpZyBvbmNlIGF0IGluaXQsIHNvIGl0J3Mga2V5ZWQgb24gdGhlIGZpbHRlclxuICAgICAgICAgICBzaWduYXR1cmU6IHdoZW4gdGhlIHJlcG9ydC1sZXZlbCBmaWx0ZXIgc2V0IGNoYW5nZXMgdGhlIGJsb2NrIGlzXG4gICAgICAgICAgIHJlY3JlYXRlZCBhbmQgcmUtcmVhZHMgdGhlIHJlYnVpbHQgY29uZmlnLiAtLT5cbiAgICAgIEBpZiAocmVwb3J0SGFzRmlsdGVycygpKSB7XG4gICAgICAgIEBmb3IgKGtleSBvZiBbcmVwb3J0RmlsdGVyS2V5KCldOyB0cmFjayBrZXkpIHtcbiAgICAgICAgICA8ZnMtZmlsdGVyXG4gICAgICAgICAgICAgIGNsYXNzPVwiZnMtYWktcmVwb3J0X19maWx0ZXJzXCJcbiAgICAgICAgICAgICAgW2NvbmZpZ109XCJyZXBvcnRGaWx0ZXJDb25maWcoKVwiPlxuICAgICAgICAgIDwvZnMtZmlsdGVyPlxuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIDwhLS0gV2hhdCBsYXlvdXQgZWRpdGluZyBjYW4gYWRkIG9yIHN3aXRjaCB0bywgYW5kIHRoZSB3YXkgb3V0IG9mIGl0LlxuICAgICAgICAgICBPbmUgc3R5bGUgZm9yIGFsbCB0aHJlZSDigJQgb3V0bGluZWQsIGljb24gYW5kIHRleHQuIFwiSGVhZGVyICYgZm9vdGVyXCJcbiAgICAgICAgICAgaXMgYSB0b2dnbGU6IGl0IGtlZXBzIGl0cyBsYWJlbCBhbmQgdHVybnMgZ3JheSB3aGlsZSBpdCBpcyBvbi4gLS0+XG4gICAgICBAaWYgKGVkaXRNb2RlKCkpIHtcbiAgICAgICAgPGRpdiBjbGFzcz1cImZzLWFpLXJlcG9ydF9fZWRpdC10b29scyBmcy1yb3cuYWxpZ24tY2VudGVyLmdhcC14c1wiPlxuICAgICAgICAgIDxidXR0b25cbiAgICAgICAgICAgICAgbWF0LXN0cm9rZWQtYnV0dG9uXG4gICAgICAgICAgICAgIHR5cGU9XCJidXR0b25cIlxuICAgICAgICAgICAgICBtYXRUb29sdGlwPVwiQWRkIGEgYmxvY2sgb2YgdGV4dFwiXG4gICAgICAgICAgICAgIChjbGljayk9XCJhZGRUZXh0KClcIj5cbiAgICAgICAgICAgIDxtYXQtaWNvbj50aXRsZTwvbWF0LWljb24+XG4gICAgICAgICAgICBBZGQgdGV4dFxuICAgICAgICAgIDwvYnV0dG9uPlxuICAgICAgICAgIDxidXR0b25cbiAgICAgICAgICAgICAgbWF0LXN0cm9rZWQtYnV0dG9uXG4gICAgICAgICAgICAgIHR5cGU9XCJidXR0b25cIlxuICAgICAgICAgICAgICBjbGFzcz1cImZzLWFpLXJlcG9ydF9fbWFzdGVyXCJcbiAgICAgICAgICAgICAgW2NsYXNzLmFjdGl2ZV09XCJpc01hc3Rlck1vZGVcIlxuICAgICAgICAgICAgICBbbWF0VG9vbHRpcF09XCJpc01hc3Rlck1vZGUgPyAnQmFjayB0byBlZGl0aW5nIHRoaXMgcGFnZScgOiAnRWRpdCB0aGUgaGVhZGVyIGFuZCBmb290ZXIgc2hvd24gb24gZXZlcnkgcGFnZSdcIlxuICAgICAgICAgICAgICAoY2xpY2spPVwidG9nZ2xlTWFzdGVyTW9kZSgpXCI+XG4gICAgICAgICAgICA8bWF0LWljb24+d2ViX2Fzc2V0PC9tYXQtaWNvbj5cbiAgICAgICAgICAgIEhlYWRlciAmIGZvb3RlclxuICAgICAgICAgIDwvYnV0dG9uPlxuICAgICAgICAgIDxidXR0b25cbiAgICAgICAgICAgICAgbWF0LXN0cm9rZWQtYnV0dG9uXG4gICAgICAgICAgICAgIHR5cGU9XCJidXR0b25cIlxuICAgICAgICAgICAgICAoY2xpY2spPVwidG9nZ2xlRWRpdE1vZGUoKVwiPlxuICAgICAgICAgICAgPG1hdC1pY29uPmNoZWNrPC9tYXQtaWNvbj5cbiAgICAgICAgICAgIERvbmUgZWRpdGluZ1xuICAgICAgICAgIDwvYnV0dG9uPlxuICAgICAgICA8L2Rpdj5cbiAgICAgIH1cblxuICAgICAgPCEtLSBUaGUgem9uZSBldmVyeSBkYXRlIGluIHRoaXMgcmVwb3J0IGlzIGZpbHRlcmVkIGFuZCBncm91cGVkIGluLCB0aGVcbiAgICAgICAgICAgc2FtZSBmb3IgZXZlcnkgdmlld2VyLiBTaG93biBvbmx5IHdoZW4gdGhlIHNlcnZlciBzZW5kcyBpdDsgYSBjbGlja1xuICAgICAgICAgICBvcGVucyBSZXBvcnQgc2V0dGluZ3MsIHdoZXJlIGl0IGlzIGNoYW5nZWQuIC0tPlxuICAgICAgQGlmIChyZXBvcnQoKT8uZWZmZWN0aXZlVGltZXpvbmU7IGFzIGVmZmVjdGl2ZVRpbWV6b25lKSB7XG4gICAgICAgIDxidXR0b25cbiAgICAgICAgICAgIG1hdC1idXR0b25cbiAgICAgICAgICAgIHR5cGU9XCJidXR0b25cIlxuICAgICAgICAgICAgY2xhc3M9XCJmcy1haS1yZXBvcnRfX3RpbWV6b25lXCJcbiAgICAgICAgICAgIFttYXRUb29sdGlwXT1cIidEYXRlcyBhcmUgZmlsdGVyZWQgYW5kIGdyb3VwZWQgaW4gJyArIGVmZmVjdGl2ZVRpbWV6b25lICsgJyBmb3IgZXZlcnlvbmUuIENoYW5nZSBpdCBpbiBSZXBvcnQgc2V0dGluZ3MuJ1wiXG4gICAgICAgICAgICAoY2xpY2spPVwicmVwb3J0U2V0dGluZ3MoKVwiPlxuICAgICAgICAgIDxtYXQtaWNvbj5zY2hlZHVsZTwvbWF0LWljb24+XG4gICAgICAgICAge3sgdGltZXpvbmVMYWJlbCgpIH19XG4gICAgICAgIDwvYnV0dG9uPlxuICAgICAgfVxuXG4gICAgICA8IS0tIE9uZSBpY29uIGZvciBib3RoIHN0YXRlczogaXQgcmVhZHMgYXMgcHJlc3NlZCB3aGlsZSBlZGl0aW5nIHJhdGhlclxuICAgICAgICAgICB0aGFuIHN3YXBwaW5nIHRvIHNvbWV0aGluZyBlbHNlLiAtLT5cbiAgICAgIDxidXR0b25cbiAgICAgICAgICBtYXQtaWNvbi1idXR0b25cbiAgICAgICAgICB0eXBlPVwiYnV0dG9uXCJcbiAgICAgICAgICBjbGFzcz1cImZzLWFpLXJlcG9ydF9fdG9nZ2xlXCJcbiAgICAgICAgICBbY2xhc3MuYWN0aXZlXT1cImVkaXRNb2RlKClcIlxuICAgICAgICAgIFttYXRUb29sdGlwXT1cImVkaXRNb2RlKCkgPyAnRG9uZSBlZGl0aW5nJyA6ICdFZGl0IGxheW91dCdcIlxuICAgICAgICAgIChjbGljayk9XCJ0b2dnbGVFZGl0TW9kZSgpXCI+XG4gICAgICAgIDxtYXQtaWNvbj5kYXNoYm9hcmRfY3VzdG9taXplPC9tYXQtaWNvbj5cbiAgICAgIDwvYnV0dG9uPlxuXG4gICAgICA8YnV0dG9uXG4gICAgICAgICAgbWF0LWljb24tYnV0dG9uXG4gICAgICAgICAgdHlwZT1cImJ1dHRvblwiXG4gICAgICAgICAgbWF0VG9vbHRpcD1cIkV4cG9ydFwiXG4gICAgICAgICAgW2ZzTWVudVRyaWdnZXJGb3JdPVwiZXhwb3J0TWVudVwiPlxuICAgICAgICA8bWF0LWljb24+ZG93bmxvYWQ8L21hdC1pY29uPlxuICAgICAgPC9idXR0b24+XG4gICAgICA8ZnMtbWVudSAjZXhwb3J0TWVudT5cbiAgICAgICAgPG5nLXRlbXBsYXRlXG4gICAgICAgICAgICBmcy1tZW51LWl0ZW1cbiAgICAgICAgICAgIChjbGljayk9XCJleHBvcnRQb3dlcnBvaW50KClcIj5cbiAgICAgICAgICBFeHBvcnQgUG93ZXJQb2ludFxuICAgICAgICA8L25nLXRlbXBsYXRlPlxuICAgICAgICA8bmctdGVtcGxhdGVcbiAgICAgICAgICAgIGZzLW1lbnUtaXRlbVxuICAgICAgICAgICAgKGNsaWNrKT1cImV4cG9ydFBkZigpXCI+XG4gICAgICAgICAgRXhwb3J0IFBERlxuICAgICAgICA8L25nLXRlbXBsYXRlPlxuICAgICAgICA8bmctdGVtcGxhdGVcbiAgICAgICAgICAgIGZzLW1lbnUtaXRlbVxuICAgICAgICAgICAgKGNsaWNrKT1cImV4cG9ydERhdGEoKVwiPlxuICAgICAgICAgIEV4cG9ydCBSYXcgRGF0YVxuICAgICAgICA8L25nLXRlbXBsYXRlPlxuICAgICAgICBAaWYgKChyZXBvcnQoKT8ucGFnZXM/Lmxlbmd0aCA/PyAwKSA+IDEpIHtcbiAgICAgICAgICA8bmctdGVtcGxhdGVcbiAgICAgICAgICAgICAgZnMtbWVudS1pdGVtXG4gICAgICAgICAgICAgIChjbGljayk9XCJleHBvcnREYXRhKHRydWUpXCI+XG4gICAgICAgICAgICBFeHBvcnQgUmF3IERhdGEgKFRoaXMgUGFnZSlcbiAgICAgICAgICA8L25nLXRlbXBsYXRlPlxuICAgICAgICB9XG4gICAgICA8L2ZzLW1lbnU+XG5cbiAgICAgIDxidXR0b25cbiAgICAgICAgICBtYXQtaWNvbi1idXR0b25cbiAgICAgICAgICB0eXBlPVwiYnV0dG9uXCJcbiAgICAgICAgICBtYXRUb29sdGlwPVwiUmVwb3J0IHNldHRpbmdzXCJcbiAgICAgICAgICAoY2xpY2spPVwicmVwb3J0U2V0dGluZ3MoKVwiPlxuICAgICAgICA8bWF0LWljb24+c2V0dGluZ3M8L21hdC1pY29uPlxuICAgICAgPC9idXR0b24+XG4gICAgfVxuICA8L2Rpdj5cblxuICA8ZGl2XG4gICAgICAjc3BsaXRcbiAgICAgIGNsYXNzPVwiZnMtYWktcmVwb3J0X19zcGxpdCBmcy1yb3cuYWxpZ24tc3RhcnRcIj5cbiAgICA8ZnMtYWktY2hhdFxuICAgICAgICAjY2hhdFBhbmVsXG4gICAgICAgIGNsYXNzPVwiY2hhdFwiXG4gICAgICAgIFtiYXNlUGF0aF09XCJiYXNlUGF0aCgpXCJcbiAgICAgICAgW3JlcXVlc3REYXRhXT1cImNoYXRSZXF1ZXN0RGF0YSgpXCJcbiAgICAgICAgW3JlYWR5XT1cImNoYXRQYWdlSWQoKSAhPT0gbnVsbFwiXG4gICAgICAgIChyZXNwb25zZSk9XCJvbkNoYXRSZXNwb25zZSgkZXZlbnQpXCI+XG4gICAgPC9mcy1haS1jaGF0PlxuXG4gICAgPGRpdlxuICAgICAgICBjbGFzcz1cInJlc2l6ZXJcIlxuICAgICAgICAocG9pbnRlcmRvd24pPVwib25SZXNpemVTdGFydCgkZXZlbnQpXCI+XG4gICAgPC9kaXY+XG5cbiAgICA8ZGl2IGNsYXNzPVwidmlld2VyIGZzLWZsZXggZnMtY29sdW1uXCI+XG4gICAgICBAaWYgKHJlcG9ydCgpKSB7XG4gICAgICAgIDxhcHAtcmVwb3J0LWNhbnZhc1xuICAgICAgICAgICAgW3JlcG9ydF09XCJyZXBvcnQoKVwiXG4gICAgICAgICAgICBbZWRpdE1vZGVdPVwiZWRpdE1vZGUoKVwiXG4gICAgICAgICAgICBbcGFnZUlkXT1cInBhZ2VJZCgpXCJcbiAgICAgICAgICAgIChjb21wb25lbnRTZXR0aW5ncyk9XCJjb21wb25lbnRTZXR0aW5ncygkZXZlbnQpXCJcbiAgICAgICAgICAgIChyZXBvcnRDaGFuZ2VkKT1cIm9uQ2FudmFzUmVwb3J0Q2hhbmdlZCgpXCJcbiAgICAgICAgICAgIChwYWdlQ2hhbmdlZCk9XCJvbkNhbnZhc1BhZ2VDaGFuZ2VkKCRldmVudClcIj5cbiAgICAgICAgPC9hcHAtcmVwb3J0LWNhbnZhcz5cbiAgICAgIH1cbiAgICA8L2Rpdj5cbiAgPC9kaXY+XG48L2Rpdj5cbiJdfQ==