@firestitch/report 18.0.16 → 18.0.18

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 (19) hide show
  1. package/app/reports/data/report.data.d.ts +1 -0
  2. package/app/reports/dialogs/entity-functions/entity-functions.component.d.ts +3 -2
  3. package/app/reports/dialogs/global-settings/components/semantic-database/semantic-database.component.d.ts +32 -10
  4. package/app/reports/interfaces/report.interface.d.ts +18 -2
  5. package/app/reports/views/reports/fs-ai-reports.component.d.ts +2 -1
  6. package/esm2022/app/reports/data/report.data.mjs +11 -1
  7. package/esm2022/app/reports/dialogs/entity-functions/entity-functions.component.mjs +16 -8
  8. package/esm2022/app/reports/dialogs/global-settings/components/semantic-database/semantic-database.component.mjs +94 -35
  9. package/esm2022/app/reports/export/report-pdf.service.mjs +5 -4
  10. package/esm2022/app/reports/export/report-pptx.service.mjs +5 -4
  11. package/esm2022/app/reports/interfaces/report.interface.mjs +8 -1
  12. package/esm2022/app/reports/views/reports/fs-ai-reports.component.mjs +34 -3
  13. package/fesm2022/{firestitch-report-echarts-CO50nSof.mjs → firestitch-report-echarts-CMOBB-Er.mjs} +2 -2
  14. package/fesm2022/{firestitch-report-echarts-CO50nSof.mjs.map → firestitch-report-echarts-CMOBB-Er.mjs.map} +1 -1
  15. package/fesm2022/{firestitch-report-firestitch-report-DlxhJJhU.mjs → firestitch-report-firestitch-report-DwgbMhwr.mjs} +172 -56
  16. package/fesm2022/firestitch-report-firestitch-report-DwgbMhwr.mjs.map +1 -0
  17. package/fesm2022/firestitch-report.mjs +1 -1
  18. package/package.json +1 -1
  19. package/fesm2022/firestitch-report-firestitch-report-DlxhJJhU.mjs.map +0 -1
@@ -20,13 +20,12 @@ import * as i3 from "@firestitch/chip";
20
20
  import * as i4 from "@firestitch/date";
21
21
  import * as i5 from "@firestitch/message";
22
22
  import * as i6 from "@firestitch/skeleton";
23
- // The Semantic Database tab: the entity scoreboard the report AI is built from
24
- // (an entity = a table + a model + a handler). Shows the last build's status,
25
- // runs (or stops) a build — streamed into the FsProcess dock so it survives the
26
- // dialog closing — and drills into every entity to reveal its shape, inlined
27
- // enum values, computed fields and its cached function counts, whose links open
28
- // the functions dialog (the full function set across all entities is far too
29
- // big to ship with the scoreboard).
23
+ // The Semantic Database tab: the scoreboard of everything the report AI was
24
+ // built from. Shows the last build's status, runs (or stops) a build — streamed
25
+ // into the FsProcess dock so it survives the dialog closing — and drills into
26
+ // every unit to reveal its shape, inlined enum values, computed fields and its
27
+ // cached function counts, whose links open the functions dialog (the full
28
+ // function set is far too big to ship with the scoreboard).
30
29
  //
31
30
  // It also reports the other half of the picture: the tables the AI CANNOT see —
32
31
  // excluded ones (no model) and junctions that bridged nothing. Those are
@@ -43,21 +42,20 @@ export class SemanticDatabaseComponent {
43
42
  K: 'Stopped',
44
43
  F: 'Failed',
45
44
  };
46
- // Scoreboard completion palette: built = green, everything else (needs
47
- // building) = grey. No error red a missing stage is unbuilt content, not a
48
- // failure.
49
- static DONE_COLOR = '#2e7d32';
50
- static PENDING_COLOR = '#9e9e9e';
51
- // The scoreboard's per-entity stage chips, left to right.
52
- stageKeys = ['introspected', 'enumsInlined', 'computed', 'functions'];
53
- stageLabels = {
54
- introspected: 'Introspected',
55
- enumsInlined: 'Enum cases',
56
- computed: 'Computed',
57
- functions: 'Functions',
58
- };
45
+ // A row that is still owed content says so; a built one says nothing. On a
46
+ // finished build every stage is done on every row, so chipping them all was
47
+ // noise that buried the one row that mattered.
48
+ static PENDING_COLOR = '#b26500';
49
+ // Class-name suffix stripped for display: `BudgetSummaryModel` reads as
50
+ // `BudgetSummary`. Only `Model` stripping `Handler` too would collide
51
+ // `WorkOrderOneTimeHandler` with `WorkOrderOneTimeModel`, which are two
52
+ // separate units.
53
+ static NAME_SUFFIX = 'Model';
59
54
  // null until loaded — gates the tab behind the skeleton.
60
55
  status = signal(null);
56
+ // Free-text filter over the unit list — at a few hundred rows the accordion
57
+ // is only usable if you can narrow it.
58
+ filter = signal('');
61
59
  // True while a build started from this tab is streaming into the dock.
62
60
  building = signal(false);
