@firestitch/report 18.17.4 → 18.18.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/app/reports/api-error-message.d.ts +1 -0
  2. package/app/reports/data/report.data.d.ts +8 -0
  3. package/app/reports/dialogs/report-package-import/report-package-import.component.d.ts +37 -0
  4. package/app/reports/interfaces/report-package-check.interface.d.ts +21 -0
  5. package/app/reports/interfaces/report-package-finding-severity.type.d.ts +1 -0
  6. package/app/reports/interfaces/report-package-finding.interface.d.ts +7 -0
  7. package/app/reports/interfaces/report-package-import-response.interface.d.ts +6 -0
  8. package/app/reports/interfaces/report-package-imported-report.interface.d.ts +4 -0
  9. package/app/reports/views/report/fs-ai-report.component.d.ts +1 -0
  10. package/app/reports/views/reports/fs-ai-reports.component.d.ts +4 -0
  11. package/esm2022/app/reports/api-error-message.mjs +8 -0
  12. package/esm2022/app/reports/data/report.data.mjs +37 -1
  13. package/esm2022/app/reports/dialogs/report-package-import/report-package-import.component.mjs +144 -0
  14. package/esm2022/app/reports/dialogs/report-settings/report-settings.component.mjs +3 -9
  15. package/esm2022/app/reports/interfaces/report-package-check.interface.mjs +2 -0
  16. package/esm2022/app/reports/interfaces/report-package-finding-severity.type.mjs +2 -0
  17. package/esm2022/app/reports/interfaces/report-package-finding.interface.mjs +2 -0
  18. package/esm2022/app/reports/interfaces/report-package-import-response.interface.mjs +2 -0
  19. package/esm2022/app/reports/interfaces/report-package-imported-report.interface.mjs +2 -0
  20. package/esm2022/app/reports/tile-loads.mjs +6 -9
  21. package/esm2022/app/reports/views/report/fs-ai-report.component.mjs +12 -3
  22. package/esm2022/app/reports/views/reports/fs-ai-reports.component.mjs +56 -9
  23. package/esm2022/public_api.mjs +6 -1
  24. package/fesm2022/{firestitch-report-echarts-BxAcubsP.mjs → firestitch-report-echarts-DrTDdBIP.mjs} +2 -2
  25. package/fesm2022/{firestitch-report-echarts-BxAcubsP.mjs.map → firestitch-report-echarts-DrTDdBIP.mjs.map} +1 -1
  26. package/fesm2022/{firestitch-report-firestitch-report-BtC-wiNZ.mjs → firestitch-report-firestitch-report-Bgr_IprU.mjs} +265 -58
  27. package/fesm2022/firestitch-report-firestitch-report-Bgr_IprU.mjs.map +1 -0
  28. package/fesm2022/firestitch-report.mjs +1 -1
  29. package/package.json +1 -1
  30. package/public_api.d.ts +5 -0
  31. package/fesm2022/firestitch-report-firestitch-report-BtC-wiNZ.mjs.map +0 -1
