bways-report 0.1.7 → 0.1.9

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 (65) hide show
  1. package/esm2022/lib/core/config/bways-report-config.mjs +3 -1
  2. package/esm2022/lib/core/models/index.mjs +1 -1
  3. package/esm2022/lib/core/models/report-api-endpoint.model.mjs +8 -0
  4. package/esm2022/lib/core/models/report-component.model.mjs +1 -1
  5. package/esm2022/lib/core/models/report-datasource.model.mjs +1 -1
  6. package/esm2022/lib/core/services/index.mjs +2 -1
  7. package/esm2022/lib/core/services/report-api-execution.service.mjs +188 -0
  8. package/esm2022/lib/core/services/report-data-discovery.service.mjs +76 -4
  9. package/esm2022/lib/data-access/adapters/endpoint-datasource.adapter.mjs +24 -1
  10. package/esm2022/lib/data-access/adapters/endpoint-lookup.adapter.mjs +24 -2
  11. package/esm2022/lib/data-access/adapters/endpoint-tokens.mjs +1 -1
  12. package/esm2022/lib/data-access/adapters/http-lookup.adapter.mjs +26 -3
  13. package/esm2022/lib/data-access/contracts/lookup.contract.mjs +1 -1
  14. package/esm2022/lib/features/designer/components/component-palette/component-palette.component.mjs +536 -6
  15. package/esm2022/lib/features/designer/components/design-canvas/design-canvas.component.mjs +31 -3
  16. package/esm2022/lib/features/designer/components/dialogs/report-saved-dialog.component.mjs +2 -2
  17. package/esm2022/lib/features/designer/components/property-editor/parameter-binding-editor.component.mjs +3 -3
  18. package/esm2022/lib/features/designer/components/property-editor/property-editor-action.component.mjs +3 -3
  19. package/esm2022/lib/features/designer/components/property-editor/property-editor-datasource.component.mjs +131 -3
  20. package/esm2022/lib/features/designer/components/property-editor/property-editor-general.component.mjs +3 -3
  21. package/esm2022/lib/features/designer/components/property-editor/property-editor-grid.component.mjs +128 -28
  22. package/esm2022/lib/features/designer/components/property-editor/property-editor-layout.component.mjs +3 -3
  23. package/esm2022/lib/features/designer/components/property-editor/property-editor-report.component.mjs +3 -3
  24. package/esm2022/lib/features/designer/components/property-editor/property-editor-validation.component.mjs +3 -3
  25. package/esm2022/lib/features/designer/components/property-editor/property-editor.component.mjs +19 -10
  26. package/esm2022/lib/features/designer/designer.component.mjs +248 -33
  27. package/esm2022/lib/features/designer/utilities/canvas-layout.util.mjs +2 -1
  28. package/esm2022/lib/features/routing/components/routed-report-runtime.component.mjs +2 -2
  29. package/esm2022/lib/features/runtime/dynamic-renderer.component.mjs +23 -4
  30. package/esm2022/lib/features/runtime/report-execution.service.mjs +21 -4
  31. package/esm2022/lib/features/runtime/report-grid-bridge.component.mjs +51 -10
  32. package/esm2022/lib/features/runtime/report-runtime.component.mjs +16 -2
  33. package/esm2022/lib/features/runtime/rpt-report.component.mjs +2 -2
  34. package/esm2022/lib/primitives/components/dropdown/rpt-dropdown.component.mjs +16 -7
  35. package/esm2022/lib/primitives/components/icon/rpt-icon.component.mjs +41 -1
  36. package/esm2022/lib/primitives/components/index.mjs +2 -1
  37. package/esm2022/lib/primitives/components/radio/rpt-radio.component.mjs +428 -0
  38. package/esm2022/lib/primitives/register-builtins.mjs +51 -2
  39. package/esm2022/lib/provide-reporting.mjs +3 -1
  40. package/fesm2022/bways-report.mjs +2171 -241
  41. package/fesm2022/bways-report.mjs.map +1 -1
  42. package/lib/core/config/bways-report-config.d.ts +13 -0
  43. package/lib/core/models/index.d.ts +2 -1
  44. package/lib/core/models/report-api-endpoint.model.d.ts +30 -0
  45. package/lib/core/models/report-component.model.d.ts +16 -4
  46. package/lib/core/models/report-datasource.model.d.ts +16 -2
  47. package/lib/core/services/index.d.ts +1 -0
  48. package/lib/core/services/report-api-execution.service.d.ts +41 -0
  49. package/lib/core/services/report-data-discovery.service.d.ts +23 -1
  50. package/lib/data-access/adapters/endpoint-datasource.adapter.d.ts +2 -0
  51. package/lib/data-access/adapters/endpoint-lookup.adapter.d.ts +1 -0
  52. package/lib/data-access/adapters/endpoint-tokens.d.ts +3 -0
  53. package/lib/data-access/adapters/http-lookup.adapter.d.ts +2 -1
  54. package/lib/data-access/contracts/lookup.contract.d.ts +3 -0
  55. package/lib/features/designer/components/component-palette/component-palette.component.d.ts +16 -0
  56. package/lib/features/designer/components/property-editor/property-editor-datasource.component.d.ts +17 -0
  57. package/lib/features/designer/components/property-editor/property-editor-grid.component.d.ts +19 -7
  58. package/lib/features/designer/components/property-editor/property-editor.component.d.ts +1 -1
  59. package/lib/features/designer/designer.component.d.ts +12 -0
  60. package/lib/features/runtime/report-execution.service.d.ts +1 -0
  61. package/lib/features/runtime/report-grid-bridge.component.d.ts +3 -1
  62. package/lib/features/runtime/report-runtime.component.d.ts +13 -1
  63. package/lib/primitives/components/index.d.ts +2 -0
  64. package/lib/primitives/components/radio/rpt-radio.component.d.ts +77 -0
  65. package/package.json +1 -1
@@ -2,6 +2,7 @@ import { ChangeDetectionStrategy, Component, computed, effect, inject, input, ou
2
2
  import { CommonModule } from '@angular/common';
3
3
  import { FormsModule } from '@angular/forms';
4
4
  import { ReportDataDiscoveryService } from '../../../../core/services/report-data-discovery.service';
5
+ import { BWAYS_REPORT_ENDPOINTS } from '../../../../data-access/adapters/endpoint-tokens';
5
6
  import { RptIconComponent } from '../../../../primitives/components/icon/rpt-icon.component';
6
7
  import { RptSearchableSelectComponent, } from '../../../../primitives/components';
7
8
  import { ParameterBindingEditorComponent } from './parameter-binding-editor.component';
@@ -10,6 +11,7 @@ import * as i0 from "@angular/core";
10
11
  import * as i1 from "@angular/forms";
11
12
  export class PropertyEditorGridComponent {
12
13
  dataDiscovery = inject(ReportDataDiscoveryService, { optional: true });
14
+ endpoints = inject(BWAYS_REPORT_ENDPOINTS, { optional: true });
13
15
  grid = input();
14
16
  dataSource = input();
15
17
  availableEntities = input([]);
@@ -36,7 +38,63 @@ export class PropertyEditorGridComponent {
36
38
  return fromParent;
37
39
  return this.internalParameters();
38
40
  });
39
- selectedSourceType = signal('stored_procedure');
41
+ internalEntities = signal([]);
42
+ allEntities = computed(() => {
43
+ const fromParent = this.availableEntities();
44
+ if (fromParent && fromParent.length > 0)
45
+ return fromParent;
46
+ return this.internalEntities();
47
+ });
48
+ activeSourceType = signal('stored_procedure');
49
+ currentSourceType = computed(() => this.activeSourceType());
50
+ activeEntityName = computed(() => {
51
+ const ds = this.dataSource();
52
+ if (!ds)
53
+ return '';
54
+ const dsType = ds.type === 'table' ? 'table' : (ds.type === 'api' ? 'api' : 'stored_procedure');
55
+ if (dsType === this.activeSourceType()) {
56
+ return ds.name || ds.endpoint || '';
57
+ }
58
+ return '';
59
+ });
60
+ apiEndpoint = computed(() => {
61
+ const ds = this.dataSource();
62
+ return ds?.endpoint || ds?.name || '';
63
+ });
64
+ apiMethod = computed(() => {
65
+ const m = (this.dataSource()?.method || 'GET').toUpperCase();
66
+ return m === 'POST' ? 'POST' : 'GET';
67
+ });
68
+ apiDataPath = computed(() => {
69
+ return this.dataSource()?.dataPath || '';
70
+ });
71
+ apiUseProxy = computed(() => {
72
+ return this.dataSource()?.useProxy === true;
73
+ });
74
+ registeredApis = computed(() => {
75
+ const apis = this.endpoints?.apiEndpoints || [];
76
+ return apis.map((api) => {
77
+ const ep = api.endpoint || api.url || '';
78
+ return {
79
+ value: ep,
80
+ label: api.name || ep,
81
+ sublabel: `${api.method || 'GET'} ${ep}`,
82
+ badge: api.category || 'API',
83
+ };
84
+ });
85
+ });
86
+ availableTables = computed(() => {
87
+ return this.allEntities().filter((e) => {
88
+ const t = (e.type || '').toLowerCase();
89
+ return t === 'table' || t === 'view';
90
+ });
91
+ });
92
+ availableProcedures = computed(() => {
93
+ return this.allEntities().filter((e) => {
94
+ const t = (e.type || '').toLowerCase();
95
+ return t === 'stored_procedure' || t === 'procedure' || t.includes('procedure');
96
+ });
97
+ });
40
98
  isExecSnippetOpen = signal(false);
41
99
  execSnippetText = signal('');
42
100
  execParseStatus = signal(null);
@@ -79,6 +137,22 @@ export class PropertyEditorGridComponent {
79
137
  }, 1500);
80
138
  }
81
139
  constructor() {
140
+ // 1. Sync active tab whenever incoming grid dataSource changes type
141
+ effect(() => {
142
+ const ds = this.dataSource();
143
+ if (ds?.type) {
144
+ if (ds.type === 'api' || ds.endpoint?.startsWith('http') || ds.endpoint?.startsWith('/')) {
145
+ this.activeSourceType.set('api');
146
+ }
147
+ else if (ds.type === 'table') {
148
+ this.activeSourceType.set('table');
149
+ }
150
+ else {
151
+ this.activeSourceType.set('stored_procedure');
152
+ }
153
+ }
154
+ }, { allowSignalWrites: true });
155
+ // 2. Fetch parameters when a stored procedure is selected
82
156
  effect(() => {
83
157
  const entity = this.activeEntityName();
84
158
  const type = this.currentSourceType();
@@ -92,29 +166,15 @@ export class PropertyEditorGridComponent {
92
166
  this.internalParameters.set([]);
93
167
  }
94
168
  }, { allowSignalWrites: true });
95
- }
96
- currentSourceType = computed(() => {
97
- const ds = this.dataSource();
98
- if (ds) {
99
- return ds.type === 'table' ? 'table' : 'stored_procedure';
169
+ // 3. Fallback discovery load if availableEntities wasn't populated by parent
170
+ if (this.dataDiscovery) {
171
+ this.dataDiscovery.getEntities().subscribe((entities) => {
172
+ if (entities && entities.length > 0) {
173
+ this.internalEntities.set(entities);
174
+ }
175
+ });
100
176
  }
101
- return this.selectedSourceType();
102
- });
103
- activeEntityName = computed(() => {
104
- return this.dataSource()?.name || this.dataSource()?.endpoint || '';
105
- });
106
- availableTables = computed(() => {
107
- return this.availableEntities().filter((e) => {
108
- const t = (e.type || '').toLowerCase();
109
- return t === 'table' || t === 'view';
110
- });
111
- });
112
- availableProcedures = computed(() => {
113
- return this.availableEntities().filter((e) => {
114
- const t = (e.type || '').toLowerCase();
115
- return t === 'stored_procedure' || t === 'procedure' || t.includes('procedure');
116
- });
117
- });
177
+ }
118
178
  activeEntityList = computed(() => {
119
179
  return this.currentSourceType() === 'table' ? this.availableTables() : this.availableProcedures();
120
180
  });
@@ -123,7 +183,7 @@ export class PropertyEditorGridComponent {
123
183
  value: ent.name,
124
184
  label: ent.friendlyName || ent.name,
125
185
  sublabel: ent.schema ? `${ent.schema}.${ent.name}` : ent.name,
126
- badge: ent.type === 'stored_procedure' ? 'SP' : (ent.type || 'Table'),
186
+ badge: ent.type === 'stored_procedure' ? 'SP' : (ent.type?.toUpperCase() || 'TABLE'),
127
187
  }));
128
188
  });
129
189
  columns = computed(() => {
@@ -142,7 +202,44 @@ export class PropertyEditorGridComponent {
142
202
  return Object.entries(mapping).map(([key, value]) => ({ key, value }));
143
203
  });
144
204
  onSourceTypeChange(type) {
145
- this.selectedSourceType.set(type);
205
+ this.activeSourceType.set(type);
206
+ if (type !== 'api' && this.allEntities().length === 0 && this.dataDiscovery) {
207
+ this.dataDiscovery.getEntities().subscribe((entities) => {
208
+ if (entities && entities.length > 0) {
209
+ this.internalEntities.set(entities);
210
+ }
211
+ });
212
+ }
213
+ }
214
+ onApiEndpointChange(endpoint) {
215
+ const current = this.dataSource();
216
+ const next = {
217
+ ...(current ?? { id: `ds-api-${Date.now()}` }),
218
+ type: 'api',
219
+ endpoint: endpoint.trim(),
220
+ name: endpoint.trim(),
221
+ method: current?.method || 'GET',
222
+ };
223
+ this.setDataSource.emit(next);
224
+ this.entityChanged.emit({ name: endpoint.trim(), type: 'api' });
225
+ }
226
+ onApiMethodChange(method) {
227
+ const current = this.dataSource();
228
+ if (current) {
229
+ this.setDataSource.emit({ ...current, method });
230
+ }
231
+ }
232
+ onApiDataPathChange(dataPath) {
233
+ const current = this.dataSource();
234
+ if (current) {
235
+ this.setDataSource.emit({ ...current, dataPath: dataPath.trim() });
236
+ }
237
+ }
238
+ onApiUseProxyChange(useProxy) {
239
+ const current = this.dataSource();
240
+ if (current) {
241
+ this.setDataSource.emit({ ...current, useProxy });
242
+ }
146
243
  }
147
244
  onSelectEntity(entityName) {
148
245
  if (!entityName)
@@ -153,6 +250,9 @@ export class PropertyEditorGridComponent {
153
250
  error: () => this.internalParameters.set([]),
154
251
  });
155
252
  }
253
+ else {
254
+ this.internalParameters.set([]);
255
+ }
156
256
  this.entityChanged.emit({ name: entityName, type: this.currentSourceType() });
157
257
  }
158
258
  getParameterValue(paramName) {
@@ -244,7 +344,7 @@ export class PropertyEditorGridComponent {
244
344
  this.updateRowClickAction.emit({ ...current, parameterMapping: nextMapping });
245
345
  }
246
346
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: PropertyEditorGridComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
247
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: PropertyEditorGridComponent, isStandalone: true, selector: "rpt-property-editor-grid", inputs: { grid: { classPropertyName: "grid", publicName: "grid", isSignal: true, isRequired: false, transformFunction: null }, dataSource: { classPropertyName: "dataSource", publicName: "dataSource", isSignal: true, isRequired: false, transformFunction: null }, availableEntities: { classPropertyName: "availableEntities", publicName: "availableEntities", isSignal: true, isRequired: false, transformFunction: null }, procedureParameters: { classPropertyName: "procedureParameters", publicName: "procedureParameters", isSignal: true, isRequired: false, transformFunction: null }, allComponents: { classPropertyName: "allComponents", publicName: "allComponents", isSignal: true, isRequired: false, transformFunction: null }, isDetecting: { classPropertyName: "isDetecting", publicName: "isDetecting", isSignal: true, isRequired: false, transformFunction: null }, statusMessage: { classPropertyName: "statusMessage", publicName: "statusMessage", isSignal: true, isRequired: false, transformFunction: null }, statusKind: { classPropertyName: "statusKind", publicName: "statusKind", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { addGrid: "addGrid", removeGrid: "removeGrid", addColumn: "addColumn", autoDetectColumns: "autoDetectColumns", removeColumn: "removeColumn", updateColumn: "updateColumn", updateOption: "updateOption", updateRowClickAction: "updateRowClickAction", setDataSource: "setDataSource", updateDataSourceParameters: "updateDataSourceParameters", entityChanged: "entityChanged" }, ngImport: i0, template: " @if (!grid()) {\n <div class=\"empty-grid-card\">\n <div class=\"empty-grid-icon\">\n <rpt-icon name=\"table\" [size]=\"28\" />\n </div>\n <h4 class=\"empty-grid-title\">No Result Grid Attached</h4>\n <p class=\"empty-grid-desc\">Attach an interactive Result Data Grid (or UltraGrid) to this report definition to render queries and stored procedure results.</p>\n <button type=\"button\" class=\"btn-create-grid-action\" (click)=\"addGrid.emit()\">\n <rpt-icon name=\"plus\" [size]=\"14\" />\n <span>+ Add Result Grid</span>\n </button>\n </div>\n } @else {\n <div class=\"props-form\">\n <!-- 1. Report Data Source & Stored Procedure Configuration -->\n <div class=\"property-group\">\n <div class=\"group-header-row\">\n <div class=\"group-title-wrap\">\n <span class=\"group-title\">Report Data Source</span>\n @if (activeEntityName()) {\n <span class=\"group-badge active-ds-badge\">{{ activeEntityName() }}</span>\n }\n </div>\n </div>\n\n <!-- Source Type Switcher (Stored Procedure vs Table) -->\n <div class=\"source-type-switcher\">\n <button\n type=\"button\"\n class=\"source-tab-btn\"\n [class.active]=\"currentSourceType() === 'stored_procedure'\"\n (click)=\"onSourceTypeChange('stored_procedure')\"\n >\n <rpt-icon name=\"code\" [size]=\"12\" />\n <span>Stored Procedure</span>\n </button>\n <button\n type=\"button\"\n class=\"source-tab-btn\"\n [class.active]=\"currentSourceType() === 'table'\"\n (click)=\"onSourceTypeChange('table')\"\n >\n <rpt-icon name=\"table\" [size]=\"12\" />\n <span>Table / View</span>\n </button>\n </div>\n\n <!-- Entity Selector Dropdown -->\n <div class=\"field-row\">\n <label class=\"field-label\">\n {{ currentSourceType() === 'stored_procedure' ? 'Stored Procedure' : 'Table / View' }}\n </label>\n <rpt-searchable-select\n [options]=\"gridEntitySelectOptions()\"\n [ngModel]=\"activeEntityName()\"\n (ngModelChange)=\"onSelectEntity($event)\"\n placeholder=\"-- Choose Data Source --\"\n [searchPlaceholder]=\"currentSourceType() === 'stored_procedure' ? 'Search procedures...' : 'Search tables & views...'\"\n />\n </div>\n\n <!-- Stored Procedure Parameter Mappings -->\n @if (currentSourceType() === 'stored_procedure' && activeEntityName()) {\n <div class=\"procedure-params-section\">\n <div class=\"params-section-header\">\n <div class=\"params-header-left\">\n <span class=\"params-title\">Procedure Parameters</span>\n <span class=\"params-count-badge\">{{ effectiveParameters().length }}</span>\n </div>\n <button\n type=\"button\"\n class=\"btn-paste-exec\"\n (click)=\"toggleExecSnippet()\"\n title=\"Paste full SSMS 'EXEC proc @param=val' snippet to fill parameters automatically\"\n >\n <rpt-icon name=\"code\" [size]=\"12\" />\n <span>{{ isExecSnippetOpen() ? 'Close SQL' : 'Paste SQL Exec' }}</span>\n </button>\n </div>\n\n @if (isExecSnippetOpen()) {\n <div class=\"exec-snippet-panel\">\n <div class=\"exec-snippet-header\">\n <span class=\"snippet-hint\">Paste full <code>EXEC ProcedureName &#64;param=val...</code> statement from SSMS:</span>\n </div>\n <textarea\n class=\"exec-snippet-textarea\"\n rows=\"3\"\n placeholder=\"e.g. exec Get_HelpList @chrCOMPANYID=N'101',@chrTableName=N'MSTACCTGLSUB'...\"\n [ngModel]=\"execSnippetText()\"\n (ngModelChange)=\"execSnippetText.set($event)\"\n ></textarea>\n <div class=\"exec-snippet-actions\">\n <button type=\"button\" class=\"btn-snippet-apply\" (click)=\"applyExecSnippet()\">\n <rpt-icon name=\"check\" [size]=\"12\" />\n <span>Apply Parameters</span>\n </button>\n <button type=\"button\" class=\"btn-snippet-cancel\" (click)=\"toggleExecSnippet()\">\n Cancel\n </button>\n </div>\n @if (execParseStatus()) {\n <div class=\"snippet-status\" [class.is-error]=\"execParseStatus()?.kind === 'error'\" [class.is-success]=\"execParseStatus()?.kind === 'success'\">\n {{ execParseStatus()?.message }}\n </div>\n }\n </div>\n }\n\n @if (effectiveParameters().length > 0) {\n <div class=\"param-cards-list\">\n @for (param of effectiveParameters(); track param.name) {\n <rpt-parameter-binding-editor\n [param]=\"param\"\n [currentValue]=\"getParameterValue(param.name)\"\n [allComponents]=\"allComponents()\"\n (valueChange)=\"onParameterChange(param.name, $event)\"\n />\n }\n </div>\n } @else {\n <div class=\"empty-params-hint\">\n <span>No required parameters for this procedure.</span>\n </div>\n }\n </div>\n }\n </div>\n\n <!-- 2. Result Columns Configuration -->\n <div class=\"property-group\">\n <div class=\"group-header-row\">\n <div class=\"group-title-wrap\">\n <span class=\"group-title\">Columns</span>\n <span class=\"group-badge\">{{ columns().length }}</span>\n </div>\n </div>\n\n <!-- Dedicated Full-Width Action Buttons (No cramping) -->\n <div class=\"columns-action-bar\">\n <button\n type=\"button\"\n class=\"btn-col-action btn-auto-detect\"\n (click)=\"autoDetectColumns.emit()\"\n [disabled]=\"isDetecting()\"\n title=\"Auto-detect all columns from procedure or data table\"\n >\n <rpt-icon name=\"refresh\" [size]=\"12\" [class.rpt-spin]=\"isDetecting()\" />\n <span>{{ isDetecting() ? 'Detecting...' : 'Auto-Detect' }}</span>\n </button>\n <button\n type=\"button\"\n class=\"btn-col-action btn-add-col\"\n (click)=\"addColumn.emit()\"\n title=\"Add a new column manually\"\n >\n <rpt-icon name=\"plus\" [size]=\"12\" />\n <span>+ Add Column</span>\n </button>\n </div>\n\n @if (statusMessage()) {\n <div class=\"col-status-banner\" [class.is-error]=\"statusKind() === 'error'\" [class.is-success]=\"statusKind() === 'success'\">\n <rpt-icon [name]=\"statusKind() === 'error' ? 'close' : 'check'\" [size]=\"12\" />\n <span>{{ statusMessage() }}</span>\n </div>\n }\n\n <div class=\"columns-editor-list\">\n @for (col of columns(); track col.field; let idx = $index) {\n <div class=\"col-edit-card\">\n <div class=\"col-card-header\">\n <div class=\"col-header-title-group\">\n <span class=\"col-drag-dots\">\u22EE\u22EE</span>\n <span class=\"col-idx-badge\">#{{ idx + 1 }}</span>\n <input\n type=\"text\"\n class=\"col-title-input\"\n placeholder=\"Column Label\"\n [ngModel]=\"col.label\"\n (ngModelChange)=\"onUpdateCol(idx, 'label', $event)\"\n />\n </div>\n <div class=\"col-card-actions\">\n <span class=\"col-type-pill\">{{ col.dataType || 'string' }}</span>\n <button\n type=\"button\"\n class=\"col-action-btn btn-delete\"\n (click)=\"removeColumn.emit(idx)\"\n title=\"Remove Column\"\n >\n <rpt-icon name=\"trash\" [size]=\"12\" />\n </button>\n </div>\n </div>\n\n <div class=\"col-card-body\">\n <div class=\"col-edit-fields\">\n <div class=\"col-field-item\">\n <span class=\"mini-label\">Field</span>\n <input\n type=\"text\"\n class=\"col-mini-input\"\n placeholder=\"field\"\n [ngModel]=\"col.field\"\n (ngModelChange)=\"onUpdateCol(idx, 'field', $event)\"\n />\n </div>\n <div class=\"col-field-item\">\n <span class=\"mini-label\">Type</span>\n <select\n class=\"col-mini-select\"\n [ngModel]=\"col.dataType || 'string'\"\n (ngModelChange)=\"onUpdateCol(idx, 'dataType', $event)\"\n >\n <option value=\"string\">String</option>\n <option value=\"number\">Number</option>\n <option value=\"currency\">Currency</option>\n <option value=\"date\">Date</option>\n <option value=\"boolean\">Boolean</option>\n </select>\n </div>\n <div class=\"col-field-item\">\n <span class=\"mini-label\">Format</span>\n <input\n type=\"text\"\n class=\"col-mini-input\"\n placeholder=\"e.g. dd/MM/yyyy\"\n [ngModel]=\"col.format\"\n (ngModelChange)=\"onUpdateCol(idx, 'format', $event)\"\n />\n </div>\n <div class=\"col-field-item\">\n <span class=\"mini-label\">Align</span>\n <select\n class=\"col-mini-select\"\n [ngModel]=\"col.align || 'left'\"\n (ngModelChange)=\"onUpdateCol(idx, 'align', $event)\"\n >\n <option value=\"left\">Left</option>\n <option value=\"center\">Center</option>\n <option value=\"right\">Right</option>\n </select>\n </div>\n <div class=\"col-field-item\">\n <span class=\"mini-label\">Aggregate</span>\n <select\n class=\"col-mini-select\"\n [ngModel]=\"col.aggregate || 'none'\"\n (ngModelChange)=\"onUpdateCol(idx, 'aggregate', $event === 'none' ? undefined : $event)\"\n >\n <option value=\"none\">None</option>\n <option value=\"sum\">Sum</option>\n <option value=\"avg\">Average</option>\n <option value=\"count\">Count</option>\n <option value=\"min\">Min</option>\n <option value=\"max\">Max</option>\n </select>\n </div>\n <div class=\"col-field-item\">\n <span class=\"mini-label\">Width</span>\n <input\n type=\"text\"\n class=\"col-mini-input\"\n placeholder=\"auto\"\n [ngModel]=\"col.width || ''\"\n (ngModelChange)=\"onUpdateCol(idx, 'width', $event || undefined)\"\n />\n </div>\n </div>\n\n <div class=\"col-card-footer\">\n <label class=\"col-checkbox-toggle\">\n <input\n type=\"checkbox\"\n [ngModel]=\"col.visible !== false\"\n (ngModelChange)=\"onUpdateCol(idx, 'visible', $event)\"\n />\n <span>Visible</span>\n </label>\n <label class=\"col-checkbox-toggle\">\n <input\n type=\"checkbox\"\n [ngModel]=\"col.checkboxSelection ?? false\"\n (ngModelChange)=\"onUpdateCol(idx, 'checkboxSelection', $event)\"\n />\n <span>Checkbox</span>\n </label>\n </div>\n </div>\n </div>\n }\n </div>\n </div>\n\n <!-- Grid Table Options Group -->\n <div class=\"property-group\">\n <div class=\"group-title\">Table Options</div>\n\n <div class=\"field-row\">\n <label class=\"checkbox-toggle\">\n <input\n type=\"checkbox\"\n [ngModel]=\"grid()?.options?.sideBar !== false\"\n (ngModelChange)=\"updateOption.emit({ field: 'sideBar', value: $event })\"\n />\n <span>Enable Side Panel (Tool Panels)</span>\n </label>\n </div>\n\n <div class=\"field-row\">\n <label class=\"checkbox-toggle\">\n <input\n type=\"checkbox\"\n [ngModel]=\"grid()?.options?.globalSearch !== false\"\n (ngModelChange)=\"updateOption.emit({ field: 'globalSearch', value: $event })\"\n />\n <span>Global Search Box</span>\n </label>\n </div>\n\n <div class=\"field-row\">\n <label class=\"checkbox-toggle\">\n <input\n type=\"checkbox\"\n [ngModel]=\"grid()?.options?.statusBar !== false\"\n (ngModelChange)=\"updateOption.emit({ field: 'statusBar', value: $event })\"\n />\n <span>Status Bar</span>\n </label>\n </div>\n\n <div class=\"field-row\">\n <label class=\"checkbox-toggle\">\n <input\n type=\"checkbox\"\n [ngModel]=\"grid()?.options?.pagination ?? true\"\n (ngModelChange)=\"updateOption.emit({ field: 'pagination', value: $event })\"\n />\n <span>Enable Pagination</span>\n </label>\n </div>\n\n <div class=\"field-row\">\n <label class=\"checkbox-toggle\">\n <input\n type=\"checkbox\"\n [ngModel]=\"grid()?.options?.selectable ?? false\"\n (ngModelChange)=\"updateOption.emit({ field: 'selectable', value: $event })\"\n />\n <span>Row Selection</span>\n </label>\n </div>\n\n @if (grid()?.options?.selectable) {\n <div class=\"field-row\">\n <label class=\"field-label\">Selection Mode</label>\n <select\n class=\"field-input\"\n [ngModel]=\"grid()?.options?.selectionMode ?? 'multiple'\"\n (ngModelChange)=\"updateOption.emit({ field: 'selectionMode', value: $event })\"\n >\n <option value=\"multiple\">Multiple Rows</option>\n <option value=\"single\">Single Row</option>\n </select>\n </div>\n\n <div class=\"field-row\">\n <label class=\"checkbox-toggle\">\n <input\n type=\"checkbox\"\n [ngModel]=\"grid()?.options?.checkboxSelection ?? true\"\n (ngModelChange)=\"updateOption.emit({ field: 'checkboxSelection', value: $event })\"\n />\n <span>Checkbox Selection</span>\n </label>\n </div>\n\n @if ((grid()?.options?.selectionMode ?? 'multiple') === 'multiple') {\n <div class=\"field-row\">\n <label class=\"checkbox-toggle\">\n <input\n type=\"checkbox\"\n [ngModel]=\"grid()?.options?.headerCheckboxSelection ?? true\"\n (ngModelChange)=\"updateOption.emit({ field: 'headerCheckboxSelection', value: $event })\"\n />\n <span>Header Select All Checkbox</span>\n </label>\n </div>\n }\n }\n\n <div class=\"field-row\">\n <label class=\"checkbox-toggle\">\n <input\n type=\"checkbox\"\n [ngModel]=\"grid()?.options?.allowColumnReorder ?? true\"\n (ngModelChange)=\"updateOption.emit({ field: 'allowColumnReorder', value: $event })\"\n />\n <span>Allow Column Reorder</span>\n </label>\n </div>\n\n <div class=\"field-row\">\n <label class=\"checkbox-toggle\">\n <input\n type=\"checkbox\"\n [ngModel]=\"grid()?.options?.allowExport ?? true\"\n (ngModelChange)=\"updateOption.emit({ field: 'allowExport', value: $event })\"\n />\n <span>Allow Export</span>\n </label>\n </div>\n\n <div class=\"field-row\">\n <label class=\"field-label\">Page Size</label>\n <input\n type=\"number\"\n class=\"field-input\"\n min=\"1\"\n max=\"1000\"\n (wheel)=\"$any($event.target).blur()\"\n (keydown.arrowup)=\"$event.preventDefault()\"\n (keydown.arrowdown)=\"$event.preventDefault()\"\n [ngModel]=\"grid()?.options?.pageSize ?? 10\"\n (ngModelChange)=\"updateOption.emit({ field: 'pageSize', value: +$event })\"\n />\n </div>\n\n <div class=\"field-row\">\n <label class=\"checkbox-toggle\">\n <input\n type=\"checkbox\"\n [ngModel]=\"grid()?.options?.showRowNumbers ?? true\"\n (ngModelChange)=\"updateOption.emit({ field: 'showRowNumbers', value: $event })\"\n />\n <span>Show Row Numbers</span>\n </label>\n </div>\n\n <div class=\"field-row\">\n <label class=\"checkbox-toggle\">\n <input\n type=\"checkbox\"\n [ngModel]=\"grid()?.options?.showFooter ?? true\"\n (ngModelChange)=\"updateOption.emit({ field: 'showFooter', value: $event })\"\n />\n <span>Show Footer Totals</span>\n </label>\n </div>\n </div>\n\n <!-- Row Click & Drill-Down Action Group -->\n <div class=\"property-group\">\n <div class=\"group-title\">Row Click & Drill-Down</div>\n\n <div class=\"field-row\">\n <label class=\"checkbox-toggle\">\n <input\n type=\"checkbox\"\n [ngModel]=\"hasRowClickAction()\"\n (ngModelChange)=\"toggleRowClickAction($event)\"\n />\n <span>Enable Row Click Action</span>\n </label>\n </div>\n\n @if (hasRowClickAction()) {\n <div class=\"field-row\">\n <label class=\"field-label\">Action Type</label>\n <select\n class=\"field-input field-select\"\n [ngModel]=\"rowClickAction()?.type || 'open-drawer'\"\n (ngModelChange)=\"updateRowActionField('type', $event)\"\n >\n <option value=\"open-drawer\">Slide-Over Detail Drawer</option>\n <option value=\"drilldown-report\">Drill-Down Report (Host Event)</option>\n <option value=\"navigate\">Navigate to URL</option>\n <option value=\"emit-custom\">Emit Custom Action</option>\n </select>\n </div>\n\n @if (rowClickAction()?.type === 'open-drawer' || rowClickAction()?.type === 'drilldown-report') {\n <div class=\"field-row\">\n <label class=\"field-label\">Target Report ID</label>\n <input\n type=\"text\"\n class=\"field-input\"\n placeholder=\"e.g. order-details\"\n [ngModel]=\"rowClickAction()?.targetReportId || ''\"\n (ngModelChange)=\"updateRowActionField('targetReportId', $event)\"\n />\n </div>\n\n <div class=\"field-row\">\n <label class=\"field-label\">Drawer Title</label>\n <input\n type=\"text\"\n class=\"field-input\"\n placeholder=\"e.g. Order Details\"\n [ngModel]=\"rowClickAction()?.drawerTitle || ''\"\n (ngModelChange)=\"updateRowActionField('drawerTitle', $event)\"\n />\n </div>\n\n <div class=\"field-row\">\n <label class=\"field-label\">Drawer Width</label>\n <input\n type=\"text\"\n class=\"field-input\"\n placeholder=\"e.g. 760px, 80%, 900px\"\n [ngModel]=\"rowClickAction()?.drawerWidth || '760px'\"\n (ngModelChange)=\"updateRowActionField('drawerWidth', $event)\"\n />\n </div>\n }\n\n @if (rowClickAction()?.type === 'navigate') {\n <div class=\"field-row\">\n <label class=\"field-label\">Target URL</label>\n <input\n type=\"text\"\n class=\"field-input\"\n [placeholder]=\"'/orders/{{row.orderId}} or https://...'\"\n [ngModel]=\"rowClickAction()?.targetUrl || ''\"\n (ngModelChange)=\"updateRowActionField('targetUrl', $event)\"\n />\n </div>\n <div class=\"field-row\">\n <label class=\"checkbox-toggle\">\n <input\n type=\"checkbox\"\n [ngModel]=\"rowClickAction()?.openNewTab ?? false\"\n (ngModelChange)=\"updateRowActionField('openNewTab', $event)\"\n />\n <span>Open in New Tab</span>\n </label>\n </div>\n }\n\n @if (rowClickAction()?.type === 'emit-custom') {\n <div class=\"field-row\">\n <label class=\"field-label\">Custom Action Name</label>\n <input\n type=\"text\"\n class=\"field-input\"\n placeholder=\"e.g. view-audit-trail\"\n [ngModel]=\"rowClickAction()?.customActionName || ''\"\n (ngModelChange)=\"updateRowActionField('customActionName', $event)\"\n />\n </div>\n }\n\n <div class=\"field-row\">\n <div class=\"field-label-row\">\n <label class=\"field-label\">Parameter Mapping</label>\n <button\n type=\"button\"\n class=\"btn-add-mapping\"\n (click)=\"addParameterMapping()\"\n >\n + Add Mapping\n </button>\n </div>\n\n @for (mapping of parameterMappings(); track mapping.key; let mIdx = $index) {\n <div class=\"mapping-pair-row\">\n <input\n type=\"text\"\n class=\"col-mini-input\"\n style=\"flex: 1;\"\n placeholder=\"Target (e.g. customerId)\"\n [ngModel]=\"mapping.key\"\n (ngModelChange)=\"updateMappingKey(mIdx, $event)\"\n />\n <span style=\"font-size: 0.75rem; color: #94a3b8;\">\u2190</span>\n <input\n type=\"text\"\n class=\"col-mini-input\"\n style=\"flex: 1;\"\n placeholder=\"Source (e.g. row.id)\"\n [ngModel]=\"mapping.value\"\n (ngModelChange)=\"updateMappingValue(mIdx, $event)\"\n />\n <button\n type=\"button\"\n class=\"col-action-btn btn-delete\"\n (click)=\"removeMapping(mIdx)\"\n title=\"Remove mapping\"\n >\n <rpt-icon name=\"trash\" [size]=\"11\" />\n </button>\n </div>\n }\n </div>\n }\n </div>\n\n <!-- Remove Grid Action -->\n <div class=\"grid-danger-zone\">\n <button type=\"button\" class=\"btn-remove-grid-action\" (click)=\"removeGrid.emit()\">\n <rpt-icon name=\"trash\" [size]=\"13\" />\n <span>Remove Grid from Report</span>\n </button>\n </div>\n </div>\n }", styles: [".property-group{display:flex;flex-direction:column;gap:12px}.group-title{font-size:.7rem;font-weight:700;color:var(--rpt-color-text-muted, #64748b);text-transform:uppercase;letter-spacing:.05em;border-bottom:1px solid var(--rpt-color-border, #e2e8f0);padding-bottom:4px}.field-row{display:flex;flex-direction:column;gap:4px}.field-label-row{display:flex;align-items:center;justify-content:space-between}.field-badge-val{font-size:.65rem;font-weight:600;color:var(--rpt-color-primary, #2563eb);background:#eff6ff;border:1px solid #bfdbfe;padding:1px 6px;border-radius:9999px}.field-label{font-size:.7rem;font-weight:600;color:var(--rpt-color-text, #0f172a)}.field-input,.field-select,.field-textarea{width:100%;box-sizing:border-box;border:1px solid var(--rpt-color-border, #cbd5e1);border-radius:var(--rpt-border-radius-sm, 4px);padding:6px 10px;font-size:var(--rpt-font-size-sm, .75rem);color:var(--rpt-color-text, #0f172a);background:#fff;outline:none;transition:all var(--rpt-transition-speed, .15s) ease}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button,.field-input[type=number]::-webkit-inner-spin-button,.field-input[type=number]::-webkit-outer-spin-button{-webkit-appearance:none;margin:0}input[type=number],.field-input[type=number]{-moz-appearance:textfield;appearance:textfield}.field-select{appearance:none;-webkit-appearance:none;background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2364748b' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E\");background-repeat:no-repeat;background-position:right 10px center;background-size:13px 13px;padding-right:28px;cursor:pointer}.field-input:focus,.field-select:focus,.field-textarea:focus{border-color:var(--rpt-color-primary, #2563eb);box-shadow:var(--rpt-box-shadow-focus, 0 0 0 3px rgba(37, 99, 235, .25))}.checkbox-toggle{display:inline-flex;align-items:center;gap:8px;font-size:.75rem;font-weight:500;color:var(--rpt-color-text, #0f172a);cursor:pointer}.preset-pill-group{display:flex;flex-wrap:wrap;gap:4px;margin-top:4px}.preset-pill{background:#f1f5f9;border:1px solid #e2e8f0;border-radius:4px;padding:2px 8px;font-size:.65rem;font-weight:600;color:#475569;cursor:pointer;transition:all .12s ease}.preset-pill:hover{background:#e2e8f0;color:#0f172a;border-color:#cbd5e1}.preset-pill-active{background:var(--rpt-color-primary, #2563eb)!important;color:#fff!important;border-color:var(--rpt-color-primary, #2563eb)!important}.preset-pill-reset{color:var(--rpt-color-primary, #2563eb);background:#eff6ff;border-color:#bfdbfe}.preset-pill-reset:hover{background:#dbeafe;color:#1d4ed8;border-color:#93c5fd}\n", ".empty-grid-card{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:40px 16px;text-align:center;border:2px dashed #cbd5e1;border-radius:8px;background:#fff;margin:10px 0}.empty-grid-icon{width:48px;height:48px;border-radius:10px;background:#eff6ff;color:#2563eb;display:flex;align-items:center;justify-content:center;margin-bottom:12px}.empty-grid-title{font-size:.95rem;font-weight:700;color:#0f172a;margin:0 0 6px}.empty-grid-desc{font-size:.775rem;color:#64748b;margin:0 0 18px;line-height:1.4;max-width:280px}.btn-create-grid-action{display:inline-flex;align-items:center;gap:6px;padding:8px 16px;background:#2563eb;color:#fff;font-size:.775rem;font-weight:600;border:none;border-radius:6px;cursor:pointer;box-shadow:0 2px 4px #2563eb33;transition:all .15s ease}.btn-create-grid-action:hover{background:#1d4ed8;box-shadow:0 4px 8px #2563eb40}.grid-danger-zone{margin-top:10px;padding-top:16px;border-top:1px dashed #e2e8f0;display:flex;justify-content:center}.btn-remove-grid-action{display:inline-flex;align-items:center;gap:6px;background:#fee2e2;border:1px solid #fecaca;color:#dc2626;font-size:.75rem;font-weight:600;padding:6px 12px;border-radius:6px;cursor:pointer;transition:all .15s ease}.btn-remove-grid-action:hover{background:#fecaca;border-color:#f87171;color:#b91c1c}.props-form{display:flex;flex-direction:column;gap:20px}.group-header-row{display:flex;align-items:center;justify-content:space-between;border-bottom:1px solid var(--rpt-color-border, #e2e8f0);padding-bottom:6px;margin-bottom:8px}.group-title-wrap{display:flex;align-items:center;gap:6px}.group-badge{font-size:.65rem;font-weight:700;color:#64748b;background:#f1f5f9;border:1px solid #e2e8f0;border-radius:10px;padding:1px 6px}.columns-action-bar{display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-bottom:12px}.btn-col-action{display:inline-flex;align-items:center;justify-content:center;gap:6px;padding:7px 8px;font-size:.725rem;font-weight:600;border-radius:6px;cursor:pointer;white-space:nowrap;transition:all .12s ease;box-sizing:border-box}.btn-col-action:disabled{opacity:.6;cursor:not-allowed}.btn-auto-detect{background:#eff6ff;border:1px solid #bfdbfe;color:#2563eb}.btn-auto-detect:hover:not(:disabled){background:#2563eb;color:#fff;border-color:#2563eb}.btn-add-col{background:#fff;border:1px solid var(--rpt-color-border, #cbd5e1);color:#334155}.btn-add-col:hover{background:#f8fafc;border-color:#94a3b8;color:#0f172a}.col-status-banner{display:flex;align-items:center;gap:6px;padding:6px 10px;border-radius:6px;font-size:.72rem;line-height:1.35;margin-bottom:10px;background:#f1f5f9;color:#334155;border:1px solid #cbd5e1}.col-status-banner.is-success{background:#f0fdf4;color:#166534;border-color:#bbf7d0}.col-status-banner.is-error{background:#fef2f2;color:#991b1b;border-color:#fecaca}@keyframes rpt-spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.rpt-spin{animation:rpt-spin 1s linear infinite}.columns-editor-list{display:flex;flex-direction:column;gap:10px}.col-edit-card{background:#fff;border:1.5px solid var(--rpt-color-border, #cbd5e1);border-radius:var(--rpt-border-radius, 6px);box-shadow:var(--rpt-box-shadow, 0 1px 2px rgba(0, 0, 0, .05));box-sizing:border-box;transition:all var(--rpt-transition-speed, .15s) ease;position:relative;overflow:hidden;display:flex;flex-direction:column}.col-edit-card:hover{border-color:var(--rpt-color-primary, #2563eb);box-shadow:0 4px 6px -1px #2563eb1a}.col-card-header{display:flex;align-items:center;justify-content:space-between;gap:6px;padding:5px 8px;background:var(--rpt-color-surface, #f8fafc);border-bottom:1px solid var(--rpt-color-border, #e2e8f0);min-height:32px;box-sizing:border-box}.col-header-title-group{display:flex;align-items:center;gap:5px;min-width:0;flex:1}.col-drag-dots{color:#94a3b8;font-size:.8rem;cursor:grab;-webkit-user-select:none;user-select:none;line-height:1;padding-left:2px}.col-idx-badge{font-size:.65rem;font-weight:700;color:#64748b;background:#e2e8f0;padding:1px 5px;border-radius:3px;letter-spacing:.02em}.col-title-input{flex:1;border:1px solid transparent;background:transparent;font-size:.75rem;font-weight:600;color:var(--rpt-color-text, #0f172a);padding:2px 6px;border-radius:4px;outline:none;transition:all .15s ease}.col-title-input:hover{border-color:#cbd5e1;background:#fff}.col-title-input:focus{border-color:var(--rpt-color-primary, #2563eb);background:#fff;box-shadow:0 0 0 2px #2563eb26}.col-card-actions{display:flex;align-items:center;gap:4px}.col-type-pill{font-size:.625rem;font-weight:700;color:#1e40af;background:#dbeafe;border:1px solid #bfdbfe;padding:1px 5px;border-radius:3px;text-transform:uppercase;letter-spacing:.04em}.col-action-btn{display:inline-flex;align-items:center;justify-content:center;background:none;border:none;color:var(--rpt-color-text-muted, #64748b);cursor:pointer;padding:3px;border-radius:4px;transition:all .15s ease}.col-action-btn.btn-delete:hover{color:var(--rpt-color-danger, #ef4444);background:#fee2e2}.col-card-body{padding:8px 10px;display:flex;flex-direction:column;gap:6px;background:#fff}.col-edit-fields{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:6px 8px}.col-field-item{display:flex;flex-direction:column;gap:2px;min-width:0}.mini-label{font-size:.625rem;font-weight:600;color:#64748b;letter-spacing:.02em}.col-mini-input,.col-mini-select{width:100%;box-sizing:border-box;border:1px solid var(--rpt-color-border, #cbd5e1);border-radius:3px;padding:3px 5px;font-size:.7rem;color:var(--rpt-color-text, #0f172a);background:#fff;outline:none;transition:all .12s ease}.col-mini-select{appearance:none;-webkit-appearance:none;background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2364748b' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E\");background-repeat:no-repeat;background-position:right 4px center;background-size:10px 10px;padding-right:16px;cursor:pointer}.col-mini-input:focus,.col-mini-select:focus{border-color:var(--rpt-color-primary, #2563eb);box-shadow:0 0 0 2px #2563eb26}.col-card-footer{display:flex;align-items:center;justify-content:flex-end;gap:12px;padding-top:4px;border-top:1px dashed #e2e8f0;margin-top:2px}.col-checkbox-toggle{display:inline-flex;align-items:center;gap:5px;font-size:.675rem;font-weight:500;color:#475569;cursor:pointer;-webkit-user-select:none;user-select:none}.btn-add-mapping{display:inline-flex;align-items:center;background:#eff6ff;border:1px solid #bfdbfe;color:#2563eb;font-size:.65rem;font-weight:600;padding:2px 6px;border-radius:4px;cursor:pointer;transition:all .12s ease}.btn-add-mapping:hover{background:#dbeafe}.mapping-pair-row{display:flex;align-items:center;gap:6px;margin-top:4px}.active-ds-badge{background:#eff6ff;color:#2563eb;font-size:.65rem;font-weight:700;padding:1px 6px;border-radius:4px;border:1px solid #bfdbfe;max-width:140px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.source-type-switcher{display:flex;background:#f1f5f9;border:1px solid var(--rpt-color-border, #cbd5e1);border-radius:6px;padding:2px;gap:2px;margin-bottom:12px}.source-tab-btn{flex:1;display:inline-flex;align-items:center;justify-content:center;gap:5px;padding:6px 4px;font-size:.725rem;font-weight:600;color:var(--rpt-color-text-muted, #64748b);background:transparent;border:none;border-radius:4px;cursor:pointer;transition:all .12s ease}.source-tab-btn:hover{color:var(--rpt-color-text, #0f172a)}.source-tab-btn.active{background:#fff;color:var(--rpt-color-primary, #2563eb);box-shadow:0 1px 2px #0000000f}.procedure-params-section{margin-top:14px;padding:0;background:transparent;border:none}.params-section-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:8px;padding-bottom:4px;border-bottom:1px solid var(--rpt-color-border, #e2e8f0)}.params-section-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:8px}.btn-paste-exec{display:inline-flex;align-items:center;gap:4px;font-size:.675rem;font-weight:600;color:#2563eb;background:#eff6ff;border:1px solid #bfdbfe;border-radius:4px;padding:3px 8px;cursor:pointer;transition:all .12s ease}.btn-paste-exec:hover{background:#2563eb;color:#fff}.exec-snippet-panel{display:flex;flex-direction:column;gap:6px;background:#f8fafc;border:1px solid #cbd5e1;border-radius:6px;padding:8px 10px;margin-bottom:10px}.snippet-hint{font-size:.675rem;color:#475569}.snippet-hint code{background:#e2e8f0;padding:1px 4px;border-radius:3px;font-family:monospace}.exec-snippet-textarea{width:100%;box-sizing:border-box;font-family:monospace;font-size:.7rem;padding:6px 8px;border:1px solid #cbd5e1;border-radius:4px;background:#fff;resize:vertical;min-height:54px}.exec-snippet-actions{display:flex;align-items:center;gap:6px}.btn-snippet-apply{display:inline-flex;align-items:center;gap:4px;font-size:.7rem;font-weight:600;padding:4px 10px;background:#16a34a;color:#fff;border:none;border-radius:4px;cursor:pointer}.btn-snippet-apply:hover{background:#15803d}.btn-snippet-cancel{font-size:.7rem;padding:4px 8px;background:#f1f5f9;color:#475569;border:1px solid #cbd5e1;border-radius:4px;cursor:pointer}.snippet-status{font-size:.675rem;padding:4px 6px;border-radius:4px}.snippet-status.is-success{background:#f0fdf4;color:#166534;border:1px solid #bbf7d0}.snippet-status.is-error{background:#fef2f2;color:#991b1b;border:1px solid #fecaca}.param-cards-list{display:flex;flex-direction:column;gap:10px;width:100%;box-sizing:border-box}.empty-params-hint{font-size:.725rem;color:#64748b;font-style:italic;padding:12px;text-align:center;background:#f8fafc;border:1px dashed #cbd5e1;border-radius:6px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { kind: "directive", type: i1.MaxValidator, selector: "input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]", inputs: ["max"] }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: RptIconComponent, selector: "rpt-icon", inputs: ["name", "size", "color", "strokeWidth"] }, { kind: "component", type: ParameterBindingEditorComponent, selector: "rpt-parameter-binding-editor", inputs: ["param", "currentValue", "allComponents", "currentComponentId", "isAdvancedMode"], outputs: ["valueChange", "linkedFieldChange"] }, { kind: "component", type: RptSearchableSelectComponent, selector: "rpt-searchable-select", inputs: ["options", "value", "placeholder", "searchPlaceholder", "disabled", "loading", "loadingText", "emptyText", "clearable", "searchable", "size", "id", "ariaLabel", "valueKey", "labelKey", "sublabelKey", "badgeKey", "panelMaxHeight", "openAbove"], outputs: ["valueChange", "selectionChange", "opened", "closed"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
347
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: PropertyEditorGridComponent, isStandalone: true, selector: "rpt-property-editor-grid", inputs: { grid: { classPropertyName: "grid", publicName: "grid", isSignal: true, isRequired: false, transformFunction: null }, dataSource: { classPropertyName: "dataSource", publicName: "dataSource", isSignal: true, isRequired: false, transformFunction: null }, availableEntities: { classPropertyName: "availableEntities", publicName: "availableEntities", isSignal: true, isRequired: false, transformFunction: null }, procedureParameters: { classPropertyName: "procedureParameters", publicName: "procedureParameters", isSignal: true, isRequired: false, transformFunction: null }, allComponents: { classPropertyName: "allComponents", publicName: "allComponents", isSignal: true, isRequired: false, transformFunction: null }, isDetecting: { classPropertyName: "isDetecting", publicName: "isDetecting", isSignal: true, isRequired: false, transformFunction: null }, statusMessage: { classPropertyName: "statusMessage", publicName: "statusMessage", isSignal: true, isRequired: false, transformFunction: null }, statusKind: { classPropertyName: "statusKind", publicName: "statusKind", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { addGrid: "addGrid", removeGrid: "removeGrid", addColumn: "addColumn", autoDetectColumns: "autoDetectColumns", removeColumn: "removeColumn", updateColumn: "updateColumn", updateOption: "updateOption", updateRowClickAction: "updateRowClickAction", setDataSource: "setDataSource", updateDataSourceParameters: "updateDataSourceParameters", entityChanged: "entityChanged" }, ngImport: i0, template: " @if (!grid()) {\n <div class=\"empty-grid-card\">\n <div class=\"empty-grid-icon\">\n <rpt-icon name=\"table\" [size]=\"28\" />\n </div>\n <h4 class=\"empty-grid-title\">No Result Grid Attached</h4>\n <p class=\"empty-grid-desc\">Attach an interactive Result Data Grid (or UltraGrid) to this report definition to render queries and stored procedure results.</p>\n <button type=\"button\" class=\"btn-create-grid-action\" (click)=\"addGrid.emit()\">\n <rpt-icon name=\"plus\" [size]=\"14\" />\n <span>+ Add Result Grid</span>\n </button>\n </div>\n } @else {\n <div class=\"props-form\">\n <!-- 1. Report Data Source & Stored Procedure Configuration -->\n <div class=\"property-group\">\n <div class=\"group-header-row\">\n <div class=\"group-title-wrap\">\n <span class=\"group-title\">Report Data Source</span>\n @if (activeEntityName()) {\n <span class=\"group-badge active-ds-badge\">{{ activeEntityName() }}</span>\n }\n </div>\n </div>\n\n <!-- Source Type Switcher (Stored Procedure vs Table vs REST API) -->\n <div class=\"source-type-switcher\">\n <button\n type=\"button\"\n class=\"source-tab-btn\"\n [class.active]=\"currentSourceType() === 'stored_procedure'\"\n (click)=\"onSourceTypeChange('stored_procedure')\"\n >\n <rpt-icon name=\"code\" [size]=\"12\" />\n <span>Stored Procedure</span>\n </button>\n <button\n type=\"button\"\n class=\"source-tab-btn\"\n [class.active]=\"currentSourceType() === 'table'\"\n (click)=\"onSourceTypeChange('table')\"\n >\n <rpt-icon name=\"table\" [size]=\"12\" />\n <span>Table / View</span>\n </button>\n <button\n type=\"button\"\n class=\"source-tab-btn\"\n [class.active]=\"currentSourceType() === 'api'\"\n (click)=\"onSourceTypeChange('api')\"\n >\n <rpt-icon name=\"globe\" [size]=\"12\" />\n <span>REST API</span>\n </button>\n </div>\n\n @if (currentSourceType() === 'api') {\n <!-- API Endpoint Selector / Input -->\n <div class=\"field-row\">\n <label class=\"field-label\">API Endpoint URL</label>\n @if (registeredApis().length > 0) {\n <div style=\"margin-bottom: 6px;\">\n <rpt-searchable-select\n [options]=\"registeredApis()\"\n [ngModel]=\"apiEndpoint()\"\n (ngModelChange)=\"onApiEndpointChange($event)\"\n placeholder=\"-- Select Registered Endpoint or type below --\"\n searchPlaceholder=\"Search registered APIs...\"\n />\n </div>\n }\n <input\n type=\"text\"\n class=\"form-control\"\n placeholder=\"e.g. /api/v1/orders or https://api.service.com/data\"\n [ngModel]=\"apiEndpoint()\"\n (ngModelChange)=\"onApiEndpointChange($event)\"\n />\n <span class=\"field-hint\" style=\"font-size: 11px; color: var(--rpt-color-text-muted, #64748b); margin-top: 4px; display: block;\">\n Direct HTTP call or backend proxy. Use <code>:param</code> for route tokens.\n </span>\n </div>\n\n <!-- HTTP Method & Data Path Grid -->\n <div class=\"field-grid-2\" style=\"display: grid; grid-template-columns: 1fr 1fr; gap: 8px;\">\n <div class=\"field-row\">\n <label class=\"field-label\">HTTP Method</label>\n <select\n class=\"form-control\"\n [ngModel]=\"apiMethod()\"\n (ngModelChange)=\"onApiMethodChange($event)\"\n >\n <option value=\"GET\">GET (Query String)</option>\n <option value=\"POST\">POST (Body Payload)</option>\n </select>\n </div>\n <div class=\"field-row\">\n <label class=\"field-label\">Response Data Path</label>\n <input\n type=\"text\"\n class=\"form-control\"\n placeholder=\"e.g. data.items, rows\"\n [ngModel]=\"apiDataPath()\"\n (ngModelChange)=\"onApiDataPathChange($event)\"\n />\n </div>\n </div>\n\n <!-- Use Proxy Toggle -->\n <div class=\"field-row checkbox-field-row\" style=\"margin-top: 4px;\">\n <label class=\"checkbox-label\" style=\"display: flex; align-items: center; gap: 6px; font-size: 12px; cursor: pointer;\">\n <input\n type=\"checkbox\"\n [checked]=\"apiUseProxy()\"\n (change)=\"onApiUseProxyChange($any($event.target).checked)\"\n />\n <span class=\"checkbox-text\">Route through backend proxy (bypasses CORS / hides credentials)</span>\n </label>\n </div>\n } @else {\n <!-- Entity Selector Dropdown -->\n <div class=\"field-row\">\n <label class=\"field-label\">\n {{ currentSourceType() === 'stored_procedure' ? 'Stored Procedure' : 'Table / View' }}\n </label>\n <rpt-searchable-select\n [options]=\"gridEntitySelectOptions()\"\n [ngModel]=\"activeEntityName()\"\n (ngModelChange)=\"onSelectEntity($event)\"\n placeholder=\"-- Choose Data Source --\"\n [searchPlaceholder]=\"currentSourceType() === 'stored_procedure' ? 'Search procedures...' : 'Search tables & views...'\"\n />\n </div>\n }\n\n <!-- Stored Procedure Parameter Mappings -->\n @if (currentSourceType() === 'stored_procedure' && activeEntityName()) {\n <div class=\"procedure-params-section\">\n <div class=\"params-section-header\">\n <div class=\"params-header-left\">\n <span class=\"params-title\">Procedure Parameters</span>\n <span class=\"params-count-badge\">{{ effectiveParameters().length }}</span>\n </div>\n <button\n type=\"button\"\n class=\"btn-paste-exec\"\n (click)=\"toggleExecSnippet()\"\n title=\"Paste full SSMS 'EXEC proc @param=val' snippet to fill parameters automatically\"\n >\n <rpt-icon name=\"code\" [size]=\"12\" />\n <span>{{ isExecSnippetOpen() ? 'Close SQL' : 'Paste SQL Exec' }}</span>\n </button>\n </div>\n\n @if (isExecSnippetOpen()) {\n <div class=\"exec-snippet-panel\">\n <div class=\"exec-snippet-header\">\n <span class=\"snippet-hint\">Paste full <code>EXEC ProcedureName &#64;param=val...</code> statement from SSMS:</span>\n </div>\n <textarea\n class=\"exec-snippet-textarea\"\n rows=\"3\"\n placeholder=\"e.g. exec Get_HelpList @chrCOMPANYID=N'101',@chrTableName=N'MSTACCTGLSUB'...\"\n [ngModel]=\"execSnippetText()\"\n (ngModelChange)=\"execSnippetText.set($event)\"\n ></textarea>\n <div class=\"exec-snippet-actions\">\n <button type=\"button\" class=\"btn-snippet-apply\" (click)=\"applyExecSnippet()\">\n <rpt-icon name=\"check\" [size]=\"12\" />\n <span>Apply Parameters</span>\n </button>\n <button type=\"button\" class=\"btn-snippet-cancel\" (click)=\"toggleExecSnippet()\">\n Cancel\n </button>\n </div>\n @if (execParseStatus()) {\n <div class=\"snippet-status\" [class.is-error]=\"execParseStatus()?.kind === 'error'\" [class.is-success]=\"execParseStatus()?.kind === 'success'\">\n {{ execParseStatus()?.message }}\n </div>\n }\n </div>\n }\n\n @if (effectiveParameters().length > 0) {\n <div class=\"param-cards-list\">\n @for (param of effectiveParameters(); track param.name) {\n <rpt-parameter-binding-editor\n [param]=\"param\"\n [currentValue]=\"getParameterValue(param.name)\"\n [allComponents]=\"allComponents()\"\n (valueChange)=\"onParameterChange(param.name, $event)\"\n />\n }\n </div>\n } @else {\n <div class=\"empty-params-hint\">\n <span>No required parameters for this procedure.</span>\n </div>\n }\n </div>\n }\n </div>\n\n <!-- 2. Result Columns Configuration -->\n <div class=\"property-group\">\n <div class=\"group-header-row\">\n <div class=\"group-title-wrap\">\n <span class=\"group-title\">Columns</span>\n <span class=\"group-badge\">{{ columns().length }}</span>\n </div>\n </div>\n\n <!-- Dedicated Full-Width Action Buttons (No cramping) -->\n <div class=\"columns-action-bar\">\n <button\n type=\"button\"\n class=\"btn-col-action btn-auto-detect\"\n (click)=\"autoDetectColumns.emit()\"\n [disabled]=\"isDetecting()\"\n title=\"Auto-detect all columns from procedure or data table\"\n >\n <rpt-icon name=\"refresh\" [size]=\"12\" [class.rpt-spin]=\"isDetecting()\" />\n <span>{{ isDetecting() ? 'Detecting...' : 'Auto-Detect' }}</span>\n </button>\n <button\n type=\"button\"\n class=\"btn-col-action btn-add-col\"\n (click)=\"addColumn.emit()\"\n title=\"Add a new column manually\"\n >\n <rpt-icon name=\"plus\" [size]=\"12\" />\n <span>+ Add Column</span>\n </button>\n </div>\n\n @if (statusMessage()) {\n <div class=\"col-status-banner\" [class.is-error]=\"statusKind() === 'error'\" [class.is-success]=\"statusKind() === 'success'\">\n <rpt-icon [name]=\"statusKind() === 'error' ? 'close' : 'check'\" [size]=\"12\" />\n <span>{{ statusMessage() }}</span>\n </div>\n }\n\n <div class=\"columns-editor-list\">\n @for (col of columns(); track col.field; let idx = $index) {\n <div class=\"col-edit-card\">\n <div class=\"col-card-header\">\n <div class=\"col-header-title-group\">\n <span class=\"col-drag-dots\">\u22EE\u22EE</span>\n <span class=\"col-idx-badge\">#{{ idx + 1 }}</span>\n <input\n type=\"text\"\n class=\"col-title-input\"\n placeholder=\"Column Label\"\n [ngModel]=\"col.label\"\n (ngModelChange)=\"onUpdateCol(idx, 'label', $event)\"\n />\n </div>\n <div class=\"col-card-actions\">\n <span class=\"col-type-pill\">{{ col.dataType || 'string' }}</span>\n <button\n type=\"button\"\n class=\"col-action-btn btn-delete\"\n (click)=\"removeColumn.emit(idx)\"\n title=\"Remove Column\"\n >\n <rpt-icon name=\"trash\" [size]=\"12\" />\n </button>\n </div>\n </div>\n\n <div class=\"col-card-body\">\n <div class=\"col-edit-fields\">\n <div class=\"col-field-item\">\n <span class=\"mini-label\">Field</span>\n <input\n type=\"text\"\n class=\"col-mini-input\"\n placeholder=\"field\"\n [ngModel]=\"col.field\"\n (ngModelChange)=\"onUpdateCol(idx, 'field', $event)\"\n />\n </div>\n <div class=\"col-field-item\">\n <span class=\"mini-label\">Type</span>\n <select\n class=\"col-mini-select\"\n [ngModel]=\"col.dataType || 'string'\"\n (ngModelChange)=\"onUpdateCol(idx, 'dataType', $event)\"\n >\n <option value=\"string\">String</option>\n <option value=\"number\">Number</option>\n <option value=\"currency\">Currency</option>\n <option value=\"date\">Date</option>\n <option value=\"boolean\">Boolean</option>\n </select>\n </div>\n <div class=\"col-field-item\">\n <span class=\"mini-label\">Format</span>\n <input\n type=\"text\"\n class=\"col-mini-input\"\n placeholder=\"e.g. dd/MM/yyyy\"\n [ngModel]=\"col.format\"\n (ngModelChange)=\"onUpdateCol(idx, 'format', $event)\"\n />\n </div>\n <div class=\"col-field-item\">\n <span class=\"mini-label\">Align</span>\n <select\n class=\"col-mini-select\"\n [ngModel]=\"col.align || 'left'\"\n (ngModelChange)=\"onUpdateCol(idx, 'align', $event)\"\n >\n <option value=\"left\">Left</option>\n <option value=\"center\">Center</option>\n <option value=\"right\">Right</option>\n </select>\n </div>\n <div class=\"col-field-item\">\n <span class=\"mini-label\">Aggregate</span>\n <select\n class=\"col-mini-select\"\n [ngModel]=\"col.aggregate || 'none'\"\n (ngModelChange)=\"onUpdateCol(idx, 'aggregate', $event === 'none' ? undefined : $event)\"\n >\n <option value=\"none\">None</option>\n <option value=\"sum\">Sum</option>\n <option value=\"avg\">Average</option>\n <option value=\"count\">Count</option>\n <option value=\"min\">Min</option>\n <option value=\"max\">Max</option>\n </select>\n </div>\n <div class=\"col-field-item\">\n <span class=\"mini-label\">Width</span>\n <input\n type=\"text\"\n class=\"col-mini-input\"\n placeholder=\"auto\"\n [ngModel]=\"col.width || ''\"\n (ngModelChange)=\"onUpdateCol(idx, 'width', $event || undefined)\"\n />\n </div>\n </div>\n\n <div class=\"col-card-footer\">\n <label class=\"col-checkbox-toggle\">\n <input\n type=\"checkbox\"\n [ngModel]=\"col.visible !== false\"\n (ngModelChange)=\"onUpdateCol(idx, 'visible', $event)\"\n />\n <span>Visible</span>\n </label>\n <label class=\"col-checkbox-toggle\">\n <input\n type=\"checkbox\"\n [ngModel]=\"col.checkboxSelection ?? false\"\n (ngModelChange)=\"onUpdateCol(idx, 'checkboxSelection', $event)\"\n />\n <span>Checkbox</span>\n </label>\n </div>\n </div>\n </div>\n }\n </div>\n </div>\n\n <!-- Grid Table Options Group -->\n <div class=\"property-group\">\n <div class=\"group-title\">Table Options</div>\n\n <div class=\"field-row\">\n <label class=\"checkbox-toggle\">\n <input\n type=\"checkbox\"\n [ngModel]=\"grid()?.options?.sideBar !== false\"\n (ngModelChange)=\"updateOption.emit({ field: 'sideBar', value: $event })\"\n />\n <span>Enable Side Panel (Tool Panels)</span>\n </label>\n </div>\n\n <div class=\"field-row\">\n <label class=\"checkbox-toggle\">\n <input\n type=\"checkbox\"\n [ngModel]=\"grid()?.options?.globalSearch !== false\"\n (ngModelChange)=\"updateOption.emit({ field: 'globalSearch', value: $event })\"\n />\n <span>Global Search Box</span>\n </label>\n </div>\n\n <div class=\"field-row\">\n <label class=\"checkbox-toggle\">\n <input\n type=\"checkbox\"\n [ngModel]=\"grid()?.options?.statusBar !== false\"\n (ngModelChange)=\"updateOption.emit({ field: 'statusBar', value: $event })\"\n />\n <span>Status Bar</span>\n </label>\n </div>\n\n <div class=\"field-row\">\n <label class=\"checkbox-toggle\">\n <input\n type=\"checkbox\"\n [ngModel]=\"grid()?.options?.pagination ?? true\"\n (ngModelChange)=\"updateOption.emit({ field: 'pagination', value: $event })\"\n />\n <span>Enable Pagination</span>\n </label>\n </div>\n\n <div class=\"field-row\">\n <label class=\"checkbox-toggle\">\n <input\n type=\"checkbox\"\n [ngModel]=\"grid()?.options?.selectable ?? false\"\n (ngModelChange)=\"updateOption.emit({ field: 'selectable', value: $event })\"\n />\n <span>Row Selection</span>\n </label>\n </div>\n\n @if (grid()?.options?.selectable) {\n <div class=\"field-row\">\n <label class=\"field-label\">Selection Mode</label>\n <select\n class=\"field-input\"\n [ngModel]=\"grid()?.options?.selectionMode ?? 'multiple'\"\n (ngModelChange)=\"updateOption.emit({ field: 'selectionMode', value: $event })\"\n >\n <option value=\"multiple\">Multiple Rows</option>\n <option value=\"single\">Single Row</option>\n </select>\n </div>\n\n <div class=\"field-row\">\n <label class=\"checkbox-toggle\">\n <input\n type=\"checkbox\"\n [ngModel]=\"grid()?.options?.checkboxSelection ?? true\"\n (ngModelChange)=\"updateOption.emit({ field: 'checkboxSelection', value: $event })\"\n />\n <span>Checkbox Selection</span>\n </label>\n </div>\n\n @if ((grid()?.options?.selectionMode ?? 'multiple') === 'multiple') {\n <div class=\"field-row\">\n <label class=\"checkbox-toggle\">\n <input\n type=\"checkbox\"\n [ngModel]=\"grid()?.options?.headerCheckboxSelection ?? true\"\n (ngModelChange)=\"updateOption.emit({ field: 'headerCheckboxSelection', value: $event })\"\n />\n <span>Header Select All Checkbox</span>\n </label>\n </div>\n }\n }\n\n <div class=\"field-row\">\n <label class=\"checkbox-toggle\">\n <input\n type=\"checkbox\"\n [ngModel]=\"grid()?.options?.allowColumnReorder ?? true\"\n (ngModelChange)=\"updateOption.emit({ field: 'allowColumnReorder', value: $event })\"\n />\n <span>Allow Column Reorder</span>\n </label>\n </div>\n\n <div class=\"field-row\">\n <label class=\"checkbox-toggle\">\n <input\n type=\"checkbox\"\n [ngModel]=\"grid()?.options?.allowExport ?? true\"\n (ngModelChange)=\"updateOption.emit({ field: 'allowExport', value: $event })\"\n />\n <span>Allow Export</span>\n </label>\n </div>\n\n <div class=\"field-row\">\n <label class=\"field-label\">Page Size</label>\n <input\n type=\"number\"\n class=\"field-input\"\n min=\"1\"\n max=\"1000\"\n (wheel)=\"$any($event.target).blur()\"\n (keydown.arrowup)=\"$event.preventDefault()\"\n (keydown.arrowdown)=\"$event.preventDefault()\"\n [ngModel]=\"grid()?.options?.pageSize ?? 10\"\n (ngModelChange)=\"updateOption.emit({ field: 'pageSize', value: +$event })\"\n />\n </div>\n\n <div class=\"field-row\">\n <label class=\"checkbox-toggle\">\n <input\n type=\"checkbox\"\n [ngModel]=\"grid()?.options?.showRowNumbers ?? true\"\n (ngModelChange)=\"updateOption.emit({ field: 'showRowNumbers', value: $event })\"\n />\n <span>Show Row Numbers</span>\n </label>\n </div>\n\n <div class=\"field-row\">\n <label class=\"checkbox-toggle\">\n <input\n type=\"checkbox\"\n [ngModel]=\"grid()?.options?.showFooter ?? true\"\n (ngModelChange)=\"updateOption.emit({ field: 'showFooter', value: $event })\"\n />\n <span>Show Footer Totals</span>\n </label>\n </div>\n </div>\n\n <!-- Row Click & Drill-Down Action Group -->\n <div class=\"property-group\">\n <div class=\"group-title\">Row Click & Drill-Down</div>\n\n <div class=\"field-row\">\n <label class=\"checkbox-toggle\">\n <input\n type=\"checkbox\"\n [ngModel]=\"hasRowClickAction()\"\n (ngModelChange)=\"toggleRowClickAction($event)\"\n />\n <span>Enable Row Click Action</span>\n </label>\n </div>\n\n @if (hasRowClickAction()) {\n <div class=\"field-row\">\n <label class=\"field-label\">Action Type</label>\n <select\n class=\"field-input field-select\"\n [ngModel]=\"rowClickAction()?.type || 'open-drawer'\"\n (ngModelChange)=\"updateRowActionField('type', $event)\"\n >\n <option value=\"open-drawer\">Slide-Over Detail Drawer</option>\n <option value=\"drilldown-report\">Drill-Down Report (Host Event)</option>\n <option value=\"navigate\">Navigate to URL</option>\n <option value=\"emit-custom\">Emit Custom Action</option>\n </select>\n </div>\n\n @if (rowClickAction()?.type === 'open-drawer' || rowClickAction()?.type === 'drilldown-report') {\n <div class=\"field-row\">\n <label class=\"field-label\">Target Report ID</label>\n <input\n type=\"text\"\n class=\"field-input\"\n placeholder=\"e.g. order-details\"\n [ngModel]=\"rowClickAction()?.targetReportId || ''\"\n (ngModelChange)=\"updateRowActionField('targetReportId', $event)\"\n />\n </div>\n\n <div class=\"field-row\">\n <label class=\"field-label\">Drawer Title</label>\n <input\n type=\"text\"\n class=\"field-input\"\n placeholder=\"e.g. Order Details\"\n [ngModel]=\"rowClickAction()?.drawerTitle || ''\"\n (ngModelChange)=\"updateRowActionField('drawerTitle', $event)\"\n />\n </div>\n\n <div class=\"field-row\">\n <label class=\"field-label\">Drawer Width</label>\n <input\n type=\"text\"\n class=\"field-input\"\n placeholder=\"e.g. 760px, 80%, 900px\"\n [ngModel]=\"rowClickAction()?.drawerWidth || '760px'\"\n (ngModelChange)=\"updateRowActionField('drawerWidth', $event)\"\n />\n </div>\n }\n\n @if (rowClickAction()?.type === 'navigate') {\n <div class=\"field-row\">\n <label class=\"field-label\">Target URL</label>\n <input\n type=\"text\"\n class=\"field-input\"\n [placeholder]=\"'/orders/{{row.orderId}} or https://...'\"\n [ngModel]=\"rowClickAction()?.targetUrl || ''\"\n (ngModelChange)=\"updateRowActionField('targetUrl', $event)\"\n />\n </div>\n <div class=\"field-row\">\n <label class=\"checkbox-toggle\">\n <input\n type=\"checkbox\"\n [ngModel]=\"rowClickAction()?.openNewTab ?? false\"\n (ngModelChange)=\"updateRowActionField('openNewTab', $event)\"\n />\n <span>Open in New Tab</span>\n </label>\n </div>\n }\n\n @if (rowClickAction()?.type === 'emit-custom') {\n <div class=\"field-row\">\n <label class=\"field-label\">Custom Action Name</label>\n <input\n type=\"text\"\n class=\"field-input\"\n placeholder=\"e.g. view-audit-trail\"\n [ngModel]=\"rowClickAction()?.customActionName || ''\"\n (ngModelChange)=\"updateRowActionField('customActionName', $event)\"\n />\n </div>\n }\n\n <div class=\"field-row\">\n <div class=\"field-label-row\">\n <label class=\"field-label\">Parameter Mapping</label>\n <button\n type=\"button\"\n class=\"btn-add-mapping\"\n (click)=\"addParameterMapping()\"\n >\n + Add Mapping\n </button>\n </div>\n\n @for (mapping of parameterMappings(); track mapping.key; let mIdx = $index) {\n <div class=\"mapping-pair-row\">\n <input\n type=\"text\"\n class=\"col-mini-input\"\n style=\"flex: 1;\"\n placeholder=\"Target (e.g. customerId)\"\n [ngModel]=\"mapping.key\"\n (ngModelChange)=\"updateMappingKey(mIdx, $event)\"\n />\n <span style=\"font-size: 0.75rem; color: #94a3b8;\">\u2190</span>\n <input\n type=\"text\"\n class=\"col-mini-input\"\n style=\"flex: 1;\"\n placeholder=\"Source (e.g. row.id)\"\n [ngModel]=\"mapping.value\"\n (ngModelChange)=\"updateMappingValue(mIdx, $event)\"\n />\n <button\n type=\"button\"\n class=\"col-action-btn btn-delete\"\n (click)=\"removeMapping(mIdx)\"\n title=\"Remove mapping\"\n >\n <rpt-icon name=\"trash\" [size]=\"11\" />\n </button>\n </div>\n }\n </div>\n }\n </div>\n\n <!-- Remove Grid Action -->\n <div class=\"grid-danger-zone\">\n <button type=\"button\" class=\"btn-remove-grid-action\" (click)=\"removeGrid.emit()\">\n <rpt-icon name=\"trash\" [size]=\"13\" />\n <span>Remove Grid from Report</span>\n </button>\n </div>\n </div>\n }", styles: [".property-group{display:flex;flex-direction:column;gap:12px}.group-title{font-size:.7rem;font-weight:700;color:var(--rpt-color-text-muted, #64748b);text-transform:uppercase;letter-spacing:.05em;line-height:1.2}.field-row{display:flex;flex-direction:column;gap:4px}.field-label-row{display:flex;align-items:center;justify-content:space-between}.field-badge-val{font-size:.65rem;font-weight:600;color:var(--rpt-color-primary, #2563eb);background:#eff6ff;border:1px solid #bfdbfe;padding:1px 6px;border-radius:9999px}.field-label{font-size:.7rem;font-weight:600;color:var(--rpt-color-text, #0f172a)}.field-input,.field-select,.field-textarea{width:100%;box-sizing:border-box;border:1px solid var(--rpt-color-border, #cbd5e1);border-radius:var(--rpt-border-radius-sm, 4px);padding:6px 10px;font-size:var(--rpt-font-size-sm, .75rem);color:var(--rpt-color-text, #0f172a);background:#fff;outline:none;transition:all var(--rpt-transition-speed, .15s) ease}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button,.field-input[type=number]::-webkit-inner-spin-button,.field-input[type=number]::-webkit-outer-spin-button{-webkit-appearance:none;margin:0}input[type=number],.field-input[type=number]{-moz-appearance:textfield;appearance:textfield}.field-select{appearance:none;-webkit-appearance:none;background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2364748b' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E\");background-repeat:no-repeat;background-position:right 10px center;background-size:13px 13px;padding-right:28px;cursor:pointer}.field-input:focus,.field-select:focus,.field-textarea:focus{border-color:var(--rpt-color-primary, #2563eb);box-shadow:var(--rpt-box-shadow-focus, 0 0 0 3px rgba(37, 99, 235, .25))}.checkbox-toggle{display:inline-flex;align-items:center;gap:8px;font-size:.75rem;font-weight:500;color:var(--rpt-color-text, #0f172a);cursor:pointer}.preset-pill-group{display:flex;flex-wrap:wrap;gap:4px;margin-top:4px}.preset-pill{background:#f1f5f9;border:1px solid #e2e8f0;border-radius:4px;padding:2px 8px;font-size:.65rem;font-weight:600;color:#475569;cursor:pointer;transition:all .12s ease}.preset-pill:hover{background:#e2e8f0;color:#0f172a;border-color:#cbd5e1}.preset-pill-active{background:var(--rpt-color-primary, #2563eb)!important;color:#fff!important;border-color:var(--rpt-color-primary, #2563eb)!important}.preset-pill-reset{color:var(--rpt-color-primary, #2563eb);background:#eff6ff;border-color:#bfdbfe}.preset-pill-reset:hover{background:#dbeafe;color:#1d4ed8;border-color:#93c5fd}\n", ".empty-grid-card{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:40px 16px;text-align:center;border:2px dashed #cbd5e1;border-radius:8px;background:#fff;margin:10px 0}.empty-grid-icon{width:48px;height:48px;border-radius:10px;background:#eff6ff;color:#2563eb;display:flex;align-items:center;justify-content:center;margin-bottom:12px}.empty-grid-title{font-size:.95rem;font-weight:700;color:#0f172a;margin:0 0 6px}.empty-grid-desc{font-size:.775rem;color:#64748b;margin:0 0 18px;line-height:1.4;max-width:280px}.btn-create-grid-action{display:inline-flex;align-items:center;gap:6px;padding:8px 16px;background:#2563eb;color:#fff;font-size:.775rem;font-weight:600;border:none;border-radius:6px;cursor:pointer;box-shadow:0 2px 4px #2563eb33;transition:all .15s ease}.btn-create-grid-action:hover{background:#1d4ed8;box-shadow:0 4px 8px #2563eb40}.grid-danger-zone{margin-top:10px;padding-top:16px;border-top:1px dashed #e2e8f0;display:flex;justify-content:center}.btn-remove-grid-action{display:inline-flex;align-items:center;gap:6px;background:#fee2e2;border:1px solid #fecaca;color:#dc2626;font-size:.75rem;font-weight:600;padding:6px 12px;border-radius:6px;cursor:pointer;transition:all .15s ease}.btn-remove-grid-action:hover{background:#fecaca;border-color:#f87171;color:#b91c1c}.props-form{display:flex;flex-direction:column;gap:20px}.group-header-row{display:flex;align-items:center;justify-content:space-between;margin-bottom:6px}.group-title-wrap{display:flex;align-items:center;gap:6px}.group-badge{font-size:.65rem;font-weight:700;color:#64748b;background:#f1f5f9;border:1px solid #e2e8f0;border-radius:10px;padding:1px 6px}.columns-action-bar{display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-bottom:12px}.btn-col-action{display:inline-flex;align-items:center;justify-content:center;gap:6px;padding:7px 8px;font-size:.725rem;font-weight:600;border-radius:6px;cursor:pointer;white-space:nowrap;transition:all .12s ease;box-sizing:border-box}.btn-col-action:disabled{opacity:.6;cursor:not-allowed}.btn-auto-detect{background:#eff6ff;border:1px solid #bfdbfe;color:#2563eb}.btn-auto-detect:hover:not(:disabled){background:#2563eb;color:#fff;border-color:#2563eb}.btn-add-col{background:#fff;border:1px solid var(--rpt-color-border, #cbd5e1);color:#334155}.btn-add-col:hover{background:#f8fafc;border-color:#94a3b8;color:#0f172a}.col-status-banner{display:flex;align-items:center;gap:6px;padding:6px 10px;border-radius:6px;font-size:.72rem;line-height:1.35;margin-bottom:10px;background:#f1f5f9;color:#334155;border:1px solid #cbd5e1}.col-status-banner.is-success{background:#f0fdf4;color:#166534;border-color:#bbf7d0}.col-status-banner.is-error{background:#fef2f2;color:#991b1b;border-color:#fecaca}@keyframes rpt-spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.rpt-spin{animation:rpt-spin 1s linear infinite}.columns-editor-list{display:flex;flex-direction:column;gap:10px}.col-edit-card{background:#fff;border:1.5px solid var(--rpt-color-border, #cbd5e1);border-radius:var(--rpt-border-radius, 6px);box-shadow:var(--rpt-box-shadow, 0 1px 2px rgba(0, 0, 0, .05));box-sizing:border-box;transition:all var(--rpt-transition-speed, .15s) ease;position:relative;overflow:hidden;display:flex;flex-direction:column}.col-edit-card:hover{border-color:var(--rpt-color-primary, #2563eb);box-shadow:0 4px 6px -1px #2563eb1a}.col-card-header{display:flex;align-items:center;justify-content:space-between;gap:6px;padding:5px 8px;background:var(--rpt-color-surface, #f8fafc);border-bottom:1px solid var(--rpt-color-border, #e2e8f0);min-height:32px;box-sizing:border-box}.col-header-title-group{display:flex;align-items:center;gap:5px;min-width:0;flex:1}.col-drag-dots{color:#94a3b8;font-size:.8rem;cursor:grab;-webkit-user-select:none;user-select:none;line-height:1;padding-left:2px}.col-idx-badge{font-size:.65rem;font-weight:700;color:#64748b;background:#e2e8f0;padding:1px 5px;border-radius:3px;letter-spacing:.02em}.col-title-input{flex:1;border:1px solid transparent;background:transparent;font-size:.75rem;font-weight:600;color:var(--rpt-color-text, #0f172a);padding:2px 6px;border-radius:4px;outline:none;transition:all .15s ease}.col-title-input:hover{border-color:#cbd5e1;background:#fff}.col-title-input:focus{border-color:var(--rpt-color-primary, #2563eb);background:#fff;box-shadow:0 0 0 2px #2563eb26}.col-card-actions{display:flex;align-items:center;gap:4px}.col-type-pill{font-size:.625rem;font-weight:700;color:#1e40af;background:#dbeafe;border:1px solid #bfdbfe;padding:1px 5px;border-radius:3px;text-transform:uppercase;letter-spacing:.04em}.col-action-btn{display:inline-flex;align-items:center;justify-content:center;background:none;border:none;color:var(--rpt-color-text-muted, #64748b);cursor:pointer;padding:3px;border-radius:4px;transition:all .15s ease}.col-action-btn.btn-delete:hover{color:var(--rpt-color-danger, #ef4444);background:#fee2e2}.col-card-body{padding:8px 10px;display:flex;flex-direction:column;gap:6px;background:#fff}.col-edit-fields{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:6px 8px}.col-field-item{display:flex;flex-direction:column;gap:2px;min-width:0}.mini-label{font-size:.625rem;font-weight:600;color:#64748b;letter-spacing:.02em}.col-mini-input,.col-mini-select{width:100%;box-sizing:border-box;border:1px solid var(--rpt-color-border, #cbd5e1);border-radius:3px;padding:3px 5px;font-size:.7rem;color:var(--rpt-color-text, #0f172a);background:#fff;outline:none;transition:all .12s ease}.col-mini-select{appearance:none;-webkit-appearance:none;background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2364748b' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E\");background-repeat:no-repeat;background-position:right 4px center;background-size:10px 10px;padding-right:16px;cursor:pointer}.col-mini-input:focus,.col-mini-select:focus{border-color:var(--rpt-color-primary, #2563eb);box-shadow:0 0 0 2px #2563eb26}.col-card-footer{display:flex;align-items:center;justify-content:flex-end;gap:12px;padding-top:4px;border-top:1px dashed #e2e8f0;margin-top:2px}.col-checkbox-toggle{display:inline-flex;align-items:center;gap:5px;font-size:.675rem;font-weight:500;color:#475569;cursor:pointer;-webkit-user-select:none;user-select:none}.btn-add-mapping{display:inline-flex;align-items:center;background:#eff6ff;border:1px solid #bfdbfe;color:#2563eb;font-size:.65rem;font-weight:600;padding:2px 6px;border-radius:4px;cursor:pointer;transition:all .12s ease}.btn-add-mapping:hover{background:#dbeafe}.mapping-pair-row{display:flex;align-items:center;gap:6px;margin-top:4px}.active-ds-badge{background:#eff6ff;color:#2563eb;font-size:.65rem;font-weight:700;padding:1px 6px;border-radius:4px;border:1px solid #bfdbfe;max-width:140px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.source-type-switcher{display:flex;background:#f1f5f9;border:1px solid var(--rpt-color-border, #cbd5e1);border-radius:6px;padding:2px;gap:2px;margin-bottom:12px}.source-tab-btn{flex:1;display:inline-flex;align-items:center;justify-content:center;gap:5px;padding:6px 4px;font-size:.725rem;font-weight:600;color:var(--rpt-color-text-muted, #64748b);background:transparent;border:none;border-radius:4px;cursor:pointer;transition:all .12s ease}.source-tab-btn:hover{color:var(--rpt-color-text, #0f172a)}.source-tab-btn.active{background:#fff;color:var(--rpt-color-primary, #2563eb);box-shadow:0 1px 2px #0000000f}.procedure-params-section{margin-top:14px;padding:0;background:transparent;border:none}.params-section-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:8px}.btn-paste-exec{display:inline-flex;align-items:center;gap:4px;font-size:.675rem;font-weight:600;color:#2563eb;background:#eff6ff;border:1px solid #bfdbfe;border-radius:4px;padding:3px 8px;cursor:pointer;transition:all .12s ease}.btn-paste-exec:hover{background:#2563eb;color:#fff}.exec-snippet-panel{display:flex;flex-direction:column;gap:6px;background:#f8fafc;border:1px solid #cbd5e1;border-radius:6px;padding:8px 10px;margin-bottom:10px}.snippet-hint{font-size:.675rem;color:#475569}.snippet-hint code{background:#e2e8f0;padding:1px 4px;border-radius:3px;font-family:monospace}.exec-snippet-textarea{width:100%;box-sizing:border-box;font-family:monospace;font-size:.7rem;padding:6px 8px;border:1px solid #cbd5e1;border-radius:4px;background:#fff;resize:vertical;min-height:54px}.exec-snippet-actions{display:flex;align-items:center;gap:6px}.btn-snippet-apply{display:inline-flex;align-items:center;gap:4px;font-size:.7rem;font-weight:600;padding:4px 10px;background:#16a34a;color:#fff;border:none;border-radius:4px;cursor:pointer}.btn-snippet-apply:hover{background:#15803d}.btn-snippet-cancel{font-size:.7rem;padding:4px 8px;background:#f1f5f9;color:#475569;border:1px solid #cbd5e1;border-radius:4px;cursor:pointer}.snippet-status{font-size:.675rem;padding:4px 6px;border-radius:4px}.snippet-status.is-success{background:#f0fdf4;color:#166534;border:1px solid #bbf7d0}.snippet-status.is-error{background:#fef2f2;color:#991b1b;border:1px solid #fecaca}.param-cards-list{display:flex;flex-direction:column;gap:10px;width:100%;box-sizing:border-box}.empty-params-hint{font-size:.725rem;color:#64748b;font-style:italic;padding:12px;text-align:center;background:#f8fafc;border:1px dashed #cbd5e1;border-radius:6px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { kind: "directive", type: i1.MaxValidator, selector: "input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]", inputs: ["max"] }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: RptIconComponent, selector: "rpt-icon", inputs: ["name", "size", "color", "strokeWidth"] }, { kind: "component", type: ParameterBindingEditorComponent, selector: "rpt-parameter-binding-editor", inputs: ["param", "currentValue", "allComponents", "currentComponentId", "isAdvancedMode"], outputs: ["valueChange", "linkedFieldChange"] }, { kind: "component", type: RptSearchableSelectComponent, selector: "rpt-searchable-select", inputs: ["options", "value", "placeholder", "searchPlaceholder", "disabled", "loading", "loadingText", "emptyText", "clearable", "searchable", "size", "id", "ariaLabel", "valueKey", "labelKey", "sublabelKey", "badgeKey", "panelMaxHeight", "openAbove"], outputs: ["valueChange", "selectionChange", "opened", "closed"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
248
348
  }
249
349
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: PropertyEditorGridComponent, decorators: [{
250
350
  type: Component,
@@ -254,6 +354,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
254
354
  RptIconComponent,
255
355
  ParameterBindingEditorComponent,
256
356
  RptSearchableSelectComponent,
257
- ], changeDetection: ChangeDetectionStrategy.OnPush, template: " @if (!grid()) {\n <div class=\"empty-grid-card\">\n <div class=\"empty-grid-icon\">\n <rpt-icon name=\"table\" [size]=\"28\" />\n </div>\n <h4 class=\"empty-grid-title\">No Result Grid Attached</h4>\n <p class=\"empty-grid-desc\">Attach an interactive Result Data Grid (or UltraGrid) to this report definition to render queries and stored procedure results.</p>\n <button type=\"button\" class=\"btn-create-grid-action\" (click)=\"addGrid.emit()\">\n <rpt-icon name=\"plus\" [size]=\"14\" />\n <span>+ Add Result Grid</span>\n </button>\n </div>\n } @else {\n <div class=\"props-form\">\n <!-- 1. Report Data Source & Stored Procedure Configuration -->\n <div class=\"property-group\">\n <div class=\"group-header-row\">\n <div class=\"group-title-wrap\">\n <span class=\"group-title\">Report Data Source</span>\n @if (activeEntityName()) {\n <span class=\"group-badge active-ds-badge\">{{ activeEntityName() }}</span>\n }\n </div>\n </div>\n\n <!-- Source Type Switcher (Stored Procedure vs Table) -->\n <div class=\"source-type-switcher\">\n <button\n type=\"button\"\n class=\"source-tab-btn\"\n [class.active]=\"currentSourceType() === 'stored_procedure'\"\n (click)=\"onSourceTypeChange('stored_procedure')\"\n >\n <rpt-icon name=\"code\" [size]=\"12\" />\n <span>Stored Procedure</span>\n </button>\n <button\n type=\"button\"\n class=\"source-tab-btn\"\n [class.active]=\"currentSourceType() === 'table'\"\n (click)=\"onSourceTypeChange('table')\"\n >\n <rpt-icon name=\"table\" [size]=\"12\" />\n <span>Table / View</span>\n </button>\n </div>\n\n <!-- Entity Selector Dropdown -->\n <div class=\"field-row\">\n <label class=\"field-label\">\n {{ currentSourceType() === 'stored_procedure' ? 'Stored Procedure' : 'Table / View' }}\n </label>\n <rpt-searchable-select\n [options]=\"gridEntitySelectOptions()\"\n [ngModel]=\"activeEntityName()\"\n (ngModelChange)=\"onSelectEntity($event)\"\n placeholder=\"-- Choose Data Source --\"\n [searchPlaceholder]=\"currentSourceType() === 'stored_procedure' ? 'Search procedures...' : 'Search tables & views...'\"\n />\n </div>\n\n <!-- Stored Procedure Parameter Mappings -->\n @if (currentSourceType() === 'stored_procedure' && activeEntityName()) {\n <div class=\"procedure-params-section\">\n <div class=\"params-section-header\">\n <div class=\"params-header-left\">\n <span class=\"params-title\">Procedure Parameters</span>\n <span class=\"params-count-badge\">{{ effectiveParameters().length }}</span>\n </div>\n <button\n type=\"button\"\n class=\"btn-paste-exec\"\n (click)=\"toggleExecSnippet()\"\n title=\"Paste full SSMS 'EXEC proc @param=val' snippet to fill parameters automatically\"\n >\n <rpt-icon name=\"code\" [size]=\"12\" />\n <span>{{ isExecSnippetOpen() ? 'Close SQL' : 'Paste SQL Exec' }}</span>\n </button>\n </div>\n\n @if (isExecSnippetOpen()) {\n <div class=\"exec-snippet-panel\">\n <div class=\"exec-snippet-header\">\n <span class=\"snippet-hint\">Paste full <code>EXEC ProcedureName &#64;param=val...</code> statement from SSMS:</span>\n </div>\n <textarea\n class=\"exec-snippet-textarea\"\n rows=\"3\"\n placeholder=\"e.g. exec Get_HelpList @chrCOMPANYID=N'101',@chrTableName=N'MSTACCTGLSUB'...\"\n [ngModel]=\"execSnippetText()\"\n (ngModelChange)=\"execSnippetText.set($event)\"\n ></textarea>\n <div class=\"exec-snippet-actions\">\n <button type=\"button\" class=\"btn-snippet-apply\" (click)=\"applyExecSnippet()\">\n <rpt-icon name=\"check\" [size]=\"12\" />\n <span>Apply Parameters</span>\n </button>\n <button type=\"button\" class=\"btn-snippet-cancel\" (click)=\"toggleExecSnippet()\">\n Cancel\n </button>\n </div>\n @if (execParseStatus()) {\n <div class=\"snippet-status\" [class.is-error]=\"execParseStatus()?.kind === 'error'\" [class.is-success]=\"execParseStatus()?.kind === 'success'\">\n {{ execParseStatus()?.message }}\n </div>\n }\n </div>\n }\n\n @if (effectiveParameters().length > 0) {\n <div class=\"param-cards-list\">\n @for (param of effectiveParameters(); track param.name) {\n <rpt-parameter-binding-editor\n [param]=\"param\"\n [currentValue]=\"getParameterValue(param.name)\"\n [allComponents]=\"allComponents()\"\n (valueChange)=\"onParameterChange(param.name, $event)\"\n />\n }\n </div>\n } @else {\n <div class=\"empty-params-hint\">\n <span>No required parameters for this procedure.</span>\n </div>\n }\n </div>\n }\n </div>\n\n <!-- 2. Result Columns Configuration -->\n <div class=\"property-group\">\n <div class=\"group-header-row\">\n <div class=\"group-title-wrap\">\n <span class=\"group-title\">Columns</span>\n <span class=\"group-badge\">{{ columns().length }}</span>\n </div>\n </div>\n\n <!-- Dedicated Full-Width Action Buttons (No cramping) -->\n <div class=\"columns-action-bar\">\n <button\n type=\"button\"\n class=\"btn-col-action btn-auto-detect\"\n (click)=\"autoDetectColumns.emit()\"\n [disabled]=\"isDetecting()\"\n title=\"Auto-detect all columns from procedure or data table\"\n >\n <rpt-icon name=\"refresh\" [size]=\"12\" [class.rpt-spin]=\"isDetecting()\" />\n <span>{{ isDetecting() ? 'Detecting...' : 'Auto-Detect' }}</span>\n </button>\n <button\n type=\"button\"\n class=\"btn-col-action btn-add-col\"\n (click)=\"addColumn.emit()\"\n title=\"Add a new column manually\"\n >\n <rpt-icon name=\"plus\" [size]=\"12\" />\n <span>+ Add Column</span>\n </button>\n </div>\n\n @if (statusMessage()) {\n <div class=\"col-status-banner\" [class.is-error]=\"statusKind() === 'error'\" [class.is-success]=\"statusKind() === 'success'\">\n <rpt-icon [name]=\"statusKind() === 'error' ? 'close' : 'check'\" [size]=\"12\" />\n <span>{{ statusMessage() }}</span>\n </div>\n }\n\n <div class=\"columns-editor-list\">\n @for (col of columns(); track col.field; let idx = $index) {\n <div class=\"col-edit-card\">\n <div class=\"col-card-header\">\n <div class=\"col-header-title-group\">\n <span class=\"col-drag-dots\">\u22EE\u22EE</span>\n <span class=\"col-idx-badge\">#{{ idx + 1 }}</span>\n <input\n type=\"text\"\n class=\"col-title-input\"\n placeholder=\"Column Label\"\n [ngModel]=\"col.label\"\n (ngModelChange)=\"onUpdateCol(idx, 'label', $event)\"\n />\n </div>\n <div class=\"col-card-actions\">\n <span class=\"col-type-pill\">{{ col.dataType || 'string' }}</span>\n <button\n type=\"button\"\n class=\"col-action-btn btn-delete\"\n (click)=\"removeColumn.emit(idx)\"\n title=\"Remove Column\"\n >\n <rpt-icon name=\"trash\" [size]=\"12\" />\n </button>\n </div>\n </div>\n\n <div class=\"col-card-body\">\n <div class=\"col-edit-fields\">\n <div class=\"col-field-item\">\n <span class=\"mini-label\">Field</span>\n <input\n type=\"text\"\n class=\"col-mini-input\"\n placeholder=\"field\"\n [ngModel]=\"col.field\"\n (ngModelChange)=\"onUpdateCol(idx, 'field', $event)\"\n />\n </div>\n <div class=\"col-field-item\">\n <span class=\"mini-label\">Type</span>\n <select\n class=\"col-mini-select\"\n [ngModel]=\"col.dataType || 'string'\"\n (ngModelChange)=\"onUpdateCol(idx, 'dataType', $event)\"\n >\n <option value=\"string\">String</option>\n <option value=\"number\">Number</option>\n <option value=\"currency\">Currency</option>\n <option value=\"date\">Date</option>\n <option value=\"boolean\">Boolean</option>\n </select>\n </div>\n <div class=\"col-field-item\">\n <span class=\"mini-label\">Format</span>\n <input\n type=\"text\"\n class=\"col-mini-input\"\n placeholder=\"e.g. dd/MM/yyyy\"\n [ngModel]=\"col.format\"\n (ngModelChange)=\"onUpdateCol(idx, 'format', $event)\"\n />\n </div>\n <div class=\"col-field-item\">\n <span class=\"mini-label\">Align</span>\n <select\n class=\"col-mini-select\"\n [ngModel]=\"col.align || 'left'\"\n (ngModelChange)=\"onUpdateCol(idx, 'align', $event)\"\n >\n <option value=\"left\">Left</option>\n <option value=\"center\">Center</option>\n <option value=\"right\">Right</option>\n </select>\n </div>\n <div class=\"col-field-item\">\n <span class=\"mini-label\">Aggregate</span>\n <select\n class=\"col-mini-select\"\n [ngModel]=\"col.aggregate || 'none'\"\n (ngModelChange)=\"onUpdateCol(idx, 'aggregate', $event === 'none' ? undefined : $event)\"\n >\n <option value=\"none\">None</option>\n <option value=\"sum\">Sum</option>\n <option value=\"avg\">Average</option>\n <option value=\"count\">Count</option>\n <option value=\"min\">Min</option>\n <option value=\"max\">Max</option>\n </select>\n </div>\n <div class=\"col-field-item\">\n <span class=\"mini-label\">Width</span>\n <input\n type=\"text\"\n class=\"col-mini-input\"\n placeholder=\"auto\"\n [ngModel]=\"col.width || ''\"\n (ngModelChange)=\"onUpdateCol(idx, 'width', $event || undefined)\"\n />\n </div>\n </div>\n\n <div class=\"col-card-footer\">\n <label class=\"col-checkbox-toggle\">\n <input\n type=\"checkbox\"\n [ngModel]=\"col.visible !== false\"\n (ngModelChange)=\"onUpdateCol(idx, 'visible', $event)\"\n />\n <span>Visible</span>\n </label>\n <label class=\"col-checkbox-toggle\">\n <input\n type=\"checkbox\"\n [ngModel]=\"col.checkboxSelection ?? false\"\n (ngModelChange)=\"onUpdateCol(idx, 'checkboxSelection', $event)\"\n />\n <span>Checkbox</span>\n </label>\n </div>\n </div>\n </div>\n }\n </div>\n </div>\n\n <!-- Grid Table Options Group -->\n <div class=\"property-group\">\n <div class=\"group-title\">Table Options</div>\n\n <div class=\"field-row\">\n <label class=\"checkbox-toggle\">\n <input\n type=\"checkbox\"\n [ngModel]=\"grid()?.options?.sideBar !== false\"\n (ngModelChange)=\"updateOption.emit({ field: 'sideBar', value: $event })\"\n />\n <span>Enable Side Panel (Tool Panels)</span>\n </label>\n </div>\n\n <div class=\"field-row\">\n <label class=\"checkbox-toggle\">\n <input\n type=\"checkbox\"\n [ngModel]=\"grid()?.options?.globalSearch !== false\"\n (ngModelChange)=\"updateOption.emit({ field: 'globalSearch', value: $event })\"\n />\n <span>Global Search Box</span>\n </label>\n </div>\n\n <div class=\"field-row\">\n <label class=\"checkbox-toggle\">\n <input\n type=\"checkbox\"\n [ngModel]=\"grid()?.options?.statusBar !== false\"\n (ngModelChange)=\"updateOption.emit({ field: 'statusBar', value: $event })\"\n />\n <span>Status Bar</span>\n </label>\n </div>\n\n <div class=\"field-row\">\n <label class=\"checkbox-toggle\">\n <input\n type=\"checkbox\"\n [ngModel]=\"grid()?.options?.pagination ?? true\"\n (ngModelChange)=\"updateOption.emit({ field: 'pagination', value: $event })\"\n />\n <span>Enable Pagination</span>\n </label>\n </div>\n\n <div class=\"field-row\">\n <label class=\"checkbox-toggle\">\n <input\n type=\"checkbox\"\n [ngModel]=\"grid()?.options?.selectable ?? false\"\n (ngModelChange)=\"updateOption.emit({ field: 'selectable', value: $event })\"\n />\n <span>Row Selection</span>\n </label>\n </div>\n\n @if (grid()?.options?.selectable) {\n <div class=\"field-row\">\n <label class=\"field-label\">Selection Mode</label>\n <select\n class=\"field-input\"\n [ngModel]=\"grid()?.options?.selectionMode ?? 'multiple'\"\n (ngModelChange)=\"updateOption.emit({ field: 'selectionMode', value: $event })\"\n >\n <option value=\"multiple\">Multiple Rows</option>\n <option value=\"single\">Single Row</option>\n </select>\n </div>\n\n <div class=\"field-row\">\n <label class=\"checkbox-toggle\">\n <input\n type=\"checkbox\"\n [ngModel]=\"grid()?.options?.checkboxSelection ?? true\"\n (ngModelChange)=\"updateOption.emit({ field: 'checkboxSelection', value: $event })\"\n />\n <span>Checkbox Selection</span>\n </label>\n </div>\n\n @if ((grid()?.options?.selectionMode ?? 'multiple') === 'multiple') {\n <div class=\"field-row\">\n <label class=\"checkbox-toggle\">\n <input\n type=\"checkbox\"\n [ngModel]=\"grid()?.options?.headerCheckboxSelection ?? true\"\n (ngModelChange)=\"updateOption.emit({ field: 'headerCheckboxSelection', value: $event })\"\n />\n <span>Header Select All Checkbox</span>\n </label>\n </div>\n }\n }\n\n <div class=\"field-row\">\n <label class=\"checkbox-toggle\">\n <input\n type=\"checkbox\"\n [ngModel]=\"grid()?.options?.allowColumnReorder ?? true\"\n (ngModelChange)=\"updateOption.emit({ field: 'allowColumnReorder', value: $event })\"\n />\n <span>Allow Column Reorder</span>\n </label>\n </div>\n\n <div class=\"field-row\">\n <label class=\"checkbox-toggle\">\n <input\n type=\"checkbox\"\n [ngModel]=\"grid()?.options?.allowExport ?? true\"\n (ngModelChange)=\"updateOption.emit({ field: 'allowExport', value: $event })\"\n />\n <span>Allow Export</span>\n </label>\n </div>\n\n <div class=\"field-row\">\n <label class=\"field-label\">Page Size</label>\n <input\n type=\"number\"\n class=\"field-input\"\n min=\"1\"\n max=\"1000\"\n (wheel)=\"$any($event.target).blur()\"\n (keydown.arrowup)=\"$event.preventDefault()\"\n (keydown.arrowdown)=\"$event.preventDefault()\"\n [ngModel]=\"grid()?.options?.pageSize ?? 10\"\n (ngModelChange)=\"updateOption.emit({ field: 'pageSize', value: +$event })\"\n />\n </div>\n\n <div class=\"field-row\">\n <label class=\"checkbox-toggle\">\n <input\n type=\"checkbox\"\n [ngModel]=\"grid()?.options?.showRowNumbers ?? true\"\n (ngModelChange)=\"updateOption.emit({ field: 'showRowNumbers', value: $event })\"\n />\n <span>Show Row Numbers</span>\n </label>\n </div>\n\n <div class=\"field-row\">\n <label class=\"checkbox-toggle\">\n <input\n type=\"checkbox\"\n [ngModel]=\"grid()?.options?.showFooter ?? true\"\n (ngModelChange)=\"updateOption.emit({ field: 'showFooter', value: $event })\"\n />\n <span>Show Footer Totals</span>\n </label>\n </div>\n </div>\n\n <!-- Row Click & Drill-Down Action Group -->\n <div class=\"property-group\">\n <div class=\"group-title\">Row Click & Drill-Down</div>\n\n <div class=\"field-row\">\n <label class=\"checkbox-toggle\">\n <input\n type=\"checkbox\"\n [ngModel]=\"hasRowClickAction()\"\n (ngModelChange)=\"toggleRowClickAction($event)\"\n />\n <span>Enable Row Click Action</span>\n </label>\n </div>\n\n @if (hasRowClickAction()) {\n <div class=\"field-row\">\n <label class=\"field-label\">Action Type</label>\n <select\n class=\"field-input field-select\"\n [ngModel]=\"rowClickAction()?.type || 'open-drawer'\"\n (ngModelChange)=\"updateRowActionField('type', $event)\"\n >\n <option value=\"open-drawer\">Slide-Over Detail Drawer</option>\n <option value=\"drilldown-report\">Drill-Down Report (Host Event)</option>\n <option value=\"navigate\">Navigate to URL</option>\n <option value=\"emit-custom\">Emit Custom Action</option>\n </select>\n </div>\n\n @if (rowClickAction()?.type === 'open-drawer' || rowClickAction()?.type === 'drilldown-report') {\n <div class=\"field-row\">\n <label class=\"field-label\">Target Report ID</label>\n <input\n type=\"text\"\n class=\"field-input\"\n placeholder=\"e.g. order-details\"\n [ngModel]=\"rowClickAction()?.targetReportId || ''\"\n (ngModelChange)=\"updateRowActionField('targetReportId', $event)\"\n />\n </div>\n\n <div class=\"field-row\">\n <label class=\"field-label\">Drawer Title</label>\n <input\n type=\"text\"\n class=\"field-input\"\n placeholder=\"e.g. Order Details\"\n [ngModel]=\"rowClickAction()?.drawerTitle || ''\"\n (ngModelChange)=\"updateRowActionField('drawerTitle', $event)\"\n />\n </div>\n\n <div class=\"field-row\">\n <label class=\"field-label\">Drawer Width</label>\n <input\n type=\"text\"\n class=\"field-input\"\n placeholder=\"e.g. 760px, 80%, 900px\"\n [ngModel]=\"rowClickAction()?.drawerWidth || '760px'\"\n (ngModelChange)=\"updateRowActionField('drawerWidth', $event)\"\n />\n </div>\n }\n\n @if (rowClickAction()?.type === 'navigate') {\n <div class=\"field-row\">\n <label class=\"field-label\">Target URL</label>\n <input\n type=\"text\"\n class=\"field-input\"\n [placeholder]=\"'/orders/{{row.orderId}} or https://...'\"\n [ngModel]=\"rowClickAction()?.targetUrl || ''\"\n (ngModelChange)=\"updateRowActionField('targetUrl', $event)\"\n />\n </div>\n <div class=\"field-row\">\n <label class=\"checkbox-toggle\">\n <input\n type=\"checkbox\"\n [ngModel]=\"rowClickAction()?.openNewTab ?? false\"\n (ngModelChange)=\"updateRowActionField('openNewTab', $event)\"\n />\n <span>Open in New Tab</span>\n </label>\n </div>\n }\n\n @if (rowClickAction()?.type === 'emit-custom') {\n <div class=\"field-row\">\n <label class=\"field-label\">Custom Action Name</label>\n <input\n type=\"text\"\n class=\"field-input\"\n placeholder=\"e.g. view-audit-trail\"\n [ngModel]=\"rowClickAction()?.customActionName || ''\"\n (ngModelChange)=\"updateRowActionField('customActionName', $event)\"\n />\n </div>\n }\n\n <div class=\"field-row\">\n <div class=\"field-label-row\">\n <label class=\"field-label\">Parameter Mapping</label>\n <button\n type=\"button\"\n class=\"btn-add-mapping\"\n (click)=\"addParameterMapping()\"\n >\n + Add Mapping\n </button>\n </div>\n\n @for (mapping of parameterMappings(); track mapping.key; let mIdx = $index) {\n <div class=\"mapping-pair-row\">\n <input\n type=\"text\"\n class=\"col-mini-input\"\n style=\"flex: 1;\"\n placeholder=\"Target (e.g. customerId)\"\n [ngModel]=\"mapping.key\"\n (ngModelChange)=\"updateMappingKey(mIdx, $event)\"\n />\n <span style=\"font-size: 0.75rem; color: #94a3b8;\">\u2190</span>\n <input\n type=\"text\"\n class=\"col-mini-input\"\n style=\"flex: 1;\"\n placeholder=\"Source (e.g. row.id)\"\n [ngModel]=\"mapping.value\"\n (ngModelChange)=\"updateMappingValue(mIdx, $event)\"\n />\n <button\n type=\"button\"\n class=\"col-action-btn btn-delete\"\n (click)=\"removeMapping(mIdx)\"\n title=\"Remove mapping\"\n >\n <rpt-icon name=\"trash\" [size]=\"11\" />\n </button>\n </div>\n }\n </div>\n }\n </div>\n\n <!-- Remove Grid Action -->\n <div class=\"grid-danger-zone\">\n <button type=\"button\" class=\"btn-remove-grid-action\" (click)=\"removeGrid.emit()\">\n <rpt-icon name=\"trash\" [size]=\"13\" />\n <span>Remove Grid from Report</span>\n </button>\n </div>\n </div>\n }", styles: [".property-group{display:flex;flex-direction:column;gap:12px}.group-title{font-size:.7rem;font-weight:700;color:var(--rpt-color-text-muted, #64748b);text-transform:uppercase;letter-spacing:.05em;border-bottom:1px solid var(--rpt-color-border, #e2e8f0);padding-bottom:4px}.field-row{display:flex;flex-direction:column;gap:4px}.field-label-row{display:flex;align-items:center;justify-content:space-between}.field-badge-val{font-size:.65rem;font-weight:600;color:var(--rpt-color-primary, #2563eb);background:#eff6ff;border:1px solid #bfdbfe;padding:1px 6px;border-radius:9999px}.field-label{font-size:.7rem;font-weight:600;color:var(--rpt-color-text, #0f172a)}.field-input,.field-select,.field-textarea{width:100%;box-sizing:border-box;border:1px solid var(--rpt-color-border, #cbd5e1);border-radius:var(--rpt-border-radius-sm, 4px);padding:6px 10px;font-size:var(--rpt-font-size-sm, .75rem);color:var(--rpt-color-text, #0f172a);background:#fff;outline:none;transition:all var(--rpt-transition-speed, .15s) ease}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button,.field-input[type=number]::-webkit-inner-spin-button,.field-input[type=number]::-webkit-outer-spin-button{-webkit-appearance:none;margin:0}input[type=number],.field-input[type=number]{-moz-appearance:textfield;appearance:textfield}.field-select{appearance:none;-webkit-appearance:none;background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2364748b' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E\");background-repeat:no-repeat;background-position:right 10px center;background-size:13px 13px;padding-right:28px;cursor:pointer}.field-input:focus,.field-select:focus,.field-textarea:focus{border-color:var(--rpt-color-primary, #2563eb);box-shadow:var(--rpt-box-shadow-focus, 0 0 0 3px rgba(37, 99, 235, .25))}.checkbox-toggle{display:inline-flex;align-items:center;gap:8px;font-size:.75rem;font-weight:500;color:var(--rpt-color-text, #0f172a);cursor:pointer}.preset-pill-group{display:flex;flex-wrap:wrap;gap:4px;margin-top:4px}.preset-pill{background:#f1f5f9;border:1px solid #e2e8f0;border-radius:4px;padding:2px 8px;font-size:.65rem;font-weight:600;color:#475569;cursor:pointer;transition:all .12s ease}.preset-pill:hover{background:#e2e8f0;color:#0f172a;border-color:#cbd5e1}.preset-pill-active{background:var(--rpt-color-primary, #2563eb)!important;color:#fff!important;border-color:var(--rpt-color-primary, #2563eb)!important}.preset-pill-reset{color:var(--rpt-color-primary, #2563eb);background:#eff6ff;border-color:#bfdbfe}.preset-pill-reset:hover{background:#dbeafe;color:#1d4ed8;border-color:#93c5fd}\n", ".empty-grid-card{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:40px 16px;text-align:center;border:2px dashed #cbd5e1;border-radius:8px;background:#fff;margin:10px 0}.empty-grid-icon{width:48px;height:48px;border-radius:10px;background:#eff6ff;color:#2563eb;display:flex;align-items:center;justify-content:center;margin-bottom:12px}.empty-grid-title{font-size:.95rem;font-weight:700;color:#0f172a;margin:0 0 6px}.empty-grid-desc{font-size:.775rem;color:#64748b;margin:0 0 18px;line-height:1.4;max-width:280px}.btn-create-grid-action{display:inline-flex;align-items:center;gap:6px;padding:8px 16px;background:#2563eb;color:#fff;font-size:.775rem;font-weight:600;border:none;border-radius:6px;cursor:pointer;box-shadow:0 2px 4px #2563eb33;transition:all .15s ease}.btn-create-grid-action:hover{background:#1d4ed8;box-shadow:0 4px 8px #2563eb40}.grid-danger-zone{margin-top:10px;padding-top:16px;border-top:1px dashed #e2e8f0;display:flex;justify-content:center}.btn-remove-grid-action{display:inline-flex;align-items:center;gap:6px;background:#fee2e2;border:1px solid #fecaca;color:#dc2626;font-size:.75rem;font-weight:600;padding:6px 12px;border-radius:6px;cursor:pointer;transition:all .15s ease}.btn-remove-grid-action:hover{background:#fecaca;border-color:#f87171;color:#b91c1c}.props-form{display:flex;flex-direction:column;gap:20px}.group-header-row{display:flex;align-items:center;justify-content:space-between;border-bottom:1px solid var(--rpt-color-border, #e2e8f0);padding-bottom:6px;margin-bottom:8px}.group-title-wrap{display:flex;align-items:center;gap:6px}.group-badge{font-size:.65rem;font-weight:700;color:#64748b;background:#f1f5f9;border:1px solid #e2e8f0;border-radius:10px;padding:1px 6px}.columns-action-bar{display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-bottom:12px}.btn-col-action{display:inline-flex;align-items:center;justify-content:center;gap:6px;padding:7px 8px;font-size:.725rem;font-weight:600;border-radius:6px;cursor:pointer;white-space:nowrap;transition:all .12s ease;box-sizing:border-box}.btn-col-action:disabled{opacity:.6;cursor:not-allowed}.btn-auto-detect{background:#eff6ff;border:1px solid #bfdbfe;color:#2563eb}.btn-auto-detect:hover:not(:disabled){background:#2563eb;color:#fff;border-color:#2563eb}.btn-add-col{background:#fff;border:1px solid var(--rpt-color-border, #cbd5e1);color:#334155}.btn-add-col:hover{background:#f8fafc;border-color:#94a3b8;color:#0f172a}.col-status-banner{display:flex;align-items:center;gap:6px;padding:6px 10px;border-radius:6px;font-size:.72rem;line-height:1.35;margin-bottom:10px;background:#f1f5f9;color:#334155;border:1px solid #cbd5e1}.col-status-banner.is-success{background:#f0fdf4;color:#166534;border-color:#bbf7d0}.col-status-banner.is-error{background:#fef2f2;color:#991b1b;border-color:#fecaca}@keyframes rpt-spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.rpt-spin{animation:rpt-spin 1s linear infinite}.columns-editor-list{display:flex;flex-direction:column;gap:10px}.col-edit-card{background:#fff;border:1.5px solid var(--rpt-color-border, #cbd5e1);border-radius:var(--rpt-border-radius, 6px);box-shadow:var(--rpt-box-shadow, 0 1px 2px rgba(0, 0, 0, .05));box-sizing:border-box;transition:all var(--rpt-transition-speed, .15s) ease;position:relative;overflow:hidden;display:flex;flex-direction:column}.col-edit-card:hover{border-color:var(--rpt-color-primary, #2563eb);box-shadow:0 4px 6px -1px #2563eb1a}.col-card-header{display:flex;align-items:center;justify-content:space-between;gap:6px;padding:5px 8px;background:var(--rpt-color-surface, #f8fafc);border-bottom:1px solid var(--rpt-color-border, #e2e8f0);min-height:32px;box-sizing:border-box}.col-header-title-group{display:flex;align-items:center;gap:5px;min-width:0;flex:1}.col-drag-dots{color:#94a3b8;font-size:.8rem;cursor:grab;-webkit-user-select:none;user-select:none;line-height:1;padding-left:2px}.col-idx-badge{font-size:.65rem;font-weight:700;color:#64748b;background:#e2e8f0;padding:1px 5px;border-radius:3px;letter-spacing:.02em}.col-title-input{flex:1;border:1px solid transparent;background:transparent;font-size:.75rem;font-weight:600;color:var(--rpt-color-text, #0f172a);padding:2px 6px;border-radius:4px;outline:none;transition:all .15s ease}.col-title-input:hover{border-color:#cbd5e1;background:#fff}.col-title-input:focus{border-color:var(--rpt-color-primary, #2563eb);background:#fff;box-shadow:0 0 0 2px #2563eb26}.col-card-actions{display:flex;align-items:center;gap:4px}.col-type-pill{font-size:.625rem;font-weight:700;color:#1e40af;background:#dbeafe;border:1px solid #bfdbfe;padding:1px 5px;border-radius:3px;text-transform:uppercase;letter-spacing:.04em}.col-action-btn{display:inline-flex;align-items:center;justify-content:center;background:none;border:none;color:var(--rpt-color-text-muted, #64748b);cursor:pointer;padding:3px;border-radius:4px;transition:all .15s ease}.col-action-btn.btn-delete:hover{color:var(--rpt-color-danger, #ef4444);background:#fee2e2}.col-card-body{padding:8px 10px;display:flex;flex-direction:column;gap:6px;background:#fff}.col-edit-fields{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:6px 8px}.col-field-item{display:flex;flex-direction:column;gap:2px;min-width:0}.mini-label{font-size:.625rem;font-weight:600;color:#64748b;letter-spacing:.02em}.col-mini-input,.col-mini-select{width:100%;box-sizing:border-box;border:1px solid var(--rpt-color-border, #cbd5e1);border-radius:3px;padding:3px 5px;font-size:.7rem;color:var(--rpt-color-text, #0f172a);background:#fff;outline:none;transition:all .12s ease}.col-mini-select{appearance:none;-webkit-appearance:none;background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2364748b' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E\");background-repeat:no-repeat;background-position:right 4px center;background-size:10px 10px;padding-right:16px;cursor:pointer}.col-mini-input:focus,.col-mini-select:focus{border-color:var(--rpt-color-primary, #2563eb);box-shadow:0 0 0 2px #2563eb26}.col-card-footer{display:flex;align-items:center;justify-content:flex-end;gap:12px;padding-top:4px;border-top:1px dashed #e2e8f0;margin-top:2px}.col-checkbox-toggle{display:inline-flex;align-items:center;gap:5px;font-size:.675rem;font-weight:500;color:#475569;cursor:pointer;-webkit-user-select:none;user-select:none}.btn-add-mapping{display:inline-flex;align-items:center;background:#eff6ff;border:1px solid #bfdbfe;color:#2563eb;font-size:.65rem;font-weight:600;padding:2px 6px;border-radius:4px;cursor:pointer;transition:all .12s ease}.btn-add-mapping:hover{background:#dbeafe}.mapping-pair-row{display:flex;align-items:center;gap:6px;margin-top:4px}.active-ds-badge{background:#eff6ff;color:#2563eb;font-size:.65rem;font-weight:700;padding:1px 6px;border-radius:4px;border:1px solid #bfdbfe;max-width:140px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.source-type-switcher{display:flex;background:#f1f5f9;border:1px solid var(--rpt-color-border, #cbd5e1);border-radius:6px;padding:2px;gap:2px;margin-bottom:12px}.source-tab-btn{flex:1;display:inline-flex;align-items:center;justify-content:center;gap:5px;padding:6px 4px;font-size:.725rem;font-weight:600;color:var(--rpt-color-text-muted, #64748b);background:transparent;border:none;border-radius:4px;cursor:pointer;transition:all .12s ease}.source-tab-btn:hover{color:var(--rpt-color-text, #0f172a)}.source-tab-btn.active{background:#fff;color:var(--rpt-color-primary, #2563eb);box-shadow:0 1px 2px #0000000f}.procedure-params-section{margin-top:14px;padding:0;background:transparent;border:none}.params-section-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:8px;padding-bottom:4px;border-bottom:1px solid var(--rpt-color-border, #e2e8f0)}.params-section-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:8px}.btn-paste-exec{display:inline-flex;align-items:center;gap:4px;font-size:.675rem;font-weight:600;color:#2563eb;background:#eff6ff;border:1px solid #bfdbfe;border-radius:4px;padding:3px 8px;cursor:pointer;transition:all .12s ease}.btn-paste-exec:hover{background:#2563eb;color:#fff}.exec-snippet-panel{display:flex;flex-direction:column;gap:6px;background:#f8fafc;border:1px solid #cbd5e1;border-radius:6px;padding:8px 10px;margin-bottom:10px}.snippet-hint{font-size:.675rem;color:#475569}.snippet-hint code{background:#e2e8f0;padding:1px 4px;border-radius:3px;font-family:monospace}.exec-snippet-textarea{width:100%;box-sizing:border-box;font-family:monospace;font-size:.7rem;padding:6px 8px;border:1px solid #cbd5e1;border-radius:4px;background:#fff;resize:vertical;min-height:54px}.exec-snippet-actions{display:flex;align-items:center;gap:6px}.btn-snippet-apply{display:inline-flex;align-items:center;gap:4px;font-size:.7rem;font-weight:600;padding:4px 10px;background:#16a34a;color:#fff;border:none;border-radius:4px;cursor:pointer}.btn-snippet-apply:hover{background:#15803d}.btn-snippet-cancel{font-size:.7rem;padding:4px 8px;background:#f1f5f9;color:#475569;border:1px solid #cbd5e1;border-radius:4px;cursor:pointer}.snippet-status{font-size:.675rem;padding:4px 6px;border-radius:4px}.snippet-status.is-success{background:#f0fdf4;color:#166534;border:1px solid #bbf7d0}.snippet-status.is-error{background:#fef2f2;color:#991b1b;border:1px solid #fecaca}.param-cards-list{display:flex;flex-direction:column;gap:10px;width:100%;box-sizing:border-box}.empty-params-hint{font-size:.725rem;color:#64748b;font-style:italic;padding:12px;text-align:center;background:#f8fafc;border:1px dashed #cbd5e1;border-radius:6px}\n"] }]
357
+ ], changeDetection: ChangeDetectionStrategy.OnPush, template: " @if (!grid()) {\n <div class=\"empty-grid-card\">\n <div class=\"empty-grid-icon\">\n <rpt-icon name=\"table\" [size]=\"28\" />\n </div>\n <h4 class=\"empty-grid-title\">No Result Grid Attached</h4>\n <p class=\"empty-grid-desc\">Attach an interactive Result Data Grid (or UltraGrid) to this report definition to render queries and stored procedure results.</p>\n <button type=\"button\" class=\"btn-create-grid-action\" (click)=\"addGrid.emit()\">\n <rpt-icon name=\"plus\" [size]=\"14\" />\n <span>+ Add Result Grid</span>\n </button>\n </div>\n } @else {\n <div class=\"props-form\">\n <!-- 1. Report Data Source & Stored Procedure Configuration -->\n <div class=\"property-group\">\n <div class=\"group-header-row\">\n <div class=\"group-title-wrap\">\n <span class=\"group-title\">Report Data Source</span>\n @if (activeEntityName()) {\n <span class=\"group-badge active-ds-badge\">{{ activeEntityName() }}</span>\n }\n </div>\n </div>\n\n <!-- Source Type Switcher (Stored Procedure vs Table vs REST API) -->\n <div class=\"source-type-switcher\">\n <button\n type=\"button\"\n class=\"source-tab-btn\"\n [class.active]=\"currentSourceType() === 'stored_procedure'\"\n (click)=\"onSourceTypeChange('stored_procedure')\"\n >\n <rpt-icon name=\"code\" [size]=\"12\" />\n <span>Stored Procedure</span>\n </button>\n <button\n type=\"button\"\n class=\"source-tab-btn\"\n [class.active]=\"currentSourceType() === 'table'\"\n (click)=\"onSourceTypeChange('table')\"\n >\n <rpt-icon name=\"table\" [size]=\"12\" />\n <span>Table / View</span>\n </button>\n <button\n type=\"button\"\n class=\"source-tab-btn\"\n [class.active]=\"currentSourceType() === 'api'\"\n (click)=\"onSourceTypeChange('api')\"\n >\n <rpt-icon name=\"globe\" [size]=\"12\" />\n <span>REST API</span>\n </button>\n </div>\n\n @if (currentSourceType() === 'api') {\n <!-- API Endpoint Selector / Input -->\n <div class=\"field-row\">\n <label class=\"field-label\">API Endpoint URL</label>\n @if (registeredApis().length > 0) {\n <div style=\"margin-bottom: 6px;\">\n <rpt-searchable-select\n [options]=\"registeredApis()\"\n [ngModel]=\"apiEndpoint()\"\n (ngModelChange)=\"onApiEndpointChange($event)\"\n placeholder=\"-- Select Registered Endpoint or type below --\"\n searchPlaceholder=\"Search registered APIs...\"\n />\n </div>\n }\n <input\n type=\"text\"\n class=\"form-control\"\n placeholder=\"e.g. /api/v1/orders or https://api.service.com/data\"\n [ngModel]=\"apiEndpoint()\"\n (ngModelChange)=\"onApiEndpointChange($event)\"\n />\n <span class=\"field-hint\" style=\"font-size: 11px; color: var(--rpt-color-text-muted, #64748b); margin-top: 4px; display: block;\">\n Direct HTTP call or backend proxy. Use <code>:param</code> for route tokens.\n </span>\n </div>\n\n <!-- HTTP Method & Data Path Grid -->\n <div class=\"field-grid-2\" style=\"display: grid; grid-template-columns: 1fr 1fr; gap: 8px;\">\n <div class=\"field-row\">\n <label class=\"field-label\">HTTP Method</label>\n <select\n class=\"form-control\"\n [ngModel]=\"apiMethod()\"\n (ngModelChange)=\"onApiMethodChange($event)\"\n >\n <option value=\"GET\">GET (Query String)</option>\n <option value=\"POST\">POST (Body Payload)</option>\n </select>\n </div>\n <div class=\"field-row\">\n <label class=\"field-label\">Response Data Path</label>\n <input\n type=\"text\"\n class=\"form-control\"\n placeholder=\"e.g. data.items, rows\"\n [ngModel]=\"apiDataPath()\"\n (ngModelChange)=\"onApiDataPathChange($event)\"\n />\n </div>\n </div>\n\n <!-- Use Proxy Toggle -->\n <div class=\"field-row checkbox-field-row\" style=\"margin-top: 4px;\">\n <label class=\"checkbox-label\" style=\"display: flex; align-items: center; gap: 6px; font-size: 12px; cursor: pointer;\">\n <input\n type=\"checkbox\"\n [checked]=\"apiUseProxy()\"\n (change)=\"onApiUseProxyChange($any($event.target).checked)\"\n />\n <span class=\"checkbox-text\">Route through backend proxy (bypasses CORS / hides credentials)</span>\n </label>\n </div>\n } @else {\n <!-- Entity Selector Dropdown -->\n <div class=\"field-row\">\n <label class=\"field-label\">\n {{ currentSourceType() === 'stored_procedure' ? 'Stored Procedure' : 'Table / View' }}\n </label>\n <rpt-searchable-select\n [options]=\"gridEntitySelectOptions()\"\n [ngModel]=\"activeEntityName()\"\n (ngModelChange)=\"onSelectEntity($event)\"\n placeholder=\"-- Choose Data Source --\"\n [searchPlaceholder]=\"currentSourceType() === 'stored_procedure' ? 'Search procedures...' : 'Search tables & views...'\"\n />\n </div>\n }\n\n <!-- Stored Procedure Parameter Mappings -->\n @if (currentSourceType() === 'stored_procedure' && activeEntityName()) {\n <div class=\"procedure-params-section\">\n <div class=\"params-section-header\">\n <div class=\"params-header-left\">\n <span class=\"params-title\">Procedure Parameters</span>\n <span class=\"params-count-badge\">{{ effectiveParameters().length }}</span>\n </div>\n <button\n type=\"button\"\n class=\"btn-paste-exec\"\n (click)=\"toggleExecSnippet()\"\n title=\"Paste full SSMS 'EXEC proc @param=val' snippet to fill parameters automatically\"\n >\n <rpt-icon name=\"code\" [size]=\"12\" />\n <span>{{ isExecSnippetOpen() ? 'Close SQL' : 'Paste SQL Exec' }}</span>\n </button>\n </div>\n\n @if (isExecSnippetOpen()) {\n <div class=\"exec-snippet-panel\">\n <div class=\"exec-snippet-header\">\n <span class=\"snippet-hint\">Paste full <code>EXEC ProcedureName &#64;param=val...</code> statement from SSMS:</span>\n </div>\n <textarea\n class=\"exec-snippet-textarea\"\n rows=\"3\"\n placeholder=\"e.g. exec Get_HelpList @chrCOMPANYID=N'101',@chrTableName=N'MSTACCTGLSUB'...\"\n [ngModel]=\"execSnippetText()\"\n (ngModelChange)=\"execSnippetText.set($event)\"\n ></textarea>\n <div class=\"exec-snippet-actions\">\n <button type=\"button\" class=\"btn-snippet-apply\" (click)=\"applyExecSnippet()\">\n <rpt-icon name=\"check\" [size]=\"12\" />\n <span>Apply Parameters</span>\n </button>\n <button type=\"button\" class=\"btn-snippet-cancel\" (click)=\"toggleExecSnippet()\">\n Cancel\n </button>\n </div>\n @if (execParseStatus()) {\n <div class=\"snippet-status\" [class.is-error]=\"execParseStatus()?.kind === 'error'\" [class.is-success]=\"execParseStatus()?.kind === 'success'\">\n {{ execParseStatus()?.message }}\n </div>\n }\n </div>\n }\n\n @if (effectiveParameters().length > 0) {\n <div class=\"param-cards-list\">\n @for (param of effectiveParameters(); track param.name) {\n <rpt-parameter-binding-editor\n [param]=\"param\"\n [currentValue]=\"getParameterValue(param.name)\"\n [allComponents]=\"allComponents()\"\n (valueChange)=\"onParameterChange(param.name, $event)\"\n />\n }\n </div>\n } @else {\n <div class=\"empty-params-hint\">\n <span>No required parameters for this procedure.</span>\n </div>\n }\n </div>\n }\n </div>\n\n <!-- 2. Result Columns Configuration -->\n <div class=\"property-group\">\n <div class=\"group-header-row\">\n <div class=\"group-title-wrap\">\n <span class=\"group-title\">Columns</span>\n <span class=\"group-badge\">{{ columns().length }}</span>\n </div>\n </div>\n\n <!-- Dedicated Full-Width Action Buttons (No cramping) -->\n <div class=\"columns-action-bar\">\n <button\n type=\"button\"\n class=\"btn-col-action btn-auto-detect\"\n (click)=\"autoDetectColumns.emit()\"\n [disabled]=\"isDetecting()\"\n title=\"Auto-detect all columns from procedure or data table\"\n >\n <rpt-icon name=\"refresh\" [size]=\"12\" [class.rpt-spin]=\"isDetecting()\" />\n <span>{{ isDetecting() ? 'Detecting...' : 'Auto-Detect' }}</span>\n </button>\n <button\n type=\"button\"\n class=\"btn-col-action btn-add-col\"\n (click)=\"addColumn.emit()\"\n title=\"Add a new column manually\"\n >\n <rpt-icon name=\"plus\" [size]=\"12\" />\n <span>+ Add Column</span>\n </button>\n </div>\n\n @if (statusMessage()) {\n <div class=\"col-status-banner\" [class.is-error]=\"statusKind() === 'error'\" [class.is-success]=\"statusKind() === 'success'\">\n <rpt-icon [name]=\"statusKind() === 'error' ? 'close' : 'check'\" [size]=\"12\" />\n <span>{{ statusMessage() }}</span>\n </div>\n }\n\n <div class=\"columns-editor-list\">\n @for (col of columns(); track col.field; let idx = $index) {\n <div class=\"col-edit-card\">\n <div class=\"col-card-header\">\n <div class=\"col-header-title-group\">\n <span class=\"col-drag-dots\">\u22EE\u22EE</span>\n <span class=\"col-idx-badge\">#{{ idx + 1 }}</span>\n <input\n type=\"text\"\n class=\"col-title-input\"\n placeholder=\"Column Label\"\n [ngModel]=\"col.label\"\n (ngModelChange)=\"onUpdateCol(idx, 'label', $event)\"\n />\n </div>\n <div class=\"col-card-actions\">\n <span class=\"col-type-pill\">{{ col.dataType || 'string' }}</span>\n <button\n type=\"button\"\n class=\"col-action-btn btn-delete\"\n (click)=\"removeColumn.emit(idx)\"\n title=\"Remove Column\"\n >\n <rpt-icon name=\"trash\" [size]=\"12\" />\n </button>\n </div>\n </div>\n\n <div class=\"col-card-body\">\n <div class=\"col-edit-fields\">\n <div class=\"col-field-item\">\n <span class=\"mini-label\">Field</span>\n <input\n type=\"text\"\n class=\"col-mini-input\"\n placeholder=\"field\"\n [ngModel]=\"col.field\"\n (ngModelChange)=\"onUpdateCol(idx, 'field', $event)\"\n />\n </div>\n <div class=\"col-field-item\">\n <span class=\"mini-label\">Type</span>\n <select\n class=\"col-mini-select\"\n [ngModel]=\"col.dataType || 'string'\"\n (ngModelChange)=\"onUpdateCol(idx, 'dataType', $event)\"\n >\n <option value=\"string\">String</option>\n <option value=\"number\">Number</option>\n <option value=\"currency\">Currency</option>\n <option value=\"date\">Date</option>\n <option value=\"boolean\">Boolean</option>\n </select>\n </div>\n <div class=\"col-field-item\">\n <span class=\"mini-label\">Format</span>\n <input\n type=\"text\"\n class=\"col-mini-input\"\n placeholder=\"e.g. dd/MM/yyyy\"\n [ngModel]=\"col.format\"\n (ngModelChange)=\"onUpdateCol(idx, 'format', $event)\"\n />\n </div>\n <div class=\"col-field-item\">\n <span class=\"mini-label\">Align</span>\n <select\n class=\"col-mini-select\"\n [ngModel]=\"col.align || 'left'\"\n (ngModelChange)=\"onUpdateCol(idx, 'align', $event)\"\n >\n <option value=\"left\">Left</option>\n <option value=\"center\">Center</option>\n <option value=\"right\">Right</option>\n </select>\n </div>\n <div class=\"col-field-item\">\n <span class=\"mini-label\">Aggregate</span>\n <select\n class=\"col-mini-select\"\n [ngModel]=\"col.aggregate || 'none'\"\n (ngModelChange)=\"onUpdateCol(idx, 'aggregate', $event === 'none' ? undefined : $event)\"\n >\n <option value=\"none\">None</option>\n <option value=\"sum\">Sum</option>\n <option value=\"avg\">Average</option>\n <option value=\"count\">Count</option>\n <option value=\"min\">Min</option>\n <option value=\"max\">Max</option>\n </select>\n </div>\n <div class=\"col-field-item\">\n <span class=\"mini-label\">Width</span>\n <input\n type=\"text\"\n class=\"col-mini-input\"\n placeholder=\"auto\"\n [ngModel]=\"col.width || ''\"\n (ngModelChange)=\"onUpdateCol(idx, 'width', $event || undefined)\"\n />\n </div>\n </div>\n\n <div class=\"col-card-footer\">\n <label class=\"col-checkbox-toggle\">\n <input\n type=\"checkbox\"\n [ngModel]=\"col.visible !== false\"\n (ngModelChange)=\"onUpdateCol(idx, 'visible', $event)\"\n />\n <span>Visible</span>\n </label>\n <label class=\"col-checkbox-toggle\">\n <input\n type=\"checkbox\"\n [ngModel]=\"col.checkboxSelection ?? false\"\n (ngModelChange)=\"onUpdateCol(idx, 'checkboxSelection', $event)\"\n />\n <span>Checkbox</span>\n </label>\n </div>\n </div>\n </div>\n }\n </div>\n </div>\n\n <!-- Grid Table Options Group -->\n <div class=\"property-group\">\n <div class=\"group-title\">Table Options</div>\n\n <div class=\"field-row\">\n <label class=\"checkbox-toggle\">\n <input\n type=\"checkbox\"\n [ngModel]=\"grid()?.options?.sideBar !== false\"\n (ngModelChange)=\"updateOption.emit({ field: 'sideBar', value: $event })\"\n />\n <span>Enable Side Panel (Tool Panels)</span>\n </label>\n </div>\n\n <div class=\"field-row\">\n <label class=\"checkbox-toggle\">\n <input\n type=\"checkbox\"\n [ngModel]=\"grid()?.options?.globalSearch !== false\"\n (ngModelChange)=\"updateOption.emit({ field: 'globalSearch', value: $event })\"\n />\n <span>Global Search Box</span>\n </label>\n </div>\n\n <div class=\"field-row\">\n <label class=\"checkbox-toggle\">\n <input\n type=\"checkbox\"\n [ngModel]=\"grid()?.options?.statusBar !== false\"\n (ngModelChange)=\"updateOption.emit({ field: 'statusBar', value: $event })\"\n />\n <span>Status Bar</span>\n </label>\n </div>\n\n <div class=\"field-row\">\n <label class=\"checkbox-toggle\">\n <input\n type=\"checkbox\"\n [ngModel]=\"grid()?.options?.pagination ?? true\"\n (ngModelChange)=\"updateOption.emit({ field: 'pagination', value: $event })\"\n />\n <span>Enable Pagination</span>\n </label>\n </div>\n\n <div class=\"field-row\">\n <label class=\"checkbox-toggle\">\n <input\n type=\"checkbox\"\n [ngModel]=\"grid()?.options?.selectable ?? false\"\n (ngModelChange)=\"updateOption.emit({ field: 'selectable', value: $event })\"\n />\n <span>Row Selection</span>\n </label>\n </div>\n\n @if (grid()?.options?.selectable) {\n <div class=\"field-row\">\n <label class=\"field-label\">Selection Mode</label>\n <select\n class=\"field-input\"\n [ngModel]=\"grid()?.options?.selectionMode ?? 'multiple'\"\n (ngModelChange)=\"updateOption.emit({ field: 'selectionMode', value: $event })\"\n >\n <option value=\"multiple\">Multiple Rows</option>\n <option value=\"single\">Single Row</option>\n </select>\n </div>\n\n <div class=\"field-row\">\n <label class=\"checkbox-toggle\">\n <input\n type=\"checkbox\"\n [ngModel]=\"grid()?.options?.checkboxSelection ?? true\"\n (ngModelChange)=\"updateOption.emit({ field: 'checkboxSelection', value: $event })\"\n />\n <span>Checkbox Selection</span>\n </label>\n </div>\n\n @if ((grid()?.options?.selectionMode ?? 'multiple') === 'multiple') {\n <div class=\"field-row\">\n <label class=\"checkbox-toggle\">\n <input\n type=\"checkbox\"\n [ngModel]=\"grid()?.options?.headerCheckboxSelection ?? true\"\n (ngModelChange)=\"updateOption.emit({ field: 'headerCheckboxSelection', value: $event })\"\n />\n <span>Header Select All Checkbox</span>\n </label>\n </div>\n }\n }\n\n <div class=\"field-row\">\n <label class=\"checkbox-toggle\">\n <input\n type=\"checkbox\"\n [ngModel]=\"grid()?.options?.allowColumnReorder ?? true\"\n (ngModelChange)=\"updateOption.emit({ field: 'allowColumnReorder', value: $event })\"\n />\n <span>Allow Column Reorder</span>\n </label>\n </div>\n\n <div class=\"field-row\">\n <label class=\"checkbox-toggle\">\n <input\n type=\"checkbox\"\n [ngModel]=\"grid()?.options?.allowExport ?? true\"\n (ngModelChange)=\"updateOption.emit({ field: 'allowExport', value: $event })\"\n />\n <span>Allow Export</span>\n </label>\n </div>\n\n <div class=\"field-row\">\n <label class=\"field-label\">Page Size</label>\n <input\n type=\"number\"\n class=\"field-input\"\n min=\"1\"\n max=\"1000\"\n (wheel)=\"$any($event.target).blur()\"\n (keydown.arrowup)=\"$event.preventDefault()\"\n (keydown.arrowdown)=\"$event.preventDefault()\"\n [ngModel]=\"grid()?.options?.pageSize ?? 10\"\n (ngModelChange)=\"updateOption.emit({ field: 'pageSize', value: +$event })\"\n />\n </div>\n\n <div class=\"field-row\">\n <label class=\"checkbox-toggle\">\n <input\n type=\"checkbox\"\n [ngModel]=\"grid()?.options?.showRowNumbers ?? true\"\n (ngModelChange)=\"updateOption.emit({ field: 'showRowNumbers', value: $event })\"\n />\n <span>Show Row Numbers</span>\n </label>\n </div>\n\n <div class=\"field-row\">\n <label class=\"checkbox-toggle\">\n <input\n type=\"checkbox\"\n [ngModel]=\"grid()?.options?.showFooter ?? true\"\n (ngModelChange)=\"updateOption.emit({ field: 'showFooter', value: $event })\"\n />\n <span>Show Footer Totals</span>\n </label>\n </div>\n </div>\n\n <!-- Row Click & Drill-Down Action Group -->\n <div class=\"property-group\">\n <div class=\"group-title\">Row Click & Drill-Down</div>\n\n <div class=\"field-row\">\n <label class=\"checkbox-toggle\">\n <input\n type=\"checkbox\"\n [ngModel]=\"hasRowClickAction()\"\n (ngModelChange)=\"toggleRowClickAction($event)\"\n />\n <span>Enable Row Click Action</span>\n </label>\n </div>\n\n @if (hasRowClickAction()) {\n <div class=\"field-row\">\n <label class=\"field-label\">Action Type</label>\n <select\n class=\"field-input field-select\"\n [ngModel]=\"rowClickAction()?.type || 'open-drawer'\"\n (ngModelChange)=\"updateRowActionField('type', $event)\"\n >\n <option value=\"open-drawer\">Slide-Over Detail Drawer</option>\n <option value=\"drilldown-report\">Drill-Down Report (Host Event)</option>\n <option value=\"navigate\">Navigate to URL</option>\n <option value=\"emit-custom\">Emit Custom Action</option>\n </select>\n </div>\n\n @if (rowClickAction()?.type === 'open-drawer' || rowClickAction()?.type === 'drilldown-report') {\n <div class=\"field-row\">\n <label class=\"field-label\">Target Report ID</label>\n <input\n type=\"text\"\n class=\"field-input\"\n placeholder=\"e.g. order-details\"\n [ngModel]=\"rowClickAction()?.targetReportId || ''\"\n (ngModelChange)=\"updateRowActionField('targetReportId', $event)\"\n />\n </div>\n\n <div class=\"field-row\">\n <label class=\"field-label\">Drawer Title</label>\n <input\n type=\"text\"\n class=\"field-input\"\n placeholder=\"e.g. Order Details\"\n [ngModel]=\"rowClickAction()?.drawerTitle || ''\"\n (ngModelChange)=\"updateRowActionField('drawerTitle', $event)\"\n />\n </div>\n\n <div class=\"field-row\">\n <label class=\"field-label\">Drawer Width</label>\n <input\n type=\"text\"\n class=\"field-input\"\n placeholder=\"e.g. 760px, 80%, 900px\"\n [ngModel]=\"rowClickAction()?.drawerWidth || '760px'\"\n (ngModelChange)=\"updateRowActionField('drawerWidth', $event)\"\n />\n </div>\n }\n\n @if (rowClickAction()?.type === 'navigate') {\n <div class=\"field-row\">\n <label class=\"field-label\">Target URL</label>\n <input\n type=\"text\"\n class=\"field-input\"\n [placeholder]=\"'/orders/{{row.orderId}} or https://...'\"\n [ngModel]=\"rowClickAction()?.targetUrl || ''\"\n (ngModelChange)=\"updateRowActionField('targetUrl', $event)\"\n />\n </div>\n <div class=\"field-row\">\n <label class=\"checkbox-toggle\">\n <input\n type=\"checkbox\"\n [ngModel]=\"rowClickAction()?.openNewTab ?? false\"\n (ngModelChange)=\"updateRowActionField('openNewTab', $event)\"\n />\n <span>Open in New Tab</span>\n </label>\n </div>\n }\n\n @if (rowClickAction()?.type === 'emit-custom') {\n <div class=\"field-row\">\n <label class=\"field-label\">Custom Action Name</label>\n <input\n type=\"text\"\n class=\"field-input\"\n placeholder=\"e.g. view-audit-trail\"\n [ngModel]=\"rowClickAction()?.customActionName || ''\"\n (ngModelChange)=\"updateRowActionField('customActionName', $event)\"\n />\n </div>\n }\n\n <div class=\"field-row\">\n <div class=\"field-label-row\">\n <label class=\"field-label\">Parameter Mapping</label>\n <button\n type=\"button\"\n class=\"btn-add-mapping\"\n (click)=\"addParameterMapping()\"\n >\n + Add Mapping\n </button>\n </div>\n\n @for (mapping of parameterMappings(); track mapping.key; let mIdx = $index) {\n <div class=\"mapping-pair-row\">\n <input\n type=\"text\"\n class=\"col-mini-input\"\n style=\"flex: 1;\"\n placeholder=\"Target (e.g. customerId)\"\n [ngModel]=\"mapping.key\"\n (ngModelChange)=\"updateMappingKey(mIdx, $event)\"\n />\n <span style=\"font-size: 0.75rem; color: #94a3b8;\">\u2190</span>\n <input\n type=\"text\"\n class=\"col-mini-input\"\n style=\"flex: 1;\"\n placeholder=\"Source (e.g. row.id)\"\n [ngModel]=\"mapping.value\"\n (ngModelChange)=\"updateMappingValue(mIdx, $event)\"\n />\n <button\n type=\"button\"\n class=\"col-action-btn btn-delete\"\n (click)=\"removeMapping(mIdx)\"\n title=\"Remove mapping\"\n >\n <rpt-icon name=\"trash\" [size]=\"11\" />\n </button>\n </div>\n }\n </div>\n }\n </div>\n\n <!-- Remove Grid Action -->\n <div class=\"grid-danger-zone\">\n <button type=\"button\" class=\"btn-remove-grid-action\" (click)=\"removeGrid.emit()\">\n <rpt-icon name=\"trash\" [size]=\"13\" />\n <span>Remove Grid from Report</span>\n </button>\n </div>\n </div>\n }", styles: [".property-group{display:flex;flex-direction:column;gap:12px}.group-title{font-size:.7rem;font-weight:700;color:var(--rpt-color-text-muted, #64748b);text-transform:uppercase;letter-spacing:.05em;line-height:1.2}.field-row{display:flex;flex-direction:column;gap:4px}.field-label-row{display:flex;align-items:center;justify-content:space-between}.field-badge-val{font-size:.65rem;font-weight:600;color:var(--rpt-color-primary, #2563eb);background:#eff6ff;border:1px solid #bfdbfe;padding:1px 6px;border-radius:9999px}.field-label{font-size:.7rem;font-weight:600;color:var(--rpt-color-text, #0f172a)}.field-input,.field-select,.field-textarea{width:100%;box-sizing:border-box;border:1px solid var(--rpt-color-border, #cbd5e1);border-radius:var(--rpt-border-radius-sm, 4px);padding:6px 10px;font-size:var(--rpt-font-size-sm, .75rem);color:var(--rpt-color-text, #0f172a);background:#fff;outline:none;transition:all var(--rpt-transition-speed, .15s) ease}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button,.field-input[type=number]::-webkit-inner-spin-button,.field-input[type=number]::-webkit-outer-spin-button{-webkit-appearance:none;margin:0}input[type=number],.field-input[type=number]{-moz-appearance:textfield;appearance:textfield}.field-select{appearance:none;-webkit-appearance:none;background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2364748b' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E\");background-repeat:no-repeat;background-position:right 10px center;background-size:13px 13px;padding-right:28px;cursor:pointer}.field-input:focus,.field-select:focus,.field-textarea:focus{border-color:var(--rpt-color-primary, #2563eb);box-shadow:var(--rpt-box-shadow-focus, 0 0 0 3px rgba(37, 99, 235, .25))}.checkbox-toggle{display:inline-flex;align-items:center;gap:8px;font-size:.75rem;font-weight:500;color:var(--rpt-color-text, #0f172a);cursor:pointer}.preset-pill-group{display:flex;flex-wrap:wrap;gap:4px;margin-top:4px}.preset-pill{background:#f1f5f9;border:1px solid #e2e8f0;border-radius:4px;padding:2px 8px;font-size:.65rem;font-weight:600;color:#475569;cursor:pointer;transition:all .12s ease}.preset-pill:hover{background:#e2e8f0;color:#0f172a;border-color:#cbd5e1}.preset-pill-active{background:var(--rpt-color-primary, #2563eb)!important;color:#fff!important;border-color:var(--rpt-color-primary, #2563eb)!important}.preset-pill-reset{color:var(--rpt-color-primary, #2563eb);background:#eff6ff;border-color:#bfdbfe}.preset-pill-reset:hover{background:#dbeafe;color:#1d4ed8;border-color:#93c5fd}\n", ".empty-grid-card{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:40px 16px;text-align:center;border:2px dashed #cbd5e1;border-radius:8px;background:#fff;margin:10px 0}.empty-grid-icon{width:48px;height:48px;border-radius:10px;background:#eff6ff;color:#2563eb;display:flex;align-items:center;justify-content:center;margin-bottom:12px}.empty-grid-title{font-size:.95rem;font-weight:700;color:#0f172a;margin:0 0 6px}.empty-grid-desc{font-size:.775rem;color:#64748b;margin:0 0 18px;line-height:1.4;max-width:280px}.btn-create-grid-action{display:inline-flex;align-items:center;gap:6px;padding:8px 16px;background:#2563eb;color:#fff;font-size:.775rem;font-weight:600;border:none;border-radius:6px;cursor:pointer;box-shadow:0 2px 4px #2563eb33;transition:all .15s ease}.btn-create-grid-action:hover{background:#1d4ed8;box-shadow:0 4px 8px #2563eb40}.grid-danger-zone{margin-top:10px;padding-top:16px;border-top:1px dashed #e2e8f0;display:flex;justify-content:center}.btn-remove-grid-action{display:inline-flex;align-items:center;gap:6px;background:#fee2e2;border:1px solid #fecaca;color:#dc2626;font-size:.75rem;font-weight:600;padding:6px 12px;border-radius:6px;cursor:pointer;transition:all .15s ease}.btn-remove-grid-action:hover{background:#fecaca;border-color:#f87171;color:#b91c1c}.props-form{display:flex;flex-direction:column;gap:20px}.group-header-row{display:flex;align-items:center;justify-content:space-between;margin-bottom:6px}.group-title-wrap{display:flex;align-items:center;gap:6px}.group-badge{font-size:.65rem;font-weight:700;color:#64748b;background:#f1f5f9;border:1px solid #e2e8f0;border-radius:10px;padding:1px 6px}.columns-action-bar{display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-bottom:12px}.btn-col-action{display:inline-flex;align-items:center;justify-content:center;gap:6px;padding:7px 8px;font-size:.725rem;font-weight:600;border-radius:6px;cursor:pointer;white-space:nowrap;transition:all .12s ease;box-sizing:border-box}.btn-col-action:disabled{opacity:.6;cursor:not-allowed}.btn-auto-detect{background:#eff6ff;border:1px solid #bfdbfe;color:#2563eb}.btn-auto-detect:hover:not(:disabled){background:#2563eb;color:#fff;border-color:#2563eb}.btn-add-col{background:#fff;border:1px solid var(--rpt-color-border, #cbd5e1);color:#334155}.btn-add-col:hover{background:#f8fafc;border-color:#94a3b8;color:#0f172a}.col-status-banner{display:flex;align-items:center;gap:6px;padding:6px 10px;border-radius:6px;font-size:.72rem;line-height:1.35;margin-bottom:10px;background:#f1f5f9;color:#334155;border:1px solid #cbd5e1}.col-status-banner.is-success{background:#f0fdf4;color:#166534;border-color:#bbf7d0}.col-status-banner.is-error{background:#fef2f2;color:#991b1b;border-color:#fecaca}@keyframes rpt-spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.rpt-spin{animation:rpt-spin 1s linear infinite}.columns-editor-list{display:flex;flex-direction:column;gap:10px}.col-edit-card{background:#fff;border:1.5px solid var(--rpt-color-border, #cbd5e1);border-radius:var(--rpt-border-radius, 6px);box-shadow:var(--rpt-box-shadow, 0 1px 2px rgba(0, 0, 0, .05));box-sizing:border-box;transition:all var(--rpt-transition-speed, .15s) ease;position:relative;overflow:hidden;display:flex;flex-direction:column}.col-edit-card:hover{border-color:var(--rpt-color-primary, #2563eb);box-shadow:0 4px 6px -1px #2563eb1a}.col-card-header{display:flex;align-items:center;justify-content:space-between;gap:6px;padding:5px 8px;background:var(--rpt-color-surface, #f8fafc);border-bottom:1px solid var(--rpt-color-border, #e2e8f0);min-height:32px;box-sizing:border-box}.col-header-title-group{display:flex;align-items:center;gap:5px;min-width:0;flex:1}.col-drag-dots{color:#94a3b8;font-size:.8rem;cursor:grab;-webkit-user-select:none;user-select:none;line-height:1;padding-left:2px}.col-idx-badge{font-size:.65rem;font-weight:700;color:#64748b;background:#e2e8f0;padding:1px 5px;border-radius:3px;letter-spacing:.02em}.col-title-input{flex:1;border:1px solid transparent;background:transparent;font-size:.75rem;font-weight:600;color:var(--rpt-color-text, #0f172a);padding:2px 6px;border-radius:4px;outline:none;transition:all .15s ease}.col-title-input:hover{border-color:#cbd5e1;background:#fff}.col-title-input:focus{border-color:var(--rpt-color-primary, #2563eb);background:#fff;box-shadow:0 0 0 2px #2563eb26}.col-card-actions{display:flex;align-items:center;gap:4px}.col-type-pill{font-size:.625rem;font-weight:700;color:#1e40af;background:#dbeafe;border:1px solid #bfdbfe;padding:1px 5px;border-radius:3px;text-transform:uppercase;letter-spacing:.04em}.col-action-btn{display:inline-flex;align-items:center;justify-content:center;background:none;border:none;color:var(--rpt-color-text-muted, #64748b);cursor:pointer;padding:3px;border-radius:4px;transition:all .15s ease}.col-action-btn.btn-delete:hover{color:var(--rpt-color-danger, #ef4444);background:#fee2e2}.col-card-body{padding:8px 10px;display:flex;flex-direction:column;gap:6px;background:#fff}.col-edit-fields{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:6px 8px}.col-field-item{display:flex;flex-direction:column;gap:2px;min-width:0}.mini-label{font-size:.625rem;font-weight:600;color:#64748b;letter-spacing:.02em}.col-mini-input,.col-mini-select{width:100%;box-sizing:border-box;border:1px solid var(--rpt-color-border, #cbd5e1);border-radius:3px;padding:3px 5px;font-size:.7rem;color:var(--rpt-color-text, #0f172a);background:#fff;outline:none;transition:all .12s ease}.col-mini-select{appearance:none;-webkit-appearance:none;background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2364748b' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E\");background-repeat:no-repeat;background-position:right 4px center;background-size:10px 10px;padding-right:16px;cursor:pointer}.col-mini-input:focus,.col-mini-select:focus{border-color:var(--rpt-color-primary, #2563eb);box-shadow:0 0 0 2px #2563eb26}.col-card-footer{display:flex;align-items:center;justify-content:flex-end;gap:12px;padding-top:4px;border-top:1px dashed #e2e8f0;margin-top:2px}.col-checkbox-toggle{display:inline-flex;align-items:center;gap:5px;font-size:.675rem;font-weight:500;color:#475569;cursor:pointer;-webkit-user-select:none;user-select:none}.btn-add-mapping{display:inline-flex;align-items:center;background:#eff6ff;border:1px solid #bfdbfe;color:#2563eb;font-size:.65rem;font-weight:600;padding:2px 6px;border-radius:4px;cursor:pointer;transition:all .12s ease}.btn-add-mapping:hover{background:#dbeafe}.mapping-pair-row{display:flex;align-items:center;gap:6px;margin-top:4px}.active-ds-badge{background:#eff6ff;color:#2563eb;font-size:.65rem;font-weight:700;padding:1px 6px;border-radius:4px;border:1px solid #bfdbfe;max-width:140px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.source-type-switcher{display:flex;background:#f1f5f9;border:1px solid var(--rpt-color-border, #cbd5e1);border-radius:6px;padding:2px;gap:2px;margin-bottom:12px}.source-tab-btn{flex:1;display:inline-flex;align-items:center;justify-content:center;gap:5px;padding:6px 4px;font-size:.725rem;font-weight:600;color:var(--rpt-color-text-muted, #64748b);background:transparent;border:none;border-radius:4px;cursor:pointer;transition:all .12s ease}.source-tab-btn:hover{color:var(--rpt-color-text, #0f172a)}.source-tab-btn.active{background:#fff;color:var(--rpt-color-primary, #2563eb);box-shadow:0 1px 2px #0000000f}.procedure-params-section{margin-top:14px;padding:0;background:transparent;border:none}.params-section-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:8px}.btn-paste-exec{display:inline-flex;align-items:center;gap:4px;font-size:.675rem;font-weight:600;color:#2563eb;background:#eff6ff;border:1px solid #bfdbfe;border-radius:4px;padding:3px 8px;cursor:pointer;transition:all .12s ease}.btn-paste-exec:hover{background:#2563eb;color:#fff}.exec-snippet-panel{display:flex;flex-direction:column;gap:6px;background:#f8fafc;border:1px solid #cbd5e1;border-radius:6px;padding:8px 10px;margin-bottom:10px}.snippet-hint{font-size:.675rem;color:#475569}.snippet-hint code{background:#e2e8f0;padding:1px 4px;border-radius:3px;font-family:monospace}.exec-snippet-textarea{width:100%;box-sizing:border-box;font-family:monospace;font-size:.7rem;padding:6px 8px;border:1px solid #cbd5e1;border-radius:4px;background:#fff;resize:vertical;min-height:54px}.exec-snippet-actions{display:flex;align-items:center;gap:6px}.btn-snippet-apply{display:inline-flex;align-items:center;gap:4px;font-size:.7rem;font-weight:600;padding:4px 10px;background:#16a34a;color:#fff;border:none;border-radius:4px;cursor:pointer}.btn-snippet-apply:hover{background:#15803d}.btn-snippet-cancel{font-size:.7rem;padding:4px 8px;background:#f1f5f9;color:#475569;border:1px solid #cbd5e1;border-radius:4px;cursor:pointer}.snippet-status{font-size:.675rem;padding:4px 6px;border-radius:4px}.snippet-status.is-success{background:#f0fdf4;color:#166534;border:1px solid #bbf7d0}.snippet-status.is-error{background:#fef2f2;color:#991b1b;border:1px solid #fecaca}.param-cards-list{display:flex;flex-direction:column;gap:10px;width:100%;box-sizing:border-box}.empty-params-hint{font-size:.725rem;color:#64748b;font-style:italic;padding:12px;text-align:center;background:#f8fafc;border:1px dashed #cbd5e1;border-radius:6px}\n"] }]
258
358
  }], ctorParameters: () => [] });
259
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHJvcGVydHktZWRpdG9yLWdyaWQuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvYndheXMtcmVwb3J0L3NyYy9saWIvZmVhdHVyZXMvZGVzaWduZXIvY29tcG9uZW50cy9wcm9wZXJ0eS1lZGl0b3IvcHJvcGVydHktZWRpdG9yLWdyaWQuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvYndheXMtcmVwb3J0L3NyYy9saWIvZmVhdHVyZXMvZGVzaWduZXIvY29tcG9uZW50cy9wcm9wZXJ0eS1lZGl0b3IvcHJvcGVydHktZWRpdG9yLWdyaWQuY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLHVCQUF1QixFQUFFLFNBQVMsRUFBRSxRQUFRLEVBQUUsTUFBTSxFQUFFLE1BQU0sRUFBRSxLQUFLLEVBQUUsTUFBTSxFQUFFLE1BQU0sRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUNwSCxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDL0MsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBSzdDLE9BQU8sRUFBRSwwQkFBMEIsRUFBRSxNQUFNLHlEQUF5RCxDQUFDO0FBQ3JHLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLDJEQUEyRCxDQUFDO0FBQzdGLE9BQU8sRUFDTCw0QkFBNEIsR0FFN0IsTUFBTSxtQ0FBbUMsQ0FBQztBQUMzQyxPQUFPLEVBQUUsK0JBQStCLEVBQUUsTUFBTSxzQ0FBc0MsQ0FBQztBQUN2RixPQUFPLEVBQUUscUJBQXFCLEVBQUUsTUFBTSw4Q0FBOEMsQ0FBQzs7O0FBZ0JyRixNQUFNLE9BQU8sMkJBQTJCO0lBQ3JCLGFBQWEsR0FBRyxNQUFNLENBQUMsMEJBQTBCLEVBQUUsRUFBRSxRQUFRLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FB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LElBQUksQ0FBQyxFQUFFLEdBQUcsT0FBTyxFQUFFLGdCQUFnQixFQUFFLFdBQVcsRUFBRSxDQUFDLENBQUM7SUFDaEYsQ0FBQzt3R0F2UVUsMkJBQTJCOzRGQUEzQiwyQkFBMkIsd2tEQzlCeEMsc2h4QkE4bEJLLGd3WUQxa0JELFlBQVksOEJBQ1osV0FBVyxtdERBQ1gsZ0JBQWdCLHVHQUNoQiwrQkFBK0Isb05BQy9CLDRCQUE0Qjs7NEZBTW5CLDJCQUEyQjtrQkFkdkMsU0FBUzsrQkFDRSwwQkFBMEIsY0FDeEIsSUFBSSxXQUNQO3dCQUNQLFlBQVk7d0JBQ1osV0FBVzt3QkFDWCxnQkFBZ0I7d0JBQ2hCLCtCQUErQjt3QkFDL0IsNEJBQTRCO3FCQUM3QixtQkFDZ0IsdUJBQXVCLENBQUMsTUFBTSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENoYW5nZURldGVjdGlvblN0cmF0ZWd5LCBDb21wb25lbnQsIGNvbXB1dGVkLCBlZmZlY3QsIGluamVjdCwgaW5wdXQsIG91dHB1dCwgc2lnbmFsIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBDb21tb25Nb2R1bGUgfSBmcm9tICdAYW5ndWxhci9jb21tb24nO1xuaW1wb3J0IHsgRm9ybXNNb2R1bGUgfSBmcm9tICdAYW5ndWxhci9mb3Jtcyc7XG5pbXBvcnQgeyBHcmlkQ29sdW1uRGVmaW5pdGlvbiwgR3JpZFJvd0NsaWNrQWN0aW9uLCBSZXBvcnRHcmlkRGVmaW5pdGlvbiB9IGZyb20gJy4uLy4uLy4uLy4uL2NvcmUvbW9kZWxzL3JlcG9ydC1ncmlkLm1vZGVsJztcbmltcG9ydCB7IFJlcG9ydERhdGFTb3VyY2VEZWZpbml0aW9uIH0gZnJvbSAnLi4vLi4vLi4vLi4vY29yZS9tb2RlbHMvcmVwb3J0LWRhdGFzb3VyY2UubW9kZWwnO1xuaW1wb3J0IHsgUmVwb3J0Q29tcG9uZW50RGVmaW5pdGlvbiB9IGZyb20gJy4uLy4uLy4uLy4uL2NvcmUvbW9kZWxzL3JlcG9ydC1jb21wb25lbnQubW9kZWwnO1xuaW1wb3J0IHsgRGF0YWJhc2VFbnRpdHlNZXRhZGF0YSwgUHJvY2VkdXJlUGFyYW1ldGVyTWV0YWRhdGEgfSBmcm9tICcuLi8uLi8uLi8uLi9kYXRhLWFjY2Vzcy9jb250cmFjdHMvc2NoZW1hLWRpc2NvdmVyeS5jb250cmFjdCc7XG5pbXBvcnQgeyBSZXBvcnREYXRhRGlzY292ZXJ5U2VydmljZSB9IGZyb20gJy4uLy4uLy4uLy4uL2NvcmUvc2VydmljZXMvcmVwb3J0LWRhdGEtZGlzY292ZXJ5LnNlcnZpY2UnO1xuaW1wb3J0IHsgUnB0SWNvbkNvbXBvbmVudCB9IGZyb20gJy4uLy4uLy4uLy4uL3ByaW1pdGl2ZXMvY29tcG9uZW50cy9pY29uL3JwdC1pY29uLmNvbXBvbmVudCc7XG5pbXBvcnQge1xuICBScHRTZWFyY2hhYmxlU2VsZWN0Q29tcG9uZW50LFxuICBTZWFyY2hhYmxlU2VsZWN0T3B0aW9uLFxufSBmcm9tICcuLi8uLi8uLi8uLi9wcmltaXRpdmVzL2NvbXBvbmVudHMnO1xuaW1wb3J0IHsgUGFyYW1ldGVyQmluZGluZ0VkaXRvckNvbXBvbmVudCB9IGZyb20gJy4vcGFyYW1ldGVyLWJpbmRpbmctZWRpdG9yLmNvbXBvbmVudCc7XG5pbXBvcnQgeyBwYXJzZVNxbEV4ZWNTdGF0ZW1lbnQgfSBmcm9tICcuLi8uLi8uLi8uLi9jb3JlL3V0aWxzL3JlcG9ydC1wYXJhbWV0ZXIudXRpbCc7XG5cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ3JwdC1wcm9wZXJ0eS1lZGl0b3ItZ3JpZCcsXG4gIHN0YW5kYWxvbmU6IHRydWUsXG4gIGltcG9ydHM6IFtcbiAgICBDb21tb25Nb2R1bGUsXG4gICAgRm9ybXNNb2R1bGUsXG4gICAgUnB0SWNvbkNvbXBvbmVudCxcbiAgICBQYXJhbWV0ZXJCaW5kaW5nRWRpdG9yQ29tcG9uZW50LFxuICAgIFJwdFNlYXJjaGFibGVTZWxlY3RDb21wb25lbnQsXG4gIF0sXG4gIGNoYW5nZURldGVjdGlvbjogQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3kuT25QdXNoLFxuICB0ZW1wbGF0ZVVybDogJy4vcHJvcGVydHktZWRpdG9yLWdyaWQuY29tcG9uZW50Lmh0bWwnLFxuICBzdHlsZVVybHM6IFsnLi9wcm9wZXJ0eS1lZGl0b3IuY29tbW9uLmNzcycsICcuL3Byb3BlcnR5LWVkaXRvci1ncmlkLmNvbXBvbmVudC5jc3MnXSxcbn0pXG5leHBvcnQgY2xhc3MgUHJvcGVydHlFZGl0b3JHcmlkQ29tcG9uZW50IHtcbiAgcHJpdmF0ZSByZWFkb25seSBkYXRhRGlzY292ZXJ5ID0gaW5qZWN0KFJlcG9ydERhdGFEaXNjb3ZlcnlTZXJ2aWNlLCB7IG9wdGlvbmFsOiB0cnVlIH0pO1xuXG4gIHJlYWRvbmx5IGdyaWQgPSBpbnB1dDxSZXBvcnRHcmlkRGVmaW5pdGlvbiB8IHVuZGVmaW5lZD4oKTtcbiAgcmVhZG9ubHkgZGF0YVNvdXJjZSA9IGlucHV0PFJlcG9ydERhdGFTb3VyY2VEZWZpbml0aW9uIHwgdW5kZWZpbmVkPigpO1xuICByZWFkb25seSBhdmFpbGFibGVFbnRpdGllcyA9IGlucHV0PERhdGFiYXNlRW50aXR5TWV0YWRhdGFbXT4oW10pO1xuICByZWFkb25seSBwcm9jZWR1cmVQYXJhbWV0ZXJzID0gaW5wdXQ8UHJvY2VkdXJlUGFyYW1ldGVyTWV0YWRhdGFbXT4oW10pO1xuICByZWFkb25seSBhbGxDb21wb25lbnRzID0gaW5wdXQ8UmVwb3J0Q29tcG9uZW50RGVmaW5pdGlvbltdPihbXSk7XG4gIHJlYWRvbmx5IGlzRGV0ZWN0aW5nID0gaW5wdXQ8Ym9vbGVhbj4oZmFsc2UpO1xuICByZWFkb25seSBzdGF0dXNNZXNzYWdlID0gaW5wdXQ8c3RyaW5nIHwgbnVsbD4obnVsbCk7XG4gIHJlYWRvbmx5IHN0YXR1c0tpbmQgPSBpbnB1dDwnaW5mbycgfCAnc3VjY2VzcycgfCAnZXJyb3InIHwgbnVsbD4obnVsbCk7XG5cbiAgcmVhZG9ubHkgYWRkR3JpZCA9IG91dHB1dDx2b2lkPigpO1xuICByZWFkb25seSByZW1vdmVHcmlkID0gb3V0cHV0PHZvaWQ+KCk7XG4gIHJlYWRvbmx5IGFkZENvbHVtbiA9IG91dHB1dDx2b2lkPigpO1xuICByZWFkb25seSBhdXRvRGV0ZWN0Q29sdW1ucyA9IG91dHB1dDx2b2lkPigpO1xuICByZWFkb25seSByZW1vdmVDb2x1bW4gPSBvdXRwdXQ8bnVtYmVyPigpO1xuICByZWFkb25seSB1cGRhdGVDb2x1bW4gPSBvdXRwdXQ8eyBpbmRleDogbnVtYmVyOyBmaWVsZDogc3RyaW5nOyB2YWx1ZTogdW5rbm93biB9PigpO1xuICByZWFkb25seSB1cGRhdGVPcHRpb24gPSBvdXRwdXQ8eyBmaWVsZDogc3RyaW5nOyB2YWx1ZTogdW5rbm93biB9PigpO1xuICByZWFkb25seSB1cGRhdGVSb3dDbGlja0FjdGlvbiA9IG91dHB1dDxHcmlkUm93Q2xpY2tBY3Rpb24gfCB1bmRlZmluZWQ+KCk7XG4gIHJlYWRvbmx5IHNldERhdGFTb3VyY2UgPSBvdXRwdXQ8UmVwb3J0RGF0YVNvdXJjZURlZmluaXRpb24+KCk7XG4gIHJlYWRvbmx5IHVwZGF0ZURhdGFTb3VyY2VQYXJhbWV0ZXJzID0gb3V0cHV0PFJlY29yZDxzdHJpbmcsIHVua25vd24+PigpO1xuICByZWFkb25seSBlbnRpdHlDaGFuZ2VkID0gb3V0cHV0PHsgbmFtZTogc3RyaW5nOyB0eXBlOiAnc3RvcmVkX3Byb2NlZHVyZScgfCAndGFibGUnIH0+KCk7XG5cbiAgcmVhZG9ubHkgaW50ZXJuYWxQYXJhbWV0ZXJzID0gc2lnbmFsPFByb2NlZHVyZVBhcmFtZXRlck1ldGFkYXRhW10+KFtdKTtcblxuICByZWFkb25seSBlZmZlY3RpdmVQYXJhbWV0ZXJzID0gY29tcHV0ZWQ8UHJvY2VkdXJlUGFyYW1ldGVyTWV0YWRhdGFbXT4oKCkgPT4ge1xuICAgIGNvbnN0IGZyb21QYXJlbnQgPSB0aGlzLnByb2NlZHVyZVBhcmFtZXRlcnMoKTtcbiAgICBpZiAoZnJvbVBhcmVudCAmJiBmcm9tUGFyZW50Lmxlbmd0aCA+IDApIHJldHVybiBmcm9tUGFyZW50O1xuICAgIHJldHVybiB0aGlzLmludGVybmFsUGFyYW1ldGVycygpO1xuICB9KTtcblxuICByZWFkb25seSBzZWxlY3RlZFNvdXJjZVR5cGUgPSBzaWduYWw8J3N0b3JlZF9wcm9jZWR1cmUnIHwgJ3RhYmxlJz4oJ3N0b3JlZF9wcm9jZWR1cmUnKTtcbiAgcmVhZG9ubHkgaXNFeGVjU25pcHBldE9wZW4gPSBzaWduYWw8Ym9vbGVhbj4oZmFsc2UpO1xuICByZWFkb25seSBleGVjU25pcHBldFRleHQgPSBzaWduYWw8c3RyaW5nPignJyk7XG4gIHJlYWRvbmx5IGV4ZWNQYXJzZVN0YXR1cyA9IHNpZ25hbDx7IG1lc3NhZ2U6IHN0cmluZzsga2luZDogJ3N1Y2Nlc3MnIHwgJ2Vycm9yJyB9IHwgbnVsbD4obnVsbCk7XG5cbiAgdG9nZ2xlRXhlY1NuaXBwZXQoKTogdm9pZCB7XG4gICAgdGhpcy5pc0V4ZWNTbmlwcGV0T3Blbi51cGRhdGUoKHYpID0+ICF2KTtcbiAgICB0aGlzLmV4ZWNQYXJzZVN0YXR1cy5zZXQobnVsbCk7XG4gIH1cblxuICBhcHBseUV4ZWNTbmlwcGV0KCk6IHZvaWQge1xuICAgIGNvbnN0IHJhdyA9IHRoaXMuZXhlY1NuaXBwZXRUZXh0KCkudHJpbSgpO1xuICAgIGlmICghcmF3KSB7XG4gICAgICB0aGlzLmV4ZWNQYXJzZVN0YXR1cy5zZXQoeyBtZXNzYWdlOiAnUGxlYXNlIHBhc3RlIGFuIEVYRUMgc3RhdGVtZW50IGZpcnN0LicsIGtpbmQ6ICdlcnJvcicgfSk7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgY29uc3QgcGFyc2VkID0gcGFyc2VTcWxFeGVjU3RhdGVtZW50KHJhdyk7XG4gICAgaWYgKCFwYXJzZWQgfHwgT2JqZWN0LmtleXMocGFyc2VkLnBhcmFtZXRlcnMpLmxlbmd0aCA9PT0gMCkge1xuICAgICAgdGhpcy5leGVjUGFyc2VTdGF0dXMuc2V0KHtcbiAgICAgICAgbWVzc2FnZTogJ0NvdWxkIG5vdCBleHRyYWN0IHBhcmFtZXRlcnMuIEV4YW1wbGU6IGV4ZWMgUHJvY05hbWUgQHAxPXZhbDEsIEBwMj12YWwyJyxcbiAgICAgICAga2luZDogJ2Vycm9yJyxcbiAgICAgIH0pO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGlmIChwYXJzZWQucHJvY2VkdXJlTmFtZSAmJiBwYXJzZWQucHJvY2VkdXJlTmFtZS50b0xvd2VyQ2FzZSgpICE9PSB0aGlzLmFjdGl2ZUVudGl0eU5hbWUoKS50b0xvd2VyQ2FzZSgpKSB7XG4gICAgICB0aGlzLm9uU2VsZWN0RW50aXR5KHBhcnNlZC5wcm9jZWR1cmVOYW1lKTtcbiAgICB9XG5cbiAgICBjb25zdCBjdXJyZW50TWFwcGluZ3MgPSB7IC4uLigodGhpcy5kYXRhU291cmNlKCk/LnBhcmFtZXRlck1hcHBpbmdzIGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+KSB8fCB7fSkgfTtcbiAgICBsZXQgY291bnQgPSAwO1xuICAgIGZvciAoY29uc3QgW2tleSwgdmFsXSBvZiBPYmplY3QuZW50cmllcyhwYXJzZWQucGFyYW1ldGVycykpIHtcbiAgICAgIGNvbnN0IGNsZWFuS2V5ID0ga2V5LnJlcGxhY2UoL15ALywgJycpO1xuICAgICAgY3VycmVudE1hcHBpbmdzW2tleV0gPSB2YWw7XG4gICAgICBjdXJyZW50TWFwcGluZ3NbY2xlYW5LZXldID0gdmFsO1xuICAgICAgY3VycmVudE1hcHBpbmdzW2BAJHtjbGVhbktleX1gXSA9IHZhbDtcbiAgICAgIGNvdW50Kys7XG4gICAgfVxuXG4gICAgdGhpcy51cGRhdGVEYXRhU291cmNlUGFyYW1ldGVycy5lbWl0KGN1cnJlbnRNYXBwaW5ncyk7XG4gICAgdGhpcy5leGVjUGFyc2VTdGF0dXMuc2V0KHsgbWVzc2FnZTogYFN1Y2Nlc3NmdWxseSBhcHBsaWVkICR7Y291bnR9IHBhcmFtZXRlcihzKSFgLCBraW5kOiAnc3VjY2VzcycgfSk7XG4gICAgc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICB0aGlzLmlzRXhlY1NuaXBwZXRPcGVuLnNldChmYWxzZSk7XG4gICAgICB0aGlzLmV4ZWNQYXJzZVN0YXR1cy5zZXQobnVsbCk7XG4gICAgICB0aGlzLmV4ZWNTbmlwcGV0VGV4dC5zZXQoJycpO1xuICAgIH0sIDE1MDApO1xuICB9XG5cbiAgY29uc3RydWN0b3IoKSB7XG4gICAgZWZmZWN0KFxuICAgICAgKCkgPT4ge1xuICAgICAgICBjb25zdCBlbnRpdHkgPSB0aGlzLmFjdGl2ZUVudGl0eU5hbWUoKTtcbiAgICAgICAgY29uc3QgdHlwZSA9IHRoaXMuY3VycmVudFNvdXJjZVR5cGUoKTtcbiAgICAgICAgaWYgKGVudGl0eSAmJiB0eXBlID09PSAnc3RvcmVkX3Byb2NlZHVyZScgJiYgdGhpcy5kYXRhRGlzY292ZXJ5KSB7XG4gICAgICAgICAgdGhpcy5kYXRhRGlzY292ZXJ5LmdldFBhcmFtZXRlcnMoZW50aXR5LCAnZGJvJykuc3Vic2NyaWJlKHtcbiAgICAgICAgICAgIG5leHQ6IChwYXJhbXMpID0+IHRoaXMuaW50ZXJuYWxQYXJhbWV0ZXJzLnNldChwYXJhbXMgfHwgW10pLFxuICAgICAgICAgICAgZXJyb3I6ICgpID0+IHRoaXMuaW50ZXJuYWxQYXJhbWV0ZXJzLnNldChbXSksXG4gICAgICAgICAgfSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgdGhpcy5pbnRlcm5hbFBhcmFtZXRlcnMuc2V0KFtdKTtcbiAgICAgICAgfVxuICAgICAgfSxcbiAgICAgIHsgYWxsb3dTaWduYWxXcml0ZXM6IHRydWUgfVxuICAgICk7XG4gIH1cblxuICByZWFkb25seSBjdXJyZW50U291cmNlVHlwZSA9IGNvbXB1dGVkPCdzdG9yZWRfcHJvY2VkdXJlJyB8ICd0YWJsZSc+KCgpID0+IHtcbiAgICBjb25zdCBkcyA9IHRoaXMuZGF0YVNvdXJjZSgpO1xuICAgIGlmIChkcykge1xuICAgICAgcmV0dXJuIGRzLnR5cGUgPT09ICd0YWJsZScgPyAndGFibGUnIDogJ3N0b3JlZF9wcm9jZWR1cmUnO1xuICAgIH1cbiAgICByZXR1cm4gdGhpcy5zZWxlY3RlZFNvdXJjZVR5cGUoKTtcbiAgfSk7XG5cbiAgcmVhZG9ubHkgYWN0aXZlRW50aXR5TmFtZSA9IGNvbXB1dGVkPHN0cmluZz4oKCkgPT4ge1xuICAgIHJldHVybiB0aGlzLmRhdGFTb3VyY2UoKT8ubmFtZSB8fCB0aGlzLmRhdGFTb3VyY2UoKT8uZW5kcG9pbnQgfHwgJyc7XG4gIH0pO1xuXG4gIHJlYWRvbmx5IGF2YWlsYWJsZVRhYmxlcyA9IGNvbXB1dGVkKCgpID0+IHtcbiAgICByZXR1cm4gdGhpcy5hdmFpbGFibGVFbnRpdGllcygpLmZpbHRlcigoZSkgPT4ge1xuICAgICAgY29uc3QgdCA9IChlLnR5cGUgfHwgJycpLnRvTG93ZXJDYXNlKCk7XG4gICAgICByZXR1cm4gdCA9PT0gJ3RhYmxlJyB8fCB0ID09PSAndmlldyc7XG4gICAgfSk7XG4gIH0pO1xuXG4gIHJlYWRvbmx5IGF2YWlsYWJsZVByb2NlZHVyZXMgPSBjb21wdXRlZCgoKSA9PiB7XG4gICAgcmV0dXJuIHRoaXMuYXZhaWxhYmxlRW50aXRpZXMoKS5maWx0ZXIoKGUpID0+IHtcbiAgICAgIGNvbnN0IHQgPSAoZS50eXBlIHx8ICcnKS50b0xvd2VyQ2FzZSgpO1xuICAgICAgcmV0dXJuIHQgPT09ICdzdG9yZWRfcHJvY2VkdXJlJyB8fCB0ID09PSAncHJvY2VkdXJlJyB8fCB0LmluY2x1ZGVzKCdwcm9jZWR1cmUnKTtcbiAgICB9KTtcbiAgfSk7XG5cbiAgcmVhZG9ubHkgYWN0aXZlRW50aXR5TGlzdCA9IGNvbXB1dGVkKCgpID0+IHtcbiAgICByZXR1cm4gdGhpcy5jdXJyZW50U291cmNlVHlwZSgpID09PSAndGFibGUnID8gdGhpcy5hdmFpbGFibGVUYWJsZXMoKSA6IHRoaXMuYXZhaWxhYmxlUHJvY2VkdXJlcygpO1xuICB9KTtcblxuICByZWFkb25seSBncmlkRW50aXR5U2VsZWN0T3B0aW9ucyA9IGNvbXB1dGVkPFNlYXJjaGFibGVTZWxlY3RPcHRpb25bXT4oKCkgPT4ge1xuICAgIHJldHVybiB0aGlzLmFjdGl2ZUVudGl0eUxpc3QoKS5tYXAoKGVudCkgPT4gKHtcbiAgICAgIHZhbHVlOiBlbnQubmFtZSxcbiAgICAgIGxhYmVsOiBlbnQuZnJpZW5kbHlOYW1lIHx8IGVudC5uYW1lLFxuICAgICAgc3VibGFiZWw6IGVudC5zY2hlbWEgPyBgJHtlbnQuc2NoZW1hfS4ke2VudC5uYW1lfWAgOiBlbnQubmFtZSxcbiAgICAgIGJhZGdlOiBlbnQudHlwZSA9PT0gJ3N0b3JlZF9wcm9jZWR1cmUnID8gJ1NQJyA6IChlbnQudHlwZSB8fCAnVGFibGUnKSxcbiAgICB9KSk7XG4gIH0pO1xuXG4gIHJlYWRvbmx5IGNvbHVtbnMgPSBjb21wdXRlZDxHcmlkQ29sdW1uRGVmaW5pdGlvbltdPigoKSA9PiB7XG4gICAgcmV0dXJuIHRoaXMuZ3JpZCgpPy5jb2x1bW5zID8/IFtdO1xuICB9KTtcblxuICByZWFkb25seSByb3dDbGlja0FjdGlvbiA9IGNvbXB1dGVkPEdyaWRSb3dDbGlja0FjdGlvbiB8IHVuZGVmaW5lZD4oKCkgPT4ge1xuICAgIHJldHVybiB0aGlzLmdyaWQoKT8ucm93Q2xpY2tBY3Rpb24gPz8gdGhpcy5ncmlkKCk/Lm9wdGlvbnM/LnJvd0NsaWNrQWN0aW9uO1xuICB9KTtcblxuICByZWFkb25seSBoYXNSb3dDbGlja0FjdGlvbiA9IGNvbXB1dGVkPGJvb2xlYW4+KCgpID0+IHtcbiAgICByZXR1cm4gISF0aGlzLnJvd0NsaWNrQWN0aW9uKCk7XG4gIH0pO1xuXG4gIHJlYWRvbmx5IHBhcmFtZXRlck1hcHBpbmdzID0gY29tcHV0ZWQ8eyBrZXk6IHN0cmluZzsgdmFsdWU6IHN0cmluZyB9W10+KCgpID0+IHtcbiAgICBjb25zdCBtYXBwaW5nID0gdGhpcy5yb3dDbGlja0FjdGlvbigpPy5wYXJhbWV0ZXJNYXBwaW5nO1xuICAgIGlmICghbWFwcGluZykgcmV0dXJuIFtdO1xuICAgIHJldHVybiBPYmplY3QuZW50cmllcyhtYXBwaW5nKS5tYXAoKFtrZXksIHZhbHVlXSkgPT4gKHsga2V5LCB2YWx1ZSB9KSk7XG4gIH0pO1xuXG4gIG9uU291cmNlVHlwZUNoYW5nZSh0eXBlOiAnc3RvcmVkX3Byb2NlZHVyZScgfCAndGFibGUnKTogdm9pZCB7XG4gICAgdGhpcy5zZWxlY3RlZFNvdXJjZVR5cGUuc2V0KHR5cGUpO1xuICB9XG5cbiAgb25TZWxlY3RFbnRpdHkoZW50aXR5TmFtZTogc3RyaW5nKTogdm9pZCB7XG4gICAgaWYgKCFlbnRpdHlOYW1lKSByZXR1cm47XG4gICAgaWYgKHRoaXMuY3VycmVudFNvdXJjZVR5cGUoKSA9PT0gJ3N0b3JlZF9wcm9jZWR1cmUnICYmIHRoaXMuZGF0YURpc2NvdmVyeSkge1xuICAgICAgdGhpcy5kYXRhRGlzY292ZXJ5LmdldFBhcmFtZXRlcnMoZW50aXR5TmFtZSwgJ2RibycpLnN1YnNjcmliZSh7XG4gICAgICAgIG5leHQ6IChwYXJhbXMpID0+IHRoaXMuaW50ZXJuYWxQYXJhbWV0ZXJzLnNldChwYXJhbXMgfHwgW10pLFxuICAgICAgICBlcnJvcjogKCkgPT4gdGhpcy5pbnRlcm5hbFBhcmFtZXRlcnMuc2V0KFtdKSxcbiAgICAgIH0pO1xuICAgIH1cbiAgICB0aGlzLmVudGl0eUNoYW5nZWQuZW1pdCh7IG5hbWU6IGVudGl0eU5hbWUsIHR5cGU6IHRoaXMuY3VycmVudFNvdXJjZVR5cGUoKSB9KTtcbiAgfVxuXG4gIGdldFBhcmFtZXRlclZhbHVlKHBhcmFtTmFtZTogc3RyaW5nKTogc3RyaW5nIHwgbnVtYmVyIHwgYm9vbGVhbiB7XG4gICAgY29uc3QgbWFwcGluZ3MgPSAodGhpcy5kYXRhU291cmNlKCk/LnBhcmFtZXRlck1hcHBpbmdzIGFzIFJlY29yZDxzdHJpbmcsIHN0cmluZyB8IG51bWJlciB8IGJvb2xlYW4+KSB8fCB7fTtcbiAgICBjb25zdCBjbGVhbk5hbWUgPSBwYXJhbU5hbWUucmVwbGFjZSgvXkAvLCAnJyk7XG4gICAgY29uc3QgdmFsID0gbWFwcGluZ3NbcGFyYW1OYW1lXSA/PyBtYXBwaW5nc1tgQCR7Y2xlYW5OYW1lfWBdID8/IG1hcHBpbmdzW2NsZWFuTmFtZV07XG4gICAgaWYgKHR5cGVvZiB2YWwgPT09ICdzdHJpbmcnIHx8IHR5cGVvZiB2YWwgPT09ICdudW1iZXInIHx8IHR5cGVvZiB2YWwgPT09ICdib29sZWFuJykge1xuICAgICAgcmV0dXJuIHZhbDtcbiAgICB9XG4gICAgcmV0dXJuICcnO1xuICB9XG5cbiAgb25QYXJhbWV0ZXJDaGFuZ2UocGFyYW1OYW1lOiBzdHJpbmcsIHZhbHVlOiBzdHJpbmcgfCBudW1iZXIgfCBib29sZWFuKTogdm9pZCB7XG4gICAgY29uc3QgY3VycmVudCA9IHsgLi4uKCh0aGlzLmRhdGFTb3VyY2UoKT8ucGFyYW1ldGVyTWFwcGluZ3MgYXMgUmVjb3JkPHN0cmluZywgc3RyaW5nIHwgbnVtYmVyIHwgYm9vbGVhbj4pIHx8IHt9KSB9O1xuICAgIGNvbnN0IGNsZWFuTmFtZSA9IHBhcmFtTmFtZS5yZXBsYWNlKC9eQC8sICcnKTtcbiAgICBjdXJyZW50W3BhcmFtTmFtZV0gPSB2YWx1ZTtcbiAgICBjdXJyZW50W2BAJHtjbGVhbk5hbWV9YF0gPSB2YWx1ZTtcbiAgICBjdXJyZW50W2NsZWFuTmFtZV0gPSB2YWx1ZTtcbiAgICB0aGlzLnVwZGF0ZURhdGFTb3VyY2VQYXJhbWV0ZXJzLmVtaXQoY3VycmVudCk7XG4gIH1cblxuICBvblVwZGF0ZUNvbChpbmRleDogbnVtYmVyLCBmaWVsZDogc3RyaW5nLCB2YWx1ZTogdW5rbm93bik6IHZvaWQge1xuICAgIHRoaXMudXBkYXRlQ29sdW1uLmVtaXQoeyBpbmRleCwgZmllbGQsIHZhbHVlIH0pO1xuICB9XG5cbiAgdG9nZ2xlUm93Q2xpY2tBY3Rpb24oZW5hYmxlZDogYm9vbGVhbik6IHZvaWQge1xuICAgIGlmIChlbmFibGVkKSB7XG4gICAgICB0aGlzLnVwZGF0ZVJvd0NsaWNrQWN0aW9uLmVtaXQoe1xuICAgICAgICB0eXBlOiAnb3Blbi1kcmF3ZXInLFxuICAgICAgICBkcmF3ZXJUaXRsZTogJ0RldGFpbHMnLFxuICAgICAgICBkcmF3ZXJXaWR0aDogJzc2MHB4JyxcbiAgICAgIH0pO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLnVwZGF0ZVJvd0NsaWNrQWN0aW9uLmVtaXQodW5kZWZpbmVkKTtcbiAgICB9XG4gIH1cblxuICB1cGRhdGVSb3dBY3Rpb25GaWVsZChmaWVsZDoga2V5b2YgR3JpZFJvd0NsaWNrQWN0aW9uLCB2YWx1ZTogdW5rbm93bik6IHZvaWQge1xuICAgIGNvbnN0IGN1cnJlbnQgPSB0aGlzLnJvd0NsaWNrQWN0aW9uKCkgPz8geyB0eXBlOiAnb3Blbi1kcmF3ZXInIH07XG4gICAgY29uc3QgbmV4dCA9IHsgLi4uY3VycmVudCwgW2ZpZWxkXTogdmFsdWUgfTtcbiAgICB0aGlzLnVwZGF0ZVJvd0NsaWNrQWN0aW9uLmVtaXQobmV4dCk7XG4gIH1cblxuICBhZGRQYXJhbWV0ZXJNYXBwaW5nKCk6IHZvaWQge1xuICAgIGNvbnN0IGN1cnJlbnQgPSB0aGlzLnJvd0NsaWNrQWN0aW9uKCkgPz8geyB0eXBlOiAnb3Blbi1kcmF3ZXInIH07XG4gICAgY29uc3QgbWFwcGluZyA9IHsgLi4uKGN1cnJlbnQucGFyYW1ldGVyTWFwcGluZyA/PyB7fSkgfTtcbiAgICBsZXQgaWR4ID0gT2JqZWN0LmtleXMobWFwcGluZykubGVuZ3RoICsgMTtcbiAgICBsZXQga2V5ID0gYHBhcmFtJHtpZHh9YDtcbiAgICB3aGlsZSAoa2V5IGluIG1hcHBpbmcpIHtcbiAgICAgIGlkeCsrO1xuICAgICAga2V5ID0gYHBhcmFtJHtpZHh9YDtcbiAgICB9XG4gICAgbWFwcGluZ1trZXldID0gJ3Jvdy5pZCc7XG4gICAgdGhpcy51cGRhdGVSb3dDbGlja0FjdGlvbi5lbWl0KHsgLi4uY3VycmVudCwgcGFyYW1ldGVyTWFwcGluZzogbWFwcGluZyB9KTtcbiAgfVxuXG4gIHVwZGF0ZU1hcHBpbmdLZXkoaW5kZXg6IG51bWJlciwgbmV3S2V5OiBzdHJpbmcpOiB2b2lkIHtcbiAgICBjb25zdCBwYWlycyA9IHRoaXMucGFyYW1ldGVyTWFwcGluZ3MoKTtcbiAgICBpZiAoIXBhaXJzW2luZGV4XSkgcmV0dXJuO1xuICAgIGNvbnN0IG5leHRNYXBwaW5nOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+ID0ge307XG4gICAgcGFpcnMuZm9yRWFjaCgocCwgaSkgPT4ge1xuICAgICAgY29uc3QgayA9IGkgPT09IGluZGV4ID8gbmV3S2V5IDogcC5rZXk7XG4gICAgICBpZiAoay50cmltKCkpIHtcbiAgICAgICAgbmV4dE1hcHBpbmdbay50cmltKCldID0gcC52YWx1ZTtcbiAgICAgIH1cbiAgICB9KTtcbiAgICBjb25zdCBjdXJyZW50ID0gdGhpcy5yb3dDbGlja0FjdGlvbigpID8/IHsgdHlwZTogJ29wZW4tZHJhd2VyJyB9O1xuICAgIHRoaXMudXBkYXRlUm93Q2xpY2tBY3Rpb24uZW1pdCh7IC4uLmN1cnJlbnQsIHBhcmFtZXRlck1hcHBpbmc6IG5leHRNYXBwaW5nIH0pO1xuICB9XG5cbiAgdXBkYXRlTWFwcGluZ1ZhbHVlKGluZGV4OiBudW1iZXIsIG5ld1ZhbHVlOiBzdHJpbmcpOiB2b2lkIHtcbiAgICBjb25zdCBwYWlycyA9IHRoaXMucGFyYW1ldGVyTWFwcGluZ3MoKTtcbiAgICBpZiAoIXBhaXJzW2luZGV4XSkgcmV0dXJuO1xuICAgIGNvbnN0IG5leHRNYXBwaW5nOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+ID0ge307XG4gICAgcGFpcnMuZm9yRWFjaCgocCwgaSkgPT4ge1xuICAgICAgY29uc3QgdiA9IGkgPT09IGluZGV4ID8gbmV3VmFsdWUgOiBwLnZhbHVlO1xuICAgICAgaWYgKHAua2V5LnRyaW0oKSkge1xuICAgICAgICBuZXh0TWFwcGluZ1twLmtleS50cmltKCldID0gdjtcbiAgICAgIH1cbiAgICB9KTtcbiAgICBjb25zdCBjdXJyZW50ID0gdGhpcy5yb3dDbGlja0FjdGlvbigpID8/IHsgdHlwZTogJ29wZW4tZHJhd2VyJyB9O1xuICAgIHRoaXMudXBkYXRlUm93Q2xpY2tBY3Rpb24uZW1pdCh7IC4uLmN1cnJlbnQsIHBhcmFtZXRlck1hcHBpbmc6IG5leHRNYXBwaW5nIH0pO1xuICB9XG5cbiAgcmVtb3ZlTWFwcGluZyhpbmRleDogbnVtYmVyKTogdm9pZCB7XG4gICAgY29uc3QgcGFpcnMgPSB0aGlzLnBhcmFtZXRlck1hcHBpbmdzKCk7XG4gICAgY29uc3QgbmV4dE1hcHBpbmc6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4gPSB7fTtcbiAgICBwYWlycy5mb3JFYWNoKChwLCBpKSA9PiB7XG4gICAgICBpZiAoaSAhPT0gaW5kZXggJiYgcC5rZXkudHJpbSgpKSB7XG4gICAgICAgIG5leHRNYXBwaW5nW3Aua2V5LnRyaW0oKV0gPSBwLnZhbHVlO1xuICAgICAgfVxuICAgIH0pO1xuICAgIGNvbnN0IGN1cnJlbnQgPSB0aGlzLnJvd0NsaWNrQWN0aW9uKCkgPz8geyB0eXBlOiAnb3Blbi1kcmF3ZXInIH07XG4gICAgdGhpcy51cGRhdGVSb3dDbGlja0FjdGlvbi5lbWl0KHsgLi4uY3VycmVudCwgcGFyYW1ldGVyTWFwcGluZzogbmV4dE1hcHBpbmcgfSk7XG4gIH1cbn1cbiIsIiAgICBAaWYgKCFncmlkKCkpIHtcbiAgICAgIDxkaXYgY2xhc3M9XCJlbXB0eS1ncmlkLWNhcmRcIj5cbiAgICAgICAgPGRpdiBjbGFzcz1cImVtcHR5LWdyaWQtaWNvblwiPlxuICAgICAgICAgIDxycHQtaWNvbiBuYW1lPVwidGFibGVcIiBbc2l6ZV09XCIyOFwiIC8+XG4gICAgICAgIDwvZGl2PlxuICAgICAgICA8aDQgY2xhc3M9XCJlbXB0eS1ncmlkLXRpdGxlXCI+Tm8gUmVzdWx0IEdyaWQgQXR0YWNoZWQ8L2g0PlxuICAgICAgICA8cCBjbGFzcz1cImVtcHR5LWdyaWQtZGVzY1wiPkF0dGFjaCBhbiBpbnRlcmFjdGl2ZSBSZXN1bHQgRGF0YSBHcmlkIChvciBVbHRyYUdyaWQpIHRvIHRoaXMgcmVwb3J0IGRlZmluaXRpb24gdG8gcmVuZGVyIHF1ZXJpZXMgYW5kIHN0b3JlZCBwcm9jZWR1cmUgcmVzdWx0cy48L3A+XG4gICAgICAgIDxidXR0b24gdHlwZT1cImJ1dHRvblwiIGNsYXNzPVwiYnRuLWNyZWF0ZS1ncmlkLWFjdGlvblwiIChjbGljayk9XCJhZGRHcmlkLmVtaXQoKVwiPlxuICAgICAgICAgIDxycHQtaWNvbiBuYW1lPVwicGx1c1wiIFtzaXplXT1cIjE0XCIgLz5cbiAgICAgICAgICA8c3Bhbj4rIEFkZCBSZXN1bHQgR3JpZDwvc3Bhbj5cbiAgICAgICAgPC9idXR0b24+XG4gICAgICA8L2Rpdj5cbiAgICB9IEBlbHNlIHtcbiAgICAgIDxkaXYgY2xhc3M9XCJwcm9wcy1mb3JtXCI+XG4gICAgICA8IS0tIDEuIFJlcG9ydCBEYXRhIFNvdXJjZSAmIFN0b3JlZCBQcm9jZWR1cmUgQ29uZmlndXJhdGlvbiAtLT5cbiAgICAgIDxkaXYgY2xhc3M9XCJwcm9wZXJ0eS1ncm91cFwiPlxuICAgICAgICA8ZGl2IGNsYXNzPVwiZ3JvdXAtaGVhZGVyLXJvd1wiPlxuICAgICAgICAgIDxkaXYgY2xhc3M9XCJncm91cC10aXRsZS13cmFwXCI+XG4gICAgICAgICAgICA8c3BhbiBjbGFzcz1cImdyb3VwLXRpdGxlXCI+UmVwb3J0IERhdGEgU291cmNlPC9zcGFuPlxuICAgICAgICAgICAgQGlmIChhY3RpdmVFbnRpdHlOYW1lKCkpIHtcbiAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJncm91cC1iYWRnZSBhY3RpdmUtZHMtYmFkZ2VcIj57eyBhY3RpdmVFbnRpdHlOYW1lKCkgfX08L3NwYW4+XG4gICAgICAgICAgICB9XG4gICAgICAgICAgPC9kaXY+XG4gICAgICAgIDwvZGl2PlxuXG4gICAgICAgIDwhLS0gU291cmNlIFR5cGUgU3dpdGNoZXIgKFN0b3JlZCBQcm9jZWR1cmUgdnMgVGFibGUpIC0tPlxuICAgICAgICA8ZGl2IGNsYXNzPVwic291cmNlLXR5cGUtc3dpdGNoZXJcIj5cbiAgICAgICAgICA8YnV0dG9uXG4gICAgICAgICAgICB0eXBlPVwiYnV0dG9uXCJcbiAgICAgICAgICAgIGNsYXNzPVwic291cmNlLXRhYi1idG5cIlxuICAgICAgICAgICAgW2NsYXNzLmFjdGl2ZV09XCJjdXJyZW50U291cmNlVHlwZSgpID09PSAnc3RvcmVkX3Byb2NlZHVyZSdcIlxuICAgICAgICAgICAgKGNsaWNrKT1cIm9uU291cmNlVHlwZUNoYW5nZSgnc3RvcmVkX3Byb2NlZHVyZScpXCJcbiAgICAgICAgICA+XG4gICAgICAgICAgICA8cnB0LWljb24gbmFtZT1cImNvZGVcIiBbc2l6ZV09XCIxMlwiIC8+XG4gICAgICAgICAgICA8c3Bhbj5TdG9yZWQgUHJvY2VkdXJlPC9zcGFuPlxuICAgICAgICAgIDwvYnV0dG9uPlxuICAgICAgICAgIDxidXR0b25cbiAgICAgICAgICAgIHR5cGU9XCJidXR0b25cIlxuICAgICAgICAgICAgY2xhc3M9XCJzb3VyY2UtdGFiLWJ0blwiXG4gICAgICAgICAgICBbY2xhc3MuYWN0aXZlXT1cImN1cnJlbnRTb3VyY2VUeXBlKCkgPT09ICd0YWJsZSdcIlxuICAgICAgICAgICAgKGNsaWNrKT1cIm9uU291cmNlVHlwZUNoYW5nZSgndGFibGUnKVwiXG4gICAgICAgICAgPlxuICAgICAgICAgICAgPHJwdC1pY29uIG5hbWU9XCJ0YWJsZVwiIFtzaXplXT1cIjEyXCIgLz5cbiAgICAgICAgICAgIDxzcGFuPlRhYmxlIC8gVmlldzwvc3Bhbj5cbiAgICAgICAgICA8L2J1dHRvbj5cbiAgICAgICAgPC9kaXY+XG5cbiAgICAgICAgPCEtLSBFbnRpdHkgU2VsZWN0b3IgRHJvcGRvd24gLS0+XG4gICAgICAgIDxkaXYgY2xhc3M9XCJmaWVsZC1yb3dcIj5cbiAgICAgICAgICA8bGFiZWwgY2xhc3M9XCJmaWVsZC1sYWJlbFwiPlxuICAgICAgICAgICAge3sgY3VycmVudFNvdXJjZVR5cGUoKSA9PT0gJ3N0b3JlZF9wcm9jZWR1cmUnID8gJ1N0b3JlZCBQcm9jZWR1cmUnIDogJ1RhYmxlIC8gVmlldycgfX1cbiAgICAgICAgICA8L2xhYmVsPlxuICAgICAgICAgIDxycHQtc2VhcmNoYWJsZS1zZWxlY3RcbiAgICAgICAgICAgIFtvcHRpb25zXT1cImdyaWRFbnRpdHlTZWxlY3RPcHRpb25zKClcIlxuICAgICAgICAgICAgW25nTW9kZWxdPVwiYWN0aXZlRW50aXR5TmFtZSgpXCJcbiAgICAgICAgICAgIChuZ01vZGVsQ2hhbmdlKT1cIm9uU2VsZWN0RW50aXR5KCRldmVudClcIlxuICAgICAgICAgICAgcGxhY2Vob2xkZXI9XCItLSBDaG9vc2UgRGF0YSBTb3VyY2UgLS1cIlxuICAgICAgICAgICAgW3NlYXJjaFBsYWNlaG9sZGVyXT1cImN1cnJlbnRTb3VyY2VUeXBlKCkgPT09ICdzdG9yZWRfcHJvY2VkdXJlJyA/ICdTZWFyY2ggcHJvY2VkdXJlcy4uLicgOiAnU2VhcmNoIHRhYmxlcyAmIHZpZXdzLi4uJ1wiXG4gICAgICAgICAgLz5cbiAgICAgICAgPC9kaXY+XG5cbiAgICAgICAgPCEtLSBTdG9yZWQgUHJvY2VkdXJlIFBhcmFtZXRlciBNYXBwaW5ncyAtLT5cbiAgICAgICAgQGlmIChjdXJyZW50U291cmNlVHlwZSgpID09PSAnc3RvcmVkX3Byb2NlZHVyZScgJiYgYWN0aXZlRW50aXR5TmFtZSgpKSB7XG4gICAgICAgICAgPGRpdiBjbGFzcz1cInByb2NlZHVyZS1wYXJhbXMtc2VjdGlvblwiPlxuICAgICAgICAgICAgPGRpdiBjbGFzcz1cInBhcmFtcy1zZWN0aW9uLWhlYWRlclwiPlxuICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwicGFyYW1zLWhlYWRlci1sZWZ0XCI+XG4gICAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJwYXJhbXMtdGl0bGVcIj5Qcm9jZWR1cmUgUGFyYW1ldGVyczwvc3Bhbj5cbiAgICAgICAgICAgICAgICA8c3BhbiBjbGFzcz1cInBhcmFtcy1jb3VudC1iYWRnZVwiPnt7IGVmZmVjdGl2ZVBhcmFtZXRlcnMoKS5sZW5ndGggfX08L3NwYW4+XG4gICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgICA8YnV0dG9uXG4gICAgICAgICAgICAgICAgdHlwZT1cImJ1dHRvblwiXG4gICAgICAgICAgICAgICAgY2xhc3M9XCJidG4tcGFzdGUtZXhlY1wiXG4gICAgICAgICAgICAgICAgKGNsaWNrKT1cInRvZ2dsZUV4ZWNTbmlwcGV0KClcIlxuICAgICAgICAgICAgICAgIHRpdGxlPVwiUGFzdGUgZnVsbCBTU01TICdFWEVDIHByb2MgQHBhcmFtPXZhbCcgc25pcHBldCB0byBmaWxsIHBhcmFtZXRlcnMgYXV0b21hdGljYWxseVwiXG4gICAgICAgICAgICAgID5cbiAgICAgICAgICAgICAgICA8cnB0LWljb24gbmFtZT1cImNvZGVcIiBbc2l6ZV09XCIxMlwiIC8+XG4gICAgICAgICAgICAgICAgPHNwYW4+e3sgaXNFeGVjU25pcHBldE9wZW4oKSA/ICdDbG9zZSBTUUwnIDogJ1Bhc3RlIFNRTCBFeGVjJyB9fTwvc3Bhbj5cbiAgICAgICAgICAgICAgPC9idXR0b24+XG4gICAgICAgICAgICA8L2Rpdj5cblxuICAgICAgICAgICAgQGlmIChpc0V4ZWNTbmlwcGV0T3BlbigpKSB7XG4gICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJleGVjLXNuaXBwZXQtcGFuZWxcIj5cbiAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwiZXhlYy1zbmlwcGV0LWhlYWRlclwiPlxuICAgICAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJzbmlwcGV0LWhpbnRcIj5QYXN0ZSBmdWxsIDxjb2RlPkVYRUMgUHJvY2VkdXJlTmFtZSAmIzY0O3BhcmFtPXZhbC4uLjwvY29kZT4gc3RhdGVtZW50IGZyb20gU1NNUzo8L3NwYW4+XG4gICAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICAgICAgPHRleHRhcmVhXG4gICAgICAgICAgICAgICAgICBjbGFzcz1cImV4ZWMtc25pcHBldC10ZXh0YXJlYVwiXG4gICAgICAgICAgICAgICAgICByb3dzPVwiM1wiXG4gICAgICAgICAgICAgICAgICBwbGFjZWhvbGRlcj1cImUuZy4gZXhlYyBHZXRfSGVscExpc3QgQGNockNPTVBBTllJRD1OJzEwMScsQGNoclRhYmxlTmFtZT1OJ01TVEFDQ1RHTFNVQicuLi5cIlxuICAgICAgICAgICAgICAgICAgW25nTW9kZWxdPVwiZXhlY1NuaXBwZXRUZXh0KClcIlxuICAgICAgICAgICAgICAgICAgKG5nTW9kZWxDaGFuZ2UpPVwiZXhlY1NuaXBwZXRUZXh0LnNldCgkZXZlbnQpXCJcbiAgICAgICAgICAgICAgICA+PC90ZXh0YXJlYT5cbiAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwiZXhlYy1zbmlwcGV0LWFjdGlvbnNcIj5cbiAgICAgICAgICAgICAgICAgIDxidXR0b24gdHlwZT1cImJ1dHRvblwiIGNsYXNzPVwiYnRuLXNuaXBwZXQtYXBwbHlcIiAoY2xpY2spPVwiYXBwbHlFeGVjU25pcHBldCgpXCI+XG4gICAgICAgICAgICAgICAgICAgIDxycHQtaWNvbiBuYW1lPVwiY2hlY2tcIiBbc2l6ZV09XCIxMlwiIC8+XG4gICAgICAgICAgICAgICAgICAgIDxzcGFuPkFwcGx5IFBhcmFtZXRlcnM8L3NwYW4+XG4gICAgICAgICAgICAgICAgICA8L2J1dHRvbj5cbiAgICAgICAgICAgICAgICAgIDxidXR0b24gdHlwZT1cImJ1dHRvblwiIGNsYXNzPVwiYnRuLXNuaXBwZXQtY2FuY2VsXCIgKGNsaWNrKT1cInRvZ2dsZUV4ZWNTbmlwcGV0KClcIj5cbiAgICAgICAgICAgICAgICAgICAgQ2FuY2VsXG4gICAgICAgICAgICAgICAgICA8L2J1dHRvbj5cbiAgICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgICAgICBAaWYgKGV4ZWNQYXJzZVN0YXR1cygpKSB7XG4gICAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwic25pcHBldC1zdGF0dXNcIiBbY2xhc3MuaXMtZXJyb3JdPVwiZXhlY1BhcnNlU3RhdHVzKCk/LmtpbmQgPT09ICdlcnJvcidcIiBbY2xhc3MuaXMtc3VjY2Vzc109XCJleGVjUGFyc2VTdGF0dXMoKT8ua2luZCA9PT0gJ3N1Y2Nlc3MnXCI+XG4gICAgICAgICAgICAgICAgICAgIHt7IGV4ZWNQYXJzZVN0YXR1cygpPy5tZXNzYWdlIH19XG4gICAgICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBAaWYgKGVmZmVjdGl2ZVBhcmFtZXRlcnMoKS5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJwYXJhbS1jYXJkcy1saXN0XCI+XG4gICAgICAgICAgICAgICAgQGZvciAocGFyYW0gb2YgZWZmZWN0aXZlUGFyYW1ldGVycygpOyB0cmFjayBwYXJhbS5uYW1lKSB7XG4gICAgICAgICAgICAgICAgICA8cnB0LXBhcmFtZXRlci1iaW5kaW5nLWVkaXRvclxuICAgICAgICAgICAgICAgICAgICBbcGFyYW1dPVwicGFyYW1cIlxuICAgICAgICAgICAgICAgICAgICBbY3VycmVudFZhbHVlXT1cImdldFBhcmFtZXRlclZhbHVlKHBhcmFtLm5hbWUpXCJcbiAgICAgICAgICAgICAgICAgICAgW2FsbENvbXBvbmVudHNdPVwiYWxsQ29tcG9uZW50cygpXCJcbiAgICAgICAgICAgICAgICAgICAgKHZhbHVlQ2hhbmdlKT1cIm9uUGFyYW1ldGVyQ2hhbmdlKHBhcmFtLm5hbWUsICRldmVudClcIlxuICAgICAgICAgICAgICAgICAgLz5cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgfSBAZWxzZSB7XG4gICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJlbXB0eS1wYXJhbXMtaGludFwiPlxuICAgICAgICAgICAgICAgIDxzcGFuPk5vIHJlcXVpcmVkIHBhcmFtZXRlcnMgZm9yIHRoaXMgcHJvY2VkdXJlLjwvc3Bhbj5cbiAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICB9XG4gICAgICAgICAgPC9kaXY+XG4gICAgICAgIH1cbiAgICAgIDwvZGl2PlxuXG4gICAgICA8IS0tIDIuIFJlc3VsdCBDb2x1bW5zIENvbmZpZ3VyYXRpb24gLS0+XG4gICAgICA8ZGl2IGNsYXNzPVwicHJvcGVydHktZ3JvdXBcIj5cbiAgICAgICAgPGRpdiBjbGFzcz1cImdyb3VwLWhlYWRlci1yb3dcIj5cbiAgICAgICAgICA8ZGl2IGNsYXNzPVwiZ3JvdXAtdGl0bGUtd3JhcFwiPlxuICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJncm91cC10aXRsZVwiPkNvbHVtbnM8L3NwYW4+XG4gICAgICAgICAgICA8c3BhbiBjbGFzcz1cImdyb3VwLWJhZGdlXCI+e3sgY29sdW1ucygpLmxlbmd0aCB9fTwvc3Bhbj5cbiAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgPC9kaXY+XG5cbiAgICAgICAgPCEtLSBEZWRpY2F0ZWQgRnVsbC1XaWR0aCBBY3Rpb24gQnV0dG9ucyAoTm8gY3JhbXBpbmcpIC0tPlxuICAgICAgICA8ZGl2IGNsYXNzPVwiY29sdW1ucy1hY3Rpb24tYmFyXCI+XG4gICAgICAgICAgPGJ1dHRvblxuICAgICAgICAgICAgdHlwZT1cImJ1dHRvblwiXG4gICAgICAgICAgICBjbGFzcz1cImJ0bi1jb2wtYWN0aW9uIGJ0bi1hdXRvLWRldGVjdFwiXG4gICAgICAgICAgICAoY2xpY2spPVwiYXV0b0RldGVjdENvbHVtbnMuZW1pdCgpXCJcbiAgICAgICAgICAgIFtkaXNhYmxlZF09XCJpc0RldGVjdGluZygpXCJcbiAgICAgICAgICAgIHRpdGxlPVwiQXV0by1kZXRlY3QgYWxsIGNvbHVtbnMgZnJvbSBwcm9jZWR1cmUgb3IgZGF0YSB0YWJsZVwiXG4gICAgICAgICAgPlxuICAgICAgICAgICAgPHJwdC1pY29uIG5hbWU9XCJyZWZyZXNoXCIgW3NpemVdPVwiMTJcIiBbY2xhc3MucnB0LXNwaW5dPVwiaXNEZXRlY3RpbmcoKVwiIC8+XG4gICAgICAgICAgICA8c3Bhbj57eyBpc0RldGVjdGluZygpID8gJ0RldGVjdGluZy4uLicgOiAnQXV0by1EZXRlY3QnIH19PC9zcGFuPlxuICAgICAgICAgIDwvYnV0dG9uPlxuICAgICAgICAgIDxidXR0b25cbiAgICAgICAgICAgIHR5cGU9XCJidXR0b25cIlxuICAgICAgICAgICAgY2xhc3M9XCJidG4tY29sLWFjdGlvbiBidG4tYWRkLWNvbFwiXG4gICAgICAgICAgICAoY2xpY2spPVwiYWRkQ29sdW1uLmVtaXQoKVwiXG4gICAgICAgICAgICB0aXRsZT1cIkFkZCBhIG5ldyBjb2x1bW4gbWFudWFsbHlcIlxuICAgICAgICAgID5cbiAgICAgICAgICAgIDxycHQtaWNvbiBuYW1lPVwicGx1c1wiIFtzaXplXT1cIjEyXCIgLz5cbiAgICAgICAgICAgIDxzcGFuPisgQWRkIENvbHVtbjwvc3Bhbj5cbiAgICAgICAgICA8L2J1dHRvbj5cbiAgICAgICAgPC9kaXY+XG5cbiAgICAgICAgQGlmIChzdGF0dXNNZXNzYWdlKCkpIHtcbiAgICAgICAgICA8ZGl2IGNsYXNzPVwiY29sLXN0YXR1cy1iYW5uZXJcIiBbY2xhc3MuaXMtZXJyb3JdPVwic3RhdHVzS2luZCgpID09PSAnZXJyb3InXCIgW2NsYXNzLmlzLXN1Y2Nlc3NdPVwic3RhdHVzS2luZCgpID09PSAnc3VjY2VzcydcIj5cbiAgICAgICAgICAgIDxycHQtaWNvbiBbbmFtZV09XCJzdGF0dXNLaW5kKCkgPT09ICdlcnJvcicgPyAnY2xvc2UnIDogJ2NoZWNrJ1wiIFtzaXplXT1cIjEyXCIgLz5cbiAgICAgICAgICAgIDxzcGFuPnt7IHN0YXR1c01lc3NhZ2UoKSB9fTwvc3Bhbj5cbiAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgfVxuXG4gICAgICAgIDxkaXYgY2xhc3M9XCJjb2x1bW5zLWVkaXRvci1saXN0XCI+XG4gICAgICAgICAgQGZvciAoY29sIG9mIGNvbHVtbnMoKTsgdHJhY2sgY29sLmZpZWxkOyBsZXQgaWR4ID0gJGluZGV4KSB7XG4gICAgICAgICAgICA8ZGl2IGNsYXNzPVwiY29sLWVkaXQtY2FyZFwiPlxuICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwiY29sLWNhcmQtaGVhZGVyXCI+XG4gICAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cImNvbC1oZWFkZXItdGl0bGUtZ3JvdXBcIj5cbiAgICAgICAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwiY29sLWRyYWctZG90c1wiPuKLruKLrjwvc3Bhbj5cbiAgICAgICAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwiY29sLWlkeC1iYWRnZVwiPiN7eyBpZHggKyAxIH19PC9zcGFuPlxuICAgICAgICAgICAgICAgICAgPGlucHV0XG4gICAgICAgICAgICAgICAgICAgIHR5cGU9XCJ0ZXh0XCJcbiAgICAgICAgICAgICAgICAgICAgY2xhc3M9XCJjb2wtdGl0bGUtaW5wdXRcIlxuICAgICAgICAgICAgICAgICAgICBwbGFjZWhvbGRlcj1cIkNvbHVtbiBMYWJlbFwiXG4gICAgICAgICAgICAgICAgICAgIFtuZ01vZGVsXT1cImNvbC5sYWJlbFwiXG4gICAgICAgICAgICAgICAgICAgIChuZ01vZGVsQ2hhbmdlKT1cIm9uVXBkYXRlQ29sKGlkeCwgJ2xhYmVsJywgJGV2ZW50KVwiXG4gICAgICAgICAgICAgICAgICAvPlxuICAgICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJjb2wtY2FyZC1hY3Rpb25zXCI+XG4gICAgICAgICAgICAgICAgICA8c3BhbiBjbGFzcz1cImNvbC10eXBlLXBpbGxcIj57eyBjb2wuZGF0YVR5cGUgfHwgJ3N0cmluZycgfX08L3NwYW4+XG4gICAgICAgICAgICAgICAgICA8YnV0dG9uXG4gICAgICAgICAgICAgICAgICAgIHR5cGU9XCJidXR0b25cIlxuICAgICAgICAgICAgICAgICAgICBjbGFzcz1cImNvbC1hY3Rpb24tYnRuIGJ0bi1kZWxldGVcIlxuICAgICAgICAgICAgICAgICAgICAoY2xpY2spPVwicmVtb3ZlQ29sdW1uLmVtaXQoaWR4KVwiXG4gICAgICAgICAgICAgICAgICAgIHRpdGxlPVwiUmVtb3ZlIENvbHVtblwiXG4gICAgICAgICAgICAgICAgICA+XG4gICAgICAgICAgICAgICAgICAgIDxycHQtaWNvbiBuYW1lPVwidHJhc2hcIiBbc2l6ZV09XCIxMlwiIC8+XG4gICAgICAgICAgICAgICAgICA8L2J1dHRvbj5cbiAgICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgICAgPC9kaXY+XG5cbiAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cImNvbC1jYXJkLWJvZHlcIj5cbiAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwiY29sLWVkaXQtZmllbGRzXCI+XG4gICAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwiY29sLWZpZWxkLWl0ZW1cIj5cbiAgICAgICAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJtaW5pLWxhYmVsXCI+RmllbGQ8L3NwYW4+XG4gICAgICAgICAgICAgICAgICAgIDxpbnB1dFxuICAgICAgICAgICAgICAgICAgICAgIHR5cGU9XCJ0ZXh0XCJcbiAgICAgICAgICAgICAgICAgICAgICBjbGFzcz1cImNvbC1taW5pLWlucHV0XCJcbiAgICAgICAgICAgICAgICAgICAgICBwbGFjZWhvbGRlcj1cImZpZWxkXCJcbiAgICAgICAgICAgICAgICAgICAgICBbbmdNb2RlbF09XCJjb2wuZmllbGRcIlxuICAgICAgICAgICAgICAgICAgICAgIChuZ01vZGVsQ2hhbmdlKT1cIm9uVXBkYXRlQ29sKGlkeCwgJ2ZpZWxkJywgJGV2ZW50KVwiXG4gICAgICAgICAgICAgICAgICAgIC8+XG4gICAgICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJjb2wtZmllbGQtaXRlbVwiPlxuICAgICAgICAgICAgICAgICAgICA8c3BhbiBjbGFzcz1cIm1pbmktbGFiZWxcIj5UeXBlPC9zcGFuPlxuICAgICAgICAgICAgICAgICAgICA8c2VsZWN0XG4gICAgICAgICAgICAgICAgICAgICAgY2xhc3M9XCJjb2wtbWluaS1zZWxlY3RcIlxuICAgICAgICAgICAgICAgICAgICAgIFtuZ01vZGVsXT1cImNvbC5kYXRhVHlwZSB8fCAnc3RyaW5nJ1wiXG4gICAgICAgICAgICAgICAgICAgICAgKG5nTW9kZWxDaGFuZ2UpPVwib25VcGRhdGVDb2woaWR4LCAnZGF0YVR5cGUnLCAkZXZlbnQpXCJcbiAgICAgICAgICAgICAgICAgICAgPlxuICAgICAgICAgICAgICAgICAgICAgIDxvcHRpb24gdmFsdWU9XCJzdHJpbmdcIj5TdHJpbmc8L29wdGlvbj5cbiAgICAgICAgICAgICAgICAgICAgICA8b3B0aW9uIHZhbHVlPVwibnVtYmVyXCI+TnVtYmVyPC9vcHRpb24+XG4gICAgICAgICAgICAgICAgICAgICAgPG9wdGlvbiB2YWx1ZT1cImN1cnJlbmN5XCI+Q3VycmVuY3k8L29wdGlvbj5cbiAgICAgICAgICAgICAgICAgICAgICA8b3B0aW9uIHZhbHVlPVwiZGF0ZVwiPkRhdGU8L29wdGlvbj5cbiAgICAgICAgICAgICAgICAgICAgICA8b3B0aW9uIHZhbHVlPVwiYm9vbGVhblwiPkJvb2xlYW48L29wdGlvbj5cbiAgICAgICAgICAgICAgICAgICAgPC9zZWxlY3Q+XG4gICAgICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJjb2wtZmllbGQtaXRlbVwiPlxuICAgICAgICAgICAgICAgICAgICA8c3BhbiBjbGFzcz1cIm1pbmktbGFiZWxcIj5Gb3JtYXQ8L3NwYW4+XG4gICAgICAgICAgICAgICAgICAgIDxpbnB1dFxuICAgICAgICAgICAgICAgICAgICAgIHR5cGU9XCJ0ZXh0XCJcbiAgICAgICAgICAgICAgICAgICAgICBjbGFzcz1cImNvbC1taW5pLWlucHV0XCJcbiAgICAgICAgICAgICAgICAgICAgICBwbGFjZWhvbGRlcj1cImUuZy4gZGQvTU0veXl5eVwiXG4gICAgICAgICAgICAgICAgICAgICAgW25nTW9kZWxdPVwiY29sLmZvcm1hdFwiXG4gICAgICAgICAgICAgICAgICAgICAgKG5nTW9kZWxDaGFuZ2UpPVwib25VcGRhdGVDb2woaWR4LCAnZm9ybWF0JywgJGV2ZW50KVwiXG4gICAgICAgICAgICAgICAgICAgIC8+XG4gICAgICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJjb2wtZmllbGQtaXRlbVwiPlxuICAgICAgICAgICAgICAgICAgICA8c3BhbiBjbGFzcz1cIm1pbmktbGFiZWxcIj5BbGlnbjwvc3Bhbj5cbiAgICAgICAgICAgICAgICAgICAgPHNlbGVjdFxuICAgICAgICAgICAgICAgICAgICAgIGNsYXNzPVwiY29sLW1pbmktc2VsZWN0XCJcbiAgICAgICAgICAgICAgICAgICAgICBbbmdNb2RlbF09XCJjb2wuYWxpZ24gfHwgJ2xlZnQnXCJcbiAgICAgICAgICAgICAgICAgICAgICAobmdNb2RlbENoYW5nZSk9XCJvblVwZGF0ZUNvbChpZHgsICdhbGlnbicsICRldmVudClcIlxuICAgICAgICAgICAgICAgICAgICA+XG4gICAgICAgICAgICAgICAgICAgICAgPG9wdGlvbiB2YWx1ZT1cImxlZnRcIj5MZWZ0PC9vcHRpb24+XG4gICAgICAgICAgICAgICAgICAgICAgPG9wdGlvbiB2YWx1ZT1cImNlbnRlclwiPkNlbnRlcjwvb3B0aW9uPlxuICAgICAgICAgICAgICAgICAgICAgIDxvcHRpb24gdmFsdWU9XCJyaWdodFwiPlJpZ2h0PC9vcHRpb24+XG4gICAgICAgICAgICAgICAgICAgIDwvc2VsZWN0PlxuICAgICAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwiY29sLWZpZWxkLWl0ZW1cIj5cbiAgICAgICAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJtaW5pLWxhYmVsXCI+QWdncmVnYXRlPC9zcGFuPlxuICAgICAgICAgICAgICAgICAgICA8c2VsZWN0XG4gICAgICAgICAgICAgICAgICAgICAgY2xhc3M9XCJjb2wtbWluaS1zZWxlY3RcIlxuICAgICAgICAgICAgICAgICAgICAgIFtuZ01vZGVsXT1cImNvbC5hZ2dyZWdhdGUgfHwgJ25vbmUnXCJcbiAgICAgICAgICAgICAgICAgICAgICAobmdNb2RlbENoYW5nZSk9XCJvblVwZGF0ZUNvbChpZHgsICdhZ2dyZWdhdGUnLCAkZXZlbnQgPT09ICdub25lJyA/IHVuZGVmaW5lZCA6ICRldmVudClcIlxuICAgICAgICAgICAgICAgICAgICA+XG4gICAgICAgICAgICAgICAgICAgICAgPG9wdGlvbiB2YWx1ZT1cIm5vbmVcIj5Ob25lPC9vcHRpb24+XG4gICAgICAgICAgICAgICAgICAgICAgPG9wdGlvbiB2YWx1ZT1cInN1bVwiPlN1bTwvb3B0aW9uPlxuICAgICAgICAgICAgICAgICAgICAgIDxvcHRpb24gdmFsdWU9XCJhdmdcIj5BdmVyYWdlPC9vcHRpb24+XG4gICAgICAgICAgICAgICAgICAgICAgPG9wdGlvbiB2YWx1ZT1cImNvdW50XCI+Q291bnQ8L29wdGlvbj5cbiAgICAgICAgICAgICAgICAgICAgICA8b3B0aW9uIHZhbHVlPVwibWluXCI+TWluPC9vcHRpb24+XG4gICAgICAgICAgICAgICAgICAgICAgPG9wdGlvbiB2YWx1ZT1cIm1heFwiPk1heDwvb3B0aW9uPlxuICAgICAgICAgICAgICAgICAgICA8L3NlbGVjdD5cbiAgICAgICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cImNvbC1maWVsZC1pdGVtXCI+XG4gICAgICAgICAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwibWluaS1sYWJlbFwiPldpZHRoPC9zcGFuPlxuICAgICAgICAgICAgICAgICAgICA8aW5wdXRcbiAgICAgICAgICAgICAgICAgICAgICB0eXBlPVwidGV4dFwiXG4gICAgICAgICAgICAgICAgICAgICAgY2xhc3M9XCJjb2wtbWluaS1pbnB1dFwiXG4gICAgICAgICAgICAgICAgICAgICAgcGxhY2Vob2xkZXI9XCJhdXRvXCJcbiAgICAgICAgICAgICAgICAgICAgICBbbmdNb2RlbF09XCJjb2wud2lkdGggfHwgJydcIlxuICAgICAgICAgICAgICAgICAgICAgIChuZ01vZGVsQ2hhbmdlKT1cIm9uVXBkYXRlQ29sKGlkeCwgJ3dpZHRoJywgJGV2ZW50IHx8IHVuZGVmaW5lZClcIlxuICAgICAgICAgICAgICAgICAgICAvPlxuICAgICAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICAgICAgPC9kaXY+XG5cbiAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwiY29sLWNhcmQtZm9vdGVyXCI+XG4gICAgICAgICAgICAgICAgICA8bGFiZWwgY2xhc3M9XCJjb2wtY2hlY2tib3gtdG9nZ2xlXCI+XG4gICAgICAgICAgICAgICAgICAgIDxpbnB1dFxuICAgICAgICAgICAgICAgICAgICAgIHR5cGU9XCJjaGVja2JveFwiXG4gICAgICAgICAgICAgICAgICAgICAgW25nTW9kZWxdPVwiY29sLnZpc2libGUgIT09IGZhbHNlXCJcbiAgICAgICAgICAgICAgICAgICAgICAobmdNb2RlbENoYW5nZSk9XCJvblVwZGF0ZUNvbChpZHgsICd2aXNpYmxlJywgJGV2ZW50KVwiXG4gICAgICAgICAgICAgICAgICAgIC8+XG4gICAgICAgICAgICAgICAgICAgIDxzcGFuPlZpc2libGU8L3NwYW4+XG4gICAgICAgICAgICAgICAgICA8L2xhYmVsPlxuICAgICAgICAgICAgICAgICAgPGxhYmVsIGNsYXNzPVwiY29sLWNoZWNrYm94LXRvZ2dsZVwiPlxuICAgICAgICAgICAgICAgICAgICA8aW5wdXRcbiAgICAgICAgICAgICAgICAgICAgICB0eXBlPVwiY2hlY2tib3hcIlxuICAgICAgICAgICAgICAgICAgICAgIFtuZ01vZGVsXT1cImNvbC5jaGVja2JveFNlbGVjdGlvbiA/PyBmYWxzZVwiXG4gICAgICAgICAgICAgICAgICAgICAgKG5nTW9kZWxDaGFuZ2UpPVwib25VcGRhdGVDb2woaWR4LCAnY2hlY2tib3hTZWxlY3Rpb24nLCAkZXZlbnQpXCJcbiAgICAgICAgICAgICAgICAgICAgLz5cbiAgICAgICAgICAgICAgICAgICAgPHNwYW4+Q2hlY2tib3g8L3NwYW4+XG4gICAgICAgICAgICAgICAgICA8L2xhYmVsPlxuICAgICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgIH1cbiAgICAgICAgPC9kaXY+XG4gICAgICA8L2Rpdj5cblxuICAgICAgPCEtLSBHcmlkIFRhYmxlIE9wdGlvbnMgR3JvdXAgLS0+XG4gICAgICA8ZGl2IGNsYXNzPVwicHJvcGVydHktZ3JvdXBcIj5cbiAgICAgICAgPGRpdiBjbGFzcz1cImdyb3VwLXRpdGxlXCI+VGFibGUgT3B0aW9uczwvZGl2PlxuXG4gICAgICAgIDxkaXYgY2xhc3M9XCJmaWVsZC1yb3dcIj5cbiAgICAgICAgICA8bGFiZWwgY2xhc3M9XCJjaGVja2JveC10b2dnbGVcIj5cbiAgICAgICAgICAgIDxpbnB1dFxuICAgICAgICAgICAgICB0eXBlPVwiY2hlY2tib3hcIlxuICAgICAgICAgICAgICBbbmdNb2RlbF09XCJncmlkKCk/Lm9wdGlvbnM/LnNpZGVCYXIgIT09IGZhbHNlXCJcbiAgICAgICAgICAgICAgKG5nTW9kZWxDaGFuZ2UpPVwidXBkYXRlT3B0aW9uLmVtaXQoeyBmaWVsZDogJ3NpZGVCYXInLCB2YWx1ZTogJGV2ZW50IH0pXCJcbiAgICAgICAgICAgIC8+XG4gICAgICAgICAgICA8c3Bhbj5FbmFibGUgU2lkZSBQYW5lbCAoVG9vbCBQYW5lbHMpPC9zcGFuPlxuICAgICAgICAgIDwvbGFiZWw+XG4gICAgICAgIDwvZGl2PlxuXG4gICAgICAgIDxkaXYgY2xhc3M9XCJmaWVsZC1yb3dcIj5cbiAgICAgICAgICA8bGFiZWwgY2xhc3M9XCJjaGVja2JveC10b2dnbGVcIj5cbiAgICAgICAgICAgIDxpbnB1dFxuICAgICAgICAgICAgICB0eXBlPVwiY2hlY2tib3hcIlxuICAgICAgICAgICAgICBbbmdNb2RlbF09XCJncmlkKCk/Lm9wdGlvbnM/Lmdsb2JhbFNlYXJjaCAhPT0gZmFsc2VcIlxuICAgICAgICAgICAgICAobmdNb2RlbENoYW5nZSk9XCJ1cGRhdGVPcHRpb24uZW1pdCh7IGZpZWxkOiAnZ2xvYmFsU2VhcmNoJywgdmFsdWU6ICRldmVudCB9KVwiXG4gICAgICAgICAgICAvPlxuICAgICAgICAgICAgPHNwYW4+R2xvYmFsIFNlYXJjaCBCb3g8L3NwYW4+XG4gICAgICAgICAgPC9sYWJlbD5cbiAgICAgICAgPC9kaXY+XG5cbiAgICAgICAgPGRpdiBjbGFzcz1cImZpZWxkLXJvd1wiPlxuICAgICAgICAgIDxsYWJlbCBjbGFzcz1cImNoZWNrYm94LXRvZ2dsZVwiPlxuICAgICAgICAgICAgPGlucHV0XG4gICAgICAgICAgICAgIHR5cGU9XCJjaGVja2JveFwiXG4gICAgICAgICAgICAgIFtuZ01vZGVsXT1cImdyaWQoKT8ub3B0aW9ucz8uc3RhdHVzQmFyICE9PSBmYWxzZVwiXG4gICAgICAgICAgICAgIChuZ01vZGVsQ2hhbmdlKT1cInVwZGF0ZU9wdGlvbi5lbWl0KHsgZmllbGQ6ICdzdGF0dXNCYXInLCB2YWx1ZTogJGV2ZW50IH0pXCJcbiAgICAgICAgICAgIC8+XG4gICAgICAgICAgICA8c3Bhbj5TdGF0dXMgQmFyPC9zcGFuPlxuICAgICAgICAgIDwvbGFiZWw+XG4gICAgICAgIDwvZGl2PlxuXG4gICAgICAgIDxkaXYgY2xhc3M9XCJmaWVsZC1yb3dcIj5cbiAgICAgICAgICA8bGFiZWwgY2xhc3M9XCJjaGVja2JveC10b2dnbGVcIj5cbiAgICAgICAgICAgIDxpbnB1dFxuICAgICAgICAgICAgICB0eXBlPVwiY2hlY2tib3hcIlxuICAgICAgICAgICAgICBbbmdNb2RlbF09XCJncmlkKCk/Lm9wdGlvbnM/LnBhZ2luYXRpb24gPz8gdHJ1ZVwiXG4gICAgICAgICAgICAgIChuZ01vZGVsQ2hhbmdlKT1cInVwZGF0ZU9wdGlvbi5lbWl0KHsgZmllbGQ6ICdwYWdpbmF0aW9uJywgdmFsdWU6ICRldmVudCB9KVwiXG4gICAgICAgICAgICAvPlxuICAgICAgICAgICAgPHNwYW4+RW5hYmxlIFBhZ2luYXRpb248L3NwYW4+XG4gICAgICAgICAgPC9sYWJlbD5cbiAgICAgICAgPC9kaXY+XG5cbiAgICAgICAgPGRpdiBjbGFzcz1cImZpZWxkLXJvd1wiPlxuICAgICAgICAgIDxsYWJlbCBjbGFzcz1cImNoZWNrYm94LXRvZ2dsZVwiPlxuICAgICAgICAgICAgPGlucHV0XG4gICAgICAgICAgICAgIHR5cGU9XCJjaGVja2JveFwiXG4gICAgICAgICAgICAgIFtuZ01vZGVsXT1cImdyaWQoKT8ub3B0aW9ucz8uc2VsZWN0YWJsZSA/PyBmYWxzZVwiXG4gICAgICAgICAgICAgIChuZ01vZGVsQ2hhbmdlKT1cInVwZGF0ZU9wdGlvbi5lbWl0KHsgZmllbGQ6ICdzZWxlY3RhYmxlJywgdmFsdWU6ICRldmVudCB9KVwiXG4gICAgICAgICAgICAvPlxuICAgICAgICAgICAgPHNwYW4+Um93IFNlbGVjdGlvbjwvc3Bhbj5cbiAgICAgICAgICA8L2xhYmVsPlxuICAgICAgICA8L2Rpdj5cblxuICAgICAgICBAaWYgKGdyaWQoKT8ub3B0aW9ucz8uc2VsZWN0YWJsZSkge1xuICAgICAgICAgIDxkaXYgY2xhc3M9XCJmaWVsZC1yb3dcIj5cbiAgICAgICAgICAgIDxsYWJlbCBjbGFzcz1cImZpZWxkLWxhYmVsXCI+U2VsZWN0aW9uIE1vZGU8L2xhYmVsPlxuICAgICAgICAgICAgPHNlbGVjdFxuICAgICAgICAgICAgICBjbGFzcz1cImZpZWxkLWlucHV0XCJcbiAgICAgICAgICAgICAgW25nTW9kZWxdPVwiZ3JpZCgpPy5vcHRpb25zPy5zZWxlY3Rpb25Nb2RlID8/ICdtdWx0aXBsZSdcIlxuICAgICAgICAgICAgICAobmdNb2RlbENoYW5nZSk9XCJ1cGRhdGVPcHRpb24uZW1pdCh7IGZpZWxkOiAnc2VsZWN0aW9uTW9kZScsIHZhbHVlOiAkZXZlbnQgfSlcIlxuICAgICAgICAgICAgPlxuICAgICAgICAgICAgICA8b3B0aW9uIHZhbHVlPVwibXVsdGlwbGVcIj5NdWx0aXBsZSBSb3dzPC9vcHRpb24+XG4gICAgICAgICAgICAgIDxvcHRpb24gdmFsdWU9XCJzaW5nbGVcIj5TaW5nbGUgUm93PC9vcHRpb24+XG4gICAgICAgICAgICA8L3NlbGVjdD5cbiAgICAgICAgICA8L2Rpdj5cblxuICAgICAgICAgIDxkaXYgY2xhc3M9XCJmaWVsZC1yb3dcIj5cbiAgICAgICAgICAgIDxsYWJlbCBjbGFzcz1cImNoZWNrYm94LXRvZ2dsZVwiPlxuICAgICAgICAgICAgICA8aW5wdXRcbiAgICAgICAgICAgICAgICB0eXBlPVwiY2hlY2tib3hcIlxuICAgICAgICAgICAgICAgIFtuZ01vZGVsXT1cImdyaWQoKT8ub3B0aW9ucz8uY2hlY2tib3hTZWxlY3Rpb24gPz8gdHJ1ZVwiXG4gICAgICAgICAgICAgICAgKG5nTW9kZWxDaGFuZ2UpPVwidXBkYXRlT3B0aW9uLmVtaXQoeyBmaWVsZDogJ2NoZWNrYm94U2VsZWN0aW9uJywgdmFsdWU6ICRldmVudCB9KVwiXG4gICAgICAgICAgICAgIC8+XG4gICAgICAgICAgICAgIDxzcGFuPkNoZWNrYm94IFNlbGVjdGlvbjwvc3Bhbj5cbiAgICAgICAgICAgIDwvbGFiZWw+XG4gICAgICAgICAgPC9kaXY+XG5cbiAgICAgICAgICBAaWYgKChncmlkKCk/Lm9wdGlvbnM/LnNlbGVjdGlvbk1vZGUgPz8gJ211bHRpcGxlJykgPT09ICdtdWx0aXBsZScpIHtcbiAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJmaWVsZC1yb3dcIj5cbiAgICAgICAgICAgICAgPGxhYmVsIGNsYXNzPVwiY2hlY2tib3gtdG9nZ2xlXCI+XG4gICAgICAgICAgICAgICAgPGlucHV0XG4gICAgICAgICAgICAgICAgICB0eXBlPVwiY2hlY2tib3hcIlxuICAgICAgICAgICAgICAgICAgW25nTW9kZWxdPVwiZ3JpZCgpPy5vcHRpb25zPy5oZWFkZXJDaGVja2JveFNlbGVjdGlvbiA/PyB0cnVlXCJcbiAgICAgICAgICAgICAgICAgIChuZ01vZGVsQ2hhbmdlKT1cInVwZGF0ZU9wdGlvbi5lbWl0KHsgZmllbGQ6ICdoZWFkZXJDaGVja2JveFNlbGVjdGlvbicsIHZhbHVlOiAkZXZlbnQgfSlcIlxuICAgICAgICAgICAgICAgIC8+XG4gICAgICAgICAgICAgICAgPHNwYW4+SGVhZGVyIFNlbGVjdCBBbGwgQ2hlY2tib3g8L3NwYW4+XG4gICAgICAgICAgICAgIDwvbGFiZWw+XG4gICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICA8ZGl2IGNsYXNzPVwiZmllbGQtcm93XCI+XG4gICAgICAgICAgPGxhYmVsIGNsYXNzPVwiY2hlY2tib3gtdG9nZ2xlXCI+XG4gICAgICAgICAgICA8aW5wdXRcbiAgICAgICAgICAgICAgdHlwZT1cImNoZWNrYm94XCJcbiAgICAgICAgICAgICAgW25nTW9kZWxdPVwiZ3JpZCgpPy5vcHRpb25zPy5hbGxvd0NvbHVtblJlb3JkZXIgPz8gdHJ1ZVwiXG4gICAgICAgICAgICAgIChuZ01vZGVsQ2hhbmdlKT1cInVwZGF0ZU9wdGlvbi5lbWl0KHsgZmllbGQ6ICdhbGxvd0NvbHVtblJlb3JkZXInLCB2YWx1ZTogJGV2ZW50IH0pXCJcbiAgICAgICAgICAgIC8+XG4gICAgICAgICAgICA8c3Bhbj5BbGxvdyBDb2x1bW4gUmVvcmRlcjwvc3Bhbj5cbiAgICAgICAgICA8L2xhYmVsPlxuICAgICAgICA8L2Rpdj5cblxuICAgICAgICA8ZGl2IGNsYXNzPVwiZmllbGQtcm93XCI+XG4gICAgICAgICAgPGxhYmVsIGNsYXNzPVwiY2hlY2tib3gtdG9nZ2xlXCI+XG4gICAgICAgICAgICA8aW5wdXRcbiAgICAgICAgICAgICAgdHlwZT1cImNoZWNrYm94XCJcbiAgICAgICAgICAgICAgW25nTW9kZWxdPVwiZ3JpZCgpPy5vcHRpb25zPy5hbGxvd0V4cG9ydCA/PyB0cnVlXCJcbiAgICAgICAgICAgICAgKG5nTW9kZWxDaGFuZ2UpPVwidXBkYXRlT3B0aW9uLmVtaXQoeyBmaWVsZDogJ2FsbG93RXhwb3J0JywgdmFsdWU6ICRldmVudCB9KVwiXG4gICAgICAgICAgICAvPlxuICAgICAgICAgICAgPHNwYW4+QWxsb3cgRXhwb3J0PC9zcGFuPlxuICAgICAgICAgIDwvbGFiZWw+XG4gICAgICAgIDwvZGl2PlxuXG4gICAgICAgIDxkaXYgY2xhc3M9XCJmaWVsZC1yb3dcIj5cbiAgICAgICAgICA8bGFiZWwgY2xhc3M9XCJmaWVsZC1sYWJlbFwiPlBhZ2UgU2l6ZTwvbGFiZWw+XG4gICAgICAgICAgPGlucHV0XG4gICAgICAgICAgICB0eXBlPVwibnVtYmVyXCJcbiAgICAgICAgICAgIGNsYXNzPVwiZmllbGQtaW5wdXRcIlxuICAgICAgICAgICAgbWluPVwiMVwiXG4gICAgICAgICAgICBtYXg9XCIxMDAwXCJcbiAgICAgICAgICAgICh3aGVlbCk9XCIkYW55KCRldmVudC50YXJnZXQpLmJsdXIoKVwiXG4gICAgICAgICAgICAoa2V5ZG93bi5hcnJvd3VwKT1cIiRldmVudC5wcmV2ZW50RGVmYXVsdCgpXCJcbiAgICAgICAgICAgIChrZXlkb3duLmFycm93ZG93bik9XCIkZXZlbnQucHJldmVudERlZmF1bHQoKVwiXG4gICAgICAgICAgICBbbmdNb2RlbF09XCJncmlkKCk/Lm9wdGlvbnM/LnBhZ2VTaXplID8/IDEwXCJcbiAgICAgICAgICAgIChuZ01vZGVsQ2hhbmdlKT1cInVwZGF0ZU9wdGlvbi5lbWl0KHsgZmllbGQ6ICdwYWdlU2l6ZScsIHZhbHVlOiArJGV2ZW50IH0pXCJcbiAgICAgICAgICAvPlxuICAgICAgICA8L2Rpdj5cblxuICAgICAgICA8ZGl2IGNsYXNzPVwiZmllbGQtcm93XCI+XG4gICAgICAgICAgPGxhYmVsIGNsYXNzPVwiY2hlY2tib3gtdG9nZ2xlXCI+XG4gICAgICAgICAgICA8aW5wdXRcbiAgICAgICAgICAgICAgdHlwZT1cImNoZWNrYm94XCJcbiAgICAgICAgICAgICAgW25nTW9kZWxdPVwiZ3JpZCgpPy5vcHRpb25zPy5zaG93Um93TnVtYmVycyA/PyB0cnVlXCJcbiAgICAgICAgICAgICAgKG5nTW9kZWxDaGFuZ2UpPVwidXBkYXRlT3B0aW9uLmVtaXQoeyBmaWVsZDogJ3Nob3dSb3dOdW1iZXJzJywgdmFsdWU6ICRldmVudCB9KVwiXG4gICAgICAgICAgICAvPlxuICAgICAgICAgICAgPHNwYW4+U2hvdyBSb3cgTnVtYmVyczwvc3Bhbj5cbiAgICAgICAgICA8L2xhYmVsPlxuICAgICAgICA8L2Rpdj5cblxuICAgICAgICA8ZGl2IGNsYXNzPVwiZmllbGQtcm93XCI+XG4gICAgICAgICAgPGxhYmVsIGNsYXNzPVwiY2hlY2tib3gtdG9nZ2xlXCI+XG4gICAgICAgICAgICA8aW5wdXRcbiAgICAgICAgICAgICAgdHlwZT1cImNoZWNrYm94XCJcbiAgICAgICAgICAgICAgW25nTW9kZWxdPVwiZ3JpZCgpPy5vcHRpb25zPy5zaG93Rm9vdGVyID8/IHRydWVcIlxuICAgICAgICAgICAgICAobmdNb2RlbENoYW5nZSk9XCJ1cGRhdGVPcHRpb24uZW1pdCh7IGZpZWxkOiAnc2hvd0Zvb3RlcicsIHZhbHVlOiAkZXZlbnQgfSlcIlxuICAgICAgICAgICAgLz5cbiAgICAgICAgICAgIDxzcGFuPlNob3cgRm9vdGVyIFRvdGFsczwvc3Bhbj5cbiAgICAgICAgICA8L2xhYmVsPlxuICAgICAgICA8L2Rpdj5cbiAgICAgIDwvZGl2PlxuXG4gICAgICA8IS0tIFJvdyBDbGljayAmIERyaWxsLURvd24gQWN0aW9uIEdyb3VwIC0tPlxuICAgICAgPGRpdiBjbGFzcz1cInByb3BlcnR5LWdyb3VwXCI+XG4gICAgICAgIDxkaXYgY2xhc3M9XCJncm91cC10aXRsZVwiPlJvdyBDbGljayAmIERyaWxsLURvd248L2Rpdj5cblxuICAgICAgICA8ZGl2IGNsYXNzPVwiZmllbGQtcm93XCI+XG4gICAgICAgICAgPGxhYmVsIGNsYXNzPVwiY2hlY2tib3gtdG9nZ2xlXCI+XG4gICAgICAgICAgICA8aW5wdXRcbiAgICAgICAgICAgICAgdHlwZT1cImNoZWNrYm94XCJcbiAgICAgICAgICAgICAgW25nTW9kZWxdPVwiaGFzUm93Q2xpY2tBY3Rpb24oKVwiXG4gICAgICAgICAgICAgIChuZ01vZGVsQ2hhbmdlKT1cInRvZ2dsZVJvd0NsaWNrQWN0aW9uKCRldmVudClcIlxuICAgICAgICAgICAgLz5cbiAgICAgICAgICAgIDxzcGFuPkVuYWJsZSBSb3cgQ2xpY2sgQWN0aW9uPC9zcGFuPlxuICAgICAgICAgIDwvbGFiZWw+XG4gICAgICAgIDwvZGl2PlxuXG4gICAgICAgIEBpZiAoaGFzUm93Q2xpY2tBY3Rpb24oKSkge1xuICAgICAgICAgIDxkaXYgY2xhc3M9XCJmaWVsZC1yb3dcIj5cbiAgICAgICAgICAgIDxsYWJlbCBjbGFzcz1cImZpZWxkLWxhYmVsXCI+QWN0aW9uIFR5cGU8L2xhYmVsPlxuICAgICAgICAgICAgPHNlbGVjdFxuICAgICAgICAgICAgICBjbGFzcz1cImZpZWxkLWlucHV0IGZpZWxkLXNlbGVjdFwiXG4gICAgICAgICAgICAgIFtuZ01vZGVsXT1cInJvd0NsaWNrQWN0aW9uKCk/LnR5cGUgfHwgJ29wZW4tZHJhd2VyJ1wiXG4gICAgICAgICAgICAgIChuZ01vZGVsQ2hhbmdlKT1cInVwZGF0ZVJvd0FjdGlvbkZpZWxkKCd0eXBlJywgJGV2ZW50KVwiXG4gICAgICAgICAgICA+XG4gICAgICAgICAgICAgIDxvcHRpb24gdmFsdWU9XCJvcGVuLWRyYXdlclwiPlNsaWRlLU92ZXIgRGV0YWlsIERyYXdlcjwvb3B0aW9uPlxuICAgICAgICAgICAgICA8b3B0aW9uIHZhbHVlPVwiZHJpbGxkb3duLXJlcG9ydFwiPkRyaWxsLURvd24gUmVwb3J0IChIb3N0IEV2ZW50KTwvb3B0aW9uPlxuICAgICAgICAgICAgICA8b3B0aW9uIHZhbHVlPVwibmF2aWdhdGVcIj5OYXZpZ2F0ZSB0byBVUkw8L29wdGlvbj5cbiAgICAgICAgICAgICAgPG9wdGlvbiB2YWx1ZT1cImVtaXQtY3VzdG9tXCI+RW1pdCBDdXN0b20gQWN0aW9uPC9vcHRpb24+XG4gICAgICAgICAgICA8L3NlbGVjdD5cbiAgICAgICAgICA8L2Rpdj5cblxuICAgICAgICAgIEBpZiAocm93Q2xpY2tBY3Rpb24oKT8udHlwZSA9PT0gJ29wZW4tZHJhd2VyJyB8fCByb3dDbGlja0FjdGlvbigpPy50eXBlID09PSAnZHJpbGxkb3duLXJlcG9ydCcpIHtcbiAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJmaWVsZC1yb3dcIj5cbiAgICAgICAgICAgICAgPGxhYmVsIGNsYXNzPVwiZmllbGQtbGFiZWxcIj5UYXJnZXQgUmVwb3J0IElEPC9sYWJlbD5cbiAgICAgICAgICAgICAgPGlucHV0XG4gICAgICAgICAgICAgICAgdHlwZT1cInRleHRcIlxuICAgICAgICAgICAgICAgIGNsYXNzPVwiZmllbGQtaW5wdXRcIlxuICAgICAgICAgICAgICAgIHBsYWNlaG9sZGVyPVwiZS5nLiBvcmRlci1kZXRhaWxzXCJcbiAgICAgICAgICAgICAgICBbbmdNb2RlbF09XCJyb3dDbGlja0FjdGlvbigpPy50YXJnZXRSZXBvcnRJZCB8fCAnJ1wiXG4gICAgICAgICAgICAgICAgKG5nTW9kZWxDaGFuZ2UpPVwidXBkYXRlUm93QWN0aW9uRmllbGQoJ3RhcmdldFJlcG9ydElkJywgJGV2ZW50KVwiXG4gICAgICAgICAgICAgIC8+XG4gICAgICAgICAgICA8L2Rpdj5cblxuICAgICAgICAgICAgPGRpdiBjbGFzcz1cImZpZWxkLXJvd1wiPlxuICAgICAgICAgICAgICA8bGFiZWwgY2xhc3M9XCJmaWVsZC1sYWJlbFwiPkRyYXdlciBUaXRsZTwvbGFiZWw+XG4gICAgICAgICAgICAgIDxpbnB1dFxuICAgICAgICAgICAgICAgIHR5cGU9XCJ0ZXh0XCJcbiAgICAgICAgICAgICAgICBjbGFzcz1cImZpZWxkLWlucHV0XCJcbiAgICAgICAgICAgICAgICBwbGFjZWhvbGRlcj1cImUuZy4gT3JkZXIgRGV0YWlsc1wiXG4gICAgICAgICAgICAgICAgW25nTW9kZWxdPVwicm93Q2xpY2tBY3Rpb24oKT8uZHJhd2VyVGl0bGUgfHwgJydcIlxuICAgICAgICAgICAgICAgIChuZ01vZGVsQ2hhbmdlKT1cInVwZGF0ZVJvd0FjdGlvbkZpZWxkKCdkcmF3ZXJUaXRsZScsICRldmVudClcIlxuICAgICAgICAgICAgICAvPlxuICAgICAgICAgICAgPC9kaXY+XG5cbiAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJmaWVsZC1yb3dcIj5cbiAgICAgICAgICAgICAgPGxhYmVsIGNsYXNzPVwiZmllbGQtbGFiZWxcIj5EcmF3ZXIgV2lkdGg8L2xhYmVsPlxuICAgICAgICAgICAgICA8aW5wdXRcbiAgICAgICAgICAgICAgICB0eXBlPVwidGV4dFwiXG4gICAgICAgICAgICAgICAgY2xhc3M9XCJmaWVsZC1pbnB1dFwiXG4gICAgICAgICAgICAgICAgcGxhY2Vob2xkZXI9XCJlLmcuIDc2MHB4LCA4MCUsIDkwMHB4XCJcbiAgICAgICAgICAgICAgICBbbmdNb2RlbF09XCJyb3dDbGlja0FjdGlvbigpPy5kcmF3ZXJXaWR0aCB8fCAnNzYwcHgnXCJcbiAgICAgICAgICAgICAgICAobmdNb2RlbENoYW5nZSk9XCJ1cGRhdGVSb3dBY3Rpb25GaWVsZCgnZHJhd2VyV2lkdGgnLCAkZXZlbnQpXCJcbiAgICAgICAgICAgICAgLz5cbiAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgIH1cblxuICAgICAgICAgIEBpZiAocm93Q2xpY2tBY3Rpb24oKT8udHlwZSA9PT0gJ25hdmlnYXRlJykge1xuICAgICAgICAgICAgPGRpdiBjbGFzcz1cImZpZWxkLXJvd1wiPlxuICAgICAgICAgICAgICA8bGFiZWwgY2xhc3M9XCJmaWVsZC1sYWJlbFwiPlRhcmdldCBVUkw8L2xhYmVsPlxuICAgICAgICAgICAgICA8aW5wdXRcbiAgICAgICAgICAgICAgICB0eXBlPVwidGV4dFwiXG4gICAgICAgICAgICAgICAgY2xhc3M9XCJmaWVsZC1pbnB1dFwiXG4gICAgICAgICAgICAgICAgW3BsYWNlaG9sZGVyXT1cIicvb3JkZXJzL3t7cm93Lm9yZGVySWR9fSBvciBodHRwczovLy4uLidcIlxuICAgICAgICAgICAgICAgIFtuZ01vZGVsXT1cInJvd0NsaWNrQWN0aW9uKCk/LnRhcmdldFVybCB8fCAnJ1wiXG4gICAgICAgICAgICAgICAgKG5nTW9kZWxDaGFuZ2UpPVwidXBkYXRlUm93QWN0aW9uRmllbGQoJ3RhcmdldFVybCcsICRldmVudClcIlxuICAgICAgICAgICAgICAvPlxuICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICA8ZGl2IGNsYXNzPVwiZmllbGQtcm93XCI+XG4gICAgICAgICAgICAgIDxsYWJlbCBjbGFzcz1cImNoZWNrYm94LXRvZ2dsZVwiPlxuICAgICAgICAgICAgICAgIDxpbnB1dFxuICAgICAgICAgICAgICAgICAgdHlwZT1cImNoZWNrYm94XCJcbiAgICAgICAgICAgICAgICAgIFtuZ01vZGVsXT1cInJvd0NsaWNrQWN0aW9uKCk/Lm9wZW5OZXdUYWIgPz8gZmFsc2VcIlxuICAgICAgICAgICAgICAgICAgKG5nTW9kZWxDaGFuZ2UpPVwidXBkYXRlUm93QWN0aW9uRmllbGQoJ29wZW5OZXdUYWInLCAkZXZlbnQpXCJcbiAgICAgICAgICAgICAgICAvPlxuICAgICAgICAgICAgICAgIDxzcGFuPk9wZW4gaW4gTmV3IFRhYjwvc3Bhbj5cbiAgICAgICAgICAgICAgPC9sYWJlbD5cbiAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgIH1cblxuICAgICAgICAgIEBpZiAocm93Q2xpY2tBY3Rpb24oKT8udHlwZSA9PT0gJ2VtaXQtY3VzdG9tJykge1xuICAgICAgICAgICAgPGRpdiBjbGFzcz1cImZpZWxkLXJvd1wiPlxuICAgICAgICAgICAgICA8bGFiZWwgY2xhc3M9XCJmaWVsZC1sYWJlbFwiPkN1c3RvbSBBY3Rpb24gTmFtZTwvbGFiZWw+XG4gICAgICAgICAgICAgIDxpbnB1dFxuICAgICAgICAgICAgICAgIHR5cGU9XCJ0ZXh0XCJcbiAgICAgICAgICAgICAgICBjbGFzcz1cImZpZWxkLWlucHV0XCJcbiAgICAgICAgICAgICAgICBwbGFjZWhvbGRlcj1cImUuZy4gdmlldy1hdWRpdC10cmFpbFwiXG4gICAgICAgICAgICAgICAgW25nTW9kZWxdPVwicm93Q2xpY2tBY3Rpb24oKT8uY3VzdG9tQWN0aW9uTmFtZSB8fCAnJ1wiXG4gICAgICAgICAgICAgICAgKG5nTW9kZWxDaGFuZ2UpPVwidXBkYXRlUm93QWN0aW9uRmllbGQoJ2N1c3RvbUFjdGlvbk5hbWUnLCAkZXZlbnQpXCJcbiAgICAgICAgICAgICAgLz5cbiAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgIH1cblxuICAgICAgICAgIDxkaXYgY2xhc3M9XCJmaWVsZC1yb3dcIj5cbiAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJmaWVsZC1sYWJlbC1yb3dcIj5cbiAgICAgICAgICAgICAgPGxhYmVsIGNsYXNzPVwiZmllbGQtbGFiZWxcIj5QYXJhbWV0ZXIgTWFwcGluZzwvbGFiZWw+XG4gICAgICAgICAgICAgIDxidXR0b25cbiAgICAgICAgICAgICAgICB0eXBlPVwiYnV0dG9uXCJcbiAgICAgICAgICAgICAgICBjbGFzcz1cImJ0bi1hZGQtbWFwcGluZ1wiXG4gICAgICAgICAgICAgICAgKGNsaWNrKT1cImFkZFBhcmFtZXRlck1hcHBpbmcoKVwiXG4gICAgICAgICAgICAgID5cbiAgICAgICAgICAgICAgICArIEFkZCBNYXBwaW5nXG4gICAgICAgICAgICAgIDwvYnV0dG9uPlxuICAgICAgICAgICAgPC9kaXY+XG5cbiAgICAgICAgICAgIEBmb3IgKG1hcHBpbmcgb2YgcGFyYW1ldGVyTWFwcGluZ3MoKTsgdHJhY2sgbWFwcGluZy5rZXk7IGxldCBtSWR4ID0gJGluZGV4KSB7XG4gICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJtYXBwaW5nLXBhaXItcm93XCI+XG4gICAgICAgICAgICAgICAgPGlucHV0XG4gICAgICAgICAgICAgICAgICB0eXBlPVwidGV4dFwiXG4gICAgICAgICAgICAgICAgICBjbGFzcz1cImNvbC1taW5pLWlucHV0XCJcbiAgICAgICAgICAgICAgICAgIHN0eWxlPVwiZmxleDogMTtcIlxuICAgICAgICAgICAgICAgICAgcGxhY2Vob2xkZXI9XCJUYXJnZXQgKGUuZy4gY3VzdG9tZXJJZClcIlxuICAgICAgICAgICAgICAgICAgW25nTW9kZWxdPVwibWFwcGluZy5rZXlcIlxuICAgICAgICAgICAgICAgICAgKG5nTW9kZWxDaGFuZ2UpPVwidXBkYXRlTWFwcGluZ0tleShtSWR4LCAkZXZlbnQpXCJcbiAgICAgICAgICAgICAgICAvPlxuICAgICAgICAgICAgICAgIDxzcGFuIHN0eWxlPVwiZm9udC1zaXplOiAwLjc1cmVtOyBjb2xvcjogIzk0YTNiODtcIj7ihpA8L3NwYW4+XG4gICAgICAgICAgICAgICAgPGlucHV0XG4gICAgICAgICAgICAgICAgICB0eXBlPVwidGV4dFwiXG4gICAgICAgICAgICAgICAgICBjbGFzcz1cImNvbC1taW5pLWlucHV0XCJcbiAgICAgICAgICAgICAgICAgIHN0eWxlPVwiZmxleDogMTtcIlxuICAgICAgICAgICAgICAgICAgcGxhY2Vob2xkZXI9XCJTb3VyY2UgKGUuZy4gcm93LmlkKVwiXG4gICAgICAgICAgICAgICAgICBbbmdNb2RlbF09XCJtYXBwaW5nLnZhbHVlXCJcbiAgICAgICAgICAgICAgICAgIChuZ01vZGVsQ2hhbmdlKT1cInVwZGF0ZU1hcHBpbmdWYWx1ZShtSWR4LCAkZXZlbnQpXCJcbiAgICAgICAgICAgICAgICAvPlxuICAgICAgICAgICAgICAgIDxidXR0b25cbiAgICAgICAgICAgICAgICAgIHR5cGU9XCJidXR0b25cIlxuICAgICAgICAgICAgICAgICAgY2xhc3M9XCJjb2wtYWN0aW9uLWJ0biBidG4tZGVsZXRlXCJcbiAgICAgICAgICAgICAgICAgIChjbGljayk9XCJyZW1vdmVNYXBwaW5nKG1JZHgpXCJcbiAgICAgICAgICAgICAgICAgIHRpdGxlPVwiUmVtb3ZlIG1hcHBpbmdcIlxuICAgICAgICAgICAgICAgID5cbiAgICAgICAgICAgICAgICAgIDxycHQtaWNvbiBuYW1lPVwidHJhc2hcIiBbc2l6ZV09XCIxMVwiIC8+XG4gICAgICAgICAgICAgICAgPC9idXR0b24+XG4gICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgfVxuICAgICAgICAgIDwvZGl2PlxuICAgICAgICB9XG4gICAgICA8L2Rpdj5cblxuICAgICAgPCEtLSBSZW1vdmUgR3JpZCBBY3Rpb24gLS0+XG4gICAgICA8ZGl2IGNsYXNzPVwiZ3JpZC1kYW5nZXItem9uZVwiPlxuICAgICAgICA8YnV0dG9uIHR5cGU9XCJidXR0b25cIiBjbGFzcz1cImJ0bi1yZW1vdmUtZ3JpZC1hY3Rpb25cIiAoY2xpY2spPVwicmVtb3ZlR3JpZC5lbWl0KClcIj5cbiAgICAgICAgICA8cnB0LWljb24gbmFtZT1cInRyYXNoXCIgW3NpemVdPVwiMTNcIiAvPlxuICAgICAgICAgIDxzcGFuPlJlbW92ZSBHcmlkIGZyb20gUmVwb3J0PC9zcGFuPlxuICAgICAgICA8L2J1dHRvbj5cbiAgICAgIDwvZGl2PlxuICAgIDwvZGl2PlxuICAgIH0iXX0=
359
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHJvcGVydHktZWRpdG9yLWdyaWQuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvYndheXMtcmVwb3J0L3NyYy9saWIvZmVhdHVyZXMvZGVzaWduZXIvY29tcG9uZW50cy9wcm9wZXJ0eS1lZGl0b3IvcHJvcGVydHktZWRpdG9yLWdyaWQuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvYndheXMtcmVwb3J0L3NyYy9saWIvZmVhdHVyZXMvZGVzaWduZXIvY29tcG9uZW50cy9wcm9wZXJ0eS1lZGl0b3IvcHJvcGVydHktZWRpdG9yLWdyaWQuY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLHVCQUF1QixFQUFFLFNBQVMsRUFBRSxRQUFRLEVBQUUsTUFBTSxFQUFFLE1BQU0sRUFBRSxLQUFLLEVBQUUsTUFBTSxFQUFFLE1BQU0sRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUNwSCxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDL0MsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBSzdDLE9BQU8sRUFBRSwwQkFBMEIsRUFBRSxNQUFNLHlEQUF5RCxDQUFDO0FBQ3JHLE9BQU8sRUFBRSxzQkFBc0IsRUFBRSxNQUFNLGtEQUFrRCxDQUFDO0FBQzFGLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLDJEQUEyRCxDQUFDO0FBQzdGLE9BQU8sRUFDTCw0QkFBNEIsR0FFN0IsTUFBTSxtQ0FBbUMsQ0FBQztBQUMzQyxPQUFPLEVBQUUsK0JBQStCLEVBQUUsTUFBTSxzQ0FBc0MsQ0FBQztBQUN2RixPQUFPLEVBQUUscUJBQXFCLEVBQUUsTUFBTSw4Q0FBOEMsQ0FBQzs7O0FBZ0JyRixNQUFNLE9BQU8sMkJBQTJCO0lBQ3JCLGFBQWEsR0FBRyxNQUFNLENBQUMsMEJBQTBCLEVBQUUsRUFBRSxRQUFRLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQztJQUN2RSxTQUFTLEdBQUcsTUFBTSxDQUFDLHNCQUFzQixFQUFFLEVBQUUsUUFBUSxFQUFFLElBQUksRUFBRSxDQUFDLENBQUM7SUFFdkUsSUFBSSxHQUFHLEtBQUssRUFBb0MsQ0FBQztJQUNqRCxVQUFVLEdBQUcsS0FBSyxFQUEwQyxDQUFDO0lBQzdELGlCQUFpQixHQUFHLEtBQUssQ0FBMkIsRUFBRSxDQUFDLENBQUM7SUFDeEQsbUJBQW1CLEdBQUcsS0FBSyxDQUErQixFQUFFLENBQUMsQ0FBQztJQUM5RCxhQUFhLEdBQUcsS0FBSyxDQUE4QixFQUFFLENBQUMsQ0FBQztJQUN2RCxXQUFXLEdBQUcsS0FBSyxDQUFVLEtBQUssQ0FBQyxDQUFDO0lBQ3BDLGFBQWEsR0FBRyxLQUFLLENBQWdCLElBQUksQ0FBQyxDQUFDO0lBQzNDLFVBQVUsR0FBRyxLQUFLLENBQXNDLElBQUksQ0FBQyxDQUFDO0lBRTlELE9BQU8sR0FBRyxNQUFNLEVBQVEsQ0FBQztJQUN6QixVQUFVLEdBQUcsTUFBTSxFQUFRLENBQUM7SUFDNUIsU0FBUyxHQUFHLE1BQU0sRUFBUSxDQUFDO0lBQzNCLGlCQUFpQixHQUFHLE1BQU0sRUFBUSxDQUFDO0lBQ25DLFlBQVksR0FBRyxNQUFNLEVBQVUsQ0FBQztJQUNoQyxZQUFZLEdBQUcsTUFBTSxFQUFvRCxDQUFDO0lBQzFFLFlBQVksR0FBRyxNQUFNLEVBQXFDLENBQUM7SUFDM0Qsb0JBQW9CLEdBQUcsTUFBTSxFQUFrQyxDQUFDO0lBQ2hFLGFBQWEsR0FBRyxNQUFNLEVBQThCLENBQUM7SUFDckQsMEJBQTBCLEdBQUcsTUFBTSxFQUEyQixDQUFDO0lBQy9ELGFBQWEsR0FBRyxNQUFNLEVBQWdFLENBQUM7SUFFdkYsa0JBQWtCLEdBQUcsTUFBTSxDQUErQixFQUFFLENBQUMsQ0FBQztJQUU5RCxtQkFBbUIsR0FBRyxRQUFRLENBQStCLEdBQUcsRUFBRTtRQUN6RSxNQUFNLFVBQVUsR0FBRyxJQUFJLENBQUMsbUJBQW1CLEVBQUUsQ0FBQztRQUM5QyxJQUFJLFVBQVUsSUFBSSxVQUFVLENBQUMsTUFBTSxHQUFHLENBQUM7WUFBRSxPQUFPLFVBQVUsQ0FBQztRQUMzRCxPQUFPLElBQUksQ0FBQyxrQkFBa0IsRUFBRSxDQUFDO0lBQ25DLENBQUMsQ0FBQyxDQUFDO0lBRU0sZ0JBQWdCLEdBQUcsTUFBTSxDQUEyQixFQUFFLENBQUMsQ0FBQztJQUV4RCxXQUFXLEdBQUcsUUFBUSxDQUEyQixHQUFHLEVBQUU7UUFDN0QsTUFBTSxVQUFVLEdBQUcsSUFBSSxDQUFDLGlCQUFpQixFQUFFLENBQUM7UUFDNUMsSUFBSSxVQUFVLElBQUksVUFBVSxDQUFDLE1BQU0sR0FBRyxDQUFDO1lBQUUsT0FBTyxVQUFVLENBQUM7UUFDM0QsT0FBTyxJQUFJLENBQUMsZ0JBQWdCLEVBQUUsQ0FBQztJQUNqQyxDQUFDLENBQUMsQ0FBQztJQUVNLGdCQUFnQixHQUFHLE1BQU0sQ0FBdUMsa0JBQWtCLENBQUMsQ0FBQztJQUNwRixpQkFBaUIsR0FBRyxRQUFRLENBQXVDLEdBQUcsRUFBRSxDQUFDLElBQUksQ0FBQyxnQkFBZ0IsRUFBRSxDQUFDLENBQUM7SUFFbEcsZ0JBQWdCLEdBQUcsUUFBUSxDQUFTLEdBQUcsRUFBRTtRQUNoRCxNQUFNLEVBQUUsR0FBRyxJQUFJLENBQUMsVUFBVSxFQUFFLENBQUM7UUFDN0IsSUFBSSxDQUFDLEVBQUU7WUFBRSxPQUFPLEVBQUUsQ0FBQztRQUNuQixNQUFNLE1BQU0sR0FBRyxFQUFFLENBQUMsSUFBSSxLQUFLLE9BQU8sQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxJQUFJLEtBQUssS0FBSyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLGtCQUFrQixDQUFDLENBQUM7UUFDaEcsSUFBSSxNQUFNLEtBQUssSUFBSSxDQUFDLGdCQUFnQixFQUFFLEVBQUUsQ0FBQztZQUN2QyxPQUFPLEVBQUUsQ0FBQyxJQUFJLElBQUksRUFBRSxDQUFDLFFBQVEsSUFBSSxFQUFFLENBQUM7UUFDdEMsQ0FBQztRQUNELE9BQU8sRUFBRSxDQUFDO0lBQ1osQ0FBQyxDQUFDLENBQUM7SUFFTSxXQUFXLEdBQUcsUUFBUSxDQUFTLEdBQUcsRUFBRTtRQUMzQyxNQUFNLEVBQUUsR0FBRyxJQUFJLENBQUMsVUFBVSxFQUFFLENBQUM7UUFDN0IsT0FBTyxFQUFFLEVBQUUsUUFBUSxJQUFJLEVBQUUsRUFBRSxJQUFJLElBQUksRUFBRSxDQUFDO0lBQ3hDLENBQUMsQ0FBQyxDQUFDO0lBRU0sU0FBUyxHQUFHLFFBQVEsQ0FBaUIsR0FBRyxFQUFFO1FBQ2pELE1BQU0sQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLFVBQVUsRUFBRSxFQUFFLE1BQU0sSUFBSSxLQUFLLENBQUMsQ0FBQyxXQUFXLEVBQUUsQ0FBQztRQUM3RCxPQUFPLENBQUMsS0FBSyxNQUFNLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDO0lBQ3ZDLENBQUMsQ0FBQyxDQUFDO0lBRU0sV0FBVyxHQUFHLFFBQVEsQ0FBUyxHQUFHLEVBQUU7UUFDM0MsT0FBUSxJQUFJLENBQUMsVUFBVSxFQUFVLEVBQUUsUUFBUSxJQUFJLEVBQUUsQ0FBQztJQUNwRCxDQUFDLENBQUMsQ0FBQztJQUVNLFdBQVcsR0FBRyxRQUFRLENBQVUsR0FBRyxFQUFFO1FBQzVDLE9BQVEsSUFBSSxDQUFDLFVBQVUsRUFBVSxFQUFFLFFBQVEsS0FBSyxJQUFJLENBQUM7SUFDdkQsQ0FBQyxDQUFDLENBQUM7SUFFTSxjQUFjLEdBQUcsUUFBUSxDQUEyQixHQUFHLEVBQUU7UUFDaEUsTUFBTSxJQUFJLEdBQUcsSUFBSSxDQUFDLFNBQVMsRUFBRSxZQUFZLElBQUksRUFBRSxDQUFDO1FBQ2hELE9BQU8sSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEdBQUcsRUFBRSxFQUFFO1lBQ3RCLE1BQU0sRUFBRSxHQUFHLEdBQUcsQ0FBQyxRQUFRLElBQUksR0FBRyxDQUFDLEdBQUcsSUFBSSxFQUFFLENBQUM7WUFDekMsT0FBTztnQkFDTCxLQUFLLEVBQUUsRUFBRTtnQkFDVCxLQUFLLEVBQUUsR0FBRyxDQUFDLElBQUksSUFBSSxFQUFFO2dCQUNyQixRQUFRLEVBQUUsR0FBRyxHQUFHLENBQUMsTUFBTSxJQUFJLEtBQUssSUFBSSxFQUFFLEVBQUU7Z0JBQ3hDLEtBQUssRUFBRSxHQUFHLENBQUMsUUFBUSxJQUFJLEtBQUs7YUFDN0IsQ0FBQztRQUNKLENBQUMsQ0FBQyxDQUFDO0lBQ0wsQ0FBQyxDQUFDLENBQUM7SUFFTSxlQUFlLEdBQUcsUUFBUSxDQUFDLEdBQUcsRUFBRTtRQUN2QyxPQUFPLElBQUksQ0FBQyxXQUFXLEVBQUUsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRTtZQUNyQyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxJQUFJLElBQUksRUFBRSxDQUFDLENBQUMsV0FBVyxFQUFFLENBQUM7WUFDdkMsT0FBTyxDQUFDLEtBQUssT0FBTyxJQUFJLENBQUMsS0FBSyxNQUFNLENBQUM7UUFDdkMsQ0FBQyxDQUFDLENBQUM7SUFDTCxDQUFDLENBQUMsQ0FBQztJQUVNLG1CQUFtQixHQUFHLFFBQVEsQ0FBQyxHQUFHLEVBQUU7UUFDM0MsT0FBTyxJQUFJLENBQUMsV0FBVyxFQUFFLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUU7WUFDckMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsSUFBSSxJQUFJLEVBQUUsQ0FBQyxDQUFDLFdBQVcsRUFBRSxDQUFDO1lBQ3ZDLE9BQU8sQ0FBQyxLQUFLLGtCQUFrQixJQUFJLENBQUMsS0FBSyxXQUFXLElBQUksQ0FBQyxDQUFDLFFBQVEsQ0FBQyxXQUFXLENBQUMsQ0FBQztRQUNsRixDQUFDLENBQUMsQ0FBQztJQUNMLENBQUMsQ0FBQyxDQUFDO0lBRU0saUJBQWlCLEdBQUcsTUFBTSxDQUFVLEtBQUssQ0FBQyxDQUFDO0lBQzNDLGVBQWUsR0FBRyxNQUFNLENBQVMsRUFBRSxDQUFDLENBQUM7SUFDckMsZUFBZSxHQUFHLE1BQU0sQ0FBd0QsSUFBSSxDQUFDLENBQUM7SUFFL0YsaUJBQWlCO1FBQ2YsSUFBSSxDQUFDLGlCQUFpQixDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUN6QyxJQUFJLENBQUMsZUFBZSxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUNqQyxDQUFDO0lBRUQsZ0JBQWdCO1FBQ2QsTUFBTSxHQUFHLEdBQUcsSUFBSSxDQUFDLGVBQWUsRUFBRSxDQUFDLElBQUksRUFBRSxDQUFDO1FBQzFDLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQztZQUNULElBQUksQ0FBQyxlQUFlLENBQUMsR0FBRyxDQUFDLEVBQUUsT0FBTyxFQUFFLHVDQUF1QyxFQUFFLElBQUksRUFBRSxPQUFPLEVBQUUsQ0FBQyxDQUFDO1lBQzlGLE9BQU87UUFDVCxDQUFDO1FBRUQsTUFBTSxNQUFNLEdBQUcscUJBQXFCLENBQUMsR0FBRyxDQUFDLENBQUM7UUFDMUMsSUFBSSxDQUFDLE1BQU0sSUFBSSxNQUFNLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxVQUFVLENBQUMsQ0FBQyxNQUFNLEtBQUssQ0FBQyxFQUFFLENBQUM7WUFDM0QsSUFBSSxDQUFDLGVBQWUsQ0FBQyxHQUFHLENBQUM7Z0JBQ3ZCLE9BQU8sRUFBRSx5RUFBeUU7Z0JBQ2xGLElBQUksRUFBRSxPQUFPO2FBQ2QsQ0FBQyxDQUFDO1lBQ0gsT0FBTztRQUNULENBQUM7UUFFRCxJQUFJLE1BQU0sQ0FBQyxhQUFhLElBQUksTUFBTSxDQUFDLGFBQWEsQ0FBQyxXQUFXLEVBQUUsS0FBSyxJQUFJLENBQUMsZ0JBQWdCLEVBQUUsQ0FBQyxXQUFXLEVBQUUsRUFBRSxDQUFDO1lBQ3pHLElBQUksQ0FBQyxjQUFjLENBQUMsTUFBTSxDQUFDLGFBQWEsQ0FBQyxDQUFDO1FBQzVDLENBQUM7UUFFRCxNQUFNLGVBQWUsR0FBRyxFQUFFLEdBQUcsQ0FBRSxJQUFJLENBQUMsVUFBVSxFQUFFLEVBQUUsaUJBQTZDLElBQUksRUFBRSxDQUFDLEVBQUUsQ0FBQztRQUN6RyxJQUFJLEtBQUssR0FBRyxDQUFDLENBQUM7UUFDZCxLQUFLLE1BQU0sQ0FBQyxHQUFHLEVBQUUsR0FBRyxDQUFDLElBQUksTUFBTSxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsVUFBVSxDQUFDLEVBQUUsQ0FBQztZQUMzRCxNQUFNLFFBQVEsR0FBRyxHQUFHLENBQUMsT0FBTyxDQUFDLElBQUksRUFBRSxFQUFFLENBQUMsQ0FBQztZQUN2QyxlQUFlLENBQUMsR0FBRyxDQUFDLEdBQUcsR0FBRyxDQUFDO1lBQzNCLGVBQWUsQ0FBQyxRQUFRLENBQUMsR0FBRyxHQUFHLENBQUM7WUFDaEMsZUFBZSxDQUFDLElBQUksUUFBUSxFQUFFLENBQUMsR0FBRyxHQUFHLENBQUM7WUFDdEMsS0FBSyxFQUFFLENBQUM7UUFDVixDQUFDO1FBRUQsSUFBSSxDQUFDLDBCQUEwQixDQUFDLElBQUksQ0FBQyxlQUFlLENBQUMsQ0FBQztRQUN0RCxJQUFJLENBQUMsZUFBZSxDQUFDLEdBQUcsQ0FBQyxFQUFFLE9BQU8sRUFBRSx3QkFBd0IsS0FBSyxnQkFBZ0IsRUFBRSxJQUFJLEVBQUUsU0FBUyxFQUFFLENBQUMsQ0FBQztRQUN0RyxVQUFVLENBQUMsR0FBRyxFQUFFO1lBQ2QsSUFBSSxDQUFDLGlCQUFpQixDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsQ0FBQztZQUNsQyxJQUFJLENBQUMsZUFBZSxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsQ0FBQztZQUMvQixJQUFJLENBQUMsZUFBZSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsQ0FBQztRQUMvQixDQUFDLEVBQUUsSUFBSSxDQUFDLENBQUM7SUFDWCxDQUFDO0lBRUQ7UUFDRSxvRUFBb0U7UUFDcEUsTUFBTSxDQUNKLEdBQUcsRUFBRTtZQUNILE1BQU0sRUFBRSxHQUFHLElBQUksQ0FBQyxVQUFVLEVBQUUsQ0FBQztZQUM3QixJQUFJLEVBQUUsRUFBRSxJQUFJLEVBQUUsQ0FBQztnQkFDYixJQUFJLEVBQUUsQ0FBQyxJQUFJLEtBQUssS0FBSyxJQUFJLEVBQUUsQ0FBQyxRQUFRLEVBQUUsVUFBVSxDQUFDLE1BQU0sQ0FBQyxJQUFJLEVBQUUsQ0FBQyxRQUFRLEVBQUUsVUFBVSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUM7b0JBQ3pGLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLENBQUM7Z0JBQ25DLENBQUM7cUJBQU0sSUFBSSxFQUFFLENBQUMsSUFBSSxLQUFLLE9BQU8sRUFBRSxDQUFDO29CQUMvQixJQUFJLENBQUMsZ0JBQWdCLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQyxDQUFDO2dCQUNyQyxDQUFDO3FCQUFNLENBQUM7b0JBQ04sSUFBSSxDQUFDLGdCQUFnQixDQUFDLEdBQUcsQ0FBQyxrQkFBa0IsQ0FBQyxDQUFDO2dCQUNoRCxDQUFDO1lBQ0gsQ0FBQztRQUNILENBQUMsRUFDRCxFQUFFLGlCQUFpQixFQUFFLElBQUksRUFBRSxDQUM1QixDQUFDO1FBRUYsMERBQTBEO1FBQzFELE1BQU0sQ0FDSixHQUFHLEVBQUU7WUFDSCxNQUFNLE1BQU0sR0FBRyxJQUFJLENBQUMsZ0JBQWdCLEVBQUUsQ0FBQztZQUN2QyxNQUFNLElBQUksR0FBRyxJQUFJLENBQUMsaUJBQWlCLEVBQUUsQ0FBQztZQUN0QyxJQUFJLE1BQU0sSUFBSSxJQUFJLEtBQUssa0JBQWtCLElBQUksSUFBSSxDQUFDLGFBQWEsRUFBRSxDQUFDO2dCQUNoRSxJQUFJLENBQUMsYUFBYSxDQUFDLGFBQWEsQ0FBQyxNQUFNLEVBQUUsS0FBSyxDQUFDLENBQUMsU0FBUyxDQUFDO29CQUN4RCxJQUFJLEVBQUUsQ0FBQyxNQUFNLEVBQUUsRUFBRSxDQUFDLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxHQUFHLENBQUMsTUFBTSxJQUFJLEVBQUUsQ0FBQztvQkFDM0QsS0FBSyxFQUFFLEdBQUcsRUFBRSxDQUFDLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDO2lCQUM3QyxDQUFDLENBQUM7WUFDTCxDQUFDO2lCQUFNLENBQUM7Z0JBQ04sSUFBSSxDQUFDLGtCQUFrQixDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsQ0FBQztZQUNsQyxDQUFDO1FBQ0gsQ0FBQyxFQUNELEVBQUUsaUJBQWlCLEVBQUUsSUFBSSxFQUFFLENBQzVCLENBQUM7UUFFRiw2RUFBNkU7UUFDN0UsSUFBSSxJQUFJLENBQUMsYUFBYSxFQUFFLENBQUM7WUFDdkIsSUFBSSxDQUFDLGFBQWEsQ0FBQyxXQUFXLEVBQUUsQ0FBQyxTQUFTLENBQUMsQ0FBQyxRQUFRLEVBQUUsRUFBRTtnQkFDdEQsSUFBSSxRQUFRLElBQUksUUFBUSxDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUUsQ0FBQztvQkFDcEMsSUFBSSxDQUFDLGdCQUFnQixDQUFDLEdBQUcsQ0FBQyxRQUFRLENBQUMsQ0FBQztnQkFDdEMsQ0FBQztZQUNILENBQUMsQ0FBQyxDQUFDO1FBQ0wsQ0FBQztJQUNILENBQUM7SUFFUSxnQkFBZ0IsR0FBRyxRQUFRLENBQUMsR0FBRyxFQUFFO1FBQ3hDLE9BQU8sSUFBSSxDQUFDLGlCQUFpQixFQUFFLEtBQUssT0FBTyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsZUFBZSxFQUFFLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxtQkFBbUIsRUFBRSxDQUFDO0lBQ3BHLENBQUMsQ0FBQyxDQUFDO0lBRU0sdUJBQXVCLEdBQUcsUUFBUSxDQUEyQixHQUFHLEVBQUU7UUFDekUsT0FBTyxJQUFJLENBQUMsZ0JBQWdCLEVBQUUsQ0FBQyxHQUFHLENBQUMsQ0FBQyxHQUFHLEVBQUUsRUFBRSxDQUFDLENBQUM7WUFDM0MsS0FBSyxFQUFFLEdBQUcsQ0FBQyxJQUFJO1lBQ2YsS0FBSyxFQUFFLEdBQUcsQ0FBQyxZQUFZLElBQUksR0FBRyxDQUFDLElBQUk7WUFDbkMsUUFBUSxFQUFFLEdBQUcsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEdBQUcsR0FBRyxDQUFDLE1BQU0sSUFBSSxHQUFHLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxJQUFJO1lBQzdELEtBQUssRUFBRSxHQUFHLENBQUMsSUFBSSxLQUFLLGtCQUFrQixDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLElBQUksRUFBRSxXQUFXLEVBQUUsSUFBSSxPQUFPLENBQUM7U0FDckYsQ0FBQyxDQUFDLENBQUM7SUFDTixDQUFDLENBQUMsQ0FBQztJQUVNLE9BQU8sR0FBRyxRQUFRLENBQXlCLEdBQUcsRUFBRTtRQUN2RCxPQUFPLElBQUksQ0FBQyxJQUFJLEVBQUUsRUFBRSxPQUFPLElBQUksRUFBRSxDQUFDO0lBQ3BDLENBQUMsQ0FBQyxDQUFDO0lBRU0sY0FBYyxHQUFHLFFBQVEsQ0FBaUMsR0FBRyxFQUFFO1FBQ3RFLE9BQU8sSUFBSSxDQUFDLElBQUksRUFBRSxFQUFFLGNBQWMsSUFBSSxJQUFJLENBQUMsSUFBSSxFQUFFLEVBQUUsT0FBTyxFQUFFLGNBQWMsQ0FBQztJQUM3RSxDQUFDLENBQUMsQ0FBQztJQUVNLGlCQUFpQixHQUFHLFFBQVEsQ0FBVSxHQUFHLEVBQUU7UUFDbEQsT0FBTyxDQUFDLENBQUMsSUFBSSxDQUFDLGNBQWMsRUFBRSxDQUFDO0lBQ2pDLENBQUMsQ0FBQyxDQUFDO0lBRU0saUJBQWlCLEdBQUcsUUFBUSxDQUFtQyxHQUFHLEVBQUU7UUFDM0UsTUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLGNBQWMsRUFBRSxFQUFFLGdCQUFnQixDQUFDO1FBQ3hELElBQUksQ0FBQyxPQUFPO1lBQUUsT0FBTyxFQUFFLENBQUM7UUFDeEIsT0FBTyxNQUFNLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsR0FBRyxFQUFFLEtBQUssQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLEVBQUUsR0FBRyxFQUFFLEtBQUssRUFBRSxDQUFDLENBQUMsQ0FBQztJQUN6RSxDQUFDLENBQUMsQ0FBQztJQUVILGtCQUFrQixDQUFDLElBQTBDO1FBQzNELElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDaEMsSUFBSSxJQUFJLEtBQUssS0FBSyxJQUFJLElBQUksQ0FBQyxXQUFXLEVBQUUsQ0FBQyxNQUFNLEtBQUssQ0FBQyxJQUFJLElBQUksQ0FBQyxhQUFhLEVBQUUsQ0FBQztZQUM1RSxJQUFJLENBQUMsYUFBYSxDQUFDLFdBQVcsRUFBRSxDQUFDLFNBQVMsQ0FBQyxDQUFDLFFBQVEsRUFBRSxFQUFFO2dCQUN0RCxJQUFJLFFBQVEsSUFBSSxRQUFRLENBQUMsTUFBTSxHQUFHLENBQUMsRUFBRSxDQUFDO29CQUNwQyxJQUFJLENBQUMsZ0JBQWdCLENBQUMsR0FBRyxDQUFDLFFBQVEsQ0FBQyxDQUFDO2dCQUN0QyxDQUFDO1lBQ0gsQ0FBQyxDQUFDLENBQUM7UUFDTCxDQUFDO0lBQ0gsQ0FBQztJQUVELG1CQUFtQixDQUFDLFFBQWdCO1FBQ2xDLE1BQU0sT0FBTyxHQUFHLElBQUksQ0FBQyxVQUFVLEVBQUUsQ0FBQztRQUNsQyxNQUFNLElBQUksR0FBK0I7WUFDdkMsR0FBRyxDQUFDLE9BQU8sSUFBSSxFQUFFLEVBQUUsRUFBRSxVQUFVLElBQUksQ0FBQyxHQUFHLEVBQUUsRUFBRSxFQUFFLENBQUM7WUFDOUMsSUFBSSxFQUFFLEtBQUs7WUFDWCxRQUFRLEVBQUUsUUFBUSxDQUFDLElBQUksRUFBRTtZQUN6QixJQUFJLEVBQUUsUUFBUSxDQUFDLElBQUksRUFBRTtZQUNyQixNQUFNLEVBQUUsT0FBTyxFQUFFLE1BQU0sSUFBSSxLQUFLO1NBQ2pDLENBQUM7UUFDRixJQUFJLENBQUMsYUFBYSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUM5QixJQUFJLENBQUMsYUFBYSxDQUFDLElBQUksQ0FBQyxFQUFFLElBQUksRUFBRSxRQUFRLENBQUMsSUFBSSxFQUFFLEVBQUUsSUFBSSxFQUFFLEtBQUssRUFBRSxDQUFDLENBQUM7SUFDbEUsQ0FBQztJQUVELGlCQUFpQixDQUFDLE1BQXNCO1FBQ3RDLE1BQU0sT0FBTyxHQUFHLElBQUksQ0FBQyxVQUFVLEVBQUUsQ0FBQztRQUNsQyxJQUFJLE9BQU8sRUFBRSxDQUFDO1lBQ1osSUFBSSxDQUFDLGFBQWEsQ0FBQyxJQUFJLENBQUMsRUFBRSxHQUFHLE9BQU8sRUFBRSxNQUFNLEVBQUUsQ0FBQyxDQUFDO1FBQ2xELENBQUM7SUFDSCxDQUFDO0lBRUQsbUJBQW1CLENBQUMsUUFBZ0I7UUFDbEMsTUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLFVBQVUsRUFBRSxDQUFDO1FBQ2xDLElBQUksT0FBTyxFQUFFLENBQUM7WUFDWixJQUFJLENBQUMsYUFBYSxDQUFDLElBQUksQ0FBQyxFQUFFLEdBQUcsT0FBTyxFQUFFLFFBQVEsRUFBRSxRQUFRLENBQUMsSUFBSSxFQUFFLEVBQUUsQ0FBQyxDQUFDO1FBQ3JFLENBQUM7SUFDSCxDQUFDO0lBRUQsbUJBQW1CLENBQUMsUUFBaUI7UUFDbkMsTUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLFVBQVUsRUFBRSxDQUFDO1FBQ2xDLElBQUksT0FBTyxFQUFFLENBQUM7WUFDWixJQUFJLENBQUMsYUFBYSxDQUFDLElBQUksQ0FBQyxFQUFFLEdBQUcsT0FBTyxFQUFFLFFBQVEsRUFBRSxDQUFDLENBQUM7UUFDcEQsQ0FBQztJQUNILENBQUM7SUFFRCxjQUFjLENBQUMsVUFBa0I7UUFDL0IsSUFBSSxDQUFDLFVBQVU7WUFBRSxPQUFPO1FBQ3hCLElBQUksSUFBSSxDQUFDLGlCQUFpQixFQUFFLEtBQUssa0JBQWtCLElBQUksSUFBSSxDQUFDLGFBQWEsRUFBRSxDQUFDO1lBQzFFLElBQUksQ0FBQyxhQUFhLENBQUMsYUFBYSxDQUFDLFVBQVUsRUFBRSxLQUFLLENBQUMsQ0FBQyxTQUFTLENBQUM7Z0JBQzVELElBQUksRUFBRSxDQUFDLE1BQU0sRUFBRSxFQUFFLENBQUMsSUFBSSxDQUFDLGtCQUFrQixDQUFDLEdBQUcsQ0FBQyxNQUFNLElBQUksRUFBRSxDQUFDO2dCQUMzRCxLQUFLLEVBQUUsR0FBRyxFQUFFLENBQUMsSUFBSSxDQUFDLGtCQUFrQixDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUM7YUFDN0MsQ0FBQyxDQUFDO1FBQ0wsQ0FBQzthQUFNLENBQUM7WUFDTixJQUFJLENBQUMsa0JBQWtCLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxDQUFDO1FBQ2xDLENBQUM7UUFDRCxJQUFJLENBQUMsYUFBYSxDQUFDLElBQUksQ0FBQyxFQUFFLElBQUksRUFBRSxVQUFVLEVBQUUsSUFBSSxFQUFFLElBQUksQ0FBQyxpQkFBaUIsRUFBRSxFQUFFLENBQUMsQ0FBQztJQUNoRixDQUFDO0lBRUQsaUJBQWlCLENBQUMsU0FBaUI7UUFDakMsTUFBTSxRQUFRLEdBQUksSUFBSSxDQUFDLFVBQVUsRUFBRSxFQUFFLGlCQUErRCxJQUFJLEVBQUUsQ0FBQztRQUMzRyxNQUFNLFNBQVMsR0FBRyxTQUFTLENBQUMsT0FBTyxDQUFDLElBQUksRUFBRSxFQUFFLENBQUMsQ0FBQztRQUM5QyxNQUFNLEdBQUcsR0FBRyxRQUFRLENBQUMsU0FBUyxDQUFDLElBQUksUUFBUSxDQUFDLElBQUksU0FBUyxFQUFFLENBQUMsSUFBSSxRQUFRLENBQUMsU0FBUyxDQUFDLENBQUM7UUFDcEYsSUFBSSxPQUFPLEdBQUcsS0FBSyxRQUFRLElBQUksT0FBTyxHQUFHLEtBQUssUUFBUSxJQUFJLE9BQU8sR0FBRyxLQUFLLFNBQVMsRUFBRSxDQUFDO1lBQ25GLE9BQU8sR0FBRyxDQUFDO1FBQ2IsQ0FBQztRQUNELE9BQU8sRUFBRSxDQUFDO0lBQ1osQ0FBQztJQUVELGlCQUFpQixDQUFDLFNBQWlCLEVBQUUsS0FBZ0M7UUFDbkUsTUFBTSxPQUFPLEdBQUcsRUFBRSxHQUFHLENBQUUsSUFBSSxDQUFDLFVBQVUsRUFBRSxFQUFFLGlCQUErRCxJQUFJLEVBQUUsQ0FBQyxFQUFFLENBQUM7UUFDbkgsTUFBTSxTQUFTLEdBQUcsU0FBUyxDQUFDLE9BQU8sQ0FBQyxJQUFJLEVBQUUsRUFBRSxDQUFDLENBQUM7UUFDOUMsT0FBTyxDQUFDLFNBQVMsQ0FBQyxHQUFHLEtBQUssQ0FBQztRQUMzQixPQUFPLENBQUMsSUFBSSxTQUFTLEVBQUUsQ0FBQyxHQUFHLEtBQUssQ0FBQztRQUNqQyxPQUFPLENBQUMsU0FBUyxDQUFDLEdBQUcsS0FBSyxDQUFDO1FBQzNCLElBQUksQ0FBQywwQkFBMEIsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUM7SUFDaEQsQ0FBQztJQUVELFdBQVcsQ0FBQyxLQUFhLEVBQUUsS0FBYSxFQUFFLEtBQWM7UUFDdEQsSUFBSSxDQUFDLFlBQVksQ0FBQyxJQUFJLENBQUMsRUFBRSxLQUFLLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBRSxDQUFDLENBQUM7SUFDbEQsQ0FBQztJQUVELG9CQUFvQixDQUFDLE9BQWdCO1FBQ25DLElBQUksT0FBTyxFQUFFLENBQUM7WUFDWixJQUFJLENBQUMsb0JBQW9CLENBQUMsSUFBSSxDQUFDO2dCQUM3QixJQUFJLEVBQUUsYUFBYTtnQkFDbkIsV0FBVyxFQUFFLFNBQVM7Z0JBQ3RCLFdBQVcsRUFBRSxPQUFPO2FBQ3JCLENBQUMsQ0FBQztRQUNMLENBQUM7YUFBTSxDQUFDO1lBQ04sSUFBSSxDQUFDLG9CQUFvQixDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQztRQUM1QyxDQUFDO0lBQ0gsQ0FBQztJQUVELG9CQUFvQixDQUFDLEtBQStCLEVBQUUsS0FBYztRQUNsRSxNQUFNLE9BQU8sR0FBRyxJQUFJLENBQUMsY0FBYyxFQUFFLElBQUksRUFBRSxJQUFJLEVBQUUsYUFBYSxFQUFFLENBQUM7UUFDakUsTUFBTSxJQUFJLEdBQUcsRUFBRSxHQUFHLE9BQU8sRUFBRSxDQUFDLEtBQUssQ0FBQyxFQUFFLEtBQUssRUFBRSxDQUFDO1FBQzVDLElBQUksQ0FBQyxvQkFBb0IsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDdkMsQ0FBQztJQUVELG1CQUFtQjtRQUNqQixNQUFNLE9BQU8sR0FBRyxJQUFJLENBQUMsY0FBYyxFQUFFLElBQUksRUFBRSxJQUFJLEVBQUUsYUFBYSxFQUFFLENBQUM7UUFDakUsTUFBTSxPQUFPLEdBQUcsRUFBRSxHQUFHLENBQUMsT0FBTyxDQUFDLGdCQUFnQixJQUFJLEVBQUUsQ0FBQyxFQUFFLENBQUM7UUFDeEQsSUFBSSxHQUFHLEdBQUcsTUFBTSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxDQUFDO1FBQzFDLElBQUksR0FBRyxHQUFHLFFBQVEsR0FBRyxFQUFFLENBQUM7UUFDeEIsT0FBTyxHQUFHLElBQUksT0FBTyxFQUFFLENBQUM7WUFDdEIsR0FBRyxFQUFFLENBQUM7WUFDTixHQUFHLEdBQUcsUUFBUSxHQUFHLEVBQUUsQ0FBQztRQUN0QixDQUFDO1FBQ0QsT0FBTyxDQUFDLEdBQUcsQ0FBQyxHQUFHLFFBQVEsQ0FBQztRQUN4QixJQUFJLENBQUMsb0JBQW9CLENBQUMsSUFBSSxDQUFDLEVBQUUsR0FBRyxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsT0FBTyxFQUFFLENBQUMsQ0FBQztJQUM1RSxDQUFDO0lBRUQsZ0JBQWdCLENBQUMsS0FBYSxFQUFFLE1BQWM7UUFDNUMsTUFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDLGlCQUFpQixFQUFFLENBQUM7UUFDdkMsSUFBSSxDQUFDLEtBQUssQ0FBQyxLQUFLLENBQUM7WUFBRSxPQUFPO1FBQzFCLE1BQU0sV0FBVyxHQUEyQixFQUFFLENBQUM7UUFDL0MsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRTtZQUNyQixNQUFNLENBQUMsR0FBRyxDQUFDLEtBQUssS0FBSyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUM7WUFDdkMsSUFBSSxDQUFDLENBQUMsSUFBSSxFQUFFLEVBQUUsQ0FBQztnQkFDYixXQUFXLENBQUMsQ0FBQyxDQUFDLElBQUksRUFBRSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEtBQUssQ0FBQztZQUNsQyxDQUFDO1FBQ0gsQ0FBQyxDQUFDLENBQUM7UUFDSCxNQUFNLE9BQU8sR0FBRyxJQUFJLENBQUMsY0FBYyxFQUFFLElBQUksRUFBRSxJQUFJLEVBQUUsYUFBYSxFQUFFLENBQUM7UUFDakUsSUFBSSxDQUFDLG9CQUFvQixDQUFDLElBQUksQ0FBQyxFQUFFLEdBQUcsT0FBTyxFQUFFLGdCQUFnQixFQUFFLFdBQVcsRUFBRSxDQUFDLENBQUM7SUFDaEYsQ0FBQztJQUVELGtCQUFrQixDQUFDLEtBQWEsRUFBRSxRQUFnQjtRQUNoRCxNQUFNLEtBQUssR0FBRyxJQUFJLENBQUMsaUJBQWlCLEVBQUUsQ0FBQztRQUN2QyxJQUFJLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FBQztZQUFFLE9BQU87UUFDMUIsTUFBTSxXQUFXLEdBQTJCLEVBQUUsQ0FBQztRQUMvQyxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUFFO1lBQ3JCLE1BQU0sQ0FBQyxHQUFHLENBQUMsS0FBSyxLQUFLLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQztZQUMzQyxJQUFJLENBQUMsQ0FBQyxHQUFHLENBQUMsSUFBSSxFQUFFLEVBQUUsQ0FBQztnQkFDakIsV0FBVyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsSUFBSSxFQUFFLENBQUMsR0FBRyxDQUFDLENBQUM7WUFDaEMsQ0FBQztRQUNILENBQUMsQ0FBQyxDQUFDO1FBQ0gsTUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLGNBQWMsRUFBRSxJQUFJLEVBQUUsSUFBSSxFQUFFLGFBQWEsRUFBRSxDQUFDO1FBQ2pFLElBQUksQ0FBQyxvQkFBb0IsQ0FBQyxJQUFJLENBQUMsRUFBRSxHQUFHLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxXQUFXLEVBQUUsQ0FBQyxDQUFDO0lBQ2hGLENBQUM7SUFFRCxhQUFhLENBQUMsS0FBYTtRQUN6QixNQUFNLEtBQUssR0FBRyxJQUFJLENBQUMsaUJBQWlCLEVBQUUsQ0FBQztRQUN2QyxNQUFNLFdBQVcsR0FBMkIsRUFBRSxDQUFDO1FBQy9DLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFLEVBQUU7WUFDckIsSUFBSSxDQUFDLEtBQUssS0FBSyxJQUFJLENBQUMsQ0FBQyxHQUFHLENBQUMsSUFBSSxFQUFFLEVBQUUsQ0FBQztnQkFDaEMsV0FBVyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsSUFBSSxFQUFFLENBQUMsR0FBRyxDQUFDLENBQUMsS0FBSyxDQUFDO1lBQ3RDLENBQUM7UUFDSCxDQUFDLENBQUMsQ0FBQztRQUNILE1BQU0sT0FBTyxHQUFHLElBQUksQ0FBQyxjQUFjLEVBQUUsSUFBSSxFQUFFLElBQUksRUFBRSxhQUFhLEVBQUUsQ0FBQztRQUNqRSxJQUFJLENBQUMsb0JBQW9CLENBQUMsSUFBSSxDQUFDLEVBQUUsR0FBRyxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsV0FBVyxFQUFFLENBQUMsQ0FBQztJQUNoRixDQUFDO3dHQXJYVSwyQkFBMkI7NEZBQTNCLDJCQUEyQix3a0RDL0J4Qyw4eDNCQXdxQksscThYRG5wQkQsWUFBWSw4QkFDWixXQUFXLG10REFDWCxnQkFBZ0IsdUdBQ2hCLCtCQUErQixvTkFDL0IsNEJBQTRCOzs0RkFNbkIsMkJBQTJCO2tCQWR2QyxTQUFTOytCQUNFLDBCQUEwQixjQUN4QixJQUFJLFdBQ1A7d0JBQ1AsWUFBWTt3QkFDWixXQUFXO3dCQUNYLGdCQUFnQjt3QkFDaEIsK0JBQStCO3dCQUMvQiw0QkFBNEI7cUJBQzdCLG1CQUNnQix1QkFBdUIsQ0FBQyxNQUFNIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3ksIENvbXBvbmVudCwgY29tcHV0ZWQsIGVmZmVjdCwgaW5qZWN0LCBpbnB1dCwgb3V0cHV0LCBzaWduYWwgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IENvbW1vbk1vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbic7XG5pbXBvcnQgeyBGb3Jtc01vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL2Zvcm1zJztcbmltcG9ydCB7IEdyaWRDb2x1bW5EZWZpbml0aW9uLCBHcmlkUm93Q2xpY2tBY3Rpb24sIFJlcG9ydEdyaWREZWZpbml0aW9uIH0gZnJvbSAnLi4vLi4vLi4vLi4vY29yZS9tb2RlbHMvcmVwb3J0LWdyaWQubW9kZWwnO1xuaW1wb3J0IHsgUmVwb3J0RGF0YVNvdXJjZURlZmluaXRpb24gfSBmcm9tICcuLi8uLi8uLi8uLi9jb3JlL21vZGVscy9yZXBvcnQtZGF0YXNvdXJjZS5tb2RlbCc7XG5pbXBvcnQgeyBSZXBvcnRDb21wb25lbnREZWZpbml0aW9uIH0gZnJvbSAnLi4vLi4vLi4vLi4vY29yZS9tb2RlbHMvcmVwb3J0LWNvbXBvbmVudC5tb2RlbCc7XG5pbXBvcnQgeyBEYXRhYmFzZUVudGl0eU1ldGFkYXRhLCBQcm9jZWR1cmVQYXJhbWV0ZXJNZXRhZGF0YSB9IGZyb20gJy4uLy4uLy4uLy4uL2RhdGEtYWNjZXNzL2NvbnRyYWN0cy9zY2hlbWEtZGlzY292ZXJ5LmNvbnRyYWN0JztcbmltcG9ydCB7IFJlcG9ydERhdGFEaXNjb3ZlcnlTZXJ2aWNlIH0gZnJvbSAnLi4vLi4vLi4vLi4vY29yZS9zZXJ2aWNlcy9yZXBvcnQtZGF0YS1kaXNjb3Zlcnkuc2VydmljZSc7XG5pbXBvcnQgeyBCV0FZU19SRVBPUlRfRU5EUE9JTlRTIH0gZnJvbSAnLi4vLi4vLi4vLi4vZGF0YS1hY2Nlc3MvYWRhcHRlcnMvZW5kcG9pbnQtdG9rZW5zJztcbmltcG9ydCB7IFJwdEljb25Db21wb25lbnQgfSBmcm9tICcuLi8uLi8uLi8uLi9wcmltaXRpdmVzL2NvbXBvbmVudHMvaWNvbi9ycHQtaWNvbi5jb21wb25lbnQnO1xuaW1wb3J0IHtcbiAgUnB0U2VhcmNoYWJsZVNlbGVjdENvbXBvbmVudCxcbiAgU2VhcmNoYWJsZVNlbGVjdE9wdGlvbixcbn0gZnJvbSAnLi4vLi4vLi4vLi4vcHJpbWl0aXZlcy9jb21wb25lbnRzJztcbmltcG9ydCB7IFBhcmFtZXRlckJpbmRpbmdFZGl0b3JDb21wb25lbnQgfSBmcm9tICcuL3BhcmFtZXRlci1iaW5kaW5nLWVkaXRvci5jb21wb25lbnQnO1xuaW1wb3J0IHsgcGFyc2VTcWxFeGVjU3RhdGVtZW50IH0gZnJvbSAnLi4vLi4vLi4vLi4vY29yZS91dGlscy9yZXBvcnQtcGFyYW1ldGVyLnV0aWwnO1xuXG5AQ29tcG9uZW50KHtcbiAgc2VsZWN0b3I6ICdycHQtcHJvcGVydHktZWRpdG9yLWdyaWQnLFxuICBzdGFuZGFsb25lOiB0cnVlLFxuICBpbXBvcnRzOiBbXG4gICAgQ29tbW9uTW9kdWxlLFxuICAgIEZvcm1zTW9kdWxlLFxuICAgIFJwdEljb25Db21wb25lbnQsXG4gICAgUGFyYW1ldGVyQmluZGluZ0VkaXRvckNvbXBvbmVudCxcbiAgICBScHRTZWFyY2hhYmxlU2VsZWN0Q29tcG9uZW50LFxuICBdLFxuICBjaGFuZ2VEZXRlY3Rpb246IENoYW5nZURldGVjdGlvblN0cmF0ZWd5Lk9uUHVzaCxcbiAgdGVtcGxhdGVVcmw6ICcuL3Byb3BlcnR5LWVkaXRvci1ncmlkLmNvbXBvbmVudC5odG1sJyxcbiAgc3R5bGVVcmxzOiBbJy4vcHJvcGVydHktZWRpdG9yLmNvbW1vbi5jc3MnLCAnLi9wcm9wZXJ0eS1lZGl0b3ItZ3JpZC5jb21wb25lbnQuY3NzJ10sXG59KVxuZXhwb3J0IGNsYXNzIFByb3BlcnR5RWRpdG9yR3JpZENvbXBvbmVudCB7XG4gIHByaXZhdGUgcmVhZG9ubHkgZGF0YURpc2NvdmVyeSA9IGluamVjdChSZXBvcnREYXRhRGlzY292ZXJ5U2VydmljZSwgeyBvcHRpb25hbDogdHJ1ZSB9KTtcbiAgcHJpdmF0ZSByZWFkb25seSBlbmRwb2ludHMgPSBpbmplY3QoQldBWVNfUkVQT1JUX0VORFBPSU5UUywgeyBvcHRpb25hbDogdHJ1ZSB9KTtcblxuICByZWFkb25seSBncmlkID0gaW5wdXQ8UmVwb3J0R3JpZERlZmluaXRpb24gfCB1bmRlZmluZWQ+KCk7XG4gIHJlYWRvbmx5IGRhdGFTb3VyY2UgPSBpbnB1dDxSZXBvcnREYXRhU291cmNlRGVmaW5pdGlvbiB8IHVuZGVmaW5lZD4oKTtcbiAgcmVhZG9ubHkgYXZhaWxhYmxlRW50aXRpZXMgPSBpbnB1dDxEYXRhYmFzZUVudGl0eU1ldGFkYXRhW10+KFtdKTtcbiAgcmVhZG9ubHkgcHJvY2VkdXJlUGFyYW1ldGVycyA9IGlucHV0PFByb2NlZHVyZVBhcmFtZXRlck1ldGFkYXRhW10+KFtdKTtcbiAgcmVhZG9ubHkgYWxsQ29tcG9uZW50cyA9IGlucHV0PFJlcG9ydENvbXBvbmVudERlZmluaXRpb25bXT4oW10pO1xuICByZWFkb25seSBpc0RldGVjdGluZyA9IGlucHV0PGJvb2xlYW4+KGZhbHNlKTtcbiAgcmVhZG9ubHkgc3RhdHVzTWVzc2FnZSA9IGlucHV0PHN0cmluZyB8IG51bGw+KG51bGwpO1xuICByZWFkb25seSBzdGF0dXNLaW5kID0gaW5wdXQ8J2luZm8nIHwgJ3N1Y2Nlc3MnIHwgJ2Vycm9yJyB8IG51bGw+KG51bGwpO1xuXG4gIHJlYWRvbmx5IGFkZEdyaWQgPSBvdXRwdXQ8dm9pZD4oKTtcbiAgcmVhZG9ubHkgcmVtb3ZlR3JpZCA9IG91dHB1dDx2b2lkPigpO1xuICByZWFkb25seSBhZGRDb2x1bW4gPSBvdXRwdXQ8dm9pZD4oKTtcbiAgcmVhZG9ubHkgYXV0b0RldGVjdENvbHVtbnMgPSBvdXRwdXQ8dm9pZD4oKTtcbiAgcmVhZG9ubHkgcmVtb3ZlQ29sdW1uID0gb3V0cHV0PG51bWJlcj4oKTtcbiAgcmVhZG9ubHkgdXBkYXRlQ29sdW1uID0gb3V0cHV0PHsgaW5kZXg6IG51bWJlcjsgZmllbGQ6IHN0cmluZzsgdmFsdWU6IHVua25vd24gfT4oKTtcbiAgcmVhZG9ubHkgdXBkYXRlT3B0aW9uID0gb3V0cHV0PHsgZmllbGQ6IHN0cmluZzsgdmFsdWU6IHVua25vd24gfT4oKTtcbiAgcmVhZG9ubHkgdXBkYXRlUm93Q2xpY2tBY3Rpb24gPSBvdXRwdXQ8R3JpZFJvd0NsaWNrQWN0aW9uIHwgdW5kZWZpbmVkPigpO1xuICByZWFkb25seSBzZXREYXRhU291cmNlID0gb3V0cHV0PFJlcG9ydERhdGFTb3VyY2VEZWZpbml0aW9uPigpO1xuICByZWFkb25seSB1cGRhdGVEYXRhU291cmNlUGFyYW1ldGVycyA9IG91dHB1dDxSZWNvcmQ8c3RyaW5nLCB1bmtub3duPj4oKTtcbiAgcmVhZG9ubHkgZW50aXR5Q2hhbmdlZCA9IG91dHB1dDx7IG5hbWU6IHN0cmluZzsgdHlwZTogJ3N0b3JlZF9wcm9jZWR1cmUnIHwgJ3RhYmxlJyB8ICdhcGknIH0+KCk7XG5cbiAgcmVhZG9ubHkgaW50ZXJuYWxQYXJhbWV0ZXJzID0gc2lnbmFsPFByb2NlZHVyZVBhcmFtZXRlck1ldGFkYXRhW10+KFtdKTtcblxuICByZWFkb25seSBlZmZlY3RpdmVQYXJhbWV0ZXJzID0gY29tcHV0ZWQ8UHJvY2VkdXJlUGFyYW1ldGVyTWV0YWRhdGFbXT4oKCkgPT4ge1xuICAgIGNvbnN0IGZyb21QYXJlbnQgPSB0aGlzLnByb2NlZHVyZVBhcmFtZXRlcnMoKTtcbiAgICBpZiAoZnJvbVBhcmVudCAmJiBmcm9tUGFyZW50Lmxlbmd0aCA+IDApIHJldHVybiBmcm9tUGFyZW50O1xuICAgIHJldHVybiB0aGlzLmludGVybmFsUGFyYW1ldGVycygpO1xuICB9KTtcblxuICByZWFkb25seSBpbnRlcm5hbEVudGl0aWVzID0gc2lnbmFsPERhdGFiYXNlRW50aXR5TWV0YWRhdGFbXT4oW10pO1xuXG4gIHJlYWRvbmx5IGFsbEVudGl0aWVzID0gY29tcHV0ZWQ8RGF0YWJhc2VFbnRpdHlNZXRhZGF0YVtdPigoKSA9PiB7XG4gICAgY29uc3QgZnJvbVBhcmVudCA9IHRoaXMuYXZhaWxhYmxlRW50aXRpZXMoKTtcbiAgICBpZiAoZnJvbVBhcmVudCAmJiBmcm9tUGFyZW50Lmxlbmd0aCA+IDApIHJldHVybiBmcm9tUGFyZW50O1xuICAgIHJldHVybiB0aGlzLmludGVybmFsRW50aXRpZXMoKTtcbiAgfSk7XG5cbiAgcmVhZG9ubHkgYWN0aXZlU291cmNlVHlwZSA9IHNpZ25hbDwnc3RvcmVkX3Byb2NlZHVyZScgfCAndGFibGUnIHwgJ2FwaSc+KCdzdG9yZWRfcHJvY2VkdXJlJyk7XG4gIHJlYWRvbmx5IGN1cnJlbnRTb3VyY2VUeXBlID0gY29tcHV0ZWQ8J3N0b3JlZF9wcm9jZWR1cmUnIHwgJ3RhYmxlJyB8ICdhcGknPigoKSA9PiB0aGlzLmFjdGl2ZVNvdXJjZVR5cGUoKSk7XG5cbiAgcmVhZG9ubHkgYWN0aXZlRW50aXR5TmFtZSA9IGNvbXB1dGVkPHN0cmluZz4oKCkgPT4ge1xuICAgIGNvbnN0IGRzID0gdGhpcy5kYXRhU291cmNlKCk7XG4gICAgaWYgKCFkcykgcmV0dXJuICcnO1xuICAgIGNvbnN0IGRzVHlwZSA9IGRzLnR5cGUgPT09ICd0YWJsZScgPyAndGFibGUnIDogKGRzLnR5cGUgPT09ICdhcGknID8gJ2FwaScgOiAnc3RvcmVkX3Byb2NlZHVyZScpO1xuICAgIGlmIChkc1R5cGUgPT09IHRoaXMuYWN0aXZlU291cmNlVHlwZSgpKSB7XG4gICAgICByZXR1cm4gZHMubmFtZSB8fCBkcy5lbmRwb2ludCB8fCAnJztcbiAgICB9XG4gICAgcmV0dXJuICcnO1xuICB9KTtcblxuICByZWFkb25seSBhcGlFbmRwb2ludCA9IGNvbXB1dGVkPHN0cmluZz4oKCkgPT4ge1xuICAgIGNvbnN0IGRzID0gdGhpcy5kYXRhU291cmNlKCk7XG4gICAgcmV0dXJuIGRzPy5lbmRwb2ludCB8fCBkcz8ubmFtZSB8fCAnJztcbiAgfSk7XG5cbiAgcmVhZG9ubHkgYXBpTWV0aG9kID0gY29tcHV0ZWQ8J0dFVCcgfCAnUE9TVCc+KCgpID0+IHtcbiAgICBjb25zdCBtID0gKHRoaXMuZGF0YVNvdXJjZSgpPy5tZXRob2QgfHwgJ0dFVCcpLnRvVXBwZXJDYXNlKCk7XG4gICAgcmV0dXJuIG0gPT09ICdQT1NUJyA/ICdQT1NUJyA6ICdHRVQnO1xuICB9KTtcblxuICByZWFkb25seSBhcGlEYXRhUGF0aCA9IGNvbXB1dGVkPHN0cmluZz4oKCkgPT4ge1xuICAgIHJldHVybiAodGhpcy5kYXRhU291cmNlKCkgYXMgYW55KT8uZGF0YVBhdGggfHwgJyc7XG4gIH0pO1xuXG4gIHJlYWRvbmx5IGFwaVVzZVByb3h5ID0gY29tcHV0ZWQ8Ym9vbGVhbj4oKCkgPT4ge1xuICAgIHJldHVybiAodGhpcy5kYXRhU291cmNlKCkgYXMgYW55KT8udXNlUHJveHkgPT09IHRydWU7XG4gIH0pO1xuXG4gIHJlYWRvbmx5IHJlZ2lzdGVyZWRBcGlzID0gY29tcHV0ZWQ8U2VhcmNoYWJsZVNlbGVjdE9wdGlvbltdPigoKSA9PiB7XG4gICAgY29uc3QgYXBpcyA9IHRoaXMuZW5kcG9pbnRzPy5hcGlFbmRwb2ludHMgfHwgW107XG4gICAgcmV0dXJuIGFwaXMubWFwKChhcGkpID0+IHtcbiAgICAgIGNvbnN0IGVwID0gYXBpLmVuZHBvaW50IHx8IGFwaS51cmwgfHwgJyc7XG4gICAgICByZXR1cm4ge1xuICAgICAgICB2YWx1ZTogZXAsXG4gICAgICAgIGxhYmVsOiBhcGkubmFtZSB8fCBlcCxcbiAgICAgICAgc3VibGFiZWw6IGAke2FwaS5tZXRob2QgfHwgJ0dFVCd9ICR7ZXB9YCxcbiAgICAgICAgYmFkZ2U6IGFwaS5jYXRlZ29yeSB8fCAnQVBJJyxcbiAgICAgIH07XG4gICAgfSk7XG4gIH0pO1xuXG4gIHJlYWRvbmx5IGF2YWlsYWJsZVRhYmxlcyA9IGNvbXB1dGVkKCgpID0+IHtcbiAgICByZXR1cm4gdGhpcy5hbGxFbnRpdGllcygpLmZpbHRlcigoZSkgPT4ge1xuICAgICAgY29uc3QgdCA9IChlLnR5cGUgfHwgJycpLnRvTG93ZXJDYXNlKCk7XG4gICAgICByZXR1cm4gdCA9PT0gJ3RhYmxlJyB8fCB0ID09PSAndmlldyc7XG4gICAgfSk7XG4gIH0pO1xuXG4gIHJlYWRvbmx5IGF2YWlsYWJsZVByb2NlZHVyZXMgPSBjb21wdXRlZCgoKSA9PiB7XG4gICAgcmV0dXJuIHRoaXMuYWxsRW50aXRpZXMoKS5maWx0ZXIoKGUpID0+IHtcbiAgICAgIGNvbnN0IHQgPSAoZS50eXBlIHx8ICcnKS50b0xvd2VyQ2FzZSgpO1xuICAgICAgcmV0dXJuIHQgPT09ICdzdG9yZWRfcHJvY2VkdXJlJyB8fCB0ID09PSAncHJvY2VkdXJlJyB8fCB0LmluY2x1ZGVzKCdwcm9jZWR1cmUnKTtcbiAgICB9KTtcbiAgfSk7XG5cbiAgcmVhZG9ubHkgaXNFeGVjU25pcHBldE9wZW4gPSBzaWduYWw8Ym9vbGVhbj4oZmFsc2UpO1xuICByZWFkb25seSBleGVjU25pcHBldFRleHQgPSBzaWduYWw8c3RyaW5nPignJyk7XG4gIHJlYWRvbmx5IGV4ZWNQYXJzZVN0YXR1cyA9IHNpZ25hbDx7IG1lc3NhZ2U6IHN0cmluZzsga2luZDogJ3N1Y2Nlc3MnIHwgJ2Vycm9yJyB9IHwgbnVsbD4obnVsbCk7XG5cbiAgdG9nZ2xlRXhlY1NuaXBwZXQoKTogdm9pZCB7XG4gICAgdGhpcy5pc0V4ZWNTbmlwcGV0T3Blbi51cGRhdGUoKHYpID0+ICF2KTtcbiAgICB0aGlzLmV4ZWNQYXJzZVN0YXR1cy5zZXQobnVsbCk7XG4gIH1cblxuICBhcHBseUV4ZWNTbmlwcGV0KCk6IHZvaWQge1xuICAgIGNvbnN0IHJhdyA9IHRoaXMuZXhlY1NuaXBwZXRUZXh0KCkudHJpbSgpO1xuICAgIGlmICghcmF3KSB7XG4gICAgICB0aGlzLmV4ZWNQYXJzZVN0YXR1cy5zZXQoeyBtZXNzYWdlOiAnUGxlYXNlIHBhc3RlIGFuIEVYRUMgc3RhdGVtZW50IGZpcnN0LicsIGtpbmQ6ICdlcnJvcicgfSk7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgY29uc3QgcGFyc2VkID0gcGFyc2VTcWxFeGVjU3RhdGVtZW50KHJhdyk7XG4gICAgaWYgKCFwYXJzZWQgfHwgT2JqZWN0LmtleXMocGFyc2VkLnBhcmFtZXRlcnMpLmxlbmd0aCA9PT0gMCkge1xuICAgICAgdGhpcy5leGVjUGFyc2VTdGF0dXMuc2V0KHtcbiAgICAgICAgbWVzc2FnZTogJ0NvdWxkIG5vdCBleHRyYWN0IHBhcmFtZXRlcnMuIEV4YW1wbGU6IGV4ZWMgUHJvY05hbWUgQHAxPXZhbDEsIEBwMj12YWwyJyxcbiAgICAgICAga2luZDogJ2Vycm9yJyxcbiAgICAgIH0pO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGlmIChwYXJzZWQucHJvY2VkdXJlTmFtZSAmJiBwYXJzZWQucHJvY2VkdXJlTmFtZS50b0xvd2VyQ2FzZSgpICE9PSB0aGlzLmFjdGl2ZUVudGl0eU5hbWUoKS50b0xvd2VyQ2FzZSgpKSB7XG4gICAgICB0aGlzLm9uU2VsZWN0RW50aXR5KHBhcnNlZC5wcm9jZWR1cmVOYW1lKTtcbiAgICB9XG5cbiAgICBjb25zdCBjdXJyZW50TWFwcGluZ3MgPSB7IC4uLigodGhpcy5kYXRhU291cmNlKCk/LnBhcmFtZXRlck1hcHBpbmdzIGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+KSB8fCB7fSkgfTtcbiAgICBsZXQgY291bnQgPSAwO1xuICAgIGZvciAoY29uc3QgW2tleSwgdmFsXSBvZiBPYmplY3QuZW50cmllcyhwYXJzZWQucGFyYW1ldGVycykpIHtcbiAgICAgIGNvbnN0IGNsZWFuS2V5ID0ga2V5LnJlcGxhY2UoL15ALywgJycpO1xuICAgICAgY3VycmVudE1hcHBpbmdzW2tleV0gPSB2YWw7XG4gICAgICBjdXJyZW50TWFwcGluZ3NbY2xlYW5LZXldID0gdmFsO1xuICAgICAgY3VycmVudE1hcHBpbmdzW2BAJHtjbGVhbktleX1gXSA9IHZhbDtcbiAgICAgIGNvdW50Kys7XG4gICAgfVxuXG4gICAgdGhpcy51cGRhdGVEYXRhU291cmNlUGFyYW1ldGVycy5lbWl0KGN1cnJlbnRNYXBwaW5ncyk7XG4gICAgdGhpcy5leGVjUGFyc2VTdGF0dXMuc2V0KHsgbWVzc2FnZTogYFN1Y2Nlc3NmdWxseSBhcHBsaWVkICR7Y291bnR9IHBhcmFtZXRlcihzKSFgLCBraW5kOiAnc3VjY2VzcycgfSk7XG4gICAgc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICB0aGlzLmlzRXhlY1NuaXBwZXRPcGVuLnNldChmYWxzZSk7XG4gICAgICB0aGlzLmV4ZWNQYXJzZVN0YXR1cy5zZXQobnVsbCk7XG4gICAgICB0aGlzLmV4ZWNTbmlwcGV0VGV4dC5zZXQoJycpO1xuICAgIH0sIDE1MDApO1xuICB9XG5cbiAgY29uc3RydWN0b3IoKSB7XG4gICAgLy8gMS4gU3luYyBhY3RpdmUgdGFiIHdoZW5ldmVyIGluY29taW5nIGdyaWQgZGF0YVNvdXJjZSBjaGFuZ2VzIHR5cGVcbiAgICBlZmZlY3QoXG4gICAgICAoKSA9PiB7XG4gICAgICAgIGNvbnN0IGRzID0gdGhpcy5kYXRhU291cmNlKCk7XG4gICAgICAgIGlmIChkcz8udHlwZSkge1xuICAgICAgICAgIGlmIChkcy50eXBlID09PSAnYXBpJyB8fCBkcy5lbmRwb2ludD8uc3RhcnRzV2l0aCgnaHR0cCcpIHx8IGRzLmVuZHBvaW50Py5zdGFydHNXaXRoKCcvJykpIHtcbiAgICAgICAgICAgIHRoaXMuYWN0aXZlU291cmNlVHlwZS5zZXQoJ2FwaScpO1xuICAgICAgICAgIH0gZWxzZSBpZiAoZHMudHlwZSA9PT0gJ3RhYmxlJykge1xuICAgICAgICAgICAgdGhpcy5hY3RpdmVTb3VyY2VUeXBlLnNldCgndGFibGUnKTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhpcy5hY3RpdmVTb3VyY2VUeXBlLnNldCgnc3RvcmVkX3Byb2NlZHVyZScpO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfSxcbiAgICAgIHsgYWxsb3dTaWduYWxXcml0ZXM6IHRydWUgfVxuICAgICk7XG5cbiAgICAvLyAyLiBGZXRjaCBwYXJhbWV0ZXJzIHdoZW4gYSBzdG9yZWQgcHJvY2VkdXJlIGlzIHNlbGVjdGVkXG4gICAgZWZmZWN0KFxuICAgICAgKCkgPT4ge1xuICAgICAgICBjb25zdCBlbnRpdHkgPSB0aGlzLmFjdGl2ZUVudGl0eU5hbWUoKTtcbiAgICAgICAgY29uc3QgdHlwZSA9IHRoaXMuY3VycmVudFNvdXJjZVR5cGUoKTtcbiAgICAgICAgaWYgKGVudGl0eSAmJiB0eXBlID09PSAnc3RvcmVkX3Byb2NlZHVyZScgJiYgdGhpcy5kYXRhRGlzY292ZXJ5KSB7XG4gICAgICAgICAgdGhpcy5kYXRhRGlzY292ZXJ5LmdldFBhcmFtZXRlcnMoZW50aXR5LCAnZGJvJykuc3Vic2NyaWJlKHtcbiAgICAgICAgICAgIG5leHQ6IChwYXJhbXMpID0+IHRoaXMuaW50ZXJuYWxQYXJhbWV0ZXJzLnNldChwYXJhbXMgfHwgW10pLFxuICAgICAgICAgICAgZXJyb3I6ICgpID0+IHRoaXMuaW50ZXJuYWxQYXJhbWV0ZXJzLnNldChbXSksXG4gICAgICAgICAgfSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgdGhpcy5pbnRlcm5hbFBhcmFtZXRlcnMuc2V0KFtdKTtcbiAgICAgICAgfVxuICAgICAgfSxcbiAgICAgIHsgYWxsb3dTaWduYWxXcml0ZXM6IHRydWUgfVxuICAgICk7XG5cbiAgICAvLyAzLiBGYWxsYmFjayBkaXNjb3ZlcnkgbG9hZCBpZiBhdmFpbGFibGVFbnRpdGllcyB3YXNuJ3QgcG9wdWxhdGVkIGJ5IHBhcmVudFxuICAgIGlmICh0aGlzLmRhdGFEaXNjb3ZlcnkpIHtcbiAgICAgIHRoaXMuZGF0YURpc2NvdmVyeS5nZXRFbnRpdGllcygpLnN1YnNjcmliZSgoZW50aXRpZXMpID0+IHtcbiAgICAgICAgaWYgKGVudGl0aWVzICYmIGVudGl0aWVzLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICB0aGlzLmludGVybmFsRW50aXRpZXMuc2V0KGVudGl0aWVzKTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgfVxuICB9XG5cbiAgcmVhZG9ubHkgYWN0aXZlRW50aXR5TGlzdCA9IGNvbXB1dGVkKCgpID0+IHtcbiAgICByZXR1cm4gdGhpcy5jdXJyZW50U291cmNlVHlwZSgpID09PSAndGFibGUnID8gdGhpcy5hdmFpbGFibGVUYWJsZXMoKSA6IHRoaXMuYXZhaWxhYmxlUHJvY2VkdXJlcygpO1xuICB9KTtcblxuICByZWFkb25seSBncmlkRW50aXR5U2VsZWN0T3B0aW9ucyA9IGNvbXB1dGVkPFNlYXJjaGFibGVTZWxlY3RPcHRpb25bXT4oKCkgPT4ge1xuICAgIHJldHVybiB0aGlzLmFjdGl2ZUVudGl0eUxpc3QoKS5tYXAoKGVudCkgPT4gKHtcbiAgICAgIHZhbHVlOiBlbnQubmFtZSxcbiAgICAgIGxhYmVsOiBlbnQuZnJpZW5kbHlOYW1lIHx8IGVudC5uYW1lLFxuICAgICAgc3VibGFiZWw6IGVudC5zY2hlbWEgPyBgJHtlbnQuc2NoZW1hfS4ke2VudC5uYW1lfWAgOiBlbnQubmFtZSxcbiAgICAgIGJhZGdlOiBlbnQudHlwZSA9PT0gJ3N0b3JlZF9wcm9jZWR1cmUnID8gJ1NQJyA6IChlbnQudHlwZT8udG9VcHBlckNhc2UoKSB8fCAnVEFCTEUnKSxcbiAgICB9KSk7XG4gIH0pO1xuXG4gIHJlYWRvbmx5IGNvbHVtbnMgPSBjb21wdXRlZDxHcmlkQ29sdW1uRGVmaW5pdGlvbltdPigoKSA9PiB7XG4gICAgcmV0dXJuIHRoaXMuZ3JpZCgpPy5jb2x1bW5zID8/IFtdO1xuICB9KTtcblxuICByZWFkb25seSByb3dDbGlja0FjdGlvbiA9IGNvbXB1dGVkPEdyaWRSb3dDbGlja0FjdGlvbiB8IHVuZGVmaW5lZD4oKCkgPT4ge1xuICAgIHJldHVybiB0aGlzLmdyaWQoKT8ucm93Q2xpY2tBY3Rpb24gPz8gdGhpcy5ncmlkKCk/Lm9wdGlvbnM/LnJvd0NsaWNrQWN0aW9uO1xuICB9KTtcblxuICByZWFkb25seSBoYXNSb3dDbGlja0FjdGlvbiA9IGNvbXB1dGVkPGJvb2xlYW4+KCgpID0+IHtcbiAgICByZXR1cm4gISF0aGlzLnJvd0NsaWNrQWN0aW9uKCk7XG4gIH0pO1xuXG4gIHJlYWRvbmx5IHBhcmFtZXRlck1hcHBpbmdzID0gY29tcHV0ZWQ8eyBrZXk6IHN0cmluZzsgdmFsdWU6IHN0cmluZyB9W10+KCgpID0+IHtcbiAgICBjb25zdCBtYXBwaW5nID0gdGhpcy5yb3dDbGlja0FjdGlvbigpPy5wYXJhbWV0ZXJNYXBwaW5nO1xuICAgIGlmICghbWFwcGluZykgcmV0dXJuIFtdO1xuICAgIHJldHVybiBPYmplY3QuZW50cmllcyhtYXBwaW5nKS5tYXAoKFtrZXksIHZhbHVlXSkgPT4gKHsga2V5LCB2YWx1ZSB9KSk7XG4gIH0pO1xuXG4gIG9uU291cmNlVHlwZUNoYW5nZSh0eXBlOiAnc3RvcmVkX3Byb2NlZHVyZScgfCAndGFibGUnIHwgJ2FwaScpOiB2b2lkIHtcbiAgICB0aGlzLmFjdGl2ZVNvdXJjZVR5cGUuc2V0KHR5cGUpO1xuICAgIGlmICh0eXBlICE9PSAnYXBpJyAmJiB0aGlzLmFsbEVudGl0aWVzKCkubGVuZ3RoID09PSAwICYmIHRoaXMuZGF0YURpc2NvdmVyeSkge1xuICAgICAgdGhpcy5kYXRhRGlzY292ZXJ5LmdldEVudGl0aWVzKCkuc3Vic2NyaWJlKChlbnRpdGllcykgPT4ge1xuICAgICAgICBpZiAoZW50aXRpZXMgJiYgZW50aXRpZXMubGVuZ3RoID4gMCkge1xuICAgICAgICAgIHRoaXMuaW50ZXJuYWxFbnRpdGllcy5zZXQoZW50aXRpZXMpO1xuICAgICAgICB9XG4gICAgICB9KTtcbiAgICB9XG4gIH1cblxuICBvbkFwaUVuZHBvaW50Q2hhbmdlKGVuZHBvaW50OiBzdHJpbmcpOiB2b2lkIHtcbiAgICBjb25zdCBjdXJyZW50ID0gdGhpcy5kYXRhU291cmNlKCk7XG4gICAgY29uc3QgbmV4dDogUmVwb3J0RGF0YVNvdXJjZURlZmluaXRpb24gPSB7XG4gICAgICAuLi4oY3VycmVudCA/PyB7IGlkOiBgZHMtYXBpLSR7RGF0ZS5ub3coKX1gIH0pLFxuICAgICAgdHlwZTogJ2FwaScsXG4gICAgICBlbmRwb2ludDogZW5kcG9pbnQudHJpbSgpLFxuICAgICAgbmFtZTogZW5kcG9pbnQudHJpbSgpLFxuICAgICAgbWV0aG9kOiBjdXJyZW50Py5tZXRob2QgfHwgJ0dFVCcsXG4gICAgfTtcbiAgICB0aGlzLnNldERhdGFTb3VyY2UuZW1pdChuZXh0KTtcbiAgICB0aGlzLmVudGl0eUNoYW5nZWQuZW1pdCh7IG5hbWU6IGVuZHBvaW50LnRyaW0oKSwgdHlwZTogJ2FwaScgfSk7XG4gIH1cblxuICBvbkFwaU1ldGhvZENoYW5nZShtZXRob2Q6ICdHRVQnIHwgJ1BPU1QnKTogdm9pZCB7XG4gICAgY29uc3QgY3VycmVudCA9IHRoaXMuZGF0YVNvdXJjZSgpO1xuICAgIGlmIChjdXJyZW50KSB7XG4gICAgICB0aGlzLnNldERhdGFTb3VyY2UuZW1pdCh7IC4uLmN1cnJlbnQsIG1ldGhvZCB9KTtcbiAgICB9XG4gIH1cblxuICBvbkFwaURhdGFQYXRoQ2hhbmdlKGRhdGFQYXRoOiBzdHJpbmcpOiB2b2lkIHtcbiAgICBjb25zdCBjdXJyZW50ID0gdGhpcy5kYXRhU291cmNlKCk7XG4gICAgaWYgKGN1cnJlbnQpIHtcbiAgICAgIHRoaXMuc2V0RGF0YVNvdXJjZS5lbWl0KHsgLi4uY3VycmVudCwgZGF0YVBhdGg6IGRhdGFQYXRoLnRyaW0oKSB9KTtcbiAgICB9XG4gIH1cblxuICBvbkFwaVVzZVByb3h5Q2hhbmdlKHVzZVByb3h5OiBib29sZWFuKTogdm9pZCB7XG4gICAgY29uc3QgY3VycmVudCA9IHRoaXMuZGF0YVNvdXJjZSgpO1xuICAgIGlmIChjdXJyZW50KSB7XG4gICAgICB0aGlzLnNldERhdGFTb3VyY2UuZW1pdCh7IC4uLmN1cnJlbnQsIHVzZVByb3h5IH0pO1xuICAgIH1cbiAgfVxuXG4gIG9uU2VsZWN0RW50aXR5KGVudGl0eU5hbWU6IHN0cmluZyk6IHZvaWQge1xuICAgIGlmICghZW50aXR5TmFtZSkgcmV0dXJuO1xuICAgIGlmICh0aGlzLmN1cnJlbnRTb3VyY2VUeXBlKCkgPT09ICdzdG9yZWRfcHJvY2VkdXJlJyAmJiB0aGlzLmRhdGFEaXNjb3ZlcnkpIHtcbiAgICAgIHRoaXMuZGF0YURpc2NvdmVyeS5nZXRQYXJhbWV0ZXJzKGVudGl0eU5hbWUsICdkYm8nKS5zdWJzY3JpYmUoe1xuICAgICAgICBuZXh0OiAocGFyYW1zKSA9PiB0aGlzLmludGVybmFsUGFyYW1ldGVycy5zZXQocGFyYW1zIHx8IFtdKSxcbiAgICAgICAgZXJyb3I6ICgpID0+IHRoaXMuaW50ZXJuYWxQYXJhbWV0ZXJzLnNldChbXSksXG4gICAgICB9KTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5pbnRlcm5hbFBhcmFtZXRlcnMuc2V0KFtdKTtcbiAgICB9XG4gICAgdGhpcy5lbnRpdHlDaGFuZ2VkLmVtaXQoeyBuYW1lOiBlbnRpdHlOYW1lLCB0eXBlOiB0aGlzLmN1cnJlbnRTb3VyY2VUeXBlKCkgfSk7XG4gIH1cblxuICBnZXRQYXJhbWV0ZXJWYWx1ZShwYXJhbU5hbWU6IHN0cmluZyk6IHN0cmluZyB8IG51bWJlciB8IGJvb2xlYW4ge1xuICAgIGNvbnN0IG1hcHBpbmdzID0gKHRoaXMuZGF0YVNvdXJjZSgpPy5wYXJhbWV0ZXJNYXBwaW5ncyBhcyBSZWNvcmQ8c3RyaW5nLCBzdHJpbmcgfCBudW1iZXIgfCBib29sZWFuPikgfHwge307XG4gICAgY29uc3QgY2xlYW5OYW1lID0gcGFyYW1OYW1lLnJlcGxhY2UoL15ALywgJycpO1xuICAgIGNvbnN0IHZhbCA9IG1hcHBpbmdzW3BhcmFtTmFtZV0gPz8gbWFwcGluZ3NbYEAke2NsZWFuTmFtZX1gXSA/PyBtYXBwaW5nc1tjbGVhbk5hbWVdO1xuICAgIGlmICh0eXBlb2YgdmFsID09PSAnc3RyaW5nJyB8fCB0eXBlb2YgdmFsID09PSAnbnVtYmVyJyB8fCB0eXBlb2YgdmFsID09PSAnYm9vbGVhbicpIHtcbiAgICAgIHJldHVybiB2YWw7XG4gICAgfVxuICAgIHJldHVybiAnJztcbiAgfVxuXG4gIG9uUGFyYW1ldGVyQ2hhbmdlKHBhcmFtTmFtZTogc3RyaW5nLCB2YWx1ZTogc3RyaW5nIHwgbnVtYmVyIHwgYm9vbGVhbik6IHZvaWQge1xuICAgIGNvbnN0IGN1cnJlbnQgPSB7IC4uLigodGhpcy5kYXRhU291cmNlKCk/LnBhcmFtZXRlck1hcHBpbmdzIGFzIFJlY29yZDxzdHJpbmcsIHN0cmluZyB8IG51bWJlciB8IGJvb2xlYW4+KSB8fCB7fSkgfTtcbiAgICBjb25zdCBjbGVhbk5hbWUgPSBwYXJhbU5hbWUucmVwbGFjZSgvXkAvLCAnJyk7XG4gICAgY3VycmVudFtwYXJhbU5hbWVdID0gdmFsdWU7XG4gICAgY3VycmVudFtgQCR7Y2xlYW5OYW1lfWBdID0gdmFsdWU7XG4gICAgY3VycmVudFtjbGVhbk5hbWVdID0gdmFsdWU7XG4gICAgdGhpcy51cGRhdGVEYXRhU291cmNlUGFyYW1ldGVycy5lbWl0KGN1cnJlbnQpO1xuICB9XG5cbiAgb25VcGRhdGVDb2woaW5kZXg6IG51bWJlciwgZmllbGQ6IHN0cmluZywgdmFsdWU6IHVua25vd24pOiB2b2lkIHtcbiAgICB0aGlzLnVwZGF0ZUNvbHVtbi5lbWl0KHsgaW5kZXgsIGZpZWxkLCB2YWx1ZSB9KTtcbiAgfVxuXG4gIHRvZ2dsZVJvd0NsaWNrQWN0aW9uKGVuYWJsZWQ6IGJvb2xlYW4pOiB2b2lkIHtcbiAgICBpZiAoZW5hYmxlZCkge1xuICAgICAgdGhpcy51cGRhdGVSb3dDbGlja0FjdGlvbi5lbWl0KHtcbiAgICAgICAgdHlwZTogJ29wZW4tZHJhd2VyJyxcbiAgICAgICAgZHJhd2VyVGl0bGU6ICdEZXRhaWxzJyxcbiAgICAgICAgZHJhd2VyV2lkdGg6ICc3NjBweCcsXG4gICAgICB9KTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy51cGRhdGVSb3dDbGlja0FjdGlvbi5lbWl0KHVuZGVmaW5lZCk7XG4gICAgfVxuICB9XG5cbiAgdXBkYXRlUm93QWN0aW9uRmllbGQoZmllbGQ6IGtleW9mIEdyaWRSb3dDbGlja0FjdGlvbiwgdmFsdWU6IHVua25vd24pOiB2b2lkIHtcbiAgICBjb25zdCBjdXJyZW50ID0gdGhpcy5yb3dDbGlja0FjdGlvbigpID8/IHsgdHlwZTogJ29wZW4tZHJhd2VyJyB9O1xuICAgIGNvbnN0IG5leHQgPSB7IC4uLmN1cnJlbnQsIFtmaWVsZF06IHZhbHVlIH07XG4gICAgdGhpcy51cGRhdGVSb3dDbGlja0FjdGlvbi5lbWl0KG5leHQpO1xuICB9XG5cbiAgYWRkUGFyYW1ldGVyTWFwcGluZygpOiB2b2lkIHtcbiAgICBjb25zdCBjdXJyZW50ID0gdGhpcy5yb3dDbGlja0FjdGlvbigpID8/IHsgdHlwZTogJ29wZW4tZHJhd2VyJyB9O1xuICAgIGNvbnN0IG1hcHBpbmcgPSB7IC4uLihjdXJyZW50LnBhcmFtZXRlck1hcHBpbmcgPz8ge30pIH07XG4gICAgbGV0IGlkeCA9IE9iamVjdC5rZXlzKG1hcHBpbmcpLmxlbmd0aCArIDE7XG4gICAgbGV0IGtleSA9IGBwYXJhbSR7aWR4fWA7XG4gICAgd2hpbGUgKGtleSBpbiBtYXBwaW5nKSB7XG4gICAgICBpZHgrKztcbiAgICAgIGtleSA9IGBwYXJhbSR7aWR4fWA7XG4gICAgfVxuICAgIG1hcHBpbmdba2V5XSA9ICdyb3cuaWQnO1xuICAgIHRoaXMudXBkYXRlUm93Q2xpY2tBY3Rpb24uZW1pdCh7IC4uLmN1cnJlbnQsIHBhcmFtZXRlck1hcHBpbmc6IG1hcHBpbmcgfSk7XG4gIH1cblxuICB1cGRhdGVNYXBwaW5nS2V5KGluZGV4OiBudW1iZXIsIG5ld0tleTogc3RyaW5nKTogdm9pZCB7XG4gICAgY29uc3QgcGFpcnMgPSB0aGlzLnBhcmFtZXRlck1hcHBpbmdzKCk7XG4gICAgaWYgKCFwYWlyc1tpbmRleF0pIHJldHVybjtcbiAgICBjb25zdCBuZXh0TWFwcGluZzogUmVjb3JkPHN0cmluZywgc3RyaW5nPiA9IHt9O1xuICAgIHBhaXJzLmZvckVhY2goKHAsIGkpID0+IHtcbiAgICAgIGNvbnN0IGsgPSBpID09PSBpbmRleCA/IG5ld0tleSA6IHAua2V5O1xuICAgICAgaWYgKGsudHJpbSgpKSB7XG4gICAgICAgIG5leHRNYXBwaW5nW2sudHJpbSgpXSA9IHAudmFsdWU7XG4gICAgICB9XG4gICAgfSk7XG4gICAgY29uc3QgY3VycmVudCA9IHRoaXMucm93Q2xpY2tBY3Rpb24oKSA/PyB7IHR5cGU6ICdvcGVuLWRyYXdlcicgfTtcbiAgICB0aGlzLnVwZGF0ZVJvd0NsaWNrQWN0aW9uLmVtaXQoeyAuLi5jdXJyZW50LCBwYXJhbWV0ZXJNYXBwaW5nOiBuZXh0TWFwcGluZyB9KTtcbiAgfVxuXG4gIHVwZGF0ZU1hcHBpbmdWYWx1ZShpbmRleDogbnVtYmVyLCBuZXdWYWx1ZTogc3RyaW5nKTogdm9pZCB7XG4gICAgY29uc3QgcGFpcnMgPSB0aGlzLnBhcmFtZXRlck1hcHBpbmdzKCk7XG4gICAgaWYgKCFwYWlyc1tpbmRleF0pIHJldHVybjtcbiAgICBjb25zdCBuZXh0TWFwcGluZzogUmVjb3JkPHN0cmluZywgc3RyaW5nPiA9IHt9O1xuICAgIHBhaXJzLmZvckVhY2goKHAsIGkpID0+IHtcbiAgICAgIGNvbnN0IHYgPSBpID09PSBpbmRleCA/IG5ld1ZhbHVlIDogcC52YWx1ZTtcbiAgICAgIGlmIChwLmtleS50cmltKCkpIHtcbiAgICAgICAgbmV4dE1hcHBpbmdbcC5rZXkudHJpbSgpXSA9IHY7XG4gICAgICB9XG4gICAgfSk7XG4gICAgY29uc3QgY3VycmVudCA9IHRoaXMucm93Q2xpY2tBY3Rpb24oKSA/PyB7IHR5cGU6ICdvcGVuLWRyYXdlcicgfTtcbiAgICB0aGlzLnVwZGF0ZVJvd0NsaWNrQWN0aW9uLmVtaXQoeyAuLi5jdXJyZW50LCBwYXJhbWV0ZXJNYXBwaW5nOiBuZXh0TWFwcGluZyB9KTtcbiAgfVxuXG4gIHJlbW92ZU1hcHBpbmcoaW5kZXg6IG51bWJlcik6IHZvaWQge1xuICAgIGNvbnN0IHBhaXJzID0gdGhpcy5wYXJhbWV0ZXJNYXBwaW5ncygpO1xuICAgIGNvbnN0IG5leHRNYXBwaW5nOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+ID0ge307XG4gICAgcGFpcnMuZm9yRWFjaCgocCwgaSkgPT4ge1xuICAgICAgaWYgKGkgIT09IGluZGV4ICYmIHAua2V5LnRyaW0oKSkge1xuICAgICAgICBuZXh0TWFwcGluZ1twLmtleS50cmltKCldID0gcC52YWx1ZTtcbiAgICAgIH1cbiAgICB9KTtcbiAgICBjb25zdCBjdXJyZW50ID0gdGhpcy5yb3dDbGlja0FjdGlvbigpID8/IHsgdHlwZTogJ29wZW4tZHJhd2VyJyB9O1xuICAgIHRoaXMudXBkYXRlUm93Q2xpY2tBY3Rpb24uZW1pdCh7IC4uLmN1cnJlbnQsIHBhcmFtZXRlck1hcHBpbmc6IG5leHRNYXBwaW5nIH0pO1xuICB9XG59XG4iLCIgICAgQGlmICghZ3JpZCgpKSB7XG4gICAgICA8ZGl2IGNsYXNzPVwiZW1wdHktZ3JpZC1jYXJkXCI+XG4gICAgICAgIDxkaXYgY2xhc3M9XCJlbXB0eS1ncmlkLWljb25cIj5cbiAgICAgICAgICA8cnB0LWljb24gbmFtZT1cInRhYmxlXCIgW3NpemVdPVwiMjhcIiAvPlxuICAgICAgICA8L2Rpdj5cbiAgICAgICAgPGg0IGNsYXNzPVwiZW1wdHktZ3JpZC10aXRsZVwiPk5vIFJlc3VsdCBHcmlkIEF0dGFjaGVkPC9oND5cbiAgICAgICAgPHAgY2xhc3M9XCJlbXB0eS1ncmlkLWRlc2NcIj5BdHRhY2ggYW4gaW50ZXJhY3RpdmUgUmVzdWx0IERhdGEgR3JpZCAob3IgVWx0cmFHcmlkKSB0byB0aGlzIHJlcG9ydCBkZWZpbml0aW9uIHRvIHJlbmRlciBxdWVyaWVzIGFuZCBzdG9yZWQgcHJvY2VkdXJlIHJlc3VsdHMuPC9wPlxuICAgICAgICA8YnV0dG9uIHR5cGU9XCJidXR0b25cIiBjbGFzcz1cImJ0bi1jcmVhdGUtZ3JpZC1hY3Rpb25cIiAoY2xpY2spPVwiYWRkR3JpZC5lbWl0KClcIj5cbiAgICAgICAgICA8cnB0LWljb24gbmFtZT1cInBsdXNcIiBbc2l6ZV09XCIxNFwiIC8+XG4gICAgICAgICAgPHNwYW4+KyBBZGQgUmVzdWx0IEdyaWQ8L3NwYW4+XG4gICAgICAgIDwvYnV0dG9uPlxuICAgICAgPC9kaXY+XG4gICAgfSBAZWxzZSB7XG4gICAgICA8ZGl2IGNsYXNzPVwicHJvcHMtZm9ybVwiPlxuICAgICAgPCEtLSAxLiBSZXBvcnQgRGF0YSBTb3VyY2UgJiBTdG9yZWQgUHJvY2VkdXJlIENvbmZpZ3VyYXRpb24gLS0+XG4gICAgICA8ZGl2IGNsYXNzPVwicHJvcGVydHktZ3JvdXBcIj5cbiAgICAgICAgPGRpdiBjbGFzcz1cImdyb3VwLWhlYWRlci1yb3dcIj5cbiAgICAgICAgICA8ZGl2IGNsYXNzPVwiZ3JvdXAtdGl0bGUtd3JhcFwiPlxuICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJncm91cC10aXRsZVwiPlJlcG9ydCBEYXRhIFNvdXJjZTwvc3Bhbj5cbiAgICAgICAgICAgIEBpZiAoYWN0aXZlRW50aXR5TmFtZSgpKSB7XG4gICAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwiZ3JvdXAtYmFkZ2UgYWN0aXZlLWRzLWJhZGdlXCI+e3sgYWN0aXZlRW50aXR5TmFtZSgpIH19PC9zcGFuPlxuICAgICAgICAgICAgfVxuICAgICAgICAgIDwvZGl2PlxuICAgICAgICA8L2Rpdj5cblxuICAgICAgICA8IS0tIFNvdXJjZSBUeXBlIFN3aXRjaGVyIChTdG9yZWQgUHJvY2VkdXJlIHZzIFRhYmxlIHZzIFJFU1QgQVBJKSAtLT5cbiAgICAgICAgPGRpdiBjbGFzcz1cInNvdXJjZS10eXBlLXN3aXRjaGVyXCI+XG4gICAgICAgICAgPGJ1dHRvblxuICAgICAgICAgICAgdHlwZT1cImJ1dHRvblwiXG4gICAgICAgICAgICBjbGFzcz1cInNvdXJjZS10YWItYnRuXCJcbiAgICAgICAgICAgIFtjbGFzcy5hY3RpdmVdPVwiY3VycmVudFNvdXJjZVR5cGUoKSA9PT0gJ3N0b3JlZF9wcm9jZWR1cmUnXCJcbiAgICAgICAgICAgIChjbGljayk9XCJvblNvdXJjZVR5cGVDaGFuZ2UoJ3N0b3JlZF9wcm9jZWR1cmUnKVwiXG4gICAgICAgICAgPlxuICAgICAgICAgICAgPHJwdC1pY29uIG5hbWU9XCJjb2RlXCIgW3NpemVdPVwiMTJcIiAvPlxuICAgICAgICAgICAgPHNwYW4+U3RvcmVkIFByb2NlZHVyZTwvc3Bhbj5cbiAgICAgICAgICA8L2J1dHRvbj5cbiAgICAgICAgICA8YnV0dG9uXG4gICAgICAgICAgICB0eXBlPVwiYnV0dG9uXCJcbiAgICAgICAgICAgIGNsYXNzPVwic291cmNlLXRhYi1idG5cIlxuICAgICAgICAgICAgW2NsYXNzLmFjdGl2ZV09XCJjdXJyZW50U291cmNlVHlwZSgpID09PSAndGFibGUnXCJcbiAgICAgICAgICAgIChjbGljayk9XCJvblNvdXJjZVR5cGVDaGFuZ2UoJ3RhYmxlJylcIlxuICAgICAgICAgID5cbiAgICAgICAgICAgIDxycHQtaWNvbiBuYW1lPVwidGFibGVcIiBbc2l6ZV09XCIxMlwiIC8+XG4gICAgICAgICAgICA8c3Bhbj5UYWJsZSAvIFZpZXc8L3NwYW4+XG4gICAgICAgICAgPC9idXR0b24+XG4gICAgICAgICAgPGJ1dHRvblxuICAgICAgICAgICAgdHlwZT1cImJ1dHRvblwiXG4gICAgICAgICAgICBjbGFzcz1cInNvdXJjZS10YWItYnRuXCJcbiAgICAgICAgICAgIFtjbGFzcy5hY3RpdmVdPVwiY3VycmVudFNvdXJjZVR5cGUoKSA9PT0gJ2FwaSdcIlxuICAgICAgICAgICAgKGNsaWNrKT1cIm9uU291cmNlVHlwZUNoYW5nZSgnYXBpJylcIlxuICAgICAgICAgID5cbiAgICAgICAgICAgIDxycHQtaWNvbiBuYW1lPVwiZ2xvYmVcIiBbc2l6ZV09XCIxMlwiIC8+XG4gICAgICAgICAgICA8c3Bhbj5SRVNUIEFQSTwvc3Bhbj5cbiAgICAgICAgICA8L2J1dHRvbj5cbiAgICAgICAgPC9kaXY+XG5cbiAgICAgICAgQGlmIChjdXJyZW50U291cmNlVHlwZSgpID09PSAnYXBpJykge1xuICAgICAgICAgIDwhLS0gQVBJIEVuZHBvaW50IFNlbGVjdG9yIC8gSW5wdXQgLS0+XG4gICAgICAgICAgPGRpdiBjbGFzcz1cImZpZWxkLXJvd1wiPlxuICAgICAgICAgICAgPGxhYmVsIGNsYXNzPVwiZmllbGQtbGFiZWxcIj5BUEkgRW5kcG9pbnQgVVJMPC9sYWJlbD5cbiAgICAgICAgICAgIEBpZiAocmVnaXN0ZXJlZEFwaXMoKS5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICAgIDxkaXYgc3R5bGU9XCJtYXJnaW4tYm90dG9tOiA2cHg7XCI+XG4gICAgICAgICAgICAgICAgPHJwdC1zZWFyY2hhYmxlLXNlbGVjdFxuICAgICAgICAgICAgICAgICAgW29wdGlvbnNdPVwicmVnaXN0ZXJlZEFwaXMoKVwiXG4gICAgICAgICAgICAgICAgICBbbmdNb2RlbF09XCJhcGlFbmRwb2ludCgpXCJcbiAgICAgICAgICAgICAgICAgIChuZ01vZGVsQ2hhbmdlKT1cIm9uQXBpRW5kcG9pbnRDaGFuZ2UoJGV2ZW50KVwiXG4gICAgICAgICAgICAgICAgICBwbGFjZWhvbGRlcj1cIi0tIFNlbGVjdCBSZWdpc3RlcmVkIEVuZHBvaW50IG9yIHR5cGUgYmVsb3cgLS1cIlxuICAgICAgICAgICAgICAgICAgc2VhcmNoUGxhY2Vob2xkZXI9XCJTZWFyY2ggcmVnaXN0ZXJlZCBBUElzLi4uXCJcbiAgICAgICAgICAgICAgICAvPlxuICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIDxpbnB1dFxuICAgICAgICAgICAgICB0eXBlPVwidGV4dFwiXG4gICAgICAgICAgICAgIGNsYXNzPVwiZm9ybS1jb250cm9sXCJcbiAgICAgICAgICAgICAgcGxhY2Vob2xkZXI9XCJlLmcuIC9hcGkvdjEvb3JkZXJzIG9yIGh0dHBzOi8vYXBpLnNlcnZpY2UuY29tL2RhdGFcIlxuICAgICAgICAgICAgICBbbmdNb2RlbF09XCJhcGlFbmRwb2ludCgpXCJcbiAgICAgICAgICAgICAgKG5nTW9kZWxDaGFuZ2UpPVwib25BcGlFbmRwb2ludENoYW5nZSgkZXZlbnQpXCJcbiAgICAgICAgICAgIC8+XG4gICAgICAgICAgICA8c3BhbiBjbGFzcz1cImZpZWxkLWhpbnRcIiBzdHlsZT1cImZvbnQtc2l6ZTogMTFweDsgY29sb3I6IHZhcigtLXJwdC1jb2xvci10ZXh0LW11dGVkLCAjNjQ3NDhiKTsgbWFyZ2luLXRvcDogNHB4OyBkaXNwbGF5OiBibG9jaztcIj5cbiAgICAgICAgICAgICAgRGlyZWN0IEhUVFAgY2FsbCBvciBiYWNrZW5kIHByb3h5LiBVc2UgPGNvZGU+OnBhcmFtPC9jb2RlPiBmb3Igcm91dGUgdG9rZW5zLlxuICAgICAgICAgICAgPC9zcGFuPlxuICAgICAgICAgIDwvZGl2PlxuXG4gICAgICAgICAgPCEtLSBIVFRQIE1ldGhvZCAmIERhdGEgUGF0aCBHcmlkIC0tPlxuICAgICAgICAgIDxkaXYgY2xhc3M9XCJmaWVsZC1ncmlkLTJcIiBzdHlsZT1cImRpc3BsYXk6IGdyaWQ7IGdyaWQtdGVtcGxhdGUtY29sdW1uczogMWZyIDFmcjsgZ2FwOiA4cHg7XCI+XG4gICAgICAgICAgICA8ZGl2IGNsYXNzPVwiZmllbGQtcm93XCI+XG4gICAgICAgICAgICAgIDxsYWJlbCBjbGFzcz1cImZpZWxkLWxhYmVsXCI+SFRUUCBNZXRob2Q8L2xhYmVsPlxuICAgICAgICAgICAgICA8c2VsZWN0XG4gICAgICAgICAgICAgICAgY2xhc3M9XCJmb3JtLWNvbnRyb2xcIlxuICAgICAgICAgICAgICAgIFtuZ01vZGVsXT1cImFwaU1ldGhvZCgpXCJcbiAgICAgICAgICAgICAgICAobmdNb2RlbENoYW5nZSk9XCJvbkFwaU1ldGhvZENoYW5nZSgkZXZlbnQpXCJcbiAgICAgICAgICAgICAgPlxuICAgICAgICAgICAgICAgIDxvcHRpb24gdmFsdWU9XCJHRVRcIj5HRVQgKFF1ZXJ5IFN0cmluZyk8L29wdGlvbj5cbiAgICAgICAgICAgICAgICA8b3B0aW9uIHZhbHVlPVwiUE9TVFwiPlBPU1QgKEJvZHkgUGF5bG9hZCk8L29wdGlvbj5cbiAgICAgICAgICAgICAgPC9zZWxlY3Q+XG4gICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJmaWVsZC1yb3dcIj5cbiAgICAgICAgICAgICAgPGxhYmVsIGNsYXNzPVwiZmllbGQtbGFiZWxcIj5SZXNwb25zZSBEYXRhIFBhdGg8L2xhYmVsPlxuICAgICAgICAgICAgICA8aW5wdXRcbiAgICAgICAgICAgICAgICB0eXBlPVwidGV4dFwiXG4gICAgICAgICAgICAgICAgY2xhc3M9XCJmb3JtLWNvbnRyb2xcIlxuICAgICAgICAgICAgICAgIHBsYWNlaG9sZGVyPVwiZS5nLiBkYXRhLml0ZW1zLCByb3dzXCJcbiAgICAgICAgICAgICAgICBbbmdNb2RlbF09XCJhcGlEYXRhUGF0aCgpXCJcbiAgICAgICAgICAgICAgICAobmdNb2RlbENoYW5nZSk9XCJvbkFwaURhdGFQYXRoQ2hhbmdlKCRldmVudClcIlxuICAgICAgICAgICAgICAvPlxuICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgPC9kaXY+XG5cbiAgICAgICAgICA8IS0tIFVzZSBQcm94eSBUb2dnbGUgLS0+XG4gICAgICAgICAgPGRpdiBjbGFzcz1cImZpZWxkLXJvdyBjaGVja2JveC1maWVsZC1yb3dcIiBzdHlsZT1cIm1hcmdpbi10b3A6IDRweDtcIj5cbiAgICAgICAgICAgIDxsYWJlbCBjbGFzcz1cImNoZWNrYm94LWxhYmVsXCIgc3R5bGU9XCJkaXNwbGF5OiBmbGV4OyBhbGlnbi1pdGVtczogY2VudGVyOyBnYXA6IDZweDsgZm9udC1zaXplOiAxMnB4OyBjdXJzb3I6IHBvaW50ZXI7XCI+XG4gICAgICAgICAgICAgIDxpbnB1dFxuICAgICAgICAgICAgICAgIHR5cGU9XCJjaGVja2JveFwiXG4gICAgICAgICAgICAgICAgW2NoZWNrZWRdPVwiYXBpVXNlUHJveHkoKVwiXG4gICAgICAgICAgICAgICAgKGNoYW5nZSk9XCJvbkFwaVVzZVByb3h5Q2hhbmdlKCRhbnkoJGV2ZW50LnRhcmdldCkuY2hlY2tlZClcIlxuICAgICAgICAgICAgICAvPlxuICAgICAgICAgICAgICA8c3BhbiBjbGFzcz1cImNoZWNrYm94LXRleHRcIj5Sb3V0ZSB0aHJvdWdoIGJhY2tlbmQgcHJveHkgKGJ5cGFzc2VzIENPUlMgLyBoaWRlcyBjcmVkZW50aWFscyk8L3NwYW4+XG4gICAgICAgICAgICA8L2xhYmVsPlxuICAgICAgICAgIDwvZGl2PlxuICAgICAgICB9IEBlbHNlIHtcbiAgICAgICAgICA8IS0tIEVudGl0eSBTZWxlY3RvciBEcm9wZG93biAtLT5cbiAgICAgICAgICA8ZGl2IGNsYXNzPVwiZmllbGQtcm93XCI+XG4gICAgICAgICAgICA8bGFiZWwgY2xhc3M9XCJmaWVsZC1sYWJlbFwiPlxuICAgICAgICAgICAgICB7eyBjdXJyZW50U291cmNlVHlwZSgpID09PSAnc3RvcmVkX3Byb2NlZHVyZScgPyAnU3RvcmVkIFByb2NlZHVyZScgOiAnVGFibGUgLyBWaWV3JyB9fVxuICAgICAgICAgICAgPC9sYWJlbD5cbiAgICAgICAgICAgIDxycHQtc2VhcmNoYWJsZS1zZWxlY3RcbiAgICAgICAgICAgICAgW29wdGlvbnNdPVwiZ3JpZEVudGl0eVNlbGVjdE9wdGlvbnMoKVwiXG4gICAgICAgICAgICAgIFtuZ01vZGVsXT1cImFjdGl2ZUVudGl0eU5hbWUoKVwiXG4gICAgICAgICAgICAgIChuZ01vZGVsQ2hhbmdlKT1cIm9uU2VsZWN0RW50aXR5KCRldmVudClcIlxuICAgICAgICAgICAgICBwbGFjZWhvbGRlcj1cIi0tIENob29zZSBEYXRhIFNvdXJjZSAtLVwiXG4gICAgICAgICAgICAgIFtzZWFyY2hQbGFjZWhvbGRlcl09XCJjdXJyZW50U291cmNlVHlwZSgpID09PSAnc3RvcmVkX3Byb2NlZHVyZScgPyAnU2VhcmNoIHByb2NlZHVyZXMuLi4nIDogJ1NlYXJjaCB0YWJsZXMgJiB2aWV3cy4uLidcIlxuICAgICAgICAgICAgLz5cbiAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgfVxuXG4gICAgICAgIDwhLS0gU3RvcmVkIFByb2NlZHVyZSBQYXJhbWV0ZXIgTWFwcGluZ3MgLS0+XG4gICAgICAgIEBpZiAoY3VycmVudFNvdXJjZVR5cGUoKSA9PT0gJ3N0b3JlZF9wcm9jZWR1cmUnICYmIGFjdGl2ZUVudGl0eU5hbWUoKSkge1xuICAgICAgICAgIDxkaXYgY2xhc3M9XCJwcm9jZWR1cmUtcGFyYW1zLXNlY3Rpb25cIj5cbiAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJwYXJhbXMtc2VjdGlvbi1oZWFkZXJcIj5cbiAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cInBhcmFtcy1oZWFkZXItbGVmdFwiPlxuICAgICAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwicGFyYW1zLXRpdGxlXCI+UHJvY2VkdXJlIFBhcmFtZXRlcnM8L3NwYW4+XG4gICAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJwYXJhbXMtY291bnQtYmFkZ2VcIj57eyBlZmZlY3RpdmVQYXJhbWV0ZXJzKCkubGVuZ3RoIH19PC9zcGFuPlxuICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgICAgPGJ1dHRvblxuICAgICAgICAgICAgICAgIHR5cGU9XCJidXR0b25cIlxuICAgICAgICAgICAgICAgIGNsYXNzPVwiYnRuLXBhc3RlLWV4ZWNcIlxuICAgICAgICAgICAgICAgIChjbGljayk9XCJ0b2dnbGVFeGVjU25pcHBldCgpXCJcbiAgICAgICAgICAgICAgICB0aXRsZT1cIlBhc3RlIGZ1bGwgU1NNUyAnRVhFQyBwcm9jIEBwYXJhbT12YWwnIHNuaXBwZXQgdG8gZmlsbCBwYXJhbWV0ZXJzIGF1dG9tYXRpY2FsbHlcIlxuICAgICAgICAgICAgICA+XG4gICAgICAgICAgICAgICAgPHJwdC1pY29uIG5hbWU9XCJjb2RlXCIgW3NpemVdPVwiMTJcIiAvPlxuICAgICAgICAgICAgICAgIDxzcGFuPnt7IGlzRXhlY1NuaXBwZXRPcGVuKCkgPyAnQ2xvc2UgU1FMJyA6ICdQYXN0ZSBTUUwgRXhlYycgfX08L3NwYW4+XG4gICAgICAgICAgICAgIDwvYnV0dG9uPlxuICAgICAgICAgICAgPC9kaXY+XG5cbiAgICAgICAgICAgIEBpZiAoaXNFeGVjU25pcHBldE9wZW4oKSkge1xuICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwiZXhlYy1zbmlwcGV0LXBhbmVsXCI+XG4gICAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cImV4ZWMtc25pcHBldC1oZWFkZXJcIj5cbiAgICAgICAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwic25pcHBldC1oaW50XCI+UGFzdGUgZnVsbCA8Y29kZT5FWEVDIFByb2NlZHVyZU5hbWUgJiM2NDtwYXJhbT12YWwuLi48L2NvZGU+IHN0YXRlbWVudCBmcm9tIFNTTVM6PC9zcGFuPlxuICAgICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgICAgIDx0ZXh0YXJlYVxuICAgICAgICAgICAgICAgICAgY2xhc3M9XCJleGVjLXNuaXBwZXQtdGV4dGFyZWFcIlxuICAgICAgICAgICAgICAgICAgcm93cz1cIjNcIlxuICAgICAgICAgICAgICAgICAgcGxhY2Vob2xkZXI9XCJlLmcuIGV4ZWMgR2V0X0hlbHBMaXN0IEBjaHJDT01QQU5ZSUQ9TicxMDEnLEBjaHJUYWJsZU5hbWU9TidNU1RBQ0NUR0xTVUInLi4uXCJcbiAgICAgICAgICAgICAgICAgIFtuZ01vZGVsXT1cImV4ZWNTbmlwcGV0VGV4dCgpXCJcbiAgICAgICAgICAgICAgICAgIChuZ01vZGVsQ2hhbmdlKT1cImV4ZWNTbmlwcGV0VGV4dC5zZXQoJGV2ZW50KVwiXG4gICAgICAgICAgICAgICAgPjwvdGV4dGFyZWE+XG4gICAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cImV4ZWMtc25pcHBldC1hY3Rpb25zXCI+XG4gICAgICAgICAgICAgICAgICA8YnV0dG9uIHR5cGU9XCJidXR0b25cIiBjbGFzcz1cImJ0bi1zbmlwcGV0LWFwcGx5XCIgKGNsaWNrKT1cImFwcGx5RXhlY1NuaXBwZXQoKVwiPlxuICAgICAgICAgICAgICAgICAgICA8cnB0LWljb24gbmFtZT1cImNoZWNrXCIgW3NpemVdPVwiMTJcIiAvPlxuICAgICAgICAgICAgICAgICAgICA8c3Bhbj5BcHBseSBQYXJhbWV0ZXJzPC9zcGFuPlxuICAgICAgICAgICAgICAgICAgPC9idXR0b24+XG4gICAgICAgICAgICAgICAgICA8YnV0dG9uIHR5cGU9XCJidXR0b25cIiBjbGFzcz1cImJ0bi1zbmlwcGV0LWNhbmNlbFwiIChjbGljayk9XCJ0b2dnbGVFeGVjU25pcHBldCgpXCI+XG4gICAgICAgICAgICAgICAgICAgIENhbmNlbFxuICAgICAgICAgICAgICAgICAgPC9idXR0b24+XG4gICAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICAgICAgQGlmIChleGVjUGFyc2VTdGF0dXMoKSkge1xuICAgICAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cInNuaXBwZXQtc3RhdHVzXCIgW2NsYXNzLmlzLWVycm9yXT1cImV4ZWNQYXJzZVN0YXR1cygpPy5raW5kID09PSAnZXJyb3InXCIgW2NsYXNzLmlzLXN1Y2Nlc3NdPVwiZXhlY1BhcnNlU3RhdHVzKCk/LmtpbmQgPT09ICdzdWNjZXNzJ1wiPlxuICAgICAgICAgICAgICAgICAgICB7eyBleGVjUGFyc2VTdGF0dXMoKT8ubWVzc2FnZSB9fVxuICAgICAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgQGlmIChlZmZlY3RpdmVQYXJhbWV0ZXJzKCkubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwicGFyYW0tY2FyZHMtbGlzdFwiPlxuICAgICAgICAgICAgICAgIEBmb3IgKHBhcmFtIG9mIGVmZmVjdGl2ZVBhcmFtZXRlcnMoKTsgdHJhY2sgcGFyYW0ubmFtZSkge1xuICAgICAgICAgICAgICAgICAgPHJwdC1wYXJhbWV0ZXItYmluZGluZy1lZGl0b3JcbiAgICAgICAgICAgICAgICAgICAgW3BhcmFtXT1cInBhcmFtXCJcbiAgICAgICAgICAgICAgICAgICAgW2N1cnJlbnRWYWx1ZV09XCJnZXRQYXJhbWV0ZXJWYWx1ZShwYXJhbS5uYW1lKVwiXG4gICAgICAgICAgICAgICAgICAgIFthbGxDb21wb25lbnRzXT1cImFsbENvbXBvbmVudHMoKVwiXG4gICAgICAgICAgICAgICAgICAgICh2YWx1ZUNoYW5nZSk9XCJvblBhcmFtZXRlckNoYW5nZShwYXJhbS5uYW1lLCAkZXZlbnQpXCJcbiAgICAgICAgICAgICAgICAgIC8+XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgIH0gQGVsc2Uge1xuICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwiZW1wdHktcGFyYW1zLWhpbnRcIj5cbiAgICAgICAgICAgICAgICA8c3Bhbj5ObyByZXF1aXJlZCBwYXJhbWV0ZXJzIGZvciB0aGlzIHByb2NlZHVyZS48L3NwYW4+XG4gICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgfVxuICAgICAgICAgIDwvZGl2PlxuICAgICAgICB9XG4gICAgICA8L2Rpdj5cblxuICAgICAgPCEtLSAyLiBSZXN1bHQgQ29sdW1ucyBDb25maWd1cmF0aW9uIC0tPlxuICAgICAgPGRpdiBjbGFzcz1cInByb3BlcnR5LWdyb3VwXCI+XG4gICAgICAgIDxkaXYgY2xhc3M9XCJncm91cC1oZWFkZXItcm93XCI+XG4gICAgICAgICAgPGRpdiBjbGFzcz1cImdyb3VwLXRpdGxlLXdyYXBcIj5cbiAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwiZ3JvdXAtdGl0bGVcIj5Db2x1bW5zPC9zcGFuPlxuICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJncm91cC1iYWRnZVwiPnt7IGNvbHVtbnMoKS5sZW5ndGggfX08L3NwYW4+XG4gICAgICAgICAgPC9kaXY+XG4gICAgICAgIDwvZGl2PlxuXG4gICAgICAgIDwhLS0gRGVkaWNhdGVkIEZ1bGwtV2lkdGggQWN0aW9uIEJ1dHRvbnMgKE5vIGNyYW1waW5nKSAtLT5cbiAgICAgICAgPGRpdiBjbGFzcz1cImNvbHVtbnMtYWN0aW9uLWJhclwiPlxuICAgICAgICAgIDxidXR0b25cbiAgICAgICAgICAgIHR5cGU9XCJidXR0b25cIlxuICAgICAgICAgICAgY2xhc3M9XCJidG4tY29sLWFjdGlvbiBidG4tYXV0by1kZXRlY3RcIlxuICAgICAgICAgICAgKGNsaWNrKT1cImF1dG9EZXRlY3RDb2x1bW5zLmVtaXQoKVwiXG4gICAgICAgICAgICBbZGlzYWJsZWRdPVwiaXNEZXRlY3RpbmcoKVwiXG4gICAgICAgICAgICB0aXRsZT1cIkF1dG8tZGV0ZWN0IGFsbCBjb2x1bW5zIGZyb20gcHJvY2VkdXJlIG9yIGRhdGEgdGFibGVcIlxuICAgICAgICAgID5cbiAgICAgICAgICAgIDxycHQtaWNvbiBuYW1lPVwicmVmcmVzaFwiIFtzaXplXT1cIjEyXCIgW2NsYXNzLnJwdC1zcGluXT1cImlzRGV0ZWN0aW5nKClcIiAvPlxuICAgICAgICAgICAgPHNwYW4+e3sgaXNEZXRlY3RpbmcoKSA/ICdEZXRlY3RpbmcuLi4nIDogJ0F1dG8tRGV0ZWN0JyB9fTwvc3Bhbj5cbiAgICAgICAgICA8L2J1dHRvbj5cbiAgICAgICAgICA8YnV0dG9uXG4gICAgICAgICAgICB0eXBlPVwiYnV0dG9uXCJcbiAgICAgICAgICAgIGNsYXNzPVwiYnRuLWNvbC1hY3Rpb24gYnRuLWFkZC1jb2xcIlxuICAgICAgICAgICAgKGNsaWNrKT1cImFkZENvbHVtbi5lbWl0KClcIlxuICAgICAgICAgICAgdGl0bGU9XCJBZGQgYSBuZXcgY29sdW1uIG1hbnVhbGx5XCJcbiAgICAgICAgICA+XG4gICAgICAgICAgICA8cnB0LWljb24gbmFtZT1cInBsdXNcIiBbc2l6ZV09XCIxMlwiIC8+XG4gICAgICAgICAgICA8c3Bhbj4rIEFkZCBDb2x1bW48L3NwYW4+XG4gICAgICAgICAgPC9idXR0b24+XG4gICAgICAgIDwvZGl2PlxuXG4gICAgICAgIEBpZiAoc3RhdHVzTWVzc2FnZSgpKSB7XG4gICAgICAgICAgPGRpdiBjbGFzcz1cImNvbC1zdGF0dXMtYmFubmVyXCIgW2NsYXNzLmlzLWVycm9yXT1cInN0YXR1c0tpbmQoKSA9PT0gJ2Vycm9yJ1wiIFtjbGFzcy5pcy1zdWNjZXNzXT1cInN0YXR1c0tpbmQoKSA9PT0gJ3N1Y2Nlc3MnXCI+XG4gICAgICAgICAgICA8cnB0LWljb24gW25hbWVdPVwic3RhdHVzS2luZCgpID09PSAnZXJyb3InID8gJ2Nsb3NlJyA6ICdjaGVjaydcIiBbc2l6ZV09XCIxMlwiIC8+XG4gICAgICAgICAgICA8c3Bhbj57eyBzdGF0dXNNZXNzYWdlKCkgfX08L3NwYW4+XG4gICAgICAgICAgPC9kaXY+XG4gICAgICAgIH1cblxuICAgICAgICA8ZGl2IGNsYXNzPVwiY29sdW1ucy1lZGl0b3ItbGlzdFwiPlxuICAgICAgICAgIEBmb3IgKGNvbCBvZiBjb2x1bW5zKCk7IHRyYWNrIGNvbC5maWVsZDsgbGV0IGlkeCA9ICRpbmRleCkge1xuICAgICAgICAgICAgPGRpdiBjbGFzcz1cImNvbC1lZGl0LWNhcmRcIj5cbiAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cImNvbC1jYXJkLWhlYWRlclwiPlxuICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJjb2wtaGVhZGVyLXRpdGxlLWdyb3VwXCI+XG4gICAgICAgICAgICAgICAgICA8c3BhbiBjbGFzcz1cImNvbC1kcmFnLWRvdHNcIj7ii67ii648L3NwYW4+XG4gICAgICAgICAgICAgICAgICA8c3BhbiBjbGFzcz1cImNvbC1pZHgtYmFkZ2VcIj4je3sgaWR4ICsgMSB9fTwvc3Bhbj5cbiAgICAgICAgICAgICAgICAgIDxpbnB1dFxuICAgICAgICAgICAgICAgICAgICB0eXBlPVwidGV4dFwiXG4gICAgICAgICAgICAgICAgICAgIGNsYXNzPVwiY29sLXRpdGxlLWlucHV0XCJcbiAgICAgICAgICAgICAgICAgICAgcGxhY2Vob2xkZXI9XCJDb2x1bW4gTGFiZWxcIlxuICAgICAgICAgICAgICAgICAgICBbbmdNb2RlbF09XCJjb2wubGFiZWxcIlxuICAgICAgICAgICAgICAgICAgICAobmdNb2RlbENoYW5nZSk9XCJvblVwZGF0ZUNvbChpZHgsICdsYWJlbCcsICRldmVudClcIlxuICAgICAgICAgICAgICAgICAgLz5cbiAgICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwiY29sLWNhcmQtYWN0aW9uc1wiPlxuICAgICAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJjb2wtdHlwZS1waWxsXCI+e3sgY29sLmRhdGFUeXBlIHx8ICdzdHJpbmcnIH19PC9zcGFuPlxuICAgICAgICAgICAgICAgICAgPGJ1dHRvblxuICAgICAgICAgICAgICAgICAgICB0eXBlPVwiYnV0dG9uXCJcbiAgICAgICAgICAgICAgICAgICAgY2xhc3M9XCJjb2wtYWN0aW9uLWJ0biBidG4tZGVsZXRlXCJcbiAgICAgICAgICAgICAgICAgICAgKGNsaWNrKT1cInJlbW92ZUNvbHVtbi5lbWl0KGlkeClcIlxuICAgICAgICAgICAgICAgICAgICB0aXRsZT1cIlJlbW92ZSBDb2x1bW5cIlxuICAgICAgICAgICAgICAgICAgPlxuICAgICAgICAgICAgICAgICAgICA8cnB0LWljb24gbmFtZT1cInRyYXNoXCIgW3NpemVdPVwiMTJcIiAvPlxuICAgICAgICAgICAgICAgICAgPC9idXR0b24+XG4gICAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICAgIDwvZGl2PlxuXG4gICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJjb2wtY2FyZC1ib2R5XCI+XG4gICAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cImNvbC1lZGl0LWZpZWxkc1wiPlxuICAgICAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cImNvbC1maWVsZC1pdGVtXCI+XG4gICAgICAgICAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwibWluaS1sYWJlbFwiPkZpZWxkPC9zcGFuPlxuICAgICAgICAgICAgICAgICAgICA8aW5wdXRcbiAgICAgICAgICAgICAgICAgICAgICB0eXBlPVwidGV4dFwiXG4gICAgICAgICAgICAgICAgICAgICAgY2xhc3M9XCJjb2wtbWluaS1pbnB1dFwiXG4gICAgICAgICAgICAgICAgICAgICAgcGxhY2Vob2xkZXI9XCJmaWVsZFwiXG4gICAgICAgICAgICAgICAgICAgICAgW25nTW9kZWxdPVwiY29sLmZpZWxkXCJcbiAgICAgICAgICAgICAgICAgICAgICAobmdNb2RlbENoYW5nZSk9XCJvblVwZGF0ZUNvbChpZHgsICdmaWVsZCcsICRldmVudClcIlxuICAgICAgICAgICAgICAgICAgICAvPlxuICAgICAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwiY29sLWZpZWxkLWl0ZW1cIj5cbiAgICAgICAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJtaW5pLWxhYmVsXCI+VHlwZTwvc3Bhbj5cbiAgICAgICAgICAgICAgICAgICAgPHNlbGVjdFxuICAgICAgICAgICAgICAgICAgICAgIGNsYXNzPVwiY29sLW1pbmktc2VsZWN0XCJcbiAgICAgICAgICAgICAgICAgICAgICBbbmdNb2RlbF09XCJjb2wuZGF0YVR5cGUgfHwgJ3N0cmluZydcIlxuICAgICAgICAgICAgICAgICAgICAgIChuZ01vZGVsQ2hhbmdlKT1cIm9uVXBkYXRlQ29sKGlkeCwgJ2RhdGFUeXBlJywgJGV2ZW50KVwiXG4gICAgICAgICAgICAgICAgICAgID5cbiAgICAgICAgICAgICAgICAgICAgICA8b3B0aW9uIHZhbHVlPVwic3RyaW5nXCI+U3RyaW5nPC9vcHRpb24+XG4gICAgICAgICAgICAgICAgICAgICAgPG9wdGlvbiB2YWx1ZT1cIm51bWJlclwiPk51bWJlcjwvb3B0aW9uPlxuICAgICAgICAgICAgICAgICAgICAgIDxvcHRpb24gdmFsdWU9XCJjdXJyZW5jeVwiPkN1cnJlbmN5PC9vcHRpb24+XG4gICAgICAgICAgICAgICAgICAgICAgPG9wdGlvbiB2YWx1ZT1cImRhdGVcIj5EYXRlPC9vcHRpb24+XG4gICAgICAgICAgICAgICAgICAgICAgPG9wdGlvbiB2YWx1ZT1cImJvb2xlYW5cIj5Cb29sZWFuPC9vcHRpb24+XG4gICAgICAgICAgICAgICAgICAgIDwvc2VsZWN0PlxuICAgICAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwiY29sLWZpZWxkLWl0ZW1cIj5cbiAgICAgICAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJtaW5pLWxhYmVsXCI+Rm9ybWF0PC9zcGFuPlxuICAgICAgICAgICAgICAgICAgICA8aW5wdXRcbiAgICAgICAgICAgICAgICAgICAgICB0eXBlPVwidGV4dFwiXG4gICAgICAgICAgICAgICAgICAgICAgY2xhc3M9XCJjb2wtbWluaS1pbnB1dFwiXG4gICAgICAgICAgICAgICAgICAgICAgcGxhY2Vob2xkZXI9XCJlLmcuIGRkL01NL3l5eXlcIlxuICAgICAgICAgICAgICAgICAgICAgIFtuZ01vZGVsXT1cImNvbC5mb3JtYXRcIlxuICAgICAgICAgICAgICAgICAgICAgIChuZ01vZGVsQ2hhbmdlKT1cIm9uVXBkYXRlQ29sKGlkeCwgJ2Zvcm1hdCcsICRldmVudClcIlxuICAgICAgICAgICAgICAgICAgICAvPlxuICAgICAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwiY29sLWZpZWxkLWl0ZW1cIj5cbiAgICAgICAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJtaW5pLWxhYmVsXCI+QWxpZ248L3NwYW4+XG4gICAgICAgICAgICAgICAgICAgIDxzZWxlY3RcbiAgICAgICAgICAgICAgICAgICAgICBjbGFzcz1cImNvbC1taW5pLXNlbGVjdFwiXG4gICAgICAgICAgICAgICAgICAgICAgW25nTW9kZWxdPVwiY29sLmFsaWduIHx8ICdsZWZ0J1wiXG4gICAgICAgICAgICAgICAgICAgICAgKG5nTW9kZWxDaGFuZ2UpPVwib25VcGRhdGVDb2woaWR4LCAnYWxpZ24nLCAkZXZlbnQpXCJcbiAgICAgICAgICAgICAgICAgICAgPlxuICAgICAgICAgICAgICAgICAgICAgIDxvcHRpb24gdmFsdWU9XCJsZWZ0XCI+TGVmdDwvb3B0aW9uPlxuICAgICAgICAgICAgICAgICAgICAgIDxvcHRpb24gdmFsdWU9XCJjZW50ZXJcIj5DZW50ZXI8L29wdGlvbj5cbiAgICAgICAgICAgICAgICAgICAgICA8b3B0aW9uIHZhbHVlPVwicmlnaHRcIj5SaWdodDwvb3B0aW9uPlxuICAgICAgICAgICAgICAgICAgICA8L3NlbGVjdD5cbiAgICAgICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cImNvbC1maWVsZC1pdGVtXCI+XG4gICAgICAgICAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwibWluaS1sYWJlbFwiPkFnZ3JlZ2F0ZTwvc3Bhbj5cbiAgICAgICAgICAgICAgICAgICAgPHNlbGVjdFxuICAgICAgICAgICAgICAgICAgICAgIGNsYXNzPVwiY29sLW1pbmktc2VsZWN0XCJcbiAgICAgICAgICAgICAgICAgICAgICBbbmdNb2RlbF09XCJjb2wuYWdncmVnYXRlIHx8ICdub25lJ1wiXG4gICAgICAgICAgICAgICAgICAgICAgKG5nTW9kZWxDaGFuZ2UpPVwib25VcGRhdGVDb2woaWR4LCAnYWdncmVnYXRlJywgJGV2ZW50ID09PSAnbm9uZScgPyB1bmRlZmluZWQgOiAkZXZlbnQpXCJcbiAgICAgICAgICAgICAgICAgICAgPlxuICAgICAgICAgICAgICAgICAgICAgIDxvcHRpb24gdmFsdWU9XCJub25lXCI+Tm9uZTwvb3B0aW9uPlxuICAgICAgICAgICAgICAgICAgICAgIDxvcHRpb24gdmFsdWU9XCJzdW1cIj5TdW08L29wdGlvbj5cbiAgICAgICAgICAgICAgICAgICAgICA8b3B0aW9uIHZhbHVlPVwiYXZnXCI+QXZlcmFnZTwvb3B0aW9uPlxuICAgICAgICAgICAgICAgICAgICAgIDxvcHRpb24gdmFsdWU9XCJjb3VudFwiPkNvdW50PC9vcHRpb24+XG4gICAgICAgICAgICAgICAgICAgICAgPG9wdGlvbiB2YWx1ZT1cIm1pblwiPk1pbjwvb3B0aW9uPlxuICAgICAgICAgICAgICAgICAgICAgIDxvcHRpb24gdmFsdWU9XCJtYXhcIj5NYXg8L29wdGlvbj5cbiAgICAgICAgICAgICAgICAgICAgPC9zZWxlY3Q+XG4gICAgICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJjb2wtZmllbGQtaXRlbVwiPlxuICAgICAgICAgICAgICAgICAgICA8c3BhbiBjbGFzcz1cIm1pbmktbGFiZWxcIj5XaWR0aDwvc3Bhbj5cbiAgICAgICAgICAgICAgICAgICAgPGlucHV0XG4gICAgICAgICAgICAgICAgICAgICAgdHlwZT1cInRleHRcIlxuICAgICAgICAgICAgICAgICAgICAgIGNsYXNzPVwiY29sLW1pbmktaW5wdXRcIlxuICAgICAgICAgICAgICAgICAgICAgIHBsYWNlaG9sZGVyPVwiYXV0b1wiXG4gICAgICAgICAgICAgICAgICAgICAgW25nTW9kZWxdPVwiY29sLndpZHRoIHx8ICcnXCJcbiAgICAgICAgICAgICAgICAgICAgICAobmdNb2RlbENoYW5nZSk9XCJvblVwZGF0ZUNvbChpZHgsICd3aWR0aCcsICRldmVudCB8fCB1bmRlZmluZWQpXCJcbiAgICAgICAgICAgICAgICAgICAgLz5cbiAgICAgICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgICAgIDwvZGl2PlxuXG4gICAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cImNvbC1jYXJkLWZvb3RlclwiPlxuICAgICAgICAgICAgICAgICAgPGxhYmVsIGNsYXNzPVwiY29sLWNoZWNrYm94LXRvZ2dsZVwiPlxuICAgICAgICAgICAgICAgICAgICA8aW5wdXRcbiAgICAgICAgICAgICAgICAgICAgICB0eXBlPVwiY2hlY2tib3hcIlxuICAgICAgICAgICAgICAgICAgICAgIFtuZ01vZGVsXT1cImNvbC52aXNpYmxlICE9PSBmYWxzZVwiXG4gICAgICAgICAgICAgICAgICAgICAgKG5nTW9kZWxDaGFuZ2UpPVwib25VcGRhdGVDb2woaWR4LCAndmlzaWJsZScsICRldmVudClcIlxuICAgICAgICAgICAgICAgICAgICAvPlxuICAgICAgICAgICAgICAgICAgICA8c3Bhbj5WaXNpYmxlPC9zcGFuPlxuICAgICAgICAgICAgICAgICAgPC9sYWJlbD5cbiAgICAgICAgICAgICAgICAgIDxsYWJlbCBjbGFzcz1cImNvbC1jaGVja2JveC10b2dnbGVcIj5cbiAgICAgICAgICAgICAgICAgICAgPGlucHV0XG4gICAgICAgICAgICAgICAgICAgICAgdHlwZT1cImNoZWNrYm94XCJcbiAgICAgICAgICAgICAgICAgICAgICBbbmdNb2RlbF09XCJjb2wuY2hlY2tib3hTZWxlY3Rpb24gPz8gZmFsc2VcIlxuICAgICAgICAgICAgICAgICAgICAgIChuZ01vZGVsQ2hhbmdlKT1cIm9uVXBkYXRlQ29sKGlkeCwgJ2NoZWNrYm94U2VsZWN0aW9uJywgJGV2ZW50KVwiXG4gICAgICAgICAgICAgICAgICAgIC8+XG4gICAgICAgICAgICAgICAgICAgIDxzcGFuPkNoZWNrYm94PC9zcGFuPlxuICAgICAgICAgICAgICAgICAgPC9sYWJlbD5cbiAgICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICB9XG4gICAgICAgIDwvZGl2PlxuICAgICAgPC9kaXY+XG5cbiAgICAgIDwhLS0gR3JpZCBUYWJsZSBPcHRpb25zIEdyb3VwIC0tPlxuICAgICAgPGRpdiBjbGFzcz1cInByb3BlcnR5LWdyb3VwXCI+XG4gICAgICAgIDxkaXYgY2xhc3M9XCJncm91cC10aXRsZVwiPlRhYmxlIE9wdGlvbnM8L2Rpdj5cblxuICAgICAgICA8ZGl2IGNsYXNzPVwiZmllbGQtcm93XCI+XG4gICAgICAgICAgPGxhYmVsIGNsYXNzPVwiY2hlY2tib3gtdG9nZ2xlXCI+XG4gICAgICAgICAgICA8aW5wdXRcbiAgICAgICAgICAgICAgdHlwZT1cImNoZWNrYm94XCJcbiAgICAgICAgICAgICAgW25nTW9kZWxdPVwiZ3JpZCgpPy5vcHRpb25zPy5zaWRlQmFyICE9PSBmYWxzZVwiXG4gICAgICAgICAgICAgIChuZ01vZGVsQ2hhbmdlKT1cInVwZGF0ZU9wdGlvbi5lbWl0KHsgZmllbGQ6ICdzaWRlQmFyJywgdmFsdWU6ICRldmVudCB9KVwiXG4gICAgICAgICAgICAvPlxuICAgICAgICAgICAgPHNwYW4+RW5hYmxlIFNpZGUgUGFuZWwgKFRvb2wgUGFuZWxzKTwvc3Bhbj5cbiAgICAgICAgICA8L2xhYmVsPlxuICAgICAgICA8L2Rpdj5cblxuICAgICAgICA8ZGl2IGNsYXNzPVwiZmllbGQtcm93XCI+XG4gICAgICAgICAgPGxhYmVsIGNsYXNzPVwiY2hlY2tib3gtdG9nZ2xlXCI+XG4gICAgICAgICAgICA8aW5wdXRcbiAgICAgICAgICAgICAgdHlwZT1cImNoZWNrYm94XCJcbiAgICAgICAgICAgICAgW25nTW9kZWxdPVwiZ3JpZCgpPy5vcHRpb25zPy5nbG9iYWxTZWFyY2ggIT09IGZhbHNlXCJcbiAgICAgICAgICAgICAgKG5nTW9kZWxDaGFuZ2UpPVwidXBkYXRlT3B0aW9uLmVtaXQoeyBmaWVsZDogJ2dsb2JhbFNlYXJjaCcsIHZhbHVlOiAkZXZlbnQgfSlcIlxuICAgICAgICAgICAgLz5cbiAgICAgICAgICAgIDxzcGFuPkdsb2JhbCBTZWFyY2ggQm94PC9zcGFuPlxuICAgICAgICAgIDwvbGFiZWw+XG4gICAgICAgIDwvZGl2PlxuXG4gICAgICAgIDxkaXYgY2xhc3M9XCJmaWVsZC1yb3dcIj5cbiAgICAgICAgICA8bGFiZWwgY2xhc3M9XCJjaGVja2JveC10b2dnbGVcIj5cbiAgICAgICAgICAgIDxpbnB1dFxuICAgICAgICAgICAgICB0eXBlPVwiY2hlY2tib3hcIlxuICAgICAgICAgICAgICBbbmdNb2RlbF09XCJncmlkKCk/Lm9wdGlvbnM/LnN0YXR1c0JhciAhPT0gZmFsc2VcIlxuICAgICAgICAgICAgICAobmdNb2RlbENoYW5nZSk9XCJ1cGRhdGVPcHRpb24uZW1pdCh7IGZpZWxkOiAnc3RhdHVzQmFyJywgdmFsdWU6ICRldmVudCB9KVwiXG4gICAgICAgICAgICAvPlxuICAgICAgICAgICAgPHNwYW4+U3RhdHVzIEJhcjwvc3Bhbj5cbiAgICAgICAgICA8L2xhYmVsPlxuICAgICAgICA8L2Rpdj5cblxuICAgICAgICA8ZGl2IGNsYXNzPVwiZmllbGQtcm93XCI+XG4gICAgICAgICAgPGxhYmVsIGNsYXNzPVwiY2hlY2tib3gtdG9nZ2xlXCI+XG4gICAgICAgICAgICA8aW5wdXRcbiAgICAgICAgICAgICAgdHlwZT1cImNoZWNrYm94XCJcbiAgICAgICAgICAgICAgW25nTW9kZWxdPVwiZ3JpZCgpPy5vcHRpb25zPy5wYWdpbmF0aW9uID8/IHRydWVcIlxuICAgICAgICAgICAgICAobmdNb2RlbENoYW5nZSk9XCJ1cGRhdGVPcHRpb24uZW1pdCh7IGZpZWxkOiAncGFnaW5hdGlvbicsIHZhbHVlOiAkZXZlbnQgfSlcIlxuICAgICAgICAgICAgLz5cbiAgICAgICAgICAgIDxzcGFuPkVuYWJsZSBQYWdpbmF0aW9uPC9zcGFuPlxuICAgICAgICAgIDwvbGFiZWw+XG4gICAgICAgIDwvZGl2PlxuXG4gICAgICAgIDxkaXYgY2xhc3M9XCJmaWVsZC1yb3dcIj5cbiAgICAgICAgICA8bGFiZWwgY2xhc3M9XCJjaGVja2JveC10b2dnbGVcIj5cbiAgICAgICAgICAgIDxpbnB1dFxuICAgICAgICAgICAgICB0eXBlPVwiY2hlY2tib3hcIlxuICAgICAgICAgICAgICBbbmdNb2RlbF09XCJncmlkKCk/Lm9wdGlvbnM/LnNlbGVjdGFibGUgPz8gZmFsc2VcIlxuICAgICAgICAgICAgICAobmdNb2RlbENoYW5nZSk9XCJ1cGRhdGVPcHRpb24uZW1pdCh7IGZpZWxkOiAnc2VsZWN0YWJsZScsIHZhbHVlOiAkZXZlbnQgfSlcIlxuICAgICAgICAgICAgLz5cbiAgICAgICAgICAgIDxzcGFuPlJvdyBTZWxlY3Rpb248L3NwYW4+XG4gICAgICAgICAgPC9sYWJlbD5cbiAgICAgICAgPC9kaXY+XG5cbiAgICAgICAgQGlmIChncmlkKCk/Lm9wdGlvbnM/LnNlbGVjdGFibGUpIHtcbiAgICAgICAgICA8ZGl2IGNsYXNzPVwiZmllbGQtcm93XCI+XG4gICAgICAgICAgICA8bGFiZWwgY2xhc3M9XCJmaWVsZC1sYWJlbFwiPlNlbGVjdGlvbiBNb2RlPC9sYWJlbD5cbiAgICAgICAgICAgIDxzZWxlY3RcbiAgICAgICAgICAgICAgY2xhc3M9XCJmaWVsZC1pbnB1dFwiXG4gICAgICAgICAgICAgIFtuZ01vZGVsXT1cImdyaWQoKT8ub3B0aW9ucz8uc2VsZWN0aW9uTW9kZSA/PyAnbXVsdGlwbGUnXCJcbiAgICAgICAgICAgICAgKG5nTW9kZWxDaGFuZ2UpPVwidXBkYXRlT3B0aW9uLmVtaXQoeyBmaWVsZDogJ3NlbGVjdGlvbk1vZGUnLCB2YWx1ZTogJGV2ZW50IH0pXCJcbiAgICAgICAgICAgID5cbiAgICAgICAgICAgICAgPG9wdGlvbiB2YWx1ZT1cIm11bHRpcGxlXCI+TXVsdGlwbGUgUm93czwvb3B0aW9uPlxuICAgICAgICAgICAgICA8b3B0aW9uIHZhbHVlPVwic2luZ2xlXCI+U2luZ2xlIFJvdzwvb3B0aW9uPlxuICAgICAgICAgICAgPC9zZWxlY3Q+XG4gICAgICAgICAgPC9kaXY+XG5cbiAgICAgICAgICA8ZGl2IGNsYXNzPVwiZmllbGQtcm93XCI+XG4gICAgICAgICAgICA8bGFiZWwgY2xhc3M9XCJjaGVja2JveC10b2dnbGVcIj5cbiAgICAgICAgICAgICAgPGlucHV0XG4gICAgICAgICAgICAgICAgdHlwZT1cImNoZWNrYm94XCJcbiAgICAgICAgICAgICAgICBbbmdNb2RlbF09XCJncmlkKCk/Lm9wdGlvbnM/LmNoZWNrYm94U2VsZWN0aW9uID8/IHRydWVcIlxuICAgICAgICAgICAgICAgIChuZ01vZGVsQ2hhbmdlKT1cInVwZGF0ZU9wdGlvbi5lbWl0KHsgZmllbGQ6ICdjaGVja2JveFNlbGVjdGlvbicsIHZhbHVlOiAkZXZlbnQgfSlcIlxuICAgICAgICAgICAgICAvPlxuICAgICAgICAgICAgICA8c3Bhbj5DaGVja2JveCBTZWxlY3Rpb248L3NwYW4+XG4gICAgICAgICAgICA8L2xhYmVsPlxuICAgICAgICAgIDwvZGl2PlxuXG4gICAgICAgICAgQGlmICgoZ3JpZCgpPy5vcHRpb25zPy5zZWxlY3Rpb25Nb2RlID8/ICdtdWx0aXBsZScpID09PSAnbXVsdGlwbGUnKSB7XG4gICAgICAgICAgICA8ZGl2IGNsYXNzPVwiZmllbGQtcm93XCI+XG4gICAgICAgICAgICAgIDxsYWJlbCBjbGFzcz1cImNoZWNrYm94LXRvZ2dsZVwiPlxuICAgICAgICAgICAgICAgIDxpbnB1dFxuICAgICAgICAgICAgICAgICAgdHlwZT1cImNoZWNrYm94XCJcbiAgICAgICAgICAgICAgICAgIFtuZ01vZGVsXT1cImdyaWQoKT8ub3B0aW9ucz8uaGVhZGVyQ2hlY2tib3hTZWxlY3Rpb24gPz8gdHJ1ZVwiXG4gICAgICAgICAgICAgICAgICAobmdNb2RlbENoYW5nZSk9XCJ1cGRhdGVPcHRpb24uZW1pdCh7IGZpZWxkOiAnaGVhZGVyQ2hlY2tib3hTZWxlY3Rpb24nLCB2YWx1ZTogJGV2ZW50IH0pXCJcbiAgICAgICAgICAgICAgICAvPlxuICAgICAgICAgICAgICAgIDxzcGFuPkhlYWRlciBTZWxlY3QgQWxsIENoZWNrYm94PC9zcGFuPlxuICAgICAgICAgICAgICA8L2xhYmVsPlxuICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgPGRpdiBjbGFzcz1cImZpZWxkLXJvd1wiPlxuICAgICAgICAgIDxsYWJlbCBjbGFzcz1cImNoZWNrYm94LXRvZ2dsZVwiPlxuICAgICAgICAgICAgPGlucHV0XG4gICAgICAgICAgICAgIHR5cGU9XCJjaGVja2JveFwiXG4gICAgICAgICAgICAgIFtuZ01vZGVsXT1cImdyaWQoKT8ub3B0aW9ucz8uYWxsb3dDb2x1bW5SZW9yZGVyID8/IHRydWVcIlxuICAgICAgICAgICAgICAobmdNb2RlbENoYW5nZSk9XCJ1cGRhdGVPcHRpb24uZW1pdCh7IGZpZWxkOiAnYWxsb3dDb2x1bW5SZW9yZGVyJywgdmFsdWU6ICRldmVudCB9KVwiXG4gICAgICAgICAgICAvPlxuICAgICAgICAgICAgPHNwYW4+QWxsb3cgQ29sdW1uIFJlb3JkZXI8L3NwYW4+XG4gICAgICAgICAgPC9sYWJlbD5cbiAgICAgICAgPC9kaXY+XG5cbiAgICAgICAgPGRpdiBjbGFzcz1cImZpZWxkLXJvd1wiPlxuICAgICAgICAgIDxsYWJlbCBjbGFzcz1cImNoZWNrYm94LXRvZ2dsZVwiPlxuICAgICAgICAgICAgPGlucHV0XG4gICAgICAgICAgICAgIHR5cGU9XCJjaGVja2JveFwiXG4gICAgICAgICAgICAgIFtuZ01vZGVsXT1cImdyaWQoKT8ub3B0aW9ucz8uYWxsb3dFeHBvcnQgPz8gdHJ1ZVwiXG4gICAgICAgICAgICAgIChuZ01vZGVsQ2hhbmdlKT1cInVwZGF0ZU9wdGlvbi5lbWl0KHsgZmllbGQ6ICdhbGxvd0V4cG9ydCcsIHZhbHVlOiAkZXZlbnQgfSlcIlxuICAgICAgICAgICAgLz5cbiAgICAgICAgICAgIDxzcGFuPkFsbG93IEV4cG9ydDwvc3Bhbj5cbiAgICAgICAgICA8L2xhYmVsPlxuICAgICAgICA8L2Rpdj5cblxuICAgICAgICA8ZGl2IGNsYXNzPVwiZmllbGQtcm93XCI+XG4gICAgICAgICAgPGxhYmVsIGNsYXNzPVwiZmllbGQtbGFiZWxcIj5QYWdlIFNpemU8L2xhYmVsPlxuICAgICAgICAgIDxpbnB1dFxuICAgICAgICAgICAgdHlwZT1cIm51bWJlclwiXG4gICAgICAgICAgICBjbGFzcz1cImZpZWxkLWlucHV0XCJcbiAgICAgICAgICAgIG1pbj1cIjFcIlxuICAgICAgICAgICAgbWF4PVwiMTAwMFwiXG4gICAgICAgICAgICAod2hlZWwpPVwiJGFueSgkZXZlbnQudGFyZ2V0KS5ibHVyKClcIlxuICAgICAgICAgICAgKGtleWRvd24uYXJyb3d1cCk9XCIkZXZlbnQucHJldmVudERlZmF1bHQoKVwiXG4gICAgICAgICAgICAoa2V5ZG93bi5hcnJvd2Rvd24pPVwiJGV2ZW50LnByZXZlbnREZWZhdWx0KClcIlxuICAgICAgICAgICAgW25nTW9kZWxdPVwiZ3JpZCgpPy5vcHRpb25zPy5wYWdlU2l6ZSA/PyAxMFwiXG4gICAgICAgICAgICAobmdNb2RlbENoYW5nZSk9XCJ1cGRhdGVPcHRpb24uZW1pdCh7IGZpZWxkOiAncGFnZVNpemUnLCB2YWx1ZTogKyRldmVudCB9KVwiXG4gICAgICAgICAgLz5cbiAgICAgICAgPC9kaXY+XG5cbiAgICAgICAgPGRpdiBjbGFzcz1cImZpZWxkLXJvd1wiPlxuICAgICAgICAgIDxsYWJlbCBjbGFzcz1cImNoZWNrYm94LXRvZ2dsZVwiPlxuICAgICAgICAgICAgPGlucHV0XG4gICAgICAgICAgICAgIHR5cGU9XCJjaGVja2JveFwiXG4gICAgICAgICAgICAgIFtuZ01vZGVsXT1cImdyaWQoKT8ub3B0aW9ucz8uc2hvd1Jvd051bWJlcnMgPz8gdHJ1ZVwiXG4gICAgICAgICAgICAgIChuZ01vZGVsQ2hhbmdlKT1cInVwZGF0ZU9wdGlvbi5lbWl0KHsgZmllbGQ6ICdzaG93Um93TnVtYmVycycsIHZhbHVlOiAkZXZlbnQgfSlcIlxuICAgICAgICAgICAgLz5cbiAgICAgICAgICAgIDxzcGFuPlNob3cgUm93IE51bWJlcnM8L3NwYW4+XG4gICAgICAgICAgPC9sYWJlbD5cbiAgICAgICAgPC9kaXY+XG5cbiAgICAgICAgPGRpdiBjbGFzcz1cImZpZWxkLXJvd1wiPlxuICAgICAgICAgIDxsYWJlbCBjbGFzcz1cImNoZWNrYm94LXRvZ2dsZVwiPlxuICAgICAgICAgICAgPGlucHV0XG4gICAgICAgICAgICAgIHR5cGU9XCJjaGVja2JveFwiXG4gICAgICAgICAgICAgIFtuZ01vZGVsXT1cImdyaWQoKT8ub3B0aW9ucz8uc2hvd0Zvb3RlciA/PyB0cnVlXCJcbiAgICAgICAgICAgICAgKG5nTW9kZWxDaGFuZ2UpPVwidXBkYXRlT3B0aW9uLmVtaXQoeyBmaWVsZDogJ3Nob3dGb290ZXInLCB2YWx1ZTogJGV2ZW50IH0pXCJcbiAgICAgICAgICAgIC8+XG4gICAgICAgICAgICA8c3Bhbj5TaG93IEZvb3RlciBUb3RhbHM8L3NwYW4+XG4gICAgICAgICAgPC9sYWJlbD5cbiAgICAgICAgPC9kaXY+XG4gICAgICA8L2Rpdj5cblxuICAgICAgPCEtLSBSb3cgQ2xpY2sgJiBEcmlsbC1Eb3duIEFjdGlvbiBHcm91cCAtLT5cbiAgICAgIDxkaXYgY2xhc3M9XCJwcm9wZXJ0eS1ncm91cFwiPlxuICAgICAgICA8ZGl2IGNsYXNzPVwiZ3JvdXAtdGl0bGVcIj5Sb3cgQ2xpY2sgJiBEcmlsbC1Eb3duPC9kaXY+XG5cbiAgICAgICAgPGRpdiBjbGFzcz1cImZpZWxkLXJvd1wiPlxuICAgICAgICAgIDxsYWJlbCBjbGFzcz1cImNoZWNrYm94LXRvZ2dsZVwiPlxuICAgICAgICAgICAgPGlucHV0XG4gICAgICAgICAgICAgIHR5cGU9XCJjaGVja2JveFwiXG4gICAgICAgICAgICAgIFtuZ01vZGVsXT1cImhhc1Jvd0NsaWNrQWN0aW9uKClcIlxuICAgICAgICAgICAgICAobmdNb2RlbENoYW5nZSk9XCJ0b2dnbGVSb3dDbGlja0FjdGlvbigkZXZlbnQpXCJcbiAgICAgICAgICAgIC8+XG4gICAgICAgICAgICA8c3Bhbj5FbmFibGUgUm93IENsaWNrIEFjdGlvbjwvc3Bhbj5cbiAgICAgICAgICA8L2xhYmVsPlxuICAgICAgICA8L2Rpdj5cblxuICAgICAgICBAaWYgKGhhc1Jvd0NsaWNrQWN0aW9uKCkpIHtcbiAgICAgICAgICA8ZGl2IGNsYXNzPVwiZmllbGQtcm93XCI+XG4gICAgICAgICAgICA8bGFiZWwgY2xhc3M9XCJmaWVsZC1sYWJlbFwiPkFjdGlvbiBUeXBlPC9sYWJlbD5cbiAgICAgICAgICAgIDxzZWxlY3RcbiAgICAgICAgICAgICAgY2xhc3M9XCJmaWVsZC1pbnB1dCBmaWVsZC1zZWxlY3RcIlxuICAgICAgICAgICAgICBbbmdNb2RlbF09XCJyb3dDbGlja0FjdGlvbigpPy50eXBlIHx8ICdvcGVuLWRyYXdlcidcIlxuICAgICAgICAgICAgICAobmdNb2RlbENoYW5nZSk9XCJ1cGRhdGVSb3dBY3Rpb25GaWVsZCgndHlwZScsICRldmVudClcIlxuICAgICAgICAgICAgPlxuICAgICAgICAgICAgICA8b3B0aW9uIHZhbHVlPVwib3Blbi1kcmF3ZXJcIj5TbGlkZS1PdmVyIERldGFpbCBEcmF3ZXI8L29wdGlvbj5cbiAgICAgICAgICAgICAgPG9wdGlvbiB2YWx1ZT1cImRyaWxsZG93bi1yZXBvcnRcIj5EcmlsbC1Eb3duIFJlcG9ydCAoSG9zdCBFdmVudCk8L29wdGlvbj5cbiAgICAgICAgICAgICAgPG9wdGlvbiB2YWx1ZT1cIm5hdmlnYXRlXCI+TmF2aWdhdGUgdG8gVVJMPC9vcHRpb24+XG4gICAgICAgICAgICAgIDxvcHRpb24gdmFsdWU9XCJlbWl0LWN1c3RvbVwiPkVtaXQgQ3VzdG9tIEFjdGlvbjwvb3B0aW9uPlxuICAgICAgICAgICAgPC9zZWxlY3Q+XG4gICAgICAgICAgPC9kaXY+XG5cbiAgICAgICAgICBAaWYgKHJvd0NsaWNrQWN0aW9uKCk/LnR5cGUgPT09ICdvcGVuLWRyYXdlcicgfHwgcm93Q2xpY2tBY3Rpb24oKT8udHlwZSA9PT0gJ2RyaWxsZG93bi1yZXBvcnQnKSB7XG4gICAgICAgICAgICA8ZGl2IGNsYXNzPVwiZmllbGQtcm93XCI+XG4gICAgICAgICAgICAgIDxsYWJlbCBjbGFzcz1cImZpZWxkLWxhYmVsXCI+VGFyZ2V0IFJlcG9ydCBJRDwvbGFiZWw+XG4gICAgICAgICAgICAgIDxpbnB1dFxuICAgICAgICAgICAgICAgIHR5cGU9XCJ0ZXh0XCJcbiAgICAgICAgICAgICAgICBjbGFzcz1cImZpZWxkLWlucHV0XCJcbiAgICAgICAgICAgICAgICBwbGFjZWhvbGRlcj1cImUuZy4gb3JkZXItZGV0YWlsc1wiXG4gICAgICAgICAgICAgICAgW25nTW9kZWxdPVwicm93Q2xpY2tBY3Rpb24oKT8udGFyZ2V0UmVwb3J0SWQgfHwgJydcIlxuICAgICAgICAgICAgICAgIChuZ01vZGVsQ2hhbmdlKT1cInVwZGF0ZVJvd0FjdGlvbkZpZWxkKCd0YXJnZXRSZXBvcnRJZCcsICRldmVudClcIlxuICAgICAgICAgICAgICAvPlxuICAgICAgICAgICAgPC9kaXY+XG5cbiAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJmaWVsZC1yb3dcIj5cbiAgICAgICAgICAgICAgPGxhYmVsIGNsYXNzPVwiZmllbGQtbGFiZWxcIj5EcmF3ZXIgVGl0bGU8L2xhYmVsPlxuICAgICAgICAgICAgICA8aW5wdXRcbiAgICAgICAgICAgICAgICB0eXBlPVwidGV4dFwiXG4gICAgICAgICAgICAgICAgY2xhc3M9XCJmaWVsZC1pbnB1dFwiXG4gICAgICAgICAgICAgICAgcGxhY2Vob2xkZXI9XCJlLmcuIE9yZGVyIERldGFpbHNcIlxuICAgICAgICAgICAgICAgIFtuZ01vZGVsXT1cInJvd0NsaWNrQWN0aW9uKCk/LmRyYXdlclRpdGxlIHx8ICcnXCJcbiAgICAgICAgICAgICAgICAobmdNb2RlbENoYW5nZSk9XCJ1cGRhdGVSb3dBY3Rpb25GaWVsZCgnZHJhd2VyVGl0bGUnLCAkZXZlbnQpXCJcbiAgICAgICAgICAgICAgLz5cbiAgICAgICAgICAgIDwvZGl2PlxuXG4gICAgICAgICAgICA8ZGl2IGNsYXNzPVwiZmllbGQtcm93XCI+XG4gICAgICAgICAgICAgIDxsYWJlbCBjbGFzcz1cImZpZWxkLWxhYmVsXCI+RHJhd2VyIFdpZHRoPC9sYWJlbD5cbiAgICAgICAgICAgICAgPGlucHV0XG4gICAgICAgICAgICAgICAgdHlwZT1cInRleHRcIlxuICAgICAgICAgICAgICAgIGNsYXNzPVwiZmllbGQtaW5wdXRcIlxuICAgICAgICAgICAgICAgIHBsYWNlaG9sZGVyPVwiZS5nLiA3NjBweCwgODAlLCA5MDBweFwiXG4gICAgICAgICAgICAgICAgW25nTW9kZWxdPVwicm93Q2xpY2tBY3Rpb24oKT8uZHJhd2VyV2lkdGggfHwgJzc2MHB4J1wiXG4gICAgICAgICAgICAgICAgKG5nTW9kZWxDaGFuZ2UpPVwidXBkYXRlUm93QWN0aW9uRmllbGQoJ2RyYXdlcldpZHRoJywgJGV2ZW50KVwiXG4gICAgICAgICAgICAgIC8+XG4gICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICB9XG5cbiAgICAgICAgICBAaWYgKHJvd0NsaWNrQWN0aW9uKCk/LnR5cGUgPT09ICduYXZpZ2F0ZScpIHtcbiAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJmaWVsZC1yb3dcIj5cbiAgICAgICAgICAgICAgPGxhYmVsIGNsYXNzPVwiZmllbGQtbGFiZWxcIj5UYXJnZXQgVVJMPC9sYWJlbD5cbiAgICAgICAgICAgICAgPGlucHV0XG4gICAgICAgICAgICAgICAgdHlwZT1cInRleHRcIlxuICAgICAgICAgICAgICAgIGNsYXNzPVwiZmllbGQtaW5wdXRcIlxuICAgICAgICAgICAgICAgIFtwbGFjZWhvbGRlcl09XCInL29yZGVycy97e3Jvdy5vcmRlcklkfX0gb3IgaHR0cHM6Ly8uLi4nXCJcbiAgICAgICAgICAgICAgICBbbmdNb2RlbF09XCJyb3dDbGlja0FjdGlvbigpPy50YXJnZXRVcmwgfHwgJydcIlxuICAgICAgICAgICAgICAgIChuZ01vZGVsQ2hhbmdlKT1cInVwZGF0ZVJvd0FjdGlvbkZpZWxkKCd0YXJnZXRVcmwnLCAkZXZlbnQpXCJcbiAgICAgICAgICAgICAgLz5cbiAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgPGRpdiBjbGFzcz1cImZpZWxkLXJvd1wiPlxuICAgICAgICAgICAgICA8bGFiZWwgY2xhc3M9XCJjaGVja2JveC10b2dnbGVcIj5cbiAgICAgICAgICAgICAgICA8aW5wdXRcbiAgICAgICAgICAgICAgICAgIHR5cGU9XCJjaGVja2JveFwiXG4gICAgICAgICAgICAgICAgICBbbmdNb2RlbF09XCJyb3dDbGlja0FjdGlvbigpPy5vcGVuTmV3VGFiID8/IGZhbHNlXCJcbiAgICAgICAgICAgICAgICAgIChuZ01vZGVsQ2hhbmdlKT1cInVwZGF0ZVJvd0FjdGlvbkZpZWxkKCdvcGVuTmV3VGFiJywgJGV2ZW50KVwiXG4gICAgICAgICAgICAgICAgLz5cbiAgICAgICAgICAgICAgICA8c3Bhbj5PcGVuIGluIE5ldyBUYWI8L3NwYW4+XG4gICAgICAgICAgICAgIDwvbGFiZWw+XG4gICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICB9XG5cbiAgICAgICAgICBAaWYgKHJvd0NsaWNrQWN0aW9uKCk/LnR5cGUgPT09ICdlbWl0LWN1c3RvbScpIHtcbiAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJmaWVsZC1yb3dcIj5cbiAgICAgICAgICAgICAgPGxhYmVsIGNsYXNzPVwiZmllbGQtbGFiZWxcIj5DdXN0b20gQWN0aW9uIE5hbWU8L2xhYmVsPlxuICAgICAgICAgICAgICA8aW5wdXRcbiAgICAgICAgICAgICAgICB0eXBlPVwidGV4dFwiXG4gICAgICAgICAgICAgICAgY2xhc3M9XCJmaWVsZC1pbnB1dFwiXG4gICAgICAgICAgICAgICAgcGxhY2Vob2xkZXI9XCJlLmcuIHZpZXctYXVkaXQtdHJhaWxcIlxuICAgICAgICAgICAgICAgIFtuZ01vZGVsXT1cInJvd0NsaWNrQWN0aW9uKCk/LmN1c3RvbUFjdGlvbk5hbWUgfHwgJydcIlxuICAgICAgICAgICAgICAgIChuZ01vZGVsQ2hhbmdlKT1cInVwZGF0ZVJvd0FjdGlvbkZpZWxkKCdjdXN0b21BY3Rpb25OYW1lJywgJGV2ZW50KVwiXG4gICAgICAgICAgICAgIC8+XG4gICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICB9XG5cbiAgICAgICAgICA8ZGl2IGNsYXNzPVwiZmllbGQtcm93XCI+XG4gICAgICAgICAgICA8ZGl2IGNsYXNzPVwiZmllbGQtbGFiZWwtcm93XCI+XG4gICAgICAgICAgICAgIDxsYWJlbCBjbGFzcz1cImZpZWxkLWxhYmVsXCI+UGFyYW1ldGVyIE1hcHBpbmc8L2xhYmVsPlxuICAgICAgICAgICAgICA8YnV0dG9uXG4gICAgICAgICAgICAgICAgdHlwZT1cImJ1dHRvblwiXG4gICAgICAgICAgICAgICAgY2xhc3M9XCJidG4tYWRkLW1hcHBpbmdcIlxuICAgICAgICAgICAgICAgIChjbGljayk9XCJhZGRQYXJhbWV0ZXJNYXBwaW5nKClcIlxuICAgICAgICAgICAgICA+XG4gICAgICAgICAgICAgICAgKyBBZGQgTWFwcGluZ1xuICAgICAgICAgICAgICA8L2J1dHRvbj5cbiAgICAgICAgICAgIDwvZGl2PlxuXG4gICAgICAgICAgICBAZm9yIChtYXBwaW5nIG9mIHBhcmFtZXRlck1hcHBpbmdzKCk7IHRyYWNrIG1hcHBpbmcua2V5OyBsZXQgbUlkeCA9ICRpbmRleCkge1xuICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwibWFwcGluZy1wYWlyLXJvd1wiPlxuICAgICAgICAgICAgICAgIDxpbnB1dFxuICAgICAgICAgICAgICAgICAgdHlwZT1cInRleHRcIlxuICAgICAgICAgICAgICAgICAgY2xhc3M9XCJjb2wtbWluaS1pbnB1dFwiXG4gICAgICAgICAgICAgICAgICBzdHlsZT1cImZsZXg6IDE7XCJcbiAgICAgICAgICAgICAgICAgIHBsYWNlaG9sZGVyPVwiVGFyZ2V0IChlLmcuIGN1c3RvbWVySWQpXCJcbiAgICAgICAgICAgICAgICAgIFtuZ01vZGVsXT1cIm1hcHBpbmcua2V5XCJcbiAgICAgICAgICAgICAgICAgIChuZ01vZGVsQ2hhbmdlKT1cInVwZGF0ZU1hcHBpbmdLZXkobUlkeCwgJGV2ZW50KVwiXG4gICAgICAgICAgICAgICAgLz5cbiAgICAgICAgICAgICAgICA8c3BhbiBzdHlsZT1cImZvbnQtc2l6ZTogMC43NXJlbTsgY29sb3I6ICM5NGEzYjg7XCI+4oaQPC9zcGFuPlxuICAgICAgICAgICAgICAgIDxpbnB1dFxuICAgICAgICAgICAgICAgICAgdHlwZT1cInRleHRcIlxuICAgICAgICAgICAgICAgICAgY2xhc3M9XCJjb2wtbWluaS1pbnB1dFwiXG4gICAgICAgICAgICAgICAgICBzdHlsZT1cImZsZXg6IDE7XCJcbiAgICAgICAgICAgICAgICAgIHBsYWNlaG9sZGVyPVwiU291cmNlIChlLmcuIHJvdy5pZClcIlxuICAgICAgICAgICAgICAgICAgW25nTW9kZWxdPVwibWFwcGluZy52YWx1ZVwiXG4gICAgICAgICAgICAgICAgICAobmdNb2RlbENoYW5nZSk9XCJ1cGRhdGVNYXBwaW5nVmFsdWUobUlkeCwgJGV2ZW50KVwiXG4gICAgICAgICAgICAgICAgLz5cbiAgICAgICAgICAgICAgICA8YnV0dG9uXG4gICAgICAgICAgICAgICAgICB0eXBlPVwiYnV0dG9uXCJcbiAgICAgICAgICAgICAgICAgIGNsYXNzPVwiY29sLWFjdGlvbi1idG4gYnRuLWRlbGV0ZVwiXG4gICAgICAgICAgICAgICAgICAoY2xpY2spPVwicmVtb3ZlTWFwcGluZyhtSWR4KVwiXG4gICAgICAgICAgICAgICAgICB0aXRsZT1cIlJlbW92ZSBtYXBwaW5nXCJcbiAgICAgICAgICAgICAgICA+XG4gICAgICAgICAgICAgICAgICA8cnB0LWljb24gbmFtZT1cInRyYXNoXCIgW3NpemVdPVwiMTFcIiAvPlxuICAgICAgICAgICAgICAgIDwvYnV0dG9uPlxuICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgIH1cbiAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgfVxuICAgICAgPC9kaXY+XG5cbiAgICAgIDwhLS0gUmVtb3ZlIEdyaWQgQWN0aW9uIC0tPlxuICAgICAgPGRpdiBjbGFzcz1cImdyaWQtZGFuZ2VyLXpvbmVcIj5cbiAgICAgICAgPGJ1dHRvbiB0eXBlPVwiYnV0dG9uXCIgY2xhc3M9XCJidG4tcmVtb3ZlLWdyaWQtYWN0aW9uXCIgKGNsaWNrKT1cInJlbW92ZUdyaWQuZW1pdCgpXCI+XG4gICAgICAgICAgPHJwdC1pY29uIG5hbWU9XCJ0cmFzaFwiIFtzaXplXT1cIjEzXCIgLz5cbiAgICAgICAgICA8c3Bhbj5SZW1vdmUgR3JpZCBmcm9tIFJlcG9ydDwvc3Bhbj5cbiAgICAgICAgPC9idXR0b24+XG4gICAgICA8L2Rpdj5cbiAgICA8L2Rpdj5cbiAgICB9Il19