@cqa-lib/cqa-ui 1.1.548-gamma.17 → 1.1.548-gamma.19

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.
@@ -1,50 +1,57 @@
1
- import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
1
+ import { ChangeDetectionStrategy, Component, Input, ViewChild, } from '@angular/core';
2
2
  import { FormControl, FormGroup } from '@angular/forms';
3
+ import { Subject, of } from 'rxjs';
4
+ import { catchError, debounceTime, distinctUntilChanged, switchMap, takeUntil, } from 'rxjs/operators';
3
5
  import * as i0 from "@angular/core";
4
- import * as i1 from "../dynamic-select/dynamic-select-field.component";
5
- import * as i2 from "@angular/common";
6
+ import * as i1 from "../segment-control/segment-control.component";
7
+ import * as i2 from "../search-bar/search-bar.component";
8
+ import * as i3 from "../dynamic-select/dynamic-select-field.component";
9
+ import * as i4 from "@angular/material/icon";
10
+ import * as i5 from "@angular/common";
6
11
  export class AssignEnvironmentsDialogComponent {
7
12
  constructor(cdr) {
8
13
  this.cdr = cdr;
9
14
  this.mode = 'assign';
10
15
  this.profileName = '';
11
- this.environments = [];
16
+ this.pageSize = 50;
17
+ /** Source-env candidates the per-row "Copy from which environment" picker
18
+ * populates from. Synchronous list — typically bounded by the profile's
19
+ * current attachments (small, often < 10). */
12
20
  this.assignedEnvironments = [];
13
21
  this.selected = new Set();
14
- this.sourceForm = new FormGroup({
15
- sourceEnvId: new FormControl(null),
16
- });
17
- this.sourceConfig = this.buildSourceConfig([]);
18
- this.sourceError = null;
22
+ this.selectedSnapshot = [];
23
+ this.searchTerm = '';
24
+ this.isInitialLoading = false;
25
+ this.isLoadingMore = false;
26
+ this.currentResults = [];
27
+ this.totalElements = 0;
28
+ this.viewMode = 'all';
29
+ /** Stable segment array — recomputed only when selection size flips zero ↔ non-zero. */
30
+ this.viewSegments = this.computeViewSegments();
31
+ /** One FormGroup, controls keyed `tgt_${targetEnvId}`. */
32
+ this.sourceForm = new FormGroup({});
33
+ this.sourceConfigById = new Map();
34
+ this.skeletonRows = [0, 1, 2, 3, 4];
35
+ this.pageIndex = 0;
36
+ this.searchInput$ = new Subject();
37
+ this.destroy$ = new Subject();
19
38
  }
20
39
  ngOnInit() {
21
- // Source picker appears in both modes when there are already-attached envs
22
- // to copy from. In clone mode it's required; in assign mode it's optional
23
- // (falling back to the base profile rows when no source is picked).
24
- if (this.showSourcePicker) {
25
- const initial = this.defaultSourceEnvId != null
26
- ? this.defaultSourceEnvId
27
- : (this.mode === 'clone' && this.assignedEnvironments && this.assignedEnvironments.length
28
- ? this.assignedEnvironments[0].id
29
- : null);
30
- this.sourceForm.get('sourceEnvId').setValue(initial);
31
- this.sourceConfig = this.buildSourceConfig(this.assignedEnvironments ?? []);
32
- }
33
- }
34
- get showSourcePicker() {
35
- return (this.assignedEnvironments && this.assignedEnvironments.length > 0);
36
- }
37
- get sourceLabel() {
38
- return this.mode === 'clone' ? 'Copy from which environment' : 'Copy rows from (optional)';
40
+ // Search-term pipeline: every distinct, debounced term resets the page and
41
+ // replaces the visible list.
42
+ this.searchInput$
43
+ .pipe(debounceTime(300), distinctUntilChanged(), switchMap(term => this.fetchPage(term, 0)), takeUntil(this.destroy$))
44
+ .subscribe(({ term, page, payload }) => {
45
+ this.applyPage(term, page, /* append */ false, payload);
46
+ });
47
+ // Initial page-0 fetch on dialog open.
48
+ this.runFetch('', 0, /* append */ false);
39
49
  }
40
- get sourceHelper() {
41
- if (this.sourceError) {
42
- return this.sourceError;
43
- }
44
- return this.mode === 'clone'
45
- ? "The selected environment's rows will be copied into each target environment below."
46
- : 'Pick an environment to copy its rows into the new ones. Leave blank to seed with the base profile rows.';
50
+ ngOnDestroy() {
51
+ this.destroy$.next();
52
+ this.destroy$.complete();
47
53
  }
54
+ // -- Public template state -----------------------------------------------
48
55
  get title() {
49
56
  return this.mode === 'clone' ? 'Clone to other environments' : 'Assign to environments';
50
57
  }
@@ -54,6 +61,33 @@ export class AssignEnvironmentsDialogComponent {
54
61
  ? `Duplicate ${name} into other environments. Column structure is shared; row values are independent per environment.`
55
62
  : `Make ${name} available in the selected environments. Columns are shared — each environment gets an independent row set.`;
56
63
  }
64
+ get showPerRowSource() {
65
+ return (this.assignedEnvironments?.length ?? 0) > 0;
66
+ }
67
+ get isEmpty() {
68
+ return !this.currentResults || this.currentResults.length === 0;
69
+ }
70
+ get hasMore() {
71
+ return this.currentResults.length < this.totalElements;
72
+ }
73
+ get displayedRows() {
74
+ return this.viewMode === 'selected' ? this.selectedSnapshot : this.currentResults;
75
+ }
76
+ get unresolvedSourcesCount() {
77
+ if (!this.showPerRowSource) {
78
+ return 0;
79
+ }
80
+ let n = 0;
81
+ for (const env of this.selectedSnapshot) {
82
+ if (env.alreadyAssigned) {
83
+ continue;
84
+ }
85
+ if (!this.isSourceResolved(env.id)) {
86
+ n++;
87
+ }
88
+ }
89
+ return n;
90
+ }
57
91
  get primaryButtonLabel() {
58
92
  const count = this.selected.size;
59
93
  const verb = this.mode === 'clone' ? 'Clone to' : 'Assign to';
@@ -63,63 +97,164 @@ export class AssignEnvironmentsDialogComponent {
63
97
  if (this.selected.size === 0) {
64
98
  return true;
65
99
  }
66
- if (this.mode === 'clone' && this.sourceForm.get('sourceEnvId').value == null) {
100
+ if (this.unresolvedSourcesCount > 0) {
67
101
  return true;
68
102
  }
69
103
  return false;
70
104
  }
71
- get selectableEnvironments() {
72
- return this.environments ?? [];
105
+ isSelected(id) {
106
+ return this.selected.has(id);
73
107
  }
74
- get hasAnySelectable() {
75
- return (this.environments ?? []).some(e => !e.alreadyAssigned);
108
+ isSourceResolved(targetEnvId) {
109
+ if (!this.showPerRowSource) {
110
+ return true;
111
+ }
112
+ const ctrl = this.sourceForm.get(this.controlKey(targetEnvId));
113
+ return ctrl?.value != null;
76
114
  }
77
- get sourceValue() {
78
- return this.sourceForm.get('sourceEnvId').value ?? null;
115
+ getSourceConfig(targetEnvId) {
116
+ return this.sourceConfigById.get(targetEnvId);
79
117
  }
80
- isSelected(id) {
81
- return this.selected.has(id);
118
+ pickedSourceName(targetEnvId) {
119
+ const value = this.sourceForm.get(this.controlKey(targetEnvId))?.value;
120
+ if (value == null) {
121
+ return '';
122
+ }
123
+ const env = (this.assignedEnvironments || []).find(e => Number(e.id) === Number(value));
124
+ return env ? env.name : '';
82
125
  }
83
- toggle(env) {
126
+ helperFor(env) {
84
127
  if (env.alreadyAssigned) {
128
+ return 'Already assigned to this environment';
129
+ }
130
+ return env.description || '';
131
+ }
132
+ trackById(_index, env) {
133
+ return env.id;
134
+ }
135
+ // -- Public template events ---------------------------------------------
136
+ onSearchChange(term) {
137
+ this.searchTerm = term ?? '';
138
+ this.isInitialLoading = true;
139
+ this.currentResults = [];
140
+ this.cdr.markForCheck();
141
+ this.searchInput$.next(this.searchTerm);
142
+ }
143
+ onViewModeChange(value) {
144
+ this.viewMode = value === 'selected' ? 'selected' : 'all';
145
+ this.cdr.markForCheck();
146
+ }
147
+ toggle(env) {
148
+ if (env?.alreadyAssigned) {
85
149
  return;
86
150
  }
87
- if (this.selected.has(env.id)) {
88
- this.selected.delete(env.id);
151
+ const id = Number(env.id);
152
+ const wasZero = this.selected.size === 0;
153
+ if (this.selected.has(id)) {
154
+ this.selected.delete(id);
155
+ this.selectedSnapshot = this.selectedSnapshot.filter(e => Number(e.id) !== id);
156
+ this.removeSourceState(id);
157
+ // If the Selected view just emptied, fall back to All so the user
158
+ // doesn't sit on a blank screen.
159
+ if (this.viewMode === 'selected' && this.selectedSnapshot.length === 0) {
160
+ this.viewMode = 'all';
161
+ }
162
+ }
163
+ else {
164
+ this.selected.add(id);
165
+ this.selectedSnapshot = [...this.selectedSnapshot, env];
166
+ this.ensureSourceState(id);
167
+ }
168
+ const isZero = this.selected.size === 0;
169
+ if (wasZero !== isZero) {
170
+ this.viewSegments = this.computeViewSegments();
89
171
  }
90
172
  else {
91
- this.selected.add(env.id);
173
+ // Keep the count up to date even when zero ↔ non-zero didn't flip.
174
+ this.viewSegments = this.computeViewSegments();
92
175
  }
93
176
  this.cdr.markForCheck();
94
177
  }
95
- helperFor(env) {
96
- if (env.alreadyAssigned) {
97
- return 'Already assigned to this environment';
178
+ onListScroll() {
179
+ const el = this.listScrollRef?.nativeElement;
180
+ if (!el) {
181
+ return;
182
+ }
183
+ if (this.viewMode === 'selected') {
184
+ return;
185
+ }
186
+ if (this.isInitialLoading || this.isLoadingMore) {
187
+ return;
188
+ }
189
+ if (!this.hasMore) {
190
+ return;
191
+ }
192
+ const distanceFromBottom = el.scrollHeight - (el.scrollTop + el.clientHeight);
193
+ if (distanceFromBottom < 80) {
194
+ this.runFetch(this.searchTerm, this.pageIndex + 1, /* append */ true);
98
195
  }
99
- return env.description || '';
100
196
  }
101
197
  getValue() {
102
198
  if (this.selected.size === 0) {
103
199
  return null;
104
200
  }
105
- const src = this.sourceValue;
106
- if (this.mode === 'clone') {
107
- if (src == null) {
108
- this.sourceError = 'Pick the environment whose rows should be copied.';
109
- this.cdr.markForCheck();
110
- return null;
201
+ if (this.unresolvedSourcesCount > 0) {
202
+ return null;
203
+ }
204
+ if (!this.showPerRowSource) {
205
+ return { selectedIds: Array.from(this.selected), sources: [] };
206
+ }
207
+ const sources = Array.from(this.selected).map(id => {
208
+ const value = this.sourceForm.get(this.controlKey(id))?.value;
209
+ return { targetEnvId: id, sourceEnvId: Number(value) };
210
+ });
211
+ return { selectedIds: Array.from(this.selected), sources };
212
+ }
213
+ // -- Internals -----------------------------------------------------------
214
+ controlKey(targetEnvId) {
215
+ return `tgt_${targetEnvId}`;
216
+ }
217
+ computeViewSegments() {
218
+ const count = this.selected.size;
219
+ return [
220
+ { label: 'All', value: 'all' },
221
+ count > 0
222
+ ? { label: 'Selected', value: 'selected', count }
223
+ : { label: 'Selected', value: 'selected' },
224
+ ];
225
+ }
226
+ ensureSourceState(targetEnvId) {
227
+ if (!this.showPerRowSource) {
228
+ return;
229
+ }
230
+ if (!this.sourceForm.contains(this.controlKey(targetEnvId))) {
231
+ this.sourceForm.addControl(this.controlKey(targetEnvId), new FormControl(null));
232
+ }
233
+ if (!this.sourceConfigById.has(targetEnvId)) {
234
+ this.sourceConfigById.set(targetEnvId, this.buildSourceConfig(targetEnvId));
235
+ }
236
+ // Pre-select the default source if the caller suggested one (and it's a
237
+ // valid candidate). Saves the user a click when there's an obvious choice.
238
+ const ctrl = this.sourceForm.get(this.controlKey(targetEnvId));
239
+ if (ctrl && ctrl.value == null) {
240
+ const defaultId = this.resolveDefaultSourceId(targetEnvId);
241
+ if (defaultId != null) {
242
+ ctrl.setValue(defaultId);
111
243
  }
112
- this.sourceError = null;
113
- return { selectedIds: Array.from(this.selected), sourceEnvId: Number(src) };
114
244
  }
115
- // Assign mode: source is optional — include it when the user picked one.
116
- this.sourceError = null;
117
- return src != null
118
- ? { selectedIds: Array.from(this.selected), sourceEnvId: Number(src) }
119
- : { selectedIds: Array.from(this.selected) };
120
245
  }
121
- buildSourceConfig(envs) {
122
- const options = (envs || []).map(e => ({
246
+ removeSourceState(targetEnvId) {
247
+ const key = this.controlKey(targetEnvId);
248
+ if (this.sourceForm.contains(key)) {
249
+ this.sourceForm.removeControl(key);
250
+ }
251
+ this.sourceConfigById.delete(targetEnvId);
252
+ }
253
+ buildSourceConfig(targetEnvId) {
254
+ // Filter the target out of its own source list — copying an env into
255
+ // itself is non-sensical.
256
+ const candidates = (this.assignedEnvironments || []).filter(e => Number(e.id) !== Number(targetEnvId));
257
+ const options = candidates.map(e => ({
123
258
  id: e.id,
124
259
  value: e.id,
125
260
  name: e.name,
@@ -127,29 +262,91 @@ export class AssignEnvironmentsDialogComponent {
127
262
  statusColor: e.color,
128
263
  }));
129
264
  return {
130
- key: 'sourceEnvId',
265
+ key: this.controlKey(targetEnvId),
131
266
  label: '',
132
267
  placeholder: 'Select source environment…',
133
268
  multiple: false,
134
- searchable: true,
269
+ searchable: options.length > 6,
135
270
  options,
136
271
  };
137
272
  }
273
+ resolveDefaultSourceId(targetEnvId) {
274
+ const candidates = (this.assignedEnvironments || []).filter(e => Number(e.id) !== Number(targetEnvId));
275
+ if (candidates.length === 0) {
276
+ return null;
277
+ }
278
+ if (this.defaultSourceEnvId != null) {
279
+ const match = candidates.find(e => Number(e.id) === Number(this.defaultSourceEnvId));
280
+ if (match) {
281
+ return Number(match.id);
282
+ }
283
+ }
284
+ if (this.mode === 'clone') {
285
+ // Clone implies a source was already in scope — pick the first attached env.
286
+ return Number(candidates[0].id);
287
+ }
288
+ return null;
289
+ }
290
+ // -- Fetch pipeline ------------------------------------------------------
291
+ runFetch(term, page, append) {
292
+ if (append) {
293
+ this.isLoadingMore = true;
294
+ }
295
+ else {
296
+ this.isInitialLoading = true;
297
+ }
298
+ this.cdr.markForCheck();
299
+ this.fetchPage(term, page)
300
+ .pipe(takeUntil(this.destroy$))
301
+ .subscribe(result => {
302
+ this.applyPage(result.term, result.page, append, result.payload);
303
+ });
304
+ }
305
+ fetchPage(term, page) {
306
+ if (!this.searchFn) {
307
+ return of({ term, page, payload: { items: [], total: 0 } });
308
+ }
309
+ return this.searchFn(term, page, this.pageSize).pipe(catchError(() => of({ items: [], total: 0 })), switchMap(payload => of({ term, page, payload })));
310
+ }
311
+ applyPage(term, page, append, payload) {
312
+ // Drop responses whose term no longer matches the active search.
313
+ if (term !== this.searchTerm) {
314
+ return;
315
+ }
316
+ const items = payload?.items ?? [];
317
+ const total = payload?.total ?? items.length;
318
+ if (append) {
319
+ this.currentResults = [...this.currentResults, ...items];
320
+ }
321
+ else {
322
+ this.currentResults = [...items];
323
+ }
324
+ this.totalElements = total;
325
+ this.pageIndex = page;
326
+ this.isInitialLoading = false;
327
+ this.isLoadingMore = false;
328
+ this.cdr.markForCheck();
329
+ }
138
330
  }
139
331
  AssignEnvironmentsDialogComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: AssignEnvironmentsDialogComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
140
- AssignEnvironmentsDialogComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.4.0", type: AssignEnvironmentsDialogComponent, selector: "cqa-assign-environments-dialog", inputs: { mode: "mode", profileName: "profileName", environments: "environments", assignedEnvironments: "assignedEnvironments", defaultSourceEnvId: "defaultSourceEnvId" }, host: { styleAttribute: "display:block;width:100%;", classAttribute: "cqa-ui-root" }, ngImport: i0, template: "<div class=\"cqa-flex cqa-flex-col cqa-gap-4 cqa-w-full\">\n\n <!-- Source env picker: required in clone mode, optional in assign mode -->\n <div *ngIf=\"showSourcePicker\" class=\"cqa-flex cqa-flex-col cqa-gap-2\">\n <label class=\"cqa-text-sm cqa-font-medium cqa-text-gray-700\">{{ sourceLabel }}</label>\n <cqa-dynamic-select\n [form]=\"sourceForm\"\n [config]=\"sourceConfig\">\n </cqa-dynamic-select>\n <span [class.cqa-text-red-600]=\"sourceError\" [class.cqa-text-gray-500]=\"!sourceError\" class=\"cqa-text-xs\">\n {{ sourceHelper }}\n </span>\n </div>\n\n <!-- Selectable envs -->\n <div\n *ngIf=\"hasAnySelectable || (environments?.length || 0) > 0\"\n class=\"cqa-flex cqa-flex-col cqa-gap-2 cqa-max-h-[340px] cqa-overflow-y-auto\">\n <label\n *ngFor=\"let env of selectableEnvironments\"\n class=\"cqa-flex cqa-items-center cqa-gap-3 cqa-px-3 cqa-py-2.5 cqa-border cqa-rounded-[10px] cqa-bg-white cqa-transition-colors\"\n [class.cqa-border-gray-200]=\"!isSelected(env.id) && !env.alreadyAssigned\"\n [class.hover:cqa-border-indigo-200]=\"!env.alreadyAssigned && !isSelected(env.id)\"\n [class.cqa-border-indigo-400]=\"isSelected(env.id)\"\n [class.cqa-bg-indigo-50]=\"isSelected(env.id)\"\n [class.cqa-opacity-50]=\"env.alreadyAssigned\"\n [class.cqa-cursor-pointer]=\"!env.alreadyAssigned\"\n [class.cqa-cursor-not-allowed]=\"env.alreadyAssigned\"\n (click)=\"toggle(env)\">\n <input\n type=\"checkbox\"\n class=\"cqa-w-4 cqa-h-4 cqa-cursor-pointer\"\n [checked]=\"isSelected(env.id)\"\n [disabled]=\"!!env.alreadyAssigned\"\n (click)=\"$event.stopPropagation()\"\n (change)=\"toggle(env)\" />\n\n <span\n class=\"cqa-inline-block cqa-w-2 cqa-h-2 cqa-rounded-full cqa-flex-none\"\n [style.background]=\"env.color || '#3F43EE'\"></span>\n\n <div class=\"cqa-flex cqa-flex-col cqa-min-w-0 cqa-flex-1\">\n <div class=\"cqa-text-sm cqa-font-medium cqa-text-gray-900\">{{ env.name }}</div>\n <div *ngIf=\"helperFor(env)\" class=\"cqa-text-xs cqa-text-gray-500 cqa-leading-[1.4]\">{{ helperFor(env) }}</div>\n </div>\n </label>\n </div>\n\n <div\n *ngIf=\"(environments?.length || 0) === 0\"\n class=\"cqa-py-8 cqa-px-4 cqa-text-center cqa-text-sm cqa-text-gray-500\">\n All environments are already assigned to this profile.\n </div>\n</div>\n", components: [{ type: i1.DynamicSelectFieldComponent, selector: "cqa-dynamic-select", inputs: ["form", "config"], outputs: ["selectionChange", "selectClick", "searchChange", "loadMore", "addCustomValue"] }], directives: [{ type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
332
+ AssignEnvironmentsDialogComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.4.0", type: AssignEnvironmentsDialogComponent, selector: "cqa-assign-environments-dialog", inputs: { mode: "mode", profileName: "profileName", searchFn: "searchFn", pageSize: "pageSize", assignedEnvironments: "assignedEnvironments", defaultSourceEnvId: "defaultSourceEnvId" }, host: { styleAttribute: "display:block;width:100%;", classAttribute: "cqa-ui-root" }, viewQueries: [{ propertyName: "listScrollRef", first: true, predicate: ["listScroll"], descendants: true }], ngImport: i0, template: "<div class=\"cqa-flex cqa-flex-col cqa-gap-3 cqa-w-full\">\n\n <!-- All / Selected (N) toggle. Visible only when source picking is enabled\n (otherwise this is a single-purpose pick list and a toggle is noise). -->\n <div *ngIf=\"showPerRowSource\" class=\"cqa-flex cqa-items-center\">\n <cqa-segment-control\n [segments]=\"viewSegments\"\n [value]=\"viewMode\"\n (valueChange)=\"onViewModeChange($event)\">\n </cqa-segment-control>\n </div>\n\n <div *ngIf=\"viewMode === 'all'\">\n <cqa-search-bar\n placeholder=\"Search environments...\"\n [value]=\"searchTerm\"\n [showClear]=\"true\"\n [fullWidth]=\"true\"\n (valueChange)=\"onSearchChange($event)\"\n (search)=\"onSearchChange($event)\"\n (cleared)=\"onSearchChange('')\">\n </cqa-search-bar>\n </div>\n\n <!-- Loading skeleton \u2014 only relevant in the searchable \"All\" view. -->\n <div *ngIf=\"viewMode === 'all' && isInitialLoading\" class=\"cqa-flex cqa-flex-col cqa-gap-1.5\">\n <div *ngFor=\"let _ of skeletonRows\"\n class=\"cqa-flex cqa-items-center cqa-gap-3 cqa-px-3.5 cqa-py-3 cqa-rounded-[10px]\"\n [style.border]=\"'1px solid #E5E7EB'\"\n [style.background]=\"'#FFFFFF'\">\n <div class=\"cqa-aed-shimmer cqa-rounded-[4px]\" [style.width.px]=\"16\" [style.height.px]=\"16\"></div>\n <div class=\"cqa-aed-shimmer cqa-rounded-full\" [style.width.px]=\"10\" [style.height.px]=\"10\"></div>\n <div class=\"cqa-flex cqa-flex-col cqa-gap-1.5 cqa-flex-1\">\n <div class=\"cqa-aed-shimmer cqa-rounded-[3px]\" style=\"height: 10px; width: 160px;\"></div>\n <div class=\"cqa-aed-shimmer cqa-rounded-[3px]\" style=\"height: 8px; width: 220px;\"></div>\n </div>\n </div>\n </div>\n\n <div\n *ngIf=\"viewMode === 'all' && !isInitialLoading && isEmpty\"\n class=\"cqa-py-8 cqa-px-4 cqa-text-center cqa-text-[13px]\"\n [style.color]=\"'#64748B'\">\n <ng-container *ngIf=\"searchTerm; else noEnvsTpl\">\n No environments match \"{{ searchTerm }}\".\n </ng-container>\n <ng-template #noEnvsTpl>\n No environments available to assign.\n </ng-template>\n </div>\n\n <div\n *ngIf=\"viewMode === 'selected' && selectedSnapshot.length === 0\"\n class=\"cqa-py-8 cqa-px-4 cqa-text-center cqa-text-[13px]\"\n [style.color]=\"'#64748B'\">\n Nothing selected yet \u2014 switch back to \"All\" to pick environments.\n </div>\n\n <div\n *ngIf=\"(viewMode === 'all' && !isInitialLoading && !isEmpty) || (viewMode === 'selected' && selectedSnapshot.length > 0)\"\n #listScroll\n class=\"cqa-flex cqa-flex-col cqa-gap-1.5 cqa-overflow-y-auto cqa-overflow-x-hidden\"\n style=\"max-height: 420px;\"\n (scroll)=\"onListScroll()\">\n\n <div\n *ngFor=\"let env of displayedRows; trackBy: trackById\"\n class=\"cqa-flex cqa-flex-col cqa-rounded-[10px] cqa-transition-colors cqa-min-w-0\"\n [style.border]=\"'1px solid ' + (isSelected(env.id) ? '#8A8CF4' : '#E5E7EB')\"\n [style.background]=\"isSelected(env.id) ? '#EEF0FF' : '#FFFFFF'\"\n [style.opacity]=\"env.alreadyAssigned ? 0.5 : 1\">\n\n <!-- Click-target region: checkbox + name/desc ONLY. The source picker\n below is a SIBLING div (not nested in this region) so clicks on\n the dropdown never trigger the toggle handler. NB: don't wrap the\n whole row in a <label> \u2014 the label's native click \u2192 checkbox\n association fires even when bubbling is stopped. -->\n <div class=\"cqa-flex cqa-items-center cqa-gap-3 cqa-px-3.5 cqa-py-3\"\n [style.cursor]=\"env.alreadyAssigned ? 'not-allowed' : 'pointer'\"\n (click)=\"toggle(env)\">\n <input\n type=\"checkbox\"\n class=\"cqa-cursor-pointer cqa-flex-none\"\n [style.width.px]=\"16\"\n [style.height.px]=\"16\"\n [checked]=\"isSelected(env.id)\"\n [disabled]=\"!!env.alreadyAssigned\"\n (click)=\"$event.stopPropagation(); toggle(env)\"\n [attr.aria-label]=\"env.alreadyAssigned ? env.name + ' (already assigned)' : 'Select ' + env.name\" />\n\n <span\n class=\"cqa-inline-block cqa-rounded-full cqa-flex-none\"\n [style.width.px]=\"10\"\n [style.height.px]=\"10\"\n [style.background]=\"env.color || '#3F43EE'\"></span>\n\n <div class=\"cqa-flex cqa-flex-col cqa-min-w-0 cqa-flex-1\">\n <div class=\"cqa-text-[13px] cqa-font-medium cqa-truncate\" [style.color]=\"'#0F172A'\">{{ env.name }}</div>\n <div *ngIf=\"helperFor(env)\"\n class=\"cqa-text-[11px] cqa-leading-[1.4]\"\n style=\"color: #64748B; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; word-break: break-word; overflow-wrap: anywhere;\"\n [innerHTML]=\"helperFor(env)\"></div>\n </div>\n </div>\n\n <!-- Inline \"Copy from which environment\" picker \u2014 sits inside the card,\n below the head. Sibling of the head (not nested) so interacting with\n the dropdown never reaches the toggle handler. -->\n <div\n *ngIf=\"showPerRowSource && isSelected(env.id) && !env.alreadyAssigned\"\n class=\"cqa-aed-source cqa-flex cqa-flex-col cqa-gap-1.5 cqa-px-3.5 cqa-pb-3 cqa-pt-2.5\"\n style=\"border-top: 1px dashed #C7D2FE;\"\n (click)=\"$event.stopPropagation()\">\n <div class=\"cqa-text-[12px] cqa-font-semibold\" [style.color]=\"'#4338CA'\">Copy from which environment</div>\n\n <div *ngIf=\"getSourceConfig(env.id) as cfg\">\n <cqa-dynamic-select\n [form]=\"sourceForm\"\n [config]=\"cfg\">\n </cqa-dynamic-select>\n </div>\n\n <div\n *ngIf=\"pickedSourceName(env.id) as pickedName; else pickPromptTpl\"\n class=\"cqa-flex cqa-items-start cqa-gap-1.5 cqa-text-[11px] cqa-leading-[1.4]\"\n [style.color]=\"'#15803D'\">\n <mat-icon class=\"cqa-flex-none\" style=\"font-size: 14px; width: 14px; height: 14px; color: #16A34A;\">check_circle</mat-icon>\n <span>\n Rows will be copied from <strong>{{ pickedName }}</strong> into <strong>{{ env.name }}</strong>.\n </span>\n </div>\n <ng-template #pickPromptTpl>\n <div class=\"cqa-text-[11px] cqa-leading-[1.4]\" [style.color]=\"'#64748B'\">\n Pick where this environment's rows should be copied from.\n </div>\n </ng-template>\n </div>\n </div>\n\n <!-- Loading-more indicator at list bottom while paginating (All view only). -->\n <div *ngIf=\"viewMode === 'all' && isLoadingMore\"\n class=\"cqa-flex cqa-items-center cqa-justify-center cqa-gap-2 cqa-py-3 cqa-text-[12px]\"\n [style.color]=\"'#64748B'\"\n aria-live=\"polite\">\n <span class=\"cqa-aed-spinner\" aria-hidden=\"true\"></span>\n Loading more environments\u2026\n </div>\n\n <!-- End-of-list marker when the user has scrolled through all results. -->\n <div\n *ngIf=\"viewMode === 'all' && !isLoadingMore && !hasMore && currentResults.length > 0\"\n class=\"cqa-text-center cqa-py-2 cqa-text-[11px]\"\n [style.color]=\"'#94A3B8'\">\n End of list \u2014 {{ currentResults.length }} of {{ totalElements }} shown.\n </div>\n </div>\n\n <!-- Inline note: tells the user why the primary button stays disabled. -->\n <div\n *ngIf=\"showPerRowSource && selected.size > 0 && unresolvedSourcesCount > 0\"\n class=\"cqa-flex cqa-items-center cqa-gap-2 cqa-px-3 cqa-py-2 cqa-rounded-[8px] cqa-text-[12px]\"\n style=\"background: #FEF3C7; color: #92400E; border: 1px solid #FDE68A;\">\n Pick a source for {{ unresolvedSourcesCount }} environment{{ unresolvedSourcesCount === 1 ? '' : 's' }} before continuing.\n </div>\n</div>\n", components: [{ type: i1.SegmentControlComponent, selector: "cqa-segment-control", inputs: ["segments", "value", "disabled", "containerBgColor", "fullWidth", "size"], outputs: ["valueChange"] }, { type: i2.SearchBarComponent, selector: "cqa-search-bar", inputs: ["placeholder", "value", "disabled", "showClear", "ariaLabel", "autoFocus", "size", "fullWidth"], outputs: ["valueChange", "search", "cleared"] }, { type: i3.DynamicSelectFieldComponent, selector: "cqa-dynamic-select", inputs: ["form", "config"], outputs: ["selectionChange", "selectClick", "searchChange", "loadMore", "addCustomValue"] }, { type: i4.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }], directives: [{ type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i5.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
141
333
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: AssignEnvironmentsDialogComponent, decorators: [{
142
334
  type: Component,
143
- args: [{ selector: 'cqa-assign-environments-dialog', changeDetection: ChangeDetectionStrategy.OnPush, host: { class: 'cqa-ui-root', style: 'display:block;width:100%;' }, template: "<div class=\"cqa-flex cqa-flex-col cqa-gap-4 cqa-w-full\">\n\n <!-- Source env picker: required in clone mode, optional in assign mode -->\n <div *ngIf=\"showSourcePicker\" class=\"cqa-flex cqa-flex-col cqa-gap-2\">\n <label class=\"cqa-text-sm cqa-font-medium cqa-text-gray-700\">{{ sourceLabel }}</label>\n <cqa-dynamic-select\n [form]=\"sourceForm\"\n [config]=\"sourceConfig\">\n </cqa-dynamic-select>\n <span [class.cqa-text-red-600]=\"sourceError\" [class.cqa-text-gray-500]=\"!sourceError\" class=\"cqa-text-xs\">\n {{ sourceHelper }}\n </span>\n </div>\n\n <!-- Selectable envs -->\n <div\n *ngIf=\"hasAnySelectable || (environments?.length || 0) > 0\"\n class=\"cqa-flex cqa-flex-col cqa-gap-2 cqa-max-h-[340px] cqa-overflow-y-auto\">\n <label\n *ngFor=\"let env of selectableEnvironments\"\n class=\"cqa-flex cqa-items-center cqa-gap-3 cqa-px-3 cqa-py-2.5 cqa-border cqa-rounded-[10px] cqa-bg-white cqa-transition-colors\"\n [class.cqa-border-gray-200]=\"!isSelected(env.id) && !env.alreadyAssigned\"\n [class.hover:cqa-border-indigo-200]=\"!env.alreadyAssigned && !isSelected(env.id)\"\n [class.cqa-border-indigo-400]=\"isSelected(env.id)\"\n [class.cqa-bg-indigo-50]=\"isSelected(env.id)\"\n [class.cqa-opacity-50]=\"env.alreadyAssigned\"\n [class.cqa-cursor-pointer]=\"!env.alreadyAssigned\"\n [class.cqa-cursor-not-allowed]=\"env.alreadyAssigned\"\n (click)=\"toggle(env)\">\n <input\n type=\"checkbox\"\n class=\"cqa-w-4 cqa-h-4 cqa-cursor-pointer\"\n [checked]=\"isSelected(env.id)\"\n [disabled]=\"!!env.alreadyAssigned\"\n (click)=\"$event.stopPropagation()\"\n (change)=\"toggle(env)\" />\n\n <span\n class=\"cqa-inline-block cqa-w-2 cqa-h-2 cqa-rounded-full cqa-flex-none\"\n [style.background]=\"env.color || '#3F43EE'\"></span>\n\n <div class=\"cqa-flex cqa-flex-col cqa-min-w-0 cqa-flex-1\">\n <div class=\"cqa-text-sm cqa-font-medium cqa-text-gray-900\">{{ env.name }}</div>\n <div *ngIf=\"helperFor(env)\" class=\"cqa-text-xs cqa-text-gray-500 cqa-leading-[1.4]\">{{ helperFor(env) }}</div>\n </div>\n </label>\n </div>\n\n <div\n *ngIf=\"(environments?.length || 0) === 0\"\n class=\"cqa-py-8 cqa-px-4 cqa-text-center cqa-text-sm cqa-text-gray-500\">\n All environments are already assigned to this profile.\n </div>\n</div>\n" }]
335
+ args: [{ selector: 'cqa-assign-environments-dialog', changeDetection: ChangeDetectionStrategy.OnPush, host: { class: 'cqa-ui-root', style: 'display:block;width:100%;' }, template: "<div class=\"cqa-flex cqa-flex-col cqa-gap-3 cqa-w-full\">\n\n <!-- All / Selected (N) toggle. Visible only when source picking is enabled\n (otherwise this is a single-purpose pick list and a toggle is noise). -->\n <div *ngIf=\"showPerRowSource\" class=\"cqa-flex cqa-items-center\">\n <cqa-segment-control\n [segments]=\"viewSegments\"\n [value]=\"viewMode\"\n (valueChange)=\"onViewModeChange($event)\">\n </cqa-segment-control>\n </div>\n\n <div *ngIf=\"viewMode === 'all'\">\n <cqa-search-bar\n placeholder=\"Search environments...\"\n [value]=\"searchTerm\"\n [showClear]=\"true\"\n [fullWidth]=\"true\"\n (valueChange)=\"onSearchChange($event)\"\n (search)=\"onSearchChange($event)\"\n (cleared)=\"onSearchChange('')\">\n </cqa-search-bar>\n </div>\n\n <!-- Loading skeleton \u2014 only relevant in the searchable \"All\" view. -->\n <div *ngIf=\"viewMode === 'all' && isInitialLoading\" class=\"cqa-flex cqa-flex-col cqa-gap-1.5\">\n <div *ngFor=\"let _ of skeletonRows\"\n class=\"cqa-flex cqa-items-center cqa-gap-3 cqa-px-3.5 cqa-py-3 cqa-rounded-[10px]\"\n [style.border]=\"'1px solid #E5E7EB'\"\n [style.background]=\"'#FFFFFF'\">\n <div class=\"cqa-aed-shimmer cqa-rounded-[4px]\" [style.width.px]=\"16\" [style.height.px]=\"16\"></div>\n <div class=\"cqa-aed-shimmer cqa-rounded-full\" [style.width.px]=\"10\" [style.height.px]=\"10\"></div>\n <div class=\"cqa-flex cqa-flex-col cqa-gap-1.5 cqa-flex-1\">\n <div class=\"cqa-aed-shimmer cqa-rounded-[3px]\" style=\"height: 10px; width: 160px;\"></div>\n <div class=\"cqa-aed-shimmer cqa-rounded-[3px]\" style=\"height: 8px; width: 220px;\"></div>\n </div>\n </div>\n </div>\n\n <div\n *ngIf=\"viewMode === 'all' && !isInitialLoading && isEmpty\"\n class=\"cqa-py-8 cqa-px-4 cqa-text-center cqa-text-[13px]\"\n [style.color]=\"'#64748B'\">\n <ng-container *ngIf=\"searchTerm; else noEnvsTpl\">\n No environments match \"{{ searchTerm }}\".\n </ng-container>\n <ng-template #noEnvsTpl>\n No environments available to assign.\n </ng-template>\n </div>\n\n <div\n *ngIf=\"viewMode === 'selected' && selectedSnapshot.length === 0\"\n class=\"cqa-py-8 cqa-px-4 cqa-text-center cqa-text-[13px]\"\n [style.color]=\"'#64748B'\">\n Nothing selected yet \u2014 switch back to \"All\" to pick environments.\n </div>\n\n <div\n *ngIf=\"(viewMode === 'all' && !isInitialLoading && !isEmpty) || (viewMode === 'selected' && selectedSnapshot.length > 0)\"\n #listScroll\n class=\"cqa-flex cqa-flex-col cqa-gap-1.5 cqa-overflow-y-auto cqa-overflow-x-hidden\"\n style=\"max-height: 420px;\"\n (scroll)=\"onListScroll()\">\n\n <div\n *ngFor=\"let env of displayedRows; trackBy: trackById\"\n class=\"cqa-flex cqa-flex-col cqa-rounded-[10px] cqa-transition-colors cqa-min-w-0\"\n [style.border]=\"'1px solid ' + (isSelected(env.id) ? '#8A8CF4' : '#E5E7EB')\"\n [style.background]=\"isSelected(env.id) ? '#EEF0FF' : '#FFFFFF'\"\n [style.opacity]=\"env.alreadyAssigned ? 0.5 : 1\">\n\n <!-- Click-target region: checkbox + name/desc ONLY. The source picker\n below is a SIBLING div (not nested in this region) so clicks on\n the dropdown never trigger the toggle handler. NB: don't wrap the\n whole row in a <label> \u2014 the label's native click \u2192 checkbox\n association fires even when bubbling is stopped. -->\n <div class=\"cqa-flex cqa-items-center cqa-gap-3 cqa-px-3.5 cqa-py-3\"\n [style.cursor]=\"env.alreadyAssigned ? 'not-allowed' : 'pointer'\"\n (click)=\"toggle(env)\">\n <input\n type=\"checkbox\"\n class=\"cqa-cursor-pointer cqa-flex-none\"\n [style.width.px]=\"16\"\n [style.height.px]=\"16\"\n [checked]=\"isSelected(env.id)\"\n [disabled]=\"!!env.alreadyAssigned\"\n (click)=\"$event.stopPropagation(); toggle(env)\"\n [attr.aria-label]=\"env.alreadyAssigned ? env.name + ' (already assigned)' : 'Select ' + env.name\" />\n\n <span\n class=\"cqa-inline-block cqa-rounded-full cqa-flex-none\"\n [style.width.px]=\"10\"\n [style.height.px]=\"10\"\n [style.background]=\"env.color || '#3F43EE'\"></span>\n\n <div class=\"cqa-flex cqa-flex-col cqa-min-w-0 cqa-flex-1\">\n <div class=\"cqa-text-[13px] cqa-font-medium cqa-truncate\" [style.color]=\"'#0F172A'\">{{ env.name }}</div>\n <div *ngIf=\"helperFor(env)\"\n class=\"cqa-text-[11px] cqa-leading-[1.4]\"\n style=\"color: #64748B; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; word-break: break-word; overflow-wrap: anywhere;\"\n [innerHTML]=\"helperFor(env)\"></div>\n </div>\n </div>\n\n <!-- Inline \"Copy from which environment\" picker \u2014 sits inside the card,\n below the head. Sibling of the head (not nested) so interacting with\n the dropdown never reaches the toggle handler. -->\n <div\n *ngIf=\"showPerRowSource && isSelected(env.id) && !env.alreadyAssigned\"\n class=\"cqa-aed-source cqa-flex cqa-flex-col cqa-gap-1.5 cqa-px-3.5 cqa-pb-3 cqa-pt-2.5\"\n style=\"border-top: 1px dashed #C7D2FE;\"\n (click)=\"$event.stopPropagation()\">\n <div class=\"cqa-text-[12px] cqa-font-semibold\" [style.color]=\"'#4338CA'\">Copy from which environment</div>\n\n <div *ngIf=\"getSourceConfig(env.id) as cfg\">\n <cqa-dynamic-select\n [form]=\"sourceForm\"\n [config]=\"cfg\">\n </cqa-dynamic-select>\n </div>\n\n <div\n *ngIf=\"pickedSourceName(env.id) as pickedName; else pickPromptTpl\"\n class=\"cqa-flex cqa-items-start cqa-gap-1.5 cqa-text-[11px] cqa-leading-[1.4]\"\n [style.color]=\"'#15803D'\">\n <mat-icon class=\"cqa-flex-none\" style=\"font-size: 14px; width: 14px; height: 14px; color: #16A34A;\">check_circle</mat-icon>\n <span>\n Rows will be copied from <strong>{{ pickedName }}</strong> into <strong>{{ env.name }}</strong>.\n </span>\n </div>\n <ng-template #pickPromptTpl>\n <div class=\"cqa-text-[11px] cqa-leading-[1.4]\" [style.color]=\"'#64748B'\">\n Pick where this environment's rows should be copied from.\n </div>\n </ng-template>\n </div>\n </div>\n\n <!-- Loading-more indicator at list bottom while paginating (All view only). -->\n <div *ngIf=\"viewMode === 'all' && isLoadingMore\"\n class=\"cqa-flex cqa-items-center cqa-justify-center cqa-gap-2 cqa-py-3 cqa-text-[12px]\"\n [style.color]=\"'#64748B'\"\n aria-live=\"polite\">\n <span class=\"cqa-aed-spinner\" aria-hidden=\"true\"></span>\n Loading more environments\u2026\n </div>\n\n <!-- End-of-list marker when the user has scrolled through all results. -->\n <div\n *ngIf=\"viewMode === 'all' && !isLoadingMore && !hasMore && currentResults.length > 0\"\n class=\"cqa-text-center cqa-py-2 cqa-text-[11px]\"\n [style.color]=\"'#94A3B8'\">\n End of list \u2014 {{ currentResults.length }} of {{ totalElements }} shown.\n </div>\n </div>\n\n <!-- Inline note: tells the user why the primary button stays disabled. -->\n <div\n *ngIf=\"showPerRowSource && selected.size > 0 && unresolvedSourcesCount > 0\"\n class=\"cqa-flex cqa-items-center cqa-gap-2 cqa-px-3 cqa-py-2 cqa-rounded-[8px] cqa-text-[12px]\"\n style=\"background: #FEF3C7; color: #92400E; border: 1px solid #FDE68A;\">\n Pick a source for {{ unresolvedSourcesCount }} environment{{ unresolvedSourcesCount === 1 ? '' : 's' }} before continuing.\n </div>\n</div>\n" }]
144
336
  }], ctorParameters: function () { return [{ type: i0.ChangeDetectorRef }]; }, propDecorators: { mode: [{
145
337
  type: Input
146
338
  }], profileName: [{
147
339
  type: Input
148
- }], environments: [{
340
+ }], searchFn: [{
341
+ type: Input
342
+ }], pageSize: [{
149
343
  type: Input
150
344
  }], assignedEnvironments: [{
151
345
  type: Input
152
346
  }], defaultSourceEnvId: [{
153
347
  type: Input
348
+ }], listScrollRef: [{
349
+ type: ViewChild,
350
+ args: ['listScroll', { static: false }]
154
351
  }] } });
155
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXNzaWduLWVudmlyb25tZW50cy1kaWFsb2cuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vc3JjL2xpYi9hc3NpZ24tZW52aXJvbm1lbnRzLWRpYWxvZy9hc3NpZ24tZW52aXJvbm1lbnRzLWRpYWxvZy5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi8uLi9zcmMvbGliL2Fzc2lnbi1lbnZpcm9ubWVudHMtZGlhbG9nL2Fzc2lnbi1lbnZpcm9ubWVudHMtZGlhbG9nLmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSx1QkFBdUIsRUFBcUIsU0FBUyxFQUFFLEtBQUssRUFBVSxNQUFNLGVBQWUsQ0FBQztBQUNyRyxPQUFPLEVBQUUsV0FBVyxFQUFFLFNBQVMsRUFBRSxNQUFNLGdCQUFnQixDQUFDOzs7O0FBa0J4RCxNQUFNLE9BQU8saUNBQWlDO0lBZ0I1QyxZQUE2QixHQUFzQjtRQUF0QixRQUFHLEdBQUgsR0FBRyxDQUFtQjtRQWYxQyxTQUFJLEdBQTJCLFFBQVEsQ0FBQztRQUN4QyxnQkFBVyxHQUFXLEVBQUUsQ0FBQztRQUN6QixpQkFBWSxHQUE4QixFQUFFLENBQUM7UUFDN0MseUJBQW9CLEdBQThCLEVBQUUsQ0FBQztRQUc5QyxhQUFRLEdBQUcsSUFBSSxHQUFHLEVBQVUsQ0FBQztRQUU3QixlQUFVLEdBQUcsSUFBSSxTQUFTLENBQUM7WUFDekMsV0FBVyxFQUFFLElBQUksV0FBVyxDQUFDLElBQUksQ0FBQztTQUNuQyxDQUFDLENBQUM7UUFDSSxpQkFBWSxHQUE2QixJQUFJLENBQUMsaUJBQWlCLENBQUMsRUFBRSxDQUFDLENBQUM7UUFFcEUsZ0JBQVcsR0FBa0IsSUFBSSxDQUFDO0lBRWEsQ0FBQztJQUV2RCxRQUFRO1FBQ04sMkVBQTJFO1FBQzNFLDBFQUEwRTtRQUMxRSxvRUFBb0U7UUFDcEUsSUFBSSxJQUFJLENBQUMsZ0JBQWdCLEVBQUU7WUFD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QUFHLEVBQUUsYUFBYTtZQUNsQixLQUFLLEVBQUUsRUFBRTtZQUNULFdBQVcsRUFBRSw0QkFBNEI7WUFDekMsUUFBUSxFQUFFLEtBQUs7WUFDZixVQUFVLEVBQUUsSUFBSTtZQUNoQixPQUFPO1NBQ1IsQ0FBQztJQUNKLENBQUM7OzhIQXpJVSxpQ0FBaUM7a0hBQWpDLGlDQUFpQyx3VUNuQjlDLHE1RUFzREE7MkZEbkNhLGlDQUFpQztrQkFON0MsU0FBUzsrQkFDRSxnQ0FBZ0MsbUJBRXpCLHVCQUF1QixDQUFDLE1BQU0sUUFDekMsRUFBRSxLQUFLLEVBQUUsYUFBYSxFQUFFLEtBQUssRUFBRSwyQkFBMkIsRUFBRTt3R0FHekQsSUFBSTtzQkFBWixLQUFLO2dCQUNHLFdBQVc7c0JBQW5CLEtBQUs7Z0JBQ0csWUFBWTtzQkFBcEIsS0FBSztnQkFDRyxvQkFBb0I7c0JBQTVCLEtBQUs7Z0JBQ0csa0JBQWtCO3NCQUExQixLQUFLIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3ksIENoYW5nZURldGVjdG9yUmVmLCBDb21wb25lbnQsIElucHV0LCBPbkluaXQgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IEZvcm1Db250cm9sLCBGb3JtR3JvdXAgfSBmcm9tICdAYW5ndWxhci9mb3Jtcyc7XG5cbmltcG9ydCB7XG4gIER5bmFtaWNTZWxlY3RGaWVsZENvbmZpZyxcbiAgU2VsZWN0T3B0aW9uLFxufSBmcm9tICcuLi9keW5hbWljLXNlbGVjdC9keW5hbWljLXNlbGVjdC1maWVsZC5jb21wb25lbnQnO1xuaW1wb3J0IHtcbiAgQXNzaWduRW52aXJvbm1lbnRPcHRpb24sXG4gIEFzc2lnbkVudmlyb25tZW50c0RpYWxvZ1ZhbHVlLFxuICBBc3NpZ25FbnZpcm9ubWVudHNNb2RlLFxufSBmcm9tICcuL2Fzc2lnbi1lbnZpcm9ubWVudHMtZGlhbG9nLm1vZGVscyc7XG5cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ2NxYS1hc3NpZ24tZW52aXJvbm1lbnRzLWRpYWxvZycsXG4gIHRlbXBsYXRlVXJsOiAnLi9hc3NpZ24tZW52aXJvbm1lbnRzLWRpYWxvZy5jb21wb25lbnQuaHRtbCcsXG4gIGNoYW5nZURldGVjdGlvbjogQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3kuT25QdXNoLFxuICBob3N0OiB7IGNsYXNzOiAnY3FhLXVpLXJvb3QnLCBzdHlsZTogJ2Rpc3BsYXk6YmxvY2s7d2lkdGg6MTAwJTsnIH0sXG59KVxuZXhwb3J0IGNsYXNzIEFzc2lnbkVudmlyb25tZW50c0RpYWxvZ0NvbXBvbmVudCBpbXBsZW1lbnRzIE9uSW5pdCB7XG4gIEBJbnB1dCgpIG1vZGU6IEFzc2lnbkVudmlyb25tZW50c01vZGUgPSAnYXNzaWduJztcbiAgQElucHV0KCkgcHJvZmlsZU5hbWU6IHN0cmluZyA9ICcnO1xuICBASW5wdXQoKSBlbnZpcm9ubWVudHM6IEFzc2lnbkVudmlyb25tZW50T3B0aW9uW10gPSBbXTtcbiAgQElucHV0KCkgYXNzaWduZWRFbnZpcm9ubWVudHM6IEFzc2lnbkVudmlyb25tZW50T3B0aW9uW10gPSBbXTtcbiAgQElucHV0KCkgZGVmYXVsdFNvdXJjZUVudklkPzogbnVtYmVyO1xuXG4gIHB1YmxpYyByZWFkb25seSBzZWxlY3RlZCA9IG5ldyBTZXQ8bnVtYmVyPigpO1xuXG4gIHB1YmxpYyByZWFkb25seSBzb3VyY2VGb3JtID0gbmV3IEZvcm1Hcm91cCh7XG4gICAgc291cmNlRW52SWQ6IG5ldyBGb3JtQ29udHJvbChudWxsKSxcbiAgfSk7XG4gIHB1YmxpYyBzb3VyY2VDb25maWc6IER5bmFtaWNTZWxlY3RGaWVsZENvbmZpZyA9IHRoaXMuYnVpbGRTb3VyY2VDb25maWcoW10pO1xuXG4gIHB1YmxpYyBzb3VyY2VFcnJvcjogc3RyaW5nIHwgbnVsbCA9IG51bGw7XG5cbiAgY29uc3RydWN0b3IocHJpdmF0ZSByZWFkb25seSBjZHI6IENoYW5nZURldGVjdG9yUmVmKSB7fVxuXG4gIG5nT25Jbml0KCk6IHZvaWQge1xuICAgIC8vIFNvdXJjZSBwaWNrZXIgYXBwZWFycyBpbiBib3RoIG1vZGVzIHdoZW4gdGhlcmUgYXJlIGFscmVhZHktYXR0YWNoZWQgZW52c1xuICAgIC8vIHRvIGNvcHkgZnJvbS4gSW4gY2xvbmUgbW9kZSBpdCdzIHJlcXVpcmVkOyBpbiBhc3NpZ24gbW9kZSBpdCdzIG9wdGlvbmFsXG4gICAgLy8gKGZhbGxpbmcgYmFjayB0byB0aGUgYmFzZSBwcm9maWxlIHJvd3Mgd2hlbiBubyBzb3VyY2UgaXMgcGlja2VkKS5cbiAgICBpZiAodGhpcy5zaG93U291cmNlUGlja2VyKSB7XG4gICAgICBjb25zdCBpbml0aWFsID0gdGhpcy5kZWZhdWx0U291cmNlRW52SWQgIT0gbnVsbFxuICAgICAgICA/IHRoaXMuZGVmYXVsdFNvdXJjZUVudklkXG4gICAgICAgIDogKHRoaXMubW9kZSA9PT0gJ2Nsb25lJyAmJiB0aGlzLmFzc2lnbmVkRW52aXJvbm1lbnRzICYmIHRoaXMuYXNzaWduZWRFbnZpcm9ubWVudHMubGVuZ3RoXG4gICAgICAgICAgPyB0aGlzLmFzc2lnbmVkRW52aXJvbm1lbnRzWzBdLmlkXG4gICAgICAgICAgOiBudWxsKTtcbiAgICAgIHRoaXMuc291cmNlRm9ybS5nZXQoJ3NvdXJjZUVudklkJykhLnNldFZhbHVlKGluaXRpYWwpO1xuICAgICAgdGhpcy5zb3VyY2VDb25maWcgPSB0aGlzLmJ1aWxkU291cmNlQ29uZmlnKHRoaXMuYXNzaWduZWRFbnZpcm9ubWVudHMgPz8gW10pO1xuICAgIH1cbiAgfVxuXG4gIHB1YmxpYyBnZXQgc2hvd1NvdXJjZVBpY2tlcigpOiBib29sZWFuIHtcbiAgICByZXR1cm4gKHRoaXMuYXNzaWduZWRFbnZpcm9ubWVudHMgJiYgdGhpcy5hc3NpZ25lZEVudmlyb25tZW50cy5sZW5ndGggPiAwKTtcbiAgfVxuXG4gIHB1YmxpYyBnZXQgc291cmNlTGFiZWwoKTogc3RyaW5nIHtcbiAgICByZXR1cm4gdGhpcy5tb2RlID09PSAnY2xvbmUnID8gJ0NvcHkgZnJvbSB3aGljaCBlbnZpcm9ubWVudCcgOiAnQ29weSByb3dzIGZyb20gKG9wdGlvbmFsKSc7XG4gIH1cblxuICBwdWJsaWMgZ2V0IHNvdXJjZUhlbHBlcigpOiBzdHJpbmcge1xuICAgIGlmICh0aGlzLnNvdXJjZUVycm9yKSB7IHJldHVybiB0aGlzLnNvdXJjZUVycm9yOyB9XG4gICAgcmV0dXJuIHRoaXMubW9kZSA9PT0gJ2Nsb25lJ1xuICAgICAgPyBcIlRoZSBzZWxlY3RlZCBlbnZpcm9ubWVudCdzIHJvd3Mgd2lsbCBiZSBjb3BpZWQgaW50byBlYWNoIHRhcmdldCBlbnZpcm9ubWVudCBiZWxvdy5cIlxuICAgICAgOiAnUGljayBhbiBlbnZpcm9ubWVudCB0byBjb3B5IGl0cyByb3dzIGludG8gdGhlIG5ldyBvbmVzLiBMZWF2ZSBibGFuayB0byBzZWVkIHdpdGggdGhlIGJhc2UgcHJvZmlsZSByb3dzLic7XG4gIH1cblxuICBwdWJsaWMgZ2V0IHRpdGxlKCk6IHN0cmluZyB7XG4gICAgcmV0dXJuIHRoaXMubW9kZSA9PT0gJ2Nsb25lJyA/ICdDbG9uZSB0byBvdGhlciBlbnZpcm9ubWVudHMnIDogJ0Fzc2lnbiB0byBlbnZpcm9ubWVudHMnO1xuICB9XG5cbiAgcHVibGljIGdldCBzdWJ0aXRsZSgpOiBzdHJpbmcge1xuICAgIGNvbnN0IG5hbWUgPSB0aGlzLnByb2ZpbGVOYW1lID8gYFwiJHt0aGlzLnByb2ZpbGVOYW1lfVwiYCA6ICd0aGlzIHByb2ZpbGUnO1xuICAgIHJldHVybiB0aGlzLm1vZGUgPT09ICdjbG9uZSdcbiAgICAgID8gYER1cGxpY2F0ZSAke25hbWV9IGludG8gb3RoZXIgZW52aXJvbm1lbnRzLiBDb2x1bW4gc3RydWN0dXJlIGlzIHNoYXJlZDsgcm93IHZhbHVlcyBhcmUgaW5kZXBlbmRlbnQgcGVyIGVudmlyb25tZW50LmBcbiAgICAgIDogYE1ha2UgJHtuYW1lfSBhdmFpbGFibGUgaW4gdGhlIHNlbGVjdGVkIGVudmlyb25tZW50cy4gQ29sdW1ucyBhcmUgc2hhcmVkIOKAlCBlYWNoIGVudmlyb25tZW50IGdldHMgYW4gaW5kZXBlbmRlbnQgcm93IHNldC5gO1xuICB9XG5cbiAgcHVibGljIGdldCBwcmltYXJ5QnV0dG9uTGFiZWwoKTogc3RyaW5nIHtcbiAgICBjb25zdCBjb3VudCA9IHRoaXMuc2VsZWN0ZWQuc2l6ZTtcbiAgICBjb25zdCB2ZXJiID0gdGhpcy5tb2RlID09PSAnY2xvbmUnID8gJ0Nsb25lIHRvJyA6ICdBc3NpZ24gdG8nO1xuICAgIHJldHVybiBgJHt2ZXJifSAke2NvdW50fSBlbnZpcm9ubWVudCR7Y291bnQgPT09IDEgPyAnJyA6ICdzJ31gO1xuICB9XG5cbiAgcHVibGljIGdldCBwcmltYXJ5RGlzYWJsZWQoKTogYm9vbGVhbiB7XG4gICAgaWYgKHRoaXMuc2VsZWN0ZWQuc2l6ZSA9PT0gMCkgeyByZXR1cm4gdHJ1ZTsgfVxuICAgIGlmICh0aGlzLm1vZGUgPT09ICdjbG9uZScgJiYgdGhpcy5zb3VyY2VGb3JtLmdldCgnc291cmNlRW52SWQnKSEudmFsdWUgPT0gbnVsbCkgeyByZXR1cm4gdHJ1ZTsgfVxuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuXG4gIHB1YmxpYyBnZXQgc2VsZWN0YWJsZUVudmlyb25tZW50cygpOiBBc3NpZ25FbnZpcm9ubWVudE9wdGlvbltdIHtcbiAgICByZXR1cm4gdGhpcy5lbnZpcm9ubWVudHMgPz8gW107XG4gIH1cblxuICBwdWJsaWMgZ2V0IGhhc0FueVNlbGVjdGFibGUoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuICh0aGlzLmVudmlyb25tZW50cyA/PyBbXSkuc29tZShlID0+ICFlLmFscmVhZHlBc3NpZ25lZCk7XG4gIH1cblxuICBwdWJsaWMgZ2V0IHNvdXJjZVZhbHVlKCk6IG51bWJlciB8IG51bGwge1xuICAgIHJldHVybiB0aGlzLnNvdXJjZUZvcm0uZ2V0KCdzb3VyY2VFbnZJZCcpIS52YWx1ZSA/PyBudWxsO1xuICB9XG5cbiAgcHVibGljIGlzU2VsZWN0ZWQoaWQ6IG51bWJlcik6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLnNlbGVjdGVkLmhhcyhpZCk7XG4gIH1cblxuICBwdWJsaWMgdG9nZ2xlKGVudjogQXNzaWduRW52aXJvbm1lbnRPcHRpb24pOiB2b2lkIHtcbiAgICBpZiAoZW52LmFscmVhZHlBc3NpZ25lZCkgeyByZXR1cm47IH1cbiAgICBpZiAodGhpcy5zZWxlY3RlZC5oYXMoZW52LmlkKSkge1xuICAgICAgdGhpcy5zZWxlY3RlZC5kZWxldGUoZW52LmlkKTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5zZWxlY3RlZC5hZGQoZW52LmlkKTtcbiAgICB9XG4gICAgdGhpcy5jZHIubWFya0ZvckNoZWNrKCk7XG4gIH1cblxuICBwdWJsaWMgaGVscGVyRm9yKGVudjogQXNzaWduRW52aXJvbm1lbnRPcHRpb24pOiBzdHJpbmcge1xuICAgIGlmIChlbnYuYWxyZWFkeUFzc2lnbmVkKSB7IHJldHVybiAnQWxyZWFkeSBhc3NpZ25lZCB0byB0aGlzIGVudmlyb25tZW50JzsgfVxuICAgIHJldHVybiBlbnYuZGVzY3JpcHRpb24gfHwgJyc7XG4gIH1cblxuICBwdWJsaWMgZ2V0VmFsdWUoKTogQXNzaWduRW52aXJvbm1lbnRzRGlhbG9nVmFsdWUgfCBudWxsIHtcbiAgICBpZiAodGhpcy5zZWxlY3RlZC5zaXplID09PSAwKSB7IHJldHVybiBudWxsOyB9XG4gICAgY29uc3Qgc3JjID0gdGhpcy5zb3VyY2VWYWx1ZTtcbiAgICBpZiAodGhpcy5tb2RlID09PSAnY2xvbmUnKSB7XG4gICAgICBpZiAoc3JjID09IG51bGwpIHtcbiAgICAgICAgdGhpcy5zb3VyY2VFcnJvciA9ICdQaWNrIHRoZSBlbnZpcm9ubWVudCB3aG9zZSByb3dzIHNob3VsZCBiZSBjb3BpZWQuJztcbiAgICAgICAgdGhpcy5jZHIubWFya0ZvckNoZWNrKCk7XG4gICAgICAgIHJldHVybiBudWxsO1xuICAgICAgfVxuICAgICAgdGhpcy5zb3VyY2VFcnJvciA9IG51bGw7XG4gICAgICByZXR1cm4geyBzZWxlY3RlZElkczogQXJyYXkuZnJvbSh0aGlzLnNlbGVjdGVkKSwgc291cmNlRW52SWQ6IE51bWJlcihzcmMpIH07XG4gICAgfVxuICAgIC8vIEFzc2lnbiBtb2RlOiBzb3VyY2UgaXMgb3B0aW9uYWwg4oCUIGluY2x1ZGUgaXQgd2hlbiB0aGUgdXNlciBwaWNrZWQgb25lLlxuICAgIHRoaXMuc291cmNlRXJyb3IgPSBudWxsO1xuICAgIHJldHVybiBzcmMgIT0gbnVsbFxuICAgICAgPyB7IHNlbGVjdGVkSWRzOiBBcnJheS5mcm9tKHRoaXMuc2VsZWN0ZWQpLCBzb3VyY2VFbnZJZDogTnVtYmVyKHNyYykgfVxuICAgICAgOiB7IHNlbGVjdGVkSWRzOiBBcnJheS5mcm9tKHRoaXMuc2VsZWN0ZWQpIH07XG4gIH1cblxuICBwcml2YXRlIGJ1aWxkU291cmNlQ29uZmlnKGVudnM6IEFzc2lnbkVudmlyb25tZW50T3B0aW9uW10pOiBEeW5hbWljU2VsZWN0RmllbGRDb25maWcge1xuICAgIGNvbnN0IG9wdGlvbnM6IFNlbGVjdE9wdGlvbltdID0gKGVudnMgfHwgW10pLm1hcChlID0+ICh7XG4gICAgICBpZDogZS5pZCxcbiAgICAgIHZhbHVlOiBlLmlkLFxuICAgICAgbmFtZTogZS5uYW1lLFxuICAgICAgbGFiZWw6IGUubmFtZSxcbiAgICAgIHN0YXR1c0NvbG9yOiBlLmNvbG9yLFxuICAgIH0pKTtcbiAgICByZXR1cm4ge1xuICAgICAga2V5OiAnc291cmNlRW52SWQnLFxuICAgICAgbGFiZWw6ICcnLFxuICAgICAgcGxhY2Vob2xkZXI6ICdTZWxlY3Qgc291cmNlIGVudmlyb25tZW504oCmJyxcbiAgICAgIG11bHRpcGxlOiBmYWxzZSxcbiAgICAgIHNlYXJjaGFibGU6IHRydWUsXG4gICAgICBvcHRpb25zLFxuICAgIH07XG4gIH1cbn1cbiIsIjxkaXYgY2xhc3M9XCJjcWEtZmxleCBjcWEtZmxleC1jb2wgY3FhLWdhcC00IGNxYS13LWZ1bGxcIj5cblxuICA8IS0tIFNvdXJjZSBlbnYgcGlja2VyOiByZXF1aXJlZCBpbiBjbG9uZSBtb2RlLCBvcHRpb25hbCBpbiBhc3NpZ24gbW9kZSAtLT5cbiAgPGRpdiAqbmdJZj1cInNob3dTb3VyY2VQaWNrZXJcIiBjbGFzcz1cImNxYS1mbGV4IGNxYS1mbGV4LWNvbCBjcWEtZ2FwLTJcIj5cbiAgICA8bGFiZWwgY2xhc3M9XCJjcWEtdGV4dC1zbSBjcWEtZm9udC1tZWRpdW0gY3FhLXRleHQtZ3JheS03MDBcIj57eyBzb3VyY2VMYWJlbCB9fTwvbGFiZWw+XG4gICAgPGNxYS1keW5hbWljLXNlbGVjdFxuICAgICAgW2Zvcm1dPVwic291cmNlRm9ybVwiXG4gICAgICBbY29uZmlnXT1cInNvdXJjZUNvbmZpZ1wiPlxuICAgIDwvY3FhLWR5bmFtaWMtc2VsZWN0PlxuICAgIDxzcGFuIFtjbGFzcy5jcWEtdGV4dC1yZWQtNjAwXT1cInNvdXJjZUVycm9yXCIgW2NsYXNzLmNxYS10ZXh0LWdyYXktNTAwXT1cIiFzb3VyY2VFcnJvclwiIGNsYXNzPVwiY3FhLXRleHQteHNcIj5cbiAgICAgIHt7IHNvdXJjZUhlbHBlciB9fVxuICAgIDwvc3Bhbj5cbiAgPC9kaXY+XG5cbiAgPCEtLSBTZWxlY3RhYmxlIGVudnMgLS0+XG4gIDxkaXZcbiAgICAqbmdJZj1cImhhc0FueVNlbGVjdGFibGUgfHwgKGVudmlyb25tZW50cz8ubGVuZ3RoIHx8IDApID4gMFwiXG4gICAgY2xhc3M9XCJjcWEtZmxleCBjcWEtZmxleC1jb2wgY3FhLWdhcC0yIGNxYS1tYXgtaC1bMzQwcHhdIGNxYS1vdmVyZmxvdy15LWF1dG9cIj5cbiAgICA8bGFiZWxcbiAgICAgICpuZ0Zvcj1cImxldCBlbnYgb2Ygc2VsZWN0YWJsZUVudmlyb25tZW50c1wiXG4gICAgICBjbGFzcz1cImNxYS1mbGV4IGNxYS1pdGVtcy1jZW50ZXIgY3FhLWdhcC0zIGNxYS1weC0zIGNxYS1weS0yLjUgY3FhLWJvcmRlciBjcWEtcm91bmRlZC1bMTBweF0gY3FhLWJnLXdoaXRlIGNxYS10cmFuc2l0aW9uLWNvbG9yc1wiXG4gICAgICBbY2xhc3MuY3FhLWJvcmRlci1ncmF5LTIwMF09XCIhaXNTZWxlY3RlZChlbnYuaWQpICYmICFlbnYuYWxyZWFkeUFzc2lnbmVkXCJcbiAgICAgIFtjbGFzcy5ob3ZlcjpjcWEtYm9yZGVyLWluZGlnby0yMDBdPVwiIWVudi5hbHJlYWR5QXNzaWduZWQgJiYgIWlzU2VsZWN0ZWQoZW52LmlkKVwiXG4gICAgICBbY2xhc3MuY3FhLWJvcmRlci1pbmRpZ28tNDAwXT1cImlzU2VsZWN0ZWQoZW52LmlkKVwiXG4gICAgICBbY2xhc3MuY3FhLWJnLWluZGlnby01MF09XCJpc1NlbGVjdGVkKGVudi5pZClcIlxuICAgICAgW2NsYXNzLmNxYS1vcGFjaXR5LTUwXT1cImVudi5hbHJlYWR5QXNzaWduZWRcIlxuICAgICAgW2NsYXNzLmNxYS1jdXJzb3ItcG9pbnRlcl09XCIhZW52LmFscmVhZHlBc3NpZ25lZFwiXG4gICAgICBbY2xhc3MuY3FhLWN1cnNvci1ub3QtYWxsb3dlZF09XCJlbnYuYWxyZWFkeUFzc2lnbmVkXCJcbiAgICAgIChjbGljayk9XCJ0b2dnbGUoZW52KVwiPlxuICAgICAgPGlucHV0XG4gICAgICAgIHR5cGU9XCJjaGVja2JveFwiXG4gICAgICAgIGNsYXNzPVwiY3FhLXctNCBjcWEtaC00IGNxYS1jdXJzb3ItcG9pbnRlclwiXG4gICAgICAgIFtjaGVja2VkXT1cImlzU2VsZWN0ZWQoZW52LmlkKVwiXG4gICAgICAgIFtkaXNhYmxlZF09XCIhIWVudi5hbHJlYWR5QXNzaWduZWRcIlxuICAgICAgICAoY2xpY2spPVwiJGV2ZW50LnN0b3BQcm9wYWdhdGlvbigpXCJcbiAgICAgICAgKGNoYW5nZSk9XCJ0b2dnbGUoZW52KVwiIC8+XG5cbiAgICAgIDxzcGFuXG4gICAgICAgIGNsYXNzPVwiY3FhLWlubGluZS1ibG9jayBjcWEtdy0yIGNxYS1oLTIgY3FhLXJvdW5kZWQtZnVsbCBjcWEtZmxleC1ub25lXCJcbiAgICAgICAgW3N0eWxlLmJhY2tncm91bmRdPVwiZW52LmNvbG9yIHx8ICcjM0Y0M0VFJ1wiPjwvc3Bhbj5cblxuICAgICAgPGRpdiBjbGFzcz1cImNxYS1mbGV4IGNxYS1mbGV4LWNvbCBjcWEtbWluLXctMCBjcWEtZmxleC0xXCI+XG4gICAgICAgIDxkaXYgY2xhc3M9XCJjcWEtdGV4dC1zbSBjcWEtZm9udC1tZWRpdW0gY3FhLXRleHQtZ3JheS05MDBcIj57eyBlbnYubmFtZSB9fTwvZGl2PlxuICAgICAgICA8ZGl2ICpuZ0lmPVwiaGVscGVyRm9yKGVudilcIiBjbGFzcz1cImNxYS10ZXh0LXhzIGNxYS10ZXh0LWdyYXktNTAwIGNxYS1sZWFkaW5nLVsxLjRdXCI+e3sgaGVscGVyRm9yKGVudikgfX08L2Rpdj5cbiAgICAgIDwvZGl2PlxuICAgIDwvbGFiZWw+XG4gIDwvZGl2PlxuXG4gIDxkaXZcbiAgICAqbmdJZj1cIihlbnZpcm9ubWVudHM/Lmxlbmd0aCB8fCAwKSA9PT0gMFwiXG4gICAgY2xhc3M9XCJjcWEtcHktOCBjcWEtcHgtNCBjcWEtdGV4dC1jZW50ZXIgY3FhLXRleHQtc20gY3FhLXRleHQtZ3JheS01MDBcIj5cbiAgICBBbGwgZW52aXJvbm1lbnRzIGFyZSBhbHJlYWR5IGFzc2lnbmVkIHRvIHRoaXMgcHJvZmlsZS5cbiAgPC9kaXY+XG48L2Rpdj5cbiJdfQ==
352
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXNzaWduLWVudmlyb25tZW50cy1kaWFsb2cuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vc3JjL2xpYi9hc3NpZ24tZW52aXJvbm1lbnRzLWRpYWxvZy9hc3NpZ24tZW52aXJvbm1lbnRzLWRpYWxvZy5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi8uLi9zcmMvbGliL2Fzc2lnbi1lbnZpcm9ubWVudHMtZGlhbG9nL2Fzc2lnbi1lbnZpcm9ubWVudHMtZGlhbG9nLmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFDTCx1QkFBdUIsRUFFdkIsU0FBUyxFQUVULEtBQUssRUFHTCxTQUFTLEdBQ1YsTUFBTSxlQUFlLENBQUM7QUFDdkIsT0FBTyxFQUFFLFdBQVcsRUFBRSxTQUFTLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUN4RCxPQUFPLEVBQWMsT0FBTyxFQUFFLEVBQUUsRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUMvQyxPQUFPLEVBQ0wsVUFBVSxFQUNWLFlBQVksRUFDWixvQkFBb0IsRUFDcEIsU0FBUyxFQUNULFNBQVMsR0FDVixNQUFNLGdCQUFnQixDQUFDOzs7Ozs7O0FBdUJ4QixNQUFNLE9BQU8saUNBQWlDO0lBMEM1QyxZQUE2QixHQUFzQjtRQUF0QixRQUFHLEdBQUgsR0FBRyxDQUFtQjtRQXpDMUMsU0FBSSxHQUEyQixRQUFRLENBQUM7UUFDeEMsZ0JBQVcsR0FBVyxFQUFFLENBQUM7UUFLekIsYUFBUSxHQUFHLEVBQUUsQ0FBQztRQUV2Qjs7dURBRStDO1FBQ3RDLHlCQUFvQixHQUE4QixFQUFFLENBQUM7UUFLOUMsYUFBUSxHQUFHLElBQUksR0FBRyxFQUFVLENBQUM7UUFDdEMscUJBQWdCLEdBQThCLEVBQUUsQ0FBQztRQUVqRCxlQUFVLEdBQUcsRUFBRSxDQUFDO1FBQ2hCLHFCQUFnQixHQUFHLEtBQUssQ0FBQztRQUN6QixrQkFBYSxHQUFHLEtB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S0FBSztnQkFHRyxrQkFBa0I7c0JBQTFCLEtBQUs7Z0JBcUI4QyxhQUFhO3NCQUFoRSxTQUFTO3VCQUFDLFlBQVksRUFBRSxFQUFFLE1BQU0sRUFBRSxLQUFLLEVBQUUiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xuICBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneSxcbiAgQ2hhbmdlRGV0ZWN0b3JSZWYsXG4gIENvbXBvbmVudCxcbiAgRWxlbWVudFJlZixcbiAgSW5wdXQsXG4gIE9uRGVzdHJveSxcbiAgT25Jbml0LFxuICBWaWV3Q2hpbGQsXG59IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgRm9ybUNvbnRyb2wsIEZvcm1Hcm91cCB9IGZyb20gJ0Bhbmd1bGFyL2Zvcm1zJztcbmltcG9ydCB7IE9ic2VydmFibGUsIFN1YmplY3QsIG9mIH0gZnJvbSAncnhqcyc7XG5pbXBvcnQge1xuICBjYXRjaEVycm9yLFxuICBkZWJvdW5jZVRpbWUsXG4gIGRpc3RpbmN0VW50aWxDaGFuZ2VkLFxuICBzd2l0Y2hNYXAsXG4gIHRha2VVbnRpbCxcbn0gZnJvbSAncnhqcy9vcGVyYXRvcnMnO1xuXG5pbXBvcnQge1xuICBEeW5hbWljU2VsZWN0RmllbGRDb25maWcsXG4gIFNlbGVjdE9wdGlvbixcbn0gZnJvbSAnLi4vZHluYW1pYy1zZWxlY3QvZHluYW1pYy1zZWxlY3QtZmllbGQuY29tcG9uZW50JztcbmltcG9ydCB7IFNlZ21lbnRPcHRpb24gfSBmcm9tICcuLi9zZWdtZW50LWNvbnRyb2wvc2VnbWVudC1jb250cm9sLmNvbXBvbmVudCc7XG5pbXBvcnQge1xuICBBc3NpZ25FbnZTZWFyY2hGbixcbiAgQXNzaWduRW52U2VhcmNoUGFnZSxcbiAgQXNzaWduRW52aXJvbm1lbnRPcHRpb24sXG4gIEFzc2lnbkVudmlyb25tZW50c0RpYWxvZ1ZhbHVlLFxuICBBc3NpZ25FbnZpcm9ubWVudHNNb2RlLFxufSBmcm9tICcuL2Fzc2lnbi1lbnZpcm9ubWVudHMtZGlhbG9nLm1vZGVscyc7XG5cbnR5cGUgVmlld01vZGUgPSAnYWxsJyB8ICdzZWxlY3RlZCc7XG5cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ2NxYS1hc3NpZ24tZW52aXJvbm1lbnRzLWRpYWxvZycsXG4gIHRlbXBsYXRlVXJsOiAnLi9hc3NpZ24tZW52aXJvbm1lbnRzLWRpYWxvZy5jb21wb25lbnQuaHRtbCcsXG4gIGNoYW5nZURldGVjdGlvbjogQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3kuT25QdXNoLFxuICBob3N0OiB7IGNsYXNzOiAnY3FhLXVpLXJvb3QnLCBzdHlsZTogJ2Rpc3BsYXk6YmxvY2s7d2lkdGg6MTAwJTsnIH0sXG59KVxuZXhwb3J0IGNsYXNzIEFzc2lnbkVudmlyb25tZW50c0RpYWxvZ0NvbXBvbmVudCBpbXBsZW1lbnRzIE9uSW5pdCwgT25EZXN0cm95IHtcbiAgQElucHV0KCkgbW9kZTogQXNzaWduRW52aXJvbm1lbnRzTW9kZSA9ICdhc3NpZ24nO1xuICBASW5wdXQoKSBwcm9maWxlTmFtZTogc3RyaW5nID0gJyc7XG5cbiAgLyoqIFBhZ2luYXRlZCBzZWFyY2ggY2FsbGJhY2suIEZpcmVzIGAoJycsIDAsIHBhZ2VTaXplKWAgb24gb3BlbiBhbmQgb24gZXZlcnlcbiAgICogIHNjcm9sbC1uZWFyLWJvdHRvbSAobmV4dCBwYWdlKSBvciBkaXN0aW5jdCBzZWFyY2ggdGVybSAocGFnZSByZXNldCkuICovXG4gIEBJbnB1dCgpIHNlYXJjaEZuPzogQXNzaWduRW52U2VhcmNoRm47XG4gIEBJbnB1dCgpIHBhZ2VTaXplID0gNTA7XG5cbiAgLyoqIFNvdXJjZS1lbnYgY2FuZGlkYXRlcyB0aGUgcGVyLXJvdyBcIkNvcHkgZnJvbSB3aGljaCBlbnZpcm9ubWVudFwiIHBpY2tlclxuICAgKiAgcG9wdWxhdGVzIGZyb20uIFN5bmNocm9ub3VzIGxpc3Qg4oCUIHR5cGljYWxseSBib3VuZGVkIGJ5IHRoZSBwcm9maWxlJ3NcbiAgICogIGN1cnJlbnQgYXR0YWNobWVudHMgKHNtYWxsLCBvZnRlbiA8IDEwKS4gKi9cbiAgQElucHV0KCkgYXNzaWduZWRFbnZpcm9ubWVudHM6IEFzc2lnbkVudmlyb25tZW50T3B0aW9uW10gPSBbXTtcblxuICAvKiogUHJlLXNlbGVjdCB0aGlzIHNvdXJjZSBmb3IgbmV3bHktdG9nZ2xlZCB0YXJnZXRzLiAqL1xuICBASW5wdXQoKSBkZWZhdWx0U291cmNlRW52SWQ/OiBudW1iZXI7XG5cbiAgcHVibGljIHJlYWRvbmx5IHNlbGVjdGVkID0gbmV3IFNldDxudW1iZXI+KCk7XG4gIHB1YmxpYyBzZWxlY3RlZFNuYXBzaG90OiBBc3NpZ25FbnZpcm9ubWVudE9wdGlvbltdID0gW107XG5cbiAgcHVibGljIHNlYXJjaFRlcm0gPSAnJztcbiAgcHVibGljIGlzSW5pdGlhbExvYWRpbmcgPSBmYWxzZTtcbiAgcHVibGljIGlzTG9hZGluZ01vcmUgPSBmYWxzZTtcbiAgcHVibGljIGN1cnJlbnRSZXN1bHRzOiBBc3NpZ25FbnZpcm9ubWVudE9wdGlvbltdID0gW107XG4gIHB1YmxpYyB0b3RhbEVsZW1lbnRzID0gMDtcblxuICBwdWJsaWMgdmlld01vZGU6IFZpZXdNb2RlID0gJ2FsbCc7XG4gIC8qKiBTdGFibGUgc2VnbWVudCBhcnJheSDigJQgcmVjb21wdXRlZCBvbmx5IHdoZW4gc2VsZWN0aW9uIHNpemUgZmxpcHMgemVybyDihpQgbm9uLXplcm8uICovXG4gIHB1YmxpYyB2aWV3U2VnbWVudHM6IFNlZ21lbnRPcHRpb25bXSA9IHRoaXMuY29tcHV0ZVZpZXdTZWdtZW50cygpO1xuXG4gIC8qKiBPbmUgRm9ybUdyb3VwLCBjb250cm9scyBrZXllZCBgdGd0XyR7dGFyZ2V0RW52SWR9YC4gKi9cbiAgcHVibGljIHJlYWRvbmx5IHNvdXJjZUZvcm0gPSBuZXcgRm9ybUdyb3VwKHt9KTtcbiAgcHVibGljIHJlYWRvbmx5IHNvdXJjZUNvbmZpZ0J5SWQgPSBuZXcgTWFwPG51bWJlciwgRHluYW1pY1NlbGVjdEZpZWxkQ29uZmlnPigpO1xuXG4gIHB1YmxpYyByZWFkb25seSBza2VsZXRvblJvd3MgPSBbMCwgMSwgMiwgMywgNF07XG5cbiAgQFZpZXdDaGlsZCgnbGlzdFNjcm9sbCcsIHsgc3RhdGljOiBmYWxzZSB9KSBwcml2YXRlIGxpc3RTY3JvbGxSZWY/OiBFbGVtZW50UmVmPEhUTUxFbGVtZW50PjtcblxuICBwcml2YXRlIHBhZ2VJbmRleCA9IDA7XG4gIHByaXZhdGUgcmVhZG9ubHkgc2VhcmNoSW5wdXQkID0gbmV3IFN1YmplY3Q8c3RyaW5nPigpO1xuICBwcml2YXRlIHJlYWRvbmx5IGRlc3Ryb3kkID0gbmV3IFN1YmplY3Q8dm9pZD4oKTtcblxuICBjb25zdHJ1Y3Rvcihwcml2YXRlIHJlYWRvbmx5IGNkcjogQ2hhbmdlRGV0ZWN0b3JSZWYpIHt9XG5cbiAgbmdPbkluaXQoKTogdm9pZCB7XG4gICAgLy8gU2VhcmNoLXRlcm0gcGlwZWxpbmU6IGV2ZXJ5IGRpc3RpbmN0LCBkZWJvdW5jZWQgdGVybSByZXNldHMgdGhlIHBhZ2UgYW5kXG4gICAgLy8gcmVwbGFjZXMgdGhlIHZpc2libGUgbGlzdC5cbiAgICB0aGlzLnNlYXJjaElucHV0JFxuICAgICAgLnBpcGUoXG4gICAgICAgIGRlYm91bmNlVGltZSgzMDApLFxuICAgICAgICBkaXN0aW5jdFVudGlsQ2hhbmdlZCgpLFxuICAgICAgICBzd2l0Y2hNYXAodGVybSA9PiB0aGlzLmZldGNoUGFnZSh0ZXJtLCAwKSksXG4gICAgICAgIHRha2VVbnRpbCh0aGlzLmRlc3Ryb3kkKSxcbiAgICAgIClcbiAgICAgIC5zdWJzY3JpYmUoKHsgdGVybSwgcGFnZSwgcGF5bG9hZCB9KSA9PiB7XG4gICAgICAgIHRoaXMuYXBwbHlQYWdlKHRlcm0sIHBhZ2UsIC8qIGFwcGVuZCAqLyBmYWxzZSwgcGF5bG9hZCk7XG4gICAgICB9KTtcblxuICAgIC8vIEluaXRpYWwgcGFnZS0wIGZldGNoIG9uIGRpYWxvZyBvcGVuLlxuICAgIHRoaXMucnVuRmV0Y2goJycsIDAsIC8qIGFwcGVuZCAqLyBmYWxzZSk7XG4gIH1cblxuICBuZ09uRGVzdHJveSgpOiB2b2lkIHtcbiAgICB0aGlzLmRlc3Ryb3kkLm5leHQoKTtcbiAgICB0aGlzLmRlc3Ryb3kkLmNvbXBsZXRlKCk7XG4gIH1cblxuICAvLyAtLSBQdWJsaWMgdGVtcGxhdGUgc3RhdGUgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxuICBwdWJsaWMgZ2V0IHRpdGxlKCk6IHN0cmluZyB7XG4gICAgcmV0dXJuIHRoaXMubW9kZSA9PT0gJ2Nsb25lJyA/ICdDbG9uZSB0byBvdGhlciBlbnZpcm9ubWVudHMnIDogJ0Fzc2lnbiB0byBlbnZpcm9ubWVudHMnO1xuICB9XG5cbiAgcHVibGljIGdldCBzdWJ0aXRsZSgpOiBzdHJpbmcge1xuICAgIGNvbnN0IG5hbWUgPSB0aGlzLnByb2ZpbGVOYW1lID8gYFwiJHt0aGlzLnByb2ZpbGVOYW1lfVwiYCA6ICd0aGlzIHByb2ZpbGUnO1xuICAgIHJldHVybiB0aGlzLm1vZGUgPT09ICdjbG9uZSdcbiAgICAgID8gYER1cGxpY2F0ZSAke25hbWV9IGludG8gb3RoZXIgZW52aXJvbm1lbnRzLiBDb2x1bW4gc3RydWN0dXJlIGlzIHNoYXJlZDsgcm93IHZhbHVlcyBhcmUgaW5kZXBlbmRlbnQgcGVyIGVudmlyb25tZW50LmBcbiAgICAgIDogYE1ha2UgJHtuYW1lfSBhdmFpbGFibGUgaW4gdGhlIHNlbGVjdGVkIGVudmlyb25tZW50cy4gQ29sdW1ucyBhcmUgc2hhcmVkIOKAlCBlYWNoIGVudmlyb25tZW50IGdldHMgYW4gaW5kZXBlbmRlbnQgcm93IHNldC5gO1xuICB9XG5cbiAgcHVibGljIGdldCBzaG93UGVyUm93U291cmNlKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiAodGhpcy5hc3NpZ25lZEVudmlyb25tZW50cz8ubGVuZ3RoID8/IDApID4gMDtcbiAgfVxuXG4gIHB1YmxpYyBnZXQgaXNFbXB0eSgpOiBib29sZWFuIHtcbiAgICByZXR1cm4gIXRoaXMuY3VycmVudFJlc3VsdHMgfHwgdGhpcy5jdXJyZW50UmVzdWx0cy5sZW5ndGggPT09IDA7XG4gIH1cblxuICBwdWJsaWMgZ2V0IGhhc01vcmUoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMuY3VycmVudFJlc3VsdHMubGVuZ3RoIDwgdGhpcy50b3RhbEVsZW1lbnRzO1xuICB9XG5cbiAgcHVibGljIGdldCBkaXNwbGF5ZWRSb3dzKCk6IEFzc2lnbkVudmlyb25tZW50T3B0aW9uW10ge1xuICAgIHJldHVybiB0aGlzLnZpZXdNb2RlID09PSAnc2VsZWN0ZWQnID8gdGhpcy5zZWxlY3RlZFNuYXBzaG90IDogdGhpcy5jdXJyZW50UmVzdWx0cztcbiAgfVxuXG4gIHB1YmxpYyBnZXQgdW5yZXNvbHZlZFNvdXJjZXNDb3VudCgpOiBudW1iZXIge1xuICAgIGlmICghdGhpcy5zaG93UGVyUm93U291cmNlKSB7IHJldHVybiAwOyB9XG4gICAgbGV0IG4gPSAwO1xuICAgIGZvciAoY29uc3QgZW52IG9mIHRoaXMuc2VsZWN0ZWRTbmFwc2hvdCkge1xuICAgICAgaWYgKGVudi5hbHJlYWR5QXNzaWduZWQpIHsgY29udGludWU7IH1cbiAgICAgIGlmICghdGhpcy5pc1NvdXJjZVJlc29sdmVkKGVudi5pZCkpIHsgbisrOyB9XG4gICAgfVxuICAgIHJldHVybiBuO1xuICB9XG5cbiAgcHVibGljIGdldCBwcmltYXJ5QnV0dG9uTGFiZWwoKTogc3RyaW5nIHtcbiAgICBjb25zdCBjb3VudCA9IHRoaXMuc2VsZWN0ZWQuc2l6ZTtcbiAgICBjb25zdCB2ZXJiID0gdGhpcy5tb2RlID09PSAnY2xvbmUnID8gJ0Nsb25lIHRvJyA6ICdBc3NpZ24gdG8nO1xuICAgIHJldHVybiBgJHt2ZXJifSAke2NvdW50fSBlbnZpcm9ubWVudCR7Y291bnQgPT09IDEgPyAnJyA6ICdzJ31gO1xuICB9XG5cbiAgcHVibGljIGdldCBwcmltYXJ5RGlzYWJsZWQoKTogYm9vbGVhbiB7XG4gICAgaWYgKHRoaXMuc2VsZWN0ZWQuc2l6ZSA9PT0gMCkgeyByZXR1cm4gdHJ1ZTsgfVxuICAgIGlmICh0aGlzLnVucmVzb2x2ZWRTb3VyY2VzQ291bnQgPiAwKSB7IHJldHVybiB0cnVlOyB9XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG5cbiAgcHVibGljIGlzU2VsZWN0ZWQoaWQ6IG51bWJlcik6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLnNlbGVjdGVkLmhhcyhpZCk7XG4gIH1cblxuICBwdWJsaWMgaXNTb3VyY2VSZXNvbHZlZCh0YXJnZXRFbnZJZDogbnVtYmVyKTogYm9vbGVhbiB7XG4gICAgaWYgKCF0aGlzLnNob3dQZXJSb3dTb3VyY2UpIHsgcmV0dXJuIHRydWU7IH1cbiAgICBjb25zdCBjdHJsID0gdGhpcy5zb3VyY2VGb3JtLmdldCh0aGlzLmNvbnRyb2xLZXkodGFyZ2V0RW52SWQpKTtcbiAgICByZXR1cm4gY3RybD8udmFsdWUgIT0gbnVsbDtcbiAgfVxuXG4gIHB1YmxpYyBnZXRTb3VyY2VDb25maWcodGFyZ2V0RW52SWQ6IG51bWJlcik6IER5bmFtaWNTZWxlY3RGaWVsZENvbmZpZyB8IHVuZGVmaW5lZCB7XG4gICAgcmV0dXJuIHRoaXMuc291cmNlQ29uZmlnQnlJZC5nZXQodGFyZ2V0RW52SWQpO1xuICB9XG5cbiAgcHVibGljIHBpY2tlZFNvdXJjZU5hbWUodGFyZ2V0RW52SWQ6IG51bWJlcik6IHN0cmluZyB7XG4gICAgY29uc3QgdmFsdWUgPSB0aGlzLnNvdXJjZUZvcm0uZ2V0KHRoaXMuY29udHJvbEtleSh0YXJnZXRFbnZJZCkpPy52YWx1ZTtcbiAgICBpZiAodmFsdWUgPT0gbnVsbCkgeyByZXR1cm4gJyc7IH1cbiAgICBjb25zdCBlbnYgPSAodGhpcy5hc3NpZ25lZEVudmlyb25tZW50cyB8fCBbXSkuZmluZChlID0+IE51bWJlcihlLmlkKSA9PT0gTnVtYmVyKHZhbHVlKSk7XG4gICAgcmV0dXJuIGVudiA/IGVudi5uYW1lIDogJyc7XG4gIH1cblxuICBwdWJsaWMgaGVscGVyRm9yKGVudjogQXNzaWduRW52aXJvbm1lbnRPcHRpb24pOiBzdHJpbmcge1xuICAgIGlmIChlbnYuYWxyZWFkeUFzc2lnbmVkKSB7IHJldHVybiAnQWxyZWFkeSBhc3NpZ25lZCB0byB0aGlzIGVudmlyb25tZW50JzsgfVxuICAgIHJldHVybiBlbnYuZGVzY3JpcHRpb24gfHwgJyc7XG4gIH1cblxuICBwdWJsaWMgdHJhY2tCeUlkKF9pbmRleDogbnVtYmVyLCBlbnY6IEFzc2lnbkVudmlyb25tZW50T3B0aW9uKTogbnVtYmVyIHtcbiAgICByZXR1cm4gZW52LmlkO1xuICB9XG5cbiAgLy8gLS0gUHVibGljIHRlbXBsYXRlIGV2ZW50cyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxuICBwdWJsaWMgb25TZWFyY2hDaGFuZ2UodGVybTogc3RyaW5nKTogdm9pZCB7XG4gICAgdGhpcy5zZWFyY2hUZXJtID0gdGVybSA/PyAnJztcbiAgICB0aGlzLmlzSW5pdGlhbExvYWRpbmcgPSB0cnVlO1xuICAgIHRoaXMuY3VycmVudFJlc3VsdHMgPSBbXTtcbiAgICB0aGlzLmNkci5tYXJrRm9yQ2hlY2soKTtcbiAgICB0aGlzLnNlYXJjaElucHV0JC5uZXh0KHRoaXMuc2VhcmNoVGVybSk7XG4gIH1cblxuICBwdWJsaWMgb25WaWV3TW9kZUNoYW5nZSh2YWx1ZTogc3RyaW5nKTogdm9pZCB7XG4gICAgdGhpcy52aWV3TW9kZSA9IHZhbHVlID09PSAnc2VsZWN0ZWQnID8gJ3NlbGVjdGVkJyA6ICdhbGwnO1xuICAgIHRoaXMuY2RyLm1hcmtGb3JDaGVjaygpO1xuICB9XG5cbiAgcHVibGljIHRvZ2dsZShlbnY6IEFzc2lnbkVudmlyb25tZW50T3B0aW9uKTogdm9pZCB7XG4gICAgaWYgKGVudj8uYWxyZWFkeUFzc2lnbmVkKSB7IHJldHVybjsgfVxuICAgIGNvbnN0IGlkID0gTnVtYmVyKGVudi5pZCk7XG4gICAgY29uc3Qgd2FzWmVybyA9IHRoaXMuc2VsZWN0ZWQuc2l6ZSA9PT0gMDtcbiAgICBpZiAodGhpcy5zZWxlY3RlZC5oYXMoaWQpKSB7XG4gICAgICB0aGlzLnNlbGVjdGVkLmRlbGV0ZShpZCk7XG4gICAgICB0aGlzLnNlbGVjdGVkU25hcHNob3QgPSB0aGlzLnNlbGVjdGVkU25hcHNob3QuZmlsdGVyKGUgPT4gTnVtYmVyKGUuaWQpICE9PSBpZCk7XG4gICAgICB0aGlzLnJlbW92ZVNvdXJjZVN0YXRlKGlkKTtcbiAgICAgIC8vIElmIHRoZSBTZWxlY3RlZCB2aWV3IGp1c3QgZW1wdGllZCwgZmFsbCBiYWNrIHRvIEFsbCBzbyB0aGUgdXNlclxuICAgICAgLy8gZG9lc24ndCBzaXQgb24gYSBibGFuayBzY3JlZW4uXG4gICAgICBpZiAodGhpcy52aWV3TW9kZSA9PT0gJ3NlbGVjdGVkJyAmJiB0aGlzLnNlbGVjdGVkU25hcHNob3QubGVuZ3RoID09PSAwKSB7XG4gICAgICAgIHRoaXMudmlld01vZGUgPSAnYWxsJztcbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5zZWxlY3RlZC5hZGQoaWQpO1xuICAgICAgdGhpcy5zZWxlY3RlZFNuYXBzaG90ID0gWy4uLnRoaXMuc2VsZWN0ZWRTbmFwc2hvdCwgZW52XTtcbiAgICAgIHRoaXMuZW5zdXJlU291cmNlU3RhdGUoaWQpO1xuICAgIH1cbiAgICBjb25zdCBpc1plcm8gPSB0aGlzLnNlbGVjdGVkLnNpemUgPT09IDA7XG4gICAgaWYgKHdhc1plcm8gIT09IGlzWmVybykge1xuICAgICAgdGhpcy52aWV3U2VnbWVudHMgPSB0aGlzLmNvbXB1dGVWaWV3U2VnbWVudHMoKTtcbiAgICB9IGVsc2Uge1xuICAgICAgLy8gS2VlcCB0aGUgY291bnQgdXAgdG8gZGF0ZSBldmVuIHdoZW4gemVybyDihpQgbm9uLXplcm8gZGlkbid0IGZsaXAuXG4gICAgICB0aGlzLnZpZXdTZWdtZW50cyA9IHRoaXMuY29tcHV0ZVZpZXdTZWdtZW50cygpO1xuICAgIH1cbiAgICB0aGlzLmNkci5tYXJrRm9yQ2hlY2soKTtcbiAgfVxuXG4gIHB1YmxpYyBvbkxpc3RTY3JvbGwoKTogdm9pZCB7XG4gICAgY29uc3QgZWwgPSB0aGlzLmxpc3RTY3JvbGxSZWY/Lm5hdGl2ZUVsZW1lbnQ7XG4gICAgaWYgKCFlbCkgeyByZXR1cm47IH1cbiAgICBpZiAodGhpcy52aWV3TW9kZSA9PT0gJ3NlbGVjdGVkJykgeyByZXR1cm47IH1cbiAgICBpZiAodGhpcy5pc0luaXRpYWxMb2FkaW5nIHx8IHRoaXMuaXNMb2FkaW5nTW9yZSkgeyByZXR1cm47IH1cbiAgICBpZiAoIXRoaXMuaGFzTW9yZSkgeyByZXR1cm47IH1cbiAgICBjb25zdCBkaXN0YW5jZUZyb21Cb3R0b20gPSBlbC5zY3JvbGxIZWlnaHQgLSAoZWwuc2Nyb2xsVG9wICsgZWwuY2xpZW50SGVpZ2h0KTtcbiAgICBpZiAoZGlzdGFuY2VGcm9tQm90dG9tIDwgODApIHtcbiAgICAgIHRoaXMucnVuRmV0Y2godGhpcy5zZWFyY2hUZXJtLCB0aGlzLnBhZ2VJbmRleCArIDEsIC8qIGFwcGVuZCAqLyB0cnVlKTtcbiAgICB9XG4gIH1cblxuICBwdWJsaWMgZ2V0VmFsdWUoKTogQXNzaWduRW52aXJvbm1lbnRzRGlhbG9nVmFsdWUgfCBudWxsIHtcbiAgICBpZiAodGhpcy5zZWxlY3RlZC5zaXplID09PSAwKSB7IHJldHVybiBudWxsOyB9XG4gICAgaWYgKHRoaXMudW5yZXNvbHZlZFNvdXJjZXNDb3VudCA+IDApIHsgcmV0dXJuIG51bGw7IH1cblxuICAgIGlmICghdGhpcy5zaG93UGVyUm93U291cmNlKSB7XG4gICAgICByZXR1cm4geyBzZWxlY3RlZElkczogQXJyYXkuZnJvbSh0aGlzLnNlbGVjdGVkKSwgc291cmNlczogW10gfTtcbiAgICB9XG5cbiAgICBjb25zdCBzb3VyY2VzID0gQXJyYXkuZnJvbSh0aGlzLnNlbGVjdGVkKS5tYXAoaWQgPT4ge1xuICAgICAgY29uc3QgdmFsdWUgPSB0aGlzLnNvdXJjZUZvcm0uZ2V0KHRoaXMuY29udHJvbEtleShpZCkpPy52YWx1ZTtcbiAgICAgIHJldHVybiB7IHRhcmdldEVudklkOiBpZCwgc291cmNlRW52SWQ6IE51bWJlcih2YWx1ZSkgfTtcbiAgICB9KTtcbiAgICByZXR1cm4geyBzZWxlY3RlZElkczogQXJyYXkuZnJvbSh0aGlzLnNlbGVjdGVkKSwgc291cmNlcyB9O1xuICB9XG5cbiAgLy8gLS0gSW50ZXJuYWxzIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cbiAgcHJpdmF0ZSBjb250cm9sS2V5KHRhcmdldEVudklkOiBudW1iZXIpOiBzdHJpbmcge1xuICAgIHJldHVybiBgdGd0XyR7dGFyZ2V0RW52SWR9YDtcbiAgfVxuXG4gIHByaXZhdGUgY29tcHV0ZVZpZXdTZWdtZW50cygpOiBTZWdtZW50T3B0aW9uW10ge1xuICAgIGNvbnN0IGNvdW50ID0gdGhpcy5zZWxlY3RlZC5zaXplO1xuICAgIHJldHVybiBbXG4gICAgICB7IGxhYmVsOiAnQWxsJywgdmFsdWU6ICdhbGwnIH0sXG4gICAgICBjb3VudCA+IDBcbiAgICAgICAgPyB7IGxhYmVsOiAnU2VsZWN0ZWQnLCB2YWx1ZTogJ3NlbGVjdGVkJywgY291bnQgfVxuICAgICAgICA6IHsgbGFiZWw6ICdTZWxlY3RlZCcsIHZhbHVlOiAnc2VsZWN0ZWQnIH0sXG4gICAgXTtcbiAgfVxuXG4gIHByaXZhdGUgZW5zdXJlU291cmNlU3RhdGUodGFyZ2V0RW52SWQ6IG51bWJlcik6IHZvaWQge1xuICAgIGlmICghdGhpcy5zaG93UGVyUm93U291cmNlKSB7IHJldHVybjsgfVxuICAgIGlmICghdGhpcy5zb3VyY2VGb3JtLmNvbnRhaW5zKHRoaXMuY29udHJvbEtleSh0YXJnZXRFbnZJZCkpKSB7XG4gICAgICB0aGlzLnNvdXJjZUZvcm0uYWRkQ29udHJvbCh0aGlzLmNvbnRyb2xLZXkodGFyZ2V0RW52SWQpLCBuZXcgRm9ybUNvbnRyb2wobnVsbCkpO1xuICAgIH1cbiAgICBpZiAoIXRoaXMuc291cmNlQ29uZmlnQnlJZC5oYXModGFyZ2V0RW52SWQpKSB7XG4gICAgICB0aGlzLnNvdXJjZUNvbmZpZ0J5SWQuc2V0KHRhcmdldEVudklkLCB0aGlzLmJ1aWxkU291cmNlQ29uZmlnKHRhcmdldEVudklkKSk7XG4gICAgfVxuICAgIC8vIFByZS1zZWxlY3QgdGhlIGRlZmF1bHQgc291cmNlIGlmIHRoZSBjYWxsZXIgc3VnZ2VzdGVkIG9uZSAoYW5kIGl0J3MgYVxuICAgIC8vIHZhbGlkIGNhbmRpZGF0ZSkuIFNhdmVzIHRoZSB1c2VyIGEgY2xpY2sgd2hlbiB0aGVyZSdzIGFuIG9idmlvdXMgY2hvaWNlLlxuICAgIGNvbnN0IGN0cmwgPSB0aGlzLnNvdXJjZUZvcm0uZ2V0KHRoaXMuY29udHJvbEtleSh0YXJnZXRFbnZJZCkpO1xuICAgIGlmIChjdHJsICYmIGN0cmwudmFsdWUgPT0gbnVsbCkge1xuICAgICAgY29uc3QgZGVmYXVsdElkID0gdGhpcy5yZXNvbHZlRGVmYXVsdFNvdXJjZUlkKHRhcmdldEVudklkKTtcbiAgICAgIGlmIChkZWZhdWx0SWQgIT0gbnVsbCkge1xuICAgICAgICBjdHJsLnNldFZhbHVlKGRlZmF1bHRJZCk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSByZW1vdmVTb3VyY2VTdGF0ZSh0YXJnZXRFbnZJZDogbnVtYmVyKTogdm9pZCB7XG4gICAgY29uc3Qga2V5ID0gdGhpcy5jb250cm9sS2V5KHRhcmdldEVudklkKTtcbiAgICBpZiAodGhpcy5zb3VyY2VGb3JtLmNvbnRhaW5zKGtleSkpIHsgdGhpcy5zb3VyY2VGb3JtLnJlbW92ZUNvbnRyb2woa2V5KTsgfVxuICAgIHRoaXMuc291cmNlQ29uZmlnQnlJZC5kZWxldGUodGFyZ2V0RW52SWQpO1xuICB9XG5cbiAgcHJpdmF0ZSBidWlsZFNvdXJjZUNvbmZpZyh0YXJnZXRFbnZJZDogbnVtYmVyKTogRHluYW1pY1NlbGVjdEZpZWxkQ29uZmlnIHtcbiAgICAvLyBGaWx0ZXIgdGhlIHRhcmdldCBvdXQgb2YgaXRzIG93biBzb3VyY2UgbGlzdCDigJQgY29weWluZyBhbiBlbnYgaW50b1xuICAgIC8vIGl0c2VsZiBpcyBub24tc2Vuc2ljYWwuXG4gICAgY29uc3QgY2FuZGlkYXRlcyA9ICh0aGlzLmFzc2lnbmVkRW52aXJvbm1lbnRzIHx8IFtdKS5maWx0ZXIoZSA9PiBOdW1iZXIoZS5pZCkgIT09IE51bWJlcih0YXJnZXRFbnZJZCkpO1xuICAgIGNvbnN0IG9wdGlvbnM6IFNlbGVjdE9wdGlvbltdID0gY2FuZGlkYXRlcy5tYXAoZSA9PiAoe1xuICAgICAgaWQ6IGUuaWQsXG4gICAgICB2YWx1ZTogZS5pZCxcbiAgICAgIG5hbWU6IGUubmFtZSxcbiAgICAgIGxhYmVsOiBlLm5hbWUsXG4gICAgICBzdGF0dXNDb2xvcjogZS5jb2xvcixcbiAgICB9KSk7XG4gICAgcmV0dXJuIHtcbiAgICAgIGtleTogdGhpcy5jb250cm9sS2V5KHRhcmdldEVudklkKSxcbiAgICAgIGxhYmVsOiAnJyxcbiAgICAgIHBsYWNlaG9sZGVyOiAnU2VsZWN0IHNvdXJjZSBlbnZpcm9ubWVudOKApicsXG4gICAgICBtdWx0aXBsZTogZmFsc2UsXG4gICAgICBzZWFyY2hhYmxlOiBvcHRpb25zLmxlbmd0aCA+IDYsXG4gICAgICBvcHRpb25zLFxuICAgIH07XG4gIH1cblxuICBwcml2YXRlIHJlc29sdmVEZWZhdWx0U291cmNlSWQodGFyZ2V0RW52SWQ6IG51bWJlcik6IG51bWJlciB8IG51bGwge1xuICAgIGNvbnN0IGNhbmRpZGF0ZXMgPSAodGhpcy5hc3NpZ25lZEVudmlyb25tZW50cyB8fCBbXSkuZmlsdGVyKGUgPT4gTnVtYmVyKGUuaWQpICE9PSBOdW1iZXIodGFyZ2V0RW52SWQpKTtcbiAgICBpZiAoY2FuZGlkYXRlcy5sZW5ndGggPT09IDApIHsgcmV0dXJuIG51bGw7IH1cbiAgICBpZiAodGhpcy5kZWZhdWx0U291cmNlRW52SWQgIT0gbnVsbCkge1xuICAgICAgY29uc3QgbWF0Y2ggPSBjYW5kaWRhdGVzLmZpbmQoZSA9PiBOdW1iZXIoZS5pZCkgPT09IE51bWJlcih0aGlzLmRlZmF1bHRTb3VyY2VFbnZJZCkpO1xuICAgICAgaWYgKG1hdGNoKSB7IHJldHVybiBOdW1iZXIobWF0Y2guaWQpOyB9XG4gICAgfVxuICAgIGlmICh0aGlzLm1vZGUgPT09ICdjbG9uZScpIHtcbiAgICAgIC8vIENsb25lIGltcGxpZXMgYSBzb3VyY2Ugd2FzIGFscmVhZHkgaW4gc2NvcGUg4oCUIHBpY2sgdGhlIGZpcnN0IGF0dGFjaGVkIGVudi5cbiAgICAgIHJldHVybiBOdW1iZXIoY2FuZGlkYXRlc1swXS5pZCk7XG4gICAgfVxuICAgIHJldHVybiBudWxsO1xuICB9XG5cbiAgLy8gLS0gRmV0Y2ggcGlwZWxpbmUgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cbiAgcHJpdmF0ZSBydW5GZXRjaCh0ZXJtOiBzdHJpbmcsIHBhZ2U6IG51bWJlciwgYXBwZW5kOiBib29sZWFuKTogdm9pZCB7XG4gICAgaWYgKGFwcGVuZCkge1xuICAgICAgdGhpcy5pc0xvYWRpbmdNb3JlID0gdHJ1ZTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5pc0luaXRpYWxMb2FkaW5nID0gdHJ1ZTtcbiAgICB9XG4gICAgdGhpcy5jZHIubWFya0ZvckNoZWNrKCk7XG5cbiAgICB0aGlzLmZldGNoUGFnZSh0ZXJtLCBwYWdlKVxuICAgICAgLnBpcGUodGFrZVVudGlsKHRoaXMuZGVzdHJveSQpKVxuICAgICAgLnN1YnNjcmliZShyZXN1bHQgPT4ge1xuICAgICAgICB0aGlzLmFwcGx5UGFnZShyZXN1bHQudGVybSwgcmVzdWx0LnBhZ2UsIGFwcGVuZCwgcmVzdWx0LnBheWxvYWQpO1xuICAgICAgfSk7XG4gIH1cblxuICBwcml2YXRlIGZldGNoUGFnZSh0ZXJtOiBzdHJpbmcsIHBhZ2U6IG51bWJlcik6IE9ic2VydmFibGU8e1xuICAgIHRlcm06IHN0cmluZztcbiAgICBwYWdlOiBudW1iZXI7XG4gICAgcGF5bG9hZDogQXNzaWduRW52U2VhcmNoUGFnZTtcbiAgfT4ge1xuICAgIGlmICghdGhpcy5zZWFyY2hGbikge1xuICAgICAgcmV0dXJuIG9mKHsgdGVybSwgcGFnZSwgcGF5bG9hZDogeyBpdGVtczogW10sIHRvdGFsOiAwIH0gfSk7XG4gICAgfVxuICAgIHJldHVybiB0aGlzLnNlYXJjaEZuKHRlcm0sIHBhZ2UsIHRoaXMucGFnZVNpemUpLnBpcGUoXG4gICAgICBjYXRjaEVycm9yKCgpID0+IG9mPEFzc2lnbkVudlNlYXJjaFBhZ2U+KHsgaXRlbXM6IFtdLCB0b3RhbDogMCB9KSksXG4gICAgICBzd2l0Y2hNYXAocGF5bG9hZCA9PiBvZih7IHRlcm0sIHBhZ2UsIHBheWxvYWQgfSkpLFxuICAgICk7XG4gIH1cblxuICBwcml2YXRlIGFwcGx5UGFnZShcbiAgICB0ZXJtOiBzdHJpbmcsXG4gICAgcGFnZTogbnVtYmVyLFxuICAgIGFwcGVuZDogYm9vbGVhbixcbiAgICBwYXlsb2FkPzogQXNzaWduRW52U2VhcmNoUGFnZSxcbiAgKTogdm9pZCB7XG4gICAgLy8gRHJvcCByZXNwb25zZXMgd2hvc2UgdGVybSBubyBsb25nZXIgbWF0Y2hlcyB0aGUgYWN0aXZlIHNlYXJjaC5cbiAgICBpZiAodGVybSAhPT0gdGhpcy5zZWFyY2hUZXJtKSB7IHJldHVybjsgfVxuXG4gICAgY29uc3QgaXRlbXMgPSBwYXlsb2FkPy5pdGVtcyA/PyBbXTtcbiAgICBjb25zdCB0b3RhbCA9IHBheWxvYWQ/LnRvdGFsID8/IGl0ZW1zLmxlbmd0aDtcblxuICAgIGlmIChhcHBlbmQpIHtcbiAgICAgIHRoaXMuY3VycmVudFJlc3VsdHMgPSBbLi4udGhpcy5jdXJyZW50UmVzdWx0cywgLi4uaXRlbXNdO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLmN1cnJlbnRSZXN1bHRzID0gWy4uLml0ZW1zXTtcbiAgICB9XG4gICAgdGhpcy50b3RhbEVsZW1lbnRzID0gdG90YWw7XG4gICAgdGhpcy5wYWdlSW5kZXggPSBwYWdlO1xuICAgIHRoaXMuaXNJbml0aWFsTG9hZGluZyA9IGZhbHNlO1xuICAgIHRoaXMuaXNMb2FkaW5nTW9yZSA9IGZhbHNlO1xuICAgIHRoaXMuY2RyLm1hcmtGb3JDaGVjaygpO1xuICB9XG59XG4iLCI8ZGl2IGNsYXNzPVwiY3FhLWZsZXggY3FhLWZsZXgtY29sIGNxYS1nYXAtMyBjcWEtdy1mdWxsXCI+XG5cbiAgPCEtLSBBbGwgLyBTZWxlY3RlZCAoTikgdG9nZ2xlLiBWaXNpYmxlIG9ubHkgd2hlbiBzb3VyY2UgcGlja2luZyBpcyBlbmFibGVkXG4gICAgICAgKG90aGVyd2lzZSB0aGlzIGlzIGEgc2luZ2xlLXB1cnBvc2UgcGljayBsaXN0IGFuZCBhIHRvZ2dsZSBpcyBub2lzZSkuIC0tPlxuICA8ZGl2ICpuZ0lmPVwic2hvd1BlclJvd1NvdXJjZVwiIGNsYXNzPVwiY3FhLWZsZXggY3FhLWl0ZW1zLWNlbnRlclwiPlxuICAgIDxjcWEtc2VnbWVudC1jb250cm9sXG4gICAgICBbc2VnbWVudHNdPVwidmlld1NlZ21lbnRzXCJcbiAgICAgIFt2YWx1ZV09XCJ2aWV3TW9kZVwiXG4gICAgICAodmFsdWVDaGFuZ2UpPVwib25WaWV3TW9kZUNoYW5nZSgkZXZlbnQpXCI+XG4gICAgPC9jcWEtc2VnbWVudC1jb250cm9sPlxuICA8L2Rpdj5cblxuICA8ZGl2ICpuZ0lmPVwidmlld01vZGUgPT09ICdhbGwnXCI+XG4gICAgPGNxYS1zZWFyY2gtYmFyXG4gICAgICBwbGFjZWhvbGRlcj1cIlNlYXJjaCBlbnZpcm9ubWVudHMuLi5cIlxuICAgICAgW3ZhbHVlXT1cInNlYXJjaFRlcm1cIlxuICAgICAgW3Nob3dDbGVhcl09XCJ0cnVlXCJcbiAgICAgIFtmdWxsV2lkdGhdPVwidHJ1ZVwiXG4gICAgICAodmFsdWVDaGFuZ2UpPVwib25TZWFyY2hDaGFuZ2UoJGV2ZW50KVwiXG4gICAgICAoc2VhcmNoKT1cIm9uU2VhcmNoQ2hhbmdlKCRldmVudClcIlxuICAgICAgKGNsZWFyZWQpPVwib25TZWFyY2hDaGFuZ2UoJycpXCI+XG4gICAgPC9jcWEtc2VhcmNoLWJhcj5cbiAgPC9kaXY+XG5cbiAgPCEtLSBMb2FkaW5nIHNrZWxldG9uIOKAlCBvbmx5IHJlbGV2YW50IGluIHRoZSBzZWFyY2hhYmxlIFwiQWxsXCIgdmlldy4gLS0+XG4gIDxkaXYgKm5nSWY9XCJ2aWV3TW9kZSA9PT0gJ2FsbCcgJiYgaXNJbml0aWFsTG9hZGluZ1wiIGNsYXNzPVwiY3FhLWZsZXggY3FhLWZsZXgtY29sIGNxYS1nYXAtMS41XCI+XG4gICAgPGRpdiAqbmdGb3I9XCJsZXQgXyBvZiBza2VsZXRvblJvd3NcIlxuICAgICAgICAgY2xhc3M9XCJjcWEtZmxleCBjcWEtaXRlbXMtY2VudGVyIGNxYS1nYXAtMyBjcWEtcHgtMy41IGNxYS1weS0zIGNxYS1yb3VuZGVkLVsxMHB4XVwiXG4gICAgICAgICBbc3R5bGUuYm9yZGVyXT1cIicxcHggc29saWQgI0U1RTdFQidcIlxuICAgICAgICAgW3N0eWxlLmJhY2tncm91bmRdPVwiJyNGRkZGRkYnXCI+XG4gICAgICA8ZGl2IGNsYXNzPVwiY3FhLWFlZC1zaGltbWVyIGNxYS1yb3VuZGVkLVs0cHhdXCIgW3N0eWxlLndpZHRoLnB4XT1cIjE2XCIgW3N0eWxlLmhlaWdodC5weF09XCIxNlwiPjwvZGl2PlxuICAgICAgPGRpdiBjbGFzcz1cImNxYS1hZWQtc2hpbW1lciBjcWEtcm91bmRlZC1mdWxsXCIgW3N0eWxlLndpZHRoLnB4XT1cIjEwXCIgW3N0eWxlLmhlaWdodC5weF09XCIxMFwiPjwvZGl2PlxuICAgICAgPGRpdiBjbGFzcz1cImNxYS1mbGV4IGNxYS1mbGV4LWNvbCBjcWEtZ2FwLTEuNSBjcWEtZmxleC0xXCI+XG4gICAgICAgIDxkaXYgY2xhc3M9XCJjcWEtYWVkLXNoaW1tZXIgY3FhLXJvdW5kZWQtWzNweF1cIiBzdHlsZT1cImhlaWdodDogMTBweDsgd2lkdGg6IDE2MHB4O1wiPjwvZGl2PlxuICAgICAgICA8ZGl2IGNsYXNzPVwiY3FhLWFlZC1zaGltbWVyIGNxYS1yb3VuZGVkLVszcHhdXCIgc3R5bGU9XCJoZWlnaHQ6IDhweDsgd2lkdGg6IDIyMHB4O1wiPjwvZGl2PlxuICAgICAgPC9kaXY+XG4gICAgPC9kaXY+XG4gIDwvZGl2PlxuXG4gIDxkaXZcbiAgICAqbmdJZj1cInZpZXdNb2RlID09PSAnYWxsJyAmJiAhaXNJbml0aWFsTG9hZGluZyAmJiBpc0VtcHR5XCJcbiAgICBjbGFzcz1cImNxYS1weS04IGNxYS1weC00IGNxYS10ZXh0LWNlbnRlciBjcWEtdGV4dC1bMTNweF1cIlxuICAgIFtzdHlsZS5jb2xvcl09XCInIzY0NzQ4QidcIj5cbiAgICA8bmctY29udGFpbmVyICpuZ0lmPVwic2VhcmNoVGVybTsgZWxzZSBub0VudnNUcGxcIj5cbiAgICAgIE5vIGVudmlyb25tZW50cyBtYXRjaCBcInt7IHNlYXJjaFRlcm0gfX1cIi5cbiAgICA8L25nLWNvbnRhaW5lcj5cbiAgICA8bmctdGVtcGxhdGUgI25vRW52c1RwbD5cbiAgICAgIE5vIGVudmlyb25tZW50cyBhdmFpbGFibGUgdG8gYXNzaWduLlxuICAgIDwvbmctdGVtcGxhdGU+XG4gIDwvZGl2PlxuXG4gIDxkaXZcbiAgICAqbmdJZj1cInZpZXdNb2RlID09PSAnc2VsZWN0ZWQnICYmIHNlbGVjdGVkU25hcHNob3QubGVuZ3RoID09PSAwXCJcbiAgICBjbGFzcz1cImNxYS1weS04IGNxYS1weC00IGNxYS10ZXh0LWNlbnRlciBjcWEtdGV4dC1bMTNweF1cIlxuICAgIFtzdHlsZS5jb2xvcl09XCInIzY0NzQ4QidcIj5cbiAgICBOb3RoaW5nIHNlbGVjdGVkIHlldCDigJQgc3dpdGNoIGJhY2sgdG8gXCJBbGxcIiB0byBwaWNrIGVudmlyb25tZW50cy5cbiAgPC9kaXY+XG5cbiAgPGRpdlxuICAgICpuZ0lmPVwiKHZpZXdNb2RlID09PSAnYWxsJyAmJiAhaXNJbml0aWFsTG9hZGluZyAmJiAhaXNFbXB0eSkgfHwgKHZpZXdNb2RlID09PSAnc2VsZWN0ZWQnICYmIHNlbGVjdGVkU25hcHNob3QubGVuZ3RoID4gMClcIlxuICAgICNsaXN0U2Nyb2xsXG4gICAgY2xhc3M9XCJjcWEtZmxleCBjcWEtZmxleC1jb2wgY3FhLWdhcC0xLjUgY3FhLW92ZXJmbG93LXktYXV0byBjcWEtb3ZlcmZsb3cteC1oaWRkZW5cIlxuICAgIHN0eWxlPVwibWF4LWhlaWdodDogNDIwcHg7XCJcbiAgICAoc2Nyb2xsKT1cIm9uTGlzdFNjcm9sbCgpXCI+XG5cbiAgICA8ZGl2XG4gICAgICAqbmdGb3I9XCJsZXQgZW52IG9mIGRpc3BsYXllZFJvd3M7IHRyYWNrQnk6IHRyYWNrQnlJZFwiXG4gICAgICBjbGFzcz1cImNxYS1mbGV4IGNxYS1mbGV4LWNvbCBjcWEtcm91bmRlZC1bMTBweF0gY3FhLXRyYW5zaXRpb24tY29sb3JzIGNxYS1taW4tdy0wXCJcbiAgICAgIFtzdHlsZS5ib3JkZXJdPVwiJzFweCBzb2xpZCAnICsgKGlzU2VsZWN0ZWQoZW52LmlkKSA/ICcjOEE4Q0Y0JyA6ICcjRTVFN0VCJylcIlxuICAgICAgW3N0eWxlLmJhY2tncm91bmRdPVwiaXNTZWxlY3RlZChlbnYuaWQpID8gJyNFRUYwRkYnIDogJyNGRkZGRkYnXCJcbiAgICAgIFtzdHlsZS5vcGFjaXR5XT1cImVudi5hbHJlYWR5QXNzaWduZWQgPyAwLjUgOiAxXCI+XG5cbiAgICAgIDwhLS0gQ2xpY2stdGFyZ2V0IHJlZ2lvbjogY2hlY2tib3ggKyBuYW1lL2Rlc2MgT05MWS4gVGhlIHNvdXJjZSBwaWNrZXJcbiAgICAgICAgICAgYmVsb3cgaXMgYSBTSUJMSU5HIGRpdiAobm90IG5lc3RlZCBpbiB0aGlzIHJlZ2lvbikgc28gY2xpY2tzIG9uXG4gICAgICAgICAgIHRoZSBkcm9wZG93biBuZXZlciB0cmlnZ2VyIHRoZSB0b2dnbGUgaGFuZGxlci4gTkI6IGRvbid0IHdyYXAgdGhlXG4gICAgICAgICAgIHdob2xlIHJvdyBpbiBhIDxsYWJlbD4g4oCUIHRoZSBsYWJlbCdzIG5hdGl2ZSBjbGljayDihpIgY2hlY2tib3hcbiAgICAgICAgICAgYXNzb2NpYXRpb24gZmlyZXMgZXZlbiB3aGVuIGJ1YmJsaW5nIGlzIHN0b3BwZWQuIC0tPlxuICAgICAgPGRpdiBjbGFzcz1cImNxYS1mbGV4IGNxYS1pdGVtcy1jZW50ZXIgY3FhLWdhcC0zIGNxYS1weC0zLjUgY3FhLXB5LTNcIlxuICAgICAgICAgICBbc3R5bGUuY3Vyc29yXT1cImVudi5hbHJlYWR5QXNzaWduZWQgPyAnbm90LWFsbG93ZWQnIDogJ3BvaW50ZXInXCJcbiAgICAgICAgICAgKGNsaWNrKT1cInRvZ2dsZShlbnYpXCI+XG4gICAgICAgIDxpbnB1dFxuICAgICAgICAgIHR5cGU9XCJjaGVja2JveFwiXG4gICAgICAgICAgY2xhc3M9XCJjcWEtY3Vyc29yLXBvaW50ZXIgY3FhLWZsZXgtbm9uZVwiXG4gICAgICAgICAgW3N0eWxlLndpZHRoLnB4XT1cIjE2XCJcbiAgICAgICAgICBbc3R5bGUuaGVpZ2h0LnB4XT1cIjE2XCJcbiAgICAgICAgICBbY2hlY2tlZF09XCJpc1NlbGVjdGVkKGVudi5pZClcIlxuICAgICAgICAgIFtkaXNhYmxlZF09XCIhIWVudi5hbHJlYWR5QXNzaWduZWRcIlxuICAgICAgICAgIChjbGljayk9XCIkZXZlbnQuc3RvcFByb3BhZ2F0aW9uKCk7IHRvZ2dsZShlbnYpXCJcbiAgICAgICAgICBbYXR0ci5hcmlhLWxhYmVsXT1cImVudi5hbHJlYWR5QXNzaWduZWQgPyBlbnYubmFtZSArICcgKGFscmVhZHkgYXNzaWduZWQpJyA6ICdTZWxlY3QgJyArIGVudi5uYW1lXCIgLz5cblxuICAgICAgICA8c3BhblxuICAgICAgICAgIGNsYXNzPVwiY3FhLWlubGluZS1ibG9jayBjcWEtcm91bmRlZC1mdWxsIGNxYS1mbGV4LW5vbmVcIlxuICAgICAgICAgIFtzdHlsZS53aWR0aC5weF09XCIxMFwiXG4gICAgICAgICAgW3N0eWxlLmhlaWdodC5weF09XCIxMFwiXG4gICAgICAgICAgW3N0eWxlLmJhY2tncm91bmRdPVwiZW52LmNvbG9yIHx8ICcjM0Y0M0VFJ1wiPjwvc3Bhbj5cblxuICAgICAgICA8ZGl2IGNsYXNzPVwiY3FhLWZsZXggY3FhLWZsZXgtY29sIGNxYS1taW4tdy0wIGNxYS1mbGV4LTFcIj5cbiAgICAgICAgICA8ZGl2IGNsYXNzPVwiY3FhLXRleHQtWzEzcHhdIGNxYS1mb250LW1lZGl1bSBjcWEtdHJ1bmNhdGVcIiBbc3R5bGUuY29sb3JdPVwiJyMwRjE3MkEnXCI+e3sgZW52Lm5hbWUgfX08L2Rpdj5cbiAgICAgICAgICA8ZGl2ICpuZ0lmPVwiaGVscGVyRm9yKGVudilcIlxuICAgICAgICAgICAgICAgY2xhc3M9XCJjcWEtdGV4dC1bMTFweF0gY3FhLWxlYWRpbmctWzEuNF1cIlxuICAgICAgICAgICAgICAgc3R5bGU9XCJjb2xvcjogIzY0NzQ4QjsgZGlzcGxheTogLXdlYmtpdC1ib3g7IC13ZWJraXQtbGluZS1jbGFtcDogMjsgLXdlYmtpdC1ib3gtb3JpZW50OiB2ZXJ0aWNhbDsgb3ZlcmZsb3c6IGhpZGRlbjsgd29yZC1icmVhazogYnJlYWstd29yZDsgb3ZlcmZsb3ctd3JhcDogYW55d2hlcmU7XCJcbiAgICAgICAgICAgICAgIFtpbm5lckhUTUxdPVwiaGVscGVyRm9yKGVudilcIj48L2Rpdj5cbiAgICAgICAgPC9kaXY+XG4gICAgICA8L2Rpdj5cblxuICAgICAgPCEtLSBJbmxpbmUgXCJDb3B5IGZyb20gd2hpY2ggZW52aXJvbm1lbnRcIiBwaWNrZXIg4oCUIHNpdHMgaW5zaWRlIHRoZSBjYXJkLFxuICAgICAgICAgICBiZWxvdyB0aGUgaGVhZC4gU2libGluZyBvZiB0aGUgaGVhZCAobm90IG5lc3RlZCkgc28gaW50ZXJhY3Rpbmcgd2l0aFxuICAgICAgICAgICB0aGUgZHJvcGRvd24gbmV2ZXIgcmVhY2hlcyB0aGUgdG9nZ2xlIGhhbmRsZXIuIC0tPlxuICAgICAgPGRpdlxuICAgICAgICAqbmdJZj1cInNob3dQZXJSb3dTb3VyY2UgJiYgaXNTZWxlY3RlZChlbnYuaWQpICYmICFlbnYuYWxyZWFkeUFzc2lnbmVkXCJcbiAgICAgICAgY2xhc3M9XCJjcWEtYWVkLXNvdXJjZSBjcWEtZmxleCBjcWEtZmxleC1jb2wgY3FhLWdhcC0xLjUgY3FhLXB4LTMuNSBjcWEtcGItMyBjcWEtcHQtMi41XCJcbiAgICAgICAgc3R5bGU9XCJib3JkZXItdG9wOiAxcHggZGFzaGVkICNDN0QyRkU7XCJcbiAgICAgICAgKGNsaWNrKT1cIiRldmVudC5zdG9wUHJvcGFnYXRpb24oKVwiPlxuICAgICAgICA8ZGl2IGNsYXNzPVwiY3FhLXRleHQtWzEycHhdIGNxYS1mb250LXNlbWlib2xkXCIgW3N0eWxlLmNvbG9yXT1cIicjNDMzOENBJ1wiPkNvcHkgZnJvbSB3aGljaCBlbnZpcm9ubWVudDwvZGl2PlxuXG4gICAgICAgIDxkaXYgKm5nSWY9XCJnZXRTb3VyY2VDb25maWcoZW52LmlkKSBhcyBjZmdcIj5cbiAgICAgICAgICA8Y3FhLWR5bmFtaWMtc2VsZWN0XG4gICAgICAgICAgICBbZm9ybV09XCJzb3VyY2VGb3JtXCJcbiAgICAgICAgICAgIFtjb25maWddPVwiY2ZnXCI+XG4gICAgICAgICAgPC9jcWEtZHluYW1pYy1zZWxlY3Q+XG4gICAgICAgIDwvZGl2PlxuXG4gICAgICAgIDxkaXZcbiAgICAgICAgICAqbmdJZj1cInBpY2tlZFNvdXJjZU5hbWUoZW52LmlkKSBhcyBwaWNrZWROYW1lOyBlbHNlIHBpY2tQcm9tcHRUcGxcIlxuICAgICAgICAgIGNsYXNzPVwiY3FhLWZsZXggY3FhLWl0ZW1zLXN0YXJ0IGNxYS1nYXAtMS41IGNxYS10ZXh0LVsxMXB4XSBjcWEtbGVhZGluZy1bMS40XVwiXG4gICAgICAgICAgW3N0eWxlLmNvbG9yXT1cIicjMTU4MDNEJ1wiPlxuICAgICAgICAgIDxtYXQtaWNvbiBjbGFzcz1cImNxYS1mbGV4LW5vbmVcIiBzdHlsZT1cImZvbnQtc2l6ZTogMTRweDsgd2lkdGg6IDE0cHg7IGhlaWdodDogMTRweDsgY29sb3I6ICMxNkEzNEE7XCI+Y2hlY2tfY2lyY2xlPC9tYXQtaWNvbj5cbiAgICAgICAgICA8c3Bhbj5cbiAgICAgICAgICAgIFJvd3Mgd2lsbCBiZSBjb3BpZWQgZnJvbSA8c3Ryb25nPnt7IHBpY2tlZE5hbWUgfX08L3N0cm9uZz4gaW50byA8c3Ryb25nPnt7IGVudi5uYW1lIH19PC9zdHJvbmc+LlxuICAgICAgICAgIDwvc3Bhbj5cbiAgICAgICAgPC9kaXY+XG4gICAgICAgIDxuZy10ZW1wbGF0ZSAjcGlja1Byb21wdFRwbD5cbiAgICAgICAgICA8ZGl2IGNsYXNzPVwiY3FhLXRleHQtWzExcHhdIGNxYS1sZWFkaW5nLVsxLjRdXCIgW3N0eWxlLmNvbG9yXT1cIicjNjQ3NDhCJ1wiPlxuICAgICAgICAgICAgUGljayB3aGVyZSB0aGlzIGVudmlyb25tZW50J3Mgcm93cyBzaG91bGQgYmUgY29waWVkIGZyb20uXG4gICAgICAgICAgPC9kaXY+XG4gICAgICAgIDwvbmctdGVtcGxhdGU+XG4gICAgICA8L2Rpdj5cbiAgICA8L2Rpdj5cblxuICAgIDwhLS0gTG9hZGluZy1tb3JlIGluZGljYXRvciBhdCBsaXN0IGJvdHRvbSB3aGlsZSBwYWdpbmF0aW5nIChBbGwgdmlldyBvbmx5KS4gLS0+XG4gICAgPGRpdiAqbmdJZj1cInZpZXdNb2RlID09PSAnYWxsJyAmJiBpc0xvYWRpbmdNb3JlXCJcbiAgICAgICAgIGNsYXNzPVwiY3FhLWZsZXggY3FhLWl0ZW1zLWNlbnRlciBjcWEtanVzdGlmeS1jZW50ZXIgY3FhLWdhcC0yIGNxYS1weS0zIGNxYS10ZXh0LVsxMnB4XVwiXG4gICAgICAgICBbc3R5bGUuY29sb3JdPVwiJyM2NDc0OEInXCJcbiAgICAgICAgIGFyaWEtbGl2ZT1cInBvbGl0ZVwiPlxuICAgICAgPHNwYW4gY2xhc3M9XCJjcWEtYWVkLXNwaW5uZXJcIiBhcmlhLWhpZGRlbj1cInRydWVcIj48L3NwYW4+XG4gICAgICBMb2FkaW5nIG1vcmUgZW52aXJvbm1lbnRz4oCmXG4gICAgPC9kaXY+XG5cbiAgICA8IS0tIEVuZC1vZi1saXN0IG1hcmtlciB3aGVuIHRoZSB1c2VyIGhhcyBzY3JvbGxlZCB0aHJvdWdoIGFsbCByZXN1bHRzLiAtLT5cbiAgICA8ZGl2XG4gICAgICAqbmdJZj1cInZpZXdNb2RlID09PSAnYWxsJyAmJiAhaXNMb2FkaW5nTW9yZSAmJiAhaGFzTW9yZSAmJiBjdXJyZW50UmVzdWx0cy5sZW5ndGggPiAwXCJcbiAgICAgIGNsYXNzPVwiY3FhLXRleHQtY2VudGVyIGNxYS1weS0yIGNxYS10ZXh0LVsxMXB4XVwiXG4gICAgICBbc3R5bGUuY29sb3JdPVwiJyM5NEEzQjgnXCI+XG4gICAgICBFbmQgb2YgbGlzdCDigJQge3sgY3VycmVudFJlc3VsdHMubGVuZ3RoIH19IG9mIHt7IHRvdGFsRWxlbWVudHMgfX0gc2hvd24uXG4gICAgPC9kaXY+XG4gIDwvZGl2PlxuXG4gIDwhLS0gSW5saW5lIG5vdGU6IHRlbGxzIHRoZSB1c2VyIHdoeSB0aGUgcHJpbWFyeSBidXR0b24gc3RheXMgZGlzYWJsZWQuIC0tPlxuICA8ZGl2XG4gICAgKm5nSWY9XCJzaG93UGVyUm93U291cmNlICYmIHNlbGVjdGVkLnNpemUgPiAwICYmIHVucmVzb2x2ZWRTb3VyY2VzQ291bnQgPiAwXCJcbiAgICBjbGFzcz1cImNxYS1mbGV4IGNxYS1pdGVtcy1jZW50ZXIgY3FhLWdhcC0yIGNxYS1weC0zIGNxYS1weS0yIGNxYS1yb3VuZGVkLVs4cHhdIGNxYS10ZXh0LVsxMnB4XVwiXG4gICAgc3R5bGU9XCJiYWNrZ3JvdW5kOiAjRkVGM0M3OyBjb2xvcjogIzkyNDAwRTsgYm9yZGVyOiAxcHggc29saWQgI0ZERTY4QTtcIj5cbiAgICBQaWNrIGEgc291cmNlIGZvciB7eyB1bnJlc29sdmVkU291cmNlc0NvdW50IH19IGVudmlyb25tZW50e3sgdW5yZXNvbHZlZFNvdXJjZXNDb3VudCA9PT0gMSA/ICcnIDogJ3MnIH19IGJlZm9yZSBjb250aW51aW5nLlxuICA8L2Rpdj5cbjwvZGl2PlxuIl19