@firestitch/report 18.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/app/reports/components/component-chart/component-chart.component.d.ts +16 -0
- package/app/reports/components/component-kpi/component-kpi.component.d.ts +12 -0
- package/app/reports/components/component-list/component-list.component.d.ts +27 -0
- package/app/reports/components/report-canvas/report-canvas.component.d.ts +84 -0
- package/app/reports/components/report-component/report-component.component.d.ts +71 -0
- package/app/reports/components/timezone-select/timezone-select.component.d.ts +18 -0
- package/app/reports/data/report.data.d.ts +48 -0
- package/app/reports/dialogs/component-settings/component-settings.component.d.ts +49 -0
- package/app/reports/dialogs/report-settings/report-settings.component.d.ts +25 -0
- package/app/reports/export/offscreen-chart.d.ts +2 -0
- package/app/reports/export/report-export-collector.service.d.ts +26 -0
- package/app/reports/export/report-pdf.service.d.ts +13 -0
- package/app/reports/export/report-pptx.service.d.ts +14 -0
- package/app/reports/format.d.ts +1 -0
- package/app/reports/interfaces/report.interface.d.ts +174 -0
- package/app/reports/layout.d.ts +11 -0
- package/app/reports/option-builder.d.ts +15 -0
- package/app/reports/report-filter-items.d.ts +9 -0
- package/app/reports/services/report-filter-state.service.d.ts +25 -0
- package/app/reports/services/report.service.d.ts +15 -0
- package/app/reports/theme/echarts.d.ts +2 -0
- package/app/reports/theme/palette.d.ts +2 -0
- package/app/reports/views/report/report.component.d.ts +50 -0
- package/esm2022/app/reports/components/component-chart/component-chart.component.mjs +47 -0
- package/esm2022/app/reports/components/component-kpi/component-kpi.component.mjs +33 -0
- package/esm2022/app/reports/components/component-list/component-list.component.mjs +178 -0
- package/esm2022/app/reports/components/report-canvas/report-canvas.component.mjs +347 -0
- package/esm2022/app/reports/components/report-component/report-component.component.mjs +453 -0
- package/esm2022/app/reports/components/timezone-select/timezone-select.component.mjs +70 -0
- package/esm2022/app/reports/data/report.data.mjs +152 -0
- package/esm2022/app/reports/dialogs/component-settings/component-settings.component.mjs +221 -0
- package/esm2022/app/reports/dialogs/report-settings/report-settings.component.mjs +109 -0
- package/esm2022/app/reports/export/offscreen-chart.mjs +33 -0
- package/esm2022/app/reports/export/report-export-collector.service.mjs +94 -0
- package/esm2022/app/reports/export/report-pdf.service.mjs +155 -0
- package/esm2022/app/reports/export/report-pptx.service.mjs +224 -0
- package/esm2022/app/reports/format.mjs +25 -0
- package/esm2022/app/reports/interfaces/report.interface.mjs +16 -0
- package/esm2022/app/reports/layout.mjs +50 -0
- package/esm2022/app/reports/option-builder.mjs +293 -0
- package/esm2022/app/reports/report-filter-items.mjs +125 -0
- package/esm2022/app/reports/services/report-filter-state.service.mjs +177 -0
- package/esm2022/app/reports/services/report.service.mjs +56 -0
- package/esm2022/app/reports/theme/echarts.mjs +59 -0
- package/esm2022/app/reports/theme/palette.mjs +10 -0
- package/esm2022/app/reports/views/report/report.component.mjs +354 -0
- package/esm2022/firestitch-report.mjs +5 -0
- package/esm2022/public_api.mjs +13 -0
- package/fesm2022/firestitch-report-echarts-BxYnpz7n.mjs +60 -0
- package/fesm2022/firestitch-report-echarts-BxYnpz7n.mjs.map +1 -0
- package/fesm2022/firestitch-report-firestitch-report-Cnotycly.mjs +3107 -0
- package/fesm2022/firestitch-report-firestitch-report-Cnotycly.mjs.map +1 -0
- package/fesm2022/firestitch-report.mjs +2 -0
- package/fesm2022/firestitch-report.mjs.map +1 -0
- package/index.d.ts +5 -0
- package/package.json +39 -0
- package/public_api.d.ts +5 -0
- package/styles.scss +1 -0
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Observable } from 'rxjs';
|
|
2
|
+
import { ReportListItem } from '../interfaces/report.interface';
|
|
3
|
+
import * as i0 from "@angular/core";
|
|
4
|
+
export declare class ReportService {
|
|
5
|
+
private _reportData;
|
|
6
|
+
private _reports$;
|
|
7
|
+
get reports$(): Observable<ReportListItem[]>;
|
|
8
|
+
load(): Observable<ReportListItem[]>;
|
|
9
|
+
filter(keyword: string): Observable<ReportListItem[]>;
|
|
10
|
+
create(name: string): Observable<ReportListItem>;
|
|
11
|
+
rename(reportId: number, name: string): Observable<ReportListItem>;
|
|
12
|
+
delete(reportId: number): Observable<void>;
|
|
13
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<ReportService, never>;
|
|
14
|
+
static ɵprov: i0.ɵɵInjectableDeclaration<ReportService>;
|
|
15
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { FilterConfig } from '@firestitch/filter';
|
|
2
|
+
import { FsAiChatResponse } from '@firestitch/ai';
|
|
3
|
+
import { Report, ReportComponent as ReportComponentModel, ReportListItem } from '../../interfaces/report.interface';
|
|
4
|
+
import * as i0 from "@angular/core";
|
|
5
|
+
export declare class ReportComponent {
|
|
6
|
+
selected: ReportListItem | null;
|
|
7
|
+
report: Report | null;
|
|
8
|
+
loadingReports: boolean;
|
|
9
|
+
editMode: boolean;
|
|
10
|
+
reportFilterConfig: FilterConfig;
|
|
11
|
+
private _split;
|
|
12
|
+
private _chatPanel;
|
|
13
|
+
readonly introMessage: {
|
|
14
|
+
text: string;
|
|
15
|
+
};
|
|
16
|
+
private _reportData;
|
|
17
|
+
private _reportService;
|
|
18
|
+
private _filterState;
|
|
19
|
+
private _exportCollector;
|
|
20
|
+
private _pptxService;
|
|
21
|
+
private _pdfService;
|
|
22
|
+
private _process;
|
|
23
|
+
private _prompt;
|
|
24
|
+
private _dialog;
|
|
25
|
+
private _destroyRef;
|
|
26
|
+
private _cdRef;
|
|
27
|
+
private _zone;
|
|
28
|
+
constructor();
|
|
29
|
+
fetchReports: (keyword: string) => import("rxjs").Observable<ReportListItem[]>;
|
|
30
|
+
reportChange(report: ReportListItem | null): void;
|
|
31
|
+
createReport(): void;
|
|
32
|
+
toggleEditMode(): void;
|
|
33
|
+
reportSettings(): void;
|
|
34
|
+
componentSettings(component: ReportComponentModel): void;
|
|
35
|
+
onCanvasReportChanged(): void;
|
|
36
|
+
exportPowerpoint(): void;
|
|
37
|
+
exportPdf(): void;
|
|
38
|
+
onChatResponse(response: FsAiChatResponse): void;
|
|
39
|
+
onResizeStart(event: PointerEvent): void;
|
|
40
|
+
private _resizeTo;
|
|
41
|
+
private _loadReport;
|
|
42
|
+
private _reportGroups;
|
|
43
|
+
get reportHasFilters(): boolean;
|
|
44
|
+
get reportFilterKey(): string;
|
|
45
|
+
private _buildReportConfig;
|
|
46
|
+
private _hasTimeSeriesChart;
|
|
47
|
+
private _refreshReportName;
|
|
48
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<ReportComponent, never>;
|
|
49
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<ReportComponent, "ng-component", never, {}, {}, never, never, true, never>;
|
|
50
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
|
|
2
|
+
import { NgxEchartsDirective } from 'ngx-echarts';
|
|
3
|
+
import { buildChartOption } from '../../option-builder';
|
|
4
|
+
import * as i0 from "@angular/core";
|
|
5
|
+
// ECharts host for a chart component. Pure rendering: the parent owns the
|
|
6
|
+
// data fetch; this maps (component config, rows) → option and exposes the
|
|
7
|
+
// chart instance for resize + the future image exports (getDataURL needs the
|
|
8
|
+
// canvas renderer registered in theme/echarts.ts).
|
|
9
|
+
export class ComponentChartComponent {
|
|
10
|
+
component;
|
|
11
|
+
data = null;
|
|
12
|
+
options = null;
|
|
13
|
+
_chart = null;
|
|
14
|
+
ngOnChanges() {
|
|
15
|
+
this.options = this.component && this.data
|
|
16
|
+
? buildChartOption(this.component, this.data)
|
|
17
|
+
: null;
|
|
18
|
+
}
|
|
19
|
+
onChartInit(chart) {
|
|
20
|
+
this._chart = chart;
|
|
21
|
+
}
|
|
22
|
+
// Called by the canvas when the box is resized in edit mode.
|
|
23
|
+
resize() {
|
|
24
|
+
this._chart?.resize();
|
|
25
|
+
}
|
|
26
|
+
// High-res image for the (later-phase) PPT/PDF exports.
|
|
27
|
+
getDataURL(pixelRatio = 3) {
|
|
28
|
+
return this._chart?.getDataURL({
|
|
29
|
+
type: 'png',
|
|
30
|
+
pixelRatio,
|
|
31
|
+
backgroundColor: '#ffffff',
|
|
32
|
+
}) ?? null;
|
|
33
|
+
}
|
|
34
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ComponentChartComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
35
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: ComponentChartComponent, isStandalone: true, selector: "app-report-component-chart", inputs: { component: "component", data: "data" }, usesOnChanges: true, ngImport: i0, template: "<div\n class=\"chart-host\"\n echarts\n [options]=\"options ?? {}\"\n [theme]=\"'report'\"\n [autoResize]=\"true\"\n (chartInit)=\"onChartInit($event)\">\n</div>\n", styles: [":host{display:block;width:100%;height:100%}.chart-host{width:100%;height:100%}\n"], dependencies: [{ kind: "directive", type: NgxEchartsDirective, selector: "echarts, [echarts]", inputs: ["options", "theme", "initOpts", "merge", "autoResize", "loading", "loadingType", "loadingOpts"], outputs: ["chartInit", "optionsError", "chartClick", "chartDblClick", "chartMouseDown", "chartMouseMove", "chartMouseUp", "chartMouseOver", "chartMouseOut", "chartGlobalOut", "chartContextMenu", "chartHighlight", "chartDownplay", "chartSelectChanged", "chartLegendSelectChanged", "chartLegendSelected", "chartLegendUnselected", "chartLegendLegendSelectAll", "chartLegendLegendInverseSelect", "chartLegendScroll", "chartDataZoom", "chartDataRangeSelected", "chartGraphRoam", "chartGeoRoam", "chartTreeRoam", "chartTimelineChanged", "chartTimelinePlayChanged", "chartRestore", "chartDataViewChanged", "chartMagicTypeChanged", "chartGeoSelectChanged", "chartGeoSelected", "chartGeoUnselected", "chartAxisAreaSelected", "chartBrush", "chartBrushEnd", "chartBrushSelected", "chartGlobalCursorTaken", "chartRendered", "chartFinished"], exportAs: ["echarts"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
36
|
+
}
|
|
37
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ComponentChartComponent, decorators: [{
|
|
38
|
+
type: Component,
|
|
39
|
+
args: [{ selector: 'app-report-component-chart', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [
|
|
40
|
+
NgxEchartsDirective,
|
|
41
|
+
], template: "<div\n class=\"chart-host\"\n echarts\n [options]=\"options ?? {}\"\n [theme]=\"'report'\"\n [autoResize]=\"true\"\n (chartInit)=\"onChartInit($event)\">\n</div>\n", styles: [":host{display:block;width:100%;height:100%}.chart-host{width:100%;height:100%}\n"] }]
|
|
42
|
+
}], propDecorators: { component: [{
|
|
43
|
+
type: Input
|
|
44
|
+
}], data: [{
|
|
45
|
+
type: Input
|
|
46
|
+
}] } });
|
|
47
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29tcG9uZW50LWNoYXJ0LmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3NyYy9hcHAvcmVwb3J0cy9jb21wb25lbnRzL2NvbXBvbmVudC1jaGFydC9jb21wb25lbnQtY2hhcnQuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vLi4vLi4vc3JjL2FwcC9yZXBvcnRzL2NvbXBvbmVudHMvY29tcG9uZW50LWNoYXJ0L2NvbXBvbmVudC1jaGFydC5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsdUJBQXVCLEVBQUUsU0FBUyxFQUFFLEtBQUssRUFBYSxNQUFNLGVBQWUsQ0FBQztBQUdyRixPQUFPLEVBQUUsbUJBQW1CLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFHbEQsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sc0JBQXNCLENBQUM7O0FBR3hELDBFQUEwRTtBQUMxRSwwRUFBMEU7QUFDMUUsNkVBQTZFO0FBQzdFLG1EQUFtRDtBQVduRCxNQUFNLE9BQU8sdUJBQXVCO0lBRWxCLFNBQVMsQ0FBa0I7SUFDM0IsSUFBSSxHQUF5QixJQUFJLENBQUM7SUFFM0MsT0FBTyxHQUF5QixJQUFJLENBQUM7SUFFcEMsTUFBTSxHQUFtQixJQUFJLENBQUM7SUFFL0IsV0FBVztRQUNoQixJQUFJLENBQUMsT0FBTyxHQUFHLElBQUksQ0FBQyxTQUFTLElBQUksSUFBSSxDQUFDLElBQUk7WUFDeEMsQ0FBQyxDQUFDLGdCQUFnQixDQUFDLElBQUksQ0FBQyxTQUFTLEVBQUUsSUFBSSxDQUFDLElBQUksQ0FBQztZQUM3QyxDQUFDLENBQUMsSUFBSSxDQUFDO0lBQ1gsQ0FBQztJQUVNLFdBQVcsQ0FBQyxLQUFjO1FBQy9CLElBQUksQ0FBQyxNQUFNLEdBQUcsS0FBSyxDQUFDO0lBQ3RCLENBQUM7SUFFRCw2REFBNkQ7SUFDdEQsTUFBTTtRQUNYLElBQUksQ0FBQyxNQUFNLEVBQUUsTUFBTSxFQUFFLENBQUM7SUFDeEIsQ0FBQztJQUVELHdEQUF3RDtJQUNqRCxVQUFVLENBQUMsVUFBVSxHQUFHLENBQUM7UUFDOUIsT0FBTyxJQUFJLENBQUMsTUFBTSxFQUFFLFVBQVUsQ0FBQztZQUM3QixJQUFJLEVBQUUsS0FBSztZQUNYLFVBQVU7WUFDVixlQUFlLEVBQUUsU0FBUztTQUMzQixDQUFDLElBQUksSUFBSSxDQUFDO0lBQ2IsQ0FBQzt3R0EvQlUsdUJBQXVCOzRGQUF2Qix1QkFBdUIsNkpDdkJwQywyS0FRQSwwSURZSSxtQkFBbUI7OzRGQUdWLHVCQUF1QjtrQkFWbkMsU0FBUzsrQkFDRSw0QkFBNEIsbUJBR3JCLHVCQUF1QixDQUFDLE1BQU0sY0FDbkMsSUFBSSxXQUNQO3dCQUNQLG1CQUFtQjtxQkFDcEI7OEJBSWUsU0FBUztzQkFBeEIsS0FBSztnQkFDVSxJQUFJO3NCQUFuQixLQUFLIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3ksIENvbXBvbmVudCwgSW5wdXQsIE9uQ2hhbmdlcyB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuXG5pbXBvcnQgdHlwZSB7IEVDaGFydHNPcHRpb24sIEVDaGFydHMgfSBmcm9tICdlY2hhcnRzJztcbmltcG9ydCB7IE5neEVjaGFydHNEaXJlY3RpdmUgfSBmcm9tICduZ3gtZWNoYXJ0cyc7XG5cbmltcG9ydCB7IENvbXBvbmVudERhdGEsIFJlcG9ydENvbXBvbmVudCB9IGZyb20gJy4uLy4uL2ludGVyZmFjZXMvcmVwb3J0LmludGVyZmFjZSc7XG5pbXBvcnQgeyBidWlsZENoYXJ0T3B0aW9uIH0gZnJvbSAnLi4vLi4vb3B0aW9uLWJ1aWxkZXInO1xuXG5cbi8vIEVDaGFydHMgaG9zdCBmb3IgYSBjaGFydCBjb21wb25lbnQuIFB1cmUgcmVuZGVyaW5nOiB0aGUgcGFyZW50IG93bnMgdGhlXG4vLyBkYXRhIGZldGNoOyB0aGlzIG1hcHMgKGNvbXBvbmVudCBjb25maWcsIHJvd3MpIOKGkiBvcHRpb24gYW5kIGV4cG9zZXMgdGhlXG4vLyBjaGFydCBpbnN0YW5jZSBmb3IgcmVzaXplICsgdGhlIGZ1dHVyZSBpbWFnZSBleHBvcnRzIChnZXREYXRhVVJMIG5lZWRzIHRoZVxuLy8gY2FudmFzIHJlbmRlcmVyIHJlZ2lzdGVyZWQgaW4gdGhlbWUvZWNoYXJ0cy50cykuXG5AQ29tcG9uZW50KHtcbiAgc2VsZWN0b3I6ICdhcHAtcmVwb3J0LWNvbXBvbmVudC1jaGFydCcsXG4gIHRlbXBsYXRlVXJsOiAnLi9jb21wb25lbnQtY2hhcnQuY29tcG9uZW50Lmh0bWwnLFxuICBzdHlsZVVybHM6IFsnLi9jb21wb25lbnQtY2hhcnQuY29tcG9uZW50LnNjc3MnXSxcbiAgY2hhbmdlRGV0ZWN0aW9uOiBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneS5PblB1c2gsXG4gIHN0YW5kYWxvbmU6IHRydWUsXG4gIGltcG9ydHM6IFtcbiAgICBOZ3hFY2hhcnRzRGlyZWN0aXZlLFxuICBdLFxufSlcbmV4cG9ydCBjbGFzcyBDb21wb25lbnRDaGFydENvbXBvbmVudCBpbXBsZW1lbnRzIE9uQ2hhbmdlcyB7XG5cbiAgQElucHV0KCkgcHVibGljIGNvbXBvbmVudDogUmVwb3J0Q29tcG9uZW50O1xuICBASW5wdXQoKSBwdWJsaWMgZGF0YTogQ29tcG9uZW50RGF0YSB8IG51bGwgPSBudWxsO1xuXG4gIHB1YmxpYyBvcHRpb25zOiBFQ2hhcnRzT3B0aW9uIHwgbnVsbCA9IG51bGw7XG5cbiAgcHJpdmF0ZSBfY2hhcnQ6IEVDaGFydHMgfCBudWxsID0gbnVsbDtcblxuICBwdWJsaWMgbmdPbkNoYW5nZXMoKTogdm9pZCB7XG4gICAgdGhpcy5vcHRpb25zID0gdGhpcy5jb21wb25lbnQgJiYgdGhpcy5kYXRhXG4gICAgICA/IGJ1aWxkQ2hhcnRPcHRpb24odGhpcy5jb21wb25lbnQsIHRoaXMuZGF0YSlcbiAgICAgIDogbnVsbDtcbiAgfVxuXG4gIHB1YmxpYyBvbkNoYXJ0SW5pdChjaGFydDogRUNoYXJ0cyk6IHZvaWQge1xuICAgIHRoaXMuX2NoYXJ0ID0gY2hhcnQ7XG4gIH1cblxuICAvLyBDYWxsZWQgYnkgdGhlIGNhbnZhcyB3aGVuIHRoZSBib3ggaXMgcmVzaXplZCBpbiBlZGl0IG1vZGUuXG4gIHB1YmxpYyByZXNpemUoKTogdm9pZCB7XG4gICAgdGhpcy5fY2hhcnQ/LnJlc2l6ZSgpO1xuICB9XG5cbiAgLy8gSGlnaC1yZXMgaW1hZ2UgZm9yIHRoZSAobGF0ZXItcGhhc2UpIFBQVC9QREYgZXhwb3J0cy5cbiAgcHVibGljIGdldERhdGFVUkwocGl4ZWxSYXRpbyA9IDMpOiBzdHJpbmcgfCBudWxsIHtcbiAgICByZXR1cm4gdGhpcy5fY2hhcnQ/LmdldERhdGFVUkwoe1xuICAgICAgdHlwZTogJ3BuZycsXG4gICAgICBwaXhlbFJhdGlvLFxuICAgICAgYmFja2dyb3VuZENvbG9yOiAnI2ZmZmZmZicsXG4gICAgfSkgPz8gbnVsbDtcbiAgfVxufVxuIiwiPGRpdlxuICBjbGFzcz1cImNoYXJ0LWhvc3RcIlxuICBlY2hhcnRzXG4gIFtvcHRpb25zXT1cIm9wdGlvbnMgPz8ge31cIlxuICBbdGhlbWVdPVwiJ3JlcG9ydCdcIlxuICBbYXV0b1Jlc2l6ZV09XCJ0cnVlXCJcbiAgKGNoYXJ0SW5pdCk9XCJvbkNoYXJ0SW5pdCgkZXZlbnQpXCI+XG48L2Rpdj5cbiJdfQ==
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
|
|
2
|
+
import { formatMeasureValue } from '../../format';
|
|
3
|
+
import * as i0 from "@angular/core";
|
|
4
|
+
// A single big number: the component's measure aggregated over all (filtered)
|
|
5
|
+
// rows server-side; this just formats the one cell.
|
|
6
|
+
export class ComponentKpiComponent {
|
|
7
|
+
component;
|
|
8
|
+
data = null;
|
|
9
|
+
value = '—';
|
|
10
|
+
label = '';
|
|
11
|
+
ngOnChanges() {
|
|
12
|
+
const config = (this.component?.config ?? {});
|
|
13
|
+
this.label = config.measure?.label ?? '';
|
|
14
|
+
const row = this.data?.rows?.[0];
|
|
15
|
+
if (!row) {
|
|
16
|
+
this.value = '—';
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
const column = config.measure?.column ?? Object.keys(row)[0];
|
|
20
|
+
this.value = formatMeasureValue(row[column], config.measure?.format);
|
|
21
|
+
}
|
|
22
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ComponentKpiComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
23
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: ComponentKpiComponent, isStandalone: true, selector: "app-report-component-kpi", inputs: { component: "component", data: "data" }, usesOnChanges: true, ngImport: i0, template: "<div class=\"kpi\">\n <div class=\"kpi-value\">{{ value }}</div>\n @if (label) {\n <div class=\"kpi-label\">{{ label }}</div>\n }\n</div>\n", styles: [":host{display:block;width:100%;height:100%}.kpi{width:100%;height:100%;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:4px}.kpi .kpi-value{font-size:34px;font-weight:600;color:#1f2933;line-height:1}.kpi .kpi-label{font-size:12px;color:#7b8794}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
24
|
+
}
|
|
25
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ComponentKpiComponent, decorators: [{
|
|
26
|
+
type: Component,
|
|
27
|
+
args: [{ selector: 'app-report-component-kpi', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, template: "<div class=\"kpi\">\n <div class=\"kpi-value\">{{ value }}</div>\n @if (label) {\n <div class=\"kpi-label\">{{ label }}</div>\n }\n</div>\n", styles: [":host{display:block;width:100%;height:100%}.kpi{width:100%;height:100%;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:4px}.kpi .kpi-value{font-size:34px;font-weight:600;color:#1f2933;line-height:1}.kpi .kpi-label{font-size:12px;color:#7b8794}\n"] }]
|
|
28
|
+
}], propDecorators: { component: [{
|
|
29
|
+
type: Input
|
|
30
|
+
}], data: [{
|
|
31
|
+
type: Input
|
|
32
|
+
}] } });
|
|
33
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29tcG9uZW50LWtwaS5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9zcmMvYXBwL3JlcG9ydHMvY29tcG9uZW50cy9jb21wb25lbnQta3BpL2NvbXBvbmVudC1rcGkuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vLi4vLi4vc3JjL2FwcC9yZXBvcnRzL2NvbXBvbmVudHMvY29tcG9uZW50LWtwaS9jb21wb25lbnQta3BpLmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSx1QkFBdUIsRUFBRSxTQUFTLEVBQUUsS0FBSyxFQUFhLE1BQU0sZUFBZSxDQUFDO0FBRXJGLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLGNBQWMsQ0FBQzs7QUFJbEQsOEVBQThFO0FBQzlFLG9EQUFvRDtBQVFwRCxNQUFNLE9BQU8scUJBQXFCO0lBRWhCLFNBQVMsQ0FBa0I7SUFDM0IsSUFBSSxHQUF5QixJQUFJLENBQUM7SUFFM0MsS0FBSyxHQUFHLEdBQUcsQ0FBQztJQUNaLEtBQUssR0FBRyxFQUFFLENBQUM7SUFFWCxXQUFXO1FBQ2hCLE1BQU0sTUFBTSxHQUFHLENBQUMsSUFBSSxDQUFDLFNBQVMsRUFBRSxNQUFNLElBQUksRUFBRSxDQUFjLENBQUM7UUFDM0QsSUFBSSxDQUFDLEtBQUssR0FBRyxNQUFNLENBQUMsT0FBTyxFQUFFLEtBQUssSUFBSSxFQUFFLENBQUM7UUFFekMsTUFBTSxHQUFHLEdBQUcsSUFBSSxDQUFDLElBQUksRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUNqQyxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUM7WUFDVCxJQUFJLENBQUMsS0FBSyxHQUFHLEdBQUcsQ0FBQztZQUVqQixPQUFPO1FBQ1QsQ0FBQztRQUVELE1BQU0sTUFBTSxHQUFHLE1BQU0sQ0FBQyxPQUFPLEVBQUUsTUFBTSxJQUFJLE1BQU0sQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDN0QsSUFBSSxDQUFDLEtBQUssR0FBRyxrQkFBa0IsQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLEVBQUUsTUFBTSxDQUFDLE9BQU8sRUFBRSxNQUFNLENBQUMsQ0FBQztJQUN2RSxDQUFDO3dHQXJCVSxxQkFBcUI7NEZBQXJCLHFCQUFxQiwySkNmbEMsbUpBTUE7OzRGRFNhLHFCQUFxQjtrQkFQakMsU0FBUzsrQkFDRSwwQkFBMEIsbUJBR25CLHVCQUF1QixDQUFDLE1BQU0sY0FDbkMsSUFBSTs4QkFJQSxTQUFTO3NCQUF4QixLQUFLO2dCQUNVLElBQUk7c0JBQW5CLEtBQUsiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneSwgQ29tcG9uZW50LCBJbnB1dCwgT25DaGFuZ2VzIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5cbmltcG9ydCB7IGZvcm1hdE1lYXN1cmVWYWx1ZSB9IGZyb20gJy4uLy4uL2Zvcm1hdCc7XG5pbXBvcnQgeyBDb21wb25lbnREYXRhLCBLcGlDb25maWcsIFJlcG9ydENvbXBvbmVudCB9IGZyb20gJy4uLy4uL2ludGVyZmFjZXMvcmVwb3J0LmludGVyZmFjZSc7XG5cblxuLy8gQSBzaW5nbGUgYmlnIG51bWJlcjogdGhlIGNvbXBvbmVudCdzIG1lYXN1cmUgYWdncmVnYXRlZCBvdmVyIGFsbCAoZmlsdGVyZWQpXG4vLyByb3dzIHNlcnZlci1zaWRlOyB0aGlzIGp1c3QgZm9ybWF0cyB0aGUgb25lIGNlbGwuXG5AQ29tcG9uZW50KHtcbiAgc2VsZWN0b3I6ICdhcHAtcmVwb3J0LWNvbXBvbmVudC1rcGknLFxuICB0ZW1wbGF0ZVVybDogJy4vY29tcG9uZW50LWtwaS5jb21wb25lbnQuaHRtbCcsXG4gIHN0eWxlVXJsczogWycuL2NvbXBvbmVudC1rcGkuY29tcG9uZW50LnNjc3MnXSxcbiAgY2hhbmdlRGV0ZWN0aW9uOiBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneS5PblB1c2gsXG4gIHN0YW5kYWxvbmU6IHRydWUsXG59KVxuZXhwb3J0IGNsYXNzIENvbXBvbmVudEtwaUNvbXBvbmVudCBpbXBsZW1lbnRzIE9uQ2hhbmdlcyB7XG5cbiAgQElucHV0KCkgcHVibGljIGNvbXBvbmVudDogUmVwb3J0Q29tcG9uZW50O1xuICBASW5wdXQoKSBwdWJsaWMgZGF0YTogQ29tcG9uZW50RGF0YSB8IG51bGwgPSBudWxsO1xuXG4gIHB1YmxpYyB2YWx1ZSA9ICfigJQnO1xuICBwdWJsaWMgbGFiZWwgPSAnJztcblxuICBwdWJsaWMgbmdPbkNoYW5nZXMoKTogdm9pZCB7XG4gICAgY29uc3QgY29uZmlnID0gKHRoaXMuY29tcG9uZW50Py5jb25maWcgPz8ge30pIGFzIEtwaUNvbmZpZztcbiAgICB0aGlzLmxhYmVsID0gY29uZmlnLm1lYXN1cmU/LmxhYmVsID8/ICcnO1xuXG4gICAgY29uc3Qgcm93ID0gdGhpcy5kYXRhPy5yb3dzPy5bMF07XG4gICAgaWYgKCFyb3cpIHtcbiAgICAgIHRoaXMudmFsdWUgPSAn4oCUJztcblxuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGNvbnN0IGNvbHVtbiA9IGNvbmZpZy5tZWFzdXJlPy5jb2x1bW4gPz8gT2JqZWN0LmtleXMocm93KVswXTtcbiAgICB0aGlzLnZhbHVlID0gZm9ybWF0TWVhc3VyZVZhbHVlKHJvd1tjb2x1bW5dLCBjb25maWcubWVhc3VyZT8uZm9ybWF0KTtcbiAgfVxufVxuIiwiPGRpdiBjbGFzcz1cImtwaVwiPlxuICA8ZGl2IGNsYXNzPVwia3BpLXZhbHVlXCI+e3sgdmFsdWUgfX08L2Rpdj5cbiAgQGlmIChsYWJlbCkge1xuICAgIDxkaXYgY2xhc3M9XCJrcGktbGFiZWxcIj57eyBsYWJlbCB9fTwvZGl2PlxuICB9XG48L2Rpdj5cbiJdfQ==
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import { ChangeDetectionStrategy, Component, DestroyRef, Input, ViewChild, inject } from '@angular/core';
|
|
2
|
+
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
3
|
+
import { DatePipe } from '@angular/common';
|
|
4
|
+
import { ItemType } from '@firestitch/filter';
|
|
5
|
+
import { FsListComponent, FsListModule, PaginationStrategy } from '@firestitch/list';
|
|
6
|
+
import { map } from 'rxjs';
|
|
7
|
+
import { ReportData } from '../../data/report.data';
|
|
8
|
+
import { dateBoundString } from '../../report-filter-items';
|
|
9
|
+
import { ReportFilterStateService } from '../../services/report-filter-state.service';
|
|
10
|
+
import * as i0 from "@angular/core";
|
|
11
|
+
import * as i1 from "@firestitch/list";
|
|
12
|
+
// A list component: FsList + FsFilter rendered from the component's config and
|
|
13
|
+
// its report_filters rows. The component's own filter bar carries its filters
|
|
14
|
+
// whose group renders at the component level; report-level groups apply
|
|
15
|
+
// through the shared filter-state service and merge into every request.
|
|
16
|
+
// Paging and sorting are pushed into the SQL wrap server-side.
|
|
17
|
+
export class ComponentListComponent {
|
|
18
|
+
reportId;
|
|
19
|
+
component;
|
|
20
|
+
groups;
|
|
21
|
+
listComponent;
|
|
22
|
+
listConfig;
|
|
23
|
+
columns = [];
|
|
24
|
+
_reportData = inject(ReportData);
|
|
25
|
+
_filterState = inject(ReportFilterStateService);
|
|
26
|
+
_destroyRef = inject(DestroyRef);
|
|
27
|
+
ngOnInit() {
|
|
28
|
+
const config = (this.component.config ?? {});
|
|
29
|
+
this.columns = config.columns ?? [];
|
|
30
|
+
this._initListConfig(config);
|
|
31
|
+
// Report-level filter changes that scope this component re-run the list.
|
|
32
|
+
this._filterState.changesFor(this.component)
|
|
33
|
+
.pipe(takeUntilDestroyed(this._destroyRef))
|
|
34
|
+
.subscribe(() => this.listComponent?.reload());
|
|
35
|
+
}
|
|
36
|
+
_initListConfig(config) {
|
|
37
|
+
this.listConfig = {
|
|
38
|
+
// Inside a report component the list is a clean data pane — no status
|
|
39
|
+
// bar, no reload button (filter changes already refetch).
|
|
40
|
+
status: false,
|
|
41
|
+
reload: false,
|
|
42
|
+
// Never touch the URL or persist filter/paging state — report filtering
|
|
43
|
+
// is session-only.
|
|
44
|
+
queryParam: false,
|
|
45
|
+
persist: false,
|
|
46
|
+
sort: config.sort
|
|
47
|
+
? { value: config.sort.column, direction: config.sort.direction ?? 'asc' }
|
|
48
|
+
: undefined,
|
|
49
|
+
paging: {
|
|
50
|
+
limit: config.pageSize ?? 25,
|
|
51
|
+
strategy: PaginationStrategy.Page,
|
|
52
|
+
},
|
|
53
|
+
filters: this._ownFilters().map((filter) => this._filterItem(filter)),
|
|
54
|
+
fetch: (query) => this._fetch(query),
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
// The filters this list renders in its own bar: its report_filters whose
|
|
58
|
+
// group is component-level. Report-level groups render in the report bar.
|
|
59
|
+
_ownFilters() {
|
|
60
|
+
return (this.component.filters ?? [])
|
|
61
|
+
.filter((filter) => {
|
|
62
|
+
const group = this.groups?.get(filter.filterGroupId);
|
|
63
|
+
return filter.enabled && (!group || group.level === 'component' || group.level === 'both');
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
_filterItem(filter) {
|
|
67
|
+
const group = this.groups?.get(filter.filterGroupId);
|
|
68
|
+
const name = `f${filter.id}`;
|
|
69
|
+
const label = filter.label || group?.label || filter.filterColumn;
|
|
70
|
+
switch (group?.type) {
|
|
71
|
+
case 'dateRange':
|
|
72
|
+
return {
|
|
73
|
+
name,
|
|
74
|
+
type: ItemType.DateRange,
|
|
75
|
+
label: [`${label} From`, `${label} To`],
|
|
76
|
+
};
|
|
77
|
+
case 'select':
|
|
78
|
+
return {
|
|
79
|
+
name,
|
|
80
|
+
type: ItemType.AutoCompleteChips,
|
|
81
|
+
label,
|
|
82
|
+
values: () => this._reportData.filterOptions(this.reportId, filter.id)
|
|
83
|
+
.pipe(map((options) => (options ?? [])
|
|
84
|
+
.map((option) => ({ name: String(option), value: option })))),
|
|
85
|
+
};
|
|
86
|
+
case 'keyword':
|
|
87
|
+
default:
|
|
88
|
+
return {
|
|
89
|
+
name,
|
|
90
|
+
type: ItemType.Keyword,
|
|
91
|
+
label,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
_fetch(query) {
|
|
96
|
+
const state = {
|
|
97
|
+
page: query.page ?? 1,
|
|
98
|
+
pageSize: query.limit ?? 25,
|
|
99
|
+
};
|
|
100
|
+
const order = String(query.order ?? '');
|
|
101
|
+
if (order) {
|
|
102
|
+
const [column, direction] = order.split(',');
|
|
103
|
+
state.sort = { column, direction: direction === 'desc' ? 'desc' : 'asc' };
|
|
104
|
+
}
|
|
105
|
+
// Report-level values from the shared session state, merged with this
|
|
106
|
+
// list's own filter-bar values (own values win per filter).
|
|
107
|
+
const resolved = new Map();
|
|
108
|
+
for (const value of this._filterState.resolveForComponent(this.component)) {
|
|
109
|
+
resolved.set(value.filterId, value);
|
|
110
|
+
}
|
|
111
|
+
for (const value of this._barValues(query)) {
|
|
112
|
+
resolved.set(value.filterId, value);
|
|
113
|
+
}
|
|
114
|
+
return this._reportData
|
|
115
|
+
.componentData(this.reportId, this.component.id, [...resolved.values()], state)
|
|
116
|
+
.pipe(map((data) => ({
|
|
117
|
+
data: data.rows ?? [],
|
|
118
|
+
paging: {
|
|
119
|
+
limit: data.paging?.pageSize ?? state.pageSize,
|
|
120
|
+
records: data.paging?.total ?? (data.rows?.length ?? 0),
|
|
121
|
+
page: data.paging?.page ?? state.page,
|
|
122
|
+
},
|
|
123
|
+
})));
|
|
124
|
+
}
|
|
125
|
+
// The list's own FsFilter values, read back out of the fetch query by the
|
|
126
|
+
// `f<filterId>` naming convention.
|
|
127
|
+
_barValues(query) {
|
|
128
|
+
const values = [];
|
|
129
|
+
for (const filter of this._ownFilters()) {
|
|
130
|
+
const group = this.groups?.get(filter.filterGroupId);
|
|
131
|
+
const name = `f${filter.id}`;
|
|
132
|
+
if (group?.type === 'dateRange') {
|
|
133
|
+
const from = dateBoundString(query[`${name}From`]);
|
|
134
|
+
const to = dateBoundString(query[`${name}To`]);
|
|
135
|
+
if (from || to) {
|
|
136
|
+
values.push({ filterId: filter.id, start: from, end: to });
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
else if (group?.type === 'select') {
|
|
140
|
+
// fs-filter joins a multi-select into one "a,b" string; split it back
|
|
141
|
+
// so each value binds separately (else `col IN ('a,b')` matches nothing).
|
|
142
|
+
const selected = query[name];
|
|
143
|
+
const selectedValues = Array.isArray(selected)
|
|
144
|
+
? selected
|
|
145
|
+
: (selected ? String(selected).split(',') : []);
|
|
146
|
+
if (selectedValues.length) {
|
|
147
|
+
values.push({ filterId: filter.id, values: selectedValues });
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
const keyword = String(query[name] ?? '').trim();
|
|
152
|
+
if (keyword) {
|
|
153
|
+
values.push({ filterId: filter.id, value: keyword });
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
return values;
|
|
158
|
+
}
|
|
159
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ComponentListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
160
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: ComponentListComponent, isStandalone: true, selector: "app-report-component-list", inputs: { reportId: "reportId", component: "component", groups: "groups" }, viewQueries: [{ propertyName: "listComponent", first: true, predicate: FsListComponent, descendants: true }], ngImport: i0, template: "<fs-list [config]=\"listConfig\">\n @for (column of columns; track column.column) {\n <fs-list-column\n [name]=\"column.column\"\n [title]=\"column.label || column.column\"\n [sortable]=\"true\">\n <ng-template\n fs-list-cell\n let-row=\"row\">\n @if (column.format === 'date') {\n {{ row[column.column] | date: 'mediumDate' }}\n } @else {\n {{ row[column.column] }}\n }\n </ng-template>\n </fs-list-column>\n }\n</fs-list>\n", styles: [":host{display:block;width:100%;height:100%;overflow:auto}\n"], dependencies: [{ kind: "pipe", type: DatePipe, name: "date" }, { kind: "ngmodule", type: FsListModule }, { kind: "component", type: i1.FsListComponent, selector: "fs-list", inputs: ["config", "loaderLines", "cellRowType"], outputs: ["filtersReady"] }, { kind: "directive", type: i1.FsListColumnDirective, selector: "fs-list-column", inputs: ["show", "title", "name", "customizable", "sortable", "sortableDefault", "sortableDirection", "direction", "align", "width", "class"] }, { kind: "directive", type: i1.FsListCellDirective, selector: "[fs-list-cell],[fsListCell]", inputs: ["colspan", "align", "class", "fsListCell", "configTyping"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
161
|
+
}
|
|
162
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ComponentListComponent, decorators: [{
|
|
163
|
+
type: Component,
|
|
164
|
+
args: [{ selector: 'app-report-component-list', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [
|
|
165
|
+
DatePipe,
|
|
166
|
+
FsListModule,
|
|
167
|
+
], template: "<fs-list [config]=\"listConfig\">\n @for (column of columns; track column.column) {\n <fs-list-column\n [name]=\"column.column\"\n [title]=\"column.label || column.column\"\n [sortable]=\"true\">\n <ng-template\n fs-list-cell\n let-row=\"row\">\n @if (column.format === 'date') {\n {{ row[column.column] | date: 'mediumDate' }}\n } @else {\n {{ row[column.column] }}\n }\n </ng-template>\n </fs-list-column>\n }\n</fs-list>\n", styles: [":host{display:block;width:100%;height:100%;overflow:auto}\n"] }]
|
|
168
|
+
}], propDecorators: { reportId: [{
|
|
169
|
+
type: Input
|
|
170
|
+
}], component: [{
|
|
171
|
+
type: Input
|
|
172
|
+
}], groups: [{
|
|
173
|
+
type: Input
|
|
174
|
+
}], listComponent: [{
|
|
175
|
+
type: ViewChild,
|
|
176
|
+
args: [FsListComponent]
|
|
177
|
+
}] } });
|
|
178
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29tcG9uZW50LWxpc3QuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vc3JjL2FwcC9yZXBvcnRzL2NvbXBvbmVudHMvY29tcG9uZW50LWxpc3QvY29tcG9uZW50LWxpc3QuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vLi4vLi4vc3JjL2FwcC9yZXBvcnRzL2NvbXBvbmVudHMvY29tcG9uZW50LWxpc3QvY29tcG9uZW50LWxpc3QuY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLHVCQUF1QixFQUFFLFNBQVMsRUFBRSxVQUFVLEVBQUUsS0FBSyxFQUFVLFNBQVMsRUFBRSxNQUFNLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDakgsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sNEJBQTRCLENBQUM7QUFDaEUsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBRTNDLE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUM5QyxPQUFPLEVBQUUsZUFBZSxFQUFnQixZQUFZLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQztBQUVuRyxPQUFPLEVBQWMsR0FBRyxFQUFFLE1BQU0sTUFBTSxDQUFDO0FBRXZDLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQVVwRCxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sMkJBQTJCLENBQUM7QUFDNUQsT0FBTyxFQUFFLHdCQUF3QixFQUFFLE1BQU0sNENBQTRDLENBQUM7OztBQUd0RiwrRUFBK0U7QUFDL0UsOEVBQThFO0FBQzlFLHdFQUF3RTtBQUN4RSx3RUFBd0U7QUFDeEUsK0RBQStEO0FBWS9ELE1BQU0sT0FBTyxzQkFBc0I7SUFFakIsUUFBUSxDQUFTO0lBQ2pCLFNBQVMsQ0FBa0I7SUFDM0IsTUFBTSxDQUFpQztJQUdoRCxhQUFhLENBQWtCO0lBRS9CLFVBQVUsQ0FBZTtJQUN6QixPQUFPLEdBQTBELEVBQUUsQ0FBQztJQUVuRSxXQUFXLEdBQUcsTUFBTSxDQUFDLFVBQVUsQ0FBQyxDQUFDO0lBQ2pDLFlBQVksR0FBRyxNQUFNLENBQUMsd0JBQXdCLENBQUMsQ0FBQztJQUNoRCxXQUFXLEdBQUcsTUFBTSxDQUFDLFVBQVUsQ0FBQyxDQUFDO0lBRWxDLFFBQVE7UUFDYixNQUFNLE1BQU0sR0FBRyxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsTUFBTSxJQUFJLEVBQUUsQ0FBZSxDQUFDO1FBQzNELElBQUksQ0FBQyxPQUFPLEdBQUcsTUFBTSxDQUFDLE9BQU8sSUFBSSxFQUFFLENBQUM7UUFFcEMsSUFBSSxDQUFDLGVBQWUsQ0FBQyxNQUFNLENBQUMsQ0FBQztRQUU3Qix5RUFBeUU7UUFDekUsSUFBSSxDQUFDLFlBQVksQ0FBQyxVQUFVLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQzthQUN6QyxJQUFJLENBQUMsa0JBQWtCLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxDQUFDO2FBQzFDLFNBQVMsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxJQUFJLENBQUMsYUFBYSxFQUFFLE1BQU0sRUFBRSxDQUFDLENBQUM7SUFDbkQsQ0FBQztJQUVPLGVBQWUsQ0FBQyxNQUFrQjtRQUN4QyxJQUFJLENBQUMsVUFBVSxHQUFHO1lBQ2hCLHNFQUFzRTtZQUN0RSwwREFBMEQ7WUFDMUQsTUFBTSxFQUFFLEtBQUs7WUFDYixNQUFNLEVBQUUsS0FBSztZQUNiLHdFQUF3RTtZQUN4RSxtQkFBbUI7WUFDbkIsVUFBVSxFQUFFLEtBQUs7WUFDakIsT0FBTyxFQUFFLEtBQUs7WUFDZCxJQUFJLEVBQUUsTUFBTSxDQUFDLElBQUk7Z0JBQ2YsQ0FBQyxDQUFDLEVBQUUsS0FBSyxFQUFFLE1BQU0sQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFLFNBQVMsRUFBRSxNQUFNLENBQUMsSUFBSSxDQUFDLFNBQVMsSUFBSSxLQUFLLEVBQUU7Z0JBQzFFLENBQUMsQ0FBQyxTQUFTO1lBQ2IsTUFBTSxFQUFFO2dCQUNOLEtBQUssRUFBRSxNQUFNLENBQUMsUUFBUSxJQUFJLEVBQUU7Z0JBQzVCLFFBQVEsRUFBRSxrQkFBa0IsQ0FBQyxJQUFJO2FBQ2xDO1lBQ0QsT0FBTyxFQUFFLElBQUksQ0FBQyxXQUFXLEVBQUUsQ0FBQyxHQUFHLENBQUMsQ0FBQyxNQUFNLEVBQUUsRUFBRSxDQUFDLElBQUksQ0FBQyxXQUFXLENBQUMsTUFBTSxDQUFDLENBQUM7WUFDckUsS0FBSyxFQUFFLENBQUMsS0FBVSxFQUFFLEVBQUUsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQztTQUMxQyxDQUFDO0lBQ0osQ0FBQztJQUVELHlFQUF5RTtJQUN6RSwwRUFBMEU7SUFDbEUsV0FBVztRQUNqQixPQUFPLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxPQUFPLElBQUksRUFBRSxDQUFDO2FBQ2xDLE1BQU0sQ0FBQyxDQUFDLE1BQU0sRUFBRSxFQUFFO1lBQ2pCLE1BQU0sS0FBSyxHQUFHLElBQUksQ0FBQyxNQUFNLEVBQUUsR0FBRyxDQUFDLE1BQU0sQ0FBQyxhQUFhLENBQUMsQ0FBQztZQUVyRCxPQUFPLE1BQU0sQ0FBQyxPQUFPLElBQUksQ0FBQyxDQUFDLEtBQUssSUFBSSxLQUFLLENBQUMsS0FBSyxLQUFLLFdBQVcsSUFBSSxLQUFLLENBQUMsS0FBSyxLQUFLLE1BQU0sQ0FBQyxDQUFDO1FBQzdGLENBQUMsQ0FBQyxDQUFDO0lBQ1AsQ0FBQztJQUVPLFdBQVcsQ0FBQyxNQUFvQjtRQUN0QyxNQUFNLEtBQUssR0FBRyxJQUFJLENBQUMsTUFBTSxFQUFFLEdBQUcsQ0FBQyxNQUFNLENBQUMsYUFBYSxDQUFDLENBQUM7UUFDckQsTUFBTSxJQUFJLEdBQUcsSUFBSSxNQUFNLENBQUMsRUFBRSxFQUFFLENBQUM7UUFDN0IsTUFBTSxLQUFLLEdBQUcsTUFBTSxDQUFDLEtBQUssSUFBSSxLQUFLLEVBQUUsS0FBSyxJQUFJLE1BQU0sQ0FBQyxZQUFZLENBQUM7UUFFbEUsUUFBUSxLQUFLLEVBQUUsSUFBSSxFQUFFLENBQUM7WUFDcEIsS0FBSyxXQUFXO2dCQUNkLE9BQU87b0JBQ0wsSUFBSTtvQkFDSixJQUFJLEVBQUUsUUFBUSxDQUFDLFNBQVM7b0JBQ3hCLEtBQUssRUFBRSxDQUFDLEdBQUcsS0FBSyxPQUFPLEVBQUUsR0FBRyxLQUFLLEtBQUssQ0FBQztpQkFDeEMsQ0FBQztZQUVKLEtBQUssUUFBUTtnQkFDWCxPQUFPO29CQUNMLElBQUk7b0JBQ0osSUFBSSxFQUFFLFFBQVEsQ0FBQyxpQkFBaUI7b0JBQ2hDLEtBQUs7b0JBQ0wsTUFBTSxFQUFFLEdBQUcsRUFBRSxDQUFDLElBQUksQ0FBQyxXQUFXLENBQUMsYUFBYSxDQUFDLElBQUksQ0FBQyxRQUFRLEVBQUUsTUFBTSxDQUFDLEVBQUUsQ0FBQzt5QkFDbkUsSUFBSSxDQUNILEdBQUcsQ0FBQyxDQUFDLE9BQWtCLEVBQUUsRUFBRSxDQUFDLENBQUMsT0FBTyxJQUFJLEVBQUUsQ0FBQzt5QkFDeEMsR0FBRyxDQUFDLENBQUMsTUFBTSxFQUFFLEVBQUUsQ0FBQyxDQUFDLEVBQUUsSUFBSSxFQUFFLE1BQU0sQ0FBQyxNQUFNLENBQUMsRUFBRSxLQUFLLEVBQUUsTUFBTSxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQy9EO2lCQUNKLENBQUM7WUFFSixLQUFLLFNBQVMsQ0FBQztZQUNmO2dCQUNFLE9BQU87b0JBQ0wsSUFBSTtvQkFDSixJQUFJLEVBQUUsUUFBUSxDQUFDLE9BQU87b0JBQ3RCLEtBQUs7aUJBQ04sQ0FBQztRQUNOLENBQUM7SUFDSCxDQUFDO0lBRU8sTUFBTSxDQUFDLEtBQVU7UUFDdkIsTUFBTSxLQUFLLEdBQXVCO1lBQ2hDLElBQUksRUFBRSxLQUFLLENBQUMsSUFBSSxJQUFJLENBQUM7WUFDckIsUUFBUSxFQUFFLEtBQUssQ0FBQyxLQUFLLElBQUksRUFBRTtTQUM1QixDQUFDO1FBRUYsTUFBTSxLQUFLLEdBQUcsTUFBTSxDQUFDLEtBQUssQ0FBQyxLQUFLLElBQUksRUFBRSxDQUFDLENBQUM7UUFDeEMsSUFBSSxLQUFLLEVBQUUsQ0FBQztZQUNWLE1BQU0sQ0FBQyxNQUFNLEVBQUUsU0FBUyxDQUFDLEdBQUcsS0FBSyxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQztZQUM3QyxLQUFLLENBQUMsSUFBSSxHQUFHLEVBQUUsTUFBTSxFQUFFLFNBQVMsRUFBRSxTQUFTLEtBQUssTUFBTSxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEtBQUssRUFBRSxDQUFDO1FBQzVFLENBQUM7UUFFRCxzRUFBc0U7UUFDdEUsNERBQTREO1FBQzVELE1BQU0sUUFBUSxHQUFHLElBQUksR0FBRyxFQUErQixDQUFDO1FBQ3hELEtBQUssTUFBTSxLQUFLLElBQUksSUFBSSxDQUFDLFlBQVksQ0FBQyxtQkFBbUIsQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLEVBQUUsQ0FBQztZQUMxRSxRQUFRLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxRQUFRLEVBQUUsS0FBSyxDQUFDLENBQUM7UUFDdEMsQ0FBQztRQUNELEtBQUssTUFBTSxLQUFLLElBQUksSUFBSSxDQUFDLFVBQVUsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDO1lBQzNDLFFBQVEsQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLFFBQVEsRUFBRSxLQUFLLENBQUMsQ0FBQztRQUN0QyxDQUFDO1FBRUQsT0FBTyxJQUFJLENBQUMsV0FBVzthQUNwQixhQUFhLENBQUMsSUFBSSxDQUFDLFFBQVEsRUFBRSxJQUFJLENBQUMsU0FBUyxDQUFDLEVBQUUsRUFBRSxDQUFDLEdBQUcsUUFBUSxDQUFDLE1BQU0sRUFBRSxDQUFDLEVBQUUsS0FBSyxDQUFDO2FBQzlFLElBQUksQ0FDSCxHQUFHLENBQUMsQ0FBQyxJQUFtQixFQUFFLEVBQUUsQ0FBQyxDQUFDO1lBQzVCLElBQUksRUFBRSxJQUFJLENBQUMsSUFBSSxJQUFJLEVBQUU7WUFDckIsTUFBTSxFQUFFO2dCQUNOLEtBQUssRUFBRSxJQUFJLENBQUMsTUFBTSxFQUFFLFFBQVEsSUFBSSxLQUFLLENBQUMsUUFBUTtnQkFDOUMsT0FBTyxFQUFFLElBQUksQ0FBQyxNQUFNLEVBQUUsS0FBSyxJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksRUFBRSxNQUFNLElBQUksQ0FBQyxDQUFDO2dCQUN2RCxJQUFJLEVBQUUsSUFBSSxDQUFDLE1BQU0sRUFBRSxJQUFJLElBQUksS0FBSyxDQUFDLElBQUk7YUFDdEM7U0FDRixDQUFDLENBQUMsQ0FDSixDQUFDO0lBQ04sQ0FBQztJQUVELDBFQUEwRTtJQUMxRSxtQ0FBbUM7SUFDM0IsVUFBVSxDQUFDLEtBQVU7UUFDM0IsTUFBTSxNQUFNLEdBQTBCLEVBQUUsQ0FBQztRQUV6QyxLQUFLLE1BQU0sTUFBTSxJQUFJLElBQUksQ0FBQyxXQUFXLEVBQUUsRUFBRSxDQUFDO1lBQ3hDLE1BQU0sS0FBSyxHQUFHLElBQUksQ0FBQyxNQUFNLEVBQUUsR0FBRyxDQUFDLE1BQU0sQ0FBQyxhQUFhLENBQUMsQ0FBQztZQUNyRCxNQUFNLElBQUksR0FBRyxJQUFJLE1BQU0sQ0FBQyxFQUFFLEVBQUUsQ0FBQztZQUU3QixJQUFJLEtBQUssRUFBRSxJQUFJLEtBQUssV0FBVyxFQUFFLENBQUM7Z0JBQ2hDLE1BQU0sSUFBSSxHQUFHLGVBQWUsQ0FBQyxLQUFLLENBQUMsR0FBRyxJQUFJLE1BQU0sQ0FBQyxDQUFDLENBQUM7Z0JBQ25ELE1BQU0sRUFBRSxHQUFHLGVBQWUsQ0FBQyxLQUFLLENBQUMsR0FBRyxJQUFJLElBQUksQ0FBQyxDQUFDLENBQUM7Z0JBQy9DLElBQUksSUFBSSxJQUFJLEVBQUUsRUFBRSxDQUFDO29CQUNmLE1BQU0sQ0FBQyxJQUFJLENBQUMsRUFBRSxRQUFRLEVBQUUsTUFBTSxDQUFDLEVBQUUsRUFBRSxLQUFLLEVBQUUsSUFBSSxFQUFFLEdBQUcsRUFBRSxFQUFFLEVBQUUsQ0FBQyxDQUFDO2dCQUM3RCxDQUFDO1lBQ0gsQ0FBQztpQkFBTSxJQUFJLEtBQUssRUFBRSxJQUFJLEtBQUssUUFBUSxFQUFFLENBQUM7Z0JBQ3BDLHNFQUFzRTtnQkFDdEUsMEVBQTBFO2dCQUMxRSxNQUFNLFFBQVEsR0FBRyxLQUFLLENBQUMsSUFBSSxDQUFDLENBQUM7Z0JBQzdCLE1BQU0sY0FBYyxHQUFHLEtBQUssQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDO29CQUM1QyxDQUFDLENBQUMsUUFBUTtvQkFDVixDQUFDLENBQUMsQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDO2dCQUNsRCxJQUFJLGNBQWMsQ0FBQyxNQUFNLEVBQUUsQ0FBQztvQkFDMUIsTUFBTSxDQUFDLElBQUksQ0FBQyxFQUFFLFFBQVEsRUFBRSxNQUFNLENBQUMsRUFBRSxFQUFFLE1BQU0sRUFBRSxjQUFjLEVBQUUsQ0FBQyxDQUFDO2dCQUMvRCxDQUFDO1lBQ0gsQ0FBQztpQkFBTSxDQUFDO2dCQUNOLE1BQU0sT0FBTyxHQUFHLE1BQU0sQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDLENBQUMsSUFBSSxFQUFFLENBQUM7Z0JBQ2pELElBQUksT0FBTyxFQUFFLENBQUM7b0JBQ1osTUFBTSxDQUFDLElBQUksQ0FBQyxFQUFFLFFBQVEsRUFBRSxNQUFNLENBQUMsRUFBRSxFQUFFLEtBQUssRUFBRSxPQUFPLEVBQUUsQ0FBQyxDQUFDO2dCQUN2RCxDQUFDO1lBQ0gsQ0FBQztRQUNILENBQUM7UUFFRCxPQUFPLE1BQU0sQ0FBQztJQUNoQixDQUFDO3dHQXRLVSxzQkFBc0I7NEZBQXRCLHNCQUFzQixnTkFNdEIsZUFBZSxnREM3QzVCLGlnQkFrQkEsZ0hEaUJJLFFBQVEsNENBQ1IsWUFBWTs7NEZBR0gsc0JBQXNCO2tCQVhsQyxTQUFTOytCQUNFLDJCQUEyQixtQkFHcEIsdUJBQXVCLENBQUMsTUFBTSxjQUNuQyxJQUFJLFdBQ1A7d0JBQ1AsUUFBUTt3QkFDUixZQUFZO3FCQUNiOzhCQUllLFFBQVE7c0JBQXZCLEtBQUs7Z0JBQ1UsU0FBUztzQkFBeEIsS0FBSztnQkFDVSxNQUFNO3NCQUFyQixLQUFLO2dCQUdDLGFBQWE7c0JBRG5CLFNBQVM7dUJBQUMsZUFBZSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENoYW5nZURldGVjdGlvblN0cmF0ZWd5LCBDb21wb25lbnQsIERlc3Ryb3lSZWYsIElucHV0LCBPbkluaXQsIFZpZXdDaGlsZCwgaW5qZWN0IH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyB0YWtlVW50aWxEZXN0cm95ZWQgfSBmcm9tICdAYW5ndWxhci9jb3JlL3J4anMtaW50ZXJvcCc7XG5pbXBvcnQgeyBEYXRlUGlwZSB9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbic7XG5cbmltcG9ydCB7IEl0ZW1UeXBlIH0gZnJvbSAnQGZpcmVzdGl0Y2gvZmlsdGVyJztcbmltcG9ydCB7IEZzTGlzdENvbXBvbmVudCwgRnNMaXN0Q29uZmlnLCBGc0xpc3RNb2R1bGUsIFBhZ2luYXRpb25TdHJhdGVneSB9IGZyb20gJ0BmaXJlc3RpdGNoL2xpc3QnO1xuXG5pbXBvcnQgeyBPYnNlcnZhYmxlLCBtYXAgfSBmcm9tICdyeGpzJztcblxuaW1wb3J0IHsgUmVwb3J0RGF0YSB9IGZyb20gJy4uLy4uL2RhdGEvcmVwb3J0LmRhdGEnO1xuaW1wb3J0IHtcbiAgQ29tcG9uZW50RGF0YSxcbiAgQ29tcG9uZW50RGF0YVN0YXRlLFxuICBMaXN0Q29uZmlnLFxuICBSZXBvcnRDb21wb25lbnQsXG4gIFJlcG9ydEZpbHRlcixcbiAgUmVwb3J0RmlsdGVyR3JvdXAsXG4gIFJlc29sdmVkRmlsdGVyVmFsdWUsXG59IGZyb20gJy4uLy4uL2ludGVyZmFjZXMvcmVwb3J0LmludGVyZmFjZSc7XG5pbXBvcnQgeyBkYXRlQm91bmRTdHJpbmcgfSBmcm9tICcuLi8uLi9yZXBvcnQtZmlsdGVyLWl0ZW1zJztcbmltcG9ydCB7IFJlcG9ydEZpbHRlclN0YXRlU2VydmljZSB9IGZyb20gJy4uLy4uL3NlcnZpY2VzL3JlcG9ydC1maWx0ZXItc3RhdGUuc2VydmljZSc7XG5cblxuLy8gQSBsaXN0IGNvbXBvbmVudDogRnNMaXN0ICsgRnNGaWx0ZXIgcmVuZGVyZWQgZnJvbSB0aGUgY29tcG9uZW50J3MgY29uZmlnIGFuZFxuLy8gaXRzIHJlcG9ydF9maWx0ZXJzIHJvd3MuIFRoZSBjb21wb25lbnQncyBvd24gZmlsdGVyIGJhciBjYXJyaWVzIGl0cyBmaWx0ZXJzXG4vLyB3aG9zZSBncm91cCByZW5kZXJzIGF0IHRoZSBjb21wb25lbnQgbGV2ZWw7IHJlcG9ydC1sZXZlbCBncm91cHMgYXBwbHlcbi8vIHRocm91Z2ggdGhlIHNoYXJlZCBmaWx0ZXItc3RhdGUgc2VydmljZSBhbmQgbWVyZ2UgaW50byBldmVyeSByZXF1ZXN0LlxuLy8gUGFnaW5nIGFuZCBzb3J0aW5nIGFyZSBwdXNoZWQgaW50byB0aGUgU1FMIHdyYXAgc2VydmVyLXNpZGUuXG5AQ29tcG9uZW50KHtcbiAgc2VsZWN0b3I6ICdhcHAtcmVwb3J0LWNvbXBvbmVudC1saXN0JyxcbiAgdGVtcGxhdGVVcmw6ICcuL2NvbXBvbmVudC1saXN0LmNvbXBvbmVudC5odG1sJyxcbiAgc3R5bGVVcmxzOiBbJy4vY29tcG9uZW50LWxpc3QuY29tcG9uZW50LnNjc3MnXSxcbiAgY2hhbmdlRGV0ZWN0aW9uOiBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneS5PblB1c2gsXG4gIHN0YW5kYWxvbmU6IHRydWUsXG4gIGltcG9ydHM6IFtcbiAgICBEYXRlUGlwZSxcbiAgICBGc0xpc3RNb2R1bGUsXG4gIF0sXG59KVxuZXhwb3J0IGNsYXNzIENvbXBvbmVudExpc3RDb21wb25lbnQgaW1wbGVtZW50cyBPbkluaXQge1xuXG4gIEBJbnB1dCgpIHB1YmxpYyByZXBvcnRJZDogbnVtYmVyO1xuICBASW5wdXQoKSBwdWJsaWMgY29tcG9uZW50OiBSZXBvcnRDb21wb25lbnQ7XG4gIEBJbnB1dCgpIHB1YmxpYyBncm91cHM6IE1hcDxudW1iZXIsIFJlcG9ydEZpbHRlckdyb3VwPjtcblxuICBAVmlld0NoaWxkKEZzTGlzdENvbXBvbmVudClcbiAgcHVibGljIGxpc3RDb21wb25lbnQ6IEZzTGlzdENvbXBvbmVudDtcblxuICBwdWJsaWMgbGlzdENvbmZpZzogRnNMaXN0Q29uZmlnO1xuICBwdWJsaWMgY29sdW1uczogeyBjb2x1bW46IHN0cmluZzsgbGFiZWw/OiBzdHJpbmc7IGZvcm1hdD86IHN0cmluZyB9W10gPSBbXTtcblxuICBwcml2YXRlIF9yZXBvcnREYXRhID0gaW5qZWN0KFJlcG9ydERhdGEpO1xuICBwcml2YXRlIF9maWx0ZXJTdGF0ZSA9IGluamVjdChSZXBvcnRGaWx0ZXJTdGF0ZVNlcnZpY2UpO1xuICBwcml2YXRlIF9kZXN0cm95UmVmID0gaW5qZWN0KERlc3Ryb3lSZWYpO1xuXG4gIHB1YmxpYyBuZ09uSW5pdCgpOiB2b2lkIHtcbiAgICBjb25zdCBjb25maWcgPSAodGhpcy5jb21wb25lbnQuY29uZmlnID8/IHt9KSBhcyBMaXN0Q29uZmlnO1xuICAgIHRoaXMuY29sdW1ucyA9IGNvbmZpZy5jb2x1bW5zID8/IFtdO1xuXG4gICAgdGhpcy5faW5pdExpc3RDb25maWcoY29uZmlnKTtcblxuICAgIC8vIFJlcG9ydC1sZXZlbCBmaWx0ZXIgY2hhbmdlcyB0aGF0IHNjb3BlIHRoaXMgY29tcG9uZW50IHJlLXJ1biB0aGUgbGlzdC5cbiAgICB0aGlzLl9maWx0ZXJTdGF0ZS5jaGFuZ2VzRm9yKHRoaXMuY29tcG9uZW50KVxuICAgICAgLnBpcGUodGFrZVVudGlsRGVzdHJveWVkKHRoaXMuX2Rlc3Ryb3lSZWYpKVxuICAgICAgLnN1YnNjcmliZSgoKSA9PiB0aGlzLmxpc3RDb21wb25lbnQ/LnJlbG9hZCgpKTtcbiAgfVxuXG4gIHByaXZhdGUgX2luaXRMaXN0Q29uZmlnKGNvbmZpZzogTGlzdENvbmZpZyk6IHZvaWQge1xuICAgIHRoaXMubGlzdENvbmZpZyA9IHtcbiAgICAgIC8vIEluc2lkZSBhIHJlcG9ydCBjb21wb25lbnQgdGhlIGxpc3QgaXMgYSBjbGVhbiBkYXRhIHBhbmUg4oCUIG5vIHN0YXR1c1xuICAgICAgLy8gYmFyLCBubyByZWxvYWQgYnV0dG9uIChmaWx0ZXIgY2hhbmdlcyBhbHJlYWR5IHJlZmV0Y2gpLlxuICAgICAgc3RhdHVzOiBmYWxzZSxcbiAgICAgIHJlbG9hZDogZmFsc2UsXG4gICAgICAvLyBOZXZlciB0b3VjaCB0aGUgVVJMIG9yIHBlcnNpc3QgZmlsdGVyL3BhZ2luZyBzdGF0ZSDigJQgcmVwb3J0IGZpbHRlcmluZ1xuICAgICAgLy8gaXMgc2Vzc2lvbi1vbmx5LlxuICAgICAgcXVlcnlQYXJhbTogZmFsc2UsXG4gICAgICBwZXJzaXN0OiBmYWxzZSxcbiAgICAgIHNvcnQ6IGNvbmZpZy5zb3J0XG4gICAgICAgID8geyB2YWx1ZTogY29uZmlnLnNvcnQuY29sdW1uLCBkaXJlY3Rpb246IGNvbmZpZy5zb3J0LmRpcmVjdGlvbiA/PyAnYXNjJyB9XG4gICAgICAgIDogdW5kZWZpbmVkLFxuICAgICAgcGFnaW5nOiB7XG4gICAgICAgIGxpbWl0OiBjb25maWcucGFnZVNpemUgPz8gMjUsXG4gICAgICAgIHN0cmF0ZWd5OiBQYWdpbmF0aW9uU3RyYXRlZ3kuUGFnZSxcbiAgICAgIH0sXG4gICAgICBmaWx0ZXJzOiB0aGlzLl9vd25GaWx0ZXJzKCkubWFwKChmaWx0ZXIpID0+IHRoaXMuX2ZpbHRlckl0ZW0oZmlsdGVyKSksXG4gICAgICBmZXRjaDogKHF1ZXJ5OiBhbnkpID0+IHRoaXMuX2ZldGNoKHF1ZXJ5KSxcbiAgICB9O1xuICB9XG5cbiAgLy8gVGhlIGZpbHRlcnMgdGhpcyBsaXN0IHJlbmRlcnMgaW4gaXRzIG93biBiYXI6IGl0cyByZXBvcnRfZmlsdGVycyB3aG9zZVxuICAvLyBncm91cCBpcyBjb21wb25lbnQtbGV2ZWwuIFJlcG9ydC1sZXZlbCBncm91cHMgcmVuZGVyIGluIHRoZSByZXBvcnQgYmFyLlxuICBwcml2YXRlIF9vd25GaWx0ZXJzKCk6IFJlcG9ydEZpbHRlcltdIHtcbiAgICByZXR1cm4gKHRoaXMuY29tcG9uZW50LmZpbHRlcnMgPz8gW10pXG4gICAgICAuZmlsdGVyKChmaWx0ZXIpID0+IHtcbiAgICAgICAgY29uc3QgZ3JvdXAgPSB0aGlzLmdyb3Vwcz8uZ2V0KGZpbHRlci5maWx0ZXJHcm91cElkKTtcblxuICAgICAgICByZXR1cm4gZmlsdGVyLmVuYWJsZWQgJiYgKCFncm91cCB8fCBncm91cC5sZXZlbCA9PT0gJ2NvbXBvbmVudCcgfHwgZ3JvdXAubGV2ZWwgPT09ICdib3RoJyk7XG4gICAgICB9KTtcbiAgfVxuXG4gIHByaXZhdGUgX2ZpbHRlckl0ZW0oZmlsdGVyOiBSZXBvcnRGaWx0ZXIpOiBhbnkge1xuICAgIGNvbnN0IGdyb3VwID0gdGhpcy5ncm91cHM/LmdldChmaWx0ZXIuZmlsdGVyR3JvdXBJZCk7XG4gICAgY29uc3QgbmFtZSA9IGBmJHtmaWx0ZXIuaWR9YDtcbiAgICBjb25zdCBsYWJlbCA9IGZpbHRlci5sYWJlbCB8fCBncm91cD8ubGFiZWwgfHwgZmlsdGVyLmZpbHRlckNvbHVtbjtcblxuICAgIHN3aXRjaCAoZ3JvdXA/LnR5cGUpIHtcbiAgICAgIGNhc2UgJ2RhdGVSYW5nZSc6XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgbmFtZSxcbiAgICAgICAgICB0eXBlOiBJdGVtVHlwZS5EYXRlUmFuZ2UsXG4gICAgICAgICAgbGFiZWw6IFtgJHtsYWJlbH0gRnJvbWAsIGAke2xhYmVsfSBUb2BdLFxuICAgICAgICB9O1xuXG4gICAgICBjYXNlICdzZWxlY3QnOlxuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgIG5hbWUsXG4gICAgICAgICAgdHlwZTogSXRlbVR5cGUuQXV0b0NvbXBsZXRlQ2hpcHMsXG4gICAgICAgICAgbGFiZWwsXG4gICAgICAgICAgdmFsdWVzOiAoKSA9PiB0aGlzLl9yZXBvcnREYXRhLmZpbHRlck9wdGlvbnModGhpcy5yZXBvcnRJZCwgZmlsdGVyLmlkKVxuICAgICAgICAgICAgLnBpcGUoXG4gICAgICAgICAgICAgIG1hcCgob3B0aW9uczogdW5rbm93bltdKSA9PiAob3B0aW9ucyA/PyBbXSlcbiAgICAgICAgICAgICAgICAubWFwKChvcHRpb24pID0+ICh7IG5hbWU6IFN0cmluZyhvcHRpb24pLCB2YWx1ZTogb3B0aW9uIH0pKSksXG4gICAgICAgICAgICApLFxuICAgICAgICB9O1xuXG4gICAgICBjYXNlICdrZXl3b3JkJzpcbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgbmFtZSxcbiAgICAgICAgICB0eXBlOiBJdGVtVHlwZS5LZXl3b3JkLFxuICAgICAgICAgIGxhYmVsLFxuICAgICAgICB9O1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgX2ZldGNoKHF1ZXJ5OiBhbnkpOiBPYnNlcnZhYmxlPHsgZGF0YTogUmVjb3JkPHN0cmluZywgdW5rbm93bj5bXTsgcGFnaW5nOiBhbnkgfT4ge1xuICAgIGNvbnN0IHN0YXRlOiBDb21wb25lbnREYXRhU3RhdGUgPSB7XG4gICAgICBwYWdlOiBxdWVyeS5wYWdlID8/IDEsXG4gICAgICBwYWdlU2l6ZTogcXVlcnkubGltaXQgPz8gMjUsXG4gICAgfTtcblxuICAgIGNvbnN0IG9yZGVyID0gU3RyaW5nKHF1ZXJ5Lm9yZGVyID8/ICcnKTtcbiAgICBpZiAob3JkZXIpIHtcbiAgICAgIGNvbnN0IFtjb2x1bW4sIGRpcmVjdGlvbl0gPSBvcmRlci5zcGxpdCgnLCcpO1xuICAgICAgc3RhdGUuc29ydCA9IHsgY29sdW1uLCBkaXJlY3Rpb246IGRpcmVjdGlvbiA9PT0gJ2Rlc2MnID8gJ2Rlc2MnIDogJ2FzYycgfTtcbiAgICB9XG5cbiAgICAvLyBSZXBvcnQtbGV2ZWwgdmFsdWVzIGZyb20gdGhlIHNoYXJlZCBzZXNzaW9uIHN0YXRlLCBtZXJnZWQgd2l0aCB0aGlzXG4gICAgLy8gbGlzdCdzIG93biBmaWx0ZXItYmFyIHZhbHVlcyAob3duIHZhbHVlcyB3aW4gcGVyIGZpbHRlcikuXG4gICAgY29uc3QgcmVzb2x2ZWQgPSBuZXcgTWFwPG51bWJlciwgUmVzb2x2ZWRGaWx0ZXJWYWx1ZT4oKTtcbiAgICBmb3IgKGNvbnN0IHZhbHVlIG9mIHRoaXMuX2ZpbHRlclN0YXRlLnJlc29sdmVGb3JDb21wb25lbnQodGhpcy5jb21wb25lbnQpKSB7XG4gICAgICByZXNvbHZlZC5zZXQodmFsdWUuZmlsdGVySWQsIHZhbHVlKTtcbiAgICB9XG4gICAgZm9yIChjb25zdCB2YWx1ZSBvZiB0aGlzLl9iYXJWYWx1ZXMocXVlcnkpKSB7XG4gICAgICByZXNvbHZlZC5zZXQodmFsdWUuZmlsdGVySWQsIHZhbHVlKTtcbiAgICB9XG5cbiAgICByZXR1cm4gdGhpcy5fcmVwb3J0RGF0YVxuICAgICAgLmNvbXBvbmVudERhdGEodGhpcy5yZXBvcnRJZCwgdGhpcy5jb21wb25lbnQuaWQsIFsuLi5yZXNvbHZlZC52YWx1ZXMoKV0sIHN0YXRlKVxuICAgICAgLnBpcGUoXG4gICAgICAgIG1hcCgoZGF0YTogQ29tcG9uZW50RGF0YSkgPT4gKHtcbiAgICAgICAgICBkYXRhOiBkYXRhLnJvd3MgPz8gW10sXG4gICAgICAgICAgcGFnaW5nOiB7XG4gICAgICAgICAgICBsaW1pdDogZGF0YS5wYWdpbmc/LnBhZ2VTaXplID8/IHN0YXRlLnBhZ2VTaXplLFxuICAgICAgICAgICAgcmVjb3JkczogZGF0YS5wYWdpbmc/LnRvdGFsID8/IChkYXRhLnJvd3M/Lmxlbmd0aCA/PyAwKSxcbiAgICAgICAgICAgIHBhZ2U6IGRhdGEucGFnaW5nPy5wYWdlID8/IHN0YXRlLnBhZ2UsXG4gICAgICAgICAgfSxcbiAgICAgICAgfSkpLFxuICAgICAgKTtcbiAgfVxuXG4gIC8vIFRoZSBsaXN0J3Mgb3duIEZzRmlsdGVyIHZhbHVlcywgcmVhZCBiYWNrIG91dCBvZiB0aGUgZmV0Y2ggcXVlcnkgYnkgdGhlXG4gIC8vIGBmPGZpbHRlcklkPmAgbmFtaW5nIGNvbnZlbnRpb24uXG4gIHByaXZhdGUgX2JhclZhbHVlcyhxdWVyeTogYW55KTogUmVzb2x2ZWRGaWx0ZXJWYWx1ZVtdIHtcbiAgICBjb25zdCB2YWx1ZXM6IFJlc29sdmVkRmlsdGVyVmFsdWVbXSA9IFtdO1xuXG4gICAgZm9yIChjb25zdCBmaWx0ZXIgb2YgdGhpcy5fb3duRmlsdGVycygpKSB7XG4gICAgICBjb25zdCBncm91cCA9IHRoaXMuZ3JvdXBzPy5nZXQoZmlsdGVyLmZpbHRlckdyb3VwSWQpO1xuICAgICAgY29uc3QgbmFtZSA9IGBmJHtmaWx0ZXIuaWR9YDtcblxuICAgICAgaWYgKGdyb3VwPy50eXBlID09PSAnZGF0ZVJhbmdlJykge1xuICAgICAgICBjb25zdCBmcm9tID0gZGF0ZUJvdW5kU3RyaW5nKHF1ZXJ5W2Ake25hbWV9RnJvbWBdKTtcbiAgICAgICAgY29uc3QgdG8gPSBkYXRlQm91bmRTdHJpbmcocXVlcnlbYCR7bmFtZX1Ub2BdKTtcbiAgICAgICAgaWYgKGZyb20gfHwgdG8pIHtcbiAgICAgICAgICB2YWx1ZXMucHVzaCh7IGZpbHRlcklkOiBmaWx0ZXIuaWQsIHN0YXJ0OiBmcm9tLCBlbmQ6IHRvIH0pO1xuICAgICAgICB9XG4gICAgICB9IGVsc2UgaWYgKGdyb3VwPy50eXBlID09PSAnc2VsZWN0Jykge1xuICAgICAgICAvLyBmcy1maWx0ZXIgam9pbnMgYSBtdWx0aS1zZWxlY3QgaW50byBvbmUgXCJhLGJcIiBzdHJpbmc7IHNwbGl0IGl0IGJhY2tcbiAgICAgICAgLy8gc28gZWFjaCB2YWx1ZSBiaW5kcyBzZXBhcmF0ZWx5IChlbHNlIGBjb2wgSU4gKCdhLGInKWAgbWF0Y2hlcyBub3RoaW5nKS5cbiAgICAgICAgY29uc3Qgc2VsZWN0ZWQgPSBxdWVyeVtuYW1lXTtcbiAgICAgICAgY29uc3Qgc2VsZWN0ZWRWYWx1ZXMgPSBBcnJheS5pc0FycmF5KHNlbGVjdGVkKVxuICAgICAgICAgID8gc2VsZWN0ZWRcbiAgICAgICAgICA6IChzZWxlY3RlZCA/IFN0cmluZyhzZWxlY3RlZCkuc3BsaXQoJywnKSA6IFtdKTtcbiAgICAgICAgaWYgKHNlbGVjdGVkVmFsdWVzLmxlbmd0aCkge1xuICAgICAgICAgIHZhbHVlcy5wdXNoKHsgZmlsdGVySWQ6IGZpbHRlci5pZCwgdmFsdWVzOiBzZWxlY3RlZFZhbHVlcyB9KTtcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgY29uc3Qga2V5d29yZCA9IFN0cmluZyhxdWVyeVtuYW1lXSA/PyAnJykudHJpbSgpO1xuICAgICAgICBpZiAoa2V5d29yZCkge1xuICAgICAgICAgIHZhbHVlcy5wdXNoKHsgZmlsdGVySWQ6IGZpbHRlci5pZCwgdmFsdWU6IGtleXdvcmQgfSk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gdmFsdWVzO1xuICB9XG59XG4iLCI8ZnMtbGlzdCBbY29uZmlnXT1cImxpc3RDb25maWdcIj5cbiAgQGZvciAoY29sdW1uIG9mIGNvbHVtbnM7IHRyYWNrIGNvbHVtbi5jb2x1bW4pIHtcbiAgICA8ZnMtbGlzdC1jb2x1bW5cbiAgICAgIFtuYW1lXT1cImNvbHVtbi5jb2x1bW5cIlxuICAgICAgW3RpdGxlXT1cImNvbHVtbi5sYWJlbCB8fCBjb2x1bW4uY29sdW1uXCJcbiAgICAgIFtzb3J0YWJsZV09XCJ0cnVlXCI+XG4gICAgICA8bmctdGVtcGxhdGVcbiAgICAgICAgZnMtbGlzdC1jZWxsXG4gICAgICAgIGxldC1yb3c9XCJyb3dcIj5cbiAgICAgICAgQGlmIChjb2x1bW4uZm9ybWF0ID09PSAnZGF0ZScpIHtcbiAgICAgICAgICB7eyByb3dbY29sdW1uLmNvbHVtbl0gfCBkYXRlOiAnbWVkaXVtRGF0ZScgfX1cbiAgICAgICAgfSBAZWxzZSB7XG4gICAgICAgICAge3sgcm93W2NvbHVtbi5jb2x1bW5dIH19XG4gICAgICAgIH1cbiAgICAgIDwvbmctdGVtcGxhdGU+XG4gICAgPC9mcy1saXN0LWNvbHVtbj5cbiAgfVxuPC9mcy1saXN0PlxuIl19
|