@firestitch/report 18.0.11 → 18.0.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (19) hide show
  1. package/app/reports/dialogs/entity-functions/entity-functions.component.d.ts +22 -0
  2. package/app/reports/dialogs/global-settings/components/semantic-database/semantic-database.component.d.ts +6 -21
  3. package/app/reports/dialogs/global-settings/global-settings.component.d.ts +3 -3
  4. package/app/reports/dialogs/instruction-history/instruction-history.component.d.ts +16 -0
  5. package/app/reports/interfaces/report.interface.d.ts +6 -1
  6. package/esm2022/app/reports/dialogs/entity-functions/entity-functions.component.mjs +81 -0
  7. package/esm2022/app/reports/dialogs/global-settings/components/semantic-database/semantic-database.component.mjs +23 -71
  8. package/esm2022/app/reports/dialogs/global-settings/global-settings.component.mjs +31 -22
  9. package/esm2022/app/reports/dialogs/instruction-history/instruction-history.component.mjs +60 -0
  10. package/esm2022/app/reports/interfaces/report.interface.mjs +1 -1
  11. package/fesm2022/{firestitch-report-echarts-DaBOoR9Z.mjs → firestitch-report-echarts-1VNsyco5.mjs} +2 -2
  12. package/fesm2022/{firestitch-report-echarts-DaBOoR9Z.mjs.map → firestitch-report-echarts-1VNsyco5.mjs.map} +1 -1
  13. package/fesm2022/{firestitch-report-firestitch-report-Cwsww3Jz.mjs → firestitch-report-firestitch-report-BNHGwPj2.mjs} +163 -115
  14. package/fesm2022/firestitch-report-firestitch-report-BNHGwPj2.mjs.map +1 -0
  15. package/fesm2022/firestitch-report.mjs +1 -1
  16. package/package.json +1 -1
  17. package/app/reports/dialogs/global-settings/components/history/history.component.d.ts +0 -8
  18. package/esm2022/app/reports/dialogs/global-settings/components/history/history.component.mjs +0 -32
  19. package/fesm2022/firestitch-report-firestitch-report-Cwsww3Jz.mjs.map +0 -1
@@ -0,0 +1,22 @@
1
+ import { SemanticEntityFunction, SemanticEntityFunctions } from '../../interfaces/report.interface';
2
+ import * as i0 from "@angular/core";
3
+ export interface EntityFunctionsDialogData {
4
+ entityKey: string;
5
+ source: 'model' | 'handler';
6
+ }
7
+ export declare class EntityFunctionsComponent {
8
+ private static readonly KIND_COLORS;
9
+ private static readonly KIND_ORDER;
10
+ private readonly _data;
11
+ readonly entityKey: string;
12
+ readonly sourceLabel: string;
13
+ readonly entityFunctions: import("@angular/core").WritableSignal<SemanticEntityFunctions>;
14
+ readonly discoveredClass: import("@angular/core").Signal<string>;
15
+ readonly functions: import("@angular/core").Signal<SemanticEntityFunction[]>;
16
+ constructor();
17
+ kindColor(kind: string): string;
18
+ private _sortFunctions;
19
+ private _kindRank;
20
+ static ɵfac: i0.ɵɵFactoryDeclaration<EntityFunctionsComponent, never>;
21
+ static ɵcmp: i0.ɵɵComponentDeclaration<EntityFunctionsComponent, "ng-component", never, {}, {}, never, never, true, never>;
22
+ }
@@ -1,20 +1,18 @@
1
- import { SemanticBuildEntity, SemanticBuildStage, SemanticBuildStatus, SemanticEntityFunctions } from '../../../../interfaces/report.interface';
1
+ import { SemanticBuildEntity, SemanticBuildStage, SemanticBuildStatus } from '../../../../interfaces/report.interface';
2
2
  import * as i0 from "@angular/core";
