@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.
- package/esm2020/lib/assets/images/image-assets.constants.mjs +3 -1
- package/esm2020/lib/compare-runs/compare-runs.component.mjs +1 -1
- package/esm2020/lib/execution-screen/db-query-execution-item/db-query-execution-item.component.mjs +1 -1
- package/esm2020/lib/execution-screen/db-verification-step/db-verification-step.component.mjs +1 -1
- package/esm2020/lib/iterations-loop/iterations-loop.component.mjs +1 -1
- package/esm2020/lib/segment-control/segment-control.component.mjs +6 -3
- package/esm2020/lib/simulator/simulator.component.mjs +1 -1
- package/esm2020/lib/step-builder/step-builder-document-generation-template-step/step-builder-document-generation-template-step.component.mjs +1 -1
- package/esm2020/lib/table/dynamic-table/dynamic-table.component.mjs +148 -4
- package/esm2020/lib/templates/modular-table-template/dialogs/delete-folder-dialog.component.mjs +181 -0
- package/esm2020/lib/templates/modular-table-template/dialogs/move-to-folder-dialog.component.mjs +264 -0
- package/esm2020/lib/templates/modular-table-template/dialogs/new-folder-dialog.component.mjs +352 -0
- package/esm2020/lib/templates/modular-table-template/directives/folder-drag.directive.mjs +45 -0
- package/esm2020/lib/templates/modular-table-template/directives/folder-drop.directive.mjs +95 -0
- package/esm2020/lib/templates/modular-table-template/directives/row-drag.directive.mjs +44 -0
- package/esm2020/lib/templates/modular-table-template/folder-sidebar/folder-sidebar.component.mjs +479 -0
- package/esm2020/lib/templates/modular-table-template/modular-table-template.component.mjs +1475 -0
- package/esm2020/lib/templates/modular-table-template/modular-table-template.models.mjs +79 -0
- package/esm2020/lib/templates/table-template.component.mjs +88 -12
- package/esm2020/lib/test-case-details/api-edit-step/api-edit-step.component.mjs +1 -1
- package/esm2020/lib/ui-kit.module.mjs +41 -1
- package/esm2020/public-api.mjs +10 -1
- package/fesm2015/cqa-lib-cqa-ui.mjs +3408 -178
- package/fesm2015/cqa-lib-cqa-ui.mjs.map +1 -1
- package/fesm2020/cqa-lib-cqa-ui.mjs +3388 -176
- package/fesm2020/cqa-lib-cqa-ui.mjs.map +1 -1
- package/lib/assets/images/image-assets.constants.d.ts +1 -0
- package/lib/segment-control/segment-control.component.d.ts +2 -1
- package/lib/table/dynamic-table/dynamic-table.component.d.ts +43 -1
- package/lib/templates/modular-table-template/dialogs/delete-folder-dialog.component.d.ts +34 -0
- package/lib/templates/modular-table-template/dialogs/move-to-folder-dialog.component.d.ts +57 -0
- package/lib/templates/modular-table-template/dialogs/new-folder-dialog.component.d.ts +79 -0
- package/lib/templates/modular-table-template/directives/folder-drag.directive.d.ts +10 -0
- package/lib/templates/modular-table-template/directives/folder-drop.directive.d.ts +22 -0
- package/lib/templates/modular-table-template/directives/row-drag.directive.d.ts +10 -0
- package/lib/templates/modular-table-template/folder-sidebar/folder-sidebar.component.d.ts +149 -0
- package/lib/templates/modular-table-template/modular-table-template.component.d.ts +453 -0
- package/lib/templates/modular-table-template/modular-table-template.models.d.ts +150 -0
- package/lib/templates/table-template.component.d.ts +40 -2
- package/lib/ui-kit.module.d.ts +153 -145
- package/package.json +1 -1
- package/public-api.d.ts +9 -0
- package/src/lib/assets/images/EmptyFolderState.png +0 -0
- package/src/lib/assets/images/image-assets.constants.ts +3 -0
- 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
|