@@ -0,0 +1,144 @@
1
+ import { HttpContext } from '@angular/common/http';
2
+ import { ChangeDetectionStrategy, Component, DestroyRef, computed, inject, signal } from '@angular/core';
3
+ import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
4
+ import { MatButton } from '@angular/material/button';
5
+ import { MatCheckbox } from '@angular/material/checkbox';
6
+ import { MAT_DIALOG_DATA, MatDialogActions, MatDialogClose, MatDialogContent, MatDialogRef, } from '@angular/material/dialog';
7
+ import { MatProgressSpinner } from '@angular/material/progress-spinner';
8
+ import { DisplayApiError } from '@firestitch/api';
9
+ import { FsDateModule } from '@firestitch/date';
10
+ import { FsDialogModule } from '@firestitch/dialog';
11
+ import { FsFormDialogActionsComponent } from '@firestitch/form';
12
+ import { FsLabelModule } from '@firestitch/label';
13
+ import { FsMessageModule } from '@firestitch/message';
14
+ import { FsSkeletonModule } from '@firestitch/skeleton';
15
+ import { of } from 'rxjs';
16
+ import { catchError, tap } from 'rxjs/operators';
17
+ import { apiErrorMessage } from '../../api-error-message';
18
+ import { ReportData } from '../../data/report.data';
19
+ import * as i0 from "@angular/core";
20
+ import * as i1 from "@firestitch/date";
21
+ import * as i2 from "@firestitch/dialog";
22
+ import * as i3 from "@firestitch/label";
23
+ import * as i4 from "@firestitch/message";
24
+ import * as i5 from "@firestitch/skeleton";
25
+ // The findings in the order they matter: what blocks the import, what has to
26
+ // be accepted, then what is only worth knowing.
27
+ const FINDING_SECTIONS = [
28
+ { severity: 'error', heading: 'Errors' },
29
+ { severity: 'warning', heading: 'Warnings' },
30
+ { severity: 'info', heading: 'Information' },
31
+ ];
32
+ // '1 page', '17 components'.
33
+ function countOf(count, noun) {
34
+ return `${count} ${noun}${count === 1 ? '' : 's'}`;
35
+ }
36
+ // Checks a report package and imports it as a NEW report — an import never
37
+ // updates or replaces one. Opened from the listing's Import with the picked
38
+ // file. The check runs on open, behind the skeleton, and says whether the
39
+ // package can be imported, what it holds, where it will be filed, where it came
40
+ // from, and everything it found, errors first. Errors leave Import disabled;
41
+ // warnings enable it only once the operator says they have reviewed them.
42
+ // Import sends the same file, and the server checks it again before it writes
43
+ // anything. The dialog closes with the new report; a refused import stays open
44
+ // with the server's message.
45
+ export class ReportPackageImportComponent {
46
+ fileName = signal('');
47
+ // Null until the check answers.
48
+ check = signal(null);
49
+ // The check request itself failed, so there is no check to show: its
50
+ // message. A package that fails the check is not this; it answers with
51
+ // error findings.
52
+ checkError = signal(null);
53
+ // The server refused the import: its message.
54
+ importError = signal(null);
55
+ warningsReviewed = signal(false);
56
+ busy = signal(false);
57
+ hasWarnings = computed(() => this._findings()
58
+ .some((finding) => finding.severity === 'warning'));
59
+ sections = computed(() => FINDING_SECTIONS
60
+ .map((section) => ({
61
+ ...section,
62
+ findings: this._findings().filter((finding) => finding.severity === section.severity),
63
+ }))
64
+ .filter((section) => section.findings.length));
65
+ // Where the import files the report: the folder the check resolved, or the
66
+ // top level when the folder it came from is not on this server.
67
+ destination = computed(() => {
68
+ const check = this.check();
69
+ return check?.reportFolderId && check.folderPath?.length
70
+ ? check.folderPath.join(' › ')
71
+ : 'Top level';
72
+ });
73
+ contents = computed(() => {
74
+ const counts = this.check()?.counts;
75
+ if (!counts) {
76
+ return '';
77
+ }
78
+ return [
79
+ countOf(counts.pages, 'page'),
80
+ countOf(counts.components, 'component'),
81
+ countOf(counts.filterGroups, 'filter group'),
82
+ countOf(counts.filters, 'filter'),
83
+ countOf(counts.assets, 'image'),
84
+ ].join(' · ');
85
+ });
86
+ canImport = computed(() => !!this.check()?.valid
87
+ && (!this.hasWarnings() || this.warningsReviewed()));
88
+ _data = inject(MAT_DIALOG_DATA);
89
+ _dialogRef = inject(MatDialogRef);
90
+ _reportData = inject(ReportData);
91
+ _destroyRef = inject(DestroyRef);
92
+ _findings = computed(() => this.check()?.findings ?? []);
93
+ constructor() {
94
+ this._init();
95
+ }
96
+ importPackage() {
97
+ if (this.busy() || !this.canImport()) {
98
+ return;
99
+ }
100
+ this.busy.set(true);
101
+ this.importError.set(null);
102
+ this._reportData.importPackage(this._data.file, { acceptWarnings: this.warningsReviewed() }, this._inlineErrors())
103
+ .pipe(tap((response) => this._dialogRef.close(response.report)), catchError((error) => {
104
+ this.importError.set(apiErrorMessage(error, 'The report could not be imported.'));
105
+ this.busy.set(false);
106
+ return of(null);
107
+ }), takeUntilDestroyed(this._destroyRef))
108
+ .subscribe();
109
+ }
110
+ _init() {
111
+ this.fileName.set(this._data.file.name);
112
+ this._reportData.checkPackage(this._data.file, this._inlineErrors())
113
+ .pipe(tap((check) => this.check.set(check)), catchError((error) => {
114
+ this.checkError.set(apiErrorMessage(error, 'The package could not be checked.'));
115
+ return of(null);
116
+ }), takeUntilDestroyed(this._destroyRef))
117
+ .subscribe();
118
+ }
119
+ // A failed check or a refused import is shown in the dialog, beside what it
120
+ // is about, rather than in a second dialog over it.
121
+ _inlineErrors() {
122
+ return { context: new HttpContext().set(DisplayApiError, false) };
123
+ }
124
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ReportPackageImportComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
125
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: ReportPackageImportComponent, isStandalone: true, selector: "ng-component", ngImport: i0, template: "<fs-dialog>\n <fs-dialog-title>\n Import Report\n <ng-template fsDialogSubtitle>\n {{ fileName() }}\n </ng-template>\n </fs-dialog-title>\n <mat-dialog-content>\n <!-- The check runs every query in the package, so it can take a while:\n the skeleton holds until it answers or fails. -->\n <ng-container *fsSkeleton=\"check() || checkError()\">\n @if (checkError()) {\n <fs-message-error>\n {{ checkError() }}\n </fs-message-error>\n }\n\n @if (check(); as packageCheck) {\n <div class=\"fs-column.gap-md\">\n @if (!packageCheck.valid) {\n <fs-message-error>\n Can't be imported. Every error below has to be fixed first.\n </fs-message-error>\n } @else if (hasWarnings()) {\n <fs-message-warning>\n Ready with warnings. Review the warnings below before importing.\n </fs-message-warning>\n } @else {\n <fs-message-success>\n Ready to import.\n </fs-message-success>\n }\n\n <!-- Nothing to describe when the archive could not be read: its one\n error finding says why. -->\n @if (packageCheck.name) {\n <div class=\"fs-column\">\n <fs-label-field>\n <fs-label>Report</fs-label>\n {{ packageCheck.name }}\n </fs-label-field>\n <fs-label-field>\n <fs-label>Imports into</fs-label>\n {{ destination() }}\n </fs-label-field>\n @if (packageCheck.source; as source) {\n <fs-label-field>\n <fs-label>Exported from</fs-label>\n {{ source.environment }}\n <div class=\"small\">\n {{ source.url }}\n </div>\n </fs-label-field>\n <fs-label-field>\n <fs-label>Exported</fs-label>\n {{ source.exportedAt | fsDate: 'date-time' }}\n @if (source.exportedBy) {\n by {{ source.exportedBy }}\n }\n </fs-label-field>\n }\n @if (contents()) {\n <fs-label-field>\n <fs-label>Contents</fs-label>\n {{ contents() }}\n </fs-label-field>\n }\n </div>\n }\n\n @for (section of sections(); track section.severity) {\n <div>\n <h3>\n {{ section.heading }} ({{ section.findings.length }})\n </h3>\n <div class=\"fs-column.gap-sm\">\n @for (finding of section.findings; track $index) {\n <div>\n @if (finding.location) {\n <div class=\"small\">\n {{ finding.location }}\n </div>\n }\n {{ finding.message }}\n </div>\n }\n </div>\n </div>\n }\n\n @if (packageCheck.valid && hasWarnings()) {\n <mat-checkbox\n [checked]=\"warningsReviewed()\"\n [disabled]=\"busy()\"\n (change)=\"warningsReviewed.set($event.checked)\">\n I've reviewed the warnings\n </mat-checkbox>\n }\n\n @if (importError()) {\n <fs-message-error>\n {{ importError() }}\n </fs-message-error>\n }\n </div>\n }\n </ng-container>\n </mat-dialog-content>\n <mat-dialog-actions>\n <fs-form-dialog-actions [save]=\"false\">\n <button\n type=\"button\"\n mat-button\n color=\"primary\"\n [disabled]=\"busy() || !canImport()\"\n (click)=\"importPackage()\">\n @if (busy()) {\n <mat-spinner [diameter]=\"20\"></mat-spinner>\n } @else {\n <span>Import</span>\n }\n </button>\n <button\n type=\"button\"\n mat-button\n [disabled]=\"busy()\"\n [mat-dialog-close]=\"undefined\">\n Cancel\n </button>\n </fs-form-dialog-actions>\n </mat-dialog-actions>\n</fs-dialog>\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: "component", type: MatCheckbox, selector: "mat-checkbox", inputs: ["aria-label", "aria-labelledby", "aria-describedby", "id", "required", "labelPosition", "name", "value", "disableRipple", "tabIndex", "color", "disabledInteractive", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { 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: "directive", type: MatDialogContent, selector: "[mat-dialog-content], mat-dialog-content, [matDialogContent]" }, { kind: "component", type: MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }, { kind: "ngmodule", type: FsDateModule }, { kind: "pipe", type: i1.FsDatePipe, name: "fsDate" }, { kind: "ngmodule", type: FsDialogModule }, { kind: "component", type: i2.FsDialogComponent, selector: "fs-dialog", inputs: ["mobileMode", "mobileButtonPlacement", "mobileWidth", "mode", "buttonLayout"] }, { kind: "component", type: i2.FsDialogTitleComponent, selector: "fs-dialog-title", inputs: ["close", "dockToggle", "back"] }, { kind: "directive", type: i2.FsDialogSubtitleDirective, selector: "[fsDialogSubtitle]" }, { kind: "component", type: FsFormDialogActionsComponent, selector: "fs-form-dialog-actions", inputs: ["save", "create", "close", "done", "closeData", "name"] }, { kind: "ngmodule", type: FsLabelModule }, { kind: "component", type: i3.FsLabelComponent, selector: "fs-label" }, { kind: "component", type: i3.FsLabelFieldComponent, selector: "fs-label-field", inputs: ["appearance", "showOutline", "disabled", "focused", "hoverable", "padless"] }, { kind: "ngmodule", type: FsMessageModule }, { kind: "component", type: i4.FsMessageWarningComponent, selector: "fs-message-warning" }, { kind: "component", type: i4.FsMessageSuccessComponent, selector: "fs-message-success" }, { kind: "component", type: i4.FsMessageErrorComponent, selector: "fs-message-error" }, { kind: "ngmodule", type: FsSkeletonModule }, { kind: "directive", type: i5.FsSkeletonContentDirective, selector: "[fsSkeleton]", inputs: ["fsSkeleton", "fsSkeletonPattern"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
126
+ }
127
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ReportPackageImportComponent, decorators: [{
128
+ type: Component,
129
+ args: [{ changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [
130
+ MatButton,
131
+ MatCheckbox,
132
+ MatDialogActions,
133
+ MatDialogClose,
134
+ MatDialogContent,
135
+ MatProgressSpinner,
136
+ FsDateModule,
137
+ FsDialogModule,
138
+ FsFormDialogActionsComponent,
139
+ FsLabelModule,
140
+ FsMessageModule,
141
+ FsSkeletonModule,
142
+ ], template: "<fs-dialog>\n <fs-dialog-title>\n Import Report\n <ng-template fsDialogSubtitle>\n {{ fileName() }}\n </ng-template>\n </fs-dialog-title>\n <mat-dialog-content>\n <!-- The check runs every query in the package, so it can take a while:\n the skeleton holds until it answers or fails. -->\n <ng-container *fsSkeleton=\"check() || checkError()\">\n @if (checkError()) {\n <fs-message-error>\n {{ checkError() }}\n </fs-message-error>\n }\n\n @if (check(); as packageCheck) {\n <div class=\"fs-column.gap-md\">\n @if (!packageCheck.valid) {\n <fs-message-error>\n Can't be imported. Every error below has to be fixed first.\n </fs-message-error>\n } @else if (hasWarnings()) {\n <fs-message-warning>\n Ready with warnings. Review the warnings below before importing.\n </fs-message-warning>\n } @else {\n <fs-message-success>\n Ready to import.\n </fs-message-success>\n }\n\n <!-- Nothing to describe when the archive could not be read: its one\n error finding says why. -->\n @if (packageCheck.name) {\n <div class=\"fs-column\">\n <fs-label-field>\n <fs-label>Report</fs-label>\n {{ packageCheck.name }}\n </fs-label-field>\n <fs-label-field>\n <fs-label>Imports into</fs-label>\n {{ destination() }}\n </fs-label-field>\n @if (packageCheck.source; as source) {\n <fs-label-field>\n <fs-label>Exported from</fs-label>\n {{ source.environment }}\n <div class=\"small\">\n {{ source.url }}\n </div>\n </fs-label-field>\n <fs-label-field>\n <fs-label>Exported</fs-label>\n {{ source.exportedAt | fsDate: 'date-time' }}\n @if (source.exportedBy) {\n by {{ source.exportedBy }}\n }\n </fs-label-field>\n }\n @if (contents()) {\n <fs-label-field>\n <fs-label>Contents</fs-label>\n {{ contents() }}\n </fs-label-field>\n }\n </div>\n }\n\n @for (section of sections(); track section.severity) {\n <div>\n <h3>\n {{ section.heading }} ({{ section.findings.length }})\n </h3>\n <div class=\"fs-column.gap-sm\">\n @for (finding of section.findings; track $index) {\n <div>\n @if (finding.location) {\n <div class=\"small\">\n {{ finding.location }}\n </div>\n }\n {{ finding.message }}\n </div>\n }\n </div>\n </div>\n }\n\n @if (packageCheck.valid && hasWarnings()) {\n <mat-checkbox\n [checked]=\"warningsReviewed()\"\n [disabled]=\"busy()\"\n (change)=\"warningsReviewed.set($event.checked)\">\n I've reviewed the warnings\n </mat-checkbox>\n }\n\n @if (importError()) {\n <fs-message-error>\n {{ importError() }}\n </fs-message-error>\n }\n </div>\n }\n </ng-container>\n </mat-dialog-content>\n <mat-dialog-actions>\n <fs-form-dialog-actions [save]=\"false\">\n <button\n type=\"button\"\n mat-button\n color=\"primary\"\n [disabled]=\"busy() || !canImport()\"\n (click)=\"importPackage()\">\n @if (busy()) {\n <mat-spinner [diameter]=\"20\"></mat-spinner>\n } @else {\n <span>Import</span>\n }\n </button>\n <button\n type=\"button\"\n mat-button\n [disabled]=\"busy()\"\n [mat-dialog-close]=\"undefined\">\n Cancel\n </button>\n </fs-form-dialog-actions>\n </mat-dialog-actions>\n</fs-dialog>\n" }]
143
+ }], ctorParameters: () => [] });
144
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVwb3J0LXBhY2thZ2UtaW1wb3J0LmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3NyYy9hcHAvcmVwb3J0cy9kaWFsb2dzL3JlcG9ydC1wYWNrYWdlLWltcG9ydC9yZXBvcnQtcGFja2FnZS1pbXBvcnQuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vLi4vLi4vc3JjL2FwcC9yZXBvcnRzL2RpYWxvZ3MvcmVwb3J0LXBhY2thZ2UtaW1wb3J0L3JlcG9ydC1wYWNrYWdlLWltcG9ydC5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFDbkQsT0FBTyxFQUFFLHVCQUF1QixFQUFFLFNBQVMsRUFBRSxVQUFVLEVBQUUsUUFBUSxFQUFFLE1BQU0sRUFBRSxNQUFNLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDekcsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sNEJBQTRCLENBQUM7QUFFaEUsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLDBCQUEwQixDQUFDO0FBQ3JELE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQztBQUN6RCxPQUFPLEVBQ0wsZUFBZSxFQUFFLGdCQUFnQixFQUFFLGNBQWMsRUFBRSxnQkFBZ0IsRUFBRSxZQUFZLEdBQ2xGLE1BQU0sMEJBQTBCLENBQUM7QUFDbEMsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sb0NBQW9DLENBQUM7QUFFeEUsT0FBTyxFQUFFLGVBQWUsRUFBaUIsTUFBTSxpQkFBaUIsQ0FBQztBQUNqRSxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sa0JBQWtCLENBQUM7QUFDaEQsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBQ3BELE9BQU8sRUFBRSw0QkFBNEIsRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBQ2hFLE9BQU8sRUFB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QixZQUFZO3dCQUNaLGNBQWM7d0JBQ2QsNEJBQTRCO3dCQUM1QixhQUFhO3dCQUNiLGVBQWU7d0JBQ2YsZ0JBQWdCO3FCQUNqQiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEh0dHBDb250ZXh0IH0gZnJvbSAnQGFuZ3VsYXIvY29tbW9uL2h0dHAnO1xuaW1wb3J0IHsgQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3ksIENvbXBvbmVudCwgRGVzdHJveVJlZiwgY29tcHV0ZWQsIGluamVjdCwgc2lnbmFsIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyB0YWtlVW50aWxEZXN0cm95ZWQgfSBmcm9tICdAYW5ndWxhci9jb3JlL3J4anMtaW50ZXJvcCc7XG5cbmltcG9ydCB7IE1hdEJ1dHRvbiB9IGZyb20gJ0Bhbmd1bGFyL21hdGVyaWFsL2J1dHRvbic7XG5pbXBvcnQgeyBNYXRDaGVja2JveCB9IGZyb20gJ0Bhbmd1bGFyL21hdGVyaWFsL2NoZWNrYm94JztcbmltcG9ydCB7XG4gIE1BVF9ESUFMT0dfREFUQSwgTWF0RGlhbG9nQWN0aW9ucywgTWF0RGlhbG9nQ2xvc2UsIE1hdERpYWxvZ0NvbnRlbnQsIE1hdERpYWxvZ1JlZixcbn0gZnJvbSAnQGFuZ3VsYXIvbWF0ZXJpYWwvZGlhbG9nJztcbmltcG9ydCB7IE1hdFByb2dyZXNzU3Bpbm5lciB9IGZyb20gJ0Bhbmd1bGFyL21hdGVyaWFsL3Byb2dyZXNzLXNwaW5uZXInO1xuXG5pbXBvcnQgeyBEaXNwbGF5QXBpRXJyb3IsIFJlcXVlc3RDb25maWcgfSBmcm9tICdAZmlyZXN0aXRjaC9hcGknO1xuaW1wb3J0IHsgRnNEYXRlTW9kdWxlIH0gZnJvbSAnQGZpcmVzdGl0Y2gvZGF0ZSc7XG5pbXBvcnQgeyBGc0RpYWxvZ01vZHVsZSB9IGZyb20gJ0BmaXJlc3RpdGNoL2RpYWxvZyc7XG5pbXBvcnQgeyBGc0Zvcm1EaWFsb2dBY3Rpb25zQ29tcG9uZW50IH0gZnJvbSAnQGZpcmVzdGl0Y2gvZm9ybSc7XG5pbXBvcnQgeyBGc0xhYmVsTW9kdWxlIH0gZnJvbSAnQGZpcmVzdGl0Y2gvbGFiZWwnO1xuaW1wb3J0IHsgRnNNZXNzYWdlTW9kdWxlIH0gZnJvbSAnQGZpcmVzdGl0Y2gvbWVzc2FnZSc7XG5pbXBvcnQgeyBGc1NrZWxldG9uTW9kdWxlIH0gZnJvbSAnQGZpcmVzdGl0Y2gvc2tlbGV0b24nO1xuXG5pbXBvcnQgeyBvZiB9IGZyb20gJ3J4anMnO1xuaW1wb3J0IHsgY2F0Y2hFcnJvciwgdGFwIH0gZnJvbSAncnhqcy9vcGVyYXRvcnMnO1xuXG5pbXBvcnQgeyBhcGlFcnJvck1lc3NhZ2UgfSBmcm9tICcuLi8uLi9hcGktZXJyb3ItbWVzc2FnZSc7XG5pbXBvcnQgeyBSZXBvcnREYXRhIH0gZnJvbSAnLi4vLi4vZGF0YS9yZXBvcnQuZGF0YSc7XG5pbXBvcnQgeyBSZXBvcnRQYWNrYWdlQ2hlY2sgfSBmcm9tICcuLi8uLi9pbnRlcmZhY2VzL3JlcG9ydC1wYWNrYWdlLWNoZWNrLmludGVyZmFjZSc7XG5pbXBvcnQgeyBSZXBvcnRQYWNrYWdlRmluZGluZ1NldmVyaXR5IH0gZnJvbSAnLi4vLi4vaW50ZXJmYWNlcy9yZXBvcnQtcGFja2FnZS1maW5kaW5nLXNldmVyaXR5LnR5cGUnO1xuaW1wb3J0IHsgUmVwb3J0UGFja2FnZUZpbmRpbmcgfSBmcm9tICcuLi8uLi9pbnRlcmZhY2VzL3JlcG9ydC1wYWNrYWdlLWZpbmRpbmcuaW50ZXJmYWNlJztcbmltcG9ydCB7IFJlcG9ydFBhY2thZ2VJbXBvcnRlZFJlcG9ydCB9IGZyb20gJy4uLy4uL2ludGVyZmFjZXMvcmVwb3J0LXBhY2thZ2UtaW1wb3J0ZWQtcmVwb3J0LmludGVyZmFjZSc7XG5pbXBvcnQgeyBSZXBvcnRQYWNrYWdlSW1wb3J0UmVzcG9uc2UgfSBmcm9tICcuLi8uLi9pbnRlcmZhY2VzL3JlcG9ydC1wYWNrYWdlLWltcG9ydC1yZXNwb25zZS5pbnRlcmZhY2UnO1xuXG5cbmV4cG9ydCBpbnRlcmZhY2UgUmVwb3J0UGFja2FnZUltcG9ydERpYWxvZ0RhdGEge1xuICAvLyBUaGUgLnppcCBwaWNrZWQgZnJvbSB0aGUgbGlzdGluZydzIEltcG9ydDsgY2hlY2tlZCBvbiBvcGVuIGFuZCBzZW50IGFnYWluXG4gIC8vIGJ5IEltcG9ydC5cbiAgZmlsZTogRmlsZTtcbn1cblxuXG4vLyBPbmUgc2V2ZXJpdHkncyBmaW5kaW5ncywgYXMgdGhlIGRpYWxvZyBsaXN0cyB0aGVtLlxuaW50ZXJmYWNlIEZpbmRpbmdTZWN0aW9uIHtcbiAgc2V2ZXJpdHk6IFJlcG9ydFBhY2thZ2VGaW5kaW5nU2V2ZXJpdHk7XG4gIGhlYWRpbmc6IHN0cmluZztcbiAgZmluZGluZ3M6IFJlcG9ydFBhY2thZ2VGaW5kaW5nW107XG59XG5cblxuLy8gVGhlIGZpbmRpbmdzIGluIHRoZSBvcmRlciB0aGV5IG1hdHRlcjogd2hhdCBibG9ja3MgdGhlIGltcG9ydCwgd2hhdCBoYXMgdG9cbi8vIGJlIGFjY2VwdGVkLCB0aGVuIHdoYXQgaXMgb25seSB3b3J0aCBrbm93aW5nLlxuY29uc3QgRklORElOR19TRUNUSU9OUzogeyBzZXZlcml0eTogUmVwb3J0UGFja2FnZUZpbmRpbmdTZXZlcml0eTsgaGVhZGluZzogc3RyaW5nIH1bXSA9IFtcbiAgeyBzZXZlcml0eTogJ2Vycm9yJywgaGVhZGluZzogJ0Vycm9ycycgfSxcbiAgeyBzZXZlcml0eTogJ3dhcm5pbmcnLCBoZWFkaW5nOiAnV2FybmluZ3MnIH0sXG4gIHsgc2V2ZXJpdHk6ICdpbmZvJywgaGVhZGluZzogJ0luZm9ybWF0aW9uJyB9LFxuXTtcblxuLy8gJzEgcGFnZScsICcxNyBjb21wb25lbnRzJy5cbmZ1bmN0aW9uIGNvdW50T2YoY291bnQ6IG51bWJlciwgbm91bjogc3RyaW5nKTogc3RyaW5nIHtcbiAgcmV0dXJuIGAke2NvdW50fSAke25vdW59JHtjb3VudCA9PT0gMSA/ICcnIDogJ3MnfWA7XG59XG5cblxuLy8gQ2hlY2tzIGEgcmVwb3J0IHBhY2thZ2UgYW5kIGltcG9ydHMgaXQgYXMgYSBORVcgcmVwb3J0IOKAlCBhbiBpbXBvcnQgbmV2ZXJcbi8vIHVwZGF0ZXMgb3IgcmVwbGFjZXMgb25lLiBPcGVuZWQgZnJvbSB0aGUgbGlzdGluZydzIEltcG9ydCB3aXRoIHRoZSBwaWNrZWRcbi8vIGZpbGUuIFRoZSBjaGVjayBydW5zIG9uIG9wZW4sIGJlaGluZCB0aGUgc2tlbGV0b24sIGFuZCBzYXlzIHdoZXRoZXIgdGhlXG4vLyBwYWNrYWdlIGNhbiBiZSBpbXBvcnRlZCwgd2hhdCBpdCBob2xkcywgd2hlcmUgaXQgd2lsbCBiZSBmaWxlZCwgd2hlcmUgaXQgY2FtZVxuLy8gZnJvbSwgYW5kIGV2ZXJ5dGhpbmcgaXQgZm91bmQsIGVycm9ycyBmaXJzdC4gRXJyb3JzIGxlYXZlIEltcG9ydCBkaXNhYmxlZDtcbi8vIHdhcm5pbmdzIGVuYWJsZSBpdCBvbmx5IG9uY2UgdGhlIG9wZXJhdG9yIHNheXMgdGhleSBoYXZlIHJldmlld2VkIHRoZW0uXG4vLyBJbXBvcnQgc2VuZHMgdGhlIHNhbWUgZmlsZSwgYW5kIHRoZSBzZXJ2ZXIgY2hlY2tzIGl0IGFnYWluIGJlZm9yZSBpdCB3cml0ZXNcbi8vIGFueXRoaW5nLiBUaGUgZGlhbG9nIGNsb3NlcyB3aXRoIHRoZSBuZXcgcmVwb3J0OyBhIHJlZnVzZWQgaW1wb3J0IHN0YXlzIG9wZW5cbi8vIHdpdGggdGhlIHNlcnZlcidzIG1lc3NhZ2UuXG5AQ29tcG9uZW50KHtcbiAgdGVtcGxhdGVVcmw6ICcuL3JlcG9ydC1wYWNrYWdlLWltcG9ydC5jb21wb25lbnQuaHRtbCcsXG4gIGNoYW5nZURldGVjdGlvbjogQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3kuT25QdXNoLFxuICBzdGFuZGFsb25lOiB0cnVlLFxuICBpbXBvcnRzOiBbXG4gICAgTWF0QnV0dG9uLFxuICAgIE1hdENoZWNrYm94LFxuICAgIE1hdERpYWxvZ0FjdGlvbnMsXG4gICAgTWF0RGlhbG9nQ2xvc2UsXG4gICAgTWF0RGlhbG9nQ29udGVudCxcbiAgICBNYXRQcm9ncmVzc1NwaW5uZXIsXG4gICAgRnNEYXRlTW9kdWxlLFxuICAgIEZzRGlhbG9nTW9kdWxlLFxuICAgIEZzRm9ybURpYWxvZ0FjdGlvbnNDb21wb25lbnQsXG4gICAgRnNMYWJlbE1vZHVsZSxcbiAgICBGc01lc3NhZ2VNb2R1bGUsXG4gICAgRnNTa2VsZXRvbk1vZHVsZSxcbiAgXSxcbn0pXG5leHBvcnQgY2xhc3MgUmVwb3J0UGFja2FnZUltcG9ydENvbXBvbmVudCB7XG5cbiAgcHVibGljIHJlYWRvbmx5IGZpbGVOYW1lID0gc2lnbmFsKCcnKTtcblxuICAvLyBOdWxsIHVudGlsIHRoZSBjaGVjayBhbnN3ZXJzLlxuICBwdWJsaWMgcmVhZG9ubHkgY2hlY2sgPSBzaWduYWw8UmVwb3J0UGFja2FnZUNoZWNrIHwgbnVsbD4obnVsbCk7XG5cbiAgLy8gVGhlIGNoZWNrIHJlcXVlc3QgaXRzZWxmIGZhaWxlZCwgc28gdGhlcmUgaXMgbm8gY2hlY2sgdG8gc2hvdzogaXRzXG4gIC8vIG1lc3NhZ2UuIEEgcGFja2FnZSB0aGF0IGZhaWxzIHRoZSBjaGVjayBpcyBub3QgdGhpczsgaXQgYW5zd2VycyB3aXRoXG4gIC8vIGVycm9yIGZpbmRpbmdzLlxuICBwdWJsaWMgcmVhZG9ubHkgY2hlY2tFcnJvciA9IHNpZ25hbDxzdHJpbmcgfCBudWxsPihudWxsKTtcblxuICAvLyBUaGUgc2VydmVyIHJlZnVzZWQgdGhlIGltcG9ydDogaXRzIG1lc3NhZ2UuXG4gIHB1YmxpYyByZWFkb25seSBpbXBvcnRFcnJvciA9IHNpZ25hbDxzdHJpbmcgfCBudWxsPihudWxsKTtcblxuICBwdWJsaWMgcmVhZG9ubHkgd2FybmluZ3NSZXZpZXdlZCA9IHNpZ25hbChmYWxzZSk7XG4gIHB1YmxpYyByZWFkb25seSBidXN5ID0gc2lnbmFsKGZhbHNlKTtcblxuICBwdWJsaWMgcmVhZG9ubHkgaGFzV2FybmluZ3MgPSBjb21wdXRlZCgoKSA9PiB0aGlzLl9maW5kaW5ncygpXG4gICAgLnNvbWUoKGZpbmRpbmcpID0+IGZpbmRpbmcuc2V2ZXJpdHkgPT09ICd3YXJuaW5nJykpO1xuXG4gIHB1YmxpYyByZWFkb25seSBzZWN0aW9ucyA9IGNvbXB1dGVkPEZpbmRpbmdTZWN0aW9uW10+KCgpID0+IEZJTkRJTkdfU0VDVElPTlNcbiAgICAubWFwKChzZWN0aW9uKSA9PiAoe1xuICAgICAgLi4uc2VjdGlvbixcbiAgICAgIGZpbmRpbmdzOiB0aGlzLl9maW5kaW5ncygpLmZpbHRlcigoZmluZGluZykgPT4gZmluZGluZy5zZXZlcml0eSA9PT0gc2VjdGlvbi5zZXZlcml0eSksXG4gICAgfSkpXG4gICAgLmZpbHRlcigoc2VjdGlvbikgPT4gc2VjdGlvbi5maW5kaW5ncy5sZW5ndGgpKTtcblxuICAvLyBXaGVyZSB0aGUgaW1wb3J0IGZpbGVzIHRoZSByZXBvcnQ6IHRoZSBmb2xkZXIgdGhlIGNoZWNrIHJlc29sdmVkLCBvciB0aGVcbiAgLy8gdG9wIGxldmVsIHdoZW4gdGhlIGZvbGRlciBpdCBjYW1lIGZyb20gaXMgbm90IG9uIHRoaXMgc2VydmVyLlxuICBwdWJsaWMgcmVhZG9ubHkgZGVzdGluYXRpb24gPSBjb21wdXRlZCgoKSA9PiB7XG4gICAgY29uc3QgY2hlY2sgPSB0aGlzLmNoZWNrKCk7XG5cbiAgICByZXR1cm4gY2hlY2s/LnJlcG9ydEZvbGRlcklkICYmIGNoZWNrLmZvbGRlclBhdGg/Lmxlbmd0aFxuICAgICAgPyBjaGVjay5mb2xkZXJQYXRoLmpvaW4oJyDigLogJylcbiAgICAgIDogJ1RvcCBsZXZlbCc7XG4gIH0pO1xuXG4gIHB1YmxpYyByZWFkb25seSBjb250ZW50cyA9IGNvbXB1dGVkKCgpID0+IHtcbiAgICBjb25zdCBjb3VudHMgPSB0aGlzLmNoZWNrKCk/LmNvdW50cztcbiAgICBpZiAoIWNvdW50cykge1xuICAgICAgcmV0dXJuICcnO1xuICAgIH1cblxuICAgIHJldHVybiBbXG4gICAgICBjb3VudE9mKGNvdW50cy5wYWdlcywgJ3BhZ2UnKSxcbiAgICAgIGNvdW50T2YoY291bnRzLmNvbXBvbmVudHMsICdjb21wb25lbnQnKSxcbiAgICAgIGNvdW50T2YoY291bnRzLmZpbHRlckdyb3VwcywgJ2ZpbHRlciBncm91cCcpLFxuICAgICAgY291bnRPZihjb3VudHMuZmlsdGVycywgJ2ZpbHRlcicpLFxuICAgICAgY291bnRPZihjb3VudHMuYXNzZXRzLCAnaW1hZ2UnKSxcbiAgICBdLmpvaW4oJyDCtyAnKTtcbiAgfSk7XG5cbiAgcHVibGljIHJlYWRvbmx5IGNhbkltcG9ydCA9IGNvbXB1dGVkKCgpID0+ICEhdGhpcy5jaGVjaygpPy52YWxpZFxuICAgICYmICghdGhpcy5oYXNXYXJuaW5ncygpIHx8IHRoaXMud2FybmluZ3NSZXZpZXdlZCgpKSk7XG5cbiAgcHJpdmF0ZSByZWFkb25seSBfZGF0YSA9IGluamVjdDxSZXBvcnRQYWNrYWdlSW1wb3J0RGlhbG9nRGF0YT4oTUFUX0RJQUxPR19EQVRBKTtcbiAgcHJpdmF0ZSByZWFkb25seSBfZGlhbG9nUmVmID0gaW5qZWN0PE1hdERpYWxvZ1JlZjxSZXBvcnRQYWNrYWdlSW1wb3J0Q29tcG9uZW50LCBSZXBvcnRQYWNrYWdlSW1wb3J0ZWRSZXBvcnQ+PihcbiAgICBNYXREaWFsb2dSZWYsXG4gICk7XG5cbiAgcHJpdmF0ZSByZWFkb25seSBfcmVwb3J0RGF0YSA9IGluamVjdChSZXBvcnREYXRhKTtcbiAgcHJpdmF0ZSByZWFkb25seSBfZGVzdHJveVJlZiA9IGluamVjdChEZXN0cm95UmVmKTtcblxuICBwcml2YXRlIHJlYWRvbmx5IF9maW5kaW5ncyA9IGNvbXB1dGVkKCgpID0+IHRoaXMuY2hlY2soKT8uZmluZGluZ3MgPz8gW10pO1xuXG4gIGNvbnN0cnVjdG9yKCkge1xuICAgIHRoaXMuX2luaXQoKTtcbiAgfVxuXG4gIHB1YmxpYyBpbXBvcnRQYWNrYWdlKCk6IHZvaWQge1xuICAgIGlmICh0aGlzLmJ1c3koKSB8fCAhdGhpcy5jYW5JbXBvcnQoKSkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIHRoaXMuYnVzeS5zZXQodHJ1ZSk7XG4gICAgdGhpcy5pbXBvcnRFcnJvci5zZXQobnVsbCk7XG5cbiAgICB0aGlzLl9yZXBvcnREYXRhLmltcG9ydFBhY2thZ2UoXG4gICAgICB0aGlzLl9kYXRhLmZpbGUsXG4gICAgICB7IGFjY2VwdFdhcm5pbmdzOiB0aGlzLndhcm5pbmdzUmV2aWV3ZWQoKSB9LFxuICAgICAgdGhpcy5faW5saW5lRXJyb3JzKCksXG4gICAgKVxuICAgICAgLnBpcGUoXG4gICAgICAgIHRhcCgocmVzcG9uc2U6IFJlcG9ydFBhY2thZ2VJbXBvcnRSZXNwb25zZSkgPT4gdGhpcy5fZGlhbG9nUmVmLmNsb3NlKHJlc3BvbnNlLnJlcG9ydCkpLFxuICAgICAgICBjYXRjaEVycm9yKChlcnJvcjogdW5rbm93bikgPT4ge1xuICAgICAgICAgIHRoaXMuaW1wb3J0RXJyb3Iuc2V0KGFwaUVycm9yTWVzc2FnZShlcnJvciwgJ1RoZSByZXBvcnQgY291bGQgbm90IGJlIGltcG9ydGVkLicpKTtcbiAgICAgICAgICB0aGlzLmJ1c3kuc2V0KGZhbHNlKTtcblxuICAgICAgICAgIHJldHVybiBvZihudWxsKTtcbiAgICAgICAgfSksXG4gICAgICAgIHRha2VVbnRpbERlc3Ryb3llZCh0aGlzLl9kZXN0cm95UmVmKSxcbiAgICAgIClcbiAgICAgIC5zdWJzY3JpYmUoKTtcbiAgfVxuXG4gIHByaXZhdGUgX2luaXQoKTogdm9pZCB7XG4gICAgdGhpcy5maWxlTmFtZS5zZXQodGhpcy5fZGF0YS5maWxlLm5hbWUpO1xuXG4gICAgdGhpcy5fcmVwb3J0RGF0YS5jaGVja1BhY2thZ2UodGhpcy5fZGF0YS5maWxlLCB0aGlzLl9pbmxpbmVFcnJvcnMoKSlcbiAgICAgIC5waXBlKFxuICAgICAgICB0YXAoKGNoZWNrOiBSZXBvcnRQYWNrYWdlQ2hlY2spID0+IHRoaXMuY2hlY2suc2V0KGNoZWNrKSksXG4gICAgICAgIGNhdGNoRXJyb3IoKGVycm9yOiB1bmtub3duKSA9PiB7XG4gICAgICAgICAgdGhpcy5jaGVja0Vycm9yLnNldChhcGlFcnJvck1lc3NhZ2UoZXJyb3IsICdUaGUgcGFja2FnZSBjb3VsZCBub3QgYmUgY2hlY2tlZC4nKSk7XG5cbiAgICAgICAgICByZXR1cm4gb2YobnVsbCk7XG4gICAgICAgIH0pLFxuICAgICAgICB0YWtlVW50aWxEZXN0cm95ZWQodGhpcy5fZGVzdHJveVJlZiksXG4gICAgICApXG4gICAgICAuc3Vic2NyaWJlKCk7XG4gIH1cblxuICAvLyBBIGZhaWxlZCBjaGVjayBvciBhIHJlZnVzZWQgaW1wb3J0IGlzIHNob3duIGluIHRoZSBkaWFsb2csIGJlc2lkZSB3aGF0IGl0XG4gIC8vIGlzIGFib3V0LCByYXRoZXIgdGhhbiBpbiBhIHNlY29uZCBkaWFsb2cgb3ZlciBpdC5cbiAgcHJpdmF0ZSBfaW5saW5lRXJyb3JzKCk6IFJlcXVlc3RDb25maWcge1xuICAgIHJldHVybiB7IGNvbnRleHQ6IG5ldyBIdHRwQ29udGV4dCgpLnNldChEaXNwbGF5QXBpRXJyb3IsIGZhbHNlKSB9O1xuICB9XG5cbn1cbiIsIjxmcy1kaWFsb2c+XG4gIDxmcy1kaWFsb2ctdGl0bGU+XG4gICAgSW1wb3J0IFJlcG9ydFxuICAgIDxuZy10ZW1wbGF0ZSBmc0RpYWxvZ1N1YnRpdGxlPlxuICAgICAge3sgZmlsZU5hbWUoKSB9fVxuICAgIDwvbmctdGVtcGxhdGU+XG4gIDwvZnMtZGlhbG9nLXRpdGxlPlxuICA8bWF0LWRpYWxvZy1jb250ZW50PlxuICAgIDwhLS0gVGhlIGNoZWNrIHJ1bnMgZXZlcnkgcXVlcnkgaW4gdGhlIHBhY2thZ2UsIHNvIGl0IGNhbiB0YWtlIGEgd2hpbGU6XG4gICAgICAgICB0aGUgc2tlbGV0b24gaG9sZHMgdW50aWwgaXQgYW5zd2VycyBvciBmYWlscy4gLS0+XG4gICAgPG5nLWNvbnRhaW5lciAqZnNTa2VsZXRvbj1cImNoZWNrKCkgfHwgY2hlY2tFcnJvcigpXCI+XG4gICAgICBAaWYgKGNoZWNrRXJyb3IoKSkge1xuICAgICAgICA8ZnMtbWVzc2FnZS1lcnJvcj5cbiAgICAgICAgICB7eyBjaGVja0Vycm9yKCkgfX1cbiAgICAgICAgPC9mcy1tZXNzYWdlLWVycm9yPlxuICAgICAgfVxuXG4gICAgICBAaWYgKGNoZWNrKCk7IGFzIHBhY2thZ2VDaGVjaykge1xuICAgICAgICA8ZGl2IGNsYXNzPVwiZnMtY29sdW1uLmdhcC1tZFwiPlxuICAgICAgICAgIEBpZiAoIXBhY2thZ2VDaGVjay52YWxpZCkge1xuICAgICAgICAgICAgPGZzLW1lc3NhZ2UtZXJyb3I+XG4gICAgICAgICAgICAgIENhbid0IGJlIGltcG9ydGVkLiBFdmVyeSBlcnJvciBiZWxvdyBoYXMgdG8gYmUgZml4ZWQgZmlyc3QuXG4gICAgICAgICAgICA8L2ZzLW1lc3NhZ2UtZXJyb3I+XG4gICAgICAgICAgfSBAZWxzZSBpZiAoaGFzV2FybmluZ3MoKSkge1xuICAgICAgICAgICAgPGZzLW1lc3NhZ2Utd2FybmluZz5cbiAgICAgICAgICAgICAgUmVhZHkgd2l0aCB3YXJuaW5ncy4gUmV2aWV3IHRoZSB3YXJuaW5ncyBiZWxvdyBiZWZvcmUgaW1wb3J0aW5nLlxuICAgICAgICAgICAgPC9mcy1tZXNzYWdlLXdhcm5pbmc+XG4gICAgICAgICAgfSBAZWxzZSB7XG4gICAgICAgICAgICA8ZnMtbWVzc2FnZS1zdWNjZXNzPlxuICAgICAgICAgICAgICBSZWFkeSB0byBpbXBvcnQuXG4gICAgICAgICAgICA8L2ZzLW1lc3NhZ2Utc3VjY2Vzcz5cbiAgICAgICAgICB9XG5cbiAgICAgICAgICA8IS0tIE5vdGhpbmcgdG8gZGVzY3JpYmUgd2hlbiB0aGUgYXJjaGl2ZSBjb3VsZCBub3QgYmUgcmVhZDogaXRzIG9uZVxuICAgICAgICAgICAgICAgZXJyb3IgZmluZGluZyBzYXlzIHdoeS4gLS0+XG4gICAgICAgICAgQGlmIChwYWNrYWdlQ2hlY2submFtZSkge1xuICAgICAgICAgICAgPGRpdiBjbGFzcz1cImZzLWNvbHVtblwiPlxuICAgICAgICAgICAgICA8ZnMtbGFiZWwtZmllbGQ+XG4gICAgICAgICAgICAgICAgPGZzLWxhYmVsPlJlcG9ydDwvZnMtbGFiZWw+XG4gICAgICAgICAgICAgICAge3sgcGFja2FnZUNoZWNrLm5hbWUgfX1cbiAgICAgICAgICAgICAgPC9mcy1sYWJlbC1maWVsZD5cbiAgICAgICAgICAgICAgPGZzLWxhYmVsLWZpZWxkPlxuICAgICAgICAgICAgICAgIDxmcy1sYWJlbD5JbXBvcnRzIGludG88L2ZzLWxhYmVsPlxuICAgICAgICAgICAgICAgIHt7IGRlc3RpbmF0aW9uKCkgfX1cbiAgICAgICAgICAgICAgPC9mcy1sYWJlbC1maWVsZD5cbiAgICAgICAgICAgICAgQGlmIChwYWNrYWdlQ2hlY2suc291cmNlOyBhcyBzb3VyY2UpIHtcbiAgICAgICAgICAgICAgICA8ZnMtbGFiZWwtZmllbGQ+XG4gICAgICAgICAgICAgICAgICA8ZnMtbGFiZWw+RXhwb3J0ZWQgZnJvbTwvZnMtbGFiZWw+XG4gICAgICAgICAgICAgICAgICB7eyBzb3VyY2UuZW52aXJvbm1lbnQgfX1cbiAgICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJzbWFsbFwiPlxuICAgICAgICAgICAgICAgICAgICB7eyBzb3VyY2UudXJsIH19XG4gICAgICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgICAgICA8L2ZzLWxhYmVsLWZpZWxkPlxuICAgICAgICAgICAgICAgIDxmcy1sYWJlbC1maWVsZD5cbiAgICAgICAgICAgICAgICAgIDxmcy1sYWJlbD5FeHBvcnRlZDwvZnMtbGFiZWw+XG4gICAgICAgICAgICAgICAgICB7eyBzb3VyY2UuZXhwb3J0ZWRBdCB8IGZzRGF0ZTogJ2RhdGUtdGltZScgfX1cbiAgICAgICAgICAgICAgICAgIEBpZiAoc291cmNlLmV4cG9ydGVkQnkpIHtcbiAgICAgICAgICAgICAgICAgICAgYnkge3sgc291cmNlLmV4cG9ydGVkQnkgfX1cbiAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICA8L2ZzLWxhYmVsLWZpZWxkPlxuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIEBpZiAoY29udGVudHMoKSkge1xuICAgICAgICAgICAgICAgIDxmcy1sYWJlbC1maWVsZD5cbiAgICAgICAgICAgICAgICAgIDxmcy1sYWJlbD5Db250ZW50czwvZnMtbGFiZWw+XG4gICAgICAgICAgICAgICAgICB7eyBjb250ZW50cygpIH19XG4gICAgICAgICAgICAgICAgPC9mcy1sYWJlbC1maWVsZD5cbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgQGZvciAoc2VjdGlvbiBvZiBzZWN0aW9ucygpOyB0cmFjayBzZWN0aW9uLnNldmVyaXR5KSB7XG4gICAgICAgICAgICA8ZGl2PlxuICAgICAgICAgICAgICA8aDM+XG4gICAgICAgICAgICAgICAge3sgc2VjdGlvbi5oZWFkaW5nIH19ICh7eyBzZWN0aW9uLmZpbmRpbmdzLmxlbmd0aCB9fSlcbiAgICAgICAgICAgICAgPC9oMz5cbiAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cImZzLWNvbHVtbi5nYXAtc21cIj5cbiAgICAgICAgICAgICAgICBAZm9yIChmaW5kaW5nIG9mIHNlY3Rpb24uZmluZGluZ3M7IHRyYWNrICRpbmRleCkge1xuICAgICAgICAgICAgICAgICAgPGRpdj5cbiAgICAgICAgICAgICAgICAgICAgQGlmIChmaW5kaW5nLmxvY2F0aW9uKSB7XG4gICAgICAgICAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cInNtYWxsXCI+XG4gICAgICAgICAgICAgICAgICAgICAgICB7eyBmaW5kaW5nLmxvY2F0aW9uIH19XG4gICAgICAgICAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAge3sgZmluZGluZy5tZXNzYWdlIH19XG4gICAgICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgQGlmIChwYWNrYWdlQ2hlY2sudmFsaWQgJiYgaGFzV2FybmluZ3MoKSkge1xuICAgICAgICAgICAgPG1hdC1jaGVja2JveFxuICAgICAgICAgICAgICAgIFtjaGVja2VkXT1cIndhcm5pbmdzUmV2aWV3ZWQoKVwiXG4gICAgICAgICAgICAgICAgW2Rpc2FibGVkXT1cImJ1c3koKVwiXG4gICAgICAgICAgICAgICAgKGNoYW5nZSk9XCJ3YXJuaW5nc1Jldmlld2VkLnNldCgkZXZlbnQuY2hlY2tlZClcIj5cbiAgICAgICAgICAgICAgSSd2ZSByZXZpZXdlZCB0aGUgd2FybmluZ3NcbiAgICAgICAgICAgIDwvbWF0LWNoZWNrYm94PlxuICAgICAgICAgIH1cblxuICAgICAgICAgIEBpZiAoaW1wb3J0RXJyb3IoKSkge1xuICAgICAgICAgICAgPGZzLW1lc3NhZ2UtZXJyb3I+XG4gICAgICAgICAgICAgIHt7IGltcG9ydEVycm9yKCkgfX1cbiAgICAgICAgICAgIDwvZnMtbWVzc2FnZS1lcnJvcj5cbiAgICAgICAgICB9XG4gICAgICAgIDwvZGl2PlxuICAgICAgfVxuICAgIDwvbmctY29udGFpbmVyPlxuICA8L21hdC1kaWFsb2ctY29udGVudD5cbiAgPG1hdC1kaWFsb2ctYWN0aW9ucz5cbiAgICA8ZnMtZm9ybS1kaWFsb2ctYWN0aW9ucyBbc2F2ZV09XCJmYWxzZVwiPlxuICAgICAgPGJ1dHRvblxuICAgICAgICAgIHR5cGU9XCJidXR0b25cIlxuICAgICAgICAgIG1hdC1idXR0b25cbiAgICAgICAgICBjb2xvcj1cInByaW1hcnlcIlxuICAgICAgICAgIFtkaXNhYmxlZF09XCJidXN5KCkgfHwgIWNhbkltcG9ydCgpXCJcbiAgICAgICAgICAoY2xpY2spPVwiaW1wb3J0UGFja2FnZSgpXCI+XG4gICAgICAgIEBpZiAoYnVzeSgpKSB7XG4gICAgICAgICAgPG1hdC1zcGlubmVyIFtkaWFtZXRlcl09XCIyMFwiPjwvbWF0LXNwaW5uZXI+XG4gICAgICAgIH0gQGVsc2Uge1xuICAgICAgICAgIDxzcGFuPkltcG9ydDwvc3Bhbj5cbiAgICAgICAgfVxuICAgICAgPC9idXR0b24+XG4gICAgICA8YnV0dG9uXG4gICAgICAgICAgdHlwZT1cImJ1dHRvblwiXG4gICAgICAgICAgbWF0LWJ1dHRvblxuICAgICAgICAgIFtkaXNhYmxlZF09XCJidXN5KClcIlxuICAgICAgICAgIFttYXQtZGlhbG9nLWNsb3NlXT1cInVuZGVmaW5lZFwiPlxuICAgICAgICBDYW5jZWxcbiAgICAgIDwvYnV0dG9uPlxuICAgIDwvZnMtZm9ybS1kaWFsb2ctYWN0aW9ucz5cbiAgPC9tYXQtZGlhbG9nLWFjdGlvbnM+XG48L2ZzLWRpYWxvZz5cbiJdfQ==