@ogidor/dashboard 1.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/README.md ADDED
@@ -0,0 +1,103 @@
1
+ # @ogidor/dashboard
2
+
3
+ A professional, high-performance financial dashboard for Angular. Highly customizable, themeable via CSS variables, and powered by `angular-gridster2` and `ApexCharts`.
4
+
5
+ ## Features
6
+
7
+ - **Drag & Drop Layout:** Responsive grid system using `angular-gridster2`.
8
+ - **Interactive Charts:** Beautiful Line, Bar, and Donut charts via `ng-apexcharts`.
9
+ - **Multi-Workspace Support:** Manage multiple dashboard pages (workspaces).
10
+ - **Deeply Themeable:** Customize every color and font using simple CSS variables or a configuration object.
11
+ - **Standalone Ready:** Sidebar removed for easy integration into your own application's navigation.
12
+
13
+ ## Installation
14
+
15
+ ```bash
16
+ npm install @ogidor/dashboard angular-gridster2 apexcharts ng-apexcharts line-awesome
17
+ ```
18
+
19
+ Ensure you have `line-awesome` icons included in your global styles (e.g., `angular.json` or `styles.scss`):
20
+
21
+ ```scss
22
+ @import "line-awesome/dist/line-awesome/css/line-awesome.css";
23
+ ```
24
+
25
+ ## Usage
26
+
27
+ Import the `DashboardModule` in your `AppModule`:
28
+
29
+ ```typescript
30
+ import { DashboardModule } from '@ogidor/dashboard';
31
+
32
+ @NgModule({
33
+ imports: [
34
+ DashboardModule,
35
+ // ...
36
+ ]
37
+ })
38
+ export class AppModule { }
39
+ ```
40
+
41
+ Use the component in your template:
42
+
43
+ ```html
44
+ <app-dashboard
45
+ [initialLayout]="savedLayout"
46
+ [theme]="myCustomTheme"
47
+ ></app-dashboard>
48
+ ```
49
+
50
+ ## API Reference
51
+
52
+ ### Inputs
53
+
54
+ | Input | Type | Description |
55
+ |---|---|---|
56
+ | `initialLayout` | `string` | A JSON string representing a previously exported layout. |
57
+ | `theme` | `DashboardTheme` | An object to override default colors and fonts programmatically. |
58
+
59
+ ### DashboardTheme Interface
60
+
61
+ ```typescript
62
+ export interface DashboardTheme {
63
+ backgroundColor?: string;
64
+ panelColor?: string;
65
+ widgetCardColor?: string;
66
+ chartForeColor?: string;
67
+ accentColor?: string;
68
+ dangerColor?: string;
69
+ chartColors?: string[];
70
+ fontFamily?: string;
71
+ }
72
+ ```
73
+
74
+ ## Customization (Theming)
75
+
76
+ You can customize the dashboard's look and feel by overriding the following CSS variables in your global stylesheet:
77
+
78
+ ```css
79
+ :root {
80
+ --dash-bg: #000000; /* Overall background */
81
+ --dash-panel-bg: #1c1c1e; /* Main content panel */
82
+ --dash-card-bg: #2c2c2e; /* Widget card background */
83
+ --dash-fore-color: #8e8e93; /* Primary text/chart labels */
84
+ --dash-accent-color: #0a84ff; /* Action buttons & active states */
85
+ --dash-danger-color: #ff453a; /* Delete/Close actions */
86
+ --dash-font-family: 'Inter', sans-serif;
87
+ }
88
+ ```
89
+
90
+ ## Methods (Public API)
91
+
92
+ Access the dashboard instance via `@ViewChild` to trigger actions:
93
+
94
+ ```typescript
95
+ @ViewChild(DashboardComponent) dashboard!: DashboardComponent;
96
+
97
+ // Export the current layout as a JSON string
98
+ const layout = this.dashboard.serializeLayout();
99
+ ```
100
+
101
+ ## License
102
+
103
+ MIT
@@ -0,0 +1,22 @@
1
+ import * as i0 from "@angular/core";
2
+ import * as i1 from "./dashboard.component";
3
+ import * as i2 from "./widget-renderer.component";
4
+ import * as i3 from "@angular/common";
5
+ import * as i4 from "@angular/forms";
6
+ import * as i5 from "angular-gridster2";
7
+ import * as i6 from "ng-apexcharts";
8
+ import * as i7 from "@angular/platform-browser";
9
+ export declare class DashboardModule {
10
+ static ɵfac: i0.ɵɵFactoryDeclaration<DashboardModule, never>;
11
+ static ɵmod: i0.ɵɵNgModuleDeclaration<DashboardModule, [typeof i1.DashboardComponent, typeof i2.WidgetRendererComponent], [typeof i3.CommonModule, typeof i4.FormsModule, typeof i5.GridsterModule, typeof i6.NgApexchartsModule], [typeof i1.DashboardComponent, typeof i2.WidgetRendererComponent]>;
12
+ static ɵinj: i0.ɵɵInjectorDeclaration<DashboardModule>;
13
+ }
14
+ /**
15
+ * Root module for local demo / testing purposes.
16
+ * In the final NPM package, users would only import the `DashboardModule`.
17
+ */
18
+ export declare class AppModule {
19
+ static ɵfac: i0.ɵɵFactoryDeclaration<AppModule, never>;
20
+ static ɵmod: i0.ɵɵNgModuleDeclaration<AppModule, never, [typeof i7.BrowserModule, typeof DashboardModule], never>;
21
+ static ɵinj: i0.ɵɵInjectorDeclaration<AppModule>;
22
+ }
@@ -0,0 +1,49 @@
1
+ import { Page, WidgetType, LineBarData, DonutData } from './models';
2
+ import * as i0 from "@angular/core";
3
+ export declare class DashboardStateService {
4
+ private readonly STORAGE_KEY;
5
+ private initialPages;
6
+ private pagesSubject;
7
+ private activePageIdSubject;
8
+ /**
9
+ * Emits whenever a widget's data is updated programmatically.
10
+ * Key = widget id, value = new data payload.
11
+ */
12
+ private widgetDataSubject;
13
+ widgetData$: import("rxjs").Observable<{
14
+ widgetId: string;
15
+ data: LineBarData | DonutData;
16
+ }>;
17
+ pages$: import("rxjs").Observable<Page[]>;
18
+ activePageId$: import("rxjs").Observable<string>;
19
+ constructor();
20
+ getActivePage(): Page | undefined;
21
+ setActivePage(id: string): void;
22
+ addPage(name: string): void;
23
+ removePage(id: string): void;
24
+ addWidget(type: WidgetType): void;
25
+ addWidgetWithData(type: WidgetType, title: string, data: LineBarData | DonutData): void;
26
+ private getDefaultDataForType;
27
+ updateWidgetPosition(pageId: string, widgetId: string, x: number, y: number, cols: number, rows: number): void;
28
+ removeWidget(widgetId: string): void;
29
+ /**
30
+ * Push new data into a widget by its id.
31
+ * The widget's chart will re-render immediately.
32
+ *
33
+ * @param widgetId The `id` of the target widget.
34
+ * @param data New data — `LineBarData` for LINE/BAR, `DonutData` for DONUT.
35
+ */
36
+ updateWidgetData(widgetId: string, data: LineBarData | DonutData): void;
37
+ updateWidgetMeta(widgetId: string, meta: {
38
+ title?: string;
39
+ colors?: string[];
40
+ cardColor?: string;
41
+ data?: LineBarData | DonutData;
42
+ }): void;
43
+ private updatePages;
44
+ serializeLayout(): string;
45
+ loadLayout(config: any): void;
46
+ private saveToLocalStorage;
47
+ static ɵfac: i0.ɵɵFactoryDeclaration<DashboardStateService, never>;
48
+ static ɵprov: i0.ɵɵInjectableDeclaration<DashboardStateService>;
49
+ }
@@ -0,0 +1,80 @@
1
+ import { OnInit, OnDestroy, OnChanges, SimpleChanges } from '@angular/core';
2
+ import { GridsterConfig } from 'angular-gridster2';
3
+ import { DashboardStateService } from './dashboard-state.service';
4
+ import { Page, Widget, WidgetType, DashboardTheme, LineBarData, DonutData } from './models';
5
+ import * as i0 from "@angular/core";
6
+ export declare class DashboardComponent implements OnInit, OnDestroy, OnChanges {
7
+ private stateService;
8
+ initialLayout?: string;
9
+ theme?: DashboardTheme;
10
+ resolvedTheme: Required<DashboardTheme>;
11
+ wrapperStyles: Record<string, string>;
12
+ options: GridsterConfig;
13
+ pages: Page[];
14
+ activePageId: string;
15
+ activePage?: Page;
16
+ dialogOpen: boolean;
17
+ dialogType: WidgetType;
18
+ dialogTitle: string;
19
+ dialogCategories: string;
20
+ dialogSeries: {
21
+ name: string;
22
+ dataRaw: string;
23
+ }[];
24
+ dialogSlices: {
25
+ label: string;
26
+ value: number | null;
27
+ }[];
28
+ readonly widgetTypes: {
29
+ value: WidgetType;
30
+ label: string;
31
+ icon: string;
32
+ }[];
33
+ private subs;
34
+ constructor(stateService: DashboardStateService);
35
+ ngOnChanges(changes: SimpleChanges): void;
36
+ ngOnInit(): void;
37
+ ngOnDestroy(): void;
38
+ private applyTheme;
39
+ private updateActivePage;
40
+ onSelectPage(id: string): void;
41
+ onAddPage(): void;
42
+ onRemovePage(event: Event, id: string): void;
43
+ openDialog(): void;
44
+ closeDialog(): void;
45
+ addSeries(): void;
46
+ removeSeries(i: number): void;
47
+ addSlice(): void;
48
+ removeSlice(i: number): void;
49
+ confirmAddWidget(): void;
50
+ editDialogOpen: boolean;
51
+ editingWidget?: Widget;
52
+ editWidgetType: WidgetType;
53
+ editTitle: string;
54
+ editCardColor: string;
55
+ editColors: string[];
56
+ editSeries: {
57
+ name: string;
58
+ dataRaw: string;
59
+ }[];
60
+ editCategories: string;
61
+ editSlices: {
62
+ label: string;
63
+ value: number | null;
64
+ }[];
65
+ private readonly DEFAULT_COLORS;
66
+ openEditDialog(widget: Widget): void;
67
+ closeEditDialog(): void;
68
+ getEditSeriesLabel(i: number): string;
69
+ addEditSeries(): void;
70
+ removeEditSeries(i: number): void;
71
+ addEditSlice(): void;
72
+ removeEditSlice(i: number): void;
73
+ confirmEditWidget(): void;
74
+ onAddWidget(type: WidgetType): void;
75
+ updateWidgetData(widgetId: string, data: LineBarData | DonutData): void;
76
+ removeWidgetHandler: (id: string) => void;
77
+ serializeLayout(): string;
78
+ static ɵfac: i0.ɵɵFactoryDeclaration<DashboardComponent, never>;
79
+ static ɵcmp: i0.ɵɵComponentDeclaration<DashboardComponent, "app-dashboard", never, { "initialLayout": "initialLayout"; "theme": "theme"; }, {}, never, never, false, never>;
80
+ }
@@ -0,0 +1,73 @@
1
+ export type WidgetType = 'DONUT' | 'LINE' | 'BAR';
2
+ /** A single named series for LINE and BAR charts */
3
+ export interface ChartSeries {
4
+ /** Label shown in the legend */
5
+ name: string;
6
+ /** Array of numeric data points */
7
+ data: number[];
8
+ /** Optional per-series x-axis category labels */
9
+ categories?: string[];
10
+ }
11
+ /** Data shape for LINE and BAR widgets */
12
+ export interface LineBarData {
13
+ /** One or more data series */
14
+ series: ChartSeries[];
15
+ /** X-axis category labels shared across all series */
16
+ categories?: string[];
17
+ }
18
+ /** Data shape for DONUT widgets */
19
+ export interface DonutData {
20
+ /** Numeric slice values — must match the length of `labels` */
21
+ series: number[];
22
+ /** Label for each slice */
23
+ labels?: string[];
24
+ }
25
+ export interface Widget {
26
+ id: string;
27
+ type: WidgetType;
28
+ x: number;
29
+ y: number;
30
+ cols: number;
31
+ rows: number;
32
+ /** Typed as LineBarData | DonutData depending on `type` */
33
+ data: LineBarData | DonutData;
34
+ title: string;
35
+ /** Optional per-widget series colors. Overrides the global theme chartColors. */
36
+ colors?: string[];
37
+ /** Optional per-widget card background color. Overrides the global theme widgetCardColor. */
38
+ cardColor?: string;
39
+ }
40
+ export interface Page {
41
+ id: string;
42
+ name: string;
43
+ widgets: Widget[];
44
+ }
45
+ export interface DashboardConfig {
46
+ pages: Page[];
47
+ activePageId: string;
48
+ }
49
+ /**
50
+ * Theme configuration for the dashboard.
51
+ * All properties are optional — any values not provided will fall back to defaults.
52
+ */
53
+ export interface DashboardTheme {
54
+ /** Background color of the overall dashboard wrapper. Default: `#000000` */
55
+ backgroundColor?: string;
56
+ /** Background color of the main content panel. Default: `#1c1c1e` */
57
+ panelColor?: string;
58
+ /** Background color of individual widget cards. Default: `#2c2c2e` */
59
+ widgetCardColor?: string;
60
+ /** Primary text / foreground color used inside charts. Default: `#8e8e93` */
61
+ chartForeColor?: string;
62
+ /** Primary accent color (active tabs, add-page button hover, etc.). Default: `#0a84ff` */
63
+ accentColor?: string;
64
+ /** Danger/close color used on the remove-widget button hover. Default: `#ff453a` */
65
+ dangerColor?: string;
66
+ /**
67
+ * Array of colors fed to ApexCharts series.
68
+ * Default: `['#0a84ff', '#30d158', '#ff9f0a', '#bf5af2', '#ff453a']`
69
+ */
70
+ chartColors?: string[];
71
+ /** Font family applied to the whole dashboard. Default: system-ui stack */
72
+ fontFamily?: string;
73
+ }
@@ -0,0 +1,40 @@
1
+ import { EventEmitter, OnInit, OnChanges, OnDestroy, SimpleChanges } from '@angular/core';
2
+ import { Widget, DashboardTheme } from './models';
3
+ import { DashboardStateService } from './dashboard-state.service';
4
+ import { ApexAxisChartSeries, ApexChart, ApexXAxis, ApexDataLabels, ApexStroke, ApexYAxis, ApexTitleSubtitle, ApexLegend, ApexPlotOptions, ApexTooltip, ApexTheme } from 'ng-apexcharts';
5
+ import * as i0 from "@angular/core";
6
+ export type ChartOptions = {
7
+ series: ApexAxisChartSeries | number[];
8
+ chart: ApexChart;
9
+ xaxis: ApexXAxis;
10
+ stroke: ApexStroke;
11
+ dataLabels: ApexDataLabels;
12
+ yaxis: ApexYAxis;
13
+ title: ApexTitleSubtitle;
14
+ labels: string[];
15
+ legend: ApexLegend;
16
+ plotOptions: ApexPlotOptions;
17
+ tooltip: ApexTooltip;
18
+ theme: ApexTheme;
19
+ colors: string[];
20
+ };
21
+ export declare class WidgetRendererComponent implements OnInit, OnChanges, OnDestroy {
22
+ private stateService;
23
+ widget: Widget;
24
+ onRemoveWidget: (id: string) => void;
25
+ theme?: Required<DashboardTheme>;
26
+ editRequested: EventEmitter<Widget>;
27
+ chartOptions: Partial<ChartOptions>;
28
+ cardStyles: Record<string, string>;
29
+ private subs;
30
+ constructor(stateService: DashboardStateService);
31
+ ngOnInit(): void;
32
+ ngOnChanges(changes: SimpleChanges): void;
33
+ ngOnDestroy(): void;
34
+ private applyStyles;
35
+ private resolvedColors;
36
+ private initChart;
37
+ onRemove(): void;
38
+ static ɵfac: i0.ɵɵFactoryDeclaration<WidgetRendererComponent, never>;
39
+ static ɵcmp: i0.ɵɵComponentDeclaration<WidgetRendererComponent, "app-widget-renderer", never, { "widget": "widget"; "onRemoveWidget": "onRemoveWidget"; "theme": "theme"; }, { "editRequested": "editRequested"; }, never, never, false, never>;
40
+ }
@@ -0,0 +1,64 @@
1
+ import { NgModule } from '@angular/core';
2
+ import { BrowserModule } from '@angular/platform-browser';
3
+ import { CommonModule } from '@angular/common';
4
+ import { FormsModule } from '@angular/forms';
5
+ import { GridsterModule } from 'angular-gridster2';
6
+ import { NgApexchartsModule } from 'ng-apexcharts';
7
+ import { DashboardComponent } from './dashboard.component';
8
+ import { WidgetRendererComponent } from './widget-renderer.component';
9
+ import { DashboardStateService } from './dashboard-state.service';
10
+ import * as i0 from "@angular/core";
11
+ export class DashboardModule {
12
+ }
13
+ DashboardModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: DashboardModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
14
+ DashboardModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.10", ngImport: i0, type: DashboardModule, declarations: [DashboardComponent,
15
+ WidgetRendererComponent], imports: [CommonModule,
16
+ FormsModule,
17
+ GridsterModule,
18
+ NgApexchartsModule], exports: [DashboardComponent,
19
+ WidgetRendererComponent] });
20
+ DashboardModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: DashboardModule, providers: [DashboardStateService], imports: [CommonModule,
21
+ FormsModule,
22
+ GridsterModule,
23
+ NgApexchartsModule] });
24
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: DashboardModule, decorators: [{
25
+ type: NgModule,
26
+ args: [{
27
+ declarations: [
28
+ DashboardComponent,
29
+ WidgetRendererComponent
30
+ ],
31
+ imports: [
32
+ CommonModule,
33
+ FormsModule,
34
+ GridsterModule,
35
+ NgApexchartsModule
36
+ ],
37
+ providers: [DashboardStateService],
38
+ exports: [
39
+ DashboardComponent,
40
+ WidgetRendererComponent
41
+ ]
42
+ }]
43
+ }] });
44
+ /**
45
+ * Root module for local demo / testing purposes.
46
+ * In the final NPM package, users would only import the `DashboardModule`.
47
+ */
48
+ export class AppModule {
49
+ }
50
+ AppModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: AppModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
51
+ AppModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.10", ngImport: i0, type: AppModule, bootstrap: [DashboardComponent], imports: [BrowserModule, DashboardModule] });
52
+ AppModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: AppModule, imports: [BrowserModule,
53
+ DashboardModule] });
54
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: AppModule, decorators: [{
55
+ type: NgModule,
56
+ args: [{
57
+ imports: [
58
+ BrowserModule,
59
+ DashboardModule
60
+ ],
61
+ bootstrap: [DashboardComponent]
62
+ }]
63
+ }] });
64
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXBwLm1vZHVsZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9hcHAvYXBwLm1vZHVsZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQ3pDLE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSwyQkFBMkIsQ0FBQztBQUMxRCxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDL0MsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQzdDLE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSxtQkFBbUIsQ0FBQztBQUNuRCxPQUFPLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFFbkQsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sdUJBQXVCLENBQUM7QUFDM0QsT0FBTyxFQUFFLHVCQUF1QixFQUFFLE1BQU0sNkJBQTZCLENBQUM7QUFDdEUsT0FBTyxFQUFFLHFCQUFxQixFQUFFLE1BQU0sMkJBQTJCLENBQUM7O0FBbUJsRSxNQUFNLE9BQU8sZUFBZTs7NkdBQWYsZUFBZTs4R0FBZixlQUFlLGlCQWZ4QixrQkFBa0I7UUFDbEIsdUJBQXVCLGFBR3ZCLFlBQVk7UUFDWixXQUFXO1FBQ1gsY0FBYztRQUNkLGtCQUFrQixhQUlsQixrQkFBa0I7UUFDbEIsdUJBQXVCOzhHQUdkLGVBQWUsYUFOZixDQUFDLHFCQUFxQixDQUFDLFlBTGhDLFlBQVk7UUFDWixXQUFXO1FBQ1gsY0FBYztRQUNkLGtCQUFrQjs0RkFRVCxlQUFlO2tCQWpCM0IsUUFBUTttQkFBQztvQkFDUixZQUFZLEVBQUU7d0JBQ1osa0JBQWtCO3dCQUNsQix1QkFBdUI7cUJBQ3hCO29CQUNELE9BQU8sRUFBRTt3QkFDUCxZQUFZO3dCQUNaLFdBQVc7d0JBQ1gsY0FBYzt3QkFDZCxrQkFBa0I7cUJBQ25CO29CQUNELFNBQVMsRUFBRSxDQUFDLHFCQUFxQixDQUFDO29CQUNsQyxPQUFPLEVBQUU7d0JBQ1Asa0JBQWtCO3dCQUNsQix1QkFBdUI7cUJBQ3hCO2lCQUNGOztBQUdEOzs7R0FHRztBQVFILE1BQU0sT0FBTyxTQUFTOzt1R0FBVCxTQUFTO3dHQUFULFNBQVMsY0FGUixrQkFBa0IsYUFINUIsYUFBYSxFQVJKLGVBQWU7d0dBYWYsU0FBUyxZQUxsQixhQUFhO1FBQ2IsZUFBZTs0RkFJTixTQUFTO2tCQVByQixRQUFRO21CQUFDO29CQUNSLE9BQU8sRUFBRTt3QkFDUCxhQUFhO3dCQUNiLGVBQWU7cUJBQ2hCO29CQUNELFNBQVMsRUFBRSxDQUFDLGtCQUFrQixDQUFDO2lCQUNoQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IE5nTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBCcm93c2VyTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvcGxhdGZvcm0tYnJvd3Nlcic7XG5pbXBvcnQgeyBDb21tb25Nb2R1bGUgfSBmcm9tICdAYW5ndWxhci9jb21tb24nO1xuaW1wb3J0IHsgRm9ybXNNb2R1bGUgfSBmcm9tICdAYW5ndWxhci9mb3Jtcyc7XG5pbXBvcnQgeyBHcmlkc3Rlck1vZHVsZSB9IGZyb20gJ2FuZ3VsYXItZ3JpZHN0ZXIyJztcbmltcG9ydCB7IE5nQXBleGNoYXJ0c01vZHVsZSB9IGZyb20gJ25nLWFwZXhjaGFydHMnO1xuXG5pbXBvcnQgeyBEYXNoYm9hcmRDb21wb25lbnQgfSBmcm9tICcuL2Rhc2hib2FyZC5jb21wb25lbnQnO1xuaW1wb3J0IHsgV2lkZ2V0UmVuZGVyZXJDb21wb25lbnQgfSBmcm9tICcuL3dpZGdldC1yZW5kZXJlci5jb21wb25lbnQnO1xuaW1wb3J0IHsgRGFzaGJvYXJkU3RhdGVTZXJ2aWNlIH0gZnJvbSAnLi9kYXNoYm9hcmQtc3RhdGUuc2VydmljZSc7XG5cbkBOZ01vZHVsZSh7XG4gIGRlY2xhcmF0aW9uczogW1xuICAgIERhc2hib2FyZENvbXBvbmVudCxcbiAgICBXaWRnZXRSZW5kZXJlckNvbXBvbmVudFxuICBdLFxuICBpbXBvcnRzOiBbXG4gICAgQ29tbW9uTW9kdWxlLFxuICAgIEZvcm1zTW9kdWxlLFxuICAgIEdyaWRzdGVyTW9kdWxlLFxuICAgIE5nQXBleGNoYXJ0c01vZHVsZVxuICBdLFxuICBwcm92aWRlcnM6IFtEYXNoYm9hcmRTdGF0ZVNlcnZpY2VdLFxuICBleHBvcnRzOiBbXG4gICAgRGFzaGJvYXJkQ29tcG9uZW50LFxuICAgIFdpZGdldFJlbmRlcmVyQ29tcG9uZW50XG4gIF1cbn0pXG5leHBvcnQgY2xhc3MgRGFzaGJvYXJkTW9kdWxlIHsgfVxuXG4vKipcbiAqIFJvb3QgbW9kdWxlIGZvciBsb2NhbCBkZW1vIC8gdGVzdGluZyBwdXJwb3Nlcy5cbiAqIEluIHRoZSBmaW5hbCBOUE0gcGFja2FnZSwgdXNlcnMgd291bGQgb25seSBpbXBvcnQgdGhlIGBEYXNoYm9hcmRNb2R1bGVgLlxuICovXG5ATmdNb2R1bGUoe1xuICBpbXBvcnRzOiBbXG4gICAgQnJvd3Nlck1vZHVsZSxcbiAgICBEYXNoYm9hcmRNb2R1bGVcbiAgXSxcbiAgYm9vdHN0cmFwOiBbRGFzaGJvYXJkQ29tcG9uZW50XVxufSlcbmV4cG9ydCBjbGFzcyBBcHBNb2R1bGUgeyB9XG4iXX0=