63
61
  buildActive = computed(() => this.building()
@@ -74,6 +72,43 @@ export class SemanticDatabaseComponent {
74
72
  // junction, but they were folded into no relationship, so neither they nor
75
73
  // what they link are reachable.
76
74
  unlinkedJunctions = computed(() => this._tables().filter((table) => table.classification === 'junction' && !!table.reason));
75
+ // Everything the build cached, entities and standalone code classes together,
76
+ // in one list ordered by the name a reader recognizes. Two arrays on the wire
77
+ // because they are genuinely different shapes; one list on screen because
78
+ // "what did the build read?" is a single question.
79
+ units = computed(() => {
80
+ const detail = this.status()?.detail;
81
+ if (!detail) {
82
+ return [];
83
+ }
84
+ const entities = (detail.entities ?? []).map((entity) => ({
85
+ key: entity.key,
86
+ name: this._displayName(entity.model, entity.key),
87
+ hasTable: true,
88
+ entity,
89
+ model: entity.model,
90
+ functionCount: entity.functionCount,
91
+ }));
92
+ const classes = (detail.classes ?? []).map((unit) => ({
93
+ key: unit.key,
94
+ name: this._displayName(unit.model, unit.key),
95
+ hasTable: false,
96
+ entity: null,
97
+ model: unit.model,
98
+ functionCount: unit.functionCount,
99
+ }));
100
+ return [...entities, ...classes]
101
+ .sort((a, b) => a.name.localeCompare(b.name));
102
+ });
103
+ // The filter matches the display name, the class and the entity key, so
104
+ // hunting by any of the three works.
105
+ filteredUnits = computed(() => {
106
+ const filter = this.filter().trim().toLowerCase();
107
+ if (!filter) {
108
+ return this.units();
109
+ }
110
+ return this.units().filter((unit) => `${unit.name} ${unit.model ?? ''} ${unit.key}`.toLowerCase().includes(filter));
111
+ });
77
112
  // The Coverage line. Assembled here because the catalog parts drop out
78
113
  // entirely on a pre-catalog artifact, which reads badly as template branches.
79
114
  coverage = computed(() => {
@@ -81,7 +116,7 @@ export class SemanticDatabaseComponent {
81
116
  if (!detail) {
82
117
  return '';
83
118
  }
84
- const parts = [`${detail.entityCount} entities`];
119
+ const parts = [`${detail.entityCount} entities`, `${detail.classCount} code classes`];
85
120
  if (this.hasCatalog()) {
86
121
  parts.push(detail.unlinkedJunctionCount
87
122
  ? `${detail.junctionCount} junctions (${detail.unlinkedJunctionCount} not linked)`
@@ -230,38 +265,62 @@ export class SemanticDatabaseComponent {
230
265
  this._message.success('Semantic database build complete.');
231
266
  }
232
267
  }
233
- stageColor(stage) {
234
- return stage === 'done'
235
- ? SemanticDatabaseComponent.DONE_COLOR
236
- : SemanticDatabaseComponent.PENDING_COLOR;
268
+ pendingColor() {
269
+ return SemanticDatabaseComponent.PENDING_COLOR;
237
270
  }
238
- stageTooltip(stage) {
239
- return stage === 'done' ? 'Built' : 'Needs building';
271
+ /**
272
+ * The build stages this row is still owed, or [] when it is fully built. A
273
+ * stopped or interrupted build is the only way to get a non-empty list.
274
+ */
275
+ pendingStages(unit) {
276
+ const stages = unit.entity?.stages;
277
+ return stages
278
+ ? Object.keys(stages).filter((stage) => stages[stage] !== 'done')
279
+ : [];
280
+ }
281
+ setFilter(value) {
282
+ this.filter.set(value);
240
283
  }
241
284
  /**
242
- * Open the child dialog listing one group of an entity's cached functions —
243
- * the model class's or the handler class's. The dialog fetches fresh on open,
244
- * so the tab never holds function payloads.
285
+ * Open the child dialog listing one group of a unit's cached functions — an
286
+ * entity's model or handler class, or a standalone class's code. The dialog
287
+ * fetches fresh on open, so the tab never holds function payloads.
245
288
  */
246
- openFunctions(entity, source) {
289
+ openFunctions(unit, source) {
247
290
  this._dialog.open(EntityFunctionsComponent, {
248
291
  width: '700px',
249
292
  maxWidth: '95vw',
250
293
  maxHeight: '85vh',
251
294
  autoFocus: false,
252
- data: { entityKey: entity.key, source },
295
+ data: { entityKey: unit.key, source },
253
296
  });
254
297
  }
255
298
  _init() {
256
299
  this._refreshStatus();
257
300
  }
301
+ /**
302
+ * What a reader recognizes the unit by: its class's short name, minus the
303
+ * `Model` suffix that every model carries and none of them are distinguished
304
+ * by. Falls back to the cache key for a unit whose class could not be
305
+ * resolved, so a row never renders nameless.
306
+ */
307
+ _displayName(model, key) {
308
+ if (!model) {
309
+ return key;
310
+ }
311
+ const shortName = model.split('\\').pop();
312
+ return shortName.length > SemanticDatabaseComponent.NAME_SUFFIX.length
313
+ && shortName.endsWith(SemanticDatabaseComponent.NAME_SUFFIX)
314
+ ? shortName.slice(0, -SemanticDatabaseComponent.NAME_SUFFIX.length)
315
+ : shortName;
316
+ }
258
317
  _refreshStatus() {
259
318
  this._reportData.semanticBuildStatus()
260
319
  .pipe(takeUntilDestroyed(this._destroyRef))
261
320
  .subscribe((status) => this.status.set(status));
262
321
  }
263
322
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: SemanticDatabaseComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
264
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: SemanticDatabaseComponent, isStandalone: true, selector: "fs-ai-report-global-settings-semantic-database", ngImport: i0, template: "<div class=\"fs-column tab-body\">\n <p class=\"hint\">\n The semantic database is what the report AI uses to understand your data \u2014\n tables, relationships and the calculations in code. Rebuild it after\n significant application updates. The build runs in the background; progress\n appears in the dock at the bottom right and this dialog can be closed while\n it runs.\n </p>\n\n <div *fsSkeleton=\"status()\">\n @if (status(); as buildStatus) {\n <div class=\"build-status\">\n @if (buildStatus.detail.generatedAt) {\n <div class=\"stat\">\n <span class=\"label\">Last built</span>\n <fs-date\n [date]=\"buildStatus.detail.generatedAt\"\n format=\"date-time\">\n </fs-date>\n </div>\n <div class=\"stat\">\n <span class=\"label\">Coverage</span>\n <span>{{ coverage() }}</span>\n </div>\n } @else {\n <fs-message-warning>\n The semantic database has not been built yet \u2014 the report AI can't\n answer data questions until it is. Run the first build.\n </fs-message-warning>\n }\n @if (buildStatus.build) {\n <div class=\"stat\">\n <span class=\"label\">Last build run</span>\n <span>\n {{ buildStateLabel() }}\n @if (buildStatus.build.message) {\n \u2014 {{ buildStatus.build.message }}\n }\n </span>\n </div>\n }\n </div>\n\n <!-- The entity scoreboard: every entity the AI knows about (an entity =\n a table + a model + a handler), its built-vs-needs-building stages,\n and a drill-down into its shape, enum values, computed fields and\n cached function counts \u2014 the counts link into the functions dialog. -->\n @if (buildStatus.detail.entities?.length) {\n <h2>Entities</h2>\n <mat-accordion class=\"entities\">\n @for (entity of buildStatus.detail.entities; track entity.key) {\n <mat-expansion-panel>\n <mat-expansion-panel-header>\n <mat-panel-title>{{ entity.key }}</mat-panel-title>\n <mat-panel-description>\n <div class=\"stage-chips\">\n @for (stage of stageKeys; track stage) {\n <fs-chip\n size=\"tiny\"\n [backgroundColor]=\"stageColor(entity.stages[stage])\"\n color=\"#ffffff\"\n [matTooltip]=\"stageTooltip(entity.stages[stage])\">\n {{ stageLabels[stage] }}\n </fs-chip>\n }\n </div>\n </mat-panel-description>\n </mat-expansion-panel-header>\n\n <!-- Deferred: the body only exists once expanded. -->\n <ng-template matExpansionPanelContent>\n <div class=\"entity-detail\">\n <div class=\"stat\">\n <span class=\"label\">Table</span>\n <span>{{ entity.table }}</span>\n </div>\n <div class=\"stat\">\n <span class=\"label\">Columns</span>\n <span>{{ entity.columns }}</span>\n </div>\n <div class=\"stat\">\n <span class=\"label\">Relationships</span>\n <span>{{ entity.relationships }}</span>\n </div>\n @if (entity.enums.length) {\n <div class=\"stat\">\n <span class=\"label\">Enumeration values</span>\n <div class=\"pair-list\">\n @for (enumColumn of entity.enums; track enumColumn.column) {\n <div class=\"pair-row\">\n <span class=\"pair-name\">{{ enumColumn.column }}</span>\n <span>{{ enumColumn.values.join(', ') }}</span>\n </div>\n }\n </div>\n </div>\n }\n @if (entity.computedFields.length) {\n <div class=\"stat\">\n <span class=\"label\">Computed fields</span>\n <span>{{ entity.computedFields.join(', ') }}</span>\n </div>\n }\n <div class=\"stat\">\n <span class=\"label\">Model functions</span>\n @if (entity.modelFunctionCount) {\n <a\n class=\"count-link\"\n (click)=\"openFunctions(entity, 'model')\">\n {{ entity.modelFunctionCount }}\n </a>\n } @else {\n <span>0</span>\n }\n </div>\n <div class=\"stat\">\n <span class=\"label\">Handler functions</span>\n @if (entity.handlerFunctionCount) {\n <a\n class=\"count-link\"\n (click)=\"openFunctions(entity, 'handler')\">\n {{ entity.handlerFunctionCount }}\n </a>\n } @else {\n <span>0</span>\n }\n </div>\n </div>\n </ng-template>\n </mat-expansion-panel>\n }\n </mat-accordion>\n }\n\n <!-- The other half of the picture: tables the AI can't reach. Excluded\n ones have no model; unlinked junctions have a composite primary key\n but were folded into no relationship, so nothing can navigate to\n them. Both are invisible by omission \u2014 no error, just a capability\n that silently isn't there. Collapsed by default: the excluded list is\n long and mostly framework plumbing. -->\n @if (hasCatalog()) {\n <h2>Not in the semantic database</h2>\n <div class=\"subheading\">\n Tables the report AI can't see. Give one a model to promote it to an\n entity, then rebuild.\n </div>\n <mat-accordion class=\"catalog\">\n @if (excludedTables().length) {\n <mat-expansion-panel>\n <mat-expansion-panel-header>\n <mat-panel-title>\n Tables excluded ({{ excludedTables().length }})\n </mat-panel-title>\n </mat-expansion-panel-header>\n\n <!-- Deferred: the body only exists once expanded. -->\n <ng-template matExpansionPanelContent>\n <div class=\"pair-list\">\n @for (table of excludedTables(); track table.table) {\n <div class=\"pair-row\">\n <span class=\"pair-name\">{{ table.table }}</span>\n <span>{{ table.reason }}</span>\n </div>\n }\n </div>\n </ng-template>\n </mat-expansion-panel>\n }\n @if (unlinkedJunctions().length) {\n <mat-expansion-panel>\n <mat-expansion-panel-header>\n <mat-panel-title>\n Junctions not linked ({{ unlinkedJunctions().length }})\n </mat-panel-title>\n </mat-expansion-panel-header>\n\n <ng-template matExpansionPanelContent>\n <p class=\"small\">\n Link tables the build couldn't fold into a relationship \u2014 so\n neither they nor what they link can be reported on.\n </p>\n <div class=\"pair-list\">\n @for (table of unlinkedJunctions(); track table.table) {\n <div class=\"pair-row\">\n <span class=\"pair-name\">{{ table.table }}</span>\n <span>{{ table.reason }}</span>\n </div>\n }\n </div>\n </ng-template>\n </mat-expansion-panel>\n }\n </mat-accordion>\n }\n }\n </div>\n</div>\n", styles: [".hint{margin:0 0 12px;color:#0009;font-size:13px;line-height:1.5}.stat{display:flex;align-items:baseline;gap:12px}.stat>.label{flex:0 0 150px;white-space:nowrap;color:#0009}.build-status{display:flex;flex-direction:column;gap:8px}.pair-list{display:flex;flex-direction:column;gap:3px}.pair-row{display:flex;gap:12px}.pair-name{flex:0 0 140px;white-space:nowrap;color:#0009}.entities{display:block;padding:3px}.entities mat-panel-description{justify-content:flex-end;margin-right:8px}.entities .stage-chips{display:flex;gap:4px}.entities .entity-detail{display:flex;flex-direction:column;gap:8px}.catalog{display:block;padding:3px}.catalog .pair-name{flex-basis:220px}\n"], dependencies: [{ kind: "ngmodule", type: MatExpansionModule }, { kind: "directive", type: i1.MatAccordion, selector: "mat-accordion", inputs: ["hideToggle", "displayMode", "togglePosition"], exportAs: ["matAccordion"] }, { kind: "component", type: i1.MatExpansionPanel, selector: "mat-expansion-panel", inputs: ["hideToggle", "togglePosition"], outputs: ["afterExpand", "afterCollapse"], exportAs: ["matExpansionPanel"] }, { kind: "component", type: i1.MatExpansionPanelHeader, selector: "mat-expansion-panel-header", inputs: ["expandedHeight", "collapsedHeight", "tabIndex"] }, { kind: "directive", type: i1.MatExpansionPanelTitle, selector: "mat-panel-title" }, { kind: "directive", type: i1.MatExpansionPanelDescription, selector: "mat-panel-description" }, { kind: "directive", type: i1.MatExpansionPanelContent, selector: "ng-template[matExpansionPanelContent]" }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i2.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "ngmodule", type: FsChipModule }, { kind: "component", type: i3.FsChipComponent, selector: "fs-chip", inputs: ["selectable", "removable", "value", "maxWidth", "width", "backgroundColor", "borderColor", "color", "shape", "outlined", "outlineDash", "icon", "image", "selected", "disabled", "padding", "contrastColor", "size"], outputs: ["selectedToggled", "removed", "click"] }, { kind: "ngmodule", type: FsDateModule }, { kind: "component", type: i4.FsDateComponent, selector: "fs-date", inputs: ["date", "format", "timezone"] }, { kind: "ngmodule", type: FsMessageModule }, { kind: "component", type: i5.FsMessageWarningComponent, selector: "fs-message-warning" }, { kind: "ngmodule", type: FsSkeletonModule }, { kind: "directive", type: i6.FsSkeletonContentDirective, selector: "[fsSkeleton]", inputs: ["fsSkeleton", "fsSkeletonPattern"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
323
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: SemanticDatabaseComponent, isStandalone: true, selector: "fs-ai-report-global-settings-semantic-database", ngImport: i0, template: "<div class=\"fs-column tab-body\">\n <p class=\"hint\">\n The semantic database is what the report AI uses to understand your data \u2014\n tables, relationships and the calculations in code. Rebuild it after\n significant application updates. The build runs in the background; progress\n appears in the dock at the bottom right and this dialog can be closed while\n it runs.\n </p>\n\n <div *fsSkeleton=\"status()\">\n @if (status(); as buildStatus) {\n <div class=\"build-status\">\n @if (buildStatus.detail.generatedAt) {\n <div class=\"stat\">\n <span class=\"label\">Last built</span>\n <fs-date\n [date]=\"buildStatus.detail.generatedAt\"\n format=\"date-time\">\n </fs-date>\n </div>\n <div class=\"stat\">\n <span class=\"label\">Coverage</span>\n <span>{{ coverage() }}</span>\n </div>\n } @else {\n <fs-message-warning>\n The semantic database has not been built yet \u2014 the report AI can't\n answer data questions until it is. Run the first build.\n </fs-message-warning>\n }\n @if (buildStatus.build) {\n <div class=\"stat\">\n <span class=\"label\">Last build run</span>\n <span>\n {{ buildStateLabel() }}\n @if (buildStatus.build.message) {\n \u2014 {{ buildStatus.build.message }}\n }\n </span>\n </div>\n }\n </div>\n\n <!-- Everything the build read, in one list: entities (a table + a model +\n a handler) and standalone code classes (domain logic with no table).\n The AI reads code from both, so splitting them into two sections\n would hide half of what was built. Each row drills into its shape,\n enum values, computed fields and cached function counts \u2014 the counts\n link into the functions dialog. -->\n @if (units().length) {\n <h2>Included ({{ units().length }})</h2>\n <div class=\"subheading\">\n Everything the report AI was built from. Entities can be queried;\n code classes are logic it reads and translates into SQL.\n </div>\n\n <input\n class=\"unit-filter\"\n type=\"search\"\n placeholder=\"Filter by name, class or key\u2026\"\n [value]=\"filter()\"\n (input)=\"setFilter($any($event.target).value)\">\n\n <mat-accordion class=\"entities\">\n @for (unit of filteredUnits(); track unit.key) {\n <mat-expansion-panel>\n <mat-expansion-panel-header>\n <mat-panel-title>{{ unit.name }}</mat-panel-title>\n <mat-panel-description>\n <div class=\"stage-chips\">\n @if (!unit.hasTable) {\n <fs-chip size=\"tiny\" matTooltip=\"Domain logic with no table \u2014 read, never queried\">\n code\n </fs-chip>\n }\n <!-- Silence means built. A chip here means an interrupted\n build left this row owing content. -->\n @for (stage of pendingStages(unit); track stage) {\n <fs-chip\n size=\"tiny\"\n [backgroundColor]=\"pendingColor()\"\n color=\"#ffffff\"\n matTooltip=\"Needs building\">\n {{ stage }}\n </fs-chip>\n }\n </div>\n </mat-panel-description>\n </mat-expansion-panel-header>\n\n <!-- Deferred: the body only exists once expanded. -->\n <ng-template matExpansionPanelContent>\n <div class=\"entity-detail\">\n @if (unit.model) {\n <div class=\"stat\">\n <span class=\"label\">Class</span>\n <span>{{ unit.model }}</span>\n </div>\n }\n @if (unit.entity; as entity) {\n <div class=\"stat\">\n <span class=\"label\">Table</span>\n <span>{{ entity.table }}</span>\n </div>\n <!-- The handle the report AI addresses this entity by in\n describe_entity / compile_query. -->\n <div class=\"stat\">\n <span class=\"label\">Entity key</span>\n <span>{{ entity.key }}</span>\n </div>\n <div class=\"stat\">\n <span class=\"label\">Columns</span>\n <span>{{ entity.columns }}</span>\n </div>\n <div class=\"stat\">\n <span class=\"label\">Relationships</span>\n <span>{{ entity.relationships }}</span>\n </div>\n @if (entity.enums.length) {\n <div class=\"stat\">\n <span class=\"label\">Enumeration values</span>\n <div class=\"pair-list\">\n @for (enumColumn of entity.enums; track enumColumn.column) {\n <div class=\"pair-row\">\n <span class=\"pair-name\">{{ enumColumn.column }}</span>\n <span>{{ enumColumn.values.join(', ') }}</span>\n </div>\n }\n </div>\n </div>\n }\n @if (entity.computedFields.length) {\n <div class=\"stat\">\n <span class=\"label\">Computed fields</span>\n <span>{{ entity.computedFields.join(', ') }}</span>\n </div>\n }\n <div class=\"stat\">\n <span class=\"label\">Model functions</span>\n @if (entity.modelFunctionCount) {\n <a\n class=\"count-link\"\n (click)=\"openFunctions(unit, 'model')\">\n {{ entity.modelFunctionCount }}\n </a>\n } @else {\n <span>0</span>\n }\n </div>\n <div class=\"stat\">\n <span class=\"label\">Handler functions</span>\n @if (entity.handlerFunctionCount) {\n <a\n class=\"count-link\"\n (click)=\"openFunctions(unit, 'handler')\">\n {{ entity.handlerFunctionCount }}\n </a>\n } @else {\n <span>0</span>\n }\n </div>\n } @else {\n <div class=\"stat\">\n <span class=\"label\">Code functions</span>\n @if (unit.functionCount) {\n <a\n class=\"count-link\"\n (click)=\"openFunctions(unit, 'class')\">\n {{ unit.functionCount }}\n </a>\n } @else {\n <span>0</span>\n }\n </div>\n }\n </div>\n </ng-template>\n </mat-expansion-panel>\n }\n </mat-accordion>\n\n @if (!filteredUnits().length) {\n <div class=\"subheading\">Nothing matches \u201C{{ filter() }}\u201D.</div>\n }\n }\n\n <!-- The other half of the picture: tables the AI can't reach. Excluded\n ones have no model; unlinked junctions have a composite primary key\n but were folded into no relationship, so nothing can navigate to\n them. Both are invisible by omission \u2014 no error, just a capability\n that silently isn't there. Collapsed by default: the excluded list is\n long and mostly framework plumbing. -->\n @if (hasCatalog()) {\n <h2>Not in the semantic database</h2>\n <div class=\"subheading\">\n Tables the report AI can't see. Give one a model to promote it to an\n entity, then rebuild.\n </div>\n <mat-accordion class=\"catalog\">\n @if (excludedTables().length) {\n <mat-expansion-panel>\n <mat-expansion-panel-header>\n <mat-panel-title>\n Tables excluded ({{ excludedTables().length }})\n </mat-panel-title>\n </mat-expansion-panel-header>\n\n <!-- Deferred: the body only exists once expanded. -->\n <ng-template matExpansionPanelContent>\n <div class=\"pair-list\">\n @for (table of excludedTables(); track table.table) {\n <div class=\"pair-row\">\n <span class=\"pair-name\">{{ table.table }}</span>\n <span>{{ table.reason }}</span>\n </div>\n }\n </div>\n </ng-template>\n </mat-expansion-panel>\n }\n @if (unlinkedJunctions().length) {\n <mat-expansion-panel>\n <mat-expansion-panel-header>\n <mat-panel-title>\n Junctions not linked ({{ unlinkedJunctions().length }})\n </mat-panel-title>\n </mat-expansion-panel-header>\n\n <ng-template matExpansionPanelContent>\n <p class=\"small\">\n Link tables the build couldn't fold into a relationship \u2014 so\n neither they nor what they link can be reported on.\n </p>\n <div class=\"pair-list\">\n @for (table of unlinkedJunctions(); track table.table) {\n <div class=\"pair-row\">\n <span class=\"pair-name\">{{ table.table }}</span>\n <span>{{ table.reason }}</span>\n </div>\n }\n </div>\n </ng-template>\n </mat-expansion-panel>\n }\n </mat-accordion>\n }\n }\n </div>\n</div>\n", styles: [".hint{margin:0 0 12px;color:#0009;font-size:13px;line-height:1.5}.stat{display:flex;align-items:baseline;gap:12px}.stat>.label{flex:0 0 150px;white-space:nowrap;color:#0009}.build-status{display:flex;flex-direction:column;gap:8px}.pair-list{display:flex;flex-direction:column;gap:3px}.pair-row{display:flex;gap:12px}.pair-name{flex:0 0 140px;white-space:nowrap;color:#0009}.unit-filter{width:100%;box-sizing:border-box;margin:8px 0 4px;padding:6px 10px;border:1px solid rgba(0,0,0,.2);border-radius:4px;font:inherit}.unit-filter:focus{outline:none;border-color:#00000080}.entities{display:block;padding:3px}.entities mat-panel-description{justify-content:flex-end;margin-right:8px}.entities .stage-chips{display:flex;gap:4px}.entities .entity-detail{display:flex;flex-direction:column;gap:8px}.catalog{display:block;padding:3px}.catalog .pair-name{flex-basis:220px}\n"], dependencies: [{ kind: "ngmodule", type: MatExpansionModule }, { kind: "directive", type: i1.MatAccordion, selector: "mat-accordion", inputs: ["hideToggle", "displayMode", "togglePosition"], exportAs: ["matAccordion"] }, { kind: "component", type: i1.MatExpansionPanel, selector: "mat-expansion-panel", inputs: ["hideToggle", "togglePosition"], outputs: ["afterExpand", "afterCollapse"], exportAs: ["matExpansionPanel"] }, { kind: "component", type: i1.MatExpansionPanelHeader, selector: "mat-expansion-panel-header", inputs: ["expandedHeight", "collapsedHeight", "tabIndex"] }, { kind: "directive", type: i1.MatExpansionPanelTitle, selector: "mat-panel-title" }, { kind: "directive", type: i1.MatExpansionPanelDescription, selector: "mat-panel-description" }, { kind: "directive", type: i1.MatExpansionPanelContent, selector: "ng-template[matExpansionPanelContent]" }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i2.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "ngmodule", type: FsChipModule }, { kind: "component", type: i3.FsChipComponent, selector: "fs-chip", inputs: ["selectable", "removable", "value", "maxWidth", "width", "backgroundColor", "borderColor", "color", "shape", "outlined", "outlineDash", "icon", "image", "selected", "disabled", "padding", "contrastColor", "size"], outputs: ["selectedToggled", "removed", "click"] }, { kind: "ngmodule", type: FsDateModule }, { kind: "component", type: i4.FsDateComponent, selector: "fs-date", inputs: ["date", "format", "timezone"] }, { kind: "ngmodule", type: FsMessageModule }, { kind: "component", type: i5.FsMessageWarningComponent, selector: "fs-message-warning" }, { kind: "ngmodule", type: FsSkeletonModule }, { kind: "directive", type: i6.FsSkeletonContentDirective, selector: "[fsSkeleton]", inputs: ["fsSkeleton", "fsSkeletonPattern"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
265
324
  }
266
325
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: SemanticDatabaseComponent, decorators: [{
267
326
  type: Component,
@@ -272,6 +331,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
272
331
  FsDateModule,
273
332
  FsMessageModule,
274
333
  FsSkeletonModule,
275
- ], template: "<div class=\"fs-column tab-body\">\n <p class=\"hint\">\n The semantic database is what the report AI uses to understand your data \u2014\n tables, relationships and the calculations in code. Rebuild it after\n significant application updates. The build runs in the background; progress\n appears in the dock at the bottom right and this dialog can be closed while\n it runs.\n </p>\n\n <div *fsSkeleton=\"status()\">\n @if (status(); as buildStatus) {\n <div class=\"build-status\">\n @if (buildStatus.detail.generatedAt) {\n <div class=\"stat\">\n <span class=\"label\">Last built</span>\n <fs-date\n [date]=\"buildStatus.detail.generatedAt\"\n format=\"date-time\">\n </fs-date>\n </div>\n <div class=\"stat\">\n <span class=\"label\">Coverage</span>\n <span>{{ coverage() }}</span>\n </div>\n } @else {\n <fs-message-warning>\n The semantic database has not been built yet \u2014 the report AI can't\n answer data questions until it is. Run the first build.\n </fs-message-warning>\n }\n @if (buildStatus.build) {\n <div class=\"stat\">\n <span class=\"label\">Last build run</span>\n <span>\n {{ buildStateLabel() }}\n @if (buildStatus.build.message) {\n \u2014 {{ buildStatus.build.message }}\n }\n </span>\n </div>\n }\n </div>\n\n <!-- The entity scoreboard: every entity the AI knows about (an entity =\n a table + a model + a handler), its built-vs-needs-building stages,\n and a drill-down into its shape, enum values, computed fields and\n cached function counts \u2014 the counts link into the functions dialog. -->\n @if (buildStatus.detail.entities?.length) {\n <h2>Entities</h2>\n <mat-accordion class=\"entities\">\n @for (entity of buildStatus.detail.entities; track entity.key) {\n <mat-expansion-panel>\n <mat-expansion-panel-header>\n <mat-panel-title>{{ entity.key }}</mat-panel-title>\n <mat-panel-description>\n <div class=\"stage-chips\">\n @for (stage of stageKeys; track stage) {\n <fs-chip\n size=\"tiny\"\n [backgroundColor]=\"stageColor(entity.stages[stage])\"\n color=\"#ffffff\"\n [matTooltip]=\"stageTooltip(entity.stages[stage])\">\n {{ stageLabels[stage] }}\n </fs-chip>\n }\n </div>\n </mat-panel-description>\n </mat-expansion-panel-header>\n\n <!-- Deferred: the body only exists once expanded. -->\n <ng-template matExpansionPanelContent>\n <div class=\"entity-detail\">\n <div class=\"stat\">\n <span class=\"label\">Table</span>\n <span>{{ entity.table }}</span>\n </div>\n <div class=\"stat\">\n <span class=\"label\">Columns</span>\n <span>{{ entity.columns }}</span>\n </div>\n <div class=\"stat\">\n <span class=\"label\">Relationships</span>\n <span>{{ entity.relationships }}</span>\n </div>\n @if (entity.enums.length) {\n <div class=\"stat\">\n <span class=\"label\">Enumeration values</span>\n <div class=\"pair-list\">\n @for (enumColumn of entity.enums; track enumColumn.column) {\n <div class=\"pair-row\">\n <span class=\"pair-name\">{{ enumColumn.column }}</span>\n <span>{{ enumColumn.values.join(', ') }}</span>\n </div>\n }\n </div>\n </div>\n }\n @if (entity.computedFields.length) {\n <div class=\"stat\">\n <span class=\"label\">Computed fields</span>\n <span>{{ entity.computedFields.join(', ') }}</span>\n </div>\n }\n <div class=\"stat\">\n <span class=\"label\">Model functions</span>\n @if (entity.modelFunctionCount) {\n <a\n class=\"count-link\"\n (click)=\"openFunctions(entity, 'model')\">\n {{ entity.modelFunctionCount }}\n </a>\n } @else {\n <span>0</span>\n }\n </div>\n <div class=\"stat\">\n <span class=\"label\">Handler functions</span>\n @if (entity.handlerFunctionCount) {\n <a\n class=\"count-link\"\n (click)=\"openFunctions(entity, 'handler')\">\n {{ entity.handlerFunctionCount }}\n </a>\n } @else {\n <span>0</span>\n }\n </div>\n </div>\n </ng-template>\n </mat-expansion-panel>\n }\n </mat-accordion>\n }\n\n <!-- The other half of the picture: tables the AI can't reach. Excluded\n ones have no model; unlinked junctions have a composite primary key\n but were folded into no relationship, so nothing can navigate to\n them. Both are invisible by omission \u2014 no error, just a capability\n that silently isn't there. Collapsed by default: the excluded list is\n long and mostly framework plumbing. -->\n @if (hasCatalog()) {\n <h2>Not in the semantic database</h2>\n <div class=\"subheading\">\n Tables the report AI can't see. Give one a model to promote it to an\n entity, then rebuild.\n </div>\n <mat-accordion class=\"catalog\">\n @if (excludedTables().length) {\n <mat-expansion-panel>\n <mat-expansion-panel-header>\n <mat-panel-title>\n Tables excluded ({{ excludedTables().length }})\n </mat-panel-title>\n </mat-expansion-panel-header>\n\n <!-- Deferred: the body only exists once expanded. -->\n <ng-template matExpansionPanelContent>\n <div class=\"pair-list\">\n @for (table of excludedTables(); track table.table) {\n <div class=\"pair-row\">\n <span class=\"pair-name\">{{ table.table }}</span>\n <span>{{ table.reason }}</span>\n </div>\n }\n </div>\n </ng-template>\n </mat-expansion-panel>\n }\n @if (unlinkedJunctions().length) {\n <mat-expansion-panel>\n <mat-expansion-panel-header>\n <mat-panel-title>\n Junctions not linked ({{ unlinkedJunctions().length }})\n </mat-panel-title>\n </mat-expansion-panel-header>\n\n <ng-template matExpansionPanelContent>\n <p class=\"small\">\n Link tables the build couldn't fold into a relationship \u2014 so\n neither they nor what they link can be reported on.\n </p>\n <div class=\"pair-list\">\n @for (table of unlinkedJunctions(); track table.table) {\n <div class=\"pair-row\">\n <span class=\"pair-name\">{{ table.table }}</span>\n <span>{{ table.reason }}</span>\n </div>\n }\n </div>\n </ng-template>\n </mat-expansion-panel>\n }\n </mat-accordion>\n }\n }\n </div>\n</div>\n", styles: [".hint{margin:0 0 12px;color:#0009;font-size:13px;line-height:1.5}.stat{display:flex;align-items:baseline;gap:12px}.stat>.label{flex:0 0 150px;white-space:nowrap;color:#0009}.build-status{display:flex;flex-direction:column;gap:8px}.pair-list{display:flex;flex-direction:column;gap:3px}.pair-row{display:flex;gap:12px}.pair-name{flex:0 0 140px;white-space:nowrap;color:#0009}.entities{display:block;padding:3px}.entities mat-panel-description{justify-content:flex-end;margin-right:8px}.entities .stage-chips{display:flex;gap:4px}.entities .entity-detail{display:flex;flex-direction:column;gap:8px}.catalog{display:block;padding:3px}.catalog .pair-name{flex-basis:220px}\n"] }]
334
+ ], template: "<div class=\"fs-column tab-body\">\n <p class=\"hint\">\n The semantic database is what the report AI uses to understand your data \u2014\n tables, relationships and the calculations in code. Rebuild it after\n significant application updates. The build runs in the background; progress\n appears in the dock at the bottom right and this dialog can be closed while\n it runs.\n </p>\n\n <div *fsSkeleton=\"status()\">\n @if (status(); as buildStatus) {\n <div class=\"build-status\">\n @if (buildStatus.detail.generatedAt) {\n <div class=\"stat\">\n <span class=\"label\">Last built</span>\n <fs-date\n [date]=\"buildStatus.detail.generatedAt\"\n format=\"date-time\">\n </fs-date>\n </div>\n <div class=\"stat\">\n <span class=\"label\">Coverage</span>\n <span>{{ coverage() }}</span>\n </div>\n } @else {\n <fs-message-warning>\n The semantic database has not been built yet \u2014 the report AI can't\n answer data questions until it is. Run the first build.\n </fs-message-warning>\n }\n @if (buildStatus.build) {\n <div class=\"stat\">\n <span class=\"label\">Last build run</span>\n <span>\n {{ buildStateLabel() }}\n @if (buildStatus.build.message) {\n \u2014 {{ buildStatus.build.message }}\n }\n </span>\n </div>\n }\n </div>\n\n <!-- Everything the build read, in one list: entities (a table + a model +\n a handler) and standalone code classes (domain logic with no table).\n The AI reads code from both, so splitting them into two sections\n would hide half of what was built. Each row drills into its shape,\n enum values, computed fields and cached function counts \u2014 the counts\n link into the functions dialog. -->\n @if (units().length) {\n <h2>Included ({{ units().length }})</h2>\n <div class=\"subheading\">\n Everything the report AI was built from. Entities can be queried;\n code classes are logic it reads and translates into SQL.\n </div>\n\n <input\n class=\"unit-filter\"\n type=\"search\"\n placeholder=\"Filter by name, class or key\u2026\"\n [value]=\"filter()\"\n (input)=\"setFilter($any($event.target).value)\">\n\n <mat-accordion class=\"entities\">\n @for (unit of filteredUnits(); track unit.key) {\n <mat-expansion-panel>\n <mat-expansion-panel-header>\n <mat-panel-title>{{ unit.name }}</mat-panel-title>\n <mat-panel-description>\n <div class=\"stage-chips\">\n @if (!unit.hasTable) {\n <fs-chip size=\"tiny\" matTooltip=\"Domain logic with no table \u2014 read, never queried\">\n code\n </fs-chip>\n }\n <!-- Silence means built. A chip here means an interrupted\n build left this row owing content. -->\n @for (stage of pendingStages(unit); track stage) {\n <fs-chip\n size=\"tiny\"\n [backgroundColor]=\"pendingColor()\"\n color=\"#ffffff\"\n matTooltip=\"Needs building\">\n {{ stage }}\n </fs-chip>\n }\n </div>\n </mat-panel-description>\n </mat-expansion-panel-header>\n\n <!-- Deferred: the body only exists once expanded. -->\n <ng-template matExpansionPanelContent>\n <div class=\"entity-detail\">\n @if (unit.model) {\n <div class=\"stat\">\n <span class=\"label\">Class</span>\n <span>{{ unit.model }}</span>\n </div>\n }\n @if (unit.entity; as entity) {\n <div class=\"stat\">\n <span class=\"label\">Table</span>\n <span>{{ entity.table }}</span>\n </div>\n <!-- The handle the report AI addresses this entity by in\n describe_entity / compile_query. -->\n <div class=\"stat\">\n <span class=\"label\">Entity key</span>\n <span>{{ entity.key }}</span>\n </div>\n <div class=\"stat\">\n <span class=\"label\">Columns</span>\n <span>{{ entity.columns }}</span>\n </div>\n <div class=\"stat\">\n <span class=\"label\">Relationships</span>\n <span>{{ entity.relationships }}</span>\n </div>\n @if (entity.enums.length) {\n <div class=\"stat\">\n <span class=\"label\">Enumeration values</span>\n <div class=\"pair-list\">\n @for (enumColumn of entity.enums; track enumColumn.column) {\n <div class=\"pair-row\">\n <span class=\"pair-name\">{{ enumColumn.column }}</span>\n <span>{{ enumColumn.values.join(', ') }}</span>\n </div>\n }\n </div>\n </div>\n }\n @if (entity.computedFields.length) {\n <div class=\"stat\">\n <span class=\"label\">Computed fields</span>\n <span>{{ entity.computedFields.join(', ') }}</span>\n </div>\n }\n <div class=\"stat\">\n <span class=\"label\">Model functions</span>\n @if (entity.modelFunctionCount) {\n <a\n class=\"count-link\"\n (click)=\"openFunctions(unit, 'model')\">\n {{ entity.modelFunctionCount }}\n </a>\n } @else {\n <span>0</span>\n }\n </div>\n <div class=\"stat\">\n <span class=\"label\">Handler functions</span>\n @if (entity.handlerFunctionCount) {\n <a\n class=\"count-link\"\n (click)=\"openFunctions(unit, 'handler')\">\n {{ entity.handlerFunctionCount }}\n </a>\n } @else {\n <span>0</span>\n }\n </div>\n } @else {\n <div class=\"stat\">\n <span class=\"label\">Code functions</span>\n @if (unit.functionCount) {\n <a\n class=\"count-link\"\n (click)=\"openFunctions(unit, 'class')\">\n {{ unit.functionCount }}\n </a>\n } @else {\n <span>0</span>\n }\n </div>\n }\n </div>\n </ng-template>\n </mat-expansion-panel>\n }\n </mat-accordion>\n\n @if (!filteredUnits().length) {\n <div class=\"subheading\">Nothing matches \u201C{{ filter() }}\u201D.</div>\n }\n }\n\n <!-- The other half of the picture: tables the AI can't reach. Excluded\n ones have no model; unlinked junctions have a composite primary key\n but were folded into no relationship, so nothing can navigate to\n them. Both are invisible by omission \u2014 no error, just a capability\n that silently isn't there. Collapsed by default: the excluded list is\n long and mostly framework plumbing. -->\n @if (hasCatalog()) {\n <h2>Not in the semantic database</h2>\n <div class=\"subheading\">\n Tables the report AI can't see. Give one a model to promote it to an\n entity, then rebuild.\n </div>\n <mat-accordion class=\"catalog\">\n @if (excludedTables().length) {\n <mat-expansion-panel>\n <mat-expansion-panel-header>\n <mat-panel-title>\n Tables excluded ({{ excludedTables().length }})\n </mat-panel-title>\n </mat-expansion-panel-header>\n\n <!-- Deferred: the body only exists once expanded. -->\n <ng-template matExpansionPanelContent>\n <div class=\"pair-list\">\n @for (table of excludedTables(); track table.table) {\n <div class=\"pair-row\">\n <span class=\"pair-name\">{{ table.table }}</span>\n <span>{{ table.reason }}</span>\n </div>\n }\n </div>\n </ng-template>\n </mat-expansion-panel>\n }\n @if (unlinkedJunctions().length) {\n <mat-expansion-panel>\n <mat-expansion-panel-header>\n <mat-panel-title>\n Junctions not linked ({{ unlinkedJunctions().length }})\n </mat-panel-title>\n </mat-expansion-panel-header>\n\n <ng-template matExpansionPanelContent>\n <p class=\"small\">\n Link tables the build couldn't fold into a relationship \u2014 so\n neither they nor what they link can be reported on.\n </p>\n <div class=\"pair-list\">\n @for (table of unlinkedJunctions(); track table.table) {\n <div class=\"pair-row\">\n <span class=\"pair-name\">{{ table.table }}</span>\n <span>{{ table.reason }}</span>\n </div>\n }\n </div>\n </ng-template>\n </mat-expansion-panel>\n }\n </mat-accordion>\n }\n }\n </div>\n</div>\n", styles: [".hint{margin:0 0 12px;color:#0009;font-size:13px;line-height:1.5}.stat{display:flex;align-items:baseline;gap:12px}.stat>.label{flex:0 0 150px;white-space:nowrap;color:#0009}.build-status{display:flex;flex-direction:column;gap:8px}.pair-list{display:flex;flex-direction:column;gap:3px}.pair-row{display:flex;gap:12px}.pair-name{flex:0 0 140px;white-space:nowrap;color:#0009}.unit-filter{width:100%;box-sizing:border-box;margin:8px 0 4px;padding:6px 10px;border:1px solid rgba(0,0,0,.2);border-radius:4px;font:inherit}.unit-filter:focus{outline:none;border-color:#00000080}.entities{display:block;padding:3px}.entities mat-panel-description{justify-content:flex-end;margin-right:8px}.entities .stage-chips{display:flex;gap:4px}.entities .entity-detail{display:flex;flex-direction:column;gap:8px}.catalog{display:block;padding:3px}.catalog .pair-name{flex-basis:220px}\n"] }]
276
335
  }], ctorParameters: () => [] });
277
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VtYW50aWMtZGF0YWJhc2UuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vc3JjL2FwcC9yZXBvcnRzL2RpYWxvZ3MvZ2xvYmFsLXNldHRpbmdzL2NvbXBvbmVudHMvc2VtYW50aWMtZGF0YWJhc2Uvc2VtYW50aWMtZGF0YWJhc2UuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vc3JjL2FwcC9yZXBvcnRzL2RpYWxvZ3MvZ2xvYmFsLXNldHRpbmdzL2NvbXBvbmVudHMvc2VtYW50aWMtZGF0YWJhc2Uvc2VtYW50aWMtZGF0YWJhc2UuY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLHVCQUF1QixFQUFFLFNBQVMsRUFBRSxVQUFVLEVBQUUsUUFBUSxFQUFFLE1BQU0sRUFBRSxNQUFNLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDekcsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sNEJBQTRCLENBQUM7QUFFaEUsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLDBCQUEwQixDQUFDO0FBQ3JELE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLDZCQUE2QixDQUFDO0FBQ2pFLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLDJCQUEyQixDQUFDO0FBRTdELE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUNsRCxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sa0JBQWtCLENBQUM7QUFDaEQsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBQ2hELE9BQU8sRUFBRSxTQUFTLEVBQUUsZUFBZSxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDakUsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBQ2hELE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUM5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QUFDLE1BQTJCLEVBQUUsRUFBRSxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUM7SUFDekUsQ0FBQzt3R0FsU1UseUJBQXlCOzRGQUF6Qix5QkFBeUIsMEdDdER0Qyx1dVFBcU1BLHN0QkR2Skksa0JBQWtCLHEwQkFDbEIsZ0JBQWdCLDRUQUNoQixZQUFZLHFYQUNaLFlBQVksNElBQ1osZUFBZSx5SEFDZixnQkFBZ0I7OzRGQUdQLHlCQUF5QjtrQkFmckMsU0FBUzsrQkFDRSxnREFBZ0QsbUJBR3pDLHVCQUF1QixDQUFDLE1BQU0sY0FDbkMsSUFBSSxXQUNQO3dCQUNQLGtCQUFrQjt3QkFDbEIsZ0JBQWdCO3dCQUNoQixZQUFZO3dCQUNaLFlBQVk7d0JBQ1osZUFBZTt3QkFDZixnQkFBZ0I7cUJBQ2pCIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3ksIENvbXBvbmVudCwgRGVzdHJveVJlZiwgY29tcHV0ZWQsIGluamVjdCwgc2lnbmFsIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyB0YWtlVW50aWxEZXN0cm95ZWQgfSBmcm9tICdAYW5ndWxhci9jb3JlL3J4anMtaW50ZXJvcCc7XG5cbmltcG9ydCB7IE1hdERpYWxvZyB9IGZyb20gJ0Bhbmd1bGFyL21hdGVyaWFsL2RpYWxvZyc7XG5pbXBvcnQgeyBNYXRFeHBhbnNpb25Nb2R1bGUgfSBmcm9tICdAYW5ndWxhci9tYXRlcmlhbC9leHBhbnNpb24nO1xuaW1wb3J0IHsgTWF0VG9vbHRpcE1vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL21hdGVyaWFsL3Rvb2x0aXAnO1xuXG5pbXBvcnQgeyBTdHJlYW1FdmVudFR5cGUgfSBmcm9tICdAZmlyZXN0aXRjaC9hcGknO1xuaW1wb3J0IHsgRnNDaGlwTW9kdWxlIH0gZnJvbSAnQGZpcmVzdGl0Y2gvY2hpcCc7XG5pbXBvcnQgeyBGc0RhdGVNb2R1bGUgfSBmcm9tICdAZmlyZXN0aXRjaC9kYXRlJztcbmltcG9ydCB7IEZzTWVzc2FnZSwgRnNNZXNzYWdlTW9kdWxlIH0gZnJvbSAnQGZpcmVzdGl0Y2gvbWVzc2FnZSc7XG5pbXBvcnQgeyBGc1Byb2Nlc3MgfSBmcm9tICdAZmlyZXN0aXRjaC9wcm9jZXNzJztcbmltcG9ydCB7IEZzUHJvbXB0IH0gZnJvbSAnQGZpcmVzdGl0Y2gvcHJvbXB0JztcbmltcG9ydCB7IEZzU2tlbGV0b25Nb2R1bGUgfSBmcm9tICdAZmlyZXN0aXRjaC9za2VsZXRvbic7XG5cbmltcG9ydCB7IGZpbHRlciwgbWFwLCBzd2l0Y2hNYXAsIHRha2UsIHRhcCB9IGZyb20gJ3J4anMvb3BlcmF0b3JzJztcblxuaW1wb3J0IHsgUmVwb3J0RGF0YSB9IGZyb20gJy4uLy4uLy4uLy4uL2RhdGEvcmVwb3J0LmRhdGEnO1xuaW1wb3J0IHtcbiAgU2VtYW50aWNCdWlsZEVudGl0eSxcbiAgU2VtYW50aWNCdWlsZFN0YWdlLFxuICBTZW1hbnRpY0J1aWxkU3RhdHVzLFxuICBTZW1hbnRpY0J1aWxkVGFibGUsXG59IGZyb20gJy4uLy4uLy4uLy4uL2ludGVyZmFjZXMvcmVwb3J0LmludGVyZmFjZSc7XG5pbXBvcnQgeyBFbnRpdHlGdW5jdGlvbnNDb21wb25lbnQgfSBmcm9tICcuLi8uLi8uLi9lbnRpdHktZnVuY3Rpb25zL2VudGl0eS1mdW5jdGlvbnMuY29tcG9uZW50JztcblxuXG4vLyBUaGUgU2VtYW50aWMgRGF0YWJhc2UgdGFiOiB0aGUgZW50aXR5IHNjb3JlYm9hcmQgdGhlIHJlcG9ydCBBSSBpcyBidWlsdCBmcm9tXG4vLyAoYW4gZW50aXR5ID0gYSB0YWJsZSArIGEgbW9kZWwgKyBhIGhhbmRsZXIpLiBTaG93cyB0aGUgbGFzdCBidWlsZCdzIHN0YXR1cyxcbi8vIHJ1bnMgKG9yIHN0b3BzKSBhIGJ1aWxkIOKAlCBzdHJlYW1lZCBpbnRvIHRoZSBGc1Byb2Nlc3MgZG9jayBzbyBpdCBzdXJ2aXZlcyB0aGVcbi8vIGRpYWxvZyBjbG9zaW5nIOKAlCBhbmQgZHJpbGxzIGludG8gZXZlcnkgZW50aXR5IHRvIHJldmVhbCBpdHMgc2hhcGUsIGlubGluZWRcbi8vIGVudW0gdmFsdWVzLCBjb21wdXRlZCBmaWVsZHMgYW5kIGl0cyBjYWNoZWQgZnVuY3Rpb24gY291bnRzLCB3aG9zZSBsaW5rcyBvcGVuXG4vLyB0aGUgZnVuY3Rpb25zIGRpYWxvZyAodGhlIGZ1bGwgZnVuY3Rpb24gc2V0IGFjcm9zcyBhbGwgZW50aXRpZXMgaXMgZmFyIHRvb1xuLy8gYmlnIHRvIHNoaXAgd2l0aCB0aGUgc2NvcmVib2FyZCkuXG4vL1xuLy8gSXQgYWxzbyByZXBvcnRzIHRoZSBvdGhlciBoYWxmIG9mIHRoZSBwaWN0dXJlOiB0aGUgdGFibGVzIHRoZSBBSSBDQU5OT1Qgc2VlIOKAlFxuLy8gZXhjbHVkZWQgb25lcyAobm8gbW9kZWwpIGFuZCBqdW5jdGlvbnMgdGhhdCBicmlkZ2VkIG5vdGhpbmcuIFRob3NlIGFyZVxuLy8gaW52aXNpYmxlIGJ5IG9taXNzaW9uIG90aGVyd2lzZTogbm90aGluZyBlcnJvcnMsIHRoZSBjYXBhYmlsaXR5IGp1c3QgaXNuJ3Rcbi8vIHRoZXJlLCBhbmQgdGhlIGZpcnN0IGFueW9uZSBsZWFybnMgaXMgYSB3cm9uZyBhbnN3ZXIgb3IgYSByZWZ1c2FsLlxuQENvbXBvbmVudCh7XG4gIHNlbGVjdG9yOiAnZnMtYWktcmVwb3J0LWdsb2JhbC1zZXR0aW5ncy1zZW1hbnRpYy1kYXRhYmFzZScsXG4gIHRlbXBsYXRlVXJsOiAnLi9zZW1hbnRpYy1kYXRhYmFzZS5jb21wb25lbnQuaHRtbCcsXG4gIHN0eWxlVXJsczogWycuL3NlbWFudGljLWRhdGFiYXNlLmNvbXBvbmVudC5zY3NzJ10sXG4gIGNoYW5nZURldGVjdGlvbjogQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3kuT25QdXNoLFxuICBzdGFuZGFsb25lOiB0cnVlLFxuICBpbXBvcnRzOiBbXG4gICAgTWF0RXhwYW5zaW9uTW9kdWxlLFxuICAgIE1hdFRvb2x0aXBNb2R1bGUsXG4gICAgRnNDaGlwTW9kdWxlLFxuICAgIEZzRGF0ZU1vZHVsZSxcbiAgICBGc01lc3NhZ2VNb2R1bGUsXG4gICAgRnNTa2VsZXRvbk1vZHVsZSxcbiAgXSxcbn0pXG5leHBvcnQgY2xhc3MgU2VtYW50aWNEYXRhYmFzZUNvbXBvbmVudCB7XG5cbiAgLy8gVGhlIGJ1aWxkLWluLWZsaWdodCBzdGF0ZXMgb2YgdGhlIGZmX3Byb2Nlc3NlcyByb3cgKHF1ZXVlZC9ydW5uaW5nL3N0b3BwaW5nKS5cbiAgcHJpdmF0ZSBzdGF0aWMgcmVhZG9ubHkgQUNUSVZFX1NUQVRFUyA9IFsnUScsICdSJywgJ1gnXTtcblxuICBwcml2YXRlIHN0YXRpYyByZWFkb25seSBTVEFURV9MQUJFTFM6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4gPSB7XG4gICAgUTogJ1F1ZXVlZCcsXG4gICAgUjogJ1J1bm5pbmcnLFxuICAgIFg6ICdTdG9wcGluZycsXG4gICAgQzogJ0NvbXBsZXRlZCcsXG4gICAgSzogJ1N0b3BwZWQnLFxuICAgIEY6ICdGYWlsZWQnLFxuICB9O1xuXG4gIC8vIFNjb3JlYm9hcmQgY29tcGxldGlvbiBwYWxldHRlOiBidWlsdCA9IGdyZWVuLCBldmVyeXRoaW5nIGVsc2UgKG5lZWRzXG4gIC8vIGJ1aWxkaW5nKSA9IGdyZXkuIE5vIGVycm9yIHJlZCDigJQgYSBtaXNzaW5nIHN0YWdlIGlzIHVuYnVpbHQgY29udGVudCwgbm90IGFcbiAgLy8gZmFpbHVyZS5cbiAgcHJpdmF0ZSBzdGF0aWMgcmVhZG9ubHkgRE9ORV9DT0xPUiA9ICcjMmU3ZDMyJztcbiAgcHJpdmF0ZSBzdGF0aWMgcmVhZG9ubHkgUEVORElOR19DT0xPUiA9ICcjOWU5ZTllJztcblxuICAvLyBUaGUgc2NvcmVib2FyZCdzIHBlci1lbnRpdHkgc3RhZ2UgY2hpcHMsIGxlZnQgdG8gcmlnaHQuXG4gIHB1YmxpYyByZWFkb25seSBzdGFnZUtleXMgPSBbJ2ludHJvc3BlY3RlZCcsICdlbnVtc0lubGluZWQnLCAnY29tcHV0ZWQnLCAnZnVuY3Rpb25zJ107XG5cbiAgcHVibGljIHJlYWRvbmx5IHN0YWdlTGFiZWxzOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+ID0ge1xuICAgIGludHJvc3BlY3RlZDogJ0ludHJvc3BlY3RlZCcsXG4gICAgZW51bXNJbmxpbmVkOiAnRW51bSBjYXNlcycsXG4gICAgY29tcHV0ZWQ6ICdDb21wdXRlZCcsXG4gICAgZnVuY3Rpb25zOiAnRnVuY3Rpb25zJyxcbiAgfTtcblxuICAvLyBudWxsIHVudGlsIGxvYWRlZCDigJQgZ2F0ZXMgdGhlIHRhYiBiZWhpbmQgdGhlIHNrZWxldG9uLlxuICBwdWJsaWMgcmVhZG9ubHkgc3RhdHVzID0gc2lnbmFsPFNlbWFudGljQnVpbGRTdGF0dXMgfCBudWxsPihudWxsKTtcblxuICAvLyBUcnVlIHdoaWxlIGEgYnVpbGQgc3RhcnRlZCBmcm9tIHRoaXMgdGFiIGlzIHN0cmVhbWluZyBpbnRvIHRoZSBkb2NrLlxuICBwdWJsaWMgcmVhZG9ubHkgYnVpbGRpbmcgPSBzaWduYWwoZmFsc2UpO1xuXG4gIHB1YmxpYyByZWFkb25seSBidWlsZEFjdGl2ZSA9IGNvbXB1dGVkPGJvb2xlYW4+KCgpID0+XG4gICAgdGhpcy5idWlsZGluZygpXG4gICAgICB8fCBTZW1hbnRpY0RhdGFiYXNlQ29tcG9uZW50LkFDVElWRV9TVEFURVMuaW5jbHVkZXModGhpcy5zdGF0dXMoKT8uYnVpbGQ/LnN0YXRlKSxcbiAgKTtcblxuICBwdWJsaWMgcmVhZG9ubHkgYnVpbGRTdGF0ZUxhYmVsID0gY29tcHV0ZWQ8c3RyaW5nPigoKSA9PlxuICAgIFNlbWFudGljRGF0YWJhc2VDb21wb25lbnQuU1RBVEVfTEFCRUxTW3RoaXMuc3RhdHVzKCk/LmJ1aWxkPy5zdGF0ZV0gPz8gJycsXG4gICk7XG5cbiAgLy8gQW4gYXJ0aWZhY3QgYnVpbHQgYmVmb3JlIHRoZSBjYXRhbG9nIGV4aXN0ZWQgY2FycmllcyBubyB0YWJsZXMuIEV2ZXJ5dGhpbmdcbiAgLy8gY2F0YWxvZy1kcml2ZW4gc3RheXMgaGlkZGVuIHJhdGhlciB0aGFuIGNsYWltaW5nIFwiMCBleGNsdWRlZFwiLCB3aGljaCB3b3VsZFxuICAvLyBiZSBhIGxpZSDigJQgYSByZWJ1aWxkIGZpbGxzIGl0IGluLlxuICBwdWJsaWMgcmVhZG9ubHkgaGFzQ2F0YWxvZyA9IGNvbXB1dGVkPGJvb2xlYW4+KCgpID0+ICEhdGhpcy5zdGF0dXMoKT8uZGV0YWlsPy50YWJsZXM/Lmxlbmd0aCk7XG5cbiAgLy8gVGFibGVzIHdpdGggbm8gbW9kZWw6IHRoZSByZXBvcnQgQUkgY2FuJ3Qgc2VlIHRoZW0gYXQgYWxsLiBBZGQgYSBtb2RlbCB0b1xuICAvLyBwcm9tb3RlIG9uZSB0byBhbiBlbnRpdHkuXG4gIHB1YmxpYyByZWFkb25seSBleGNsdWRlZFRhYmxlcyA9IGNvbXB1dGVkPFNlbWFudGljQnVpbGRUYWJsZVtdPigoKSA9PlxuICAgIHRoaXMuX3RhYmxlcygpLmZpbHRlcigodGFibGUpID0+IHRhYmxlLmNsYXNzaWZpY2F0aW9uID09PSAnZXhjbHVkZWQnKSxcbiAgKTtcblxuICAvLyBMaW5rIHRhYmxlcyB0aGF0IGJyaWRnZWQgbm90aGluZyDigJQgYSBjb21wb3NpdGUgcHJpbWFyeSBrZXkgbWFkZSB0aGVtIGFcbiAgLy8ganVuY3Rpb24sIGJ1dCB0aGV5IHdlcmUgZm9sZGVkIGludG8gbm8gcmVsYXRpb25zaGlwLCBzbyBuZWl0aGVyIHRoZXkgbm9yXG4gIC8vIHdoYXQgdGhleSBsaW5rIGFyZSByZWFjaGFibGUuXG4gIHB1YmxpYyByZWFkb25seSB1bmxpbmtlZEp1bmN0aW9ucyA9IGNvbXB1dGVkPFNlbWFudGljQnVpbGRUYWJsZVtdPigoKSA9PlxuICAgIHRoaXMuX3RhYmxlcygpLmZpbHRlcigodGFibGUpID0+IHRhYmxlLmNsYXNzaWZpY2F0aW9uID09PSAnanVuY3Rpb24nICYmICEhdGFibGUucmVhc29uKSxcbiAgKTtcblxuICAvLyBUaGUgQ292ZXJhZ2UgbGluZS4gQXNzZW1ibGVkIGhlcmUgYmVjYXVzZSB0aGUgY2F0YWxvZyBwYXJ0cyBkcm9wIG91dFxuICAvLyBlbnRpcmVseSBvbiBhIHByZS1jYXRhbG9nIGFydGlmYWN0LCB3aGljaCByZWFkcyBiYWRseSBhcyB0ZW1wbGF0ZSBicmFuY2hlcy5cbiAgcHVibGljIHJlYWRvbmx5IGNvdmVyYWdlID0gY29tcHV0ZWQ8c3RyaW5nPigoKSA9PiB7XG4gICAgY29uc3QgZGV0YWlsID0gdGhpcy5zdGF0dXMoKT8uZGV0YWlsO1xuICAgIGlmICghZGV0YWlsKSB7XG4gICAgICByZXR1cm4gJyc7XG4gICAgfVxuXG4gICAgY29uc3QgcGFydHMgPSBbYCR7ZGV0YWlsLmVudGl0eUNvdW50fSBlbnRpdGllc2BdO1xuXG4gICAgaWYgKHRoaXMuaGFzQ2F0YWxvZygpKSB7XG4gICAgICBwYXJ0cy5wdXNoKGRldGFpbC51bmxpbmtlZEp1bmN0aW9uQ291bnRcbiAgICAgICAgPyBgJHtkZXRhaWwuanVuY3Rpb25Db3VudH0ganVuY3Rpb25zICgke2RldGFpbC51bmxpbmtlZEp1bmN0aW9uQ291bnR9IG5vdCBsaW5rZWQpYFxuICAgICAgICA6IGAke2RldGFpbC5qdW5jdGlvbkNvdW50fSBqdW5jdGlvbnNgKTtcbiAgICB9XG5cbiAgICBwYXJ0cy5wdXNoKGAke2RldGFpbC5mdW5jdGlvbkNvdW50fSBjb2RlIGZ1bmN0aW9uc2ApO1xuXG4gICAgaWYgKHRoaXMuaGFzQ2F0YWxvZygpKSB7XG4gICAgICBwYXJ0cy5wdXNoKGAke2RldGFpbC5leGNsdWRlZENvdW50fSB0YWJsZXMgZXhjbHVkZWRgKTtcbiAgICB9XG5cbiAgICByZXR1cm4gcGFydHMuam9pbignIMK3ICcpO1xuICB9KTtcblxuICAvLyBUaGUgdGFibGUgY2F0YWxvZywgb3IgW10gd2hlbiB0aGUgc3RhdHVzIGhhc24ndCBsb2FkZWQgb3IgdGhlIGFydGlmYWN0XG4gIC8vIHByZWRhdGVzIGl0LlxuICBwcml2YXRlIHJlYWRvbmx5IF90YWJsZXMgPSBjb21wdXRlZDxTZW1hbnRpY0J1aWxkVGFibGVbXT4oKCkgPT4gdGhpcy5zdGF0dXMoKT8uZGV0YWlsPy50YWJsZXMgPz8gW10pO1xuXG4gIC8vIEd1YXJkcyB0aGUgb3V0Y29tZSBtZXNzYWdlIHRvIGZpcmUgZXhhY3RseSBvbmNlIHBlciBydW4g4oCUIHdoZXRoZXIgdGhlIHN0cmVhbVxuICAvLyBjb21wbGV0ZXMgKGJ1aWxkIGZpbmlzaGVkLCBwb3NzaWJseSBmYWlsZWQpIG9yIGVycm9ycyBvdXRyaWdodC5cbiAgcHJpdmF0ZSBfYnVpbGRGaW5hbGl6ZWQgPSBmYWxzZTtcblxuICBwcml2YXRlIHJlYWRvbmx5IF9kaWFsb2cgPSBpbmplY3QoTWF0RGlhbG9nKTtcbiAgcHJpdmF0ZSByZWFkb25seSBfcmVwb3J0RGF0YSA9IGluamVjdChSZXBvcnREYXRhKTtcbiAgcHJpdmF0ZSByZWFkb25seSBfcHJvY2VzcyA9IGluamVjdChGc1Byb2Nlc3MpO1xuICBwcml2YXRlIHJlYWRvbmx5IF9wcm9tcHQgPSBpbmplY3QoRnNQcm9tcHQpO1xuICBwcml2YXRlIHJlYWRvbmx5IF9tZXNzYWdlID0gaW5qZWN0KEZzTWVzc2FnZSk7XG4gIHByaXZhdGUgcmVhZG9ubHkgX2Rlc3Ryb3lSZWYgPSBpbmplY3QoRGVzdHJveVJlZik7XG5cbiAgY29uc3RydWN0b3IoKSB7XG4gICAgdGhpcy5faW5pdCgpO1xuICB9XG5cbiAgLy8gQ29uZmlybSBiZWZvcmUga2lja2luZyBvZmYgYSBidWlsZCDigJQgYSByZWJ1aWxkIHJlcGxhY2VzIHRoZSBjdXJyZW50XG4gIC8vIHNlbWFudGljIGRhdGFiYXNlLCBzbyBpdCBzaG91bGQgbmV2ZXIgZmlyZSBvbiBhIHN0cmF5IGNsaWNrLlxuICBwdWJsaWMgYnVpbGQoKTogdm9pZCB7XG4gICAgY29uc3QgcmVidWlsZCA9ICEhdGhpcy5zdGF0dXMoKT8uZGV0YWlsPy5nZW5lcmF0ZWRBdDtcblxuICAgIHRoaXMuX3Byb21wdC5jb25maXJtKHtcbiAgICAgIHRpdGxlOiByZWJ1aWxkID8gJ1JlYnVpbGQgc2VtYW50aWMgZGF0YWJhc2UnIDogJ0J1aWxkIHNlbWFudGljIGRhdGFiYXNlJyxcbiAgICAgIHRlbXBsYXRlOiByZWJ1aWxkXG4gICAgICAgID8gJ1JlYnVpbGQgdGhlIHNlbWFudGljIGRhdGFiYXNlPyBJdCBydW5zIGluIHRoZSBiYWNrZ3JvdW5kIGFuZCByZXBsYWNlcyB0aGUgY3VycmVudCBvbmUgd2hlbiBpdCBmaW5pc2hlcy4nXG4gICAgICAgIDogJ0J1aWxkIHRoZSBzZW1hbnRpYyBkYXRhYmFzZT8gSXQgcnVucyBpbiB0aGUgYmFja2dyb3VuZC4nLFxuICAgICAgY29tbWl0TGFiZWw6IHJlYnVpbGQgPyAnUmVidWlsZCcgOiAnQnVpbGQnLFxuICAgIH0pXG4gICAgICAucGlwZSh0YWtlVW50aWxEZXN0cm95ZWQodGhpcy5fZGVzdHJveVJlZikpXG4gICAgICAuc3Vic2NyaWJlKCgpID0+IHRoaXMuX3J1bkJ1aWxkKCkpO1xuICB9XG5cbiAgcHVibGljIHN0b3BCdWlsZCgpOiB2b2lkIHtcbiAgICB0aGlzLl9wcm9tcHQuY29uZmlybSh7XG4gICAgICB0aXRsZTogJ1N0b3AgYnVpbGQnLFxuICAgICAgdGVtcGxhdGU6ICdTdG9wIHRoZSBydW5uaW5nIGJ1aWxkPyBUaGUgY3VycmVudCBzZW1hbnRpYyBkYXRhYmFzZSBzdGF5cyBpbiBwbGFjZSB1bnRpbCBhIGJ1aWxkIGZpbmlzaGVzLicsXG4gICAgICBjb21taXRMYWJlbDogJ1N0b3AnLFxuICAgIH0pXG4gICAgICAucGlwZShcbiAgICAgICAgc3dpdGNoTWFwKCgpID0+IHRoaXMuX3JlcG9ydERhdGEuc2VtYW50aWNCdWlsZFN0b3AoKSksXG4gICAgICAgIHRha2VVbnRpbERlc3Ryb3llZCh0aGlzLl9kZXN0cm95UmVmKSxcbiAgICAgIClcbiAgICAgIC5zdWJzY3JpYmUoKCkgPT4ge1xuICAgICAgICB0aGlzLmJ1aWxkaW5nLnNldChmYWxzZSk7XG4gICAgICAgIHRoaXMuX21lc3NhZ2Uuc3VjY2VzcygnU3RvcHBpbmcgdGhlIGJ1aWxk4oCmJyk7XG4gICAgICAgIHRoaXMuX3JlZnJlc2hTdGF0dXMoKTtcbiAgICAgIH0pO1xuICB9XG5cbiAgLy8gUnVuIHRoZSBzZW1hbnRpYy1kYXRhYmFzZSBidWlsZC4gVGhlIGxpdmUgZmVlZCBzdHJlYW1zIGludG8gdGhlIEZzUHJvY2Vzc1xuICAvLyBkb2NrIChib3R0b20tcmlnaHQpLCB3aG9zZSBzdWJzY3JpcHRpb24gc3Vydml2ZXMgdGhpcyBkaWFsb2cgY2xvc2luZyDigJQgc29cbiAgLy8gZGlzbWlzc2luZyB0aGUgZGlhbG9nIG5ldmVyIGludGVycnVwdHMgYSBydW5uaW5nIGJ1aWxkLlxuICBwcml2YXRlIF9ydW5CdWlsZCgpOiB2b2lkIHtcbiAgICB0aGlzLmJ1aWxkaW5nLnNldCh0cnVlKTtcbiAgICB0aGlzLl9idWlsZEZpbmFsaXplZCA9IGZhbHNlO1xuXG4gICAgY29uc3QgdGFyZ2V0JCA9IHRoaXMuX3JlcG9ydERhdGEuc2VtYW50aWNCdWlsZCgpXG4gICAgICAucGlwZShcbiAgICAgICAgLy8gQSBoYXJkIHN0cmVhbS90cmFuc3BvcnQgZmFpbHVyZSAodGhlIGJ1aWxkIGNvdWxkbid0IGV2ZW4gc3RhcnQpXG4gICAgICAgIC8vIGZpbmFsaXplcyBoZXJlIOKAlCBjb21wbGV0ZWQkIHdvbid0IGZpcmUgaW4gdGhhdCBjYXNlLlxuICAgICAgICB0YXAoeyBlcnJvcjogKGVycm9yKSA9PiB0aGlzLl9maW5hbGl6ZUJ1aWxkKGVycm9yKSB9KSxcbiAgICAgICAgZmlsdGVyKChldmVudCkgPT5cbiAgICAgICAgICBldmVudD8udHlwZSA9PT0gU3RyZWFtRXZlbnRUeXBlLkRhdGFcbiAgICAgICAgICAmJiBldmVudC5kYXRhPy5raW5kID09PSAnbG9nJ1xuICAgICAgICAgICYmIHR5cGVvZiBldmVudC5kYXRhLmxpbmUgPT09ICdzdHJpbmcnKSxcbiAgICAgICAgbWFwKChldmVudCkgPT4gZXZlbnQuZGF0YS5saW5lIGFzIHN0cmluZyksXG4gICAgICApO1xuXG4gICAgdGhpcy5fcHJvY2Vzc1xuICAgICAgLnJ1bignU2VtYW50aWMgZGF0YWJhc2UgYnVpbGQnLCB0YXJnZXQkKVxuICAgICAgLmNvbXBsZXRlZCRcbiAgICAgIC5waXBlKFxuICAgICAgICB0YWtlKDEpLFxuICAgICAgICB0YWtlVW50aWxEZXN0cm95ZWQodGhpcy5fZGVzdHJveVJlZiksXG4gICAgICApXG4gICAgICAuc3Vic2NyaWJlKCgpID0+IHRoaXMuX2ZpbmFsaXplQnVpbGQobnVsbCkpO1xuICB9XG5cbiAgLyoqXG4gICAqIFdyYXAgdXAgb25lIGJ1aWxkIHJ1biBleGFjdGx5IG9uY2UuIE9uIGEgaGFyZCBzdHJlYW0gZXJyb3IsIHN1cmZhY2UgdGhlXG4gICAqIGFjdHVhbCBzZXJ2ZXItc2lkZSByZWFzb24gcHVsbGVkIG9mZiB0aGUgYnJva2VuIHN0cmVhbSDigJQgdGhlIGdlbmVyaWNcbiAgICogXCJjb3VsZCBub3QgcnVuXCIgbGluZSBvbmx5IHdoZW4gdGhlIGZhaWx1cmUgY2FycmllZCBubyBzZXJ2ZXIgdGV4dCBhdCBhbGw7XG4gICAqIG90aGVyd2lzZSByZWZyZXNoIHRoZSBzdGF0dXMgYW5kIGFubm91bmNlIGhvdyB0aGUgYnVpbGQgYWN0dWFsbHkgZW5kZWQg4oCUIGFcbiAgICogYnVpbGQgdGhhdCBmYWlsZWQgKGUuZy4gdGhlIEFJIGNvdWxkbid0IGJlIHJlYWNoZWQpIHJlcG9ydHMgJ0ZhaWxlZCcgd2l0aFxuICAgKiBhIHJlYXNvbiwgYW5kIHRoYXQgbXVzdCBzdXJmYWNlIGluc3RlYWQgb2YgdGhlIHJ1biBzaWxlbnRseSBkb2luZyBub3RoaW5nLlxuICAgKi9cbiAgcHJpdmF0ZSBfZmluYWxpemVCdWlsZChzdHJlYW1FcnJvcjogdW5rbm93bik6IHZvaWQge1xuICAgIGlmICh0aGlzLl9idWlsZEZpbmFsaXplZCkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICB0aGlzLl9idWlsZEZpbmFsaXplZCA9IHRydWU7XG5cbiAgICB0aGlzLmJ1aWxkaW5nLnNldChmYWxzZSk7XG5cbiAgICBpZiAoc3RyZWFtRXJyb3IpIHtcbiAgICAgIGNvbnN0IGRldGFpbCA9IHRoaXMuX3N0cmVhbUVycm9yRGV0YWlsKHN0cmVhbUVycm9yKTtcblxuICAgICAgdGhpcy5fbWVzc2FnZS5lcnJvcihkZXRhaWxcbiAgICAgICAgPyBgVGhlIHNlbWFudGljIGRhdGFiYXNlIGJ1aWxkIGZhaWxlZCDigJQgJHtkZXRhaWx9YFxuICAgICAgICA6ICdUaGUgc2VtYW50aWMgZGF0YWJhc2UgYnVpbGQgY291bGQgbm90IHJ1biDigJQgY2hlY2sgdGhlIEFJIGNvbm5lY3Rpb24gYW5kIHRyeSBhZ2Fpbi4nKTtcbiAgICAgIHRoaXMuX3JlZnJlc2hTdGF0dXMoKTtcblxuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIHRoaXMuX3JlcG9ydERhdGEuc2VtYW50aWNCdWlsZFN0YXR1cygpXG4gICAgICAucGlwZSh0YWtlVW50aWxEZXN0cm95ZWQodGhpcy5fZGVzdHJveVJlZikpXG4gICAgICAuc3Vic2NyaWJlKChzdGF0dXM6IFNlbWFudGljQnVpbGRTdGF0dXMpID0+IHtcbiAgICAgICAgdGhpcy5zdGF0dXMuc2V0KHN0YXR1cyk7XG4gICAgICAgIHRoaXMuX2Fubm91bmNlT3V0Y29tZShzdGF0dXMpO1xuICAgICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogVGhlIHJlYWwgcmVhc29uIGEgYnJva2VuIGJ1aWxkIHN0cmVhbSBicm9rZSwgZnJvbSB3aGF0IHRoZSBzZXJ2ZXIgYWN0dWFsbHlcbiAgICogc2VudC4gQSBzdHJ1Y3R1cmVkIGVycm9yIGZyYW1lIGFycml2ZXMgYXMge21lc3NhZ2V9IG9uIHRoZSBlcnJvciBib2R5OyBhXG4gICAqIG1pZC1zdHJlYW0gY3Jhc2ggZHVtcHMgcmF3IHRleHQgaW50byB0aGUgc3RyZWFtICh0aGUgc3RyZWFtIGludGVyY2VwdG9yXG4gICAqIGhhbmRzIGl0IGJhY2sgYXMgc3RhdHVzVGV4dCksIHdoZXJlIHRoZSBmcmFtZXMgYXJlIEpTT04gbGluZXMgYW5kIHRoZVxuICAgKiBmaXJzdCBub24tSlNPTiBsaW5lcyBhcmUgdGhlIGVycm9yIGFuZCBpdHMgbG9jYXRpb24uICcnIHdoZW4gdGhlIGZhaWx1cmVcbiAgICogY2FycmllZCBubyBzZXJ2ZXIgdGV4dCBhdCBhbGwgKHRyYW5zcG9ydCBkb3duIC8gc2VydmVyIHVucmVhY2hhYmxlKS5cbiAgICovXG4gIHByaXZhdGUgX3N0cmVhbUVycm9yRGV0YWlsKHN0cmVhbUVycm9yOiB1bmtub3duKTogc3RyaW5nIHtcbiAgICBjb25zdCBlcnJvciA9IHN0cmVhbUVycm9yIGFzIHsgZXJyb3I/OiB7IG1lc3NhZ2U/OiBzdHJpbmcgfTsgc3RhdHVzVGV4dD86IHN0cmluZyB9O1xuXG4gICAgaWYgKGVycm9yPy5lcnJvcj8ubWVzc2FnZSkge1xuICAgICAgcmV0dXJuIGVycm9yLmVycm9yLm1lc3NhZ2U7XG4gICAgfVxuXG4gICAgY29uc3Qgc3RhdHVzVGV4dCA9IGVycm9yPy5zdGF0dXNUZXh0O1xuICAgIGlmICghc3RhdHVzVGV4dCB8fCBzdGF0dXNUZXh0ID09PSAnVW5rbm93biBFcnJvcicpIHtcbiAgICAgIHJldHVybiAnJztcbiAgICB9XG5cbiAgICBjb25zdCBsaW5lcyA9IHN0YXR1c1RleHQuc3BsaXQoJ1xcbicpXG4gICAgICAubWFwKChsaW5lKSA9PiBsaW5lLnRyaW0oKSlcbiAgICAgIC5maWx0ZXIoKGxpbmUpID0+IHtcbiAgICAgICAgaWYgKCFsaW5lKSB7XG4gICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG5cbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICBKU09OLnBhcnNlKGxpbmUpO1xuXG4gICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9IGNhdGNoIHtcbiAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgfVxuICAgICAgfSk7XG5cbiAgICByZXR1cm4gbGluZXMuc2xpY2UoMCwgMikuam9pbignIOKAlCAnKS5zdWJzdHJpbmcoMCwgMzAwKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBUZWxsIHRoZSBvcGVyYXRvciBob3cgdGhlIGJ1aWxkIGVuZGVkOiBhIGZhaWxlZC9zdG9wcGVkIGJ1aWxkIHN1cmZhY2VzIGl0c1xuICAgKiByZWFzb24gKHNvIGFuIEFJIGNvbm5lY3Rpb24gcHJvYmxlbSBpcyBuZXZlciBzaWxlbnQpLCBhIGNvbXBsZXRlZCBvbmVcbiAgICogY29uZmlybXMgc3VjY2Vzcy5cbiAgICovXG4gIHByaXZhdGUgX2Fubm91bmNlT3V0Y29tZShzdGF0dXM6IFNlbWFudGljQnVpbGRTdGF0dXMpOiB2b2lkIHtcbiAgICBjb25zdCBidWlsZCA9IHN0YXR1cz8uYnVpbGQ7XG4gICAgaWYgKGJ1aWxkPy5zdGF0ZSA9PT0gJ0YnIHx8IGJ1aWxkPy5zdGF0ZSA9PT0gJ0snKSB7XG4gICAgICB0aGlzLl9tZXNzYWdlLmVycm9yKGJ1aWxkLm1lc3NhZ2UgfHwgJ1RoZSBzZW1hbnRpYyBkYXRhYmFzZSBidWlsZCBkaWQgbm90IGZpbmlzaC4nKTtcbiAgICB9IGVsc2UgaWYgKGJ1aWxkPy5zdGF0ZSA9PT0gJ0MnKSB7XG4gICAgICB0aGlzLl9tZXNzYWdlLnN1Y2Nlc3MoJ1NlbWFudGljIGRhdGFiYXNlIGJ1aWxkIGNvbXBsZXRlLicpO1xuICAgIH1cbiAgfVxuXG4gIHB1YmxpYyBzdGFnZUNvbG9yKHN0YWdlOiBTZW1hbnRpY0J1aWxkU3RhZ2UpOiBzdHJpbmcge1xuICAgIHJldHVybiBzdGFnZSA9PT0gJ2RvbmUnXG4gICAgICA/IFNlbWFudGljRGF0YWJhc2VDb21wb25lbnQuRE9ORV9DT0xPUlxuICAgICAgOiBTZW1hbnRpY0RhdGFiYXNlQ29tcG9uZW50LlBFTkRJTkdfQ09MT1I7XG4gIH1cblxuICBwdWJsaWMgc3RhZ2VUb29sdGlwKHN0YWdlOiBTZW1hbnRpY0J1aWxkU3RhZ2UpOiBzdHJpbmcge1xuICAgIHJldHVybiBzdGFnZSA9PT0gJ2RvbmUnID8gJ0J1aWx0JyA6ICdOZWVkcyBidWlsZGluZyc7XG4gIH1cblxuICAvKipcbiAgICogT3BlbiB0aGUgY2hpbGQgZGlhbG9nIGxpc3Rpbmcgb25lIGdyb3VwIG9mIGFuIGVudGl0eSdzIGNhY2hlZCBmdW5jdGlvbnMg4oCUXG4gICAqIHRoZSBtb2RlbCBjbGFzcydzIG9yIHRoZSBoYW5kbGVyIGNsYXNzJ3MuIFRoZSBkaWFsb2cgZmV0Y2hlcyBmcmVzaCBvbiBvcGVuLFxuICAgKiBzbyB0aGUgdGFiIG5ldmVyIGhvbGRzIGZ1bmN0aW9uIHBheWxvYWRzLlxuICAgKi9cbiAgcHVibGljIG9wZW5GdW5jdGlvbnMoZW50aXR5OiBTZW1hbnRpY0J1aWxkRW50aXR5LCBzb3VyY2U6ICdtb2RlbCcgfCAnaGFuZGxlcicpOiB2b2lkIHtcbiAgICB0aGlzLl9kaWFsb2cub3BlbihFbnRpdHlGdW5jdGlvbnNDb21wb25lbnQsIHtcbiAgICAgIHdpZHRoOiAnNzAwcHgnLFxuICAgICAgbWF4V2lkdGg6ICc5NXZ3JyxcbiAgICAgIG1heEhlaWdodDogJzg1dmgnLFxuICAgICAgYXV0b0ZvY3VzOiBmYWxzZSxcbiAgICAgIGRhdGE6IHsgZW50aXR5S2V5OiBlbnRpdHkua2V5LCBzb3VyY2UgfSxcbiAgICB9KTtcbiAgfVxuXG4gIHByaXZhdGUgX2luaXQoKTogdm9pZCB7XG4gICAgdGhpcy5fcmVmcmVzaFN0YXR1cygpO1xuICB9XG5cbiAgcHJpdmF0ZSBfcmVmcmVzaFN0YXR1cygpOiB2b2lkIHtcbiAgICB0aGlzLl9yZXBvcnREYXRhLnNlbWFudGljQnVpbGRTdGF0dXMoKVxuICAgICAgLnBpcGUodGFrZVVudGlsRGVzdHJveWVkKHRoaXMuX2Rlc3Ryb3lSZWYpKVxuICAgICAgLnN1YnNjcmliZSgoc3RhdHVzOiBTZW1hbnRpY0J1aWxkU3RhdHVzKSA9PiB0aGlzLnN0YXR1cy5zZXQoc3RhdHVzKSk7XG4gIH1cbn1cbiIsIjxkaXYgY2xhc3M9XCJmcy1jb2x1bW4gdGFiLWJvZHlcIj5cbiAgPHAgY2xhc3M9XCJoaW50XCI+XG4gICAgVGhlIHNlbWFudGljIGRhdGFiYXNlIGlzIHdoYXQgdGhlIHJlcG9ydCBBSSB1c2VzIHRvIHVuZGVyc3RhbmQgeW91ciBkYXRhIOKAlFxuICAgIHRhYmxlcywgcmVsYXRpb25zaGlwcyBhbmQgdGhlIGNhbGN1bGF0aW9ucyBpbiBjb2RlLiBSZWJ1aWxkIGl0IGFmdGVyXG4gICAgc2lnbmlmaWNhbnQgYXBwbGljYXRpb24gdXBkYXRlcy4gVGhlIGJ1aWxkIHJ1bnMgaW4gdGhlIGJhY2tncm91bmQ7IHByb2dyZXNzXG4gICAgYXBwZWFycyBpbiB0aGUgZG9jayBhdCB0aGUgYm90dG9tIHJpZ2h0IGFuZCB0aGlzIGRpYWxvZyBjYW4gYmUgY2xvc2VkIHdoaWxlXG4gICAgaXQgcnVucy5cbiAgPC9wPlxuXG4gIDxkaXYgKmZzU2tlbGV0b249XCJzdGF0dXMoKVwiPlxuICAgIEBpZiAoc3RhdHVzKCk7IGFzIGJ1aWxkU3RhdHVzKSB7XG4gICAgICA8ZGl2IGNsYXNzPVwiYnVpbGQtc3RhdHVzXCI+XG4gICAgICAgIEBpZiAoYnVpbGRTdGF0dXMuZGV0YWlsLmdlbmVyYXRlZEF0KSB7XG4gICAgICAgICAgPGRpdiBjbGFzcz1cInN0YXRcIj5cbiAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwibGFiZWxcIj5MYXN0IGJ1aWx0PC9zcGFuPlxuICAgICAgICAgICAgPGZzLWRhdGVcbiAgICAgICAgICAgICAgICBbZGF0ZV09XCJidWlsZFN0YXR1cy5kZXRhaWwuZ2VuZXJhdGVkQXRcIlxuICAgICAgICAgICAgICAgIGZvcm1hdD1cImRhdGUtdGltZVwiPlxuICAgICAgICAgICAgPC9mcy1kYXRlPlxuICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgIDxkaXYgY2xhc3M9XCJzdGF0XCI+XG4gICAgICAgICAgICA8c3BhbiBjbGFzcz1cImxhYmVsXCI+Q292ZXJhZ2U8L3NwYW4+XG4gICAgICAgICAgICA8c3Bhbj57eyBjb3ZlcmFnZSgpIH19PC9zcGFuPlxuICAgICAgICAgIDwvZGl2PlxuICAgICAgICB9IEBlbHNlIHtcbiAgICAgICAgICA8ZnMtbWVzc2FnZS13YXJuaW5nPlxuICAgICAgICAgICAgVGhlIHNlbWFudGljIGRhdGFiYXNlIGhhcyBub3QgYmVlbiBidWlsdCB5ZXQg4oCUIHRoZSByZXBvcnQgQUkgY2FuJ3RcbiAgICAgICAgICAgIGFuc3dlciBkYXRhIHF1ZXN0aW9ucyB1bnRpbCBpdCBpcy4gUnVuIHRoZSBmaXJzdCBidWlsZC5cbiAgICAgICAgICA8L2ZzLW1lc3NhZ2Utd2FybmluZz5cbiAgICAgICAgfVxuICAgICAgICBAaWYgKGJ1aWxkU3RhdHVzLmJ1aWxkKSB7XG4gICAgICAgICAgPGRpdiBjbGFzcz1cInN0YXRcIj5cbiAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwibGFiZWxcIj5MYXN0IGJ1aWxkIHJ1bjwvc3Bhbj5cbiAgICAgICAgICAgIDxzcGFuPlxuICAgICAgICAgICAgICB7eyBidWlsZFN0YXRlTGFiZWwoKSB9fVxuICAgICAgICAgICAgICBAaWYgKGJ1aWxkU3RhdHVzLmJ1aWxkLm1lc3NhZ2UpIHtcbiAgICAgICAgICAgICAgICDigJQge3sgYnVpbGRTdGF0dXMuYnVpbGQubWVzc2FnZSB9fVxuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICA8L3NwYW4+XG4gICAgICAgICAgPC9kaXY+XG4gICAgICAgIH1cbiAgICAgIDwvZGl2PlxuXG4gICAgICA8IS0tIFRoZSBlbnRpdHkgc2NvcmVib2FyZDogZXZlcnkgZW50aXR5IHRoZSBBSSBrbm93cyBhYm91dCAoYW4gZW50aXR5ID1cbiAgICAgICAgICAgYSB0YWJsZSArIGEgbW9kZWwgKyBhIGhhbmRsZXIpLCBpdHMgYnVpbHQtdnMtbmVlZHMtYnVpbGRpbmcgc3RhZ2VzLFxuICAgICAgICAgICBhbmQgYSBkcmlsbC1kb3duIGludG8gaXRzIHNoYXBlLCBlbnVtIHZhbHVlcywgY29tcHV0ZWQgZmllbGRzIGFuZFxuICAgICAgICAgICBjYWNoZWQgZnVuY3Rpb24gY291bnRzIOKAlCB0aGUgY291bnRzIGxpbmsgaW50byB0aGUgZnVuY3Rpb25zIGRpYWxvZy4gLS0+XG4gICAgICBAaWYgKGJ1aWxkU3RhdHVzLmRldGFpbC5lbnRpdGllcz8ubGVuZ3RoKSB7XG4gICAgICAgIDxoMj5FbnRpdGllczwvaDI+XG4gICAgICAgIDxtYXQtYWNjb3JkaW9uIGNsYXNzPVwiZW50aXRpZXNcIj5cbiAgICAgICAgICBAZm9yIChlbnRpdHkgb2YgYnVpbGRTdGF0dXMuZGV0YWlsLmVudGl0aWVzOyB0cmFjayBlbnRpdHkua2V5KSB7XG4gICAgICAgICAgICA8bWF0LWV4cGFuc2lvbi1wYW5lbD5cbiAgICAgICAgICAgICAgPG1hdC1leHBhbnNpb24tcGFuZWwtaGVhZGVyPlxuICAgICAgICAgICAgICAgIDxtYXQtcGFuZWwtdGl0bGU+e3sgZW50aXR5LmtleSB9fTwvbWF0LXBhbmVsLXRpdGxlPlxuICAgICAgICAgICAgICAgIDxtYXQtcGFuZWwtZGVzY3JpcHRpb24+XG4gICAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwic3RhZ2UtY2hpcHNcIj5cbiAgICAgICAgICAgICAgICAgICAgQGZvciAoc3RhZ2Ugb2Ygc3RhZ2VLZXlzOyB0cmFjayBzdGFnZSkge1xuICAgICAgICAgICAgICAgICAgICAgIDxmcy1jaGlwXG4gICAgICAgICAgICAgICAgICAgICAgICAgIHNpemU9XCJ0aW55XCJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgW2JhY2tncm91bmRDb2xvcl09XCJzdGFnZUNvbG9yKGVudGl0eS5zdGFnZXNbc3RhZ2VdKVwiXG4gICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yPVwiI2ZmZmZmZlwiXG4gICAgICAgICAgICAgICAgICAgICAgICAgIFttYXRUb29sdGlwXT1cInN0YWdlVG9vbHRpcChlbnRpdHkuc3RhZ2VzW3N0YWdlXSlcIj5cbiAgICAgICAgICAgICAgICAgICAgICAgIHt7IHN0YWdlTGFiZWxzW3N0YWdlXSB9fVxuICAgICAgICAgICAgICAgICAgICAgIDwvZnMtY2hpcD5cbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICAgICAgPC9tYXQtcGFuZWwtZGVzY3JpcHRpb24+XG4gICAgICAgICAgICAgIDwvbWF0LWV4cGFuc2lvbi1wYW5lbC1oZWFkZXI+XG5cbiAgICAgICAgICAgICAgPCEtLSBEZWZlcnJlZDogdGhlIGJvZHkgb25seSBleGlzdHMgb25jZSBleHBhbmRlZC4gLS0+XG4gICAgICAgICAgICAgIDxuZy10ZW1wbGF0ZSBtYXRFeHBhbnNpb25QYW5lbENvbnRlbnQ+XG4gICAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cImVudGl0eS1kZXRhaWxcIj5cbiAgICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJzdGF0XCI+XG4gICAgICAgICAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwibGFiZWxcIj5UYWJsZTwvc3Bhbj5cbiAgICAgICAgICAgICAgICAgICAgPHNwYW4+e3sgZW50aXR5LnRhYmxlIH19PC9zcGFuPlxuICAgICAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwic3RhdFwiPlxuICAgICAgICAgICAgICAgICAgICA8c3BhbiBjbGFzcz1cImxhYmVsXCI+Q29sdW1uczwvc3Bhbj5cbiAgICAgICAgICAgICAgICAgICAgPHNwYW4+e3sgZW50aXR5LmNvbHVtbnMgfX08L3NwYW4+XG4gICAgICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJzdGF0XCI+XG4gICAgICAgICAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwibGFiZWxcIj5SZWxhdGlvbnNoaXBzPC9zcGFuPlxuICAgICAgICAgICAgICAgICAgICA8c3Bhbj57eyBlbnRpdHkucmVsYXRpb25zaGlwcyB9fTwvc3Bhbj5cbiAgICAgICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgICAgICAgQGlmIChlbnRpdHkuZW51bXMubGVuZ3RoKSB7XG4gICAgICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJzdGF0XCI+XG4gICAgICAgICAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJsYWJlbFwiPkVudW1lcmF0aW9uIHZhbHVlczwvc3Bhbj5cbiAgICAgICAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwicGFpci1saXN0XCI+XG4gICAgICAgICAgICAgICAgICAgICAgICBAZm9yIChlbnVtQ29sdW1uIG9mIGVudGl0eS5lbnVtczsgdHJhY2sgZW51bUNvbHVtbi5jb2x1bW4pIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cInBhaXItcm93XCI+XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJwYWlyLW5hbWVcIj57eyBlbnVtQ29sdW1uLmNvbHVtbiB9fTwvc3Bhbj5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8c3Bhbj57eyBlbnVtQ29sdW1uLnZhbHVlcy5qb2luKCcsICcpIH19PC9zcGFuPlxuICAgICAgICAgICAgICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICBAaWYgKGVudGl0eS5jb21wdXRlZEZpZWxkcy5sZW5ndGgpIHtcbiAgICAgICAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cInN0YXRcIj5cbiAgICAgICAgICAgICAgICAgICAgICA8c3BhbiBjbGFzcz1cImxhYmVsXCI+Q29tcHV0ZWQgZmllbGRzPC9zcGFuPlxuICAgICAgICAgICAgICAgICAgICAgIDxzcGFuPnt7IGVudGl0eS5jb21wdXRlZEZpZWxkcy5qb2luKCcsICcpIH19PC9zcGFuPlxuICAgICAgICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJzdGF0XCI+XG4gICAgICAgICAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwibGFiZWxcIj5Nb2RlbCBmdW5jdGlvbnM8L3NwYW4+XG4gICAgICAgICAgICAgICAgICAgIEBpZiAoZW50aXR5Lm1vZGVsRnVuY3Rpb25Db3VudCkge1xuICAgICAgICAgICAgICAgICAgICAgIDxhXG4gICAgICAgICAgICAgICAgICAgICAgICAgIGNsYXNzPVwiY291bnQtbGlua1wiXG4gICAgICAgICAgICAgICAgICAgICAgICAgIChjbGljayk9XCJvcGVuRnVuY3Rpb25zKGVudGl0eSwgJ21vZGVsJylcIj5cbiAgICAgICAgICAgICAgICAgICAgICAgIHt7IGVudGl0eS5tb2RlbEZ1bmN0aW9uQ291bnQgfX1cbiAgICAgICAgICAgICAgICAgICAgICA8L2E+XG4gICAgICAgICAgICAgICAgICAgIH0gQGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgIDxzcGFuPjA8L3NwYW4+XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cInN0YXRcIj5cbiAgICAgICAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJsYWJlbFwiPkhhbmRsZXIgZnVuY3Rpb25zPC9zcGFuPlxuICAgICAgICAgICAgICAgICAgICBAaWYgKGVudGl0eS5oYW5kbGVyRnVuY3Rpb25Db3VudCkge1xuICAgICAgICAgICAgICAgICAgICAgIDxhXG4gICAgICAgICAgICAgICAgICAgICAgICAgIGNsYXNzPVwiY291bnQtbGlua1wiXG4gICAgICAgICAgICAgICAgICAgICAgICAgIChjbGljayk9XCJvcGVuRnVuY3Rpb25zKGVudGl0eSwgJ2hhbmRsZXInKVwiPlxuICAgICAgICAgICAgICAgICAgICAgICAge3sgZW50aXR5LmhhbmRsZXJGdW5jdGlvbkNvdW50IH19XG4gICAgICAgICAgICAgICAgICAgICAgPC9hPlxuICAgICAgICAgICAgICAgICAgICB9IEBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICA8c3Bhbj4wPC9zcGFuPlxuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgICAgPC9uZy10ZW1wbGF0ZT5cbiAgICAgICAgICAgIDwvbWF0LWV4cGFuc2lvbi1wYW5lbD5cbiAgICAgICAgICB9XG4gICAgICAgIDwvbWF0LWFjY29yZGlvbj5cbiAgICAgIH1cblxuICAgICAgPCEtLSBUaGUgb3RoZXIgaGFsZiBvZiB0aGUgcGljdHVyZTogdGFibGVzIHRoZSBBSSBjYW4ndCByZWFjaC4gRXhjbHVkZWRcbiAgICAgICAgICAgb25lcyBoYXZlIG5vIG1vZGVsOyB1bmxpbmtlZCBqdW5jdGlvbnMgaGF2ZSBhIGNvbXBvc2l0ZSBwcmltYXJ5IGtleVxuICAgICAgICAgICBidXQgd2VyZSBmb2xkZWQgaW50byBubyByZWxhdGlvbnNoaXAsIHNvIG5vdGhpbmcgY2FuIG5hdmlnYXRlIHRvXG4gICAgICAgICAgIHRoZW0uIEJvdGggYXJlIGludmlzaWJsZSBieSBvbWlzc2lvbiDigJQgbm8gZXJyb3IsIGp1c3QgYSBjYXBhYmlsaXR5XG4gICAgICAgICAgIHRoYXQgc2lsZW50bHkgaXNuJ3QgdGhlcmUuIENvbGxhcHNlZCBieSBkZWZhdWx0OiB0aGUgZXhjbHVkZWQgbGlzdCBpc1xuICAgICAgICAgICBsb25nIGFuZCBtb3N0bHkgZnJhbWV3b3JrIHBsdW1iaW5nLiAtLT5cbiAgICAgIEBpZiAoaGFzQ2F0YWxvZygpKSB7XG4gICAgICAgIDxoMj5Ob3QgaW4gdGhlIHNlbWFudGljIGRhdGFiYXNlPC9oMj5cbiAgICAgICAgPGRpdiBjbGFzcz1cInN1YmhlYWRpbmdcIj5cbiAgICAgICAgICBUYWJsZXMgdGhlIHJlcG9ydCBBSSBjYW4ndCBzZWUuIEdpdmUgb25lIGEgbW9kZWwgdG8gcHJvbW90ZSBpdCB0byBhblxuICAgICAgICAgIGVudGl0eSwgdGhlbiByZWJ1aWxkLlxuICAgICAgICA8L2Rpdj5cbiAgICAgICAgPG1hdC1hY2NvcmRpb24gY2xhc3M9XCJjYXRhbG9nXCI+XG4gICAgICAgICAgQGlmIChleGNsdWRlZFRhYmxlcygpLmxlbmd0aCkge1xuICAgICAgICAgICAgPG1hdC1leHBhbnNpb24tcGFuZWw+XG4gICAgICAgICAgICAgIDxtYXQtZXhwYW5zaW9uLXBhbmVsLWhlYWRlcj5cbiAgICAgICAgICAgICAgICA8bWF0LXBhbmVsLXRpdGxlPlxuICAgICAgICAgICAgICAgICAgVGFibGVzIGV4Y2x1ZGVkICh7eyBleGNsdWRlZFRhYmxlcygpLmxlbmd0aCB9fSlcbiAgICAgICAgICAgICAgICA8L21hdC1wYW5lbC10aXRsZT5cbiAgICAgICAgICAgICAgPC9tYXQtZXhwYW5zaW9uLXBhbmVsLWhlYWRlcj5cblxuICAgICAgICAgICAgICA8IS0tIERlZmVycmVkOiB0aGUgYm9keSBvbmx5IGV4aXN0cyBvbmNlIGV4cGFuZGVkLiAtLT5cbiAgICAgICAgICAgICAgPG5nLXRlbXBsYXRlIG1hdEV4cGFuc2lvblBhbmVsQ29udGVudD5cbiAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwicGFpci1saXN0XCI+XG4gICAgICAgICAgICAgICAgICBAZm9yICh0YWJsZSBvZiBleGNsdWRlZFRhYmxlcygpOyB0cmFjayB0YWJsZS50YWJsZSkge1xuICAgICAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwicGFpci1yb3dcIj5cbiAgICAgICAgICAgICAgICAgICAgICA8c3BhbiBjbGFzcz1cInBhaXItbmFtZVwiPnt7IHRhYmxlLnRhYmxlIH19PC9zcGFuPlxuICAgICAgICAgICAgICAgICAgICAgIDxzcGFuPnt7IHRhYmxlLnJlYXNvbiB9fTwvc3Bhbj5cbiAgICAgICAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICAgIDwvbmctdGVtcGxhdGU+XG4gICAgICAgICAgICA8L21hdC1leHBhbnNpb24tcGFuZWw+XG4gICAgICAgICAgfVxuICAgICAgICAgIEBpZiAodW5saW5rZWRKdW5jdGlvbnMoKS5sZW5ndGgpIHtcbiAgICAgICAgICAgIDxtYXQtZXhwYW5zaW9uLXBhbmVsPlxuICAgICAgICAgICAgICA8bWF0LWV4cGFuc2lvbi1wYW5lbC1oZWFkZXI+XG4gICAgICAgICAgICAgICAgPG1hdC1wYW5lbC10aXRsZT5cbiAgICAgICAgICAgICAgICAgIEp1bmN0aW9ucyBub3QgbGlua2VkICh7eyB1bmxpbmtlZEp1bmN0aW9ucygpLmxlbmd0aCB9fSlcbiAgICAgICAgICAgICAgICA8L21hdC1wYW5lbC10aXRsZT5cbiAgICAgICAgICAgICAgPC9tYXQtZXhwYW5zaW9uLXBhbmVsLWhlYWRlcj5cblxuICAgICAgICAgICAgICA8bmctdGVtcGxhdGUgbWF0RXhwYW5zaW9uUGFuZWxDb250ZW50PlxuICAgICAgICAgICAgICAgIDxwIGNsYXNzPVwic21hbGxcIj5cbiAgICAgICAgICAgICAgICAgIExpbmsgdGFibGVzIHRoZSBidWlsZCBjb3VsZG4ndCBmb2xkIGludG8gYSByZWxhdGlvbnNoaXAg4oCUIHNvXG4gICAgICAgICAgICAgICAgICBuZWl0aGVyIHRoZXkgbm9yIHdoYXQgdGhleSBsaW5rIGNhbiBiZSByZXBvcnRlZCBvbi5cbiAgICAgICAgICAgICAgICA8L3A+XG4gICAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cInBhaXItbGlzdFwiPlxuICAgICAgICAgICAgICAgICAgQGZvciAodGFibGUgb2YgdW5saW5rZWRKdW5jdGlvbnMoKTsgdHJhY2sgdGFibGUudGFibGUpIHtcbiAgICAgICAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cInBhaXItcm93XCI+XG4gICAgICAgICAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJwYWlyLW5hbWVcIj57eyB0YWJsZS50YWJsZSB9fTwvc3Bhbj5cbiAgICAgICAgICAgICAgICAgICAgICA8c3Bhbj57eyB0YWJsZS5yZWFzb24gfX08L3NwYW4+XG4gICAgICAgICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgICA8L25nLXRlbXBsYXRlPlxuICAgICAgICAgICAgPC9tYXQtZXhwYW5zaW9uLXBhbmVsPlxuICAgICAgICAgIH1cbiAgICAgICAgPC9tYXQtYWNjb3JkaW9uPlxuICAgICAgfVxuICAgIH1cbiAgPC9kaXY+XG48L2Rpdj5cbiJdfQ==
336
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VtYW50aWMtZGF0YWJhc2UuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vc3JjL2FwcC9yZXBvcnRzL2RpYWxvZ3MvZ2xvYmFsLXNldHRpbmdzL2NvbXBvbmVudHMvc2VtYW50aWMtZGF0YWJhc2Uvc2VtYW50aWMtZGF0YWJhc2UuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vc3JjL2FwcC9yZXBvcnRzL2RpYWxvZ3MvZ2xvYmFsLXNldHRpbmdzL2NvbXBvbmVudHMvc2VtYW50aWMtZGF0YWJhc2Uvc2VtYW50aWMtZGF0YWJhc2UuY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLHVCQUF1QixFQUFFLFNBQVMsRUFBRSxVQUFVLEVBQUUsUUFBUSxFQUFFLE1BQU0sRUFBRSxNQUFNLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDekcsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sNEJBQTRCLENBQUM7QUFFaEUsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLDBCQUEwQixDQUFDO0FBQ3JELE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLDZCQUE2QixDQUFDO0FBQ2pFLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLDJCQUEyQixDQUFDO0FBRTdELE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUNsRCxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sa0JBQWtCLENBQUM7QUFDaEQsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBQ2hELE9BQU8sRUFBRSxTQUFTLEVBQUUsZUFBZSxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDakUsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBQ2hELE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUM5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VyxDQUFDLE1BQU0sQ0FBQztZQUNuRSxDQUFDLENBQUMsU0FBUyxDQUFDO0lBQ2hCLENBQUM7SUFFTyxjQUFjO1FBQ3BCLElBQUksQ0FBQyxXQUFXLENBQUMsbUJBQW1CLEVBQUU7YUFDbkMsSUFBSSxDQUFDLGtCQUFrQixDQUFDLElBQUksQ0FBQyxXQUFXLENBQUMsQ0FBQzthQUMxQyxTQUFTLENBQUMsQ0FBQyxNQUEyQixFQUFFLEVBQUUsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDO0lBQ3pFLENBQUM7d0dBMVdVLHlCQUF5Qjs0RkFBekIseUJBQXlCLDBHQ3JFdEMsb2dWQXlQQSw0NUJENUxJLGtCQUFrQixxMEJBQ2xCLGdCQUFnQiw0VEFDaEIsWUFBWSxxWEFDWixZQUFZLDRJQUNaLGVBQWUseUhBQ2YsZ0JBQWdCOzs0RkFHUCx5QkFBeUI7a0JBZnJDLFNBQVM7K0JBQ0UsZ0RBQWdELG1CQUd6Qyx1QkFBdUIsQ0FBQyxNQUFNLGNBQ25DLElBQUksV0FDUDt3QkFDUCxrQkFBa0I7d0JBQ2xCLGdCQUFnQjt3QkFDaEIsWUFBWTt3QkFDWixZQUFZO3dCQUNaLGVBQWU7d0JBQ2YsZ0JBQWdCO3FCQUNqQiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENoYW5nZURldGVjdGlvblN0cmF0ZWd5LCBDb21wb25lbnQsIERlc3Ryb3lSZWYsIGNvbXB1dGVkLCBpbmplY3QsIHNpZ25hbCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgdGFrZVVudGlsRGVzdHJveWVkIH0gZnJvbSAnQGFuZ3VsYXIvY29yZS9yeGpzLWludGVyb3AnO1xuXG5pbXBvcnQgeyBNYXREaWFsb2cgfSBmcm9tICdAYW5ndWxhci9tYXRlcmlhbC9kaWFsb2cnO1xuaW1wb3J0IHsgTWF0RXhwYW5zaW9uTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvbWF0ZXJpYWwvZXhwYW5zaW9uJztcbmltcG9ydCB7IE1hdFRvb2x0aXBNb2R1bGUgfSBmcm9tICdAYW5ndWxhci9tYXRlcmlhbC90b29sdGlwJztcblxuaW1wb3J0IHsgU3RyZWFtRXZlbnRUeXBlIH0gZnJvbSAnQGZpcmVzdGl0Y2gvYXBpJztcbmltcG9ydCB7IEZzQ2hpcE1vZHVsZSB9IGZyb20gJ0BmaXJlc3RpdGNoL2NoaXAnO1xuaW1wb3J0IHsgRnNEYXRlTW9kdWxlIH0gZnJvbSAnQGZpcmVzdGl0Y2gvZGF0ZSc7XG5pbXBvcnQgeyBGc01lc3NhZ2UsIEZzTWVzc2FnZU1vZHVsZSB9IGZyb20gJ0BmaXJlc3RpdGNoL21lc3NhZ2UnO1xuaW1wb3J0IHsgRnNQcm9jZXNzIH0gZnJvbSAnQGZpcmVzdGl0Y2gvcHJvY2Vzcyc7XG5pbXBvcnQgeyBGc1Byb21wdCB9IGZyb20gJ0BmaXJlc3RpdGNoL3Byb21wdCc7XG5pbXBvcnQgeyBGc1NrZWxldG9uTW9kdWxlIH0gZnJvbSAnQGZpcmVzdGl0Y2gvc2tlbGV0b24nO1xuXG5pbXBvcnQgeyBmaWx0ZXIsIG1hcCwgc3dpdGNoTWFwLCB0YWtlLCB0YXAgfSBmcm9tICdyeGpzL29wZXJhdG9ycyc7XG5cbmltcG9ydCB7IFJlcG9ydERhdGEgfSBmcm9tICcuLi8uLi8uLi8uLi9kYXRhL3JlcG9ydC5kYXRhJztcbmltcG9ydCB7XG4gIFNlbWFudGljQnVpbGRDbGFzcyxcbiAgU2VtYW50aWNCdWlsZEVudGl0eSxcbiAgU2VtYW50aWNCdWlsZFN0YXR1cyxcbiAgU2VtYW50aWNCdWlsZFRhYmxlLFxuICBTZW1hbnRpY0Z1bmN0aW9uU291cmNlLFxufSBmcm9tICcuLi8uLi8uLi8uLi9pbnRlcmZhY2VzL3JlcG9ydC5pbnRlcmZhY2UnO1xuaW1wb3J0IHsgRW50aXR5RnVuY3Rpb25zQ29tcG9uZW50IH0gZnJvbSAnLi4vLi4vLi4vZW50aXR5LWZ1bmN0aW9ucy9lbnRpdHktZnVuY3Rpb25zLmNvbXBvbmVudCc7XG5cblxuLy8gT25lIHJvdyBvZiB0aGUgc2NvcmVib2FyZC4gVGhlIGJ1aWxkIGNhY2hlcyB0d28ga2luZHMgb2YgdW5pdCBhbmQgdGhlIHJlcG9ydFxuLy8gQUkgcmVhZHMgY29kZSBmcm9tIGJvdGgsIHNvIHRoZXkgYmVsb25nIGluIE9ORSBsaXN0OiBhbiBlbnRpdHkgKGEgdGFibGUgcGx1c1xuLy8gaXRzIG1vZGVsIGFuZCBoYW5kbGVyKSBhbmQgYSBzdGFuZGFsb25lIGNvZGUgY2xhc3MgKGRvbWFpbiBsb2dpYyB3aXRoIG5vXG4vLyB0YWJsZSDigJQgYSBzdW1tYXJ5IG1vZGVsLCBhIGNhbGN1bGF0aW9uIHNlcnZpY2UpLiBBIGNsYXNzIHJvdyBzaW1wbHkgaGFzIG5vXG4vLyB0YWJsZSwgY29sdW1ucyBvciByZWxhdGlvbnNoaXBzIHRvIHNob3cuXG5pbnRlcmZhY2UgU2VtYW50aWNVbml0VmlldyB7XG4gIGtleTogc3RyaW5nO1xuICBuYW1lOiBzdHJpbmc7XG4gIGhhc1RhYmxlOiBib29sZWFuO1xuICBlbnRpdHk6IFNlbWFudGljQnVpbGRFbnRpdHkgfCBudWxsO1xuICBtb2RlbDogc3RyaW5nIHwgbnVsbDtcbiAgZnVuY3Rpb25Db3VudDogbnVtYmVyO1xufVxuXG5cbi8vIFRoZSBTZW1hbnRpYyBEYXRhYmFzZSB0YWI6IHRoZSBzY29yZWJvYXJkIG9mIGV2ZXJ5dGhpbmcgdGhlIHJlcG9ydCBBSSB3YXNcbi8vIGJ1aWx0IGZyb20uIFNob3dzIHRoZSBsYXN0IGJ1aWxkJ3Mgc3RhdHVzLCBydW5zIChvciBzdG9wcykgYSBidWlsZCDigJQgc3RyZWFtZWRcbi8vIGludG8gdGhlIEZzUHJvY2VzcyBkb2NrIHNvIGl0IHN1cnZpdmVzIHRoZSBkaWFsb2cgY2xvc2luZyDigJQgYW5kIGRyaWxscyBpbnRvXG4vLyBldmVyeSB1bml0IHRvIHJldmVhbCBpdHMgc2hhcGUsIGlubGluZWQgZW51bSB2YWx1ZXMsIGNvbXB1dGVkIGZpZWxkcyBhbmQgaXRzXG4vLyBjYWNoZWQgZnVuY3Rpb24gY291bnRzLCB3aG9zZSBsaW5rcyBvcGVuIHRoZSBmdW5jdGlvbnMgZGlhbG9nICh0aGUgZnVsbFxuLy8gZnVuY3Rpb24gc2V0IGlzIGZhciB0b28gYmlnIHRvIHNoaXAgd2l0aCB0aGUgc2NvcmVib2FyZCkuXG4vL1xuLy8gSXQgYWxzbyByZXBvcnRzIHRoZSBvdGhlciBoYWxmIG9mIHRoZSBwaWN0dXJlOiB0aGUgdGFibGVzIHRoZSBBSSBDQU5OT1Qgc2VlIOKAlFxuLy8gZXhjbHVkZWQgb25lcyAobm8gbW9kZWwpIGFuZCBqdW5jdGlvbnMgdGhhdCBicmlkZ2VkIG5vdGhpbmcuIFRob3NlIGFyZVxuLy8gaW52aXNpYmxlIGJ5IG9taXNzaW9uIG90aGVyd2lzZTogbm90aGluZyBlcnJvcnMsIHRoZSBjYXBhYmlsaXR5IGp1c3QgaXNuJ3Rcbi8vIHRoZXJlLCBhbmQgdGhlIGZpcnN0IGFueW9uZSBsZWFybnMgaXMgYSB3cm9uZyBhbnN3ZXIgb3IgYSByZWZ1c2FsLlxuQENvbXBvbmVudCh7XG4gIHNlbGVjdG9yOiAnZnMtYWktcmVwb3J0LWdsb2JhbC1zZXR0aW5ncy1zZW1hbnRpYy1kYXRhYmFzZScsXG4gIHRlbXBsYXRlVXJsOiAnLi9zZW1hbnRpYy1kYXRhYmFzZS5jb21wb25lbnQuaHRtbCcsXG4gIHN0eWxlVXJsczogWycuL3NlbWFudGljLWRhdGFiYXNlLmNvbXBvbmVudC5zY3NzJ10sXG4gIGNoYW5nZURldGVjdGlvbjogQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3kuT25QdXNoLFxuICBzdGFuZGFsb25lOiB0cnVlLFxuICBpbXBvcnRzOiBbXG4gICAgTWF0RXhwYW5zaW9uTW9kdWxlLFxuICAgIE1hdFRvb2x0aXBNb2R1bGUsXG4gICAgRnNDaGlwTW9kdWxlLFxuICAgIEZzRGF0ZU1vZHVsZSxcbiAgICBGc01lc3NhZ2VNb2R1bGUsXG4gICAgRnNTa2VsZXRvbk1vZHVsZSxcbiAgXSxcbn0pXG5leHBvcnQgY2xhc3MgU2VtYW50aWNEYXRhYmFzZUNvbXBvbmVudCB7XG5cbiAgLy8gVGhlIGJ1aWxkLWluLWZsaWdodCBzdGF0ZXMgb2YgdGhlIGZmX3Byb2Nlc3NlcyByb3cgKHF1ZXVlZC9ydW5uaW5nL3N0b3BwaW5nKS5cbiAgcHJpdmF0ZSBzdGF0aWMgcmVhZG9ubHkgQUNUSVZFX1NUQVRFUyA9IFsnUScsICdSJywgJ1gnXTtcblxuICBwcml2YXRlIHN0YXRpYyByZWFkb25seSBTVEFURV9MQUJFTFM6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4gPSB7XG4gICAgUTogJ1F1ZXVlZCcsXG4gICAgUjogJ1J1bm5pbmcnLFxuICAgIFg6ICdTdG9wcGluZycsXG4gICAgQzogJ0NvbXBsZXRlZCcsXG4gICAgSzogJ1N0b3BwZWQnLFxuICAgIEY6ICdGYWlsZWQnLFxuICB9O1xuXG4gIC8vIEEgcm93IHRoYXQgaXMgc3RpbGwgb3dlZCBjb250ZW50IHNheXMgc287IGEgYnVpbHQgb25lIHNheXMgbm90aGluZy4gT24gYVxuICAvLyBmaW5pc2hlZCBidWlsZCBldmVyeSBzdGFnZSBpcyBkb25lIG9uIGV2ZXJ5IHJvdywgc28gY2hpcHBpbmcgdGhlbSBhbGwgd2FzXG4gIC8vIG5vaXNlIHRoYXQgYnVyaWVkIHRoZSBvbmUgcm93IHRoYXQgbWF0dGVyZWQuXG4gIHByaXZhdGUgc3RhdGljIHJlYWRvbmx5IFBFTkRJTkdfQ09MT1IgPSAnI2IyNjUwMCc7XG5cbiAgLy8gQ2xhc3MtbmFtZSBzdWZmaXggc3RyaXBwZWQgZm9yIGRpc3BsYXk6IGBCdWRnZXRTdW1tYXJ5TW9kZWxgIHJlYWRzIGFzXG4gIC8vIGBCdWRnZXRTdW1tYXJ5YC4gT25seSBgTW9kZWxgIOKAlCBzdHJpcHBpbmcgYEhhbmRsZXJgIHRvbyB3b3VsZCBjb2xsaWRlXG4gIC8vIGBXb3JrT3JkZXJPbmVUaW1lSGFuZGxlcmAgd2l0aCBgV29ya09yZGVyT25lVGltZU1vZGVsYCwgd2hpY2ggYXJlIHR3b1xuICAvLyBzZXBhcmF0ZSB1bml0cy5cbiAgcHJpdmF0ZSBzdGF0aWMgcmVhZG9ubHkgTkFNRV9TVUZGSVggPSAnTW9kZWwnO1xuXG4gIC8vIG51bGwgdW50aWwgbG9hZGVkIOKAlCBnYXRlcyB0aGUgdGFiIGJlaGluZCB0aGUgc2tlbGV0b24uXG4gIHB1YmxpYyByZWFkb25seSBzdGF0dXMgPSBzaWduYWw8U2VtYW50aWNCdWlsZFN0YXR1cyB8IG51bGw+KG51bGwpO1xuXG4gIC8vIEZyZWUtdGV4dCBmaWx0ZXIgb3ZlciB0aGUgdW5pdCBsaXN0IOKAlCBhdCBhIGZldyBodW5kcmVkIHJvd3MgdGhlIGFjY29yZGlvblxuICAvLyBpcyBvbmx5IHVzYWJsZSBpZiB5b3UgY2FuIG5hcnJvdyBpdC5cbiAgcHVibGljIHJlYWRvbmx5IGZpbHRlciA9IHNpZ25hbDxzdHJpbmc+KCcnKTtcblxuICAvLyBUcnVlIHdoaWxlIGEgYnVpbGQgc3RhcnRlZCBmcm9tIHRoaXMgdGFiIGlzIHN0cmVhbWluZyBpbnRvIHRoZSBkb2NrLlxuICBwdWJsaWMgcmVhZG9ubHkgYnVpbGRpbmcgPSBzaWduYWwoZmFsc2UpO1xuXG4gIHB1YmxpYyByZWFkb25seSBidWlsZEFjdGl2ZSA9IGNvbXB1dGVkPGJvb2xlYW4+KCgpID0+XG4gICAgdGhpcy5idWlsZGluZygpXG4gICAgICB8fCBTZW1hbnRpY0RhdGFiYXNlQ29tcG9uZW50LkFDVElWRV9TVEFURVMuaW5jbHVkZXModGhpcy5zdGF0dXMoKT8uYnVpbGQ/LnN0YXRlKSxcbiAgKTtcblxuICBwdWJsaWMgcmVhZG9ubHkgYnVpbGRTdGF0ZUxhYmVsID0gY29tcHV0ZWQ8c3RyaW5nPigoKSA9PlxuICAgIFNlbWFudGljRGF0YWJhc2VDb21wb25lbnQuU1RBVEVfTEFCRUxTW3RoaXMuc3RhdHVzKCk/LmJ1aWxkPy5zdGF0ZV0gPz8gJycsXG4gICk7XG5cbiAgLy8gQW4gYXJ0aWZhY3QgYnVpbHQgYmVmb3JlIHRoZSBjYXRhbG9nIGV4aXN0ZWQgY2FycmllcyBubyB0YWJsZXMuIEV2ZXJ5dGhpbmdcbiAgLy8gY2F0YWxvZy1kcml2ZW4gc3RheXMgaGlkZGVuIHJhdGhlciB0aGFuIGNsYWltaW5nIFwiMCBleGNsdWRlZFwiLCB3aGljaCB3b3VsZFxuICAvLyBiZSBhIGxpZSDigJQgYSByZWJ1aWxkIGZpbGxzIGl0IGluLlxuICBwdWJsaWMgcmVhZG9ubHkgaGFzQ2F0YWxvZyA9IGNvbXB1dGVkPGJvb2xlYW4+KCgpID0+ICEhdGhpcy5zdGF0dXMoKT8uZGV0YWlsPy50YWJsZXM/Lmxlbmd0aCk7XG5cbiAgLy8gVGFibGVzIHdpdGggbm8gbW9kZWw6IHRoZSByZXBvcnQgQUkgY2FuJ3Qgc2VlIHRoZW0gYXQgYWxsLiBBZGQgYSBtb2RlbCB0b1xuICAvLyBwcm9tb3RlIG9uZSB0byBhbiBlbnRpdHkuXG4gIHB1YmxpYyByZWFkb25seSBleGNsdWRlZFRhYmxlcyA9IGNvbXB1dGVkPFNlbWFudGljQnVpbGRUYWJsZVtdPigoKSA9PlxuICAgIHRoaXMuX3RhYmxlcygpLmZpbHRlcigodGFibGUpID0+IHRhYmxlLmNsYXNzaWZpY2F0aW9uID09PSAnZXhjbHVkZWQnKSxcbiAgKTtcblxuICAvLyBMaW5rIHRhYmxlcyB0aGF0IGJyaWRnZWQgbm90aGluZyDigJQgYSBjb21wb3NpdGUgcHJpbWFyeSBrZXkgbWFkZSB0aGVtIGFcbiAgLy8ganVuY3Rpb24sIGJ1dCB0aGV5IHdlcmUgZm9sZGVkIGludG8gbm8gcmVsYXRpb25zaGlwLCBzbyBuZWl0aGVyIHRoZXkgbm9yXG4gIC8vIHdoYXQgdGhleSBsaW5rIGFyZSByZWFjaGFibGUuXG4gIHB1YmxpYyByZWFkb25seSB1bmxpbmtlZEp1bmN0aW9ucyA9IGNvbXB1dGVkPFNlbWFudGljQnVpbGRUYWJsZVtdPigoKSA9PlxuICAgIHRoaXMuX3RhYmxlcygpLmZpbHRlcigodGFibGUpID0+IHRhYmxlLmNsYXNzaWZpY2F0aW9uID09PSAnanVuY3Rpb24nICYmICEhdGFibGUucmVhc29uKSxcbiAgKTtcblxuICAvLyBFdmVyeXRoaW5nIHRoZSBidWlsZCBjYWNoZWQsIGVudGl0aWVzIGFuZCBzdGFuZGFsb25lIGNvZGUgY2xhc3NlcyB0b2dldGhlcixcbiAgLy8gaW4gb25lIGxpc3Qgb3JkZXJlZCBieSB0aGUgbmFtZSBhIHJlYWRlciByZWNvZ25pemVzLiBUd28gYXJyYXlzIG9uIHRoZSB3aXJlXG4gIC8vIGJlY2F1c2UgdGhleSBhcmUgZ2VudWluZWx5IGRpZmZlcmVudCBzaGFwZXM7IG9uZSBsaXN0IG9uIHNjcmVlbiBiZWNhdXNlXG4gIC8vIFwid2hhdCBkaWQgdGhlIGJ1aWxkIHJlYWQ/XCIgaXMgYSBzaW5nbGUgcXVlc3Rpb24uXG4gIHB1YmxpYyByZWFkb25seSB1bml0cyA9IGNvbXB1dGVkPFNlbWFudGljVW5pdFZpZXdbXT4oKCkgPT4ge1xuICAgIGNvbnN0IGRldGFpbCA9IHRoaXMuc3RhdHVzKCk/LmRldGFpbDtcbiAgICBpZiAoIWRldGFpbCkge1xuICAgICAgcmV0dXJuIFtdO1xuICAgIH1cblxuICAgIGNvbnN0IGVudGl0aWVzID0gKGRldGFpbC5lbnRpdGllcyA/PyBbXSkubWFwKChlbnRpdHkpID0+ICh7XG4gICAgICBrZXk6IGVudGl0eS5rZXksXG4gICAgICBuYW1lOiB0aGlzLl9kaXNwbGF5TmFtZShlbnRpdHkubW9kZWwsIGVudGl0eS5rZXkpLFxuICAgICAgaGFzVGFibGU6IHRydWUsXG4gICAgICBlbnRpdHksXG4gICAgICBtb2RlbDogZW50aXR5Lm1vZGVsLFxuICAgICAgZnVuY3Rpb25Db3VudDogZW50aXR5LmZ1bmN0aW9uQ291bnQsXG4gICAgfSkpO1xuXG4gICAgY29uc3QgY2xhc3NlcyA9IChkZXRhaWwuY2xhc3NlcyA/PyBbXSkubWFwKCh1bml0OiBTZW1hbnRpY0J1aWxkQ2xhc3MpID0+ICh7XG4gICAgICBrZXk6IHVuaXQua2V5LFxuICAgICAgbmFtZTogdGhpcy5fZGlzcGxheU5hbWUodW5pdC5tb2RlbCwgdW5pdC5rZXkpLFxuICAgICAgaGFzVGFibGU6IGZhbHNlLFxuICAgICAgZW50aXR5OiBudWxsLFxuICAgICAgbW9kZWw6IHVuaXQubW9kZWwsXG4gICAgICBmdW5jdGlvbkNvdW50OiB1bml0LmZ1bmN0aW9uQ291bnQsXG4gICAgfSkpO1xuXG4gICAgcmV0dXJuIFsuLi5lbnRpdGllcywgLi4uY2xhc3Nlc11cbiAgICAgIC5zb3J0KChhLCBiKSA9PiBhLm5hbWUubG9jYWxlQ29tcGFyZShiLm5hbWUpKTtcbiAgfSk7XG5cbiAgLy8gVGhlIGZpbHRlciBtYXRjaGVzIHRoZSBkaXNwbGF5IG5hbWUsIHRoZSBjbGFzcyBhbmQgdGhlIGVudGl0eSBrZXksIHNvXG4gIC8vIGh1bnRpbmcgYnkgYW55IG9mIHRoZSB0aHJlZSB3b3Jrcy5cbiAgcHVibGljIHJlYWRvbmx5IGZpbHRlcmVkVW5pdHMgPSBjb21wdXRlZDxTZW1hbnRpY1VuaXRWaWV3W10+KCgpID0+IHtcbiAgICBjb25zdCBmaWx0ZXIgPSB0aGlzLmZpbHRlcigpLnRyaW0oKS50b0xvd2VyQ2FzZSgpO1xuICAgIGlmICghZmlsdGVyKSB7XG4gICAgICByZXR1cm4gdGhpcy51bml0cygpO1xuICAgIH1cblxuICAgIHJldHVybiB0aGlzLnVuaXRzKCkuZmlsdGVyKCh1bml0KSA9PlxuICAgICAgYCR7dW5pdC5uYW1lfSAke3VuaXQubW9kZWwgPz8gJyd9ICR7dW5pdC5rZXl9YC50b0xvd2VyQ2FzZSgpLmluY2x1ZGVzKGZpbHRlcikpO1xuICB9KTtcblxuICAvLyBUaGUgQ292ZXJhZ2UgbGluZS4gQXNzZW1ibGVkIGhlcmUgYmVjYXVzZSB0aGUgY2F0YWxvZyBwYXJ0cyBkcm9wIG91dFxuICAvLyBlbnRpcmVseSBvbiBhIHByZS1jYXRhbG9nIGFydGlmYWN0LCB3aGljaCByZWFkcyBiYWRseSBhcyB0ZW1wbGF0ZSBicmFuY2hlcy5cbiAgcHVibGljIHJlYWRvbmx5IGNvdmVyYWdlID0gY29tcHV0ZWQ8c3RyaW5nPigoKSA9PiB7XG4gICAgY29uc3QgZGV0YWlsID0gdGhpcy5zdGF0dXMoKT8uZGV0YWlsO1xuICAgIGlmICghZGV0YWlsKSB7XG4gICAgICByZXR1cm4gJyc7XG4gICAgfVxuXG4gICAgY29uc3QgcGFydHMgPSBbYCR7ZGV0YWlsLmVudGl0eUNvdW50fSBlbnRpdGllc2AsIGAke2RldGFpbC5jbGFzc0NvdW50fSBjb2RlIGNsYXNzZXNgXTtcblxuICAgIGlmICh0aGlzLmhhc0NhdGFsb2coKSkge1xuICAgICAgcGFydHMucHVzaChkZXRhaWwudW5saW5rZWRKdW5jdGlvbkNvdW50XG4gICAgICAgID8gYCR7ZGV0YWlsLmp1bmN0aW9uQ291bnR9IGp1bmN0aW9ucyAoJHtkZXRhaWwudW5saW5rZWRKdW5jdGlvbkNvdW50fSBub3QgbGlua2VkKWBcbiAgICAgICAgOiBgJHtkZXRhaWwuanVuY3Rpb25Db3VudH0ganVuY3Rpb25zYCk7XG4gICAgfVxuXG4gICAgcGFydHMucHVzaChgJHtkZXRhaWwuZnVuY3Rpb25Db3VudH0gY29kZSBmdW5jdGlvbnNgKTtcblxuICAgIGlmICh0aGlzLmhhc0NhdGFsb2coKSkge1xuICAgICAgcGFydHMucHVzaChgJHtkZXRhaWwuZXhjbHVkZWRDb3VudH0gdGFibGVzIGV4Y2x1ZGVkYCk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHBhcnRzLmpvaW4oJyDCtyAnKTtcbiAgfSk7XG5cbiAgLy8gVGhlIHRhYmxlIGNhdGFsb2csIG9yIFtdIHdoZW4gdGhlIHN0YXR1cyBoYXNuJ3QgbG9hZGVkIG9yIHRoZSBhcnRpZmFjdFxuICAvLyBwcmVkYXRlcyBpdC5cbiAgcHJpdmF0ZSByZWFkb25seSBfdGFibGVzID0gY29tcHV0ZWQ8U2VtYW50aWNCdWlsZFRhYmxlW10+KCgpID0+IHRoaXMuc3RhdHVzKCk/LmRldGFpbD8udGFibGVzID8/IFtdKTtcblxuICAvLyBHdWFyZHMgdGhlIG91dGNvbWUgbWVzc2FnZSB0byBmaXJlIGV4YWN0bHkgb25jZSBwZXIgcnVuIOKAlCB3aGV0aGVyIHRoZSBzdHJlYW1cbiAgLy8gY29tcGxldGVzIChidWlsZCBmaW5pc2hlZCwgcG9zc2libHkgZmFpbGVkKSBvciBlcnJvcnMgb3V0cmlnaHQuXG4gIHByaXZhdGUgX2J1aWxkRmluYWxpemVkID0gZmFsc2U7XG5cbiAgcHJpdmF0ZSByZWFkb25seSBfZGlhbG9nID0gaW5qZWN0KE1hdERpYWxvZyk7XG4gIHByaXZhdGUgcmVhZG9ubHkgX3JlcG9ydERhdGEgPSBpbmplY3QoUmVwb3J0RGF0YSk7XG4gIHByaXZhdGUgcmVhZG9ubHkgX3Byb2Nlc3MgPSBpbmplY3QoRnNQcm9jZXNzKTtcbiAgcHJpdmF0ZSByZWFkb25seSBfcHJvbXB0ID0gaW5qZWN0KEZzUHJvbXB0KTtcbiAgcHJpdmF0ZSByZWFkb25seSBfbWVzc2FnZSA9IGluamVjdChGc01lc3NhZ2UpO1xuICBwcml2YXRlIHJlYWRvbmx5IF9kZXN0cm95UmVmID0gaW5qZWN0KERlc3Ryb3lSZWYpO1xuXG4gIGNvbnN0cnVjdG9yKCkge1xuICAgIHRoaXMuX2luaXQoKTtcbiAgfVxuXG4gIC8vIENvbmZpcm0gYmVmb3JlIGtpY2tpbmcgb2ZmIGEgYnVpbGQg4oCUIGEgcmVidWlsZCByZXBsYWNlcyB0aGUgY3VycmVudFxuICAvLyBzZW1hbnRpYyBkYXRhYmFzZSwgc28gaXQgc2hvdWxkIG5ldmVyIGZpcmUgb24gYSBzdHJheSBjbGljay5cbiAgcHVibGljIGJ1aWxkKCk6IHZvaWQge1xuICAgIGNvbnN0IHJlYnVpbGQgPSAhIXRoaXMuc3RhdHVzKCk/LmRldGFpbD8uZ2VuZXJhdGVkQXQ7XG5cbiAgICB0aGlzLl9wcm9tcHQuY29uZmlybSh7XG4gICAgICB0aXRsZTogcmVidWlsZCA/ICdSZWJ1aWxkIHNlbWFudGljIGRhdGFiYXNlJyA6ICdCdWlsZCBzZW1hbnRpYyBkYXRhYmFzZScsXG4gICAgICB0ZW1wbGF0ZTogcmVidWlsZFxuICAgICAgICA/ICdSZWJ1aWxkIHRoZSBzZW1hbnRpYyBkYXRhYmFzZT8gSXQgcnVucyBpbiB0aGUgYmFja2dyb3VuZCBhbmQgcmVwbGFjZXMgdGhlIGN1cnJlbnQgb25lIHdoZW4gaXQgZmluaXNoZXMuJ1xuICAgICAgICA6ICdCdWlsZCB0aGUgc2VtYW50aWMgZGF0YWJhc2U/IEl0IHJ1bnMgaW4gdGhlIGJhY2tncm91bmQuJyxcbiAgICAgIGNvbW1pdExhYmVsOiByZWJ1aWxkID8gJ1JlYnVpbGQnIDogJ0J1aWxkJyxcbiAgICB9KVxuICAgICAgLnBpcGUodGFrZVVudGlsRGVzdHJveWVkKHRoaXMuX2Rlc3Ryb3lSZWYpKVxuICAgICAgLnN1YnNjcmliZSgoKSA9PiB0aGlzLl9ydW5CdWlsZCgpKTtcbiAgfVxuXG4gIHB1YmxpYyBzdG9wQnVpbGQoKTogdm9pZCB7XG4gICAgdGhpcy5fcHJvbXB0LmNvbmZpcm0oe1xuICAgICAgdGl0bGU6ICdTdG9wIGJ1aWxkJyxcbiAgICAgIHRlbXBsYXRlOiAnU3RvcCB0aGUgcnVubmluZyBidWlsZD8gVGhlIGN1cnJlbnQgc2VtYW50aWMgZGF0YWJhc2Ugc3RheXMgaW4gcGxhY2UgdW50aWwgYSBidWlsZCBmaW5pc2hlcy4nLFxuICAgICAgY29tbWl0TGFiZWw6ICdTdG9wJyxcbiAgICB9KVxuICAgICAgLnBpcGUoXG4gICAgICAgIHN3aXRjaE1hcCgoKSA9PiB0aGlzLl9yZXBvcnREYXRhLnNlbWFudGljQnVpbGRTdG9wKCkpLFxuICAgICAgICB0YWtlVW50aWxEZXN0cm95ZWQodGhpcy5fZGVzdHJveVJlZiksXG4gICAgICApXG4gICAgICAuc3Vic2NyaWJlKCgpID0+IHtcbiAgICAgICAgdGhpcy5idWlsZGluZy5zZXQoZmFsc2UpO1xuICAgICAgICB0aGlzLl9tZXNzYWdlLnN1Y2Nlc3MoJ1N0b3BwaW5nIHRoZSBidWlsZOKApicpO1xuICAgICAgICB0aGlzLl9yZWZyZXNoU3RhdHVzKCk7XG4gICAgICB9KTtcbiAgfVxuXG4gIC8vIFJ1biB0aGUgc2VtYW50aWMtZGF0YWJhc2UgYnVpbGQuIFRoZSBsaXZlIGZlZWQgc3RyZWFtcyBpbnRvIHRoZSBGc1Byb2Nlc3NcbiAgLy8gZG9jayAoYm90dG9tLXJpZ2h0KSwgd2hvc2Ugc3Vic2NyaXB0aW9uIHN1cnZpdmVzIHRoaXMgZGlhbG9nIGNsb3Npbmcg4oCUIHNvXG4gIC8vIGRpc21pc3NpbmcgdGhlIGRpYWxvZyBuZXZlciBpbnRlcnJ1cHRzIGEgcnVubmluZyBidWlsZC5cbiAgcHJpdmF0ZSBfcnVuQnVpbGQoKTogdm9pZCB7XG4gICAgdGhpcy5idWlsZGluZy5zZXQodHJ1ZSk7XG4gICAgdGhpcy5fYnVpbGRGaW5hbGl6ZWQgPSBmYWxzZTtcblxuICAgIGNvbnN0IHRhcmdldCQgPSB0aGlzLl9yZXBvcnREYXRhLnNlbWFudGljQnVpbGQoKVxuICAgICAgLnBpcGUoXG4gICAgICAgIC8vIEEgaGFyZCBzdHJlYW0vdHJhbnNwb3J0IGZhaWx1cmUgKHRoZSBidWlsZCBjb3VsZG4ndCBldmVuIHN0YXJ0KVxuICAgICAgICAvLyBmaW5hbGl6ZXMgaGVyZSDigJQgY29tcGxldGVkJCB3b24ndCBmaXJlIGluIHRoYXQgY2FzZS5cbiAgICAgICAgdGFwKHsgZXJyb3I6IChlcnJvcikgPT4gdGhpcy5fZmluYWxpemVCdWlsZChlcnJvcikgfSksXG4gICAgICAgIGZpbHRlcigoZXZlbnQpID0+XG4gICAgICAgICAgZXZlbnQ/LnR5cGUgPT09IFN0cmVhbUV2ZW50VHlwZS5EYXRhXG4gICAgICAgICAgJiYgZXZlbnQuZGF0YT8ua2luZCA9PT0gJ2xvZydcbiAgICAgICAgICAmJiB0eXBlb2YgZXZlbnQuZGF0YS5saW5lID09PSAnc3RyaW5nJyksXG4gICAgICAgIG1hcCgoZXZlbnQpID0+IGV2ZW50LmRhdGEubGluZSBhcyBzdHJpbmcpLFxuICAgICAgKTtcblxuICAgIHRoaXMuX3Byb2Nlc3NcbiAgICAgIC5ydW4oJ1NlbWFudGljIGRhdGFiYXNlIGJ1aWxkJywgdGFyZ2V0JClcbiAgICAgIC5jb21wbGV0ZWQkXG4gICAgICAucGlwZShcbiAgICAgICAgdGFrZSgxKSxcbiAgICAgICAgdGFrZVVudGlsRGVzdHJveWVkKHRoaXMuX2Rlc3Ryb3lSZWYpLFxuICAgICAgKVxuICAgICAgLnN1YnNjcmliZSgoKSA9PiB0aGlzLl9maW5hbGl6ZUJ1aWxkKG51bGwpKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBXcmFwIHVwIG9uZSBidWlsZCBydW4gZXhhY3RseSBvbmNlLiBPbiBhIGhhcmQgc3RyZWFtIGVycm9yLCBzdXJmYWNlIHRoZVxuICAgKiBhY3R1YWwgc2VydmVyLXNpZGUgcmVhc29uIHB1bGxlZCBvZmYgdGhlIGJyb2tlbiBzdHJlYW0g4oCUIHRoZSBnZW5lcmljXG4gICAqIFwiY291bGQgbm90IHJ1blwiIGxpbmUgb25seSB3aGVuIHRoZSBmYWlsdXJlIGNhcnJpZWQgbm8gc2VydmVyIHRleHQgYXQgYWxsO1xuICAgKiBvdGhlcndpc2UgcmVmcmVzaCB0aGUgc3RhdHVzIGFuZCBhbm5vdW5jZSBob3cgdGhlIGJ1aWxkIGFjdHVhbGx5IGVuZGVkIOKAlCBhXG4gICAqIGJ1aWxkIHRoYXQgZmFpbGVkIChlLmcuIHRoZSBBSSBjb3VsZG4ndCBiZSByZWFjaGVkKSByZXBvcnRzICdGYWlsZWQnIHdpdGhcbiAgICogYSByZWFzb24sIGFuZCB0aGF0IG11c3Qgc3VyZmFjZSBpbnN0ZWFkIG9mIHRoZSBydW4gc2lsZW50bHkgZG9pbmcgbm90aGluZy5cbiAgICovXG4gIHByaXZhdGUgX2ZpbmFsaXplQnVpbGQoc3RyZWFtRXJyb3I6IHVua25vd24pOiB2b2lkIHtcbiAgICBpZiAodGhpcy5fYnVpbGRGaW5hbGl6ZWQpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgdGhpcy5fYnVpbGRGaW5hbGl6ZWQgPSB0cnVlO1xuXG4gICAgdGhpcy5idWlsZGluZy5zZXQoZmFsc2UpO1xuXG4gICAgaWYgKHN0cmVhbUVycm9yKSB7XG4gICAgICBjb25zdCBkZXRhaWwgPSB0aGlzLl9zdHJlYW1FcnJvckRldGFpbChzdHJlYW1FcnJvcik7XG5cbiAgICAgIHRoaXMuX21lc3NhZ2UuZXJyb3IoZGV0YWlsXG4gICAgICAgID8gYFRoZSBzZW1hbnRpYyBkYXRhYmFzZSBidWlsZCBmYWlsZWQg4oCUICR7ZGV0YWlsfWBcbiAgICAgICAgOiAnVGhlIHNlbWFudGljIGRhdGFiYXNlIGJ1aWxkIGNvdWxkIG5vdCBydW4g4oCUIGNoZWNrIHRoZSBBSSBjb25uZWN0aW9uIGFuZCB0cnkgYWdhaW4uJyk7XG4gICAgICB0aGlzLl9yZWZyZXNoU3RhdHVzKCk7XG5cbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICB0aGlzLl9yZXBvcnREYXRhLnNlbWFudGljQnVpbGRTdGF0dXMoKVxuICAgICAgLnBpcGUodGFrZVVudGlsRGVzdHJveWVkKHRoaXMuX2Rlc3Ryb3lSZWYpKVxuICAgICAgLnN1YnNjcmliZSgoc3RhdHVzOiBTZW1hbnRpY0J1aWxkU3RhdHVzKSA9PiB7XG4gICAgICAgIHRoaXMuc3RhdHVzLnNldChzdGF0dXMpO1xuICAgICAgICB0aGlzLl9hbm5vdW5jZU91dGNvbWUoc3RhdHVzKTtcbiAgICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIFRoZSByZWFsIHJlYXNvbiBhIGJyb2tlbiBidWlsZCBzdHJlYW0gYnJva2UsIGZyb20gd2hhdCB0aGUgc2VydmVyIGFjdHVhbGx5XG4gICAqIHNlbnQuIEEgc3RydWN0dXJlZCBlcnJvciBmcmFtZSBhcnJpdmVzIGFzIHttZXNzYWdlfSBvbiB0aGUgZXJyb3IgYm9keTsgYVxuICAgKiBtaWQtc3RyZWFtIGNyYXNoIGR1bXBzIHJhdyB0ZXh0IGludG8gdGhlIHN0cmVhbSAodGhlIHN0cmVhbSBpbnRlcmNlcHRvclxuICAgKiBoYW5kcyBpdCBiYWNrIGFzIHN0YXR1c1RleHQpLCB3aGVyZSB0aGUgZnJhbWVzIGFyZSBKU09OIGxpbmVzIGFuZCB0aGVcbiAgICogZmlyc3Qgbm9uLUpTT04gbGluZXMgYXJlIHRoZSBlcnJvciBhbmQgaXRzIGxvY2F0aW9uLiAnJyB3aGVuIHRoZSBmYWlsdXJlXG4gICAqIGNhcnJpZWQgbm8gc2VydmVyIHRleHQgYXQgYWxsICh0cmFuc3BvcnQgZG93biAvIHNlcnZlciB1bnJlYWNoYWJsZSkuXG4gICAqL1xuICBwcml2YXRlIF9zdHJlYW1FcnJvckRldGFpbChzdHJlYW1FcnJvcjogdW5rbm93bik6IHN0cmluZyB7XG4gICAgY29uc3QgZXJyb3IgPSBzdHJlYW1FcnJvciBhcyB7IGVycm9yPzogeyBtZXNzYWdlPzogc3RyaW5nIH07IHN0YXR1c1RleHQ/OiBzdHJpbmcgfTtcblxuICAgIGlmIChlcnJvcj8uZXJyb3I/Lm1lc3NhZ2UpIHtcbiAgICAgIHJldHVybiBlcnJvci5lcnJvci5tZXNzYWdlO1xuICAgIH1cblxuICAgIGNvbnN0IHN0YXR1c1RleHQgPSBlcnJvcj8uc3RhdHVzVGV4dDtcbiAgICBpZiAoIXN0YXR1c1RleHQgfHwgc3RhdHVzVGV4dCA9PT0gJ1Vua25vd24gRXJyb3InKSB7XG4gICAgICByZXR1cm4gJyc7XG4gICAgfVxuXG4gICAgY29uc3QgbGluZXMgPSBzdGF0dXNUZXh0LnNwbGl0KCdcXG4nKVxuICAgICAgLm1hcCgobGluZSkgPT4gbGluZS50cmltKCkpXG4gICAgICAuZmlsdGVyKChsaW5lKSA9PiB7XG4gICAgICAgIGlmICghbGluZSkge1xuICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuXG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgSlNPTi5wYXJzZShsaW5lKTtcblxuICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfSBjYXRjaCB7XG4gICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuXG4gICAgcmV0dXJuIGxpbmVzLnNsaWNlKDAsIDIpLmpvaW4oJyDigJQgJykuc3Vic3RyaW5nKDAsIDMwMCk7XG4gIH1cblxuICAvKipcbiAgICogVGVsbCB0aGUgb3BlcmF0b3IgaG93IHRoZSBidWlsZCBlbmRlZDogYSBmYWlsZWQvc3RvcHBlZCBidWlsZCBzdXJmYWNlcyBpdHNcbiAgICogcmVhc29uIChzbyBhbiBBSSBjb25uZWN0aW9uIHByb2JsZW0gaXMgbmV2ZXIgc2lsZW50KSwgYSBjb21wbGV0ZWQgb25lXG4gICAqIGNvbmZpcm1zIHN1Y2Nlc3MuXG4gICAqL1xuICBwcml2YXRlIF9hbm5vdW5jZU91dGNvbWUoc3RhdHVzOiBTZW1hbnRpY0J1aWxkU3RhdHVzKTogdm9pZCB7XG4gICAgY29uc3QgYnVpbGQgPSBzdGF0dXM/LmJ1aWxkO1xuICAgIGlmIChidWlsZD8uc3RhdGUgPT09ICdGJyB8fCBidWlsZD8uc3RhdGUgPT09ICdLJykge1xuICAgICAgdGhpcy5fbWVzc2FnZS5lcnJvcihidWlsZC5tZXNzYWdlIHx8ICdUaGUgc2VtYW50aWMgZGF0YWJhc2UgYnVpbGQgZGlkIG5vdCBmaW5pc2guJyk7XG4gICAgfSBlbHNlIGlmIChidWlsZD8uc3RhdGUgPT09ICdDJykge1xuICAgICAgdGhpcy5fbWVzc2FnZS5zdWNjZXNzKCdTZW1hbnRpYyBkYXRhYmFzZSBidWlsZCBjb21wbGV0ZS4nKTtcbiAgICB9XG4gIH1cblxuICBwdWJsaWMgcGVuZGluZ0NvbG9yKCk6IHN0cmluZyB7XG4gICAgcmV0dXJuIFNlbWFudGljRGF0YWJhc2VDb21wb25lbnQuUEVORElOR19DT0xPUjtcbiAgfVxuXG4gIC8qKlxuICAgKiBUaGUgYnVpbGQgc3RhZ2VzIHRoaXMgcm93IGlzIHN0aWxsIG93ZWQsIG9yIFtdIHdoZW4gaXQgaXMgZnVsbHkgYnVpbHQuIEFcbiAgICogc3RvcHBlZCBvciBpbnRlcnJ1cHRlZCBidWlsZCBpcyB0aGUgb25seSB3YXkgdG8gZ2V0IGEgbm9uLWVtcHR5IGxpc3QuXG4gICAqL1xuICBwdWJsaWMgcGVuZGluZ1N0YWdlcyh1bml0OiBTZW1hbnRpY1VuaXRWaWV3KTogc3RyaW5nW10ge1xuICAgIGNvbnN0IHN0YWdlcyA9IHVuaXQuZW50aXR5Py5zdGFnZXM7XG5cbiAgICByZXR1cm4gc3RhZ2VzXG4gICAgICA/IE9iamVjdC5rZXlzKHN0YWdlcykuZmlsdGVyKChzdGFnZSkgPT4gc3RhZ2VzW3N0YWdlXSAhPT0gJ2RvbmUnKVxuICAgICAgOiBbXTtcbiAgfVxuXG4gIHB1YmxpYyBzZXRGaWx0ZXIodmFsdWU6IHN0cmluZyk6IHZvaWQge1xuICAgIHRoaXMuZmlsdGVyLnNldCh2YWx1ZSk7XG4gIH1cblxuICAvKipcbiAgICogT3BlbiB0aGUgY2hpbGQgZGlhbG9nIGxpc3Rpbmcgb25lIGdyb3VwIG9mIGEgdW5pdCdzIGNhY2hlZCBmdW5jdGlvbnMg4oCUIGFuXG4gICAqIGVudGl0eSdzIG1vZGVsIG9yIGhhbmRsZXIgY2xhc3MsIG9yIGEgc3RhbmRhbG9uZSBjbGFzcydzIGNvZGUuIFRoZSBkaWFsb2dcbiAgICogZmV0Y2hlcyBmcmVzaCBvbiBvcGVuLCBzbyB0aGUgdGFiIG5ldmVyIGhvbGRzIGZ1bmN0aW9uIHBheWxvYWRzLlxuICAgKi9cbiAgcHVibGljIG9wZW5GdW5jdGlvbnModW5pdDogU2VtYW50aWNVbml0Vmlldywgc291cmNlOiBTZW1hbnRpY0Z1bmN0aW9uU291cmNlKTogdm9pZCB7XG4gICAgdGhpcy5fZGlhbG9nLm9wZW4oRW50aXR5RnVuY3Rpb25zQ29tcG9uZW50LCB7XG4gICAgICB3aWR0aDogJzcwMHB4JyxcbiAgICAgIG1heFdpZHRoOiAnOTV2dycsXG4gICAgICBtYXhIZWlnaHQ6ICc4NXZoJyxcbiAgICAgIGF1dG9Gb2N1czogZmFsc2UsXG4gICAgICBkYXRhOiB7IGVudGl0eUtleTogdW5pdC5rZXksIHNvdXJjZSB9LFxuICAgIH0pO1xuICB9XG5cbiAgcHJpdmF0ZSBfaW5pdCgpOiB2b2lkIHtcbiAgICB0aGlzLl9yZWZyZXNoU3RhdHVzKCk7XG4gIH1cblxuICAvKipcbiAgICogV2hhdCBhIHJlYWRlciByZWNvZ25pemVzIHRoZSB1bml0IGJ5OiBpdHMgY2xhc3MncyBzaG9ydCBuYW1lLCBtaW51cyB0aGVcbiAgICogYE1vZGVsYCBzdWZmaXggdGhhdCBldmVyeSBtb2RlbCBjYXJyaWVzIGFuZCBub25lIG9mIHRoZW0gYXJlIGRpc3Rpbmd1aXNoZWRcbiAgICogYnkuIEZhbGxzIGJhY2sgdG8gdGhlIGNhY2hlIGtleSBmb3IgYSB1bml0IHdob3NlIGNsYXNzIGNvdWxkIG5vdCBiZVxuICAgKiByZXNvbHZlZCwgc28gYSByb3cgbmV2ZXIgcmVuZGVycyBuYW1lbGVzcy5cbiAgICovXG4gIHByaXZhdGUgX2Rpc3BsYXlOYW1lKG1vZGVsOiBzdHJpbmcgfCBudWxsLCBrZXk6IHN0cmluZyk6IHN0cmluZyB7XG4gICAgaWYgKCFtb2RlbCkge1xuICAgICAgcmV0dXJuIGtleTtcbiAgICB9XG5cbiAgICBjb25zdCBzaG9ydE5hbWUgPSBtb2RlbC5zcGxpdCgnXFxcXCcpLnBvcCgpO1xuXG4gICAgcmV0dXJuIHNob3J0TmFtZS5sZW5ndGggPiBTZW1hbnRpY0RhdGFiYXNlQ29tcG9uZW50Lk5BTUVfU1VGRklYLmxlbmd0aFxuICAgICAgJiYgc2hvcnROYW1lLmVuZHNXaXRoKFNlbWFudGljRGF0YWJhc2VDb21wb25lbnQuTkFNRV9TVUZGSVgpXG4gICAgICA/IHNob3J0TmFtZS5zbGljZSgwLCAtU2VtYW50aWNEYXRhYmFzZUNvbXBvbmVudC5OQU1FX1NVRkZJWC5sZW5ndGgpXG4gICAgICA6IHNob3J0TmFtZTtcbiAgfVxuXG4gIHByaXZhdGUgX3JlZnJlc2hTdGF0dXMoKTogdm9pZCB7XG4gICAgdGhpcy5fcmVwb3J0RGF0YS5zZW1hbnRpY0J1aWxkU3RhdHVzKClcbiAgICAgIC5waXBlKHRha2VVbnRpbERlc3Ryb3llZCh0aGlzLl9kZXN0cm95UmVmKSlcbiAgICAgIC5zdWJzY3JpYmUoKHN0YXR1czogU2VtYW50aWNCdWlsZFN0YXR1cykgPT4gdGhpcy5zdGF0dXMuc2V0KHN0YXR1cykpO1xuICB9XG59XG4iLCI8ZGl2IGNsYXNzPVwiZnMtY29sdW1uIHRhYi1ib2R5XCI+XG4gIDxwIGNsYXNzPVwiaGludFwiPlxuICAgIFRoZSBzZW1hbnRpYyBkYXRhYmFzZSBpcyB3aGF0IHRoZSByZXBvcnQgQUkgdXNlcyB0byB1bmRlcnN0YW5kIHlvdXIgZGF0YSDigJRcbiAgICB0YWJsZXMsIHJlbGF0aW9uc2hpcHMgYW5kIHRoZSBjYWxjdWxhdGlvbnMgaW4gY29kZS4gUmVidWlsZCBpdCBhZnRlclxuICAgIHNpZ25pZmljYW50IGFwcGxpY2F0aW9uIHVwZGF0ZXMuIFRoZSBidWlsZCBydW5zIGluIHRoZSBiYWNrZ3JvdW5kOyBwcm9ncmVzc1xuICAgIGFwcGVhcnMgaW4gdGhlIGRvY2sgYXQgdGhlIGJvdHRvbSByaWdodCBhbmQgdGhpcyBkaWFsb2cgY2FuIGJlIGNsb3NlZCB3aGlsZVxuICAgIGl0IHJ1bnMuXG4gIDwvcD5cblxuICA8ZGl2ICpmc1NrZWxldG9uPVwic3RhdHVzKClcIj5cbiAgICBAaWYgKHN0YXR1cygpOyBhcyBidWlsZFN0YXR1cykge1xuICAgICAgPGRpdiBjbGFzcz1cImJ1aWxkLXN0YXR1c1wiPlxuICAgICAgICBAaWYgKGJ1aWxkU3RhdHVzLmRldGFpbC5nZW5lcmF0ZWRBdCkge1xuICAgICAgICAgIDxkaXYgY2xhc3M9XCJzdGF0XCI+XG4gICAgICAgICAgICA8c3BhbiBjbGFzcz1cImxhYmVsXCI+TGFzdCBidWlsdDwvc3Bhbj5cbiAgICAgICAgICAgIDxmcy1kYXRlXG4gICAgICAgICAgICAgICAgW2RhdGVdPVwiYnVpbGRTdGF0dXMuZGV0YWlsLmdlbmVyYXRlZEF0XCJcbiAgICAgICAgICAgICAgICBmb3JtYXQ9XCJkYXRlLXRpbWVcIj5cbiAgICAgICAgICAgIDwvZnMtZGF0ZT5cbiAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICA8ZGl2IGNsYXNzPVwic3RhdFwiPlxuICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJsYWJlbFwiPkNvdmVyYWdlPC9zcGFuPlxuICAgICAgICAgICAgPHNwYW4+e3sgY292ZXJhZ2UoKSB9fTwvc3Bhbj5cbiAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgfSBAZWxzZSB7XG4gICAgICAgICAgPGZzLW1lc3NhZ2Utd2FybmluZz5cbiAgICAgICAgICAgIFRoZSBzZW1hbnRpYyBkYXRhYmFzZSBoYXMgbm90IGJlZW4gYnVpbHQgeWV0IOKAlCB0aGUgcmVwb3J0IEFJIGNhbid0XG4gICAgICAgICAgICBhbnN3ZXIgZGF0YSBxdWVzdGlvbnMgdW50aWwgaXQgaXMuIFJ1biB0aGUgZmlyc3QgYnVpbGQuXG4gICAgICAgICAgPC9mcy1tZXNzYWdlLXdhcm5pbmc+XG4gICAgICAgIH1cbiAgICAgICAgQGlmIChidWlsZFN0YXR1cy5idWlsZCkge1xuICAgICAgICAgIDxkaXYgY2xhc3M9XCJzdGF0XCI+XG4gICAgICAgICAgICA8c3BhbiBjbGFzcz1cImxhYmVsXCI+TGFzdCBidWlsZCBydW48L3NwYW4+XG4gICAgICAgICAgICA8c3Bhbj5cbiAgICAgICAgICAgICAge3sgYnVpbGRTdGF0ZUxhYmVsKCkgfX1cbiAgICAgICAgICAgICAgQGlmIChidWlsZFN0YXR1cy5idWlsZC5tZXNzYWdlKSB7XG4gICAgICAgICAgICAgICAg4oCUIHt7IGJ1aWxkU3RhdHVzLmJ1aWxkLm1lc3NhZ2UgfX1cbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgPC9zcGFuPlxuICAgICAgICAgIDwvZGl2PlxuICAgICAgICB9XG4gICAgICA8L2Rpdj5cblxuICAgICAgPCEtLSBFdmVyeXRoaW5nIHRoZSBidWlsZCByZWFkLCBpbiBvbmUgbGlzdDogZW50aXRpZXMgKGEgdGFibGUgKyBhIG1vZGVsICtcbiAgICAgICAgICAgYSBoYW5kbGVyKSBhbmQgc3RhbmRhbG9uZSBjb2RlIGNsYXNzZXMgKGRvbWFpbiBsb2dpYyB3aXRoIG5vIHRhYmxlKS5cbiAgICAgICAgICAgVGhlIEFJIHJlYWRzIGNvZGUgZnJvbSBib3RoLCBzbyBzcGxpdHRpbmcgdGhlbSBpbnRvIHR3byBzZWN0aW9uc1xuICAgICAgICAgICB3b3VsZCBoaWRlIGhhbGYgb2Ygd2hhdCB3YXMgYnVpbHQuIEVhY2ggcm93IGRyaWxscyBpbnRvIGl0cyBzaGFwZSxcbiAgICAgICAgICAgZW51bSB2YWx1ZXMsIGNvbXB1dGVkIGZpZWxkcyBhbmQgY2FjaGVkIGZ1bmN0aW9uIGNvdW50cyDigJQgdGhlIGNvdW50c1xuICAgICAgICAgICBsaW5rIGludG8gdGhlIGZ1bmN0aW9ucyBkaWFsb2cuIC0tPlxuICAgICAgQGlmICh1bml0cygpLmxlbmd0aCkge1xuICAgICAgICA8aDI+SW5jbHVkZWQgKHt7IHVuaXRzKCkubGVuZ3RoIH19KTwvaDI+XG4gICAgICAgIDxkaXYgY2xhc3M9XCJzdWJoZWFkaW5nXCI+XG4gICAgICAgICAgRXZlcnl0aGluZyB0aGUgcmVwb3J0IEFJIHdhcyBidWlsdCBmcm9tLiBFbnRpdGllcyBjYW4gYmUgcXVlcmllZDtcbiAgICAgICAgICBjb2RlIGNsYXNzZXMgYXJlIGxvZ2ljIGl0IHJlYWRzIGFuZCB0cmFuc2xhdGVzIGludG8gU1FMLlxuICAgICAgICA8L2Rpdj5cblxuICAgICAgICA8aW5wdXRcbiAgICAgICAgICAgIGNsYXNzPVwidW5pdC1maWx0ZXJcIlxuICAgICAgICAgICAgdHlwZT1cInNlYXJjaFwiXG4gICAgICAgICAgICBwbGFjZWhvbGRlcj1cIkZpbHRlciBieSBuYW1lLCBjbGFzcyBvciBrZXnigKZcIlxuICAgICAgICAgICAgW3ZhbHVlXT1cImZpbHRlcigpXCJcbiAgICAgICAgICAgIChpbnB1dCk9XCJzZXRGaWx0ZXIoJGFueSgkZXZlbnQudGFyZ2V0KS52YWx1ZSlcIj5cblxuICAgICAgICA8bWF0LWFjY29yZGlvbiBjbGFzcz1cImVudGl0aWVzXCI+XG4gICAgICAgICAgQGZvciAodW5pdCBvZiBmaWx0ZXJlZFVuaXRzKCk7IHRyYWNrIHVuaXQua2V5KSB7XG4gICAgICAgICAgICA8bWF0LWV4cGFuc2lvbi1wYW5lbD5cbiAgICAgICAgICAgICAgPG1hdC1leHBhbnNpb24tcGFuZWwtaGVhZGVyPlxuICAgICAgICAgICAgICAgIDxtYXQtcGFuZWwtdGl0bGU+e3sgdW5pdC5uYW1lIH19PC9tYXQtcGFuZWwtdGl0bGU+XG4gICAgICAgICAgICAgICAgPG1hdC1wYW5lbC1kZXNjcmlwdGlvbj5cbiAgICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJzdGFnZS1jaGlwc1wiPlxuICAgICAgICAgICAgICAgICAgICBAaWYgKCF1bml0Lmhhc1RhYmxlKSB7XG4gICAgICAgICAgICAgICAgICAgICAgPGZzLWNoaXAgc2l6ZT1cInRpbnlcIiBtYXRUb29sdGlwPVwiRG9tYWluIGxvZ2ljIHdpdGggbm8gdGFibGUg4oCUIHJlYWQsIG5ldmVyIHF1ZXJpZWRcIj5cbiAgICAgICAgICAgICAgICAgICAgICAgIGNvZGVcbiAgICAgICAgICAgICAgICAgICAgICA8L2ZzLWNoaXA+XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgPCEtLSBTaWxlbmNlIG1lYW5zIGJ1aWx0LiBBIGNoaXAgaGVyZSBtZWFucyBhbiBpbnRlcnJ1cHRlZFxuICAgICAgICAgICAgICAgICAgICAgICAgIGJ1aWxkIGxlZnQgdGhpcyByb3cgb3dpbmcgY29udGVudC4gLS0+XG4gICAgICAgICAgICAgICAgICAgIEBmb3IgKHN0YWdlIG9mIHBlbmRpbmdTdGFnZXModW5pdCk7IHRyYWNrIHN0YWdlKSB7XG4gICAgICAgICAgICAgICAgICAgICAgPGZzLWNoaXBcbiAgICAgICAgICAgICAgICAgICAgICAgICAgc2l6ZT1cInRpbnlcIlxuICAgICAgICAgICAgICAgICAgICAgICAgICBbYmFja2dyb3VuZENvbG9yXT1cInBlbmRpbmdDb2xvcigpXCJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3I9XCIjZmZmZmZmXCJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgbWF0VG9vbHRpcD1cIk5lZWRzIGJ1aWxkaW5nXCI+XG4gICAgICAgICAgICAgICAgICAgICAgICB7eyBzdGFnZSB9fVxuICAgICAgICAgICAgICAgICAgICAgIDwvZnMtY2hpcD5cbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICAgICAgPC9tYXQtcGFuZWwtZGVzY3JpcHRpb24+XG4gICAgICAgICAgICAgIDwvbWF0LWV4cGFuc2lvbi1wYW5lbC1oZWFkZXI+XG5cbiAgICAgICAgICAgICAgPCEtLSBEZWZlcnJlZDogdGhlIGJvZHkgb25seSBleGlzdHMgb25jZSBleHBhbmRlZC4gLS0+XG4gICAgICAgICAgICAgIDxuZy10ZW1wbGF0ZSBtYXRFeHBhbnNpb25QYW5lbENvbnRlbnQ+XG4gICAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cImVudGl0eS1kZXRhaWxcIj5cbiAgICAgICAgICAgICAgICAgIEBpZiAodW5pdC5tb2RlbCkge1xuICAgICAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwic3RhdFwiPlxuICAgICAgICAgICAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwibGFiZWxcIj5DbGFzczwvc3Bhbj5cbiAgICAgICAgICAgICAgICAgICAgICA8c3Bhbj57eyB1bml0Lm1vZGVsIH19PC9zcGFuPlxuICAgICAgICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgIEBpZiAodW5pdC5lbnRpdHk7IGFzIGVudGl0eSkge1xuICAgICAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwic3RhdFwiPlxuICAgICAgICAgICAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwibGFiZWxcIj5UYWJsZTwvc3Bhbj5cbiAgICAgICAgICAgICAgICAgICAgICA8c3Bhbj57eyBlbnRpdHkudGFibGUgfX08L3NwYW4+XG4gICAgICAgICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgICAgICAgICA8IS0tIFRoZSBoYW5kbGUgdGhlIHJlcG9ydCBBSSBhZGRyZXNzZXMgdGhpcyBlbnRpdHkgYnkgaW5cbiAgICAgICAgICAgICAgICAgICAgICAgICBkZXNjcmliZV9lbnRpdHkgLyBjb21waWxlX3F1ZXJ5LiAtLT5cbiAgICAgICAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cInN0YXRcIj5cbiAgICAgICAgICAgICAgICAgICAgICA8c3BhbiBjbGFzcz1cImxhYmVsXCI+RW50aXR5IGtleTwvc3Bhbj5cbiAgICAgICAgICAgICAgICAgICAgICA8c3Bhbj57eyBlbnRpdHkua2V5IH19PC9zcGFuPlxuICAgICAgICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cInN0YXRcIj5cbiAgICAgICAgICAgICAgICAgICAgICA8c3BhbiBjbGFzcz1cImxhYmVsXCI+Q29sdW1uczwvc3Bhbj5cbiAgICAgICAgICAgICAgICAgICAgICA8c3Bhbj57eyBlbnRpdHkuY29sdW1ucyB9fTwvc3Bhbj5cbiAgICAgICAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJzdGF0XCI+XG4gICAgICAgICAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJsYWJlbFwiPlJlbGF0aW9uc2hpcHM8L3NwYW4+XG4gICAgICAgICAgICAgICAgICAgICAgPHNwYW4+e3sgZW50aXR5LnJlbGF0aW9uc2hpcHMgfX08L3NwYW4+XG4gICAgICAgICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgICAgICAgICBAaWYgKGVudGl0eS5lbnVtcy5sZW5ndGgpIHtcbiAgICAgICAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwic3RhdFwiPlxuICAgICAgICAgICAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJsYWJlbFwiPkVudW1lcmF0aW9uIHZhbHVlczwvc3Bhbj5cbiAgICAgICAgICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJwYWlyLWxpc3RcIj5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgQGZvciAoZW51bUNvbHVtbiBvZiBlbnRpdHkuZW51bXM7IHRyYWNrIGVudW1Db2x1bW4uY29sdW1uKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cInBhaXItcm93XCI+XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8c3BhbiBjbGFzcz1cInBhaXItbmFtZVwiPnt7IGVudW1Db2x1bW4uY29sdW1uIH19PC9zcGFuPlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHNwYW4+e3sgZW51bUNvbHVtbi52YWx1ZXMuam9pbignLCAnKSB9fTwvc3Bhbj5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgQGlmIChlbnRpdHkuY29tcHV0ZWRGaWVsZHMubGVuZ3RoKSB7XG4gICAgICAgICAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cInN0YXRcIj5cbiAgICAgICAgICAgICAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwibGFiZWxcIj5Db21wdXRlZCBmaWVsZHM8L3NwYW4+XG4gICAgICAgICAgICAgICAgICAgICAgICA8c3Bhbj57eyBlbnRpdHkuY29tcHV0ZWRGaWVsZHMuam9pbignLCAnKSB9fTwvc3Bhbj5cbiAgICAgICAgICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwic3RhdFwiPlxuICAgICAgICAgICAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwibGFiZWxcIj5Nb2RlbCBmdW5jdGlvbnM8L3NwYW4+XG4gICAgICAgICAgICAgICAgICAgICAgQGlmIChlbnRpdHkubW9kZWxGdW5jdGlvbkNvdW50KSB7XG4gICAgICAgICAgICAgICAgICAgICAgICA8YVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNsYXNzPVwiY291bnQtbGlua1wiXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgKGNsaWNrKT1cIm9wZW5GdW5jdGlvbnModW5pdCwgJ21vZGVsJylcIj5cbiAgICAgICAgICAgICAgICAgICAgICAgICAge3sgZW50aXR5Lm1vZGVsRnVuY3Rpb25Db3VudCB9fVxuICAgICAgICAgICAgICAgICAgICAgICAgPC9hPlxuICAgICAgICAgICAgICAgICAgICAgIH0gQGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgPHNwYW4+MDwvc3Bhbj5cbiAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwic3RhdFwiPlxuICAgICAgICAgICAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwibGFiZWxcIj5IYW5kbGVyIGZ1bmN0aW9uczwvc3Bhbj5cbiAgICAgICAgICAgICAgICAgICAgICBAaWYgKGVudGl0eS5oYW5kbGVyRnVuY3Rpb25Db3VudCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgPGFcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjbGFzcz1cImNvdW50LWxpbmtcIlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIChjbGljayk9XCJvcGVuRnVuY3Rpb25zKHVuaXQsICdoYW5kbGVyJylcIj5cbiAgICAgICAgICAgICAgICAgICAgICAgICAge3sgZW50aXR5LmhhbmRsZXJGdW5jdGlvbkNvdW50IH19XG4gICAgICAgICAgICAgICAgICAgICAgICA8L2E+XG4gICAgICAgICAgICAgICAgICAgICAgfSBAZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICA8c3Bhbj4wPC9zcGFuPlxuICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICAgICAgICB9IEBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cInN0YXRcIj5cbiAgICAgICAgICAgICAgICAgICAgICA8c3BhbiBjbGFzcz1cImxhYmVsXCI+Q29kZSBmdW5jdGlvbnM8L3NwYW4+XG4gICAgICAgICAgICAgICAgICAgICAgQGlmICh1bml0LmZ1bmN0aW9uQ291bnQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIDxhXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY2xhc3M9XCJjb3VudC1saW5rXCJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAoY2xpY2spPVwib3BlbkZ1bmN0aW9ucyh1bml0LCAnY2xhc3MnKVwiPlxuICAgICAgICAgICAgICAgICAgICAgICAgICB7eyB1bml0LmZ1bmN0aW9uQ291bnQgfX1cbiAgICAgICAgICAgICAgICAgICAgICAgIDwvYT5cbiAgICAgICAgICAgICAgICAgICAgICB9IEBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIDxzcGFuPjA8L3NwYW4+XG4gICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgICAgPC9uZy10ZW1wbGF0ZT5cbiAgICAgICAgICAgIDwvbWF0LWV4cGFuc2lvbi1wYW5lbD5cbiAgICAgICAgICB9XG4gICAgICAgIDwvbWF0LWFjY29yZGlvbj5cblxuICAgICAgICBAaWYgKCFmaWx0ZXJlZFVuaXRzKCkubGVuZ3RoKSB7XG4gICAgICAgICAgPGRpdiBjbGFzcz1cInN1YmhlYWRpbmdcIj5Ob3RoaW5nIG1hdGNoZXMg4oCce3sgZmlsdGVyKCkgfX3igJ0uPC9kaXY+XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgPCEtLSBUaGUgb3RoZXIgaGFsZiBvZiB0aGUgcGljdHVyZTogdGFibGVzIHRoZSBBSSBjYW4ndCByZWFjaC4gRXhjbHVkZWRcbiAgICAgICAgICAgb25lcyBoYXZlIG5vIG1vZGVsOyB1bmxpbmtlZCBqdW5jdGlvbnMgaGF2ZSBhIGNvbXBvc2l0ZSBwcmltYXJ5IGtleVxuICAgICAgICAgICBidXQgd2VyZSBmb2xkZWQgaW50byBubyByZWxhdGlvbnNoaXAsIHNvIG5vdGhpbmcgY2FuIG5hdmlnYXRlIHRvXG4gICAgICAgICAgIHRoZW0uIEJvdGggYXJlIGludmlzaWJsZSBieSBvbWlzc2lvbiDigJQgbm8gZXJyb3IsIGp1c3QgYSBjYXBhYmlsaXR5XG4gICAgICAgICAgIHRoYXQgc2lsZW50bHkgaXNuJ3QgdGhlcmUuIENvbGxhcHNlZCBieSBkZWZhdWx0OiB0aGUgZXhjbHVkZWQgbGlzdCBpc1xuICAgICAgICAgICBsb25nIGFuZCBtb3N0bHkgZnJhbWV3b3JrIHBsdW1iaW5nLiAtLT5cbiAgICAgIEBpZiAoaGFzQ2F0YWxvZygpKSB7XG4gICAgICAgIDxoMj5Ob3QgaW4gdGhlIHNlbWFudGljIGRhdGFiYXNlPC9oMj5cbiAgICAgICAgPGRpdiBjbGFzcz1cInN1YmhlYWRpbmdcIj5cbiAgICAgICAgICBUYWJsZXMgdGhlIHJlcG9ydCBBSSBjYW4ndCBzZWUuIEdpdmUgb25lIGEgbW9kZWwgdG8gcHJvbW90ZSBpdCB0byBhblxuICAgICAgICAgIGVudGl0eSwgdGhlbiByZWJ1aWxkLlxuICAgICAgICA8L2Rpdj5cbiAgICAgICAgPG1hdC1hY2NvcmRpb24gY2xhc3M9XCJjYXRhbG9nXCI+XG4gICAgICAgICAgQGlmIChleGNsdWRlZFRhYmxlcygpLmxlbmd0aCkge1xuICAgICAgICAgICAgPG1hdC1leHBhbnNpb24tcGFuZWw+XG4gICAgICAgICAgICAgIDxtYXQtZXhwYW5zaW9uLXBhbmVsLWhlYWRlcj5cbiAgICAgICAgICAgICAgICA8bWF0LXBhbmVsLXRpdGxlPlxuICAgICAgICAgICAgICAgICAgVGFibGVzIGV4Y2x1ZGVkICh7eyBleGNsdWRlZFRhYmxlcygpLmxlbmd0aCB9fSlcbiAgICAgICAgICAgICAgICA8L21hdC1wYW5lbC10aXRsZT5cbiAgICAgICAgICAgICAgPC9tYXQtZXhwYW5zaW9uLXBhbmVsLWhlYWRlcj5cblxuICAgICAgICAgICAgICA8IS0tIERlZmVycmVkOiB0aGUgYm9keSBvbmx5IGV4aXN0cyBvbmNlIGV4cGFuZGVkLiAtLT5cbiAgICAgICAgICAgICAgPG5nLXRlbXBsYXRlIG1hdEV4cGFuc2lvblBhbmVsQ29udGVudD5cbiAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwicGFpci1saXN0XCI+XG4gICAgICAgICAgICAgICAgICBAZm9yICh0YWJsZSBvZiBleGNsdWRlZFRhYmxlcygpOyB0cmFjayB0YWJsZS50YWJsZSkge1xuICAgICAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwicGFpci1yb3dcIj5cbiAgICAgICAgICAgICAgICAgICAgICA8c3BhbiBjbGFzcz1cInBhaXItbmFtZVwiPnt7IHRhYmxlLnRhYmxlIH19PC9zcGFuPlxuICAgICAgICAgICAgICAgICAgICAgIDxzcGFuPnt7IHRhYmxlLnJlYXNvbiB9fTwvc3Bhbj5cbiAgICAgICAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICAgIDwvbmctdGVtcGxhdGU+XG4gICAgICAgICAgICA8L21hdC1leHBhbnNpb24tcGFuZWw+XG4gICAgICAgICAgfVxuICAgICAgICAgIEBpZiAodW5saW5rZWRKdW5jdGlvbnMoKS5sZW5ndGgpIHtcbiAgICAgICAgICAgIDxtYXQtZXhwYW5zaW9uLXBhbmVsPlxuICAgICAgICAgICAgICA8bWF0LWV4cGFuc2lvbi1wYW5lbC1oZWFkZXI+XG4gICAgICAgICAgICAgICAgPG1hdC1wYW5lbC10aXRsZT5cbiAgICAgICAgICAgICAgICAgIEp1bmN0aW9ucyBub3QgbGlua2VkICh7eyB1bmxpbmtlZEp1bmN0aW9ucygpLmxlbmd0aCB9fSlcbiAgICAgICAgICAgICAgICA8L21hdC1wYW5lbC10aXRsZT5cbiAgICAgICAgICAgICAgPC9tYXQtZXhwYW5zaW9uLXBhbmVsLWhlYWRlcj5cblxuICAgICAgICAgICAgICA8bmctdGVtcGxhdGUgbWF0RXhwYW5zaW9uUGFuZWxDb250ZW50PlxuICAgICAgICAgICAgICAgIDxwIGNsYXNzPVwic21hbGxcIj5cbiAgICAgICAgICAgICAgICAgIExpbmsgdGFibGVzIHRoZSBidWlsZCBjb3VsZG4ndCBmb2xkIGludG8gYSByZWxhdGlvbnNoaXAg4oCUIHNvXG4gICAgICAgICAgICAgICAgICBuZWl0aGVyIHRoZXkgbm9yIHdoYXQgdGhleSBsaW5rIGNhbiBiZSByZXBvcnRlZCBvbi5cbiAgICAgICAgICAgICAgICA8L3A+XG4gICAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cInBhaXItbGlzdFwiPlxuICAgICAgICAgICAgICAgICAgQGZvciAodGFibGUgb2YgdW5saW5rZWRKdW5jdGlvbnMoKTsgdHJhY2sgdGFibGUudGFibGUpIHtcbiAgICAgICAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cInBhaXItcm93XCI+XG4gICAgICAgICAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJwYWlyLW5hbWVcIj57eyB0YWJsZS50YWJsZSB9fTwvc3Bhbj5cbiAgICAgICAgICAgICAgICAgICAgICA8c3Bhbj57eyB0YWJsZS5yZWFzb24gfX08L3NwYW4+XG4gICAgICAgICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgICA8L25nLXRlbXBsYXRlPlxuICAgICAgICAgICAgPC9tYXQtZXhwYW5zaW9uLXBhbmVsPlxuICAgICAgICAgIH1cbiAgICAgICAgPC9tYXQtYWNjb3JkaW9uPlxuICAgICAgfVxuICAgIH1cbiAgPC9kaXY+XG48L2Rpdj5cbiJdfQ==