@firestitch/report 18.4.0 → 18.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -15,9 +15,11 @@ export declare class SemanticDatabaseComponent {
15
15
  private static readonly PENDING_COLOR;
16
16
  private static readonly NAME_SUFFIX;
17
17
  readonly status: import("@angular/core").WritableSignal<SemanticBuildStatus>;
18
+ readonly statusError: import("@angular/core").WritableSignal<boolean>;
18
19
  readonly filter: import("@angular/core").WritableSignal<string>;
19
20
  readonly building: import("@angular/core").WritableSignal<boolean>;
20
21
  readonly buildActive: import("@angular/core").Signal<boolean>;
22
+ readonly rebuild: import("@angular/core").Signal<boolean>;
21
23
  readonly buildStateLabel: import("@angular/core").Signal<string>;
22
24
  readonly buildComplete: import("@angular/core").Signal<boolean>;
23
25
  readonly incompleteEntityCount: import("@angular/core").Signal<number>;
@@ -86,6 +88,7 @@ export declare class SemanticDatabaseComponent {
86
88
  */
87
89
  private _displayName;
88
90
  private _refreshStatus;
91
+ private _loadStatus;
89
92
  static ɵfac: i0.ɵɵFactoryDeclaration<SemanticDatabaseComponent, never>;
90
93
  static ɵcmp: i0.ɵɵComponentDeclaration<SemanticDatabaseComponent, "fs-ai-report-global-settings-semantic-database", never, {}, {}, never, never, true, never>;
91
94
  }
@@ -8,6 +8,10 @@ export declare class ReportPptxService {
8
8
  private _renderComponent;
9
9
  private _renderChart;
10
10
  private _addChart;
11
+ private _renderWaterfall;
12
+ private _waterfallSeries;
13
+ private _categoryLabels;
14
+ private _axisTextOptions;
11
15
  private _renderTable;
12
16
  private _renderKpi;
13
17
  private _cell;
@@ -87,8 +87,9 @@ export declare const GRANULARITY_OPTIONS: {
87
87
  name: string;
88
88
  }[];
89
89
  export type AxisChartType = 'bar' | 'line' | 'area';
90
+ export type WaterfallStepKind = 'rise' | 'fall' | 'total';
90
91
  export interface ChartConfig {
91
- chartType?: AxisChartType | 'pie' | 'donut';
92
+ chartType?: AxisChartType | 'waterfall' | 'pie' | 'donut';
92
93
  xAxis?: {
93
94
  column: string;
94
95
  kind?: 'category' | 'time';
@@ -1,5 +1,5 @@
1
1
  import type { EChartsOption } from 'echarts';
2
- import { AxisChartType, ChartConfig, ChartGranularity, ComponentData, LegendPosition, ReportComponent } from './interfaces/report.interface';
2
+ import { AxisChartType, ChartConfig, ChartGranularity, ComponentData, LegendPosition, ReportComponent, WaterfallStepKind } from './interfaces/report.interface';
3
3
  export declare function isColorBy(config: ChartConfig): boolean;
4
4
  export declare function colorByColumn(config: ChartConfig): string | undefined;
5
5
  export interface ExtractedChartSeries {
@@ -12,6 +12,18 @@ export interface ExtractedChartSeries {
12
12
  }
13
13
  export declare function extractChartSeries(component: ReportComponent, data: ComponentData): ExtractedChartSeries;
14
14
  export declare function seriesTypes(extracted: ExtractedChartSeries, chartType: AxisChartType): AxisChartType[];
15
+ export interface WaterfallStep {
16
+ category: string;
17
+ start: number;
18
+ change: number | null;
19
+ kind: WaterfallStepKind;
20
+ }
21
+ export interface ExtractedWaterfall {
22
+ name: string;
23
+ steps: WaterfallStep[];
24
+ }
25
+ export declare const WATERFALL_TOTAL_LABEL = "Total";
26
+ export declare function extractWaterfall(component: ReportComponent, data: ComponentData): ExtractedWaterfall;
15
27
  export declare function buildChartOption(component: ReportComponent, data: ComponentData): EChartsOption;
16
28
  export declare function resolveLegendPosition(config: ChartConfig, seriesCount: number, colorBy?: boolean): LegendPosition;
17
29
  export declare function spansMultipleYears(categories: string[]): boolean;
@@ -27,3 +27,4 @@ export interface TextParagraph {
27
27
  export declare function fillTextTokens(html: string, context: TextTokenContext): string;
28
28
  export declare function textParagraphs(html: string, context: TextTokenContext): TextParagraph[];
29
29
  export declare function textPlain(html: string, context: TextTokenContext): string;
30
+ export declare function escapeHtml(value: string): string;
@@ -1,2 +1,4 @@
1
+ import { WaterfallStepKind } from '../interfaces/report.interface';
1
2
  export declare const REPORT_CHART_COLORS: string[];
2
3
  export declare const REPORT_CHART_COLORS_CSS: string[];
4
+ export declare const REPORT_WATERFALL_COLORS: Record<WaterfallStepKind, string>;
@@ -10,7 +10,8 @@ import { FsMessage, FsMessageModule } from '@firestitch/message';
10
10
  import { FsProcess } from '@firestitch/process';
11
11
  import { FsPrompt } from '@firestitch/prompt';
12
12
  import { FsSkeletonModule } from '@firestitch/skeleton';
13
- import { filter, map, switchMap, take, tap } from 'rxjs/operators';
13
+ import { EMPTY } from 'rxjs';
14
+ import { catchError, filter, map, switchMap, take, tap } from 'rxjs/operators';
14
15
  import { ReportData } from '../../../../data/report.data';
15
16
  import { EntityFunctionsComponent } from '../../../entity-functions/entity-functions.component';
16
17
  import * as i0 from "@angular/core";
@@ -57,6 +58,9 @@ export class SemanticDatabaseComponent {
57
58
  static NAME_SUFFIX = 'Model';
58
59
  // null until loaded — gates the tab behind the skeleton.
59
60
  status = signal(null);
61
+ // The status request failed. Settles the skeleton and shows why; the Build
62
+ // action never depends on the status, so a build can still be started.
63
+ statusError = signal(false);
60
64
  // Free-text filter over the unit list — at a few hundred rows the accordion
61
65
  // is only usable if you can narrow it.
62
66
  filter = signal('');
@@ -64,6 +68,9 @@ export class SemanticDatabaseComponent {
64
68
  building = signal(false);
65
69
  buildActive = computed(() => this.building()
66
70
  || SemanticDatabaseComponent.ACTIVE_STATES.includes(this.status()?.build?.state));
71
+ // A semantic database has been published before, so a build replaces it.
72
+ // False while the status is unloaded or failed to load.
73
+ rebuild = computed(() => !!this.status()?.detail?.generatedAt);
67
74
  buildStateLabel = computed(() => SemanticDatabaseComponent.STATE_LABELS[this.status()?.build?.state] ?? '');
68
75
  // Whether the published semantic database came from a build that finished.
69
76
  //
@@ -167,7 +174,7 @@ export class SemanticDatabaseComponent {
167
174
  // Confirm before kicking off a build — a rebuild replaces the current
168
175
  // semantic database, so it should never fire on a stray click.
169
176
  build() {
170
- const rebuild = !!this.status()?.detail?.generatedAt;
177
+ const rebuild = this.rebuild();
171
178
  this._prompt.confirm({
172
179
  title: rebuild ? 'Rebuild semantic database' : 'Build semantic database',
173
180
  template: rebuild
@@ -233,12 +240,8 @@ export class SemanticDatabaseComponent {
233
240
  this._refreshStatus();
234
241
  return;
235
242
  }
236
- this._reportData.semanticBuildStatus()
237
- .pipe(takeUntilDestroyed(this._destroyRef))
238
- .subscribe((status) => {
239
- this.status.set(status);
240
- this._announceOutcome(status);
241
- });
243
+ this._loadStatus()
244
+ .subscribe((status) => this._announceOutcome(status));
242
245
  }
243
246
  /**
244
247
  * The real reason a broken build stream broke, from what the server actually
@@ -337,12 +340,23 @@ export class SemanticDatabaseComponent {
337
340
  : shortName;
338
341
  }
339
342
  _refreshStatus() {
340
- this._reportData.semanticBuildStatus()
341
- .pipe(takeUntilDestroyed(this._destroyRef))
342
- .subscribe((status) => this.status.set(status));
343
+ this._loadStatus()
344
+ .subscribe();
345
+ }
346
+ // Fetch the status into the tab. A failure flags statusError and completes
347
+ // quietly, so the tab settles and callers never see the error.
348
+ _loadStatus() {
349
+ return this._reportData.semanticBuildStatus()
350
+ .pipe(tap((status) => {
351
+ this.statusError.set(false);
352
+ this.status.set(status);
353
+ }), catchError(() => {
354
+ this.statusError.set(true);
355
+ return EMPTY;
356
+ }), takeUntilDestroyed(this._destroyRef));
343
357
  }
344
358
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: SemanticDatabaseComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
345
- 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\n <!-- Everything above is true about what was published, and on its own it\n reads as a finished build: the structural half publishes BEFORE the\n AI function pass, so a run that died in that pass still stamps a\n date and still fills in the whole coverage line. This is the only\n line that says the build never got to the end. -->\n @if (buildStatus.detail.generatedAt && !buildComplete()) {\n <fs-message-warning>\n The last build did not finish, so this semantic database is incomplete \u2014\n {{ incompleteEntityCount() }} of {{ buildStatus.detail.entityCount }}\n entities have no code-function knowledge. The report AI answers from what\n is here and cannot see the rest. Rebuild to complete it.\n </fs-message-warning>\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 });
359
+ 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 <!-- A failed status load settles the skeleton too, so the tab says what\n happened instead of loading forever. -->\n @if (statusError()) {\n <fs-message-warning>\n The build status could not be loaded, so the last build and its coverage\n can't be shown. You can still run a build.\n </fs-message-warning>\n }\n\n <div *fsSkeleton=\"status() || statusError()\">\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\n <!-- Everything above is true about what was published, and on its own it\n reads as a finished build: the structural half publishes BEFORE the\n AI function pass, so a run that died in that pass still stamps a\n date and still fills in the whole coverage line. This is the only\n line that says the build never got to the end. -->\n @if (buildStatus.detail.generatedAt && !buildComplete()) {\n <fs-message-warning>\n The last build did not finish, so this semantic database is incomplete \u2014\n {{ incompleteEntityCount() }} of {{ buildStatus.detail.entityCount }}\n entities have no code-function knowledge. The report AI answers from what\n is here and cannot see the rest. Rebuild to complete it.\n </fs-message-warning>\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 });
346
360
  }
347
361
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: SemanticDatabaseComponent, decorators: [{
348
362
  type: Component,
@@ -353,6 +367,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
353
367
  FsDateModule,
354
368
  FsMessageModule,
355
369
  FsSkeletonModule,
356
- ], 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\n <!-- Everything above is true about what was published, and on its own it\n reads as a finished build: the structural half publishes BEFORE the\n AI function pass, so a run that died in that pass still stamps a\n date and still fills in the whole coverage line. This is the only\n line that says the build never got to the end. -->\n @if (buildStatus.detail.generatedAt && !buildComplete()) {\n <fs-message-warning>\n The last build did not finish, so this semantic database is incomplete \u2014\n {{ incompleteEntityCount() }} of {{ buildStatus.detail.entityCount }}\n entities have no code-function knowledge. The report AI answers from what\n is here and cannot see the rest. Rebuild to complete it.\n </fs-message-warning>\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"] }]
370
+ ], 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 <!-- A failed status load settles the skeleton too, so the tab says what\n happened instead of loading forever. -->\n @if (statusError()) {\n <fs-message-warning>\n The build status could not be loaded, so the last build and its coverage\n can't be shown. You can still run a build.\n </fs-message-warning>\n }\n\n <div *fsSkeleton=\"status() || statusError()\">\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\n <!-- Everything above is true about what was published, and on its own it\n reads as a finished build: the structural half publishes BEFORE the\n AI function pass, so a run that died in that pass still stamps a\n date and still fills in the whole coverage line. This is the only\n line that says the build never got to the end. -->\n @if (buildStatus.detail.generatedAt && !buildComplete()) {\n <fs-message-warning>\n The last build did not finish, so this semantic database is incomplete \u2014\n {{ incompleteEntityCount() }} of {{ buildStatus.detail.entityCount }}\n entities have no code-function knowledge. The report AI answers from what\n is here and cannot see the rest. Rebuild to complete it.\n </fs-message-warning>\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"] }]
357
371
  }], ctorParameters: () => [] });
358
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VtYW50aWMtZGF0YWJhc2UuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vc3JjL2FwcC9yZXBvcnRzL2RpYWxvZ3MvZ2xvYmFsLXNldHRpbmdzL2NvbXBvbmVudHMvc2VtYW50aWMtZGF0YWJhc2Uvc2VtYW50aWMtZGF0YWJhc2UuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vc3JjL2FwcC9yZXBvcnRzL2RpYWxvZ3MvZ2xvYmFsLXNldHRpbmdzL2NvbXBvbmVudHMvc2VtYW50aWMtZGF0YWJhc2Uvc2VtYW50aWMtZGF0YWJhc2UuY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLHVCQUF1QixFQUFFLFNBQVMsRUFBRSxVQUFVLEVBQUUsUUFBUSxFQUFFLE1BQU0sRUFBRSxNQUFNLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDekcsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sNEJBQTRCLENBQUM7QUFFaEUsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLDBCQUEwQixDQUFDO0FBQ3JELE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLDZCQUE2QixDQUFDO0FBQ2pFLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLDJCQUEyQixDQUFDO0FBRTdELE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUNsRCxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sa0JBQWtCLENBQUM7QUFDaEQsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBQ2hELE9BQU8sRUFBRSxTQUFTLEVBQUUsZUFBZSxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDakUsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBQ2hELE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUM5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SSxrQkFBa0IscTBCQUNsQixnQkFBZ0IsNFRBQ2hCLFlBQVkscVhBQ1osWUFBWSw0SUFDWixlQUFlLHlIQUNmLGdCQUFnQjs7NEZBR1AseUJBQXlCO2tCQWZyQyxTQUFTOytCQUNFLGdEQUFnRCxtQkFHekMsdUJBQXVCLENBQUMsTUFBTSxjQUNuQyxJQUFJLFdBQ1A7d0JBQ1Asa0JBQWtCO3dCQUNsQixnQkFBZ0I7d0JBQ2hCLFlBQVk7d0JBQ1osWUFBWTt3QkFDWixlQUFlO3dCQUNmLGdCQUFnQjtxQkFDakIiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneSwgQ29tcG9uZW50LCBEZXN0cm95UmVmLCBjb21wdXRlZCwgaW5qZWN0LCBzaWduYWwgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IHRha2VVbnRpbERlc3Ryb3llZCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUvcnhqcy1pbnRlcm9wJztcblxuaW1wb3J0IHsgTWF0RGlhbG9nIH0gZnJvbSAnQGFuZ3VsYXIvbWF0ZXJpYWwvZGlhbG9nJztcbmltcG9ydCB7IE1hdEV4cGFuc2lvbk1vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL21hdGVyaWFsL2V4cGFuc2lvbic7XG5pbXBvcnQgeyBNYXRUb29sdGlwTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvbWF0ZXJpYWwvdG9vbHRpcCc7XG5cbmltcG9ydCB7IFN0cmVhbUV2ZW50VHlwZSB9IGZyb20gJ0BmaXJlc3RpdGNoL2FwaSc7XG5pbXBvcnQgeyBGc0NoaXBNb2R1bGUgfSBmcm9tICdAZmlyZXN0aXRjaC9jaGlwJztcbmltcG9ydCB7IEZzRGF0ZU1vZHVsZSB9IGZyb20gJ0BmaXJlc3RpdGNoL2RhdGUnO1xuaW1wb3J0IHsgRnNNZXNzYWdlLCBGc01lc3NhZ2VNb2R1bGUgfSBmcm9tICdAZmlyZXN0aXRjaC9tZXNzYWdlJztcbmltcG9ydCB7IEZzUHJvY2VzcyB9IGZyb20gJ0BmaXJlc3RpdGNoL3Byb2Nlc3MnO1xuaW1wb3J0IHsgRnNQcm9tcHQgfSBmcm9tICdAZmlyZXN0aXRjaC9wcm9tcHQnO1xuaW1wb3J0IHsgRnNTa2VsZXRvbk1vZHVsZSB9IGZyb20gJ0BmaXJlc3RpdGNoL3NrZWxldG9uJztcblxuaW1wb3J0IHsgZmlsdGVyLCBtYXAsIHN3aXRjaE1hcCwgdGFrZSwgdGFwIH0gZnJvbSAncnhqcy9vcGVyYXRvcnMnO1xuXG5pbXBvcnQgeyBSZXBvcnREYXRhIH0gZnJvbSAnLi4vLi4vLi4vLi4vZGF0YS9yZXBvcnQuZGF0YSc7XG5pbXBvcnQge1xuICBTZW1hbnRpY0J1aWxkQ2xhc3MsXG4gIFNlbWFudGljQnVpbGRFbnRpdHksXG4gIFNlbWFudGljQnVpbGRTdGF0dXMsXG4gIFNlbWFudGljQnVpbGRUYWJsZSxcbiAgU2VtYW50aWNGdW5jdGlvblNvdXJjZSxcbn0gZnJvbSAnLi4vLi4vLi4vLi4vaW50ZXJmYWNlcy9yZXBvcnQuaW50ZXJmYWNlJztcbmltcG9ydCB7IEVudGl0eUZ1bmN0aW9uc0NvbXBvbmVudCB9IGZyb20gJy4uLy4uLy4uL2VudGl0eS1mdW5jdGlvbnMvZW50aXR5LWZ1bmN0aW9ucy5jb21wb25lbnQnO1xuXG5cbi8vIE9uZSByb3cgb2YgdGhlIHNjb3JlYm9hcmQuIFRoZSBidWlsZCBjYWNoZXMgdHdvIGtpbmRzIG9mIHVuaXQgYW5kIHRoZSByZXBvcnRcbi8vIEFJIHJlYWRzIGNvZGUgZnJvbSBib3RoLCBzbyB0aGV5IGJlbG9uZyBpbiBPTkUgbGlzdDogYW4gZW50aXR5IChhIHRhYmxlIHBsdXNcbi8vIGl0cyBtb2RlbCBhbmQgaGFuZGxlcikgYW5kIGEgc3RhbmRhbG9uZSBjb2RlIGNsYXNzIChkb21haW4gbG9naWMgd2l0aCBub1xuLy8gdGFibGUg4oCUIGEgc3VtbWFyeSBtb2RlbCwgYSBjYWxjdWxhdGlvbiBzZXJ2aWNlKS4gQSBjbGFzcyByb3cgc2ltcGx5IGhhcyBub1xuLy8gdGFibGUsIGNvbHVtbnMgb3IgcmVsYXRpb25zaGlwcyB0byBzaG93LlxuaW50ZXJmYWNlIFNlbWFudGljVW5pdFZpZXcge1xuICBrZXk6IHN0cmluZztcbiAgbmFtZTogc3RyaW5nO1xuICBoYXNUYWJsZTogYm9vbGVhbjtcbiAgZW50aXR5OiBTZW1hbnRpY0J1aWxkRW50aXR5IHwgbnVsbDtcbiAgbW9kZWw6IHN0cmluZyB8IG51bGw7XG4gIGZ1bmN0aW9uQ291bnQ6IG51bWJlcjtcbn1cblxuXG4vLyBUaGUgU2VtYW50aWMgRGF0YWJhc2UgdGFiOiB0aGUgc2NvcmVib2FyZCBvZiBldmVyeXRoaW5nIHRoZSByZXBvcnQgQUkgd2FzXG4vLyBidWlsdCBmcm9tLiBTaG93cyB0aGUgbGFzdCBidWlsZCdzIHN0YXR1cywgcnVucyAob3Igc3RvcHMpIGEgYnVpbGQg4oCUIHN0cmVhbWVkXG4vLyBpbnRvIHRoZSBGc1Byb2Nlc3MgZG9jayBzbyBpdCBzdXJ2aXZlcyB0aGUgZGlhbG9nIGNsb3Npbmcg4oCUIGFuZCBkcmlsbHMgaW50b1xuLy8gZXZlcnkgdW5pdCB0byByZXZlYWwgaXRzIHNoYXBlLCBpbmxpbmVkIGVudW0gdmFsdWVzLCBjb21wdXRlZCBmaWVsZHMgYW5kIGl0c1xuLy8gY2FjaGVkIGZ1bmN0aW9uIGNvdW50cywgd2hvc2UgbGlua3Mgb3BlbiB0aGUgZnVuY3Rpb25zIGRpYWxvZyAodGhlIGZ1bGxcbi8vIGZ1bmN0aW9uIHNldCBpcyBmYXIgdG9vIGJpZyB0byBzaGlwIHdpdGggdGhlIHNjb3JlYm9hcmQpLlxuLy9cbi8vIEl0IGFsc28gcmVwb3J0cyB0aGUgb3RoZXIgaGFsZiBvZiB0aGUgcGljdHVyZTogdGhlIHRhYmxlcyB0aGUgQUkgQ0FOTk9UIHNlZSDigJRcbi8vIGV4Y2x1ZGVkIG9uZXMgKG5vIG1vZGVsKSBhbmQganVuY3Rpb25zIHRoYXQgYnJpZGdlZCBub3RoaW5nLiBUaG9zZSBhcmVcbi8vIGludmlzaWJsZSBieSBvbWlzc2lvbiBvdGhlcndpc2U6IG5vdGhpbmcgZXJyb3JzLCB0aGUgY2FwYWJpbGl0eSBqdXN0IGlzbid0XG4vLyB0aGVyZSwgYW5kIHRoZSBmaXJzdCBhbnlvbmUgbGVhcm5zIGlzIGEgd3JvbmcgYW5zd2VyIG9yIGEgcmVmdXNhbC5cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ2ZzLWFpLXJlcG9ydC1nbG9iYWwtc2V0dGluZ3Mtc2VtYW50aWMtZGF0YWJhc2UnLFxuICB0ZW1wbGF0ZVVybDogJy4vc2VtYW50aWMtZGF0YWJhc2UuY29tcG9uZW50Lmh0bWwnLFxuICBzdHlsZVVybHM6IFsnLi9zZW1hbnRpYy1kYXRhYmFzZS5jb21wb25lbnQuc2NzcyddLFxuICBjaGFuZ2VEZXRlY3Rpb246IENoYW5nZURldGVjdGlvblN0cmF0ZWd5Lk9uUHVzaCxcbiAgc3RhbmRhbG9uZTogdHJ1ZSxcbiAgaW1wb3J0czogW1xuICAgIE1hdEV4cGFuc2lvbk1vZHVsZSxcbiAgICBNYXRUb29sdGlwTW9kdWxlLFxuICAgIEZzQ2hpcE1vZHVsZSxcbiAgICBGc0RhdGVNb2R1bGUsXG4gICAgRnNNZXNzYWdlTW9kdWxlLFxuICAgIEZzU2tlbGV0b25Nb2R1bGUsXG4gIF0sXG59KVxuZXhwb3J0IGNsYXNzIFNlbWFudGljRGF0YWJhc2VDb21wb25lbnQge1xuXG4gIC8vIFRoZSBidWlsZC1pbi1mbGlnaHQgc3RhdGVzIG9mIHRoZSBmZl9wcm9jZXNzZXMgcm93IChxdWV1ZWQvcnVubmluZy9zdG9wcGluZykuXG4gIHByaXZhdGUgc3RhdGljIHJlYWRvbmx5IEFDVElWRV9TVEFURVMgPSBbJ1EnLCAnUicsICdYJ107XG5cbiAgcHJpdmF0ZSBzdGF0aWMgcmVhZG9ubHkgU1RBVEVfTEFCRUxTOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+ID0ge1xuICAgIFE6ICdRdWV1ZWQnLFxuICAgIFI6ICdSdW5uaW5nJyxcbiAgICBYOiAnU3RvcHBpbmcnLFxuICAgIEM6ICdDb21wbGV0ZWQnLFxuICAgIEs6ICdTdG9wcGVkJyxcbiAgICBGOiAnRmFpbGVkJyxcbiAgfTtcblxuICAvLyBUaGUgc3RyZWFtZWQgZnJhbWVzIHRoYXQgY2FycnkgYSBsaW5lIGZvciB0aGUgZmVlZDogcHJvZ3Jlc3MsIGFuZCB0aGUgZmluYWxcbiAgLy8gZnJhbWUgdGhlIGJhY2tlbmQgc2VuZHMgd2hlbiBhIHJ1biBlbmRzIGJhZGx5LiBXaXRob3V0IHRoZSBlcnJvciBraW5kIHRoZVxuICAvLyBmZWVkIHN0b3BzIG9uIHRoZSBsYXN0IHByb2dyZXNzIGxpbmUgYW5kIG5ldmVyIHNheXMgd2hhdCB3ZW50IHdyb25nLlxuICBwcml2YXRlIHN0YXRpYyByZWFkb25seSBMT0dfS0lORFMgPSBbJ2xvZycsICdlcnJvciddO1xuXG4gIC8vIEEgcm93IHRoYXQgaXMgc3RpbGwgb3dlZCBjb250ZW50IHNheXMgc287IGEgYnVpbHQgb25lIHNheXMgbm90aGluZy4gT24gYVxuICAvLyBmaW5pc2hlZCBidWlsZCBldmVyeSBzdGFnZSBpcyBkb25lIG9uIGV2ZXJ5IHJvdywgc28gY2hpcHBpbmcgdGhlbSBhbGwgd2FzXG4gIC8vIG5vaXNlIHRoYXQgYnVyaWVkIHRoZSBvbmUgcm93IHRoYXQgbWF0dGVyZWQuXG4gIHByaXZhdGUgc3RhdGljIHJlYWRvbmx5IFBFTkRJTkdfQ09MT1IgPSAnI2IyNjUwMCc7XG5cbiAgLy8gQ2xhc3MtbmFtZSBzdWZmaXggc3RyaXBwZWQgZm9yIGRpc3BsYXk6IGBCdWRnZXRTdW1tYXJ5TW9kZWxgIHJlYWRzIGFzXG4gIC8vIGBCdWRnZXRTdW1tYXJ5YC4gT25seSBgTW9kZWxgIOKAlCBzdHJpcHBpbmcgYEhhbmRsZXJgIHRvbyB3b3VsZCBjb2xsaWRlXG4gIC8vIGBXb3JrT3JkZXJPbmVUaW1lSGFuZGxlcmAgd2l0aCBgV29ya09yZGVyT25lVGltZU1vZGVsYCwgd2hpY2ggYXJlIHR3b1xuICAvLyBzZXBhcmF0ZSB1bml0cy5cbiAgcHJpdmF0ZSBzdGF0aWMgcmVhZG9ubHkgTkFNRV9TVUZGSVggPSAnTW9kZWwnO1xuXG4gIC8vIG51bGwgdW50aWwgbG9hZGVkIOKAlCBnYXRlcyB0aGUgdGFiIGJlaGluZCB0aGUgc2tlbGV0b24uXG4gIHB1YmxpYyByZWFkb25seSBzdGF0dXMgPSBzaWduYWw8U2VtYW50aWNCdWlsZFN0YXR1cyB8IG51bGw+KG51bGwpO1xuXG4gIC8vIEZyZWUtdGV4dCBmaWx0ZXIgb3ZlciB0aGUgdW5pdCBsaXN0IOKAlCBhdCBhIGZldyBodW5kcmVkIHJvd3MgdGhlIGFjY29yZGlvblxuICAvLyBpcyBvbmx5IHVzYWJsZSBpZiB5b3UgY2FuIG5hcnJvdyBpdC5cbiAgcHVibGljIHJlYWRvbmx5IGZpbHRlciA9IHNpZ25hbDxzdHJpbmc+KCcnKTtcblxuICAvLyBUcnVlIHdoaWxlIGEgYnVpbGQgc3RhcnRlZCBmcm9tIHRoaXMgdGFiIGlzIHN0cmVhbWluZyBpbnRvIHRoZSBkb2NrLlxuICBwdWJsaWMgcmVhZG9ubHkgYnVpbGRpbmcgPSBzaWduYWwoZmFsc2UpO1xuXG4gIHB1YmxpYyByZWFkb25seSBidWlsZEFjdGl2ZSA9IGNvbXB1dGVkPGJvb2xlYW4+KCgpID0+XG4gICAgdGhpcy5idWlsZGluZygpXG4gICAgICB8fCBTZW1hbnRpY0RhdGFiYXNlQ29tcG9uZW50LkFDVElWRV9TVEFURVMuaW5jbHVkZXModGhpcy5zdGF0dXMoKT8uYnVpbGQ/LnN0YXRlKSxcbiAgKTtcblxuICBwdWJsaWMgcmVhZG9ubHkgYnVpbGRTdGF0ZUxhYmVsID0gY29tcHV0ZWQ8c3RyaW5nPigoKSA9PlxuICAgIFNlbWFudGljRGF0YWJhc2VDb21wb25lbnQuU1RBVEVfTEFCRUxTW3RoaXMuc3RhdHVzKCk/LmJ1aWxkPy5zdGF0ZV0gPz8gJycsXG4gICk7XG5cbiAgLy8gV2hldGhlciB0aGUgcHVibGlzaGVkIHNlbWFudGljIGRhdGFiYXNlIGNhbWUgZnJvbSBhIGJ1aWxkIHRoYXQgZmluaXNoZWQuXG4gIC8vXG4gIC8vIEEgZmFpbGVkIG9yIHN0b3BwZWQgYnVpbGQgc3RpbGwgbGVhdmVzIGEgZGF0ZWQsIGZ1bGx5IGNvdW50ZWQgYXJ0aWZhY3RcbiAgLy8gYmVoaW5kLCBiZWNhdXNlIHRoZSBzdHJ1Y3R1cmFsIGhhbGYgcHVibGlzaGVzIEJFRk9SRSB0aGUgQUkgZnVuY3Rpb24gcGFzc1xuICAvLyBhbmQgaXQgaXMgdGhlIEFJIHBhc3MgdGhhdCBmYWlscy4gU28gXCJMYXN0IGJ1aWx0XCIgYW5kIENvdmVyYWdlIGJvdGggZmlsbGVkXG4gIC8vIGluIGFuZCByZWFkIGFzIGEgY2xlYW4gc3VjY2VzcywgYW5kIHRoZSBvbmx5IGRpc3NlbnRpbmcgd29yZCBvbiB0aGUgd2hvbGVcbiAgLy8gcGFuZWwgd2FzIG9uZSBsaW5lIG9mIFwiTGFzdCBidWlsZCBydW5cIiB0ZXh0IChSRS1UMTMwMikuXG4gIC8vXG4gIC8vIFJlYWRzIGFzIGNvbXBsZXRlIHdoaWxlIHRoZSBzdGF0dXMgaXMgc3RpbGwgbG9hZGluZywgc28gdGhlIHdhcm5pbmcgY2Fubm90XG4gIC8vIGZsYXNoIG9uIG9wZW4gYmVmb3JlIHRoZXJlIGlzIGFueXRoaW5nIHRvIHdhcm4gYWJvdXQuXG4gIHB1YmxpYyByZWFkb25seSBidWlsZENvbXBsZXRlID0gY29tcHV0ZWQ8Ym9vbGVhbj4oKCkgPT4gdGhpcy5zdGF0dXMoKT8uZGV0YWlsPy5jb21wbGV0ZSAhPT0gZmFsc2UpO1xuXG4gIC8vIEVudGl0aWVzIHRoZSBidWlsZCBuZXZlciByZWFjaGVkIOKAlCB0aG9zZSBzdGlsbCBvd2VkIHRoZSBBSSBmdW5jdGlvbiBwYXNzLlxuICAvLyBUaGUgbnVtYmVyIHRoZSBpbmNvbXBsZXRlIHdhcm5pbmcgcXVvdGVzLCBhbmQgdGhlIHNhbWUgcm93cyB0aGUgc2NvcmVib2FyZFxuICAvLyBiZWxvdyBhbHJlYWR5IGNoaXBzIG9uZSBhdCBhIHRpbWUuXG4gIHB1YmxpYyByZWFkb25seSBpbmNvbXBsZXRlRW50aXR5Q291bnQgPSBjb21wdXRlZDxudW1iZXI+KCgpID0+XG4gICAgKHRoaXMuc3RhdHVzKCk/LmRldGFpbD8uZW50aXRpZXMgPz8gW10pXG4gICAgICAuZmlsdGVyKChlbnRpdHkpID0+IGVudGl0eS5zdGFnZXMuZnVuY3Rpb25zICE9PSAnZG9uZScpXG4gICAgICAubGVuZ3RoLFxuICApO1xuXG4gIC8vIEFuIGFydGlmYWN0IGJ1aWx0IGJlZm9yZSB0aGUgY2F0YWxvZyBleGlzdGVkIGNhcnJpZXMgbm8gdGFibGVzLiBFdmVyeXRoaW5nXG4gIC8vIGNhdGFsb2ctZHJpdmVuIHN0YXlzIGhpZGRlbiByYXRoZXIgdGhhbiBjbGFpbWluZyBcIjAgZXhjbHVkZWRcIiwgd2hpY2ggd291bGRcbiAgLy8gYmUgYSBsaWUg4oCUIGEgcmVidWlsZCBmaWxscyBpdCBpbi5cbiAgcHVibGljIHJlYWRvbmx5IGhhc0NhdGFsb2cgPSBjb21wdXRlZDxib29sZWFuPigoKSA9PiAhIXRoaXMuc3RhdHVzKCk/LmRldGFpbD8udGFibGVzPy5sZW5ndGgpO1xuXG4gIC8vIFRhYmxlcyB3aXRoIG5vIG1vZGVsOiB0aGUgcmVwb3J0IEFJIGNhbid0IHNlZSB0aGVtIGF0IGFsbC4gQWRkIGEgbW9kZWwgdG9cbiAgLy8gcHJvbW90ZSBvbmUgdG8gYW4gZW50aXR5LlxuICBwdWJsaWMgcmVhZG9ubHkgZXhjbHVkZWRUYWJsZXMgPSBjb21wdXRlZDxTZW1hbnRpY0J1aWxkVGFibGVbXT4oKCkgPT5cbiAgICB0aGlzLl90YWJsZXMoKS5maWx0ZXIoKHRhYmxlKSA9PiB0YWJsZS5jbGFzc2lmaWNhdGlvbiA9PT0gJ2V4Y2x1ZGVkJyksXG4gICk7XG5cbiAgLy8gTGluayB0YWJsZXMgdGhhdCBicmlkZ2VkIG5vdGhpbmcg4oCUIGEgY29tcG9zaXRlIHByaW1hcnkga2V5IG1hZGUgdGhlbSBhXG4gIC8vIGp1bmN0aW9uLCBidXQgdGhleSB3ZXJlIGZvbGRlZCBpbnRvIG5vIHJlbGF0aW9uc2hpcCwgc28gbmVpdGhlciB0aGV5IG5vclxuICAvLyB3aGF0IHRoZXkgbGluayBhcmUgcmVhY2hhYmxlLlxuICBwdWJsaWMgcmVhZG9ubHkgdW5saW5rZWRKdW5jdGlvbnMgPSBjb21wdXRlZDxTZW1hbnRpY0J1aWxkVGFibGVbXT4oKCkgPT5cbiAgICB0aGlzLl90YWJsZXMoKS5maWx0ZXIoKHRhYmxlKSA9PiB0YWJsZS5jbGFzc2lmaWNhdGlvbiA9PT0gJ2p1bmN0aW9uJyAmJiAhIXRhYmxlLnJlYXNvbiksXG4gICk7XG5cbiAgLy8gRXZlcnl0aGluZyB0aGUgYnVpbGQgY2FjaGVkLCBlbnRpdGllcyBhbmQgc3RhbmRhbG9uZSBjb2RlIGNsYXNzZXMgdG9nZXRoZXIsXG4gIC8vIGluIG9uZSBsaXN0IG9yZGVyZWQgYnkgdGhlIG5hbWUgYSByZWFkZXIgcmVjb2duaXplcy4gVHdvIGFycmF5cyBvbiB0aGUgd2lyZVxuICAvLyBiZWNhdXNlIHRoZXkgYXJlIGdlbnVpbmVseSBkaWZmZXJlbnQgc2hhcGVzOyBvbmUgbGlzdCBvbiBzY3JlZW4gYmVjYXVzZVxuICAvLyBcIndoYXQgZGlkIHRoZSBidWlsZCByZWFkP1wiIGlzIGEgc2luZ2xlIHF1ZXN0aW9uLlxuICBwdWJsaWMgcmVhZG9ubHkgdW5pdHMgPSBjb21wdXRlZDxTZW1hbnRpY1VuaXRWaWV3W10+KCgpID0+IHtcbiAgICBjb25zdCBkZXRhaWwgPSB0aGlzLnN0YXR1cygpPy5kZXRhaWw7XG4gICAgaWYgKCFkZXRhaWwpIHtcbiAgICAgIHJldHVybiBbXTtcbiAgICB9XG5cbiAgICBjb25zdCBlbnRpdGllcyA9IChkZXRhaWwuZW50aXRpZXMgPz8gW10pLm1hcCgoZW50aXR5KSA9PiAoe1xuICAgICAga2V5OiBlbnRpdHkua2V5LFxuICAgICAgbmFtZTogdGhpcy5fZGlzcGxheU5hbWUoZW50aXR5Lm1vZGVsLCBlbnRpdHkua2V5KSxcbiAgICAgIGhhc1RhYmxlOiB0cnVlLFxuICAgICAgZW50aXR5LFxuICAgICAgbW9kZWw6IGVudGl0eS5tb2RlbCxcbiAgICAgIGZ1bmN0aW9uQ291bnQ6IGVudGl0eS5mdW5jdGlvbkNvdW50LFxuICAgIH0pKTtcblxuICAgIGNvbnN0IGNsYXNzZXMgPSAoZGV0YWlsLmNsYXNzZXMgPz8gW10pLm1hcCgodW5pdDogU2VtYW50aWNCdWlsZENsYXNzKSA9PiAoe1xuICAgICAga2V5OiB1bml0LmtleSxcbiAgICAgIG5hbWU6IHRoaXMuX2Rpc3BsYXlOYW1lKHVuaXQubW9kZWwsIHVuaXQua2V5KSxcbiAgICAgIGhhc1RhYmxlOiBmYWxzZSxcbiAgICAgIGVudGl0eTogbnVsbCxcbiAgICAgIG1vZGVsOiB1bml0Lm1vZGVsLFxuICAgICAgZnVuY3Rpb25Db3VudDogdW5pdC5mdW5jdGlvbkNvdW50LFxuICAgIH0pKTtcblxuICAgIHJldHVybiBbLi4uZW50aXRpZXMsIC4uLmNsYXNzZXNdXG4gICAgICAuc29ydCgoYSwgYikgPT4gYS5uYW1lLmxvY2FsZUNvbXBhcmUoYi5uYW1lKSk7XG4gIH0pO1xuXG4gIC8vIFRoZSBmaWx0ZXIgbWF0Y2hlcyB0aGUgZGlzcGxheSBuYW1lLCB0aGUgY2xhc3MgYW5kIHRoZSBlbnRpdHkga2V5LCBzb1xuICAvLyBodW50aW5nIGJ5IGFueSBvZiB0aGUgdGhyZWUgd29ya3MuXG4gIHB1YmxpYyByZWFkb25seSBmaWx0ZXJlZFVuaXRzID0gY29tcHV0ZWQ8U2VtYW50aWNVbml0Vmlld1tdPigoKSA9PiB7XG4gICAgY29uc3QgZmlsdGVyID0gdGhpcy5maWx0ZXIoKS50cmltKCkudG9Mb3dlckNhc2UoKTtcbiAgICBpZiAoIWZpbHRlcikge1xuICAgICAgcmV0dXJuIHRoaXMudW5pdHMoKTtcbiAgICB9XG5cbiAgICByZXR1cm4gdGhpcy51bml0cygpLmZpbHRlcigodW5pdCkgPT5cbiAgICAgIGAke3VuaXQubmFtZX0gJHt1bml0Lm1vZGVsID8/ICcnfSAke3VuaXQua2V5fWAudG9Mb3dlckNhc2UoKS5pbmNsdWRlcyhmaWx0ZXIpKTtcbiAgfSk7XG5cbiAgLy8gVGhlIENvdmVyYWdlIGxpbmUuIEFzc2VtYmxlZCBoZXJlIGJlY2F1c2UgdGhlIGNhdGFsb2cgcGFydHMgZHJvcCBvdXRcbiAgLy8gZW50aXJlbHkgb24gYSBwcmUtY2F0YWxvZyBhcnRpZmFjdCwgd2hpY2ggcmVhZHMgYmFkbHkgYXMgdGVtcGxhdGUgYnJhbmNoZXMuXG4gIHB1YmxpYyByZWFkb25seSBjb3ZlcmFnZSA9IGNvbXB1dGVkPHN0cmluZz4oKCkgPT4ge1xuICAgIGNvbnN0IGRldGFpbCA9IHRoaXMuc3RhdHVzKCk/LmRldGFpbDtcbiAgICBpZiAoIWRldGFpbCkge1xuICAgICAgcmV0dXJuICcnO1xuICAgIH1cblxuICAgIGNvbnN0IHBhcnRzID0gW2Ake2RldGFpbC5lbnRpdHlDb3VudH0gZW50aXRpZXNgLCBgJHtkZXRhaWwuY2xhc3NDb3VudH0gY29kZSBjbGFzc2VzYF07XG5cbiAgICBpZiAodGhpcy5oYXNDYXRhbG9nKCkpIHtcbiAgICAgIHBhcnRzLnB1c2goZGV0YWlsLnVubGlua2VkSnVuY3Rpb25Db3VudFxuICAgICAgICA/IGAke2RldGFpbC5qdW5jdGlvbkNvdW50fSBqdW5jdGlvbnMgKCR7ZGV0YWlsLnVubGlua2VkSnVuY3Rpb25Db3VudH0gbm90IGxpbmtlZClgXG4gICAgICAgIDogYCR7ZGV0YWlsLmp1bmN0aW9uQ291bnR9IGp1bmN0aW9uc2ApO1xuICAgIH1cblxuICAgIHBhcnRzLnB1c2goYCR7ZGV0YWlsLmZ1bmN0aW9uQ291bnR9IGNvZGUgZnVuY3Rpb25zYCk7XG5cbiAgICBpZiAodGhpcy5oYXNDYXRhbG9nKCkpIHtcbiAgICAgIHBhcnRzLnB1c2goYCR7ZGV0YWlsLmV4Y2x1ZGVkQ291bnR9IHRhYmxlcyBleGNsdWRlZGApO1xuICAgIH1cblxuICAgIHJldHVybiBwYXJ0cy5qb2luKCcgwrcgJyk7XG4gIH0pO1xuXG4gIC8vIFRoZSB0YWJsZSBjYXRhbG9nLCBvciBbXSB3aGVuIHRoZSBzdGF0dXMgaGFzbid0IGxvYWRlZCBvciB0aGUgYXJ0aWZhY3RcbiAgLy8gcHJlZGF0ZXMgaXQuXG4gIHByaXZhdGUgcmVhZG9ubHkgX3RhYmxlcyA9IGNvbXB1dGVkPFNlbWFudGljQnVpbGRUYWJsZVtdPigoKSA9PiB0aGlzLnN0YXR1cygpPy5kZXRhaWw/LnRhYmxlcyA/PyBbXSk7XG5cbiAgLy8gR3VhcmRzIHRoZSBvdXRjb21lIG1lc3NhZ2UgdG8gZmlyZSBleGFjdGx5IG9uY2UgcGVyIHJ1biDigJQgd2hldGhlciB0aGUgc3RyZWFtXG4gIC8vIGNvbXBsZXRlcyAoYnVpbGQgZmluaXNoZWQsIHBvc3NpYmx5IGZhaWxlZCkgb3IgZXJyb3JzIG91dHJpZ2h0LlxuICBwcml2YXRlIF9idWlsZEZpbmFsaXplZCA9IGZhbHNlO1xuXG4gIHByaXZhdGUgcmVhZG9ubHkgX2RpYWxvZyA9IGluamVjdChNYXREaWFsb2cpO1xuICBwcml2YXRlIHJlYWRvbmx5IF9yZXBvcnREYXRhID0gaW5qZWN0KFJlcG9ydERhdGEpO1xuICBwcml2YXRlIHJlYWRvbmx5IF9wcm9jZXNzID0gaW5qZWN0KEZzUHJvY2Vzcyk7XG4gIHByaXZhdGUgcmVhZG9ubHkgX3Byb21wdCA9IGluamVjdChGc1Byb21wdCk7XG4gIHByaXZhdGUgcmVhZG9ubHkgX21lc3NhZ2UgPSBpbmplY3QoRnNNZXNzYWdlKTtcbiAgcHJpdmF0ZSByZWFkb25seSBfZGVzdHJveVJlZiA9IGluamVjdChEZXN0cm95UmVmKTtcblxuICBjb25zdHJ1Y3RvcigpIHtcbiAgICB0aGlzLl9pbml0KCk7XG4gIH1cblxuICAvLyBDb25maXJtIGJlZm9yZSBraWNraW5nIG9mZiBhIGJ1aWxkIOKAlCBhIHJlYnVpbGQgcmVwbGFjZXMgdGhlIGN1cnJlbnRcbiAgLy8gc2VtYW50aWMgZGF0YWJhc2UsIHNvIGl0IHNob3VsZCBuZXZlciBmaXJlIG9uIGEgc3RyYXkgY2xpY2suXG4gIHB1YmxpYyBidWlsZCgpOiB2b2lkIHtcbiAgICBjb25zdCByZWJ1aWxkID0gISF0aGlzLnN0YXR1cygpPy5kZXRhaWw/LmdlbmVyYXRlZEF0O1xuXG4gICAgdGhpcy5fcHJvbXB0LmNvbmZpcm0oe1xuICAgICAgdGl0bGU6IHJlYnVpbGQgPyAnUmVidWlsZCBzZW1hbnRpYyBkYXRhYmFzZScgOiAnQnVpbGQgc2VtYW50aWMgZGF0YWJhc2UnLFxuICAgICAgdGVtcGxhdGU6IHJlYnVpbGRcbiAgICAgICAgPyAnUmVidWlsZCB0aGUgc2VtYW50aWMgZGF0YWJhc2U/IEl0IHJ1bnMgaW4gdGhlIGJhY2tncm91bmQgYW5kIHJlcGxhY2VzIHRoZSBjdXJyZW50IG9uZSB3aGVuIGl0IGZpbmlzaGVzLidcbiAgICAgICAgOiAnQnVpbGQgdGhlIHNlbWFudGljIGRhdGFiYXNlPyBJdCBydW5zIGluIHRoZSBiYWNrZ3JvdW5kLicsXG4gICAgICBjb21taXRMYWJlbDogcmVidWlsZCA/ICdSZWJ1aWxkJyA6ICdCdWlsZCcsXG4gICAgfSlcbiAgICAgIC5waXBlKHRha2VVbnRpbERlc3Ryb3llZCh0aGlzLl9kZXN0cm95UmVmKSlcbiAgICAgIC5zdWJzY3JpYmUoKCkgPT4gdGhpcy5fcnVuQnVpbGQoKSk7XG4gIH1cblxuICBwdWJsaWMgc3RvcEJ1aWxkKCk6IHZvaWQge1xuICAgIHRoaXMuX3Byb21wdC5jb25maXJtKHtcbiAgICAgIHRpdGxlOiAnU3RvcCBidWlsZCcsXG4gICAgICB0ZW1wbGF0ZTogJ1N0b3AgdGhlIHJ1bm5pbmcgYnVpbGQ/IFRoZSBjdXJyZW50IHNlbWFudGljIGRhdGFiYXNlIHN0YXlzIGluIHBsYWNlIHVudGlsIGEgYnVpbGQgZmluaXNoZXMuJyxcbiAgICAgIGNvbW1pdExhYmVsOiAnU3RvcCcsXG4gICAgfSlcbiAgICAgIC5waXBlKFxuICAgICAgICBzd2l0Y2hNYXAoKCkgPT4gdGhpcy5fcmVwb3J0RGF0YS5zZW1hbnRpY0J1aWxkU3RvcCgpKSxcbiAgICAgICAgdGFrZVVudGlsRGVzdHJveWVkKHRoaXMuX2Rlc3Ryb3lSZWYpLFxuICAgICAgKVxuICAgICAgLnN1YnNjcmliZSgoKSA9PiB7XG4gICAgICAgIHRoaXMuYnVpbGRpbmcuc2V0KGZhbHNlKTtcbiAgICAgICAgdGhpcy5fbWVzc2FnZS5zdWNjZXNzKCdTdG9wcGluZyB0aGUgYnVpbGTigKYnKTtcbiAgICAgICAgdGhpcy5fcmVmcmVzaFN0YXR1cygpO1xuICAgICAgfSk7XG4gIH1cblxuICAvLyBSdW4gdGhlIHNlbWFudGljLWRhdGFiYXNlIGJ1aWxkLiBUaGUgbGl2ZSBmZWVkIHN0cmVhbXMgaW50byB0aGUgRnNQcm9jZXNzXG4gIC8vIGRvY2sgKGJvdHRvbS1yaWdodCksIHdob3NlIHN1YnNjcmlwdGlvbiBzdXJ2aXZlcyB0aGlzIGRpYWxvZyBjbG9zaW5nIOKAlCBzb1xuICAvLyBkaXNtaXNzaW5nIHRoZSBkaWFsb2cgbmV2ZXIgaW50ZXJydXB0cyBhIHJ1bm5pbmcgYnVpbGQuXG4gIHByaXZhdGUgX3J1bkJ1aWxkKCk6IHZvaWQge1xuICAgIHRoaXMuYnVpbGRpbmcuc2V0KHRydWUpO1xuICAgIHRoaXMuX2J1aWxkRmluYWxpemVkID0gZmFsc2U7XG5cbiAgICBjb25zdCB0YXJnZXQkID0gdGhpcy5fcmVwb3J0RGF0YS5zZW1hbnRpY0J1aWxkKClcbiAgICAgIC5waXBlKFxuICAgICAgICAvLyBBIGhhcmQgc3RyZWFtL3RyYW5zcG9ydCBmYWlsdXJlICh0aGUgYnVpbGQgY291bGRuJ3QgZXZlbiBzdGFydClcbiAgICAgICAgLy8gZmluYWxpemVzIGhlcmUg4oCUIGNvbXBsZXRlZCQgd29uJ3QgZmlyZSBpbiB0aGF0IGNhc2UuXG4gICAgICAgIHRhcCh7IGVycm9yOiAoZXJyb3IpID0+IHRoaXMuX2ZpbmFsaXplQnVpbGQoZXJyb3IpIH0pLFxuICAgICAgICBmaWx0ZXIoKGV2ZW50KSA9PlxuICAgICAgICAgIGV2ZW50Py50eXBlID09PSBTdHJlYW1FdmVudFR5cGUuRGF0YVxuICAgICAgICAgICYmIFNlbWFudGljRGF0YWJhc2VDb21wb25lbnQuTE9HX0tJTkRTLmluY2x1ZGVzKGV2ZW50LmRhdGE/LmtpbmQpXG4gICAgICAgICAgJiYgdHlwZW9mIGV2ZW50LmRhdGEubGluZSA9PT0gJ3N0cmluZycpLFxuICAgICAgICBtYXAoKGV2ZW50KSA9PiBldmVudC5kYXRhLmxpbmUgYXMgc3RyaW5nKSxcbiAgICAgICk7XG5cbiAgICB0aGlzLl9wcm9jZXNzXG4gICAgICAucnVuKCdTZW1hbnRpYyBkYXRhYmFzZSBidWlsZCcsIHRhcmdldCQpXG4gICAgICAuY29tcGxldGVkJFxuICAgICAgLnBpcGUoXG4gICAgICAgIHRha2UoMSksXG4gICAgICAgIHRha2VVbnRpbERlc3Ryb3llZCh0aGlzLl9kZXN0cm95UmVmKSxcbiAgICAgIClcbiAgICAgIC5zdWJzY3JpYmUoKCkgPT4gdGhpcy5fZmluYWxpemVCdWlsZChudWxsKSk7XG4gIH1cblxuICAvKipcbiAgICogV3JhcCB1cCBvbmUgYnVpbGQgcnVuIGV4YWN0bHkgb25jZS4gT24gYSBoYXJkIHN0cmVhbSBlcnJvciwgc3VyZmFjZSB0aGVcbiAgICogYWN0dWFsIHNlcnZlci1zaWRlIHJlYXNvbiBwdWxsZWQgb2ZmIHRoZSBicm9rZW4gc3RyZWFtIOKAlCB0aGUgZ2VuZXJpY1xuICAgKiBcImNvdWxkIG5vdCBydW5cIiBsaW5lIG9ubHkgd2hlbiB0aGUgZmFpbHVyZSBjYXJyaWVkIG5vIHNlcnZlciB0ZXh0IGF0IGFsbDtcbiAgICogb3RoZXJ3aXNlIHJlZnJlc2ggdGhlIHN0YXR1cyBhbmQgYW5ub3VuY2UgaG93IHRoZSBidWlsZCBhY3R1YWxseSBlbmRlZC4gQVxuICAgKiBmYWlsZWQgYnVpbGQgYWx3YXlzIG5hbWVzIGl0cyByZWFzb24gb24gdGhlIHJvdyAodGhlIGJhY2tlbmQgcmVjb3JkcyBvbmUgZm9yXG4gICAqIGV2ZXJ5IHdheSBhIHJ1biBjYW4gZGllLCBmYXRhbHMgaW5jbHVkZWQpLCBhbmQgdGhhdCByZWFzb24gbXVzdCBzdXJmYWNlXG4gICAqIGluc3RlYWQgb2YgdGhlIHJ1biBzaWxlbnRseSBkb2luZyBub3RoaW5nLlxuICAgKi9cbiAgcHJpdmF0ZSBfZmluYWxpemVCdWlsZChzdHJlYW1FcnJvcjogdW5rbm93bik6IHZvaWQge1xuICAgIGlmICh0aGlzLl9idWlsZEZpbmFsaXplZCkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICB0aGlzLl9idWlsZEZpbmFsaXplZCA9IHRydWU7XG5cbiAgICB0aGlzLmJ1aWxkaW5nLnNldChmYWxzZSk7XG5cbiAgICBpZiAoc3RyZWFtRXJyb3IpIHtcbiAgICAgIGNvbnN0IGRldGFpbCA9IHRoaXMuX3N0cmVhbUVycm9yRGV0YWlsKHN0cmVhbUVycm9yKTtcblxuICAgICAgdGhpcy5fbWVzc2FnZS5lcnJvcihkZXRhaWxcbiAgICAgICAgPyBgVGhlIHNlbWFudGljIGRhdGFiYXNlIGJ1aWxkIGZhaWxlZCDigJQgJHtkZXRhaWx9YFxuICAgICAgICA6ICdUaGUgc2VtYW50aWMgZGF0YWJhc2UgYnVpbGQgY291bGQgbm90IHJ1biDigJQgdGhlIGNvbm5lY3Rpb24gdG8gdGhlIHNlcnZlciB3YXMgbG9zdC4nKTtcbiAgICAgIHRoaXMuX3JlZnJlc2hTdGF0dXMoKTtcblxuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIHRoaXMuX3JlcG9ydERhdGEuc2VtYW50aWNCdWlsZFN0YXR1cygpXG4gICAgICAucGlwZSh0YWtlVW50aWxEZXN0cm95ZWQodGhpcy5fZGVzdHJveVJlZikpXG4gICAgICAuc3Vic2NyaWJlKChzdGF0dXM6IFNlbWFudGljQnVpbGRTdGF0dXMpID0+IHtcbiAgICAgICAgdGhpcy5zdGF0dXMuc2V0KHN0YXR1cyk7XG4gICAgICAgIHRoaXMuX2Fubm91bmNlT3V0Y29tZShzdGF0dXMpO1xuICAgICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogVGhlIHJlYWwgcmVhc29uIGEgYnJva2VuIGJ1aWxkIHN0cmVhbSBicm9rZSwgZnJvbSB3aGF0IHRoZSBzZXJ2ZXIgYWN0dWFsbHlcbiAgICogc2VudC4gQSBzdHJ1Y3R1cmVkIGVycm9yIGZyYW1lIGFycml2ZXMgYXMge21lc3NhZ2V9IG9uIHRoZSBlcnJvciBib2R5OyBhXG4gICAqIG1pZC1zdHJlYW0gY3Jhc2ggZHVtcHMgcmF3IHRleHQgaW50byB0aGUgc3RyZWFtICh0aGUgc3RyZWFtIGludGVyY2VwdG9yXG4gICAqIGhhbmRzIGl0IGJhY2sgYXMgc3RhdHVzVGV4dCksIHdoZXJlIHRoZSBmcmFtZXMgYXJlIEpTT04gbGluZXMgYW5kIHRoZVxuICAgKiBmaXJzdCBub24tSlNPTiBsaW5lcyBhcmUgdGhlIGVycm9yIGFuZCBpdHMgbG9jYXRpb24uICcnIHdoZW4gdGhlIGZhaWx1cmVcbiAgICogY2FycmllZCBubyBzZXJ2ZXIgdGV4dCBhdCBhbGwgKHRyYW5zcG9ydCBkb3duIC8gc2VydmVyIHVucmVhY2hhYmxlKS5cbiAgICovXG4gIHByaXZhdGUgX3N0cmVhbUVycm9yRGV0YWlsKHN0cmVhbUVycm9yOiB1bmtub3duKTogc3RyaW5nIHtcbiAgICBjb25zdCBlcnJvciA9IHN0cmVhbUVycm9yIGFzIHsgZXJyb3I/OiB7IG1lc3NhZ2U/OiBzdHJpbmcgfTsgc3RhdHVzVGV4dD86IHN0cmluZyB9O1xuXG4gICAgaWYgKGVycm9yPy5lcnJvcj8ubWVzc2FnZSkge1xuICAgICAgcmV0dXJuIGVycm9yLmVycm9yLm1lc3NhZ2U7XG4gICAgfVxuXG4gICAgY29uc3Qgc3RhdHVzVGV4dCA9IGVycm9yPy5zdGF0dXNUZXh0O1xuICAgIGlmICghc3RhdHVzVGV4dCB8fCBzdGF0dXNUZXh0ID09PSAnVW5rbm93biBFcnJvcicpIHtcbiAgICAgIHJldHVybiAnJztcbiAgICB9XG5cbiAgICBjb25zdCBsaW5lcyA9IHN0YXR1c1RleHQuc3BsaXQoJ1xcbicpXG4gICAgICAubWFwKChsaW5lKSA9PiBsaW5lLnRyaW0oKSlcbiAgICAgIC5maWx0ZXIoKGxpbmUpID0+IHtcbiAgICAgICAgaWYgKCFsaW5lKSB7XG4gICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG5cbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICBKU09OLnBhcnNlKGxpbmUpO1xuXG4gICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9IGNhdGNoIHtcbiAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgfVxuICAgICAgfSk7XG5cbiAgICByZXR1cm4gbGluZXMuc2xpY2UoMCwgMikuam9pbignIOKAlCAnKS5zdWJzdHJpbmcoMCwgMzAwKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBUZWxsIHRoZSBvcGVyYXRvciBob3cgdGhlIGJ1aWxkIGVuZGVkOiBhIGZhaWxlZC9zdG9wcGVkIGJ1aWxkIHN1cmZhY2VzIGl0c1xuICAgKiByZWFzb24gKHNvIGFuIEFJIGNvbm5lY3Rpb24gcHJvYmxlbSBpcyBuZXZlciBzaWxlbnQpLCBhIGNvbXBsZXRlZCBvbmVcbiAgICogY29uZmlybXMgc3VjY2Vzcy5cbiAgICovXG4gIHByaXZhdGUgX2Fubm91bmNlT3V0Y29tZShzdGF0dXM6IFNlbWFudGljQnVpbGRTdGF0dXMpOiB2b2lkIHtcbiAgICBjb25zdCBidWlsZCA9IHN0YXR1cz8uYnVpbGQ7XG4gICAgaWYgKGJ1aWxkPy5zdGF0ZSA9PT0gJ0YnIHx8IGJ1aWxkPy5zdGF0ZSA9PT0gJ0snKSB7XG4gICAgICB0aGlzLl9tZXNzYWdlLmVycm9yKGJ1aWxkLm1lc3NhZ2UgfHwgJ1RoZSBzZW1hbnRpYyBkYXRhYmFzZSBidWlsZCBkaWQgbm90IGZpbmlzaC4nKTtcbiAgICB9IGVsc2UgaWYgKGJ1aWxkPy5zdGF0ZSA9PT0gJ0MnKSB7XG4gICAgICB0aGlzLl9tZXNzYWdlLnN1Y2Nlc3MoJ1NlbWFudGljIGRhdGFiYXNlIGJ1aWxkIGNvbXBsZXRlLicpO1xuICAgIH1cbiAgfVxuXG4gIHB1YmxpYyBwZW5kaW5nQ29sb3IoKTogc3RyaW5nIHtcbiAgICByZXR1cm4gU2VtYW50aWNEYXRhYmFzZUNvbXBvbmVudC5QRU5ESU5HX0NPTE9SO1xuICB9XG5cbiAgLyoqXG4gICAqIFRoZSBidWlsZCBzdGFnZXMgdGhpcyByb3cgaXMgc3RpbGwgb3dlZCwgb3IgW10gd2hlbiBpdCBpcyBmdWxseSBidWlsdC4gQVxuICAgKiBzdG9wcGVkIG9yIGludGVycnVwdGVkIGJ1aWxkIGlzIHRoZSBvbmx5IHdheSB0byBnZXQgYSBub24tZW1wdHkgbGlzdC5cbiAgICovXG4gIHB1YmxpYyBwZW5kaW5nU3RhZ2VzKHVuaXQ6IFNlbWFudGljVW5pdFZpZXcpOiBzdHJpbmdbXSB7XG4gICAgY29uc3Qgc3RhZ2VzID0gdW5pdC5lbnRpdHk/LnN0YWdlcztcblxuICAgIHJldHVybiBzdGFnZXNcbiAgICAgID8gT2JqZWN0LmtleXMoc3RhZ2VzKS5maWx0ZXIoKHN0YWdlKSA9PiBzdGFnZXNbc3RhZ2VdICE9PSAnZG9uZScpXG4gICAgICA6IFtdO1xuICB9XG5cbiAgcHVibGljIHNldEZpbHRlcih2YWx1ZTogc3RyaW5nKTogdm9pZCB7XG4gICAgdGhpcy5maWx0ZXIuc2V0KHZhbHVlKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBPcGVuIHRoZSBjaGlsZCBkaWFsb2cgbGlzdGluZyBvbmUgZ3JvdXAgb2YgYSB1bml0J3MgY2FjaGVkIGZ1bmN0aW9ucyDigJQgYW5cbiAgICogZW50aXR5J3MgbW9kZWwgb3IgaGFuZGxlciBjbGFzcywgb3IgYSBzdGFuZGFsb25lIGNsYXNzJ3MgY29kZS4gVGhlIGRpYWxvZ1xuICAgKiBmZXRjaGVzIGZyZXNoIG9uIG9wZW4sIHNvIHRoZSB0YWIgbmV2ZXIgaG9sZHMgZnVuY3Rpb24gcGF5bG9hZHMuXG4gICAqL1xuICBwdWJsaWMgb3BlbkZ1bmN0aW9ucyh1bml0OiBTZW1hbnRpY1VuaXRWaWV3LCBzb3VyY2U6IFNlbWFudGljRnVuY3Rpb25Tb3VyY2UpOiB2b2lkIHtcbiAgICB0aGlzLl9kaWFsb2cub3BlbihFbnRpdHlGdW5jdGlvbnNDb21wb25lbnQsIHtcbiAgICAgIHdpZHRoOiAnNzAwcHgnLFxuICAgICAgbWF4V2lkdGg6ICc5NXZ3JyxcbiAgICAgIG1heEhlaWdodDogJzg1dmgnLFxuICAgICAgYXV0b0ZvY3VzOiBmYWxzZSxcbiAgICAgIGRhdGE6IHsgZW50aXR5S2V5OiB1bml0LmtleSwgc291cmNlIH0sXG4gICAgfSk7XG4gIH1cblxuICBwcml2YXRlIF9pbml0KCk6IHZvaWQge1xuICAgIHRoaXMuX3JlZnJlc2hTdGF0dXMoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBXaGF0IGEgcmVhZGVyIHJlY29nbml6ZXMgdGhlIHVuaXQgYnk6IGl0cyBjbGFzcydzIHNob3J0IG5hbWUsIG1pbnVzIHRoZVxuICAgKiBgTW9kZWxgIHN1ZmZpeCB0aGF0IGV2ZXJ5IG1vZGVsIGNhcnJpZXMgYW5kIG5vbmUgb2YgdGhlbSBhcmUgZGlzdGluZ3Vpc2hlZFxuICAgKiBieS4gRmFsbHMgYmFjayB0byB0aGUgY2FjaGUga2V5IGZvciBhIHVuaXQgd2hvc2UgY2xhc3MgY291bGQgbm90IGJlXG4gICAqIHJlc29sdmVkLCBzbyBhIHJvdyBuZXZlciByZW5kZXJzIG5hbWVsZXNzLlxuICAgKi9cbiAgcHJpdmF0ZSBfZGlzcGxheU5hbWUobW9kZWw6IHN0cmluZyB8IG51bGwsIGtleTogc3RyaW5nKTogc3RyaW5nIHtcbiAgICBpZiAoIW1vZGVsKSB7XG4gICAgICByZXR1cm4ga2V5O1xuICAgIH1cblxuICAgIGNvbnN0IHNob3J0TmFtZSA9IG1vZGVsLnNwbGl0KCdcXFxcJykucG9wKCk7XG5cbiAgICByZXR1cm4gc2hvcnROYW1lLmxlbmd0aCA+IFNlbWFudGljRGF0YWJhc2VDb21wb25lbnQuTkFNRV9TVUZGSVgubGVuZ3RoXG4gICAgICAmJiBzaG9ydE5hbWUuZW5kc1dpdGgoU2VtYW50aWNEYXRhYmFzZUNvbXBvbmVudC5OQU1FX1NVRkZJWClcbiAgICAgID8gc2hvcnROYW1lLnNsaWNlKDAsIC1TZW1hbnRpY0RhdGFiYXNlQ29tcG9uZW50Lk5BTUVfU1VGRklYLmxlbmd0aClcbiAgICAgIDogc2hvcnROYW1lO1xuICB9XG5cbiAgcHJpdmF0ZSBfcmVmcmVzaFN0YXR1cygpOiB2b2lkIHtcbiAgICB0aGlzLl9yZXBvcnREYXRhLnNlbWFudGljQnVpbGRTdGF0dXMoKVxuICAgICAgLnBpcGUodGFrZVVudGlsRGVzdHJveWVkKHRoaXMuX2Rlc3Ryb3lSZWYpKVxuICAgICAgLnN1YnNjcmliZSgoc3RhdHVzOiBTZW1hbnRpY0J1aWxkU3RhdHVzKSA9PiB0aGlzLnN0YXR1cy5zZXQoc3RhdHVzKSk7XG4gIH1cbn1cbiIsIjxkaXYgY2xhc3M9XCJmcy1jb2x1bW4gdGFiLWJvZHlcIj5cbiAgPHAgY2xhc3M9XCJoaW50XCI+XG4gICAgVGhlIHNlbWFudGljIGRhdGFiYXNlIGlzIHdoYXQgdGhlIHJlcG9ydCBBSSB1c2VzIHRvIHVuZGVyc3RhbmQgeW91ciBkYXRhIOKAlFxuICAgIHRhYmxlcywgcmVsYXRpb25zaGlwcyBhbmQgdGhlIGNhbGN1bGF0aW9ucyBpbiBjb2RlLiBSZWJ1aWxkIGl0IGFmdGVyXG4gICAgc2lnbmlmaWNhbnQgYXBwbGljYXRpb24gdXBkYXRlcy4gVGhlIGJ1aWxkIHJ1bnMgaW4gdGhlIGJhY2tncm91bmQ7IHByb2dyZXNzXG4gICAgYXBwZWFycyBpbiB0aGUgZG9jayBhdCB0aGUgYm90dG9tIHJpZ2h0IGFuZCB0aGlzIGRpYWxvZyBjYW4gYmUgY2xvc2VkIHdoaWxlXG4gICAgaXQgcnVucy5cbiAgPC9wPlxuXG4gIDxkaXYgKmZzU2tlbGV0b249XCJzdGF0dXMoKVwiPlxuICAgIEBpZiAoc3RhdHVzKCk7IGFzIGJ1aWxkU3RhdHVzKSB7XG4gICAgICA8ZGl2IGNsYXNzPVwiYnVpbGQtc3RhdHVzXCI+XG4gICAgICAgIEBpZiAoYnVpbGRTdGF0dXMuZGV0YWlsLmdlbmVyYXRlZEF0KSB7XG4gICAgICAgICAgPGRpdiBjbGFzcz1cInN0YXRcIj5cbiAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwibGFiZWxcIj5MYXN0IGJ1aWx0PC9zcGFuPlxuICAgICAgICAgICAgPGZzLWRhdGVcbiAgICAgICAgICAgICAgICBbZGF0ZV09XCJidWlsZFN0YXR1cy5kZXRhaWwuZ2VuZXJhdGVkQXRcIlxuICAgICAgICAgICAgICAgIGZvcm1hdD1cImRhdGUtdGltZVwiPlxuICAgICAgICAgICAgPC9mcy1kYXRlPlxuICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgIDxkaXYgY2xhc3M9XCJzdGF0XCI+XG4gICAgICAgICAgICA8c3BhbiBjbGFzcz1cImxhYmVsXCI+Q292ZXJhZ2U8L3NwYW4+XG4gICAgICAgICAgICA8c3Bhbj57eyBjb3ZlcmFnZSgpIH19PC9zcGFuPlxuICAgICAgICAgIDwvZGl2PlxuICAgICAgICB9IEBlbHNlIHtcbiAgICAgICAgICA8ZnMtbWVzc2FnZS13YXJuaW5nPlxuICAgICAgICAgICAgVGhlIHNlbWFudGljIGRhdGFiYXNlIGhhcyBub3QgYmVlbiBidWlsdCB5ZXQg4oCUIHRoZSByZXBvcnQgQUkgY2FuJ3RcbiAgICAgICAgICAgIGFuc3dlciBkYXRhIHF1ZXN0aW9ucyB1bnRpbCBpdCBpcy4gUnVuIHRoZSBmaXJzdCBidWlsZC5cbiAgICAgICAgICA8L2ZzLW1lc3NhZ2Utd2FybmluZz5cbiAgICAgICAgfVxuICAgICAgICBAaWYgKGJ1aWxkU3RhdHVzLmJ1aWxkKSB7XG4gICAgICAgICAgPGRpdiBjbGFzcz1cInN0YXRcIj5cbiAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwibGFiZWxcIj5MYXN0IGJ1aWxkIHJ1bjwvc3Bhbj5cbiAgICAgICAgICAgIDxzcGFuPlxuICAgICAgICAgICAgICB7eyBidWlsZFN0YXRlTGFiZWwoKSB9fVxuICAgICAgICAgICAgICBAaWYgKGJ1aWxkU3RhdHVzLmJ1aWxkLm1lc3NhZ2UpIHtcbiAgICAgICAgICAgICAgICDigJQge3sgYnVpbGRTdGF0dXMuYnVpbGQubWVzc2FnZSB9fVxuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICA8L3NwYW4+XG4gICAgICAgICAgPC9kaXY+XG4gICAgICAgIH1cblxuICAgICAgICA8IS0tIEV2ZXJ5dGhpbmcgYWJvdmUgaXMgdHJ1ZSBhYm91dCB3aGF0IHdhcyBwdWJsaXNoZWQsIGFuZCBvbiBpdHMgb3duIGl0XG4gICAgICAgICAgICAgcmVhZHMgYXMgYSBmaW5pc2hlZCBidWlsZDogdGhlIHN0cnVjdHVyYWwgaGFsZiBwdWJsaXNoZXMgQkVGT1JFIHRoZVxuICAgICAgICAgICAgIEFJIGZ1bmN0aW9uIHBhc3MsIHNvIGEgcnVuIHRoYXQgZGllZCBpbiB0aGF0IHBhc3Mgc3RpbGwgc3RhbXBzIGFcbiAgICAgICAgICAgICBkYXRlIGFuZCBzdGlsbCBmaWxscyBpbiB0aGUgd2hvbGUgY292ZXJhZ2UgbGluZS4gVGhpcyBpcyB0aGUgb25seVxuICAgICAgICAgICAgIGxpbmUgdGhhdCBzYXlzIHRoZSBidWlsZCBuZXZlciBnb3QgdG8gdGhlIGVuZC4gLS0+XG4gICAgICAgIEBpZiAoYnVpbGRTdGF0dXMuZGV0YWlsLmdlbmVyYXRlZEF0ICYmICFidWlsZENvbXBsZXRlKCkpIHtcbiAgICAgICAgICA8ZnMtbWVzc2FnZS13YXJuaW5nPlxuICAgICAgICAgICAgVGhlIGxhc3QgYnVpbGQgZGlkIG5vdCBmaW5pc2gsIHNvIHRoaXMgc2VtYW50aWMgZGF0YWJhc2UgaXMgaW5jb21wbGV0ZSDigJRcbiAgICAgICAgICAgIHt7IGluY29tcGxldGVFbnRpdHlDb3VudCgpIH19IG9mIHt7IGJ1aWxkU3RhdHVzLmRldGFpbC5lbnRpdHlDb3VudCB9fVxuICAgICAgICAgICAgZW50aXRpZXMgaGF2ZSBubyBjb2RlLWZ1bmN0aW9uIGtub3dsZWRnZS4gVGhlIHJlcG9ydCBBSSBhbnN3ZXJzIGZyb20gd2hhdFxuICAgICAgICAgICAgaXMgaGVyZSBhbmQgY2Fubm90IHNlZSB0aGUgcmVzdC4gUmVidWlsZCB0byBjb21wbGV0ZSBpdC5cbiAgICAgICAgICA8L2ZzLW1lc3NhZ2Utd2FybmluZz5cbiAgICAgICAgfVxuICAgICAgPC9kaXY+XG5cbiAgICAgIDwhLS0gRXZlcnl0aGluZyB0aGUgYnVpbGQgcmVhZCwgaW4gb25lIGxpc3Q6IGVudGl0aWVzIChhIHRhYmxlICsgYSBtb2RlbCArXG4gICAgICAgICAgIGEgaGFuZGxlcikgYW5kIHN0YW5kYWxvbmUgY29kZSBjbGFzc2VzIChkb21haW4gbG9naWMgd2l0aCBubyB0YWJsZSkuXG4gICAgICAgICAgIFRoZSBBSSByZWFkcyBjb2RlIGZyb20gYm90aCwgc28gc3BsaXR0aW5nIHRoZW0gaW50byB0d28gc2VjdGlvbnNcbiAgICAgICAgICAgd291bGQgaGlkZSBoYWxmIG9mIHdoYXQgd2FzIGJ1aWx0LiBFYWNoIHJvdyBkcmlsbHMgaW50byBpdHMgc2hhcGUsXG4gICAgICAgICAgIGVudW0gdmFsdWVzLCBjb21wdXRlZCBmaWVsZHMgYW5kIGNhY2hlZCBmdW5jdGlvbiBjb3VudHMg4oCUIHRoZSBjb3VudHNcbiAgICAgICAgICAgbGluayBpbnRvIHRoZSBmdW5jdGlvbnMgZGlhbG9nLiAtLT5cbiAgICAgIEBpZiAodW5pdHMoKS5sZW5ndGgpIHtcbiAgICAgICAgPGgyPkluY2x1ZGVkICh7eyB1bml0cygpLmxlbmd0aCB9fSk8L2gyPlxuICAgICAgICA8ZGl2IGNsYXNzPVwic3ViaGVhZGluZ1wiPlxuICAgICAgICAgIEV2ZXJ5dGhpbmcgdGhlIHJlcG9ydCBBSSB3YXMgYnVpbHQgZnJvbS4gRW50aXRpZXMgY2FuIGJlIHF1ZXJpZWQ7XG4gICAgICAgICAgY29kZSBjbGFzc2VzIGFyZSBsb2dpYyBpdCByZWFkcyBhbmQgdHJhbnNsYXRlcyBpbnRvIFNRTC5cbiAgICAgICAgPC9kaXY+XG5cbiAgICAgICAgPGlucHV0XG4gICAgICAgICAgICBjbGFzcz1cInVuaXQtZmlsdGVyXCJcbiAgICAgICAgICAgIHR5cGU9XCJzZWFyY2hcIlxuICAgICAgICAgICAgcGxhY2Vob2xkZXI9XCJGaWx0ZXIgYnkgbmFtZSwgY2xhc3Mgb3Iga2V54oCmXCJcbiAgICAgICAgICAgIFt2YWx1ZV09XCJmaWx0ZXIoKVwiXG4gICAgICAgICAgICAoaW5wdXQpPVwic2V0RmlsdGVyKCRhbnkoJGV2ZW50LnRhcmdldCkudmFsdWUpXCI+XG5cbiAgICAgICAgPG1hdC1hY2NvcmRpb24gY2xhc3M9XCJlbnRpdGllc1wiPlxuICAgICAgICAgIEBmb3IgKHVuaXQgb2YgZmlsdGVyZWRVbml0cygpOyB0cmFjayB1bml0LmtleSkge1xuICAgICAgICAgICAgPG1hdC1leHBhbnNpb24tcGFuZWw+XG4gICAgICAgICAgICAgIDxtYXQtZXhwYW5zaW9uLXBhbmVsLWhlYWRlcj5cbiAgICAgICAgICAgICAgICA8bWF0LXBhbmVsLXRpdGxlPnt7IHVuaXQubmFtZSB9fTwvbWF0LXBhbmVsLXRpdGxlPlxuICAgICAgICAgICAgICAgIDxtYXQtcGFuZWwtZGVzY3JpcHRpb24+XG4gICAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwic3RhZ2UtY2hpcHNcIj5cbiAgICAgICAgICAgICAgICAgICAgQGlmICghdW5pdC5oYXNUYWJsZSkge1xuICAgICAgICAgICAgICAgICAgICAgIDxmcy1jaGlwIHNpemU9XCJ0aW55XCIgbWF0VG9vbHRpcD1cIkRvbWFpbiBsb2dpYyB3aXRoIG5vIHRhYmxlIOKAlCByZWFkLCBuZXZlciBxdWVyaWVkXCI+XG4gICAgICAgICAgICAgICAgICAgICAgICBjb2RlXG4gICAgICAgICAgICAgICAgICAgICAgPC9mcy1jaGlwPlxuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIDwhLS0gU2lsZW5jZSBtZWFucyBidWlsdC4gQSBjaGlwIGhlcmUgbWVhbnMgYW4gaW50ZXJydXB0ZWRcbiAgICAgICAgICAgICAgICAgICAgICAgICBidWlsZCBsZWZ0IHRoaXMgcm93IG93aW5nIGNvbnRlbnQuIC0tPlxuICAgICAgICAgICAgICAgICAgICBAZm9yIChzdGFnZSBvZiBwZW5kaW5nU3RhZ2VzKHVuaXQpOyB0cmFjayBzdGFnZSkge1xuICAgICAgICAgICAgICAgICAgICAgIDxmcy1jaGlwXG4gICAgICAgICAgICAgICAgICAgICAgICAgIHNpemU9XCJ0aW55XCJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgW2JhY2tncm91bmRDb2xvcl09XCJwZW5kaW5nQ29sb3IoKVwiXG4gICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yPVwiI2ZmZmZmZlwiXG4gICAgICAgICAgICAgICAgICAgICAgICAgIG1hdFRvb2x0aXA9XCJOZWVkcyBidWlsZGluZ1wiPlxuICAgICAgICAgICAgICAgICAgICAgICAge3sgc3RhZ2UgfX1cbiAgICAgICAgICAgICAgICAgICAgICA8L2ZzLWNoaXA+XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgICAgIDwvbWF0LXBhbmVsLWRlc2NyaXB0aW9uPlxuICAgICAgICAgICAgICA8L21hdC1leHBhbnNpb24tcGFuZWwtaGVhZGVyPlxuXG4gICAgICAgICAgICAgIDwhLS0gRGVmZXJyZWQ6IHRoZSBib2R5IG9ubHkgZXhpc3RzIG9uY2UgZXhwYW5kZWQuIC0tPlxuICAgICAgICAgICAgICA8bmctdGVtcGxhdGUgbWF0RXhwYW5zaW9uUGFuZWxDb250ZW50PlxuICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJlbnRpdHktZGV0YWlsXCI+XG4gICAgICAgICAgICAgICAgICBAaWYgKHVuaXQubW9kZWwpIHtcbiAgICAgICAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cInN0YXRcIj5cbiAgICAgICAgICAgICAgICAgICAgICA8c3BhbiBjbGFzcz1cImxhYmVsXCI+Q2xhc3M8L3NwYW4+XG4gICAgICAgICAgICAgICAgICAgICAgPHNwYW4+e3sgdW5pdC5tb2RlbCB9fTwvc3Bhbj5cbiAgICAgICAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICBAaWYgKHVuaXQuZW50aXR5OyBhcyBlbnRpdHkpIHtcbiAgICAgICAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cInN0YXRcIj5cbiAgICAgICAgICAgICAgICAgICAgICA8c3BhbiBjbGFzcz1cImxhYmVsXCI+VGFibGU8L3NwYW4+XG4gICAgICAgICAgICAgICAgICAgICAgPHNwYW4+e3sgZW50aXR5LnRhYmxlIH19PC9zcGFuPlxuICAgICAgICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgICAgICAgICAgPCEtLSBUaGUgaGFuZGxlIHRoZSByZXBvcnQgQUkgYWRkcmVzc2VzIHRoaXMgZW50aXR5IGJ5IGluXG4gICAgICAgICAgICAgICAgICAgICAgICAgZGVzY3JpYmVfZW50aXR5IC8gY29tcGlsZV9xdWVyeS4gLS0+XG4gICAgICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJzdGF0XCI+XG4gICAgICAgICAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJsYWJlbFwiPkVudGl0eSBrZXk8L3NwYW4+XG4gICAgICAgICAgICAgICAgICAgICAgPHNwYW4+e3sgZW50aXR5LmtleSB9fTwvc3Bhbj5cbiAgICAgICAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJzdGF0XCI+XG4gICAgICAgICAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJsYWJlbFwiPkNvbHVtbnM8L3NwYW4+XG4gICAgICAgICAgICAgICAgICAgICAgPHNwYW4+e3sgZW50aXR5LmNvbHVtbnMgfX08L3NwYW4+XG4gICAgICAgICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwic3RhdFwiPlxuICAgICAgICAgICAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwibGFiZWxcIj5SZWxhdGlvbnNoaXBzPC9zcGFuPlxuICAgICAgICAgICAgICAgICAgICAgIDxzcGFuPnt7IGVudGl0eS5yZWxhdGlvbnNoaXBzIH19PC9zcGFuPlxuICAgICAgICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgICAgICAgICAgQGlmIChlbnRpdHkuZW51bXMubGVuZ3RoKSB7XG4gICAgICAgICAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cInN0YXRcIj5cbiAgICAgICAgICAgICAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwibGFiZWxcIj5FbnVtZXJhdGlvbiB2YWx1ZXM8L3NwYW4+XG4gICAgICAgICAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwicGFpci1saXN0XCI+XG4gICAgICAgICAgICAgICAgICAgICAgICAgIEBmb3IgKGVudW1Db2x1bW4gb2YgZW50aXR5LmVudW1zOyB0cmFjayBlbnVtQ29sdW1uLmNvbHVtbikge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJwYWlyLXJvd1wiPlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJwYWlyLW5hbWVcIj57eyBlbnVtQ29sdW1uLmNvbHVtbiB9fTwvc3Bhbj5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxzcGFuPnt7IGVudW1Db2x1bW4udmFsdWVzLmpvaW4oJywgJykgfX08L3NwYW4+XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIEBpZiAoZW50aXR5LmNvbXB1dGVkRmllbGRzLmxlbmd0aCkge1xuICAgICAgICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJzdGF0XCI+XG4gICAgICAgICAgICAgICAgICAgICAgICA8c3BhbiBjbGFzcz1cImxhYmVsXCI+Q29tcHV0ZWQgZmllbGRzPC9zcGFuPlxuICAgICAgICAgICAgICAgICAgICAgICAgPHNwYW4+e3sgZW50aXR5LmNvbXB1dGVkRmllbGRzLmpvaW4oJywgJykgfX08L3NwYW4+XG4gICAgICAgICAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cInN0YXRcIj5cbiAgICAgICAgICAgICAgICAgICAgICA8c3BhbiBjbGFzcz1cImxhYmVsXCI+TW9kZWwgZnVuY3Rpb25zPC9zcGFuPlxuICAgICAgICAgICAgICAgICAgICAgIEBpZiAoZW50aXR5Lm1vZGVsRnVuY3Rpb25Db3VudCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgPGFcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjbGFzcz1cImNvdW50LWxpbmtcIlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIChjbGljayk9XCJvcGVuRnVuY3Rpb25zKHVuaXQsICdtb2RlbCcpXCI+XG4gICAgICAgICAgICAgICAgICAgICAgICAgIHt7IGVudGl0eS5tb2RlbEZ1bmN0aW9uQ291bnQgfX1cbiAgICAgICAgICAgICAgICAgICAgICAgIDwvYT5cbiAgICAgICAgICAgICAgICAgICAgICB9IEBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIDxzcGFuPjA8L3NwYW4+XG4gICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cInN0YXRcIj5cbiAgICAgICAgICAgICAgICAgICAgICA8c3BhbiBjbGFzcz1cImxhYmVsXCI+SGFuZGxlciBmdW5jdGlvbnM8L3NwYW4+XG4gICAgICAgICAgICAgICAgICAgICAgQGlmIChlbnRpdHkuaGFuZGxlckZ1bmN0aW9uQ291bnQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIDxhXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY2xhc3M9XCJjb3VudC1saW5rXCJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAoY2xpY2spPVwib3BlbkZ1bmN0aW9ucyh1bml0LCAnaGFuZGxlcicpXCI+XG4gICAgICAgICAgICAgICAgICAgICAgICAgIHt7IGVudGl0eS5oYW5kbGVyRnVuY3Rpb25Db3VudCB9fVxuICAgICAgICAgICAgICAgICAgICAgICAgPC9hPlxuICAgICAgICAgICAgICAgICAgICAgIH0gQGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgPHNwYW4+MDwvc3Bhbj5cbiAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgICAgICAgfSBAZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJzdGF0XCI+XG4gICAgICAgICAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJsYWJlbFwiPkNvZGUgZnVuY3Rpb25zPC9zcGFuPlxuICAgICAgICAgICAgICAgICAgICAgIEBpZiAodW5pdC5mdW5jdGlvbkNvdW50KSB7XG4gICAgICAgICAgICAgICAgICAgICAgICA8YVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNsYXNzPVwiY291bnQtbGlua1wiXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgKGNsaWNrKT1cIm9wZW5GdW5jdGlvbnModW5pdCwgJ2NsYXNzJylcIj5cbiAgICAgICAgICAgICAgICAgICAgICAgICAge3sgdW5pdC5mdW5jdGlvbkNvdW50IH19XG4gICAgICAgICAgICAgICAgICAgICAgICA8L2E+XG4gICAgICAgICAgICAgICAgICAgICAgfSBAZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICA8c3Bhbj4wPC9zcGFuPlxuICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICAgIDwvbmctdGVtcGxhdGU+XG4gICAgICAgICAgICA8L21hdC1leHBhbnNpb24tcGFuZWw+XG4gICAgICAgICAgfVxuICAgICAgICA8L21hdC1hY2NvcmRpb24+XG5cbiAgICAgICAgQGlmICghZmlsdGVyZWRVbml0cygpLmxlbmd0aCkge1xuICAgICAgICAgIDxkaXYgY2xhc3M9XCJzdWJoZWFkaW5nXCI+Tm90aGluZyBtYXRjaGVzIOKAnHt7IGZpbHRlcigpIH194oCdLjwvZGl2PlxuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIDwhLS0gVGhlIG90aGVyIGhhbGYgb2YgdGhlIHBpY3R1cmU6IHRhYmxlcyB0aGUgQUkgY2FuJ3QgcmVhY2guIEV4Y2x1ZGVkXG4gICAgICAgICAgIG9uZXMgaGF2ZSBubyBtb2RlbDsgdW5saW5rZWQganVuY3Rpb25zIGhhdmUgYSBjb21wb3NpdGUgcHJpbWFyeSBrZXlcbiAgICAgICAgICAgYnV0IHdlcmUgZm9sZGVkIGludG8gbm8gcmVsYXRpb25zaGlwLCBzbyBub3RoaW5nIGNhbiBuYXZpZ2F0ZSB0b1xuICAgICAgICAgICB0aGVtLiBCb3RoIGFyZSBpbnZpc2libGUgYnkgb21pc3Npb24g4oCUIG5vIGVycm9yLCBqdXN0IGEgY2FwYWJpbGl0eVxuICAgICAgICAgICB0aGF0IHNpbGVudGx5IGlzbid0IHRoZXJlLiBDb2xsYXBzZWQgYnkgZGVmYXVsdDogdGhlIGV4Y2x1ZGVkIGxpc3QgaXNcbiAgICAgICAgICAgbG9uZyBhbmQgbW9zdGx5IGZyYW1ld29yayBwbHVtYmluZy4gLS0+XG4gICAgICBAaWYgKGhhc0NhdGFsb2coKSkge1xuICAgICAgICA8aDI+Tm90IGluIHRoZSBzZW1hbnRpYyBkYXRhYmFzZTwvaDI+XG4gICAgICAgIDxkaXYgY2xhc3M9XCJzdWJoZWFkaW5nXCI+XG4gICAgICAgICAgVGFibGVzIHRoZSByZXBvcnQgQUkgY2FuJ3Qgc2VlLiBHaXZlIG9uZSBhIG1vZGVsIHRvIHByb21vdGUgaXQgdG8gYW5cbiAgICAgICAgICBlbnRpdHksIHRoZW4gcmVidWlsZC5cbiAgICAgICAgPC9kaXY+XG4gICAgICAgIDxtYXQtYWNjb3JkaW9uIGNsYXNzPVwiY2F0YWxvZ1wiPlxuICAgICAgICAgIEBpZiAoZXhjbHVkZWRUYWJsZXMoKS5sZW5ndGgpIHtcbiAgICAgICAgICAgIDxtYXQtZXhwYW5zaW9uLXBhbmVsPlxuICAgICAgICAgICAgICA8bWF0LWV4cGFuc2lvbi1wYW5lbC1oZWFkZXI+XG4gICAgICAgICAgICAgICAgPG1hdC1wYW5lbC10aXRsZT5cbiAgICAgICAgICAgICAgICAgIFRhYmxlcyBleGNsdWRlZCAoe3sgZXhjbHVkZWRUYWJsZXMoKS5sZW5ndGggfX0pXG4gICAgICAgICAgICAgICAgPC9tYXQtcGFuZWwtdGl0bGU+XG4gICAgICAgICAgICAgIDwvbWF0LWV4cGFuc2lvbi1wYW5lbC1oZWFkZXI+XG5cbiAgICAgICAgICAgICAgPCEtLSBEZWZlcnJlZDogdGhlIGJvZHkgb25seSBleGlzdHMgb25jZSBleHBhbmRlZC4gLS0+XG4gICAgICAgICAgICAgIDxuZy10ZW1wbGF0ZSBtYXRFeHBhbnNpb25QYW5lbENvbnRlbnQ+XG4gICAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cInBhaXItbGlzdFwiPlxuICAgICAgICAgICAgICAgICAgQGZvciAodGFibGUgb2YgZXhjbHVkZWRUYWJsZXMoKTsgdHJhY2sgdGFibGUudGFibGUpIHtcbiAgICAgICAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cInBhaXItcm93XCI+XG4gICAgICAgICAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJwYWlyLW5hbWVcIj57eyB0YWJsZS50YWJsZSB9fTwvc3Bhbj5cbiAgICAgICAgICAgICAgICAgICAgICA8c3Bhbj57eyB0YWJsZS5yZWFzb24gfX08L3NwYW4+XG4gICAgICAgICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgICA8L25nLXRlbXBsYXRlPlxuICAgICAgICAgICAgPC9tYXQtZXhwYW5zaW9uLXBhbmVsPlxuICAgICAgICAgIH1cbiAgICAgICAgICBAaWYgKHVubGlua2VkSnVuY3Rpb25zKCkubGVuZ3RoKSB7XG4gICAgICAgICAgICA8bWF0LWV4cGFuc2lvbi1wYW5lbD5cbiAgICAgICAgICAgICAgPG1hdC1leHBhbnNpb24tcGFuZWwtaGVhZGVyPlxuICAgICAgICAgICAgICAgIDxtYXQtcGFuZWwtdGl0bGU+XG4gICAgICAgICAgICAgICAgICBKdW5jdGlvbnMgbm90IGxpbmtlZCAoe3sgdW5saW5rZWRKdW5jdGlvbnMoKS5sZW5ndGggfX0pXG4gICAgICAgICAgICAgICAgPC9tYXQtcGFuZWwtdGl0bGU+XG4gICAgICAgICAgICAgIDwvbWF0LWV4cGFuc2lvbi1wYW5lbC1oZWFkZXI+XG5cbiAgICAgICAgICAgICAgPG5nLXRlbXBsYXRlIG1hdEV4cGFuc2lvblBhbmVsQ29udGVudD5cbiAgICAgICAgICAgICAgICA8cCBjbGFzcz1cInNtYWxsXCI+XG4gICAgICAgICAgICAgICAgICBMaW5rIHRhYmxlcyB0aGUgYnVpbGQgY291bGRuJ3QgZm9sZCBpbnRvIGEgcmVsYXRpb25zaGlwIOKAlCBzb1xuICAgICAgICAgICAgICAgICAgbmVpdGhlciB0aGV5IG5vciB3aGF0IHRoZXkgbGluayBjYW4gYmUgcmVwb3J0ZWQgb24uXG4gICAgICAgICAgICAgICAgPC9wPlxuICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJwYWlyLWxpc3RcIj5cbiAgICAgICAgICAgICAgICAgIEBmb3IgKHRhYmxlIG9mIHVubGlua2VkSnVuY3Rpb25zKCk7IHRyYWNrIHRhYmxlLnRhYmxlKSB7XG4gICAgICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJwYWlyLXJvd1wiPlxuICAgICAgICAgICAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwicGFpci1uYW1lXCI+e3sgdGFibGUudGFibGUgfX08L3NwYW4+XG4gICAgICAgICAgICAgICAgICAgICAgPHNwYW4+e3sgdGFibGUucmVhc29uIH19PC9zcGFuPlxuICAgICAgICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgICAgPC9uZy10ZW1wbGF0ZT5cbiAgICAgICAgICAgIDwvbWF0LWV4cGFuc2lvbi1wYW5lbD5cbiAgICAgICAgICB9XG4gICAgICAgIDwvbWF0LWFjY29yZGlvbj5cbiAgICAgIH1cbiAgICB9XG4gIDwvZGl2PlxuPC9kaXY+XG4iXX0=
372
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VtYW50aWMtZGF0YWJhc2UuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vc3JjL2FwcC9yZXBvcnRzL2RpYWxvZ3MvZ2xvYmFsLXNldHRpbmdzL2NvbXBvbmVudHMvc2VtYW50aWMtZGF0YWJhc2Uvc2VtYW50aWMtZGF0YWJhc2UuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vc3JjL2FwcC9yZXBvcnRzL2RpYWxvZ3MvZ2xvYmFsLXNldHRpbmdzL2NvbXBvbmVudHMvc2VtYW50aWMtZGF0YWJhc2Uvc2VtYW50aWMtZGF0YWJhc2UuY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLHVCQUF1QixFQUFFLFNBQVMsRUFBRSxVQUFVLEVBQUUsUUFBUSxFQUFFLE1BQU0sRUFBRSxNQUFNLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDekcsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sNEJBQTRCLENBQUM7QUFFaEUsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLDBCQUEwQixDQUFDO0FBQ3JELE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLDZCQUE2QixDQUFDO0FBQ2pFLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLDJCQUEyQixDQUFDO0FBRTdELE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUNsRCxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sa0JBQWtCLENBQUM7QUFDaEQsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBQ2hELE9BQU8sRUFBRSxTQUFTLEVBQUUsZUFBZSxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDakUsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBQ2hELE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUM5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Q0FBQyxNQUEyQixFQUFFLEVBQUU7WUFDbEMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLENBQUM7WUFDNUIsSUFBSSxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLENBQUM7UUFDMUIsQ0FBQyxDQUFDLEVBQ0YsVUFBVSxDQUFDLEdBQUcsRUFBRTtZQUNkLElBQUksQ0FBQyxXQUFXLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxDQUFDO1lBRTNCLE9BQU8sS0FBSyxDQUFDO1FBQ2YsQ0FBQyxDQUFDLEVBQ0Ysa0JBQWtCLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxDQUNyQyxDQUFDO0lBQ04sQ0FBQzt3R0ExWlUseUJBQXlCOzRGQUF6Qix5QkFBeUIsMEdDdEV0Qywyc1hBZ1JBLDQ1QkRsTkksa0JBQWtCLHEwQkFDbEIsZ0JBQWdCLDRUQUNoQixZQUFZLHFYQUNaLFlBQVksNElBQ1osZUFBZSx5SEFDZixnQkFBZ0I7OzRGQUdQLHlCQUF5QjtrQkFmckMsU0FBUzsrQkFDRSxnREFBZ0QsbUJBR3pDLHVCQUF1QixDQUFDLE1BQU0sY0FDbkMsSUFBSSxXQUNQO3dCQUNQLGtCQUFrQjt3QkFDbEIsZ0JBQWdCO3dCQUNoQixZQUFZO3dCQUNaLFlBQVk7d0JBQ1osZUFBZTt3QkFDZixnQkFBZ0I7cUJBQ2pCIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3ksIENvbXBvbmVudCwgRGVzdHJveVJlZiwgY29tcHV0ZWQsIGluamVjdCwgc2lnbmFsIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyB0YWtlVW50aWxEZXN0cm95ZWQgfSBmcm9tICdAYW5ndWxhci9jb3JlL3J4anMtaW50ZXJvcCc7XG5cbmltcG9ydCB7IE1hdERpYWxvZyB9IGZyb20gJ0Bhbmd1bGFyL21hdGVyaWFsL2RpYWxvZyc7XG5pbXBvcnQgeyBNYXRFeHBhbnNpb25Nb2R1bGUgfSBmcm9tICdAYW5ndWxhci9tYXRlcmlhbC9leHBhbnNpb24nO1xuaW1wb3J0IHsgTWF0VG9vbHRpcE1vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL21hdGVyaWFsL3Rvb2x0aXAnO1xuXG5pbXBvcnQgeyBTdHJlYW1FdmVudFR5cGUgfSBmcm9tICdAZmlyZXN0aXRjaC9hcGknO1xuaW1wb3J0IHsgRnNDaGlwTW9kdWxlIH0gZnJvbSAnQGZpcmVzdGl0Y2gvY2hpcCc7XG5pbXBvcnQgeyBGc0RhdGVNb2R1bGUgfSBmcm9tICdAZmlyZXN0aXRjaC9kYXRlJztcbmltcG9ydCB7IEZzTWVzc2FnZSwgRnNNZXNzYWdlTW9kdWxlIH0gZnJvbSAnQGZpcmVzdGl0Y2gvbWVzc2FnZSc7XG5pbXBvcnQgeyBGc1Byb2Nlc3MgfSBmcm9tICdAZmlyZXN0aXRjaC9wcm9jZXNzJztcbmltcG9ydCB7IEZzUHJvbXB0IH0gZnJvbSAnQGZpcmVzdGl0Y2gvcHJvbXB0JztcbmltcG9ydCB7IEZzU2tlbGV0b25Nb2R1bGUgfSBmcm9tICdAZmlyZXN0aXRjaC9za2VsZXRvbic7XG5cbmltcG9ydCB7IEVNUFRZLCBPYnNlcnZhYmxlIH0gZnJvbSAncnhqcyc7XG5pbXBvcnQgeyBjYXRjaEVycm9yLCBmaWx0ZXIsIG1hcCwgc3dpdGNoTWFwLCB0YWtlLCB0YXAgfSBmcm9tICdyeGpzL29wZXJhdG9ycyc7XG5cbmltcG9ydCB7IFJlcG9ydERhdGEgfSBmcm9tICcuLi8uLi8uLi8uLi9kYXRhL3JlcG9ydC5kYXRhJztcbmltcG9ydCB7XG4gIFNlbWFudGljQnVpbGRDbGFzcyxcbiAgU2VtYW50aWNCdWlsZEVudGl0eSxcbiAgU2VtYW50aWNCdWlsZFN0YXR1cyxcbiAgU2VtYW50aWNCdWlsZFRhYmxlLFxuICBTZW1hbnRpY0Z1bmN0aW9uU291cmNlLFxufSBmcm9tICcuLi8uLi8uLi8uLi9pbnRlcmZhY2VzL3JlcG9ydC5pbnRlcmZhY2UnO1xuaW1wb3J0IHsgRW50aXR5RnVuY3Rpb25zQ29tcG9uZW50IH0gZnJvbSAnLi4vLi4vLi4vZW50aXR5LWZ1bmN0aW9ucy9lbnRpdHktZnVuY3Rpb25zLmNvbXBvbmVudCc7XG5cblxuLy8gT25lIHJvdyBvZiB0aGUgc2NvcmVib2FyZC4gVGhlIGJ1aWxkIGNhY2hlcyB0d28ga2luZHMgb2YgdW5pdCBhbmQgdGhlIHJlcG9ydFxuLy8gQUkgcmVhZHMgY29kZSBmcm9tIGJvdGgsIHNvIHRoZXkgYmVsb25nIGluIE9ORSBsaXN0OiBhbiBlbnRpdHkgKGEgdGFibGUgcGx1c1xuLy8gaXRzIG1vZGVsIGFuZCBoYW5kbGVyKSBhbmQgYSBzdGFuZGFsb25lIGNvZGUgY2xhc3MgKGRvbWFpbiBsb2dpYyB3aXRoIG5vXG4vLyB0YWJsZSDigJQgYSBzdW1tYXJ5IG1vZGVsLCBhIGNhbGN1bGF0aW9uIHNlcnZpY2UpLiBBIGNsYXNzIHJvdyBzaW1wbHkgaGFzIG5vXG4vLyB0YWJsZSwgY29sdW1ucyBvciByZWxhdGlvbnNoaXBzIHRvIHNob3cuXG5pbnRlcmZhY2UgU2VtYW50aWNVbml0VmlldyB7XG4gIGtleTogc3RyaW5nO1xuICBuYW1lOiBzdHJpbmc7XG4gIGhhc1RhYmxlOiBib29sZWFuO1xuICBlbnRpdHk6IFNlbWFudGljQnVpbGRFbnRpdHkgfCBudWxsO1xuICBtb2RlbDogc3RyaW5nIHwgbnVsbDtcbiAgZnVuY3Rpb25Db3VudDogbnVtYmVyO1xufVxuXG5cbi8vIFRoZSBTZW1hbnRpYyBEYXRhYmFzZSB0YWI6IHRoZSBzY29yZWJvYXJkIG9mIGV2ZXJ5dGhpbmcgdGhlIHJlcG9ydCBBSSB3YXNcbi8vIGJ1aWx0IGZyb20uIFNob3dzIHRoZSBsYXN0IGJ1aWxkJ3Mgc3RhdHVzLCBydW5zIChvciBzdG9wcykgYSBidWlsZCDigJQgc3RyZWFtZWRcbi8vIGludG8gdGhlIEZzUHJvY2VzcyBkb2NrIHNvIGl0IHN1cnZpdmVzIHRoZSBkaWFsb2cgY2xvc2luZyDigJQgYW5kIGRyaWxscyBpbnRvXG4vLyBldmVyeSB1bml0IHRvIHJldmVhbCBpdHMgc2hhcGUsIGlubGluZWQgZW51bSB2YWx1ZXMsIGNvbXB1dGVkIGZpZWxkcyBhbmQgaXRzXG4vLyBjYWNoZWQgZnVuY3Rpb24gY291bnRzLCB3aG9zZSBsaW5rcyBvcGVuIHRoZSBmdW5jdGlvbnMgZGlhbG9nICh0aGUgZnVsbFxuLy8gZnVuY3Rpb24gc2V0IGlzIGZhciB0b28gYmlnIHRvIHNoaXAgd2l0aCB0aGUgc2NvcmVib2FyZCkuXG4vL1xuLy8gSXQgYWxzbyByZXBvcnRzIHRoZSBvdGhlciBoYWxmIG9mIHRoZSBwaWN0dXJlOiB0aGUgdGFibGVzIHRoZSBBSSBDQU5OT1Qgc2VlIOKAlFxuLy8gZXhjbHVkZWQgb25lcyAobm8gbW9kZWwpIGFuZCBqdW5jdGlvbnMgdGhhdCBicmlkZ2VkIG5vdGhpbmcuIFRob3NlIGFyZVxuLy8gaW52aXNpYmxlIGJ5IG9taXNzaW9uIG90aGVyd2lzZTogbm90aGluZyBlcnJvcnMsIHRoZSBjYXBhYmlsaXR5IGp1c3QgaXNuJ3Rcbi8vIHRoZXJlLCBhbmQgdGhlIGZpcnN0IGFueW9uZSBsZWFybnMgaXMgYSB3cm9uZyBhbnN3ZXIgb3IgYSByZWZ1c2FsLlxuQENvbXBvbmVudCh7XG4gIHNlbGVjdG9yOiAnZnMtYWktcmVwb3J0LWdsb2JhbC1zZXR0aW5ncy1zZW1hbnRpYy1kYXRhYmFzZScsXG4gIHRlbXBsYXRlVXJsOiAnLi9zZW1hbnRpYy1kYXRhYmFzZS5jb21wb25lbnQuaHRtbCcsXG4gIHN0eWxlVXJsczogWycuL3NlbWFudGljLWRhdGFiYXNlLmNvbXBvbmVudC5zY3NzJ10sXG4gIGNoYW5nZURldGVjdGlvbjogQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3kuT25QdXNoLFxuICBzdGFuZGFsb25lOiB0cnVlLFxuICBpbXBvcnRzOiBbXG4gICAgTWF0RXhwYW5zaW9uTW9kdWxlLFxuICAgIE1hdFRvb2x0aXBNb2R1bGUsXG4gICAgRnNDaGlwTW9kdWxlLFxuICAgIEZzRGF0ZU1vZHVsZSxcbiAgICBGc01lc3NhZ2VNb2R1bGUsXG4gICAgRnNTa2VsZXRvbk1vZHVsZSxcbiAgXSxcbn0pXG5leHBvcnQgY2xhc3MgU2VtYW50aWNEYXRhYmFzZUNvbXBvbmVudCB7XG5cbiAgLy8gVGhlIGJ1aWxkLWluLWZsaWdodCBzdGF0ZXMgb2YgdGhlIGZmX3Byb2Nlc3NlcyByb3cgKHF1ZXVlZC9ydW5uaW5nL3N0b3BwaW5nKS5cbiAgcHJpdmF0ZSBzdGF0aWMgcmVhZG9ubHkgQUNUSVZFX1NUQVRFUyA9IFsnUScsICdSJywgJ1gnXTtcblxuICBwcml2YXRlIHN0YXRpYyByZWFkb25seSBTVEFURV9MQUJFTFM6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4gPSB7XG4gICAgUTogJ1F1ZXVlZCcsXG4gICAgUjogJ1J1bm5pbmcnLFxuICAgIFg6ICdTdG9wcGluZycsXG4gICAgQzogJ0NvbXBsZXRlZCcsXG4gICAgSzogJ1N0b3BwZWQnLFxuICAgIEY6ICdGYWlsZWQnLFxuICB9O1xuXG4gIC8vIFRoZSBzdHJlYW1lZCBmcmFtZXMgdGhhdCBjYXJyeSBhIGxpbmUgZm9yIHRoZSBmZWVkOiBwcm9ncmVzcywgYW5kIHRoZSBmaW5hbFxuICAvLyBmcmFtZSB0aGUgYmFja2VuZCBzZW5kcyB3aGVuIGEgcnVuIGVuZHMgYmFkbHkuIFdpdGhvdXQgdGhlIGVycm9yIGtpbmQgdGhlXG4gIC8vIGZlZWQgc3RvcHMgb24gdGhlIGxhc3QgcHJvZ3Jlc3MgbGluZSBhbmQgbmV2ZXIgc2F5cyB3aGF0IHdlbnQgd3JvbmcuXG4gIHByaXZhdGUgc3RhdGljIHJlYWRvbmx5IExPR19LSU5EUyA9IFsnbG9nJywgJ2Vycm9yJ107XG5cbiAgLy8gQSByb3cgdGhhdCBpcyBzdGlsbCBvd2VkIGNvbnRlbnQgc2F5cyBzbzsgYSBidWlsdCBvbmUgc2F5cyBub3RoaW5nLiBPbiBhXG4gIC8vIGZpbmlzaGVkIGJ1aWxkIGV2ZXJ5IHN0YWdlIGlzIGRvbmUgb24gZXZlcnkgcm93LCBzbyBjaGlwcGluZyB0aGVtIGFsbCB3YXNcbiAgLy8gbm9pc2UgdGhhdCBidXJpZWQgdGhlIG9uZSByb3cgdGhhdCBtYXR0ZXJlZC5cbiAgcHJpdmF0ZSBzdGF0aWMgcmVhZG9ubHkgUEVORElOR19DT0xPUiA9ICcjYjI2NTAwJztcblxuICAvLyBDbGFzcy1uYW1lIHN1ZmZpeCBzdHJpcHBlZCBmb3IgZGlzcGxheTogYEJ1ZGdldFN1bW1hcnlNb2RlbGAgcmVhZHMgYXNcbiAgLy8gYEJ1ZGdldFN1bW1hcnlgLiBPbmx5IGBNb2RlbGAg4oCUIHN0cmlwcGluZyBgSGFuZGxlcmAgdG9vIHdvdWxkIGNvbGxpZGVcbiAgLy8gYFdvcmtPcmRlck9uZVRpbWVIYW5kbGVyYCB3aXRoIGBXb3JrT3JkZXJPbmVUaW1lTW9kZWxgLCB3aGljaCBhcmUgdHdvXG4gIC8vIHNlcGFyYXRlIHVuaXRzLlxuICBwcml2YXRlIHN0YXRpYyByZWFkb25seSBOQU1FX1NVRkZJWCA9ICdNb2RlbCc7XG5cbiAgLy8gbnVsbCB1bnRpbCBsb2FkZWQg4oCUIGdhdGVzIHRoZSB0YWIgYmVoaW5kIHRoZSBza2VsZXRvbi5cbiAgcHVibGljIHJlYWRvbmx5IHN0YXR1cyA9IHNpZ25hbDxTZW1hbnRpY0J1aWxkU3RhdHVzIHwgbnVsbD4obnVsbCk7XG5cbiAgLy8gVGhlIHN0YXR1cyByZXF1ZXN0IGZhaWxlZC4gU2V0dGxlcyB0aGUgc2tlbGV0b24gYW5kIHNob3dzIHdoeTsgdGhlIEJ1aWxkXG4gIC8vIGFjdGlvbiBuZXZlciBkZXBlbmRzIG9uIHRoZSBzdGF0dXMsIHNvIGEgYnVpbGQgY2FuIHN0aWxsIGJlIHN0YXJ0ZWQuXG4gIHB1YmxpYyByZWFkb25seSBzdGF0dXNFcnJvciA9IHNpZ25hbChmYWxzZSk7XG5cbiAgLy8gRnJlZS10ZXh0IGZpbHRlciBvdmVyIHRoZSB1bml0IGxpc3Qg4oCUIGF0IGEgZmV3IGh1bmRyZWQgcm93cyB0aGUgYWNjb3JkaW9uXG4gIC8vIGlzIG9ubHkgdXNhYmxlIGlmIHlvdSBjYW4gbmFycm93IGl0LlxuICBwdWJsaWMgcmVhZG9ubHkgZmlsdGVyID0gc2lnbmFsPHN0cmluZz4oJycpO1xuXG4gIC8vIFRydWUgd2hpbGUgYSBidWlsZCBzdGFydGVkIGZyb20gdGhpcyB0YWIgaXMgc3RyZWFtaW5nIGludG8gdGhlIGRvY2suXG4gIHB1YmxpYyByZWFkb25seSBidWlsZGluZyA9IHNpZ25hbChmYWxzZSk7XG5cbiAgcHVibGljIHJlYWRvbmx5IGJ1aWxkQWN0aXZlID0gY29tcHV0ZWQ8Ym9vbGVhbj4oKCkgPT5cbiAgICB0aGlzLmJ1aWxkaW5nKClcbiAgICAgIHx8IFNlbWFudGljRGF0YWJhc2VDb21wb25lbnQuQUNUSVZFX1NUQVRFUy5pbmNsdWRlcyh0aGlzLnN0YXR1cygpPy5idWlsZD8uc3RhdGUpLFxuICApO1xuXG4gIC8vIEEgc2VtYW50aWMgZGF0YWJhc2UgaGFzIGJlZW4gcHVibGlzaGVkIGJlZm9yZSwgc28gYSBidWlsZCByZXBsYWNlcyBpdC5cbiAgLy8gRmFsc2Ugd2hpbGUgdGhlIHN0YXR1cyBpcyB1bmxvYWRlZCBvciBmYWlsZWQgdG8gbG9hZC5cbiAgcHVibGljIHJlYWRvbmx5IHJlYnVpbGQgPSBjb21wdXRlZDxib29sZWFuPigoKSA9PiAhIXRoaXMuc3RhdHVzKCk/LmRldGFpbD8uZ2VuZXJhdGVkQXQpO1xuXG4gIHB1YmxpYyByZWFkb25seSBidWlsZFN0YXRlTGFiZWwgPSBjb21wdXRlZDxzdHJpbmc+KCgpID0+XG4gICAgU2VtYW50aWNEYXRhYmFzZUNvbXBvbmVudC5TVEFURV9MQUJFTFNbdGhpcy5zdGF0dXMoKT8uYnVpbGQ/LnN0YXRlXSA/PyAnJyxcbiAgKTtcblxuICAvLyBXaGV0aGVyIHRoZSBwdWJsaXNoZWQgc2VtYW50aWMgZGF0YWJhc2UgY2FtZSBmcm9tIGEgYnVpbGQgdGhhdCBmaW5pc2hlZC5cbiAgLy9cbiAgLy8gQSBmYWlsZWQgb3Igc3RvcHBlZCBidWlsZCBzdGlsbCBsZWF2ZXMgYSBkYXRlZCwgZnVsbHkgY291bnRlZCBhcnRpZmFjdFxuICAvLyBiZWhpbmQsIGJlY2F1c2UgdGhlIHN0cnVjdHVyYWwgaGFsZiBwdWJsaXNoZXMgQkVGT1JFIHRoZSBBSSBmdW5jdGlvbiBwYXNzXG4gIC8vIGFuZCBpdCBpcyB0aGUgQUkgcGFzcyB0aGF0IGZhaWxzLiBTbyBcIkxhc3QgYnVpbHRcIiBhbmQgQ292ZXJhZ2UgYm90aCBmaWxsZWRcbiAgLy8gaW4gYW5kIHJlYWQgYXMgYSBjbGVhbiBzdWNjZXNzLCBhbmQgdGhlIG9ubHkgZGlzc2VudGluZyB3b3JkIG9uIHRoZSB3aG9sZVxuICAvLyBwYW5lbCB3YXMgb25lIGxpbmUgb2YgXCJMYXN0IGJ1aWxkIHJ1blwiIHRleHQgKFJFLVQxMzAyKS5cbiAgLy9cbiAgLy8gUmVhZHMgYXMgY29tcGxldGUgd2hpbGUgdGhlIHN0YXR1cyBpcyBzdGlsbCBsb2FkaW5nLCBzbyB0aGUgd2FybmluZyBjYW5ub3RcbiAgLy8gZmxhc2ggb24gb3BlbiBiZWZvcmUgdGhlcmUgaXMgYW55dGhpbmcgdG8gd2FybiBhYm91dC5cbiAgcHVibGljIHJlYWRvbmx5IGJ1aWxkQ29tcGxldGUgPSBjb21wdXRlZDxib29sZWFuPigoKSA9PiB0aGlzLnN0YXR1cygpPy5kZXRhaWw/LmNvbXBsZXRlICE9PSBmYWxzZSk7XG5cbiAgLy8gRW50aXRpZXMgdGhlIGJ1aWxkIG5ldmVyIHJlYWNoZWQg4oCUIHRob3NlIHN0aWxsIG93ZWQgdGhlIEFJIGZ1bmN0aW9uIHBhc3MuXG4gIC8vIFRoZSBudW1iZXIgdGhlIGluY29tcGxldGUgd2FybmluZyBxdW90ZXMsIGFuZCB0aGUgc2FtZSByb3dzIHRoZSBzY29yZWJvYXJkXG4gIC8vIGJlbG93IGFscmVhZHkgY2hpcHMgb25lIGF0IGEgdGltZS5cbiAgcHVibGljIHJlYWRvbmx5IGluY29tcGxldGVFbnRpdHlDb3VudCA9IGNvbXB1dGVkPG51bWJlcj4oKCkgPT5cbiAgICAodGhpcy5zdGF0dXMoKT8uZGV0YWlsPy5lbnRpdGllcyA/PyBbXSlcbiAgICAgIC5maWx0ZXIoKGVudGl0eSkgPT4gZW50aXR5LnN0YWdlcy5mdW5jdGlvbnMgIT09ICdkb25lJylcbiAgICAgIC5sZW5ndGgsXG4gICk7XG5cbiAgLy8gQW4gYXJ0aWZhY3QgYnVpbHQgYmVmb3JlIHRoZSBjYXRhbG9nIGV4aXN0ZWQgY2FycmllcyBubyB0YWJsZXMuIEV2ZXJ5dGhpbmdcbiAgLy8gY2F0YWxvZy1kcml2ZW4gc3RheXMgaGlkZGVuIHJhdGhlciB0aGFuIGNsYWltaW5nIFwiMCBleGNsdWRlZFwiLCB3aGljaCB3b3VsZFxuICAvLyBiZSBhIGxpZSDigJQgYSByZWJ1aWxkIGZpbGxzIGl0IGluLlxuICBwdWJsaWMgcmVhZG9ubHkgaGFzQ2F0YWxvZyA9IGNvbXB1dGVkPGJvb2xlYW4+KCgpID0+ICEhdGhpcy5zdGF0dXMoKT8uZGV0YWlsPy50YWJsZXM/Lmxlbmd0aCk7XG5cbiAgLy8gVGFibGVzIHdpdGggbm8gbW9kZWw6IHRoZSByZXBvcnQgQUkgY2FuJ3Qgc2VlIHRoZW0gYXQgYWxsLiBBZGQgYSBtb2RlbCB0b1xuICAvLyBwcm9tb3RlIG9uZSB0byBhbiBlbnRpdHkuXG4gIHB1YmxpYyByZWFkb25seSBleGNsdWRlZFRhYmxlcyA9IGNvbXB1dGVkPFNlbWFudGljQnVpbGRUYWJsZVtdPigoKSA9PlxuICAgIHRoaXMuX3RhYmxlcygpLmZpbHRlcigodGFibGUpID0+IHRhYmxlLmNsYXNzaWZpY2F0aW9uID09PSAnZXhjbHVkZWQnKSxcbiAgKTtcblxuICAvLyBMaW5rIHRhYmxlcyB0aGF0IGJyaWRnZWQgbm90aGluZyDigJQgYSBjb21wb3NpdGUgcHJpbWFyeSBrZXkgbWFkZSB0aGVtIGFcbiAgLy8ganVuY3Rpb24sIGJ1dCB0aGV5IHdlcmUgZm9sZGVkIGludG8gbm8gcmVsYXRpb25zaGlwLCBzbyBuZWl0aGVyIHRoZXkgbm9yXG4gIC8vIHdoYXQgdGhleSBsaW5rIGFyZSByZWFjaGFibGUuXG4gIHB1YmxpYyByZWFkb25seSB1bmxpbmtlZEp1bmN0aW9ucyA9IGNvbXB1dGVkPFNlbWFudGljQnVpbGRUYWJsZVtdPigoKSA9PlxuICAgIHRoaXMuX3RhYmxlcygpLmZpbHRlcigodGFibGUpID0+IHRhYmxlLmNsYXNzaWZpY2F0aW9uID09PSAnanVuY3Rpb24nICYmICEhdGFibGUucmVhc29uKSxcbiAgKTtcblxuICAvLyBFdmVyeXRoaW5nIHRoZSBidWlsZCBjYWNoZWQsIGVudGl0aWVzIGFuZCBzdGFuZGFsb25lIGNvZGUgY2xhc3NlcyB0b2dldGhlcixcbiAgLy8gaW4gb25lIGxpc3Qgb3JkZXJlZCBieSB0aGUgbmFtZSBhIHJlYWRlciByZWNvZ25pemVzLiBUd28gYXJyYXlzIG9uIHRoZSB3aXJlXG4gIC8vIGJlY2F1c2UgdGhleSBhcmUgZ2VudWluZWx5IGRpZmZlcmVudCBzaGFwZXM7IG9uZSBsaXN0IG9uIHNjcmVlbiBiZWNhdXNlXG4gIC8vIFwid2hhdCBkaWQgdGhlIGJ1aWxkIHJlYWQ/XCIgaXMgYSBzaW5nbGUgcXVlc3Rpb24uXG4gIHB1YmxpYyByZWFkb25seSB1bml0cyA9IGNvbXB1dGVkPFNlbWFudGljVW5pdFZpZXdbXT4oKCkgPT4ge1xuICAgIGNvbnN0IGRldGFpbCA9IHRoaXMuc3RhdHVzKCk/LmRldGFpbDtcbiAgICBpZiAoIWRldGFpbCkge1xuICAgICAgcmV0dXJuIFtdO1xuICAgIH1cblxuICAgIGNvbnN0IGVudGl0aWVzID0gKGRldGFpbC5lbnRpdGllcyA/PyBbXSkubWFwKChlbnRpdHkpID0+ICh7XG4gICAgICBrZXk6IGVudGl0eS5rZXksXG4gICAgICBuYW1lOiB0aGlzLl9kaXNwbGF5TmFtZShlbnRpdHkubW9kZWwsIGVudGl0eS5rZXkpLFxuICAgICAgaGFzVGFibGU6IHRydWUsXG4gICAgICBlbnRpdHksXG4gICAgICBtb2RlbDogZW50aXR5Lm1vZGVsLFxuICAgICAgZnVuY3Rpb25Db3VudDogZW50aXR5LmZ1bmN0aW9uQ291bnQsXG4gICAgfSkpO1xuXG4gICAgY29uc3QgY2xhc3NlcyA9IChkZXRhaWwuY2xhc3NlcyA/PyBbXSkubWFwKCh1bml0OiBTZW1hbnRpY0J1aWxkQ2xhc3MpID0+ICh7XG4gICAgICBrZXk6IHVuaXQua2V5LFxuICAgICAgbmFtZTogdGhpcy5fZGlzcGxheU5hbWUodW5pdC5tb2RlbCwgdW5pdC5rZXkpLFxuICAgICAgaGFzVGFibGU6IGZhbHNlLFxuICAgICAgZW50aXR5OiBudWxsLFxuICAgICAgbW9kZWw6IHVuaXQubW9kZWwsXG4gICAgICBmdW5jdGlvbkNvdW50OiB1bml0LmZ1bmN0aW9uQ291bnQsXG4gICAgfSkpO1xuXG4gICAgcmV0dXJuIFsuLi5lbnRpdGllcywgLi4uY2xhc3Nlc11cbiAgICAgIC5zb3J0KChhLCBiKSA9PiBhLm5hbWUubG9jYWxlQ29tcGFyZShiLm5hbWUpKTtcbiAgfSk7XG5cbiAgLy8gVGhlIGZpbHRlciBtYXRjaGVzIHRoZSBkaXNwbGF5IG5hbWUsIHRoZSBjbGFzcyBhbmQgdGhlIGVudGl0eSBrZXksIHNvXG4gIC8vIGh1bnRpbmcgYnkgYW55IG9mIHRoZSB0aHJlZSB3b3Jrcy5cbiAgcHVibGljIHJlYWRvbmx5IGZpbHRlcmVkVW5pdHMgPSBjb21wdXRlZDxTZW1hbnRpY1VuaXRWaWV3W10+KCgpID0+IHtcbiAgICBjb25zdCBmaWx0ZXIgPSB0aGlzLmZpbHRlcigpLnRyaW0oKS50b0xvd2VyQ2FzZSgpO1xuICAgIGlmICghZmlsdGVyKSB7XG4gICAgICByZXR1cm4gdGhpcy51bml0cygpO1xuICAgIH1cblxuICAgIHJldHVybiB0aGlzLnVuaXRzKCkuZmlsdGVyKCh1bml0KSA9PlxuICAgICAgYCR7dW5pdC5uYW1lfSAke3VuaXQubW9kZWwgPz8gJyd9ICR7dW5pdC5rZXl9YC50b0xvd2VyQ2FzZSgpLmluY2x1ZGVzKGZpbHRlcikpO1xuICB9KTtcblxuICAvLyBUaGUgQ292ZXJhZ2UgbGluZS4gQXNzZW1ibGVkIGhlcmUgYmVjYXVzZSB0aGUgY2F0YWxvZyBwYXJ0cyBkcm9wIG91dFxuICAvLyBlbnRpcmVseSBvbiBhIHByZS1jYXRhbG9nIGFydGlmYWN0LCB3aGljaCByZWFkcyBiYWRseSBhcyB0ZW1wbGF0ZSBicmFuY2hlcy5cbiAgcHVibGljIHJlYWRvbmx5IGNvdmVyYWdlID0gY29tcHV0ZWQ8c3RyaW5nPigoKSA9PiB7XG4gICAgY29uc3QgZGV0YWlsID0gdGhpcy5zdGF0dXMoKT8uZGV0YWlsO1xuICAgIGlmICghZGV0YWlsKSB7XG4gICAgICByZXR1cm4gJyc7XG4gICAgfVxuXG4gICAgY29uc3QgcGFydHMgPSBbYCR7ZGV0YWlsLmVudGl0eUNvdW50fSBlbnRpdGllc2AsIGAke2RldGFpbC5jbGFzc0NvdW50fSBjb2RlIGNsYXNzZXNgXTtcblxuICAgIGlmICh0aGlzLmhhc0NhdGFsb2coKSkge1xuICAgICAgcGFydHMucHVzaChkZXRhaWwudW5saW5rZWRKdW5jdGlvbkNvdW50XG4gICAgICAgID8gYCR7ZGV0YWlsLmp1bmN0aW9uQ291bnR9IGp1bmN0aW9ucyAoJHtkZXRhaWwudW5saW5rZWRKdW5jdGlvbkNvdW50fSBub3QgbGlua2VkKWBcbiAgICAgICAgOiBgJHtkZXRhaWwuanVuY3Rpb25Db3VudH0ganVuY3Rpb25zYCk7XG4gICAgfVxuXG4gICAgcGFydHMucHVzaChgJHtkZXRhaWwuZnVuY3Rpb25Db3VudH0gY29kZSBmdW5jdGlvbnNgKTtcblxuICAgIGlmICh0aGlzLmhhc0NhdGFsb2coKSkge1xuICAgICAgcGFydHMucHVzaChgJHtkZXRhaWwuZXhjbHVkZWRDb3VudH0gdGFibGVzIGV4Y2x1ZGVkYCk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHBhcnRzLmpvaW4oJyDCtyAnKTtcbiAgfSk7XG5cbiAgLy8gVGhlIHRhYmxlIGNhdGFsb2csIG9yIFtdIHdoZW4gdGhlIHN0YXR1cyBoYXNuJ3QgbG9hZGVkIG9yIHRoZSBhcnRpZmFjdFxuICAvLyBwcmVkYXRlcyBpdC5cbiAgcHJpdmF0ZSByZWFkb25seSBfdGFibGVzID0gY29tcHV0ZWQ8U2VtYW50aWNCdWlsZFRhYmxlW10+KCgpID0+IHRoaXMuc3RhdHVzKCk/LmRldGFpbD8udGFibGVzID8/IFtdKTtcblxuICAvLyBHdWFyZHMgdGhlIG91dGNvbWUgbWVzc2FnZSB0byBmaXJlIGV4YWN0bHkgb25jZSBwZXIgcnVuIOKAlCB3aGV0aGVyIHRoZSBzdHJlYW1cbiAgLy8gY29tcGxldGVzIChidWlsZCBmaW5pc2hlZCwgcG9zc2libHkgZmFpbGVkKSBvciBlcnJvcnMgb3V0cmlnaHQuXG4gIHByaXZhdGUgX2J1aWxkRmluYWxpemVkID0gZmFsc2U7XG5cbiAgcHJpdmF0ZSByZWFkb25seSBfZGlhbG9nID0gaW5qZWN0KE1hdERpYWxvZyk7XG4gIHByaXZhdGUgcmVhZG9ubHkgX3JlcG9ydERhdGEgPSBpbmplY3QoUmVwb3J0RGF0YSk7XG4gIHByaXZhdGUgcmVhZG9ubHkgX3Byb2Nlc3MgPSBpbmplY3QoRnNQcm9jZXNzKTtcbiAgcHJpdmF0ZSByZWFkb25seSBfcHJvbXB0ID0gaW5qZWN0KEZzUHJvbXB0KTtcbiAgcHJpdmF0ZSByZWFkb25seSBfbWVzc2FnZSA9IGluamVjdChGc01lc3NhZ2UpO1xuICBwcml2YXRlIHJlYWRvbmx5IF9kZXN0cm95UmVmID0gaW5qZWN0KERlc3Ryb3lSZWYpO1xuXG4gIGNvbnN0cnVjdG9yKCkge1xuICAgIHRoaXMuX2luaXQoKTtcbiAgfVxuXG4gIC8vIENvbmZpcm0gYmVmb3JlIGtpY2tpbmcgb2ZmIGEgYnVpbGQg4oCUIGEgcmVidWlsZCByZXBsYWNlcyB0aGUgY3VycmVudFxuICAvLyBzZW1hbnRpYyBkYXRhYmFzZSwgc28gaXQgc2hvdWxkIG5ldmVyIGZpcmUgb24gYSBzdHJheSBjbGljay5cbiAgcHVibGljIGJ1aWxkKCk6IHZvaWQge1xuICAgIGNvbnN0IHJlYnVpbGQgPSB0aGlzLnJlYnVpbGQoKTtcblxuICAgIHRoaXMuX3Byb21wdC5jb25maXJtKHtcbiAgICAgIHRpdGxlOiByZWJ1aWxkID8gJ1JlYnVpbGQgc2VtYW50aWMgZGF0YWJhc2UnIDogJ0J1aWxkIHNlbWFudGljIGRhdGFiYXNlJyxcbiAgICAgIHRlbXBsYXRlOiByZWJ1aWxkXG4gICAgICAgID8gJ1JlYnVpbGQgdGhlIHNlbWFudGljIGRhdGFiYXNlPyBJdCBydW5zIGluIHRoZSBiYWNrZ3JvdW5kIGFuZCByZXBsYWNlcyB0aGUgY3VycmVudCBvbmUgd2hlbiBpdCBmaW5pc2hlcy4nXG4gICAgICAgIDogJ0J1aWxkIHRoZSBzZW1hbnRpYyBkYXRhYmFzZT8gSXQgcnVucyBpbiB0aGUgYmFja2dyb3VuZC4nLFxuICAgICAgY29tbWl0TGFiZWw6IHJlYnVpbGQgPyAnUmVidWlsZCcgOiAnQnVpbGQnLFxuICAgIH0pXG4gICAgICAucGlwZSh0YWtlVW50aWxEZXN0cm95ZWQodGhpcy5fZGVzdHJveVJlZikpXG4gICAgICAuc3Vic2NyaWJlKCgpID0+IHRoaXMuX3J1bkJ1aWxkKCkpO1xuICB9XG5cbiAgcHVibGljIHN0b3BCdWlsZCgpOiB2b2lkIHtcbiAgICB0aGlzLl9wcm9tcHQuY29uZmlybSh7XG4gICAgICB0aXRsZTogJ1N0b3AgYnVpbGQnLFxuICAgICAgdGVtcGxhdGU6ICdTdG9wIHRoZSBydW5uaW5nIGJ1aWxkPyBUaGUgY3VycmVudCBzZW1hbnRpYyBkYXRhYmFzZSBzdGF5cyBpbiBwbGFjZSB1bnRpbCBhIGJ1aWxkIGZpbmlzaGVzLicsXG4gICAgICBjb21taXRMYWJlbDogJ1N0b3AnLFxuICAgIH0pXG4gICAgICAucGlwZShcbiAgICAgICAgc3dpdGNoTWFwKCgpID0+IHRoaXMuX3JlcG9ydERhdGEuc2VtYW50aWNCdWlsZFN0b3AoKSksXG4gICAgICAgIHRha2VVbnRpbERlc3Ryb3llZCh0aGlzLl9kZXN0cm95UmVmKSxcbiAgICAgIClcbiAgICAgIC5zdWJzY3JpYmUoKCkgPT4ge1xuICAgICAgICB0aGlzLmJ1aWxkaW5nLnNldChmYWxzZSk7XG4gICAgICAgIHRoaXMuX21lc3NhZ2Uuc3VjY2VzcygnU3RvcHBpbmcgdGhlIGJ1aWxk4oCmJyk7XG4gICAgICAgIHRoaXMuX3JlZnJlc2hTdGF0dXMoKTtcbiAgICAgIH0pO1xuICB9XG5cbiAgLy8gUnVuIHRoZSBzZW1hbnRpYy1kYXRhYmFzZSBidWlsZC4gVGhlIGxpdmUgZmVlZCBzdHJlYW1zIGludG8gdGhlIEZzUHJvY2Vzc1xuICAvLyBkb2NrIChib3R0b20tcmlnaHQpLCB3aG9zZSBzdWJzY3JpcHRpb24gc3Vydml2ZXMgdGhpcyBkaWFsb2cgY2xvc2luZyDigJQgc29cbiAgLy8gZGlzbWlzc2luZyB0aGUgZGlhbG9nIG5ldmVyIGludGVycnVwdHMgYSBydW5uaW5nIGJ1aWxkLlxuICBwcml2YXRlIF9ydW5CdWlsZCgpOiB2b2lkIHtcbiAgICB0aGlzLmJ1aWxkaW5nLnNldCh0cnVlKTtcbiAgICB0aGlzLl9idWlsZEZpbmFsaXplZCA9IGZhbHNlO1xuXG4gICAgY29uc3QgdGFyZ2V0JCA9IHRoaXMuX3JlcG9ydERhdGEuc2VtYW50aWNCdWlsZCgpXG4gICAgICAucGlwZShcbiAgICAgICAgLy8gQSBoYXJkIHN0cmVhbS90cmFuc3BvcnQgZmFpbHVyZSAodGhlIGJ1aWxkIGNvdWxkbid0IGV2ZW4gc3RhcnQpXG4gICAgICAgIC8vIGZpbmFsaXplcyBoZXJlIOKAlCBjb21wbGV0ZWQkIHdvbid0IGZpcmUgaW4gdGhhdCBjYXNlLlxuICAgICAgICB0YXAoeyBlcnJvcjogKGVycm9yKSA9PiB0aGlzLl9maW5hbGl6ZUJ1aWxkKGVycm9yKSB9KSxcbiAgICAgICAgZmlsdGVyKChldmVudCkgPT5cbiAgICAgICAgICBldmVudD8udHlwZSA9PT0gU3RyZWFtRXZlbnRUeXBlLkRhdGFcbiAgICAgICAgICAmJiBTZW1hbnRpY0RhdGFiYXNlQ29tcG9uZW50LkxPR19LSU5EUy5pbmNsdWRlcyhldmVudC5kYXRhPy5raW5kKVxuICAgICAgICAgICYmIHR5cGVvZiBldmVudC5kYXRhLmxpbmUgPT09ICdzdHJpbmcnKSxcbiAgICAgICAgbWFwKChldmVudCkgPT4gZXZlbnQuZGF0YS5saW5lIGFzIHN0cmluZyksXG4gICAgICApO1xuXG4gICAgdGhpcy5fcHJvY2Vzc1xuICAgICAgLnJ1bignU2VtYW50aWMgZGF0YWJhc2UgYnVpbGQnLCB0YXJnZXQkKVxuICAgICAgLmNvbXBsZXRlZCRcbiAgICAgIC5waXBlKFxuICAgICAgICB0YWtlKDEpLFxuICAgICAgICB0YWtlVW50aWxEZXN0cm95ZWQodGhpcy5fZGVzdHJveVJlZiksXG4gICAgICApXG4gICAgICAuc3Vic2NyaWJlKCgpID0+IHRoaXMuX2ZpbmFsaXplQnVpbGQobnVsbCkpO1xuICB9XG5cbiAgLyoqXG4gICAqIFdyYXAgdXAgb25lIGJ1aWxkIHJ1biBleGFjdGx5IG9uY2UuIE9uIGEgaGFyZCBzdHJlYW0gZXJyb3IsIHN1cmZhY2UgdGhlXG4gICAqIGFjdHVhbCBzZXJ2ZXItc2lkZSByZWFzb24gcHVsbGVkIG9mZiB0aGUgYnJva2VuIHN0cmVhbSDigJQgdGhlIGdlbmVyaWNcbiAgICogXCJjb3VsZCBub3QgcnVuXCIgbGluZSBvbmx5IHdoZW4gdGhlIGZhaWx1cmUgY2FycmllZCBubyBzZXJ2ZXIgdGV4dCBhdCBhbGw7XG4gICAqIG90aGVyd2lzZSByZWZyZXNoIHRoZSBzdGF0dXMgYW5kIGFubm91bmNlIGhvdyB0aGUgYnVpbGQgYWN0dWFsbHkgZW5kZWQuIEFcbiAgICogZmFpbGVkIGJ1aWxkIGFsd2F5cyBuYW1lcyBpdHMgcmVhc29uIG9uIHRoZSByb3cgKHRoZSBiYWNrZW5kIHJlY29yZHMgb25lIGZvclxuICAgKiBldmVyeSB3YXkgYSBydW4gY2FuIGRpZSwgZmF0YWxzIGluY2x1ZGVkKSwgYW5kIHRoYXQgcmVhc29uIG11c3Qgc3VyZmFjZVxuICAgKiBpbnN0ZWFkIG9mIHRoZSBydW4gc2lsZW50bHkgZG9pbmcgbm90aGluZy5cbiAgICovXG4gIHByaXZhdGUgX2ZpbmFsaXplQnVpbGQoc3RyZWFtRXJyb3I6IHVua25vd24pOiB2b2lkIHtcbiAgICBpZiAodGhpcy5fYnVpbGRGaW5hbGl6ZWQpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgdGhpcy5fYnVpbGRGaW5hbGl6ZWQgPSB0cnVlO1xuXG4gICAgdGhpcy5idWlsZGluZy5zZXQoZmFsc2UpO1xuXG4gICAgaWYgKHN0cmVhbUVycm9yKSB7XG4gICAgICBjb25zdCBkZXRhaWwgPSB0aGlzLl9zdHJlYW1FcnJvckRldGFpbChzdHJlYW1FcnJvcik7XG5cbiAgICAgIHRoaXMuX21lc3NhZ2UuZXJyb3IoZGV0YWlsXG4gICAgICAgID8gYFRoZSBzZW1hbnRpYyBkYXRhYmFzZSBidWlsZCBmYWlsZWQg4oCUICR7ZGV0YWlsfWBcbiAgICAgICAgOiAnVGhlIHNlbWFudGljIGRhdGFiYXNlIGJ1aWxkIGNvdWxkIG5vdCBydW4g4oCUIHRoZSBjb25uZWN0aW9uIHRvIHRoZSBzZXJ2ZXIgd2FzIGxvc3QuJyk7XG4gICAgICB0aGlzLl9yZWZyZXNoU3RhdHVzKCk7XG5cbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICB0aGlzLl9sb2FkU3RhdHVzKClcbiAgICAgIC5zdWJzY3JpYmUoKHN0YXR1czogU2VtYW50aWNCdWlsZFN0YXR1cykgPT4gdGhpcy5fYW5ub3VuY2VPdXRjb21lKHN0YXR1cykpO1xuICB9XG5cbiAgLyoqXG4gICAqIFRoZSByZWFsIHJlYXNvbiBhIGJyb2tlbiBidWlsZCBzdHJlYW0gYnJva2UsIGZyb20gd2hhdCB0aGUgc2VydmVyIGFjdHVhbGx5XG4gICAqIHNlbnQuIEEgc3RydWN0dXJlZCBlcnJvciBmcmFtZSBhcnJpdmVzIGFzIHttZXNzYWdlfSBvbiB0aGUgZXJyb3IgYm9keTsgYVxuICAgKiBtaWQtc3RyZWFtIGNyYXNoIGR1bXBzIHJhdyB0ZXh0IGludG8gdGhlIHN0cmVhbSAodGhlIHN0cmVhbSBpbnRlcmNlcHRvclxuICAgKiBoYW5kcyBpdCBiYWNrIGFzIHN0YXR1c1RleHQpLCB3aGVyZSB0aGUgZnJhbWVzIGFyZSBKU09OIGxpbmVzIGFuZCB0aGVcbiAgICogZmlyc3Qgbm9uLUpTT04gbGluZXMgYXJlIHRoZSBlcnJvciBhbmQgaXRzIGxvY2F0aW9uLiAnJyB3aGVuIHRoZSBmYWlsdXJlXG4gICAqIGNhcnJpZWQgbm8gc2VydmVyIHRleHQgYXQgYWxsICh0cmFuc3BvcnQgZG93biAvIHNlcnZlciB1bnJlYWNoYWJsZSkuXG4gICAqL1xuICBwcml2YXRlIF9zdHJlYW1FcnJvckRldGFpbChzdHJlYW1FcnJvcjogdW5rbm93bik6IHN0cmluZyB7XG4gICAgY29uc3QgZXJyb3IgPSBzdHJlYW1FcnJvciBhcyB7IGVycm9yPzogeyBtZXNzYWdlPzogc3RyaW5nIH07IHN0YXR1c1RleHQ/OiBzdHJpbmcgfTtcblxuICAgIGlmIChlcnJvcj8uZXJyb3I/Lm1lc3NhZ2UpIHtcbiAgICAgIHJldHVybiBlcnJvci5lcnJvci5tZXNzYWdlO1xuICAgIH1cblxuICAgIGNvbnN0IHN0YXR1c1RleHQgPSBlcnJvcj8uc3RhdHVzVGV4dDtcbiAgICBpZiAoIXN0YXR1c1RleHQgfHwgc3RhdHVzVGV4dCA9PT0gJ1Vua25vd24gRXJyb3InKSB7XG4gICAgICByZXR1cm4gJyc7XG4gICAgfVxuXG4gICAgY29uc3QgbGluZXMgPSBzdGF0dXNUZXh0LnNwbGl0KCdcXG4nKVxuICAgICAgLm1hcCgobGluZSkgPT4gbGluZS50cmltKCkpXG4gICAgICAuZmlsdGVyKChsaW5lKSA9PiB7XG4gICAgICAgIGlmICghbGluZSkge1xuICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuXG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgSlNPTi5wYXJzZShsaW5lKTtcblxuICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfSBjYXRjaCB7XG4gICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuXG4gICAgcmV0dXJuIGxpbmVzLnNsaWNlKDAsIDIpLmpvaW4oJyDigJQgJykuc3Vic3RyaW5nKDAsIDMwMCk7XG4gIH1cblxuICAvKipcbiAgICogVGVsbCB0aGUgb3BlcmF0b3IgaG93IHRoZSBidWlsZCBlbmRlZDogYSBmYWlsZWQvc3RvcHBlZCBidWlsZCBzdXJmYWNlcyBpdHNcbiAgICogcmVhc29uIChzbyBhbiBBSSBjb25uZWN0aW9uIHByb2JsZW0gaXMgbmV2ZXIgc2lsZW50KSwgYSBjb21wbGV0ZWQgb25lXG4gICAqIGNvbmZpcm1zIHN1Y2Nlc3MuXG4gICAqL1xuICBwcml2YXRlIF9hbm5vdW5jZU91dGNvbWUoc3RhdHVzOiBTZW1hbnRpY0J1aWxkU3RhdHVzKTogdm9pZCB7XG4gICAgY29uc3QgYnVpbGQgPSBzdGF0dXM/LmJ1aWxkO1xuICAgIGlmIChidWlsZD8uc3RhdGUgPT09ICdGJyB8fCBidWlsZD8uc3RhdGUgPT09ICdLJykge1xuICAgICAgdGhpcy5fbWVzc2FnZS5lcnJvcihidWlsZC5tZXNzYWdlIHx8ICdUaGUgc2VtYW50aWMgZGF0YWJhc2UgYnVpbGQgZGlkIG5vdCBmaW5pc2guJyk7XG4gICAgfSBlbHNlIGlmIChidWlsZD8uc3RhdGUgPT09ICdDJykge1xuICAgICAgdGhpcy5fbWVzc2FnZS5zdWNjZXNzKCdTZW1hbnRpYyBkYXRhYmFzZSBidWlsZCBjb21wbGV0ZS4nKTtcbiAgICB9XG4gIH1cblxuICBwdWJsaWMgcGVuZGluZ0NvbG9yKCk6IHN0cmluZyB7XG4gICAgcmV0dXJuIFNlbWFudGljRGF0YWJhc2VDb21wb25lbnQuUEVORElOR19DT0xPUjtcbiAgfVxuXG4gIC8qKlxuICAgKiBUaGUgYnVpbGQgc3RhZ2VzIHRoaXMgcm93IGlzIHN0aWxsIG93ZWQsIG9yIFtdIHdoZW4gaXQgaXMgZnVsbHkgYnVpbHQuIEFcbiAgICogc3RvcHBlZCBvciBpbnRlcnJ1cHRlZCBidWlsZCBpcyB0aGUgb25seSB3YXkgdG8gZ2V0IGEgbm9uLWVtcHR5IGxpc3QuXG4gICAqL1xuICBwdWJsaWMgcGVuZGluZ1N0YWdlcyh1bml0OiBTZW1hbnRpY1VuaXRWaWV3KTogc3RyaW5nW10ge1xuICAgIGNvbnN0IHN0YWdlcyA9IHVuaXQuZW50aXR5Py5zdGFnZXM7XG5cbiAgICByZXR1cm4gc3RhZ2VzXG4gICAgICA/IE9iamVjdC5rZXlzKHN0YWdlcykuZmlsdGVyKChzdGFnZSkgPT4gc3RhZ2VzW3N0YWdlXSAhPT0gJ2RvbmUnKVxuICAgICAgOiBbXTtcbiAgfVxuXG4gIHB1YmxpYyBzZXRGaWx0ZXIodmFsdWU6IHN0cmluZyk6IHZvaWQge1xuICAgIHRoaXMuZmlsdGVyLnNldCh2YWx1ZSk7XG4gIH1cblxuICAvKipcbiAgICogT3BlbiB0aGUgY2hpbGQgZGlhbG9nIGxpc3Rpbmcgb25lIGdyb3VwIG9mIGEgdW5pdCdzIGNhY2hlZCBmdW5jdGlvbnMg4oCUIGFuXG4gICAqIGVudGl0eSdzIG1vZGVsIG9yIGhhbmRsZXIgY2xhc3MsIG9yIGEgc3RhbmRhbG9uZSBjbGFzcydzIGNvZGUuIFRoZSBkaWFsb2dcbiAgICogZmV0Y2hlcyBmcmVzaCBvbiBvcGVuLCBzbyB0aGUgdGFiIG5ldmVyIGhvbGRzIGZ1bmN0aW9uIHBheWxvYWRzLlxuICAgKi9cbiAgcHVibGljIG9wZW5GdW5jdGlvbnModW5pdDogU2VtYW50aWNVbml0Vmlldywgc291cmNlOiBTZW1hbnRpY0Z1bmN0aW9uU291cmNlKTogdm9pZCB7XG4gICAgdGhpcy5fZGlhbG9nLm9wZW4oRW50aXR5RnVuY3Rpb25zQ29tcG9uZW50LCB7XG4gICAgICB3aWR0aDogJzcwMHB4JyxcbiAgICAgIG1heFdpZHRoOiAnOTV2dycsXG4gICAgICBtYXhIZWlnaHQ6ICc4NXZoJyxcbiAgICAgIGF1dG9Gb2N1czogZmFsc2UsXG4gICAgICBkYXRhOiB7IGVudGl0eUtleTogdW5pdC5rZXksIHNvdXJjZSB9LFxuICAgIH0pO1xuICB9XG5cbiAgcHJpdmF0ZSBfaW5pdCgpOiB2b2lkIHtcbiAgICB0aGlzLl9yZWZyZXNoU3RhdHVzKCk7XG4gIH1cblxuICAvKipcbiAgICogV2hhdCBhIHJlYWRlciByZWNvZ25pemVzIHRoZSB1bml0IGJ5OiBpdHMgY2xhc3MncyBzaG9ydCBuYW1lLCBtaW51cyB0aGVcbiAgICogYE1vZGVsYCBzdWZmaXggdGhhdCBldmVyeSBtb2RlbCBjYXJyaWVzIGFuZCBub25lIG9mIHRoZW0gYXJlIGRpc3Rpbmd1aXNoZWRcbiAgICogYnkuIEZhbGxzIGJhY2sgdG8gdGhlIGNhY2hlIGtleSBmb3IgYSB1bml0IHdob3NlIGNsYXNzIGNvdWxkIG5vdCBiZVxuICAgKiByZXNvbHZlZCwgc28gYSByb3cgbmV2ZXIgcmVuZGVycyBuYW1lbGVzcy5cbiAgICovXG4gIHByaXZhdGUgX2Rpc3BsYXlOYW1lKG1vZGVsOiBzdHJpbmcgfCBudWxsLCBrZXk6IHN0cmluZyk6IHN0cmluZyB7XG4gICAgaWYgKCFtb2RlbCkge1xuICAgICAgcmV0dXJuIGtleTtcbiAgICB9XG5cbiAgICBjb25zdCBzaG9ydE5hbWUgPSBtb2RlbC5zcGxpdCgnXFxcXCcpLnBvcCgpO1xuXG4gICAgcmV0dXJuIHNob3J0TmFtZS5sZW5ndGggPiBTZW1hbnRpY0RhdGFiYXNlQ29tcG9uZW50Lk5BTUVfU1VGRklYLmxlbmd0aFxuICAgICAgJiYgc2hvcnROYW1lLmVuZHNXaXRoKFNlbWFudGljRGF0YWJhc2VDb21wb25lbnQuTkFNRV9TVUZGSVgpXG4gICAgICA/IHNob3J0TmFtZS5zbGljZSgwLCAtU2VtYW50aWNEYXRhYmFzZUNvbXBvbmVudC5OQU1FX1NVRkZJWC5sZW5ndGgpXG4gICAgICA6IHNob3J0TmFtZTtcbiAgfVxuXG4gIHByaXZhdGUgX3JlZnJlc2hTdGF0dXMoKTogdm9pZCB7XG4gICAgdGhpcy5fbG9hZFN0YXR1cygpXG4gICAgICAuc3Vic2NyaWJlKCk7XG4gIH1cblxuICAvLyBGZXRjaCB0aGUgc3RhdHVzIGludG8gdGhlIHRhYi4gQSBmYWlsdXJlIGZsYWdzIHN0YXR1c0Vycm9yIGFuZCBjb21wbGV0ZXNcbiAgLy8gcXVpZXRseSwgc28gdGhlIHRhYiBzZXR0bGVzIGFuZCBjYWxsZXJzIG5ldmVyIHNlZSB0aGUgZXJyb3IuXG4gIHByaXZhdGUgX2xvYWRTdGF0dXMoKTogT2JzZXJ2YWJsZTxTZW1hbnRpY0J1aWxkU3RhdHVzPiB7XG4gICAgcmV0dXJuIHRoaXMuX3JlcG9ydERhdGEuc2VtYW50aWNCdWlsZFN0YXR1cygpXG4gICAgICAucGlwZShcbiAgICAgICAgdGFwKChzdGF0dXM6IFNlbWFudGljQnVpbGRTdGF0dXMpID0+IHtcbiAgICAgICAgICB0aGlzLnN0YXR1c0Vycm9yLnNldChmYWxzZSk7XG4gICAgICAgICAgdGhpcy5zdGF0dXMuc2V0KHN0YXR1cyk7XG4gICAgICAgIH0pLFxuICAgICAgICBjYXRjaEVycm9yKCgpID0+IHtcbiAgICAgICAgICB0aGlzLnN0YXR1c0Vycm9yLnNldCh0cnVlKTtcblxuICAgICAgICAgIHJldHVybiBFTVBUWTtcbiAgICAgICAgfSksXG4gICAgICAgIHRha2VVbnRpbERlc3Ryb3llZCh0aGlzLl9kZXN0cm95UmVmKSxcbiAgICAgICk7XG4gIH1cbn1cbiIsIjxkaXYgY2xhc3M9XCJmcy1jb2x1bW4gdGFiLWJvZHlcIj5cbiAgPHAgY2xhc3M9XCJoaW50XCI+XG4gICAgVGhlIHNlbWFudGljIGRhdGFiYXNlIGlzIHdoYXQgdGhlIHJlcG9ydCBBSSB1c2VzIHRvIHVuZGVyc3RhbmQgeW91ciBkYXRhIOKAlFxuICAgIHRhYmxlcywgcmVsYXRpb25zaGlwcyBhbmQgdGhlIGNhbGN1bGF0aW9ucyBpbiBjb2RlLiBSZWJ1aWxkIGl0IGFmdGVyXG4gICAgc2lnbmlmaWNhbnQgYXBwbGljYXRpb24gdXBkYXRlcy4gVGhlIGJ1aWxkIHJ1bnMgaW4gdGhlIGJhY2tncm91bmQ7IHByb2dyZXNzXG4gICAgYXBwZWFycyBpbiB0aGUgZG9jayBhdCB0aGUgYm90dG9tIHJpZ2h0IGFuZCB0aGlzIGRpYWxvZyBjYW4gYmUgY2xvc2VkIHdoaWxlXG4gICAgaXQgcnVucy5cbiAgPC9wPlxuXG4gIDwhLS0gQSBmYWlsZWQgc3RhdHVzIGxvYWQgc2V0dGxlcyB0aGUgc2tlbGV0b24gdG9vLCBzbyB0aGUgdGFiIHNheXMgd2hhdFxuICAgICAgIGhhcHBlbmVkIGluc3RlYWQgb2YgbG9hZGluZyBmb3JldmVyLiAtLT5cbiAgQGlmIChzdGF0dXNFcnJvcigpKSB7XG4gICAgPGZzLW1lc3NhZ2Utd2FybmluZz5cbiAgICAgIFRoZSBidWlsZCBzdGF0dXMgY291bGQgbm90IGJlIGxvYWRlZCwgc28gdGhlIGxhc3QgYnVpbGQgYW5kIGl0cyBjb3ZlcmFnZVxuICAgICAgY2FuJ3QgYmUgc2hvd24uIFlvdSBjYW4gc3RpbGwgcnVuIGEgYnVpbGQuXG4gICAgPC9mcy1tZXNzYWdlLXdhcm5pbmc+XG4gIH1cblxuICA8ZGl2ICpmc1NrZWxldG9uPVwic3RhdHVzKCkgfHwgc3RhdHVzRXJyb3IoKVwiPlxuICAgIEBpZiAoc3RhdHVzKCk7IGFzIGJ1aWxkU3RhdHVzKSB7XG4gICAgICA8ZGl2IGNsYXNzPVwiYnVpbGQtc3RhdHVzXCI+XG4gICAgICAgIEBpZiAoYnVpbGRTdGF0dXMuZGV0YWlsLmdlbmVyYXRlZEF0KSB7XG4gICAgICAgICAgPGRpdiBjbGFzcz1cInN0YXRcIj5cbiAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwibGFiZWxcIj5MYXN0IGJ1aWx0PC9zcGFuPlxuICAgICAgICAgICAgPGZzLWRhdGVcbiAgICAgICAgICAgICAgICBbZGF0ZV09XCJidWlsZFN0YXR1cy5kZXRhaWwuZ2VuZXJhdGVkQXRcIlxuICAgICAgICAgICAgICAgIGZvcm1hdD1cImRhdGUtdGltZVwiPlxuICAgICAgICAgICAgPC9mcy1kYXRlPlxuICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgIDxkaXYgY2xhc3M9XCJzdGF0XCI+XG4gICAgICAgICAgICA8c3BhbiBjbGFzcz1cImxhYmVsXCI+Q292ZXJhZ2U8L3NwYW4+XG4gICAgICAgICAgICA8c3Bhbj57eyBjb3ZlcmFnZSgpIH19PC9zcGFuPlxuICAgICAgICAgIDwvZGl2PlxuICAgICAgICB9IEBlbHNlIHtcbiAgICAgICAgICA8ZnMtbWVzc2FnZS13YXJuaW5nPlxuICAgICAgICAgICAgVGhlIHNlbWFudGljIGRhdGFiYXNlIGhhcyBub3QgYmVlbiBidWlsdCB5ZXQg4oCUIHRoZSByZXBvcnQgQUkgY2FuJ3RcbiAgICAgICAgICAgIGFuc3dlciBkYXRhIHF1ZXN0aW9ucyB1bnRpbCBpdCBpcy4gUnVuIHRoZSBmaXJzdCBidWlsZC5cbiAgICAgICAgICA8L2ZzLW1lc3NhZ2Utd2FybmluZz5cbiAgICAgICAgfVxuICAgICAgICBAaWYgKGJ1aWxkU3RhdHVzLmJ1aWxkKSB7XG4gICAgICAgICAgPGRpdiBjbGFzcz1cInN0YXRcIj5cbiAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwibGFiZWxcIj5MYXN0IGJ1aWxkIHJ1bjwvc3Bhbj5cbiAgICAgICAgICAgIDxzcGFuPlxuICAgICAgICAgICAgICB7eyBidWlsZFN0YXRlTGFiZWwoKSB9fVxuICAgICAgICAgICAgICBAaWYgKGJ1aWxkU3RhdHVzLmJ1aWxkLm1lc3NhZ2UpIHtcbiAgICAgICAgICAgICAgICDigJQge3sgYnVpbGRTdGF0dXMuYnVpbGQubWVzc2FnZSB9fVxuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICA8L3NwYW4+XG4gICAgICAgICAgPC9kaXY+XG4gICAgICAgIH1cblxuICAgICAgICA8IS0tIEV2ZXJ5dGhpbmcgYWJvdmUgaXMgdHJ1ZSBhYm91dCB3aGF0IHdhcyBwdWJsaXNoZWQsIGFuZCBvbiBpdHMgb3duIGl0XG4gICAgICAgICAgICAgcmVhZHMgYXMgYSBmaW5pc2hlZCBidWlsZDogdGhlIHN0cnVjdHVyYWwgaGFsZiBwdWJsaXNoZXMgQkVGT1JFIHRoZVxuICAgICAgICAgICAgIEFJIGZ1bmN0aW9uIHBhc3MsIHNvIGEgcnVuIHRoYXQgZGllZCBpbiB0aGF0IHBhc3Mgc3RpbGwgc3RhbXBzIGFcbiAgICAgICAgICAgICBkYXRlIGFuZCBzdGlsbCBmaWxscyBpbiB0aGUgd2hvbGUgY292ZXJhZ2UgbGluZS4gVGhpcyBpcyB0aGUgb25seVxuICAgICAgICAgICAgIGxpbmUgdGhhdCBzYXlzIHRoZSBidWlsZCBuZXZlciBnb3QgdG8gdGhlIGVuZC4gLS0+XG4gICAgICAgIEBpZiAoYnVpbGRTdGF0dXMuZGV0YWlsLmdlbmVyYXRlZEF0ICYmICFidWlsZENvbXBsZXRlKCkpIHtcbiAgICAgICAgICA8ZnMtbWVzc2FnZS13YXJuaW5nPlxuICAgICAgICAgICAgVGhlIGxhc3QgYnVpbGQgZGlkIG5vdCBmaW5pc2gsIHNvIHRoaXMgc2VtYW50aWMgZGF0YWJhc2UgaXMgaW5jb21wbGV0ZSDigJRcbiAgICAgICAgICAgIHt7IGluY29tcGxldGVFbnRpdHlDb3VudCgpIH19IG9mIHt7IGJ1aWxkU3RhdHVzLmRldGFpbC5lbnRpdHlDb3VudCB9fVxuICAgICAgICAgICAgZW50aXRpZXMgaGF2ZSBubyBjb2RlLWZ1bmN0aW9uIGtub3dsZWRnZS4gVGhlIHJlcG9ydCBBSSBhbnN3ZXJzIGZyb20gd2hhdFxuICAgICAgICAgICAgaXMgaGVyZSBhbmQgY2Fubm90IHNlZSB0aGUgcmVzdC4gUmVidWlsZCB0byBjb21wbGV0ZSBpdC5cbiAgICAgICAgICA8L2ZzLW1lc3NhZ2Utd2FybmluZz5cbiAgICAgICAgfVxuICAgICAgPC9kaXY+XG5cbiAgICAgIDwhLS0gRXZlcnl0aGluZyB0aGUgYnVpbGQgcmVhZCwgaW4gb25lIGxpc3Q6IGVudGl0aWVzIChhIHRhYmxlICsgYSBtb2RlbCArXG4gICAgICAgICAgIGEgaGFuZGxlcikgYW5kIHN0YW5kYWxvbmUgY29kZSBjbGFzc2VzIChkb21haW4gbG9naWMgd2l0aCBubyB0YWJsZSkuXG4gICAgICAgICAgIFRoZSBBSSByZWFkcyBjb2RlIGZyb20gYm90aCwgc28gc3BsaXR0aW5nIHRoZW0gaW50byB0d28gc2VjdGlvbnNcbiAgICAgICAgICAgd291bGQgaGlkZSBoYWxmIG9mIHdoYXQgd2FzIGJ1aWx0LiBFYWNoIHJvdyBkcmlsbHMgaW50byBpdHMgc2hhcGUsXG4gICAgICAgICAgIGVudW0gdmFsdWVzLCBjb21wdXRlZCBmaWVsZHMgYW5kIGNhY2hlZCBmdW5jdGlvbiBjb3VudHMg4oCUIHRoZSBjb3VudHNcbiAgICAgICAgICAgbGluayBpbnRvIHRoZSBmdW5jdGlvbnMgZGlhbG9nLiAtLT5cbiAgICAgIEBpZiAodW5pdHMoKS5sZW5ndGgpIHtcbiAgICAgICAgPGgyPkluY2x1ZGVkICh7eyB1bml0cygpLmxlbmd0aCB9fSk8L2gyPlxuICAgICAgICA8ZGl2IGNsYXNzPVwic3ViaGVhZGluZ1wiPlxuICAgICAgICAgIEV2ZXJ5dGhpbmcgdGhlIHJlcG9ydCBBSSB3YXMgYnVpbHQgZnJvbS4gRW50aXRpZXMgY2FuIGJlIHF1ZXJpZWQ7XG4gICAgICAgICAgY29kZSBjbGFzc2VzIGFyZSBsb2dpYyBpdCByZWFkcyBhbmQgdHJhbnNsYXRlcyBpbnRvIFNRTC5cbiAgICAgICAgPC9kaXY+XG5cbiAgICAgICAgPGlucHV0XG4gICAgICAgICAgICBjbGFzcz1cInVuaXQtZmlsdGVyXCJcbiAgICAgICAgICAgIHR5cGU9XCJzZWFyY2hcIlxuICAgICAgICAgICAgcGxhY2Vob2xkZXI9XCJGaWx0ZXIgYnkgbmFtZSwgY2xhc3Mgb3Iga2V54oCmXCJcbiAgICAgICAgICAgIFt2YWx1ZV09XCJmaWx0ZXIoKVwiXG4gICAgICAgICAgICAoaW5wdXQpPVwic2V0RmlsdGVyKCRhbnkoJGV2ZW50LnRhcmdldCkudmFsdWUpXCI+XG5cbiAgICAgICAgPG1hdC1hY2NvcmRpb24gY2xhc3M9XCJlbnRpdGllc1wiPlxuICAgICAgICAgIEBmb3IgKHVuaXQgb2YgZmlsdGVyZWRVbml0cygpOyB0cmFjayB1bml0LmtleSkge1xuICAgICAgICAgICAgPG1hdC1leHBhbnNpb24tcGFuZWw+XG4gICAgICAgICAgICAgIDxtYXQtZXhwYW5zaW9uLXBhbmVsLWhlYWRlcj5cbiAgICAgICAgICAgICAgICA8bWF0LXBhbmVsLXRpdGxlPnt7IHVuaXQubmFtZSB9fTwvbWF0LXBhbmVsLXRpdGxlPlxuICAgICAgICAgICAgICAgIDxtYXQtcGFuZWwtZGVzY3JpcHRpb24+XG4gICAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwic3RhZ2UtY2hpcHNcIj5cbiAgICAgICAgICAgICAgICAgICAgQGlmICghdW5pdC5oYXNUYWJsZSkge1xuICAgICAgICAgICAgICAgICAgICAgIDxmcy1jaGlwIHNpemU9XCJ0aW55XCIgbWF0VG9vbHRpcD1cIkRvbWFpbiBsb2dpYyB3aXRoIG5vIHRhYmxlIOKAlCByZWFkLCBuZXZlciBxdWVyaWVkXCI+XG4gICAgICAgICAgICAgICAgICAgICAgICBjb2RlXG4gICAgICAgICAgICAgICAgICAgICAgPC9mcy1jaGlwPlxuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIDwhLS0gU2lsZW5jZSBtZWFucyBidWlsdC4gQSBjaGlwIGhlcmUgbWVhbnMgYW4gaW50ZXJydXB0ZWRcbiAgICAgICAgICAgICAgICAgICAgICAgICBidWlsZCBsZWZ0IHRoaXMgcm93IG93aW5nIGNvbnRlbnQuIC0tPlxuICAgICAgICAgICAgICAgICAgICBAZm9yIChzdGFnZSBvZiBwZW5kaW5nU3RhZ2VzKHVuaXQpOyB0cmFjayBzdGFnZSkge1xuICAgICAgICAgICAgICAgICAgICAgIDxmcy1jaGlwXG4gICAgICAgICAgICAgICAgICAgICAgICAgIHNpemU9XCJ0aW55XCJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgW2JhY2tncm91bmRDb2xvcl09XCJwZW5kaW5nQ29sb3IoKVwiXG4gICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yPVwiI2ZmZmZmZlwiXG4gICAgICAgICAgICAgICAgICAgICAgICAgIG1hdFRvb2x0aXA9XCJOZWVkcyBidWlsZGluZ1wiPlxuICAgICAgICAgICAgICAgICAgICAgICAge3sgc3RhZ2UgfX1cbiAgICAgICAgICAgICAgICAgICAgICA8L2ZzLWNoaXA+XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgICAgIDwvbWF0LXBhbmVsLWRlc2NyaXB0aW9uPlxuICAgICAgICAgICAgICA8L21hdC1leHBhbnNpb24tcGFuZWwtaGVhZGVyPlxuXG4gICAgICAgICAgICAgIDwhLS0gRGVmZXJyZWQ6IHRoZSBib2R5IG9ubHkgZXhpc3RzIG9uY2UgZXhwYW5kZWQuIC0tPlxuICAgICAgICAgICAgICA8bmctdGVtcGxhdGUgbWF0RXhwYW5zaW9uUGFuZWxDb250ZW50PlxuICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJlbnRpdHktZGV0YWlsXCI+XG4gICAgICAgICAgICAgICAgICBAaWYgKHVuaXQubW9kZWwpIHtcbiAgICAgICAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cInN0YXRcIj5cbiAgICAgICAgICAgICAgICAgICAgICA8c3BhbiBjbGFzcz1cImxhYmVsXCI+Q2xhc3M8L3NwYW4+XG4gICAgICAgICAgICAgICAgICAgICAgPHNwYW4+e3sgdW5pdC5tb2RlbCB9fTwvc3Bhbj5cbiAgICAgICAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICBAaWYgKHVuaXQuZW50aXR5OyBhcyBlbnRpdHkpIHtcbiAgICAgICAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cInN0YXRcIj5cbiAgICAgICAgICAgICAgICAgICAgICA8c3BhbiBjbGFzcz1cImxhYmVsXCI+VGFibGU8L3NwYW4+XG4gICAgICAgICAgICAgICAgICAgICAgPHNwYW4+e3sgZW50aXR5LnRhYmxlIH19PC9zcGFuPlxuICAgICAgICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgICAgICAgICAgPCEtLSBUaGUgaGFuZGxlIHRoZSByZXBvcnQgQUkgYWRkcmVzc2VzIHRoaXMgZW50aXR5IGJ5IGluXG4gICAgICAgICAgICAgICAgICAgICAgICAgZGVzY3JpYmVfZW50aXR5IC8gY29tcGlsZV9xdWVyeS4gLS0+XG4gICAgICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJzdGF0XCI+XG4gICAgICAgICAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJsYWJlbFwiPkVudGl0eSBrZXk8L3NwYW4+XG4gICAgICAgICAgICAgICAgICAgICAgPHNwYW4+e3sgZW50aXR5LmtleSB9fTwvc3Bhbj5cbiAgICAgICAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJzdGF0XCI+XG4gICAgICAgICAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJsYWJlbFwiPkNvbHVtbnM8L3NwYW4+XG4gICAgICAgICAgICAgICAgICAgICAgPHNwYW4+e3sgZW50aXR5LmNvbHVtbnMgfX08L3NwYW4+XG4gICAgICAgICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwic3RhdFwiPlxuICAgICAgICAgICAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwibGFiZWxcIj5SZWxhdGlvbnNoaXBzPC9zcGFuPlxuICAgICAgICAgICAgICAgICAgICAgIDxzcGFuPnt7IGVudGl0eS5yZWxhdGlvbnNoaXBzIH19PC9zcGFuPlxuICAgICAgICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgICAgICAgICAgQGlmIChlbnRpdHkuZW51bXMubGVuZ3RoKSB7XG4gICAgICAgICAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cInN0YXRcIj5cbiAgICAgICAgICAgICAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwibGFiZWxcIj5FbnVtZXJhdGlvbiB2YWx1ZXM8L3NwYW4+XG4gICAgICAgICAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwicGFpci1saXN0XCI+XG4gICAgICAgICAgICAgICAgICAgICAgICAgIEBmb3IgKGVudW1Db2x1bW4gb2YgZW50aXR5LmVudW1zOyB0cmFjayBlbnVtQ29sdW1uLmNvbHVtbikge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJwYWlyLXJvd1wiPlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJwYWlyLW5hbWVcIj57eyBlbnVtQ29sdW1uLmNvbHVtbiB9fTwvc3Bhbj5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxzcGFuPnt7IGVudW1Db2x1bW4udmFsdWVzLmpvaW4oJywgJykgfX08L3NwYW4+XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIEBpZiAoZW50aXR5LmNvbXB1dGVkRmllbGRzLmxlbmd0aCkge1xuICAgICAgICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJzdGF0XCI+XG4gICAgICAgICAgICAgICAgICAgICAgICA8c3BhbiBjbGFzcz1cImxhYmVsXCI+Q29tcHV0ZWQgZmllbGRzPC9zcGFuPlxuICAgICAgICAgICAgICAgICAgICAgICAgPHNwYW4+e3sgZW50aXR5LmNvbXB1dGVkRmllbGRzLmpvaW4oJywgJykgfX08L3NwYW4+XG4gICAgICAgICAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cInN0YXRcIj5cbiAgICAgICAgICAgICAgICAgICAgICA8c3BhbiBjbGFzcz1cImxhYmVsXCI+TW9kZWwgZnVuY3Rpb25zPC9zcGFuPlxuICAgICAgICAgICAgICAgICAgICAgIEBpZiAoZW50aXR5Lm1vZGVsRnVuY3Rpb25Db3VudCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgPGFcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjbGFzcz1cImNvdW50LWxpbmtcIlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIChjbGljayk9XCJvcGVuRnVuY3Rpb25zKHVuaXQsICdtb2RlbCcpXCI+XG4gICAgICAgICAgICAgICAgICAgICAgICAgIHt7IGVudGl0eS5tb2RlbEZ1bmN0aW9uQ291bnQgfX1cbiAgICAgICAgICAgICAgICAgICAgICAgIDwvYT5cbiAgICAgICAgICAgICAgICAgICAgICB9IEBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIDxzcGFuPjA8L3NwYW4+XG4gICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cInN0YXRcIj5cbiAgICAgICAgICAgICAgICAgICAgICA8c3BhbiBjbGFzcz1cImxhYmVsXCI+SGFuZGxlciBmdW5jdGlvbnM8L3NwYW4+XG4gICAgICAgICAgICAgICAgICAgICAgQGlmIChlbnRpdHkuaGFuZGxlckZ1bmN0aW9uQ291bnQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIDxhXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY2xhc3M9XCJjb3VudC1saW5rXCJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAoY2xpY2spPVwib3BlbkZ1bmN0aW9ucyh1bml0LCAnaGFuZGxlcicpXCI+XG4gICAgICAgICAgICAgICAgICAgICAgICAgIHt7IGVudGl0eS5oYW5kbGVyRnVuY3Rpb25Db3VudCB9fVxuICAgICAgICAgICAgICAgICAgICAgICAgPC9hPlxuICAgICAgICAgICAgICAgICAgICAgIH0gQGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgPHNwYW4+MDwvc3Bhbj5cbiAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgICAgICAgfSBAZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJzdGF0XCI+XG4gICAgICAgICAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJsYWJlbFwiPkNvZGUgZnVuY3Rpb25zPC9zcGFuPlxuICAgICAgICAgICAgICAgICAgICAgIEBpZiAodW5pdC5mdW5jdGlvbkNvdW50KSB7XG4gICAgICAgICAgICAgICAgICAgICAgICA8YVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNsYXNzPVwiY291bnQtbGlua1wiXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgKGNsaWNrKT1cIm9wZW5GdW5jdGlvbnModW5pdCwgJ2NsYXNzJylcIj5cbiAgICAgICAgICAgICAgICAgICAgICAgICAge3sgdW5pdC5mdW5jdGlvbkNvdW50IH19XG4gICAgICAgICAgICAgICAgICAgICAgICA8L2E+XG4gICAgICAgICAgICAgICAgICAgICAgfSBAZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICA8c3Bhbj4wPC9zcGFuPlxuICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICAgIDwvbmctdGVtcGxhdGU+XG4gICAgICAgICAgICA8L21hdC1leHBhbnNpb24tcGFuZWw+XG4gICAgICAgICAgfVxuICAgICAgICA8L21hdC1hY2NvcmRpb24+XG5cbiAgICAgICAgQGlmICghZmlsdGVyZWRVbml0cygpLmxlbmd0aCkge1xuICAgICAgICAgIDxkaXYgY2xhc3M9XCJzdWJoZWFkaW5nXCI+Tm90aGluZyBtYXRjaGVzIOKAnHt7IGZpbHRlcigpIH194oCdLjwvZGl2PlxuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIDwhLS0gVGhlIG90aGVyIGhhbGYgb2YgdGhlIHBpY3R1cmU6IHRhYmxlcyB0aGUgQUkgY2FuJ3QgcmVhY2guIEV4Y2x1ZGVkXG4gICAgICAgICAgIG9uZXMgaGF2ZSBubyBtb2RlbDsgdW5saW5rZWQganVuY3Rpb25zIGhhdmUgYSBjb21wb3NpdGUgcHJpbWFyeSBrZXlcbiAgICAgICAgICAgYnV0IHdlcmUgZm9sZGVkIGludG8gbm8gcmVsYXRpb25zaGlwLCBzbyBub3RoaW5nIGNhbiBuYXZpZ2F0ZSB0b1xuICAgICAgICAgICB0aGVtLiBCb3RoIGFyZSBpbnZpc2libGUgYnkgb21pc3Npb24g4oCUIG5vIGVycm9yLCBqdXN0IGEgY2FwYWJpbGl0eVxuICAgICAgICAgICB0aGF0IHNpbGVudGx5IGlzbid0IHRoZXJlLiBDb2xsYXBzZWQgYnkgZGVmYXVsdDogdGhlIGV4Y2x1ZGVkIGxpc3QgaXNcbiAgICAgICAgICAgbG9uZyBhbmQgbW9zdGx5IGZyYW1ld29yayBwbHVtYmluZy4gLS0+XG4gICAgICBAaWYgKGhhc0NhdGFsb2coKSkge1xuICAgICAgICA8aDI+Tm90IGluIHRoZSBzZW1hbnRpYyBkYXRhYmFzZTwvaDI+XG4gICAgICAgIDxkaXYgY2xhc3M9XCJzdWJoZWFkaW5nXCI+XG4gICAgICAgICAgVGFibGVzIHRoZSByZXBvcnQgQUkgY2FuJ3Qgc2VlLiBHaXZlIG9uZSBhIG1vZGVsIHRvIHByb21vdGUgaXQgdG8gYW5cbiAgICAgICAgICBlbnRpdHksIHRoZW4gcmVidWlsZC5cbiAgICAgICAgPC9kaXY+XG4gICAgICAgIDxtYXQtYWNjb3JkaW9uIGNsYXNzPVwiY2F0YWxvZ1wiPlxuICAgICAgICAgIEBpZiAoZXhjbHVkZWRUYWJsZXMoKS5sZW5ndGgpIHtcbiAgICAgICAgICAgIDxtYXQtZXhwYW5zaW9uLXBhbmVsPlxuICAgICAgICAgICAgICA8bWF0LWV4cGFuc2lvbi1wYW5lbC1oZWFkZXI+XG4gICAgICAgICAgICAgICAgPG1hdC1wYW5lbC10aXRsZT5cbiAgICAgICAgICAgICAgICAgIFRhYmxlcyBleGNsdWRlZCAoe3sgZXhjbHVkZWRUYWJsZXMoKS5sZW5ndGggfX0pXG4gICAgICAgICAgICAgICAgPC9tYXQtcGFuZWwtdGl0bGU+XG4gICAgICAgICAgICAgIDwvbWF0LWV4cGFuc2lvbi1wYW5lbC1oZWFkZXI+XG5cbiAgICAgICAgICAgICAgPCEtLSBEZWZlcnJlZDogdGhlIGJvZHkgb25seSBleGlzdHMgb25jZSBleHBhbmRlZC4gLS0+XG4gICAgICAgICAgICAgIDxuZy10ZW1wbGF0ZSBtYXRFeHBhbnNpb25QYW5lbENvbnRlbnQ+XG4gICAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cInBhaXItbGlzdFwiPlxuICAgICAgICAgICAgICAgICAgQGZvciAodGFibGUgb2YgZXhjbHVkZWRUYWJsZXMoKTsgdHJhY2sgdGFibGUudGFibGUpIHtcbiAgICAgICAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cInBhaXItcm93XCI+XG4gICAgICAgICAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJwYWlyLW5hbWVcIj57eyB0YWJsZS50YWJsZSB9fTwvc3Bhbj5cbiAgICAgICAgICAgICAgICAgICAgICA8c3Bhbj57eyB0YWJsZS5yZWFzb24gfX08L3NwYW4+XG4gICAgICAgICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgICA8L25nLXRlbXBsYXRlPlxuICAgICAgICAgICAgPC9tYXQtZXhwYW5zaW9uLXBhbmVsPlxuICAgICAgICAgIH1cbiAgICAgICAgICBAaWYgKHVubGlua2VkSnVuY3Rpb25zKCkubGVuZ3RoKSB7XG4gICAgICAgICAgICA8bWF0LWV4cGFuc2lvbi1wYW5lbD5cbiAgICAgICAgICAgICAgPG1hdC1leHBhbnNpb24tcGFuZWwtaGVhZGVyPlxuICAgICAgICAgICAgICAgIDxtYXQtcGFuZWwtdGl0bGU+XG4gICAgICAgICAgICAgICAgICBKdW5jdGlvbnMgbm90IGxpbmtlZCAoe3sgdW5saW5rZWRKdW5jdGlvbnMoKS5sZW5ndGggfX0pXG4gICAgICAgICAgICAgICAgPC9tYXQtcGFuZWwtdGl0bGU+XG4gICAgICAgICAgICAgIDwvbWF0LWV4cGFuc2lvbi1wYW5lbC1oZWFkZXI+XG5cbiAgICAgICAgICAgICAgPG5nLXRlbXBsYXRlIG1hdEV4cGFuc2lvblBhbmVsQ29udGVudD5cbiAgICAgICAgICAgICAgICA8cCBjbGFzcz1cInNtYWxsXCI+XG4gICAgICAgICAgICAgICAgICBMaW5rIHRhYmxlcyB0aGUgYnVpbGQgY291bGRuJ3QgZm9sZCBpbnRvIGEgcmVsYXRpb25zaGlwIOKAlCBzb1xuICAgICAgICAgICAgICAgICAgbmVpdGhlciB0aGV5IG5vciB3aGF0IHRoZXkgbGluayBjYW4gYmUgcmVwb3J0ZWQgb24uXG4gICAgICAgICAgICAgICAgPC9wPlxuICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJwYWlyLWxpc3RcIj5cbiAgICAgICAgICAgICAgICAgIEBmb3IgKHRhYmxlIG9mIHVubGlua2VkSnVuY3Rpb25zKCk7IHRyYWNrIHRhYmxlLnRhYmxlKSB7XG4gICAgICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJwYWlyLXJvd1wiPlxuICAgICAgICAgICAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwicGFpci1uYW1lXCI+e3sgdGFibGUudGFibGUgfX08L3NwYW4+XG4gICAgICAgICAgICAgICAgICAgICAgPHNwYW4+e3sgdGFibGUucmVhc29uIH19PC9zcGFuPlxuICAgICAgICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgICAgPC9uZy10ZW1wbGF0ZT5cbiAgICAgICAgICAgIDwvbWF0LWV4cGFuc2lvbi1wYW5lbD5cbiAgICAgICAgICB9XG4gICAgICAgIDwvbWF0LWFjY29yZGlvbj5cbiAgICAgIH1cbiAgICB9XG4gIDwvZGl2PlxuPC9kaXY+XG4iXX0=