@firestitch/report 18.0.9 → 18.0.11

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.
@@ -1,6 +1,5 @@
1
1
  import { ChangeDetectionStrategy, Component, DestroyRef, computed, inject, signal } from '@angular/core';
2
2
  import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
3
- import { MatButton } from '@angular/material/button';
4
3
  import { MatExpansionModule } from '@angular/material/expansion';
5
4
  import { MatTooltipModule } from '@angular/material/tooltip';
6
5
  import { StreamEventType } from '@firestitch/api';
@@ -10,7 +9,7 @@ import { FsMessage, FsMessageModule } from '@firestitch/message';
10
9
  import { FsProcess } from '@firestitch/process';
11
10
  import { FsPrompt } from '@firestitch/prompt';
12
11
  import { FsSkeletonModule } from '@firestitch/skeleton';
13
- import { filter, map, switchMap, take } from 'rxjs/operators';
12
+ import { filter, map, switchMap, take, tap } from 'rxjs/operators';
14
13
  import { ReportData } from '../../../../data/report.data';
15
14
  import * as i0 from "@angular/core";
16
15
  import * as i1 from "@angular/material/expansion";
@@ -71,6 +70,9 @@ export class SemanticDatabaseComponent {
71
70
  // Per-entity function caches, loaded on first expand. undefined = not
72
71
  // requested yet, null = request in flight (the skeleton window), object = loaded.
73
72
  _entityFunctions = signal({});
73
+ // Guards the outcome message to fire exactly once per run — whether the stream
74
+ // completes (build finished, possibly failed) or errors outright.
75
+ _buildFinalized = false;
74
76
  _reportData = inject(ReportData);
75
77
  _process = inject(FsProcess);
76
78
  _prompt = inject(FsPrompt);
@@ -79,26 +81,19 @@ export class SemanticDatabaseComponent {
79
81
  constructor() {
80
82
  this._init();
81
83
  }
82
- // Run the semantic-database build. The live feed streams into the FsProcess
83
- // dock (bottom-right), whose subscription survives this dialog closing — so
84
- // dismissing the dialog never interrupts a running build.
84
+ // Confirm before kicking off a build — a rebuild replaces the current
85
+ // semantic database, so it should never fire on a stray click.
85
86
  build() {
86
- this.building.set(true);
87
- const target$ = this._reportData.semanticBuild()
88
- .pipe(filter((event) => event?.type === StreamEventType.Data
89
- && event.data?.kind === 'log'
90
- && typeof event.data.line === 'string'), map((event) => event.data.line));
91
- this._process
92
- .run('Semantic database build', target$)
93
- .completed$
94
- .pipe(take(1), takeUntilDestroyed(this._destroyRef))
95
- .subscribe(() => {
96
- this.building.set(false);
97
- // The build rewrote every entity's function cache — drop the loaded
98
- // copies so the next expand refetches fresh data.
99
- this._entityFunctions.set({});
100
- this._refreshStatus();
101
- });
87
+ const rebuild = !!this.status()?.detail?.generatedAt;
88
+ this._prompt.confirm({
89
+ title: rebuild ? 'Rebuild semantic database' : 'Build semantic database',
90
+ template: rebuild
91
+ ? 'Rebuild the semantic database? It runs in the background and replaces the current one when it finishes.'
92
+ : 'Build the semantic database? It runs in the background.',
93
+ commitLabel: rebuild ? 'Rebuild' : 'Build',
94
+ })
95
+ .pipe(takeUntilDestroyed(this._destroyRef))
96
+ .subscribe(() => this._runBuild());
102
97
  }
103
98
  stopBuild() {
104
99
  this._prompt.confirm({
@@ -113,6 +108,67 @@ export class SemanticDatabaseComponent {
113
108
  this._refreshStatus();
114
109
  });
115
110
  }
111
+ // Run the semantic-database build. The live feed streams into the FsProcess
112
+ // dock (bottom-right), whose subscription survives this dialog closing — so
113
+ // dismissing the dialog never interrupts a running build.
114
+ _runBuild() {
115
+ this.building.set(true);
116
+ this._buildFinalized = false;
117
+ const target$ = this._reportData.semanticBuild()
118
+ .pipe(
119
+ // A hard stream/transport failure (the build couldn't even start)
120
+ // finalizes here — completed$ won't fire in that case.
121
+ tap({ error: (error) => this._finalizeBuild(error) }), filter((event) => event?.type === StreamEventType.Data
122
+ && event.data?.kind === 'log'
123
+ && typeof event.data.line === 'string'), map((event) => event.data.line));
124
+ this._process
125
+ .run('Semantic database build', target$)
126
+ .completed$
127
+ .pipe(take(1), takeUntilDestroyed(this._destroyRef))
128
+ .subscribe(() => this._finalizeBuild(null));
129
+ }
130
+ /**
131
+ * Wrap up one build run exactly once. On a hard stream error there is no
132
+ * status to read, so say so directly; otherwise refresh the status and
133
+ * announce how the build actually ended — a build that failed (e.g. the AI
134
+ * couldn't be reached) reports 'Failed' with a reason, and that must surface
135
+ * instead of the run silently doing nothing.
136
+ */
137
+ _finalizeBuild(streamError) {
138
+ if (this._buildFinalized) {
139
+ return;
140
+ }
141
+ this._buildFinalized = true;
142
+ this.building.set(false);
143
+ // The build rewrote every entity's function cache — drop the loaded copies
144
+ // so the next expand refetches fresh data.
145
+ this._entityFunctions.set({});
146
+ if (streamError) {
147
+ this._message.error('The semantic database build could not run — check the AI connection and try again.');
148
+ this._refreshStatus();
149
+ return;
150
+ }
151
+ this._reportData.semanticBuildStatus()
152
+ .pipe(takeUntilDestroyed(this._destroyRef))
153
+ .subscribe((status) => {
154
+ this.status.set(status);
155
+ this._announceOutcome(status);
156
+ });
157
+ }
158
+ /**
159
+ * Tell the operator how the build ended: a failed/stopped build surfaces its
160
+ * reason (so an AI connection problem is never silent), a completed one
161
+ * confirms success.
162
+ */
163
+ _announceOutcome(status) {
164
+ const build = status?.build;
165
+ if (build?.state === 'F' || build?.state === 'K') {
166
+ this._message.error(build.message || 'The semantic database build did not finish.');
167
+ }
168
+ else if (build?.state === 'C') {
169
+ this._message.success('Semantic database build complete.');
170
+ }
171
+ }
116
172
  stageColor(stage) {
117
173
  return stage === 'done'
118
174
  ? SemanticDatabaseComponent.DONE_COLOR
@@ -178,18 +234,17 @@ export class SemanticDatabaseComponent {
178
234
  return rank === -1 ? SemanticDatabaseComponent.KIND_ORDER.length : rank;
179
235
  }
180
236
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: SemanticDatabaseComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
181
- 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>\n {{ buildStatus.detail.entityCount }} entities \u00B7\n {{ buildStatus.detail.functionCount }} code functions\n </span>\n </div>\n } @else {\n <fs-message-warning>\n The semantic database has not been built yet \u2014 the report AI can't\n answer data questions until it is. Run the first build.\n </fs-message-warning>\n }\n @if (buildStatus.build) {\n <div class=\"stat\">\n <span class=\"label\">Last build run</span>\n <span>\n {{ buildStateLabel() }}\n @if (buildStatus.build.message) {\n \u2014 {{ buildStatus.build.message }}\n }\n </span>\n </div>\n }\n </div>\n\n <div class=\"build-actions\">\n @if (buildActive()) {\n <button\n type=\"button\"\n mat-button\n color=\"warn\"\n (click)=\"stopBuild()\">\n Stop Build\n </button>\n } @else {\n <button\n type=\"button\"\n mat-button\n color=\"primary\"\n (click)=\"build()\">\n {{ buildStatus.detail.generatedAt ? 'Rebuild' : 'Build' }}\n </button>\n }\n </div>\n\n <!-- The model scoreboard: every entity the AI knows about, its\n built-vs-needs-building stages, and a drill-down into its shape, enum\n values, computed fields and AI-classified code functions. -->\n @if (buildStatus.detail.entities?.length) {\n <mat-accordion class=\"entities\">\n @for (entity of buildStatus.detail.entities; track entity.key) {\n <mat-expansion-panel (opened)=\"entityOpened(entity)\">\n <mat-expansion-panel-header>\n <mat-panel-title>{{ entity.key }}</mat-panel-title>\n <mat-panel-description>\n <div class=\"stage-chips\">\n @for (stage of stageKeys; track stage) {\n <fs-chip\n size=\"tiny\"\n [backgroundColor]=\"stageColor(entity.stages[stage])\"\n color=\"#ffffff\"\n [matTooltip]=\"stageTooltip(entity.stages[stage])\">\n {{ stageLabels[stage] }}\n </fs-chip>\n }\n </div>\n </mat-panel-description>\n </mat-expansion-panel-header>\n\n <!-- Deferred: the body (and its functions request) only exists\n once expanded. -->\n <ng-template matExpansionPanelContent>\n <div class=\"entity-detail\">\n <div><strong>Table:</strong> {{ entity.table }}</div>\n <div><strong>Columns:</strong> {{ entity.columns }}</div>\n <div><strong>Relationships:</strong> {{ entity.relationships }}</div>\n @if (entity.enums.length) {\n <div class=\"enum-list\">\n <strong>Enum values:</strong>\n @for (enumColumn of entity.enums; track enumColumn.column) {\n <div class=\"enum-row\">\n <span class=\"enum-column\">{{ enumColumn.column }}</span>\n <span class=\"enum-values\">{{ enumColumn.values.join(', ') }}</span>\n </div>\n }\n </div>\n }\n @if (entity.computedFields.length) {\n <div><strong>Computed fields:</strong> {{ entity.computedFields.join(', ') }}</div>\n }\n\n <div class=\"functions-section\">\n <h3 class=\"functions-heading\">\n Code functions\n @if (entity.functionCount) {\n <span class=\"functions-count\">({{ entity.functionCount }})</span>\n }\n </h3>\n\n <div class=\"functions-body\" *fsSkeleton=\"entityFunctions(entity.key)\">\n @if (entityFunctions(entity.key); as fns) {\n @if (fns.functions.length) {\n @if (fns.generatedAt) {\n <div class=\"hint functions-generated\">\n Discovered from {{ fns.class }} &middot;\n <fs-date\n [date]=\"fns.generatedAt\"\n format=\"date-time\">\n </fs-date>\n </div>\n }\n <div class=\"functions-list\">\n @for (fn of fns.functions; track fn.method) {\n <div class=\"function-row\">\n <div class=\"function-head\">\n <fs-chip\n size=\"tiny\"\n [backgroundColor]=\"kindColor(fn.kind)\"\n color=\"#ffffff\">\n {{ fn.kind }}\n </fs-chip>\n <code class=\"function-method\">{{ fn.method }}</code>\n </div>\n <div class=\"function-summary\">{{ fn.summary }}</div>\n @if (fn.produces) {\n <div class=\"function-produces hint\">Produces: {{ fn.produces }}</div>\n }\n </div>\n }\n </div>\n } @else {\n <div class=\"hint\">\n No functions cached for this entity yet \u2014 run a build to discover its code.\n </div>\n }\n }\n </div>\n </div>\n </div>\n </ng-template>\n </mat-expansion-panel>\n }\n </mat-accordion>\n }\n }\n </div>\n</div>\n", styles: [".tab-body{padding-top:16px}.hint{margin:0 0 12px;color:#0009;font-size:13px;line-height:1.5}.build-status{display:flex;flex-direction:column;gap:8px}.build-status .stat{display:flex;gap:8px}.build-status .stat .label{min-width:110px;color:#0009}.build-actions{margin:12px 0}.entities{display:block}.entities .stage-chips{display:flex;flex-wrap:wrap;gap:4px}.entities .entity-detail{display:flex;flex-direction:column;gap:5px}.entities .entity-detail .enum-list{display:flex;flex-direction:column;gap:3px}.entities .entity-detail .enum-list .enum-row{display:flex;gap:10px;padding-left:10px}.entities .entity-detail .enum-list .enum-row .enum-column{min-width:140px;font-weight:600}.entities .entity-detail .enum-list .enum-row .enum-values{color:#0009}.entities .entity-detail .functions-section{margin-top:10px}.entities .entity-detail .functions-section .functions-heading{margin:0 0 5px;font-size:15px}.entities .entity-detail .functions-section .functions-heading .functions-count{font-weight:400;color:#0009}.entities .entity-detail .functions-section .functions-generated{margin-bottom:10px}.entities .entity-detail .functions-section .functions-list{display:flex;flex-direction:column}.entities .entity-detail .functions-section .functions-list .function-row{display:flex;flex-direction:column;gap:3px;padding:10px 0}.entities .entity-detail .functions-section .functions-list .function-row+.function-row{border-top:1px solid rgba(0,0,0,.08)}.entities .entity-detail .functions-section .functions-list .function-row .function-head{display:flex;align-items:center;gap:8px}.entities .entity-detail .functions-section .functions-list .function-row .function-method{font-family:monospace;font-size:13px;font-weight:600}.entities .entity-detail .functions-section .functions-list .function-row .function-summary{color:#000000bf}.entities .entity-detail .functions-section .functions-list .function-row .function-produces{padding-left:10px}\n"], dependencies: [{ kind: "component", type: MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }, { 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 });
237
+ 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>\n {{ buildStatus.detail.entityCount }} entities \u00B7\n {{ buildStatus.detail.functionCount }} code functions\n </span>\n </div>\n } @else {\n <fs-message-warning>\n The semantic database has not been built yet \u2014 the report AI can't\n answer data questions until it is. Run the first build.\n </fs-message-warning>\n }\n @if (buildStatus.build) {\n <div class=\"stat\">\n <span class=\"label\">Last build run</span>\n <span>\n {{ buildStateLabel() }}\n @if (buildStatus.build.message) {\n \u2014 {{ buildStatus.build.message }}\n }\n </span>\n </div>\n }\n </div>\n\n <!-- The model scoreboard: every entity the AI knows about, its\n built-vs-needs-building stages, and a drill-down into its shape, enum\n values, computed fields and AI-classified code functions. -->\n @if (buildStatus.detail.entities?.length) {\n <mat-accordion class=\"entities\">\n @for (entity of buildStatus.detail.entities; track entity.key) {\n <mat-expansion-panel (opened)=\"entityOpened(entity)\">\n <mat-expansion-panel-header>\n <mat-panel-title>{{ entity.key }}</mat-panel-title>\n <mat-panel-description>\n <div class=\"stage-chips\">\n @for (stage of stageKeys; track stage) {\n <fs-chip\n size=\"tiny\"\n [backgroundColor]=\"stageColor(entity.stages[stage])\"\n color=\"#ffffff\"\n [matTooltip]=\"stageTooltip(entity.stages[stage])\">\n {{ stageLabels[stage] }}\n </fs-chip>\n }\n </div>\n </mat-panel-description>\n </mat-expansion-panel-header>\n\n <!-- Deferred: the body (and its functions request) only exists\n once expanded. -->\n <ng-template matExpansionPanelContent>\n <div class=\"entity-detail\">\n <div><strong>Table:</strong> {{ entity.table }}</div>\n <div><strong>Columns:</strong> {{ entity.columns }}</div>\n <div><strong>Relationships:</strong> {{ entity.relationships }}</div>\n @if (entity.enums.length) {\n <div class=\"enum-list\">\n <strong>Enum values:</strong>\n @for (enumColumn of entity.enums; track enumColumn.column) {\n <div class=\"enum-row\">\n <span class=\"enum-column\">{{ enumColumn.column }}</span>\n <span class=\"enum-values\">{{ enumColumn.values.join(', ') }}</span>\n </div>\n }\n </div>\n }\n @if (entity.computedFields.length) {\n <div><strong>Computed fields:</strong> {{ entity.computedFields.join(', ') }}</div>\n }\n\n <div class=\"functions-section\">\n <h3 class=\"functions-heading\">\n Code functions\n @if (entity.functionCount) {\n <span class=\"functions-count\">({{ entity.functionCount }})</span>\n }\n </h3>\n\n <div class=\"functions-body\" *fsSkeleton=\"entityFunctions(entity.key)\">\n @if (entityFunctions(entity.key); as fns) {\n @if (fns.functions.length) {\n @if (fns.generatedAt) {\n <div class=\"hint functions-generated\">\n Discovered from {{ fns.class }} &middot;\n <fs-date\n [date]=\"fns.generatedAt\"\n format=\"date-time\">\n </fs-date>\n </div>\n }\n <div class=\"functions-list\">\n @for (fn of fns.functions; track fn.method) {\n <div class=\"function-row\">\n <div class=\"function-head\">\n <fs-chip\n size=\"tiny\"\n [backgroundColor]=\"kindColor(fn.kind)\"\n color=\"#ffffff\">\n {{ fn.kind }}\n </fs-chip>\n <code class=\"function-method\">{{ fn.method }}</code>\n </div>\n <div class=\"function-summary\">{{ fn.summary }}</div>\n @if (fn.produces) {\n <div class=\"function-produces hint\">Produces: {{ fn.produces }}</div>\n }\n </div>\n }\n </div>\n } @else {\n <div class=\"hint\">\n No functions cached for this entity yet \u2014 run a build to discover its code.\n </div>\n }\n }\n </div>\n </div>\n </div>\n </ng-template>\n </mat-expansion-panel>\n }\n </mat-accordion>\n }\n }\n </div>\n</div>\n", styles: [".tab-body{padding-top:16px}.hint{margin:0 0 12px;color:#0009;font-size:13px;line-height:1.5}.build-status{display:flex;flex-direction:column;gap:8px}.build-status .stat{display:flex;gap:8px}.build-status .stat .label{min-width:110px;color:#0009}.entities{display:block;padding:3px}.entities .stage-chips{display:flex;flex-wrap:wrap;gap:4px}.entities .entity-detail{display:flex;flex-direction:column;gap:5px}.entities .entity-detail .enum-list{display:flex;flex-direction:column;gap:3px}.entities .entity-detail .enum-list .enum-row{display:flex;gap:10px;padding-left:10px}.entities .entity-detail .enum-list .enum-row .enum-column{min-width:140px;font-weight:600}.entities .entity-detail .enum-list .enum-row .enum-values{color:#0009}.entities .entity-detail .functions-section{margin-top:10px}.entities .entity-detail .functions-section .functions-heading{margin:0 0 5px;font-size:15px}.entities .entity-detail .functions-section .functions-heading .functions-count{font-weight:400;color:#0009}.entities .entity-detail .functions-section .functions-generated{margin-bottom:10px}.entities .entity-detail .functions-section .functions-list{display:flex;flex-direction:column}.entities .entity-detail .functions-section .functions-list .function-row{display:flex;flex-direction:column;gap:3px;padding:10px 0}.entities .entity-detail .functions-section .functions-list .function-row+.function-row{border-top:1px solid rgba(0,0,0,.08)}.entities .entity-detail .functions-section .functions-list .function-row .function-head{display:flex;align-items:center;gap:8px}.entities .entity-detail .functions-section .functions-list .function-row .function-method{font-family:monospace;font-size:13px;font-weight:600}.entities .entity-detail .functions-section .functions-list .function-row .function-summary{color:#000000bf}.entities .entity-detail .functions-section .functions-list .function-row .function-produces{padding-left:10px}\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 });
182
238
  }
183
239
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: SemanticDatabaseComponent, decorators: [{
184
240
  type: Component,
185
241
  args: [{ selector: 'fs-ai-report-global-settings-semantic-database', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [
186
- MatButton,
187
242
  MatExpansionModule,
188
243
  MatTooltipModule,
189
244
  FsChipModule,
190
245
  FsDateModule,
191
246
  FsMessageModule,
192
247
  FsSkeletonModule,
193
- ], 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>\n {{ buildStatus.detail.entityCount }} entities \u00B7\n {{ buildStatus.detail.functionCount }} code functions\n </span>\n </div>\n } @else {\n <fs-message-warning>\n The semantic database has not been built yet \u2014 the report AI can't\n answer data questions until it is. Run the first build.\n </fs-message-warning>\n }\n @if (buildStatus.build) {\n <div class=\"stat\">\n <span class=\"label\">Last build run</span>\n <span>\n {{ buildStateLabel() }}\n @if (buildStatus.build.message) {\n \u2014 {{ buildStatus.build.message }}\n }\n </span>\n </div>\n }\n </div>\n\n <div class=\"build-actions\">\n @if (buildActive()) {\n <button\n type=\"button\"\n mat-button\n color=\"warn\"\n (click)=\"stopBuild()\">\n Stop Build\n </button>\n } @else {\n <button\n type=\"button\"\n mat-button\n color=\"primary\"\n (click)=\"build()\">\n {{ buildStatus.detail.generatedAt ? 'Rebuild' : 'Build' }}\n </button>\n }\n </div>\n\n <!-- The model scoreboard: every entity the AI knows about, its\n built-vs-needs-building stages, and a drill-down into its shape, enum\n values, computed fields and AI-classified code functions. -->\n @if (buildStatus.detail.entities?.length) {\n <mat-accordion class=\"entities\">\n @for (entity of buildStatus.detail.entities; track entity.key) {\n <mat-expansion-panel (opened)=\"entityOpened(entity)\">\n <mat-expansion-panel-header>\n <mat-panel-title>{{ entity.key }}</mat-panel-title>\n <mat-panel-description>\n <div class=\"stage-chips\">\n @for (stage of stageKeys; track stage) {\n <fs-chip\n size=\"tiny\"\n [backgroundColor]=\"stageColor(entity.stages[stage])\"\n color=\"#ffffff\"\n [matTooltip]=\"stageTooltip(entity.stages[stage])\">\n {{ stageLabels[stage] }}\n </fs-chip>\n }\n </div>\n </mat-panel-description>\n </mat-expansion-panel-header>\n\n <!-- Deferred: the body (and its functions request) only exists\n once expanded. -->\n <ng-template matExpansionPanelContent>\n <div class=\"entity-detail\">\n <div><strong>Table:</strong> {{ entity.table }}</div>\n <div><strong>Columns:</strong> {{ entity.columns }}</div>\n <div><strong>Relationships:</strong> {{ entity.relationships }}</div>\n @if (entity.enums.length) {\n <div class=\"enum-list\">\n <strong>Enum values:</strong>\n @for (enumColumn of entity.enums; track enumColumn.column) {\n <div class=\"enum-row\">\n <span class=\"enum-column\">{{ enumColumn.column }}</span>\n <span class=\"enum-values\">{{ enumColumn.values.join(', ') }}</span>\n </div>\n }\n </div>\n }\n @if (entity.computedFields.length) {\n <div><strong>Computed fields:</strong> {{ entity.computedFields.join(', ') }}</div>\n }\n\n <div class=\"functions-section\">\n <h3 class=\"functions-heading\">\n Code functions\n @if (entity.functionCount) {\n <span class=\"functions-count\">({{ entity.functionCount }})</span>\n }\n </h3>\n\n <div class=\"functions-body\" *fsSkeleton=\"entityFunctions(entity.key)\">\n @if (entityFunctions(entity.key); as fns) {\n @if (fns.functions.length) {\n @if (fns.generatedAt) {\n <div class=\"hint functions-generated\">\n Discovered from {{ fns.class }} &middot;\n <fs-date\n [date]=\"fns.generatedAt\"\n format=\"date-time\">\n </fs-date>\n </div>\n }\n <div class=\"functions-list\">\n @for (fn of fns.functions; track fn.method) {\n <div class=\"function-row\">\n <div class=\"function-head\">\n <fs-chip\n size=\"tiny\"\n [backgroundColor]=\"kindColor(fn.kind)\"\n color=\"#ffffff\">\n {{ fn.kind }}\n </fs-chip>\n <code class=\"function-method\">{{ fn.method }}</code>\n </div>\n <div class=\"function-summary\">{{ fn.summary }}</div>\n @if (fn.produces) {\n <div class=\"function-produces hint\">Produces: {{ fn.produces }}</div>\n }\n </div>\n }\n </div>\n } @else {\n <div class=\"hint\">\n No functions cached for this entity yet \u2014 run a build to discover its code.\n </div>\n }\n }\n </div>\n </div>\n </div>\n </ng-template>\n </mat-expansion-panel>\n }\n </mat-accordion>\n }\n }\n </div>\n</div>\n", styles: [".tab-body{padding-top:16px}.hint{margin:0 0 12px;color:#0009;font-size:13px;line-height:1.5}.build-status{display:flex;flex-direction:column;gap:8px}.build-status .stat{display:flex;gap:8px}.build-status .stat .label{min-width:110px;color:#0009}.build-actions{margin:12px 0}.entities{display:block}.entities .stage-chips{display:flex;flex-wrap:wrap;gap:4px}.entities .entity-detail{display:flex;flex-direction:column;gap:5px}.entities .entity-detail .enum-list{display:flex;flex-direction:column;gap:3px}.entities .entity-detail .enum-list .enum-row{display:flex;gap:10px;padding-left:10px}.entities .entity-detail .enum-list .enum-row .enum-column{min-width:140px;font-weight:600}.entities .entity-detail .enum-list .enum-row .enum-values{color:#0009}.entities .entity-detail .functions-section{margin-top:10px}.entities .entity-detail .functions-section .functions-heading{margin:0 0 5px;font-size:15px}.entities .entity-detail .functions-section .functions-heading .functions-count{font-weight:400;color:#0009}.entities .entity-detail .functions-section .functions-generated{margin-bottom:10px}.entities .entity-detail .functions-section .functions-list{display:flex;flex-direction:column}.entities .entity-detail .functions-section .functions-list .function-row{display:flex;flex-direction:column;gap:3px;padding:10px 0}.entities .entity-detail .functions-section .functions-list .function-row+.function-row{border-top:1px solid rgba(0,0,0,.08)}.entities .entity-detail .functions-section .functions-list .function-row .function-head{display:flex;align-items:center;gap:8px}.entities .entity-detail .functions-section .functions-list .function-row .function-method{font-family:monospace;font-size:13px;font-weight:600}.entities .entity-detail .functions-section .functions-list .function-row .function-summary{color:#000000bf}.entities .entity-detail .functions-section .functions-list .function-row .function-produces{padding-left:10px}\n"] }]
248
+ ], 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>\n {{ buildStatus.detail.entityCount }} entities \u00B7\n {{ buildStatus.detail.functionCount }} code functions\n </span>\n </div>\n } @else {\n <fs-message-warning>\n The semantic database has not been built yet \u2014 the report AI can't\n answer data questions until it is. Run the first build.\n </fs-message-warning>\n }\n @if (buildStatus.build) {\n <div class=\"stat\">\n <span class=\"label\">Last build run</span>\n <span>\n {{ buildStateLabel() }}\n @if (buildStatus.build.message) {\n \u2014 {{ buildStatus.build.message }}\n }\n </span>\n </div>\n }\n </div>\n\n <!-- The model scoreboard: every entity the AI knows about, its\n built-vs-needs-building stages, and a drill-down into its shape, enum\n values, computed fields and AI-classified code functions. -->\n @if (buildStatus.detail.entities?.length) {\n <mat-accordion class=\"entities\">\n @for (entity of buildStatus.detail.entities; track entity.key) {\n <mat-expansion-panel (opened)=\"entityOpened(entity)\">\n <mat-expansion-panel-header>\n <mat-panel-title>{{ entity.key }}</mat-panel-title>\n <mat-panel-description>\n <div class=\"stage-chips\">\n @for (stage of stageKeys; track stage) {\n <fs-chip\n size=\"tiny\"\n [backgroundColor]=\"stageColor(entity.stages[stage])\"\n color=\"#ffffff\"\n [matTooltip]=\"stageTooltip(entity.stages[stage])\">\n {{ stageLabels[stage] }}\n </fs-chip>\n }\n </div>\n </mat-panel-description>\n </mat-expansion-panel-header>\n\n <!-- Deferred: the body (and its functions request) only exists\n once expanded. -->\n <ng-template matExpansionPanelContent>\n <div class=\"entity-detail\">\n <div><strong>Table:</strong> {{ entity.table }}</div>\n <div><strong>Columns:</strong> {{ entity.columns }}</div>\n <div><strong>Relationships:</strong> {{ entity.relationships }}</div>\n @if (entity.enums.length) {\n <div class=\"enum-list\">\n <strong>Enum values:</strong>\n @for (enumColumn of entity.enums; track enumColumn.column) {\n <div class=\"enum-row\">\n <span class=\"enum-column\">{{ enumColumn.column }}</span>\n <span class=\"enum-values\">{{ enumColumn.values.join(', ') }}</span>\n </div>\n }\n </div>\n }\n @if (entity.computedFields.length) {\n <div><strong>Computed fields:</strong> {{ entity.computedFields.join(', ') }}</div>\n }\n\n <div class=\"functions-section\">\n <h3 class=\"functions-heading\">\n Code functions\n @if (entity.functionCount) {\n <span class=\"functions-count\">({{ entity.functionCount }})</span>\n }\n </h3>\n\n <div class=\"functions-body\" *fsSkeleton=\"entityFunctions(entity.key)\">\n @if (entityFunctions(entity.key); as fns) {\n @if (fns.functions.length) {\n @if (fns.generatedAt) {\n <div class=\"hint functions-generated\">\n Discovered from {{ fns.class }} &middot;\n <fs-date\n [date]=\"fns.generatedAt\"\n format=\"date-time\">\n </fs-date>\n </div>\n }\n <div class=\"functions-list\">\n @for (fn of fns.functions; track fn.method) {\n <div class=\"function-row\">\n <div class=\"function-head\">\n <fs-chip\n size=\"tiny\"\n [backgroundColor]=\"kindColor(fn.kind)\"\n color=\"#ffffff\">\n {{ fn.kind }}\n </fs-chip>\n <code class=\"function-method\">{{ fn.method }}</code>\n </div>\n <div class=\"function-summary\">{{ fn.summary }}</div>\n @if (fn.produces) {\n <div class=\"function-produces hint\">Produces: {{ fn.produces }}</div>\n }\n </div>\n }\n </div>\n } @else {\n <div class=\"hint\">\n No functions cached for this entity yet \u2014 run a build to discover its code.\n </div>\n }\n }\n </div>\n </div>\n </div>\n </ng-template>\n </mat-expansion-panel>\n }\n </mat-accordion>\n }\n }\n </div>\n</div>\n", styles: [".tab-body{padding-top:16px}.hint{margin:0 0 12px;color:#0009;font-size:13px;line-height:1.5}.build-status{display:flex;flex-direction:column;gap:8px}.build-status .stat{display:flex;gap:8px}.build-status .stat .label{min-width:110px;color:#0009}.entities{display:block;padding:3px}.entities .stage-chips{display:flex;flex-wrap:wrap;gap:4px}.entities .entity-detail{display:flex;flex-direction:column;gap:5px}.entities .entity-detail .enum-list{display:flex;flex-direction:column;gap:3px}.entities .entity-detail .enum-list .enum-row{display:flex;gap:10px;padding-left:10px}.entities .entity-detail .enum-list .enum-row .enum-column{min-width:140px;font-weight:600}.entities .entity-detail .enum-list .enum-row .enum-values{color:#0009}.entities .entity-detail .functions-section{margin-top:10px}.entities .entity-detail .functions-section .functions-heading{margin:0 0 5px;font-size:15px}.entities .entity-detail .functions-section .functions-heading .functions-count{font-weight:400;color:#0009}.entities .entity-detail .functions-section .functions-generated{margin-bottom:10px}.entities .entity-detail .functions-section .functions-list{display:flex;flex-direction:column}.entities .entity-detail .functions-section .functions-list .function-row{display:flex;flex-direction:column;gap:3px;padding:10px 0}.entities .entity-detail .functions-section .functions-list .function-row+.function-row{border-top:1px solid rgba(0,0,0,.08)}.entities .entity-detail .functions-section .functions-list .function-row .function-head{display:flex;align-items:center;gap:8px}.entities .entity-detail .functions-section .functions-list .function-row .function-method{font-family:monospace;font-size:13px;font-weight:600}.entities .entity-detail .functions-section .functions-list .function-row .function-summary{color:#000000bf}.entities .entity-detail .functions-section .functions-list .function-row .function-produces{padding-left:10px}\n"] }]
194
249
  }], ctorParameters: () => [] });
195
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VtYW50aWMtZGF0YWJhc2UuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vc3JjL2FwcC9yZXBvcnRzL2RpYWxvZ3MvZ2xvYmFsLXNldHRpbmdzL2NvbXBvbmVudHMvc2VtYW50aWMtZGF0YWJhc2Uvc2VtYW50aWMtZGF0YWJhc2UuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vc3JjL2FwcC9yZXBvcnRzL2RpYWxvZ3MvZ2xvYmFsLXNldHRpbmdzL2NvbXBvbmVudHMvc2VtYW50aWMtZGF0YWJhc2Uvc2VtYW50aWMtZGF0YWJhc2UuY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLHVCQUF1QixFQUFFLFNBQVMsRUFBRSxVQUFVLEVBQUUsUUFBUSxFQUFFLE1BQU0sRUFBRSxNQUFNLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDekcsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sNEJBQTRCLENBQUM7QUFFaEUsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLDBCQUEwQixDQUFDO0FBQ3JELE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLDZCQUE2QixDQUFDO0FBQ2pFLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLDJCQUEyQixDQUFDO0FBRTdELE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUNsRCxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sa0JBQWtCLENBQUM7QUFDaEQsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBQ2hELE9BQU8sRUFBRSxTQUFTLEVBQUUsZUFBZSxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDakUsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBQ2hELE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUM5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LE1BQU0sUUFBUSxHQUFHLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxHQUFHLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDO1lBRWpFLE9BQU8sUUFBUSxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLGFBQWEsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUM7UUFDdEUsQ0FBQyxDQUFDLENBQUM7SUFDUCxDQUFDO0lBRU8sU0FBUyxDQUFDLElBQVk7UUFDNUIsTUFBTSxJQUFJLEdBQUcseUJBQXlCLENBQUMsVUFBVSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUVoRSxPQUFPLElBQUksS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMseUJBQXlCLENBQUMsVUFBVSxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDO0lBQzFFLENBQUM7d0dBbk1VLHlCQUF5Qjs0RkFBekIseUJBQXlCLDBHQ2pEdEMsa3BPQXdLQSxpOUREaElJLFNBQVMsZ0xBQ1Qsa0JBQWtCLHEwQkFDbEIsZ0JBQWdCLDRUQUNoQixZQUFZLHFYQUNaLFlBQVksNElBQ1osZUFBZSx5SEFDZixnQkFBZ0I7OzRGQUdQLHlCQUF5QjtrQkFoQnJDLFNBQVM7K0JBQ0UsZ0RBQWdELG1CQUd6Qyx1QkFBdUIsQ0FBQyxNQUFNLGNBQ25DLElBQUksV0FDUDt3QkFDUCxTQUFTO3dCQUNULGtCQUFrQjt3QkFDbEIsZ0JBQWdCO3dCQUNoQixZQUFZO3dCQUNaLFlBQVk7d0JBQ1osZUFBZTt3QkFDZixnQkFBZ0I7cUJBQ2pCIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3ksIENvbXBvbmVudCwgRGVzdHJveVJlZiwgY29tcHV0ZWQsIGluamVjdCwgc2lnbmFsIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyB0YWtlVW50aWxEZXN0cm95ZWQgfSBmcm9tICdAYW5ndWxhci9jb3JlL3J4anMtaW50ZXJvcCc7XG5cbmltcG9ydCB7IE1hdEJ1dHRvbiB9IGZyb20gJ0Bhbmd1bGFyL21hdGVyaWFsL2J1dHRvbic7XG5pbXBvcnQgeyBNYXRFeHBhbnNpb25Nb2R1bGUgfSBmcm9tICdAYW5ndWxhci9tYXRlcmlhbC9leHBhbnNpb24nO1xuaW1wb3J0IHsgTWF0VG9vbHRpcE1vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL21hdGVyaWFsL3Rvb2x0aXAnO1xuXG5pbXBvcnQgeyBTdHJlYW1FdmVudFR5cGUgfSBmcm9tICdAZmlyZXN0aXRjaC9hcGknO1xuaW1wb3J0IHsgRnNDaGlwTW9kdWxlIH0gZnJvbSAnQGZpcmVzdGl0Y2gvY2hpcCc7XG5pbXBvcnQgeyBGc0RhdGVNb2R1bGUgfSBmcm9tICdAZmlyZXN0aXRjaC9kYXRlJztcbmltcG9ydCB7IEZzTWVzc2FnZSwgRnNNZXNzYWdlTW9kdWxlIH0gZnJvbSAnQGZpcmVzdGl0Y2gvbWVzc2FnZSc7XG5pbXBvcnQgeyBGc1Byb2Nlc3MgfSBmcm9tICdAZmlyZXN0aXRjaC9wcm9jZXNzJztcbmltcG9ydCB7IEZzUHJvbXB0IH0gZnJvbSAnQGZpcmVzdGl0Y2gvcHJvbXB0JztcbmltcG9ydCB7IEZzU2tlbGV0b25Nb2R1bGUgfSBmcm9tICdAZmlyZXN0aXRjaC9za2VsZXRvbic7XG5cbmltcG9ydCB7IGZpbHRlciwgbWFwLCBzd2l0Y2hNYXAsIHRha2UgfSBmcm9tICdyeGpzL29wZXJhdG9ycyc7XG5cbmltcG9ydCB7IFJlcG9ydERhdGEgfSBmcm9tICcuLi8uLi8uLi8uLi9kYXRhL3JlcG9ydC5kYXRhJztcbmltcG9ydCB7XG4gIFNlbWFudGljQnVpbGRFbnRpdHksXG4gIFNlbWFudGljQnVpbGRTdGFnZSxcbiAgU2VtYW50aWNCdWlsZFN0YXR1cyxcbiAgU2VtYW50aWNFbnRpdHlGdW5jdGlvbnMsXG59IGZyb20gJy4uLy4uLy4uLy4uL2ludGVyZmFjZXMvcmVwb3J0LmludGVyZmFjZSc7XG5cblxuLy8gVGhlIFNlbWFudGljIERhdGFiYXNlIHRhYjogdGhlIG1vZGVsIHNjb3JlYm9hcmQgdGhlIHJlcG9ydCBBSSBpcyBidWlsdCBmcm9tLlxuLy8gU2hvd3MgdGhlIGxhc3QgYnVpbGQncyBzdGF0dXMsIHJ1bnMgKG9yIHN0b3BzKSBhIGJ1aWxkIOKAlCBzdHJlYW1lZCBpbnRvIHRoZVxuLy8gRnNQcm9jZXNzIGRvY2sgc28gaXQgc3Vydml2ZXMgdGhlIGRpYWxvZyBjbG9zaW5nIOKAlCBhbmQgZHJpbGxzIGludG8gZXZlcnlcbi8vIGVudGl0eSB0byByZXZlYWwgaXRzIHNoYXBlLCBpbmxpbmVkIGVudW0gdmFsdWVzLCBjb21wdXRlZCBmaWVsZHMgYW5kIHRoZVxuLy8gQUktY2xhc3NpZmllZCBjb2RlIGZ1bmN0aW9ucyBjYWNoZWQgZnJvbSBpdHMgbW9kZWwgY2xhc3MuIEVhY2ggZW50aXR5J3Ncbi8vIGZ1bmN0aW9ucyBsb2FkIGxhemlseSBvbiBmaXJzdCBleHBhbmQsIGJlY2F1c2UgdGhlIGZ1bGwgc2V0IGFjcm9zcyBhbGxcbi8vIGVudGl0aWVzIGlzIGZhciB0b28gYmlnIHRvIHNoaXAgd2l0aCB0aGUgc2NvcmVib2FyZC5cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ2ZzLWFpLXJlcG9ydC1nbG9iYWwtc2V0dGluZ3Mtc2VtYW50aWMtZGF0YWJhc2UnLFxuICB0ZW1wbGF0ZVVybDogJy4vc2VtYW50aWMtZGF0YWJhc2UuY29tcG9uZW50Lmh0bWwnLFxuICBzdHlsZVVybHM6IFsnLi9zZW1hbnRpYy1kYXRhYmFzZS5jb21wb25lbnQuc2NzcyddLFxuICBjaGFuZ2VEZXRlY3Rpb246IENoYW5nZURldGVjdGlvblN0cmF0ZWd5Lk9uUHVzaCxcbiAgc3RhbmRhbG9uZTogdHJ1ZSxcbiAgaW1wb3J0czogW1xuICAgIE1hdEJ1dHRvbixcbiAgICBNYXRFeHBhbnNpb25Nb2R1bGUsXG4gICAgTWF0VG9vbHRpcE1vZHVsZSxcbiAgICBGc0NoaXBNb2R1bGUsXG4gICAgRnNEYXRlTW9kdWxlLFxuICAgIEZzTWVzc2FnZU1vZHVsZSxcbiAgICBGc1NrZWxldG9uTW9kdWxlLFxuICBdLFxufSlcbmV4cG9ydCBjbGFzcyBTZW1hbnRpY0RhdGFiYXNlQ29tcG9uZW50IHtcblxuICAvLyBUaGUgYnVpbGQtaW4tZmxpZ2h0IHN0YXRlcyBvZiB0aGUgZmZfcHJvY2Vzc2VzIHJvdyAocXVldWVkL3J1bm5pbmcvc3RvcHBpbmcpLlxuICBwcml2YXRlIHN0YXRpYyByZWFkb25seSBBQ1RJVkVfU1RBVEVTID0gWydRJywgJ1InLCAnWCddO1xuXG4gIHByaXZhdGUgc3RhdGljIHJlYWRvbmx5IFNUQVRFX0xBQkVMUzogUmVjb3JkPHN0cmluZywgc3RyaW5nPiA9IHtcbiAgICBROiAnUXVldWVkJyxcbiAgICBSOiAnUnVubmluZycsXG4gICAgWDogJ1N0b3BwaW5nJyxcbiAgICBDOiAnQ29tcGxldGVkJyxcbiAgICBLOiAnU3RvcHBlZCcsXG4gICAgRjogJ0ZhaWxlZCcsXG4gIH07XG5cbiAgLy8gU2NvcmVib2FyZCBjb21wbGV0aW9uIHBhbGV0dGU6IGJ1aWx0ID0gZ3JlZW4sIGV2ZXJ5dGhpbmcgZWxzZSAobmVlZHNcbiAgLy8gYnVpbGRpbmcpID0gZ3JleS4gTm8gZXJyb3IgcmVkIOKAlCBhIG1pc3Npbmcgc3RhZ2UgaXMgdW5idWlsdCBjb250ZW50LCBub3QgYVxuICAvLyBmYWlsdXJlLlxuICBwcml2YXRlIHN0YXRpYyByZWFkb25seSBET05FX0NPTE9SID0gJyMyZTdkMzInO1xuICBwcml2YXRlIHN0YXRpYyByZWFkb25seSBQRU5ESU5HX0NPTE9SID0gJyM5ZTllOWUnO1xuXG4gIC8vIE9uZSBjb2xvciBwZXIgQUkgY2xhc3NpZmljYXRpb24ga2luZCwgc28gYSBmdW5jdGlvbidzIG5hdHVyZSByZWFkcyBhdCBhIGdsYW5jZS5cbiAgcHJpdmF0ZSBzdGF0aWMgcmVhZG9ubHkgS0lORF9DT0xPUlM6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4gPSB7XG4gICAgJ2NhbGN1bGF0aW9uJzogJyMxNTY1YzAnLFxuICAgICdidXNpbmVzcy1ydWxlJzogJyM2YTFiOWEnLFxuICAgICdxdWVyeSc6ICcjMDA2OTVjJyxcbiAgICAnbXV0YXRpb24nOiAnI2U2NTEwMCcsXG4gICAgJ2FjY2Vzc29yJzogJyM1NDZlN2EnLFxuICAgICdvdGhlcic6ICcjNzU3NTc1JyxcbiAgfTtcblxuICAvLyBJbnRlcmVzdGluZyBsb2dpYyBmaXJzdDogZGVyaXZlZCB2YWx1ZXMgYW5kIHJ1bGVzLCB0aGVuIGRhdGEgYWNjZXNzLCB0aGVuIHRoZSByZXN0LlxuICBwcml2YXRlIHN0YXRpYyByZWFkb25seSBLSU5EX09SREVSID0gWydjYWxjdWxhdGlvbicsICdidXNpbmVzcy1ydWxlJywgJ3F1ZXJ5JywgJ211dGF0aW9uJywgJ2FjY2Vzc29yJywgJ290aGVyJ107XG5cbiAgLy8gVGhlIHNjb3JlYm9hcmQncyBwZXItZW50aXR5IHN0YWdlIGNoaXBzLCBsZWZ0IHRvIHJpZ2h0LlxuICBwdWJsaWMgcmVhZG9ubHkgc3RhZ2VLZXlzID0gWydpbnRyb3NwZWN0ZWQnLCAnZW51bXNJbmxpbmVkJywgJ2NvbXB1dGVkJywgJ2Z1bmN0aW9ucyddO1xuXG4gIHB1YmxpYyByZWFkb25seSBzdGFnZUxhYmVsczogUmVjb3JkPHN0cmluZywgc3RyaW5nPiA9IHtcbiAgICBpbnRyb3NwZWN0ZWQ6ICdJbnRyb3NwZWN0ZWQnLFxuICAgIGVudW1zSW5saW5lZDogJ0VudW0gY2FzZXMnLFxuICAgIGNvbXB1dGVkOiAnQ29tcHV0ZWQnLFxuICAgIGZ1bmN0aW9uczogJ0Z1bmN0aW9ucycsXG4gIH07XG5cbiAgLy8gbnVsbCB1bnRpbCBsb2FkZWQg4oCUIGdhdGVzIHRoZSB0YWIgYmVoaW5kIHRoZSBza2VsZXRvbi5cbiAgcHVibGljIHJlYWRvbmx5IHN0YXR1cyA9IHNpZ25hbDxTZW1hbnRpY0J1aWxkU3RhdHVzIHwgbnVsbD4obnVsbCk7XG5cbiAgLy8gVHJ1ZSB3aGlsZSBhIGJ1aWxkIHN0YXJ0ZWQgZnJvbSB0aGlzIHRhYiBpcyBzdHJlYW1pbmcgaW50byB0aGUgZG9jay5cbiAgcHVibGljIHJlYWRvbmx5IGJ1aWxkaW5nID0gc2lnbmFsKGZhbHNlKTtcblxuICBwdWJsaWMgcmVhZG9ubHkgYnVpbGRBY3RpdmUgPSBjb21wdXRlZDxib29sZWFuPigoKSA9PlxuICAgIHRoaXMuYnVpbGRpbmcoKVxuICAgICAgfHwgU2VtYW50aWNEYXRhYmFzZUNvbXBvbmVudC5BQ1RJVkVfU1RBVEVTLmluY2x1ZGVzKHRoaXMuc3RhdHVzKCk/LmJ1aWxkPy5zdGF0ZSksXG4gICk7XG5cbiAgcHVibGljIHJlYWRvbmx5IGJ1aWxkU3RhdGVMYWJlbCA9IGNvbXB1dGVkPHN0cmluZz4oKCkgPT5cbiAgICBTZW1hbnRpY0RhdGFiYXNlQ29tcG9uZW50LlNUQVRFX0xBQkVMU1t0aGlzLnN0YXR1cygpPy5idWlsZD8uc3RhdGVdID8/ICcnLFxuICApO1xuXG4gIC8vIFBlci1lbnRpdHkgZnVuY3Rpb24gY2FjaGVzLCBsb2FkZWQgb24gZmlyc3QgZXhwYW5kLiB1bmRlZmluZWQgPSBub3RcbiAgLy8gcmVxdWVzdGVkIHlldCwgbnVsbCA9IHJlcXVlc3QgaW4gZmxpZ2h0ICh0aGUgc2tlbGV0b24gd2luZG93KSwgb2JqZWN0ID0gbG9hZGVkLlxuICBwcml2YXRlIHJlYWRvbmx5IF9lbnRpdHlGdW5jdGlvbnMgPSBzaWduYWw8UmVjb3JkPHN0cmluZywgU2VtYW50aWNFbnRpdHlGdW5jdGlvbnMgfCBudWxsPj4oe30pO1xuXG4gIHByaXZhdGUgcmVhZG9ubHkgX3JlcG9ydERhdGEgPSBpbmplY3QoUmVwb3J0RGF0YSk7XG4gIHByaXZhdGUgcmVhZG9ubHkgX3Byb2Nlc3MgPSBpbmplY3QoRnNQcm9jZXNzKTtcbiAgcHJpdmF0ZSByZWFkb25seSBfcHJvbXB0ID0gaW5qZWN0KEZzUHJvbXB0KTtcbiAgcHJpdmF0ZSByZWFkb25seSBfbWVzc2FnZSA9IGluamVjdChGc01lc3NhZ2UpO1xuICBwcml2YXRlIHJlYWRvbmx5IF9kZXN0cm95UmVmID0gaW5qZWN0KERlc3Ryb3lSZWYpO1xuXG4gIGNvbnN0cnVjdG9yKCkge1xuICAgIHRoaXMuX2luaXQoKTtcbiAgfVxuXG4gIC8vIFJ1biB0aGUgc2VtYW50aWMtZGF0YWJhc2UgYnVpbGQuIFRoZSBsaXZlIGZlZWQgc3RyZWFtcyBpbnRvIHRoZSBGc1Byb2Nlc3NcbiAgLy8gZG9jayAoYm90dG9tLXJpZ2h0KSwgd2hvc2Ugc3Vic2NyaXB0aW9uIHN1cnZpdmVzIHRoaXMgZGlhbG9nIGNsb3Npbmcg4oCUIHNvXG4gIC8vIGRpc21pc3NpbmcgdGhlIGRpYWxvZyBuZXZlciBpbnRlcnJ1cHRzIGEgcnVubmluZyBidWlsZC5cbiAgcHVibGljIGJ1aWxkKCk6IHZvaWQge1xuICAgIHRoaXMuYnVpbGRpbmcuc2V0KHRydWUpO1xuXG4gICAgY29uc3QgdGFyZ2V0JCA9IHRoaXMuX3JlcG9ydERhdGEuc2VtYW50aWNCdWlsZCgpXG4gICAgICAucGlwZShcbiAgICAgICAgZmlsdGVyKChldmVudCkgPT5cbiAgICAgICAgICBldmVudD8udHlwZSA9PT0gU3RyZWFtRXZlbnRUeXBlLkRhdGFcbiAgICAgICAgICAmJiBldmVudC5kYXRhPy5raW5kID09PSAnbG9nJ1xuICAgICAgICAgICYmIHR5cGVvZiBldmVudC5kYXRhLmxpbmUgPT09ICdzdHJpbmcnKSxcbiAgICAgICAgbWFwKChldmVudCkgPT4gZXZlbnQuZGF0YS5saW5lIGFzIHN0cmluZyksXG4gICAgICApO1xuXG4gICAgdGhpcy5fcHJvY2Vzc1xuICAgICAgLnJ1bignU2VtYW50aWMgZGF0YWJhc2UgYnVpbGQnLCB0YXJnZXQkKVxuICAgICAgLmNvbXBsZXRlZCRcbiAgICAgIC5waXBlKFxuICAgICAgICB0YWtlKDEpLFxuICAgICAgICB0YWtlVW50aWxEZXN0cm95ZWQodGhpcy5fZGVzdHJveVJlZiksXG4gICAgICApXG4gICAgICAuc3Vic2NyaWJlKCgpID0+IHtcbiAgICAgICAgdGhpcy5idWlsZGluZy5zZXQoZmFsc2UpO1xuICAgICAgICAvLyBUaGUgYnVpbGQgcmV3cm90ZSBldmVyeSBlbnRpdHkncyBmdW5jdGlvbiBjYWNoZSDigJQgZHJvcCB0aGUgbG9hZGVkXG4gICAgICAgIC8vIGNvcGllcyBzbyB0aGUgbmV4dCBleHBhbmQgcmVmZXRjaGVzIGZyZXNoIGRhdGEuXG4gICAgICAgIHRoaXMuX2VudGl0eUZ1bmN0aW9ucy5zZXQoe30pO1xuICAgICAgICB0aGlzLl9yZWZyZXNoU3RhdHVzKCk7XG4gICAgICB9KTtcbiAgfVxuXG4gIHB1YmxpYyBzdG9wQnVpbGQoKTogdm9pZCB7XG4gICAgdGhpcy5fcHJvbXB0LmNvbmZpcm0oe1xuICAgICAgdGl0bGU6ICdTdG9wIGJ1aWxkJyxcbiAgICAgIHRlbXBsYXRlOiAnU3RvcCB0aGUgcnVubmluZyBidWlsZD8gVGhlIGN1cnJlbnQgc2VtYW50aWMgZGF0YWJhc2Ugc3RheXMgaW4gcGxhY2UgdW50aWwgYSBidWlsZCBmaW5pc2hlcy4nLFxuICAgICAgY29tbWl0TGFiZWw6ICdTdG9wJyxcbiAgICB9KVxuICAgICAgLnBpcGUoXG4gICAgICAgIHN3aXRjaE1hcCgoKSA9PiB0aGlzLl9yZXBvcnREYXRhLnNlbWFudGljQnVpbGRTdG9wKCkpLFxuICAgICAgICB0YWtlVW50aWxEZXN0cm95ZWQodGhpcy5fZGVzdHJveVJlZiksXG4gICAgICApXG4gICAgICAuc3Vic2NyaWJlKCgpID0+IHtcbiAgICAgICAgdGhpcy5idWlsZGluZy5zZXQoZmFsc2UpO1xuICAgICAgICB0aGlzLl9tZXNzYWdlLnN1Y2Nlc3MoJ1N0b3BwaW5nIHRoZSBidWlsZOKApicpO1xuICAgICAgICB0aGlzLl9yZWZyZXNoU3RhdHVzKCk7XG4gICAgICB9KTtcbiAgfVxuXG4gIHB1YmxpYyBzdGFnZUNvbG9yKHN0YWdlOiBTZW1hbnRpY0J1aWxkU3RhZ2UpOiBzdHJpbmcge1xuICAgIHJldHVybiBzdGFnZSA9PT0gJ2RvbmUnXG4gICAgICA/IFNlbWFudGljRGF0YWJhc2VDb21wb25lbnQuRE9ORV9DT0xPUlxuICAgICAgOiBTZW1hbnRpY0RhdGFiYXNlQ29tcG9uZW50LlBFTkRJTkdfQ09MT1I7XG4gIH1cblxuICBwdWJsaWMgc3RhZ2VUb29sdGlwKHN0YWdlOiBTZW1hbnRpY0J1aWxkU3RhZ2UpOiBzdHJpbmcge1xuICAgIHJldHVybiBzdGFnZSA9PT0gJ2RvbmUnID8gJ0J1aWx0JyA6ICdOZWVkcyBidWlsZGluZyc7XG4gIH1cblxuICBwdWJsaWMga2luZENvbG9yKGtpbmQ6IHN0cmluZyk6IHN0cmluZyB7XG4gICAgcmV0dXJuIFNlbWFudGljRGF0YWJhc2VDb21wb25lbnQuS0lORF9DT0xPUlNba2luZF0gPz8gU2VtYW50aWNEYXRhYmFzZUNvbXBvbmVudC5LSU5EX0NPTE9SUy5vdGhlcjtcbiAgfVxuXG4gIC8qKlxuICAgKiBUaGUgbG9hZGVkIGZ1bmN0aW9uIGNhY2hlIGZvciBhbiBlbnRpdHk6IHVuZGVmaW5lZCB1bnRpbCB0aGUgcGFuZWwgaXMgZmlyc3RcbiAgICogZXhwYW5kZWQsIG51bGwgd2hpbGUgdGhlIHJlcXVlc3QgaXMgaW4gZmxpZ2h0ICh0aGUgc2tlbGV0b24gd2luZG93KSwgdGhlblxuICAgKiB0aGUgbG9hZGVkIGNhY2hlLlxuICAgKi9cbiAgcHVibGljIGVudGl0eUZ1bmN0aW9ucyhrZXk6IHN0cmluZyk6IFNlbWFudGljRW50aXR5RnVuY3Rpb25zIHwgbnVsbCB8IHVuZGVmaW5lZCB7XG4gICAgcmV0dXJuIHRoaXMuX2VudGl0eUZ1bmN0aW9ucygpW2tleV07XG4gIH1cblxuICAvKipcbiAgICogRmlyc3QgZXhwYW5kIG9mIGFuIGVudGl0eTogZmV0Y2ggaXRzIGNhY2hlZCBmdW5jdGlvbnMgdGhyb3VnaCB0aGUgcGVyLWVudGl0eVxuICAgKiBlbmRwb2ludC4gU3Vic2VxdWVudCBleHBhbmRzIHJldXNlIHRoZSBsb2FkZWQgY29weSAoYSBmaW5pc2hlZCBidWlsZCBjbGVhcnNcbiAgICogdGhlIGNvcGllcyBzbyBhIHJlLWV4cGFuZCByZWZldGNoZXMgZnJlc2ggZGF0YSkuXG4gICAqL1xuICBwdWJsaWMgZW50aXR5T3BlbmVkKGVudGl0eTogU2VtYW50aWNCdWlsZEVudGl0eSk6IHZvaWQge1xuICAgIGlmICh0aGlzLl9lbnRpdHlGdW5jdGlvbnMoKVtlbnRpdHkua2V5XSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgdGhpcy5fZW50aXR5RnVuY3Rpb25zLnVwZGF0ZSgobG9hZGVkKSA9PiAoeyAuLi5sb2FkZWQsIFtlbnRpdHkua2V5XTogbnVsbCB9KSk7XG5cbiAgICB0aGlzLl9yZXBvcnREYXRhLnNlbWFudGljRW50aXR5RnVuY3Rpb25zKGVudGl0eS5rZXkpXG4gICAgICAucGlwZSh0YWtlVW50aWxEZXN0cm95ZWQodGhpcy5fZGVzdHJveVJlZikpXG4gICAgICAuc3Vic2NyaWJlKChlbnRpdHlGdW5jdGlvbnM6IFNlbWFudGljRW50aXR5RnVuY3Rpb25zKSA9PiB7XG4gICAgICAgIHRoaXMuX2VudGl0eUZ1bmN0aW9ucy51cGRhdGUoKGxvYWRlZCkgPT4gKHtcbiAgICAgICAgICAuLi5sb2FkZWQsXG4gICAgICAgICAgW2VudGl0eS5rZXldOiB7XG4gICAgICAgICAgICAuLi5lbnRpdHlGdW5jdGlvbnMsXG4gICAgICAgICAgICBmdW5jdGlvbnM6IHRoaXMuX3NvcnRGdW5jdGlvbnMoZW50aXR5RnVuY3Rpb25zKSxcbiAgICAgICAgICB9LFxuICAgICAgICB9KSk7XG4gICAgICB9KTtcbiAgfVxuXG4gIHByaXZhdGUgX2luaXQoKTogdm9pZCB7XG4gICAgdGhpcy5fcmVmcmVzaFN0YXR1cygpO1xuICB9XG5cbiAgcHJpdmF0ZSBfcmVmcmVzaFN0YXR1cygpOiB2b2lkIHtcbiAgICB0aGlzLl9yZXBvcnREYXRhLnNlbWFudGljQnVpbGRTdGF0dXMoKVxuICAgICAgLnBpcGUodGFrZVVudGlsRGVzdHJveWVkKHRoaXMuX2Rlc3Ryb3lSZWYpKVxuICAgICAgLnN1YnNjcmliZSgoc3RhdHVzOiBTZW1hbnRpY0J1aWxkU3RhdHVzKSA9PiB0aGlzLnN0YXR1cy5zZXQoc3RhdHVzKSk7XG4gIH1cblxuICAvKipcbiAgICogT3JkZXIgb25jZSBhdCBsb2FkIHRpbWUgKGtpbmQgcHJpb3JpdHksIHRoZW4gbWV0aG9kIG5hbWUpIHNvIHRoZSB0ZW1wbGF0ZVxuICAgKiByZW5kZXJzIHRoZSBsaXN0IGFzLWlzLlxuICAgKi9cbiAgcHJpdmF0ZSBfc29ydEZ1bmN0aW9ucyhlbnRpdHlGdW5jdGlvbnM6IFNlbWFudGljRW50aXR5RnVuY3Rpb25zKTogU2VtYW50aWNFbnRpdHlGdW5jdGlvbnNbJ2Z1bmN0aW9ucyddIHtcbiAgICByZXR1cm4gWy4uLmVudGl0eUZ1bmN0aW9ucy5mdW5jdGlvbnNdXG4gICAgICAuc29ydCgoYSwgYikgPT4ge1xuICAgICAgICBjb25zdCBraW5kRGlmZiA9IHRoaXMuX2tpbmRSYW5rKGEua2luZCkgLSB0aGlzLl9raW5kUmFuayhiLmtpbmQpO1xuXG4gICAgICAgIHJldHVybiBraW5kRGlmZiAhPT0gMCA/IGtpbmREaWZmIDogYS5tZXRob2QubG9jYWxlQ29tcGFyZShiLm1ldGhvZCk7XG4gICAgICB9KTtcbiAgfVxuXG4gIHByaXZhdGUgX2tpbmRSYW5rKGtpbmQ6IHN0cmluZyk6IG51bWJlciB7XG4gICAgY29uc3QgcmFuayA9IFNlbWFudGljRGF0YWJhc2VDb21wb25lbnQuS0lORF9PUkRFUi5pbmRleE9mKGtpbmQpO1xuXG4gICAgcmV0dXJuIHJhbmsgPT09IC0xID8gU2VtYW50aWNEYXRhYmFzZUNvbXBvbmVudC5LSU5EX09SREVSLmxlbmd0aCA6IHJhbms7XG4gIH1cbn1cbiIsIjxkaXYgY2xhc3M9XCJmcy1jb2x1bW4gdGFiLWJvZHlcIj5cbiAgPHAgY2xhc3M9XCJoaW50XCI+XG4gICAgVGhlIHNlbWFudGljIGRhdGFiYXNlIGlzIHdoYXQgdGhlIHJlcG9ydCBBSSB1c2VzIHRvIHVuZGVyc3RhbmQgeW91ciBkYXRhIOKAlFxuICAgIHRhYmxlcywgcmVsYXRpb25zaGlwcyBhbmQgdGhlIGNhbGN1bGF0aW9ucyBpbiBjb2RlLiBSZWJ1aWxkIGl0IGFmdGVyXG4gICAgc2lnbmlmaWNhbnQgYXBwbGljYXRpb24gdXBkYXRlcy4gVGhlIGJ1aWxkIHJ1bnMgaW4gdGhlIGJhY2tncm91bmQ7IHByb2dyZXNzXG4gICAgYXBwZWFycyBpbiB0aGUgZG9jayBhdCB0aGUgYm90dG9tIHJpZ2h0IGFuZCB0aGlzIGRpYWxvZyBjYW4gYmUgY2xvc2VkIHdoaWxlXG4gICAgaXQgcnVucy5cbiAgPC9wPlxuXG4gIDxkaXYgKmZzU2tlbGV0b249XCJzdGF0dXMoKVwiPlxuICAgIEBpZiAoc3RhdHVzKCk7IGFzIGJ1aWxkU3RhdHVzKSB7XG4gICAgICA8ZGl2IGNsYXNzPVwiYnVpbGQtc3RhdHVzXCI+XG4gICAgICAgIEBpZiAoYnVpbGRTdGF0dXMuZGV0YWlsLmdlbmVyYXRlZEF0KSB7XG4gICAgICAgICAgPGRpdiBjbGFzcz1cInN0YXRcIj5cbiAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwibGFiZWxcIj5MYXN0IGJ1aWx0PC9zcGFuPlxuICAgICAgICAgICAgPGZzLWRhdGVcbiAgICAgICAgICAgICAgICBbZGF0ZV09XCJidWlsZFN0YXR1cy5kZXRhaWwuZ2VuZXJhdGVkQXRcIlxuICAgICAgICAgICAgICAgIGZvcm1hdD1cImRhdGUtdGltZVwiPlxuICAgICAgICAgICAgPC9mcy1kYXRlPlxuICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgIDxkaXYgY2xhc3M9XCJzdGF0XCI+XG4gICAgICAgICAgICA8c3BhbiBjbGFzcz1cImxhYmVsXCI+Q292ZXJhZ2U8L3NwYW4+XG4gICAgICAgICAgICA8c3Bhbj5cbiAgICAgICAgICAgICAge3sgYnVpbGRTdGF0dXMuZGV0YWlsLmVudGl0eUNvdW50IH19IGVudGl0aWVzIMK3XG4gICAgICAgICAgICAgIHt7IGJ1aWxkU3RhdHVzLmRldGFpbC5mdW5jdGlvbkNvdW50IH19IGNvZGUgZnVuY3Rpb25zXG4gICAgICAgICAgICA8L3NwYW4+XG4gICAgICAgICAgPC9kaXY+XG4gICAgICAgIH0gQGVsc2Uge1xuICAgICAgICAgIDxmcy1tZXNzYWdlLXdhcm5pbmc+XG4gICAgICAgICAgICBUaGUgc2VtYW50aWMgZGF0YWJhc2UgaGFzIG5vdCBiZWVuIGJ1aWx0IHlldCDigJQgdGhlIHJlcG9ydCBBSSBjYW4ndFxuICAgICAgICAgICAgYW5zd2VyIGRhdGEgcXVlc3Rpb25zIHVudGlsIGl0IGlzLiBSdW4gdGhlIGZpcnN0IGJ1aWxkLlxuICAgICAgICAgIDwvZnMtbWVzc2FnZS13YXJuaW5nPlxuICAgICAgICB9XG4gICAgICAgIEBpZiAoYnVpbGRTdGF0dXMuYnVpbGQpIHtcbiAgICAgICAgICA8ZGl2IGNsYXNzPVwic3RhdFwiPlxuICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJsYWJlbFwiPkxhc3QgYnVpbGQgcnVuPC9zcGFuPlxuICAgICAgICAgICAgPHNwYW4+XG4gICAgICAgICAgICAgIHt7IGJ1aWxkU3RhdGVMYWJlbCgpIH19XG4gICAgICAgICAgICAgIEBpZiAoYnVpbGRTdGF0dXMuYnVpbGQubWVzc2FnZSkge1xuICAgICAgICAgICAgICAgIOKAlCB7eyBidWlsZFN0YXR1cy5idWlsZC5tZXNzYWdlIH19XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIDwvc3Bhbj5cbiAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgfVxuICAgICAgPC9kaXY+XG5cbiAgICAgIDxkaXYgY2xhc3M9XCJidWlsZC1hY3Rpb25zXCI+XG4gICAgICAgIEBpZiAoYnVpbGRBY3RpdmUoKSkge1xuICAgICAgICAgIDxidXR0b25cbiAgICAgICAgICAgICAgdHlwZT1cImJ1dHRvblwiXG4gICAgICAgICAgICAgIG1hdC1idXR0b25cbiAgICAgICAgICAgICAgY29sb3I9XCJ3YXJuXCJcbiAgICAgICAgICAgICAgKGNsaWNrKT1cInN0b3BCdWlsZCgpXCI+XG4gICAgICAgICAgICBTdG9wIEJ1aWxkXG4gICAgICAgICAgPC9idXR0b24+XG4gICAgICAgIH0gQGVsc2Uge1xuICAgICAgICAgIDxidXR0b25cbiAgICAgICAgICAgICAgdHlwZT1cImJ1dHRvblwiXG4gICAgICAgICAgICAgIG1hdC1idXR0b25cbiAgICAgICAgICAgICAgY29sb3I9XCJwcmltYXJ5XCJcbiAgICAgICAgICAgICAgKGNsaWNrKT1cImJ1aWxkKClcIj5cbiAgICAgICAgICAgIHt7IGJ1aWxkU3RhdHVzLmRldGFpbC5nZW5lcmF0ZWRBdCA/ICdSZWJ1aWxkJyA6ICdCdWlsZCcgfX1cbiAgICAgICAgICA8L2J1dHRvbj5cbiAgICAgICAgfVxuICAgICAgPC9kaXY+XG5cbiAgICAgIDwhLS0gVGhlIG1vZGVsIHNjb3JlYm9hcmQ6IGV2ZXJ5IGVudGl0eSB0aGUgQUkga25vd3MgYWJvdXQsIGl0c1xuICAgICAgICAgICBidWlsdC12cy1uZWVkcy1idWlsZGluZyBzdGFnZXMsIGFuZCBhIGRyaWxsLWRvd24gaW50byBpdHMgc2hhcGUsIGVudW1cbiAgICAgICAgICAgdmFsdWVzLCBjb21wdXRlZCBmaWVsZHMgYW5kIEFJLWNsYXNzaWZpZWQgY29kZSBmdW5jdGlvbnMuIC0tPlxuICAgICAgQGlmIChidWlsZFN0YXR1cy5kZXRhaWwuZW50aXRpZXM/Lmxlbmd0aCkge1xuICAgICAgICA8bWF0LWFjY29yZGlvbiBjbGFzcz1cImVudGl0aWVzXCI+XG4gICAgICAgICAgQGZvciAoZW50aXR5IG9mIGJ1aWxkU3RhdHVzLmRldGFpbC5lbnRpdGllczsgdHJhY2sgZW50aXR5LmtleSkge1xuICAgICAgICAgICAgPG1hdC1leHBhbnNpb24tcGFuZWwgKG9wZW5lZCk9XCJlbnRpdHlPcGVuZWQoZW50aXR5KVwiPlxuICAgICAgICAgICAgICA8bWF0LWV4cGFuc2lvbi1wYW5lbC1oZWFkZXI+XG4gICAgICAgICAgICAgICAgPG1hdC1wYW5lbC10aXRsZT57eyBlbnRpdHkua2V5IH19PC9tYXQtcGFuZWwtdGl0bGU+XG4gICAgICAgICAgICAgICAgPG1hdC1wYW5lbC1kZXNjcmlwdGlvbj5cbiAgICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJzdGFnZS1jaGlwc1wiPlxuICAgICAgICAgICAgICAgICAgICBAZm9yIChzdGFnZSBvZiBzdGFnZUtleXM7IHRyYWNrIHN0YWdlKSB7XG4gICAgICAgICAgICAgICAgICAgICAgPGZzLWNoaXBcbiAgICAgICAgICAgICAgICAgICAgICAgICAgc2l6ZT1cInRpbnlcIlxuICAgICAgICAgICAgICAgICAgICAgICAgICBbYmFja2dyb3VuZENvbG9yXT1cInN0YWdlQ29sb3IoZW50aXR5LnN0YWdlc1tzdGFnZV0pXCJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3I9XCIjZmZmZmZmXCJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgW21hdFRvb2x0aXBdPVwic3RhZ2VUb29sdGlwKGVudGl0eS5zdGFnZXNbc3RhZ2VdKVwiPlxuICAgICAgICAgICAgICAgICAgICAgICAge3sgc3RhZ2VMYWJlbHNbc3RhZ2VdIH19XG4gICAgICAgICAgICAgICAgICAgICAgPC9mcy1jaGlwPlxuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgICAgICA8L21hdC1wYW5lbC1kZXNjcmlwdGlvbj5cbiAgICAgICAgICAgICAgPC9tYXQtZXhwYW5zaW9uLXBhbmVsLWhlYWRlcj5cblxuICAgICAgICAgICAgICA8IS0tIERlZmVycmVkOiB0aGUgYm9keSAoYW5kIGl0cyBmdW5jdGlvbnMgcmVxdWVzdCkgb25seSBleGlzdHNcbiAgICAgICAgICAgICAgICAgICBvbmNlIGV4cGFuZGVkLiAtLT5cbiAgICAgICAgICAgICAgPG5nLXRlbXBsYXRlIG1hdEV4cGFuc2lvblBhbmVsQ29udGVudD5cbiAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwiZW50aXR5LWRldGFpbFwiPlxuICAgICAgICAgICAgICAgICAgPGRpdj48c3Ryb25nPlRhYmxlOjwvc3Ryb25nPiB7eyBlbnRpdHkudGFibGUgfX08L2Rpdj5cbiAgICAgICAgICAgICAgICAgIDxkaXY+PHN0cm9uZz5Db2x1bW5zOjwvc3Ryb25nPiB7eyBlbnRpdHkuY29sdW1ucyB9fTwvZGl2PlxuICAgICAgICAgICAgICAgICAgPGRpdj48c3Ryb25nPlJlbGF0aW9uc2hpcHM6PC9zdHJvbmc+IHt7IGVudGl0eS5yZWxhdGlvbnNoaXBzIH19PC9kaXY+XG4gICAgICAgICAgICAgICAgICBAaWYgKGVudGl0eS5lbnVtcy5sZW5ndGgpIHtcbiAgICAgICAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cImVudW0tbGlzdFwiPlxuICAgICAgICAgICAgICAgICAgICAgIDxzdHJvbmc+RW51bSB2YWx1ZXM6PC9zdHJvbmc+XG4gICAgICAgICAgICAgICAgICAgICAgQGZvciAoZW51bUNvbHVtbiBvZiBlbnRpdHkuZW51bXM7IHRyYWNrIGVudW1Db2x1bW4uY29sdW1uKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwiZW51bS1yb3dcIj5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJlbnVtLWNvbHVtblwiPnt7IGVudW1Db2x1bW4uY29sdW1uIH19PC9zcGFuPlxuICAgICAgICAgICAgICAgICAgICAgICAgICA8c3BhbiBjbGFzcz1cImVudW0tdmFsdWVzXCI+e3sgZW51bUNvbHVtbi52YWx1ZXMuam9pbignLCAnKSB9fTwvc3Bhbj5cbiAgICAgICAgICAgICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICBAaWYgKGVudGl0eS5jb21wdXRlZEZpZWxkcy5sZW5ndGgpIHtcbiAgICAgICAgICAgICAgICAgICAgPGRpdj48c3Ryb25nPkNvbXB1dGVkIGZpZWxkczo8L3N0cm9uZz4ge3sgZW50aXR5LmNvbXB1dGVkRmllbGRzLmpvaW4oJywgJykgfX08L2Rpdj5cbiAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cImZ1bmN0aW9ucy1zZWN0aW9uXCI+XG4gICAgICAgICAgICAgICAgICAgIDxoMyBjbGFzcz1cImZ1bmN0aW9ucy1oZWFkaW5nXCI+XG4gICAgICAgICAgICAgICAgICAgICAgQ29kZSBmdW5jdGlvbnNcbiAgICAgICAgICAgICAgICAgICAgICBAaWYgKGVudGl0eS5mdW5jdGlvbkNvdW50KSB7XG4gICAgICAgICAgICAgICAgICAgICAgICA8c3BhbiBjbGFzcz1cImZ1bmN0aW9ucy1jb3VudFwiPih7eyBlbnRpdHkuZnVuY3Rpb25Db3VudCB9fSk8L3NwYW4+XG4gICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICA8L2gzPlxuXG4gICAgICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJmdW5jdGlvbnMtYm9keVwiICpmc1NrZWxldG9uPVwiZW50aXR5RnVuY3Rpb25zKGVudGl0eS5rZXkpXCI+XG4gICAgICAgICAgICAgICAgICAgICAgQGlmIChlbnRpdHlGdW5jdGlvbnMoZW50aXR5LmtleSk7IGFzIGZucykge1xuICAgICAgICAgICAgICAgICAgICAgICAgQGlmIChmbnMuZnVuY3Rpb25zLmxlbmd0aCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICBAaWYgKGZucy5nZW5lcmF0ZWRBdCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJoaW50IGZ1bmN0aW9ucy1nZW5lcmF0ZWRcIj5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIERpc2NvdmVyZWQgZnJvbSB7eyBmbnMuY2xhc3MgfX0gJm1pZGRvdDtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxmcy1kYXRlXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgW2RhdGVdPVwiZm5zLmdlbmVyYXRlZEF0XCJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmb3JtYXQ9XCJkYXRlLXRpbWVcIj5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvZnMtZGF0ZT5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwiZnVuY3Rpb25zLWxpc3RcIj5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBAZm9yIChmbiBvZiBmbnMuZnVuY3Rpb25zOyB0cmFjayBmbi5tZXRob2QpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJmdW5jdGlvbi1yb3dcIj5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cImZ1bmN0aW9uLWhlYWRcIj5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8ZnMtY2hpcFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaXplPVwidGlueVwiXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFtiYWNrZ3JvdW5kQ29sb3JdPVwia2luZENvbG9yKGZuLmtpbmQpXCJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3I9XCIjZmZmZmZmXCI+XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB7eyBmbi5raW5kIH19XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9mcy1jaGlwPlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxjb2RlIGNsYXNzPVwiZnVuY3Rpb24tbWV0aG9kXCI+e3sgZm4ubWV0aG9kIH19PC9jb2RlPlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cImZ1bmN0aW9uLXN1bW1hcnlcIj57eyBmbi5zdW1tYXJ5IH19PC9kaXY+XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEBpZiAoZm4ucHJvZHVjZXMpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwiZnVuY3Rpb24tcHJvZHVjZXMgaGludFwiPlByb2R1Y2VzOiB7eyBmbi5wcm9kdWNlcyB9fTwvZGl2PlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgICAgICAgICAgICAgfSBAZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJoaW50XCI+XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgTm8gZnVuY3Rpb25zIGNhY2hlZCBmb3IgdGhpcyBlbnRpdHkgeWV0IOKAlCBydW4gYSBidWlsZCB0byBkaXNjb3ZlciBpdHMgY29kZS5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgICA8L25nLXRlbXBsYXRlPlxuICAgICAgICAgICAgPC9tYXQtZXhwYW5zaW9uLXBhbmVsPlxuICAgICAgICAgIH1cbiAgICAgICAgPC9tYXQtYWNjb3JkaW9uPlxuICAgICAgfVxuICAgIH1cbiAgPC9kaXY+XG48L2Rpdj5cbiJdfQ==
250
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VtYW50aWMtZGF0YWJhc2UuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vc3JjL2FwcC9yZXBvcnRzL2RpYWxvZ3MvZ2xvYmFsLXNldHRpbmdzL2NvbXBvbmVudHMvc2VtYW50aWMtZGF0YWJhc2Uvc2VtYW50aWMtZGF0YWJhc2UuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vc3JjL2FwcC9yZXBvcnRzL2RpYWxvZ3MvZ2xvYmFsLXNldHRpbmdzL2NvbXBvbmVudHMvc2VtYW50aWMtZGF0YWJhc2Uvc2VtYW50aWMtZGF0YWJhc2UuY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLHVCQUF1QixFQUFFLFNBQVMsRUFBRSxVQUFVLEVBQUUsUUFBUSxFQUFFLE1BQU0sRUFBRSxNQUFNLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDekcsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sNEJBQTRCLENBQUM7QUFFaEUsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sNkJBQTZCLENBQUM7QUFDakUsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sMkJBQTJCLENBQUM7QUFFN0QsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQ2xELE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQztBQUNoRCxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sa0JBQWtCLENBQUM7QUFDaEQsT0FBTyxFQUFFLFNBQVMsRUFBRSxlQUFlLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQUNqRSxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDaEQsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBQzlDLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBRXhELE9BQU8sRUFBRSxNQUFNLEVBQUUsR0FBRyxFQUFFLFNBQVMsRUFBRSxJQUFJLEVBQUUsR0FBRyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFFbkUsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLDhCQUE4QixDQUFDOzs7Ozs7OztBQVMxRCwrRUFBK0U7QUFDL0UsNkVBQTZFO0FBQzdFLDJFQUEyRTtBQUMzRSwyRUFBMkU7QUFDM0UsMEVBQTBFO0FBQzFFLHlFQUF5RTtBQUN6RSx1REFBdUQ7QUFnQnZELE1BQU0sT0FBTyx5QkFBeUI7SUFFcEMsZ0ZBQWdGO0lBQ3hFLE1BQU0sQ0FBVSxhQUFhLEdBQUcsQ0FBQyxHQUFHLEVBQUUsR0FBRyxFQUFFLEdBQUcsQ0FBQyxDQUFDO0lBRWhELE1BQU0sQ0FBVSxZQUFZLEdBQTJCO1FBQzdELENBQUMsRUFBRSxRQUFRO1FBQ1gsQ0FBQyxFQUFFLFNBQVM7UUFDWixDQUFDLEVBQUUsVUFBVTtRQUNiLENBQUMsRUFBRSxXQUFXO1FBQ2QsQ0FBQyxFQUFFLFNBQVM7UUFDWixDQUFDLEVBQUUsUUFBUTtLQUNaLENBQUM7SUFFRix1RUFBdUU7SUFDdkUsNkVBQTZFO0lBQzdFLFdBQVc7SUFDSCxNQUFNLENBQVUsVUFBVSxHQUFHLFNBQVMsQ0FBQztJQUN2QyxNQUFNLENBQVUsYUFBYSxHQUFHLFNBQVMsQ0FBQztJQUVsRCxrRkFBa0Y7SUFDMUUsTUFBTSxDQUFVLFdBQVcsR0FBMkI7UUFDNUQsYUFBYSxFQUFFLFNBQVM7UUFDeEIsZUFBZSxFQUFFLFNBQVM7UUFDMUIsT0FBTyxFQUFFLFNBQVM7UUFDbEIsVUFBVSxFQUFFLFNBQVM7UUFDckIsVUFBVSxFQUFFLFNBQVM7UUFDckIsT0FBTyxFQUFFLFNBQVM7S0FDbkIsQ0FBQztJQUVGLHNGQUFzRjtJQUM5RSxNQUFNLENBQVUsVUFBVSxHQUFHLENBQUMsYUFBYSxFQUFFLGVBQWUsRUFBRSxPQUFPLEVBQUUsVUFBVSxFQUFFLFVBQVUsRUFBRSxPQUFPLENBQUMsQ0FBQztJQUVoSCwwREFBMEQ7SUFDMUMsU0FBUyxHQUFHLENBQUMsY0FBYyxFQUFFLGNBQWMsRUFBRSxVQUFVLEVBQUUsV0FBVyxDQUFDLENBQUM7SUFFdEUsV0FBVyxHQUEyQjtRQUNwRCxZQUFZLEVBQUUsY0FBYztRQUM1QixZQUFZLEVBQUUsWUFBWTtRQUMxQixRQUFRLEVBQUUsVUFBVTtRQUNwQixTQUFTLEVBQUUsV0FBVztLQUN2QixDQUFDO0lBRUYseURBQXlEO0lBQ3pDLE1BQU0sR0FBRyxNQUFNLENBQTZCLElBQUksQ0FBQyxDQUFDO0lBRWxFLHVFQUF1RTtJQUN2RCxRQUFRLEdBQUcsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBRXpCLFdBQVcsR0FBRyxRQUFRLENBQVUsR0FBRyxFQUFFLENBQ25ELElBQUksQ0FBQyxRQUFRLEVBQUU7V0FDVix5QkFBeUIsQ0FBQyxhQUFhLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxNQUFNLEVBQUUsRUFBRSxLQUFLLEVBQUUsS0FBSyxDQUFDLENBQ25GLENBQUM7SUFFYyxlQUFlLEdBQUcsUUFBUSxDQUFTLEdBQUcsRUFBRSxDQUN0RCx5QkFBeUIsQ0FBQyxZQUFZLENBQUMsSUFBSSxDQUFDLE1BQU0sRUFBRSxFQUFFLEtBQUssRUFBRSxLQUFLLENBQUMsSUFBSSxFQUFFLENBQzFFLENBQUM7SUFFRixzRUFBc0U7SUFDdEUsa0ZBQWtGO0lBQ2pFLGdCQUFnQixHQUFHLE1BQU0sQ0FBaUQsRUFBRSxDQUFDLENBQUM7SUFFL0YsK0VBQStFO0lBQy9FLGtFQUFrRTtJQUMxRCxlQUFlLEdBQUcsS0FBSyxDQUFDO0lBRWYsV0FBVyxHQUFHLE1BQU0sQ0FBQyxVQUFVLENBQUMsQ0FBQztJQUNqQyxRQUFRLEdBQUcsTUFBTSxDQUFDLFNBQVMsQ0FBQyxDQUFDO0lBQzdCLE9BQU8sR0FBRyxNQUFNLENBQUMsUUFBUSxDQUFDLENBQUM7SUFDM0IsUUFBUSxHQUFHLE1BQU0sQ0FBQyxTQUFTLENBQUMsQ0FBQztJQUM3QixXQUFXLEdBQUcsTUFBTSxDQUFDLFVBQVUsQ0FBQyxDQUFDO0lBRWxEO1FBQ0UsSUFBSSxDQUFDLEtBQUssRUFBRSxDQUFDO0lBQ2YsQ0FBQztJQUVELHNFQUFzRTtJQUN0RSwrREFBK0Q7SUFDeEQsS0FBSztRQUNWLE1BQU0sT0FBTyxHQUFHLENBQUMsQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFLEVBQUUsTUFBTSxFQUFFLFdBQVcsQ0FBQztRQUVyRCxJQUFJLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQztZQUNuQixLQUFLLEVBQUUsT0FBTyxDQUFDLENBQUMsQ0FBQywyQkFBMkIsQ0FBQyxDQUFDLENBQUMseUJBQXlCO1lBQ3hFLFFBQVEsRUFBRSxPQUFPO2dCQUNmLENBQUMsQ0FBQyx5R0FBeUc7Z0JBQzNHLENBQUMsQ0FBQyx5REFBeUQ7WUFDN0QsV0FBVyxFQUFFLE9BQU8sQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxPQUFPO1NBQzNDLENBQUM7YUFDQyxJQUFJLENBQUMsa0JBQWtCLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxDQUFDO2FBQzFDLFNBQVMsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxJQUFJLENBQUMsU0FBUyxFQUFFLENBQUMsQ0FBQztJQUN2QyxDQUFDO0lBRU0sU0FBUztRQUNkLElBQUksQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDO1lBQ25CLEtBQUssRUFBRSxZQUFZO1lBQ25CLFFBQVEsRUFBRSw4RkFBOEY7WUFDeEcsV0FBVyxFQUFFLE1BQU07U0FDcEIsQ0FBQzthQUNDLElBQUksQ0FDSCxTQUFTLENBQUMsR0FBRyxFQUFFLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxpQkFBaUIsRUFBRSxDQUFDLEVBQ3JELGtCQUFrQixDQUFDLElBQUksQ0FBQyxXQUFXLENBQUMsQ0FDckM7YUFDQSxTQUFTLENBQUMsR0FBRyxFQUFFO1lBQ2QsSUFBSSxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLENBQUM7WUFDekIsSUFBSSxDQUFDLFFBQVEsQ0FBQyxPQUFPLENBQUMscUJBQXFCLENBQUMsQ0FBQztZQUM3QyxJQUFJLENBQUMsY0FBYyxFQUFFLENBQUM7UUFDeEIsQ0FBQyxDQUFDLENBQUM7SUFDUCxDQUFDO0lBRUQsNEVBQTRFO0lBQzVFLDRFQUE0RTtJQUM1RSwwREFBMEQ7SUFDbEQsU0FBUztRQUNmLElBQUksQ0FBQyxRQUFRLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxDQUFDO1FBQ3hCLElBQUksQ0FBQyxlQUFlLEdBQUcsS0FBSyxDQUFDO1FBRTdCLE1BQU0sT0FBTyxHQUFHLElBQUksQ0FBQyxXQUFXLENBQUMsYUFBYSxFQUFFO2FBQzdDLElBQUk7UUFDSCxrRUFBa0U7UUFDbEUsdURBQXVEO1FBQ3ZELEdBQUcsQ0FBQyxFQUFFLEtBQUssRUFBRSxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsSUFBSSxDQUFDLGNBQWMsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLEVBQ3JELE1BQU0sQ0FBQyxDQUFDLEtBQUssRUFBRSxFQUFFLENBQ2YsS0FBSyxFQUFFLElBQUksS0FBSyxlQUFlLENBQUMsSUFBSTtlQUNqQyxLQUFLLENBQUMsSUFBSSxFQUFFLElBQUksS0FBSyxLQUFLO2VBQzFCLE9BQU8sS0FBSyxDQUFDLElBQUksQ0FBQyxJQUFJLEtBQUssUUFBUSxDQUFDLEVBQ3pDLEdBQUcsQ0FBQyxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxJQUFjLENBQUMsQ0FDMUMsQ0FBQztRQUVKLElBQUksQ0FBQyxRQUFRO2FBQ1YsR0FBRyxDQUFDLHlCQUF5QixFQUFFLE9BQU8sQ0FBQzthQUN2QyxVQUFVO2FBQ1YsSUFBSSxDQUNILElBQUksQ0FBQyxDQUFDLENBQUMsRUFDUCxrQkFBa0IsQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLENBQ3JDO2FBQ0EsU0FBUyxDQUFDLEdBQUcsRUFBRSxDQUFDLElBQUksQ0FBQyxjQUFjLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQztJQUNoRCxDQUFDO0lBRUQ7Ozs7OztPQU1HO0lBQ0ssY0FBYyxDQUFDLFdBQW9CO1FBQ3pDLElBQUksSUFBSSxDQUFDLGVBQWUsRUFBRSxDQUFDO1lBQ3pCLE9BQU87UUFDVCxDQUFDO1FBQ0QsSUFBSSxDQUFDLGVBQWUsR0FBRyxJQUFJLENBQUM7UUFFNUIsSUFBSSxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDekIsMkVBQTJFO1FBQzNFLDJDQUEyQztRQUMzQyxJQUFJLENBQUMsZ0JBQWdCLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxDQUFDO1FBRTlCLElBQUksV0FBVyxFQUFFLENBQUM7WUFDaEIsSUFBSSxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsb0ZBQW9GLENBQUMsQ0FBQztZQUMxRyxJQUFJLENBQUMsY0FBYyxFQUFFLENBQUM7WUFFdEIsT0FBTztRQUNULENBQUM7UUFFRCxJQUFJLENBQUMsV0FBVyxDQUFDLG1CQUFtQixFQUFFO2FBQ25DLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLENBQUM7YUFDMUMsU0FBUyxDQUFDLENBQUMsTUFBMkIsRUFBRSxFQUFFO1lBQ3pDLElBQUksQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLE1BQU0sQ0FBQyxDQUFDO1lBQ3hCLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxNQUFNLENBQUMsQ0FBQztRQUNoQyxDQUFDLENBQUMsQ0FBQztJQUNQLENBQUM7SUFFRDs7OztPQUlHO0lBQ0ssZ0JBQWdCLENBQUMsTUFBMkI7UUFDbEQsTUFBTSxLQUFLLEdBQUcsTUFBTSxFQUFFLEtBQUssQ0FBQztRQUM1QixJQUFJLEtBQUssRUFBRSxLQUFLLEtBQUssR0FBRyxJQUFJLEtBQUssRUFBRSxLQUFLLEtBQUssR0FBRyxFQUFFLENBQUM7WUFDakQsSUFBSSxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsS0FBSyxDQUFDLE9BQU8sSUFBSSw2Q0FBNkMsQ0FBQyxDQUFDO1FBQ3RGLENBQUM7YUFBTSxJQUFJLEtBQUssRUFBRSxLQUFLLEtBQUssR0FBRyxFQUFFLENBQUM7WUFDaEMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxPQUFPLENBQUMsbUNBQW1DLENBQUMsQ0FBQztRQUM3RCxDQUFDO0lBQ0gsQ0FBQztJQUVNLFVBQVUsQ0FBQyxLQUF5QjtRQUN6QyxPQUFPLEtBQUssS0FBSyxNQUFNO1lBQ3JCLENBQUMsQ0FBQyx5QkFBeUIsQ0FBQyxVQUFVO1lBQ3RDLENBQUMsQ0FBQyx5QkFBeUIsQ0FBQyxhQUFhLENBQUM7SUFDOUMsQ0FBQztJQUVNLFlBQVksQ0FBQyxLQUF5QjtRQUMzQyxPQUFPLEtBQUssS0FBSyxNQUFNLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsZ0JBQWdCLENBQUM7SUFDdkQsQ0FBQztJQUVNLFNBQVMsQ0FBQyxJQUFZO1FBQzNCLE9BQU8seUJBQXlCLENBQUMsV0FBVyxDQUFDLElBQUksQ0FBQyxJQUFJLHlCQUF5QixDQUFDLFdBQVcsQ0FBQyxLQUFLLENBQUM7SUFDcEcsQ0FBQztJQUVEOzs7O09BSUc7SUFDSSxlQUFlLENBQUMsR0FBVztRQUNoQyxPQUFPLElBQUksQ0FBQyxnQkFBZ0IsRUFBRSxDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBQ3RDLENBQUM7SUFFRDs7OztPQUlHO0lBQ0ksWUFBWSxDQUFDLE1BQTJCO1FBQzdDLElBQUksSUFBSSxDQUFDLGdCQUFnQixFQUFFLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxLQUFLLFNBQVMsRUFBRSxDQUFDO1lBQ3RELE9BQU87UUFDVCxDQUFDO1FBRUQsSUFBSSxDQUFDLGdCQUFnQixDQUFDLE1BQU0sQ0FBQyxDQUFDLE1BQU0sRUFBRSxFQUFFLENBQUMsQ0FBQyxFQUFFLEdBQUcsTUFBTSxFQUFFLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxFQUFFLElBQUksRUFBRSxDQUFDLENBQUMsQ0FBQztRQUU5RSxJQUFJLENBQUMsV0FBVyxDQUFDLHVCQUF1QixDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUM7YUFDakQsSUFBSSxDQUFDLGtCQUFrQixDQUFDLElBQUksQ0FBQyxXQUFXLENBQUMsQ0FBQzthQUMxQyxTQUFTLENBQUMsQ0FBQyxlQUF3QyxFQUFFLEVBQUU7WUFDdEQsSUFBSSxDQUFDLGdCQUFnQixDQUFDLE1BQU0sQ0FBQyxDQUFDLE1BQU0sRUFBRSxFQUFFLENBQUMsQ0FBQztnQkFDeEMsR0FBRyxNQUFNO2dCQUNULENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxFQUFFO29CQUNaLEdBQUcsZUFBZTtvQkFDbEIsU0FBUyxFQUFFLElBQUksQ0FBQyxjQUFjLENBQUMsZUFBZSxDQUFDO2lCQUNoRDthQUNGLENBQUMsQ0FBQyxDQUFDO1FBQ04sQ0FBQyxDQUFDLENBQUM7SUFDUCxDQUFDO0lBRU8sS0FBSztRQUNYLElBQUksQ0FBQyxjQUFjLEVBQUUsQ0FBQztJQUN4QixDQUFDO0lBRU8sY0FBYztRQUNwQixJQUFJLENBQUMsV0FBVyxDQUFDLG1CQUFtQixFQUFFO2FBQ25DLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLENBQUM7YUFDMUMsU0FBUyxDQUFDLENBQUMsTUFBMkIsRUFBRSxFQUFFLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQztJQUN6RSxDQUFDO0lBRUQ7OztPQUdHO0lBQ0ssY0FBYyxDQUFDLGVBQXdDO1FBQzdELE9BQU8sQ0FBQyxHQUFHLGVBQWUsQ0FBQyxTQUFTLENBQUM7YUFDbEMsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUFFO1lBQ2IsTUFBTSxRQUFRLEdBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLEdBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUM7WUFFakUsT0FBTyxRQUFRLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsYUFBYSxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQztRQUN0RSxDQUFDLENBQUMsQ0FBQztJQUNQLENBQUM7SUFFTyxTQUFTLENBQUMsSUFBWTtRQUM1QixNQUFNLElBQUksR0FBRyx5QkFBeUIsQ0FBQyxVQUFVLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDO1FBRWhFLE9BQU8sSUFBSSxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyx5QkFBeUIsQ0FBQyxVQUFVLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUM7SUFDMUUsQ0FBQzt3R0FwUVUseUJBQXlCOzRGQUF6Qix5QkFBeUIsMEdDL0N0Qyxtbk5Bb0pBLCs3REQ3R0ksa0JBQWtCLHEwQkFDbEIsZ0JBQWdCLDRUQUNoQixZQUFZLHFYQUNaLFlBQVksNElBQ1osZUFBZSx5SEFDZixnQkFBZ0I7OzRGQUdQLHlCQUF5QjtrQkFmckMsU0FBUzsrQkFDRSxnREFBZ0QsbUJBR3pDLHVCQUF1QixDQUFDLE1BQU0sY0FDbkMsSUFBSSxXQUNQO3dCQUNQLGtCQUFrQjt3QkFDbEIsZ0JBQWdCO3dCQUNoQixZQUFZO3dCQUNaLFlBQVk7d0JBQ1osZUFBZTt3QkFDZixnQkFBZ0I7cUJBQ2pCIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3ksIENvbXBvbmVudCwgRGVzdHJveVJlZiwgY29tcHV0ZWQsIGluamVjdCwgc2lnbmFsIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyB0YWtlVW50aWxEZXN0cm95ZWQgfSBmcm9tICdAYW5ndWxhci9jb3JlL3J4anMtaW50ZXJvcCc7XG5cbmltcG9ydCB7IE1hdEV4cGFuc2lvbk1vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL21hdGVyaWFsL2V4cGFuc2lvbic7XG5pbXBvcnQgeyBNYXRUb29sdGlwTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvbWF0ZXJpYWwvdG9vbHRpcCc7XG5cbmltcG9ydCB7IFN0cmVhbUV2ZW50VHlwZSB9IGZyb20gJ0BmaXJlc3RpdGNoL2FwaSc7XG5pbXBvcnQgeyBGc0NoaXBNb2R1bGUgfSBmcm9tICdAZmlyZXN0aXRjaC9jaGlwJztcbmltcG9ydCB7IEZzRGF0ZU1vZHVsZSB9IGZyb20gJ0BmaXJlc3RpdGNoL2RhdGUnO1xuaW1wb3J0IHsgRnNNZXNzYWdlLCBGc01lc3NhZ2VNb2R1bGUgfSBmcm9tICdAZmlyZXN0aXRjaC9tZXNzYWdlJztcbmltcG9ydCB7IEZzUHJvY2VzcyB9IGZyb20gJ0BmaXJlc3RpdGNoL3Byb2Nlc3MnO1xuaW1wb3J0IHsgRnNQcm9tcHQgfSBmcm9tICdAZmlyZXN0aXRjaC9wcm9tcHQnO1xuaW1wb3J0IHsgRnNTa2VsZXRvbk1vZHVsZSB9IGZyb20gJ0BmaXJlc3RpdGNoL3NrZWxldG9uJztcblxuaW1wb3J0IHsgZmlsdGVyLCBtYXAsIHN3aXRjaE1hcCwgdGFrZSwgdGFwIH0gZnJvbSAncnhqcy9vcGVyYXRvcnMnO1xuXG5pbXBvcnQgeyBSZXBvcnREYXRhIH0gZnJvbSAnLi4vLi4vLi4vLi4vZGF0YS9yZXBvcnQuZGF0YSc7XG5pbXBvcnQge1xuICBTZW1hbnRpY0J1aWxkRW50aXR5LFxuICBTZW1hbnRpY0J1aWxkU3RhZ2UsXG4gIFNlbWFudGljQnVpbGRTdGF0dXMsXG4gIFNlbWFudGljRW50aXR5RnVuY3Rpb25zLFxufSBmcm9tICcuLi8uLi8uLi8uLi9pbnRlcmZhY2VzL3JlcG9ydC5pbnRlcmZhY2UnO1xuXG5cbi8vIFRoZSBTZW1hbnRpYyBEYXRhYmFzZSB0YWI6IHRoZSBtb2RlbCBzY29yZWJvYXJkIHRoZSByZXBvcnQgQUkgaXMgYnVpbHQgZnJvbS5cbi8vIFNob3dzIHRoZSBsYXN0IGJ1aWxkJ3Mgc3RhdHVzLCBydW5zIChvciBzdG9wcykgYSBidWlsZCDigJQgc3RyZWFtZWQgaW50byB0aGVcbi8vIEZzUHJvY2VzcyBkb2NrIHNvIGl0IHN1cnZpdmVzIHRoZSBkaWFsb2cgY2xvc2luZyDigJQgYW5kIGRyaWxscyBpbnRvIGV2ZXJ5XG4vLyBlbnRpdHkgdG8gcmV2ZWFsIGl0cyBzaGFwZSwgaW5saW5lZCBlbnVtIHZhbHVlcywgY29tcHV0ZWQgZmllbGRzIGFuZCB0aGVcbi8vIEFJLWNsYXNzaWZpZWQgY29kZSBmdW5jdGlvbnMgY2FjaGVkIGZyb20gaXRzIG1vZGVsIGNsYXNzLiBFYWNoIGVudGl0eSdzXG4vLyBmdW5jdGlvbnMgbG9hZCBsYXppbHkgb24gZmlyc3QgZXhwYW5kLCBiZWNhdXNlIHRoZSBmdWxsIHNldCBhY3Jvc3MgYWxsXG4vLyBlbnRpdGllcyBpcyBmYXIgdG9vIGJpZyB0byBzaGlwIHdpdGggdGhlIHNjb3JlYm9hcmQuXG5AQ29tcG9uZW50KHtcbiAgc2VsZWN0b3I6ICdmcy1haS1yZXBvcnQtZ2xvYmFsLXNldHRpbmdzLXNlbWFudGljLWRhdGFiYXNlJyxcbiAgdGVtcGxhdGVVcmw6ICcuL3NlbWFudGljLWRhdGFiYXNlLmNvbXBvbmVudC5odG1sJyxcbiAgc3R5bGVVcmxzOiBbJy4vc2VtYW50aWMtZGF0YWJhc2UuY29tcG9uZW50LnNjc3MnXSxcbiAgY2hhbmdlRGV0ZWN0aW9uOiBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneS5PblB1c2gsXG4gIHN0YW5kYWxvbmU6IHRydWUsXG4gIGltcG9ydHM6IFtcbiAgICBNYXRFeHBhbnNpb25Nb2R1bGUsXG4gICAgTWF0VG9vbHRpcE1vZHVsZSxcbiAgICBGc0NoaXBNb2R1bGUsXG4gICAgRnNEYXRlTW9kdWxlLFxuICAgIEZzTWVzc2FnZU1vZHVsZSxcbiAgICBGc1NrZWxldG9uTW9kdWxlLFxuICBdLFxufSlcbmV4cG9ydCBjbGFzcyBTZW1hbnRpY0RhdGFiYXNlQ29tcG9uZW50IHtcblxuICAvLyBUaGUgYnVpbGQtaW4tZmxpZ2h0IHN0YXRlcyBvZiB0aGUgZmZfcHJvY2Vzc2VzIHJvdyAocXVldWVkL3J1bm5pbmcvc3RvcHBpbmcpLlxuICBwcml2YXRlIHN0YXRpYyByZWFkb25seSBBQ1RJVkVfU1RBVEVTID0gWydRJywgJ1InLCAnWCddO1xuXG4gIHByaXZhdGUgc3RhdGljIHJlYWRvbmx5IFNUQVRFX0xBQkVMUzogUmVjb3JkPHN0cmluZywgc3RyaW5nPiA9IHtcbiAgICBROiAnUXVldWVkJyxcbiAgICBSOiAnUnVubmluZycsXG4gICAgWDogJ1N0b3BwaW5nJyxcbiAgICBDOiAnQ29tcGxldGVkJyxcbiAgICBLOiAnU3RvcHBlZCcsXG4gICAgRjogJ0ZhaWxlZCcsXG4gIH07XG5cbiAgLy8gU2NvcmVib2FyZCBjb21wbGV0aW9uIHBhbGV0dGU6IGJ1aWx0ID0gZ3JlZW4sIGV2ZXJ5dGhpbmcgZWxzZSAobmVlZHNcbiAgLy8gYnVpbGRpbmcpID0gZ3JleS4gTm8gZXJyb3IgcmVkIOKAlCBhIG1pc3Npbmcgc3RhZ2UgaXMgdW5idWlsdCBjb250ZW50LCBub3QgYVxuICAvLyBmYWlsdXJlLlxuICBwcml2YXRlIHN0YXRpYyByZWFkb25seSBET05FX0NPTE9SID0gJyMyZTdkMzInO1xuICBwcml2YXRlIHN0YXRpYyByZWFkb25seSBQRU5ESU5HX0NPTE9SID0gJyM5ZTllOWUnO1xuXG4gIC8vIE9uZSBjb2xvciBwZXIgQUkgY2xhc3NpZmljYXRpb24ga2luZCwgc28gYSBmdW5jdGlvbidzIG5hdHVyZSByZWFkcyBhdCBhIGdsYW5jZS5cbiAgcHJpdmF0ZSBzdGF0aWMgcmVhZG9ubHkgS0lORF9DT0xPUlM6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4gPSB7XG4gICAgJ2NhbGN1bGF0aW9uJzogJyMxNTY1YzAnLFxuICAgICdidXNpbmVzcy1ydWxlJzogJyM2YTFiOWEnLFxuICAgICdxdWVyeSc6ICcjMDA2OTVjJyxcbiAgICAnbXV0YXRpb24nOiAnI2U2NTEwMCcsXG4gICAgJ2FjY2Vzc29yJzogJyM1NDZlN2EnLFxuICAgICdvdGhlcic6ICcjNzU3NTc1JyxcbiAgfTtcblxuICAvLyBJbnRlcmVzdGluZyBsb2dpYyBmaXJzdDogZGVyaXZlZCB2YWx1ZXMgYW5kIHJ1bGVzLCB0aGVuIGRhdGEgYWNjZXNzLCB0aGVuIHRoZSByZXN0LlxuICBwcml2YXRlIHN0YXRpYyByZWFkb25seSBLSU5EX09SREVSID0gWydjYWxjdWxhdGlvbicsICdidXNpbmVzcy1ydWxlJywgJ3F1ZXJ5JywgJ211dGF0aW9uJywgJ2FjY2Vzc29yJywgJ290aGVyJ107XG5cbiAgLy8gVGhlIHNjb3JlYm9hcmQncyBwZXItZW50aXR5IHN0YWdlIGNoaXBzLCBsZWZ0IHRvIHJpZ2h0LlxuICBwdWJsaWMgcmVhZG9ubHkgc3RhZ2VLZXlzID0gWydpbnRyb3NwZWN0ZWQnLCAnZW51bXNJbmxpbmVkJywgJ2NvbXB1dGVkJywgJ2Z1bmN0aW9ucyddO1xuXG4gIHB1YmxpYyByZWFkb25seSBzdGFnZUxhYmVsczogUmVjb3JkPHN0cmluZywgc3RyaW5nPiA9IHtcbiAgICBpbnRyb3NwZWN0ZWQ6ICdJbnRyb3NwZWN0ZWQnLFxuICAgIGVudW1zSW5saW5lZDogJ0VudW0gY2FzZXMnLFxuICAgIGNvbXB1dGVkOiAnQ29tcHV0ZWQnLFxuICAgIGZ1bmN0aW9uczogJ0Z1bmN0aW9ucycsXG4gIH07XG5cbiAgLy8gbnVsbCB1bnRpbCBsb2FkZWQg4oCUIGdhdGVzIHRoZSB0YWIgYmVoaW5kIHRoZSBza2VsZXRvbi5cbiAgcHVibGljIHJlYWRvbmx5IHN0YXR1cyA9IHNpZ25hbDxTZW1hbnRpY0J1aWxkU3RhdHVzIHwgbnVsbD4obnVsbCk7XG5cbiAgLy8gVHJ1ZSB3aGlsZSBhIGJ1aWxkIHN0YXJ0ZWQgZnJvbSB0aGlzIHRhYiBpcyBzdHJlYW1pbmcgaW50byB0aGUgZG9jay5cbiAgcHVibGljIHJlYWRvbmx5IGJ1aWxkaW5nID0gc2lnbmFsKGZhbHNlKTtcblxuICBwdWJsaWMgcmVhZG9ubHkgYnVpbGRBY3RpdmUgPSBjb21wdXRlZDxib29sZWFuPigoKSA9PlxuICAgIHRoaXMuYnVpbGRpbmcoKVxuICAgICAgfHwgU2VtYW50aWNEYXRhYmFzZUNvbXBvbmVudC5BQ1RJVkVfU1RBVEVTLmluY2x1ZGVzKHRoaXMuc3RhdHVzKCk/LmJ1aWxkPy5zdGF0ZSksXG4gICk7XG5cbiAgcHVibGljIHJlYWRvbmx5IGJ1aWxkU3RhdGVMYWJlbCA9IGNvbXB1dGVkPHN0cmluZz4oKCkgPT5cbiAgICBTZW1hbnRpY0RhdGFiYXNlQ29tcG9uZW50LlNUQVRFX0xBQkVMU1t0aGlzLnN0YXR1cygpPy5idWlsZD8uc3RhdGVdID8/ICcnLFxuICApO1xuXG4gIC8vIFBlci1lbnRpdHkgZnVuY3Rpb24gY2FjaGVzLCBsb2FkZWQgb24gZmlyc3QgZXhwYW5kLiB1bmRlZmluZWQgPSBub3RcbiAgLy8gcmVxdWVzdGVkIHlldCwgbnVsbCA9IHJlcXVlc3QgaW4gZmxpZ2h0ICh0aGUgc2tlbGV0b24gd2luZG93KSwgb2JqZWN0ID0gbG9hZGVkLlxuICBwcml2YXRlIHJlYWRvbmx5IF9lbnRpdHlGdW5jdGlvbnMgPSBzaWduYWw8UmVjb3JkPHN0cmluZywgU2VtYW50aWNFbnRpdHlGdW5jdGlvbnMgfCBudWxsPj4oe30pO1xuXG4gIC8vIEd1YXJkcyB0aGUgb3V0Y29tZSBtZXNzYWdlIHRvIGZpcmUgZXhhY3RseSBvbmNlIHBlciBydW4g4oCUIHdoZXRoZXIgdGhlIHN0cmVhbVxuICAvLyBjb21wbGV0ZXMgKGJ1aWxkIGZpbmlzaGVkLCBwb3NzaWJseSBmYWlsZWQpIG9yIGVycm9ycyBvdXRyaWdodC5cbiAgcHJpdmF0ZSBfYnVpbGRGaW5hbGl6ZWQgPSBmYWxzZTtcblxuICBwcml2YXRlIHJlYWRvbmx5IF9yZXBvcnREYXRhID0gaW5qZWN0KFJlcG9ydERhdGEpO1xuICBwcml2YXRlIHJlYWRvbmx5IF9wcm9jZXNzID0gaW5qZWN0KEZzUHJvY2Vzcyk7XG4gIHByaXZhdGUgcmVhZG9ubHkgX3Byb21wdCA9IGluamVjdChGc1Byb21wdCk7XG4gIHByaXZhdGUgcmVhZG9ubHkgX21lc3NhZ2UgPSBpbmplY3QoRnNNZXNzYWdlKTtcbiAgcHJpdmF0ZSByZWFkb25seSBfZGVzdHJveVJlZiA9IGluamVjdChEZXN0cm95UmVmKTtcblxuICBjb25zdHJ1Y3RvcigpIHtcbiAgICB0aGlzLl9pbml0KCk7XG4gIH1cblxuICAvLyBDb25maXJtIGJlZm9yZSBraWNraW5nIG9mZiBhIGJ1aWxkIOKAlCBhIHJlYnVpbGQgcmVwbGFjZXMgdGhlIGN1cnJlbnRcbiAgLy8gc2VtYW50aWMgZGF0YWJhc2UsIHNvIGl0IHNob3VsZCBuZXZlciBmaXJlIG9uIGEgc3RyYXkgY2xpY2suXG4gIHB1YmxpYyBidWlsZCgpOiB2b2lkIHtcbiAgICBjb25zdCByZWJ1aWxkID0gISF0aGlzLnN0YXR1cygpPy5kZXRhaWw/LmdlbmVyYXRlZEF0O1xuXG4gICAgdGhpcy5fcHJvbXB0LmNvbmZpcm0oe1xuICAgICAgdGl0bGU6IHJlYnVpbGQgPyAnUmVidWlsZCBzZW1hbnRpYyBkYXRhYmFzZScgOiAnQnVpbGQgc2VtYW50aWMgZGF0YWJhc2UnLFxuICAgICAgdGVtcGxhdGU6IHJlYnVpbGRcbiAgICAgICAgPyAnUmVidWlsZCB0aGUgc2VtYW50aWMgZGF0YWJhc2U/IEl0IHJ1bnMgaW4gdGhlIGJhY2tncm91bmQgYW5kIHJlcGxhY2VzIHRoZSBjdXJyZW50IG9uZSB3aGVuIGl0IGZpbmlzaGVzLidcbiAgICAgICAgOiAnQnVpbGQgdGhlIHNlbWFudGljIGRhdGFiYXNlPyBJdCBydW5zIGluIHRoZSBiYWNrZ3JvdW5kLicsXG4gICAgICBjb21taXRMYWJlbDogcmVidWlsZCA/ICdSZWJ1aWxkJyA6ICdCdWlsZCcsXG4gICAgfSlcbiAgICAgIC5waXBlKHRha2VVbnRpbERlc3Ryb3llZCh0aGlzLl9kZXN0cm95UmVmKSlcbiAgICAgIC5zdWJzY3JpYmUoKCkgPT4gdGhpcy5fcnVuQnVpbGQoKSk7XG4gIH1cblxuICBwdWJsaWMgc3RvcEJ1aWxkKCk6IHZvaWQge1xuICAgIHRoaXMuX3Byb21wdC5jb25maXJtKHtcbiAgICAgIHRpdGxlOiAnU3RvcCBidWlsZCcsXG4gICAgICB0ZW1wbGF0ZTogJ1N0b3AgdGhlIHJ1bm5pbmcgYnVpbGQ/IFRoZSBjdXJyZW50IHNlbWFudGljIGRhdGFiYXNlIHN0YXlzIGluIHBsYWNlIHVudGlsIGEgYnVpbGQgZmluaXNoZXMuJyxcbiAgICAgIGNvbW1pdExhYmVsOiAnU3RvcCcsXG4gICAgfSlcbiAgICAgIC5waXBlKFxuICAgICAgICBzd2l0Y2hNYXAoKCkgPT4gdGhpcy5fcmVwb3J0RGF0YS5zZW1hbnRpY0J1aWxkU3RvcCgpKSxcbiAgICAgICAgdGFrZVVudGlsRGVzdHJveWVkKHRoaXMuX2Rlc3Ryb3lSZWYpLFxuICAgICAgKVxuICAgICAgLnN1YnNjcmliZSgoKSA9PiB7XG4gICAgICAgIHRoaXMuYnVpbGRpbmcuc2V0KGZhbHNlKTtcbiAgICAgICAgdGhpcy5fbWVzc2FnZS5zdWNjZXNzKCdTdG9wcGluZyB0aGUgYnVpbGTigKYnKTtcbiAgICAgICAgdGhpcy5fcmVmcmVzaFN0YXR1cygpO1xuICAgICAgfSk7XG4gIH1cblxuICAvLyBSdW4gdGhlIHNlbWFudGljLWRhdGFiYXNlIGJ1aWxkLiBUaGUgbGl2ZSBmZWVkIHN0cmVhbXMgaW50byB0aGUgRnNQcm9jZXNzXG4gIC8vIGRvY2sgKGJvdHRvbS1yaWdodCksIHdob3NlIHN1YnNjcmlwdGlvbiBzdXJ2aXZlcyB0aGlzIGRpYWxvZyBjbG9zaW5nIOKAlCBzb1xuICAvLyBkaXNtaXNzaW5nIHRoZSBkaWFsb2cgbmV2ZXIgaW50ZXJydXB0cyBhIHJ1bm5pbmcgYnVpbGQuXG4gIHByaXZhdGUgX3J1bkJ1aWxkKCk6IHZvaWQge1xuICAgIHRoaXMuYnVpbGRpbmcuc2V0KHRydWUpO1xuICAgIHRoaXMuX2J1aWxkRmluYWxpemVkID0gZmFsc2U7XG5cbiAgICBjb25zdCB0YXJnZXQkID0gdGhpcy5fcmVwb3J0RGF0YS5zZW1hbnRpY0J1aWxkKClcbiAgICAgIC5waXBlKFxuICAgICAgICAvLyBBIGhhcmQgc3RyZWFtL3RyYW5zcG9ydCBmYWlsdXJlICh0aGUgYnVpbGQgY291bGRuJ3QgZXZlbiBzdGFydClcbiAgICAgICAgLy8gZmluYWxpemVzIGhlcmUg4oCUIGNvbXBsZXRlZCQgd29uJ3QgZmlyZSBpbiB0aGF0IGNhc2UuXG4gICAgICAgIHRhcCh7IGVycm9yOiAoZXJyb3IpID0+IHRoaXMuX2ZpbmFsaXplQnVpbGQoZXJyb3IpIH0pLFxuICAgICAgICBmaWx0ZXIoKGV2ZW50KSA9PlxuICAgICAgICAgIGV2ZW50Py50eXBlID09PSBTdHJlYW1FdmVudFR5cGUuRGF0YVxuICAgICAgICAgICYmIGV2ZW50LmRhdGE/LmtpbmQgPT09ICdsb2cnXG4gICAgICAgICAgJiYgdHlwZW9mIGV2ZW50LmRhdGEubGluZSA9PT0gJ3N0cmluZycpLFxuICAgICAgICBtYXAoKGV2ZW50KSA9PiBldmVudC5kYXRhLmxpbmUgYXMgc3RyaW5nKSxcbiAgICAgICk7XG5cbiAgICB0aGlzLl9wcm9jZXNzXG4gICAgICAucnVuKCdTZW1hbnRpYyBkYXRhYmFzZSBidWlsZCcsIHRhcmdldCQpXG4gICAgICAuY29tcGxldGVkJFxuICAgICAgLnBpcGUoXG4gICAgICAgIHRha2UoMSksXG4gICAgICAgIHRha2VVbnRpbERlc3Ryb3llZCh0aGlzLl9kZXN0cm95UmVmKSxcbiAgICAgIClcbiAgICAgIC5zdWJzY3JpYmUoKCkgPT4gdGhpcy5fZmluYWxpemVCdWlsZChudWxsKSk7XG4gIH1cblxuICAvKipcbiAgICogV3JhcCB1cCBvbmUgYnVpbGQgcnVuIGV4YWN0bHkgb25jZS4gT24gYSBoYXJkIHN0cmVhbSBlcnJvciB0aGVyZSBpcyBub1xuICAgKiBzdGF0dXMgdG8gcmVhZCwgc28gc2F5IHNvIGRpcmVjdGx5OyBvdGhlcndpc2UgcmVmcmVzaCB0aGUgc3RhdHVzIGFuZFxuICAgKiBhbm5vdW5jZSBob3cgdGhlIGJ1aWxkIGFjdHVhbGx5IGVuZGVkIOKAlCBhIGJ1aWxkIHRoYXQgZmFpbGVkIChlLmcuIHRoZSBBSVxuICAgKiBjb3VsZG4ndCBiZSByZWFjaGVkKSByZXBvcnRzICdGYWlsZWQnIHdpdGggYSByZWFzb24sIGFuZCB0aGF0IG11c3Qgc3VyZmFjZVxuICAgKiBpbnN0ZWFkIG9mIHRoZSBydW4gc2lsZW50bHkgZG9pbmcgbm90aGluZy5cbiAgICovXG4gIHByaXZhdGUgX2ZpbmFsaXplQnVpbGQoc3RyZWFtRXJyb3I6IHVua25vd24pOiB2b2lkIHtcbiAgICBpZiAodGhpcy5fYnVpbGRGaW5hbGl6ZWQpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgdGhpcy5fYnVpbGRGaW5hbGl6ZWQgPSB0cnVlO1xuXG4gICAgdGhpcy5idWlsZGluZy5zZXQoZmFsc2UpO1xuICAgIC8vIFRoZSBidWlsZCByZXdyb3RlIGV2ZXJ5IGVudGl0eSdzIGZ1bmN0aW9uIGNhY2hlIOKAlCBkcm9wIHRoZSBsb2FkZWQgY29waWVzXG4gICAgLy8gc28gdGhlIG5leHQgZXhwYW5kIHJlZmV0Y2hlcyBmcmVzaCBkYXRhLlxuICAgIHRoaXMuX2VudGl0eUZ1bmN0aW9ucy5zZXQoe30pO1xuXG4gICAgaWYgKHN0cmVhbUVycm9yKSB7XG4gICAgICB0aGlzLl9tZXNzYWdlLmVycm9yKCdUaGUgc2VtYW50aWMgZGF0YWJhc2UgYnVpbGQgY291bGQgbm90IHJ1biDigJQgY2hlY2sgdGhlIEFJIGNvbm5lY3Rpb24gYW5kIHRyeSBhZ2Fpbi4nKTtcbiAgICAgIHRoaXMuX3JlZnJlc2hTdGF0dXMoKTtcblxuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIHRoaXMuX3JlcG9ydERhdGEuc2VtYW50aWNCdWlsZFN0YXR1cygpXG4gICAgICAucGlwZSh0YWtlVW50aWxEZXN0cm95ZWQodGhpcy5fZGVzdHJveVJlZikpXG4gICAgICAuc3Vic2NyaWJlKChzdGF0dXM6IFNlbWFudGljQnVpbGRTdGF0dXMpID0+IHtcbiAgICAgICAgdGhpcy5zdGF0dXMuc2V0KHN0YXR1cyk7XG4gICAgICAgIHRoaXMuX2Fubm91bmNlT3V0Y29tZShzdGF0dXMpO1xuICAgICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogVGVsbCB0aGUgb3BlcmF0b3IgaG93IHRoZSBidWlsZCBlbmRlZDogYSBmYWlsZWQvc3RvcHBlZCBidWlsZCBzdXJmYWNlcyBpdHNcbiAgICogcmVhc29uIChzbyBhbiBBSSBjb25uZWN0aW9uIHByb2JsZW0gaXMgbmV2ZXIgc2lsZW50KSwgYSBjb21wbGV0ZWQgb25lXG4gICAqIGNvbmZpcm1zIHN1Y2Nlc3MuXG4gICAqL1xuICBwcml2YXRlIF9hbm5vdW5jZU91dGNvbWUoc3RhdHVzOiBTZW1hbnRpY0J1aWxkU3RhdHVzKTogdm9pZCB7XG4gICAgY29uc3QgYnVpbGQgPSBzdGF0dXM/LmJ1aWxkO1xuICAgIGlmIChidWlsZD8uc3RhdGUgPT09ICdGJyB8fCBidWlsZD8uc3RhdGUgPT09ICdLJykge1xuICAgICAgdGhpcy5fbWVzc2FnZS5lcnJvcihidWlsZC5tZXNzYWdlIHx8ICdUaGUgc2VtYW50aWMgZGF0YWJhc2UgYnVpbGQgZGlkIG5vdCBmaW5pc2guJyk7XG4gICAgfSBlbHNlIGlmIChidWlsZD8uc3RhdGUgPT09ICdDJykge1xuICAgICAgdGhpcy5fbWVzc2FnZS5zdWNjZXNzKCdTZW1hbnRpYyBkYXRhYmFzZSBidWlsZCBjb21wbGV0ZS4nKTtcbiAgICB9XG4gIH1cblxuICBwdWJsaWMgc3RhZ2VDb2xvcihzdGFnZTogU2VtYW50aWNCdWlsZFN0YWdlKTogc3RyaW5nIHtcbiAgICByZXR1cm4gc3RhZ2UgPT09ICdkb25lJ1xuICAgICAgPyBTZW1hbnRpY0RhdGFiYXNlQ29tcG9uZW50LkRPTkVfQ09MT1JcbiAgICAgIDogU2VtYW50aWNEYXRhYmFzZUNvbXBvbmVudC5QRU5ESU5HX0NPTE9SO1xuICB9XG5cbiAgcHVibGljIHN0YWdlVG9vbHRpcChzdGFnZTogU2VtYW50aWNCdWlsZFN0YWdlKTogc3RyaW5nIHtcbiAgICByZXR1cm4gc3RhZ2UgPT09ICdkb25lJyA/ICdCdWlsdCcgOiAnTmVlZHMgYnVpbGRpbmcnO1xuICB9XG5cbiAgcHVibGljIGtpbmRDb2xvcihraW5kOiBzdHJpbmcpOiBzdHJpbmcge1xuICAgIHJldHVybiBTZW1hbnRpY0RhdGFiYXNlQ29tcG9uZW50LktJTkRfQ09MT1JTW2tpbmRdID8/IFNlbWFudGljRGF0YWJhc2VDb21wb25lbnQuS0lORF9DT0xPUlMub3RoZXI7XG4gIH1cblxuICAvKipcbiAgICogVGhlIGxvYWRlZCBmdW5jdGlvbiBjYWNoZSBmb3IgYW4gZW50aXR5OiB1bmRlZmluZWQgdW50aWwgdGhlIHBhbmVsIGlzIGZpcnN0XG4gICAqIGV4cGFuZGVkLCBudWxsIHdoaWxlIHRoZSByZXF1ZXN0IGlzIGluIGZsaWdodCAodGhlIHNrZWxldG9uIHdpbmRvdyksIHRoZW5cbiAgICogdGhlIGxvYWRlZCBjYWNoZS5cbiAgICovXG4gIHB1YmxpYyBlbnRpdHlGdW5jdGlvbnMoa2V5OiBzdHJpbmcpOiBTZW1hbnRpY0VudGl0eUZ1bmN0aW9ucyB8IG51bGwgfCB1bmRlZmluZWQge1xuICAgIHJldHVybiB0aGlzLl9lbnRpdHlGdW5jdGlvbnMoKVtrZXldO1xuICB9XG5cbiAgLyoqXG4gICAqIEZpcnN0IGV4cGFuZCBvZiBhbiBlbnRpdHk6IGZldGNoIGl0cyBjYWNoZWQgZnVuY3Rpb25zIHRocm91Z2ggdGhlIHBlci1lbnRpdHlcbiAgICogZW5kcG9pbnQuIFN1YnNlcXVlbnQgZXhwYW5kcyByZXVzZSB0aGUgbG9hZGVkIGNvcHkgKGEgZmluaXNoZWQgYnVpbGQgY2xlYXJzXG4gICAqIHRoZSBjb3BpZXMgc28gYSByZS1leHBhbmQgcmVmZXRjaGVzIGZyZXNoIGRhdGEpLlxuICAgKi9cbiAgcHVibGljIGVudGl0eU9wZW5lZChlbnRpdHk6IFNlbWFudGljQnVpbGRFbnRpdHkpOiB2b2lkIHtcbiAgICBpZiAodGhpcy5fZW50aXR5RnVuY3Rpb25zKClbZW50aXR5LmtleV0gIT09IHVuZGVmaW5lZCkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIHRoaXMuX2VudGl0eUZ1bmN0aW9ucy51cGRhdGUoKGxvYWRlZCkgPT4gKHsgLi4ubG9hZGVkLCBbZW50aXR5LmtleV06IG51bGwgfSkpO1xuXG4gICAgdGhpcy5fcmVwb3J0RGF0YS5zZW1hbnRpY0VudGl0eUZ1bmN0aW9ucyhlbnRpdHkua2V5KVxuICAgICAgLnBpcGUodGFrZVVudGlsRGVzdHJveWVkKHRoaXMuX2Rlc3Ryb3lSZWYpKVxuICAgICAgLnN1YnNjcmliZSgoZW50aXR5RnVuY3Rpb25zOiBTZW1hbnRpY0VudGl0eUZ1bmN0aW9ucykgPT4ge1xuICAgICAgICB0aGlzLl9lbnRpdHlGdW5jdGlvbnMudXBkYXRlKChsb2FkZWQpID0+ICh7XG4gICAgICAgICAgLi4ubG9hZGVkLFxuICAgICAgICAgIFtlbnRpdHkua2V5XToge1xuICAgICAgICAgICAgLi4uZW50aXR5RnVuY3Rpb25zLFxuICAgICAgICAgICAgZnVuY3Rpb25zOiB0aGlzLl9zb3J0RnVuY3Rpb25zKGVudGl0eUZ1bmN0aW9ucyksXG4gICAgICAgICAgfSxcbiAgICAgICAgfSkpO1xuICAgICAgfSk7XG4gIH1cblxuICBwcml2YXRlIF9pbml0KCk6IHZvaWQge1xuICAgIHRoaXMuX3JlZnJlc2hTdGF0dXMoKTtcbiAgfVxuXG4gIHByaXZhdGUgX3JlZnJlc2hTdGF0dXMoKTogdm9pZCB7XG4gICAgdGhpcy5fcmVwb3J0RGF0YS5zZW1hbnRpY0J1aWxkU3RhdHVzKClcbiAgICAgIC5waXBlKHRha2VVbnRpbERlc3Ryb3llZCh0aGlzLl9kZXN0cm95UmVmKSlcbiAgICAgIC5zdWJzY3JpYmUoKHN0YXR1czogU2VtYW50aWNCdWlsZFN0YXR1cykgPT4gdGhpcy5zdGF0dXMuc2V0KHN0YXR1cykpO1xuICB9XG5cbiAgLyoqXG4gICAqIE9yZGVyIG9uY2UgYXQgbG9hZCB0aW1lIChraW5kIHByaW9yaXR5LCB0aGVuIG1ldGhvZCBuYW1lKSBzbyB0aGUgdGVtcGxhdGVcbiAgICogcmVuZGVycyB0aGUgbGlzdCBhcy1pcy5cbiAgICovXG4gIHByaXZhdGUgX3NvcnRGdW5jdGlvbnMoZW50aXR5RnVuY3Rpb25zOiBTZW1hbnRpY0VudGl0eUZ1bmN0aW9ucyk6IFNlbWFudGljRW50aXR5RnVuY3Rpb25zWydmdW5jdGlvbnMnXSB7XG4gICAgcmV0dXJuIFsuLi5lbnRpdHlGdW5jdGlvbnMuZnVuY3Rpb25zXVxuICAgICAgLnNvcnQoKGEsIGIpID0+IHtcbiAgICAgICAgY29uc3Qga2luZERpZmYgPSB0aGlzLl9raW5kUmFuayhhLmtpbmQpIC0gdGhpcy5fa2luZFJhbmsoYi5raW5kKTtcblxuICAgICAgICByZXR1cm4ga2luZERpZmYgIT09IDAgPyBraW5kRGlmZiA6IGEubWV0aG9kLmxvY2FsZUNvbXBhcmUoYi5tZXRob2QpO1xuICAgICAgfSk7XG4gIH1cblxuICBwcml2YXRlIF9raW5kUmFuayhraW5kOiBzdHJpbmcpOiBudW1iZXIge1xuICAgIGNvbnN0IHJhbmsgPSBTZW1hbnRpY0RhdGFiYXNlQ29tcG9uZW50LktJTkRfT1JERVIuaW5kZXhPZihraW5kKTtcblxuICAgIHJldHVybiByYW5rID09PSAtMSA/IFNlbWFudGljRGF0YWJhc2VDb21wb25lbnQuS0lORF9PUkRFUi5sZW5ndGggOiByYW5rO1xuICB9XG59XG4iLCI8ZGl2IGNsYXNzPVwiZnMtY29sdW1uIHRhYi1ib2R5XCI+XG4gIDxwIGNsYXNzPVwiaGludFwiPlxuICAgIFRoZSBzZW1hbnRpYyBkYXRhYmFzZSBpcyB3aGF0IHRoZSByZXBvcnQgQUkgdXNlcyB0byB1bmRlcnN0YW5kIHlvdXIgZGF0YSDigJRcbiAgICB0YWJsZXMsIHJlbGF0aW9uc2hpcHMgYW5kIHRoZSBjYWxjdWxhdGlvbnMgaW4gY29kZS4gUmVidWlsZCBpdCBhZnRlclxuICAgIHNpZ25pZmljYW50IGFwcGxpY2F0aW9uIHVwZGF0ZXMuIFRoZSBidWlsZCBydW5zIGluIHRoZSBiYWNrZ3JvdW5kOyBwcm9ncmVzc1xuICAgIGFwcGVhcnMgaW4gdGhlIGRvY2sgYXQgdGhlIGJvdHRvbSByaWdodCBhbmQgdGhpcyBkaWFsb2cgY2FuIGJlIGNsb3NlZCB3aGlsZVxuICAgIGl0IHJ1bnMuXG4gIDwvcD5cblxuICA8ZGl2ICpmc1NrZWxldG9uPVwic3RhdHVzKClcIj5cbiAgICBAaWYgKHN0YXR1cygpOyBhcyBidWlsZFN0YXR1cykge1xuICAgICAgPGRpdiBjbGFzcz1cImJ1aWxkLXN0YXR1c1wiPlxuICAgICAgICBAaWYgKGJ1aWxkU3RhdHVzLmRldGFpbC5nZW5lcmF0ZWRBdCkge1xuICAgICAgICAgIDxkaXYgY2xhc3M9XCJzdGF0XCI+XG4gICAgICAgICAgICA8c3BhbiBjbGFzcz1cImxhYmVsXCI+TGFzdCBidWlsdDwvc3Bhbj5cbiAgICAgICAgICAgIDxmcy1kYXRlXG4gICAgICAgICAgICAgICAgW2RhdGVdPVwiYnVpbGRTdGF0dXMuZGV0YWlsLmdlbmVyYXRlZEF0XCJcbiAgICAgICAgICAgICAgICBmb3JtYXQ9XCJkYXRlLXRpbWVcIj5cbiAgICAgICAgICAgIDwvZnMtZGF0ZT5cbiAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICA8ZGl2IGNsYXNzPVwic3RhdFwiPlxuICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJsYWJlbFwiPkNvdmVyYWdlPC9zcGFuPlxuICAgICAgICAgICAgPHNwYW4+XG4gICAgICAgICAgICAgIHt7IGJ1aWxkU3RhdHVzLmRldGFpbC5lbnRpdHlDb3VudCB9fSBlbnRpdGllcyDCt1xuICAgICAgICAgICAgICB7eyBidWlsZFN0YXR1cy5kZXRhaWwuZnVuY3Rpb25Db3VudCB9fSBjb2RlIGZ1bmN0aW9uc1xuICAgICAgICAgICAgPC9zcGFuPlxuICAgICAgICAgIDwvZGl2PlxuICAgICAgICB9IEBlbHNlIHtcbiAgICAgICAgICA8ZnMtbWVzc2FnZS13YXJuaW5nPlxuICAgICAgICAgICAgVGhlIHNlbWFudGljIGRhdGFiYXNlIGhhcyBub3QgYmVlbiBidWlsdCB5ZXQg4oCUIHRoZSByZXBvcnQgQUkgY2FuJ3RcbiAgICAgICAgICAgIGFuc3dlciBkYXRhIHF1ZXN0aW9ucyB1bnRpbCBpdCBpcy4gUnVuIHRoZSBmaXJzdCBidWlsZC5cbiAgICAgICAgICA8L2ZzLW1lc3NhZ2Utd2FybmluZz5cbiAgICAgICAgfVxuICAgICAgICBAaWYgKGJ1aWxkU3RhdHVzLmJ1aWxkKSB7XG4gICAgICAgICAgPGRpdiBjbGFzcz1cInN0YXRcIj5cbiAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwibGFiZWxcIj5MYXN0IGJ1aWxkIHJ1bjwvc3Bhbj5cbiAgICAgICAgICAgIDxzcGFuPlxuICAgICAgICAgICAgICB7eyBidWlsZFN0YXRlTGFiZWwoKSB9fVxuICAgICAgICAgICAgICBAaWYgKGJ1aWxkU3RhdHVzLmJ1aWxkLm1lc3NhZ2UpIHtcbiAgICAgICAgICAgICAgICDigJQge3sgYnVpbGRTdGF0dXMuYnVpbGQubWVzc2FnZSB9fVxuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICA8L3NwYW4+XG4gICAgICAgICAgPC9kaXY+XG4gICAgICAgIH1cbiAgICAgIDwvZGl2PlxuXG4gICAgICA8IS0tIFRoZSBtb2RlbCBzY29yZWJvYXJkOiBldmVyeSBlbnRpdHkgdGhlIEFJIGtub3dzIGFib3V0LCBpdHNcbiAgICAgICAgICAgYnVpbHQtdnMtbmVlZHMtYnVpbGRpbmcgc3RhZ2VzLCBhbmQgYSBkcmlsbC1kb3duIGludG8gaXRzIHNoYXBlLCBlbnVtXG4gICAgICAgICAgIHZhbHVlcywgY29tcHV0ZWQgZmllbGRzIGFuZCBBSS1jbGFzc2lmaWVkIGNvZGUgZnVuY3Rpb25zLiAtLT5cbiAgICAgIEBpZiAoYnVpbGRTdGF0dXMuZGV0YWlsLmVudGl0aWVzPy5sZW5ndGgpIHtcbiAgICAgICAgPG1hdC1hY2NvcmRpb24gY2xhc3M9XCJlbnRpdGllc1wiPlxuICAgICAgICAgIEBmb3IgKGVudGl0eSBvZiBidWlsZFN0YXR1cy5kZXRhaWwuZW50aXRpZXM7IHRyYWNrIGVudGl0eS5rZXkpIHtcbiAgICAgICAgICAgIDxtYXQtZXhwYW5zaW9uLXBhbmVsIChvcGVuZWQpPVwiZW50aXR5T3BlbmVkKGVudGl0eSlcIj5cbiAgICAgICAgICAgICAgPG1hdC1leHBhbnNpb24tcGFuZWwtaGVhZGVyPlxuICAgICAgICAgICAgICAgIDxtYXQtcGFuZWwtdGl0bGU+e3sgZW50aXR5LmtleSB9fTwvbWF0LXBhbmVsLXRpdGxlPlxuICAgICAgICAgICAgICAgIDxtYXQtcGFuZWwtZGVzY3JpcHRpb24+XG4gICAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwic3RhZ2UtY2hpcHNcIj5cbiAgICAgICAgICAgICAgICAgICAgQGZvciAoc3RhZ2Ugb2Ygc3RhZ2VLZXlzOyB0cmFjayBzdGFnZSkge1xuICAgICAgICAgICAgICAgICAgICAgIDxmcy1jaGlwXG4gICAgICAgICAgICAgICAgICAgICAgICAgIHNpemU9XCJ0aW55XCJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgW2JhY2tncm91bmRDb2xvcl09XCJzdGFnZUNvbG9yKGVudGl0eS5zdGFnZXNbc3RhZ2VdKVwiXG4gICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yPVwiI2ZmZmZmZlwiXG4gICAgICAgICAgICAgICAgICAgICAgICAgIFttYXRUb29sdGlwXT1cInN0YWdlVG9vbHRpcChlbnRpdHkuc3RhZ2VzW3N0YWdlXSlcIj5cbiAgICAgICAgICAgICAgICAgICAgICAgIHt7IHN0YWdlTGFiZWxzW3N0YWdlXSB9fVxuICAgICAgICAgICAgICAgICAgICAgIDwvZnMtY2hpcD5cbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICAgICAgPC9tYXQtcGFuZWwtZGVzY3JpcHRpb24+XG4gICAgICAgICAgICAgIDwvbWF0LWV4cGFuc2lvbi1wYW5lbC1oZWFkZXI+XG5cbiAgICAgICAgICAgICAgPCEtLSBEZWZlcnJlZDogdGhlIGJvZHkgKGFuZCBpdHMgZnVuY3Rpb25zIHJlcXVlc3QpIG9ubHkgZXhpc3RzXG4gICAgICAgICAgICAgICAgICAgb25jZSBleHBhbmRlZC4gLS0+XG4gICAgICAgICAgICAgIDxuZy10ZW1wbGF0ZSBtYXRFeHBhbnNpb25QYW5lbENvbnRlbnQ+XG4gICAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cImVudGl0eS1kZXRhaWxcIj5cbiAgICAgICAgICAgICAgICAgIDxkaXY+PHN0cm9uZz5UYWJsZTo8L3N0cm9uZz4ge3sgZW50aXR5LnRhYmxlIH19PC9kaXY+XG4gICAgICAgICAgICAgICAgICA8ZGl2PjxzdHJvbmc+Q29sdW1uczo8L3N0cm9uZz4ge3sgZW50aXR5LmNvbHVtbnMgfX08L2Rpdj5cbiAgICAgICAgICAgICAgICAgIDxkaXY+PHN0cm9uZz5SZWxhdGlvbnNoaXBzOjwvc3Ryb25nPiB7eyBlbnRpdHkucmVsYXRpb25zaGlwcyB9fTwvZGl2PlxuICAgICAgICAgICAgICAgICAgQGlmIChlbnRpdHkuZW51bXMubGVuZ3RoKSB7XG4gICAgICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJlbnVtLWxpc3RcIj5cbiAgICAgICAgICAgICAgICAgICAgICA8c3Ryb25nPkVudW0gdmFsdWVzOjwvc3Ryb25nPlxuICAgICAgICAgICAgICAgICAgICAgIEBmb3IgKGVudW1Db2x1bW4gb2YgZW50aXR5LmVudW1zOyB0cmFjayBlbnVtQ29sdW1uLmNvbHVtbikge1xuICAgICAgICAgICAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cImVudW0tcm93XCI+XG4gICAgICAgICAgICAgICAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwiZW51bS1jb2x1bW5cIj57eyBlbnVtQ29sdW1uLmNvbHVtbiB9fTwvc3Bhbj5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJlbnVtLXZhbHVlc1wiPnt7IGVudW1Db2x1bW4udmFsdWVzLmpvaW4oJywgJykgfX08L3NwYW4+XG4gICAgICAgICAgICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgQGlmIChlbnRpdHkuY29tcHV0ZWRGaWVsZHMubGVuZ3RoKSB7XG4gICAgICAgICAgICAgICAgICAgIDxkaXY+PHN0cm9uZz5Db21wdXRlZCBmaWVsZHM6PC9zdHJvbmc+IHt7IGVudGl0eS5jb21wdXRlZEZpZWxkcy5qb2luKCcsICcpIH19PC9kaXY+XG4gICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJmdW5jdGlvbnMtc2VjdGlvblwiPlxuICAgICAgICAgICAgICAgICAgICA8aDMgY2xhc3M9XCJmdW5jdGlvbnMtaGVhZGluZ1wiPlxuICAgICAgICAgICAgICAgICAgICAgIENvZGUgZnVuY3Rpb25zXG4gICAgICAgICAgICAgICAgICAgICAgQGlmIChlbnRpdHkuZnVuY3Rpb25Db3VudCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJmdW5jdGlvbnMtY291bnRcIj4oe3sgZW50aXR5LmZ1bmN0aW9uQ291bnQgfX0pPC9zcGFuPlxuICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgPC9oMz5cblxuICAgICAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwiZnVuY3Rpb25zLWJvZHlcIiAqZnNTa2VsZXRvbj1cImVudGl0eUZ1bmN0aW9ucyhlbnRpdHkua2V5KVwiPlxuICAgICAgICAgICAgICAgICAgICAgIEBpZiAoZW50aXR5RnVuY3Rpb25zKGVudGl0eS5rZXkpOyBhcyBmbnMpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIEBpZiAoZm5zLmZ1bmN0aW9ucy5sZW5ndGgpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgQGlmIChmbnMuZ2VuZXJhdGVkQXQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwiaGludCBmdW5jdGlvbnMtZ2VuZXJhdGVkXCI+XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICBEaXNjb3ZlcmVkIGZyb20ge3sgZm5zLmNsYXNzIH19ICZtaWRkb3Q7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8ZnMtZGF0ZVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFtkYXRlXT1cImZucy5nZW5lcmF0ZWRBdFwiXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZm9ybWF0PVwiZGF0ZS10aW1lXCI+XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L2ZzLWRhdGU+XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cImZ1bmN0aW9ucy1saXN0XCI+XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgQGZvciAoZm4gb2YgZm5zLmZ1bmN0aW9uczsgdHJhY2sgZm4ubWV0aG9kKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwiZnVuY3Rpb24tcm93XCI+XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJmdW5jdGlvbi1oZWFkXCI+XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPGZzLWNoaXBcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2l6ZT1cInRpbnlcIlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBbYmFja2dyb3VuZENvbG9yXT1cImtpbmRDb2xvcihmbi5raW5kKVwiXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yPVwiI2ZmZmZmZlwiPlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAge3sgZm4ua2luZCB9fVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvZnMtY2hpcD5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8Y29kZSBjbGFzcz1cImZ1bmN0aW9uLW1ldGhvZFwiPnt7IGZuLm1ldGhvZCB9fTwvY29kZT5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJmdW5jdGlvbi1zdW1tYXJ5XCI+e3sgZm4uc3VtbWFyeSB9fTwvZGl2PlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBAaWYgKGZuLnByb2R1Y2VzKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cImZ1bmN0aW9uLXByb2R1Y2VzIGhpbnRcIj5Qcm9kdWNlczoge3sgZm4ucHJvZHVjZXMgfX08L2Rpdj5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgICAgICAgICAgICAgIH0gQGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwiaGludFwiPlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIE5vIGZ1bmN0aW9ucyBjYWNoZWQgZm9yIHRoaXMgZW50aXR5IHlldCDigJQgcnVuIGEgYnVpbGQgdG8gZGlzY292ZXIgaXRzIGNvZGUuXG4gICAgICAgICAgICAgICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgICAgPC9uZy10ZW1wbGF0ZT5cbiAgICAgICAgICAgIDwvbWF0LWV4cGFuc2lvbi1wYW5lbD5cbiAgICAgICAgICB9XG4gICAgICAgIDwvbWF0LWFjY29yZGlvbj5cbiAgICAgIH1cbiAgICB9XG4gIDwvZGl2PlxuPC9kaXY+XG4iXX0=