3
3
  export declare class SemanticDatabaseComponent {
4
4
  private static readonly ACTIVE_STATES;
5
5
  private static readonly STATE_LABELS;
6
6
  private static readonly DONE_COLOR;
7
7
  private static readonly PENDING_COLOR;
8
- private static readonly KIND_COLORS;
9
- private static readonly KIND_ORDER;
10
8
  readonly stageKeys: string[];
11
9
  readonly stageLabels: Record<string, string>;
12
10
  readonly status: import("@angular/core").WritableSignal<SemanticBuildStatus>;
13
11
  readonly building: import("@angular/core").WritableSignal<boolean>;
14
12
  readonly buildActive: import("@angular/core").Signal<boolean>;
15
13
  readonly buildStateLabel: import("@angular/core").Signal<string>;
16
- private readonly _entityFunctions;
17
14
  private _buildFinalized;
15
+ private readonly _dialog;
18
16
  private readonly _reportData;
19
17
  private readonly _process;
20
18
  private readonly _prompt;
@@ -40,27 +38,14 @@ export declare class SemanticDatabaseComponent {
40
38
  private _announceOutcome;
41
39
  stageColor(stage: SemanticBuildStage): string;
42
40
  stageTooltip(stage: SemanticBuildStage): string;
43
- kindColor(kind: string): string;
44
41
  /**
45
- * The loaded function cache for an entity: undefined until the panel is first
46
- * expanded, null while the request is in flight (the skeleton window), then
47
- * the loaded cache.
42
+ * Open the child dialog listing one group of an entity's cached functions —
43
+ * the model class's or the handler class's. The dialog fetches fresh on open,
44
+ * so the tab never holds function payloads.
48
45
  */
49
- entityFunctions(key: string): SemanticEntityFunctions | null | undefined;
50
- /**
51
- * First expand of an entity: fetch its cached functions through the per-entity
52
- * endpoint. Subsequent expands reuse the loaded copy (a finished build clears
53
- * the copies so a re-expand refetches fresh data).
54
- */
55
- entityOpened(entity: SemanticBuildEntity): void;
46
+ openFunctions(entity: SemanticBuildEntity, source: 'model' | 'handler'): void;
56
47
  private _init;
57
48
  private _refreshStatus;
58
- /**
59
- * Order once at load time (kind priority, then method name) so the template
60
- * renders the list as-is.
61
- */
62
- private _sortFunctions;
63
- private _kindRank;
64
49
  static ɵfac: i0.ɵɵFactoryDeclaration<SemanticDatabaseComponent, never>;
65
50
  static ɵcmp: i0.ɵɵComponentDeclaration<SemanticDatabaseComponent, "fs-ai-report-global-settings-semantic-database", never, {}, {}, never, never, true, never>;
66
51
  }
@@ -1,5 +1,5 @@
1
1
  import { FsMarkdownEditorConfig } from '@firestitch/markdown-editor';
2
- import { ReportInstruction, ReportInstructions, ReportSettings } from '../../interfaces/report.interface';
2
+ import { ReportInstructions, ReportSettings } from '../../interfaces/report.interface';
3
3
  import { SemanticDatabaseComponent } from './components/semantic-database/semantic-database.component';
4
4
  import * as i0 from "@angular/core";
5
5
  export declare class GlobalSettingsComponent {
@@ -12,13 +12,13 @@ export declare class GlobalSettingsComponent {
12
12
  readonly concurrency: import("@angular/core").WritableSignal<number>;
13
13
  readonly loaded: import("@angular/core").Signal<boolean>;
14
14
  private readonly _dialogRef;
15
+ private readonly _dialog;
15
16
  private readonly _reportData;
16
17
  private readonly _message;
17
- private readonly _prompt;
18
18
  private readonly _destroyRef;
19
19
  constructor();
20
20
  save: () => import("rxjs").Observable<ReportSettings> | import("rxjs").Observable<ReportInstructions>;
21
- restore(version: ReportInstruction): void;
21
+ openHistory(): void;
22
22
  private _init;
23
23
  private _applyInstructions;
24
24
  private _applySettings;
@@ -0,0 +1,16 @@
1
+ import { ReportInstruction } from '../../interfaces/report.interface';
2
+ import * as i0 from "@angular/core";
3
+ export interface InstructionHistoryDialogData {
4
+ versions: ReportInstruction[];
5
+ }
6
+ export declare class InstructionHistoryComponent {
7
+ private readonly _data;
8
+ readonly versions: import("@angular/core").WritableSignal<ReportInstruction[]>;
9
+ private readonly _reportData;
10
+ private readonly _prompt;
11
+ private readonly _message;
12
+ private readonly _destroyRef;
13
+ restore(version: ReportInstruction): void;
14
+ static ɵfac: i0.ɵɵFactoryDeclaration<InstructionHistoryComponent, never>;
15
+ static ɵcmp: i0.ɵɵComponentDeclaration<InstructionHistoryComponent, "ng-component", never, {}, {}, never, never, true, never>;
16
+ }
@@ -211,6 +211,8 @@ export interface SemanticBuildEntity {
211
211
  enums: SemanticBuildEnum[];
212
212
  computedFields: string[];
213
213
  functionCount: number;
214
+ modelFunctionCount: number;
215
+ handlerFunctionCount: number;
214
216
  stages: Record<string, SemanticBuildStage>;
215
217
  }
216
218
  export interface SemanticBuildDetail {
@@ -220,16 +222,19 @@ export interface SemanticBuildDetail {
220
222
  entities: SemanticBuildEntity[];
221
223
  }
222
224
  export interface SemanticEntityFunction {
225
+ class: string;
223
226
  method: string;
224
227
  signature: string;
225
228
  kind: string;
226
229
  summary: string;
227
230
  produces: string;
231
+ source: 'model' | 'handler';
228
232
  }
229
233
  export interface SemanticEntityFunctions {
230
234
  entity: string;
231
235
  generatedAt: Date | null;
232
- class: string | null;
236
+ modelClass: string | null;
237
+ handlerClass: string | null;
233
238
  functions: SemanticEntityFunction[];
234
239
  }
235
240
  export interface SemanticBuildStatus {
@@ -0,0 +1,81 @@
1
+ import { ChangeDetectionStrategy, Component, computed, inject, signal } from '@angular/core';
2
+ import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
3
+ import { MatButton } from '@angular/material/button';
4
+ import { MAT_DIALOG_DATA, MatDialogActions, MatDialogClose, MatDialogContent } from '@angular/material/dialog';
5
+ import { FsChipModule } from '@firestitch/chip';
6
+ import { FsDateModule } from '@firestitch/date';
7
+ import { FsDialogModule } from '@firestitch/dialog';
8
+ import { FsSkeletonModule } from '@firestitch/skeleton';
9
+ import { ReportData } from '../../data/report.data';
10
+ import * as i0 from "@angular/core";
11
+ import * as i1 from "@firestitch/chip";
12
+ import * as i2 from "@firestitch/date";
13
+ import * as i3 from "@firestitch/dialog";
14
+ import * as i4 from "@firestitch/skeleton";
15
+ // One group of an entity's AI-classified cached code functions — the model
16
+ // class's or the handler class's, per the source it was opened for. Fetched on
17
+ // open from the shared per-entity endpoint (one payload carries both groups,
18
+ // each row tagged with its source) and filtered client-side.
19
+ export class EntityFunctionsComponent {
20
+ // One color per AI classification kind, so a function's nature reads at a glance.
21
+ static KIND_COLORS = {
22
+ 'calculation': '#1565c0',
23
+ 'business-rule': '#6a1b9a',
24
+ 'query': '#00695c',
25
+ 'mutation': '#e65100',
26
+ 'accessor': '#546e7a',
27
+ 'other': '#757575',
28
+ };
29
+ // Interesting logic first: derived values and rules, then data access, then the rest.
30
+ static KIND_ORDER = ['calculation', 'business-rule', 'query', 'mutation', 'accessor', 'other'];
31
+ _data = inject(MAT_DIALOG_DATA);
32
+ entityKey = this._data.entityKey;
33
+ sourceLabel = this._data.source === 'model' ? 'Model functions' : 'Handler functions';
34
+ // null until loaded — gates the list behind the skeleton.
35
+ entityFunctions = signal(null);
36
+ // The class this group's functions were discovered from.
37
+ discoveredClass = computed(() => {
38
+ const loaded = this.entityFunctions();
39
+ return this._data.source === 'model' ? loaded?.modelClass : loaded?.handlerClass;
40
+ });
41
+ // This group's functions, ordered by kind priority then method name.
42
+ functions = computed(() => this._sortFunctions((this.entityFunctions()?.functions ?? [])
43
+ .filter((fn) => fn.source === this._data.source)));
44
+ constructor() {
45
+ inject(ReportData).semanticEntityFunctions(this._data.entityKey)
46
+ .pipe(takeUntilDestroyed())
47
+ .subscribe((entityFunctions) => {
48
+ this.entityFunctions.set(entityFunctions);
49
+ });
50
+ }
51
+ kindColor(kind) {
52
+ return EntityFunctionsComponent.KIND_COLORS[kind] ?? EntityFunctionsComponent.KIND_COLORS.other;
53
+ }
54
+ _sortFunctions(functions) {
55
+ return [...functions]
56
+ .sort((a, b) => {
57
+ const kindDiff = this._kindRank(a.kind) - this._kindRank(b.kind);
58
+ return kindDiff !== 0 ? kindDiff : a.method.localeCompare(b.method);
59
+ });
60
+ }
61
+ _kindRank(kind) {
62
+ const rank = EntityFunctionsComponent.KIND_ORDER.indexOf(kind);
63
+ return rank === -1 ? EntityFunctionsComponent.KIND_ORDER.length : rank;
64
+ }
65
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: EntityFunctionsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
66
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: EntityFunctionsComponent, isStandalone: true, selector: "ng-component", ngImport: i0, template: "<fs-dialog>\n <fs-dialog-title>\n {{ entityKey }} \u2014 {{ sourceLabel }}\n </fs-dialog-title>\n <mat-dialog-content>\n <div *fsSkeleton=\"entityFunctions()\">\n @if (entityFunctions(); as fns) {\n @if (functions().length) {\n @if (fns.generatedAt) {\n <div class=\"hint functions-generated\">\n Discovered from {{ discoveredClass() }} &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 functions(); track fn.class + '::' + 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 </mat-dialog-content>\n <mat-dialog-actions>\n <button\n type=\"button\"\n mat-button\n color=\"primary\"\n [mat-dialog-close]=\"undefined\">\n Close\n </button>\n </mat-dialog-actions>\n</fs-dialog>\n", styles: [".hint{margin:0;color:#0009;font-size:13px;line-height:1.5}.functions-generated{margin-bottom:10px}.functions-list{display:flex;flex-direction:column}.functions-list .function-row{display:flex;flex-direction:column;gap:3px;padding:10px 0}.functions-list .function-row+.function-row{border-top:1px solid rgba(0,0,0,.08)}.functions-list .function-row .function-head{display:flex;align-items:center;gap:8px}.functions-list .function-row .function-method{font-family:monospace;font-size:13px;font-weight:600}.functions-list .function-row .function-summary{color:#000000bf}.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: "directive", type: MatDialogContent, selector: "[mat-dialog-content], mat-dialog-content, [matDialogContent]" }, { kind: "directive", type: MatDialogActions, selector: "[mat-dialog-actions], mat-dialog-actions, [matDialogActions]", inputs: ["align"] }, { kind: "directive", type: MatDialogClose, selector: "[mat-dialog-close], [matDialogClose]", inputs: ["aria-label", "type", "mat-dialog-close", "matDialogClose"], exportAs: ["matDialogClose"] }, { kind: "ngmodule", type: FsChipModule }, { kind: "component", type: i1.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: i2.FsDateComponent, selector: "fs-date", inputs: ["date", "format", "timezone"] }, { kind: "ngmodule", type: FsDialogModule }, { kind: "component", type: i3.FsDialogComponent, selector: "fs-dialog", inputs: ["mobileMode", "mobileButtonPlacement", "mobileWidth", "mode", "buttonLayout"] }, { kind: "component", type: i3.FsDialogTitleComponent, selector: "fs-dialog-title", inputs: ["close", "dockToggle", "back"] }, { kind: "ngmodule", type: FsSkeletonModule }, { kind: "directive", type: i4.FsSkeletonContentDirective, selector: "[fsSkeleton]", inputs: ["fsSkeleton", "fsSkeletonPattern"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
67
+ }
68
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: EntityFunctionsComponent, decorators: [{
69
+ type: Component,
70
+ args: [{ changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [
71
+ MatButton,
72
+ MatDialogContent,
73
+ MatDialogActions,
74
+ MatDialogClose,
75
+ FsChipModule,
76
+ FsDateModule,
77
+ FsDialogModule,
78
+ FsSkeletonModule,
79
+ ], template: "<fs-dialog>\n <fs-dialog-title>\n {{ entityKey }} \u2014 {{ sourceLabel }}\n </fs-dialog-title>\n <mat-dialog-content>\n <div *fsSkeleton=\"entityFunctions()\">\n @if (entityFunctions(); as fns) {\n @if (functions().length) {\n @if (fns.generatedAt) {\n <div class=\"hint functions-generated\">\n Discovered from {{ discoveredClass() }} &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 functions(); track fn.class + '::' + 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 </mat-dialog-content>\n <mat-dialog-actions>\n <button\n type=\"button\"\n mat-button\n color=\"primary\"\n [mat-dialog-close]=\"undefined\">\n Close\n </button>\n </mat-dialog-actions>\n</fs-dialog>\n", styles: [".hint{margin:0;color:#0009;font-size:13px;line-height:1.5}.functions-generated{margin-bottom:10px}.functions-list{display:flex;flex-direction:column}.functions-list .function-row{display:flex;flex-direction:column;gap:3px;padding:10px 0}.functions-list .function-row+.function-row{border-top:1px solid rgba(0,0,0,.08)}.functions-list .function-row .function-head{display:flex;align-items:center;gap:8px}.functions-list .function-row .function-method{font-family:monospace;font-size:13px;font-weight:600}.functions-list .function-row .function-summary{color:#000000bf}.functions-list .function-row .function-produces{padding-left:10px}\n"] }]
80
+ }], ctorParameters: () => [] });
81
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZW50aXR5LWZ1bmN0aW9ucy5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9zcmMvYXBwL3JlcG9ydHMvZGlhbG9ncy9lbnRpdHktZnVuY3Rpb25zL2VudGl0eS1mdW5jdGlvbnMuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vLi4vLi4vc3JjL2FwcC9yZXBvcnRzL2RpYWxvZ3MvZW50aXR5LWZ1bmN0aW9ucy9lbnRpdHktZnVuY3Rpb25zLmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSx1QkFBdUIsRUFBRSxTQUFTLEVBQUUsUUFBUSxFQUFFLE1BQU0sRUFBRSxNQUFNLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDN0YsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sNEJBQTRCLENBQUM7QUFFaEUsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLDBCQUEwQixDQUFDO0FBQ3JELE9BQU8sRUFBRSxlQUFlLEVBQUUsZ0JBQWdCLEVBQUUsY0FBYyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFFL0csT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBQ2hELE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQztBQUNoRCxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFDcEQsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFFeEQsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLHdCQUF3QixDQUFDOzs7Ozs7QUFhcEQsMkVBQTJFO0FBQzNFLCtFQUErRTtBQUMvRSw2RUFBNkU7QUFDN0UsNkRBQTZEO0FBaUI3RCxNQUFNLE9BQU8sd0JBQXdCO0lBRW5DLGtGQUFrRjtJQUMxRSxNQUFNLENBQVUsV0FBVyxHQUEyQjtRQUM1RCxhQUFhLEVBQUUsU0FBUztRQUN4Qixl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QztJQUN6RSxDQUFDO3dHQS9EVSx3QkFBd0I7NEZBQXhCLHdCQUF3Qix3RUM1Q3JDLG95REFzREEsc3JCRHBCSSxTQUFTLGlMQUNULGdCQUFnQix5R0FDaEIsZ0JBQWdCLDRIQUNoQixjQUFjLG9MQUNkLFlBQVkscVhBQ1osWUFBWSw0SUFDWixjQUFjLDhUQUNkLGdCQUFnQjs7NEZBR1Asd0JBQXdCO2tCQWhCcEMsU0FBUztzQ0FHUyx1QkFBdUIsQ0FBQyxNQUFNLGNBQ25DLElBQUksV0FDUDt3QkFDUCxTQUFTO3dCQUNULGdCQUFnQjt3QkFDaEIsZ0JBQWdCO3dCQUNoQixjQUFjO3dCQUNkLFlBQVk7d0JBQ1osWUFBWTt3QkFDWixjQUFjO3dCQUNkLGdCQUFnQjtxQkFDakIiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneSwgQ29tcG9uZW50LCBjb21wdXRlZCwgaW5qZWN0LCBzaWduYWwgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IHRha2VVbnRpbERlc3Ryb3llZCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUvcnhqcy1pbnRlcm9wJztcblxuaW1wb3J0IHsgTWF0QnV0dG9uIH0gZnJvbSAnQGFuZ3VsYXIvbWF0ZXJpYWwvYnV0dG9uJztcbmltcG9ydCB7IE1BVF9ESUFMT0dfREFUQSwgTWF0RGlhbG9nQWN0aW9ucywgTWF0RGlhbG9nQ2xvc2UsIE1hdERpYWxvZ0NvbnRlbnQgfSBmcm9tICdAYW5ndWxhci9tYXRlcmlhbC9kaWFsb2cnO1xuXG5pbXBvcnQgeyBGc0NoaXBNb2R1bGUgfSBmcm9tICdAZmlyZXN0aXRjaC9jaGlwJztcbmltcG9ydCB7IEZzRGF0ZU1vZHVsZSB9IGZyb20gJ0BmaXJlc3RpdGNoL2RhdGUnO1xuaW1wb3J0IHsgRnNEaWFsb2dNb2R1bGUgfSBmcm9tICdAZmlyZXN0aXRjaC9kaWFsb2cnO1xuaW1wb3J0IHsgRnNTa2VsZXRvbk1vZHVsZSB9IGZyb20gJ0BmaXJlc3RpdGNoL3NrZWxldG9uJztcblxuaW1wb3J0IHsgUmVwb3J0RGF0YSB9IGZyb20gJy4uLy4uL2RhdGEvcmVwb3J0LmRhdGEnO1xuaW1wb3J0IHtcbiAgU2VtYW50aWNFbnRpdHlGdW5jdGlvbixcbiAgU2VtYW50aWNFbnRpdHlGdW5jdGlvbnMsXG59IGZyb20gJy4uLy4uL2ludGVyZmFjZXMvcmVwb3J0LmludGVyZmFjZSc7XG5cblxuZXhwb3J0IGludGVyZmFjZSBFbnRpdHlGdW5jdGlvbnNEaWFsb2dEYXRhIHtcbiAgZW50aXR5S2V5OiBzdHJpbmc7XG4gIHNvdXJjZTogJ21vZGVsJyB8ICdoYW5kbGVyJztcbn1cblxuXG4vLyBPbmUgZ3JvdXAgb2YgYW4gZW50aXR5J3MgQUktY2xhc3NpZmllZCBjYWNoZWQgY29kZSBmdW5jdGlvbnMg4oCUIHRoZSBtb2RlbFxuLy8gY2xhc3MncyBvciB0aGUgaGFuZGxlciBjbGFzcydzLCBwZXIgdGhlIHNvdXJjZSBpdCB3YXMgb3BlbmVkIGZvci4gRmV0Y2hlZCBvblxuLy8gb3BlbiBmcm9tIHRoZSBzaGFyZWQgcGVyLWVudGl0eSBlbmRwb2ludCAob25lIHBheWxvYWQgY2FycmllcyBib3RoIGdyb3Vwcyxcbi8vIGVhY2ggcm93IHRhZ2dlZCB3aXRoIGl0cyBzb3VyY2UpIGFuZCBmaWx0ZXJlZCBjbGllbnQtc2lkZS5cbkBDb21wb25lbnQoe1xuICB0ZW1wbGF0ZVVybDogJy4vZW50aXR5LWZ1bmN0aW9ucy5jb21wb25lbnQuaHRtbCcsXG4gIHN0eWxlVXJsczogWycuL2VudGl0eS1mdW5jdGlvbnMuY29tcG9uZW50LnNjc3MnXSxcbiAgY2hhbmdlRGV0ZWN0aW9uOiBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneS5PblB1c2gsXG4gIHN0YW5kYWxvbmU6IHRydWUsXG4gIGltcG9ydHM6IFtcbiAgICBNYXRCdXR0b24sXG4gICAgTWF0RGlhbG9nQ29udGVudCxcbiAgICBNYXREaWFsb2dBY3Rpb25zLFxuICAgIE1hdERpYWxvZ0Nsb3NlLFxuICAgIEZzQ2hpcE1vZHVsZSxcbiAgICBGc0RhdGVNb2R1bGUsXG4gICAgRnNEaWFsb2dNb2R1bGUsXG4gICAgRnNTa2VsZXRvbk1vZHVsZSxcbiAgXSxcbn0pXG5leHBvcnQgY2xhc3MgRW50aXR5RnVuY3Rpb25zQ29tcG9uZW50IHtcblxuICAvLyBPbmUgY29sb3IgcGVyIEFJIGNsYXNzaWZpY2F0aW9uIGtpbmQsIHNvIGEgZnVuY3Rpb24ncyBuYXR1cmUgcmVhZHMgYXQgYSBnbGFuY2UuXG4gIHByaXZhdGUgc3RhdGljIHJlYWRvbmx5IEtJTkRfQ09MT1JTOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+ID0ge1xuICAgICdjYWxjdWxhdGlvbic6ICcjMTU2NWMwJyxcbiAgICAnYnVzaW5lc3MtcnVsZSc6ICcjNmExYjlhJyxcbiAgICAncXVlcnknOiAnIzAwNjk1YycsXG4gICAgJ211dGF0aW9uJzogJyNlNjUxMDAnLFxuICAgICdhY2Nlc3Nvcic6ICcjNTQ2ZTdhJyxcbiAgICAnb3RoZXInOiAnIzc1NzU3NScsXG4gIH07XG5cbiAgLy8gSW50ZXJlc3RpbmcgbG9naWMgZmlyc3Q6IGRlcml2ZWQgdmFsdWVzIGFuZCBydWxlcywgdGhlbiBkYXRhIGFjY2VzcywgdGhlbiB0aGUgcmVzdC5cbiAgcHJpdmF0ZSBzdGF0aWMgcmVhZG9ubHkgS0lORF9PUkRFUiA9IFsnY2FsY3VsYXRpb24nLCAnYnVzaW5lc3MtcnVsZScsICdxdWVyeScsICdtdXRhdGlvbicsICdhY2Nlc3NvcicsICdvdGhlciddO1xuXG4gIHByaXZhdGUgcmVhZG9ubHkgX2RhdGEgPSBpbmplY3Q8RW50aXR5RnVuY3Rpb25zRGlhbG9nRGF0YT4oTUFUX0RJQUxPR19EQVRBKTtcblxuICBwdWJsaWMgcmVhZG9ubHkgZW50aXR5S2V5ID0gdGhpcy5fZGF0YS5lbnRpdHlLZXk7XG4gIHB1YmxpYyByZWFkb25seSBzb3VyY2VMYWJlbCA9IHRoaXMuX2RhdGEuc291cmNlID09PSAnbW9kZWwnID8gJ01vZGVsIGZ1bmN0aW9ucycgOiAnSGFuZGxlciBmdW5jdGlvbnMnO1xuXG4gIC8vIG51bGwgdW50aWwgbG9hZGVkIOKAlCBnYXRlcyB0aGUgbGlzdCBiZWhpbmQgdGhlIHNrZWxldG9uLlxuICBwdWJsaWMgcmVhZG9ubHkgZW50aXR5RnVuY3Rpb25zID0gc2lnbmFsPFNlbWFudGljRW50aXR5RnVuY3Rpb25zIHwgbnVsbD4obnVsbCk7XG5cbiAgLy8gVGhlIGNsYXNzIHRoaXMgZ3JvdXAncyBmdW5jdGlvbnMgd2VyZSBkaXNjb3ZlcmVkIGZyb20uXG4gIHB1YmxpYyByZWFkb25seSBkaXNjb3ZlcmVkQ2xhc3MgPSBjb21wdXRlZDxzdHJpbmcgfCBudWxsPigoKSA9PiB7XG4gICAgY29uc3QgbG9hZGVkID0gdGhpcy5lbnRpdHlGdW5jdGlvbnMoKTtcblxuICAgIHJldHVybiB0aGlzLl9kYXRhLnNvdXJjZSA9PT0gJ21vZGVsJyA/IGxvYWRlZD8ubW9kZWxDbGFzcyA6IGxvYWRlZD8uaGFuZGxlckNsYXNzO1xuICB9KTtcblxuICAvLyBUaGlzIGdyb3VwJ3MgZnVuY3Rpb25zLCBvcmRlcmVkIGJ5IGtpbmQgcHJpb3JpdHkgdGhlbiBtZXRob2QgbmFtZS5cbiAgcHVibGljIHJlYWRvbmx5IGZ1bmN0aW9ucyA9IGNvbXB1dGVkPFNlbWFudGljRW50aXR5RnVuY3Rpb25bXT4oKCkgPT5cbiAgICB0aGlzLl9zb3J0RnVuY3Rpb25zKFxuICAgICAgKHRoaXMuZW50aXR5RnVuY3Rpb25zKCk/LmZ1bmN0aW9ucyA/PyBbXSlcbiAgICAgICAgLmZpbHRlcigoZm4pID0+IGZuLnNvdXJjZSA9PT0gdGhpcy5fZGF0YS5zb3VyY2UpLFxuICAgICksXG4gICk7XG5cbiAgY29uc3RydWN0b3IoKSB7XG4gICAgaW5qZWN0KFJlcG9ydERhdGEpLnNlbWFudGljRW50aXR5RnVuY3Rpb25zKHRoaXMuX2RhdGEuZW50aXR5S2V5KVxuICAgICAgLnBpcGUodGFrZVVudGlsRGVzdHJveWVkKCkpXG4gICAgICAuc3Vic2NyaWJlKChlbnRpdHlGdW5jdGlvbnM6IFNlbWFudGljRW50aXR5RnVuY3Rpb25zKSA9PiB7XG4gICAgICAgIHRoaXMuZW50aXR5RnVuY3Rpb25zLnNldChlbnRpdHlGdW5jdGlvbnMpO1xuICAgICAgfSk7XG4gIH1cblxuICBwdWJsaWMga2luZENvbG9yKGtpbmQ6IHN0cmluZyk6IHN0cmluZyB7XG4gICAgcmV0dXJuIEVudGl0eUZ1bmN0aW9uc0NvbXBvbmVudC5LSU5EX0NPTE9SU1traW5kXSA/PyBFbnRpdHlGdW5jdGlvbnNDb21wb25lbnQuS0lORF9DT0xPUlMub3RoZXI7XG4gIH1cblxuICBwcml2YXRlIF9zb3J0RnVuY3Rpb25zKGZ1bmN0aW9uczogU2VtYW50aWNFbnRpdHlGdW5jdGlvbltdKTogU2VtYW50aWNFbnRpdHlGdW5jdGlvbltdIHtcbiAgICByZXR1cm4gWy4uLmZ1bmN0aW9uc11cbiAgICAgIC5zb3J0KChhLCBiKSA9PiB7XG4gICAgICAgIGNvbnN0IGtpbmREaWZmID0gdGhpcy5fa2luZFJhbmsoYS5raW5kKSAtIHRoaXMuX2tpbmRSYW5rKGIua2luZCk7XG5cbiAgICAgICAgcmV0dXJuIGtpbmREaWZmICE9PSAwID8ga2luZERpZmYgOiBhLm1ldGhvZC5sb2NhbGVDb21wYXJlKGIubWV0aG9kKTtcbiAgICAgIH0pO1xuICB9XG5cbiAgcHJpdmF0ZSBfa2luZFJhbmsoa2luZDogc3RyaW5nKTogbnVtYmVyIHtcbiAgICBjb25zdCByYW5rID0gRW50aXR5RnVuY3Rpb25zQ29tcG9uZW50LktJTkRfT1JERVIuaW5kZXhPZihraW5kKTtcblxuICAgIHJldHVybiByYW5rID09PSAtMSA/IEVudGl0eUZ1bmN0aW9uc0NvbXBvbmVudC5LSU5EX09SREVSLmxlbmd0aCA6IHJhbms7XG4gIH1cbn1cbiIsIjxmcy1kaWFsb2c+XG4gIDxmcy1kaWFsb2ctdGl0bGU+XG4gICAge3sgZW50aXR5S2V5IH19IOKAlCB7eyBzb3VyY2VMYWJlbCB9fVxuICA8L2ZzLWRpYWxvZy10aXRsZT5cbiAgPG1hdC1kaWFsb2ctY29udGVudD5cbiAgICA8ZGl2ICpmc1NrZWxldG9uPVwiZW50aXR5RnVuY3Rpb25zKClcIj5cbiAgICAgIEBpZiAoZW50aXR5RnVuY3Rpb25zKCk7IGFzIGZucykge1xuICAgICAgICBAaWYgKGZ1bmN0aW9ucygpLmxlbmd0aCkge1xuICAgICAgICAgIEBpZiAoZm5zLmdlbmVyYXRlZEF0KSB7XG4gICAgICAgICAgICA8ZGl2IGNsYXNzPVwiaGludCBmdW5jdGlvbnMtZ2VuZXJhdGVkXCI+XG4gICAgICAgICAgICAgIERpc2NvdmVyZWQgZnJvbSB7eyBkaXNjb3ZlcmVkQ2xhc3MoKSB9fSAmbWlkZG90O1xuICAgICAgICAgICAgICA8ZnMtZGF0ZVxuICAgICAgICAgICAgICAgICAgW2RhdGVdPVwiZm5zLmdlbmVyYXRlZEF0XCJcbiAgICAgICAgICAgICAgICAgIGZvcm1hdD1cImRhdGUtdGltZVwiPlxuICAgICAgICAgICAgICA8L2ZzLWRhdGU+XG4gICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICB9XG4gICAgICAgICAgPGRpdiBjbGFzcz1cImZ1bmN0aW9ucy1saXN0XCI+XG4gICAgICAgICAgICBAZm9yIChmbiBvZiBmdW5jdGlvbnMoKTsgdHJhY2sgZm4uY2xhc3MgKyAnOjonICsgZm4ubWV0aG9kKSB7XG4gICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJmdW5jdGlvbi1yb3dcIj5cbiAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwiZnVuY3Rpb24taGVhZFwiPlxuICAgICAgICAgICAgICAgICAgPGZzLWNoaXBcbiAgICAgICAgICAgICAgICAgICAgICBzaXplPVwidGlueVwiXG4gICAgICAgICAgICAgICAgICAgICAgW2JhY2tncm91bmRDb2xvcl09XCJraW5kQ29sb3IoZm4ua2luZClcIlxuICAgICAgICAgICAgICAgICAgICAgIGNvbG9yPVwiI2ZmZmZmZlwiPlxuICAgICAgICAgICAgICAgICAgICB7eyBmbi5raW5kIH19XG4gICAgICAgICAgICAgICAgICA8L2ZzLWNoaXA+XG4gICAgICAgICAgICAgICAgICA8Y29kZSBjbGFzcz1cImZ1bmN0aW9uLW1ldGhvZFwiPnt7IGZuLm1ldGhvZCB9fTwvY29kZT5cbiAgICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwiZnVuY3Rpb24tc3VtbWFyeVwiPnt7IGZuLnN1bW1hcnkgfX08L2Rpdj5cbiAgICAgICAgICAgICAgICBAaWYgKGZuLnByb2R1Y2VzKSB7XG4gICAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwiZnVuY3Rpb24tcHJvZHVjZXMgaGludFwiPlByb2R1Y2VzOiB7eyBmbi5wcm9kdWNlcyB9fTwvZGl2PlxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICB9XG4gICAgICAgICAgPC9kaXY+XG4gICAgICAgIH0gQGVsc2Uge1xuICAgICAgICAgIDxkaXYgY2xhc3M9XCJoaW50XCI+XG4gICAgICAgICAgICBObyBmdW5jdGlvbnMgY2FjaGVkIGZvciB0aGlzIGVudGl0eSB5ZXQg4oCUIHJ1biBhIGJ1aWxkIHRvIGRpc2NvdmVyIGl0cyBjb2RlLlxuICAgICAgICAgIDwvZGl2PlxuICAgICAgICB9XG4gICAgICB9XG4gICAgPC9kaXY+XG4gIDwvbWF0LWRpYWxvZy1jb250ZW50PlxuICA8bWF0LWRpYWxvZy1hY3Rpb25zPlxuICAgIDxidXR0b25cbiAgICAgICAgdHlwZT1cImJ1dHRvblwiXG4gICAgICAgIG1hdC1idXR0b25cbiAgICAgICAgY29sb3I9XCJwcmltYXJ5XCJcbiAgICAgICAgW21hdC1kaWFsb2ctY2xvc2VdPVwidW5kZWZpbmVkXCI+XG4gICAgICBDbG9zZVxuICAgIDwvYnV0dG9uPlxuICA8L21hdC1kaWFsb2ctYWN0aW9ucz5cbjwvZnMtZGlhbG9nPlxuIl19