@cqa-lib/cqa-ui 1.1.525 → 1.1.526

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 (45) hide show
  1. package/esm2020/lib/assets/images/image-assets.constants.mjs +3 -1
  2. package/esm2020/lib/compare-runs/compare-runs.component.mjs +1 -1
  3. package/esm2020/lib/execution-screen/db-query-execution-item/db-query-execution-item.component.mjs +1 -1
  4. package/esm2020/lib/execution-screen/db-verification-step/db-verification-step.component.mjs +1 -1
  5. package/esm2020/lib/iterations-loop/iterations-loop.component.mjs +1 -1
  6. package/esm2020/lib/segment-control/segment-control.component.mjs +6 -3
  7. package/esm2020/lib/simulator/simulator.component.mjs +1 -1
  8. package/esm2020/lib/step-builder/step-builder-document-generation-template-step/step-builder-document-generation-template-step.component.mjs +1 -1
  9. package/esm2020/lib/table/dynamic-table/dynamic-table.component.mjs +148 -4
  10. package/esm2020/lib/templates/modular-table-template/dialogs/delete-folder-dialog.component.mjs +181 -0
  11. package/esm2020/lib/templates/modular-table-template/dialogs/move-to-folder-dialog.component.mjs +264 -0
  12. package/esm2020/lib/templates/modular-table-template/dialogs/new-folder-dialog.component.mjs +352 -0
  13. package/esm2020/lib/templates/modular-table-template/directives/folder-drag.directive.mjs +45 -0
  14. package/esm2020/lib/templates/modular-table-template/directives/folder-drop.directive.mjs +95 -0
  15. package/esm2020/lib/templates/modular-table-template/directives/row-drag.directive.mjs +44 -0
  16. package/esm2020/lib/templates/modular-table-template/folder-sidebar/folder-sidebar.component.mjs +479 -0
  17. package/esm2020/lib/templates/modular-table-template/modular-table-template.component.mjs +1475 -0
  18. package/esm2020/lib/templates/modular-table-template/modular-table-template.models.mjs +79 -0
  19. package/esm2020/lib/templates/table-template.component.mjs +88 -12
  20. package/esm2020/lib/test-case-details/api-edit-step/api-edit-step.component.mjs +1 -1
  21. package/esm2020/lib/ui-kit.module.mjs +41 -1
  22. package/esm2020/public-api.mjs +10 -1
  23. package/fesm2015/cqa-lib-cqa-ui.mjs +3408 -178
  24. package/fesm2015/cqa-lib-cqa-ui.mjs.map +1 -1
  25. package/fesm2020/cqa-lib-cqa-ui.mjs +3388 -176
  26. package/fesm2020/cqa-lib-cqa-ui.mjs.map +1 -1
  27. package/lib/assets/images/image-assets.constants.d.ts +1 -0
  28. package/lib/segment-control/segment-control.component.d.ts +2 -1
  29. package/lib/table/dynamic-table/dynamic-table.component.d.ts +43 -1
  30. package/lib/templates/modular-table-template/dialogs/delete-folder-dialog.component.d.ts +34 -0
  31. package/lib/templates/modular-table-template/dialogs/move-to-folder-dialog.component.d.ts +57 -0
  32. package/lib/templates/modular-table-template/dialogs/new-folder-dialog.component.d.ts +79 -0
  33. package/lib/templates/modular-table-template/directives/folder-drag.directive.d.ts +10 -0
  34. package/lib/templates/modular-table-template/directives/folder-drop.directive.d.ts +22 -0
  35. package/lib/templates/modular-table-template/directives/row-drag.directive.d.ts +10 -0
  36. package/lib/templates/modular-table-template/folder-sidebar/folder-sidebar.component.d.ts +149 -0
  37. package/lib/templates/modular-table-template/modular-table-template.component.d.ts +453 -0
  38. package/lib/templates/modular-table-template/modular-table-template.models.d.ts +150 -0
  39. package/lib/templates/table-template.component.d.ts +40 -2
  40. package/lib/ui-kit.module.d.ts +153 -145
  41. package/package.json +1 -1
  42. package/public-api.d.ts +9 -0
  43. package/src/lib/assets/images/EmptyFolderState.png +0 -0
  44. package/src/lib/assets/images/image-assets.constants.ts +3 -0
  45. package/styles.css +1 -1
@@ -0,0 +1,1475 @@
1
+ import { Component, Input, Output, EventEmitter, ChangeDetectionStrategy, ViewChild, } from '@angular/core';
2
+ import { DynamicFilterComponent } from '../../filters/dynamic-filter/dynamic-filter.component';
3
+ import { EMPTY_STATE_IMAGES } from '../../assets/images/image-assets.constants';
4
+ import { DEFAULT_MODULAR_CONFIG, DEFAULT_MODULAR_LABELS, DEFAULT_REORDER_LABELS, } from './modular-table-template.models';
5
+ import { MoveToFolderDialogComponent } from './dialogs/move-to-folder-dialog.component';
6
+ import { NewFolderDialogComponent } from './dialogs/new-folder-dialog.component';
7
+ import { DeleteFolderDialogComponent } from './dialogs/delete-folder-dialog.component';
8
+ import * as i0 from "@angular/core";
9
+ import * as i1 from "../../dialog/dialog.service";
10
+ import * as i2 from "../../search-bar/search-bar.component";
11
+ import * as i3 from "../../button/button.component";
12
+ import * as i4 from "../../export-code-modal/export-code-modal.component";
13
+ import * as i5 from "../../column-visibility/column-visibility.component";
14
+ import * as i6 from "../../segment-control/segment-control.component";
15
+ import * as i7 from "../../selected-filters/selected-filters.component";
16
+ import * as i8 from "../../filters/dynamic-filter/dynamic-filter.component";
17
+ import * as i9 from "./folder-sidebar/folder-sidebar.component";
18
+ import * as i10 from "@angular/material/icon";
19
+ import * as i11 from "../../table/dynamic-table/dynamic-table.component";
20
+ import * as i12 from "../../empty-state/empty-state.component";
21
+ import * as i13 from "../../pagination/pagination.component";
22
+ import * as i14 from "../../table-action-toolbar/table-action-toolbar.component";
23
+ import * as i15 from "@angular/common";
24
+ import * as i16 from "./directives/folder-drop.directive";
25
+ export class ModularTableTemplateComponent {
26
+ constructor(cdr, dialogService) {
27
+ this.cdr = cdr;
28
+ this.dialogService = dialogService;
29
+ // Search bar inputs
30
+ this.searchPlaceholder = 'Search components';
31
+ this.searchValue = '';
32
+ this.showClear = true;
33
+ this.showSearchBar = true;
34
+ this.showExportButton = false;
35
+ this.isExporting = false;
36
+ // Search bar outputs
37
+ this.onSearchChange = new EventEmitter();
38
+ this.onExportClick = new EventEmitter();
39
+ // Filter outputs
40
+ this.onApplyFilterClick = new EventEmitter();
41
+ this.onResetFilterClick = new EventEmitter();
42
+ this.onClearAll = new EventEmitter();
43
+ this.removeChip = new EventEmitter();
44
+ // Filter inputs
45
+ this.filterConfig = [];
46
+ this.filterModel = {};
47
+ this.showFilterPanel = false;
48
+ this.showFilterButton = true;
49
+ // Other buttons input (array of button templates/components)
50
+ this.otherButtons = [];
51
+ // Other dropdown buttons input (array of dropdown button templates/components)
52
+ this.otherDropDownButtons = [];
53
+ // Other select dropdown buttons input (array of select dropdown button templates/components)
54
+ this.otherSelectDropDownButtons = [];
55
+ // Legacy single button inputs (deprecated, kept for backward compatibility)
56
+ /** @deprecated Use otherButtons array instead */
57
+ this.otherButtonLabel = 'Other Button';
58
+ /** @deprecated Use otherButtons array instead */
59
+ this.otherButtonVariant = 'filled';
60
+ /** @deprecated Use otherButtons array instead */
61
+ this.showOtherButton = true;
62
+ // Action menu button (three-dot menu in table rows)
63
+ this.showActionButton = true;
64
+ // Settings and refresh buttons
65
+ this.showSettingsButton = true;
66
+ this.showAutoRefreshButton = true;
67
+ // View-mode toggle (List | Modular). Hidden by default for backward compatibility.
68
+ this.showViewModeToggle = false;
69
+ this.viewMode = 'list';
70
+ this.viewModeLabels = { list: 'List', modular: 'Modular' };
71
+ this.viewModeChange = new EventEmitter();
72
+ // Data input
73
+ this.data = [];
74
+ // Empty state inputs
75
+ this.isEmptyState = false;
76
+ this.emptyStateConfig = {
77
+ title: 'No Data Available Yet',
78
+ description: 'Run or upload your first test to see your analytics and trends here. Watch your quality metrics come to life with real-time insights.',
79
+ imageUrl: EMPTY_STATE_IMAGES.DASHBOARD,
80
+ actions: [{ label: 'Run Test Suite', variant: 'filled' }],
81
+ };
82
+ // Action bar inputs
83
+ this.actions = [
84
+ {
85
+ id: 'delete',
86
+ label: 'Delete',
87
+ icon: 'delete',
88
+ tooltip: 'Delete selected',
89
+ onClick: (context) => {
90
+ console.log('Delete action clicked:', context);
91
+ }
92
+ },
93
+ {
94
+ id: 'edit',
95
+ label: 'Edit',
96
+ icon: 'edit',
97
+ tooltip: 'Edit selected',
98
+ onClick: (context) => {
99
+ console.log('Edit action clicked:', context);
100
+ }
101
+ },
102
+ {
103
+ id: 'add-tag',
104
+ label: 'Add Tag',
105
+ icon: 'local_offer',
106
+ tooltip: 'Add tags',
107
+ onClick: (context) => {
108
+ console.log('Add tag action clicked:', context);
109
+ }
110
+ },
111
+ {
112
+ id: 'remove-tag',
113
+ label: 'Remove Tag',
114
+ icon: 'label_off',
115
+ tooltip: 'Remove tags',
116
+ onClick: (context) => {
117
+ console.log('Remove tag action clicked:', context);
118
+ }
119
+ },
120
+ ];
121
+ // Chips inputs
122
+ this.chips = [];
123
+ this.filterApplied = false;
124
+ // Table inputs
125
+ this.columns = [];
126
+ this.selectedAutoRefreshInterval = 0;
127
+ this.pageIndex = 0;
128
+ this.pageSize = 10;
129
+ this.pageSizeOptions = [10, 20, 40, 60, 80];
130
+ this.pageSizeMenuDirection = 'auto';
131
+ // Server-side pagination controls
132
+ this.serverSidePagination = false;
133
+ this.totalElements = 0;
134
+ this.pageChange = new EventEmitter();
135
+ /**
136
+ * When false, header sort does not reorder rows locally (use with serverSidePagination + sortChange).
137
+ * Default true for backward compatibility.
138
+ */
139
+ this.enableLocalSort = true;
140
+ this.sortChange = new EventEmitter();
141
+ // Selected items (full objects) for maintaining selection across pagination (server-side)
142
+ this.selectedItems = [];
143
+ /**
144
+ * When true, the action toolbar renders the "Select all" affordance. Defaults to false
145
+ * for now — host opts in. Matches the current product requirement to hide Select All.
146
+ */
147
+ this.showSelectAllInToolbar = false;
148
+ /**
149
+ * When true, the action toolbar renders the dismiss (×) affordance. Defaults to false
150
+ * for now — host opts in. Matches the current product requirement to hide Cancel.
151
+ */
152
+ this.showDismissInToolbar = false;
153
+ /** Bound to the toolbar's "Select all" checkbox — drives the checked state. */
154
+ this.allSelectedInToolbar = false;
155
+ // Internal state for column visibility
156
+ this._columnVisibility = {};
157
+ this._cachedVisibilityColumns = [];
158
+ this.filteredRows = [];
159
+ this.pagedRows = [];
160
+ // ============================================================================
161
+ // Folder / modular inputs
162
+ // ============================================================================
163
+ this.folders = [];
164
+ this.selectedFolderId = null;
165
+ this.expandedFolderIds = [];
166
+ this.unorganisedCount = 0;
167
+ this.folderIdAccessor = (row) => row?.folderId ?? null;
168
+ this.modularConfig = { ...DEFAULT_MODULAR_CONFIG };
169
+ this.modularLabels = { ...DEFAULT_MODULAR_LABELS };
170
+ this.bulkActions = [];
171
+ this.sidebarCollapsed = false;
172
+ /**
173
+ * When true (default), the library opens its own Move dialog for convenience
174
+ * during testing. Hosts taking over API + UX should set this to `false` and
175
+ * listen on `moveRequested` to render their own.
176
+ */
177
+ this.useInternalDialogs = true;
178
+ // ============================================================================
179
+ // Folder / modular outputs
180
+ // ============================================================================
181
+ this.folderSelected = new EventEmitter();
182
+ this.folderExpansionToggled = new EventEmitter();
183
+ this.folderCreated = new EventEmitter();
184
+ /** Emitted when the user clicks "+ New folder"; host should open a creation modal. */
185
+ this.folderCreateRequested = new EventEmitter();
186
+ this.folderRenamed = new EventEmitter();
187
+ /**
188
+ * Fires after the user confirms folder deletion via the internal dialog (or
189
+ * immediately, when `useInternalDialogs` is false and the host drives the UX).
190
+ * Payload now includes the user's chosen `strategy` for what happens to the
191
+ * folder's test cases.
192
+ */
193
+ this.folderDeleted = new EventEmitter();
194
+ this.testsMoved = new EventEmitter();
195
+ // ---------------------------------------------------------------------------
196
+ // Bulk action toolbar surface — naming mirrors cqa-table-template so consumers
197
+ // get the same events from either component (plus the folder events below).
198
+ // ---------------------------------------------------------------------------
199
+ /** Fires on raw toolbar action click — *before* any internal dialog opens. */
200
+ this.bulkActionClick = new EventEmitter();
201
+ /** Fires when the toolbar's "Select all" is toggled. */
202
+ this.bulkSelectAllChange = new EventEmitter();
203
+ /** Fires when the toolbar's dismiss (×) is clicked. */
204
+ this.bulkDismiss = new EventEmitter();
205
+ /**
206
+ * Fires *after* the library-internal move-to-folder dialog resolves with a
207
+ * user confirmation, OR immediately for non-dialog bulk actions supplied by
208
+ * the host. Hosts with their own UX should listen on `bulkActionClick` +
209
+ * `moveRequested` and treat this as the "confirmed" signal.
210
+ */
211
+ this.bulkActionInvoked = new EventEmitter();
212
+ this.sidebarCollapsedChange = new EventEmitter();
213
+ // ============================================================================
214
+ // Row-reorder surface
215
+ // ============================================================================
216
+ /** When true, renders a "Reorder" button in the toolbar. Host-driven. */
217
+ this.showReorderButton = false;
218
+ /**
219
+ * Host flips this true while its bulk-update API call is in-flight. The
220
+ * component keeps the reorder UI pinned ("Saving...") while true and exits
221
+ * reorder mode when it flips back to false (the "future API call" hook).
222
+ */
223
+ this.reorderSaving = false;
224
+ this._reorderLabels = { ...DEFAULT_REORDER_LABELS };
225
+ /** Fires when the user clicks "Reorder" and the component enters reorder mode. */
226
+ this.reorderStart = new EventEmitter();
227
+ /** Fires when the user clicks "Cancel" — the original order is already restored. */
228
+ this.reorderCancel = new EventEmitter();
229
+ /**
230
+ * Fires when the user clicks "Done". Host should take `orderedItems`, call its
231
+ * bulk-update API, refresh `[data]`, and flip `reorderSaving` back to `false` —
232
+ * the component will then exit reorder mode.
233
+ *
234
+ * Note: for server-side pagination, `orderedItems` is the *current page slice*,
235
+ * not the full dataset — same as the in-memory view the user was dragging.
236
+ */
237
+ this.reorderSave = new EventEmitter();
238
+ /** Internal — true while the user is in reorder mode. */
239
+ this.isReordering = false;
240
+ /** Snapshot of `pagedRows` taken on enter; used to revert on cancel. */
241
+ this.reorderSnapshot = null;
242
+ /** Draft of the reordered rows (current working state). */
243
+ this.reorderDraft = null;
244
+ /** Auto-refresh interval captured on enter, so we can restore on cancel/done. */
245
+ this.reorderSavedAutoRefresh = 0;
246
+ /** True after Done has been clicked, awaiting the host's `reorderSaving` → false flip. */
247
+ this.reorderAwaitingSaveFlip = false;
248
+ /**
249
+ * Fires when the user clicks the "Move to folder" bulk action — *before* the
250
+ * internal dialog opens. Hosts that want to render their own modal should
251
+ * set `useInternalDialogs = false` and listen here.
252
+ */
253
+ this.moveRequested = new EventEmitter();
254
+ /** Fires whenever the component's `selectedItems` changes from within (Select All / Dismiss). */
255
+ this.selectedItemsChange = new EventEmitter();
256
+ /**
257
+ * Fires when the user clicks a folder's delete affordance — *before* the
258
+ * internal confirmation dialog opens. Hosts owning the UX listen here.
259
+ * Payload includes `testCount` + `hasParent` so hosts can render the right
260
+ * options in their own modal.
261
+ */
262
+ this.folderDeleteRequested = new EventEmitter();
263
+ /**
264
+ * Fires when the user picks "Move folder" from a folder row's context menu —
265
+ * *before* any dialog opens. Hosts owning the UX listen here with
266
+ * `useInternalDialogs = false` and open their own folder picker.
267
+ */
268
+ this.folderMoveRequested = new EventEmitter();
269
+ /**
270
+ * Fires after the user confirms a folder move via the internal picker
271
+ * (or immediately when `useInternalDialogs = false` and the host drives it).
272
+ */
273
+ this.folderMoved = new EventEmitter();
274
+ /**
275
+ * Fires when the user picks "Duplicate folder" from a folder row's context menu.
276
+ * The library doesn't own persistence, so the host is expected to clone the
277
+ * folder's subtree server-side and *reference* (not copy) the test cases.
278
+ */
279
+ this.folderDuplicateRequested = new EventEmitter();
280
+ this.onReload = new EventEmitter();
281
+ this.onAutoRefreshClick = new EventEmitter();
282
+ this.columnVisibilityChange = new EventEmitter();
283
+ this.autoRefreshIntervalChange = new EventEmitter();
284
+ // Derived columns with visibility applied.
285
+ this.computedColumns = [];
286
+ // Auto-generated visibility columns from columns input
287
+ this.visibilityColumns = [];
288
+ // Export modal state
289
+ this.isExportModalOpen = false;
290
+ /**
291
+ * Row-drag payload builder used by the [cqaRowDrag] directive via (buildPayload).
292
+ */
293
+ this.buildRowDragPayload = (row) => {
294
+ const selected = this.currentSelectedItems;
295
+ // If the dragged row is part of the current selection, drag the whole selection.
296
+ const rowId = row?.id;
297
+ const inSelection = rowId != null && selected.some(s => s?.id === rowId);
298
+ const ids = (inSelection ? selected : [row]).map(r => r?.id).filter(v => v != null);
299
+ return ids;
300
+ };
301
+ }
302
+ get viewModeSegments() {
303
+ return [
304
+ { label: this.viewModeLabels.list, value: 'list', icon: 'view_list' },
305
+ { label: this.viewModeLabels.modular, value: 'modular', icon: 'folder' },
306
+ ];
307
+ }
308
+ onViewModeChange(value) {
309
+ const next = value === 'modular' ? 'modular' : 'list';
310
+ if (next !== this.viewMode) {
311
+ this.viewMode = next;
312
+ this.viewModeChange.emit(next);
313
+ }
314
+ }
315
+ /** Partial override for the default reorder labels ("Reorder", "Done", etc.). */
316
+ set reorderLabels(partial) {
317
+ this._reorderLabels = { ...DEFAULT_REORDER_LABELS, ...(partial || {}) };
318
+ }
319
+ get reorderLabels() {
320
+ return this._reorderLabels;
321
+ }
322
+ updateComputedColumns() {
323
+ const visibility = this._columnVisibility || {};
324
+ const source = this.columns || [];
325
+ this.computedColumns = source.map(col => {
326
+ if (['checkbox', 'actions'].includes(col.fieldId)) {
327
+ return col;
328
+ }
329
+ const show = visibility[col.fieldId];
330
+ return { ...col, isShow: show !== false };
331
+ });
332
+ this.cdr.markForCheck();
333
+ }
334
+ updateVisibilityColumns() {
335
+ this._cachedVisibilityColumns = this.mapVisibilityColumns();
336
+ this.visibilityColumns = this._cachedVisibilityColumns;
337
+ this.cdr.markForCheck();
338
+ }
339
+ // Controlled column visibility: parent can seed and push updates.
340
+ set columnVisibility(cfg) {
341
+ if (cfg) {
342
+ this._columnVisibility = { ...cfg };
343
+ this.updateComputedColumns();
344
+ this.cdr.markForCheck();
345
+ }
346
+ }
347
+ get columnVisibility() {
348
+ return this._columnVisibility;
349
+ }
350
+ ngOnInit() {
351
+ this.initializeComponent();
352
+ this.updateComputedColumns();
353
+ this.updateVisibilityColumns();
354
+ }
355
+ ngOnChanges(changes) {
356
+ if (changes['data'] || changes['isEmptyState']) {
357
+ this.initializeComponent();
358
+ }
359
+ if (changes['columns']) {
360
+ this.initializeColumnVisibility();
361
+ this.updateComputedColumns();
362
+ this.updateVisibilityColumns();
363
+ }
364
+ if (changes['selectedFolderId'] && !changes['selectedFolderId'].firstChange) {
365
+ // Per the approved plan: clear selection and reset pagination on folder change.
366
+ this.selectedItems = [];
367
+ this.pageIndex = 0;
368
+ this.rebuildFilteredRows();
369
+ this.applyPagination();
370
+ }
371
+ if (changes['viewMode'] && !changes['viewMode'].firstChange) {
372
+ // Switching between list and modular changes whether the folder filter applies.
373
+ this.pageIndex = 0;
374
+ this.rebuildFilteredRows();
375
+ this.applyPagination();
376
+ }
377
+ if (changes['selectedItems'] || changes['data']) {
378
+ this.restoreSelectionState();
379
+ }
380
+ if (changes['reorderSaving'] && !changes['reorderSaving'].firstChange) {
381
+ const nowSaving = !!changes['reorderSaving'].currentValue;
382
+ // Host finished its bulk-update call — exit reorder mode.
383
+ if (!nowSaving && this.reorderAwaitingSaveFlip) {
384
+ this.exitReorderMode();
385
+ }
386
+ }
387
+ }
388
+ initializeComponent() {
389
+ if (this.isEmptyState) {
390
+ this.filteredRows = [];
391
+ this.pagedRows = [];
392
+ return;
393
+ }
394
+ // In server-side mode, assume incoming data is already a page slice
395
+ if (this.serverSidePagination) {
396
+ this.filteredRows = [...this.data];
397
+ this.pagedRows = [...this.filteredRows];
398
+ this.initializeColumnVisibility();
399
+ this.restoreSelectionState();
400
+ return;
401
+ }
402
+ this.rebuildFilteredRows();
403
+ this.applyPagination();
404
+ this.initializeColumnVisibility();
405
+ this.updateComputedColumns();
406
+ this.restoreSelectionState();
407
+ }
408
+ /**
409
+ * Build `filteredRows` from `data` by applying (a) the field filters (status/priority/etc.)
410
+ * and (b) the folder filter derived from `selectedFolderId` + `folderIdAccessor`.
411
+ */
412
+ rebuildFilteredRows() {
413
+ const effective = this.appliedFilters ?? {};
414
+ this.filteredRows = this.data.filter(r => this.passFilters(effective, r) && this.passFolder(r));
415
+ }
416
+ passFolder(row) {
417
+ // List view ignores folder filtering entirely — behaves like the traditional flat table.
418
+ if (!this.isModularView)
419
+ return true;
420
+ const folderId = this.folderIdAccessor ? this.folderIdAccessor(row) : row?.folderId;
421
+ // Root view: show only rows that do not belong to any folder (the "Unorganised" bucket).
422
+ // Folder tiles above the table are the entry point to per-folder contents.
423
+ if (this.selectedFolderId == null) {
424
+ return folderId == null;
425
+ }
426
+ return folderId != null && String(folderId) === String(this.selectedFolderId);
427
+ }
428
+ /** True when the component should render the modular (folder-aware) UI. */
429
+ get isModularView() {
430
+ return this.viewMode === 'modular';
431
+ }
432
+ /**
433
+ * Get selected IDs from selectedItems (objects)
434
+ */
435
+ getSelectedIds() {
436
+ if (this.selectedItems && this.selectedItems.length > 0) {
437
+ return new Set(this.selectedItems.map(item => Number(item.id)).filter(id => !isNaN(id)));
438
+ }
439
+ return new Set();
440
+ }
441
+ restoreSelectionState() {
442
+ const selectedIdsSet = this.getSelectedIds();
443
+ if (selectedIdsSet.size === 0) {
444
+ // If no selected IDs, clear all selection states
445
+ if (this.pagedRows) {
446
+ this.pagedRows.forEach(row => {
447
+ if (row) {
448
+ row.isSelected = false;
449
+ }
450
+ });
451
+ }
452
+ return;
453
+ }
454
+ // Restore selection state based on selectedItems
455
+ if (this.pagedRows) {
456
+ this.pagedRows.forEach(row => {
457
+ if (row && row.id !== undefined) {
458
+ row.isSelected = selectedIdsSet.has(Number(row.id));
459
+ }
460
+ });
461
+ }
462
+ // Also update filteredRows for consistency
463
+ if (this.filteredRows) {
464
+ this.filteredRows.forEach(row => {
465
+ if (row && row.id !== undefined) {
466
+ row.isSelected = selectedIdsSet.has(Number(row.id));
467
+ }
468
+ });
469
+ }
470
+ this.cdr.markForCheck();
471
+ }
472
+ initializeColumnVisibility() {
473
+ // Cache visibility columns to avoid creating new arrays on every change detection
474
+ this._cachedVisibilityColumns = this.mapVisibilityColumns();
475
+ // Seed visibility state from each column's isShow (default to true) so consumers
476
+ // can pre-apply persisted preferences via columns[i].isShow.
477
+ const source = this.columns || [];
478
+ for (const col of this._cachedVisibilityColumns) {
479
+ if (this._columnVisibility[col.id] === undefined) {
480
+ const srcCol = source.find(c => c.fieldId === col.id);
481
+ this._columnVisibility[col.id] = srcCol && srcCol.isShow === false ? false : true;
482
+ }
483
+ }
484
+ }
485
+ get anyRowSelected() {
486
+ // Check if there are any selected items (either on current page or across all pages via selectedItems)
487
+ const hasSelectedOnPage = !!(this.pagedRows && this.pagedRows.some(r => !!r.isSelected));
488
+ const selectedIdsSet = this.getSelectedIds();
489
+ const hasSelectedAcrossPages = selectedIdsSet.size > 0;
490
+ return hasSelectedOnPage || hasSelectedAcrossPages;
491
+ }
492
+ get currentSelectedItems() {
493
+ // If selectedItems (full objects) are provided, use them directly
494
+ // This ensures all selected items are returned, including those from other pages
495
+ if (this.selectedItems && this.selectedItems.length > 0) {
496
+ return this.selectedItems;
497
+ }
498
+ // Fallback: For client-side pagination or when selectedItems is not provided,
499
+ // filter pagedRows to get selected items from current page only
500
+ if (!this.pagedRows || this.pagedRows.length === 0) {
501
+ return [];
502
+ }
503
+ const selectedIdsSet = this.getSelectedIds();
504
+ // Filter rows that are selected
505
+ return this.pagedRows
506
+ .filter(r => {
507
+ if (!r || r.id === undefined)
508
+ return false;
509
+ const rowId = Number(r.id);
510
+ // Include if either:
511
+ // 1. The row has isSelected = true (current page selection)
512
+ // 2. The row's ID is in selectedItems (selected on other pages or restored selection)
513
+ return !!r.isSelected || selectedIdsSet.has(rowId);
514
+ });
515
+ }
516
+ actionClick(data) {
517
+ console.log('action toolbar', data);
518
+ }
519
+ view(id) {
520
+ console.log('View', id);
521
+ }
522
+ edit(row) {
523
+ console.log('Edit', row);
524
+ }
525
+ delete(row) {
526
+ console.log('Delete', row);
527
+ }
528
+ toggleFilter() {
529
+ this.showFilterPanel = !this.showFilterPanel;
530
+ }
531
+ onColumnVisibilityChange(cfg) {
532
+ this._columnVisibility = { ...cfg };
533
+ this.updateComputedColumns();
534
+ this.cdr.markForCheck();
535
+ this.columnVisibilityChange.emit({ ...cfg });
536
+ }
537
+ onAutoRefreshChange(intervalMs) {
538
+ this.selectedAutoRefreshInterval = intervalMs;
539
+ this.setupAutoRefresh(intervalMs);
540
+ this.autoRefreshIntervalChange.emit(intervalMs);
541
+ this.triggerReload();
542
+ }
543
+ valueChange(value) {
544
+ console.log('Value changed', value);
545
+ this.onSearchChange.emit(value);
546
+ }
547
+ search(value) {
548
+ console.log('Search', value);
549
+ }
550
+ cleared() {
551
+ console.log('Cleared');
552
+ }
553
+ onEmptyAction(action) {
554
+ if (action?.label === 'Show filters') {
555
+ this.toggleFilter();
556
+ }
557
+ }
558
+ onFiltersChanged(current) {
559
+ // Defer applying filters and updating chips until Apply Filter is clicked
560
+ this.pendingFilters = current;
561
+ }
562
+ onFiltersApplied(applied) {
563
+ this.showFilterPanel = false;
564
+ const effective = applied ?? this.pendingFilters ?? {};
565
+ this.appliedFilters = effective;
566
+ this.rebuildFilteredRows();
567
+ this.pageIndex = 0;
568
+ this.applyPagination();
569
+ const chips = [];
570
+ if (effective) {
571
+ for (const key of Object.keys(effective)) {
572
+ const value = effective[key];
573
+ if (value == null || value === '' || (Array.isArray(value) && value.length === 0))
574
+ continue;
575
+ // Find the filter config item for this key
576
+ const filterConfigItem = this.filterConfig?.find(c => c.key === key);
577
+ const options = filterConfigItem?.options || [];
578
+ // Helper function to find display text from options
579
+ const getDisplayText = (val) => {
580
+ // If value is already an object with name/label, use it
581
+ if (val && typeof val === 'object' && (val.name || val.label || val.value)) {
582
+ return val.name ?? val.label ?? String(val.value ?? val);
583
+ }
584
+ // Look up the option in the config
585
+ const option = options.find((opt) => {
586
+ const optId = opt.id ?? opt.value;
587
+ const optValue = opt.value;
588
+ const valStr = String(val);
589
+ return String(optId) === valStr || String(optValue) === valStr;
590
+ });
591
+ if (option) {
592
+ return option.name ?? option.label ?? String(option.value ?? val);
593
+ }
594
+ // Fallback to the raw value
595
+ return String(val);
596
+ };
597
+ let text = '';
598
+ let label = filterConfigItem?.label;
599
+ if (Array.isArray(value)) {
600
+ text = value.map((v) => getDisplayText(v)).join(', ');
601
+ }
602
+ else if (typeof value === 'object') {
603
+ if ('start' in value || 'end' in value) {
604
+ const s = value.start ? new Date(value.start).toLocaleDateString() : '';
605
+ const e = value.end ? new Date(value.end).toLocaleDateString() : '';
606
+ text = [s, e].filter(Boolean).join(' - ');
607
+ }
608
+ else {
609
+ text = getDisplayText(value);
610
+ }
611
+ }
612
+ else {
613
+ text = getDisplayText(value);
614
+ }
615
+ chips.push({ key, label, text, fullText: text, hasMore: text.length > 30 });
616
+ }
617
+ }
618
+ this.chips = chips;
619
+ this.filterApplied = this.chips.length > 0;
620
+ }
621
+ handleResetFilterClick() {
622
+ // Clear chips and reset filtered data when reset is clicked
623
+ this.pendingFilters = undefined;
624
+ this.appliedFilters = undefined;
625
+ this.chips = [];
626
+ this.filterApplied = false;
627
+ this.rebuildFilteredRows();
628
+ this.pageIndex = 0;
629
+ this.applyPagination();
630
+ this.onResetFilterClick.emit();
631
+ }
632
+ handleRefreshClick() {
633
+ this.onAutoRefreshClick.emit();
634
+ this.triggerReload();
635
+ }
636
+ triggerReload() {
637
+ this.rebuildFilteredRows();
638
+ this.pageIndex = 0;
639
+ this.applyPagination();
640
+ this.onReload.emit();
641
+ }
642
+ setupAutoRefresh(intervalMs) {
643
+ this.clearAutoRefresh();
644
+ if (intervalMs && intervalMs > 0) {
645
+ this.autoRefreshTimer = setInterval(() => {
646
+ this.triggerReload();
647
+ }, intervalMs);
648
+ }
649
+ }
650
+ clearAutoRefresh() {
651
+ if (this.autoRefreshTimer) {
652
+ clearInterval(this.autoRefreshTimer);
653
+ this.autoRefreshTimer = undefined;
654
+ }
655
+ }
656
+ ngOnDestroy() {
657
+ this.clearAutoRefresh();
658
+ }
659
+ onPaginate(e) {
660
+ this.pageIndex = e.pageIndex;
661
+ this.pageSize = e.pageSize;
662
+ if (this.serverSidePagination) {
663
+ this.pageChange.emit({ pageIndex: this.pageIndex, pageSize: this.pageSize });
664
+ return;
665
+ }
666
+ this.applyPagination();
667
+ }
668
+ onPageSizeChange(size) {
669
+ this.pageSize = size;
670
+ this.pageIndex = 0;
671
+ if (this.serverSidePagination) {
672
+ this.pageChange.emit({ pageIndex: this.pageIndex, pageSize: this.pageSize });
673
+ return;
674
+ }
675
+ this.applyPagination();
676
+ }
677
+ onRemoveChip(chip) {
678
+ this.chips = this.chips.filter(c => c !== chip);
679
+ this.filterApplied = this.chips.length > 0;
680
+ // Emit event to parent component (same pattern as execution tab)
681
+ this.removeChip.emit(chip);
682
+ }
683
+ onClearAllChips() {
684
+ this.chips = [];
685
+ this.filterApplied = false;
686
+ // Reset the dynamic-filter component form when clearing all chips
687
+ if (this.dynamicFilterComponent) {
688
+ this.dynamicFilterComponent.reset();
689
+ }
690
+ }
691
+ applyPagination() {
692
+ if (this.serverSidePagination) {
693
+ // Server mode: parent supplies already-paginated data
694
+ this.pagedRows = [...this.filteredRows];
695
+ return;
696
+ }
697
+ const start = this.pageIndex * this.pageSize;
698
+ const end = start + this.pageSize;
699
+ this.pagedRows = this.filteredRows.slice(start, end);
700
+ }
701
+ mapVisibilityColumns() {
702
+ return (this.columns || [])
703
+ .filter(c => c.isDefault === false)
704
+ .map(c => ({ id: c.fieldId, label: c.fieldName || c.fieldId }));
705
+ }
706
+ normalizeDate(d) {
707
+ if (!d)
708
+ return null;
709
+ const ts = Date.parse(d);
710
+ return isNaN(ts) ? null : ts;
711
+ }
712
+ passFilters(filters, row) {
713
+ if (!filters)
714
+ return true;
715
+ if (filters.status && Array.isArray(filters.status) && filters.status.length) {
716
+ if (!filters.status.includes(row.status))
717
+ return false;
718
+ }
719
+ if (filters.priority && Array.isArray(filters.priority) && filters.priority.length) {
720
+ if (!filters.priority.includes(row.priorityName))
721
+ return false;
722
+ }
723
+ if (filters.testType && Array.isArray(filters.testType) && filters.testType.length) {
724
+ if (!filters.testType.includes(row.testType))
725
+ return false;
726
+ }
727
+ if (filters.created_date && (filters.created_date.start || filters.created_date.end)) {
728
+ const startTs = this.normalizeDate(filters.created_date.start);
729
+ const endTs = this.normalizeDate(filters.created_date.end);
730
+ const rowTs = this.normalizeDate(row.createdAt);
731
+ if (rowTs != null) {
732
+ if (startTs != null && rowTs < startTs)
733
+ return false;
734
+ if (endTs != null && rowTs > endTs)
735
+ return false;
736
+ }
737
+ }
738
+ return true;
739
+ }
740
+ trackByTemplateRef(index) {
741
+ return index;
742
+ }
743
+ trackByDropdownTemplateRef(index) {
744
+ return index;
745
+ }
746
+ trackBySelectDropdownTemplateRef(index) {
747
+ return index;
748
+ }
749
+ exportCodeClick() {
750
+ // Get selected items
751
+ const selectedItems = this.currentSelectedItems;
752
+ if (selectedItems.length === 0) {
753
+ // Emit event to parent to handle the case when no items are selected
754
+ this.onExportClick.emit();
755
+ return;
756
+ }
757
+ this.isExportModalOpen = true;
758
+ }
759
+ closeExportModal() {
760
+ this.isExportModalOpen = false;
761
+ }
762
+ onExportModalExport(result) {
763
+ this.isExportModalOpen = false;
764
+ // Emit event to parent with export result
765
+ this.onExportClick.emit({
766
+ type: result.type,
767
+ emails: result.emails,
768
+ framework: result.framework,
769
+ selectedItems: this.currentSelectedItems
770
+ });
771
+ }
772
+ get selectedCasesForExport() {
773
+ return this.currentSelectedItems.map(item => ({
774
+ id: item.id,
775
+ name: item.name || item.title || 'Unnamed'
776
+ }));
777
+ }
778
+ get arrowClasses() {
779
+ const baseClasses = [
780
+ 'cqa-w-4',
781
+ 'cqa-h-4',
782
+ 'cqa-relative',
783
+ 'cqa-transition-transform'
784
+ ];
785
+ if (this.showFilterPanel) {
786
+ baseClasses.push('cqa-rotate-180');
787
+ }
788
+ return baseClasses.join(' ');
789
+ }
790
+ // ============================================================================
791
+ // Folder / modular helpers
792
+ // ============================================================================
793
+ /**
794
+ * Flat list of root-level folders for the "Organised" grid on the root view.
795
+ */
796
+ get rootFolderTiles() {
797
+ return this.folders || [];
798
+ }
799
+ /**
800
+ * Subfolders of the currently-selected folder (for the "Subfolders in ..." grid).
801
+ */
802
+ get subfolderTiles() {
803
+ if (this.selectedFolderId == null)
804
+ return [];
805
+ const node = this.findFolder(this.folders, this.selectedFolderId);
806
+ return node?.children ?? [];
807
+ }
808
+ /**
809
+ * Breadcrumb trail from "All folders" down to the currently-selected folder.
810
+ */
811
+ get breadcrumbTrail() {
812
+ if (this.selectedFolderId == null)
813
+ return [];
814
+ const trail = [];
815
+ this.buildTrail(this.folders, this.selectedFolderId, trail);
816
+ return trail;
817
+ }
818
+ buildTrail(nodes, targetId, acc) {
819
+ for (const n of nodes || []) {
820
+ acc.push(n);
821
+ // Use String() coercion for safety in case ids arrive as either number or
822
+ // string from different API/test data shapes (e.g. raw JSON parse results).
823
+ if (String(n.id) === String(targetId))
824
+ return true;
825
+ if (n.children && this.buildTrail(n.children, targetId, acc))
826
+ return true;
827
+ acc.pop();
828
+ }
829
+ return false;
830
+ }
831
+ findFolder(nodes, targetId) {
832
+ for (const n of nodes || []) {
833
+ if (String(n.id) === String(targetId))
834
+ return n;
835
+ const found = n.children ? this.findFolder(n.children, targetId) : null;
836
+ if (found)
837
+ return found;
838
+ }
839
+ return null;
840
+ }
841
+ /**
842
+ * Whether the component is in "root" view (no folder selected). Controls which
843
+ * sections render on the right-hand pane.
844
+ */
845
+ get isRootView() {
846
+ return this.selectedFolderId == null;
847
+ }
848
+ /** The currently-selected folder node (or null at root). */
849
+ get currentFolderNode() {
850
+ if (this.selectedFolderId == null)
851
+ return null;
852
+ return this.findFolder(this.folders, this.selectedFolderId);
853
+ }
854
+ /** Count of test cases directly under the currently-selected folder (excluding descendants). */
855
+ get currentFolderDirectCount() {
856
+ if (this.selectedFolderId == null)
857
+ return 0;
858
+ return this.filteredRows.length;
859
+ }
860
+ /**
861
+ * Renders the empty-state slot when the host explicitly opts in, OR when the
862
+ * table would otherwise render blank (no loading + no rows). Using a derived
863
+ * flag keeps the host contract identical to `cqa-table-template` while letting
864
+ * the modular view show "No Test Case Found" out of the box — the earlier ask.
865
+ */
866
+ get effectiveIsEmptyState() {
867
+ if (this.isEmptyState)
868
+ return true;
869
+ if (this.isTableLoading || this.isTableDataLoading)
870
+ return false;
871
+ return !this.pagedRows || this.pagedRows.length === 0;
872
+ }
873
+ /**
874
+ * Picks the host-provided `emptyStateConfig` when the host flagged the state
875
+ * itself; otherwise falls back to a library-owned "No Test Case Found" config
876
+ * driven by `modularLabels`.
877
+ */
878
+ get effectiveEmptyStateConfig() {
879
+ if (this.isEmptyState)
880
+ return this.emptyStateConfig;
881
+ return {
882
+ title: this.modularLabels.emptyNoTestsInFolderTitle,
883
+ description: this.modularLabels.emptyNoTestsInFolderDescription,
884
+ imageUrl: EMPTY_STATE_IMAGES.TEST_CASE,
885
+ actions: [],
886
+ };
887
+ }
888
+ onFolderSelected(id) {
889
+ this.selectedFolderId = id;
890
+ this.selectedItems = [];
891
+ this.pageIndex = 0;
892
+ this.rebuildFilteredRows();
893
+ this.applyPagination();
894
+ this.folderSelected.emit(id);
895
+ this.cdr.markForCheck();
896
+ }
897
+ onFolderExpansionToggled(event) {
898
+ const set = new Set(this.expandedFolderIds || []);
899
+ if (event.expanded) {
900
+ set.add(event.id);
901
+ }
902
+ else {
903
+ set.delete(event.id);
904
+ }
905
+ this.expandedFolderIds = Array.from(set);
906
+ this.folderExpansionToggled.emit(event);
907
+ }
908
+ onFolderCreated(payload) {
909
+ this.folderCreated.emit(payload);
910
+ }
911
+ onFolderCreateRequested(payload) {
912
+ // Emit the "requested" event first so a host can intercept when it owns the UX.
913
+ this.folderCreateRequested.emit(payload);
914
+ if (!this.useInternalDialogs)
915
+ return;
916
+ this.openCreateFolderDialog(payload.parentId);
917
+ }
918
+ onFolderRenamed(payload) {
919
+ this.folderRenamed.emit(payload);
920
+ }
921
+ /**
922
+ * Wired to the sidebar's `folderDeleted` output — which fires on delete-icon
923
+ * *click*, not on confirmation. We re-emit a `folderDeleteRequested` event
924
+ * first (so hosts can intercept) and, when `useInternalDialogs` is enabled,
925
+ * open the confirmation dialog. `folderDeleted` now only fires after confirm.
926
+ */
927
+ onFolderDeleted(payload) {
928
+ const ctx = this.buildDeleteContext(payload.id);
929
+ this.folderDeleteRequested.emit(ctx);
930
+ if (!this.useInternalDialogs)
931
+ return;
932
+ this.openDeleteFolderDialog(ctx);
933
+ }
934
+ /** Builds the { id, name, testCount, hasParent } payload used by delete events/dialogs. */
935
+ buildDeleteContext(folderId) {
936
+ const node = this.findFolder(this.folders, folderId);
937
+ return {
938
+ id: folderId,
939
+ name: node?.name ?? '',
940
+ testCount: this.countTestsInFolder(folderId),
941
+ hasParent: this.folderHasParent(folderId),
942
+ };
943
+ }
944
+ countTestsInFolder(folderId) {
945
+ const accessor = this.folderIdAccessor ?? ((r) => r?.folderId);
946
+ return (this.data || []).filter(r => {
947
+ const id = accessor(r);
948
+ return id != null && Number(id) === Number(folderId);
949
+ }).length;
950
+ }
951
+ /** Returns true when the folder is nested (i.e. not a root-level folder). */
952
+ folderHasParent(folderId) {
953
+ return !(this.folders || []).some(n => n.id === folderId);
954
+ }
955
+ onTestsDropped(event) {
956
+ if (!this.modularConfig.allowTestDragDrop)
957
+ return;
958
+ this.testsMoved.emit(event);
959
+ }
960
+ /**
961
+ * Folder-to-folder drag-drop. The sidebar has already validated against self/descendant
962
+ * cycles, so the drop is its own confirmation — we emit `folderMoved` directly without
963
+ * opening the move dialog. Gated on `allowTestDragDrop` (same flag as test drag-drop).
964
+ */
965
+ onFolderDropped(event) {
966
+ if (!this.modularConfig.allowTestDragDrop)
967
+ return;
968
+ this.folderMoved.emit(event);
969
+ }
970
+ /**
971
+ * Sidebar emitted `folderMoveRequested` (user picked "Move folder" from the context menu).
972
+ * We re-emit a richer payload for hosts, and — when running with internal dialogs —
973
+ * open the existing move-to-folder picker configured for a folder-move (self and
974
+ * descendants are disabled to prevent cycles).
975
+ */
976
+ onFolderMoveRequested(payload) {
977
+ const node = this.findFolder(this.folders, payload.id);
978
+ const ctx = {
979
+ id: payload.id,
980
+ name: node?.name ?? '',
981
+ hasParent: this.folderHasParent(payload.id),
982
+ };
983
+ this.folderMoveRequested.emit(ctx);
984
+ if (!this.useInternalDialogs)
985
+ return;
986
+ this.openMoveFolderDialog(ctx);
987
+ }
988
+ /**
989
+ * Sidebar emitted `folderDuplicateRequested`. The library can't persist —
990
+ * emit the host-level event so the host clones the subtree server-side.
991
+ * Test cases should be *referenced* from the new folders, not duplicated.
992
+ */
993
+ onFolderDuplicateRequested(payload) {
994
+ const node = this.findFolder(this.folders, payload.id);
995
+ this.folderDuplicateRequested.emit({
996
+ id: payload.id,
997
+ name: node?.name ?? '',
998
+ });
999
+ }
1000
+ onSidebarCollapsedChange(collapsed) {
1001
+ this.sidebarCollapsed = collapsed;
1002
+ this.sidebarCollapsedChange.emit(collapsed);
1003
+ }
1004
+ toggleSidebar() {
1005
+ this.onSidebarCollapsedChange(!this.sidebarCollapsed);
1006
+ }
1007
+ /**
1008
+ * Default bulk actions shown in the toolbar merged with any host-supplied
1009
+ * `bulkActions`. Currently only "Move to folder" ships by default —
1010
+ * Delete / Add Tag are opt-in per the current product requirement. Hosts
1011
+ * that want them back pass them via `bulkActions`.
1012
+ */
1013
+ get effectiveBulkActions() {
1014
+ const defaults = [
1015
+ { id: 'move', label: this.modularLabels.moveToFolder, icon: 'drive_file_move', tooltip: this.modularLabels.moveToFolder },
1016
+ ];
1017
+ const overrides = new Map((this.bulkActions || []).map(a => [a.id, a]));
1018
+ const merged = defaults.map(d => overrides.get(d.id) ?? d);
1019
+ for (const extra of this.bulkActions || []) {
1020
+ if (!defaults.some(d => d.id === extra.id)) {
1021
+ merged.push(extra);
1022
+ }
1023
+ }
1024
+ return merged;
1025
+ }
1026
+ onBulkAction(event) {
1027
+ // Always emit the raw click so hosts owning the UX can intercept early.
1028
+ this.bulkActionClick.emit({ id: event.id, selected: event.selected });
1029
+ const selectedIds = (event.selected || []).map(r => r?.id).filter(v => v != null);
1030
+ if (event.id === 'move') {
1031
+ this.openMoveDialog(selectedIds, event.selected);
1032
+ return;
1033
+ }
1034
+ // For non-dialog actions (custom entries from host-supplied `bulkActions`), invoke immediately.
1035
+ this.bulkActionInvoked.emit({ id: event.id, selected: event.selected });
1036
+ }
1037
+ onBulkSelectAll(checked) {
1038
+ // Apply the action locally so the action toolbar's "Select all" works out-of-the-box.
1039
+ // When checked, select every row in the *current* filtered set (i.e. all tests in
1040
+ // the selected folder). When unchecked, clear selection.
1041
+ this.selectedItems = checked ? [...this.filteredRows] : [];
1042
+ this.restoreSelectionState();
1043
+ this.selectedItemsChange.emit([...this.selectedItems]);
1044
+ this.bulkSelectAllChange.emit(checked);
1045
+ this.cdr.markForCheck();
1046
+ }
1047
+ onBulkDismiss() {
1048
+ // Clear selection AND the per-row isSelected flags so the action toolbar closes
1049
+ // (it's gated on `anyRowSelected`, which reads both selectedItems and row flags).
1050
+ this.selectedItems = [];
1051
+ this.restoreSelectionState();
1052
+ this.selectedItemsChange.emit([]);
1053
+ this.bulkDismiss.emit();
1054
+ this.cdr.markForCheck();
1055
+ }
1056
+ openMoveDialog(testIds, selected) {
1057
+ // Fire the "requested" event first so a host can intercept when it owns the UX.
1058
+ this.moveRequested.emit({
1059
+ testIds,
1060
+ selected,
1061
+ currentFolderId: this.selectedFolderId,
1062
+ folders: this.folders,
1063
+ });
1064
+ if (!this.useInternalDialogs)
1065
+ return;
1066
+ const count = testIds.length;
1067
+ const description = (count === 1
1068
+ ? this.modularLabels.moveDialogDescriptionSingular
1069
+ : this.modularLabels.moveDialogDescriptionPlural).replace('{n}', '' + count);
1070
+ const ref = this.dialogService.open({
1071
+ title: this.modularLabels.moveDialogTitle,
1072
+ description,
1073
+ width: '500px',
1074
+ content: {
1075
+ type: 'component',
1076
+ component: MoveToFolderDialogComponent,
1077
+ inputs: {
1078
+ folders: this.folders,
1079
+ labels: this.modularLabels,
1080
+ currentFolderId: this.selectedFolderId,
1081
+ },
1082
+ },
1083
+ buttons: [
1084
+ { label: this.modularLabels.moveDialogCancel, role: 'secondary', handler: r => r.close(undefined) },
1085
+ {
1086
+ label: this.modularLabels.moveDialogConfirm,
1087
+ role: 'primary',
1088
+ handler: r => {
1089
+ const instance = r.getComponentInstance();
1090
+ r.close(instance ? instance.pickedFolderId : null);
1091
+ },
1092
+ },
1093
+ ],
1094
+ buttonAlignment: 'right',
1095
+ });
1096
+ ref.afterClosed().subscribe(targetFolderId => {
1097
+ if (targetFolderId === undefined)
1098
+ return; // cancelled
1099
+ this.testsMoved.emit({ testIds, targetFolderId: targetFolderId ?? null });
1100
+ this.bulkActionInvoked.emit({ id: 'move', selected });
1101
+ });
1102
+ }
1103
+ /**
1104
+ * Opens the folder-picker dialog configured for moving a folder (rather than tests).
1105
+ * The source folder itself is marked as the "current" folder so it's rendered as
1106
+ * disabled in the picker. On confirm, emits `folderMoved` with the chosen parent.
1107
+ */
1108
+ openMoveFolderDialog(ctx) {
1109
+ const ref = this.dialogService.open({
1110
+ title: this.modularLabels.folderMenuMove,
1111
+ width: '500px',
1112
+ content: {
1113
+ type: 'component',
1114
+ component: MoveToFolderDialogComponent,
1115
+ inputs: {
1116
+ folders: this.folders,
1117
+ labels: this.modularLabels,
1118
+ // Reuse the "disabled" treatment: the folder being moved can't be its own destination.
1119
+ currentFolderId: ctx.id,
1120
+ },
1121
+ },
1122
+ buttons: [
1123
+ { label: this.modularLabels.moveDialogCancel, role: 'secondary', handler: r => r.close(undefined) },
1124
+ {
1125
+ label: this.modularLabels.moveDialogConfirm,
1126
+ role: 'primary',
1127
+ handler: r => {
1128
+ const instance = r.getComponentInstance();
1129
+ r.close(instance ? instance.pickedFolderId : null);
1130
+ },
1131
+ },
1132
+ ],
1133
+ buttonAlignment: 'right',
1134
+ });
1135
+ ref.afterClosed().subscribe(targetFolderId => {
1136
+ if (targetFolderId === undefined)
1137
+ return; // cancelled
1138
+ this.folderMoved.emit({ id: ctx.id, newParentId: targetFolderId ?? null });
1139
+ });
1140
+ }
1141
+ openCreateFolderDialog(initialParentId) {
1142
+ const ref = this.dialogService.open({
1143
+ title: this.modularLabels.newFolderDialogTitle,
1144
+ description: this.modularLabels.newFolderDialogDescription,
1145
+ width: '500px',
1146
+ content: {
1147
+ type: 'component',
1148
+ component: NewFolderDialogComponent,
1149
+ inputs: {
1150
+ folders: this.folders,
1151
+ labels: this.modularLabels,
1152
+ name: '',
1153
+ parentId: initialParentId,
1154
+ },
1155
+ },
1156
+ buttons: [
1157
+ { label: this.modularLabels.newFolderDialogCancel, role: 'secondary', handler: r => r.close(false) },
1158
+ {
1159
+ label: this.modularLabels.newFolderDialogConfirm,
1160
+ role: 'primary',
1161
+ handler: r => {
1162
+ const inst = r.getComponentInstance();
1163
+ if (!inst || !inst.isValid)
1164
+ return false; // keep the dialog open on invalid submit
1165
+ r.close({ name: (inst.name || '').trim(), parentId: inst.parentId, color: inst.color });
1166
+ return;
1167
+ },
1168
+ },
1169
+ ],
1170
+ buttonAlignment: 'right',
1171
+ });
1172
+ ref.afterClosed().subscribe(result => {
1173
+ if (result) {
1174
+ this.folderCreated.emit({ parentId: result.parentId, name: result.name, color: result.color });
1175
+ }
1176
+ });
1177
+ }
1178
+ openDeleteFolderDialog(ctx) {
1179
+ const ref = this.dialogService.open({
1180
+ title: this.modularLabels.deleteFolderDialogTitle,
1181
+ width: '500px',
1182
+ content: {
1183
+ type: 'component',
1184
+ component: DeleteFolderDialogComponent,
1185
+ inputs: {
1186
+ folderName: ctx.name,
1187
+ testCount: ctx.testCount,
1188
+ hasParent: ctx.hasParent,
1189
+ labels: this.modularLabels,
1190
+ strategy: ctx.hasParent ? 'move-to-parent' : 'move-to-unorganised',
1191
+ },
1192
+ },
1193
+ buttons: [
1194
+ { label: this.modularLabels.deleteFolderDialogCancel, role: 'secondary', handler: r => r.close(false) },
1195
+ {
1196
+ label: this.modularLabels.deleteFolderDialogConfirm,
1197
+ role: 'warn',
1198
+ handler: r => {
1199
+ const inst = r.getComponentInstance();
1200
+ r.close(inst ? { strategy: inst.strategy } : false);
1201
+ },
1202
+ },
1203
+ ],
1204
+ buttonAlignment: 'right',
1205
+ });
1206
+ ref.afterClosed().subscribe(result => {
1207
+ if (result) {
1208
+ this.folderDeleted.emit({ id: ctx.id, strategy: result.strategy });
1209
+ }
1210
+ });
1211
+ }
1212
+ // ============================================================================
1213
+ // Row-reorder handlers
1214
+ // ============================================================================
1215
+ startReorder() {
1216
+ if (this.isReordering)
1217
+ return;
1218
+ this.reorderSnapshot = [...(this.pagedRows || [])];
1219
+ this.reorderDraft = [...(this.pagedRows || [])];
1220
+ // Pause auto-refresh while reordering — avoids the timer clobbering the draft.
1221
+ this.reorderSavedAutoRefresh = this.selectedAutoRefreshInterval;
1222
+ if (this.reorderSavedAutoRefresh > 0) {
1223
+ this.setupAutoRefresh(0);
1224
+ }
1225
+ this.isReordering = true;
1226
+ this.reorderAwaitingSaveFlip = false;
1227
+ this.reorderStart.emit();
1228
+ this.cdr.markForCheck();
1229
+ }
1230
+ cancelReorder() {
1231
+ if (!this.isReordering)
1232
+ return;
1233
+ // Restore the original page order so the user sees the pre-drag state.
1234
+ if (this.reorderSnapshot) {
1235
+ this.pagedRows = [...this.reorderSnapshot];
1236
+ }
1237
+ this.exitReorderMode();
1238
+ this.reorderCancel.emit();
1239
+ }
1240
+ saveReorder() {
1241
+ if (!this.isReordering)
1242
+ return;
1243
+ const ordered = this.reorderDraft ? [...this.reorderDraft] : [...(this.pagedRows || [])];
1244
+ this.reorderAwaitingSaveFlip = true;
1245
+ this.reorderSave.emit({ orderedItems: ordered });
1246
+ // If the host never flips `reorderSaving` (e.g. synchronous no-op), exit
1247
+ // immediately so the UI doesn't get stuck in "Saving..." state.
1248
+ if (!this.reorderSaving) {
1249
+ // Give the host a microtask to flip `reorderSaving` to true — if it
1250
+ // hasn't, assume no async work and exit.
1251
+ Promise.resolve().then(() => {
1252
+ if (this.reorderAwaitingSaveFlip && !this.reorderSaving) {
1253
+ this.exitReorderMode();
1254
+ }
1255
+ });
1256
+ }
1257
+ }
1258
+ onRowReorder(event) {
1259
+ if (!this.isReordering)
1260
+ return;
1261
+ this.reorderDraft = [...event.orderedData];
1262
+ this.pagedRows = this.reorderDraft;
1263
+ this.cdr.markForCheck();
1264
+ }
1265
+ exitReorderMode() {
1266
+ this.isReordering = false;
1267
+ this.reorderSnapshot = null;
1268
+ this.reorderDraft = null;
1269
+ this.reorderAwaitingSaveFlip = false;
1270
+ // Restore previously-selected auto-refresh interval (if any).
1271
+ if (this.reorderSavedAutoRefresh > 0) {
1272
+ this.setupAutoRefresh(this.reorderSavedAutoRefresh);
1273
+ this.reorderSavedAutoRefresh = 0;
1274
+ }
1275
+ this.cdr.markForCheck();
1276
+ }
1277
+ }
1278
+ ModularTableTemplateComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: ModularTableTemplateComponent, deps: [{ token: i0.ChangeDetectorRef }, { token: i1.DialogService }], target: i0.ɵɵFactoryTarget.Component });
1279
+ ModularTableTemplateComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.4.0", type: ModularTableTemplateComponent, selector: "cqa-modular-table-template", inputs: { searchPlaceholder: "searchPlaceholder", searchValue: "searchValue", showClear: "showClear", showSearchBar: "showSearchBar", showExportButton: "showExportButton", isExporting: "isExporting", filterConfig: "filterConfig", filterModel: "filterModel", showFilterPanel: "showFilterPanel", showFilterButton: "showFilterButton", otherButtons: "otherButtons", otherDropDownButtons: "otherDropDownButtons", otherSelectDropDownButtons: "otherSelectDropDownButtons", otherButtonLabel: "otherButtonLabel", otherButtonVariant: "otherButtonVariant", showOtherButton: "showOtherButton", showActionButton: "showActionButton", showSettingsButton: "showSettingsButton", showAutoRefreshButton: "showAutoRefreshButton", showViewModeToggle: "showViewModeToggle", viewMode: "viewMode", viewModeLabels: "viewModeLabels", data: "data", isEmptyState: "isEmptyState", emptyStateConfig: "emptyStateConfig", actions: "actions", chips: "chips", filterApplied: "filterApplied", columns: "columns", rowSelectable: "rowSelectable", selectedAutoRefreshInterval: "selectedAutoRefreshInterval", pageIndex: "pageIndex", pageSize: "pageSize", pageSizeOptions: "pageSizeOptions", pageSizeMenuDirection: "pageSizeMenuDirection", serverSidePagination: "serverSidePagination", totalElements: "totalElements", enableLocalSort: "enableLocalSort", isTableLoading: "isTableLoading", isTableDataLoading: "isTableDataLoading", cellJsonPathGetter: "cellJsonPathGetter", onJsonPathCopiedHandler: "onJsonPathCopiedHandler", selectedItems: "selectedItems", showSelectAllInToolbar: "showSelectAllInToolbar", showDismissInToolbar: "showDismissInToolbar", allSelectedInToolbar: "allSelectedInToolbar", folders: "folders", selectedFolderId: "selectedFolderId", expandedFolderIds: "expandedFolderIds", unorganisedCount: "unorganisedCount", folderIdAccessor: "folderIdAccessor", modularConfig: "modularConfig", modularLabels: "modularLabels", bulkActions: "bulkActions", sidebarCollapsed: "sidebarCollapsed", useInternalDialogs: "useInternalDialogs", showReorderButton: "showReorderButton", reorderSaving: "reorderSaving", reorderLabels: "reorderLabels", columnVisibility: "columnVisibility" }, outputs: { onSearchChange: "onSearchChange", onExportClick: "onExportClick", onApplyFilterClick: "onApplyFilterClick", onResetFilterClick: "onResetFilterClick", onClearAll: "onClearAll", removeChip: "removeChip", viewModeChange: "viewModeChange", pageChange: "pageChange", sortChange: "sortChange", folderSelected: "folderSelected", folderExpansionToggled: "folderExpansionToggled", folderCreated: "folderCreated", folderCreateRequested: "folderCreateRequested", folderRenamed: "folderRenamed", folderDeleted: "folderDeleted", testsMoved: "testsMoved", bulkActionClick: "bulkActionClick", bulkSelectAllChange: "bulkSelectAllChange", bulkDismiss: "bulkDismiss", bulkActionInvoked: "bulkActionInvoked", sidebarCollapsedChange: "sidebarCollapsedChange", reorderStart: "reorderStart", reorderCancel: "reorderCancel", reorderSave: "reorderSave", moveRequested: "moveRequested", selectedItemsChange: "selectedItemsChange", folderDeleteRequested: "folderDeleteRequested", folderMoveRequested: "folderMoveRequested", folderMoved: "folderMoved", folderDuplicateRequested: "folderDuplicateRequested", onReload: "onReload", onAutoRefreshClick: "onAutoRefreshClick", columnVisibilityChange: "columnVisibilityChange", autoRefreshIntervalChange: "autoRefreshIntervalChange" }, host: { classAttribute: "cqa-ui-root" }, viewQueries: [{ propertyName: "dynamicFilterComponent", first: true, predicate: DynamicFilterComponent, descendants: true }], usesOnChanges: true, ngImport: i0, template: "<!-- Reusable folder-icon chip. Render via <ng-container *ngTemplateOutlet=\"folderIconChip\"></ng-container>. -->\n<ng-template #folderIconChip>\n <span class=\"cqa-inline-flex cqa-items-center cqa-justify-center cqa-w-10 cqa-h-10 cqa-rounded-[10px] cqa-bg-neutral-100 cqa-shrink-0\">\n <svg width=\"17\" height=\"15\" viewBox=\"0 0 17 15\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <path d=\"M15.6375 12.6377C15.6375 13.0355 15.4794 13.4171 15.1981 13.6984C14.9168 13.9797 14.5353 14.1377 14.1375 14.1377H2.13745C1.73963 14.1377 1.3581 13.9797 1.07679 13.6984C0.795486 13.4171 0.637451 13.0355 0.637451 12.6377V2.1377C0.637451 1.73987 0.795486 1.35834 1.07679 1.07704C1.3581 0.795731 1.73963 0.637695 2.13745 0.637695H5.88745L7.38745 2.8877H14.1375C14.5353 2.8877 14.9168 3.04573 15.1981 3.32704C15.4794 3.60834 15.6375 3.98987 15.6375 4.3877V12.6377Z\" stroke=\"#6D6D74\" stroke-width=\"1.275\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </span>\n</ng-template>\n\n<!-- Reusable \"+\" chip used by the \"New folder\" tile. -->\n<ng-template #addIconChip>\n <span class=\"cqa-inline-flex cqa-items-center cqa-justify-center cqa-w-10 cqa-h-10 cqa-rounded-[10px] cqa-bg-neutral-100 cqa-shrink-0\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <path d=\"M8 3V13M3 8H13\" stroke=\"#6D6D74\" stroke-width=\"1.275\" stroke-linecap=\"round\"/>\n </svg>\n </span>\n</ng-template>\n\n<div class=\"cqa-ui-root\">\n <div class=\"cqa-w-full cqa-flex cqa-flex-col cqa-relative\">\n <div [class]=\"!showSearchBar ? 'cqa-justify-end' : 'cqa-justify-between'\" class=\"cqa-w-full cqa-flex cqa-items-center cqa-gap-3 cqa-flex-wrap cqa-mb-3\">\n <cqa-search-bar\n *ngIf=\"showSearchBar\"\n [placeholder]=\"searchPlaceholder\"\n [value]=\"searchValue\"\n [showClear]=\"showClear\"\n (valueChange)=\"valueChange($event)\"\n (search)=\"search($event)\"\n (cleared)=\"cleared()\"\n ></cqa-search-bar>\n <div class=\"cqa-flex cqa-items-center cqa-gap-2 cqa-flex-wrap\">\n <cqa-button\n *ngIf=\"showExportButton\"\n variant=\"grey-solid\"\n icon=\"open_in_new\"\n [text]=\"isExporting ? 'Exporting...' : 'Export'\"\n [disabled]=\"isExporting\"\n (clicked)=\"exportCodeClick()\"\n >\n <span>{{ isExporting ? 'Exporting...' : 'Export' }}</span>\n </cqa-button>\n \n <!-- Export Code Modal -->\n <cqa-export-code-modal\n *ngIf=\"showExportButton\"\n [isOpen]=\"isExportModalOpen\"\n [cases]=\"selectedCasesForExport\"\n [disabled]=\"false\"\n (closeModal)=\"closeExportModal()\"\n (export)=\"onExportModalExport($event)\">\n </cqa-export-code-modal>\n <ng-container *ngFor=\"let dropdownTemplate of otherDropDownButtons; trackBy: trackByDropdownTemplateRef\">\n <ng-container *ngTemplateOutlet=\"dropdownTemplate\"></ng-container>\n </ng-container>\n\n <ng-container *ngFor=\"let selectDropdownTemplate of otherSelectDropDownButtons; trackBy: trackBySelectDropdownTemplateRef\">\n <ng-container *ngTemplateOutlet=\"selectDropdownTemplate\"></ng-container>\n </ng-container>\n \n <cqa-button\n *ngIf=\"showFilterButton\"\n variant=\"grey-solid\"\n icon=\"add\"\n [disabled]=\"isReordering\"\n (clicked)=\"toggleFilter()\"\n >\n <span class=\"cqa-flex cqa-items-center cqa-gap-1\">\n Filter \n <div [class]=\"arrowClasses\">\n <svg\n class=\"cqa-w-2 cqa-h-1 cqa-absolute cqa-left-[4px] cqa-top-[6px]\"\n viewBox=\"0 0 8 4\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M0 0L4 4L8 0\"\n stroke=\"#0B0B0C\"\n stroke-width=\"1.33\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n </div>\n </span>\n </cqa-button>\n <cqa-column-visibility\n *ngIf=\"showSettingsButton\"\n [columns]=\"visibilityColumns\"\n [columnVisibility]=\"columnVisibility\"\n [selectedAutoRefreshInterval]=\"selectedAutoRefreshInterval\"\n (columnVisibilityChange)=\"onColumnVisibilityChange($event)\"\n (autoRefreshChange)=\"onAutoRefreshChange($event)\"\n ></cqa-column-visibility>\n <cqa-button\n *ngIf=\"showAutoRefreshButton\"\n variant=\"grey-solid\"\n icon=\"refresh\"\n (clicked)=\"handleRefreshClick()\"\n [tooltip]=\"'Refresh'\"\n tooltipPosition=\"below\"\n [disabled]=\"isReordering\"\n ></cqa-button>\n <ng-container *ngFor=\"let buttonTemplate of otherButtons; trackBy: trackByTemplateRef\">\n <ng-container *ngTemplateOutlet=\"buttonTemplate\"></ng-container>\n </ng-container>\n <cqa-segment-control\n *ngIf=\"showViewModeToggle\"\n size=\"lg\"\n [segments]=\"viewModeSegments\"\n [value]=\"viewMode\"\n (valueChange)=\"onViewModeChange($event)\"\n ></cqa-segment-control>\n <cqa-button\n *ngIf=\"showReorderButton && !isReordering\"\n variant=\"outlined\"\n icon=\"drag_indicator\"\n [text]=\"reorderLabels.reorderButton\"\n [disabled]=\"!pagedRows || pagedRows.length === 0 || isTableLoading || isTableDataLoading\"\n (clicked)=\"startReorder()\"\n ></cqa-button>\n <ng-container *ngIf=\"showReorderButton && isReordering\">\n <cqa-button\n variant=\"outlined\"\n [text]=\"reorderLabels.cancelButton\"\n [disabled]=\"reorderSaving\"\n (clicked)=\"cancelReorder()\"\n ></cqa-button>\n <cqa-button\n variant=\"filled\"\n [icon]=\"reorderSaving ? 'hourglass_empty' : ''\"\n [text]=\"reorderSaving ? reorderLabels.savingButton : reorderLabels.doneButton\"\n [disabled]=\"reorderSaving\"\n (clicked)=\"saveReorder()\"\n ></cqa-button>\n </ng-container>\n </div>\n </div>\n\n <!-- Reorder mode banner -->\n <div *ngIf=\"isReordering\" class=\"cqa-flex cqa-items-center cqa-gap-2 cqa-mb-3 cqa-px-3 cqa-py-2 cqa-rounded-md cqa-bg-[#FFFBEB] cqa-border cqa-border-[#FDE68A]\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <circle cx=\"3\" cy=\"3\" r=\"1.5\" fill=\"#92400E\"></circle>\n <circle cx=\"8\" cy=\"3\" r=\"1.5\" fill=\"#92400E\"></circle>\n <circle cx=\"13\" cy=\"3\" r=\"1.5\" fill=\"#92400E\"></circle>\n <circle cx=\"3\" cy=\"8\" r=\"1.5\" fill=\"#92400E\"></circle>\n <circle cx=\"8\" cy=\"8\" r=\"1.5\" fill=\"#92400E\"></circle>\n <circle cx=\"13\" cy=\"8\" r=\"1.5\" fill=\"#92400E\"></circle>\n <circle cx=\"3\" cy=\"13\" r=\"1.5\" fill=\"#92400E\"></circle>\n <circle cx=\"8\" cy=\"13\" r=\"1.5\" fill=\"#92400E\"></circle>\n <circle cx=\"13\" cy=\"13\" r=\"1.5\" fill=\"#92400E\"></circle>\n </svg>\n <span class=\"cqa-text-sm cqa-font-semibold cqa-text-[#92400E]\">{{ reorderLabels.bannerTitle }}</span>\n <span class=\"cqa-text-sm cqa-text-[#92400E]\">{{ reorderLabels.bannerDescription }}</span>\n </div>\n\n <cqa-selected-filters\n [filterApplied]=\"filterApplied\"\n [chips]=\"chips\"\n (removeChip)=\"onRemoveChip($event)\"\n (clearAll)=\"onClearAllChips()\"\n (onClearAll)=\"onClearAll.emit()\"\n >\n </cqa-selected-filters>\n\n <cqa-dynamic-filter\n *ngIf=\"showFilterPanel\"\n [config]=\"filterConfig\"\n [model]=\"filterModel\"\n [showFilterPanel]=\"showFilterPanel\"\n (filtersChanged)=\"onFiltersChanged($event)\"\n (filtersApplied)=\"onFiltersApplied($event)\"\n (onApplyFilterClick)=\"onApplyFilterClick.emit($event)\"\n (onResetFilterClick)=\"handleResetFilterClick()\"\n >\n </cqa-dynamic-filter>\n\n <div class=\"cqa-flex cqa-items-stretch cqa-gap-3 cqa-min-h-0\">\n <!-- Sidebar (only shown in modular view) -->\n <cqa-folder-sidebar\n *ngIf=\"isModularView && modularConfig.showSidebar\"\n [folders]=\"folders\"\n [selectedFolderId]=\"selectedFolderId\"\n [expandedFolderIds]=\"expandedFolderIds\"\n [unorganisedCount]=\"unorganisedCount\"\n [allowCreate]=\"modularConfig.allowCreateFolder\"\n [allowRename]=\"modularConfig.allowRenameFolder\"\n [allowDelete]=\"modularConfig.allowDeleteFolder\"\n [allowDrop]=\"modularConfig.allowTestDragDrop\"\n [showCounts]=\"modularConfig.showCounts\"\n [collapsed]=\"sidebarCollapsed\"\n [labels]=\"modularLabels\"\n (folderSelected)=\"onFolderSelected($event)\"\n (folderExpansionToggled)=\"onFolderExpansionToggled($event)\"\n (folderCreated)=\"onFolderCreated($event)\"\n (folderCreateRequested)=\"onFolderCreateRequested($event)\"\n (folderRenamed)=\"onFolderRenamed($event)\"\n (folderDeleted)=\"onFolderDeleted($event)\"\n (folderMoveRequested)=\"onFolderMoveRequested($event)\"\n (folderDuplicateRequested)=\"onFolderDuplicateRequested($event)\"\n (testsDropped)=\"onTestsDropped($event)\"\n (folderDropped)=\"onFolderDropped($event)\"\n (collapsedChange)=\"onSidebarCollapsedChange($event)\"\n ></cqa-folder-sidebar>\n\n <!-- Right pane -->\n <div class=\"cqa-flex-1 cqa-flex cqa-flex-col cqa-min-w-0\">\n <!-- Breadcrumb (modular view, folder drilled-in) -->\n <nav\n *ngIf=\"isModularView && modularConfig.showBreadcrumb && !isRootView\"\n aria-label=\"Folder path\"\n class=\"cqa-flex cqa-items-center cqa-gap-1 cqa-text-sm cqa-text-neutral-600 cqa-mb-3\"\n >\n <button type=\"button\" class=\"hover:cqa-text-indigo-600\" (click)=\"onFolderSelected(null)\">\n <mat-icon class=\"cqa-align-middle\" style=\"font-size:16px;width:16px;height:16px\">folder_open</mat-icon>\n <span class=\"cqa-align-middle cqa-ml-1\">{{ modularLabels.allFolders }}</span>\n </button>\n <ng-container *ngFor=\"let crumb of breadcrumbTrail; let last = last\">\n <span class=\"cqa-text-neutral-400\">/</span>\n <button\n type=\"button\"\n class=\"hover:cqa-text-indigo-600\"\n [class.cqa-text-neutral-900]=\"last\"\n [class.cqa-font-semibold]=\"last\"\n [disabled]=\"last\"\n (click)=\"!last && onFolderSelected(crumb.id)\"\n >{{ crumb.name }}</button>\n </ng-container>\n </nav>\n\n <!-- Folder grid: modular + root view -->\n <section\n *ngIf=\"isModularView && isRootView && modularConfig.showFolderGrid && rootFolderTiles.length\"\n class=\"cqa-mb-4\"\n >\n <div class=\"cqa-flex cqa-items-center cqa-gap-2 cqa-mb-2\">\n <mat-icon class=\"cqa-text-neutral-600\" style=\"font-size:16px;width:16px;height:16px\">folder</mat-icon>\n <h3 class=\"cqa-text-sm cqa-font-semibold cqa-text-neutral-800\">{{ modularLabels.organised }}</h3>\n <span class=\"cqa-text-xs cqa-text-neutral-500\">\n {{ rootFolderTiles.length === 1 ? modularLabels.foldersCountSingular : modularLabels.foldersCountPlural.replace('{n}', '' + rootFolderTiles.length) }}\n </span>\n </div>\n <div class=\"cqa-flex cqa-flex-nowrap cqa-gap-3 cqa-overflow-x-auto cqa-scrollbar-thin cqa-pb-2\">\n <button\n *ngFor=\"let f of rootFolderTiles\"\n type=\"button\"\n [cqaFolderDrop]=\"f.id\"\n [dropEnabled]=\"modularConfig.allowTestDragDrop\"\n (testsDropped)=\"onTestsDropped($event)\"\n (click)=\"onFolderSelected(f.id)\"\n class=\"cqa-shrink-0 cqa-w-[240px] cqa-flex cqa-items-center cqa-justify-between cqa-gap-3 cqa-text-left cqa-p-3 cqa-rounded-[10px] cqa-border-solid cqa-border-[0.5px] cqa-border-[#E2E2E3] cqa-bg-white hover:cqa-border-[#D8D9FC] hover:cqa-shadow-sm cqa-transition-colors\"\n >\n <div class=\"cqa-flex cqa-items-center cqa-gap-3 cqa-min-w-0\">\n <ng-container *ngTemplateOutlet=\"folderIconChip\"></ng-container>\n <div class=\"cqa-flex cqa-flex-col cqa-min-w-0\">\n <span class=\"cqa-text-base cqa-font-semibold cqa-text-neutral-900 cqa-truncate cqa-leading-tight\">{{ f.name }}</span>\n <span *ngIf=\"modularConfig.showCounts\" class=\"cqa-text-sm cqa-text-neutral-500 cqa-truncate\">\n {{ (f.count ?? 0) === 1 ? modularLabels.testsCountSingular : modularLabels.testsCountPlural.replace('{n}', '' + (f.count ?? 0)) }}<ng-container *ngIf=\"f.children?.length\"> \u00B7 {{ f.children!.length === 1 ? modularLabels.oneSubfolder : modularLabels.subfoldersCount.replace('{n}', '' + f.children!.length) }}</ng-container>\n </span>\n </div>\n </div>\n <mat-icon class=\"cqa-text-neutral-400 cqa-shrink-0\" style=\"font-size:20px;width:20px;height:20px\">chevron_right</mat-icon>\n </button>\n\n <!-- \"+ New folder\" tile -->\n <button\n *ngIf=\"modularConfig.allowCreateFolder\"\n type=\"button\"\n (click)=\"onFolderCreateRequested({ parentId: null })\"\n class=\"cqa-shrink-0 cqa-w-[240px] cqa-flex cqa-items-center cqa-gap-3 cqa-text-left cqa-p-3 cqa-rounded-[10px] cqa-border-solid cqa-border-[0.5px] cqa-border-[#E2E2E3] cqa-bg-neutral-50 hover:cqa-border-[#D8D9FC] hover:cqa-bg-white cqa-transition-colors\"\n >\n <ng-container *ngTemplateOutlet=\"addIconChip\"></ng-container>\n <div class=\"cqa-flex cqa-flex-col cqa-min-w-0\">\n <span class=\"cqa-text-base cqa-font-semibold cqa-text-neutral-600 cqa-truncate cqa-leading-tight\">{{ modularLabels.newFolder }}</span>\n <span class=\"cqa-text-sm cqa-text-neutral-400\">{{ modularLabels.testsCountPlural.replace('{n}', '0') }}</span>\n </div>\n </button>\n </div>\n </section>\n\n <!-- Subfolder section: modular + folder view. Shown whenever drilled in (even if no subfolders, so the \"+ New folder\" tile remains reachable). -->\n <section\n *ngIf=\"isModularView && !isRootView && modularConfig.showSubfolderSection && subfolderTiles.length\"\n class=\"cqa-mb-4\"\n >\n <div *ngIf=\"subfolderTiles.length || modularConfig.allowCreateFolder\" class=\"cqa-text-sm cqa-text-neutral-600 cqa-mb-2\">\n {{ modularLabels.subfoldersIn }} {{ breadcrumbTrail.length ? breadcrumbTrail[breadcrumbTrail.length - 1].name : '' }}\n </div>\n <div class=\"cqa-flex cqa-flex-nowrap cqa-gap-3 cqa-overflow-x-auto cqa-scrollbar-thin cqa-pb-2\">\n <button\n *ngFor=\"let f of subfolderTiles\"\n type=\"button\"\n [cqaFolderDrop]=\"f.id\"\n [dropEnabled]=\"modularConfig.allowTestDragDrop\"\n (testsDropped)=\"onTestsDropped($event)\"\n (click)=\"onFolderSelected(f.id)\"\n class=\"cqa-shrink-0 cqa-w-[240px] cqa-flex cqa-items-center cqa-justify-between cqa-gap-3 cqa-text-left cqa-p-3 cqa-rounded-[10px] cqa-border-solid cqa-border-[0.5px] cqa-border-[#E2E2E3] cqa-bg-white hover:cqa-border-[#D8D9FC] hover:cqa-shadow-sm cqa-transition-colors\"\n >\n <div class=\"cqa-flex cqa-items-center cqa-gap-3 cqa-min-w-0\">\n <ng-container *ngTemplateOutlet=\"folderIconChip\"></ng-container>\n <div class=\"cqa-flex cqa-flex-col cqa-min-w-0\">\n <span class=\"cqa-text-base cqa-font-semibold cqa-text-neutral-900 cqa-truncate cqa-leading-tight\">{{ f.name }}</span>\n <span *ngIf=\"modularConfig.showCounts\" class=\"cqa-text-sm cqa-text-neutral-500 cqa-truncate\">\n {{ (f.count ?? 0) === 1 ? modularLabels.testsCountSingular : modularLabels.testsCountPlural.replace('{n}', '' + (f.count ?? 0)) }}\n </span>\n </div>\n </div>\n <mat-icon class=\"cqa-text-neutral-400 cqa-shrink-0\" style=\"font-size:20px;width:20px;height:20px\">chevron_right</mat-icon>\n </button>\n\n <!-- \"+ New folder\" tile -->\n <button\n *ngIf=\"modularConfig.allowCreateFolder\"\n type=\"button\"\n (click)=\"onFolderCreateRequested({ parentId: selectedFolderId })\"\n class=\"cqa-shrink-0 cqa-w-[240px] cqa-flex cqa-items-center cqa-gap-3 cqa-text-left cqa-p-3 cqa-rounded-[10px] cqa-border-solid cqa-border-[0.5px] cqa-border-[#E2E2E3] cqa-bg-neutral-50 hover:cqa-border-[#D8D9FC] hover:cqa-bg-white cqa-transition-colors\"\n >\n <ng-container *ngTemplateOutlet=\"addIconChip\"></ng-container>\n <div class=\"cqa-flex cqa-flex-col cqa-min-w-0\">\n <span class=\"cqa-text-base cqa-font-semibold cqa-text-neutral-600 cqa-truncate cqa-leading-tight\">{{ modularLabels.newFolder }}</span>\n <span class=\"cqa-text-sm cqa-text-neutral-400\">{{ modularLabels.testsCountPlural.replace('{n}', '0') }}</span>\n </div>\n </button>\n </div>\n </section>\n\n <!-- Folder panel header above the table: \"Hotel Search (3)\" + Clear filter -->\n <div\n *ngIf=\"isModularView && !isRootView && modularConfig.showUnorganisedSection\"\n class=\"cqa-flex cqa-mb-1 cqa-items-center cqa-justify-between cqa-px-4 cqa-py-3 cqa-rounded-t-lg cqa-bg-indigo-50 cqa-border cqa-border-indigo-100\"\n >\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <mat-icon class=\"cqa-text-indigo-500\" style=\"font-size:18px;width:18px;height:18px\">folder_open</mat-icon>\n <span class=\"cqa-text-sm cqa-font-semibold cqa-text-indigo-700\">\n {{ currentFolderNode?.name }} ({{ currentFolderDirectCount }})\n </span>\n </div>\n <button\n type=\"button\"\n class=\"cqa-px-3 cqa-py-1 cqa-text-xs cqa-font-medium cqa-text-indigo-700 cqa-bg-white cqa-border cqa-border-indigo-200 cqa-rounded hover:cqa-bg-indigo-50\"\n (click)=\"onFolderSelected(null)\"\n >{{ modularLabels.clearFilter }}</button>\n </div>\n\n <!-- Unorganised section header at root view -->\n <div\n *ngIf=\"isModularView && isRootView && modularConfig.showUnorganisedSection\"\n class=\"cqa-flex cqa-items-center cqa-gap-2 cqa-mb-2 cqa-mt-2\"\n >\n <mat-icon class=\"cqa-text-neutral-600\" style=\"font-size:16px;width:16px;height:16px\">inbox</mat-icon>\n <h3 class=\"cqa-text-sm cqa-font-semibold cqa-text-neutral-800\">{{ modularLabels.unorganised }}</h3>\n <span class=\"cqa-text-xs cqa-text-neutral-500\">\n {{ unorganisedCount === 1 ? modularLabels.testsCountSingular : modularLabels.testsCountPlural.replace('{n}', '' + unorganisedCount) }}\n </span>\n </div>\n\n <!-- Table -->\n <div class=\"cqa-rounded-[7px] cqa-overflow-hidden cqa-border-t cqa-border-l cqa-border-r cqa-border-grey-200 cqa-relative cqa-overflow-x-auto\">\n <ng-container *ngIf=\"(isTableLoading || isTableDataLoading) || (!effectiveIsEmptyState && pagedRows && pagedRows.length > 0); else storyEmptyTpl\">\n <app-dynamic-table\n [columns]=\"computedColumns\"\n [data]=\"pagedRows\"\n [rowSelectable]=\"rowSelectable\"\n [enableLocalSort]=\"enableLocalSort && !isReordering\"\n [isTableLoading]=\"isTableLoading\"\n [isTableDataLoading]=\"isTableDataLoading\"\n [cellJsonPathGetter]=\"cellJsonPathGetter\"\n [onJsonPathCopiedHandler]=\"onJsonPathCopiedHandler\"\n [enableRowReorder]=\"isReordering\"\n (rowReorder)=\"onRowReorder($event)\"\n (sortChange)=\"sortChange.emit($event)\">\n <ng-template #emptyTableTpl>\n <div class=\"cqa-flex cqa-flex-col cqa-items-center cqa-justify-center cqa-py-8\">\n <img src=\"/assets/illustrations/empty-state.svg\" alt=\"No data\" class=\"cqa-w-32 cqa-h-32 cqa-mb-4\" />\n <h3 class=\"cqa-text-lg cqa-font-semibold cqa-mb-2\">No test cases</h3>\n <p class=\"cqa-text-sm cqa-text-neutral-500 cqa-mb-4\">Try adjusting filters or create a new test case.</p>\n <cqa-button variant=\"filled\" (clicked)=\"toggleFilter()\">Show Filters</cqa-button>\n </div>\n </ng-template>\n </app-dynamic-table>\n </ng-container>\n\n <ng-template #storyEmptyTpl>\n <div class=\"cqa-p-6 cqa-flex cqa-flex-col cqa-items-center cqa-justify-center\">\n <cqa-empty-state\n *ngIf=\"effectiveIsEmptyState\"\n [title]=\"effectiveEmptyStateConfig.title\"\n [description]=\"effectiveEmptyStateConfig.description\"\n [imageUrl]=\"effectiveEmptyStateConfig.imageUrl\"\n [actions]=\"effectiveEmptyStateConfig.actions\"\n (actionClick)=\"onEmptyAction($event)\"\n >\n </cqa-empty-state>\n </div>\n </ng-template>\n </div>\n\n <cqa-pagination\n [totalElements]=\"serverSidePagination ? totalElements : filteredRows.length\"\n [pageIndex]=\"pageIndex\"\n [pageSize]=\"pageSize\"\n [pageSizeOptions]=\"pageSizeOptions\"\n [pageSizeMenuDirection]=\"pageSizeMenuDirection\"\n [pageItemCount]=\"pagedRows.length\"\n (paginate)=\"onPaginate($event)\"\n (pageSizeChange)=\"onPageSizeChange($event)\"\n >\n </cqa-pagination>\n </div>\n </div>\n\n <!-- Reused bulk action toolbar -->\n <div *ngIf=\"anyRowSelected && modularConfig.allowBulkSelection && !isReordering\" class=\"cqa-absolute cqa-bottom-[18.75px] cqa-left-[50%] cqa-translate-x-[-50%] cqa-w-full lg:cqa-max-w-[68%] cqa-sm:max-w-[75%] cqa-max-w-[90%] cqa-z-[1]\">\n <cqa-table-action-toolbar\n [selectedItems]=\"selectedItems && selectedItems.length > 0 ? selectedItems : currentSelectedItems\"\n [actions]=\"effectiveBulkActions\"\n [showSelectAll]=\"showSelectAllInToolbar\"\n [allSelected]=\"allSelectedInToolbar\"\n [showDismiss]=\"showDismissInToolbar\"\n (actionClick)=\"onBulkAction($event)\"\n (selectAllChange)=\"onBulkSelectAll($event)\"\n (dismiss)=\"onBulkDismiss()\"\n ></cqa-table-action-toolbar>\n </div>\n\n </div>\n</div>\n\n", components: [{ type: i2.SearchBarComponent, selector: "cqa-search-bar", inputs: ["placeholder", "value", "disabled", "showClear", "ariaLabel", "autoFocus", "size", "fullWidth"], outputs: ["valueChange", "search", "cleared"] }, { type: i3.ButtonComponent, selector: "cqa-button", inputs: ["variant", "btnSize", "disabled", "loading", "icon", "iconPosition", "fullWidth", "iconColor", "type", "text", "customClass", "inlineStyles", "tooltip", "tooltipPosition"], outputs: ["clicked"] }, { type: i4.ExportCodeModalComponent, selector: "cqa-export-code-modal", inputs: ["isOpen", "cases", "disabled"], outputs: ["closeModal", "export"] }, { type: i5.ColumnVisibilityComponent, selector: "cqa-column-visibility", inputs: ["isStepGroup", "columns", "columnVisibility", "selectedAutoRefreshInterval"], outputs: ["columnVisibilityChange", "autoRefreshChange"] }, { type: i6.SegmentControlComponent, selector: "cqa-segment-control", inputs: ["segments", "value", "disabled", "containerBgColor", "fullWidth", "size"], outputs: ["valueChange"] }, { type: i7.SelectedFiltersComponent, selector: "cqa-selected-filters", inputs: ["filterApplied", "chips", "defaultChips", "defaultChipClass"], outputs: ["removeChip", "clearAll", "onClearAll"] }, { type: i8.DynamicFilterComponent, selector: "cqa-dynamic-filter", inputs: ["config", "model", "showFilterPanel", "buttonLayout"], outputs: ["filtersApplied", "filtersChanged", "resetAction", "onApplyFilterClick", "onResetFilterClick"] }, { type: i9.FolderSidebarComponent, selector: "cqa-folder-sidebar", inputs: ["folders", "selectedFolderId", "expandedFolderIds", "unorganisedCount", "allowCreate", "allowRename", "allowDelete", "allowMove", "allowDuplicate", "allowDrop", "showCounts", "collapsed", "labels"], outputs: ["folderSelected", "folderExpansionToggled", "folderCreated", "folderCreateRequested", "folderRenamed", "folderDeleted", "folderMoveRequested", "folderDuplicateRequested", "testsDropped", "folderDropped", "collapsedChange"] }, { type: i10.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { type: i11.DynamicTableComponent, selector: "app-dynamic-table", inputs: ["data", "columns", "emptyState", "gridTemplateColumns", "screenWidth", "enableSelectAll", "rowSelectable", "enableLocalSort", "isTableLoading", "isTableDataLoading", "cellJsonPathGetter", "onJsonPathCopiedHandler", "enableRowReorder", "reorderHandleTooltip"], outputs: ["sortChange", "rowReorder"] }, { type: i12.EmptyStateComponent, selector: "cqa-empty-state", inputs: ["preset", "imageUrl", "title", "description", "actions"], outputs: ["actionClick"] }, { type: i13.PaginationComponent, selector: "cqa-pagination", inputs: ["totalElements", "totalPages", "pageIndex", "pageSize", "pageItemCount", "pageSizeOptions", "pageSizeMenuDirection"], outputs: ["pageIndexChange", "pageSizeChange", "paginate"] }, { type: i14.TableActionToolbarComponent, selector: "cqa-table-action-toolbar", inputs: ["selectedItems", "actions", "showSelectAll", "allSelected", "showDismiss"], outputs: ["actionClick", "selectAllChange", "dismiss"] }], directives: [{ type: i15.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i15.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i15.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }, { type: i16.FolderDropDirective, selector: "[cqaFolderDrop]", inputs: ["cqaFolderDrop", "dropEnabled"], outputs: ["testsDropped", "folderDropped"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1280
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: ModularTableTemplateComponent, decorators: [{
1281
+ type: Component,
1282
+ args: [{ selector: 'cqa-modular-table-template', host: { class: 'cqa-ui-root' }, changeDetection: ChangeDetectionStrategy.OnPush, template: "<!-- Reusable folder-icon chip. Render via <ng-container *ngTemplateOutlet=\"folderIconChip\"></ng-container>. -->\n<ng-template #folderIconChip>\n <span class=\"cqa-inline-flex cqa-items-center cqa-justify-center cqa-w-10 cqa-h-10 cqa-rounded-[10px] cqa-bg-neutral-100 cqa-shrink-0\">\n <svg width=\"17\" height=\"15\" viewBox=\"0 0 17 15\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <path d=\"M15.6375 12.6377C15.6375 13.0355 15.4794 13.4171 15.1981 13.6984C14.9168 13.9797 14.5353 14.1377 14.1375 14.1377H2.13745C1.73963 14.1377 1.3581 13.9797 1.07679 13.6984C0.795486 13.4171 0.637451 13.0355 0.637451 12.6377V2.1377C0.637451 1.73987 0.795486 1.35834 1.07679 1.07704C1.3581 0.795731 1.73963 0.637695 2.13745 0.637695H5.88745L7.38745 2.8877H14.1375C14.5353 2.8877 14.9168 3.04573 15.1981 3.32704C15.4794 3.60834 15.6375 3.98987 15.6375 4.3877V12.6377Z\" stroke=\"#6D6D74\" stroke-width=\"1.275\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </span>\n</ng-template>\n\n<!-- Reusable \"+\" chip used by the \"New folder\" tile. -->\n<ng-template #addIconChip>\n <span class=\"cqa-inline-flex cqa-items-center cqa-justify-center cqa-w-10 cqa-h-10 cqa-rounded-[10px] cqa-bg-neutral-100 cqa-shrink-0\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <path d=\"M8 3V13M3 8H13\" stroke=\"#6D6D74\" stroke-width=\"1.275\" stroke-linecap=\"round\"/>\n </svg>\n </span>\n</ng-template>\n\n<div class=\"cqa-ui-root\">\n <div class=\"cqa-w-full cqa-flex cqa-flex-col cqa-relative\">\n <div [class]=\"!showSearchBar ? 'cqa-justify-end' : 'cqa-justify-between'\" class=\"cqa-w-full cqa-flex cqa-items-center cqa-gap-3 cqa-flex-wrap cqa-mb-3\">\n <cqa-search-bar\n *ngIf=\"showSearchBar\"\n [placeholder]=\"searchPlaceholder\"\n [value]=\"searchValue\"\n [showClear]=\"showClear\"\n (valueChange)=\"valueChange($event)\"\n (search)=\"search($event)\"\n (cleared)=\"cleared()\"\n ></cqa-search-bar>\n <div class=\"cqa-flex cqa-items-center cqa-gap-2 cqa-flex-wrap\">\n <cqa-button\n *ngIf=\"showExportButton\"\n variant=\"grey-solid\"\n icon=\"open_in_new\"\n [text]=\"isExporting ? 'Exporting...' : 'Export'\"\n [disabled]=\"isExporting\"\n (clicked)=\"exportCodeClick()\"\n >\n <span>{{ isExporting ? 'Exporting...' : 'Export' }}</span>\n </cqa-button>\n \n <!-- Export Code Modal -->\n <cqa-export-code-modal\n *ngIf=\"showExportButton\"\n [isOpen]=\"isExportModalOpen\"\n [cases]=\"selectedCasesForExport\"\n [disabled]=\"false\"\n (closeModal)=\"closeExportModal()\"\n (export)=\"onExportModalExport($event)\">\n </cqa-export-code-modal>\n <ng-container *ngFor=\"let dropdownTemplate of otherDropDownButtons; trackBy: trackByDropdownTemplateRef\">\n <ng-container *ngTemplateOutlet=\"dropdownTemplate\"></ng-container>\n </ng-container>\n\n <ng-container *ngFor=\"let selectDropdownTemplate of otherSelectDropDownButtons; trackBy: trackBySelectDropdownTemplateRef\">\n <ng-container *ngTemplateOutlet=\"selectDropdownTemplate\"></ng-container>\n </ng-container>\n \n <cqa-button\n *ngIf=\"showFilterButton\"\n variant=\"grey-solid\"\n icon=\"add\"\n [disabled]=\"isReordering\"\n (clicked)=\"toggleFilter()\"\n >\n <span class=\"cqa-flex cqa-items-center cqa-gap-1\">\n Filter \n <div [class]=\"arrowClasses\">\n <svg\n class=\"cqa-w-2 cqa-h-1 cqa-absolute cqa-left-[4px] cqa-top-[6px]\"\n viewBox=\"0 0 8 4\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M0 0L4 4L8 0\"\n stroke=\"#0B0B0C\"\n stroke-width=\"1.33\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n </div>\n </span>\n </cqa-button>\n <cqa-column-visibility\n *ngIf=\"showSettingsButton\"\n [columns]=\"visibilityColumns\"\n [columnVisibility]=\"columnVisibility\"\n [selectedAutoRefreshInterval]=\"selectedAutoRefreshInterval\"\n (columnVisibilityChange)=\"onColumnVisibilityChange($event)\"\n (autoRefreshChange)=\"onAutoRefreshChange($event)\"\n ></cqa-column-visibility>\n <cqa-button\n *ngIf=\"showAutoRefreshButton\"\n variant=\"grey-solid\"\n icon=\"refresh\"\n (clicked)=\"handleRefreshClick()\"\n [tooltip]=\"'Refresh'\"\n tooltipPosition=\"below\"\n [disabled]=\"isReordering\"\n ></cqa-button>\n <ng-container *ngFor=\"let buttonTemplate of otherButtons; trackBy: trackByTemplateRef\">\n <ng-container *ngTemplateOutlet=\"buttonTemplate\"></ng-container>\n </ng-container>\n <cqa-segment-control\n *ngIf=\"showViewModeToggle\"\n size=\"lg\"\n [segments]=\"viewModeSegments\"\n [value]=\"viewMode\"\n (valueChange)=\"onViewModeChange($event)\"\n ></cqa-segment-control>\n <cqa-button\n *ngIf=\"showReorderButton && !isReordering\"\n variant=\"outlined\"\n icon=\"drag_indicator\"\n [text]=\"reorderLabels.reorderButton\"\n [disabled]=\"!pagedRows || pagedRows.length === 0 || isTableLoading || isTableDataLoading\"\n (clicked)=\"startReorder()\"\n ></cqa-button>\n <ng-container *ngIf=\"showReorderButton && isReordering\">\n <cqa-button\n variant=\"outlined\"\n [text]=\"reorderLabels.cancelButton\"\n [disabled]=\"reorderSaving\"\n (clicked)=\"cancelReorder()\"\n ></cqa-button>\n <cqa-button\n variant=\"filled\"\n [icon]=\"reorderSaving ? 'hourglass_empty' : ''\"\n [text]=\"reorderSaving ? reorderLabels.savingButton : reorderLabels.doneButton\"\n [disabled]=\"reorderSaving\"\n (clicked)=\"saveReorder()\"\n ></cqa-button>\n </ng-container>\n </div>\n </div>\n\n <!-- Reorder mode banner -->\n <div *ngIf=\"isReordering\" class=\"cqa-flex cqa-items-center cqa-gap-2 cqa-mb-3 cqa-px-3 cqa-py-2 cqa-rounded-md cqa-bg-[#FFFBEB] cqa-border cqa-border-[#FDE68A]\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <circle cx=\"3\" cy=\"3\" r=\"1.5\" fill=\"#92400E\"></circle>\n <circle cx=\"8\" cy=\"3\" r=\"1.5\" fill=\"#92400E\"></circle>\n <circle cx=\"13\" cy=\"3\" r=\"1.5\" fill=\"#92400E\"></circle>\n <circle cx=\"3\" cy=\"8\" r=\"1.5\" fill=\"#92400E\"></circle>\n <circle cx=\"8\" cy=\"8\" r=\"1.5\" fill=\"#92400E\"></circle>\n <circle cx=\"13\" cy=\"8\" r=\"1.5\" fill=\"#92400E\"></circle>\n <circle cx=\"3\" cy=\"13\" r=\"1.5\" fill=\"#92400E\"></circle>\n <circle cx=\"8\" cy=\"13\" r=\"1.5\" fill=\"#92400E\"></circle>\n <circle cx=\"13\" cy=\"13\" r=\"1.5\" fill=\"#92400E\"></circle>\n </svg>\n <span class=\"cqa-text-sm cqa-font-semibold cqa-text-[#92400E]\">{{ reorderLabels.bannerTitle }}</span>\n <span class=\"cqa-text-sm cqa-text-[#92400E]\">{{ reorderLabels.bannerDescription }}</span>\n </div>\n\n <cqa-selected-filters\n [filterApplied]=\"filterApplied\"\n [chips]=\"chips\"\n (removeChip)=\"onRemoveChip($event)\"\n (clearAll)=\"onClearAllChips()\"\n (onClearAll)=\"onClearAll.emit()\"\n >\n </cqa-selected-filters>\n\n <cqa-dynamic-filter\n *ngIf=\"showFilterPanel\"\n [config]=\"filterConfig\"\n [model]=\"filterModel\"\n [showFilterPanel]=\"showFilterPanel\"\n (filtersChanged)=\"onFiltersChanged($event)\"\n (filtersApplied)=\"onFiltersApplied($event)\"\n (onApplyFilterClick)=\"onApplyFilterClick.emit($event)\"\n (onResetFilterClick)=\"handleResetFilterClick()\"\n >\n </cqa-dynamic-filter>\n\n <div class=\"cqa-flex cqa-items-stretch cqa-gap-3 cqa-min-h-0\">\n <!-- Sidebar (only shown in modular view) -->\n <cqa-folder-sidebar\n *ngIf=\"isModularView && modularConfig.showSidebar\"\n [folders]=\"folders\"\n [selectedFolderId]=\"selectedFolderId\"\n [expandedFolderIds]=\"expandedFolderIds\"\n [unorganisedCount]=\"unorganisedCount\"\n [allowCreate]=\"modularConfig.allowCreateFolder\"\n [allowRename]=\"modularConfig.allowRenameFolder\"\n [allowDelete]=\"modularConfig.allowDeleteFolder\"\n [allowDrop]=\"modularConfig.allowTestDragDrop\"\n [showCounts]=\"modularConfig.showCounts\"\n [collapsed]=\"sidebarCollapsed\"\n [labels]=\"modularLabels\"\n (folderSelected)=\"onFolderSelected($event)\"\n (folderExpansionToggled)=\"onFolderExpansionToggled($event)\"\n (folderCreated)=\"onFolderCreated($event)\"\n (folderCreateRequested)=\"onFolderCreateRequested($event)\"\n (folderRenamed)=\"onFolderRenamed($event)\"\n (folderDeleted)=\"onFolderDeleted($event)\"\n (folderMoveRequested)=\"onFolderMoveRequested($event)\"\n (folderDuplicateRequested)=\"onFolderDuplicateRequested($event)\"\n (testsDropped)=\"onTestsDropped($event)\"\n (folderDropped)=\"onFolderDropped($event)\"\n (collapsedChange)=\"onSidebarCollapsedChange($event)\"\n ></cqa-folder-sidebar>\n\n <!-- Right pane -->\n <div class=\"cqa-flex-1 cqa-flex cqa-flex-col cqa-min-w-0\">\n <!-- Breadcrumb (modular view, folder drilled-in) -->\n <nav\n *ngIf=\"isModularView && modularConfig.showBreadcrumb && !isRootView\"\n aria-label=\"Folder path\"\n class=\"cqa-flex cqa-items-center cqa-gap-1 cqa-text-sm cqa-text-neutral-600 cqa-mb-3\"\n >\n <button type=\"button\" class=\"hover:cqa-text-indigo-600\" (click)=\"onFolderSelected(null)\">\n <mat-icon class=\"cqa-align-middle\" style=\"font-size:16px;width:16px;height:16px\">folder_open</mat-icon>\n <span class=\"cqa-align-middle cqa-ml-1\">{{ modularLabels.allFolders }}</span>\n </button>\n <ng-container *ngFor=\"let crumb of breadcrumbTrail; let last = last\">\n <span class=\"cqa-text-neutral-400\">/</span>\n <button\n type=\"button\"\n class=\"hover:cqa-text-indigo-600\"\n [class.cqa-text-neutral-900]=\"last\"\n [class.cqa-font-semibold]=\"last\"\n [disabled]=\"last\"\n (click)=\"!last && onFolderSelected(crumb.id)\"\n >{{ crumb.name }}</button>\n </ng-container>\n </nav>\n\n <!-- Folder grid: modular + root view -->\n <section\n *ngIf=\"isModularView && isRootView && modularConfig.showFolderGrid && rootFolderTiles.length\"\n class=\"cqa-mb-4\"\n >\n <div class=\"cqa-flex cqa-items-center cqa-gap-2 cqa-mb-2\">\n <mat-icon class=\"cqa-text-neutral-600\" style=\"font-size:16px;width:16px;height:16px\">folder</mat-icon>\n <h3 class=\"cqa-text-sm cqa-font-semibold cqa-text-neutral-800\">{{ modularLabels.organised }}</h3>\n <span class=\"cqa-text-xs cqa-text-neutral-500\">\n {{ rootFolderTiles.length === 1 ? modularLabels.foldersCountSingular : modularLabels.foldersCountPlural.replace('{n}', '' + rootFolderTiles.length) }}\n </span>\n </div>\n <div class=\"cqa-flex cqa-flex-nowrap cqa-gap-3 cqa-overflow-x-auto cqa-scrollbar-thin cqa-pb-2\">\n <button\n *ngFor=\"let f of rootFolderTiles\"\n type=\"button\"\n [cqaFolderDrop]=\"f.id\"\n [dropEnabled]=\"modularConfig.allowTestDragDrop\"\n (testsDropped)=\"onTestsDropped($event)\"\n (click)=\"onFolderSelected(f.id)\"\n class=\"cqa-shrink-0 cqa-w-[240px] cqa-flex cqa-items-center cqa-justify-between cqa-gap-3 cqa-text-left cqa-p-3 cqa-rounded-[10px] cqa-border-solid cqa-border-[0.5px] cqa-border-[#E2E2E3] cqa-bg-white hover:cqa-border-[#D8D9FC] hover:cqa-shadow-sm cqa-transition-colors\"\n >\n <div class=\"cqa-flex cqa-items-center cqa-gap-3 cqa-min-w-0\">\n <ng-container *ngTemplateOutlet=\"folderIconChip\"></ng-container>\n <div class=\"cqa-flex cqa-flex-col cqa-min-w-0\">\n <span class=\"cqa-text-base cqa-font-semibold cqa-text-neutral-900 cqa-truncate cqa-leading-tight\">{{ f.name }}</span>\n <span *ngIf=\"modularConfig.showCounts\" class=\"cqa-text-sm cqa-text-neutral-500 cqa-truncate\">\n {{ (f.count ?? 0) === 1 ? modularLabels.testsCountSingular : modularLabels.testsCountPlural.replace('{n}', '' + (f.count ?? 0)) }}<ng-container *ngIf=\"f.children?.length\"> \u00B7 {{ f.children!.length === 1 ? modularLabels.oneSubfolder : modularLabels.subfoldersCount.replace('{n}', '' + f.children!.length) }}</ng-container>\n </span>\n </div>\n </div>\n <mat-icon class=\"cqa-text-neutral-400 cqa-shrink-0\" style=\"font-size:20px;width:20px;height:20px\">chevron_right</mat-icon>\n </button>\n\n <!-- \"+ New folder\" tile -->\n <button\n *ngIf=\"modularConfig.allowCreateFolder\"\n type=\"button\"\n (click)=\"onFolderCreateRequested({ parentId: null })\"\n class=\"cqa-shrink-0 cqa-w-[240px] cqa-flex cqa-items-center cqa-gap-3 cqa-text-left cqa-p-3 cqa-rounded-[10px] cqa-border-solid cqa-border-[0.5px] cqa-border-[#E2E2E3] cqa-bg-neutral-50 hover:cqa-border-[#D8D9FC] hover:cqa-bg-white cqa-transition-colors\"\n >\n <ng-container *ngTemplateOutlet=\"addIconChip\"></ng-container>\n <div class=\"cqa-flex cqa-flex-col cqa-min-w-0\">\n <span class=\"cqa-text-base cqa-font-semibold cqa-text-neutral-600 cqa-truncate cqa-leading-tight\">{{ modularLabels.newFolder }}</span>\n <span class=\"cqa-text-sm cqa-text-neutral-400\">{{ modularLabels.testsCountPlural.replace('{n}', '0') }}</span>\n </div>\n </button>\n </div>\n </section>\n\n <!-- Subfolder section: modular + folder view. Shown whenever drilled in (even if no subfolders, so the \"+ New folder\" tile remains reachable). -->\n <section\n *ngIf=\"isModularView && !isRootView && modularConfig.showSubfolderSection && subfolderTiles.length\"\n class=\"cqa-mb-4\"\n >\n <div *ngIf=\"subfolderTiles.length || modularConfig.allowCreateFolder\" class=\"cqa-text-sm cqa-text-neutral-600 cqa-mb-2\">\n {{ modularLabels.subfoldersIn }} {{ breadcrumbTrail.length ? breadcrumbTrail[breadcrumbTrail.length - 1].name : '' }}\n </div>\n <div class=\"cqa-flex cqa-flex-nowrap cqa-gap-3 cqa-overflow-x-auto cqa-scrollbar-thin cqa-pb-2\">\n <button\n *ngFor=\"let f of subfolderTiles\"\n type=\"button\"\n [cqaFolderDrop]=\"f.id\"\n [dropEnabled]=\"modularConfig.allowTestDragDrop\"\n (testsDropped)=\"onTestsDropped($event)\"\n (click)=\"onFolderSelected(f.id)\"\n class=\"cqa-shrink-0 cqa-w-[240px] cqa-flex cqa-items-center cqa-justify-between cqa-gap-3 cqa-text-left cqa-p-3 cqa-rounded-[10px] cqa-border-solid cqa-border-[0.5px] cqa-border-[#E2E2E3] cqa-bg-white hover:cqa-border-[#D8D9FC] hover:cqa-shadow-sm cqa-transition-colors\"\n >\n <div class=\"cqa-flex cqa-items-center cqa-gap-3 cqa-min-w-0\">\n <ng-container *ngTemplateOutlet=\"folderIconChip\"></ng-container>\n <div class=\"cqa-flex cqa-flex-col cqa-min-w-0\">\n <span class=\"cqa-text-base cqa-font-semibold cqa-text-neutral-900 cqa-truncate cqa-leading-tight\">{{ f.name }}</span>\n <span *ngIf=\"modularConfig.showCounts\" class=\"cqa-text-sm cqa-text-neutral-500 cqa-truncate\">\n {{ (f.count ?? 0) === 1 ? modularLabels.testsCountSingular : modularLabels.testsCountPlural.replace('{n}', '' + (f.count ?? 0)) }}\n </span>\n </div>\n </div>\n <mat-icon class=\"cqa-text-neutral-400 cqa-shrink-0\" style=\"font-size:20px;width:20px;height:20px\">chevron_right</mat-icon>\n </button>\n\n <!-- \"+ New folder\" tile -->\n <button\n *ngIf=\"modularConfig.allowCreateFolder\"\n type=\"button\"\n (click)=\"onFolderCreateRequested({ parentId: selectedFolderId })\"\n class=\"cqa-shrink-0 cqa-w-[240px] cqa-flex cqa-items-center cqa-gap-3 cqa-text-left cqa-p-3 cqa-rounded-[10px] cqa-border-solid cqa-border-[0.5px] cqa-border-[#E2E2E3] cqa-bg-neutral-50 hover:cqa-border-[#D8D9FC] hover:cqa-bg-white cqa-transition-colors\"\n >\n <ng-container *ngTemplateOutlet=\"addIconChip\"></ng-container>\n <div class=\"cqa-flex cqa-flex-col cqa-min-w-0\">\n <span class=\"cqa-text-base cqa-font-semibold cqa-text-neutral-600 cqa-truncate cqa-leading-tight\">{{ modularLabels.newFolder }}</span>\n <span class=\"cqa-text-sm cqa-text-neutral-400\">{{ modularLabels.testsCountPlural.replace('{n}', '0') }}</span>\n </div>\n </button>\n </div>\n </section>\n\n <!-- Folder panel header above the table: \"Hotel Search (3)\" + Clear filter -->\n <div\n *ngIf=\"isModularView && !isRootView && modularConfig.showUnorganisedSection\"\n class=\"cqa-flex cqa-mb-1 cqa-items-center cqa-justify-between cqa-px-4 cqa-py-3 cqa-rounded-t-lg cqa-bg-indigo-50 cqa-border cqa-border-indigo-100\"\n >\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <mat-icon class=\"cqa-text-indigo-500\" style=\"font-size:18px;width:18px;height:18px\">folder_open</mat-icon>\n <span class=\"cqa-text-sm cqa-font-semibold cqa-text-indigo-700\">\n {{ currentFolderNode?.name }} ({{ currentFolderDirectCount }})\n </span>\n </div>\n <button\n type=\"button\"\n class=\"cqa-px-3 cqa-py-1 cqa-text-xs cqa-font-medium cqa-text-indigo-700 cqa-bg-white cqa-border cqa-border-indigo-200 cqa-rounded hover:cqa-bg-indigo-50\"\n (click)=\"onFolderSelected(null)\"\n >{{ modularLabels.clearFilter }}</button>\n </div>\n\n <!-- Unorganised section header at root view -->\n <div\n *ngIf=\"isModularView && isRootView && modularConfig.showUnorganisedSection\"\n class=\"cqa-flex cqa-items-center cqa-gap-2 cqa-mb-2 cqa-mt-2\"\n >\n <mat-icon class=\"cqa-text-neutral-600\" style=\"font-size:16px;width:16px;height:16px\">inbox</mat-icon>\n <h3 class=\"cqa-text-sm cqa-font-semibold cqa-text-neutral-800\">{{ modularLabels.unorganised }}</h3>\n <span class=\"cqa-text-xs cqa-text-neutral-500\">\n {{ unorganisedCount === 1 ? modularLabels.testsCountSingular : modularLabels.testsCountPlural.replace('{n}', '' + unorganisedCount) }}\n </span>\n </div>\n\n <!-- Table -->\n <div class=\"cqa-rounded-[7px] cqa-overflow-hidden cqa-border-t cqa-border-l cqa-border-r cqa-border-grey-200 cqa-relative cqa-overflow-x-auto\">\n <ng-container *ngIf=\"(isTableLoading || isTableDataLoading) || (!effectiveIsEmptyState && pagedRows && pagedRows.length > 0); else storyEmptyTpl\">\n <app-dynamic-table\n [columns]=\"computedColumns\"\n [data]=\"pagedRows\"\n [rowSelectable]=\"rowSelectable\"\n [enableLocalSort]=\"enableLocalSort && !isReordering\"\n [isTableLoading]=\"isTableLoading\"\n [isTableDataLoading]=\"isTableDataLoading\"\n [cellJsonPathGetter]=\"cellJsonPathGetter\"\n [onJsonPathCopiedHandler]=\"onJsonPathCopiedHandler\"\n [enableRowReorder]=\"isReordering\"\n (rowReorder)=\"onRowReorder($event)\"\n (sortChange)=\"sortChange.emit($event)\">\n <ng-template #emptyTableTpl>\n <div class=\"cqa-flex cqa-flex-col cqa-items-center cqa-justify-center cqa-py-8\">\n <img src=\"/assets/illustrations/empty-state.svg\" alt=\"No data\" class=\"cqa-w-32 cqa-h-32 cqa-mb-4\" />\n <h3 class=\"cqa-text-lg cqa-font-semibold cqa-mb-2\">No test cases</h3>\n <p class=\"cqa-text-sm cqa-text-neutral-500 cqa-mb-4\">Try adjusting filters or create a new test case.</p>\n <cqa-button variant=\"filled\" (clicked)=\"toggleFilter()\">Show Filters</cqa-button>\n </div>\n </ng-template>\n </app-dynamic-table>\n </ng-container>\n\n <ng-template #storyEmptyTpl>\n <div class=\"cqa-p-6 cqa-flex cqa-flex-col cqa-items-center cqa-justify-center\">\n <cqa-empty-state\n *ngIf=\"effectiveIsEmptyState\"\n [title]=\"effectiveEmptyStateConfig.title\"\n [description]=\"effectiveEmptyStateConfig.description\"\n [imageUrl]=\"effectiveEmptyStateConfig.imageUrl\"\n [actions]=\"effectiveEmptyStateConfig.actions\"\n (actionClick)=\"onEmptyAction($event)\"\n >\n </cqa-empty-state>\n </div>\n </ng-template>\n </div>\n\n <cqa-pagination\n [totalElements]=\"serverSidePagination ? totalElements : filteredRows.length\"\n [pageIndex]=\"pageIndex\"\n [pageSize]=\"pageSize\"\n [pageSizeOptions]=\"pageSizeOptions\"\n [pageSizeMenuDirection]=\"pageSizeMenuDirection\"\n [pageItemCount]=\"pagedRows.length\"\n (paginate)=\"onPaginate($event)\"\n (pageSizeChange)=\"onPageSizeChange($event)\"\n >\n </cqa-pagination>\n </div>\n </div>\n\n <!-- Reused bulk action toolbar -->\n <div *ngIf=\"anyRowSelected && modularConfig.allowBulkSelection && !isReordering\" class=\"cqa-absolute cqa-bottom-[18.75px] cqa-left-[50%] cqa-translate-x-[-50%] cqa-w-full lg:cqa-max-w-[68%] cqa-sm:max-w-[75%] cqa-max-w-[90%] cqa-z-[1]\">\n <cqa-table-action-toolbar\n [selectedItems]=\"selectedItems && selectedItems.length > 0 ? selectedItems : currentSelectedItems\"\n [actions]=\"effectiveBulkActions\"\n [showSelectAll]=\"showSelectAllInToolbar\"\n [allSelected]=\"allSelectedInToolbar\"\n [showDismiss]=\"showDismissInToolbar\"\n (actionClick)=\"onBulkAction($event)\"\n (selectAllChange)=\"onBulkSelectAll($event)\"\n (dismiss)=\"onBulkDismiss()\"\n ></cqa-table-action-toolbar>\n </div>\n\n </div>\n</div>\n\n", styles: [] }]
1283
+ }], ctorParameters: function () { return [{ type: i0.ChangeDetectorRef }, { type: i1.DialogService }]; }, propDecorators: { searchPlaceholder: [{
1284
+ type: Input
1285
+ }], searchValue: [{
1286
+ type: Input
1287
+ }], showClear: [{
1288
+ type: Input
1289
+ }], showSearchBar: [{
1290
+ type: Input
1291
+ }], showExportButton: [{
1292
+ type: Input
1293
+ }], isExporting: [{
1294
+ type: Input
1295
+ }], onSearchChange: [{
1296
+ type: Output
1297
+ }], onExportClick: [{
1298
+ type: Output
1299
+ }], onApplyFilterClick: [{
1300
+ type: Output
1301
+ }], onResetFilterClick: [{
1302
+ type: Output
1303
+ }], onClearAll: [{
1304
+ type: Output
1305
+ }], removeChip: [{
1306
+ type: Output
1307
+ }], filterConfig: [{
1308
+ type: Input
1309
+ }], filterModel: [{
1310
+ type: Input
1311
+ }], showFilterPanel: [{
1312
+ type: Input
1313
+ }], showFilterButton: [{
1314
+ type: Input
1315
+ }], otherButtons: [{
1316
+ type: Input
1317
+ }], otherDropDownButtons: [{
1318
+ type: Input
1319
+ }], otherSelectDropDownButtons: [{
1320
+ type: Input
1321
+ }], otherButtonLabel: [{
1322
+ type: Input
1323
+ }], otherButtonVariant: [{
1324
+ type: Input
1325
+ }], showOtherButton: [{
1326
+ type: Input
1327
+ }], showActionButton: [{
1328
+ type: Input
1329
+ }], showSettingsButton: [{
1330
+ type: Input
1331
+ }], showAutoRefreshButton: [{
1332
+ type: Input
1333
+ }], showViewModeToggle: [{
1334
+ type: Input
1335
+ }], viewMode: [{
1336
+ type: Input
1337
+ }], viewModeLabels: [{
1338
+ type: Input
1339
+ }], viewModeChange: [{
1340
+ type: Output
1341
+ }], data: [{
1342
+ type: Input
1343
+ }], isEmptyState: [{
1344
+ type: Input
1345
+ }], emptyStateConfig: [{
1346
+ type: Input
1347
+ }], actions: [{
1348
+ type: Input
1349
+ }], chips: [{
1350
+ type: Input
1351
+ }], filterApplied: [{
1352
+ type: Input
1353
+ }], columns: [{
1354
+ type: Input
1355
+ }], rowSelectable: [{
1356
+ type: Input
1357
+ }], selectedAutoRefreshInterval: [{
1358
+ type: Input
1359
+ }], pageIndex: [{
1360
+ type: Input
1361
+ }], pageSize: [{
1362
+ type: Input
1363
+ }], pageSizeOptions: [{
1364
+ type: Input
1365
+ }], pageSizeMenuDirection: [{
1366
+ type: Input
1367
+ }], serverSidePagination: [{
1368
+ type: Input
1369
+ }], totalElements: [{
1370
+ type: Input
1371
+ }], pageChange: [{
1372
+ type: Output
1373
+ }], enableLocalSort: [{
1374
+ type: Input
1375
+ }], sortChange: [{
1376
+ type: Output
1377
+ }], isTableLoading: [{
1378
+ type: Input
1379
+ }], isTableDataLoading: [{
1380
+ type: Input
1381
+ }], cellJsonPathGetter: [{
1382
+ type: Input
1383
+ }], onJsonPathCopiedHandler: [{
1384
+ type: Input
1385
+ }], selectedItems: [{
1386
+ type: Input
1387
+ }], showSelectAllInToolbar: [{
1388
+ type: Input
1389
+ }], showDismissInToolbar: [{
1390
+ type: Input
1391
+ }], allSelectedInToolbar: [{
1392
+ type: Input
1393
+ }], folders: [{
1394
+ type: Input
1395
+ }], selectedFolderId: [{
1396
+ type: Input
1397
+ }], expandedFolderIds: [{
1398
+ type: Input
1399
+ }], unorganisedCount: [{
1400
+ type: Input
1401
+ }], folderIdAccessor: [{
1402
+ type: Input
1403
+ }], modularConfig: [{
1404
+ type: Input
1405
+ }], modularLabels: [{
1406
+ type: Input
1407
+ }], bulkActions: [{
1408
+ type: Input
1409
+ }], sidebarCollapsed: [{
1410
+ type: Input
1411
+ }], useInternalDialogs: [{
1412
+ type: Input
1413
+ }], folderSelected: [{
1414
+ type: Output
1415
+ }], folderExpansionToggled: [{
1416
+ type: Output
1417
+ }], folderCreated: [{
1418
+ type: Output
1419
+ }], folderCreateRequested: [{
1420
+ type: Output
1421
+ }], folderRenamed: [{
1422
+ type: Output
1423
+ }], folderDeleted: [{
1424
+ type: Output
1425
+ }], testsMoved: [{
1426
+ type: Output
1427
+ }], bulkActionClick: [{
1428
+ type: Output
1429
+ }], bulkSelectAllChange: [{
1430
+ type: Output
1431
+ }], bulkDismiss: [{
1432
+ type: Output
1433
+ }], bulkActionInvoked: [{
1434
+ type: Output
1435
+ }], sidebarCollapsedChange: [{
1436
+ type: Output
1437
+ }], showReorderButton: [{
1438
+ type: Input
1439
+ }], reorderSaving: [{
1440
+ type: Input
1441
+ }], reorderLabels: [{
1442
+ type: Input
1443
+ }], reorderStart: [{
1444
+ type: Output
1445
+ }], reorderCancel: [{
1446
+ type: Output
1447
+ }], reorderSave: [{
1448
+ type: Output
1449
+ }], moveRequested: [{
1450
+ type: Output
1451
+ }], selectedItemsChange: [{
1452
+ type: Output
1453
+ }], folderDeleteRequested: [{
1454
+ type: Output
1455
+ }], folderMoveRequested: [{
1456
+ type: Output
1457
+ }], folderMoved: [{
1458
+ type: Output
1459
+ }], folderDuplicateRequested: [{
1460
+ type: Output
1461
+ }], onReload: [{
1462
+ type: Output
1463
+ }], onAutoRefreshClick: [{
1464
+ type: Output
1465
+ }], columnVisibilityChange: [{
1466
+ type: Output
1467
+ }], autoRefreshIntervalChange: [{
1468
+ type: Output
1469
+ }], dynamicFilterComponent: [{
1470
+ type: ViewChild,
1471
+ args: [DynamicFilterComponent]
1472
+ }], columnVisibility: [{
1473
+ type: Input
1474
+ }] } });
1475
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibW9kdWxhci10YWJsZS10ZW1wbGF0ZS5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9zcmMvbGliL3RlbXBsYXRlcy9tb2R1bGFyLXRhYmxlLXRlbXBsYXRlL21vZHVsYXItdGFibGUtdGVtcGxhdGUuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vLi4vLi4vc3JjL2xpYi90ZW1wbGF0ZXMvbW9kdWxhci10YWJsZS10ZW1wbGF0ZS9tb2R1bGFyLXRhYmxlLXRlbXBsYXRlLmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFDTCxTQUFTLEVBQ1QsS0FBSyxFQUNMLE1BQU0sRUFDTixZQUFZLEVBS1osdUJBQXVCLEVBR3ZCLFNBQVMsR0FDVixNQUFNLGVBQWUsQ0FBQztBQUN2QixPQUFPLEVBQXFCLHNCQUFzQixFQUFFLE1BQU0sdURBQXVELENBQUM7QUFLbEgsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sNENBQTRDLENBQUM7QUFFaEYsT0FBTyxFQUNMLHNCQUFzQixFQUN0QixzQkFBc0IsRUFDdEIsc0JBQXNCLEdBaUJ2QixNQUFNLGlDQUFpQyxDQUFDO0FBQ3pDLE9BQU8sRUFBRSwyQkFBMkIsRUFBRSxNQUFNLDJDQUEyQyxDQUFDO0FBQ3hGLE9BQU8sRUFBRSx3QkFBd0IsRUFBRSxNQUFNLHVDQUF1QyxDQUFDO0FBQ2pGLE9BQU8sRUFBRSwyQkFBMkIsRUFBRSxNQUFNLDBDQUEwQyxDQUFDOzs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFTdkYsTUFBTSxPQUFPLDZCQUE2QjtJQXFVeEMsWUFBb0IsR0FBc0IsRUFBVSxhQUE0QjtRQUE1RCxRQUFHLEdBQUgsR0FBRyxDQUFtQjtRQUFVLGtCQUFhLEdBQWIsYUFBYSxDQUFlO1FBcFVoRixvQkFBb0I7UUFDWCxzQkFBaUIsR0FBVyxtQkFBbUIsQ0FBQztRQUNoRCxnQkFBVyxHQUFXLEVBQUUsQ0FBQztRQUN6QixjQUFT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QUFhO3NCQUF6QixLQUFLO2dCQVNJLFlBQVk7c0JBQXJCLE1BQU07Z0JBRUcsYUFBYTtzQkFBdEIsTUFBTTtnQkFTRyxXQUFXO3NCQUFwQixNQUFNO2dCQWtCRyxhQUFhO3NCQUF0QixNQUFNO2dCQVFHLG1CQUFtQjtzQkFBNUIsTUFBTTtnQkFRRyxxQkFBcUI7c0JBQTlCLE1BQU07Z0JBT0csbUJBQW1CO3NCQUE1QixNQUFNO2dCQUtHLFdBQVc7c0JBQXBCLE1BQU07Z0JBTUcsd0JBQXdCO3NCQUFqQyxNQUFNO2dCQU1HLFFBQVE7c0JBQWpCLE1BQU07Z0JBQ0csa0JBQWtCO3NCQUEzQixNQUFNO2dCQUNHLHNCQUFzQjtzQkFBL0IsTUFBTTtnQkFDRyx5QkFBeUI7c0JBQWxDLE1BQU07Z0JBQzRCLHNCQUFzQjtzQkFBeEQsU0FBUzt1QkFBQyxzQkFBc0I7Z0JBMkJwQixnQkFBZ0I7c0JBQTVCLEtBQUsiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xuICBDb21wb25lbnQsXG4gIElucHV0LFxuICBPdXRwdXQsXG4gIEV2ZW50RW1pdHRlcixcbiAgT25DaGFuZ2VzLFxuICBPbkluaXQsXG4gIFNpbXBsZUNoYW5nZXMsXG4gIE9uRGVzdHJveSxcbiAgQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3ksXG4gIENoYW5nZURldGVjdG9yUmVmLFxuICBUZW1wbGF0ZVJlZixcbiAgVmlld0NoaWxkLFxufSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IER5bmFtaWNGaWx0ZXJJdGVtLCBEeW5hbWljRmlsdGVyQ29tcG9uZW50IH0gZnJvbSAnLi4vLi4vZmlsdGVycy9keW5hbWljLWZpbHRlci9keW5hbWljLWZpbHRlci5jb21wb25lbnQnO1xuaW1wb3J0IHsgRHluYW1pY1RhYmxlQ29sdW1uIH0gZnJvbSAnLi4vLi4vdGFibGUvZHluYW1pYy10YWJsZS9keW5hbWljLXRhYmxlLmNvbXBvbmVudCc7XG5pbXBvcnQgeyBDb2x1bW5WaXNpYmlsaXR5Q29uZmlnIH0gZnJvbSAnLi4vLi4vY29sdW1uLXZpc2liaWxpdHkvY29sdW1uLXZpc2liaWxpdHkuY29tcG9uZW50JztcbmltcG9ydCB7IFRhYmxlQWN0aW9uIH0gZnJvbSAnLi4vLi4vdGFibGUtYWN0aW9uLXRvb2xiYXIvdGFibGUtYWN0aW9uLXRvb2xiYXIuY29tcG9uZW50JztcbmltcG9ydCB7IEVtcHR5U3RhdGVDb25maWcgfSBmcm9tICcuLi8uLi9lbXB0eS1zdGF0ZS9lbXB0eS1zdGF0ZS1jb25maWcuaW50ZXJmYWNlJztcbmltcG9ydCB7IEVNUFRZX1NUQVRFX0lNQUdFUyB9IGZyb20gJy4uLy4uL2Fzc2V0cy9pbWFnZXMvaW1hZ2UtYXNzZXRzLmNvbnN0YW50cyc7XG5pbXBvcnQgeyBEaWFsb2dTZXJ2aWNlIH0gZnJvbSAnLi4vLi4vZGlhbG9nL2RpYWxvZy5zZXJ2aWNlJztcbmltcG9ydCB7XG4gIERFRkFVTFRfTU9EVUxBUl9DT05GSUcsXG4gIERFRkFVTFRfTU9EVUxBUl9MQUJFTFMsXG4gIERFRkFVTFRfUkVPUkRFUl9MQUJFTFMsXG4gIEZvbGRlckNyZWF0ZWRQYXlsb2FkLFxuICBGb2xkZXJEZWxldGVSZXF1ZXN0ZWRQYXlsb2FkLFxuICBGb2xkZXJEZWxldGVTdHJhdGVneSxcbiAgRm9sZGVyRGVsZXRlZFBheWxvYWQsXG4gIEZvbGRlcklkQWNjZXNzb3IsXG4gIEZvbGRlck5vZGUsXG4gIEZvbGRlclJlbmFtZWRQYXlsb2FkLFxuICBGb2xkZXJNb3ZlUmVxdWVzdGVkUGF5bG9hZCxcbiAgRm9sZGVyTW92ZWRQYXlsb2FkLFxuICBGb2xkZXJEdXBsaWNhdGVSZXF1ZXN0ZWRQYXlsb2FkLFxuICBNb2R1bGFyQ29uZmlnLFxuICBNb2R1bGFyTGFiZWxzLFxuICBSZW9yZGVyTGFiZWxzLFxuICBSZW9yZGVyU2F2ZVBheWxvYWQsXG4gIFRlc3RzTW92ZWRQYXlsb2FkLFxuICBCdWxrQWN0aW9uSW52b2tlZFBheWxvYWQsXG59IGZyb20gJy4vbW9kdWxhci10YWJsZS10ZW1wbGF0ZS5tb2RlbHMnO1xuaW1wb3J0IHsgTW92ZVRvRm9sZGVyRGlhbG9nQ29tcG9uZW50IH0gZnJvbSAnLi9kaWFsb2dzL21vdmUtdG8tZm9sZGVyLWRpYWxvZy5jb21wb25lbnQnO1xuaW1wb3J0IHsgTmV3Rm9sZGVyRGlhbG9nQ29tcG9uZW50IH0gZnJvbSAnLi9kaWFsb2dzL25ldy1mb2xkZXItZGlhbG9nLmNvbXBvbmVudCc7XG5pbXBvcnQgeyBEZWxldGVGb2xkZXJEaWFsb2dDb21wb25lbnQgfSBmcm9tICcuL2RpYWxvZ3MvZGVsZXRlLWZvbGRlci1kaWFsb2cuY29tcG9uZW50JztcblxuQENvbXBvbmVudCh7XG4gIHNlbGVjdG9yOiAnY3FhLW1vZHVsYXItdGFibGUtdGVtcGxhdGUnLFxuICB0ZW1wbGF0ZVVybDogJy4vbW9kdWxhci10YWJsZS10ZW1wbGF0ZS5jb21wb25lbnQuaHRtbCcsXG4gIHN0eWxlVXJsczogW10sXG4gIGhvc3Q6IHsgY2xhc3M6ICdjcWEtdWktcm9vdCcgfSxcbiAgY2hhbmdlRGV0ZWN0aW9uOiBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneS5PblB1c2hcbn0pXG5leHBvcnQgY2xhc3MgTW9kdWxhclRhYmxlVGVtcGxhdGVDb21wb25lbnQgaW1wbGVtZW50cyBPbkluaXQsIE9uQ2hhbmdlcywgT25EZXN0cm95IHtcbiAgLy8gU2VhcmNoIGJhciBpbnB1dHNcbiAgQElucHV0KCkgc2VhcmNoUGxhY2Vob2xkZXI6IHN0cmluZyA9ICdTZWFyY2ggY29tcG9uZW50cyc7XG4gIEBJbnB1dCgpIHNlYXJjaFZhbHVlOiBzdHJpbmcgPSAnJztcbiAgQElucHV0KCkgc2hvd0NsZWFyOiBib29sZWFuID0gdHJ1ZTtcbiAgQElucHV0KCkgc2hvd1NlYXJjaEJhcjogYm9vbGVhbiA9IHRydWU7XG4gIEBJbnB1dCgpIHNob3dFeHBvcnRCdXR0b246IGJvb2xlYW4gPSBmYWxzZTtcbiAgQElucHV0KCkgaXNFeHBvcnRpbmc6IGJvb2xlYW4gPSBmYWxzZTtcbiAgLy8gU2VhcmNoIGJhciBvdXRwdXRzXG4gIEBPdXRwdXQoKSBvblNlYXJjaENoYW5nZSA9IG5ldyBFdmVudEVtaXR0ZXI8c3RyaW5nPigpO1xuICBAT3V0cHV0KCkgb25FeHBvcnRDbGljayA9IG5ldyBFdmVudEVtaXR0ZXI8eyB0eXBlOiAnbG9jYWwnIHwgJ2VtYWlsJzsgZW1haWxzPzogc3RyaW5nW107IGZyYW1ld29yaz86ICdXRUJEUklWRVJfSU8nIHwgJ1NFTEVOSVVNX0pBVkEnOyBzZWxlY3RlZEl0ZW1zOiBhbnlbXSB9IHwgdm9pZD4oKTtcbiAgLy8gRmlsdGVyIG91dHB1dHNcbiAgQE91dHB1dCgpIG9uQXBwbHlGaWx0ZXJDbGljayA9IG5ldyBFdmVudEVtaXR0ZXI8YW55PigpO1xuICBAT3V0cHV0KCkgb25SZXNldEZpbHRlckNsaWNrID0gbmV3IEV2ZW50RW1pdHRlcjx2b2lkPigpO1xuICBAT3V0cHV0KCkgb25DbGVhckFsbCA9IG5ldyBFdmVudEVtaXR0ZXI8dm9pZD4oKTtcbiAgQE91dHB1dCgpIHJlbW92ZUNoaXAgPSBuZXcgRXZlbnRFbWl0dGVyPGFueT4oKTtcblxuICAvLyBGaWx0ZXIgaW5wdXRzXG4gIEBJbnB1dCgpIGZpbHRlckNvbmZpZzogRHluYW1pY0ZpbHRlckl0ZW1bXSA9IFtdO1xuICBASW5wdXQoKSBmaWx0ZXJNb2RlbDogUmVjb3JkPHN0cmluZywgYW55PiA9IHt9O1xuICBASW5wdXQoKSBzaG93RmlsdGVyUGFuZWw6IGJvb2xlYW4gPSBmYWxzZTtcbiAgQElucHV0KCkgc2hvd0ZpbHRlckJ1dHRvbjogYm9vbGVhbiA9IHRydWU7XG5cbiAgLy8gT3RoZXIgYnV0dG9ucyBpbnB1dCAoYXJyYXkgb2YgYnV0dG9uIHRlbXBsYXRlcy9jb21wb25lbnRzKVxuICBASW5wdXQoKSBvdGhlckJ1dHRvbnM6IFRlbXBsYXRlUmVmPGFueT5bXSA9IFtdO1xuICBcbiAgLy8gT3RoZXIgZHJvcGRvd24gYnV0dG9ucyBpbnB1dCAoYXJyYXkgb2YgZHJvcGRvd24gYnV0dG9uIHRlbXBsYXRlcy9jb21wb25lbnRzKVxuICBASW5wdXQoKSBvdGhlckRyb3BEb3duQnV0dG9uczogVGVtcGxhdGVSZWY8YW55PltdID0gW107XG4gIFxuICAvLyBPdGhlciBzZWxlY3QgZHJvcGRvd24gYnV0dG9ucyBpbnB1dCAoYXJyYXkgb2Ygc2VsZWN0IGRyb3Bkb3duIGJ1dHRvbiB0ZW1wbGF0ZXMvY29tcG9uZW50cylcbiAgQElucHV0KCkgb3RoZXJTZWxlY3REcm9wRG93bkJ1dHRvbnM6IFRlbXBsYXRlUmVmPGFueT5bXSA9IFtdO1xuICBcbiAgLy8gTGVnYWN5IHNpbmdsZSBidXR0b24gaW5wdXRzIChkZXByZWNhdGVkLCBrZXB0IGZvciBiYWNrd2FyZCBjb21wYXRpYmlsaXR5KVxuICAvKiogQGRlcHJlY2F0ZWQgVXNlIG90aGVyQnV0dG9ucyBhcnJheSBpbnN0ZWFkICovXG4gIEBJbnB1dCgpIG90aGVyQnV0dG9uTGFiZWw6IHN0cmluZyA9ICdPdGhlciBCdXR0b24nO1xuICAvKiogQGRlcHJlY2F0ZWQgVXNlIG90aGVyQnV0dG9ucyBhcnJheSBpbnN0ZWFkICovXG4gIEBJbnB1dCgpIG90aGVyQnV0dG9uVmFyaWFudDogJ2ZpbGxlZCcgfCAnb3V0bGluZWQnIHwgJ3RleHQnIHwgJ2VsZXZhdGVkJyB8ICd0b25hbCcgfCAnZ3JleS1zb2xpZCcgPSAnZmlsbGVkJztcbiAgLyoqIEBkZXByZWNhdGVkIFVzZSBvdGhlckJ1dHRvbnMgYXJyYXkgaW5zdGVhZCAqL1xuICBASW5wdXQoKSBzaG93T3RoZXJCdXR0b246IGJvb2xlYW4gPSB0cnVlO1xuICBcbiAgLy8gQWN0aW9uIG1lbnUgYnV0dG9uICh0aHJlZS1kb3QgbWVudSBpbiB0YWJsZSByb3dzKVxuICBASW5wdXQoKSBzaG93QWN0aW9uQnV0dG9uOiBib29sZWFuID0gdHJ1ZTtcblxuICAvLyBTZXR0aW5ncyBhbmQgcmVmcmVzaCBidXR0b25zXG4gIEBJbnB1dCgpIHNob3dTZXR0aW5nc0J1dHRvbjogYm9vbGVhbiA9IHRydWU7XG4gIEBJbnB1dCgpIHNob3dBdXRvUmVmcmVzaEJ1dHRvbjogYm9vbGVhbiA9IHRydWU7XG5cbiAgLy8gVmlldy1tb2RlIHRvZ2dsZSAoTGlzdCB8IE1vZHVsYXIpLiBIaWRkZW4gYnkgZGVmYXVsdCBmb3IgYmFja3dhcmQgY29tcGF0aWJpbGl0eS5cbiAgQElucHV0KCkgc2hvd1ZpZXdNb2RlVG9nZ2xlOiBib29sZWFuID0gZmFsc2U7XG4gIEBJbnB1dCgpIHZpZXdNb2RlOiAnbGlzdCcgfCAnbW9kdWxhcicgPSAnbGlzdCc7XG4gIEBJbnB1dCgpIHZpZXdNb2RlTGFiZWxzOiB7IGxpc3Q6IHN0cmluZzsgbW9kdWxhcjogc3RyaW5nIH0gPSB7IGxpc3Q6ICdMaXN0JywgbW9kdWxhcjogJ01vZHVsYXInIH07XG4gIEBPdXRwdXQoKSB2aWV3TW9kZUNoYW5nZSA9IG5ldyBFdmVudEVtaXR0ZXI8J2xpc3QnIHwgJ21vZHVsYXInPigpO1xuXG4gIGdldCB2aWV3TW9kZVNlZ21lbnRzKCk6IEFycmF5PHsgbGFiZWw6IHN0cmluZzsgdmFsdWU6IHN0cmluZzsgaWNvbj86IHN0cmluZyB9PiB7XG4gICAgcmV0dXJuIFtcbiAgICAgIHsgbGFiZWw6IHRoaXMudmlld01vZGVMYWJlbHMubGlzdCwgdmFsdWU6ICdsaXN0JywgaWNvbjogJ3ZpZXdfbGlzdCcgfSxcbiAgICAgIHsgbGFiZWw6IHRoaXMudmlld01vZGVMYWJlbHMubW9kdWxhciwgdmFsdWU6ICdtb2R1bGFyJywgaWNvbjogJ2ZvbGRlcicgfSxcbiAgICBdO1xuICB9XG5cbiAgb25WaWV3TW9kZUNoYW5nZSh2YWx1ZTogc3RyaW5nKTogdm9pZCB7XG4gICAgY29uc3QgbmV4dCA9IHZhbHVlID09PSAnbW9kdWxhcicgPyAnbW9kdWxhcicgOiAnbGlzdCc7XG4gICAgaWYgKG5leHQgIT09IHRoaXMudmlld01vZGUpIHtcbiAgICAgIHRoaXMudmlld01vZGUgPSBuZXh0O1xuICAgICAgdGhpcy52aWV3TW9kZUNoYW5nZS5lbWl0KG5leHQpO1xuICAgIH1cbiAgfVxuXG4gIC8vIERhdGEgaW5wdXRcbiAgQElucHV0KCkgZGF0YTogYW55W10gPSBbXTtcblxuICAvLyBFbXB0eSBzdGF0ZSBpbnB1dHNcbiAgQElucHV0KCkgaXNFbXB0eVN0YXRlOiBib29sZWFuID0gZmFsc2U7XG4gIEBJbnB1dCgpIGVtcHR5U3RhdGVDb25maWc6IEVtcHR5U3RhdGVDb25maWcgPSB7XG4gICAgdGl0bGU6ICdObyBEYXRhIEF2YWlsYWJsZSBZZXQnLFxuICAgIGRlc2NyaXB0aW9uOiAnUnVuIG9yIHVwbG9hZCB5b3VyIGZpcnN0IHRlc3QgdG8gc2VlIHlvdXIgYW5hbHl0aWNzIGFuZCB0cmVuZHMgaGVyZS4gV2F0Y2ggeW91ciBxdWFsaXR5IG1ldHJpY3MgY29tZSB0byBsaWZlIHdpdGggcmVhbC10aW1lIGluc2lnaHRzLicsXG4gICAgaW1hZ2VVcmw6IEVNUFRZX1NUQVRFX0lNQUdFUy5EQVNIQk9BUkQsXG4gICAgYWN0aW9uczogW3sgbGFiZWw6ICdSdW4gVGVzdCBTdWl0ZScsIHZhcmlhbnQ6ICdmaWxsZWQnIH1dLFxuICB9O1xuXG4gIC8vIEFjdGlvbiBiYXIgaW5wdXRzXG4gIEBJbnB1dCgpIGFjdGlvbnM6IFRhYmxlQWN0aW9uW10gPSBbXG4gICAgeyBcbiAgICAgIGlkOiAnZGVsZXRlJywgXG4gICAgICBsYWJlbDogJ0RlbGV0ZScsIFxuICAgICAgaWNvbjogJ2RlbGV0ZScsIFxuICAgICAgdG9vbHRpcDogJ0RlbGV0ZSBzZWxlY3RlZCcsXG4gICAgICBvbkNsaWNrOiAoY29udGV4dCkgPT4ge1xuICAgICAgICBjb25zb2xlLmxvZygnRGVsZXRlIGFjdGlvbiBjbGlja2VkOicsIGNvbnRleHQpO1xuICAgICAgfVxuICAgIH0sXG4gICAgeyBcbiAgICAgIGlkOiAnZWRpdCcsIFxuICAgICAgbGFiZWw6ICdFZGl0JywgXG4gICAgICBpY29uOiAnZWRpdCcsIFxuICAgICAgdG9vbHRpcDogJ0VkaXQgc2VsZWN0ZWQnLFxuICAgICAgb25DbGljazogKGNvbnRleHQpID0+IHtcbiAgICAgICAgY29uc29sZS5sb2coJ0VkaXQgYWN0aW9uIGNsaWNrZWQ6JywgY29udGV4dCk7XG4gICAgICB9XG4gICAgfSxcbiAgICB7IFxuICAgICAgaWQ6ICdhZGQtdGFnJywgXG4gICAgICBsYWJlbDogJ0FkZCBUYWcnLCBcbiAgICAgIGljb246ICdsb2NhbF9vZmZlcicsIFxuICAgICAgdG9vbHRpcDogJ0FkZCB0YWdzJyxcbiAgICAgIG9uQ2xpY2s6IChjb250ZXh0KSA9PiB7XG4gICAgICAgIGNvbnNvbGUubG9nKCdBZGQgdGFnIGFjdGlvbiBjbGlja2VkOicsIGNvbnRleHQpO1xuICAgICAgfVxuICAgIH0sXG4gICAgeyBcbiAgICAgIGlkOiAncmVtb3ZlLXRhZycsIFxuICAgICAgbGFiZWw6ICdSZW1vdmUgVGFnJywgXG4gICAgICBpY29uOiAnbGFiZWxfb2ZmJywgXG4gICAgICB0b29sdGlwOiAnUmVtb3ZlIHRhZ3MnLFxuICAgICAgb25DbGljazogKGNvbnRleHQpID0+IHtcbiAgICAgICAgY29uc29sZS5sb2coJ1JlbW92ZSB0YWcgYWN0aW9uIGNsaWNrZWQ6JywgY29udGV4dCk7XG4gICAgICB9XG4gICAgfSxcbiAgXTtcblxuICAvLyBDaGlwcyBpbnB1dHNcbiAgQElucHV0KCkgY2hpcHM6IEFycmF5PHsga2V5Pzogc3RyaW5nOyBsYWJlbD86IHN0cmluZzsgdGV4dDogc3RyaW5nOyBmdWxsVGV4dD86IHN0cmluZzsgaGFzTW9yZT86IGJvb2xlYW4gfT4gPSBbXTtcbiAgQElucHV0KCkgZmlsdGVyQXBwbGllZDogYm9vbGVhbiA9IGZhbHNlO1xuXG4gIC8vIFRhYmxlIGlucHV0c1xuICBASW5wdXQoKSBjb2x1bW5zOiBEeW5hbWljVGFibGVDb2x1bW5bXSA9IFtdO1xuICBASW5wdXQoKSByb3dTZWxlY3RhYmxlPzogKHJvdzogYW55KSA9PiBib29sZWFuO1xuICBASW5wdXQoKSBzZWxlY3RlZEF1dG9SZWZyZXNoSW50ZXJ2YWw6IG51bWJlciA9IDA7XG4gIEBJbnB1dCgpIHBhZ2VJbmRleDogbnVtYmVyID0gMDtcbiAgQElucHV0KCkgcGFnZVNpemU6IG51bWJlciA9IDEwO1xuICBASW5wdXQoKSBwYWdlU2l6ZU9wdGlvbnM6IG51bWJlcltdID0gWzEwLCAyMCwgNDAsIDYwLCA4MF07XG4gIEBJbnB1dCgpIHBhZ2VTaXplTWVudURpcmVjdGlvbjogJ2F1dG8nIHwgJ3VwJyB8ICdkb3duJyA9ICdhdXRvJztcbiAgLy8gU2VydmVyLXNpZGUgcGFnaW5hdGlvbiBjb250cm9sc1xuICBASW5wdXQoKSBzZXJ2ZXJTaWRlUGFnaW5hdGlvbjogYm9vbGVhbiA9IGZhbHNlO1xuICBASW5wdXQoKSB0b3RhbEVsZW1lbnRzOiBudW1iZXIgPSAwO1xuICBAT3V0cHV0KCkgcGFnZUNoYW5nZSA9IG5ldyBFdmVudEVtaXR0ZXI8eyBwYWdlSW5kZXg6IG51bWJlcjsgcGFnZVNpemU6IG51bWJlciB9PigpO1xuICAvKipcbiAgICogV2hlbiBmYWxzZSwgaGVhZGVyIHNvcnQgZG9lcyBub3QgcmVvcmRlciByb3dzIGxvY2FsbHkgKHVzZSB3aXRoIHNlcnZlclNpZGVQYWdpbmF0aW9uICsgc29ydENoYW5nZSkuXG4gICAqIERlZmF1bHQgdHJ1ZSBmb3IgYmFja3dhcmQgY29tcGF0aWJpbGl0eS5cbiAgICovXG4gIEBJbnB1dCgpIGVuYWJsZUxvY2FsU29ydDogYm9vbGVhbiA9IHRydWU7XG4gIEBPdXRwdXQoKSBzb3J0Q2hhbmdlID0gbmV3IEV2ZW50RW1pdHRlcjx7XG4gICAgZmllbGRJZDogc3RyaW5nO1xuICAgIGZpZWxkVmFsdWU/OiBzdHJpbmc7XG4gICAgZGlyZWN0aW9uOiAnYXNjJyB8ICdkZXNjJyB8IG51bGw7XG4gIH0+KCk7XG4gIC8vIExvYWRlciBjb250cm9scyAocGFzc2VkIGRvd24gdG8gZHluYW1pYyB0YWJsZSlcbiAgQElucHV0KCkgaXNUYWJsZUxvYWRpbmc/OiBib29sZWFuO1xuICBASW5wdXQoKSBpc1RhYmxlRGF0YUxvYWRpbmc/OiBib29sZWFuO1xuICAvLyBCYWNrd2FyZC1jb21wYXRpYmlsaXR5IGZsYWc7IGlmIHByb3ZpZGVkLCBkeW5hbWljIHRhYmxlIHdpbGwgdXNlIGl0IHdoZW4gc3BlY2lmaWMgZmxhZ3MgYXJlIHVuZGVmaW5lZFxuXG4gIC8vIE9wdGlvbmFsIGdldHRlciBmb3IgSlNPTiBwYXRoIHBlciBjZWxsLiBXaGVuIHByb3ZpZGVkLCBkb3VibGUtY2xpY2tpbmcgYSBjZWxsIGNvcGllcyB0aGUgcGF0aC5cbiAgQElucHV0KCkgY2VsbEpzb25QYXRoR2V0dGVyPzogKHJvd0luZGV4OiBudW1iZXIsIGNvbElkOiBzdHJpbmcsIHJvdzogYW55KSA9PiBzdHJpbmc7XG5cbiAgLy8gT3B0aW9uYWwgaGFuZGxlciBjYWxsZWQgd2hlbiBhIEpTT04gcGF0aCBpcyBjb3BpZWQgZnJvbSBhIHRhYmxlIGNlbGxcbiAgQElucHV0KCkgb25Kc29uUGF0aENvcGllZEhhbmRsZXI/OiAoZXZlbnQ6IHsgcGF0aDogc3RyaW5nOyBzb3VyY2U6IHN0cmluZyB9KSA9PiB2b2lkO1xuXG4gIC8vIFNlbGVjdGVkIGl0ZW1zIChmdWxsIG9iamVjdHMpIGZvciBtYWludGFpbmluZyBzZWxlY3Rpb24gYWNyb3NzIHBhZ2luYXRpb24gKHNlcnZlci1zaWRlKVxuICBASW5wdXQoKSBzZWxlY3RlZEl0ZW1zOiBhbnlbXSA9IFtdO1xuXG4gIC8qKlxuICAgKiBXaGVuIHRydWUsIHRoZSBhY3Rpb24gdG9vbGJhciByZW5kZXJzIHRoZSBcIlNlbGVjdCBhbGxcIiBhZmZvcmRhbmNlLiBEZWZhdWx0cyB0byBmYWxzZVxuICAgKiBmb3Igbm93IOKAlCBob3N0IG9wdHMgaW4uIE1hdGNoZXMgdGhlIGN1cnJlbnQgcHJvZHVjdCByZXF1aXJlbWVudCB0byBoaWRlIFNlbGVjdCBBbGwuXG4gICAqL1xuICBASW5wdXQoKSBzaG93U2VsZWN0QWxsSW5Ub29sYmFyOiBib29sZWFuID0gZmFsc2U7XG4gIC8qKlxuICAgKiBXaGVuIHRydWUsIHRoZSBhY3Rpb24gdG9vbGJhciByZW5kZXJzIHRoZSBkaXNtaXNzICjDlykgYWZmb3JkYW5jZS4gRGVmYXVsdHMgdG8gZmFsc2VcbiAgICogZm9yIG5vdyDigJQgaG9zdCBvcHRzIGluLiBNYXRjaGVzIHRoZSBjdXJyZW50IHByb2R1Y3QgcmVxdWlyZW1lbnQgdG8gaGlkZSBDYW5jZWwuXG4gICAqL1xuICBASW5wdXQoKSBzaG93RGlzbWlzc0luVG9vbGJhcjogYm9vbGVhbiA9IGZhbHNlO1xuICAvKiogQm91bmQgdG8gdGhlIHRvb2xiYXIncyBcIlNlbGVjdCBhbGxcIiBjaGVja2JveCDigJQgZHJpdmVzIHRoZSBjaGVja2VkIHN0YXRlLiAqL1xuICBASW5wdXQoKSBhbGxTZWxlY3RlZEluVG9vbGJhcjogYm9vbGVhbiA9IGZhbHNlO1xuXG4gIC8vIEludGVybmFsIHN0YXRlIGZvciBjb2x1bW4gdmlzaWJpbGl0eVxuICBwcml2YXRlIF9jb2x1bW5WaXNpYmlsaXR5OiBDb2x1bW5WaXNpYmlsaXR5Q29uZmlnID0ge307XG4gIHByaXZhdGUgX2NhY2hlZFZpc2liaWxpdHlDb2x1bW5zOiBBcnJheTx7IGlkOiBzdHJpbmc7IGxhYmVsOiBzdHJpbmcgfT4gPSBbXTtcbiAgZmlsdGVyZWRSb3dzOiBhbnlbXSA9IFtdO1xuICBwYWdlZFJvd3M6IGFueVtdID0gW107XG5cbiAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuICAvLyBGb2xkZXIgLyBtb2R1bGFyIGlucHV0c1xuICAvLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4gIEBJbnB1dCgpIGZvbGRlcnM6IEZvbGRlck5vZGVbXSA9IFtdO1xuICBASW5wdXQoKSBzZWxlY3RlZEZvbGRlcklkOiBudW1iZXIgfCBudWxsID0gbnVsbDtcbiAgQElucHV0KCkgZXhwYW5kZWRGb2xkZXJJZHM6IG51bWJlcltdID0gW107XG4gIEBJbnB1dCgpIHVub3JnYW5pc2VkQ291bnQ6IG51bWJlciA9IDA7XG4gIEBJbnB1dCgpIGZvbGRlcklkQWNjZXNzb3I6IEZvbGRlcklkQWNjZXNzb3IgPSAocm93OiBhbnkpID0+IHJvdz8uZm9sZGVySWQgPz8gbnVsbDtcbiAgQElucHV0KCkgbW9kdWxhckNvbmZpZzogTW9kdWxhckNvbmZpZyA9IHsgLi4uREVGQVVMVF9NT0RVTEFSX0NPTkZJRyB9O1xuICBASW5wdXQoKSBtb2R1bGFyTGFiZWxzOiBNb2R1bGFyTGFiZWxzID0geyAuLi5ERUZBVUxUX01PRFVMQVJfTEFCRUxTIH07XG4gIEBJbnB1dCgpIGJ1bGtBY3Rpb25zOiBUYWJsZUFjdGlvbltdID0gW107XG4gIEBJbnB1dCgpIHNpZGViYXJDb2xsYXBzZWQ6IGJvb2xlYW4gPSBmYWxzZTtcblxuICAvKipcbiAgICogV2hlbiB0cnVlIChkZWZhdWx0KSwgdGhlIGxpYnJhcnkgb3BlbnMgaXRzIG93biBNb3ZlIGRpYWxvZyBmb3IgY29udmVuaWVuY2VcbiAgICogZHVyaW5nIHRlc3RpbmcuIEhvc3RzIHRha2luZyBvdmVyIEFQSSArIFVYIHNob3VsZCBzZXQgdGhpcyB0byBgZmFsc2VgIGFuZFxuICAgKiBsaXN0ZW4gb24gYG1vdmVSZXF1ZXN0ZWRgIHRvIHJlbmRlciB0aGVpciBvd24uXG4gICAqL1xuICBASW5wdXQoKSB1c2VJbnRlcm5hbERpYWxvZ3M6IGJvb2xlYW4gPSB0cnVlO1xuXG4gIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAgLy8gRm9sZGVyIC8gbW9kdWxhciBvdXRwdXRzXG4gIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAgQE91dHB1dCgpIGZvbGRlclNlbGVjdGVkID0gbmV3IEV2ZW50RW1pdHRlcjxudW1iZXIgfCBudWxsPigpO1xuICBAT3V0cHV0KCkgZm9sZGVyRXhwYW5zaW9uVG9nZ2xlZCA9IG5ldyBFdmVudEVtaXR0ZXI8eyBpZDogbnVtYmVyOyBleHBhbmRlZDogYm9vbGVhbiB9PigpO1xuICBAT3V0cHV0KCkgZm9sZGVyQ3JlYXRlZCA9IG5ldyBFdmVudEVtaXR0ZXI8Rm9sZGVyQ3JlYXRlZFBheWxvYWQ+KCk7XG4gIC8qKiBFbWl0dGVkIHdoZW4gdGhlIHVzZXIgY2xpY2tzIFwiKyBOZXcgZm9sZGVyXCI7IGhvc3Qgc2hvdWxkIG9wZW4gYSBjcmVhdGlvbiBtb2RhbC4gKi9cbiAgQE91dHB1dCgpIGZvbGRlckNyZWF0ZVJlcXVlc3RlZCA9IG5ldyBFdmVudEVtaXR0ZXI8eyBwYXJlbnRJZDogbnVtYmVyIHwgbnVsbCB9PigpO1xuICBAT3V0cHV0KCkgZm9sZGVyUmVuYW1lZCA9IG5ldyBFdmVudEVtaXR0ZXI8Rm9sZGVyUmVuYW1lZFBheWxvYWQ+KCk7XG4gIC8qKlxuICAgKiBGaXJlcyBhZnRlciB0aGUgdXNlciBjb25maXJtcyBmb2xkZXIgZGVsZXRpb24gdmlhIHRoZSBpbnRlcm5hbCBkaWFsb2cgKG9yXG4gICAqIGltbWVkaWF0ZWx5LCB3aGVuIGB1c2VJbnRlcm5hbERpYWxvZ3NgIGlzIGZhbHNlIGFuZCB0aGUgaG9zdCBkcml2ZXMgdGhlIFVYKS5cbiAgICogUGF5bG9hZCBub3cgaW5jbHVkZXMgdGhlIHVzZXIncyBjaG9zZW4gYHN0cmF0ZWd5YCBmb3Igd2hhdCBoYXBwZW5zIHRvIHRoZVxuICAgKiBmb2xkZXIncyB0ZXN0IGNhc2VzLlxuICAgKi9cbiAgQE91dHB1dCgpIGZvbGRlckRlbGV0ZWQgPSBuZXcgRXZlbnRFbWl0dGVyPEZvbGRlckRlbGV0ZWRQYXlsb2FkPigpO1xuICBAT3V0cHV0KCkgdGVzdHNNb3ZlZCA9IG5ldyBFdmVudEVtaXR0ZXI8VGVzdHNNb3ZlZFBheWxvYWQ+KCk7XG5cbiAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gIC8vIEJ1bGsgYWN0aW9uIHRvb2xiYXIgc3VyZmFjZSDigJQgbmFtaW5nIG1pcnJvcnMgY3FhLXRhYmxlLXRlbXBsYXRlIHNvIGNvbnN1bWVyc1xuICAvLyBnZXQgdGhlIHNhbWUgZXZlbnRzIGZyb20gZWl0aGVyIGNvbXBvbmVudCAocGx1cyB0aGUgZm9sZGVyIGV2ZW50cyBiZWxvdykuXG4gIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG4gIC8qKiBGaXJlcyBvbiByYXcgdG9vbGJhciBhY3Rpb24gY2xpY2sg4oCUICpiZWZvcmUqIGFueSBpbnRlcm5hbCBkaWFsb2cgb3BlbnMuICovXG4gIEBPdXRwdXQoKSBidWxrQWN0aW9uQ2xpY2sgPSBuZXcgRXZlbnRFbWl0dGVyPHsgaWQ6IHN0cmluZzsgc2VsZWN0ZWQ6IGFueVtdIH0+KCk7XG4gIC8qKiBGaXJlcyB3aGVuIHRoZSB0b29sYmFyJ3MgXCJTZWxlY3QgYWxsXCIgaXMgdG9nZ2xlZC4gKi9cbiAgQE91dHB1dCgpIGJ1bGtTZWxlY3RBbGxDaGFuZ2UgPSBuZXcgRXZlbnRFbWl0dGVyPGJvb2xlYW4+KCk7XG4gIC8qKiBGaXJlcyB3aGVuIHRoZSB0b29sYmFyJ3MgZGlzbWlzcyAow5cpIGlzIGNsaWNrZWQuICovXG4gIEBPdXRwdXQoKSBidWxrRGlzbWlzcyA9IG5ldyBFdmVudEVtaXR0ZXI8dm9pZD4oKTtcblxuICAvKipcbiAgICogRmlyZXMgKmFmdGVyKiB0aGUgbGlicmFyeS1pbnRlcm5hbCBtb3ZlLXRvLWZvbGRlciBkaWFsb2cgcmVzb2x2ZXMgd2l0aCBhXG4gICAqIHVzZXIgY29uZmlybWF0aW9uLCBPUiBpbW1lZGlhdGVseSBmb3Igbm9uLWRpYWxvZyBidWxrIGFjdGlvbnMgc3VwcGxpZWQgYnlcbiAgICogdGhlIGhvc3QuIEhvc3RzIHdpdGggdGhlaXIgb3duIFVYIHNob3VsZCBsaXN0ZW4gb24gYGJ1bGtBY3Rpb25DbGlja2AgK1xuICAgKiBgbW92ZVJlcXVlc3RlZGAgYW5kIHRyZWF0IHRoaXMgYXMgdGhlIFwiY29uZmlybWVkXCIgc2lnbmFsLlxuICAgKi9cbiAgQE91dHB1dCgpIGJ1bGtBY3Rpb25JbnZva2VkID0gbmV3IEV2ZW50RW1pdHRlcjxCdWxrQWN0aW9uSW52b2tlZFBheWxvYWQ+KCk7XG5cbiAgQE91dHB1dCgpIHNpZGViYXJDb2xsYXBzZWRDaGFuZ2UgPSBuZXcgRXZlbnRFbWl0dGVyPGJvb2xlYW4+KCk7XG5cbiAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuICAvLyBSb3ctcmVvcmRlciBzdXJmYWNlXG4gIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAgLyoqIFdoZW4gdHJ1ZSwgcmVuZGVycyBhIFwiUmVvcmRlclwiIGJ1dHRvbiBpbiB0aGUgdG9vbGJhci4gSG9zdC1kcml2ZW4uICovXG4gIEBJbnB1dCgpIHNob3dSZW9yZGVyQnV0dG9uOiBib29sZWFuID0gZmFsc2U7XG4gIC8qKlxuICAgKiBIb3N0IGZsaXBzIHRoaXMgdHJ1ZSB3aGlsZSBpdHMgYnVsay11cGRhdGUgQVBJIGNhbGwgaXMgaW4tZmxpZ2h0LiBUaGVcbiAgICogY29tcG9uZW50IGtlZXBzIHRoZSByZW9yZGVyIFVJIHBpbm5lZCAoXCJTYXZpbmcuLi5cIikgd2hpbGUgdHJ1ZSBhbmQgZXhpdHNcbiAgICogcmVvcmRlciBtb2RlIHdoZW4gaXQgZmxpcHMgYmFjayB0byBmYWxzZSAodGhlIFwiZnV0dXJlIEFQSSBjYWxsXCIgaG9vaykuXG4gICAqL1xuICBASW5wdXQoKSByZW9yZGVyU2F2aW5nOiBib29sZWFuID0gZmFsc2U7XG4gIC8qKiBQYXJ0aWFsIG92ZXJyaWRlIGZvciB0aGUgZGVmYXVsdCByZW9yZGVyIGxhYmVscyAoXCJSZW9yZGVyXCIsIFwiRG9uZVwiLCBldGMuKS4gKi9cbiAgQElucHV0KCkgc2V0IHJlb3JkZXJMYWJlbHMocGFydGlhbDogUGFydGlhbDxSZW9yZGVyTGFiZWxzPiB8IHVuZGVmaW5lZCkge1xuICAgIHRoaXMuX3Jlb3JkZXJMYWJlbHMgPSB7IC4uLkRFRkFVTFRfUkVPUkRFUl9MQUJFTFMsIC4uLihwYXJ0aWFsIHx8IHt9KSB9O1xuICB9XG4gIGdldCByZW9yZGVyTGFiZWxzKCk6IFJlb3JkZXJMYWJlbHMge1xuICAgIHJldHVybiB0aGlzLl9yZW9yZGVyTGFiZWxzO1xuICB9XG4gIHByaXZhdGUgX3Jlb3JkZXJMYWJlbHM6IFJlb3JkZXJMYWJlbHMgPSB7IC4uLkRFRkFVTFRfUkVPUkRFUl9MQUJFTFMgfTtcblxuICAvKiogRmlyZXMgd2hlbiB0aGUgdXNlciBjbGlja3MgXCJSZW9yZGVyXCIgYW5kIHRoZSBjb21wb25lbnQgZW50ZXJzIHJlb3JkZXIgbW9kZS4gKi9cbiAgQE91dHB1dCgpIHJlb3JkZXJTdGFydCA9IG5ldyBFdmVudEVtaXR0ZXI8dm9pZD4oKTtcbiAgLyoqIEZpcmVzIHdoZW4gdGhlIHVzZXIgY2xpY2tzIFwiQ2FuY2VsXCIg4oCUIHRoZSBvcmlnaW5hbCBvcmRlciBpcyBhbHJlYWR5IHJlc3RvcmVkLiAqL1xuICBAT3V0cHV0KCkgcmVvcmRlckNhbmNlbCA9IG5ldyBFdmVudEVtaXR0ZXI8dm9pZD4oKTtcbiAgLyoqXG4gICAqIEZpcmVzIHdoZW4gdGhlIHVzZXIgY2xpY2tzIFwiRG9uZVwiLiBIb3N0IHNob3VsZCB0YWtlIGBvcmRlcmVkSXRlbXNgLCBjYWxsIGl0c1xuICAgKiBidWxrLXVwZGF0ZSBBUEksIHJlZnJlc2ggYFtkYXRhXWAsIGFuZCBmbGlwIGByZW9yZGVyU2F2aW5nYCBiYWNrIHRvIGBmYWxzZWAg4oCUXG4gICAqIHRoZSBjb21wb25lbnQgd2lsbCB0aGVuIGV4aXQgcmVvcmRlciBtb2RlLlxuICAgKlxuICAgKiBOb3RlOiBmb3Igc2VydmVyLXNpZGUgcGFnaW5hdGlvbiwgYG9yZGVyZWRJdGVtc2AgaXMgdGhlICpjdXJyZW50IHBhZ2Ugc2xpY2UqLFxuICAgKiBub3QgdGhlIGZ1bGwgZGF0YXNldCDigJQgc2FtZSBhcyB0aGUgaW4tbWVtb3J5IHZpZXcgdGhlIHVzZXIgd2FzIGRyYWdnaW5nLlxuICAgKi9cbiAgQE91dHB1dCgpIHJlb3JkZXJTYXZlID0gbmV3IEV2ZW50RW1pdHRlcjxSZW9yZGVyU2F2ZVBheWxvYWQ+KCk7XG5cbiAgLyoqIEludGVybmFsIOKAlCB0cnVlIHdoaWxlIHRoZSB1c2VyIGlzIGluIHJlb3JkZXIgbW9kZS4gKi9cbiAgaXNSZW9yZGVyaW5nOiBib29sZWFuID0gZmFsc2U7XG4gIC8qKiBTbmFwc2hvdCBvZiBgcGFnZWRSb3dzYCB0YWtlbiBvbiBlbnRlcjsgdXNlZCB0byByZXZlcnQgb24gY2FuY2VsLiAqL1xuICBwcml2YXRlIHJlb3JkZXJTbmFwc2hvdDogYW55W10gfCBudWxsID0gbnVsbDtcbiAgLyoqIERyYWZ0IG9mIHRoZSByZW9yZGVyZWQgcm93cyAoY3VycmVudCB3b3JraW5nIHN0YXRlKS4gKi9cbiAgcHJpdmF0ZSByZW9yZGVyRHJhZnQ6IGFueVtdIHwgbnVsbCA9IG51bGw7XG4gIC8qKiBBdXRvLXJlZnJlc2ggaW50ZXJ2YWwgY2FwdHVyZWQgb24gZW50ZXIsIHNvIHdlIGNhbiByZXN0b3JlIG9uIGNhbmNlbC9kb25lLiAqL1xuICBwcml2YXRlIHJlb3JkZXJTYXZlZEF1dG9SZWZyZXNoOiBudW1iZXIgPSAwO1xuICAvKiogVHJ1ZSBhZnRlciBEb25lIGhhcyBiZWVuIGNsaWNrZWQsIGF3YWl0aW5nIHRoZSBob3N0J3MgYHJlb3JkZXJTYXZpbmdgIOKGkiBmYWxzZSBmbGlwLiAqL1xuICBwcml2YXRlIHJlb3JkZXJBd2FpdGluZ1NhdmVGbGlwOiBib29sZWFuID0gZmFsc2U7XG5cbiAgLyoqXG4gICAqIEZpcmVzIHdoZW4gdGhlIHVzZXIgY2xpY2tzIHRoZSBcIk1vdmUgdG8gZm9sZGVyXCIgYnVsayBhY3Rpb24g4oCUICpiZWZvcmUqIHRoZVxuICAgKiBpbnRlcm5hbCBkaWFsb2cgb3BlbnMuIEhvc3RzIHRoYXQgd2FudCB0byByZW5kZXIgdGhlaXIgb3duIG1vZGFsIHNob3VsZFxuICAgKiBzZXQgYHVzZUludGVybmFsRGlhbG9ncyA9IGZhbHNlYCBhbmQgbGlzdGVuIGhlcmUuXG4gICAqL1xuICBAT3V0cHV0KCkgbW92ZVJlcXVlc3RlZCA9IG5ldyBFdmVudEVtaXR0ZXI8e1xuICAgIHRlc3RJZHM6IEFycmF5PHN0cmluZyB8IG51bWJlcj47XG4gICAgc2VsZWN0ZWQ6IGFueVtdO1xuICAgIGN1cnJlbnRGb2xkZXJJZDogbnVtYmVyIHwgbnVsbDtcbiAgICBmb2xkZXJzOiBGb2xkZXJOb2RlW107XG4gIH0+KCk7XG5cbiAgLyoqIEZpcmVzIHdoZW5ldmVyIHRoZSBjb21wb25lbnQncyBgc2VsZWN0ZWRJdGVtc2AgY2hhbmdlcyBmcm9tIHdpdGhpbiAoU2VsZWN0IEFsbCAvIERpc21pc3MpLiAqL1xuICBAT3V0cHV0KCkgc2VsZWN0ZWRJdGVtc0NoYW5nZSA9IG5ldyBFdmVudEVtaXR0ZXI8YW55W10+KCk7XG5cbiAgLyoqXG4gICAqIEZpcmVzIHdoZW4gdGhlIHVzZXIgY2xpY2tzIGEgZm9sZGVyJ3MgZGVsZXRlIGFmZm9yZGFuY2Ug4oCUICpiZWZvcmUqIHRoZVxuICAgKiBpbnRlcm5hbCBjb25maXJtYXRpb24gZGlhbG9nIG9wZW5zLiBIb3N0cyBvd25pbmcgdGhlIFVYIGxpc3RlbiBoZXJlLlxuICAgKiBQYXlsb2FkIGluY2x1ZGVzIGB0ZXN0Q291bnRgICsgYGhhc1BhcmVudGAgc28gaG9zdHMgY2FuIHJlbmRlciB0aGUgcmlnaHRcbiAgICogb3B0aW9ucyBpbiB0aGVpciBvd24gbW9kYWwuXG4gICAqL1xuICBAT3V0cHV0KCkgZm9sZGVyRGVsZXRlUmVxdWVzdGVkID0gbmV3IEV2ZW50RW1pdHRlcjxGb2xkZXJEZWxldGVSZXF1ZXN0ZWRQYXlsb2FkPigpO1xuXG4gIC8qKlxuICAgKiBGaXJlcyB3aGVuIHRoZSB1c2VyIHBpY2tzIFwiTW92ZSBmb2xkZXJcIiBmcm9tIGEgZm9sZGVyIHJvdydzIGNvbnRleHQgbWVudSDigJRcbiAgICogKmJlZm9yZSogYW55IGRpYWxvZyBvcGVucy4gSG9zdHMgb3duaW5nIHRoZSBVWCBsaXN0ZW4gaGVyZSB3aXRoXG4gICAqIGB1c2VJbnRlcm5hbERpYWxvZ3MgPSBmYWxzZWAgYW5kIG9wZW4gdGhlaXIgb3duIGZvbGRlciBwaWNrZXIuXG4gICAqL1xuICBAT3V0cHV0KCkgZm9sZGVyTW92ZVJlcXVlc3RlZCA9IG5ldyBFdmVudEVtaXR0ZXI8Rm9sZGVyTW92ZVJlcXVlc3RlZFBheWxvYWQ+KCk7XG4gIC8qKlxuICAgKiBGaXJlcyBhZnRlciB0aGUgdXNlciBjb25maXJtcyBhIGZvbGRlciBtb3ZlIHZpYSB0aGUgaW50ZXJuYWwgcGlja2VyXG4gICAqIChvciBpbW1lZGlhdGVseSB3aGVuIGB1c2VJbnRlcm5hbERpYWxvZ3MgPSBmYWxzZWAgYW5kIHRoZSBob3N0IGRyaXZlcyBpdCkuXG4gICAqL1xuICBAT3V0cHV0KCkgZm9sZGVyTW92ZWQgPSBuZXcgRXZlbnRFbWl0dGVyPEZvbGRlck1vdmVkUGF5bG9hZD4oKTtcbiAgLyoqXG4gICAqIEZpcmVzIHdoZW4gdGhlIHVzZXIgcGlja3MgXCJEdXBsaWNhdGUgZm9sZGVyXCIgZnJvbSBhIGZvbGRlciByb3cncyBjb250ZXh0IG1lbnUuXG4gICAqIFRoZSBsaWJyYXJ5IGRvZXNuJ3Qgb3duIHBlcnNpc3RlbmNlLCBzbyB0aGUgaG9zdCBpcyBleHBlY3RlZCB0byBjbG9uZSB0aGVcbiAgICogZm9sZGVyJ3Mgc3VidHJlZSBzZXJ2ZXItc2lkZSBhbmQgKnJlZmVyZW5jZSogKG5vdCBjb3B5KSB0aGUgdGVzdCBjYXNlcy5cbiAgICovXG4gIEBPdXRwdXQoKSBmb2xkZXJEdXBsaWNhdGVSZXF1ZXN0ZWQgPSBuZXcgRXZlbnRFbWl0dGVyPEZvbGRlckR1cGxpY2F0ZVJlcXVlc3RlZFBheWxvYWQ+KCk7XG5cbiAgY29uc3RydWN0b3IocHJpdmF0ZSBjZHI6IENoYW5nZURldGVjdG9yUmVmLCBwcml2YXRlIGRpYWxvZ1NlcnZpY2U6IERpYWxvZ1NlcnZpY2UpIHt9XG4gIHByaXZhdGUgcGVuZGluZ0ZpbHRlcnM6IGFueTtcbiAgcHJpdmF0ZSBhcHBsaWVkRmlsdGVyczogYW55O1xuICBwcml2YXRlIGF1dG9SZWZyZXNoVGltZXI/OiBSZXR1cm5UeXBlPHR5cGVvZiBzZXRJbnRlcnZhbD47XG4gIEBPdXRwdXQoKSBvblJlbG9hZCA9IG5ldyBFdmVudEVtaXR0ZXI8dm9pZD4oKTtcbiAgQE91dHB1dCgpIG9uQXV0b1JlZnJlc2hDbGljayA9IG5ldyBFdmVudEVtaXR0ZXI8dm9pZD4oKTtcbiAgQE91dHB1dCgpIGNvbHVtblZpc2liaWxpdHlDaGFuZ2UgPSBuZXcgRXZlbnRFbWl0dGVyPENvbHVtblZpc2liaWxpdHlDb25maWc+KCk7XG4gIEBPdXRwdXQoKSBhdXRvUmVmcmVzaEludGVydmFsQ2hhbmdlID0gbmV3IEV2ZW50RW1pdHRlcjxudW1iZXI+KCk7XG4gIEBWaWV3Q2hpbGQoRHluYW1pY0ZpbHRlckNvbXBvbmVudCkgZHluYW1pY0ZpbHRlckNvbXBvbmVudD86IER5bmFtaWNGaWx0ZXJDb21wb25lbnQ7XG5cbiAgLy8gRGVyaXZlZCBjb2x1bW5zIHdpdGggdmlzaWJpbGl0eSBhcHBsaWVkLlxuICBjb21wdXRlZENvbHVtbnM6IER5bmFtaWNUYWJsZUNvbHVtbltdID0gW107XG4gIC8vIEF1dG8tZ2VuZXJhdGVkIHZpc2liaWxpdHkgY29sdW1ucyBmcm9tIGNvbHVtbnMgaW5wdXRcbiAgdmlzaWJpbGl0eUNvbHVtbnM6IEFycmF5PHsgaWQ6IHN0cmluZzsgbGFiZWw6IHN0cmluZyB9PiA9IFtdO1xuXG4gIHByaXZhdGUgdXBkYXRlQ29tcHV0ZWRDb2x1bW5zKCk6IHZvaWQge1xuICAgIGNvbnN0IHZpc2liaWxpdHkgPSB0aGlzLl9jb2x1bW5WaXNpYmlsaXR5IHx8IHt9O1xuICAgIGNvbnN0IHNvdXJjZSA9IHRoaXMuY29sdW1ucyB8fCBbXTtcbiAgICB0aGlzLmNvbXB1dGVkQ29sdW1ucyA9IHNvdXJjZS5tYXAoY29sID0+IHtcbiAgICAgIGlmIChbJ2NoZWNrYm94JywgJ2FjdGlvbnMnXS5pbmNsdWRlcyhjb2wuZmllbGRJZCkpIHtcbiAgICAgICAgcmV0dXJuIGNvbDtcbiAgICAgIH1cbiAgICAgIGNvbnN0IHNob3cgPSB2aXNpYmlsaXR5W2NvbC5maWVsZElkXTtcbiAgICAgIHJldHVybiB7IC4uLmNvbCwgaXNTaG93OiBzaG93ICE9PSBmYWxzZSB9O1xuICAgIH0pO1xuICAgIHRoaXMuY2RyLm1hcmtGb3JDaGVjaygpO1xuICB9XG5cbiAgcHJpdmF0ZSB1cGRhdGVWaXNpYmlsaXR5Q29sdW1ucygpOiB2b2lkIHtcbiAgICB0aGlzLl9jYWNoZWRWaXNpYmlsaXR5Q29sdW1ucyA9IHRoaXMubWFwVmlzaWJpbGl0eUNvbHVtbnMoKTtcbiAgICB0aGlzLnZpc2liaWxpdHlDb2x1bW5zID0gdGhpcy5fY2FjaGVkVmlzaWJpbGl0eUNvbHVtbnM7XG4gICAgdGhpcy5jZHIubWFya0ZvckNoZWNrKCk7XG4gIH1cblxuICAvLyBDb250cm9sbGVkIGNvbHVtbiB2aXNpYmlsaXR5OiBwYXJlbnQgY2FuIHNlZWQgYW5kIHB1c2ggdXBkYXRlcy5cbiAgQElucHV0KCkgc2V0IGNvbHVtblZpc2liaWxpdHkoY2ZnOiBDb2x1bW5WaXNpYmlsaXR5Q29uZmlnIHwgdW5kZWZpbmVkKSB7XG4gICAgaWYgKGNmZykge1xuICAgICAgdGhpcy5fY29sdW1uVmlzaWJpbGl0eSA9IHsgLi4uY2ZnIH07XG4gICAgICB0aGlzLnVwZGF0ZUNvbXB1dGVkQ29sdW1ucygpO1xuICAgICAgdGhpcy5jZHIubWFya0ZvckNoZWNrKCk7XG4gICAgfVxuICB9XG4gIGdldCBjb2x1bW5WaXNpYmlsaXR5KCk6IENvbHVtblZpc2liaWxpdHlDb25maWcge1xuICAgIHJldHVybiB0aGlzLl9jb2x1bW5WaXNpYmlsaXR5O1xuICB9XG4gIG5nT25Jbml0KCk6IHZvaWQge1xuICAgIHRoaXMuaW5pdGlhbGl6ZUNvbXBvbmVudCgpO1xuICAgIHRoaXMudXBkYXRlQ29tcHV0ZWRDb2x1bW5zKCk7XG4gICAgdGhpcy51cGRhdGVWaXNpYmlsaXR5Q29sdW1ucygpO1xuICB9XG5cbiAgbmdPbkNoYW5nZXMoY2hhbmdlczogU2ltcGxlQ2hhbmdlcyk6IHZvaWQge1xuICAgIGlmIChjaGFuZ2VzWydkYXRhJ10gfHwgY2hhbmdlc1snaXNFbXB0eVN0YXRlJ10pIHtcbiAgICAgIHRoaXMuaW5pdGlhbGl6ZUNvbXBvbmVudCgpO1xuICAgIH1cbiAgICBpZiAoY2hhbmdlc1snY29sdW1ucyddKSB7XG4gICAgICB0aGlzLmluaXRpYWxpemVDb2x1bW5WaXNpYmlsaXR5KCk7XG4gICAgICB0aGlzLnVwZGF0ZUNvbXB1dGVkQ29sdW1ucygpO1xuICAgICAgdGhpcy51cGRhdGVWaXNpYmlsaXR5Q29sdW1ucygpO1xuICAgIH1cbiAgICBpZiAoY2hhbmdlc1snc2VsZWN0ZWRGb2xkZXJJZCddICYmICFjaGFuZ2VzWydzZWxlY3RlZEZvbGRlcklkJ10uZmlyc3RDaGFuZ2UpIHtcbiAgICAgIC8vIFBlciB0aGUgYXBwcm92ZWQgcGxhbjogY2xlYXIgc2VsZWN0aW9uIGFuZCByZXNldCBwYWdpbmF0aW9uIG9uIGZvbGRlciBjaGFuZ2UuXG4gICAgICB0aGlzLnNlbGVjdGVkSXRlbXMgPSBbXTtcbiAgICAgIHRoaXMucGFnZUluZGV4ID0gMDtcbiAgICAgIHRoaXMucmVidWlsZEZpbHRlcmVkUm93cygpO1xuICAgICAgdGhpcy5hcHBseVBhZ2luYXRpb24oKTtcbiAgICB9XG4gICAgaWYgKGNoYW5nZXNbJ3ZpZXdNb2RlJ10gJiYgIWNoYW5nZXNbJ3ZpZXdNb2RlJ10uZmlyc3RDaGFuZ2UpIHtcbiAgICAgIC8vIFN3aXRjaGluZyBiZXR3ZWVuIGxpc3QgYW5kIG1vZHVsYXIgY2hhbmdlcyB3aGV0aGVyIHRoZSBmb2xkZXIgZmlsdGVyIGFwcGxpZXMuXG4gICAgICB0aGlzLnBhZ2VJbmRleCA9IDA7XG4gICAgICB0aGlzLnJlYnVpbGRGaWx0ZXJlZFJvd3MoKTtcbiAgICAgIHRoaXMuYXBwbHlQYWdpbmF0aW9uKCk7XG4gICAgfVxuICAgIGlmIChjaGFuZ2VzWydzZWxlY3RlZEl0ZW1zJ10gfHwgY2hhbmdlc1snZGF0YSddKSB7XG4gICAgICB0aGlzLnJlc3RvcmVTZWxlY3Rpb25TdGF0ZSgpO1xuICAgIH1cbiAgICBpZiAoY2hhbmdlc1sncmVvcmRlclNhdmluZyddICYmICFjaGFuZ2VzWydyZW9yZGVyU2F2aW5nJ10uZmlyc3RDaGFuZ2UpIHtcbiAgICAgIGNvbnN0IG5vd1NhdmluZyA9ICEhY2hhbmdlc1sncmVvcmRlclNhdmluZyddLmN1cnJlbnRWYWx1ZTtcbiAgICAgIC8vIEhvc3QgZmluaXNoZWQgaXRzIGJ1bGstdXBkYXRlIGNhbGwg4oCUIGV4aXQgcmVvcmRlciBtb2RlLlxuICAgICAgaWYgKCFub3dTYXZpbmcgJiYgdGhpcy5yZW9yZGVyQXdhaXRpbmdTYXZlRmxpcCkge1xuICAgICAgICB0aGlzLmV4aXRSZW9yZGVyTW9kZSgpO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgaW5pdGlhbGl6ZUNvbXBvbmVudCgpOiB2b2lkIHtcbiAgICBpZiAodGhpcy5pc0VtcHR5U3RhdGUpIHtcbiAgICAgIHRoaXMuZmlsdGVyZWRSb3dzID0gW107XG4gICAgICB0aGlzLnBhZ2VkUm93cyA9IFtdO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIC8vIEluIHNlcnZlci1zaWRlIG1vZGUsIGFzc3VtZSBpbmNvbWluZyBkYXRhIGlzIGFscmVhZHkgYSBwYWdlIHNsaWNlXG4gICAgaWYgKHRoaXMuc2VydmVyU2lkZVBhZ2luYXRpb24pIHtcbiAgICAgIHRoaXMuZmlsdGVyZWRSb3dzID0gWy4uLnRoaXMuZGF0YV07XG4gICAgICB0aGlzLnBhZ2VkUm93cyA9IFsuLi50aGlzLmZpbHRlcmVkUm93c107XG4gICAgICB0aGlzLmluaXRpYWxpemVDb2x1bW5WaXNpYmlsaXR5KCk7XG4gICAgICB0aGlzLnJlc3RvcmVTZWxlY3Rpb25TdGF0ZSgpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIHRoaXMucmVidWlsZEZpbHRlcmVkUm93cygpO1xuICAgIHRoaXMuYXBwbHlQYWdpbmF0aW9uKCk7XG4gICAgdGhpcy5pbml0aWFsaXplQ29sdW1uVmlzaWJpbGl0eSgpO1xuICAgIHRoaXMudXBkYXRlQ29tcHV0ZWRDb2x1bW5zKCk7XG4gICAgdGhpcy5yZXN0b3JlU2VsZWN0aW9uU3RhdGUoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBCdWlsZCBgZmlsdGVyZWRSb3dzYCBmcm9tIGBkYXRhYCBieSBhcHBseWluZyAoYSkgdGhlIGZpZWxkIGZpbHRlcnMgKHN0YXR1cy9wcmlvcml0eS9ldGMuKVxuICAgKiBhbmQgKGIpIHRoZSBmb2xkZXIgZmlsdGVyIGRlcml2ZWQgZnJvbSBgc2VsZWN0ZWRGb2xkZXJJZGAgKyBgZm9sZGVySWRBY2Nlc3NvcmAuXG4gICAqL1xuICBwcml2YXRlIHJlYnVpbGRGaWx0ZXJlZFJvd3MoKTogdm9pZCB7XG4gICAgY29uc3QgZWZmZWN0aXZlID0gdGhpcy5hcHBsaWVkRmlsdGVycyA/PyB7fTtcbiAgICB0aGlzLmZpbHRlcmVkUm93cyA9IHRoaXMuZGF0YS5maWx0ZXIociA9PiB0aGlzLnBhc3NGaWx0ZXJzKGVmZmVjdGl2ZSwgcikgJiYgdGhpcy5wYXNzRm9sZGVyKHIpKTtcbiAgfVxuXG4gIHByaXZhdGUgcGFzc0ZvbGRlcihyb3c6IGFueSk6IGJvb2xlYW4ge1xuICAgIC8vIExpc3QgdmlldyBpZ25vcmVzIGZvbGRlciBmaWx0ZXJpbmcgZW50aXJlbHkg4oCUIGJlaGF2ZXMgbGlrZSB0aGUgdHJhZGl0aW9uYWwgZmxhdCB0YWJsZS5cbiAgICBpZiAoIXRoaXMuaXNNb2R1bGFyVmlldykgcmV0dXJuIHRydWU7XG4gICAgY29uc3QgZm9sZGVySWQgPSB0aGlzLmZvbGRlcklkQWNjZXNzb3IgPyB0aGlzLmZvbGRlcklkQWNjZXNzb3Iocm93KSA6IHJvdz8uZm9sZGVySWQ7XG4gICAgLy8gUm9vdCB2aWV3OiBzaG93IG9ubHkgcm93cyB0aGF0IGRvIG5vdCBiZWxvbmcgdG8gYW55IGZvbGRlciAodGhlIFwiVW5vcmdhbmlzZWRcIiBidWNrZXQpLlxuICAgIC8vIEZvbGRlciB0aWxlcyBhYm92ZSB0aGUgdGFibGUgYXJlIHRoZSBlbnRyeSBwb2ludCB0byBwZXItZm9sZGVyIGNvbnRlbnRzLlxuICAgIGlmICh0aGlzLnNlbGVjdGVkRm9sZGVySWQgPT0gbnVsbCkge1xuICAgICAgcmV0dXJuIGZvbGRlcklkID09IG51bGw7XG4gICAgfVxuICAgIHJldHVybiBmb2xkZXJJZCAhPSBudWxsICYmIFN0cmluZyhmb2xkZXJJZCkgPT09IFN0cmluZyh0aGlzLnNlbGVjdGVkRm9sZGVySWQpO1xuICB9XG5cbiAgLyoqIFRydWUgd2hlbiB0aGUgY29tcG9uZW50IHNob3VsZCByZW5kZXIgdGhlIG1vZHVsYXIgKGZvbGRlci1hd2FyZSkgVUkuICovXG4gIGdldCBpc01vZHVsYXJWaWV3KCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLnZpZXdNb2RlID09PSAnbW9kdWxhcic7XG4gIH1cblxuICAvKipcbiAgICogR2V0IHNlbGVjdGVkIElEcyBmcm9tIHNlbGVjdGVkSXRlbXMgKG9iamVjdHMpXG4gICAqL1xuICBwcml2YXRlIGdldFNlbGVjdGVkSWRzKCk6IFNldDxudW1iZXI+IHtcbiAgICBpZiAodGhpcy5zZWxlY3RlZEl0ZW1zICYmIHRoaXMuc2VsZWN0ZWRJdGVtcy5sZW5ndGggPiAwKSB7XG4gICAgICByZXR1cm4gbmV3IFNldCh0aGlzLnNlbGVjdGVkSXRlbXMubWFwKGl0ZW0gPT4gTnVtYmVyKGl0ZW0uaWQpKS5maWx0ZXIoaWQgPT4gIWlzTmFOKGlkKSkpO1xuICAgIH1cbiAgICByZXR1cm4gbmV3IFNldCgpO1xuICB9XG5cbiAgcHJpdmF0ZSByZXN0b3JlU2VsZWN0aW9uU3RhdGUoKTogdm9pZCB7XG4gICAgY29uc3Qgc2VsZWN0ZWRJZHNTZXQgPSB0aGlzLmdldFNlbGVjdGVkSWRzKCk7XG5cbiAgICBpZiAoc2VsZWN0ZWRJZHNTZXQuc2l6ZSA9PT0gMCkge1xuICAgICAgLy8gSWYgbm8gc2VsZWN0ZWQgSURzLCBjbGVhciBhbGwgc2VsZWN0aW9uIHN0YXRlc1xuICAgICAgaWYgKHRoaXMucGFnZWRSb3dzKSB7XG4gICAgICAgIHRoaXMucGFnZWRSb3dzLmZvckVhY2gocm93ID0+IHtcbiAgICAgICAgICBpZiAocm93KSB7XG4gICAgICAgICAgICAocm93IGFzIGFueSkuaXNTZWxlY3RlZCA9IGZhbHNlO1xuICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgLy8gUmVzdG9yZSBzZWxlY3Rpb24gc3RhdGUgYmFzZWQgb24gc2VsZWN0ZWRJdGVtc1xuICAgIGlmICh0aGlzLnBhZ2VkUm93cykge1xuICAgICAgdGhpcy5wYWdlZFJvd3MuZm9yRWFjaChyb3cgPT4ge1xuICAgICAgICBpZiAocm93ICYmIHJvdy5pZCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgKHJvdyBhcyBhbnkpLmlzU2VsZWN0ZWQgPSBzZWxlY3RlZElkc1NldC5oYXMoTnVtYmVyKHJvdy5pZCkpO1xuICAgICAgICB9XG4gICAgICB9KTtcbiAgICB9XG5cbiAgICAvLyBBbHNvIHVwZGF0ZSBmaWx0ZXJlZFJvd3MgZm9yIGNvbnNpc3RlbmN5XG4gICAgaWYgKHRoaXMuZmlsdGVyZWRSb3dzKSB7XG4gICAgICB0aGlzLmZpbHRlcmVkUm93cy5mb3JFYWNoKHJvdyA9PiB7XG4gICAgICAgIGlmIChyb3cgJiYgcm93LmlkICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAocm93IGFzIGFueSkuaXNTZWxlY3RlZCA9IHNlbGVjdGVkSWRzU2V0LmhhcyhOdW1iZXIocm93LmlkKSk7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgIH1cblxuICAgIHRoaXMuY2RyLm1hcmtGb3JDaGVjaygpO1xuICB9XG5cbiAgcHJpdmF0ZSBpbml0aWFsaXplQ29sdW1uVmlzaWJpbGl0eSgpOiB2b2lkIHtcbiAgICAvLyBDYWNoZSB2aXNpYmlsaXR5IGNvbHVtbnMgdG8gYXZvaWQgY3JlYXRpbmcgbmV3IGFycmF5cyBvbiBldmVyeSBjaGFuZ2UgZGV0ZWN0aW9uXG4gICAgdGhpcy5fY2FjaGVkVmlzaWJpbGl0eUNvbHVtbnMgPSB0aGlzLm1hcFZpc2liaWxpdHlDb2x1bW5zKCk7XG4gICAgLy8gU2VlZCB2aXNpYmlsaXR5IHN0YXRlIGZyb20gZWFjaCBjb2x1bW4ncyBpc1Nob3cgKGRlZmF1bHQgdG8gdHJ1ZSkgc28gY29uc3VtZXJzXG4gICAgLy8gY2FuIHByZS1hcHBseSBwZXJzaXN0ZWQgcHJlZmVyZW5jZXMgdmlhIGNvbHVtbnNbaV0uaXNTaG93LlxuICAgIGNvbnN0IHNvdXJjZSA9IHRoaXMuY29sdW1ucyB8fCBbXTtcbiAgICBmb3IgKGNvbnN0IGNvbCBvZiB0aGlzLl9jYWNoZWRWaXNpYmlsaXR5Q29sdW1ucykge1xuICAgICAgaWYgKHRoaXMuX2NvbHVtblZpc2liaWxpdHlbY29sLmlkXSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIGNvbnN0IHNyY0NvbCA9IHNvdXJjZS5maW5kKGMgPT4gYy5maWVsZElkID09PSBjb2wuaWQpO1xuICAgICAgICB0aGlzLl9jb2x1bW5WaXNpYmlsaXR5W2NvbC5pZF0gPSBzcmNDb2wgJiYgc3JjQ29sLmlzU2hvdyA9PT0gZmFsc2UgPyBmYWxzZSA6IHRydWU7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgZ2V0IGFueVJvd1NlbGVjdGVkKCk6IGJvb2xlYW4ge1xuICAgIC8vIENoZWNrIGlmIHRoZXJlIGFyZSBhbnkgc2VsZWN0ZWQgaXRlbXMgKGVpdGhlciBvbiBjdXJyZW50IHBhZ2Ugb3IgYWNyb3NzIGFsbCBwYWdlcyB2aWEgc2VsZWN0ZWRJdGVtcylcbiAgICBjb25zdCBoYXNTZWxlY3RlZE9uUGFnZSA9ICEhKHRoaXMucGFnZWRSb3dzICYmIHRoaXMucGFnZWRSb3dzLnNvbWUociA9PiAhIShyIGFzIGFueSkuaXNTZWxlY3RlZCkpO1xuICAgIGNvbnN0IHNlbGVjdGVkSWRzU2V0ID0gdGhpcy5nZXRTZWxlY3RlZElkcygpO1xuICAgIGNvbnN0IGhhc1NlbGVjdGVkQWNyb3NzUGFnZXMgPSBzZWxlY3RlZElkc1NldC5zaXplID4gMDtcbiAgICByZXR1cm4gaGFzU2VsZWN0ZWRPblBhZ2UgfHwgaGFzU2VsZWN0ZWRBY3Jvc3NQYWdlcztcbiAgfVxuXG4gIGdldCBjdXJyZW50U2VsZWN0ZWRJdGVtcygpOiBhbnlbXSB7XG4gICAgLy8gSWYgc2VsZWN0ZWRJdGVtcyAoZnVsbCBvYmplY3RzKSBhcmUgcHJvdmlkZWQsIHVzZSB0aGVtIGRpcmVjdGx5XG4gICAgLy8gVGhpcyBlbnN1cmVzIGFsbCBzZWxlY3RlZCBpdGVtcyBhcmUgcmV0dXJuZWQsIGluY2x1ZGluZyB0aG9zZSBmcm9tIG90aGVyIHBhZ2VzXG4gICAgaWYgKHRoaXMuc2VsZWN0ZWRJdGVtcyAmJiB0aGlzLnNlbGVjdGVkSXRlbXMubGVuZ3RoID4gMCkge1xuICAgICAgcmV0dXJuIHRoaXMuc2VsZWN0ZWRJdGVtcztcbiAgICB9XG4gICAgLy8gRmFsbGJhY2s6IEZvciBjbGllbnQtc2lkZSBwYWdpbmF0aW9uIG9yIHdoZW4gc2VsZWN0ZWRJdGVtcyBpcyBub3QgcHJvdmlkZWQsXG4gICAgLy8gZmlsdGVyIHBhZ2VkUm93cyB0byBnZXQgc2VsZWN0ZWQgaXRlbXMgZnJvbSBjdXJyZW50IHBhZ2Ugb25seVxuICAgIGlmICghdGhpcy5wYWdlZFJvd3MgfHwgdGhpcy5wYWdlZFJvd3MubGVuZ3RoID09PSAwKSB7XG4gICAgICByZXR1cm4gW107XG4gICAgfVxuXG4gICAgY29uc3Qgc2VsZWN0ZWRJZHNTZXQgPSB0aGlzLmdldFNlbGVjdGVkSWRzKCk7XG4gICAgXG4gICAgLy8gRmlsdGVyIHJvd3MgdGhhdCBhcmUgc2VsZWN0ZWRcbiAgICByZXR1cm4gdGhpcy5wYWdlZFJvd3NcbiAgICAgIC5maWx0ZXIociA9PiB7XG4gICAgICAgIGlmICghciB8fCByLmlkID09PSB1bmRlZmluZWQpIHJldHVybiBmYWxzZTtcbiAgICAgICAgY29uc3Qgcm93SWQgPSBOdW1iZXIoci5pZCk7XG4gICAgICAgIC8vIEluY2x1ZGUgaWYgZWl0aGVyOlxuICAgICAgICAvLyAxLiBUaGUgcm93IGhhcyBpc1NlbGVjdGVkID0gdHJ1ZSAoY3VycmVudCBwYWdlIHNlbGVjdGlvbilcbiAgICAgICAgLy8gMi4gVGhlIHJvdydzIElEIGlzIGluIHNlbGVjdGVkSXRlbXMgKHNlbGVjdGVkIG9uIG90aGVyIHBhZ2VzIG9yIHJlc3RvcmVkIHNlbGVjdGlvbilcbiAgICAgICAgcmV0dXJuICEhKHIgYXMgYW55KS5pc1NlbGVjdGVkIHx8IHNlbGVjdGVkSWRzU2V0Lmhhcyhyb3dJZCk7XG4gICAgICB9KTtcbiAgfVxuXG4gIGFjdGlvbkNsaWNrKGRhdGE6IGFueSkge1xuICAgIGNvbnNvbGUubG9nKCdhY3Rpb24gdG9vbGJhcicsIGRhdGEpO1xuICB9XG5cbiAgdmlldyhpZDogbnVtYmVyIHwgc3RyaW5nKTogdm9pZCB7XG4gICAgY29uc29sZS5sb2coJ1ZpZXcnLCBpZCk7XG4gIH1cblxuICBlZGl0KHJvdzogYW55KTogdm9pZCB7XG4gICAgY29uc29sZS5sb2coJ0VkaXQnLCByb3cpO1xuICB9XG5cbiAgZGVsZXRlKHJvdzogYW55KTogdm9pZCB7XG4gICAgY29uc29sZS5sb2coJ0RlbGV0ZScsIHJvdyk7XG4gIH1cblxuICB0b2dnbGVGaWx0ZXIoKTogdm9pZCB7XG4gICAgdGhpcy5zaG93RmlsdGVyUGFuZWwgPSAhdGhpcy5zaG93RmlsdGVyUGFuZWw7XG4gIH1cblxuICBvbkNvbHVtblZpc2liaWxpdHlDaGFuZ2UoY2ZnOiBDb2x1bW5WaXNpYmlsaXR5Q29uZmlnKTogdm9pZCB7XG4gICAgdGhpcy5fY29sdW1uVmlzaWJpbGl0eSA9IHsgLi4uY2ZnIH07XG4gICAgdGhpcy51cGRhdGVDb21wdXRlZENvbHVtbnMoKTtcbiAgICB0aGlzLmNkci5tYXJrRm9yQ2hlY2soKTtcbiAgICB0aGlzLmNvbHVtblZpc2liaWxpdHlDaGFuZ2UuZW1pdCh7IC4uLmNmZyB9KTtcbiAgfVxuXG4gIG9uQXV0b1JlZnJlc2hDaGFuZ2UoaW50ZXJ2YWxNczogbnVtYmVyKTogdm9pZCB7XG4gICAgdGhpcy5zZWxlY3RlZEF1dG9SZWZyZXNoSW50ZXJ2YWwgPSBpbnRlcnZhbE1zO1xuICAgIHRoaXMuc2V0dXBBdXRvUmVmcmVzaChpbnRlcnZhbE1zKTtcbiAgICB0aGlzLmF1dG9SZWZyZXNoSW50ZXJ2YWxDaGFuZ2UuZW1pdChpbnRlcnZhbE1zKTtcbiAgICB0aGlzLnRyaWdnZXJSZWxvYWQoKTtcbiAgfVxuXG4gIHZhbHVlQ2hhbmdlKHZhbHVlOiBzdHJpbmcpOiB2b2lkIHtcbiAgICBjb25zb2xlLmxvZygnVmFsdWUgY2hhbmdlZCcsIHZhbHVlKTtcbiAgICB0aGlzLm9uU2VhcmNoQ2hhbmdlLmVtaXQodmFsdWUpO1xuICB9XG5cbiAgc2VhcmNoKHZhbHVlOiBzdHJpbmcpOiB2b2lkIHtcbiAgICBjb25zb2xlLmxvZygnU2VhcmNoJywgdmFsdWUpO1xuICB9XG5cbiAgY2xlYXJlZCgpOiB2b2lkIHtcbiAgICBjb25zb2xlLmxvZygnQ2xlYXJlZCcpO1xuICB9XG5cbiAgb25FbXB0eUFjdGlvbihhY3Rpb246IGFueSkge1xuICAgIGlmIChhY3Rpb24/LmxhYmVsID09PSAnU2hvdyBmaWx0ZXJzJykge1xuICAgICAgdGhpcy50b2dnbGVGaWx0ZXIoKTtcbiAgICB9XG4gIH1cblxuICBvbkZpbHRlcnNDaGFuZ2VkKGN1cnJlbnQ6IGFueSk6IHZvaWQge1xuICAgIC8vIERlZmVyIGFwcGx5aW5nIGZpbHRlcnMgYW5kIHVwZGF0aW5nIGNoaXBzIHVudGlsIEFwcGx5IEZpbHRlciBpcyBjbGlja2VkXG4gICAgdGhpcy5wZW5kaW5nRmlsdGVycyA9IGN1cnJlbnQ7XG4gIH1cblxuICBvbkZpbHRlcnNBcHBsaWVkKGFwcGxpZWQ6IGFueSk6IHZvaWQge1xuICAgIHRoaXMuc2hvd0ZpbHRlclBhbmVsID0gZmFsc2U7XG4gICAgY29uc3QgZWZmZWN0aXZlID0gYXBwbGllZCA/PyB0aGlzLnBlbmRpbmdGaWx0ZXJzID8/IHt9O1xuICAgIHRoaXMuYXBwbGllZEZpbHRlcnMgPSBlZmZlY3RpdmU7XG4gICAgdGhpcy5yZWJ1aWxkRmlsdGVyZWRSb3dzKCk7XG4gICAgdGhpcy5wYWdlSW5kZXggPSAwO1xuICAgIHRoaXMuYXBwbHlQYWdpbmF0aW9uKCk7XG4gICAgY29uc3QgY2hpcHM6IEFycmF5PHsga2V5Pzogc3RyaW5nOyBsYWJlbD86IHN0cmluZzsgdGV4dDogc3RyaW5nOyBmdWxsVGV4dD86IHN0cmluZzsgaGFzTW9yZT86IGJvb2xlYW4gfT4gPSBbXTtcbiAgICBpZiAoZWZmZWN0aXZlKSB7XG4gICAgICBmb3IgKGNvbnN0IGtleSBvZiBPYmplY3Qua2V5cyhlZmZlY3RpdmUpKSB7XG4gICAgICAgIGNvbnN0IHZhbHVlID0gZWZmZWN0aXZlW2tleV07XG4gICAgICAgIGlmICh2YWx1ZSA9PSBudWxsIHx8IHZhbHVlID09PSAnJyB8fCAoQXJyYXkuaXNBcnJheSh2YWx1ZSkgJiYgdmFsdWUubGVuZ3RoID09PSAwKSkgY29udGludWU7XG4gICAgICAgIFxuICAgICAgICAvLyBGaW5kIHRoZSBmaWx0ZXIgY29uZmlnIGl0ZW0gZm9yIHRoaXMga2V5XG4gICAgICAgIGNvbnN0IGZpbHRlckNvbmZpZ0l0ZW0gPSB0aGlzLmZpbHRlckNvbmZpZz8uZmluZChjID0+IGMua2V5ID09PSBrZXkpO1xuICAgICAgICBjb25zdCBvcHRpb25zID0gZmlsdGVyQ29uZmlnSXRlbT8ub3B0aW9ucyB8fCBbXTtcbiAgICAgICAgXG4gICAgICAgIC8vIEhlbHBlciBmdW5jdGlvbiB0byBmaW5kIGRpc3BsYXkgdGV4dCBmcm9tIG9wdGlvbnNcbiAgICAgICAgY29uc3QgZ2V0RGlzcGxheVRleHQgPSAodmFsOiBhbnkpOiBzdHJpbmcgPT4ge1xuICAgICAgICAgIC8vIElmIHZhbHVlIGlzIGFscmVhZHkgYW4gb2JqZWN0IHdpdGggbmFtZS9sYWJlbCwgdXNlIGl0XG4gICAgICAgICAgaWYgKHZhbCAmJiB0eXBlb2YgdmFsID09PSAnb2JqZWN0JyAmJiAodmFsLm5hbWUgfHwgdmFsLmxhYmVsIHx8IHZhbC52YWx1ZSkpIHtcbiAgICAgICAgICAgIHJldHVybiB2YWwubmFtZSA/PyB2YWwubGFiZWwgPz8gU3RyaW5nKHZhbC52YWx1ZSA/PyB2YWwpO1xuICAgICAgICAgIH1cbiAgICAgICAgICBcbiAgICAgICAgICAvLyBMb29rIHVwIHRoZSBvcHRpb24gaW4gdGhlIGNvbmZpZ1xuICAgICAgICAgIGNvbnN0IG9wdGlvbiA9IG9wdGlvbnMuZmluZCgob3B0OiBhbnkpID0+IHtcbiAgICAgICAgICAgIGNvbnN0IG9wdElkID0gb3B0LmlkID8/IG9wdC52YWx1ZTtcbiAgICAgICAgICAgIGNvbnN0IG9wdFZhbHVlID0gb3B0LnZhbHVlO1xuICAgICAgICAgICAgY29uc3QgdmFsU3RyID0gU3RyaW5nKHZhbCk7XG4gICAgICAgICAgICByZXR1cm4gU3RyaW5nKG9wdElkKSA9PT0gdmFsU3RyIHx8IFN0cmluZyhvcHRWYWx1ZSkgPT09IHZhbFN0cjtcbiAgICAgICAgICB9KTtcbiAgICAgICAgICBcbiAgICAgICAgICBpZiAob3B0aW9uKSB7XG4gICAgICAgICAgICByZXR1cm4gb3B0aW9uLm5hbWUgPz8gb3B0aW9uLmxhYmVsID8/IFN0cmluZyhvcHRpb24udmFsdWUgPz8gdmFsKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgXG4gICAgICAgICAgLy8gRmFsbGJhY2sgdG8gdGhlIHJhdyB2YWx1ZVxuICAgICAgICAgIHJldHVybiBTdHJpbmcodmFsKTtcbiAgICAgICAgfTtcbiAgICAgICAgXG4gICAgICAgIGxldCB0ZXh0ID0gJyc7XG4gICAgICAgIGxldCBsYWJlbCA9IGZpbHRlckNvbmZpZ0l0ZW0/LmxhYmVsO1xuICAgICAgICBcbiAgICAgICAgaWYgKEFycmF5LmlzQXJyYXkodmFsdWUpKSB7XG4gICAgICAgICAgdGV4dCA9IHZhbHVlLm1hcCgodjogYW55KSA9PiBnZXREaXNwbGF5VGV4dCh2KSkuam9pbignLCAnKTtcbiAgICAgICAgfSBlbHNlIGlmICh0eXBlb2YgdmFsdWUgPT09ICdvYmplY3QnKSB7XG4gICAgICAgICAgaWYgKCdzdGFydCcgaW4gdmFsdWUgfHwgJ2VuZCcgaW4gdmFsdWUpIHtcbiAgICAgICAgICAgIGNvbnN0IHMgPSB2YWx1ZS5zdGFydCA/IG5ldyBEYXRlKHZhbHVlLnN0YXJ0KS50b0xvY2FsZURhdGVTdHJpbmcoKSA6ICcnO1xuICAgICAgICAgICAgY29uc3QgZSA9IHZhbHVlLmVuZCA/IG5ldyBEYXRlKHZhbHVlLmVuZCkudG9Mb2NhbGVEYXRlU3RyaW5nKCkgOiAnJztcbiAgICAgICAgICAgIHRleHQgPSBbcywgZV0uZmlsdGVyKEJvb2xlYW4pLmpvaW4oJyAtICcpO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0ZXh0ID0gZ2V0RGlzcGxheVRleHQodmFsdWUpO1xuICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICB0ZXh0ID0gZ2V0RGlzcGxheVRleHQodmFsdWUpO1xuICAgICAgICB9XG4gICAgICAgIGNoaXBzLnB1c2goeyBrZXksIGxhYmVsLCB0ZXh0LCBmdWxsVGV4dDogdGV4dCwgaGFzTW9yZTogdGV4dC5sZW5ndGggPiAzMCB9KTtcbiAgICAgIH1cbiAgICB9XG4gICAgdGhpcy5jaGlwcyA9IGNoaXBzO1xuICAgIHRoaXMuZmlsdGVyQXBwbGllZCA9IHRoaXMuY2hpcHMubGVuZ3RoID4gMDtcbiAgfVxuXG4gIGhhbmRsZVJlc2V0RmlsdGVyQ2xpY2soKTogdm9pZCB7XG4gICAgLy8gQ2xlYXIgY2hpcHMgYW5kIHJlc2V0IGZpbHRlcmVkIGRhdGEgd2hlbiByZXNldCBpcyBjbGlja2VkXG4gICAgdGhpcy5wZW5kaW5nRmlsdGVycyA9IHVuZGVmaW5lZDtcbiAgICB0aGlzLmFwcGxpZWRGaWx0ZXJzID0gdW5kZWZpbmVkO1xuICAgIHRoaXMuY2hpcHMgPSBbXTtcbiAgICB0aGlzLmZpbHRlckFwcGxpZWQgPSBmYWxzZTtcbiAgICB0aGlzLnJlYnVpbGRGaWx0ZXJlZFJvd3MoKTtcbiAgICB0aGlzLnBhZ2VJbmRleCA9IDA7XG4gICAgdGhpcy5hcHBseVBhZ2luYXRpb24oKTtcbiAgICB0aGlzLm9uUmVzZXRGaWx0ZXJDbGljay5lbWl0KCk7XG4gIH1cblxuICBoYW5kbGVSZWZyZXNoQ2xpY2soKTogdm9pZCB7XG4gICAgdGhpcy5vbkF1dG9SZWZyZXNoQ2xpY2suZW1pdCgpO1xuICAgIHRoaXMudHJpZ2dlclJlbG9hZCgpO1xuICB9XG5cbiAgcHJpdmF0ZSB0cmlnZ2VyUmVsb2FkKCk6IHZvaWQge1xuICAgIHRoaXMucmVidWlsZEZpbHRlcmVkUm93cygpO1xuICAgIHRoaXMucGFnZUluZGV4ID0gMDtcbiAgICB0aGlzLmFwcGx5UGFnaW5hdGlvbigpO1xuICAgIHRoaXMub25SZWxvYWQuZW1pdCgpO1xuICB9XG5cbiAgcHJpdmF0ZSBzZXR1cEF1dG9SZWZyZXNoKGludGVydmFsTXM6IG51bWJlcik6IHZvaWQge1xuICAgIHRoaXMuY2xlYXJBdXRvUmVmcmVzaCgpO1xuICAgIGlmIChpbnRlcnZhbE1zICYmIGludGVydmFsTXMgPiAwKSB7XG4gICAgICB0aGlzLmF1dG9SZWZyZXNoVGltZXIgPSBzZXRJbnRlcnZhbCgoKSA9PiB7XG4gICAgICAgIHRoaXMudHJpZ2dlclJlbG9hZCgpO1xuICAgICAgfSwgaW50ZXJ2YWxNcyk7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBjbGVhckF1dG9SZWZyZXNoKCk6IHZvaWQge1xuICAgIGlmICh0aGlzLmF1dG9SZWZyZXNoVGltZXIpIHtcbiAgICAgIGNsZWFySW50ZXJ2YWwodGhpcy5hdXRvUmVmcmVzaFRpbWVyKTtcbiAgICAgIHRoaXMuYXV0b1JlZnJlc2hUaW1lciA9IHVuZGVmaW5lZDtcbiAgICB9XG4gIH1cblxuICBuZ09uRGVzdHJveSgpOiB2b2lkIHtcbiAgICB0aGlzLmNsZWFyQXV0b1JlZnJlc2goKTtcbiAgfVxuXG4gIG9uUGFnaW5hdGUoZTogeyBwYWdlSW5kZXg6IG51bWJlcjsgcGFnZVNpemU6IG51bWJlciB9KTogdm9pZCB7XG4gICAgdGhpcy5wYWdlSW5kZXggPSBlLnBhZ2VJbmRleDtcbiAgICB0aGlzLnBhZ2VTaXplID0gZS5wYWdlU2l6ZTtcbiAgICBpZiAodGhpcy5zZXJ2ZXJTaWRlUGFnaW5hdGlvbikge1xuICAgICAgdGhpcy5wYWdlQ2hhbmdlLmVtaXQoeyBwYWdlSW5kZXg6IHRoaXMucGFnZUluZGV4LCBwYWdlU2l6ZTogdGhpcy5wYWdlU2l6ZSB9KTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgdGhpcy5hcHBseVBhZ2luYXRpb24oKTtcbiAgfVxuXG4gIG9uUGFnZVNpemVDaGFuZ2Uoc2l6ZTogbnVtYmVyKTogdm9pZCB7XG4gICAgdGhpcy5wYWdlU2l6ZSA9IHNpemU7XG4gICAgdGhpcy5wYWdlSW5kZXggPSAwO1xuICAgIGlmICh0aGlzLnNlcnZlclNpZGVQYWdpbmF0aW9uKSB7XG4gICAgICB0aGlzLnBhZ2VDaGFuZ2UuZW1pdCh7IHBhZ2VJbmRleDogdGhpcy5wYWdlSW5kZXgsIHBhZ2VTaXplOiB0aGlzLnBhZ2VTaXplIH0pO1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICB0aGlzLmFwcGx5UGFnaW5hdGlvbigpO1xuICB9XG5cbiAgb25SZW1vdmVDaGlwKGNoaXA6IGFueSk6IHZvaWQge1xuICAgIHRoaXMuY2hpcHMgPSB0aGlzLmNoaXBzLmZpbHRlcihjID0+IGMgIT09IGNoaXApO1xuICAgIHRoaXMuZmlsdGVyQXBwbGllZCA9IHRoaXMuY2hpcHMubGVuZ3RoID4gMDtcbiAgICAvLyBFbWl0IGV2ZW50IHRvIHBhcmVudCBjb21wb25lbnQgKHNhbWUgcGF0dGVybiBhcyBleGVjdXRpb24gdGFiKVxuICAgIHRoaXMucmVtb3ZlQ2hpcC5lbWl0KGNoaXApO1xuICB9XG5cbiAgb25DbGVhckFsbENoaXBzKCk6IHZvaWQge1xuICAgIHRoaXMuY2hpcHMgPSBbXTtcbiAgICB0aGlzLmZpbHRlckFwcGxpZWQgPSBmYWxzZTtcbiAgICAvLyBSZXNldCB0aGUgZHluYW1pYy1maWx0ZXIgY29tcG9uZW50IGZvcm0gd2hlbiBjbGVhcmluZyBhbGwgY2hpcHNcbiAgICBpZiAodGhpcy5keW5hbWljRmlsdGVyQ29tcG9uZW50KSB7XG4gICAgICB0aGlzLmR5bmFtaWNGaWx0ZXJDb21wb25lbnQucmVzZXQoKTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIGFwcGx5UGFnaW5hdGlvbigpOiB2b2lkIHtcbiAgICBpZiAodGhpcy5zZXJ2ZXJTaWRlUGFnaW5hdGlvbikge1xuICAgICAgLy8gU2VydmVyIG1vZGU6IHBhcmVudCBzdXBwbGllcyBhbHJlYWR5LXBhZ2luYXRlZCBkYXRhXG4gICAgICB0aGlzLnBhZ2VkUm93cyA9IFsuLi50aGlzLmZpbHRlcmVkUm93c107XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGNvbnN0IHN0YXJ0ID0gdGhpcy5wYWdlSW5kZXggKiB0aGlzLnBhZ2VTaXplO1xuICAgIGNvbnN0IGVuZCA9IHN0YXJ0ICsgdGhpcy5wYWdlU2l6ZTtcbiAgICB0aGlzLnBhZ2VkUm93cyA9IHRoaXMuZmlsdGVyZWRSb3dzLnNsaWNlKHN0YXJ0LCBlbmQpO1xuICB9XG5cbiAgcHJpdmF0ZSBtYXBWaXNpYmlsaXR5Q29sdW1ucygpOiBBcnJheTx7IGlkOiBzdHJpbmc7IGxhYmVsOiBzdHJpbmcgfT4ge1xuICAgIHJldHVybiAodGhpcy5jb2x1bW5zIHx8IFtdKVxuICAgICAgLmZpbHRlcihjID0+IGMuaXNEZWZhdWx0ID09PSBmYWxzZSlcbiAgICAgIC5tYXAoYyA9PiAoeyBpZDogYy5maWVsZElkLCBsYWJlbDogYy5maWVsZE5hbWUgfHwgYy5maWVsZElkIH0pKTtcbiAgfVxuXG4gIHByaXZhdGUgbm9ybWFsaXplRGF0ZShkOiBhbnkpOiBudW1iZXIgfCBudWxsIHtcbiAgICBpZiAoIWQpIHJldHVybiBudWxsO1xuICAgIGNvbnN0IHRzID0gRGF0ZS5wYXJzZShkKTtcbiAgICByZXR1cm4gaXNOYU4odHMpID8gbnVsbCA6IHRzO1xuICB9XG5cbiAgcHJpdmF0ZSBwYXNzRmlsdGVycyhmaWx0ZXJzOiBhbnksIHJvdzogYW55KTogYm9vbGVhbiB7XG4gICAgaWYgKCFmaWx0ZXJzKSByZXR1cm4gdHJ1ZTtcbiAgICBpZiAoZmlsdGVycy5zdGF0dXMgJiYgQXJyYXkuaXNBcnJheShmaWx0ZXJzLnN0YXR1cykgJiYgZmlsdGVycy5zdGF0dXMubGVuZ3RoKSB7XG4gICAgICBpZiAoIWZpbHRlcnMuc3RhdHVzLmluY2x1ZGVzKHJvdy5zdGF0dXMpKSByZXR1cm4gZmFsc2U7XG4gICAgfVxuICAgIGlmIChmaWx0ZXJzLnByaW9yaXR5ICYmIEFycmF5LmlzQXJyYXkoZmlsdGVycy5wcmlvcml0eSkgJiYgZmlsdGVycy5wcmlvcml0eS5sZW5ndGgpIHtcbiAgICAgIGlmICghZmlsdGVycy5wcmlvcml0eS5pbmNsdWRlcyhyb3cucHJpb3JpdHlOYW1lKSkgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgICBpZiAoZmlsdGVycy50ZXN0VHlwZSAmJiBBcnJheS5pc0FycmF5KGZpbHRlcnMudGVzdFR5cGUpICYmIGZpbHRlcnMudGVzdFR5cGUubGVuZ3RoKSB7XG4gICAgICBpZiAoIWZpbHRlcnMudGVzdFR5cGUuaW5jbHVkZXMocm93LnRlc3RUeXBlKSkgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgICBpZiAoZmlsdGVycy5jcmVhdGVkX2RhdGUgJiYgKGZpbHRlcnMuY3JlYXRlZF9kYXRlLnN0YXJ0IHx8IGZpbHRlcnMuY3JlYXRlZF9kYXRlLmVuZCkpIHtcbiAgICAgIGNvbnN0IHN0YXJ0VHMgPSB0aGlzLm5vcm1hbGl6ZURhdGUoZmlsdGVycy5jcmVhdGVkX2RhdGUuc3RhcnQpO1xuICAgICAgY29uc3QgZW5kVHMgPSB0aGlzLm5vcm1hbGl6ZURhdGUoZmlsdGVycy5jcmVhdGVkX2RhdGUuZW5kKTtcbiAgICAgIGNvbnN0IHJvd1RzID0gdGhpcy5ub3JtYWxpemVEYXRlKHJvdy5jcmVhdGVkQXQpO1xuICAgICAgaWYgKHJvd1RzICE9IG51bGwpIHtcbiAgICAgICAgaWYgKHN0YXJ0VHMgIT0gbnVsbCAmJiByb3dUcyA8IHN0YXJ0VHMpIHJldHVybiBmYWxzZTtcbiAgICAgICAgaWYgKGVuZFRzICE9IG51bGwgJiYgcm93VHMgPiBlbmRUcykgcmV0dXJuIGZhbHNlO1xuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gdHJ1ZTtcbiAgfVxuXG4gIHRyYWNrQnlUZW1wbGF0ZVJlZihpbmRleDogbnVtYmVyKTogbnVtYmVyIHtcbiAgICByZXR1cm4gaW5kZXg7XG4gIH1cblxuICB0cmFja0J5RHJvcGRvd25UZW1wbGF0ZVJlZihpbmRleDogbnVtYmVyKTogbnVtYmVyIHtcbiAgICByZXR1cm4gaW5kZXg7XG4gIH1cblxuICB0cmFja0J5U2VsZWN0RHJvcGRvd25UZW1wbGF0ZVJlZihpbmRleDogbnVtYmVyKTogbnVtYmVyIHtcbiAgICByZXR1cm4gaW5kZXg7XG4gIH1cblxuICAvLyBFeHBvcnQgbW9kYWwgc3RhdGVcbiAgaXNFeHBvcnRNb2RhbE9wZW46IGJvb2xlYW4gPSBmYWxzZTtcblxuICBleHBvcnRDb2RlQ2xpY2soKTogdm9pZCB7XG4gICAgLy8gR2V0IHNlbGVjdGVkIGl0ZW1zXG4gICAgY29uc3Qgc2VsZWN0ZWRJdGVtcyA9IHRoaXMuY3VycmVudFNlbGVjdGVkSXRlbXM7XG4gICAgaWYgKHNlbGVjdGVkSXRlbXMubGVuZ3RoID09PSAwKSB7XG4gICAgICAvLyBFbWl0IGV2ZW50IHRvIHBhcmVudCB0byBoYW5kbGUgdGhlIGNhc2Ugd2hlbiBubyBpdGVtcyBhcmUgc2VsZWN0ZWRcbiAgICAgIHRoaXMub25FeHBvcnRDbGljay5lbWl0KCk7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIHRoaXMuaXNFeHBvcnRNb2RhbE9wZW4gPSB0cnVlO1xuICB9XG5cbiAgY2xvc2VFeHBvcnRNb2RhbCgpOiB2b2lkIHtcbiAgICB0aGlzLmlzRXhwb3J0TW9kYWxPcGVuID0gZmFsc2U7XG4gIH1cblxuICBvbkV4cG9ydE1vZGFsRXhwb3J0KHJlc3VsdDogeyB0eXBlOiAnbG9jYWwnIHwgJ2VtYWlsJzsgZW1haWxzPzogc3RyaW5nW107IGZyYW1ld29yazogJ1dFQkRSSVZFUl9JTycgfCAnU0VMRU5JVU1fSkFWQScgfSk6IHZvaWQge1xuICAgIHRoaXMuaXNFeHBvcnRNb2RhbE9wZW4gPSBmYWxzZTtcbiAgICAvLyBFbWl0IGV2ZW50IHRvIHBhcmVudCB3aXRoIGV4cG9ydCByZXN1bHRcbiAgICB0aGlzLm9uRXhwb3J0Q2xpY2suZW1pdCh7XG4gICAgICB0eXBlOiByZXN1bHQudHlwZSxcbiAgICAgIGVtYWlsczogcmVzdWx0LmVtYWlscyxcbiAgICAgIGZyYW1ld29yazogcmVzdWx0LmZyYW1ld29yayxcbiAgICAgIHNlbGVjdGVkSXRlbXM6IHRoaXMuY3VycmVudFNlbGVjdGVkSXRlbXNcbiAgICB9KTtcbiAgfVxuXG4gIGdldCBzZWxlY3RlZENhc2VzRm9yRXhwb3J0KCk6IEFycmF5PHsgaWQ/OiBudW1iZXI7IG5hbWU/OiBzdHJpbmcgfT4ge1xuICAgIHJldHVybiB0aGlzLmN1cnJlbnRTZWxlY3RlZEl0ZW1zLm1hcChpdGVtID0+ICh7XG4gICAgICBpZDogaXRlbS5pZCxcbiAgICAgIG5hbWU6IGl0ZW0ubmFtZSB8fCBpdGVtLnRpdGxlIHx8ICdVbm5hbWVkJ1xuICAgIH0pKTtcbiAgfVxuICBnZXQgYXJyb3dDbGFzc2VzKCk6IHN0cmluZyB7XG4gICAgY29uc3QgYmFzZUNsYXNzZXMgPSBbXG4gICAgICAnY3FhLXctNCcsXG4gICAgICAnY3FhLWgtNCcsXG4gICAgICAnY3FhLXJlbGF0aXZlJyxcbiAgICAgICdjcWEtdHJhbnNpdGlvbi10cmFuc2Zvcm0nXG4gICAgXTtcblxuICAgIGlmICh0aGlzLnNob3dGaWx0ZXJQYW5lbCkge1xuICAgICAgYmFzZUNsYXNzZXMucHVzaCgnY3FhLXJvdGF0ZS0xODAnKTtcbiAgICB9XG5cbiAgICByZXR1cm4gYmFzZUNsYXNzZXMuam9pbignICcpO1xuICB9XG5cbiAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuICAvLyBGb2xkZXIgLyBtb2R1bGFyIGhlbHBlcnNcbiAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuXG4gIC8qKlxuICAgKiBGbGF0IGxpc3Qgb2Ygcm9vdC1sZXZlbCBmb2xkZXJzIGZvciB0aGUgXCJPcmdhbmlzZWRcIiBncmlkIG9uIHRoZSByb290IHZpZXcuXG4gICAqL1xuICBnZXQgcm9vdEZvbGRlclRpbGVzKCk6IEZvbGRlck5vZGVbXSB7XG4gICAgcmV0dXJuIHRoaXMuZm9sZGVycyB8fCBbXTtcbiAgfVxuXG4gIC8qKlxuICAgKiBTdWJmb2xkZXJzIG9mIHRoZSBjdXJyZW50bHktc2VsZWN0ZWQgZm9sZGVyIChmb3IgdGhlIFwiU3ViZm9sZGVycyBpbiAuLi5cIiBncmlkKS5cbiAgICovXG4gIGdldCBzdWJmb2xkZXJUaWxlcygpOiBGb2xkZXJOb2RlW10ge1xuICAgIGlmICh0aGlzLnNlbGVjdGVkRm9sZGVySWQgPT0gbnVsbCkgcmV0dXJuIFtdO1xuICAgIGNvbnN0IG5vZGUgPSB0aGlzLmZpbmRGb2xkZXIodGhpcy5mb2xkZXJzLCB0aGlzLnNlbGVjdGVkRm9sZGVySWQpO1xuICAgIHJldHVybiBub2RlPy5jaGlsZHJlbiA/PyBbXTtcbiAgfVxuXG4gIC8qKlxuICAgKiBCcmVhZGNydW1iIHRyYWlsIGZyb20gXCJBbGwgZm9sZGVyc1wiIGRvd24gdG8gdGhlIGN1cnJlbnRseS1zZWxlY3RlZCBmb2xkZXIuXG4gICAqL1xuICBnZXQgYnJlYWRjcnVtYlRyYWlsKCk6IEZvbGRlck5vZGVbXSB7XG4gICAgaWYgKHRoaXMuc2VsZWN0ZWRGb2xkZXJJZCA9PSBudWxsKSByZXR1cm4gW107XG4gICAgY29uc3QgdHJhaWw6IEZvbGRlck5vZGVbXSA9IFtdO1xuICAgIHRoaXMuYnVpbGRUcmFpbCh0aGlzLmZvbGRlcnMsIHRoaXMuc2VsZWN0ZWRGb2xkZXJJZCwgdHJhaWwpO1xuICAgIHJldHVybiB0cmFpbDtcbiAgfVxuXG4gIHByaXZhdGUgYnVpbGRUcmFpbChub2RlczogRm9sZGVyTm9kZVtdLCB0YXJnZXRJZDogbnVtYmVyLCBhY2M6IEZvbGRlck5vZGVbXSk6IGJvb2xlYW4ge1xuICAgIGZvciAoY29uc3QgbiBvZiBub2RlcyB8fCBbXSkge1xuICAgICAgYWNjLnB1c2gobik7XG4gICAgICAvLyBVc2UgU3RyaW5nKCkgY29lcmNpb24gZm9yIHNhZmV0eSBpbiBjYXNlIGlkcyBhcnJpdmUgYXMgZWl0aGVyIG51bWJlciBvclxuICAgICAgLy8gc3RyaW5nIGZyb20gZGlmZmVyZW50IEFQSS90ZXN0IGRhdGEgc2hhcGVzIChlLmcuIHJhdyBKU09OIHBhcnNlIHJlc3VsdHMpLlxuICAgICAgaWYgKFN0cmluZyhuLmlkKSA9PT0gU3RyaW5nKHRhcmdldElkKSkgcmV0dXJuIHRydWU7XG4gICAgICBpZiAobi5jaGlsZHJlbiAmJiB0aGlzLmJ1aWxkVHJhaWwobi5jaGlsZHJlbiwgdGFyZ2V0SWQsIGFjYykpIHJldHVybiB0cnVlO1xuICAgICAgYWNjLnBvcCgpO1xuICAgIH1cbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cblxuICBwcml2YXRlIGZpbmRGb2xkZXIobm9kZXM6IEZvbGRlck5vZGVbXSwgdGFyZ2V0SWQ6IG51bWJlcik6IEZvbGRlck5vZGUgfCBudWxsIHtcbiAgICBmb3IgKGNvbnN0IG4gb2Ygbm9kZXMgfHwgW10pIHtcbiAgICAgIGlmIChTdHJpbmcobi5pZCkgPT09IFN0cmluZyh0YXJnZXRJZCkpIHJldHVybiBuO1xuICAgICAgY29uc3QgZm91bmQgPSBuLmNoaWxkcmVuID8gdGhpcy5maW5kRm9sZGVyKG4uY2hpbGRyZW4sIHRhcmdldElkKSA6IG51bGw7XG4gICAgICBpZiAoZm91bmQpIHJldHVybiBmb3VuZDtcbiAgICB9XG4gICAgcmV0dXJuIG51bGw7XG4gIH1cblxuICAvKipcbiAgICogV2hldGhlciB0aGUgY29tcG9uZW50IGlzIGluIFwicm9vdFwiIHZpZXcgKG5vIGZvbGRlciBzZWxlY3RlZCkuIENvbnRyb2xzIHdoaWNoXG4gICAqIHNlY3Rpb25zIHJlbmRlciBvbiB0aGUgcmlnaHQtaGFuZCBwYW5lLlxuICAgKi9cbiAgZ2V0IGlzUm9vdFZpZXcoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMuc2VsZWN0ZWRGb2xkZXJJZCA9PSBudWxsO1xuICB9XG5cbiAgLyoqIFRoZSBjdXJyZW50bHktc2VsZWN0ZWQgZm9sZGVyIG5vZGUgKG9yIG51bGwgYXQgcm9vdCkuICovXG4gIGdldCBjdXJyZW50Rm9sZGVyTm9kZSgpOiBGb2xkZXJOb2RlIHwgbnVsbCB7XG4gICAgaWYgKHRoaXMuc2VsZWN0ZWRGb2xkZXJJZCA9PSBudWxsKSByZXR1cm4gbnVsbDtcbiAgICByZXR1cm4gdGhpcy5maW5kRm9sZGVyKHRoaXMuZm9sZGVycywgdGhpcy5zZWxlY3RlZEZvbGRlcklkKTtcbiAgfVxuXG4gIC8qKiBDb3VudCBvZiB0ZXN0IGNhc2VzIGRpcmVjdGx5IHVuZGVyIHRoZSBjdXJyZW50bHktc2VsZWN0ZWQgZm9sZGVyIChleGNsdWRpbmcgZGVzY2VuZGFudHMpLiAqL1xuICBnZXQgY3VycmVudEZvbGRlckRpcmVjdENvdW50KCk6IG51bWJlciB7XG4gICAgaWYgKHRoaXMuc2VsZWN0ZWRGb2xkZXJJZCA9PSBudWxsKSByZXR1cm4gMDtcbiAgICByZXR1cm4gdGhpcy5maWx0ZXJlZFJvd3MubGVuZ3RoO1xuICB9XG5cbiAgLyoqXG4gICAqIFJlbmRlcnMgdGhlIGVtcHR5LXN0YXRlIHNsb3Qgd2hlbiB0aGUgaG9zdCBleHBsaWNpdGx5IG9wdHMgaW4sIE9SIHdoZW4gdGhlXG4gICAqIHRhYmxlIHdvdWxkIG90aGVyd2lzZSByZW5kZXIgYmxhbmsgKG5vIGxvYWRpbmcgKyBubyByb3dzKS4gVXNpbmcgYSBkZXJpdmVkXG4gICAqIGZsYWcga2VlcHMgdGhlIGhvc3QgY29udHJhY3QgaWRlbnRpY2FsIHRvIGBjcWEtdGFibGUtdGVtcGxhdGVgIHdoaWxlIGxldHRpbmdcbiAgICogdGhlIG1vZHVsYXIgdmlldyBzaG93IFwiTm8gVGVzdCBDYXNlIEZvdW5kXCIgb3V0IG9mIHRoZSBib3gg4oCUIHRoZSBlYXJsaWVyIGFzay5cbiAgICovXG4gIGdldCBlZmZlY3RpdmVJc0VtcHR5U3RhdGUoKTogYm9vbGVhbiB7XG4gICAgaWYgKHRoaXMuaXNFbXB0eVN0YXRlKSByZXR1cm4gdHJ1ZTtcbiAgICBpZiAodGhpcy5pc1RhYmxlTG9hZGluZyB8fCB0aGlzLmlzVGFibGVEYXRhTG9hZGluZykgcmV0dXJuIGZhbHNlO1xuICAgIHJldHVybiAhdGhpcy5wYWdlZFJvd3MgfHwgdGhpcy5wYWdlZFJvd3MubGVuZ3RoID09PSAwO1xuICB9XG5cbiAgLyoqXG4gICAqIFBpY2tzIHRoZSBob3N0LXByb3ZpZGVkIGBlbXB0eVN0YXRlQ29uZmlnYCB3aGVuIHRoZSBob3N0IGZsYWdnZWQgdGhlIHN0YXRlXG4gICAqIGl0c2VsZjsgb3RoZXJ3aXNlIGZhbGxzIGJhY2sgdG8gYSBsaWJyYXJ5LW93bmVkIFwiTm8gVGVzdCBDYXNlIEZvdW5kXCIgY29uZmlnXG4gICAqIGRyaXZlbiBieSBgbW9kdWxhckxhYmVsc2AuXG4gICAqL1xuICBnZXQgZWZmZWN0aXZlRW1wdHlTdGF0ZUNvbmZpZygpOiBFbXB0eVN0YXRlQ29uZmlnIHtcbiAgICBpZiAodGhpcy5pc0VtcHR5U3RhdGUpIHJldHVybiB0aGlzLmVtcHR5U3RhdGVDb25maWc7XG4gICAgcmV0dXJuIHtcbiAgICAgIHRpdGxlOiB0aGlzLm1vZHVsYXJMYWJlbHMuZW1wdHlOb1Rlc3RzSW5Gb2xkZXJUaXRsZSxcbiAgICAgIGRlc2NyaXB0aW9uOiB0aGlzLm1vZHVsYXJMYWJlbHMuZW1wdHlOb1Rlc3RzSW5Gb2xkZXJEZXNjcmlwdGlvbixcbiAgICAgIGltYWdlVXJsOiBFTVBUWV9TVEFURV9JTUFHRVMuVEVTVF9DQVNFLFxuICAgICAgYWN0aW9uczogW10sXG4gICAgfTtcbiAgfVxuXG4gIG9uRm9sZGVyU2VsZWN0ZWQoaWQ6IG51bWJlciB8IG51bGwpOiB2b2lkIHtcbiAgICB0aGlzLnNlbGVjdGVkRm9sZGVySWQgPSBpZDtcbiAgICB0aGlzLnNlbGVjdGVkSXRlbXMgPSBbXTtcbiAgICB0aGlzLnBhZ2VJbmRleCA9IDA7XG4gICAgdGhpcy5yZWJ1aWxkRmlsdGVyZWRSb3dzKCk7XG4gICAgdGhpcy5hcHBseVBhZ2luYXRpb24oKTtcbiAgICB0aGlzLmZvbGRlclNlbGVjdGVkLmVtaXQoaWQpO1xuICAgIHRoaXMuY2RyLm1hcmtGb3JDaGVjaygpO1xuICB9XG5cbiAgb25Gb2xkZXJFeHBhbnNpb25Ub2dnbGVkKGV2ZW50OiB7IGlkOiBudW1iZXI7IGV4cGFuZGVkOiBib29sZWFuIH0pOiB2b2lkIHtcbiAgICBjb25zdCBzZXQgPSBuZXcgU2V0KHRoaXMuZXhwYW5kZWRGb2xkZXJJZHMgfHwgW10pO1xuICAgIGlmIChldmVudC5leHBhbmRlZCkge1xuICAgICAgc2V0LmFkZChldmVudC5pZCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHNldC5kZWxldGUoZXZlbnQuaWQpO1xuICAgIH1cbiAgICB0aGlzLmV4cGFuZGVkRm9sZGVySWRzID0gQXJyYXkuZnJvbShzZXQpO1xuICAgIHRoaXMuZm9sZGVyRXhwYW5zaW9uVG9nZ2xlZC5lbWl0KGV2ZW50KTtcbiAgfVxuXG4gIG9uRm9sZGVyQ3JlYXRlZChwYXlsb2FkOiBGb2xkZXJDcmVhdGVkUGF5bG9hZCk6IHZvaWQge1xuICAgIHRoaXMuZm9sZGVyQ3JlYXRlZC5lbWl0KHBheWxvYWQpO1xuICB9XG5cbiAgb25Gb2xkZXJDcmVhdGVSZXF1ZXN0ZWQocGF5bG9hZDogeyBwYXJlbnRJZDogbnVtYmVyIHwgbnVsbCB9KTogdm9pZCB7XG4gICAgLy8gRW1pdCB0aGUgXCJyZXF1ZXN0ZWRcIiBldmVudCBmaXJzdCBzbyBhIGhvc3QgY2FuIGludGVyY2VwdCB3aGVuIGl0IG93bnMgdGhlIFVYLlxuICAgIHRoaXMuZm9sZGVyQ3JlYXRlUmVxdWVzdGVkLmVtaXQocGF5bG9hZCk7XG4gICAgaWYgKCF0aGlzLnVzZUludGVybmFsRGlhbG9ncykgcmV0dXJuO1xuICAgIHRoaXMub3BlbkNyZWF0ZUZvbGRlckRpYWxvZyhwYXlsb2FkLnBhcmVudElkKTtcbiAgfVxuXG4gIG9uRm9sZGVyUmVuYW1lZChwYXlsb2FkOiBGb2xkZXJSZW5hbWVkUGF5bG9hZCk6IHZvaWQge1xuICAgIHRoaXMuZm9sZGVyUmVuYW1lZC5lbWl0KHBheWxvYWQpO1xuICB9XG5cbiAgLyoqXG4gICAqIFdpcmVkIHRvIHRoZSBzaWRlYmFyJ3MgYGZvbGRlckRlbGV0ZWRgIG91dHB1dCDigJQgd2hpY2ggZmlyZXMgb24gZGVsZXRlLWljb25cbiAgICogKmNsaWNrKiwgbm90IG9uIGNvbmZpcm1hdGlvbi4gV2UgcmUtZW1pdCBhIGBmb2xkZXJEZWxldGVSZXF1ZXN0ZWRgIGV2ZW50XG4gICAqIGZpcnN0IChzbyBob3N0cyBjYW4gaW50ZXJjZXB0KSBhbmQsIHdoZW4gYHVzZUludGVybmFsRGlhbG9nc2AgaXMgZW5hYmxlZCxcbiAgICogb3BlbiB0aGUgY29uZmlybWF0aW9uIGRpYWxvZy4gYGZvbGRlckRlbGV0ZWRgIG5vdyBvbmx5IGZpcmVzIGFmdGVyIGNvbmZpcm0uXG4gICAqL1xuICBvbkZvbGRlckRlbGV0ZWQocGF5bG9hZDogeyBpZDogbnVtYmVyIH0pOiB2b2lkIHtcbiAgICBjb25zdCBjdHggPSB0aGlzLmJ1aWxkRGVsZXRlQ29udGV4dChwYXlsb2FkLmlkKTtcbiAgICB0aGlzLmZvbGRlckRlbGV0ZVJlcXVlc3RlZC5lbWl0KGN0eCk7XG4gICAgaWYgKCF0aGlzLnVzZUludGVybmFsRGlhbG9ncykgcmV0dXJuO1xuICAgIHRoaXMub3BlbkRlbGV0ZUZvbGRlckRpYWxvZyhjdHgpO1xuICB9XG5cbiAgLyoqIEJ1aWxkcyB0aGUgeyBpZCwgbmFtZSwgdGVzdENvdW50LCBoYXNQYXJlbnQgfSBwYXlsb2FkIHVzZWQgYnkgZGVsZXRlIGV2ZW50cy9kaWFsb2dzLiAqL1xuICBwcml2YXRlIGJ1aWxkRGVsZXRlQ29udGV4dChmb2xkZXJJZDogbnVtYmVyKTogRm9sZGVyRGVsZXRlUmVxdWVzdGVkUGF5bG9hZCB7XG4gICAgY29uc3Qgbm9kZSA9IHRoaXMuZmluZEZvbGRlcih0aGlzLmZvbGRlcnMsIGZvbGRlcklkKTtcbiAgICByZXR1cm4ge1xuICAgICAgaWQ6IGZvbGRlcklkLFxuICAgICAgbmFtZTogbm9kZT8ubmFtZSA/PyAnJyxcbiAgICAgIHRlc3RDb3VudDogdGhpcy5jb3VudFRlc3RzSW5Gb2xkZXIoZm9sZGVySWQpLFxuICAgICAgaGFzUGFyZW50OiB0aGlzLmZvbGRlckhhc1BhcmVudChmb2xkZXJJZCksXG4gICAgfTtcbiAgfVxuXG4gIHByaXZhdGUgY291bnRUZXN0c0luRm9sZGVyKGZvbGRlcklkOiBudW1iZXIpOiBudW1iZXIge1xuICAgIGNvbnN0IGFjY2Vzc29yID0gdGhpcy5mb2xkZXJJZEFjY2Vzc29yID8/ICgocjogYW55KSA9PiByPy5mb2xkZXJJZCk7XG4gICAgcmV0dXJuICh0aGlzLmRhdGEgfHwgW10pLmZpbHRlcihyID0+IHtcbiAgICAgIGNvbnN0IGlkID0gYWNjZXNzb3Iocik7XG4gICAgICByZXR1cm4gaWQgIT0gbnVsbCAmJiBOdW1iZXIoaWQpID09PSBOdW1iZXIoZm9sZGVySWQpO1xuICAgIH0pLmxlbmd0aDtcbiAgfVxuXG4gIC8qKiBSZXR1cm5zIHRydWUgd2hlbiB0aGUgZm9sZGVyIGlzIG5lc3RlZCAoaS5lLiBub3QgYSByb290LWxldmVsIGZvbGRlcikuICovXG4gIHByaXZhdGUgZm9sZGVySGFzUGFyZW50KGZvbGRlcklkOiBudW1iZXIpOiBib29sZWFuIHtcbiAgICByZXR1cm4gISh0aGlzLmZvbGRlcnMgfHwgW10pLnNvbWUobiA9PiBuLmlkID09PSBmb2xkZXJJZCk7XG4gIH1cblxuICBvblRlc3RzRHJvcHBlZChldmVudDogeyB0ZXN0SWRzOiBBcnJheTxzdHJpbmcgfCBudW1iZXI+OyB0YXJnZXRGb2xkZXJJZDogbnVtYmVyIHwgbnVsbCB9KTogdm9pZCB7XG4gICAgaWYgKCF0aGlzLm1vZHVsYXJDb25maWcuYWxsb3dUZXN0RHJhZ0Ryb3ApIHJldHVybjtcbiAgICB0aGlzLnRlc3RzTW92ZWQuZW1pdChldmVudCk7XG4gIH1cblxuICAvKipcbiAgICogRm9sZGVyLXRvLWZvbGRlciBkcmFnLWRyb3AuIFRoZSBzaWRlYmFyIGhhcyBhbHJlYWR5IHZhbGlkYXRlZCBhZ2FpbnN0IHNlbGYvZGVzY2VuZGFudFxuICAgKiBjeWNsZXMsIHNvIHRoZSBkcm9wIGlzIGl0cyBvd24gY29uZmlybWF0aW9uIOKAlCB3ZSBlbWl0IGBmb2xkZXJNb3ZlZGAgZGlyZWN0bHkgd2l0aG91dFxuICAgKiBvcGVuaW5nIHRoZSBtb3ZlIGRpYWxvZy4gR2F0ZWQgb24gYGFsbG93VGVzdERyYWdEcm9wYCAoc2FtZSBmbGFnIGFzIHRlc3QgZHJhZy1kcm9wKS5cbiAgICovXG4gIG9uRm9sZGVyRHJvcHBlZChldmVudDogeyBpZDogbnVtYmVyOyBuZXdQYXJlbnRJZDogbnVtYmVyIHwgbnVsbCB9KTogdm9pZCB7XG4gICAgaWYgKCF0aGlzLm1vZHVsYXJDb25maWcuYWxsb3dUZXN0RHJhZ0Ryb3ApIHJldHVybjtcbiAgICB0aGlzLmZvbGRlck1vdmVkLmVtaXQoZXZlbnQpO1xuICB9XG5cbiAgLyoqXG4gICAqIFNpZGViYXIgZW1pdHRlZCBgZm9sZGVyTW92ZVJlcXVlc3RlZGAgKHVzZXIgcGlja2VkIFwiTW92ZSBmb2xkZXJcIiBmcm9tIHRoZSBjb250ZXh0IG1lbnUpLlxuICAgKiBXZSByZS1lbWl0IGEgcmljaGVyIHBheWxvYWQgZm9yIGhvc3RzLCBhbmQg4oCUIHdoZW4gcnVubmluZyB3aXRoIGludGVybmFsIGRpYWxvZ3Mg4oCUXG4gICAqIG9wZW4gdGhlIGV4aXN0aW5nIG1vdmUtdG8tZm9sZGVyIHBpY2tlciBjb25maWd1cmVkIGZvciBhIGZvbGRlci1tb3ZlIChzZWxmIGFuZFxuICAgKiBkZXNjZW5kYW50cyBhcmUgZGlzYWJsZWQgdG8gcHJldmVudCBjeWNsZXMpLlxuICAgKi9cbiAgb25Gb2xkZXJNb3ZlUmVxdWVzdGVkKHBheWxvYWQ6IHsgaWQ6IG51bWJlciB9KTogdm9pZCB7XG4gICAgY29uc3Qgbm9kZSA9IHRoaXMuZmluZEZvbGRlcih0aGlzLmZvbGRlcnMsIHBheWxvYWQuaWQpO1xuICAgIGNvbnN0IGN0eDogRm9sZGVyTW92ZVJlcXVlc3RlZFBheWxvYWQgPSB7XG4gICAgICBpZDogcGF5bG9hZC5pZCxcbiAgICAgIG5hbWU6IG5vZGU/Lm5hbWUgPz8gJycsXG4gICAgICBoYXNQYXJlbnQ6IHRoaXMuZm9sZGVySGFzUGFyZW50KHBheWxvYWQuaWQpLFxuICAgIH07XG4gICAgdGhpcy5mb2xkZXJNb3ZlUmVxdWVzdGVkLmVtaXQoY3R4KTtcbiAgICBpZiAoIXRoaXMudXNlSW50ZXJuYWxEaWFsb2dzKSByZXR1cm47XG4gICAgdGhpcy5vcGVuTW92ZUZvbGRlckRpYWxvZyhjdHgpO1xuICB9XG5cbiAgLyoqXG4gICAqIFNpZGViYXIgZW1pdHRlZCBgZm9sZGVyRHVwbGljYXRlUmVxdWVzdGVkYC4gVGhlIGxpYnJhcnkgY2FuJ3QgcGVyc2lzdCDigJRcbiAgICogZW1pdCB0aGUgaG9zdC1sZXZlbCBldmVudCBzbyB0aGUgaG9zdCBjbG9uZXMgdGhlIHN1YnRyZWUgc2VydmVyLXNpZGUuXG4gICAqIFRlc3QgY2FzZXMgc2hvdWxkIGJlICpyZWZlcmVuY2VkKiBmcm9tIHRoZSBuZXcgZm9sZGVycywgbm90IGR1cGxpY2F0ZWQuXG4gICAqL1xuICBvbkZvbGRlckR1cGxpY2F0ZVJlcXVlc3RlZChwYXlsb2FkOiB7IGlkOiBudW1iZXIgfSk6IHZvaWQge1xuICAgIGNvbnN0IG5vZGUgPSB0aGlzLmZpbmRGb2xkZXIodGhpcy5mb2xkZXJzLCBwYXlsb2FkLmlkKTtcbiAgICB0aGlzLmZvbGRlckR1cGxpY2F0ZVJlcXVlc3RlZC5lbWl0KHtcbiAgICAgIGlkOiBwYXlsb2FkLmlkLFxuICAgICAgbmFtZTogbm9kZT8ubmFtZSA/PyAnJyxcbiAgICB9KTtcbiAgfVxuXG4gIG9uU2lkZWJhckNvbGxhcHNlZENoYW5nZShjb2xsYXBzZWQ6IGJvb2xlYW4pOiB2b2lkIHtcbiAgICB0aGlzLnNpZGViYXJDb2xsYXBzZWQgPSBjb2xsYXBzZWQ7XG4gICAgdGhpcy5zaWRlYmFyQ29sbGFwc2VkQ2hhbmdlLmVtaXQoY29sbGFwc2VkKTtcbiAgfVxuXG4gIHRvZ2dsZVNpZGViYXIoKTogdm9pZCB7XG4gICAgdGhpcy5vblNpZGViYXJDb2xsYXBzZWRDaGFuZ2UoIXRoaXMuc2lkZWJhckNvbGxhcHNlZCk7XG4gIH1cblxuICAvKipcbiAgICogRGVmYXVsdCBidWxrIGFjdGlvbnMgc2hvd24gaW4gdGhlIHRvb2xiYXIgbWVyZ2VkIHdpdGggYW55IGhvc3Qtc3VwcGxpZWRcbiAgICogYGJ1bGtBY3Rpb25zYC4gQ3VycmVudGx5IG9ubHkgXCJNb3ZlIHRvIGZvbGRlclwiIHNoaXBzIGJ5IGRlZmF1bHQg4oCUXG4gICAqIERlbGV0ZSAvIEFkZCBUYWcgYXJlIG9wdC1pbiBwZXIgdGhlIGN1cnJlbnQgcHJvZHVjdCByZXF1aXJlbWVudC4gSG9zdHNcbiAgICogdGhhdCB3YW50IHRoZW0gYmFjayBwYXNzIHRoZW0gdmlhIGBidWxrQWN0aW9uc2AuXG4gICAqL1xuICBnZXQgZWZmZWN0aXZlQnVsa0FjdGlvbnMoKTogVGFibGVBY3Rpb25bXSB7XG4gICAgY29uc3QgZGVmYXVsdHM6IFRhYmxlQWN0aW9uW10gPSBbXG4gICAgICB7IGlkOiAnbW92ZScsIGxhYmVsOiB0aGlzLm1vZHVsYXJMYWJlbHMubW92ZVRvRm9sZGVyLCBpY29uOiAnZHJpdmVfZmlsZV9tb3ZlJywgdG9vbHRpcDogdGhpcy5tb2R1bGFyTGFiZWxzLm1vdmVUb0ZvbGRlciB9LFxuICAgIF07XG4gICAgY29uc3Qgb3ZlcnJpZGVzID0gbmV3IE1hcCgodGhpcy5idWxrQWN0aW9ucyB8fCBbXSkubWFwKGEgPT4gW2EuaWQsIGFdIGFzIGNvbnN0KSk7XG4gICAgY29uc3QgbWVyZ2VkID0gZGVmYXVsdHMubWFwKGQgPT4gb3ZlcnJpZGVzLmdldChkLmlkKSA/PyBkKTtcbiAgICBmb3IgKGNvbnN0IGV4dHJhIG9mIHRoaXMuYnVsa0FjdGlvbnMgfHwgW10pIHtcbiAgICAgIGlmICghZGVmYXVsdHMuc29tZShkID0+IGQuaWQgPT09IGV4dHJhLmlkKSkge1xuICAgICAgICBtZXJnZWQucHVzaChleHRyYSk7XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiBtZXJnZWQ7XG4gIH1cblxuICBvbkJ1bGtBY3Rpb24oZXZlbnQ6IHsgaWQ6IHN0cmluZzsgc2VsZWN0ZWQ6IGFueVtdIH0pOiB2b2lkIHtcbiAgICAvLyBBbHdheXMgZW1pdCB0aGUgcmF3IGNsaWNrIHNvIGhvc3RzIG93bmluZyB0aGUgVVggY2FuIGludGVyY2VwdCBlYXJseS5cbiAgICB0aGlzLmJ1bGtBY3Rpb25DbGljay5lbWl0KHsgaWQ6IGV2ZW50LmlkLCBzZWxlY3RlZDogZXZlbnQuc2VsZWN0ZWQgfSk7XG5cbiAgICBjb25zdCBzZWxlY3RlZElkcyA9IChldmVudC5zZWxlY3RlZCB8fCBbXSkubWFwKHIgPT4gcj8uaWQpLmZpbHRlcih2ID0+IHYgIT0gbnVsbCk7XG4gICAgaWYgKGV2ZW50LmlkID09PSAnbW92ZScpIHtcbiAgICAgIHRoaXMub3Blbk1vdmVEaWFsb2coc2VsZWN0ZWRJZHMsIGV2ZW50LnNlbGVjdGVkKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgLy8gRm9yIG5vbi1kaWFsb2cgYWN0aW9ucyAoY3VzdG9tIGVudHJpZXMgZnJvbSBob3N0LXN1cHBsaWVkIGBidWxrQWN0aW9uc2ApLCBpbnZva2UgaW1tZWRpYXRlbHkuXG4gICAgdGhpcy5idWxrQWN0aW9uSW52b2tlZC5lbWl0KHsgaWQ6IGV2ZW50LmlkLCBzZWxlY3RlZDogZXZlbnQuc2VsZWN0ZWQgfSk7XG4gIH1cblxuICBvbkJ1bGtTZWxlY3RBbGwoY2hlY2tlZDogYm9vbGVhbik6IHZvaWQge1xuICAgIC8vIEFwcGx5IHRoZSBhY3Rpb24gbG9jYWxseSBzbyB0aGUgYWN0aW9uIHRvb2xiYXIncyBcIlNlbGVjdCBhbGxcIiB3b3JrcyBvdXQtb2YtdGhlLWJveC5cbiAgICAvLyBXaGVuIGNoZWNrZWQsIHNlbGVjdCBldmVyeSByb3cgaW4gdGhlICpjdXJyZW50KiBmaWx0ZXJlZCBzZXQgKGkuZS4gYWxsIHRlc3RzIGluXG4gICAgLy8gdGhlIHNlbGVjdGVkIGZvbGRlcikuIFdoZW4gdW5jaGVja2VkLCBjbGVhciBzZWxlY3Rpb24uXG4gICAgdGhpcy5zZWxlY3RlZEl0ZW1zID0gY2hlY2tlZCA/IFsuLi50aGlzLmZpbHRlcmVkUm93c10gOiBbXTtcbiAgICB0aGlzLnJlc3RvcmVTZWxlY3Rpb25TdGF0ZSgpO1xuICAgIHRoaXMuc2VsZWN0ZWRJdGVtc0NoYW5nZS5lbWl0KFsuLi50aGlzLnNlbGVjdGVkSXRlbXNdKTtcbiAgICB0aGlzLmJ1bGtTZWxlY3RBbGxDaGFuZ2UuZW1pdChjaGVja2VkKTtcbiAgICB0aGlzLmNkci5tYXJrRm9yQ2hlY2soKTtcbiAgfVxuXG4gIG9uQnVsa0Rpc21pc3MoKTogdm9pZCB7XG4gICAgLy8gQ2xlYXIgc2VsZWN0aW9uIEFORCB0aGUgcGVyLXJvdyBpc1NlbGVjdGVkIGZsYWdzIHNvIHRoZSBhY3Rpb24gdG9vbGJhciBjbG9zZXNcbiAgICAvLyAoaXQncyBnYXRlZCBvbiBgYW55Um93U2VsZWN0ZWRgLCB3aGljaCByZWFkcyBib3RoIHNlbGVjdGVkSXRlbXMgYW5kIHJvdyBmbGFncykuXG4gICAgdGhpcy5zZWxlY3RlZEl0ZW1zID0gW107XG4gICAgdGhpcy5yZXN0b3JlU2VsZWN0aW9uU3RhdGUoKTtcbiAgICB0aGlzLnNlbGVjdGVkSXRlbXNDaGFuZ2UuZW1pdChbXSk7XG4gICAgdGhpcy5idWxrRGlzbWlzcy5lbWl0KCk7XG4gICAgdGhpcy5jZHIubWFya0ZvckNoZWNrKCk7XG4gIH1cblxuICBwcml2YXRlIG9wZW5Nb3ZlRGlhbG9nKHRlc3RJZHM6IEFycmF5PHN0cmluZyB8IG51bWJlcj4sIHNlbGVjdGVkOiBhbnlbXSk6IHZvaWQge1xuICAgIC8vIEZpcmUgdGhlIFwicmVxdWVzdGVkXCIgZXZlbnQgZmlyc3Qgc28gYSBob3N0IGNhbiBpbnRlcmNlcHQgd2hlbiBpdCBvd25zIHRoZSBVWC5cbiAgICB0aGlzLm1vdmVSZXF1ZXN0ZWQuZW1pdCh7XG4gICAgICB0ZXN0SWRzLFxuICAgICAgc2VsZWN0ZWQsXG4gICAgICBjdXJyZW50Rm9sZGVySWQ6IHRoaXMuc2VsZWN0ZWRGb2xkZXJJZCxcbiAgICAgIGZvbGRlcnM6IHRoaXMuZm9sZGVycyxcbiAgICB9KTtcbiAgICBpZiAoIXRoaXMudXNlSW50ZXJuYWxEaWFsb2dzKSByZXR1cm47XG5cbiAgICBjb25zdCBjb3VudCA9IHRlc3RJZHMubGVuZ3RoO1xuICAgIGNvbnN0IGRlc2NyaXB0aW9uID0gKGNvdW50ID09PSAxXG4gICAgICA/IHRoaXMubW9kdWxhckxhYmVscy5tb3ZlRGlhbG9nRGVzY3JpcHRpb25TaW5ndWxhclxuICAgICAgOiB0aGlzLm1vZHVsYXJMYWJlbHMubW92ZURpYWxvZ0Rlc2NyaXB0aW9uUGx1cmFsXG4gICAgKS5yZXBsYWNlKCd7bn0nLCAnJyArIGNvdW50KTtcbiAgICBjb25zdCByZWYgPSB0aGlzLmRpYWxvZ1NlcnZpY2Uub3BlbjxhbnksIG51bWJlciB8IG51bGw+KHtcbiAgICAgIHRpdGxlOiB0aGlzLm1vZHVsYXJMYWJlbHMubW92ZURpYWxvZ1RpdGxlLFxuICAgICAgZGVzY3JpcHRpb24sXG4gICAgICB3aWR0aDogJzUwMHB4JyxcbiAgICAgIGNvbnRlbnQ6IHtcbiAgICAgICAgdHlwZTogJ2NvbXBvbmVudCcsXG4gICAgICAgIGNvbXBvbmVudDogTW92ZVRvRm9sZGVyRGlhbG9nQ29tcG9uZW50LFxuICAgICAgICBpbnB1dHM6IHtcbiAgICAgICAgICBmb2xkZXJzOiB0aGlzLmZvbGRlcnMsXG4gICAgICAgICAgbGFiZWxzOiB0aGlzLm1vZHVsYXJMYWJlbHMsXG4gICAgICAgICAgY3VycmVudEZvbGRlcklkOiB0aGlzLnNlbGVjdGVkRm9sZGVySWQsXG4gICAgICAgIH0sXG4gICAgICB9LFxuICAgICAgYnV0dG9uczogW1xuICAgICAgICB7IGxhYmVsOiB0aGlzLm1vZHVsYXJMYWJlbHMubW92ZURpYWxvZ0NhbmNlbCwgcm9sZTogJ3NlY29uZGFyeScsIGhhbmRsZXI6IHIgPT4gci5jbG9zZSh1bmRlZmluZWQgYXMgYW55KSB9LFxuICAgICAgICB7XG4gICAgICAgICAgbGFiZWw6IHRoaXMubW9kdWxhckxhYmVscy5tb3ZlRGlhbG9nQ29uZmlybSxcbiAgICAgICAgICByb2xlOiAncHJpbWFyeScsXG4gICAgICAgICAgaGFuZGxlcjogciA9PiB7XG4gICAgICAgICAgICBjb25zdCBpbnN0YW5jZSA9IHIuZ2V0Q29tcG9uZW50SW5zdGFuY2U8TW92ZVRvRm9sZGVyRGlhbG9nQ29tcG9uZW50PigpO1xuICAgICAgICAgICAgci5jbG9zZShpbnN0YW5jZSA/IGluc3RhbmNlLnBpY2tlZEZvbGRlcklkIDogbnVsbCk7XG4gICAgICAgICAgfSxcbiAgICAgICAgfSxcbiAgICAgIF0sXG4gICAgICBidXR0b25BbGlnbm1lbnQ6ICdyaWdodCcsXG4gICAgfSk7XG4gICAgcmVmLmFmdGVyQ2xvc2VkKCkuc3Vic2NyaWJlKHRhcmdldEZvbGRlcklkID0+IHtcbiAgICAgIGlmICh0YXJnZXRGb2xkZXJJZCA9PT0gdW5kZWZpbmVkKSByZXR1cm47IC8vIGNhbmNlbGxlZFxuICAgICAgdGhpcy50ZXN0c01vdmVkLmVtaXQoeyB0ZXN0SWRzLCB0YXJnZXRGb2xkZXJJZDogdGFyZ2V0Rm9sZGVySWQgPz8gbnVsbCB9KTtcbiAgICAgIHRoaXMuYnVsa0FjdGlvbkludm9rZWQuZW1pdCh7IGlkOiAnbW92ZScsIHNlbGVjdGVkIH0pO1xuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIE9wZW5zIHRoZSBmb2xkZXItcGlja2VyIGRpYWxvZyBjb25maWd1cmVkIGZvciBtb3ZpbmcgYSBmb2xkZXIgKHJhdGhlciB0aGFuIHRlc3RzKS5cbiAgICogVGhlIHNvdXJjZSBmb2xkZXIgaXRzZWxmIGlzIG1hcmtlZCBhcyB0aGUgXCJjdXJyZW50XCIgZm9sZGVyIHNvIGl0J3MgcmVuZGVyZWQgYXNcbiAgICogZGlzYWJsZWQgaW4gdGhlIHBpY2tlci4gT24gY29uZmlybSwgZW1pdHMgYGZvbGRlck1vdmVkYCB3aXRoIHRoZSBjaG9zZW4gcGFyZW50LlxuICAgKi9cbiAgcHJpdmF0ZSBvcGVuTW92ZUZvbGRlckRpYWxvZyhjdHg6IEZvbGRlck1vdmVSZXF1ZXN0ZWRQYXlsb2FkKTogdm9pZCB7XG4gICAgY29uc3QgcmVmID0gdGhpcy5kaWFsb2dTZXJ2aWNlLm9wZW48YW55LCBudW1iZXIgfCBudWxsIHwgdW5kZWZpbmVkPih7XG4gICAgICB0aXRsZTogdGhpcy5tb2R1bGFyTGFiZWxzLmZvbGRlck1lbnVNb3ZlLFxuICAgICAgd2lkdGg6ICc1MDBweCcsXG4gICAgICBjb250ZW50OiB7XG4gICAgICAgIHR5cGU6ICdjb21wb25lbnQnLFxuICAgICAgICBjb21wb25lbnQ6IE1vdmVUb0ZvbGRlckRpYWxvZ0NvbXBvbmVudCxcbiAgICAgICAgaW5wdXRzOiB7XG4gICAgICAgICAgZm9sZGVyczogdGhpcy5mb2xkZXJzLFxuICAgICAgICAgIGxhYmVsczogdGhpcy5tb2R1bGFyTGFiZWxzLFxuICAgICAgICAgIC8vIFJldXNlIHRoZSBcImRpc2FibGVkXCIgdHJlYXRtZW50OiB0aGUgZm9sZGVyIGJlaW5nIG1vdmVkIGNhbid0IGJlIGl0cyBvd24gZGVzdGluYXRpb24uXG4gICAgICAgICAgY3VycmVudEZvbGRlcklkOiBjdHguaWQsXG4gICAgICAgIH0sXG4gICAgICB9LFxuICAgICAgYnV0dG9uczogW1xuICAgICAgICB7IGxhYmVsOiB0aGlzLm1vZHVsYXJMYWJlbHMubW92ZURpYWxvZ0NhbmNlbCwgcm9sZTogJ3NlY29uZGFyeScsIGhhbmRsZXI6IHIgPT4gci5jbG9zZSh1bmRlZmluZWQgYXMgYW55KSB9LFxuICAgICAgICB7XG4gICAgICAgICAgbGFiZWw6IHRoaXMubW9kdWxhckxhYmVscy5tb3ZlRGlhbG9nQ29uZmlybSxcbiAgICAgICAgICByb2xlOiAncHJpbWFyeScsXG4gICAgICAgICAgaGFuZGxlcjogciA9PiB7XG4gICAgICAgICAgICBjb25zdCBpbnN0YW5jZSA9IHIuZ2V0Q29tcG9uZW50SW5zdGFuY2U8TW92ZVRvRm9sZGVyRGlhbG9nQ29tcG9uZW50PigpO1xuICAgICAgICAgICAgci5jbG9zZShpbnN0YW5jZSA/IGluc3RhbmNlLnBpY2tlZEZvbGRlcklkIDogbnVsbCk7XG4gICAgICAgICAgfSxcbiAgICAgICAgfSxcbiAgICAgIF0sXG4gICAgICBidXR0b25BbGlnbm1lbnQ6ICdyaWdodCcsXG4gICAgfSk7XG4gICAgcmVmLmFmdGVyQ2xvc2VkKCkuc3Vic2NyaWJlKHRhcmdldEZvbGRlcklkID0+IHtcbiAgICAgIGlmICh0YXJnZXRGb2xkZXJJZCA9PT0gdW5kZWZpbmVkKSByZXR1cm47IC8vIGNhbmNlbGxlZFxuICAgICAgdGhpcy5mb2xkZXJNb3ZlZC5lbWl0KHsgaWQ6IGN0eC5pZCwgbmV3UGFyZW50SWQ6IHRhcmdldEZvbGRlcklkID8/IG51bGwgfSk7XG4gICAgfSk7XG4gIH1cblxuICBwcml2YXRlIG9wZW5DcmVhdGVGb2xkZXJEaWFsb2coaW5pdGlhbFBhcmVudElkOiBudW1iZXIgfCBudWxsKTogdm9pZCB7XG4gICAgY29uc3QgcmVmID0gdGhpcy5kaWFsb2dTZXJ2aWNlLm9wZW48YW55LCB7IG5hbWU6IHN0cmluZzsgcGFyZW50SWQ6IG51bWJlciB8IG51bGw7IGNvbG9yOiBzdHJpbmcgfSB8IGZhbHNlPih7XG4gICAgICB0aXRsZTogdGhpcy5tb2R1bGFyTGFiZWxzLm5ld0ZvbGRlckRpYWxvZ1RpdGxlLFxuICAgICAgZGVzY3JpcHRpb246IHRoaXMubW9kdWxhckxhYmVscy5uZXdGb2xkZXJEaWFsb2dEZXNjcmlwdGlvbixcbiAgICAgIHdpZHRoOiAnNTAwcHgnLFxuICAgICAgY29udGVudDoge1xuICAgICAgICB0eXBlOiAnY29tcG9uZW50JyxcbiAgICAgICAgY29tcG9uZW50OiBOZXdGb2xkZXJEaWFsb2dDb21wb25lbnQsXG4gICAgICAgIGlucHV0czoge1xuICAgICAgICAgIGZvbGRlcnM6IHRoaXMuZm9sZGVycyxcbiAgICAgICAgICBsYWJlbHM6IHRoaXMubW9kdWxhckxhYmVscyxcbiAgICAgICAgICBuYW1lOiAnJyxcbiAgICAgICAgICBwYXJlbnRJZDogaW5pdGlhbFBhcmVudElkLFxuICAgICAgICB9LFxuICAgICAgfSxcbiAgICAgIGJ1dHRvbnM6IFtcbiAgICAgICAgeyBsYWJlbDogdGhpcy5tb2R1bGFyTGFiZWxzLm5ld0ZvbGRlckRpYWxvZ0NhbmNlbCwgcm9sZTogJ3NlY29uZGFyeScsIGhhbmRsZXI6IHIgPT4gci5jbG9zZShmYWxzZSkgfSxcbiAgICAgICAge1xuICAgICAgICAgIGxhYmVsOiB0aGlzLm1vZHVsYXJMYWJlbHMubmV3Rm9sZGVyRGlhbG9nQ29uZmlybSxcbiAgICAgICAgICByb2xlOiAncHJpbWFyeScsXG4gICAgICAgICAgaGFuZGxlcjogciA9PiB7XG4gICAgICAgICAgICBjb25zdCBpbnN0ID0gci5nZXRDb21wb25lbnRJbnN0YW5jZTxOZXdGb2xkZXJEaWFsb2dDb21wb25lbnQ+KCk7XG4gICAgICAgICAgICBpZiAoIWluc3QgfHwgIWluc3QuaXNWYWxpZCkgcmV0dXJuIGZhbHNlOyAvLyBrZWVwIHRoZSBkaWFsb2cgb3BlbiBvbiBpbnZhbGlkIHN1Ym1pdFxuICAgICAgICAgICAgci5jbG9zZSh7IG5hbWU6IChpbnN0Lm5hbWUgfHwgJycpLnRyaW0oKSwgcGFyZW50SWQ6IGluc3QucGFyZW50SWQsIGNvbG9yOiBpbnN0LmNvbG9yIH0pO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgIH0sXG4gICAgICAgIH0sXG4gICAgICBdLFxuICAgICAgYnV0dG9uQWxpZ25tZW50OiAncmlnaHQnLFxuICAgIH0pO1xuICAgIHJlZi5hZnRlckNsb3NlZCgpLnN1YnNjcmliZShyZXN1bHQgPT4ge1xuICAgICAgaWYgKHJlc3VsdCkge1xuICAgICAgICB0aGlzLmZvbGRlckNyZWF0ZWQuZW1pdCh7IHBhcmVudElkOiByZXN1bHQucGFyZW50SWQsIG5hbWU6IHJlc3VsdC5uYW1lLCBjb2xvcjogcmVzdWx0LmNvbG9yIH0pO1xuICAgICAgfVxuICAgIH0pO1xuICB9XG5cbiAgcHJpdmF0ZSBvcGVuRGVsZXRlRm9sZGVyRGlhbG9nKGN0eDogRm9sZGVyRGVsZXRlUmVxdWVzdGVkUGF5bG9hZCk6IHZvaWQge1xuICAgIGNvbnN0IHJlZiA9IHRoaXMuZGlhbG9nU2VydmljZS5vcGVuPGFueSwgeyBzdHJhdGVneTogRm9sZGVyRGVsZXRlU3RyYXRlZ3kgfSB8IGZhbHNlPih7XG4gICAgICB0aXRsZTogdGhpcy5tb2R1bGFyTGFiZWxzLmRlbGV0ZUZvbGRlckRpYWxvZ1RpdGxlLFxuICAgICAgd2lkdGg6ICc1MDBweCcsXG4gICAgICBjb250ZW50OiB7XG4gICAgICAgIHR5cGU6ICdjb21wb25lbnQnLFxuICAgICAgICBjb21wb25lbnQ6IERlbGV0ZUZvbGRlckRpYWxvZ0NvbXBvbmVudCxcbiAgICAgICAgaW5wdXRzOiB7XG4gICAgICAgICAgZm9sZGVyTmFtZTogY3R4Lm5hbWUsXG4gICAgICAgICAgdGVzdENvdW50OiBjdHgudGVzdENvdW50LFxuICAgICAgICAgIGhhc1BhcmVudDogY3R4Lmhhc1BhcmVudCxcbiAgICAgICAgICBsYWJlbHM6IHRoaXMubW9kdWxhckxhYmVscyxcbiAgICAgICAgICBzdHJhdGVneTogY3R4Lmhhc1BhcmVudCA/ICdtb3ZlLXRvLXBhcmVudCcgOiAnbW92ZS10by11bm9yZ2FuaXNlZCcsXG4gICAgICAgIH0sXG4gICAgICB9LFxuICAgICAgYnV0dG9uczogW1xuICAgICAgICB7IGxhYmVsOiB0aGlzLm1vZHVsYXJMYWJlbHMuZGVsZXRlRm9sZGVyRGlhbG9nQ2FuY2VsLCByb2xlOiAnc2Vjb25kYXJ5JywgaGFuZGxlcjogciA9PiByLmNsb3NlKGZhbHNlKSB9LFxuICAgICAgICB7XG4gICAgICAgICAgbGFiZWw6IHRoaXMubW9kdWxhckxhYmVscy5kZWxldGVGb2xkZXJEaWFsb2dDb25maXJtLFxuICAgICAgICAgIHJvbGU6ICd3YXJuJyxcbiAgICAgICAgICBoYW5kbGVyOiByID0+IHtcbiAgICAgICAgICAgIGNvbnN0IGluc3QgPSByLmdldENvbXBvbmVudEluc3RhbmNlPERlbGV0ZUZvbGRlckRpYWxvZ0NvbXBvbmVudD4oKTtcbiAgICAgICAgICAgIHIuY2xvc2UoaW5zdCA/IHsgc3RyYXRlZ3k6IGluc3Quc3RyYXRlZ3kgfSA6IGZhbHNlKTtcbiAgICAgICAgICB9LFxuICAgICAgICB9LFxuICAgICAgXSxcbiAgICAgIGJ1dHRvbkFsaWdubWVudDogJ3JpZ2h0JyxcbiAgICB9KTtcbiAgICByZWYuYWZ0ZXJDbG9zZWQoKS5zdWJzY3JpYmUocmVzdWx0ID0+IHtcbiAgICAgIGlmIChyZXN1bHQpIHtcbiAgICAgICAgdGhpcy5mb2xkZXJEZWxldGVkLmVtaXQoeyBpZDogY3R4LmlkLCBzdHJhdGVneTogcmVzdWx0LnN0cmF0ZWd5IH0pO1xuICAgICAgfVxuICAgIH0pO1xuICB9XG5cbiAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuICAvLyBSb3ctcmVvcmRlciBoYW5kbGVyc1xuICAvLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG5cbiAgc3RhcnRSZW9yZGVyKCk6IHZvaWQge1xuICAgIGlmICh0aGlzLmlzUmVvcmRlcmluZykgcmV0dXJuO1xuICAgIHRoaXMucmVvcmRlclNuYXBzaG90ID0gWy4uLih0aGlzLnBhZ2VkUm93cyB8fCBbXSldO1xuICAgIHRoaXMucmVvcmRlckRyYWZ0ID0gWy4uLih0aGlzLnBhZ2VkUm93cyB8fCBbXSldO1xuICAgIC8vIFBhdXNlIGF1dG8tcmVmcmVzaCB3aGlsZSByZW9yZGVyaW5nIOKAlCBhdm9pZHMgdGhlIHRpbWVyIGNsb2JiZXJpbmcgdGhlIGRyYWZ0LlxuICAgIHRoaXMucmVvcmRlclNhdmVkQXV0b1JlZnJlc2ggPSB0aGlzLnNlbGVjdGVkQXV0b1JlZnJlc2hJbnRlcnZhbDtcbiAgICBpZiAodGhpcy5yZW9yZGVyU2F2ZWRBdXRvUmVmcmVzaCA+IDApIHtcbiAgICAgIHRoaXMuc2V0dXBBdXRvUmVmcmVzaCgwKTtcbiAgICB9XG4gICAgdGhpcy5pc1Jlb3JkZXJpbmcgPSB0cnVlO1xuICAgIHRoaXMucmVvcmRlckF3YWl0aW5nU2F2ZUZsaXAgPSBmYWxzZTtcbiAgICB0aGlzLnJlb3JkZXJTdGFydC5lbWl0KCk7XG4gICAgdGhpcy5jZHIubWFya0ZvckNoZWNrKCk7XG4gIH1cblxuICBjYW5jZWxSZW9yZGVyKCk6IHZvaWQge1xuICAgIGlmICghdGhpcy5pc1Jlb3JkZXJpbmcpIHJldHVybjtcbiAgICAvLyBSZXN0b3JlIHRoZSBvcmlnaW5hbCBwYWdlIG9yZGVyIHNvIHRoZSB1c2VyIHNlZXMgdGhlIHByZS1kcmFnIHN0YXRlLlxuICAgIGlmICh0aGlzLnJlb3JkZXJTbmFwc2hvdCkge1xuICAgICAgdGhpcy5wYWdlZFJvd3MgPSBbLi4udGhpcy5yZW9yZGVyU25hcHNob3RdO1xuICAgIH1cbiAgICB0aGlzLmV4aXRSZW9yZGVyTW9kZSgpO1xuICAgIHRoaXMucmVvcmRlckNhbmNlbC5lbWl0KCk7XG4gIH1cblxuICBzYXZlUmVvcmRlcigpOiB2b2lkIHtcbiAgICBpZiAoIXRoaXMuaXNSZW9yZGVyaW5nKSByZXR1cm47XG4gICAgY29uc3Qgb3JkZXJlZCA9IHRoaXMucmVvcmRlckRyYWZ0ID8gWy4uLnRoaXMucmVvcmRlckRyYWZ0XSA6IFsuLi4odGhpcy5wYWdlZFJvd3MgfHwgW10pXTtcbiAgICB0aGlzLnJlb3JkZXJBd2FpdGluZ1NhdmVGbGlwID0gdHJ1ZTtcbiAgICB0aGlzLnJlb3JkZXJTYXZlLmVtaXQoeyBvcmRlcmVkSXRlbXM6IG9yZGVyZWQgfSk7XG4gICAgLy8gSWYgdGhlIGhvc3QgbmV2ZXIgZmxpcHMgYHJlb3JkZXJTYXZpbmdgIChlLmcuIHN5bmNocm9ub3VzIG5vLW9wKSwgZXhpdFxuICAgIC8vIGltbWVkaWF0ZWx5IHNvIHRoZSBVSSBkb2Vzbid0IGdldCBzdHVjayBpbiBcIlNhdmluZy4uLlwiIHN0YXRlLlxuICAgIGlmICghdGhpcy5yZW9yZGVyU2F2aW5nKSB7XG4gICAgICAvLyBHaXZlIHRoZSBob3N0IGEgbWljcm90YXNrIHRvIGZsaXAgYHJlb3JkZXJTYXZpbmdgIHRvIHRydWUg4oCUIGlmIGl0XG4gICAgICAvLyBoYXNuJ3QsIGFzc3VtZSBubyBhc3luYyB3b3JrIGFuZCBleGl0LlxuICAgICAgUHJvbWlzZS5yZXNvbHZlKCkudGhlbigoKSA9PiB7XG4gICAgICAgIGlmICh0aGlzLnJlb3JkZXJBd2FpdGluZ1NhdmVGbGlwICYmICF0aGlzLnJlb3JkZXJTYXZpbmcpIHtcbiAgICAgICAgICB0aGlzLmV4aXRSZW9yZGVyTW9kZSgpO1xuICAgICAgICB9XG4gICAgICB9KTtcbiAgICB9XG4gIH1cblxuICBvblJvd1Jlb3JkZXIoZXZlbnQ6IHsgcHJldmlvdXNJbmRleDogbnVtYmVyOyBjdXJyZW50SW5kZXg6IG51bWJlcjsgb3JkZXJlZERhdGE6IGFueVtdIH0pOiB2b2lkIHtcbiAgICBpZiAoIXRoaXMuaXNSZW9yZGVyaW5nKSByZXR1cm47XG4gICAgdGhpcy5yZW9yZGVyRHJhZnQgPSBbLi4uZXZlbnQub3JkZXJlZERhdGFdO1xuICAgIHRoaXMucGFnZWRSb3dzID0gdGhpcy5yZW9yZGVyRHJhZnQ7XG4gICAgdGhpcy5jZHIubWFya0ZvckNoZWNrKCk7XG4gIH1cblxuICBwcml2YXRlIGV4aXRSZW9yZGVyTW9kZSgpOiB2b2lkIHtcbiAgICB0aGlzLmlzUmVvcmRlcmluZyA9IGZhbHNlO1xuICAgIHRoaXMucmVvcmRlclNuYXBzaG90ID0gbnVsbDtcbiAgICB0aGlzLnJlb3JkZXJEcmFmdCA9IG51bGw7XG4gICAgdGhpcy5yZW9yZGVyQXdhaXRpbmdTYXZlRmxpcCA9IGZhbHNlO1xuICAgIC8vIFJlc3RvcmUgcHJldmlvdXNseS1zZWxlY3RlZCBhdXRvLXJlZnJlc2ggaW50ZXJ2YWwgKGlmIGFueSkuXG4gICAgaWYgKHRoaXMucmVvcmRlclNhdmVkQXV0b1JlZnJlc2ggPiAwKSB7XG4gICAgICB0aGlzLnNldHVwQXV0b1JlZnJlc2godGhpcy5yZW9yZGVyU2F2ZWRBdXRvUmVmcmVzaCk7XG4gICAgICB0aGlzLnJlb3JkZXJTYXZlZEF1dG9SZWZyZXNoID0gMDtcbiAgICB9XG4gICAgdGhpcy5jZHIubWFya0ZvckNoZWNrKCk7XG4gIH1cblxuICAvKipcbiAgICogUm93LWRyYWcgcGF5bG9hZCBidWlsZGVyIHVzZWQgYnkgdGhlIFtjcWFSb3dEcmFnXSBkaXJlY3RpdmUgdmlhIChidWlsZFBheWxvYWQpLlxuICAgKi9cbiAgYnVpbGRSb3dEcmFnUGF5bG9hZCA9IChyb3c6IGFueSk6IEFycmF5PHN0cmluZyB8IG51bWJlcj4gPT4ge1xuICAgIGNvbnN0IHNlbGVjdGVkID0gdGhpcy5jdXJyZW50U2VsZWN0ZWRJdGVtcztcbiAgICAvLyBJZiB0aGUgZHJhZ2dlZCByb3cgaXMgcGFydCBvZiB0aGUgY3VycmVudCBzZWxlY3Rpb24sIGRyYWcgdGhlIHdob2xlIHNlbGVjdGlvbi5cbiAgICBjb25zdCByb3dJZCA9IHJvdz8uaWQ7XG4gICAgY29uc3QgaW5TZWxlY3Rpb24gPSByb3dJZCAhPSBudWxsICYmIHNlbGVjdGVkLnNvbWUocyA9PiBzPy5pZCA9PT0gcm93SWQpO1xuICAgIGNvbnN0IGlkcyA9IChpblNlbGVjdGlvbiA/IHNlbGVjdGVkIDogW3Jvd10pLm1hcChyID0+IHI/LmlkKS5maWx0ZXIodiA9PiB2ICE9IG51bGwpO1xuICAgIHJldHVybiBpZHM7XG4gIH07XG59XG4iLCI8IS0tIFJldXNhYmxlIGZvbGRlci1pY29uIGNoaXAuIFJlbmRlciB2aWEgPG5nLWNvbnRhaW5lciAqbmdUZW1wbGF0ZU91dGxldD1cImZvbGRlckljb25DaGlwXCI+PC9uZy1jb250YWluZXI+LiAtLT5cbjxuZy10ZW1wbGF0ZSAjZm9sZGVySWNvbkNoaXA+XG4gIDxzcGFuIGNsYXNzPVwiY3FhLWlubGluZS1mbGV4IGNxYS1pdGVtcy1jZW50ZXIgY3FhLWp1c3RpZnktY2VudGVyIGNxYS13LTEwIGNxYS1oLTEwIGNxYS1yb3VuZGVkLVsxMHB4XSBjcWEtYmctbmV1dHJhbC0xMDAgY3FhLXNocmluay0wXCI+XG4gICAgPHN2ZyB3aWR0aD1cIjE3XCIgaGVpZ2h0PVwiMTVcIiB2aWV3Qm94PVwiMCAwIDE3IDE1XCIgZmlsbD1cIm5vbmVcIiB4bWxucz1cImh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnXCIgYXJpYS1oaWRkZW49XCJ0cnVlXCI+XG4gICAgICA8cGF0aCBkPVwiTTE1LjYzNzUgMTIuNjM3N0MxNS42Mzc1IDEzLjAzNTUgMTUuNDc5NCAxMy40MTcxIDE1LjE5ODEgMTMuNjk4NEMxNC45MTY4IDEzLjk3OTcgMTQuNTM1MyAxNC4xMzc3IDE0LjEzNzUgMTQuMTM3N0gyLjEzNzQ1QzEuNzM5NjMgMTQuMTM3NyAxLjM1ODEgMTMuOTc5NyAxLjA3Njc5IDEzLjY5ODRDMC43OTU0ODYgMTMuNDE3MSAwLjYzNzQ1MSAxMy4wMzU1IDAuNjM3NDUxIDEyLjYzNzdWMi4xMzc3QzAuNjM3NDUxIDEuNzM5ODcgMC43OTU0ODYgMS4zNTgzNCAxLjA3Njc5IDEuMDc3MDRDMS4zNTgxIDAuNzk1NzMxIDEuNzM5NjMgMC42Mzc2OTUgMi4xMzc0NSAwLjYzNzY5NUg1Ljg4NzQ1TDcuMzg3NDUgMi44ODc3SDE0LjEzNzVDMTQuNTM1MyAyLjg4NzcgMTQuOTE2OCAzLjA0NTczIDE1LjE5ODEgMy4zMjcwNEMxNS40Nzk0IDMuNjA4MzQgMTUuNjM3NSAzLjk4OTg3IDE1LjYzNzUgNC4zODc3VjEyLjYzNzdaXCIgc3Ryb2tlPVwiIzZENkQ3NFwiIHN0cm9rZS13aWR0aD1cIjEuMjc1XCIgc3Ryb2tlLWxpbmVjYXA9XCJyb3VuZFwiIHN0cm9rZS1saW5lam9pbj1cInJvdW5kXCIvPlxuICAgIDwvc3ZnPlxuICA8L3NwYW4+XG48L25nLXRlbXBsYXRlPlxuXG48IS0tIFJldXNhYmxlIFwiK1wiIGNoaXAgdXNlZCBieSB0aGUgXCJOZXcgZm9sZGVyXCIgdGlsZS4gLS0+XG48bmctdGVtcGxhdGUgI2FkZEljb25DaGlwPlxuICA8c3BhbiBjbGFzcz1cImNxYS1pbmxpbmUtZmxleCBjcWEtaXRlbXMtY2VudGVyIGNxYS1qdXN0aWZ5LWNlbnRlciBjcWEtdy0xMCBjcWEtaC0xMCBjcWEtcm91bmRlZC1bMTBweF0gY3FhLWJnLW5ldXRyYWwtMTAwIGNxYS1zaHJpbmstMFwiPlxuICAgIDxzdmcgd2lkdGg9XCIxNlwiIGhlaWdodD1cIjE2XCIgdmlld0JveD1cIjAgMCAxNiAxNlwiIGZpbGw9XCJub25lXCIgeG1sbnM9XCJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2Z1wiIGFyaWEtaGlkZGVuPVwidHJ1ZVwiPlxuICAgICAgPHBhdGggZD1cIk04IDNWMTNNMyA4SDEzXCIgc3Ryb2tlPVwiIzZENkQ3NFwiIHN0cm9rZS13aWR0aD1cIjEuMjc1XCIgc3Ryb2tlLWxpbmVjYXA9XCJyb3VuZFwiLz5cbiAgICA8L3N2Zz5cbiAgPC9zcGFuPlxuPC9uZy10ZW1wbGF0ZT5cblxuPGRpdiBjbGFzcz1cImNxYS11aS1yb290XCI+XG4gIDxkaXYgY2xhc3M9XCJjcWEtdy1mdWxsIGNxYS1mbGV4IGNxYS1mbGV4LWNvbCBjcWEtcmVsYXRpdmVcIj5cbiAgICA8ZGl2IFtjbGFzc109XCIhc2hvd1NlYXJjaEJhciA/ICdjcWEtanVzdGlmeS1lbmQnIDogJ2NxYS1qdXN0aWZ5LWJldHdlZW4nXCIgY2xhc3M9XCJjcWEtdy1mdWxsIGNxYS1mbGV4IGNxYS1pdGVtcy1jZW50ZXIgY3FhLWdhcC0zIGNxYS1mbGV4LXdyYXAgY3FhLW1iLTNcIj5cbiAgICAgIDxjcWEtc2VhcmNoLWJhclxuICAgICAgICAqbmdJZj1cInNob3dTZWFyY2hCYXJcIlxuICAgICAgICBbcGxhY2Vob2xkZXJdPVwic2VhcmNoUGxhY2Vob2xkZXJcIlxuICAgICAgICBbdmFsdWVdPVwic2VhcmNoVmFsdWVcIlxuICAgICAgICBbc2hvd0NsZWFyXT1cInNob3dDbGVhclwiXG4gICAgICAgICh2YWx1ZUNoYW5nZSk9XCJ2YWx1ZUNoYW5nZSgkZXZlbnQpXCJcbiAgICAgICAgKHNlYXJjaCk9XCJzZWFyY2goJGV2ZW50KVwiXG4gICAgICAgIChjbGVhcmVkKT1cImNsZWFyZWQoKVwiXG4gICAgICA+PC9jcWEtc2VhcmNoLWJhcj5cbiAgICAgIDxkaXYgY2xhc3M9XCJjcWEtZmxleCBjcWEtaXRlbXMtY2VudGVyIGNxYS1nYXAtMiBjcWEtZmxleC13cmFwXCI+XG4gICAgICAgIDxjcWEtYnV0dG9uXG4gICAgICAgICpuZ0lmPVwic2hvd0V4cG9ydEJ1dHRvblwiXG4gICAgICAgIHZhcmlhbnQ9XCJncmV5LXNvbGlkXCJcbiAgICAgICAgaWNvbj1cIm9wZW5faW5fbmV3XCJcbiAgICAgICAgW3RleHRdPVwiaXNFeHBvcnRpbmcgPyAnRXhwb3J0aW5nLi4uJyA6ICdFeHBvcnQnXCJcbiAgICAgICAgW2Rpc2FibGVkXT1cImlzRXhwb3J0aW5nXCJcbiAgICAgICAgKGNsaWNrZWQpPVwiZXhwb3J0Q29kZUNsaWNrKClcIlxuICAgICAgPlxuICAgICAgICA8c3Bhbj57eyBpc0V4cG9ydGluZyA/ICdFeHBvcnRpbmcuLi4nIDogJ0V4cG9ydCcgfX08L3NwYW4+XG4gICAgICA8L2NxYS1idXR0b24+XG4gICAgICBcbiAgICAgIDwhLS0gRXhwb3J0IENvZGUgTW9kYWwgLS0+XG4gICAgICA8Y3FhLWV4cG9ydC1jb2RlLW1vZGFsXG4gICAgICAgICpuZ0lmPVwic2hvd0V4cG9ydEJ1dHRvblwiXG4gICAgICAgIFtpc09wZW5dPVwiaXNFeHBvcnRNb2RhbE9wZW5cIlxuICAgICAgICBbY2FzZXNdPVwic2VsZWN0ZWRDYXNlc0ZvckV4cG9ydFwiXG4gICAgICAgIFtkaXNhYmxlZF09XCJmYWxzZVwiXG4gICAgICAgIChjbG9zZU1vZGFsKT1cImNsb3NlRXhwb3J0TW9kYWwoKVwiXG4gICAgICAgIChleHBvcnQpPVwib25FeHBvcnRNb2RhbEV4cG9ydCgkZXZlbnQpXCI+XG4gICAgICA8L2NxYS1leHBvcnQtY29kZS1tb2RhbD5cbiAgICAgICAgIDxuZy1jb250YWluZXIgKm5nRm9yPVwibGV0IGRyb3Bkb3duVGVtcGxhdGUgb2Ygb3RoZXJEcm9wRG93bkJ1dHRvbnM7IHRyYWNrQnk6IHRyYWNrQnlEcm9wZG93blRlbXBsYXRlUmVmXCI+XG4gICAgICAgICAgPG5nLWNvbnRhaW5lciAqbmdUZW1wbGF0ZU91dGxldD1cImRyb3Bkb3duVGVtcGxhdGVcIj48L25nLWNvbnRhaW5lcj5cbiAgICAgICAgPC9uZy1jb250YWluZXI+XG5cbiAgICAgICAgPG5nLWNvbnRhaW5lciAqbmdGb3I9XCJsZXQgc2VsZWN0RHJvcGRvd25UZW1wbGF0ZSBvZiBvdGhlclNlbGVjdERyb3BEb3duQnV0dG9uczsgdHJhY2tCeTogdHJhY2tCeVNlbGVjdERyb3Bkb3duVGVtcGxhdGVSZWZcIj5cbiAgICAgICAgICA8bmctY29udGFpbmVyICpuZ1RlbXBsYXRlT3V0bGV0PVwic2VsZWN0RHJvcGRvd25UZW1wbGF0ZVwiPjwvbmctY29udGFpbmVyPlxuICAgICAgICA8L25nLWNvbnRhaW5lcj5cbiAgICAgICAgXG4gICAgICAgIDxjcWEtYnV0dG9uXG4gICAgICAgICAgKm5nSWY9XCJzaG93RmlsdGVyQnV0dG9uXCJcbiAgICAgICAgICB2YXJpYW50PVwiZ3JleS1zb2xpZFwiXG4gICAgICAgICAgaWNvbj1cImFkZFwiXG4gICAgICAgICAgW2Rpc2FibGVkXT1cImlzUmVvcmRlcmluZ1wiXG4gICAgICAgICAgKGNsaWNrZWQpPVwidG9nZ2xlRmlsdGVyKClcIlxuICAgICAgICA+XG4gICAgICAgIDxzcGFuIGNsYXNzPVwiY3FhLWZsZXggY3FhLWl0ZW1zLWNlbnRlciBjcWEtZ2FwLTFcIj5cbiAgICAgICAgICBGaWx0ZXIgICAgICAgICAgXG4gICAgICAgICAgIDxkaXYgW2NsYXNzXT1cImFycm93Q2xhc3Nlc1wiPlxuICAgICAgICAgICAgPHN2Z1xuICAgICAgICAgICAgICBjbGFzcz1cImNxYS13LTIgY3FhLWgtMSBjcWEtYWJzb2x1dGUgY3FhLWxlZnQtWzRweF0gY3FhLXRvcC1bNnB4XVwiXG4gICAgICAgICAgICAgIHZpZXdCb3g9XCIwIDAgOCA0XCJcbiAgICAgICAgICAgICAgZmlsbD1cIm5vbmVcIlxuICAgICAgICAgICAgICB4bWxucz1cImh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnXCJcbiAgICAgICAgICAgID5cbiAgICAgICAgICAgICAgPHBhdGhcbiAgICAgICAgICAgICAgICBkPVwiTTAgMEw0IDRMOCAwXCJcbiAgICAgICAgICAgICAgICBzdHJva2U9XCIjMEIwQjBDXCJcbiAgICAgICAgICAgICAgICBzdHJva2Utd2lkdGg9XCIxLjMzXCJcbiAgICAgICAgICAgICAgICBzdHJva2UtbGluZWNhcD1cInJvdW5kXCJcbiAgICAgICAgICAgICAgICBzdHJva2UtbGluZWpvaW49XCJyb3VuZFwiXG4gICAgICAgICAgICAgIC8+XG4gICAgICAgICAgICA8L3N2Zz5cbiAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgPC9zcGFuPlxuICAgICAgICA8L2NxYS1idXR0b24+XG4gICAgICAgIDxjcWEtY29sdW1uLXZpc2liaWxpdHlcbiAgICAgICAgICAqbmdJZj1cInNob3dTZXR0aW5nc0J1dHRvblwiXG4gICAgICAgICAgW2NvbHVtbnNdPVwidmlzaWJpbGl0eUNvbHVtbnNcIlxuICAgICAgICAgIFtjb2x1bW5WaXNpYmlsaXR5XT1cImNvbHVtblZpc2liaWxpdHlcIlxuICAgICAgICAgIFtzZWxlY3RlZEF1dG9SZWZyZXNoSW50ZXJ2YWxdPVwic2VsZWN0ZWRBdXRvUmVmcmVzaEludGVydmFsXCJcbiAgICAgICAgICAoY29sdW1uVmlzaWJpbGl0eUNoYW5nZSk9XCJvbkNvbHVtblZpc2liaWxpdHlDaGFuZ2UoJGV2ZW50KVwiXG4gICAgICAgICAgKGF1dG9SZWZyZXNoQ2hhbmdlKT1cIm9uQXV0b1JlZnJlc2hDaGFuZ2UoJGV2ZW50KVwiXG4gICAgICAgID48L2NxYS1jb2x1bW4tdmlzaWJpbGl0eT5cbiAgICAgICAgPGNxYS1idXR0b25cbiAgICAgICAgICAqbmdJZj1cInNob3dBdXRvUmVmcmVzaEJ1dHRvblwiXG4gICAgICAgICAgdmFyaWFudD1cImdyZXktc29saWRcIlxuICAgICAgICAgIGljb249XCJyZWZyZXNoXCJcbiAgICAgICAgICAoY2xpY2tlZCk9XCJoYW5kbGVSZWZyZXNoQ2xpY2soKVwiXG4gICAgICAgICAgW3Rvb2x0aXBdPVwiJ1JlZnJlc2gnXCJcbiAgICAgICAgICB0b29sdGlwUG9zaXRpb249XCJiZWxvd1wiXG4gICAgICAgICAgW2Rpc2FibGVkXT1cImlzUmVvcmRlcmluZ1wiXG4gICAgICAgID48L2NxYS1idXR0b24+XG4gICAgICAgIDxuZy1jb250YWluZXIgKm5nRm9yPVwibGV0IGJ1dHRvblRlbXBsYXRlIG9mIG90aGVyQnV0dG9uczsgdHJhY2tCeTogdHJhY2tCeVRlbXBsYXRlUmVmXCI+XG4gICAgICAgICAgPG5nLWNvbnRhaW5lciAqbmdUZW1wbGF0ZU91dGxldD1cImJ1dHRvblRlbXBsYXRlXCI+PC9uZy1jb250YWluZXI+XG4gICAgICAgIDwvbmctY29udGFpbmVyPlxuICAgICAgICA8Y3FhLXNlZ21lbnQtY29udHJvbFxuICAgICAgICAgICpuZ0lmPVwic2hvd1ZpZXdNb2RlVG9nZ2xlXCJcbiAgICAgICAgICBzaXplPVwibGdcIlxuICAgICAgICAgIFtzZWdtZW50c109XCJ2aWV3TW9kZVNlZ21lbnRzXCJcbiAgICAgICAgICBbdmFsdWVdPVwidmlld01vZGVcIlxuICAgICAgICAgICh2YWx1ZUNoYW5nZSk9XCJvblZpZXdNb2RlQ2hhbmdlKCRldmVudClcIlxuICAgICAgICA+PC9jcWEtc2VnbWVudC1jb250cm9sPlxuICAgICAgICA8Y3FhLWJ1dHRvblxuICAgICAgICAgICpuZ0lmPVwic2hvd1Jlb3JkZXJCdXR0b24gJiYgIWlzUmVvcmRlcmluZ1wiXG4gICAgICAgICAgdmFyaWFudD1cIm91dGxpbmVkXCJcbiAgICAgICAgICBpY29uPVwiZHJhZ19pbmRpY2F0b3JcIlxuICAgICAgICAgIFt0ZXh0XT1cInJlb3JkZXJMYWJlbHMucmVvcmRlckJ1dHRvblwiXG4gICAgICAgICAgW2Rpc2FibGVkXT1cIiFwYWdlZFJvd3MgfHwgcGFnZWRSb3dzLmxlbmd0aCA9PT0gMCB8fCBpc1RhYmxlTG9hZGluZyB8fCBpc1RhYmxlRGF0YUxvYWRpbmdcIlxuICAgICAgICAgIChjbGlja2VkKT1cInN0YXJ0UmVvcmRlcigpXCJcbiAgICAgICAgPjwvY3FhLWJ1dHRvbj5cbiAgICAgICAgPG5nLWNvbnRhaW5lciAqbmdJZj1cInNob3dSZW9yZGVyQnV0dG9uICYmIGlzUmVvcmRlcmluZ1wiPlxuICAgICAgICAgIDxjcWEtYnV0dG9uXG4gICAgICAgICAgICB2YXJpYW50PVwib3V0bGluZWRcIlxuICAgICAgICAgICAgW3RleHRdPVwicmVvcmRlckxhYmVscy5jYW5jZWxCdXR0b25cIlxuICAgICAgICAgICAgW2Rpc2FibGVkXT1cInJlb3JkZXJTYXZpbmdcIlxuICAgICAgICAgICAgKGNsaWNrZWQpPVwiY2FuY2VsUmVvcmRlcigpXCJcbiAgICAgICAgICA+PC9jcWEtYnV0dG9uPlxuICAgICAgICAgIDxjcWEtYnV0dG9uXG4gICAgICAgICAgICB2YXJpYW50PVwiZmlsbGVkXCJcbiAgICAgICAgICAgIFtpY29uXT1cInJlb3JkZXJTYXZpbmcgPyAnaG91cmdsYXNzX2VtcHR5JyA6ICcnXCJcbiAgICAgICAgICAgIFt0ZXh0XT1cInJlb3JkZXJTYXZpbmcgPyByZW9yZGVyTGFiZWxzLnNhdmluZ0J1dHRvbiA6IHJlb3JkZXJMYWJlbHMuZG9uZUJ1dHRvblwiXG4gICAgICAgICAgICBbZGlzYWJsZWRdPVwicmVvcmRlclNhdmluZ1wiXG4gICAgICAgICAgICAoY2xpY2tlZCk9XCJzYXZlUmVvcmRlcigpXCJcbiAgICAgICAgICA+PC9jcWEtYnV0dG9uPlxuICAgICAgICA8L25nLWNvbnRhaW5lcj5cbiAgICAgIDwvZGl2PlxuICAgIDwvZGl2PlxuXG4gICAgPCEtLSBSZW9yZGVyIG1vZGUgYmFubmVyIC0tPlxuICAgIDxkaXYgKm5nSWY9XCJpc1Jlb3JkZXJpbmdcIiBjbGFzcz1cImNxYS1mbGV4IGNxYS1pdGVtcy1jZW50ZXIgY3FhLWdhcC0yIGNxYS1tYi0zIGNxYS1weC0zIGNxYS1weS0yIGNxYS1yb3VuZGVkLW1kIGNxYS1iZy1bI0ZGRkJFQl0gY3FhLWJvcmRlciBjcWEtYm9yZGVyLVsjRkRFNjhBXVwiPlxuICAgICAgPHN2ZyB3aWR0aD1cIjE2XCIgaGVpZ2h0PVwiMTZcIiB2aWV3Qm94PVwiMCAwIDE2IDE2XCIgZmlsbD1cIm5vbmVcIiB4bWxucz1cImh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnXCIgYXJpYS1oaWRkZW49XCJ0cnVlXCI+XG4gICAgICAgIDxjaXJjbGUgY3g9XCIzXCIgY3k9XCIzXCIgcj1cIjEuNVwiIGZpbGw9XCIjOTI0MDBFXCI+PC9jaXJjbGU+XG4gICAgICAgIDxjaXJjbGUgY3g9XCI4XCIgY3k9XCIzXCIgcj1cIjEuNVwiIGZpbGw9XCIjOTI0MDBFXCI+PC9jaXJjbGU+XG4gICAgICAgIDxjaXJjbGUgY3g9XCIxM1wiIGN5PVwiM1wiIHI9XCIxLjVcIiBmaWxsPVwiIzkyNDAwRVwiPjwvY2lyY2xlPlxuICAgICAgICA8Y2lyY2xlIGN4PVwiM1wiIGN5PVwiOFwiIHI9XCIxLjVcIiBmaWxsPVwiIzkyNDAwRVwiPjwvY2lyY2xlPlxuICAgICAgICA8Y2lyY2xlIGN4PVwiOFwiIGN5PVwiOFwiIHI9XCIxLjVcIiBmaWxsPVwiIzkyNDAwRVwiPjwvY2lyY2xlPlxuICAgICAgICA8Y2lyY2xlIGN4PVwiMTNcIiBjeT1cIjhcIiByPVwiMS41XCIgZmlsbD1cIiM5MjQwMEVcIj48L2NpcmNsZT5cbiAgICAgICAgPGNpcmNsZSBjeD1cIjNcIiBjeT1cIjEzXCIgcj1cIjEuNVwiIGZpbGw9XCIjOTI0MDBFXCI+PC9jaXJjbGU+XG4gICAgICAgIDxjaXJjbGUgY3g9XCI4XCIgY3k9XCIxM1wiIHI9XCIxLjVcIiBmaWxsPVwiIzkyNDAwRVwiPjwvY2lyY2xlPlxuICAgICAgICA8Y2lyY2xlIGN4PVwiMTNcIiBjeT1cIjEzXCIgcj1cIjEuNVwiIGZpbGw9XCIjOTI0MDBFXCI+PC9jaXJjbGU+XG4gICAgICA8L3N2Zz5cbiAgICAgIDxzcGFuIGNsYXNzPVwiY3FhLXRleHQtc20gY3FhLWZvbnQtc2VtaWJvbGQgY3FhLXRleHQtWyM5MjQwMEVdXCI+e3sgcmVvcmRlckxhYmVscy5iYW5uZXJUaXRsZSB9fTwvc3Bhbj5cbiAgICAgIDxzcGFuIGNsYXNzPVwiY3FhLXRleHQtc20gY3FhLXRleHQtWyM5MjQwMEVdXCI+e3sgcmVvcmRlckxhYmVscy5iYW5uZXJEZXNjcmlwdGlvbiB9fTwvc3Bhbj5cbiAgICA8L2Rpdj5cblxuICAgIDxjcWEtc2VsZWN0ZWQtZmlsdGVyc1xuICAgICAgW2ZpbHRlckFwcGxpZWRdPVwiZmlsdGVyQXBwbGllZFwiXG4gICAgICBbY2hpcHNdPVwiY2hpcHNcIlxuICAgICAgKHJlbW92ZUNoaXApPVwib25SZW1vdmVDaGlwKCRldmVudClcIlxuICAgICAgKGNsZWFyQWxsKT1cIm9uQ2xlYXJBbGxDaGlwcygpXCJcbiAgICAgIChvbkNsZWFyQWxsKT1cIm9uQ2xlYXJBbGwuZW1pdCgpXCJcbiAgICA+XG4gICAgPC9jcWEtc2VsZWN0ZWQtZmlsdGVycz5cblxuICAgIDxjcWEtZHluYW1pYy1maWx0ZXJcbiAgICAgICpuZ0lmPVwic2hvd0ZpbHRlclBhbmVsXCJcbiAgICAgIFtjb25maWddPVwiZmlsdGVyQ29uZmlnXCJcbiAgICAgIFttb2RlbF09XCJmaWx0ZXJNb2RlbFwiXG4gICAgICBbc2hvd0ZpbHRlclBhbmVsXT1cInNob3dGaWx0ZXJQYW5lbFwiXG4gICAgICAoZmlsdGVyc0NoYW5nZWQpPVwib25GaWx0ZXJzQ2hhbmdlZCgkZXZlbnQpXCJcbiAgICAgIChmaWx0ZXJzQXBwbGllZCk9XCJvbkZpbHRlcnNBcHBsaWVkKCRldmVudClcIlxuICAgICAgKG9uQXBwbHlGaWx0ZXJDbGljayk9XCJvbkFwcGx5RmlsdGVyQ2xpY2suZW1pdCgkZXZlbnQpXCJcbiAgICAgIChvblJlc2V0RmlsdGVyQ2xpY2spPVwiaGFuZGxlUmVzZXRGaWx0ZXJDbGljaygpXCJcbiAgICA+XG4gICAgPC9jcWEtZHluYW1pYy1maWx0ZXI+XG5cbiAgICA8ZGl2IGNsYXNzPVwiY3FhLWZsZXggY3FhLWl0ZW1zLXN0cmV0Y2ggY3FhLWdhcC0zIGNxYS1taW4taC0wXCI+XG4gICAgICA8IS0tIFNpZGViYXIgKG9ubHkgc2hvd24gaW4gbW9kdWxhciB2aWV3KSAtLT5cbiAgICAgIDxjcWEtZm9sZGVyLXNpZGViYXJcbiAgICAgICAgKm5nSWY9XCJpc01vZHVsYXJWaWV3ICYmIG1vZHVsYXJDb25maWcuc2hvd1NpZGViYXJcIlxuICAgICAgICBbZm9sZGVyc109XCJmb2xkZXJzXCJcbiAgICAgICAgW3NlbGVjdGVkRm9sZGVySWRdPVwic2VsZWN0ZWRGb2xkZXJJZFwiXG4gICAgICAgIFtleHBhbmRlZEZvbGRlcklkc109XCJleHBhbmRlZEZvbGRlcklkc1wiXG4gICAgICAgIFt1bm9yZ2FuaXNlZENvdW50XT1cInVub3JnYW5pc2VkQ291bnRcIlxuICAgICAgICBbYWxsb3dDcmVhdGVdPVwibW9kdWxhckNvbmZpZy5hbGxvd0NyZWF0ZUZvbGRlclwiXG4gICAgICAgIFthbGxvd1JlbmFtZV09XCJtb2R1bGFyQ29uZmlnLmFsbG93UmVuYW1lRm9sZGVyXCJcbiAgICAgICAgW2FsbG93RGVsZXRlXT1cIm1vZHVsYXJDb25maWcuYWxsb3dEZWxldGVGb2xkZXJcIlxuICAgICAgICBbYWxsb3dEcm9wXT1cIm1vZHVsYXJDb25maWcuYWxsb3dUZXN0RHJhZ0Ryb3BcIlxuICAgICAgICBbc2hvd0NvdW50c109XCJtb2R1bGFyQ29uZmlnLnNob3dDb3VudHNcIlxuICAgICAgICBbY29sbGFwc2VkXT1cInNpZGViYXJDb2xsYXBzZWRcIlxuICAgICAgICBbbGFiZWxzXT1cIm1vZHVsYXJMYWJlbHNcIlxuICAgICAgICAoZm9sZGVyU2VsZWN0ZWQpPVwib25Gb2xkZXJTZWxlY3RlZCgkZXZlbnQpXCJcbiAgICAgICAgKGZvbGRlckV4cGFuc2lvblRvZ2dsZWQpPVwib25Gb2xkZXJFeHBhbnNpb25Ub2dnbGVkKCRldmVudClcIlxuICAgICAgICAoZm9sZGVyQ3JlYXRlZCk9XCJvbkZvbGRlckNyZWF0ZWQoJGV2ZW50KVwiXG4gICAgICAgIChmb2xkZXJDcmVhdGVSZXF1ZXN0ZWQpPVwib25Gb2xkZXJDcmVhdGVSZXF1ZXN0ZWQoJGV2ZW50KVwiXG4gICAgICAgIChmb2xkZXJSZW5hbWVkKT1cIm9uRm9sZGVyUmVuYW1lZCgkZXZlbnQpXCJcbiAgICAgICAgKGZvbGRlckRlbGV0ZWQpPVwib25Gb2xkZXJEZWxldGVkKCRldmVudClcIlxuICAgICAgICAoZm9sZGVyTW92ZVJlcXVlc3RlZCk9XCJvbkZvbGRlck1vdmVSZXF1ZXN0ZWQoJGV2ZW50KVwiXG4gICAgICAgIChmb2xkZXJEdXBsaWNhdGVSZXF1ZXN0ZWQpPVwib25Gb2xkZXJEdXBsaWNhdGVSZXF1ZXN0ZWQoJGV2ZW50KVwiXG4gICAgICAgICh0ZXN0c0Ryb3BwZWQpPVwib25UZXN0c0Ryb3BwZWQoJGV2ZW50KVwiXG4gICAgICAgIChmb2xkZXJEcm9wcGVkKT1cIm9uRm9sZGVyRHJvcHBlZCgkZXZlbnQpXCJcbiAgICAgICAgKGNvbGxhcHNlZENoYW5nZSk9XCJvblNpZGViYXJDb2xsYXBzZWRDaGFuZ2UoJGV2ZW50KVwiXG4gICAgICA+PC9jcWEtZm9sZGVyLXNpZGViYXI+XG5cbiAgICAgIDwhLS0gUmlnaHQgcGFuZSAtLT5cbiAgICAgIDxkaXYgY2xhc3M9XCJjcWEtZmxleC0xIGNxYS1mbGV4IGNxYS1mbGV4LWNvbCBjcWEtbWluLXctMFwiPlxuICAgICAgICA8IS0tIEJyZWFkY3J1bWIgKG1vZHVsYXIgdmlldywgZm9sZGVyIGRyaWxsZWQtaW4pIC0tPlxuICAgICAgICA8bmF2XG4gICAgICAgICAgKm5nSWY9XCJpc01vZHVsYXJWaWV3ICYmIG1vZHVsYXJDb25maWcuc2hvd0JyZWFkY3J1bWIgJiYgIWlzUm9vdFZpZXdcIlxuICAgICAgICAgIGFyaWEtbGFiZWw9XCJGb2xkZXIgcGF0aFwiXG4gICAgICAgICAgY2xhc3M9XCJjcWEtZmxleCBjcWEtaXRlbXMtY2VudGVyIGNxYS1nYXAtMSBjcWEtdGV4dC1zbSBjcWEtdGV4dC1uZXV0cmFsLTYwMCBjcWEtbWItM1wiXG4gICAgICAgID5cbiAgICAgICAgICA8YnV0dG9uIHR5cGU9XCJidXR0b25cIiBjbGFzcz1cImhvdmVyOmNxYS10ZXh0LWluZGlnby02MDBcIiAoY2xpY2spPVwib25Gb2xkZXJTZWxlY3RlZChudWxsKVwiPlxuICAgICAgICAgICAgPG1hdC1pY29uIGNsYXNzPVwiY3FhLWFsaWduLW1pZGRsZVwiIHN0eWxlPVwiZm9udC1zaXplOjE2cHg7d2lkdGg6MTZweDtoZWlnaHQ6MTZweFwiPmZvbGRlcl9vcGVuPC9tYXQtaWNvbj5cbiAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwiY3FhLWFsaWduLW1pZGRsZSBjcWEtbWwtMVwiPnt7IG1vZHVsYXJMYWJlbHMuYWxsRm9sZGVycyB9fTwvc3Bhbj5cbiAgICAgICAgICA8L2J1dHRvbj5cbiAgICAgICAgICA8bmctY29udGFpbmVyICpuZ0Zvcj1cImxldCBjcnVtYiBvZiBicmVhZGNydW1iVHJhaWw7IGxldCBsYXN0ID0gbGFzdFwiPlxuICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJjcWEtdGV4dC1uZXV0cmFsLTQwMFwiPi88L3NwYW4+XG4gICAgICAgICAgICA8YnV0dG9uXG4gICAgICAgICAgICAgIHR5cGU9XCJidXR0b25cIlxuICAgICAgICAgICAgICBjbGFzcz1cImhvdmVyOmNxYS10ZXh0LWluZGlnby02MDBcIlxuICAgICAgICAgICAgICBbY2xhc3MuY3FhLXRleHQtbmV1dHJhbC05MDBdPVwibGFzdFwiXG4gICAgICAgICAgICAgIFtjbGFzcy5jcWEtZm9udC1zZW1pYm9sZF09XCJsYXN0XCJcbiAgICAgICAgICAgICAgW2Rpc2FibGVkXT1cImxhc3RcIlxuICAgICAgICAgICAgICAoY2xpY2spPVwiIWxhc3QgJiYgb25Gb2xkZXJTZWxlY3RlZChjcnVtYi5pZClcIlxuICAgICAgICAgICAgPnt7IGNydW1iLm5hbWUgfX08L2J1dHRvbj5cbiAgICAgICAgICA8L25nLWNvbnRhaW5lcj5cbiAgICAgICAgPC9uYXY+XG5cbiAgICAgICAgPCEtLSBGb2xkZXIgZ3JpZDogbW9kdWxhciArIHJvb3QgdmlldyAtLT5cbiAgICAgICAgPHNlY3Rpb25cbiAgICAgICAgICAqbmdJZj1cImlzTW9kdWxhclZpZXcgJiYgaXNSb290VmlldyAmJiBtb2R1bGFyQ29uZmlnLnNob3dGb2xkZXJHcmlkICYmIHJvb3RGb2xkZXJUaWxlcy5sZW5ndGhcIlxuICAgICAgICAgIGNsYXNzPVwiY3FhLW1iLTRcIlxuICAgICAgICA+XG4gICAgICAgICAgPGRpdiBjbGFzcz1cImNxYS1mbGV4IGNxYS1pdGVtcy1jZW50ZXIgY3FhLWdhcC0yIGNxYS1tYi0yXCI+XG4gICAgICAgICAgICA8bWF0LWljb24gY2xhc3M9XCJjcWEtdGV4dC1uZXV0cmFsLTYwMFwiIHN0eWxlPVwiZm9udC1zaXplOjE2cHg7d2lkdGg6MTZweDtoZWlnaHQ6MTZweFwiPmZvbGRlcjwvbWF0LWljb24+XG4gICAgICAgICAgICA8aDMgY2xhc3M9XCJjcWEtdGV4dC1zbSBjcWEtZm9udC1zZW1pYm9sZCBjcWEtdGV4dC1uZXV0cmFsLTgwMFwiPnt7IG1vZHVsYXJMYWJlbHMub3JnYW5pc2VkIH19PC9oMz5cbiAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwiY3FhLXRleHQteHMgY3FhLXRleHQtbmV1dHJhbC01MDBcIj5cbiAgICAgICAgICAgICAge3sgcm9vdEZvbGRlclRpbGVzLmxlbmd0aCA9PT0gMSA/IG1vZHVsYXJMYWJlbHMuZm9sZGVyc0NvdW50U2luZ3VsYXIgOiBtb2R1bGFyTGFiZWxzLmZvbGRlcnNDb3VudFBsdXJhbC5yZXBsYWNlKCd7bn0nLCAnJyArIHJvb3RGb2xkZXJUaWxlcy5sZW5ndGgpIH19XG4gICAgICAgICAgICA8L3NwYW4+XG4gICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgPGRpdiBjbGFzcz1cImNxYS1mbGV4IGNxYS1mbGV4LW5vd3JhcCBjcWEtZ2FwLTMgY3FhLW92ZXJmbG93LXgtYXV0byBjcWEtc2Nyb2xsYmFyLXRoaW4gY3FhLXBiLTJcIj5cbiAgICAgICAgICAgIDxidXR0b25cbiAgICAgICAgICAgICAgKm5nRm9yPVwibGV0IGYgb2Ygcm9vdEZvbGRlclRpbGVzXCJcbiAgICAgICAgICAgICAgdHlwZT1cImJ1dHRvblwiXG4gICAgICAgICAgICAgIFtjcWFGb2xkZXJEcm9wXT1cImYuaWRcIlxuICAgICAgICAgICAgICBbZHJvcEVuYWJsZWRdPVwibW9kdWxhckNvbmZpZy5hbGxvd1Rlc3REcmFnRHJvcFwiXG4gICAgICAgICAgICAgICh0ZXN0c0Ryb3BwZWQpPVwib25UZXN0c0Ryb3BwZWQoJGV2ZW50KVwiXG4gICAgICAgICAgICAgIChjbGljayk9XCJvbkZvbGRlclNlbGVjdGVkKGYuaWQpXCJcbiAgICAgICAgICAgICAgY2xhc3M9XCJjcWEtc2hyaW5rLTAgY3FhLXctWzI0MHB4XSBjcWEtZmxleCBjcWEtaXRlbXMtY2VudGVyIGNxYS1qdXN0aWZ5LWJldHdlZW4gY3FhLWdhcC0zIGNxYS10ZXh0LWxlZnQgY3FhLXAtMyBjcWEtcm91bmRlZC1bMTBweF0gY3FhLWJvcmRlci1zb2xpZCBjcWEtYm9yZGVyLVswLjVweF0gY3FhLWJvcmRlci1bI0UyRTJFM10gY3FhLWJnLXdoaXRlIGhvdmVyOmNxYS1ib3JkZXItWyNEOEQ5RkNdIGhvdmVyOmNxYS1zaGFkb3ctc20gY3FhLXRyYW5zaXRpb24tY29sb3JzXCJcbiAgICAgICAgICAgID5cbiAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cImNxYS1mbGV4IGNxYS1pdGVtcy1jZW50ZXIgY3FhLWdhcC0zIGNxYS1taW4tdy0wXCI+XG4gICAgICAgICAgICAgICAgPG5nLWNvbnRhaW5lciAqbmdUZW1wbGF0ZU91dGxldD1cImZvbGRlckljb25DaGlwXCI+PC9uZy1jb250YWluZXI+XG4gICAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cImNxYS1mbGV4IGNxYS1mbGV4LWNvbCBjcWEtbWluLXctMFwiPlxuICAgICAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJjcWEtdGV4dC1iYXNlIGNxYS1mb250LXNlbWlib2xkIGNxYS10ZXh0LW5ldXRyYWwtOTAwIGNxYS10cnVuY2F0ZSBjcWEtbGVhZGluZy10aWdodFwiPnt7IGYubmFtZSB9fTwvc3Bhbj5cbiAgICAgICAgICAgICAgICAgIDxzcGFuICpuZ0lmPVwibW9kdWxhckNvbmZpZy5zaG93Q291bnRzXCIgY2xhc3M9XCJjcWEtdGV4dC1zbSBjcWEtdGV4dC1uZXV0cmFsLTUwMCBjcWEtdHJ1bmNhdGVcIj5cbiAgICAgICAgICAgICAgICAgICAge3sgKGYuY291bnQgPz8gMCkgPT09IDEgPyBtb2R1bGFyTGFiZWxzLnRlc3RzQ291bnRTaW5ndWxhciA6IG1vZHVsYXJMYWJlbHMudGVzdHNDb3VudFBsdXJhbC5yZXBsYWNlKCd7bn0nLCAnJyArIChmLmNvdW50ID8/IDApKSB9fTxuZy1jb250YWluZXIgKm5nSWY9XCJmLmNoaWxkcmVuPy5sZW5ndGhcIj4gwrcge3sgZi5jaGlsZHJlbiEubGVuZ3RoID09PSAxID8gbW9kdWxhckxhYmVscy5vbmVTdWJmb2xkZXIgOiBtb2R1bGFyTGFiZWxzLnN1YmZvbGRlcnNDb3VudC5yZXBsYWNlKCd7bn0nLCAnJyArIGYuY2hpbGRyZW4hLmxlbmd0aCkgfX08L25nLWNvbnRhaW5lcj5cbiAgICAgICAgICAgICAgICAgIDwvc3Bhbj5cbiAgICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICAgIDxtYXQtaWNvbiBjbGFzcz1cImNxYS10ZXh0LW5ldXRyYWwtNDAwIGNxYS1zaHJpbmstMFwiIHN0eWxlPVwiZm9udC1zaXplOjIwcHg7d2lkdGg6MjBweDtoZWlnaHQ6MjBweFwiPmNoZXZyb25fcmlnaHQ8L21hdC1pY29uPlxuICAgICAgICAgICAgPC9idXR0b24+XG5cbiAgICAgICAgICAgIDwhLS0gXCIrIE5ldyBmb2xkZXJcIiB0aWxlIC0tPlxuICAgICAgICAgICAgPGJ1dHRvblxuICAgICAgICAgICAgICAqbmdJZj1cIm1vZHVsYXJDb25maWcuYWxsb3dDcmVhdGVGb2xkZXJcIlxuICAgICAgICAgICAgICB0eXBlPVwiYnV0dG9uXCJcbiAgICAgICAgICAgICAgKGNsaWNrKT1cIm9uRm9sZGVyQ3JlYXRlUmVxdWVzdGVkKHsgcGFyZW50SWQ6IG51bGwgfSlcIlxuICAgICAgICAgICAgICBjbGFzcz1cImNxYS1zaHJpbmstMCBjcWEtdy1bMjQwcHhdIGNxYS1mbGV4IGNxYS1pdGVtcy1jZW50ZXIgY3FhLWdhcC0zIGNxYS10ZXh0LWxlZnQgY3FhLXAtMyBjcWEtcm91bmRlZC1bMTBweF0gY3FhLWJvcmRlci1zb2xpZCBjcWEtYm9yZGVyLVswLjVweF0gY3FhLWJvcmRlci1bI0UyRTJFM10gY3FhLWJnLW5ldXRyYWwtNTAgaG92ZXI6Y3FhLWJvcmRlci1bI0Q4RDlGQ10gaG92ZXI6Y3FhLWJnLXdoaXRlIGNxYS10cmFuc2l0aW9uLWNvbG9yc1wiXG4gICAgICAgICAgICA+XG4gICAgICAgICAgICAgIDxuZy1jb250YWluZXIgKm5nVGVtcGxhdGVPdXRsZXQ9XCJhZGRJY29uQ2hpcFwiPjwvbmctY29udGFpbmVyPlxuICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwiY3FhLWZsZXggY3FhLWZsZXgtY29sIGNxYS1taW4tdy0wXCI+XG4gICAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJjcWEtdGV4dC1iYXNlIGNxYS1mb250LXNlbWlib2xkIGNxYS10ZXh0LW5ldXRyYWwtNjAwIGNxYS10cnVuY2F0ZSBjcWEtbGVhZGluZy10aWdodFwiPnt7IG1vZHVsYXJMYWJlbHMubmV3Rm9sZGVyIH19PC9zcGFuPlxuICAgICAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwiY3FhLXRleHQtc20gY3FhLXRleHQtbmV1dHJhbC00MDBcIj57eyBtb2R1bGFyTGFiZWxzLnRlc3RzQ291bnRQbHVyYWwucmVwbGFjZSgne259JywgJzAnKSB9fTwvc3Bhbj5cbiAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICA8L2J1dHRvbj5cbiAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgPC9zZWN0aW9uPlxuXG4gICAgICAgIDwhLS0gU3ViZm9sZGVyIHNlY3Rpb246IG1vZHVsYXIgKyBmb2xkZXIgdmlldy4gU2hvd24gd2hlbmV2ZXIgZHJpbGxlZCBpbiAoZXZlbiBpZiBubyBzdWJmb2xkZXJzLCBzbyB0aGUgXCIrIE5ldyBmb2xkZXJcIiB0aWxlIHJlbWFpbnMgcmVhY2hhYmxlKS4gLS0+XG4gICAgICAgIDxzZWN0aW9uXG4gICAgICAgICAgKm5nSWY9XCJpc01vZHVsYXJWaWV3ICYmICFpc1Jvb3RWaWV3ICYmIG1vZHVsYXJDb25maWcuc2hvd1N1YmZvbGRlclNlY3Rpb24gJiYgc3ViZm9sZGVyVGlsZXMubGVuZ3RoXCJcbiAgICAgICAgICBjbGFzcz1cImNxYS1tYi00XCJcbiAgICAgICAgPlxuICAgICAgICAgIDxkaXYgKm5nSWY9XCJzdWJmb2xkZXJUaWxlcy5sZW5ndGggfHwgbW9kdWxhckNvbmZpZy5hbGxvd0NyZWF0ZUZvbGRlclwiIGNsYXNzPVwiY3FhLXRleHQtc20gY3FhLXRleHQtbmV1dHJhbC02MDAgY3FhLW1iLTJcIj5cbiAgICAgICAgICAgIHt7IG1vZHVsYXJMYWJlbHMuc3ViZm9sZGVyc0luIH19IHt7IGJyZWFkY3J1bWJUcmFpbC5sZW5ndGggPyBicmVhZGNydW1iVHJhaWxbYnJlYWRjcnVtYlRyYWlsLmxlbmd0aCAtIDFdLm5hbWUgOiAnJyB9fVxuICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgIDxkaXYgY2xhc3M9XCJjcWEtZmxleCBjcWEtZmxleC1ub3dyYXAgY3FhLWdhcC0zIGNxYS1vdmVyZmxvdy14LWF1dG8gY3FhLXNjcm9sbGJhci10aGluIGNxYS1wYi0yXCI+XG4gICAgICAgICAgICA8YnV0dG9uXG4gICAgICAgICAgICAgICpuZ0Zvcj1cImxldCBmIG9mIHN1YmZvbGRlclRpbGVzXCJcbiAgICAgICAgICAgICAgdHlwZT1cImJ1dHRvblwiXG4gICAgICAgICAgICAgIFtjcWFGb2xkZXJEcm9wXT1cImYuaWRcIlxuICAgICAgICAgICAgICBbZHJvcEVuYWJsZWRdPVwibW9kdWxhckNvbmZpZy5hbGxvd1Rlc3REcmFnRHJvcFwiXG4gICAgICAgICAgICAgICh0ZXN0c0Ryb3BwZWQpPVwib25UZXN0c0Ryb3BwZWQoJGV2ZW50KVwiXG4gICAgICAgICAgICAgIChjbGljayk9XCJvbkZvbGRlclNlbGVjdGVkKGYuaWQpXCJcbiAgICAgICAgICAgICAgY2xhc3M9XCJjcWEtc2hyaW5rLTAgY3FhLXctWzI0MHB4XSBjcWEtZmxleCBjcWEtaXRlbXMtY2VudGVyIGNxYS1qdXN0aWZ5LWJldHdlZW4gY3FhLWdhcC0zIGNxYS10ZXh0LWxlZnQgY3FhLXAtMyBjcWEtcm91bmRlZC1bMTBweF0gY3FhLWJvcmRlci1zb2xpZCBjcWEtYm9yZGVyLVswLjVweF0gY3FhLWJvcmRlci1bI0UyRTJFM10gY3FhLWJnLXdoaXRlIGhvdmVyOmNxYS1ib3JkZXItWyNEOEQ5RkNdIGhvdmVyOmNxYS1zaGFkb3ctc20gY3FhLXRyYW5zaXRpb24tY29sb3JzXCJcbiAgICAgICAgICAgID5cbiAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cImNxYS1mbGV4IGNxYS1pdGVtcy1jZW50ZXIgY3FhLWdhcC0zIGNxYS1taW4tdy0wXCI+XG4gICAgICAgICAgICAgICAgPG5nLWNvbnRhaW5lciAqbmdUZW1wbGF0ZU91dGxldD1cImZvbGRlckljb25DaGlwXCI+PC9uZy1jb250YWluZXI+XG4gICAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cImNxYS1mbGV4IGNxYS1mbGV4LWNvbCBjcWEtbWluLXctMFwiPlxuICAgICAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJjcWEtdGV4dC1iYXNlIGNxYS1mb250LXNlbWlib2xkIGNxYS10ZXh0LW5ldXRyYWwtOTAwIGNxYS10cnVuY2F0ZSBjcWEtbGVhZGluZy10aWdodFwiPnt7IGYubmFtZSB9fTwvc3Bhbj5cbiAgICAgICAgICAgICAgICAgIDxzcGFuICpuZ0lmPVwibW9kdWxhckNvbmZpZy5zaG93Q291bnRzXCIgY2xhc3M9XCJjcWEtdGV4dC1zbSBjcWEtdGV4dC1uZXV0cmFsLTUwMCBjcWEtdHJ1bmNhdGVcIj5cbiAgICAgICAgICAgICAgICAgICAge3sgKGYuY291bnQgPz8gMCkgPT09IDEgPyBtb2R1bGFyTGFiZWxzLnRlc3RzQ291bnRTaW5ndWxhciA6IG1vZHVsYXJMYWJlbHMudGVzdHNDb3VudFBsdXJhbC5yZXBsYWNlKCd7bn0nLCAnJyArIChmLmNvdW50ID8/IDApKSB9fVxuICAgICAgICAgICAgICAgICAgPC9zcGFuPlxuICAgICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgICAgPG1hdC1pY29uIGNsYXNzPVwiY3FhLXRleHQtbmV1dHJhbC00MDAgY3FhLXNocmluay0wXCIgc3R5bGU9XCJmb250LXNpemU6MjBweDt3aWR0aDoyMHB4O2hlaWdodDoyMHB4XCI+Y2hldnJvbl9yaWdodDwvbWF0LWljb24+XG4gICAgICAgICAgICA8L2J1dHRvbj5cblxuICAgICAgICAgICAgPCEtLSBcIisgTmV3IGZvbGRlclwiIHRpbGUgLS0+XG4gICAgICAgICAgICA8YnV0dG9uXG4gICAgICAgICAgICAgICpuZ0lmPVwibW9kdWxhckNvbmZpZy5hbGxvd0NyZWF0ZUZvbGRlclwiXG4gICAgICAgICAgICAgIHR5cGU9XCJidXR0b25cIlxuICAgICAgICAgICAgICAoY2xpY2spPVwib25Gb2xkZXJDcmVhdGVSZXF1ZXN0ZWQoeyBwYXJlbnRJZDogc2VsZWN0ZWRGb2xkZXJJZCB9KVwiXG4gICAgICAgICAgICAgIGNsYXNzPVwiY3FhLXNocmluay0wIGNxYS13LVsyNDBweF0gY3FhLWZsZXggY3FhLWl0ZW1zLWNlbnRlciBjcWEtZ2FwLTMgY3FhLXRleHQtbGVmdCBjcWEtcC0zIGNxYS1yb3VuZGVkLVsxMHB4XSBjcWEtYm9yZGVyLXNvbGlkIGNxYS1ib3JkZXItWzAuNXB4XSBjcWEtYm9yZGVyLVsjRTJFMkUzXSBjcWEtYmctbmV1dHJhbC01MCBob3ZlcjpjcWEtYm9yZGVyLVsjRDhEOUZDXSBob3ZlcjpjcWEtYmctd2hpdGUgY3FhLXRyYW5zaXRpb24tY29sb3JzXCJcbiAgICAgICAgICAgID5cbiAgICAgICAgICAgICAgPG5nLWNvbnRhaW5lciAqbmdUZW1wbGF0ZU91dGxldD1cImFkZEljb25DaGlwXCI+PC9uZy1jb250YWluZXI+XG4gICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJjcWEtZmxleCBjcWEtZmxleC1jb2wgY3FhLW1pbi13LTBcIj5cbiAgICAgICAgICAgICAgICA8c3BhbiBjbGFzcz1cImNxYS10ZXh0LWJhc2UgY3FhLWZvbnQtc2VtaWJvbGQgY3FhLXRleHQtbmV1dHJhbC02MDAgY3FhLXRydW5jYXRlIGNxYS1sZWFkaW5nLXRpZ2h0XCI+e3sgbW9kdWxhckxhYmVscy5uZXdGb2xkZXIgfX08L3NwYW4+XG4gICAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJjcWEtdGV4dC1zbSBjcWEtdGV4dC1uZXV0cmFsLTQwMFwiPnt7IG1vZHVsYXJMYWJlbHMudGVzdHNDb3VudFBsdXJhbC5yZXBsYWNlKCd7bn0nLCAnMCcpIH19PC9zcGFuPlxuICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgIDwvYnV0dG9uPlxuICAgICAgICAgIDwvZGl2PlxuICAgICAgICA8L3NlY3Rpb24+XG5cbiAgICAgICAgPCEtLSBGb2xkZXIgcGFuZWwgaGVhZGVyIGFib3ZlIHRoZSB0YWJsZTogXCJIb3RlbCBTZWFyY2ggKDMpXCIgKyBDbGVhciBmaWx0ZXIgLS0+XG4gICAgICAgIDxkaXZcbiAgICAgICAgICAqbmdJZj1cImlzTW9kdWxhclZpZXcgJiYgIWlzUm9vdFZpZXcgJiYgbW9kdWxhckNvbmZpZy5zaG93VW5vcmdhbmlzZWRTZWN0aW9uXCJcbiAgICAgICAgICBjbGFzcz1cImNxYS1mbGV4IGNxYS1tYi0xIGNxYS1pdGVtcy1jZW50ZXIgY3FhLWp1c3RpZnktYmV0d2VlbiBjcWEtcHgtNCBjcWEtcHktMyBjcWEtcm91bmRlZC10LWxnIGNxYS1iZy1pbmRpZ28tNTAgY3FhLWJvcmRlciBjcWEtYm9yZGVyLWluZGlnby0xMDBcIlxuICAgICAgICA+XG4gICAgICAgICAgPGRpdiBjbGFzcz1cImNxYS1mbGV4IGNxYS1pdGVtcy1jZW50ZXIgY3FhLWdhcC0yXCI+XG4gICAgICAgICAgICA8bWF0LWljb24gY2xhc3M9XCJjcWEtdGV4dC1pbmRpZ28tNTAwXCIgc3R5bGU9XCJmb250LXNpemU6MThweDt3aWR0aDoxOHB4O2hlaWdodDoxOHB4XCI+Zm9sZGVyX29wZW48L21hdC1pY29uPlxuICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJjcWEtdGV4dC1zbSBjcWEtZm9udC1zZW1pYm9sZCBjcWEtdGV4dC1pbmRpZ28tNzAwXCI+XG4gICAgICAgICAgICAgIHt7IGN1cnJlbnRGb2xkZXJOb2RlPy5uYW1lIH19ICh7eyBjdXJyZW50Rm9sZGVyRGlyZWN0Q291bnQgfX0pXG4gICAgICAgICAgICA8L3NwYW4+XG4gICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgPGJ1dHRvblxuICAgICAgICAgICAgdHlwZT1cImJ1dHRvblwiXG4gICAgICAgICAgICBjbGFzcz1cImNxYS1weC0zIGNxYS1weS0xIGNxYS10ZXh0LXhzIGNxYS1mb250LW1lZGl1bSBjcWEtdGV4dC1pbmRpZ28tNzAwIGNxYS1iZy13aGl0ZSBjcWEtYm9yZGVyIGNxYS1ib3JkZXItaW5kaWdvLTIwMCBjcWEtcm91bmRlZCBob3ZlcjpjcWEtYmctaW5kaWdvLTUwXCJcbiAgICAgICAgICAgIChjbGljayk9XCJvbkZvbGRlclNlbGVjdGVkKG51bGwpXCJcbiAgICAgICAgICA+e3sgbW9kdWxhckxhYmVscy5jbGVhckZpbHRlciB9fTwvYnV0dG9uPlxuICAgICAgICA8L2Rpdj5cblxuICAgICAgICA8IS0tIFVub3JnYW5pc2VkIHNlY3Rpb24gaGVhZGVyIGF0IHJvb3QgdmlldyAtLT5cbiAgICAgICAgPGRpdlxuICAgICAgICAgICpuZ0lmPVwiaXNNb2R1bGFyVmlldyAmJiBpc1Jvb3RWaWV3ICYmIG1vZHVsYXJDb25maWcuc2hvd1Vub3JnYW5pc2VkU2VjdGlvblwiXG4gICAgICAgICAgY2xhc3M9XCJjcWEtZmxleCBjcWEtaXRlbXMtY2VudGVyIGNxYS1nYXAtMiBjcWEtbWItMiBjcWEtbXQtMlwiXG4gICAgICAgID5cbiAgICAgICAgICA8bWF0LWljb24gY2xhc3M9XCJjcWEtdGV4dC1uZXV0cmFsLTYwMFwiIHN0eWxlPVwiZm9udC1zaXplOjE2cHg7d2lkdGg6MTZweDtoZWlnaHQ6MTZweFwiPmluYm94PC9tYXQtaWNvbj5cbiAgICAgICAgICA8aDMgY2xhc3M9XCJjcWEtdGV4dC1zbSBjcWEtZm9udC1zZW1pYm9sZCBjcWEtdGV4dC1uZXV0cmFsLTgwMFwiPnt7IG1vZHVsYXJMYWJlbHMudW5vcmdhbmlzZWQgfX08L2gzPlxuICAgICAgICAgIDxzcGFuIGNsYXNzPVwiY3FhLXRleHQteHMgY3FhLXRleHQtbmV1dHJhbC01MDBcIj5cbiAgICAgICAgICAgIHt7IHVub3JnYW5pc2VkQ291bnQgPT09IDEgPyBtb2R1bGFyTGFiZWxzLnRlc3RzQ291bnRTaW5ndWxhciA6IG1vZHVsYXJMYWJlbHMudGVzdHNDb3VudFBsdXJhbC5yZXBsYWNlKCd7bn0nLCAnJyArIHVub3JnYW5pc2VkQ291bnQpIH19XG4gICAgICAgICAgPC9zcGFuPlxuICAgICAgICA8L2Rpdj5cblxuICAgICAgICA8IS0tIFRhYmxlIC0tPlxuICAgICAgICA8ZGl2IGNsYXNzPVwiY3FhLXJvdW5kZWQtWzdweF0gY3FhLW92ZXJmbG93LWhpZGRlbiBjcWEtYm9yZGVyLXQgY3FhLWJvcmRlci1sIGNxYS1ib3JkZXItciBjcWEtYm9yZGVyLWdyZXktMjAwIGNxYS1yZWxhdGl2ZSBjcWEtb3ZlcmZsb3cteC1hdXRvXCI+XG4gICAgICAgICAgPG5nLWNvbnRhaW5lciAqbmdJZj1cIihpc1RhYmxlTG9hZGluZyB8fCBpc1RhYmxlRGF0YUxvYWRpbmcpIHx8ICghZWZmZWN0aXZlSXNFbXB0eVN0YXRlICYmIHBhZ2VkUm93cyAmJiBwYWdlZFJvd3MubGVuZ3RoID4gMCk7IGVsc2Ugc3RvcnlFbXB0eVRwbFwiPlxuICAgICAgICAgICAgPGFwcC1keW5hbWljLXRhYmxlXG4gICAgICAgICAgICAgIFtjb2x1bW5zXT1cImNvbXB1dGVkQ29sdW1uc1wiXG4gICAgICAgICAgICAgIFtkYXRhXT1cInBhZ2VkUm93c1wiXG4gICAgICAgICAgICAgIFtyb3dTZWxlY3RhYmxlXT1cInJvd1NlbGVjdGFibGVcIlxuICAgICAgICAgICAgICBbZW5hYmxlTG9jYWxTb3J0XT1cImVuYWJsZUxvY2FsU29ydCAmJiAhaXNSZW9yZGVyaW5nXCJcbiAgICAgICAgICAgICAgW2lzVGFibGVMb2FkaW5nXT1cImlzVGFibGVMb2FkaW5nXCJcbiAgICAgICAgICAgICAgW2lzVGFibGVEYXRhTG9hZGluZ109XCJpc1RhYmxlRGF0YUxvYWRpbmdcIlxuICAgICAgICAgICAgICBbY2VsbEpzb25QYXRoR2V0dGVyXT1cImNlbGxKc29uUGF0aEdldHRlclwiXG4gICAgICAgICAgICAgIFtvbkpzb25QYXRoQ29waWVkSGFuZGxlcl09XCJvbkpzb25QYXRoQ29waWVkSGFuZGxlclwiXG4gICAgICAgICAgICAgIFtlbmFibGVSb3dSZW9yZGVyXT1cImlzUmVvcmRlcmluZ1wiXG4gICAgICAgICAgICAgIChyb3dSZW9yZGVyKT1cIm9uUm93UmVvcmRlcigkZXZlbnQpXCJcbiAgICAgICAgICAgICAgKHNvcnRDaGFuZ2UpPVwic29ydENoYW5nZS5lbWl0KCRldmVudClcIj5cbiAgICAgICAgICAgICAgPG5nLXRlbXBsYXRlICNlbXB0eVRhYmxlVHBsPlxuICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJjcWEtZmxleCBjcWEtZmxleC1jb2wgY3FhLWl0ZW1zLWNlbnRlciBjcWEtanVzdGlmeS1jZW50ZXIgY3FhLXB5LThcIj5cbiAgICAgICAgICAgICAgICAgIDxpbWcgc3JjPVwiL2Fzc2V0cy9pbGx1c3RyYXRpb25zL2VtcHR5LXN0YXRlLnN2Z1wiIGFsdD1cIk5vIGRhdGFcIiBjbGFzcz1cImNxYS13LTMyIGNxYS1oLTMyIGNxYS1tYi00XCIgLz5cbiAgICAgICAgICAgICAgICAgIDxoMyBjbGFzcz1cImNxYS10ZXh0LWxnIGNxYS1mb250LXNlbWlib2xkIGNxYS1tYi0yXCI+Tm8gdGVzdCBjYXNlczwvaDM+XG4gICAgICAgICAgICAgICAgICA8cCBjbGFzcz1cImNxYS10ZXh0LXNtIGNxYS10ZXh0LW5ldXRyYWwtNTAwIGNxYS1tYi00XCI+VHJ5IGFkanVzdGluZyBmaWx0ZXJzIG9yIGNyZWF0ZSBhIG5ldyB0ZXN0IGNhc2UuPC9wPlxuICAgICAgICAgICAgICAgICAgPGNxYS1idXR0b24gdmFyaWFudD1cImZpbGxlZFwiIChjbGlja2VkKT1cInRvZ2dsZUZpbHRlcigpXCI+U2hvdyBGaWx0ZXJzPC9jcWEtYnV0dG9uPlxuICAgICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgICA8L25nLXRlbXBsYXRlPlxuICAgICAgICAgICAgPC9hcHAtZHluYW1pYy10YWJsZT5cbiAgICAgICAgICA8L25nLWNvbnRhaW5lcj5cblxuICAgICAgICAgIDxuZy10ZW1wbGF0ZSAjc3RvcnlFbXB0eVRwbD5cbiAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJjcWEtcC02IGNxYS1mbGV4IGNxYS1mbGV4LWNvbCBjcWEtaXRlbXMtY2VudGVyIGNxYS1qdXN0aWZ5LWNlbnRlclwiPlxuICAgICAgICAgICAgICA8Y3FhLWVtcHR5LXN0YXRlXG4gICAgICAgICAgICAgICAgKm5nSWY9XCJlZmZlY3RpdmVJc0VtcHR5U3RhdGVcIlxuICAgICAgICAgICAgICAgIFt0aXRsZV09XCJlZmZlY3RpdmVFbXB0eVN0YXRlQ29uZmlnLnRpdGxlXCJcbiAgICAgICAgICAgICAgICBbZGVzY3JpcHRpb25dPVwiZWZmZWN0aXZlRW1wdHlTdGF0ZUNvbmZpZy5kZXNjcmlwdGlvblwiXG4gICAgICAgICAgICAgICAgW2ltYWdlVXJsXT1cImVmZmVjdGl2ZUVtcHR5U3RhdGVDb25maWcuaW1hZ2VVcmxcIlxuICAgICAgICAgICAgICAgIFthY3Rpb25zXT1cImVmZmVjdGl2ZUVtcHR5U3RhdGVDb25maWcuYWN0aW9uc1wiXG4gICAgICAgICAgICAgICAgKGFjdGlvbkNsaWNrKT1cIm9uRW1wdHlBY3Rpb24oJGV2ZW50KVwiXG4gICAgICAgICAgICAgID5cbiAgICAgICAgICAgICAgPC9jcWEtZW1wdHktc3RhdGU+XG4gICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICA8L25nLXRlbXBsYXRlPlxuICAgICAgICA8L2Rpdj5cblxuICAgICAgICA8Y3FhLXBhZ2luYXRpb25cbiAgICAgICAgICBbdG90YWxFbGVtZW50c109XCJzZXJ2ZXJTaWRlUGFnaW5hdGlvbiA/IHRvdGFsRWxlbWVudHMgOiBmaWx0ZXJlZFJvd3MubGVuZ3RoXCJcbiAgICAgICAgICBbcGFnZUluZGV4XT1cInBhZ2VJbmRleFwiXG4gICAgICAgICAgW3BhZ2VTaXplXT1cInBhZ2VTaXplXCJcbiAgICAgICAgICBbcGFnZVNpemVPcHRpb25zXT1cInBhZ2VTaXplT3B0aW9uc1wiXG4gICAgICAgICAgW3BhZ2VTaXplTWVudURpcmVjdGlvbl09XCJwYWdlU2l6ZU1lbnVEaXJlY3Rpb25cIlxuICAgICAgICAgIFtwYWdlSXRlbUNvdW50XT1cInBhZ2VkUm93cy5sZW5ndGhcIlxuICAgICAgICAgIChwYWdpbmF0ZSk9XCJvblBhZ2luYXRlKCRldmVudClcIlxuICAgICAgICAgIChwYWdlU2l6ZUNoYW5nZSk9XCJvblBhZ2VTaXplQ2hhbmdlKCRldmVudClcIlxuICAgICAgICA+XG4gICAgICAgIDwvY3FhLXBhZ2luYXRpb24+XG4gICAgICA8L2Rpdj5cbiAgICA8L2Rpdj5cblxuICAgIDwhLS0gUmV1c2VkIGJ1bGsgYWN0aW9uIHRvb2xiYXIgLS0+XG4gICAgPGRpdiAqbmdJZj1cImFueVJvd1NlbGVjdGVkICYmIG1vZHVsYXJDb25maWcuYWxsb3dCdWxrU2VsZWN0aW9uICYmICFpc1Jlb3JkZXJpbmdcIiBjbGFzcz1cImNxYS1hYnNvbHV0ZSBjcWEtYm90dG9tLVsxOC43NXB4XSBjcWEtbGVmdC1bNTAlXSBjcWEtdHJhbnNsYXRlLXgtWy01MCVdIGNxYS13LWZ1bGwgbGc6Y3FhLW1heC13LVs2OCVdIGNxYS1zbTptYXgtdy1bNzUlXSBjcWEtbWF4LXctWzkwJV0gY3FhLXotWzFdXCI+XG4gICAgICA8Y3FhLXRhYmxlLWFjdGlvbi10b29sYmFyXG4gICAgICAgIFtzZWxlY3RlZEl0ZW1zXT1cInNlbGVjdGVkSXRlbXMgJiYgc2VsZWN0ZWRJdGVtcy5sZW5ndGggPiAwID8gc2VsZWN0ZWRJdGVtcyA6IGN1cnJlbnRTZWxlY3RlZEl0ZW1zXCJcbiAgICAgICAgW2FjdGlvbnNdPVwiZWZmZWN0aXZlQnVsa0FjdGlvbnNcIlxuICAgICAgICBbc2hvd1NlbGVjdEFsbF09XCJzaG93U2VsZWN0QWxsSW5Ub29sYmFyXCJcbiAgICAgICAgW2FsbFNlbGVjdGVkXT1cImFsbFNlbGVjdGVkSW5Ub29sYmFyXCJcbiAgICAgICAgW3Nob3dEaXNtaXNzXT1cInNob3dEaXNtaXNzSW5Ub29sYmFyXCJcbiAgICAgICAgKGFjdGlvbkNsaWNrKT1cIm9uQnVsa0FjdGlvbigkZXZlbnQpXCJcbiAgICAgICAgKHNlbGVjdEFsbENoYW5nZSk9XCJvbkJ1bGtTZWxlY3RBbGwoJGV2ZW50KVwiXG4gICAgICAgIChkaXNtaXNzKT1cIm9uQnVsa0Rpc21pc3MoKVwiXG4gICAgICA+PC9jcWEtdGFibGUtYWN0aW9uLXRvb2xiYXI+XG4gICAgPC9kaXY+XG5cbiAgPC9kaXY+XG48L2Rpdj5cblxuIl19