tango-app-ui-store-builder 1.2.10 → 1.2.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/esm2022/lib/components/chips-input/chips-input.component.mjs +101 -0
  2. package/esm2022/lib/components/collection-update-ai/find-replace-layout/prepare-template/prepare-template.component.mjs +2 -2
  3. package/esm2022/lib/components/create-fixture/create-fixture.component.mjs +66 -25
  4. package/esm2022/lib/components/create-vm/create-vm.component.mjs +2 -2
  5. package/esm2022/lib/components/fixture-template/template-basic-details/template-basic-details.component.mjs +1 -1
  6. package/esm2022/lib/components/fixture-template/template-products/template-products.component.mjs +15 -5
  7. package/esm2022/lib/components/fixture-template/template-vms/template-vms.component.mjs +31 -12
  8. package/esm2022/lib/components/fixture-template-table/popups/create-fixture-template/create-fixture-template.component.mjs +1 -1
  9. package/esm2022/lib/components/look-plano-collection/look-plano-collection.component.mjs +156 -0
  10. package/esm2022/lib/components/look-plano-collection-form/look-plano-collection-form.component.mjs +1204 -0
  11. package/esm2022/lib/components/manage-store-plano/manage-store-plano.component.mjs +1 -1
  12. package/esm2022/lib/components/manage-store-plano/plano-rollout/plano-rollout.component.mjs +1 -1
  13. package/esm2022/lib/components/manage-store-plano/template-basic-details/template-basic-details.component.mjs +1 -1
  14. package/esm2022/lib/components/manage-store-plano/template-products/template-products.component.mjs +2 -2
  15. package/esm2022/lib/components/manage-store-plano/template-vms/template-vms.component.mjs +2 -2
  16. package/esm2022/lib/components/manage-store-plano/verification-feedback/zone-editable-fixture/zone-editable-fixture.component.mjs +1 -1
  17. package/esm2022/lib/components/multiselect-chip-dropdown/multiselect-chip-dropdown.component.mjs +27 -4
  18. package/esm2022/lib/components/onboard-store-plano/create-planogram/create-planogram.component.mjs +2 -2
  19. package/esm2022/lib/components/onboard-store-plano/onboard-store-plano.component.mjs +1 -1
  20. package/esm2022/lib/components/plano-library/fixture-library/popups/create-fixture-modal/create-fixture-modal.component.mjs +1 -1
  21. package/esm2022/lib/components/plano-tools/delete-floor/delete-floor.component.mjs +3 -3
  22. package/esm2022/lib/components/plano-tools/move-bucket/move-bucket.component.mjs +1 -1
  23. package/esm2022/lib/components/plano-tools/swap-template/swap-template.component.mjs +1 -1
  24. package/esm2022/lib/components/planogram/plano-details-parent/plano-details-parent.component.mjs +1 -1
  25. package/esm2022/lib/components/planogram/plano-overview/plano-overview.component.mjs +1 -1
  26. package/esm2022/lib/components/popups/publish-plano-modal/publish-plano-modal.component.mjs +1 -1
  27. package/esm2022/lib/components/reactive-select/reactive-select.component.mjs +22 -3
  28. package/esm2022/lib/components/searchable-select/searchable-select.component.mjs +265 -0
  29. package/esm2022/lib/components/store-plano/store-plano.component.mjs +1 -1
  30. package/esm2022/lib/interfaces/fixture-library.interface.mjs +1 -1
  31. package/esm2022/lib/services/store-builder.service.mjs +28 -3
  32. package/esm2022/lib/tango-store-builder-routing.module.mjs +11 -1
  33. package/esm2022/lib/tango-store-builder.module.mjs +23 -4
  34. package/fesm2022/tango-app-ui-store-builder.mjs +1914 -69
  35. package/fesm2022/tango-app-ui-store-builder.mjs.map +1 -1
  36. package/lib/components/chips-input/chips-input.component.d.ts +35 -0
  37. package/lib/components/create-fixture/create-fixture.component.d.ts +3 -0
  38. package/lib/components/fixture-template/template-products/template-products.component.d.ts +9 -1
  39. package/lib/components/fixture-template/template-vms/template-vms.component.d.ts +9 -1
  40. package/lib/components/look-plano-collection/look-plano-collection.component.d.ts +53 -0
  41. package/lib/components/look-plano-collection-form/look-plano-collection-form.component.d.ts +237 -0
  42. package/lib/components/manage-plano/rollout-table/rollout-table.component.d.ts +4 -4
  43. package/lib/components/manage-plano/verification-table/verification-table.component.d.ts +5 -5
  44. package/lib/components/multiselect-chip-dropdown/multiselect-chip-dropdown.component.d.ts +12 -1
  45. package/lib/components/reactive-select/reactive-select.component.d.ts +12 -1
  46. package/lib/components/searchable-select/searchable-select.component.d.ts +56 -0
  47. package/lib/interfaces/fixture-library.interface.d.ts +1 -0
  48. package/lib/services/store-builder.service.d.ts +7 -1
  49. package/lib/tango-store-builder.module.d.ts +39 -34
  50. package/package.json +1 -1
@@ -0,0 +1,1204 @@
1
+ import { Component } from '@angular/core';
2
+ import { Validators } from '@angular/forms';
3
+ import { debounceTime, lastValueFrom, Subject, takeUntil } from 'rxjs';
4
+ import * as i0 from "@angular/core";
5
+ import * as i1 from "@angular/forms";
6
+ import * as i2 from "@angular/router";
7
+ import * as i3 from "tango-app-ui-global";
8
+ import * as i4 from "../../services/store-builder.service";
9
+ import * as i5 from "tango-app-ui-shared";
10
+ import * as i6 from "../../services/plano-data.service";
11
+ import * as i7 from "@angular/common";
12
+ import * as i8 from "../multiselect-chip-dropdown/multiselect-chip-dropdown.component";
13
+ import * as i9 from "../fixture-template/template-products/template-products.component";
14
+ import * as i10 from "../searchable-select/searchable-select.component";
15
+ import * as i11 from "../chips-input/chips-input.component";
16
+ import * as i12 from "../fixture-template/template-vms/template-vms.component";
17
+ export class LookPlanoCollectionFormComponent {
18
+ fb;
19
+ route;
20
+ router;
21
+ gs;
22
+ builderService;
23
+ toast;
24
+ pageInfo;
25
+ planoDataService;
26
+ clientId = '';
27
+ collectionId = null;
28
+ isNew = true;
29
+ loading = false;
30
+ saving = false;
31
+ form;
32
+ selectedLookIndex = -1;
33
+ selectedSlotIndex = -1;
34
+ // Display labels are Wall / Floor; the stored ids stay 'shelf' / 'eurocenter'
35
+ // so the library filter, slot defaults, and the backend slotType/fixtureType
36
+ // enums keep working unchanged ('shelf' → wall fixtures, 'eurocenter' → floor).
37
+ fixtureTypeOptions = [
38
+ { id: 'shelf', name: 'Wall' },
39
+ { id: 'eurocenter', name: 'Floor' },
40
+ ];
41
+ fixtureLibraryItems = [];
42
+ // Dropdowns inside placement rows.
43
+ vmTypeOptions = [];
44
+ vmArtworkOptions = [];
45
+ productOptions = [];
46
+ /** Cached per-vmType artwork list — same reference returned each lookup so
47
+ * lib-reactive-select doesn't reset state every CD cycle. */
48
+ vmArtworkByType = new Map();
49
+ /** (vmName||vmType) and (vmName) → planovm _id, so a VM placement's artwork
50
+ * name can be resolved to the _id the embedded VM editor matches against. */
51
+ vmIdByNameType = new Map();
52
+ /**
53
+ * Cached filtered list bound to the "Fixture libraries" multiselect.
54
+ * Must NOT be a getter — the underlying multiselect re-clones its items on
55
+ * every ngOnChanges, which detaches click targets and breaks selection.
56
+ */
57
+ fixtureLibraryItemsForSlot = [];
58
+ // State for the per-slot Fixture Library Configuration card.
59
+ selectedLibraryIdInMap = '';
60
+ selectedLibraryDetails = null;
61
+ loadingLibraryDetails = false;
62
+ embeddedTab = 'products';
63
+ // === Fixture Library Configuration card helpers ===
64
+ /** Slot's placements with kind = 'vm', exposed as dropdown items. */
65
+ get currentSlotVmItems() {
66
+ return this.placementsToItems('vm');
67
+ }
68
+ /** Slot's placements with kind = 'pid', exposed as dropdown items. */
69
+ get currentSlotPidItems() {
70
+ return this.placementsToItems('pid');
71
+ }
72
+ placementsToItems(kind) {
73
+ const slot = this.selectedSlotGroup;
74
+ if (!slot)
75
+ return [];
76
+ const arr = slot.get('placements');
77
+ if (!arr)
78
+ return [];
79
+ return arr.controls
80
+ .map((c) => c.value)
81
+ .filter((p) => p?.kind === kind && p?.position)
82
+ .map((p) => ({
83
+ id: p.position,
84
+ name: p.rawValue ? `${p.position} — ${p.rawValue}` : p.position,
85
+ }));
86
+ }
87
+ /** Fixture-library options for the dropdown — filtered to the libraries
88
+ * selected on the currently-active slot's multiselect. */
89
+ get selectedSlotLibrariesForDropdown() {
90
+ const slot = this.selectedSlotGroup;
91
+ if (!slot)
92
+ return [];
93
+ const refs = slot.get('fixtureLibraryRefs')?.value || [];
94
+ return this.fixtureLibraryItems.filter((item) => refs.includes(item.id));
95
+ }
96
+ /** The FormArray that stores per-(library, shelf) VM/PID values for the active slot. */
97
+ get selectedSlotLibraryConfigs() {
98
+ const slot = this.selectedSlotGroup;
99
+ return slot ? slot.get('libraryConfigurations') : null;
100
+ }
101
+ /** Form-array entries scoped to the currently-shown library in the config card. */
102
+ configEntriesForCurrentLibrary() {
103
+ const configs = this.selectedSlotLibraryConfigs;
104
+ if (!configs || !this.selectedLibraryIdInMap)
105
+ return [];
106
+ return configs.controls
107
+ .map((c, i) => ({ control: c, arrayIndex: i }))
108
+ .filter((x) => x.control.get('libraryRef')?.value === this.selectedLibraryIdInMap);
109
+ }
110
+ /** Reset card state whenever the active slot changes so we don't carry over
111
+ * stale selections from a previously-viewed slot. */
112
+ resetLibraryMap() {
113
+ this.selectedLibraryIdInMap = '';
114
+ this.selectedLibraryDetails = null;
115
+ this.refreshEmbeddedHostKeys();
116
+ // Clear the shared BehaviorSubject too so the embedded TemplateProducts /
117
+ // TemplateVms components, if they're still mounted, don't render stale
118
+ // data from the previous slot's library.
119
+ this.planoDataService.fixtureTemplateDetails.next(null);
120
+ }
121
+ /** When a slot is loaded, automatically pick the first library it has linked
122
+ * so the embedded fixture-template editor opens straight to that library. */
123
+ autoSelectFirstLibrary() {
124
+ const slot = this.selectedSlotGroup;
125
+ if (!slot)
126
+ return;
127
+ const refs = slot.get('fixtureLibraryRefs')?.value || [];
128
+ const firstId = refs.find((id) => !!id);
129
+ if (!firstId)
130
+ return;
131
+ if (this.selectedLibraryIdInMap === firstId)
132
+ return;
133
+ this.onLibraryMapSelect(firstId);
134
+ }
135
+ /** Read the slot's saved snapshot for a library, if any. */
136
+ getLibrarySnapshot(libId) {
137
+ const slot = this.selectedSlotGroup;
138
+ if (!slot)
139
+ return null;
140
+ const snaps = slot.get('librarySnapshots')?.value || [];
141
+ const entry = snaps.find((s) => s?.libraryRef === libId);
142
+ return entry?.snapshot || null;
143
+ }
144
+ /** Persist a snapshot into the slot's librarySnapshots FormControl. */
145
+ captureLibrarySnapshot(libId, snapshot) {
146
+ const slot = this.selectedSlotGroup;
147
+ if (!slot || !libId)
148
+ return;
149
+ const ctrl = slot.get('librarySnapshots');
150
+ if (!ctrl)
151
+ return;
152
+ const current = Array.isArray(ctrl.value) ? [...ctrl.value] : [];
153
+ // Strip the ignoreUpdate flag before saving so we don't echo it back later.
154
+ const { ignoreUpdate: _ignored, ...clean } = snapshot || {};
155
+ const i = current.findIndex((s) => s?.libraryRef === libId);
156
+ if (i >= 0) {
157
+ current[i] = { libraryRef: libId, snapshot: clean };
158
+ }
159
+ else {
160
+ current.push({ libraryRef: libId, snapshot: clean });
161
+ }
162
+ ctrl.setValue(current);
163
+ }
164
+ /** Resolve a VM placement's artwork NAME (+ vmType) to its planovm _id. */
165
+ resolveVmId(vmName, vmType) {
166
+ const name = this.normVmType(vmName);
167
+ const type = this.normVmType(vmType);
168
+ return (this.vmIdByNameType.get(`${name}||${type}`) ||
169
+ this.vmIdByNameType.get(name) ||
170
+ vmName);
171
+ }
172
+ /**
173
+ * Re-derive every assigned library's snapshot from the active slot's
174
+ * current placements. Driven by the "Look and Visual Merchandising
175
+ * Placements" list — so editing one placement updates ALL assigned
176
+ * libraries at once.
177
+ *
178
+ * - PID placements: `position` (Top/Mid/Bottom) → shelf zone; the shelf's
179
+ * productBrandName is OVERWRITTEN with the placement's product list.
180
+ * - VM placements: `position` → vmType; the matching vmConfig entry's
181
+ * artwork (vmId/vmName) is updated while the library keeps its own VM
182
+ * positions. vmTypes not yet present are appended.
183
+ */
184
+ applyPlacementsToAssignedLibraries() {
185
+ const slot = this.selectedSlotGroup;
186
+ if (!slot)
187
+ return;
188
+ const refs = (slot.get('fixtureLibraryRefs')?.value || [])
189
+ .filter((r) => !!r);
190
+ if (!refs.length)
191
+ return;
192
+ const placements = slot.get('placements')?.value || [];
193
+ const norm = (s) => String(s ?? '').trim().toLowerCase();
194
+ // zone -> product list (PIDs); supports both rawValues[] and legacy rawValue.
195
+ const pidByZone = new Map();
196
+ for (const p of placements) {
197
+ if (p?.kind !== 'pid' || !p?.position)
198
+ continue;
199
+ const vals = Array.isArray(p.rawValues) && p.rawValues.length
200
+ ? p.rawValues.filter((v) => !!v)
201
+ : (p.rawValue ? [String(p.rawValue)] : []);
202
+ if (vals.length)
203
+ pidByZone.set(norm(p.position), vals);
204
+ }
205
+ // vmType -> { vmId, vmName, label } (VMs)
206
+ const vmByType = new Map();
207
+ for (const p of placements) {
208
+ if (p?.kind !== 'vm' || !p?.position || !p?.rawValue)
209
+ continue;
210
+ const label = String(p.position);
211
+ vmByType.set(norm(label), {
212
+ vmId: this.resolveVmId(String(p.rawValue), label),
213
+ vmName: String(p.rawValue),
214
+ label,
215
+ });
216
+ }
217
+ for (const libId of refs) {
218
+ const target = this.getLibrarySnapshot(libId);
219
+ if (!target)
220
+ continue; // seed creates one per assigned library
221
+ const shelves = Array.isArray(target.shelfConfig) ? target.shelfConfig : [];
222
+ const newShelfConfig = shelves.map((shelf) => {
223
+ const zone = norm(shelf?.zone || shelf?.label);
224
+ if (!zone || !pidByZone.has(zone))
225
+ return shelf;
226
+ return {
227
+ ...shelf,
228
+ zone: shelf?.zone || shelf?.label || '',
229
+ productBrandName: [...pidByZone.get(zone)],
230
+ };
231
+ });
232
+ const existingVms = Array.isArray(target.vmConfig) ? target.vmConfig : [];
233
+ const seen = new Set();
234
+ const newVmConfig = existingVms.map((vm) => {
235
+ const key = norm(vm?.vmType);
236
+ seen.add(key);
237
+ const upd = vmByType.get(key);
238
+ return upd ? { ...vm, vmId: upd.vmId, vmName: upd.vmName } : vm;
239
+ });
240
+ for (const [key, upd] of vmByType) {
241
+ if (seen.has(key))
242
+ continue;
243
+ newVmConfig.push({
244
+ vmType: upd.label,
245
+ vmId: upd.vmId,
246
+ vmName: upd.vmName,
247
+ startYPosition: 1,
248
+ endYPosition: 1,
249
+ xZone: '',
250
+ yZone: '',
251
+ position: '',
252
+ });
253
+ }
254
+ this.captureLibrarySnapshot(libId, {
255
+ ...target,
256
+ shelfConfig: newShelfConfig,
257
+ vmConfig: newVmConfig,
258
+ productResolutionLevel: 'L3',
259
+ });
260
+ }
261
+ // Reflect the change in the currently-open embedded editor.
262
+ this.reloadDisplayedLibrary();
263
+ }
264
+ /**
265
+ * Remount the embedded editor for the active library so it picks up the
266
+ * snapshot we just rewrote. The embedded components guard against re-init
267
+ * while mounted, so we toggle the host key off then on to force a fresh
268
+ * ngOnInit with the updated data.
269
+ */
270
+ reloadDisplayedLibrary() {
271
+ const libId = this.selectedLibraryIdInMap;
272
+ if (!libId)
273
+ return;
274
+ const updated = this.getLibrarySnapshot(libId);
275
+ if (!updated)
276
+ return;
277
+ this.selectedLibraryDetails = updated;
278
+ // Push the fresh snapshot, then bump the nonce so refreshEmbeddedHostKeys
279
+ // produces a NEW key — that's what actually forces the *ngFor to destroy
280
+ // the old embedded editor and mount a new one that re-reads the snapshot.
281
+ this.planoDataService.fixtureTemplateDetails.next({
282
+ ...updated,
283
+ productResolutionLevel: updated.productResolutionLevel || 'L3',
284
+ });
285
+ this.embeddedReloadNonce++;
286
+ this.refreshEmbeddedHostKeys();
287
+ }
288
+ async onLibraryMapSelect(libId) {
289
+ // Toggling the active chip off → clear immediately (no async work needed).
290
+ if (!libId) {
291
+ this.selectedLibraryIdInMap = '';
292
+ this.selectedLibraryDetails = null;
293
+ this.refreshEmbeddedHostKeys();
294
+ this.planoDataService.fixtureTemplateDetails.next(null);
295
+ return;
296
+ }
297
+ // Switching to a different chip: light the new chip up right away, but
298
+ // KEEP the previous library's embedded preview mounted while we fetch
299
+ // the new snapshot/details. Otherwise the card would collapse to its
300
+ // header height during the fetch and re-expand once new data lands —
301
+ // visible as a "crunch" the user reported.
302
+ this.selectedLibraryIdInMap = libId;
303
+ this.loadingLibraryDetails = true;
304
+ let newDetails = null;
305
+ try {
306
+ // If an auto-apply for this library is still running, wait for it so
307
+ // we don't beat it to the snapshot and render the un-filled library.
308
+ const pending = this.autoApplyInFlight.get(libId);
309
+ if (pending) {
310
+ try {
311
+ await pending;
312
+ }
313
+ catch (_e) { /* ignore */ }
314
+ }
315
+ const saved = this.getLibrarySnapshot(libId);
316
+ if (saved) {
317
+ newDetails = saved;
318
+ }
319
+ else {
320
+ const res = await lastValueFrom(this.builderService.getFixtureLibraryDetails(libId));
321
+ newDetails = res?.data || null;
322
+ }
323
+ }
324
+ catch (err) {
325
+ console.log('@@ ~ onLibraryMapSelect [ERR]:', err);
326
+ newDetails = null;
327
+ }
328
+ // Atomic swap — selectedLibraryDetails, BehaviorSubject, and the
329
+ // ngFor host key all flip in one synchronous block, so Angular destroys
330
+ // the old embedded component and mounts the new one in the same change
331
+ // detection cycle. No empty-state in between → no card-height crunch.
332
+ this.selectedLibraryDetails = newDetails;
333
+ if (newDetails) {
334
+ this.planoDataService.fixtureTemplateDetails.next({
335
+ ...newDetails,
336
+ productResolutionLevel: newDetails.productResolutionLevel || 'L3',
337
+ });
338
+ }
339
+ else {
340
+ this.planoDataService.fixtureTemplateDetails.next(null);
341
+ }
342
+ this.refreshEmbeddedHostKeys();
343
+ this.loadingLibraryDetails = false;
344
+ }
345
+ /**
346
+ * Composite key tied to the currently-active (look, slot, library) triple.
347
+ * Stable property — recomputed only when the underlying selection changes
348
+ * (see refreshEmbeddedHostKeys()). Avoids returning a new array reference
349
+ * every CD cycle, which used to ripple into other multi-selects' inputs.
350
+ */
351
+ embeddedHostKey = '';
352
+ embeddedHostKeys = [];
353
+ // Bumped by reloadDisplayedLibrary() to force the embedded editor to remount
354
+ // even when look/slot/library are unchanged (a same-key round-trip via the
355
+ // *ngFor trackBy does NOT remount; a changed key does).
356
+ embeddedReloadNonce = 0;
357
+ refreshEmbeddedHostKeys() {
358
+ const key = `${this.selectedLookIndex}-${this.selectedSlotIndex}-${this.selectedLibraryIdInMap}-${this.embeddedReloadNonce}`;
359
+ if (key !== this.embeddedHostKey) {
360
+ this.embeddedHostKey = key;
361
+ }
362
+ const next = this.selectedLibraryDetails ? [this.embeddedHostKey] : [];
363
+ const current = this.embeddedHostKeys;
364
+ // Only assign a new array if the contents differ — otherwise the ngFor sees
365
+ // a "new" array each CD and trackBy still has to compare every entry.
366
+ if (next.length !== current.length || next[0] !== current[0]) {
367
+ this.embeddedHostKeys = next;
368
+ }
369
+ }
370
+ trackByEmbeddedKey(_, key) {
371
+ return key;
372
+ }
373
+ /**
374
+ * The slot-type dropdown in the right pane only offers values that the
375
+ * parent Look has selected in its Fixture Type multiselect. If nothing is
376
+ * selected yet, fall back to showing all options so the user isn't blocked.
377
+ */
378
+ get availableSlotTypes() {
379
+ const lookGroup = this.selectedLookGroup;
380
+ if (!lookGroup)
381
+ return this.fixtureTypeOptions;
382
+ const selected = lookGroup.get('fixtureType')?.value;
383
+ if (!Array.isArray(selected) || selected.length === 0) {
384
+ return this.fixtureTypeOptions;
385
+ }
386
+ return this.fixtureTypeOptions.filter((opt) => selected.includes(opt.id));
387
+ }
388
+ // 20 very mild pastels (all Tailwind-50 / 100 range) arranged so adjacent
389
+ // palette slots are on opposite sides of the colour wheel for distinguish-
390
+ // ability without any colour feeling saturated.
391
+ static BUCKET_PALETTE = [
392
+ '#fef2f2',
393
+ '#f0fdfa',
394
+ '#fff7ed',
395
+ '#eef2ff',
396
+ '#fefce8',
397
+ '#faf5ff',
398
+ '#f0fdf4',
399
+ '#fff1f2',
400
+ '#ecfeff',
401
+ '#ffedd5',
402
+ '#eff6ff',
403
+ '#f0f9ff',
404
+ '#f5f3ff',
405
+ '#f7fee7',
406
+ '#fdf4ff',
407
+ '#ecfdf5',
408
+ '#fdf2f8',
409
+ '#fffbeb',
410
+ '#f1f5f9',
411
+ '#f5f5f4', // 20 Linen stone-100
412
+ ];
413
+ destroy$ = new Subject();
414
+ constructor(fb, route, router, gs, builderService, toast, pageInfo, planoDataService) {
415
+ this.fb = fb;
416
+ this.route = route;
417
+ this.router = router;
418
+ this.gs = gs;
419
+ this.builderService = builderService;
420
+ this.toast = toast;
421
+ this.pageInfo = pageInfo;
422
+ this.planoDataService = planoDataService;
423
+ }
424
+ ngOnInit() {
425
+ this.setPageData();
426
+ this.initForm();
427
+ // Listen to the shared fixtureTemplateDetails — when the embedded
428
+ // TemplateProducts/TemplateVms components push edits back into the
429
+ // BehaviorSubject, persist a snapshot under the active slot + library.
430
+ this.planoDataService.fixtureTemplateDetails
431
+ .pipe(takeUntil(this.destroy$))
432
+ .subscribe((data) => {
433
+ if (!data || !this.selectedLibraryIdInMap)
434
+ return;
435
+ // Only capture user edits, not the initial load we pushed ourselves.
436
+ // The embedded components set `ignoreUpdate: true` when they push
437
+ // their form changes back; we use that as our signal.
438
+ if (!data.ignoreUpdate)
439
+ return;
440
+ // Persist edits made directly in the embedded editor (e.g. VM
441
+ // positions, which stay editable in looksMode) to the active library.
442
+ // Cross-library propagation is driven by the slot's placements list
443
+ // instead (see applyPlacementsToAssignedLibraries).
444
+ this.captureLibrarySnapshot(this.selectedLibraryIdInMap, data);
445
+ });
446
+ this.gs.dataRangeValue.pipe(takeUntil(this.destroy$)).subscribe((data) => {
447
+ const headerFilters = JSON.parse(localStorage.getItem('header-filters') || '{}');
448
+ this.clientId = data?.client || headerFilters?.client;
449
+ if (this.clientId) {
450
+ this.loadFixtureLibraries();
451
+ this.loadPlacementDropdownData();
452
+ }
453
+ });
454
+ this.route.params.pipe(takeUntil(this.destroy$)).subscribe(async (params) => {
455
+ const id = params['collectionId'];
456
+ this.collectionId = id && id !== 'new' ? id : null;
457
+ this.isNew = !this.collectionId;
458
+ if (this.collectionId) {
459
+ await this.loadDetails();
460
+ }
461
+ });
462
+ // Embedded TemplateProductsComponent / TemplateVmsComponent read these
463
+ // query params from the active route. Force them to edit-mode and pin
464
+ // the products view to the "section" level.
465
+ this.router.navigate([], {
466
+ relativeTo: this.route,
467
+ queryParams: { isEdit: 'true', level: 'section' },
468
+ queryParamsHandling: 'merge',
469
+ replaceUrl: true,
470
+ });
471
+ }
472
+ setPageData() {
473
+ this.pageInfo.setTitle('Look Collection');
474
+ this.pageInfo.setBreadcrumbs([
475
+ { title: 'Planogram', path: '/manage/planogram/manage-planograms', isActive: false, isSeparator: false },
476
+ { title: '', path: '', isActive: false, isSeparator: true },
477
+ { title: 'Looks', path: '/manage/planogram/looks', isActive: false, isSeparator: false },
478
+ { title: '', path: '', isActive: false, isSeparator: true },
479
+ { title: 'Edit', path: '', isActive: true, isSeparator: false },
480
+ ]);
481
+ }
482
+ initForm() {
483
+ this.form = this.fb.group({
484
+ name: ['', Validators.required],
485
+ description: [''],
486
+ isActive: [false],
487
+ looks: this.fb.array([]),
488
+ });
489
+ }
490
+ get looks() {
491
+ return this.form.get('looks');
492
+ }
493
+ fixtureSlots(lookIndex) {
494
+ return this.looks.at(lookIndex).get('fixtureSlots');
495
+ }
496
+ placements(lookIndex, slotIndex) {
497
+ return this.fixtureSlots(lookIndex).at(slotIndex).get('placements');
498
+ }
499
+ get selectedLookGroup() {
500
+ return this.selectedLookIndex >= 0 && this.selectedLookIndex < this.looks.length
501
+ ? this.looks.at(this.selectedLookIndex)
502
+ : null;
503
+ }
504
+ get selectedSlotsArray() {
505
+ const look = this.selectedLookGroup;
506
+ return look ? look.get('fixtureSlots') : null;
507
+ }
508
+ get selectedSlotGroup() {
509
+ const slots = this.selectedSlotsArray;
510
+ if (!slots)
511
+ return null;
512
+ return this.selectedSlotIndex >= 0 && this.selectedSlotIndex < slots.length
513
+ ? slots.at(this.selectedSlotIndex)
514
+ : null;
515
+ }
516
+ get selectedPlacements() {
517
+ const slot = this.selectedSlotGroup;
518
+ return slot ? slot.get('placements') : null;
519
+ }
520
+ createLookGroup(seed = {}) {
521
+ const seedSlots = Array.isArray(seed.fixtureSlots) && seed.fixtureSlots.length
522
+ ? seed.fixtureSlots
523
+ : Array.from({ length: Math.max(1, Number(seed.fixtureCount) || 1) }, (_, i) => ({ slotIndex: i + 1 }));
524
+ const slots = seedSlots.map((s, i) => this.createSlotGroup({ ...s, slotIndex: i + 1 }));
525
+ const lookGroup = this.fb.group({
526
+ keyType: [seed.keyType || 'mbq'],
527
+ mbqBucket: [seed.mbqBucket || ''],
528
+ brandCategory: [seed.brandCategory || ''],
529
+ fixtureCount: [slots.length, [Validators.required, Validators.min(0)]],
530
+ fixtureType: [Array.isArray(seed.fixtureType) ? seed.fixtureType : []],
531
+ layoutVariant: [seed.layoutVariant || 'shelf'],
532
+ storeProto: [seed.storeProto || ''],
533
+ fixtureSlots: this.fb.array(slots),
534
+ });
535
+ // fixtureCount → slots length (user-edited count adjusts the slots array)
536
+ lookGroup.get('fixtureCount').valueChanges
537
+ .pipe(takeUntil(this.destroy$))
538
+ .subscribe((next) => {
539
+ const target = Math.max(0, Math.min(30, Number(next) || 0));
540
+ const slotsArr = lookGroup.get('fixtureSlots');
541
+ while (slotsArr.length < target) {
542
+ slotsArr.push(this.createSlotGroup({ slotIndex: slotsArr.length + 1 }));
543
+ }
544
+ while (slotsArr.length > target) {
545
+ slotsArr.removeAt(slotsArr.length - 1);
546
+ }
547
+ this.renumberSlotsForGroup(lookGroup);
548
+ // Reconcile slot selection if it's now out of bounds
549
+ if (this.selectedLookIndex >= 0 && this.looks.at(this.selectedLookIndex) === lookGroup) {
550
+ if (slotsArr.length === 0) {
551
+ this.selectedSlotIndex = -1;
552
+ }
553
+ else if (this.selectedSlotIndex >= slotsArr.length) {
554
+ this.selectedSlotIndex = slotsArr.length - 1;
555
+ }
556
+ else if (this.selectedSlotIndex < 0) {
557
+ this.selectedSlotIndex = 0;
558
+ }
559
+ }
560
+ });
561
+ return lookGroup;
562
+ }
563
+ createSlotGroup(seed = {}) {
564
+ const placements = (Array.isArray(seed.placements) ? seed.placements : [])
565
+ .map((p) => this.createPlacementGroup(p));
566
+ const libraryConfigs = (Array.isArray(seed.libraryConfigurations) ? seed.libraryConfigurations : [])
567
+ .map((c) => this.createLibraryConfigGroup(c));
568
+ return this.fb.group({
569
+ slotIndex: [seed.slotIndex ?? 1, Validators.required],
570
+ slotType: [seed.slotType || 'shelf'],
571
+ brand: [seed.brand || ''],
572
+ fixtureLevelZone: [seed.fixtureLevelZone || ''],
573
+ fixtureLibraryRef: [seed.fixtureLibraryRef || ''],
574
+ fixtureLibraryLabel: [seed.fixtureLibraryLabel || ''],
575
+ fixtureLibraryRefs: [Array.isArray(seed.fixtureLibraryRefs) ? seed.fixtureLibraryRefs : []],
576
+ cadHeaderVariants: [Array.isArray(seed.cadHeaderVariants) ? seed.cadHeaderVariants : []],
577
+ placements: this.fb.array(placements),
578
+ libraryConfigurations: this.fb.array(libraryConfigs),
579
+ // Per-library snapshot of the embedded fixture-template editor state
580
+ // (shelfConfig + product/VM placements). Keyed by libraryRef.
581
+ librarySnapshots: [
582
+ Array.isArray(seed.librarySnapshots) ? seed.librarySnapshots : [],
583
+ ],
584
+ });
585
+ }
586
+ createLibraryConfigGroup(seed = {}) {
587
+ return this.fb.group({
588
+ libraryRef: [seed.libraryRef || ''],
589
+ shelfNumber: [seed.shelfNumber ?? 1],
590
+ label: [seed.label || ''],
591
+ shelfType: [seed.shelfType || ''],
592
+ // VMs and PIDs picked from the slot's `placements` array (by position name).
593
+ vmRefs: [Array.isArray(seed.vmRefs) ? seed.vmRefs : []],
594
+ pidRefs: [Array.isArray(seed.pidRefs) ? seed.pidRefs : []],
595
+ });
596
+ }
597
+ createPlacementGroup(seed = {}) {
598
+ // Backward-compat: legacy data stored a single string in `rawValue`. For
599
+ // PID placements we now use `rawValues` (array, multi-select). If the
600
+ // seed only has `rawValue`, migrate it to the array on first load.
601
+ const rawValuesSeed = Array.isArray(seed.rawValues)
602
+ ? seed.rawValues
603
+ : (seed.kind === 'pid' && seed.rawValue ? [String(seed.rawValue)] : []);
604
+ return this.fb.group({
605
+ position: [seed.position || ''],
606
+ kind: [seed.kind || 'pid'],
607
+ // For VM rows this holds the artwork id (single string). For PID rows
608
+ // it's left empty in favour of `rawValues`.
609
+ rawValue: [seed.kind === 'pid' ? '' : (seed.rawValue || '')],
610
+ rawValues: [rawValuesSeed],
611
+ vmRef: [seed.vmRef || ''],
612
+ skuCollectionRef: [seed.skuCollectionRef || ''],
613
+ });
614
+ }
615
+ addPlacement() {
616
+ if (!this.selectedPlacements)
617
+ return;
618
+ this.selectedPlacements.push(this.createPlacementGroup());
619
+ }
620
+ removePlacement(index) {
621
+ if (!this.selectedPlacements)
622
+ return;
623
+ this.selectedPlacements.removeAt(index);
624
+ }
625
+ normVmType(t) {
626
+ return String(t ?? '').trim().toLowerCase();
627
+ }
628
+ /** Stable per-vmType artwork list lookup. Returns the same array reference
629
+ * for the same vmType across CD cycles so lib-reactive-select doesn't
630
+ * re-init. Falls back to the full list when vmType is empty. */
631
+ vmArtworkOptionsFor(vmType) {
632
+ const key = this.normVmType(vmType);
633
+ if (key && this.vmArtworkByType.has(key)) {
634
+ return this.vmArtworkByType.get(key);
635
+ }
636
+ return this.vmArtworkByType.get('') || [];
637
+ }
638
+ /** Populate the dropdown data used by Placement rows:
639
+ * - VM Type list (`getVmTypesList`)
640
+ * - VM Artwork list (`vmNameList`)
641
+ * - Product / SKU collection list (flattened from brand → category mapping
642
+ * that powers /manage/planogram/config). */
643
+ async loadPlacementDropdownData() {
644
+ if (!this.clientId)
645
+ return;
646
+ try {
647
+ const [vmTypesRes, vmsRes, brandsRes, brandMetaRes] = await Promise.all([
648
+ lastValueFrom(this.builderService.getVmTypesList(this.clientId)),
649
+ lastValueFrom(this.builderService.getVMNameList(this.clientId)),
650
+ lastValueFrom(this.builderService.getBrandList(this.clientId)),
651
+ lastValueFrom(this.builderService.getBrandMetaData(this.clientId)),
652
+ ]);
653
+ const vmTypes = vmTypesRes?.data || [];
654
+ this.vmTypeOptions = vmTypes
655
+ .map((t) => {
656
+ const v = t?.vmType || t?.vmTypeName || t?.name || t?._id;
657
+ const l = t?.vmTypeName || t?.vmType || t?.name || v;
658
+ return v ? { value: String(v), label: String(l) } : null;
659
+ })
660
+ .filter((x) => !!x);
661
+ const vms = vmsRes?.data || [];
662
+ this.vmArtworkOptions = vms
663
+ .map((v) => {
664
+ const id = v?.vmName || v?._id;
665
+ if (!id)
666
+ return null;
667
+ return {
668
+ value: String(id),
669
+ label: String(v?.vmName || id),
670
+ vmType: v?.vmType ? String(v.vmType) : undefined,
671
+ };
672
+ })
673
+ .filter((x) => !!x);
674
+ // (vmName, vmType) → _id so we can turn a placement's artwork NAME into
675
+ // the planovm _id the embedded VM editor matches against.
676
+ this.vmIdByNameType = new Map();
677
+ for (const v of vms) {
678
+ if (!v?._id || !v?.vmName)
679
+ continue;
680
+ const name = this.normVmType(v.vmName);
681
+ const type = this.normVmType(v.vmType);
682
+ this.vmIdByNameType.set(`${name}||${type}`, String(v._id));
683
+ if (!this.vmIdByNameType.has(name)) {
684
+ this.vmIdByNameType.set(name, String(v._id));
685
+ }
686
+ }
687
+ // Rebuild the (vmType → artworks) index now that the artwork list
688
+ // changed. Keys are normalised (trim + lower-case) so a mismatch in
689
+ // casing/whitespace between vmTypes and vms.vmType still matches.
690
+ this.vmArtworkByType = new Map();
691
+ const fullList = this.vmArtworkOptions.map((v) => ({ value: v.value, label: v.label }));
692
+ this.vmArtworkByType.set('', fullList);
693
+ for (const v of this.vmArtworkOptions) {
694
+ const key = this.normVmType(v.vmType);
695
+ if (!key)
696
+ continue;
697
+ if (!this.vmArtworkByType.has(key))
698
+ this.vmArtworkByType.set(key, []);
699
+ this.vmArtworkByType.get(key).push({ value: v.value, label: v.label });
700
+ }
701
+ console.log('[Looks form] vmTypes:', this.vmTypeOptions.length, 'artworks:', this.vmArtworkOptions.length, 'artworksByType keys:', Array.from(this.vmArtworkByType.keys()));
702
+ // Source: every value the brand & product mapping page exposes.
703
+ // - `getBrandList` → per-brand `category[]` and `subCategory[]`
704
+ // - `getBrandMetaData` → rows with `pidCat`, `category`, `tempGroup`
705
+ const brands = brandsRes?.data || [];
706
+ const brandMeta = brandMetaRes?.data || [];
707
+ const seenCats = new Set();
708
+ const products = [];
709
+ const pushOne = (v) => {
710
+ const s = String(v ?? '').trim();
711
+ if (!s || seenCats.has(s))
712
+ return;
713
+ seenCats.add(s);
714
+ products.push({ value: s, label: s });
715
+ };
716
+ const pushArr = (arr) => {
717
+ if (!Array.isArray(arr))
718
+ return;
719
+ for (const v of arr)
720
+ pushOne(v);
721
+ };
722
+ for (const b of brands) {
723
+ pushArr(b?.category);
724
+ pushArr(b?.subCategory);
725
+ }
726
+ for (const row of brandMeta) {
727
+ pushOne(row?.pidCat);
728
+ pushOne(row?.category);
729
+ pushOne(row?.tempGroup);
730
+ }
731
+ this.productOptions = products;
732
+ console.log('[Looks form] product/SKU options:', this.productOptions.length, 'from', brands.length, 'brands and', brandMeta.length, 'brand-meta rows');
733
+ }
734
+ catch (err) {
735
+ console.log('@@ ~ loadPlacementDropdownData [ERR]:', err);
736
+ }
737
+ }
738
+ async loadFixtureLibraries() {
739
+ if (!this.clientId)
740
+ return;
741
+ try {
742
+ // Only list fixture templates available in India (country code 'IN').
743
+ const res = await lastValueFrom(this.builderService.getFixtureLibNameList(this.clientId, 'non-draft', 'IN'));
744
+ // Response shape: { code, status, data: [{ id, fixtureName, fixtureType }] }.
745
+ const list = Array.isArray(res?.data) ? res.data : [];
746
+ this.fixtureLibraryItems = list.map((l) => ({
747
+ id: l.id,
748
+ name: l.fixtureName,
749
+ fixtureType: (l.fixtureType || '').toString().toLowerCase().trim(),
750
+ }));
751
+ const typeTally = {};
752
+ for (const it of this.fixtureLibraryItems) {
753
+ const k = it.fixtureType || '(empty)';
754
+ typeTally[k] = (typeTally[k] || 0) + 1;
755
+ }
756
+ console.log('[Looks form] fixture libraries loaded:', this.fixtureLibraryItems.length, 'fixtureType tally:', typeTally);
757
+ this.recomputeFixtureLibraryItemsForSlot();
758
+ }
759
+ catch (err) {
760
+ console.log('@@ ~ loadFixtureLibraries [ERR]:', err);
761
+ this.fixtureLibraryItems = [];
762
+ }
763
+ }
764
+ /**
765
+ * Recompute the slot-type-filtered library list once. Stable reference
766
+ * so the multiselect doesn't tear down its click targets every CD cycle.
767
+ */
768
+ recomputeFixtureLibraryItemsForSlot() {
769
+ const slot = this.selectedSlotGroup;
770
+ if (!slot) {
771
+ this.fixtureLibraryItemsForSlot = this.fixtureLibraryItems.slice();
772
+ return;
773
+ }
774
+ const slotType = slot.get('slotType')?.value;
775
+ const target = slotType === 'eurocenter' ? 'floor' : 'wall';
776
+ this.fixtureLibraryItemsForSlot = this.fixtureLibraryItems.filter((item) => {
777
+ const t = item.fixtureType;
778
+ if (!t)
779
+ return false;
780
+ if (target === 'wall')
781
+ return t === 'wall' || t.includes('wall');
782
+ return t === 'floor' || t.includes('floor') || t.includes('euro') || t.includes('free');
783
+ });
784
+ }
785
+ /**
786
+ * Subscriptions scoped to whichever slot is currently active. Cleared and
787
+ * rebuilt every time the active slot changes.
788
+ */
789
+ slotSubs = [];
790
+ /** Pending auto-apply promises keyed by libId so chip clicks can await. */
791
+ autoApplyInFlight = new Map();
792
+ /** Wire/refresh subscriptions that depend on the active slot:
793
+ * - re-filter the library multiselect when slotType changes
794
+ * - run auto-apply when a new library is added to fixtureLibraryRefs
795
+ */
796
+ bindActiveSlotListeners() {
797
+ for (const s of this.slotSubs)
798
+ s?.unsubscribe?.();
799
+ this.slotSubs = [];
800
+ const slot = this.selectedSlotGroup;
801
+ if (!slot) {
802
+ this.fixtureLibraryItemsForSlot = this.fixtureLibraryItems.slice();
803
+ return;
804
+ }
805
+ this.recomputeFixtureLibraryItemsForSlot();
806
+ const typeSub = slot.get('slotType')?.valueChanges
807
+ .pipe(takeUntil(this.destroy$))
808
+ .subscribe(() => this.recomputeFixtureLibraryItemsForSlot());
809
+ if (typeSub)
810
+ this.slotSubs.push(typeSub);
811
+ // Track previous refs so we can detect *new* additions and auto-apply
812
+ // the slot's PIDs to those new libraries.
813
+ let prevRefs = [...(slot.get('fixtureLibraryRefs')?.value || [])];
814
+ const refsSub = slot.get('fixtureLibraryRefs')?.valueChanges
815
+ .pipe(takeUntil(this.destroy$))
816
+ .subscribe((nextRefs) => {
817
+ const next = Array.isArray(nextRefs) ? nextRefs : [];
818
+ const added = next.filter((r) => !!r && !prevRefs.includes(r));
819
+ prevRefs = [...next];
820
+ // If the currently-previewed library was unselected, clear the
821
+ // embedded view so we don't show stale data.
822
+ if (this.selectedLibraryIdInMap
823
+ && !next.includes(this.selectedLibraryIdInMap)) {
824
+ this.onLibraryMapSelect('');
825
+ }
826
+ for (const libId of added) {
827
+ const p = this.autoApplyPidsToLibrary(libId);
828
+ this.autoApplyInFlight.set(libId, p);
829
+ p.finally(() => {
830
+ if (this.autoApplyInFlight.get(libId) === p) {
831
+ this.autoApplyInFlight.delete(libId);
832
+ }
833
+ });
834
+ }
835
+ // If nothing is being previewed yet, auto-activate the first library
836
+ // the user just added so the embedded PID/VM editor opens immediately
837
+ // (especially relevant when adding the FIRST library to an empty
838
+ // multiselect — previously the chip strip showed it but the preview
839
+ // pane stayed blank until the user clicked the chip).
840
+ if (!this.selectedLibraryIdInMap) {
841
+ const firstActive = added.find((id) => !!id) || next.find((id) => !!id);
842
+ if (firstActive)
843
+ this.onLibraryMapSelect(firstActive);
844
+ }
845
+ });
846
+ if (refsSub)
847
+ this.slotSubs.push(refsSub);
848
+ // When any placement in the "Look and Visual Merchandising Placements"
849
+ // list changes, re-derive every assigned library's snapshot so the edit
850
+ // propagates to all of them. Debounced so rapid typing collapses into a
851
+ // single re-apply.
852
+ const placementsArr = slot.get('placements');
853
+ const placementsSub = placementsArr?.valueChanges
854
+ .pipe(debounceTime(400), takeUntil(this.destroy$))
855
+ .subscribe(() => this.applyPlacementsToAssignedLibraries());
856
+ if (placementsSub)
857
+ this.slotSubs.push(placementsSub);
858
+ }
859
+ /**
860
+ * When a new library is added to the slot, walk its shelfConfig and for
861
+ * each shelf whose section currently has no brand, copy the rawValue of
862
+ * the slot's PID placement whose `position` matches the shelf's
863
+ * `zone`/`label`. Result is saved as the library's snapshot so the
864
+ * embedded fixture-template editor picks it up the next time the chip
865
+ * is opened.
866
+ */
867
+ async autoApplyPidsToLibrary(libId) {
868
+ if (!libId)
869
+ return;
870
+ const slot = this.selectedSlotGroup;
871
+ if (!slot)
872
+ return;
873
+ const placementsArr = slot.get('placements');
874
+ const placements = placementsArr?.value || [];
875
+ const pidPlacements = placements.filter((p) => p?.kind === 'pid' && p?.position && p?.rawValue);
876
+ const norm = (s) => String(s ?? '').trim().toLowerCase();
877
+ const placementMap = new Map();
878
+ for (const p of pidPlacements) {
879
+ placementMap.set(norm(p.position), String(p.rawValue));
880
+ }
881
+ // Start from an existing snapshot if we already saved one for this slot
882
+ // + library; otherwise fetch the fresh library doc. The per-field guards
883
+ // below still ensure we never overwrite user-set brands or VMs.
884
+ let libData = this.getLibrarySnapshot(libId);
885
+ if (!libData) {
886
+ try {
887
+ const res = await lastValueFrom(this.builderService.getFixtureLibraryDetails(libId));
888
+ libData = res?.data;
889
+ }
890
+ catch (err) {
891
+ console.log('@@ ~ autoApplyPidsToLibrary [ERR]:', err);
892
+ return;
893
+ }
894
+ }
895
+ if (!libData)
896
+ return;
897
+ const shelfConfig = Array.isArray(libData.shelfConfig) ? libData.shelfConfig : [];
898
+ let pidsApplied = false;
899
+ const newShelfConfig = shelfConfig.map((shelf) => {
900
+ if (Array.isArray(shelf?.productBrandName) && shelf.productBrandName.length > 0) {
901
+ return shelf;
902
+ }
903
+ const sourceLabel = shelf?.zone || shelf?.label || '';
904
+ const matchKey = norm(sourceLabel);
905
+ if (!matchKey)
906
+ return shelf;
907
+ const match = placementMap.get(matchKey);
908
+ if (!match)
909
+ return shelf;
910
+ pidsApplied = true;
911
+ // groupShelvesByZone() in TemplateProductsComponent SKIPS any shelf
912
+ // whose `zone` is empty, so we must set zone (using the shelf's label
913
+ // if it isn't already set) for the section to form.
914
+ return {
915
+ ...shelf,
916
+ zone: shelf?.zone || sourceLabel,
917
+ productBrandName: [match],
918
+ };
919
+ });
920
+ // --- VM auto-apply -----------------------------------------------------
921
+ // If the library has no VMs configured yet, copy each of the slot's VM
922
+ // placements over as a vmConfig entry. No position-based matching here —
923
+ // the placement's `rawValue` becomes the VM artwork and `position`
924
+ // becomes the VM type label.
925
+ const existingVms = Array.isArray(libData.vmConfig) ? libData.vmConfig : [];
926
+ let newVmConfig = existingVms;
927
+ let vmsApplied = false;
928
+ if (existingVms.length === 0) {
929
+ const vmPlacements = placements.filter((p) => p?.kind === 'vm' && p?.rawValue);
930
+ if (vmPlacements.length > 0) {
931
+ newVmConfig = vmPlacements.map((p) => ({
932
+ vmType: String(p?.position || ''),
933
+ vmId: String(p?.rawValue || ''),
934
+ startYPosition: 1,
935
+ endYPosition: 1,
936
+ xZone: '',
937
+ yZone: '',
938
+ position: '',
939
+ }));
940
+ vmsApplied = true;
941
+ }
942
+ }
943
+ if (!pidsApplied && !vmsApplied)
944
+ return;
945
+ // The embedded TemplateProductsComponent only reads section-level brand
946
+ // values when productResolutionLevel === 'L3'.
947
+ const updatedLib = {
948
+ ...libData,
949
+ shelfConfig: newShelfConfig,
950
+ vmConfig: newVmConfig,
951
+ productResolutionLevel: 'L3',
952
+ };
953
+ this.captureLibrarySnapshot(libId, updatedLib);
954
+ }
955
+ async loadDetails() {
956
+ if (!this.collectionId)
957
+ return;
958
+ this.loading = true;
959
+ try {
960
+ const res = await lastValueFrom(this.builderService.getLookPlanoCollectionDetails(this.collectionId));
961
+ const data = res?.data;
962
+ if (data) {
963
+ this.form.patchValue({
964
+ name: data.name || '',
965
+ description: data.description || '',
966
+ isActive: !!data.isActive,
967
+ });
968
+ this.looks.clear();
969
+ (data.looks || []).forEach((l) => this.looks.push(this.createLookGroup(l)));
970
+ this.selectedLookIndex = this.looks.length ? 0 : -1;
971
+ const slots = this.selectedLookIndex >= 0 ? this.fixtureSlots(this.selectedLookIndex) : null;
972
+ this.selectedSlotIndex = slots && slots.length ? 0 : -1;
973
+ this.resetLibraryMap();
974
+ this.bindActiveSlotListeners();
975
+ this.autoSelectFirstLibrary();
976
+ }
977
+ }
978
+ catch (err) {
979
+ console.log('@@ ~ loadDetails [ERR]:', err);
980
+ this.toast.getErrorToast?.('Failed to load Look collection');
981
+ }
982
+ finally {
983
+ this.loading = false;
984
+ }
985
+ }
986
+ addLook() {
987
+ const next = this.createLookGroup({ mbqBucket: '', fixtureCount: 1 });
988
+ this.looks.push(next);
989
+ this.selectedLookIndex = this.looks.length - 1;
990
+ this.selectedSlotIndex = this.fixtureSlots(this.selectedLookIndex).length ? 0 : -1;
991
+ this.bindActiveSlotListeners();
992
+ }
993
+ removeLook(index) {
994
+ this.looks.removeAt(index);
995
+ if (this.selectedLookIndex === index) {
996
+ this.selectedLookIndex = this.looks.length ? 0 : -1;
997
+ this.selectedSlotIndex = -1;
998
+ }
999
+ else if (this.selectedLookIndex > index) {
1000
+ this.selectedLookIndex -= 1;
1001
+ }
1002
+ }
1003
+ selectLook(index) {
1004
+ this.selectedLookIndex = index;
1005
+ const slots = this.fixtureSlots(index);
1006
+ this.selectedSlotIndex = slots.length ? 0 : -1;
1007
+ this.resetLibraryMap();
1008
+ this.bindActiveSlotListeners();
1009
+ this.autoSelectFirstLibrary();
1010
+ }
1011
+ addSlot() {
1012
+ if (this.selectedLookIndex < 0)
1013
+ return;
1014
+ const lookGroup = this.looks.at(this.selectedLookIndex);
1015
+ const slots = this.fixtureSlots(this.selectedLookIndex);
1016
+ slots.push(this.createSlotGroup({ slotIndex: slots.length + 1 }));
1017
+ lookGroup.get('fixtureCount').setValue(slots.length, { emitEvent: false });
1018
+ this.selectedSlotIndex = slots.length - 1;
1019
+ this.bindActiveSlotListeners();
1020
+ }
1021
+ removeSlot(slotIndex) {
1022
+ if (this.selectedLookIndex < 0)
1023
+ return;
1024
+ const lookGroup = this.looks.at(this.selectedLookIndex);
1025
+ const slots = this.fixtureSlots(this.selectedLookIndex);
1026
+ slots.removeAt(slotIndex);
1027
+ this.renumberSlotsForGroup(lookGroup);
1028
+ lookGroup.get('fixtureCount').setValue(slots.length, { emitEvent: false });
1029
+ if (this.selectedSlotIndex === slotIndex) {
1030
+ this.selectedSlotIndex = slots.length ? Math.min(slotIndex, slots.length - 1) : -1;
1031
+ }
1032
+ else if (this.selectedSlotIndex > slotIndex) {
1033
+ this.selectedSlotIndex -= 1;
1034
+ }
1035
+ }
1036
+ renumberSlotsForGroup(lookGroup) {
1037
+ const slotsArr = lookGroup.get('fixtureSlots');
1038
+ slotsArr.controls.forEach((slot, i) => {
1039
+ slot.get('slotIndex')?.setValue(i + 1, { emitEvent: false });
1040
+ });
1041
+ }
1042
+ selectSlot(slotIndex) {
1043
+ this.selectedSlotIndex = slotIndex;
1044
+ this.resetLibraryMap();
1045
+ this.bindActiveSlotListeners();
1046
+ this.autoSelectFirstLibrary();
1047
+ }
1048
+ lookTitle(lookGroup) {
1049
+ const keyType = lookGroup.get('keyType')?.value;
1050
+ const key = keyType === 'brandCategory'
1051
+ ? lookGroup.get('brandCategory')?.value
1052
+ : lookGroup.get('mbqBucket')?.value;
1053
+ const count = lookGroup.get('fixtureCount')?.value;
1054
+ return `${key || '(unnamed)'} — ${count || 0} fixtures`;
1055
+ }
1056
+ bucketKey(lookGroup) {
1057
+ const keyType = lookGroup.get('keyType')?.value;
1058
+ const key = keyType === 'brandCategory'
1059
+ ? lookGroup.get('brandCategory')?.value
1060
+ : lookGroup.get('mbqBucket')?.value;
1061
+ return (key || '').trim();
1062
+ }
1063
+ /**
1064
+ * Assign a colour to each unique bucket key by **insertion order**, not by hash.
1065
+ * The Nth distinct bucket (counted top-to-bottom through the looks array) gets
1066
+ * `BUCKET_PALETTE[N]`. Only after all 20 palette slots are used does the assignment
1067
+ * wrap around — so no colour is ever reused while < 20 distinct buckets exist.
1068
+ *
1069
+ * Recomputed on every call so live edits to the bucket name re-flow colours.
1070
+ */
1071
+ bucketColor(lookGroup) {
1072
+ const key = this.bucketKey(lookGroup);
1073
+ if (!key)
1074
+ return '#f9fafb';
1075
+ const palette = LookPlanoCollectionFormComponent.BUCKET_PALETTE;
1076
+ let nextIndex = 0;
1077
+ const assigned = new Map();
1078
+ for (const group of this.looks.controls) {
1079
+ const k = this.bucketKey(group);
1080
+ if (k && !assigned.has(k)) {
1081
+ assigned.set(k, palette[nextIndex % palette.length]);
1082
+ nextIndex += 1;
1083
+ }
1084
+ if (k === key) {
1085
+ return assigned.get(k);
1086
+ }
1087
+ }
1088
+ return '#f9fafb';
1089
+ }
1090
+ /**
1091
+ * Reorder the looks FormArray so that the bucket with the **most** looks
1092
+ * comes first and the one with the fewest comes last (alphabetical tie-break
1093
+ * within the same count). Looks within the same bucket are sorted by
1094
+ * ascending fixtureCount. Selection is preserved by reference, not by index.
1095
+ */
1096
+ applySortedOrder() {
1097
+ const groups = this.looks.controls;
1098
+ if (groups.length <= 1)
1099
+ return;
1100
+ // Tally how many looks each bucket has so we can sort buckets by frequency.
1101
+ const bucketCounts = new Map();
1102
+ for (const g of groups) {
1103
+ const k = this.bucketKey(g);
1104
+ if (!k)
1105
+ continue;
1106
+ bucketCounts.set(k, (bucketCounts.get(k) || 0) + 1);
1107
+ }
1108
+ const sorted = [...groups].sort((a, b) => {
1109
+ const aKey = this.bucketKey(a);
1110
+ const bKey = this.bucketKey(b);
1111
+ // Empty bucket keys go to the end so unfinished looks don't disrupt the groups
1112
+ if (aKey && !bKey)
1113
+ return -1;
1114
+ if (!aKey && bKey)
1115
+ return 1;
1116
+ // Primary: bucket frequency, descending (most-populated bucket first)
1117
+ const aCount = bucketCounts.get(aKey) || 0;
1118
+ const bCount = bucketCounts.get(bKey) || 0;
1119
+ if (aCount !== bCount)
1120
+ return bCount - aCount;
1121
+ // Tie-break: alphabetical bucket name
1122
+ if (aKey !== bKey)
1123
+ return aKey.localeCompare(bKey);
1124
+ // Within the same bucket: ascending fixtureCount
1125
+ const aFC = Number(a.get('fixtureCount')?.value) || 0;
1126
+ const bFC = Number(b.get('fixtureCount')?.value) || 0;
1127
+ return aFC - bFC;
1128
+ });
1129
+ const orderChanged = sorted.some((g, i) => g !== groups[i]);
1130
+ if (!orderChanged)
1131
+ return;
1132
+ const currentLook = this.selectedLookGroup;
1133
+ const currentSlot = this.selectedSlotGroup;
1134
+ this.looks.clear({ emitEvent: false });
1135
+ sorted.forEach((g) => this.looks.push(g, { emitEvent: false }));
1136
+ if (currentLook) {
1137
+ const newLookIdx = sorted.indexOf(currentLook);
1138
+ this.selectedLookIndex = newLookIdx;
1139
+ if (this.selectedLookIndex >= 0 && currentSlot) {
1140
+ const slotsArr = this.fixtureSlots(this.selectedLookIndex);
1141
+ const newSlotIdx = slotsArr.controls.indexOf(currentSlot);
1142
+ this.selectedSlotIndex = newSlotIdx;
1143
+ }
1144
+ }
1145
+ }
1146
+ async save() {
1147
+ if (this.form.invalid) {
1148
+ this.toast.getErrorToast?.('Please fill all required fields');
1149
+ return;
1150
+ }
1151
+ this.saving = true;
1152
+ try {
1153
+ // Sort the looks before serialising so both the persisted payload
1154
+ // and the on-screen list reflect grouping by MBQ bucket / brand category
1155
+ // and ascending fixture count.
1156
+ this.applySortedOrder();
1157
+ const payload = {
1158
+ ...this.form.value,
1159
+ clientId: this.clientId,
1160
+ };
1161
+ if (this.isNew) {
1162
+ const res = await lastValueFrom(this.builderService.createLookPlanoCollection(payload));
1163
+ const newId = res?.data?._id;
1164
+ this.toast.getSuccessToast?.('Look collection created');
1165
+ if (newId) {
1166
+ this.router.navigate(['/manage/planogram/looks', newId]);
1167
+ }
1168
+ else {
1169
+ this.router.navigate(['/manage/planogram/looks']);
1170
+ }
1171
+ }
1172
+ else {
1173
+ await lastValueFrom(this.builderService.updateLookPlanoCollection({ ...payload, collectionId: this.collectionId }));
1174
+ this.toast.getSuccessToast?.('Look collection updated');
1175
+ }
1176
+ }
1177
+ catch (err) {
1178
+ console.log('@@ ~ save [ERR]:', err);
1179
+ this.toast.getErrorToast?.('Failed to save Look collection');
1180
+ }
1181
+ finally {
1182
+ this.saving = false;
1183
+ }
1184
+ }
1185
+ cancel() {
1186
+ this.router.navigate(['/manage/planogram/looks']);
1187
+ }
1188
+ trackByIndex(index) {
1189
+ return index;
1190
+ }
1191
+ ngOnDestroy() {
1192
+ this.destroy$.next();
1193
+ this.destroy$.complete();
1194
+ // Release the shared BehaviorSubject so other pages don't inherit a stale library.
1195
+ this.planoDataService.fixtureTemplateDetails.next(null);
1196
+ }
1197
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: LookPlanoCollectionFormComponent, deps: [{ token: i1.FormBuilder }, { token: i2.ActivatedRoute }, { token: i2.Router }, { token: i3.GlobalStateService }, { token: i4.StoreBuilderService }, { token: i5.ToastService }, { token: i3.PageInfoService }, { token: i6.PlanoDataService }], target: i0.ɵɵFactoryTarget.Component });
1198
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: LookPlanoCollectionFormComponent, selector: "lib-look-plano-collection-form", ngImport: i0, template: "<section class=\"look-form\">\r\n <!-- Top bar (bound to the outer form) -->\r\n <div class=\"card p-4 mb-4\" [formGroup]=\"form\">\r\n <div class=\"row align-items-end\">\r\n <div class=\"col-md-4\">\r\n <label class=\"form-label fw-bold\">Name *</label>\r\n <input type=\"text\" class=\"form-control\" formControlName=\"name\" placeholder=\"e.g. Master Look Plan FY26\" />\r\n </div>\r\n <div class=\"col-md-5\">\r\n <label class=\"form-label fw-bold\">Description</label>\r\n <input type=\"text\" class=\"form-control\" formControlName=\"description\" placeholder=\"Optional description\" />\r\n </div>\r\n <div class=\"col-md-1 text-center\">\r\n <label class=\"form-label fw-bold d-block\">Active</label>\r\n <input type=\"checkbox\" class=\"form-check-input\" formControlName=\"isActive\" />\r\n </div>\r\n <div class=\"col-md-2 text-end\">\r\n <button type=\"button\" class=\"btn btn-light me-2\" (click)=\"cancel()\">Cancel</button>\r\n <button type=\"button\" class=\"btn btn-primary\" [disabled]=\"saving\" (click)=\"save()\">\r\n {{ saving ? 'Saving\u2026' : 'Save' }}\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Three-pane editor -->\r\n <div class=\"row mx-0 g-3\">\r\n <!-- Left: Looks list (no form binding needed \u2014 just navigation) -->\r\n <div class=\"col-md-3\">\r\n <div class=\"card p-3 h-100\">\r\n <div class=\"d-flex justify-content-between align-items-center mb-3\">\r\n <h6 class=\"m-0\">MBQ Bucket - Fixture Combinations</h6>\r\n <button type=\"button\" class=\"btn btn-sm btn-primary\" (click)=\"addLook()\">+ Add Look</button>\r\n </div>\r\n <div *ngIf=\"looks.length === 0\" class=\"text-muted small\">No looks yet. Add one to start.</div>\r\n <div class=\"looks-tree\">\r\n <div\r\n *ngFor=\"let look of looks.controls; let i = index; trackBy: trackByIndex\"\r\n class=\"look-row d-flex justify-content-between align-items-center px-2 py-2 mb-1 rounded\"\r\n [class.selected]=\"selectedLookIndex === i\"\r\n [style.background-color]=\"bucketColor($any(look))\"\r\n (click)=\"selectLook(i)\"\r\n >\r\n <span class=\"d-flex align-items-center gap-2 text-truncate\">\r\n <span class=\"bucket-dot\" [style.background-color]=\"bucketColor($any(look))\"></span>\r\n <span class=\"text-truncate\">{{ lookTitle($any(look)) }}</span>\r\n </span>\r\n <button type=\"button\" class=\"btn btn-sm btn-light-danger ms-2\" (click)=\"$event.stopPropagation(); removeLook(i)\">\u00D7</button>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Centre: selected Look metadata + slots -->\r\n <div class=\"col-md-3\">\r\n <ng-container *ngIf=\"selectedLookGroup as lookGroup; else noLook\">\r\n <div class=\"card p-3 h-100\" [formGroup]=\"lookGroup\">\r\n <h6 class=\"mb-3\">Fixture Combination Details</h6>\r\n\r\n <div class=\"row g-2 mb-3\">\r\n <div class=\"col-md-6\">\r\n <label class=\"form-label small\">MBQ bucket</label>\r\n <input type=\"text\" class=\"form-control form-control-sm\" formControlName=\"mbqBucket\" placeholder=\"e.g. JJ / OD Eye\" />\r\n </div>\r\n <div class=\"col-md-6\">\r\n <label class=\"form-label small\">Fixture count *</label>\r\n <input type=\"number\" min=\"0\" max=\"30\" class=\"form-control form-control-sm\" formControlName=\"fixtureCount\" />\r\n </div>\r\n <div class=\"col-md-12\">\r\n <label class=\"form-label small\">Fixture Positions</label>\r\n <multiselect-chip-dropdown\r\n [items]=\"fixtureTypeOptions\"\r\n idField=\"id\"\r\n nameField=\"name\"\r\n placeholder=\"Select fixture position\"\r\n formControlName=\"fixtureType\">\r\n </multiselect-chip-dropdown>\r\n </div>\r\n </div>\r\n\r\n <hr />\r\n\r\n <div class=\"d-flex justify-content-between align-items-center mb-2\">\r\n <h6 class=\"m-0\">Fixtures</h6>\r\n <button type=\"button\" class=\"btn btn-sm btn-light\" (click)=\"addSlot()\">+ Add Fixture</button>\r\n </div>\r\n <div class=\"slots-list\">\r\n <div\r\n *ngFor=\"let slot of (selectedSlotsArray?.controls || []); let s = index; trackBy: trackByIndex\"\r\n class=\"slot-row d-flex justify-content-between align-items-center px-2 py-2 mb-1 rounded\"\r\n [class.selected]=\"selectedSlotIndex === s\"\r\n (click)=\"selectSlot(s)\"\r\n >\r\n <div class=\"d-flex flex-column\">\r\n <span class=\"fw-bold small\">\r\n Fixture {{ $any(slot).get('slotIndex')?.value }} \u2014 {{ $any(slot).get('slotType')?.value }}\r\n </span>\r\n <span class=\"text-muted small\">\r\n {{ $any(slot).get('brand')?.value || '(no brand)' }} \u00B7\r\n {{ $any(slot).get('fixtureLevelZone')?.value || '(no zone)' }}\r\n </span>\r\n </div>\r\n <button type=\"button\" class=\"btn btn-sm btn-light-danger ms-2\" (click)=\"$event.stopPropagation(); removeSlot(s)\">\u00D7</button>\r\n </div>\r\n </div>\r\n </div>\r\n </ng-container>\r\n <ng-template #noLook>\r\n <div class=\"card p-5 h-100 text-center text-muted\">Select or add a Look to edit it.</div>\r\n </ng-template>\r\n </div>\r\n\r\n <!-- Right: selected slot \u2014 placements editor -->\r\n <div class=\"col-md-6\">\r\n <ng-container *ngIf=\"selectedSlotGroup as slotGroup; else noSlot\">\r\n <div class=\"card p-3 h-100\" [formGroup]=\"slotGroup\">\r\n <h6 class=\"mb-3\">Fixture {{ selectedSlotIndex + 1 }} - Definition</h6>\r\n\r\n <div class=\"row g-2 mb-3\">\r\n <div class=\"col-md-12\">\r\n <label class=\"form-label small text-muted\">Slot index (auto)</label>\r\n <input type=\"text\" class=\"form-control form-control-sm\" [value]=\"selectedSlotIndex + 1\" readonly disabled />\r\n </div>\r\n <div class=\"col-md-6\">\r\n <label class=\"form-label small\">Fixture Type</label>\r\n <select class=\"form-select form-select-sm\" formControlName=\"slotType\">\r\n <option *ngFor=\"let opt of availableSlotTypes\" [value]=\"opt.id\">{{ opt.name }}</option>\r\n </select>\r\n </div>\r\n <div class=\"col-md-6\">\r\n <label class=\"form-label small\">Brand</label>\r\n <input type=\"text\" class=\"form-control form-control-sm\" formControlName=\"brand\" placeholder=\"John Jacobs\" />\r\n </div>\r\n <div class=\"col-md-12\">\r\n <label class=\"form-label small\">Fixture Header</label>\r\n <input type=\"text\" class=\"form-control form-control-sm\" formControlName=\"fixtureLevelZone\" placeholder=\"Premium Trending\" />\r\n </div>\r\n <div class=\"col-md-12\">\r\n <label class=\"form-label small\">CAD Header Varients</label>\r\n <lib-chips-input\r\n formControlName=\"cadHeaderVariants\"\r\n placeholder=\"Type a variant and press Enter\">\r\n </lib-chips-input>\r\n </div>\r\n <div class=\"col-md-12\">\r\n <label class=\"form-label small\">Fixture Templates</label>\r\n <multiselect-chip-dropdown\r\n class=\"fixture-libraries-select\"\r\n [items]=\"fixtureLibraryItemsForSlot\"\r\n idField=\"id\"\r\n nameField=\"name\"\r\n [search]=\"true\"\r\n searchField=\"name\"\r\n placeholder=\"Select fixture templates\"\r\n formControlName=\"fixtureLibraryRefs\">\r\n </multiselect-chip-dropdown>\r\n <small class=\"text-muted\" *ngIf=\"slotGroup.get('slotType')?.value === 'eurocenter'\">\r\n Showing floor fixtures (eurocenter slot).\r\n </small>\r\n <small class=\"text-muted\" *ngIf=\"slotGroup.get('slotType')?.value !== 'eurocenter'\">\r\n Showing wall fixtures (shelf slot).\r\n </small>\r\n </div>\r\n </div>\r\n\r\n <hr />\r\n\r\n <div class=\"d-flex justify-content-between align-items-center mb-2\">\r\n <h6 class=\"m-0\">Look and Visual Merchandising Placements</h6>\r\n <button type=\"button\" class=\"btn btn-sm btn-light\" (click)=\"addPlacement()\">+ Add placement</button>\r\n </div>\r\n <div *ngIf=\"(selectedPlacements?.length || 0) === 0\" class=\"text-muted small mb-2\">\r\n No placements yet. Click <strong>+ Add placement</strong> to add one.\r\n </div>\r\n <div class=\"placements-scroll\" formArrayName=\"placements\">\r\n <div\r\n *ngFor=\"let p of (selectedPlacements?.controls || []); let pi = index; trackBy: trackByIndex\"\r\n class=\"placement-row mb-2\"\r\n [formGroupName]=\"pi\"\r\n >\r\n <div class=\"d-flex align-items-start gap-2 placement-fields\">\r\n <div class=\"ph-field\">\r\n <select class=\"form-select form-select-sm\" formControlName=\"kind\">\r\n <option value=\"pid\">Product Merchandising</option>\r\n <option value=\"vm\">Visual Merchandising</option>\r\n </select>\r\n </div>\r\n\r\n <!-- Visual Merchandising rows: VM Type (single) + VM Artwork (single) -->\r\n <ng-container *ngIf=\"$any(p).get('kind')?.value === 'vm'; else pidInputs\">\r\n <div class=\"ph-field\">\r\n <lib-searchable-select\r\n [items]=\"vmTypeOptions\"\r\n idField=\"value\"\r\n nameField=\"label\"\r\n placeholder=\"Visual Merchandising Type\"\r\n formControlName=\"position\">\r\n </lib-searchable-select>\r\n </div>\r\n <div class=\"ph-field\">\r\n <lib-searchable-select\r\n [items]=\"vmArtworkOptionsFor($any(p).get('position')?.value)\"\r\n idField=\"value\"\r\n nameField=\"label\"\r\n placeholder=\"Visual Merchandising Artwork\"\r\n formControlName=\"rawValue\">\r\n </lib-searchable-select>\r\n </div>\r\n </ng-container>\r\n\r\n <!-- Product Merchandising rows: Top/Mid/Bottom position + multi-select product/SKU -->\r\n <ng-template #pidInputs>\r\n <div class=\"ph-field\">\r\n <select class=\"form-select form-select-sm\" formControlName=\"position\">\r\n <option value=\"\">Position</option>\r\n <option value=\"Top\">Top</option>\r\n <option value=\"Mid\">Mid</option>\r\n <option value=\"Bottom\">Bottom</option>\r\n </select>\r\n </div>\r\n <div class=\"ph-field\">\r\n <lib-searchable-select\r\n [items]=\"productOptions\"\r\n idField=\"value\"\r\n nameField=\"label\"\r\n [multiple]=\"true\"\r\n placeholder=\"Product / SKU\"\r\n formControlName=\"rawValues\">\r\n </lib-searchable-select>\r\n </div>\r\n </ng-template>\r\n\r\n <button type=\"button\" class=\"btn btn-sm btn-light-danger ph-remove\" (click)=\"removePlacement(pi)\">\u00D7</button>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </ng-container>\r\n <ng-template #noSlot>\r\n <div class=\"card p-5 h-100 text-center text-muted\">Select a fixture slot to edit placements.</div>\r\n </ng-template>\r\n </div>\r\n </div>\r\n\r\n <!-- Per-slot Fixture Library Configuration card -->\r\n <ng-container *ngIf=\"selectedSlotGroup as slotGroupForMap\">\r\n <div class=\"card p-4 mt-4 library-config-card\" [formGroup]=\"slotGroupForMap\">\r\n <div class=\"mb-4\">\r\n <h5 class=\"form-label d-block mb-3\">Fixture library</h5>\r\n <div class=\"library-chips\">\r\n <button\r\n *ngFor=\"let lib of selectedSlotLibrariesForDropdown\"\r\n type=\"button\"\r\n class=\"library-chip\"\r\n [class.active]=\"selectedLibraryIdInMap === lib.id\"\r\n (click)=\"onLibraryMapSelect(selectedLibraryIdInMap === lib.id ? '' : lib.id)\">\r\n {{ lib.name }}\r\n </button>\r\n </div>\r\n <small *ngIf=\"selectedSlotLibrariesForDropdown.length === 0\" class=\"text-muted\">\r\n No libraries linked to this slot yet. Add some in the \"Fixture libraries\" multiselect above.\r\n </small>\r\n </div>\r\n\r\n <div *ngIf=\"loadingLibraryDetails\" class=\"text-muted\">Loading fixture details\u2026</div>\r\n\r\n <!--\r\n Use *ngFor + trackBy keyed on (look, slot, library) so Angular treats\r\n a switch as a new item \u2014 that forces the embedded template-products\r\n / template-vms components to remount and rerun their ngOnInit\r\n (otherwise their `isPageLoading` guard skips the form rebuild).\r\n -->\r\n <ng-container *ngFor=\"let _ of embeddedHostKeys; trackBy: trackByEmbeddedKey\">\r\n <ul class=\"nav nav-tabs custom-tabs mb-3\">\r\n <li class=\"nav-item\">\r\n <button type=\"button\" class=\"nav-link\"\r\n [class.active]=\"embeddedTab === 'products'\"\r\n (click)=\"embeddedTab = 'products'\">Product Merchandising</button>\r\n </li>\r\n <li class=\"nav-item\">\r\n <button type=\"button\" class=\"nav-link\"\r\n [class.active]=\"embeddedTab === 'vms'\"\r\n (click)=\"embeddedTab = 'vms'\">Visual Merchandising</button>\r\n </li>\r\n </ul>\r\n\r\n <div *ngIf=\"embeddedTab === 'products'\">\r\n <lib-template-products [looksMode]=\"true\"></lib-template-products>\r\n </div>\r\n <div *ngIf=\"embeddedTab === 'vms'\">\r\n <lib-template-vms [looksMode]=\"true\"></lib-template-vms>\r\n </div>\r\n </ng-container>\r\n </div>\r\n </ng-container>\r\n</section>\r\n", styles: [".look-form .col-md-3>.card,.look-form .col-md-6>.card{display:flex!important;flex-direction:column;height:75vh!important;min-height:600px}.look-form .looks-tree,.look-form .slots-list,.look-form .placements-scroll{flex:1 1 auto;min-height:0;overflow-y:auto}.look-form .look-row,.look-form .slot-row{cursor:pointer;border:1px solid transparent;background:#f9fafb;transition:filter .15s ease,box-shadow .15s ease,border-color .15s ease}.look-form .look-row:hover,.look-form .slot-row:hover{filter:brightness(.96)}.look-form .look-row.selected,.look-form .slot-row.selected{filter:brightness(.96);outline:1px solid rgba(14,165,233,.55);outline-offset:-1px}.look-form .bucket-dot{display:inline-block;width:10px;height:10px;border-radius:50%;flex-shrink:0;border:1px solid rgba(0,0,0,.12)}.look-form .fixture-libraries-select{display:block}.look-form .fixture-libraries-select ::ng-deep .multiselect-container{align-items:flex-start}.look-form .fixture-libraries-select ::ng-deep .chip-list{max-height:84px;overflow-y:auto;padding-right:4px}.look-form .placement-row .placement-fields .ph-field{flex:1 1 0;min-width:0}.look-form .placement-row .placement-fields .ph-remove{flex:0 0 auto}.look-form .placement-row .placement-fields ::ng-deep multiselect-chip-dropdown .multiselect-container{padding:4px 10px;min-height:31px}.look-form .placement-row .placement-fields ::ng-deep multiselect-chip-dropdown .chip-list{min-height:21px}.look-form .placement-row .placement-fields ::ng-deep multiselect-chip-dropdown .multi-placeholder{font-size:13px;line-height:21px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.look-form .library-config-card .library-chips{display:flex;flex-wrap:wrap;gap:8px}.look-form .library-config-card .library-chip{background:#f1f5f9;border:1px solid #cbd5e1;color:#1e293b;border-radius:999px;padding:6px 14px;font-size:13px;font-weight:500;cursor:pointer;transition:background-color .15s ease,border-color .15s ease,color .15s ease}.look-form .library-config-card .library-chip:hover{background:#e2e8f0;border-color:#94a3b8}.look-form .library-config-card .library-chip.active{background:#0ea5e9;border-color:#0284c7;color:#fff}.look-form .library-config-card ::ng-deep #fixture-template-products .cols.col>ul.nav.nav-tabs.custom-tabs{display:none!important}.look-form .library-config-card ::ng-deep #fixture-template-products .cols.col-8>ul.nav.nav-tabs.custom-tabs{display:none!important}.look-form .library-config-card ::ng-deep #fixture-template-products input[readonly]{background-color:var(--bs-gray-200, #e9ecef);cursor:not-allowed}.look-form .library-config-card .fixture-preview{border:1px solid #e2e8f0;border-radius:8px;background:#fff;padding:12px}.look-form .library-config-card .fixture-preview .fx-header,.look-form .library-config-card .fixture-preview .fx-footer{background:#f1f5f9;border:1px dashed #cbd5e1;border-radius:6px;padding:6px 10px;font-size:12px;color:#475569;text-align:center;margin:4px 0}.look-form .library-config-card .fixture-preview .fx-body{display:flex;flex-direction:column;gap:4px;padding:4px 0}.look-form .library-config-card .fixture-preview .fx-shelf{background:linear-gradient(180deg,#f8fafc,#eef2f7);border:1px solid #cbd5e1;border-radius:4px;padding:8px 10px;display:flex;align-items:center;gap:8px;font-size:13px;min-height:36px}.look-form .library-config-card .fixture-preview .fx-shelf .fx-shelf-badge{background:#0ea5e9;color:#fff;font-weight:700;padding:2px 8px;border-radius:999px;font-size:11px;flex-shrink:0}.look-form .library-config-card .fixture-preview .fx-shelf .fx-shelf-label{font-weight:500;color:#1e293b}.look-form .library-config-card .fixture-preview .fx-shelf .fx-shelf-meta{color:#64748b;font-size:11px;margin-left:auto}.look-form .library-config-card .fixture-preview .fx-shelf.fx-shelf-tray{background:linear-gradient(180deg,#fef3c7,#fde68a);border-color:#f59e0b}.look-form .library-config-card .fixture-preview .fx-shelf.fx-shelf-tray .fx-shelf-badge{background:#d97706}.look-form .library-config-card .fixture-preview .fx-shelf.fx-shelf-vmonly{background:linear-gradient(180deg,#ede9fe,#ddd6fe);border-color:#8b5cf6}.look-form .library-config-card .fixture-preview .fx-shelf.fx-shelf-vmonly .fx-shelf-badge{background:#7c3aed}.look-form .library-config-card .fixture-preview .fx-dims{text-align:center}.look-form .library-config-card .shelf-mappings{max-height:70vh;overflow-y:auto;padding-right:4px}.look-form .library-config-card .shelf-mappings .shelf-mapping{border:1px solid #e5e7eb;border-radius:8px;padding:12px;background:#f9fafb}\n"], dependencies: [{ kind: "directive", type: i7.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i7.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { kind: "directive", type: i1.MaxValidator, selector: "input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]", inputs: ["max"] }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i1.FormGroupName, selector: "[formGroupName]", inputs: ["formGroupName"] }, { kind: "directive", type: i1.FormArrayName, selector: "[formArrayName]", inputs: ["formArrayName"] }, { kind: "component", type: i8.MultiselectChipDropdownComponent, selector: "multiselect-chip-dropdown", inputs: ["idField", "nameField", "placeholder", "items", "search", "searchField", "maxSelection", "compact", "extraActionLabel", "extraActionActive", "disabled"], outputs: ["extraActionClick"] }, { kind: "component", type: i9.TemplateProductsComponent, selector: "lib-template-products", inputs: ["looksMode"] }, { kind: "component", type: i10.SearchableSelectComponent, selector: "lib-searchable-select", inputs: ["items", "idField", "nameField", "searchField", "placeholder", "multiple", "compact"] }, { kind: "component", type: i11.ChipsInputComponent, selector: "lib-chips-input", inputs: ["placeholder", "allowDuplicates"] }, { kind: "component", type: i12.TemplateVmsComponent, selector: "lib-template-vms", inputs: ["looksMode"] }] });
1199
+ }
1200
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: LookPlanoCollectionFormComponent, decorators: [{
1201
+ type: Component,
1202
+ args: [{ selector: 'lib-look-plano-collection-form', template: "<section class=\"look-form\">\r\n <!-- Top bar (bound to the outer form) -->\r\n <div class=\"card p-4 mb-4\" [formGroup]=\"form\">\r\n <div class=\"row align-items-end\">\r\n <div class=\"col-md-4\">\r\n <label class=\"form-label fw-bold\">Name *</label>\r\n <input type=\"text\" class=\"form-control\" formControlName=\"name\" placeholder=\"e.g. Master Look Plan FY26\" />\r\n </div>\r\n <div class=\"col-md-5\">\r\n <label class=\"form-label fw-bold\">Description</label>\r\n <input type=\"text\" class=\"form-control\" formControlName=\"description\" placeholder=\"Optional description\" />\r\n </div>\r\n <div class=\"col-md-1 text-center\">\r\n <label class=\"form-label fw-bold d-block\">Active</label>\r\n <input type=\"checkbox\" class=\"form-check-input\" formControlName=\"isActive\" />\r\n </div>\r\n <div class=\"col-md-2 text-end\">\r\n <button type=\"button\" class=\"btn btn-light me-2\" (click)=\"cancel()\">Cancel</button>\r\n <button type=\"button\" class=\"btn btn-primary\" [disabled]=\"saving\" (click)=\"save()\">\r\n {{ saving ? 'Saving\u2026' : 'Save' }}\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Three-pane editor -->\r\n <div class=\"row mx-0 g-3\">\r\n <!-- Left: Looks list (no form binding needed \u2014 just navigation) -->\r\n <div class=\"col-md-3\">\r\n <div class=\"card p-3 h-100\">\r\n <div class=\"d-flex justify-content-between align-items-center mb-3\">\r\n <h6 class=\"m-0\">MBQ Bucket - Fixture Combinations</h6>\r\n <button type=\"button\" class=\"btn btn-sm btn-primary\" (click)=\"addLook()\">+ Add Look</button>\r\n </div>\r\n <div *ngIf=\"looks.length === 0\" class=\"text-muted small\">No looks yet. Add one to start.</div>\r\n <div class=\"looks-tree\">\r\n <div\r\n *ngFor=\"let look of looks.controls; let i = index; trackBy: trackByIndex\"\r\n class=\"look-row d-flex justify-content-between align-items-center px-2 py-2 mb-1 rounded\"\r\n [class.selected]=\"selectedLookIndex === i\"\r\n [style.background-color]=\"bucketColor($any(look))\"\r\n (click)=\"selectLook(i)\"\r\n >\r\n <span class=\"d-flex align-items-center gap-2 text-truncate\">\r\n <span class=\"bucket-dot\" [style.background-color]=\"bucketColor($any(look))\"></span>\r\n <span class=\"text-truncate\">{{ lookTitle($any(look)) }}</span>\r\n </span>\r\n <button type=\"button\" class=\"btn btn-sm btn-light-danger ms-2\" (click)=\"$event.stopPropagation(); removeLook(i)\">\u00D7</button>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Centre: selected Look metadata + slots -->\r\n <div class=\"col-md-3\">\r\n <ng-container *ngIf=\"selectedLookGroup as lookGroup; else noLook\">\r\n <div class=\"card p-3 h-100\" [formGroup]=\"lookGroup\">\r\n <h6 class=\"mb-3\">Fixture Combination Details</h6>\r\n\r\n <div class=\"row g-2 mb-3\">\r\n <div class=\"col-md-6\">\r\n <label class=\"form-label small\">MBQ bucket</label>\r\n <input type=\"text\" class=\"form-control form-control-sm\" formControlName=\"mbqBucket\" placeholder=\"e.g. JJ / OD Eye\" />\r\n </div>\r\n <div class=\"col-md-6\">\r\n <label class=\"form-label small\">Fixture count *</label>\r\n <input type=\"number\" min=\"0\" max=\"30\" class=\"form-control form-control-sm\" formControlName=\"fixtureCount\" />\r\n </div>\r\n <div class=\"col-md-12\">\r\n <label class=\"form-label small\">Fixture Positions</label>\r\n <multiselect-chip-dropdown\r\n [items]=\"fixtureTypeOptions\"\r\n idField=\"id\"\r\n nameField=\"name\"\r\n placeholder=\"Select fixture position\"\r\n formControlName=\"fixtureType\">\r\n </multiselect-chip-dropdown>\r\n </div>\r\n </div>\r\n\r\n <hr />\r\n\r\n <div class=\"d-flex justify-content-between align-items-center mb-2\">\r\n <h6 class=\"m-0\">Fixtures</h6>\r\n <button type=\"button\" class=\"btn btn-sm btn-light\" (click)=\"addSlot()\">+ Add Fixture</button>\r\n </div>\r\n <div class=\"slots-list\">\r\n <div\r\n *ngFor=\"let slot of (selectedSlotsArray?.controls || []); let s = index; trackBy: trackByIndex\"\r\n class=\"slot-row d-flex justify-content-between align-items-center px-2 py-2 mb-1 rounded\"\r\n [class.selected]=\"selectedSlotIndex === s\"\r\n (click)=\"selectSlot(s)\"\r\n >\r\n <div class=\"d-flex flex-column\">\r\n <span class=\"fw-bold small\">\r\n Fixture {{ $any(slot).get('slotIndex')?.value }} \u2014 {{ $any(slot).get('slotType')?.value }}\r\n </span>\r\n <span class=\"text-muted small\">\r\n {{ $any(slot).get('brand')?.value || '(no brand)' }} \u00B7\r\n {{ $any(slot).get('fixtureLevelZone')?.value || '(no zone)' }}\r\n </span>\r\n </div>\r\n <button type=\"button\" class=\"btn btn-sm btn-light-danger ms-2\" (click)=\"$event.stopPropagation(); removeSlot(s)\">\u00D7</button>\r\n </div>\r\n </div>\r\n </div>\r\n </ng-container>\r\n <ng-template #noLook>\r\n <div class=\"card p-5 h-100 text-center text-muted\">Select or add a Look to edit it.</div>\r\n </ng-template>\r\n </div>\r\n\r\n <!-- Right: selected slot \u2014 placements editor -->\r\n <div class=\"col-md-6\">\r\n <ng-container *ngIf=\"selectedSlotGroup as slotGroup; else noSlot\">\r\n <div class=\"card p-3 h-100\" [formGroup]=\"slotGroup\">\r\n <h6 class=\"mb-3\">Fixture {{ selectedSlotIndex + 1 }} - Definition</h6>\r\n\r\n <div class=\"row g-2 mb-3\">\r\n <div class=\"col-md-12\">\r\n <label class=\"form-label small text-muted\">Slot index (auto)</label>\r\n <input type=\"text\" class=\"form-control form-control-sm\" [value]=\"selectedSlotIndex + 1\" readonly disabled />\r\n </div>\r\n <div class=\"col-md-6\">\r\n <label class=\"form-label small\">Fixture Type</label>\r\n <select class=\"form-select form-select-sm\" formControlName=\"slotType\">\r\n <option *ngFor=\"let opt of availableSlotTypes\" [value]=\"opt.id\">{{ opt.name }}</option>\r\n </select>\r\n </div>\r\n <div class=\"col-md-6\">\r\n <label class=\"form-label small\">Brand</label>\r\n <input type=\"text\" class=\"form-control form-control-sm\" formControlName=\"brand\" placeholder=\"John Jacobs\" />\r\n </div>\r\n <div class=\"col-md-12\">\r\n <label class=\"form-label small\">Fixture Header</label>\r\n <input type=\"text\" class=\"form-control form-control-sm\" formControlName=\"fixtureLevelZone\" placeholder=\"Premium Trending\" />\r\n </div>\r\n <div class=\"col-md-12\">\r\n <label class=\"form-label small\">CAD Header Varients</label>\r\n <lib-chips-input\r\n formControlName=\"cadHeaderVariants\"\r\n placeholder=\"Type a variant and press Enter\">\r\n </lib-chips-input>\r\n </div>\r\n <div class=\"col-md-12\">\r\n <label class=\"form-label small\">Fixture Templates</label>\r\n <multiselect-chip-dropdown\r\n class=\"fixture-libraries-select\"\r\n [items]=\"fixtureLibraryItemsForSlot\"\r\n idField=\"id\"\r\n nameField=\"name\"\r\n [search]=\"true\"\r\n searchField=\"name\"\r\n placeholder=\"Select fixture templates\"\r\n formControlName=\"fixtureLibraryRefs\">\r\n </multiselect-chip-dropdown>\r\n <small class=\"text-muted\" *ngIf=\"slotGroup.get('slotType')?.value === 'eurocenter'\">\r\n Showing floor fixtures (eurocenter slot).\r\n </small>\r\n <small class=\"text-muted\" *ngIf=\"slotGroup.get('slotType')?.value !== 'eurocenter'\">\r\n Showing wall fixtures (shelf slot).\r\n </small>\r\n </div>\r\n </div>\r\n\r\n <hr />\r\n\r\n <div class=\"d-flex justify-content-between align-items-center mb-2\">\r\n <h6 class=\"m-0\">Look and Visual Merchandising Placements</h6>\r\n <button type=\"button\" class=\"btn btn-sm btn-light\" (click)=\"addPlacement()\">+ Add placement</button>\r\n </div>\r\n <div *ngIf=\"(selectedPlacements?.length || 0) === 0\" class=\"text-muted small mb-2\">\r\n No placements yet. Click <strong>+ Add placement</strong> to add one.\r\n </div>\r\n <div class=\"placements-scroll\" formArrayName=\"placements\">\r\n <div\r\n *ngFor=\"let p of (selectedPlacements?.controls || []); let pi = index; trackBy: trackByIndex\"\r\n class=\"placement-row mb-2\"\r\n [formGroupName]=\"pi\"\r\n >\r\n <div class=\"d-flex align-items-start gap-2 placement-fields\">\r\n <div class=\"ph-field\">\r\n <select class=\"form-select form-select-sm\" formControlName=\"kind\">\r\n <option value=\"pid\">Product Merchandising</option>\r\n <option value=\"vm\">Visual Merchandising</option>\r\n </select>\r\n </div>\r\n\r\n <!-- Visual Merchandising rows: VM Type (single) + VM Artwork (single) -->\r\n <ng-container *ngIf=\"$any(p).get('kind')?.value === 'vm'; else pidInputs\">\r\n <div class=\"ph-field\">\r\n <lib-searchable-select\r\n [items]=\"vmTypeOptions\"\r\n idField=\"value\"\r\n nameField=\"label\"\r\n placeholder=\"Visual Merchandising Type\"\r\n formControlName=\"position\">\r\n </lib-searchable-select>\r\n </div>\r\n <div class=\"ph-field\">\r\n <lib-searchable-select\r\n [items]=\"vmArtworkOptionsFor($any(p).get('position')?.value)\"\r\n idField=\"value\"\r\n nameField=\"label\"\r\n placeholder=\"Visual Merchandising Artwork\"\r\n formControlName=\"rawValue\">\r\n </lib-searchable-select>\r\n </div>\r\n </ng-container>\r\n\r\n <!-- Product Merchandising rows: Top/Mid/Bottom position + multi-select product/SKU -->\r\n <ng-template #pidInputs>\r\n <div class=\"ph-field\">\r\n <select class=\"form-select form-select-sm\" formControlName=\"position\">\r\n <option value=\"\">Position</option>\r\n <option value=\"Top\">Top</option>\r\n <option value=\"Mid\">Mid</option>\r\n <option value=\"Bottom\">Bottom</option>\r\n </select>\r\n </div>\r\n <div class=\"ph-field\">\r\n <lib-searchable-select\r\n [items]=\"productOptions\"\r\n idField=\"value\"\r\n nameField=\"label\"\r\n [multiple]=\"true\"\r\n placeholder=\"Product / SKU\"\r\n formControlName=\"rawValues\">\r\n </lib-searchable-select>\r\n </div>\r\n </ng-template>\r\n\r\n <button type=\"button\" class=\"btn btn-sm btn-light-danger ph-remove\" (click)=\"removePlacement(pi)\">\u00D7</button>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </ng-container>\r\n <ng-template #noSlot>\r\n <div class=\"card p-5 h-100 text-center text-muted\">Select a fixture slot to edit placements.</div>\r\n </ng-template>\r\n </div>\r\n </div>\r\n\r\n <!-- Per-slot Fixture Library Configuration card -->\r\n <ng-container *ngIf=\"selectedSlotGroup as slotGroupForMap\">\r\n <div class=\"card p-4 mt-4 library-config-card\" [formGroup]=\"slotGroupForMap\">\r\n <div class=\"mb-4\">\r\n <h5 class=\"form-label d-block mb-3\">Fixture library</h5>\r\n <div class=\"library-chips\">\r\n <button\r\n *ngFor=\"let lib of selectedSlotLibrariesForDropdown\"\r\n type=\"button\"\r\n class=\"library-chip\"\r\n [class.active]=\"selectedLibraryIdInMap === lib.id\"\r\n (click)=\"onLibraryMapSelect(selectedLibraryIdInMap === lib.id ? '' : lib.id)\">\r\n {{ lib.name }}\r\n </button>\r\n </div>\r\n <small *ngIf=\"selectedSlotLibrariesForDropdown.length === 0\" class=\"text-muted\">\r\n No libraries linked to this slot yet. Add some in the \"Fixture libraries\" multiselect above.\r\n </small>\r\n </div>\r\n\r\n <div *ngIf=\"loadingLibraryDetails\" class=\"text-muted\">Loading fixture details\u2026</div>\r\n\r\n <!--\r\n Use *ngFor + trackBy keyed on (look, slot, library) so Angular treats\r\n a switch as a new item \u2014 that forces the embedded template-products\r\n / template-vms components to remount and rerun their ngOnInit\r\n (otherwise their `isPageLoading` guard skips the form rebuild).\r\n -->\r\n <ng-container *ngFor=\"let _ of embeddedHostKeys; trackBy: trackByEmbeddedKey\">\r\n <ul class=\"nav nav-tabs custom-tabs mb-3\">\r\n <li class=\"nav-item\">\r\n <button type=\"button\" class=\"nav-link\"\r\n [class.active]=\"embeddedTab === 'products'\"\r\n (click)=\"embeddedTab = 'products'\">Product Merchandising</button>\r\n </li>\r\n <li class=\"nav-item\">\r\n <button type=\"button\" class=\"nav-link\"\r\n [class.active]=\"embeddedTab === 'vms'\"\r\n (click)=\"embeddedTab = 'vms'\">Visual Merchandising</button>\r\n </li>\r\n </ul>\r\n\r\n <div *ngIf=\"embeddedTab === 'products'\">\r\n <lib-template-products [looksMode]=\"true\"></lib-template-products>\r\n </div>\r\n <div *ngIf=\"embeddedTab === 'vms'\">\r\n <lib-template-vms [looksMode]=\"true\"></lib-template-vms>\r\n </div>\r\n </ng-container>\r\n </div>\r\n </ng-container>\r\n</section>\r\n", styles: [".look-form .col-md-3>.card,.look-form .col-md-6>.card{display:flex!important;flex-direction:column;height:75vh!important;min-height:600px}.look-form .looks-tree,.look-form .slots-list,.look-form .placements-scroll{flex:1 1 auto;min-height:0;overflow-y:auto}.look-form .look-row,.look-form .slot-row{cursor:pointer;border:1px solid transparent;background:#f9fafb;transition:filter .15s ease,box-shadow .15s ease,border-color .15s ease}.look-form .look-row:hover,.look-form .slot-row:hover{filter:brightness(.96)}.look-form .look-row.selected,.look-form .slot-row.selected{filter:brightness(.96);outline:1px solid rgba(14,165,233,.55);outline-offset:-1px}.look-form .bucket-dot{display:inline-block;width:10px;height:10px;border-radius:50%;flex-shrink:0;border:1px solid rgba(0,0,0,.12)}.look-form .fixture-libraries-select{display:block}.look-form .fixture-libraries-select ::ng-deep .multiselect-container{align-items:flex-start}.look-form .fixture-libraries-select ::ng-deep .chip-list{max-height:84px;overflow-y:auto;padding-right:4px}.look-form .placement-row .placement-fields .ph-field{flex:1 1 0;min-width:0}.look-form .placement-row .placement-fields .ph-remove{flex:0 0 auto}.look-form .placement-row .placement-fields ::ng-deep multiselect-chip-dropdown .multiselect-container{padding:4px 10px;min-height:31px}.look-form .placement-row .placement-fields ::ng-deep multiselect-chip-dropdown .chip-list{min-height:21px}.look-form .placement-row .placement-fields ::ng-deep multiselect-chip-dropdown .multi-placeholder{font-size:13px;line-height:21px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.look-form .library-config-card .library-chips{display:flex;flex-wrap:wrap;gap:8px}.look-form .library-config-card .library-chip{background:#f1f5f9;border:1px solid #cbd5e1;color:#1e293b;border-radius:999px;padding:6px 14px;font-size:13px;font-weight:500;cursor:pointer;transition:background-color .15s ease,border-color .15s ease,color .15s ease}.look-form .library-config-card .library-chip:hover{background:#e2e8f0;border-color:#94a3b8}.look-form .library-config-card .library-chip.active{background:#0ea5e9;border-color:#0284c7;color:#fff}.look-form .library-config-card ::ng-deep #fixture-template-products .cols.col>ul.nav.nav-tabs.custom-tabs{display:none!important}.look-form .library-config-card ::ng-deep #fixture-template-products .cols.col-8>ul.nav.nav-tabs.custom-tabs{display:none!important}.look-form .library-config-card ::ng-deep #fixture-template-products input[readonly]{background-color:var(--bs-gray-200, #e9ecef);cursor:not-allowed}.look-form .library-config-card .fixture-preview{border:1px solid #e2e8f0;border-radius:8px;background:#fff;padding:12px}.look-form .library-config-card .fixture-preview .fx-header,.look-form .library-config-card .fixture-preview .fx-footer{background:#f1f5f9;border:1px dashed #cbd5e1;border-radius:6px;padding:6px 10px;font-size:12px;color:#475569;text-align:center;margin:4px 0}.look-form .library-config-card .fixture-preview .fx-body{display:flex;flex-direction:column;gap:4px;padding:4px 0}.look-form .library-config-card .fixture-preview .fx-shelf{background:linear-gradient(180deg,#f8fafc,#eef2f7);border:1px solid #cbd5e1;border-radius:4px;padding:8px 10px;display:flex;align-items:center;gap:8px;font-size:13px;min-height:36px}.look-form .library-config-card .fixture-preview .fx-shelf .fx-shelf-badge{background:#0ea5e9;color:#fff;font-weight:700;padding:2px 8px;border-radius:999px;font-size:11px;flex-shrink:0}.look-form .library-config-card .fixture-preview .fx-shelf .fx-shelf-label{font-weight:500;color:#1e293b}.look-form .library-config-card .fixture-preview .fx-shelf .fx-shelf-meta{color:#64748b;font-size:11px;margin-left:auto}.look-form .library-config-card .fixture-preview .fx-shelf.fx-shelf-tray{background:linear-gradient(180deg,#fef3c7,#fde68a);border-color:#f59e0b}.look-form .library-config-card .fixture-preview .fx-shelf.fx-shelf-tray .fx-shelf-badge{background:#d97706}.look-form .library-config-card .fixture-preview .fx-shelf.fx-shelf-vmonly{background:linear-gradient(180deg,#ede9fe,#ddd6fe);border-color:#8b5cf6}.look-form .library-config-card .fixture-preview .fx-shelf.fx-shelf-vmonly .fx-shelf-badge{background:#7c3aed}.look-form .library-config-card .fixture-preview .fx-dims{text-align:center}.look-form .library-config-card .shelf-mappings{max-height:70vh;overflow-y:auto;padding-right:4px}.look-form .library-config-card .shelf-mappings .shelf-mapping{border:1px solid #e5e7eb;border-radius:8px;padding:12px;background:#f9fafb}\n"] }]
1203
+ }], ctorParameters: () => [{ type: i1.FormBuilder }, { type: i2.ActivatedRoute }, { type: i2.Router }, { type: i3.GlobalStateService }, { type: i4.StoreBuilderService }, { type: i5.ToastService }, { type: i3.PageInfoService }, { type: i6.PlanoDataService }] });
1204
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibG9vay1wbGFuby1jb2xsZWN0aW9uLWZvcm0uY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvdGFuZ28tc3RvcmUtYnVpbGRlci9zcmMvbGliL2NvbXBvbmVudHMvbG9vay1wbGFuby1jb2xsZWN0aW9uLWZvcm0vbG9vay1wbGFuby1jb2xsZWN0aW9uLWZvcm0uY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvdGFuZ28tc3RvcmUtYnVpbGRlci9zcmMvbGliL2NvbXBvbmVudHMvbG9vay1wbGFuby1jb2xsZWN0aW9uLWZvcm0vbG9vay1wbGFuby1jb2xsZWN0aW9uLWZvcm0uY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFNBQVMsRUFBcUIsTUFBTSxlQUFlLENBQUM7QUFDN0QsT0FBTyxFQUFxQyxVQUFVLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUUvRSxPQUFPLEVBQUUsWUFBWSxFQUFFLGFBQWEsRUFBRSxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sTUFBTSxDQUFDOzs7Ozs7Ozs7Ozs7OztBQVd2RSxNQUFNLE9BQU8sZ0NBQWdDO0lBb1pqQztJQUNBO0lBQ0E7SUFDQTtJQUNBO0lBQ0E7SUFDQTtJQUNBO0lBMVpWLFFBQVEsR0FBRyxFQUFFLENBQUM7SUFDZCxZQUFZLEdBQWtCLElBQUksQ0FBQztJQUNuQyxLQUFLLEdBQUcsSUFBSSxDQUFDO0lBQ2IsT0FBTyxHQUFHLEtBQUssQ0FBQztJQUNoQixNQUFNLEdBQUcsS0FBSyxDQUFDO0lBRWYsSUFBSSxDQUFhO0lBQ2pCLGlCQUFpQixHQUFXLENBQUMsQ0FBQyxDQUFDO0lBQy9CLGlCQUFpQixHQUFXLENBQUMsQ0FBQyxDQUFDO0lBRS9CLDhFQUE4RTtJQUM5RSw2RUFBNkU7SUFDN0UsZ0ZBQWdGO0lBQ3ZFLGtCQUFrQixHQUFHO1FBQzVCLEVBQUUsRUFB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LFFBQVEsQ0FBQyxDQUFDLHlCQUF5QixDQUFDLENBQUMsQ0FBQztJQUNwRCxDQUFDO0lBRUQsWUFBWSxDQUFDLEtBQWE7UUFDeEIsT0FBTyxLQUFLLENBQUM7SUFDZixDQUFDO0lBRUQsV0FBVztRQUNULElBQUksQ0FBQyxRQUFRLENBQUMsSUFBSSxFQUFFLENBQUM7UUFDckIsSUFBSSxDQUFDLFFBQVEsQ0FBQyxRQUFRLEVBQUUsQ0FBQztRQUN6QixtRkFBbUY7UUFDbkYsSUFBSSxDQUFDLGdCQUFnQixDQUFDLHNCQUFzQixDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUMxRCxDQUFDO3dHQTV0Q1UsZ0NBQWdDOzRGQUFoQyxnQ0FBZ0Msc0VDZDdDLDAwZEF3U0E7OzRGRDFSYSxnQ0FBZ0M7a0JBTDVDLFNBQVM7K0JBQ0UsZ0NBQWdDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQ29tcG9uZW50LCBPbkRlc3Ryb3ksIE9uSW5pdCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xyXG5pbXBvcnQgeyBGb3JtQXJyYXksIEZvcm1CdWlsZGVyLCBGb3JtR3JvdXAsIFZhbGlkYXRvcnMgfSBmcm9tICdAYW5ndWxhci9mb3Jtcyc7XHJcbmltcG9ydCB7IEFjdGl2YXRlZFJvdXRlLCBSb3V0ZXIgfSBmcm9tICdAYW5ndWxhci9yb3V0ZXInO1xyXG5pbXBvcnQgeyBkZWJvdW5jZVRpbWUsIGxhc3RWYWx1ZUZyb20sIFN1YmplY3QsIHRha2VVbnRpbCB9IGZyb20gJ3J4anMnO1xyXG5pbXBvcnQgeyBHbG9iYWxTdGF0ZVNlcnZpY2UsIFBhZ2VJbmZvU2VydmljZSB9IGZyb20gJ3RhbmdvLWFwcC11aS1nbG9iYWwnO1xyXG5pbXBvcnQgeyBUb2FzdFNlcnZpY2UgfSBmcm9tICd0YW5nby1hcHAtdWktc2hhcmVkJztcclxuaW1wb3J0IHsgU3RvcmVCdWlsZGVyU2VydmljZSB9IGZyb20gJy4uLy4uL3NlcnZpY2VzL3N0b3JlLWJ1aWxkZXIuc2VydmljZSc7XHJcbmltcG9ydCB7IFBsYW5vRGF0YVNlcnZpY2UgfSBmcm9tICcuLi8uLi9zZXJ2aWNlcy9wbGFuby1kYXRhLnNlcnZpY2UnO1xyXG5cclxuQENvbXBvbmVudCh7XHJcbiAgc2VsZWN0b3I6ICdsaWItbG9vay1wbGFuby1jb2xsZWN0aW9uLWZvcm0nLFxyXG4gIHRlbXBsYXRlVXJsOiAnLi9sb29rLXBsYW5vLWNvbGxlY3Rpb24tZm9ybS5jb21wb25lbnQuaHRtbCcsXHJcbiAgc3R5bGVVcmw6ICcuL2xvb2stcGxhbm8tY29sbGVjdGlvbi1mb3JtLmNvbXBvbmVudC5zY3NzJyxcclxufSlcclxuZXhwb3J0IGNsYXNzIExvb2tQbGFub0NvbGxlY3Rpb25Gb3JtQ29tcG9uZW50IGltcGxlbWVudHMgT25Jbml0LCBPbkRlc3Ryb3kge1xyXG4gIGNsaWVudElkID0gJyc7XHJcbiAgY29sbGVjdGlvbklkOiBzdHJpbmcgfCBudWxsID0gbnVsbDtcclxuICBpc05ldyA9IHRydWU7XHJcbiAgbG9hZGluZyA9IGZhbHNlO1xyXG4gIHNhdmluZyA9IGZhbHNlO1xyXG5cclxuICBmb3JtITogRm9ybUdyb3VwO1xyXG4gIHNlbGVjdGVkTG9va0luZGV4OiBudW1iZXIgPSAtMTtcclxuICBzZWxlY3RlZFNsb3RJbmRleDogbnVtYmVyID0gLTE7XHJcblxyXG4gIC8vIERpc3BsYXkgbGFiZWxzIGFyZSBXYWxsIC8gRmxvb3I7IHRoZSBzdG9yZWQgaWRzIHN0YXkgJ3NoZWxmJyAvICdldXJvY2VudGVyJ1xyXG4gIC8vIHNvIHRoZSBsaWJyYXJ5IGZpbHRlciwgc2xvdCBkZWZhdWx0cywgYW5kIHRoZSBiYWNrZW5kIHNsb3RUeXBlL2ZpeHR1cmVUeXBlXHJcbiAgLy8gZW51bXMga2VlcCB3b3JraW5nIHVuY2hhbmdlZCAoJ3NoZWxmJyDihpIgd2FsbCBmaXh0dXJlcywgJ2V1cm9jZW50ZXInIOKGkiBmbG9vcikuXHJcbiAgcmVhZG9ubHkgZml4dHVyZVR5cGVPcHRpb25zID0gW1xyXG4gICAgeyBpZDogJ3NoZWxmJywgbmFtZTogJ1dhbGwnIH0sXHJcbiAgICB7IGlkOiAnZXVyb2NlbnRlcicsIG5hbWU6ICdGbG9vcicgfSxcclxuICBdO1xyXG5cclxuICBmaXh0dXJlTGlicmFyeUl0ZW1zOiB7IGlkOiBzdHJpbmc7IG5hbWU6IHN0cmluZzsgZml4dHVyZVR5cGU6IHN0cmluZyB9W10gPSBbXTtcclxuXHJcbiAgLy8gRHJvcGRvd25zIGluc2lkZSBwbGFjZW1lbnQgcm93cy5cclxuICB2bVR5cGVPcHRpb25zOiB7IHZhbHVlOiBzdHJpbmc7IGxhYmVsOiBzdHJpbmcgfVtdID0gW107XHJcbiAgdm1BcnR3b3JrT3B0aW9uczogeyB2YWx1ZTogc3RyaW5nOyBsYWJlbDogc3RyaW5nOyB2bVR5cGU/OiBzdHJpbmcgfVtdID0gW107XHJcbiAgcHJvZHVjdE9wdGlvbnM6IHsgdmFsdWU6IHN0cmluZzsgbGFiZWw6IHN0cmluZyB9W10gPSBbXTtcclxuICAvKiogQ2FjaGVkIHBlci12bVR5cGUgYXJ0d29yayBsaXN0IOKAlCBzYW1lIHJlZmVyZW5jZSByZXR1cm5lZCBlYWNoIGxvb2t1cCBzb1xyXG4gICAqICBsaWItcmVhY3RpdmUtc2VsZWN0IGRvZXNuJ3QgcmVzZXQgc3RhdGUgZXZlcnkgQ0QgY3ljbGUuICovXHJcbiAgcHJpdmF0ZSB2bUFydHdvcmtCeVR5cGU6IE1hcDxzdHJpbmcsIHsgdmFsdWU6IHN0cmluZzsgbGFiZWw6IHN0cmluZyB9W10+ID0gbmV3IE1hcCgpO1xyXG4gIC8qKiAodm1OYW1lfHx2bVR5cGUpIGFuZCAodm1OYW1lKSDihpIgcGxhbm92bSBfaWQsIHNvIGEgVk0gcGxhY2VtZW50J3MgYXJ0d29ya1xyXG4gICAqICBuYW1lIGNhbiBiZSByZXNvbHZlZCB0byB0aGUgX2lkIHRoZSBlbWJlZGRlZCBWTSBlZGl0b3IgbWF0Y2hlcyBhZ2FpbnN0LiAqL1xyXG4gIHByaXZhdGUgdm1JZEJ5TmFtZVR5cGU6IE1hcDxzdHJpbmcsIHN0cmluZz4gPSBuZXcgTWFwKCk7XHJcbiAgLyoqXHJcbiAgICogQ2FjaGVkIGZpbHRlcmVkIGxpc3QgYm91bmQgdG8gdGhlIFwiRml4dHVyZSBsaWJyYXJpZXNcIiBtdWx0aXNlbGVjdC5cclxuICAgKiBNdXN0IE5PVCBiZSBhIGdldHRlciDigJQgdGhlIHVuZGVybHlpbmcgbXVsdGlzZWxlY3QgcmUtY2xvbmVzIGl0cyBpdGVtcyBvblxyXG4gICAqIGV2ZXJ5IG5nT25DaGFuZ2VzLCB3aGljaCBkZXRhY2hlcyBjbGljayB0YXJnZXRzIGFuZCBicmVha3Mgc2VsZWN0aW9uLlxyXG4gICAqL1xyXG4gIGZpeHR1cmVMaWJyYXJ5SXRlbXNGb3JTbG90OiB7IGlkOiBzdHJpbmc7IG5hbWU6IHN0cmluZzsgZml4dHVyZVR5cGU6IHN0cmluZyB9W10gPSBbXTtcclxuXHJcbiAgLy8gU3RhdGUgZm9yIHRoZSBwZXItc2xvdCBGaXh0dXJlIExpYnJhcnkgQ29uZmlndXJhdGlvbiBjYXJkLlxyXG4gIHNlbGVjdGVkTGlicmFyeUlkSW5NYXA6IHN0cmluZyA9ICcnO1xyXG4gIHNlbGVjdGVkTGlicmFyeURldGFpbHM6IGFueSA9IG51bGw7XHJcbiAgbG9hZGluZ0xpYnJhcnlEZXRhaWxzOiBib29sZWFuID0gZmFsc2U7XHJcbiAgZW1iZWRkZWRUYWI6ICdwcm9kdWN0cycgfCAndm1zJyA9ICdwcm9kdWN0cyc7XHJcblxyXG4gIC8vID09PSBGaXh0dXJlIExpYnJhcnkgQ29uZmlndXJhdGlvbiBjYXJkIGhlbHBlcnMgPT09XHJcblxyXG4gIC8qKiBTbG90J3MgcGxhY2VtZW50cyB3aXRoIGtpbmQgPSAndm0nLCBleHBvc2VkIGFzIGRyb3Bkb3duIGl0ZW1zLiAqL1xyXG4gIGdldCBjdXJyZW50U2xvdFZtSXRlbXMoKTogeyBpZDogc3RyaW5nOyBuYW1lOiBzdHJpbmcgfVtdIHtcclxuICAgIHJldHVybiB0aGlzLnBsYWNlbWVudHNUb0l0ZW1zKCd2bScpO1xyXG4gIH1cclxuXHJcbiAgLyoqIFNsb3QncyBwbGFjZW1lbnRzIHdpdGgga2luZCA9ICdwaWQnLCBleHBvc2VkIGFzIGRyb3Bkb3duIGl0ZW1zLiAqL1xyXG4gIGdldCBjdXJyZW50U2xvdFBpZEl0ZW1zKCk6IHsgaWQ6IHN0cmluZzsgbmFtZTogc3RyaW5nIH1bXSB7XHJcbiAgICByZXR1cm4gdGhpcy5wbGFjZW1lbnRzVG9JdGVtcygncGlkJyk7XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIHBsYWNlbWVudHNUb0l0ZW1zKGtpbmQ6ICd2bScgfCAncGlkJyk6IHsgaWQ6IHN0cmluZzsgbmFtZTogc3RyaW5nIH1bXSB7XHJcbiAgICBjb25zdCBzbG90ID0gdGhpcy5zZWxlY3RlZFNsb3RHcm91cDtcclxuICAgIGlmICghc2xvdCkgcmV0dXJuIFtdO1xyXG4gICAgY29uc3QgYXJyID0gc2xvdC5nZXQoJ3BsYWNlbWVudHMnKSBhcyBGb3JtQXJyYXkgfCBudWxsO1xyXG4gICAgaWYgKCFhcnIpIHJldHVybiBbXTtcclxuICAgIHJldHVybiBhcnIuY29udHJvbHNcclxuICAgICAgICAubWFwKChjKSA9PiBjLnZhbHVlKVxyXG4gICAgICAgIC5maWx0ZXIoKHA6IGFueSkgPT4gcD8ua2luZCA9PT0ga2luZCAmJiBwPy5wb3NpdGlvbilcclxuICAgICAgICAubWFwKChwOiBhbnkpID0+ICh7XHJcbiAgICAgICAgICBpZDogcC5wb3NpdGlvbixcclxuICAgICAgICAgIG5hbWU6IHAucmF3VmFsdWUgPyBgJHtwLnBvc2l0aW9ufSDigJQgJHtwLnJhd1ZhbHVlfWAgOiBwLnBvc2l0aW9uLFxyXG4gICAgICAgIH0pKTtcclxuICB9XHJcblxyXG4gIC8qKiBGaXh0dXJlLWxpYnJhcnkgb3B0aW9ucyBmb3IgdGhlIGRyb3Bkb3duIOKAlCBmaWx0ZXJlZCB0byB0aGUgbGlicmFyaWVzXHJcbiAgICogIHNlbGVjdGVkIG9uIHRoZSBjdXJyZW50bHktYWN0aXZlIHNsb3QncyBtdWx0aXNlbGVjdC4gKi9cclxuICBnZXQgc2VsZWN0ZWRTbG90TGlicmFyaWVzRm9yRHJvcGRvd24oKTogeyBpZDogc3RyaW5nOyBuYW1lOiBzdHJpbmcgfVtdIHtcclxuICAgIGNvbnN0IHNsb3QgPSB0aGlzLnNlbGVjdGVkU2xvdEdyb3VwO1xyXG4gICAgaWYgKCFzbG90KSByZXR1cm4gW107XHJcbiAgICBjb25zdCByZWZzOiBzdHJpbmdbXSA9IHNsb3QuZ2V0KCdmaXh0dXJlTGlicmFyeVJlZnMnKT8udmFsdWUgfHwgW107XHJcbiAgICByZXR1cm4gdGhpcy5maXh0dXJlTGlicmFyeUl0ZW1zLmZpbHRlcigoaXRlbSkgPT4gcmVmcy5pbmNsdWRlcyhpdGVtLmlkKSk7XHJcbiAgfVxyXG5cclxuICAvKiogVGhlIEZvcm1BcnJheSB0aGF0IHN0b3JlcyBwZXItKGxpYnJhcnksIHNoZWxmKSBWTS9QSUQgdmFsdWVzIGZvciB0aGUgYWN0aXZlIHNsb3QuICovXHJcbiAgZ2V0IHNlbGVjdGVkU2xvdExpYnJhcnlDb25maWdzKCk6IEZvcm1BcnJheSB8IG51bGwge1xyXG4gICAgY29uc3Qgc2xvdCA9IHRoaXMuc2VsZWN0ZWRTbG90R3JvdXA7XHJcbiAgICByZXR1cm4gc2xvdCA/IChzbG90LmdldCgnbGlicmFyeUNvbmZpZ3VyYXRpb25zJykgYXMgRm9ybUFycmF5KSA6IG51bGw7XHJcbiAgfVxyXG5cclxuICAvKiogRm9ybS1hcnJheSBlbnRyaWVzIHNjb3BlZCB0byB0aGUgY3VycmVudGx5LXNob3duIGxpYnJhcnkgaW4gdGhlIGNvbmZpZyBjYXJkLiAqL1xyXG4gIGNvbmZpZ0VudHJpZXNGb3JDdXJyZW50TGlicmFyeSgpOiB7IGNvbnRyb2w6IEZvcm1Hcm91cDsgYXJyYXlJbmRleDogbnVtYmVyIH1bXSB7XHJcbiAgICBjb25zdCBjb25maWdzID0gdGhpcy5zZWxlY3RlZFNsb3RMaWJyYXJ5Q29uZmlncztcclxuICAgIGlmICghY29uZmlncyB8fCAhdGhpcy5zZWxlY3RlZExpYnJhcnlJZEluTWFwKSByZXR1cm4gW107XHJcbiAgICByZXR1cm4gY29uZmlncy5jb250cm9sc1xyXG4gICAgICAgIC5tYXAoKGMsIGkpID0+ICh7IGNvbnRyb2w6IGMgYXMgRm9ybUdyb3VwLCBhcnJheUluZGV4OiBpIH0pKVxyXG4gICAgICAgIC5maWx0ZXIoKHgpID0+IHguY29udHJvbC5nZXQoJ2xpYnJhcnlSZWYnKT8udmFsdWUgPT09IHRoaXMuc2VsZWN0ZWRMaWJyYXJ5SWRJbk1hcCk7XHJcbiAgfVxyXG5cclxuICAvKiogUmVzZXQgY2FyZCBzdGF0ZSB3aGVuZXZlciB0aGUgYWN0aXZlIHNsb3QgY2hhbmdlcyBzbyB3ZSBkb24ndCBjYXJyeSBvdmVyXHJcbiAgICogIHN0YWxlIHNlbGVjdGlvbnMgZnJvbSBhIHByZXZpb3VzbHktdmlld2VkIHNsb3QuICovXHJcbiAgcHJpdmF0ZSByZXNldExpYnJhcnlNYXAoKTogdm9pZCB7XHJcbiAgICB0aGlzLnNlbGVjdGVkTGlicmFyeUlkSW5NYXAgPSAnJztcclxuICAgIHRoaXMuc2VsZWN0ZWRMaWJyYXJ5RGV0YWlscyA9IG51bGw7XHJcbiAgICB0aGlzLnJlZnJlc2hFbWJlZGRlZEhvc3RLZXlzKCk7XHJcbiAgICAvLyBDbGVhciB0aGUgc2hhcmVkIEJlaGF2aW9yU3ViamVjdCB0b28gc28gdGhlIGVtYmVkZGVkIFRlbXBsYXRlUHJvZHVjdHMgL1xyXG4gICAgLy8gVGVtcGxhdGVWbXMgY29tcG9uZW50cywgaWYgdGhleSdyZSBzdGlsbCBtb3VudGVkLCBkb24ndCByZW5kZXIgc3RhbGVcclxuICAgIC8vIGRhdGEgZnJvbSB0aGUgcHJldmlvdXMgc2xvdCdzIGxpYnJhcnkuXHJcbiAgICB0aGlzLnBsYW5vRGF0YVNlcnZpY2UuZml4dHVyZVRlbXBsYXRlRGV0YWlscy5uZXh0KG51bGwpO1xyXG4gIH1cclxuXHJcbiAgLyoqIFdoZW4gYSBzbG90IGlzIGxvYWRlZCwgYXV0b21hdGljYWxseSBwaWNrIHRoZSBmaXJzdCBsaWJyYXJ5IGl0IGhhcyBsaW5rZWRcclxuICAgKiAgc28gdGhlIGVtYmVkZGVkIGZpeHR1cmUtdGVtcGxhdGUgZWRpdG9yIG9wZW5zIHN0cmFpZ2h0IHRvIHRoYXQgbGlicmFyeS4gKi9cclxuICBwcml2YXRlIGF1dG9TZWxlY3RGaXJzdExpYnJhcnkoKTogdm9pZCB7XHJcbiAgICBjb25zdCBzbG90ID0gdGhpcy5zZWxlY3RlZFNsb3RHcm91cDtcclxuICAgIGlmICghc2xvdCkgcmV0dXJuO1xyXG4gICAgY29uc3QgcmVmczogc3RyaW5nW10gPSBzbG90LmdldCgnZml4dHVyZUxpYnJhcnlSZWZzJyk/LnZhbHVlIHx8IFtdO1xyXG4gICAgY29uc3QgZmlyc3RJZCA9IHJlZnMuZmluZCgoaWQpID0+ICEhaWQpO1xyXG4gICAgaWYgKCFmaXJzdElkKSByZXR1cm47XHJcbiAgICBpZiAodGhpcy5zZWxlY3RlZExpYnJhcnlJZEluTWFwID09PSBmaXJzdElkKSByZXR1cm47XHJcbiAgICB0aGlzLm9uTGlicmFyeU1hcFNlbGVjdChmaXJzdElkKTtcclxuICB9XHJcblxyXG4gIC8qKiBSZWFkIHRoZSBzbG90J3Mgc2F2ZWQgc25hcHNob3QgZm9yIGEgbGlicmFyeSwgaWYgYW55LiAqL1xyXG4gIHByaXZhdGUgZ2V0TGlicmFyeVNuYXBzaG90KGxpYklkOiBzdHJpbmcpOiBhbnkgfCBudWxsIHtcclxuICAgIGNvbnN0IHNsb3QgPSB0aGlzLnNlbGVjdGVkU2xvdEdyb3VwO1xyXG4gICAgaWYgKCFzbG90KSByZXR1cm4gbnVsbDtcclxuICAgIGNvbnN0IHNuYXBzOiBhbnlbXSA9IHNsb3QuZ2V0KCdsaWJyYXJ5U25hcHNob3RzJyk/LnZhbHVlIHx8IFtdO1xyXG4gICAgY29uc3QgZW50cnkgPSBzbmFwcy5maW5kKChzKSA9PiBzPy5saWJyYXJ5UmVmID09PSBsaWJJZCk7XHJcbiAgICByZXR1cm4gZW50cnk/LnNuYXBzaG90IHx8IG51bGw7XHJcbiAgfVxyXG5cclxuICAvKiogUGVyc2lzdCBhIHNuYXBzaG90IGludG8gdGhlIHNsb3QncyBsaWJyYXJ5U25hcHNob3RzIEZvcm1Db250cm9sLiAqL1xyXG4gIHByaXZhdGUgY2FwdHVyZUxpYnJhcnlTbmFwc2hvdChsaWJJZDogc3RyaW5nLCBzbmFwc2hvdDogYW55KTogdm9pZCB7XHJcbiAgICBjb25zdCBzbG90ID0gdGhpcy5zZWxlY3RlZFNsb3RHcm91cDtcclxuICAgIGlmICghc2xvdCB8fCAhbGliSWQpIHJldHVybjtcclxuICAgIGNvbnN0IGN0cmwgPSBzbG90LmdldCgnbGlicmFyeVNuYXBzaG90cycpO1xyXG4gICAgaWYgKCFjdHJsKSByZXR1cm47XHJcbiAgICBjb25zdCBjdXJyZW50OiBhbnlbXSA9IEFycmF5LmlzQXJyYXkoY3RybC52YWx1ZSkgPyBbLi4uY3RybC52YWx1ZV0gOiBbXTtcclxuICAgIC8vIFN0cmlwIHRoZSBpZ25vcmVVcGRhdGUgZmxhZyBiZWZvcmUgc2F2aW5nIHNvIHdlIGRvbid0IGVjaG8gaXQgYmFjayBsYXRlci5cclxuICAgIGNvbnN0IHsgaWdub3JlVXBkYXRlOiBfaWdub3JlZCwgLi4uY2xlYW4gfSA9IHNuYXBzaG90IHx8IHt9O1xyXG4gICAgY29uc3QgaSA9IGN1cnJlbnQuZmluZEluZGV4KChzKSA9PiBzPy5saWJyYXJ5UmVmID09PSBsaWJJZCk7XHJcbiAgICBpZiAoaSA+PSAwKSB7XHJcbiAgICAgIGN1cnJlbnRbaV0gPSB7IGxpYnJhcnlSZWY6IGxpYklkLCBzbmFwc2hvdDogY2xlYW4gfTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIGN1cnJlbnQucHVzaCh7IGxpYnJhcnlSZWY6IGxpYklkLCBzbmFwc2hvdDogY2xlYW4gfSk7XHJcbiAgICB9XHJcbiAgICBjdHJsLnNldFZhbHVlKGN1cnJlbnQpO1xyXG4gIH1cclxuXHJcbiAgLyoqIFJlc29sdmUgYSBWTSBwbGFjZW1lbnQncyBhcnR3b3JrIE5BTUUgKCsgdm1UeXBlKSB0byBpdHMgcGxhbm92bSBfaWQuICovXHJcbiAgcHJpdmF0ZSByZXNvbHZlVm1JZCh2bU5hbWU6IHN0cmluZywgdm1UeXBlOiBzdHJpbmcpOiBzdHJpbmcge1xyXG4gICAgY29uc3QgbmFtZSA9IHRoaXMubm9ybVZtVHlwZSh2bU5hbWUpO1xyXG4gICAgY29uc3QgdHlwZSA9IHRoaXMubm9ybVZtVHlwZSh2bVR5cGUpO1xyXG4gICAgcmV0dXJuIChcclxuICAgICAgdGhpcy52bUlkQnlOYW1lVHlwZS5nZXQoYCR7bmFtZX18fCR7dHlwZX1gKSB8fFxyXG4gICAgICB0aGlzLnZtSWRCeU5hbWVUeXBlLmdldChuYW1lKSB8fFxyXG4gICAgICB2bU5hbWVcclxuICAgICk7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBSZS1kZXJpdmUgZXZlcnkgYXNzaWduZWQgbGlicmFyeSdzIHNuYXBzaG90IGZyb20gdGhlIGFjdGl2ZSBzbG90J3NcclxuICAgKiBjdXJyZW50IHBsYWNlbWVudHMuIERyaXZlbiBieSB0aGUgXCJMb29rIGFuZCBWaXN1YWwgTWVyY2hhbmRpc2luZ1xyXG4gICAqIFBsYWNlbWVudHNcIiBsaXN0IOKAlCBzbyBlZGl0aW5nIG9uZSBwbGFjZW1lbnQgdXBkYXRlcyBBTEwgYXNzaWduZWRcclxuICAgKiBsaWJyYXJpZXMgYXQgb25jZS5cclxuICAgKlxyXG4gICAqICAtIFBJRCBwbGFjZW1lbnRzOiBgcG9zaXRpb25gIChUb3AvTWlkL0JvdHRvbSkg4oaSIHNoZWxmIHpvbmU7IHRoZSBzaGVsZidzXHJcbiAgICogICAgcHJvZHVjdEJyYW5kTmFtZSBpcyBPVkVSV1JJVFRFTiB3aXRoIHRoZSBwbGFjZW1lbnQncyBwcm9kdWN0IGxpc3QuXHJcbiAgICogIC0gVk0gcGxhY2VtZW50czogYHBvc2l0aW9uYCDihpIgdm1UeXBlOyB0aGUgbWF0Y2hpbmcgdm1Db25maWcgZW50cnknc1xyXG4gICAqICAgIGFydHdvcmsgKHZtSWQvdm1OYW1lKSBpcyB1cGRhdGVkIHdoaWxlIHRoZSBsaWJyYXJ5IGtlZXBzIGl0cyBvd24gVk1cclxuICAgKiAgICBwb3NpdGlvbnMuIHZtVHlwZXMgbm90IHlldCBwcmVzZW50IGFyZSBhcHBlbmRlZC5cclxuICAgKi9cclxuICBwcml2YXRlIGFwcGx5UGxhY2VtZW50c1RvQXNzaWduZWRMaWJyYXJpZXMoKTogdm9pZCB7XHJcbiAgICBjb25zdCBzbG90ID0gdGhpcy5zZWxlY3RlZFNsb3RHcm91cDtcclxuICAgIGlmICghc2xvdCkgcmV0dXJuO1xyXG4gICAgY29uc3QgcmVmczogc3RyaW5nW10gPSAoc2xvdC5nZXQoJ2ZpeHR1cmVMaWJyYXJ5UmVmcycpPy52YWx1ZSB8fCBbXSlcclxuICAgICAgICAuZmlsdGVyKChyOiBzdHJpbmcpID0+ICEhcik7XHJcbiAgICBpZiAoIXJlZnMubGVuZ3RoKSByZXR1cm47XHJcblxyXG4gICAgY29uc3QgcGxhY2VtZW50czogYW55W10gPSAoc2xvdC5nZXQoJ3BsYWNlbWVudHMnKSBhcyBGb3JtQXJyYXkgfCBudWxsKT8udmFsdWUgfHwgW107XHJcbiAgICBjb25zdCBub3JtID0gKHM6IGFueSk6IHN0cmluZyA9PiBTdHJpbmcocyA/PyAnJykudHJpbSgpLnRvTG93ZXJDYXNlKCk7XHJcblxyXG4gICAgLy8gem9uZSAtPiBwcm9kdWN0IGxpc3QgKFBJRHMpOyBzdXBwb3J0cyBib3RoIHJhd1ZhbHVlc1tdIGFuZCBsZWdhY3kgcmF3VmFsdWUuXHJcbiAgICBjb25zdCBwaWRCeVpvbmUgPSBuZXcgTWFwPHN0cmluZywgc3RyaW5nW10+KCk7XHJcbiAgICBmb3IgKGNvbnN0IHAgb2YgcGxhY2VtZW50cykge1xyXG4gICAgICBpZiAocD8ua2luZCAhPT0gJ3BpZCcgfHwgIXA/LnBvc2l0aW9uKSBjb250aW51ZTtcclxuICAgICAgY29uc3QgdmFsczogc3RyaW5nW10gPSBBcnJheS5pc0FycmF5KHAucmF3VmFsdWVzKSAmJiBwLnJhd1ZhbHVlcy5sZW5ndGhcclxuICAgICAgICA/IHAucmF3VmFsdWVzLmZpbHRlcigodjogc3RyaW5nKSA9PiAhIXYpXHJcbiAgICAgICAgOiAocC5yYXdWYWx1ZSA/IFsgU3RyaW5nKHAucmF3VmFsdWUpIF0gOiBbXSk7XHJcbiAgICAgIGlmICh2YWxzLmxlbmd0aCkgcGlkQnlab25lLnNldChub3JtKHAucG9zaXRpb24pLCB2YWxzKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyB2bVR5cGUgLT4geyB2bUlkLCB2bU5hbWUsIGxhYmVsIH0gKFZNcylcclxuICAgIGNvbnN0IHZtQnlUeXBlID0gbmV3IE1hcDxzdHJpbmcsIHsgdm1JZDogc3RyaW5nOyB2bU5hbWU6IHN0cmluZzsgbGFiZWw6IHN0cmluZyB9PigpO1xyXG4gICAgZm9yIChjb25zdCBwIG9mIHBsYWNlbWVudHMpIHtcclxuICAgICAgaWYgKHA/LmtpbmQgIT09ICd2bScgfHwgIXA/LnBvc2l0aW9uIHx8ICFwPy5yYXdWYWx1ZSkgY29udGludWU7XHJcbiAgICAgIGNvbnN0IGxhYmVsID0gU3RyaW5nKHAucG9zaXRpb24pO1xyXG4gICAgICB2bUJ5VHlwZS5zZXQobm9ybShsYWJlbCksIHtcclxuICAgICAgICB2bUlkOiB0aGlzLnJlc29sdmVWbUlkKFN0cmluZyhwLnJhd1ZhbHVlKSwgbGFiZWwpLFxyXG4gICAgICAgIHZtTmFtZTogU3RyaW5nKHAucmF3VmFsdWUpLFxyXG4gICAgICAgIGxhYmVsLFxyXG4gICAgICB9KTtcclxuICAgIH1cclxuXHJcbiAgICBmb3IgKGNvbnN0IGxpYklkIG9mIHJlZnMpIHtcclxuICAgICAgY29uc3QgdGFyZ2V0ID0gdGhpcy5nZXRMaWJyYXJ5U25hcHNob3QobGliSWQpO1xyXG4gICAgICBpZiAoIXRhcmdldCkgY29udGludWU7IC8vIHNlZWQgY3JlYXRlcyBvbmUgcGVyIGFzc2lnbmVkIGxpYnJhcnlcclxuXHJcbiAgICAgIGNvbnN0IHNoZWx2ZXM6IGFueVtdID0gQXJyYXkuaXNBcnJheSh0YXJnZXQuc2hlbGZDb25maWcpID8gdGFyZ2V0LnNoZWxmQ29uZmlnIDogW107XHJcbiAgICAgIGNvbnN0IG5ld1NoZWxmQ29uZmlnID0gc2hlbHZlcy5tYXAoKHNoZWxmOiBhbnkpID0+IHtcclxuICAgICAgICBjb25zdCB6b25lID0gbm9ybShzaGVsZj8uem9uZSB8fCBzaGVsZj8ubGFiZWwpO1xyXG4gICAgICAgIGlmICghem9uZSB8fCAhcGlkQnlab25lLmhhcyh6b25lKSkgcmV0dXJuIHNoZWxmO1xyXG4gICAgICAgIHJldHVybiB7XHJcbiAgICAgICAgICAuLi5zaGVsZixcclxuICAgICAgICAgIHpvbmU6IHNoZWxmPy56b25lIHx8IHNoZWxmPy5sYWJlbCB8fCAnJyxcclxuICAgICAgICAgIHByb2R1Y3RCcmFuZE5hbWU6IFsgLi4ucGlkQnlab25lLmdldCh6b25lKSEgXSxcclxuICAgICAgICB9O1xyXG4gICAgICB9KTtcclxuXHJcbiAgICAgIGNvbnN0IGV4aXN0aW5nVm1zOiBhbnlbXSA9IEFycmF5LmlzQXJyYXkodGFyZ2V0LnZtQ29uZmlnKSA/IHRhcmdldC52bUNvbmZpZyA6IFtdO1xyXG4gICAgICBjb25zdCBzZWVuID0gbmV3IFNldDxzdHJpbmc+KCk7XHJcbiAgICAgIGNvbnN0IG5ld1ZtQ29uZmlnID0gZXhpc3RpbmdWbXMubWFwKCh2bTogYW55KSA9PiB7XHJcbiAgICAgICAgY29uc3Qga2V5ID0gbm9ybSh2bT8udm1UeXBlKTtcclxuICAgICAgICBzZWVuLmFkZChrZXkpO1xyXG4gICAgICAgIGNvbnN0IHVwZCA9IHZtQnlUeXBlLmdldChrZXkpO1xyXG4gICAgICAgIHJldHVybiB1cGQgPyB7IC4uLnZtLCB2bUlkOiB1cGQudm1JZCwgdm1OYW1lOiB1cGQudm1OYW1lIH0gOiB2bTtcclxuICAgICAgfSk7XHJcbiAgICAgIGZvciAoY29uc3QgWyBrZXksIHVwZCBdIG9mIHZtQnlUeXBlKSB7XHJcbiAgICAgICAgaWYgKHNlZW4uaGFzKGtleSkpIGNvbnRpbnVlO1xyXG4gICAgICAgIG5ld1ZtQ29uZmlnLnB1c2goe1xyXG4gICAgICAgICAgdm1UeXBlOiB1cGQubGFiZWwsXHJcbiAgICAgICAgICB2bUlkOiB1cGQudm1JZCxcclxuICAgICAgICAgIHZtTmFtZTogdXBkLnZtTmFtZSxcclxuICAgICAgICAgIHN0YXJ0WVBvc2l0aW9uOiAxLFxyXG4gICAgICAgICAgZW5kWVBvc2l0aW9uOiAxLFxyXG4gICAgICAgICAgeFpvbmU6ICcnLFxyXG4gICAgICAgICAgeVpvbmU6ICcnLFxyXG4gICAgICAgICAgcG9zaXRpb246ICcnLFxyXG4gICAgICAgIH0pO1xyXG4gICAgICB9XHJcblxyXG4gICAgICB0aGlzLmNhcHR1cmVMaWJyYXJ5U25hcHNob3QobGliSWQsIHtcclxuICAgICAgICAuLi50YXJnZXQsXHJcbiAgICAgICAgc2hlbGZDb25maWc6IG5ld1NoZWxmQ29uZmlnLFxyXG4gICAgICAgIHZtQ29uZmlnOiBuZXdWbUNvbmZpZyxcclxuICAgICAgICBwcm9kdWN0UmVzb2x1dGlvbkxldmVsOiAnTDMnLFxyXG4gICAgICB9KTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBSZWZsZWN0IHRoZSBjaGFuZ2UgaW4gdGhlIGN1cnJlbnRseS1vcGVuIGVtYmVkZGVkIGVkaXRvci5cclxuICAgIHRoaXMucmVsb2FkRGlzcGxheWVkTGlicmFyeSgpO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogUmVtb3VudCB0aGUgZW1iZWRkZWQgZWRpdG9yIGZvciB0aGUgYWN0aXZlIGxpYnJhcnkgc28gaXQgcGlja3MgdXAgdGhlXHJcbiAgICogc25hcHNob3Qgd2UganVzdCByZXdyb3RlLiBUaGUgZW1iZWRkZWQgY29tcG9uZW50cyBndWFyZCBhZ2FpbnN0IHJlLWluaXRcclxuICAgKiB3aGlsZSBtb3VudGVkLCBzbyB3ZSB0b2dnbGUgdGhlIGhvc3Qga2V5IG9mZiB0aGVuIG9uIHRvIGZvcmNlIGEgZnJlc2hcclxuICAgKiBuZ09uSW5pdCB3aXRoIHRoZSB1cGRhdGVkIGRhdGEuXHJcbiAgICovXHJcbiAgcHJpdmF0ZSByZWxvYWREaXNwbGF5ZWRMaWJyYXJ5KCk6IHZvaWQge1xyXG4gICAgY29uc3QgbGliSWQgPSB0aGlzLnNlbGVjdGVkTGlicmFyeUlkSW5NYXA7XHJcbiAgICBpZiAoIWxpYklkKSByZXR1cm47XHJcbiAgICBjb25zdCB1cGRhdGVkID0gdGhpcy5nZXRMaWJyYXJ5U25hcHNob3QobGliSWQpO1xyXG4gICAgaWYgKCF1cGRhdGVkKSByZXR1cm47XHJcbiAgICB0aGlzLnNlbGVjdGVkTGlicmFyeURldGFpbHMgPSB1cGRhdGVkO1xyXG4gICAgLy8gUHVzaCB0aGUgZnJlc2ggc25hcHNob3QsIHRoZW4gYnVtcCB0aGUgbm9uY2Ugc28gcmVmcmVzaEVtYmVkZGVkSG9zdEtleXNcclxuICAgIC8vIHByb2R1Y2VzIGEgTkVXIGtleSDigJQgdGhhdCdzIHdoYXQgYWN0dWFsbHkgZm9yY2VzIHRoZSAqbmdGb3IgdG8gZGVzdHJveVxyXG4gICAgLy8gdGhlIG9sZCBlbWJlZGRlZCBlZGl0b3IgYW5kIG1vdW50IGEgbmV3IG9uZSB0aGF0IHJlLXJlYWRzIHRoZSBzbmFwc2hvdC5cclxuICAgIHRoaXMucGxhbm9EYXRhU2VydmljZS5maXh0dXJlVGVtcGxhdGVEZXRhaWxzLm5leHQoe1xyXG4gICAgICAuLi51cGRhdGVkLFxyXG4gICAgICBwcm9kdWN0UmVzb2x1dGlvbkxldmVsOiB1cGRhdGVkLnByb2R1Y3RSZXNvbHV0aW9uTGV2ZWwgfHwgJ0wzJyxcclxuICAgIH0pO1xyXG4gICAgdGhpcy5lbWJlZGRlZFJlbG9hZE5vbmNlKys7XHJcbiAgICB0aGlzLnJlZnJlc2hFbWJlZGRlZEhvc3RLZXlzKCk7XHJcbiAgfVxyXG5cclxuICBhc3luYyBvbkxpYnJhcnlNYXBTZWxlY3QobGliSWQ6IHN0cmluZyk6IFByb21pc2U8dm9pZD4ge1xyXG4gICAgLy8gVG9nZ2xpbmcgdGhlIGFjdGl2ZSBjaGlwIG9mZiDihpIgY2xlYXIgaW1tZWRpYXRlbHkgKG5vIGFzeW5jIHdvcmsgbmVlZGVkKS5cclxuICAgIGlmICghbGliSWQpIHtcclxuICAgICAgdGhpcy5zZWxlY3RlZExpYnJhcnlJZEluTWFwID0gJyc7XHJcbiAgICAgIHRoaXMuc2VsZWN0ZWRMaWJyYXJ5RGV0YWlscyA9IG51bGw7XHJcbiAgICAgIHRoaXMucmVmcmVzaEVtYmVkZGVkSG9zdEtleXMoKTtcclxuICAgICAgdGhpcy5wbGFub0RhdGFTZXJ2aWNlLmZpeHR1cmVUZW1wbGF0ZURldGFpbHMubmV4dChudWxsKTtcclxuICAgICAgcmV0dXJuO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFN3aXRjaGluZyB0byBhIGRpZmZlcmVudCBjaGlwOiBsaWdodCB0aGUgbmV3IGNoaXAgdXAgcmlnaHQgYXdheSwgYnV0XHJcbiAgICAvLyBLRUVQIHRoZSBwcmV2aW91cyBsaWJyYXJ5J3MgZW1iZWRkZWQgcHJldmlldyBtb3VudGVkIHdoaWxlIHdlIGZldGNoXHJcbiAgICAvLyB0aGUgbmV3IHNuYXBzaG90L2RldGFpbHMuIE90aGVyd2lzZSB0aGUgY2FyZCB3b3VsZCBjb2xsYXBzZSB0byBpdHNcclxuICAgIC8vIGhlYWRlciBoZWlnaHQgZHVyaW5nIHRoZSBmZXRjaCBhbmQgcmUtZXhwYW5kIG9uY2UgbmV3IGRhdGEgbGFuZHMg4oCUXHJcbiAgICAvLyB2aXNpYmxlIGFzIGEgXCJjcnVuY2hcIiB0aGUgdXNlciByZXBvcnRlZC5cclxuICAgIHRoaXMuc2VsZWN0ZWRMaWJyYXJ5SWRJbk1hcCA9IGxpYklkO1xyXG4gICAgdGhpcy5sb2FkaW5nTGlicmFyeURldGFpbHMgPSB0cnVlO1xyXG5cclxuICAgIGxldCBuZXdEZXRhaWxzOiBhbnkgPSBudWxsO1xyXG4gICAgdHJ5IHtcclxuICAgICAgLy8gSWYgYW4gYXV0by1hcHBseSBmb3IgdGhpcyBsaWJyYXJ5IGlzIHN0aWxsIHJ1bm5pbmcsIHdhaXQgZm9yIGl0IHNvXHJcbiAgICAgIC8vIHdlIGRvbid0IGJlYXQgaXQgdG8gdGhlIHNuYXBzaG90IGFuZCByZW5kZXIgdGhlIHVuLWZpbGxlZCBsaWJyYXJ5LlxyXG4gICAgICBjb25zdCBwZW5kaW5nID0gdGhpcy5hdXRvQXBwbHlJbkZsaWdodC5nZXQobGliSWQpO1xyXG4gICAgICBpZiAocGVuZGluZykge1xyXG4gICAgICAgIHRyeSB7IGF3YWl0IHBlbmRpbmc7IH0gY2F0Y2ggKF9lKSB7IC8qIGlnbm9yZSAqLyB9XHJcbiAgICAgIH1cclxuICAgICAgY29uc3Qgc2F2ZWQgPSB0aGlzLmdldExpYnJhcnlTbmFwc2hvdChsaWJJZCk7XHJcbiAgICAgIGlmIChzYXZlZCkge1xyXG4gICAgICAgIG5ld0RldGFpbHMgPSBzYXZlZDtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICBjb25zdCByZXM6IGFueSA9IGF3YWl0IGxhc3RWYWx1ZUZyb20oXHJcbiAgICAgICAgICB0aGlzLmJ1aWxkZXJTZXJ2aWNlLmdldEZpeHR1cmVMaWJyYXJ5RGV0YWlscyhsaWJJZCksXHJcbiAgICAgICAgKTtcclxuICAgICAgICBuZXdEZXRhaWxzID0gcmVzPy5kYXRhIHx8IG51bGw7XHJcbiAgICAgIH1cclxuICAgIH0gY2F0Y2ggKGVycikge1xyXG4gICAgICBjb25zb2xlLmxvZygnQEAgfiBvbkxpYnJhcnlNYXBTZWxlY3QgW0VSUl06JywgZXJyKTtcclxuICAgICAgbmV3RGV0YWlscyA9IG51bGw7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQXRvbWljIHN3YXAg4oCUIHNlbGVjdGVkTGlicmFyeURldGFpbHMsIEJlaGF2aW9yU3ViamVjdCwgYW5kIHRoZVxyXG4gICAgLy8gbmdGb3IgaG9zdCBrZXkgYWxsIGZsaXAgaW4gb25lIHN5bmNocm9ub3VzIGJsb2NrLCBzbyBBbmd1bGFyIGRlc3Ryb3lzXHJcbiAgICAvLyB0aGUgb2xkIGVtYmVkZGVkIGNvbXBvbmVudCBhbmQgbW91bnRzIHRoZSBuZXcgb25lIGluIHRoZSBzYW1lIGNoYW5nZVxyXG4gICAgLy8gZGV0ZWN0aW9uIGN5Y2xlLiBObyBlbXB0eS1zdGF0ZSBpbiBiZXR3ZWVuIOKGkiBubyBjYXJkLWhlaWdodCBjcnVuY2guXHJcbiAgICB0aGlzLnNlbGVjdGVkTGlicmFyeURldGFpbHMgPSBuZXdEZXRhaWxzO1xyXG4gICAgaWYgKG5ld0RldGFpbHMpIHtcclxuICAgICAgdGhpcy5wbGFub0RhdGFTZXJ2aWNlLmZpeHR1cmVUZW1wbGF0ZURldGFpbHMubmV4dCh7XHJcbiAgICAgICAgLi4ubmV3RGV0YWlscyxcclxuICAgICAgICBwcm9kdWN0UmVzb2x1dGlvbkxldmVsOiBuZXdEZXRhaWxzLnByb2R1Y3RSZXNvbHV0aW9uTGV2ZWwgfHwgJ0wzJyxcclxuICAgICAgfSk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICB0aGlzLnBsYW5vRGF0YVNlcnZpY2UuZml4dHVyZVRlbXBsYXRlRGV0YWlscy5uZXh0KG51bGwpO1xyXG4gICAgfVxyXG4gICAgdGhpcy5yZWZyZXNoRW1iZWRkZWRIb3N0S2V5cygpO1xyXG4gICAgdGhpcy5sb2FkaW5nTGlicmFyeURldGFpbHMgPSBmYWxzZTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIENvbXBvc2l0ZSBrZXkgdGllZCB0byB0aGUgY3VycmVudGx5LWFjdGl2ZSAobG9vaywgc2xvdCwgbGlicmFyeSkgdHJpcGxlLlxyXG4gICAqIFN0YWJsZSBwcm9wZXJ0eSDigJQgcmVjb21wdXRlZCBvbmx5IHdoZW4gdGhlIHVuZGVybHlpbmcgc2VsZWN0aW9uIGNoYW5nZXNcclxuICAgKiAoc2VlIHJlZnJlc2hFbWJlZGRlZEhvc3RLZXlzKCkpLiBBdm9pZHMgcmV0dXJuaW5nIGEgbmV3IGFycmF5IHJlZmVyZW5jZVxyXG4gICAqIGV2ZXJ5IENEIGN5Y2xlLCB3aGljaCB1c2VkIHRvIHJpcHBsZSBpbnRvIG90aGVyIG11bHRpLXNlbGVjdHMnIGlucHV0cy5cclxuICAgKi9cclxuICBlbWJlZGRlZEhvc3RLZXk6IHN0cmluZyA9ICcnO1xyXG4gIGVtYmVkZGVkSG9zdEtleXM6IHN0cmluZ1tdID0gW107XHJcbiAgLy8gQnVtcGVkIGJ5IHJlbG9hZERpc3BsYXllZExpYnJhcnkoKSB0byBmb3JjZSB0aGUgZW1iZWRkZWQgZWRpdG9yIHRvIHJlbW91bnRcclxuICAvLyBldmVuIHdoZW4gbG9vay9zbG90L2xpYnJhcnkgYXJlIHVuY2hhbmdlZCAoYSBzYW1lLWtleSByb3VuZC10cmlwIHZpYSB0aGVcclxuICAvLyAqbmdGb3IgdHJhY2tCeSBkb2VzIE5PVCByZW1vdW50OyBhIGNoYW5nZWQga2V5IGRvZXMpLlxyXG4gIHByaXZhdGUgZW1iZWRkZWRSZWxvYWROb25jZSA9IDA7XHJcblxyXG4gIHByaXZhdGUgcmVmcmVzaEVtYmVkZGVkSG9zdEtleXMoKTogdm9pZCB7XHJcbiAgICBjb25zdCBrZXkgPSBgJHt0aGlzLnNlbGVjdGVkTG9va0luZGV4fS0ke3RoaXMuc2VsZWN0ZWRTbG90SW5kZXh9LSR7dGhpcy5zZWxlY3RlZExpYnJhcnlJZEluTWFwfS0ke3RoaXMuZW1iZWRkZWRSZWxvYWROb25jZX1gO1xyXG4gICAgaWYgKGtleSAhPT0gdGhpcy5lbWJlZGRlZEhvc3RLZXkpIHtcclxuICAgICAgdGhpcy5lbWJlZGRlZEhvc3RLZXkgPSBrZXk7XHJcbiAgICB9XHJcbiAgICBjb25zdCBuZXh0ID0gdGhpcy5zZWxlY3RlZExpYnJhcnlEZXRhaWxzID8gW3RoaXMuZW1iZWRkZWRIb3N0S2V5XSA6IFtdO1xyXG4gICAgY29uc3QgY3VycmVudCA9IHRoaXMuZW1iZWRkZWRIb3N0S2V5cztcclxuICAgIC8vIE9ubHkgYXNzaWduIGEgbmV3IGFycmF5IGlmIHRoZSBjb250ZW50cyBkaWZmZXIg4oCUIG90aGVyd2lzZSB0aGUgbmdGb3Igc2Vlc1xyXG4gICAgLy8gYSBcIm5ld1wiIGFycmF5IGVhY2ggQ0QgYW5kIHRyYWNrQnkgc3RpbGwgaGFzIHRvIGNvbXBhcmUgZXZlcnkgZW50cnkuXHJcbiAgICBpZiAobmV4dC5sZW5ndGggIT09IGN1cnJlbnQubGVuZ3RoIHx8IG5leHRbMF0gIT09IGN1cnJlbnRbMF0pIHtcclxuICAgICAgdGhpcy5lbWJlZGRlZEhvc3RLZXlzID0gbmV4dDtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIHRyYWNrQnlFbWJlZGRlZEtleShfOiBudW1iZXIsIGtleTogc3RyaW5nKTogc3RyaW5nIHtcclxuICAgIHJldHVybiBrZXk7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBUaGUgc2xvdC10eXBlIGRyb3Bkb3duIGluIHRoZSByaWdodCBwYW5lIG9ubHkgb2ZmZXJzIHZhbHVlcyB0aGF0IHRoZVxyXG4gICAqIHBhcmVudCBMb29rIGhhcyBzZWxlY3RlZCBpbiBpdHMgRml4dHVyZSBUeXBlIG11bHRpc2VsZWN0LiBJZiBub3RoaW5nIGlzXHJcbiAgICogc2VsZWN0ZWQgeWV0LCBmYWxsIGJhY2sgdG8gc2hvd2luZyBhbGwgb3B0aW9ucyBzbyB0aGUgdXNlciBpc24ndCBibG9ja2VkLlxyXG4gICAqL1xyXG4gIGdldCBhdmFpbGFibGVTbG90VHlwZXMoKTogeyBpZDogc3RyaW5nOyBuYW1lOiBzdHJpbmcgfVtdIHtcclxuICAgIGNvbnN0IGxvb2tHcm91cCA9IHRoaXMuc2VsZWN0ZWRMb29rR3JvdXA7XHJcbiAgICBpZiAoIWxvb2tHcm91cCkgcmV0dXJuIHRoaXMuZml4dHVyZVR5cGVPcHRpb25zO1xyXG4gICAgY29uc3Qgc2VsZWN0ZWQgPSBsb29rR3JvdXAuZ2V0KCdmaXh0dXJlVHlwZScpPy52YWx1ZSBhcyBzdHJpbmdbXSB8IG51bGw7XHJcbiAgICBpZiAoIUFycmF5LmlzQXJyYXkoc2VsZWN0ZWQpIHx8IHNlbGVjdGVkLmxlbmd0aCA9PT0gMCkge1xyXG4gICAgICByZXR1cm4gdGhpcy5maXh0dXJlVHlwZU9wdGlvbnM7XHJcbiAgICB9XHJcbiAgICByZXR1cm4gdGhpcy5maXh0dXJlVHlwZU9wdGlvbnMuZmlsdGVyKChvcHQpID0+IHNlbGVjdGVkLmluY2x1ZGVzKG9wdC5pZCkpO1xyXG4gIH1cclxuXHJcbiAgLy8gMjAgdmVyeSBtaWxkIHBhc3RlbHMgKGFsbCBUYWlsd2luZC01MCAvIDEwMCByYW5nZSkgYXJyYW5nZWQgc28gYWRqYWNlbnRcclxuICAvLyBwYWxldHRlIHNsb3RzIGFyZSBvbiBvcHBvc2l0ZSBzaWRlcyBvZiB0aGUgY29sb3VyIHdoZWVsIGZvciBkaXN0aW5ndWlzaC1cclxuICAvLyBhYmlsaXR5IHdpdGhvdXQgYW55IGNvbG91ciBmZWVsaW5nIHNhdHVyYXRlZC5cclxuICBwcml2YXRlIHN0YXRpYyByZWFkb25seSBCVUNLRVRfUEFMRVRURTogcmVhZG9ubHkgc3RyaW5nW10gPSBbXHJcbiAgICAnI2ZlZjJmMicsIC8vICAxIEJsdXNoICAgICAgICAgIHJlZC01MFxyXG4gICAgJyNmMGZkZmEnLCAvLyAgMiBNaW50IFdoaXNwZXIgICB0ZWFsLTUwICAgIChvcHBvc2l0ZSBvZiByZWQpXHJcbiAgICAnI2ZmZjdlZCcsIC8vICAzIEFwcmljb3QgICAgICAgIG9yYW5nZS01MFxyXG4gICAgJyNlZWYyZmYnLCAvLyAgNCBJcmlzICAgICAgICAgICBpbmRpZ28tNTAgIChvcHBvc2l0ZSBvZiBvcmFuZ2UpXHJcbiAgICAnI2ZlZmNlOCcsIC8vICA1IEJ1dHRlciAgICAgICAgIHllbGxvdy01MFxyXG4gICAgJyNmYWY1ZmYnLCAvLyAgNiBMYXZlbmRlciAgICAgICBwdXJwbGUtNTAgIChvcHBvc2l0ZSBvZiB5ZWxsb3cpXHJcbiAgICAnI2YwZmRmNCcsIC8vICA3IFNwcmluZyAgICAgICAgIGdyZWVuLTUwXHJcbiAgICAnI2ZmZjFmMicsIC8vICA4IFJvc2UgUGV0YWwgICAgIHJvc2UtNTAgICAgKG9wcG9zaXRlIG9mIGdyZWVuKVxyXG4gICAgJyNlY2ZlZmYnLCAvLyAgOSBTa3kgVGludCAgICAgICBjeWFuLTUwXHJcbiAgICAnI2ZmZWRkNScsIC8vIDEwIFBlYWNoICAgICAgICAgIG9yYW5nZS0xMDBcclxuICAgICcjZWZmNmZmJywgLy8gMTEgUG93ZGVyIEJsdWUgICAgYmx1ZS01MFxyXG4gICAgJyNmMGY5ZmYnLCAvLyAxMiBTa3kgICAgICAgICAgICBza3ktNTAgICAgIChvcHBvc2l0ZSBvZiBvcmFuZ2UpXHJcbiAgICAnI2Y1ZjNmZicsIC8vIDEzIFZpb2xldCBNaXN0ICAgIHZpb2xldC01MFxyXG4gICAgJyNmN2ZlZTcnLCAvLyAxNCBMaW1lIFdoaXNwZXIgICBsaW1lLTUwICAgIChvcHBvc2l0ZSBvZiB2aW9sZXQpXHJcbiAgICAnI2ZkZjRmZicsIC8vIDE1IExpbGFjICAgICAgICAgIGZ1Y2hzaWEtNTBcclxuICAgICcjZWNmZGY1JywgLy8gMTYgTWludCAgICAgICAgICAgZW1lcmFsZC01MFxyXG4gICAgJyNmZGYyZjgnLCAvLyAxNyBQZXRhbCBQaW5rICAgICBwaW5rLTUwXHJcbiAgICAnI2ZmZmJlYicsIC8vIDE4IEhvbmV5ICAgICAgICAgIGFtYmVyLTUwXHJcbiAgICAnI2YxZjVmOScsIC8vIDE5IENsb3VkICAgICAgICAgIHNsYXRlLTEwMFxyXG4gICAgJyNmNWY1ZjQnLCAvLyAyMCBMaW5lbiAgICAgICAgICBzdG9uZS0xMDBcclxuICBdO1xyXG5cclxuICBwcml2YXRlIGRlc3Ryb3kkID0gbmV3IFN1YmplY3Q8dm9pZD4oKTtcclxuXHJcbiAgY29uc3RydWN0b3IoXHJcbiAgICBwcml2YXRlIGZiOiBGb3JtQnVpbGRlcixcclxuICAgIHByaXZhdGUgcm91dGU6IEFjdGl2YXRlZFJvdXRlLFxyXG4gICAgcHJpdmF0ZSByb3V0ZXI6IFJvdXRlcixcclxuICAgIHByaXZhdGUgZ3M6IEdsb2JhbFN0YXRlU2VydmljZSxcclxuICAgIHByaXZhdGUgYnVpbGRlclNlcnZpY2U6IFN0b3JlQnVpbGRlclNlcnZpY2UsXHJcbiAgICBwcml2YXRlIHRvYXN0OiBUb2FzdFNlcnZpY2UsXHJcbiAgICBwcml2YXRlIHBhZ2VJbmZvOiBQYWdlSW5mb1NlcnZpY2UsXHJcbiAgICBwcml2YXRlIHBsYW5vRGF0YVNlcnZpY2U6IFBsYW5vRGF0YVNlcnZpY2UsXHJcbiAgKSB7fVxyXG5cclxuICBuZ09uSW5pdCgpOiB2b2lkIHtcclxuICAgIHRoaXMuc2V0UGFnZURhdGEoKTtcclxuICAgIHRoaXMuaW5pdEZvcm0oKTtcclxuXHJcbiAgICAvLyBMaXN0ZW4gdG8gdGhlIHNoYXJlZCBmaXh0dXJlVGVtcGxhdGVEZXRhaWxzIOKAlCB3aGVuIHRoZSBlbWJlZGRlZFxyXG4gICAgLy8gVGVtcGxhdGVQcm9kdWN0cy9UZW1wbGF0ZVZtcyBjb21wb25lbnRzIHB1c2ggZWRpdHMgYmFjayBpbnRvIHRoZVxyXG4gICAgLy8gQmVoYXZpb3JTdWJqZWN0LCBwZXJzaXN0IGEgc25hcHNob3QgdW5kZXIgdGhlIGFjdGl2ZSBzbG90ICsgbGlicmFyeS5cclxuICAgIHRoaXMucGxhbm9EYXRhU2VydmljZS5maXh0dXJlVGVtcGxhdGVEZXRhaWxzXHJcbiAgICAgIC5waXBlKHRha2VVbnRpbCh0aGlzLmRlc3Ryb3kkKSlcclxuICAgICAgLnN1YnNjcmliZSgoZGF0YTogYW55KSA9PiB7XHJcbiAgICAgICAgaWYgKCFkYXRhIHx8ICF0aGlzLnNlbGVjdGVkTGlicmFyeUlkSW5NYXApIHJldHVybjtcclxuICAgICAgICAvLyBPbmx5IGNhcHR1cmUgdXNlciBlZGl0cywgbm90IHRoZSBpbml0aWFsIGxvYWQgd2UgcHVzaGVkIG91cnNlbHZlcy5cclxuICAgICAgICAvLyBUaGUgZW1iZWRkZWQgY29tcG9uZW50cyBzZXQgYGlnbm9yZVVwZGF0ZTogdHJ1ZWAgd2hlbiB0aGV5IHB1c2hcclxuICAgICAgICAvLyB0aGVpciBmb3JtIGNoYW5nZXMgYmFjazsgd2UgdXNlIHRoYXQgYXMgb3VyIHNpZ25hbC5cclxuICAgICAgICBpZiAoIWRhdGEuaWdub3JlVXBkYXRlKSByZXR1cm47XHJcbiAgICAgICAgLy8gUGVyc2lzdCBlZGl0cyBtYWRlIGRpcmVjdGx5IGluIHRoZSBlbWJlZGRlZCBlZGl0b3IgKGUuZy4gVk1cclxuICAgICAgICAvLyBwb3NpdGlvbnMsIHdoaWNoIHN0YXkgZWRpdGFibGUgaW4gbG9va3NNb2RlKSB0byB0aGUgYWN0aXZlIGxpYnJhcnkuXHJcbiAgICAgICAgLy8gQ3Jvc3MtbGlicmFyeSBwcm9wYWdhdGlvbiBpcyBkcml2ZW4gYnkgdGhlIHNsb3QncyBwbGFjZW1lbnRzIGxpc3RcclxuICAgICAgICAvLyBpbnN0ZWFkIChzZWUgYXBwbHlQbGFjZW1lbnRzVG9Bc3NpZ25lZExpYnJhcmllcykuXHJcbiAgICAgICAgdGhpcy5jYXB0dXJlTGlicmFyeVNuYXBzaG90KHRoaXMuc2VsZWN0ZWRMaWJyYXJ5SWRJbk1hcCwgZGF0YSk7XHJcbiAgICAgIH0pO1xyXG5cclxuICAgIHRoaXMuZ3MuZGF0YVJhbmdlVmFsdWUucGlwZSh0YWtlVW50aWwodGhpcy5kZXN0cm95JCkpLnN1YnNjcmliZSgoZGF0YSkgPT4ge1xyXG4gICAgICBjb25zdCBoZWFkZXJGaWx0ZXJzID0gSlNPTi5wYXJzZShsb2NhbFN0b3JhZ2UuZ2V0SXRlbSgnaGVhZGVyLWZpbHRlcnMnKSB8fCAne30nKTtcclxuICAgICAgdGhpcy5jbGllbnRJZCA9IGRhdGE/LmNsaWVudCB8fCBoZWFkZXJGaWx0ZXJzPy5jbGllbnQ7XHJcbiAgICAgIGlmICh0aGlzLmNsaWVudElkKSB7XHJcbiAgICAgICAgdGhpcy5sb2FkRml4dHVyZUxpYnJhcmllcygpO1xyXG4gICAgICAgIHRoaXMubG9hZFBsYWNlbWVudERyb3Bkb3duRGF0YSgpO1xyXG4gICAgICB9XHJcbiAgICB9KTtcclxuXHJcbiAgICB0aGlzLnJvdXRlLnBhcmFtcy5waXBlKHRha2VVbnRpbCh0aGlzLmRlc3Ryb3kkKSkuc3Vic2NyaWJlKGFzeW5jIChwYXJhbXMpID0+IHtcclxuICAgICAgY29uc3QgaWQgPSBwYXJhbXNbJ2NvbGxlY3Rpb25JZCddO1xyXG4gICAgICB0aGlzLmNvbGxlY3Rpb25JZCA9IGlkICYmIGlkICE9PSAnbmV3JyA/IGlkIDogbnVsbDtcclxuICAgICAgdGhpcy5pc05ldyA9ICF0aGlzLmNvbGxlY3Rpb25JZDtcclxuICAgICAgaWYgKHRoaXMuY29sbGVjdGlvbklkKSB7XHJcbiAgICAgICAgYXdhaXQgdGhpcy5sb2FkRGV0YWlscygpO1xyXG4gICAgICB9XHJcbiAgICB9KTtcclxuXHJcbiAgICAvLyBFbWJlZGRlZCBUZW1wbGF0ZVByb2R1Y3RzQ29tcG9uZW50IC8gVGVtcGxhdGVWbXNDb21wb25lbnQgcmVhZCB0aGVzZVxyXG4gICAgLy8gcXVlcnkgcGFyYW1zIGZyb20gdGhlIGFjdGl2ZSByb3V0ZS4gRm9yY2UgdGhlbSB0byBlZGl0LW1vZGUgYW5kIHBpblxyXG4gICAgLy8gdGhlIHByb2R1Y3RzIHZpZXcgdG8gdGhlIFwic2VjdGlvblwiIGxldmVsLlxyXG4gICAgdGhpcy5yb3V0ZXIubmF2aWdhdGUoW10sIHtcclxuICAgICAgcmVsYXRpdmVUbzogdGhpcy5yb3V0ZSxcclxuICAgICAgcXVlcnlQYXJhbXM6IHsgaXNFZGl0OiAndHJ1ZScsIGxldmVsOiAnc2VjdGlvbicgfSxcclxuICAgICAgcXVlcnlQYXJhbXNIYW5kbGluZzogJ21lcmdlJyxcclxuICAgICAgcmVwbGFjZVVybDogdHJ1ZSxcclxuICAgIH0pO1xyXG4gIH1cclxuXHJcbiAgc2V0UGFnZURhdGEoKSB7XHJcbiAgICB0aGlzLnBhZ2VJbmZvLnNldFRpdGxlKCdMb29rIENvbGxlY3Rpb24nKTtcclxuICAgIHRoaXMucGFnZUluZm8uc2V0QnJlYWRjcnVtYnMoW1xyXG4gICAgICB7IHRpdGxlOiAnUGxhbm9ncmFtJywgcGF0aDogJy9tYW5hZ2UvcGxhbm9ncmFtL21hbmFnZS1wbGFub2dyYW1zJywgaXNBY3RpdmU6IGZhbHNlLCBpc1NlcGFyYXRvcjogZmFsc2UgfSxcclxuICAgICAgeyB0aXRsZTogJycsIHBhdGg6ICcnLCBpc0FjdGl2ZTogZmFsc2UsIGlzU2VwYXJhdG9yOiB0cnVlIH0sXHJcbiAgICAgIHsgdGl0bGU6ICdMb29rcycsIHBhdGg6ICcvbWFuYWdlL3BsYW5vZ3JhbS9sb29rcycsIGlzQWN0aXZlOiBmYWxzZSwgaXNTZXBhcmF0b3I6IGZhbHNlIH0sXHJcbiAgICAgIHsgdGl0bGU6ICcnLCBwYXRoOiAnJywgaXNBY3RpdmU6IGZhbHNlLCBpc1NlcGFyYXRvcjogdHJ1ZSB9LFxyXG4gICAgICB7IHRpdGxlOiAnRWRpdCcsIHBhdGg6ICcnLCBpc0FjdGl2ZTogdHJ1ZSwgaXNTZXBhcmF0b3I6IGZhbHNlIH0sXHJcbiAgICBdKTtcclxuICB9XHJcblxyXG4gIGluaXRGb3JtKCkge1xyXG4gICAgdGhpcy5mb3JtID0gdGhpcy5mYi5ncm91cCh7XHJcbiAgICAgIG5hbWU6IFsnJywgVmFsaWRhdG9ycy5yZXF1aXJlZF0sXHJcbiAgICAgIGRlc2NyaXB0aW9uOiBbJyddLFxyXG4gICAgICBpc0FjdGl2ZTogW2ZhbHNlXSxcclxuICAgICAgbG9va3M6IHRoaXMuZmIuYXJyYXkoW10pLFxyXG4gICAgfSk7XHJcbiAgfVxyXG5cclxuICBnZXQgbG9va3MoKTogRm9ybUFycmF5IHtcclxuICAgIHJldHVybiB0aGlzLmZvcm0uZ2V0KCdsb29rcycpIGFzIEZvcm1BcnJheTtcclxuICB9XHJcblxyXG4gIGZpeHR1cmVTbG90cyhsb29rSW5kZXg6IG51bWJlcik6IEZvcm1BcnJheSB7XHJcbiAgICByZXR1cm4gdGhpcy5sb29rcy5hdChsb29rSW5kZXgpLmdldCgnZml4dHVyZVNsb3RzJykgYXMgRm9ybUFycmF5O1xyXG4gIH1cclxuXHJcbiAgcGxhY2VtZW50cyhsb29rSW5kZXg6IG51bWJlciwgc2xvdEluZGV4OiBudW1iZXIpOiBGb3JtQXJyYXkge1xyXG4gICAgcmV0dXJuIHRoaXMuZml4dHVyZVNsb3RzKGxvb2tJbmRleCkuYXQoc2xvdEluZGV4KS5nZXQoJ3BsYWNlbWVudHMnKSBhcyBGb3JtQXJyYXk7XHJcbiAgfVxyXG5cclxuICBnZXQgc2VsZWN0ZWRMb29rR3JvdXAoKTogRm9ybUdyb3VwIHwgbnVsbCB7XHJcbiAgICByZXR1cm4gdGhpcy5zZWxlY3RlZExvb2tJbmRleCA+PSAwICYmIHRoaXMuc2VsZWN0ZWRMb29rSW5kZXggPCB0aGlzLmxvb2tzLmxlbmd0aFxyXG4gICAgICA/ICh0aGlzLmxvb2tzLmF0KHRoaXMuc2VsZWN0ZWRMb29rSW5kZXgpIGFzIEZvcm1Hcm91cClcclxuICAgICAgOiBudWxsO1xyXG4gIH1cclxuXHJcbiAgZ2V0IHNlbGVjdGVkU2xvdHNBcnJheSgpOiBGb3JtQXJyYXkgfCBudWxsIHtcclxuICAgIGNvbnN0IGxvb2sgPSB0aGlzLnNlbGVjdGVkTG9va0dyb3VwO1xyXG4gICAgcmV0dXJuIGxvb2sgPyAobG9vay5nZXQoJ2ZpeHR1cmVTbG90cycpIGFzIEZvcm1BcnJheSkgOiBudWxsO1xyXG4gIH1cclxuXHJcbiAgZ2V0IHNlbGVjdGVkU2xvdEdyb3VwKCk6IEZvcm1Hcm91cCB8IG51bGwge1xyXG4gICAgY29uc3Qgc2xvdHMgPSB0aGlzLnNlbGVjdGVkU2xvdHNBcnJheTtcclxuICAgIGlmICghc2xvdHMpIHJldHVybiBudWxsO1xyXG4gICAgcmV0dXJuIHRoaXMuc2VsZWN0ZWRTbG90SW5kZXggPj0gMCAmJiB0aGlzLnNlbGVjdGVkU2xvdEluZGV4IDwgc2xvdHMubGVuZ3RoXHJcbiAgICAgID8gKHNsb3RzLmF0KHRoaXMuc2VsZWN0ZWRTbG90SW5kZXgpIGFzIEZvcm1Hcm91cClcclxuICAgICAgOiBudWxsO1xyXG4gIH1cclxuXHJcbiAgZ2V0IHNlbGVjdGVkUGxhY2VtZW50cygpOiBGb3JtQXJyYXkgfCBudWxsIHtcclxuICAgIGNvbnN0IHNsb3QgPSB0aGlzLnNlbGVjdGVkU2xvdEdyb3VwO1xyXG4gICAgcmV0dXJuIHNsb3QgPyAoc2xvdC5nZXQoJ3BsYWNlbWVudHMnKSBhcyBGb3JtQXJyYXkpIDogbnVsbDtcclxuICB9XHJcblxyXG4gIGNyZWF0ZUxvb2tHcm91cChzZWVkOiBhbnkgPSB7fSk6IEZvcm1Hcm91cCB7XHJcbiAgICBjb25zdCBzZWVkU2xvdHMgPSBBcnJheS5pc0FycmF5KHNlZWQuZml4dHVyZVNsb3RzKSAmJiBzZWVkLmZpeHR1cmVTbG90cy5sZW5ndGhcclxuICAgICAgPyBzZWVkLmZpeHR1cmVTbG90c1xyXG4gICAgICA6IEFycmF5LmZyb20oeyBsZW5ndGg6IE1hdGgubWF4KDEsIE51bWJlcihzZWVkLmZpeHR1cmVDb3VudCkgfHwgMSkgfSwgKF8sIGkpID0+ICh7IHNsb3RJbmRleDogaSArIDEgfSkpO1xyXG4gICAgY29uc3Qgc2xvdHMgPSBzZWVkU2xvdHMubWFwKChzOiBhbnksIGk6IG51bWJlcikgPT4gdGhpcy5jcmVhdGVTbG90R3JvdXAoeyAuLi5zLCBzbG90SW5kZXg6IGkgKyAxIH0pKTtcclxuXHJcbiAgICBjb25zdCBsb29rR3JvdXAgPSB0aGlzLmZiLmdyb3VwKHtcclxuICAgICAga2V5VHlwZTogW3NlZWQua2V5VHlwZSB8fCAnbWJxJ10sXHJcbiAgICAgIG1icUJ1Y2tldDogW3NlZWQubWJxQnVja2V0IHx8ICcnXSxcclxuICAgICAgYnJhbmRDYXRlZ29yeTogW3NlZWQuYnJhbmRDYXRlZ29yeSB8fCAnJ10sXHJcbiAgICAgIGZpeHR1cmVDb3VudDogW3Nsb3RzLmxlbmd0aCwgW1ZhbGlkYXRvcnMucmVxdWlyZWQsIFZhbGlkYXRvcnMubWluKDApXV0sXHJcbiAgICAgIGZpeHR1cmVUeXBlOiBbQXJyYXkuaXNBcnJheShzZWVkLmZpeHR1cmVUeXBlKSA/IHNlZWQuZml4dHVyZVR5cGUgOiBbXV0sXHJcbiAgICAgIGxheW91dFZhcmlhbnQ6IFtzZWVkLmxheW91dFZhcmlhbnQgfHwgJ3NoZWxmJ10sXHJcbiAgICAgIHN0b3JlUHJvdG86IFtzZWVkLnN0b3JlUHJvdG8gfHwgJyddLFxyXG4gICAgICBmaXh0dXJlU2xvdHM6IHRoaXMuZmIuYXJyYXkoc2xvdHMpLFxyXG4gICAgfSk7XHJcblxyXG4gICAgLy8gZml4dHVyZUNvdW50IOKGkiBzbG90cyBsZW5ndGggKHVzZXItZWRpdGVkIGNvdW50IGFkanVzdHMgdGhlIHNsb3RzIGFycmF5KVxyXG4gICAgbG9va0dyb3VwLmdldCgnZml4dHVyZUNvdW50JykhLnZhbHVlQ2hhbmdlc1xyXG4gICAgICAucGlwZSh0YWtlVW50aWwodGhpcy5kZXN0cm95JCkpXHJcbiAgICAgIC5zdWJzY3JpYmUoKG5leHQ6IG51bWJlcikgPT4ge1xyXG4gICAgICAgIGNvbnN0IHRhcmdldCA9IE1hdGgubWF4KDAsIE1hdGgubWluKDMwLCBOdW1iZXIobmV4dCkgfHwgMCkpO1xyXG4gICAgICAgIGNvbnN0IHNsb3RzQXJyID0gbG9va0dyb3VwLmdldCgnZml4dHVyZVNsb3RzJykgYXMgRm9ybUFycmF5O1xyXG4gICAgICAgIHdoaWxlIChzbG90c0Fyci5sZW5ndGggPCB0YXJnZXQpIHtcclxuICAgICAgICAgIHNsb3RzQXJyLnB1c2godGhpcy5jcmVhdGVTbG90R3JvdXAoeyBzbG90SW5kZXg6IHNsb3RzQXJyLmxlbmd0aCArIDEgfSkpO1xyXG4gICAgICAgIH1cclxuICAgICAgICB3aGlsZSAoc2xvdHNBcnIubGVuZ3RoID4gdGFyZ2V0KSB7XHJcbiAgICAgICAgICBzbG90c0Fyci5yZW1vdmVBdChzbG90c0Fyci5sZW5ndGggLSAxKTtcclxuICAgICAgICB9XHJcbiAgICAgICAgdGhpcy5yZW51bWJlclNsb3RzRm9yR3JvdXAobG9va0dyb3VwKTtcclxuICAgICAgICAvLyBSZWNvbmNpbGUgc2xvdCBzZWxlY3Rpb24gaWYgaXQncyBub3cgb3V0IG9mIGJvdW5kc1xyXG4gICAgICAgIGlmICh0aGlzLnNlbGVjdGVkTG9va0luZGV4ID49IDAgJiYgdGhpcy5sb29rcy5hdCh0aGlzLnNlbGVjdGVkTG9va0luZGV4KSA9PT0gbG9va0dyb3VwKSB7XHJcbiAgICAgICAgICBpZiAoc2xvdHNBcnIubGVuZ3RoID09PSAwKSB7XHJcbiAgICAgICAgICAgIHRoaXMuc2VsZWN0ZWRTbG90SW5kZXggPSAtMTtcclxuICAgICAgICAgIH0gZWxzZSBpZiAodGhpcy5zZWxlY3RlZFNsb3RJbmRleCA+PSBzbG90c0Fyci5sZW5ndGgpIHtcclxuICAgICAgICAgICAgdGhpcy5zZWxlY3RlZFNsb3RJbmRleCA9IHNsb3RzQXJyLmxlbmd0aCAtIDE7XHJcbiAgICAgICAgICB9IGVsc2UgaWYgKHRoaXMuc2VsZWN0ZWRTbG90SW5kZXggPCAwKSB7XHJcbiAgICAgICAgICAgIHRoaXMuc2VsZWN0ZWRTbG90SW5kZXggPSAwO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgfSk7XHJcblxyXG4gICAgcmV0dXJuIGxvb2tHcm91cDtcclxuICB9XHJcblxyXG4gIGNyZWF0ZVNsb3RHcm91cChzZWVkOiBhbnkgPSB7fSk6IEZvcm1Hcm91cCB7XHJcbiAgICBjb25zdCBwbGFjZW1lbnRzID0gKEFycmF5LmlzQXJyYXkoc2VlZC5wbGFjZW1lbnRzKSA/IHNlZWQucGxhY2VtZW50cyA6IFtdKVxyXG4gICAgICAubWFwKChwOiBhbnkpID0+IHRoaXMuY3JlYXRlUGxhY2VtZW50R3JvdXAocCkpO1xyXG4gICAgY29uc3QgbGlicmFyeUNvbmZpZ3MgPSAoQXJyYXkuaXNBcnJheShzZWVkLmxpYnJhcnlDb25maWd1cmF0aW9ucykgPyBzZWVkLmxpYnJhcnlDb25maWd1cmF0aW9ucyA6IFtdKVxyXG4gICAgICAubWFwKChjOiBhbnkpID0+IHRoaXMuY3JlYXRlTGlicmFyeUNvbmZpZ0dyb3VwKGMpKTtcclxuICAgIHJldHVybiB0aGlzLmZiLmdyb3VwKHtcclxuICAgICAgc2xvdEluZGV4OiBbc2VlZC5zbG90SW5kZXggPz8gMSwgVmFsaWRhdG9ycy5yZXF1aXJlZF0sXHJcbiAgICAgIHNsb3RUeXBlOiBbc2VlZC5zbG90VHlwZSB8fCAnc2hlbGYnXSxcclxuICAgICAgYnJhbmQ6IFtzZWVkLmJyYW5kIHx8ICcnXSxcclxuICAgICAgZml4dHVyZUxldmVsWm9uZTogW3NlZWQuZml4dHVyZUxldmVsWm9uZSB8fCAnJ10sXHJcbiAgICAgIGZpeHR1cmVMaWJyYXJ5UmVmOiBbc2VlZC5maXh0dXJlTGlicmFyeVJlZiB8fCAnJ10sXHJcbiAgICAgIGZpeHR1cmVMaWJyYXJ5TGFiZWw6IFtzZWVkLmZpeHR1cmVMaWJyYXJ5TGFiZWwgfHwgJyddLFxyXG4gICAgICBmaXh0dXJlTGlicmFyeVJlZnM6IFtBcnJheS5pc0FycmF5KHNlZWQuZml4dHVyZUxpYnJhcnlSZWZzKSA/IHNlZWQuZml4dHVyZUxpYnJhcnlSZWZzIDogW11dLFxyXG4gICAgICBjYWRIZWFkZXJWYXJpYW50czogW0FycmF5LmlzQXJyYXkoc2VlZC5jYWRIZWFkZXJWYXJpYW50cykgPyBzZWVkLmNhZEhlYWRlclZhcmlhbnRzIDogW11dLFxyXG4gICAgICBwbGFjZW1lbnRzOiB0aGlzLmZiLmFycmF5KHBsYWNlbWVudHMpLFxyXG4gICAgICBsaWJyYXJ5Q29uZmlndXJhdGlvbnM6IHRoaXMuZmIuYXJyYXkobGlicmFyeUNvbmZpZ3MpLFxyXG4gICAgICAvLyBQZXItbGlicmFyeSBzbmFwc2hvdCBvZiB0aGUgZW1iZWRkZWQgZml4dHVyZS10ZW1wbGF0ZSBlZGl0b3Igc3RhdGVcclxuICAgICAgLy8gKHNoZWxmQ29uZmlnICsgcHJvZHVjdC9WTSBwbGFjZW1lbnRzKS4gS2V5ZWQgYnkgbGlicmFyeVJlZi5cclxuICAgICAgbGlicmFyeVNuYXBzaG90czogW1xyXG4gICAgICAgIEFycmF5LmlzQXJyYXkoc2VlZC5saWJyYXJ5U25hcHNob3RzKSA/IHNlZWQubGlicmFyeVNuYXBzaG90cyA6IFtdLFxyXG4gICAgICBdLFxyXG4gICAgfSk7XHJcbiAgfVxyXG5cclxuICBjcmVhdGVMaWJyYXJ5Q29uZmlnR3JvdXAoc2VlZDogYW55ID0ge30pOiBGb3JtR3JvdXAge1xyXG4gICAgcmV0dXJuIHRoaXMuZmIuZ3JvdXAoe1xyXG4gICAgICBsaWJyYXJ5UmVmOiBbc2VlZC5saWJyYXJ5UmVmIHx8ICcnXSxcclxuICAgICAgc2hlbGZOdW1iZXI6IFtzZWVkLnNoZWxmTnVtYmVyID8/IDFdLFxyXG4gICAgICBsYWJlbDogW3NlZWQubGFiZWwgfHwgJyddLFxyXG4gICAgICBzaGVsZlR5cGU6IFtzZWVkLnNoZWxmVHlwZSB8fCAnJ10sXHJcbiAgICAgIC8vIFZNcyBhbmQgUElEcyBwaWNrZWQgZnJvbSB0aGUgc2xvdCdzIGBwbGFjZW1lbnRzYCBhcnJheSAoYnkgcG9zaXRpb24gbmFtZSkuXHJcbiAgICAgIHZtUmVmczogW0FycmF5LmlzQXJyYXkoc2VlZC52bVJlZnMpID8gc2VlZC52bVJlZnMgOiBbXV0sXHJcbiAgICAgIHBpZFJlZnM6IFtBcnJheS5pc0FycmF5KHNlZWQucGlkUmVmcykgPyBzZWVkLnBpZFJlZnMgOiBbXV0sXHJcbiAgICB9KTtcclxuICB9XHJcblxyXG4gIGNyZWF0ZVBsYWNlbWVudEdyb3VwKHNlZWQ6IGFueSA9IHt9KTogRm9ybUdyb3VwIHtcclxuICAgIC8vIEJhY2t3YXJkLWNvbXBhdDogbGVnYWN5IGRhdGEgc3RvcmVkIGEgc2luZ2xlIHN0cmluZyBpbiBgcmF3VmFsdWVgLiBGb3JcclxuICAgIC8vIFBJRCBwbGFjZW1lbnRzIHdlIG5vdyB1c2UgYHJhd1ZhbHVlc2AgKGFycmF5LCBtdWx0aS1zZWxlY3QpLiBJZiB0aGVcclxuICAgIC8vIHNlZWQgb25seSBoYXMgYHJhd1ZhbHVlYCwgbWlncmF0ZSBpdCB0byB0aGUgYXJyYXkgb24gZmlyc3QgbG9hZC5cclxuICAgIGNvbnN0IHJhd1ZhbHVlc1NlZWQgPSBBcnJheS5pc0FycmF5KHNlZWQucmF3VmFsdWVzKVxyXG4gICAgICA/IHNlZWQucmF3VmFsdWVzXHJcbiAgICAgIDogKHNlZWQua2luZCA9PT0gJ3BpZCcgJiYgc2VlZC5yYXdWYWx1ZSA/IFtTdHJpbmcoc2VlZC5yYXdWYWx1ZSldIDogW10pO1xyXG4gICAgcmV0dXJuIHRoaXMuZmIuZ3JvdXAoe1xyXG4gICAgICBwb3NpdGlvbjogW3NlZWQucG9zaXRpb24gfHwgJyddLFxyXG4gICAgICBraW5kOiBbc2VlZC5raW5kIHx8ICdwaWQnXSxcclxuICAgICAgLy8gRm9yIFZNIHJvd3MgdGhpcyBob2xkcyB0aGUgYXJ0d29yayBpZCAoc2luZ2xlIHN0cmluZykuIEZvciBQSUQgcm93c1xyXG4gICAgICAvLyBpdCdzIGxlZnQgZW1wdHkgaW4gZmF2b3VyIG9mIGByYXdWYWx1ZXNgLlxyXG4gICAgICByYXdWYWx1ZTogW3NlZWQua2luZCA9PT0gJ3BpZCcgPyAnJyA6IChzZWVkLnJhd1ZhbHVlIHx8ICcnKV0sXHJcbiAgICAgIHJhd1ZhbHVlczogW3Jhd1ZhbHVlc1NlZWRdLFxyXG4gICAgICB2bVJlZjogW3NlZWQudm1SZWYgfHwgJyddLFxyXG4gICAgICBza3VDb2xsZWN0aW9uUmVmOiBbc2VlZC5za3VDb2xsZWN0aW9uUmVmIHx8ICcnXSxcclxuICAgIH0pO1xyXG4gIH1cclxuXHJcbiAgYWRkUGxhY2VtZW50KCkge1xyXG4gICAgaWYgKCF0aGlzLnNlbGVjdGVkUGxhY2VtZW50cykgcmV0dXJuO1xyXG4gICAgdGhpcy5zZWxlY3RlZFBsYWNlbWVudHMucHVzaCh0aGlzLmNyZWF0ZVBsYWNlbWVudEdyb3VwKCkpO1xyXG4gIH1cclxuXHJcbiAgcmVtb3ZlUGxhY2VtZW50KGluZGV4OiBudW1iZXIpIHtcclxuICAgIGlmICghdGhpcy5zZWxlY3RlZFBsYWNlbWVudHMpIHJldHVybjtcclxuICAgIHRoaXMuc2VsZWN0ZWRQbGFjZW1lbnRzLnJlbW92ZUF0KGluZGV4KTtcclxuICB9XHJcblxyXG4gIHByaXZhdGUgbm9ybVZtVHlwZSh0OiBhbnkpOiBzdHJpbmcge1xyXG4gICAgcmV0dXJuIFN0cmluZyh0ID8/ICcnKS50cmltKCkudG9Mb3dlckNhc2UoKTtcclxuICB9XHJcblxyXG4gIC8qKiBTdGFibGUgcGVyLXZtVHlwZSBhcnR3b3JrIGxpc3QgbG9va3VwLiBSZXR1cm5zIHRoZSBzYW1lIGFycmF5IHJlZmVyZW5jZVxyXG4gICAqICBmb3IgdGhlIHNhbWUgdm1UeXBlIGFjcm9zcyBDRCBjeWNsZXMgc28gbGliLXJlYWN0aXZlLXNlbGVjdCBkb2Vzbid0XHJcbiAgICogIHJlLWluaXQuIEZhbGxzIGJhY2sgdG8gdGhlIGZ1bGwgbGlzdCB3aGVuIHZtVHlwZSBpcyBlbXB0eS4gKi9cclxuICB2bUFydHdvcmtPcHRpb25zRm9yKHZtVHlwZTogc3RyaW5nKTogeyB2YWx1ZTogc3RyaW5nOyBsYWJlbDogc3RyaW5nIH1bXSB7XHJcbiAgICBjb25zdCBrZXkgPSB0aGlzLm5vcm1WbVR5cGUodm1UeXBlKTtcclxuICAgIGlmIChrZXkgJiYgdGhpcy52bUFydHdvcmtCeVR5cGUuaGFzKGtleSkpIHtcclxuICAgICAgcmV0dXJuIHRoaXMudm1BcnR3b3JrQnlUeXBlLmdldChrZXkpITtcclxuICAgIH1cclxuICAgIHJldHVybiB0aGlzLnZtQXJ0d29ya0J5VHlwZS5nZXQoJycpIHx8IFtdO1xyXG4gIH1cclxuXHJcbiAgLyoqIFBvcHVsYXRlIHRoZSBkcm9wZG93biBkYXRhIHVzZWQgYnkgUGxhY2VtZW50IHJvd3M6XHJcbiAgICogIC0gVk0gVHlwZSBsaXN0IChgZ2V0Vm1UeXBlc0xpc3RgKVxyXG4gICAqICAtIFZNIEFydHdvcmsgbGlzdCAoYHZtTmFtZUxpc3RgKVxyXG4gICAqICAtIFByb2R1Y3QgLyBTS1UgY29sbGVjdGlvbiBsaXN0IChmbGF0dGVuZWQgZnJvbSBicmFuZCDihpIgY2F0ZWdvcnkgbWFwcGluZ1xyXG4gICAqICAgIHRoYXQgcG93ZXJzIC9tYW5hZ2UvcGxhbm9ncmFtL2NvbmZpZykuICovXHJcbiAgYXN5bmMgbG9hZFBsYWNlbWVudERyb3Bkb3duRGF0YSgpIHtcclxuICAgIGlmICghdGhpcy5jbGllbnRJZCkgcmV0dXJuO1xyXG4gICAgdHJ5IHtcclxuICAgICAgY29uc3QgW3ZtVHlwZXNSZXMsIHZtc1JlcywgYnJhbmRzUmVzLCBicmFuZE1ldGFSZXNdID0gYXdhaXQgUHJvbWlzZS5hbGwoW1xyXG4gICAgICAgIGxhc3RWYWx1ZUZyb20odGhpcy5idWlsZGVyU2VydmljZS5nZXRWbVR5cGVzTGlzdCh0aGlzLmNsaWVudElkKSksXHJcbiAgICAgICAgbGFzdFZhbHVlRnJvbSh0aGlzLmJ1aWxkZXJTZXJ2aWNlLmdldFZNTmFtZUxpc3QodGhpcy5jbGllbnRJZCkpLFxyXG4gICAgICAgIGxhc3RWYWx1ZUZyb20odGhpcy5idWlsZGVyU2VydmljZS5nZXRCcmFuZExpc3QodGhpcy5jbGllbnRJZCkpLFxyXG4gICAgICAgIGxhc3RWYWx1ZUZyb20odGhpcy5idWlsZGVyU2VydmljZS5nZXRCcmFuZE1ldGFEYXRhKHRoaXMuY2xpZW50SWQpKSxcclxuICAgICAgXSk7XHJcblxyXG4gICAgICBjb25zdCB2bVR5cGVzOiBhbnlbXSA9ICh2bVR5cGVzUmVzIGFzIGFueSk/LmRhdGEgfHwgW107XHJcbiAgICAgIHRoaXMudm1UeXBlT3B0aW9ucyA9IHZtVHlwZXNcclxuICAgICAgICAubWFwKCh0OiBhbnkpID0+IHtcclxuICAgICAgICAgIGNvbnN0IHYgPSB0Py52bVR5cGUgfHwgdD8udm1UeXBlTmFtZSB8fCB0Py5uYW1lIHx8IHQ/Ll9pZDtcclxuICAgICAgICAgIGNvbnN0IGwgPSB0Py52bVR5cGVOYW1lIHx8IHQ/LnZtVHlwZSB8fCB0Py5uYW1lIHx8IHY7XHJcbiAgICAgICAgICByZXR1cm4gdiA/IHsgdmFsdWU6IFN0cmluZyh2KSwgbGFiZWw6IFN0cmluZyhsKSB9IDogbnVsbDtcclxuICAgICAgICB9KVxyXG4gICAgICAgIC5maWx0ZXIoKHgpOiB4IGlzIHsgdmFsdWU6IHN0cmluZzsgbGFiZWw6IHN0cmluZyB9ID0+ICEheCk7XHJcblxyXG4gICAgICBjb25zdCB2bXM6IGFueVtdID0gKHZtc1JlcyBhcyBhbnkpPy5kYXRhIHx8IFtdO1xyXG4gICAgICB0aGlzLnZtQXJ0d29ya09wdGlvbnMgPSB2bXNcclxuICAgICAgICAubWFwKCh2OiBhbnkpOiB7IHZhbHVlOiBzdHJpbmc7IGxhYmVsOiBzdHJpbmc7IHZtVHlwZT86IHN0cmluZyB9IHwgbnVsbCA9PiB7XHJcbiAgICAgICAgICBjb25zdCBpZCA9IHY/LnZtTmFtZSB8fCB2Py5faWQ7XHJcbiAgICAgICAgICBpZiAoIWlkKSByZXR1cm4gbnVsbDtcclxuICAgICAgICAgIHJldHVybiB7XHJcbiAgICAgICAgICAgIHZhbHVlOiBTdHJpbmcoaWQpLFxyXG4gICAgICAgICAgICBsYWJlbDogU3RyaW5nKHY/LnZtTmFtZSB8fCBpZCksXHJcbiAgICAgICAgICAgIHZtVHlwZTogdj8udm1UeXBlID8gU3RyaW5nKHYudm1UeXBlKSA6IHVuZGVmaW5lZCxcclxuICAgICAgICAgIH07XHJcbiAgICAgICAgfSlcclxuICAgICAgICAuZmlsdGVyKCh4KTogeCBpcyB7IHZhbHVlOiBzdHJpbmc7IGxhYmVsOiBzdHJpbmc7IHZtVHlwZT86IHN0cmluZyB9ID0+ICEheCk7XHJcblxyXG4gICAgICAvLyAodm1OYW1lLCB2bVR5cGUpIOKGkiBfaWQgc28gd2UgY2FuIHR1cm4gYSBwbGFjZW1lbnQncyBhcnR3b3JrIE5BTUUgaW50b1xyXG4gICAgICAvLyB0aGUgcGxhbm92bSBfaWQgdGhlIGVtYmVkZGVkIFZNIGVkaXRvciBtYXRjaGVzIGFnYWluc3QuXHJcbiAgICAgIHRoaXMudm1JZEJ5TmFtZVR5cGUgPSBuZXcgTWFwKCk7XHJcbiAgICAgIGZvciAoY29uc3QgdiBvZiB2bXMpIHtcclxuICAgICAgICBpZiAoIXY/Ll9pZCB8fCAhdj8udm1OYW1lKSBjb250aW51ZTtcclxuICAgICAgICBjb25zdCBuYW1lID0gdGhpcy5ub3JtVm1UeXBlKHYudm1OYW1lKTtcclxuICAgICAgICBjb25zdCB0eXBlID0gdGhpcy5ub3JtVm1UeXBlKHYudm1UeXBlKTtcclxuICAgICAgICB0aGlzLnZtSWRCeU5hbWVUeXBlLnNldChgJHtuYW1lfXx8JHt0eXBlfWAsIFN0cmluZyh2Ll9pZCkpO1xyXG4gICAgICAgIGlmICghdGhpcy52bUlkQnlOYW1lVHlwZS5oYXMobmFtZSkpIHtcclxuICAgICAgICAgIHRoaXMudm1JZEJ5TmFtZVR5cGUuc2V0KG5hbWUsIFN0cmluZyh2Ll9pZCkpO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gUmVidWlsZCB0aGUgKHZtVHlwZSDihpIgYXJ0d29ya3MpIGluZGV4IG5vdyB0aGF0IHRoZSBhcnR3b3JrIGxpc3RcclxuICAgICAgLy8gY2hhbmdlZC4gS2V5cyBhcmUgbm9ybWFsaXNlZCAodHJpbSArIGxvd2VyLWNhc2UpIHNvIGEgbWlzbWF0Y2ggaW5cclxuICAgICAgLy8gY2FzaW5nL3doaXRlc3BhY2UgYmV0d2VlbiB2bVR5cGVzIGFuZCB2bXMudm1UeXBlIHN0aWxsIG1hdGNoZXMuXHJcbiAgICAgIHRoaXMudm1BcnR3b3JrQnlUeXBlID0gbmV3IE1hcCgpO1xyXG4gICAgICBjb25zdCBmdWxsTGlzdCA9IHRoaXMudm1BcnR3b3JrT3B0aW9ucy5tYXAoKHYpID0+ICh7IHZhbHVlOiB2LnZhbHVlLCBsYWJlbDogdi5sYWJlbCB9KSk7XHJcbiAgICAgIHRoaXMudm1BcnR3b3JrQnlUeXBlLnNldCgnJywgZnVsbExpc3QpO1xyXG4gICAgICBmb3IgKGNvbnN0IHYgb2YgdGhpcy52bUFydHdvcmtPcHRpb25zKSB7XHJcbiAgICAgICAgY29uc3Qga2V5ID0gdGhpcy5ub3JtVm1UeXBlKHYudm1UeXBlKTtcclxuICAgICAgICBpZiAoIWtleSkgY29udGludWU7XHJcbiAgICAgICAgaWYgKCF0aGlzLnZtQXJ0d29ya0J5VHlwZS5oYXMoa2V5KSkgdGhpcy52bUFydHdvcmtCeVR5cGUuc2V0KGtleSwgW10pO1xyXG4gICAgICAgIHRoaXMudm1BcnR3b3JrQnlUeXBlLmdldChrZXkpIS5wdXNoKHsgdmFsdWU6IHYudmFsdWUsIGxhYmVsOiB2LmxhYmVsIH0pO1xyXG4gICAgICB9XHJcbiAgICAgIGNvbnNvbGUubG9nKFxyXG4gICAgICAgICdbTG9va3MgZm9ybV0gdm1UeXBlczonLCB0aGlzLnZtVHlwZU9wdGlvbnMubGVuZ3RoLFxyXG4gICAgICAgICdhcnR3b3JrczonLCB0aGlzLnZtQXJ0d29ya09wdGlvbnMubGVuZ3RoLFxyXG4gICAgICAgICdhcnR3b3Jrc0J5VHlwZSBrZXlzOicsIEFycmF5LmZyb20odGhpcy52bUFydHdvcmtCeVR5cGUua2V5cygpKSxcclxuICAgICAgKTtcclxuXHJcbiAgICAgIC8vIFNvdXJjZTogZXZlcnkgdmFsdWUgdGhlIGJyYW5kICYgcHJvZHVjdCBtYXBwaW5nIHBhZ2UgZXhwb3Nlcy5cclxuICAgICAgLy8gIC0gYGdldEJyYW5kTGlzdGAgICAgIOKGkiBwZXItYnJhbmQgYGNhdGVnb3J5W11gIGFuZCBgc3ViQ2F0ZWdvcnlbXWBcclxuICAgICAgLy8gIC0gYGdldEJyYW5kTWV0YURhdGFgIOKGkiByb3dzIHdpdGggYHBpZENhdGAsIGBjYXRlZ29yeWAsIGB0ZW1wR3JvdXBgXHJcbiAgICAgIGNvbnN0IGJyYW5kczogYW55W10gPSAoYnJhbmRzUmVzIGFzIGFueSk/LmRhdGEgfHwgW107XHJcbiAgICAgIGNvbnN0IGJyYW5kTWV0YTogYW55W10gPSAoYnJhbmRNZXRhUmVzIGFzIGFueSk/LmRhdGEgfHwgW107XHJcbiAgICAgIGNvbnN0IHNlZW5DYXRzID0gbmV3IFNldDxzdHJpbmc+KCk7XHJcbiAgICAgIGNvbnN0IHByb2R1Y3RzOiB7IHZhbHVlOiBzdHJpbmc7IGxhYmVsOiBzdHJpbmcgfVtdID0gW107XHJcbiAgICAgIGNvbnN0IHB1c2hPbmUgPSAodjogYW55KSA9PiB7XHJcbiAgICAgICAgY29uc3QgcyA9IFN0cmluZyh2ID8/ICcnKS50cmltKCk7XHJcbiAgICAgICAgaWYgKCFzIHx8IHNlZW5DYXRzLmhhcyhzKSkgcmV0dXJuO1xyXG4gICAgICAgIHNlZW5DYXRzLmFkZChzKTtcclxuICAgICAgICBwcm9kdWN0cy5wdXNoKHsgdmFsdWU6IHMsIGxhYmVsOiBzIH0pO1xyXG4gICAgICB9O1xyXG4gICAgICBjb25zdCBwdXNoQXJyID0gKGFycjogYW55KSA9PiB7XHJcbiAgICAgICAgaWYgKCFBcnJheS5pc0FycmF5KGFycikpIHJldHVybjtcclxuICAgICAgICBmb3IgKGNvbnN0IHYgb2YgYXJyKSBwdXNoT25lKHYpO1xyXG4gICAgICB9O1xyXG4gICAgICBmb3IgKGNvbnN0IGIgb2YgYnJhbmRzKSB7XHJcbiAgICAgICAgcHVzaEFycihiPy5jYXRlZ29yeSk7XHJcbiAgICAgICAgcHVzaEFycihiPy5zdWJDYXRlZ29yeSk7XHJcbiAgICAgIH1cclxuICAgICAgZm9yIChjb25zdCByb3cgb2YgYnJhbmRNZXRhKSB7XHJcbiAgICAgICAgcHVzaE9uZShyb3c/LnBpZENhdCk7XHJcbiAgICAgICAgcHVzaE9uZShyb3c/LmNhdGVnb3J5KTtcclxuICAgICAgICBwdXNoT25lKHJvdz8udGVtcEdyb3VwKTtcclxuICAgICAgfVxyXG4gICAgICB0aGlzLnByb2R1Y3RPcHRpb25zID0gcHJvZHVjdHM7XHJcbiAgICAgIGNvbnNvbGUubG9nKFxyXG4gICAgICAgICdbTG9va3MgZm9ybV0gcHJvZHVjdC9TS1Ugb3B0aW9uczonLFxyXG4gICAgICAgIHRoaXMucHJvZHVjdE9wdGlvbnMubGVuZ3RoLFxyXG4gICAgICAgICdmcm9tJyxcclxuICAgICAgICBicmFuZHMubGVuZ3RoLFxyXG4gICAgICAgICdicmFuZHMgYW5kJyxcclxuICAgICAgICBicmFuZE1ldGEubGVuZ3RoLFxyXG4gICAgICAgICdicmFuZC1tZXRhIHJvd3MnLFxyXG4gICAgICApO1xyXG4gICAgfSBjYXRjaCAoZXJyKSB7XHJcbiAgICAgIGNvbnNvbGUubG9nKCdAQCB+IGxvYWRQbGFjZW1lbnREcm9wZG93bkRhdGEgW0VSUl06JywgZXJyKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIGFzeW5jIGxvYWRGaXh0dXJlTGlicmFyaWVzKCkge1xyXG4gICAgaWYgKCF0aGlzLmNsaWVudElkKSByZXR1cm47XHJcbiAgICB0cnkge1xyXG4gICAgICAvLyBPbmx5IGxpc3QgZml4dHVyZSB0ZW1wbGF0ZXMgYXZhaWxhYmxlIGluIEluZGlhIChjb3VudHJ5IGNvZGUgJ0lOJykuXHJcbiAgICAgIGNvbnN0IHJlczogYW55ID0gYXdhaXQgbGFzdFZhbHVlRnJvbShcclxuICAgICAgICB0aGlzLmJ1aWxkZXJTZXJ2aWNlLmdldEZpeHR1cmVMaWJOYW1lTGlzdCh0aGlzLmNsaWVudElkLCAnbm9uLWRyYWZ0JywgJ0lOJyksXHJcbiAgICAgICk7XHJcbiAgICAgIC8vIFJlc3BvbnNlIHNoYXBlOiB7IGNvZGUsIHN0YXR1cywgZGF0YTogW3sgaWQsIGZpeHR1cmVOYW1lLCBmaXh0dXJlVHlwZSB9XSB9LlxyXG4gICAgICBjb25zdCBsaXN0OiB7IGlkOiBzdHJpbmc7IGZpeHR1cmVOYW1lOiBzdHJpbmc7IGZpeHR1cmVUeXBlOiBzdHJpbmcgfVtdID1cclxuICAgICAgICBBcnJheS5pc0FycmF5KHJlcz8uZGF0YSkgPyByZXMuZGF0YSA6IFtdO1xyXG4gICAgICB0aGlzLmZpeHR1cmVMaWJyYXJ5SXRlbXMgPSBsaXN0Lm1hcCgobCkgPT4gKHtcclxuICAgICAgICBpZDogbC5pZCxcclxuICAgICAgICBuYW1lOiBsLmZpeHR1cmVOYW1lLFxyXG4gICAgICAgIGZpeHR1cmVUeXBlOiAobC5maXh0dXJlVHlwZSB8fCAnJykudG9TdHJpbmcoKS50b0xvd2VyQ2FzZSgpLnRyaW0oKSxcclxuICAgICAgfSkpO1xyXG4gICAgICBjb25zdCB0eXBlVGFsbHk6IFJlY29yZDxzdHJpbmcsIG51bWJlcj4gPSB7fTtcclxuICAgICAgZm9yIChjb25zdCBpdCBvZiB0aGlzLmZpeHR1cmVMaWJyYXJ5SXRlbXMpIHtcclxuICAgICAgICBjb25zdCBrID0gaXQuZml4dHVyZVR5cGUgfHwgJyhlbXB0eSknO1xyXG4gICAgICAgIHR5cGVUYWxseVtrXSA9ICh0eXBlVGFsbHlba10gfHwgMCkgKyAxO1xyXG4gICAgICB9XHJcbiAgICAgIGNvbnNvbGUubG9nKFxyXG4gICAgICAgICdbTG9va3MgZm9ybV0gZml4dHVyZSBsaWJyYXJpZXMgbG9hZGVkOicsXHJcbiAgICAgICAgdGhpcy5maXh0dXJlTGlicmFyeUl0ZW1zLmxlbmd0aCxcclxuICAgICAgICAnZml4dHVyZVR5cGUgdGFsbHk6JyxcclxuICAgICAgICB0eXBlVGFsbHksXHJcbiAgICAgICk7XHJcbiAgICAgIHRoaXMucmVjb21wdXRlRml4dHVyZUxpYnJhcnlJdGVtc0ZvclNsb3QoKTtcclxuICAgIH0gY2F0Y2ggKGVycikge1xyXG4gICAgICBjb25zb2xlLmxvZygnQEAgfiBsb2FkRml4dHVyZUxpYnJhcmllcyBbRVJSXTonLCBlcnIpO1xyXG4gICAgICB0aGlzLmZpeHR1cmVMaWJyYXJ5SXRlbXMgPSBbXTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIFJlY29tcHV0ZSB0aGUgc2xvdC10eXBlLWZpbHRlcmVkIGxpYnJhcnkgbGlzdCBvbmNlLiBTdGFibGUgcmVmZXJlbmNlXHJcbiAgICogc28gdGhlIG11bHRpc2VsZWN0IGRvZXNuJ3QgdGVhciBkb3duIGl0cyBjbGljayB0YXJnZXRzIGV2ZXJ5IENEIGN5Y2xlLlxyXG4gICAqL1xyXG4gIHByaXZhdGUgcmVjb21wdXRlRml4dHVyZUxpYnJhcnlJdGVtc0ZvclNsb3QoKTogdm9pZCB7XHJcbiAgICBjb25zdCBzbG90ID0gdGhpcy5zZWxlY3RlZFNsb3RHcm91cDtcclxuICAgIGlmICghc2xvdCkge1xyXG4gICAgICB0aGlzLmZpeHR1cmVMaWJyYXJ5SXRlbXNGb3JTbG90ID0gdGhpcy5maXh0dXJlTGlicmFyeUl0ZW1zLnNsaWNlKCk7XHJcbiAgICAgIHJldHVybjtcclxuICAgIH1cclxuICAgIGNvbnN0IHNsb3RUeXBlID0gc2xvdC5nZXQoJ3Nsb3RUeXBlJyk/LnZhbHVlO1xyXG4gICAgY29uc3QgdGFyZ2V0ID0gc2xvdFR5cGUgPT09ICdldXJvY2VudGVyJyA/ICdmbG9vcicgOiAnd2FsbCc7XHJcbiAgICB0aGlzLmZpeHR1cmVMaWJyYXJ5SXRlbXNGb3JTbG90ID0gdGhpcy5maXh0dXJlTGlicmFyeUl0ZW1zLmZpbHRlcigoaXRlbSkgPT4ge1xyXG4gICAgICBjb25zdCB0ID0gaXRlbS5maXh0dXJlVHlwZTtcclxuICAgICAgaWYgKCF0KSByZXR1cm4gZmFsc2U7XHJcbiAgICAgIGlmICh0YXJnZXQgPT09ICd3YWxsJykgcmV0dXJuIHQgPT09ICd3YWxsJyB8fCB0LmluY2x1ZGVzKCd3YWxsJyk7XHJcbiAgICAgIHJldHVybiB0ID09PSAnZmxvb3InIHx8IHQuaW5jbHVkZXMoJ2Zsb29yJykgfHwgdC5pbmNsdWRlcygnZXVybycpIHx8IHQuaW5jbHVkZXMoJ2ZyZWUnKTtcclxuICAgIH0pO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogU3Vic2NyaXB0aW9ucyBzY29wZWQgdG8gd2hpY2hldmVyIHNsb3QgaXMgY3VycmVudGx5IGFjdGl2ZS4gQ2xlYXJlZCBhbmRcclxuICAgKiByZWJ1aWx0IGV2ZXJ5IHRpbWUgdGhlIGFjdGl2ZSBzbG90IGNoYW5nZXMuXHJcbiAgICovXHJcbiAgcHJpdmF0ZSBzbG90U3ViczogYW55W10gPSBbXTtcclxuXHJcbiAgLyoqIFBlbmRpbmcgYXV0by1hcHBseSBwcm9taXNlcyBrZXllZCBieSBsaWJJZCBzbyBjaGlwIGNsaWNrcyBjYW4gYXdhaXQuICovXHJcbiAgcHJpdmF0ZSBhdXRvQXBwbHlJbkZsaWdodCA9IG5ldyBNYXA8c3RyaW5nLCBQcm9taXNlPHZvaWQ+PigpO1xyXG5cclxuICAvKiogV2lyZS9yZWZyZXNoIHN1YnNjcmlwdGlvbnMgdGhhdCBkZXBlbmQgb24gdGhlIGFjdGl2ZSBzbG90OlxyXG4gICAqICAtIHJlLWZpbHRlciB0aGUgbGlicmFyeSBtdWx0aXNlbGVjdCB3aGVuIHNsb3RUeXBlIGNoYW5nZXNcclxuICAgKiAgLSBydW4gYXV0by1hcHBseSB3aGVuIGEgbmV3IGxpYnJhcnkgaXMgYWRkZWQgdG8gZml4dHVyZUxpYnJhcnlSZWZzXHJcbiAgICovXHJcbiAgcHJpdmF0ZSBiaW5kQWN0aXZlU2xvdExpc3RlbmVycygpOiB2b2lkIHtcclxuICAgIGZvciAoY29uc3QgcyBvZiB0aGlzLnNsb3RTdWJzKSBzPy51bnN1YnNjcmliZT8uKCk7XHJcbiAgICB0aGlzLnNsb3RTdWJzID0gW107XHJcblxyXG4gICAgY29uc3Qgc2xvdCA9IHRoaXMuc2VsZWN0ZWRTbG90R3JvdXA7XHJcbiAgICBpZiAoIXNsb3QpIHtcclxuICAgICAgdGhpcy5maXh0dXJlTGlicmFyeUl0ZW1zRm9yU2xvdCA9IHRoaXMuZml4dHVyZUxpYnJhcnlJdGVtcy5zbGljZSgpO1xyXG4gICAgICByZXR1cm47XHJcbiAgICB9XHJcbiAgICB0aGlzLnJlY29tcHV0ZUZpeHR1cmVMaWJyYXJ5SXRlbXNGb3JTbG90KCk7XHJcblxyXG4gICAgY29uc3QgdHlwZVN1YiA9IHNsb3QuZ2V0KCdzbG90VHlwZScpPy52YWx1ZUNoYW5nZXNcclxuICAgICAgLnBpcGUodGFrZVVudGlsKHRoaXMuZGVzdHJveSQpKVxyXG4gICAgICAuc3Vic2NyaWJlKCgpID0+IHRoaXMucmVjb21wdXRlRml4dHVyZUxpYnJhcnlJdGVtc0ZvclNsb3QoKSk7XHJcbiAgICBpZiAodHlwZVN1YikgdGhpcy5zbG90U3Vicy5wdXNoKHR5cGVTdWIpO1xyXG5cclxuICAgIC8vIFRyYWNrIHByZXZpb3VzIHJlZnMgc28gd2UgY2FuIGRldGVjdCAqbmV3KiBhZGRpdGlvbnMgYW5kIGF1dG8tYXBwbHlcclxuICAgIC8vIHRoZSBzbG90J3MgUElEcyB0byB0aG9zZSBuZXcgbGlicmFyaWVzLlxyXG4gICAgbGV0IHByZXZSZWZzOiBzdHJpbmdbXSA9IFsuLi4oc2xvdC5nZXQoJ2ZpeHR1cmVMaWJyYXJ5UmVmcycpPy52YWx1ZSB8fCBbXSldO1xyXG4gICAgY29uc3QgcmVmc1N1YiA9IHNsb3QuZ2V0KCdmaXh0dXJlTGlicmFyeVJlZnMnKT8udmFsdWVDaGFuZ2VzXHJcbiAgICAgIC5waXBlKHRha2VVbnRpbCh0aGlzLmRlc3Ryb3kkKSlcclxuICAgICAgLnN1YnNjcmliZSgobmV4dFJlZnM6IHN0cmluZ1tdKSA9PiB7XHJcbiAgICAgIGNvbnN0IG5leHQgPSBBcnJheS5pc0FycmF5KG5leHRSZWZzKSA/IG5leHRSZWZzIDogW107XHJcbiAgICAgIGNvbnN0IGFkZGVkID0gbmV4dC5maWx0ZXIoKHIpID0+ICEhciAmJiAhcHJldlJlZnMuaW5jbHVkZXMocikpO1xyXG4gICAgICBwcmV2UmVmcyA9IFsuLi5uZXh0XTtcclxuXHJcbiAgICAgIC8vIElmIHRoZSBjdXJyZW50bHktcHJldmlld2VkIGxpYnJhcnkgd2FzIHVuc2VsZWN0ZWQsIGNsZWFyIHRoZVxyXG4gICAgICAvLyBlbWJlZGRlZCB2aWV3IHNvIHdlIGRvbid0IHNob3cgc3RhbGUgZGF0YS5cclxuICAgICAgaWYgKFxyXG4gICAgICAgIHRoaXMuc2VsZWN0ZWRMaWJyYXJ5SWRJbk1hcFxyXG4gICAgICAgICAgJiYgIW5leHQuaW5jbHVkZXModGhpcy5zZWxlY3RlZExpYnJhcnlJZEluTWFwKVxyXG4gICAgICApIHtcclxuICAgICAgICB0aGlzLm9uTGlicmFyeU1hcFNlbGVjdCgnJyk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIGZvciAoY29uc3QgbGliSWQgb2YgYWRkZWQpIHtcclxuICAgICAgICBjb25zdCBwID0gdGhpcy5hdXRvQXBwbHlQaWRzVG9MaWJyYXJ5KGxpYklkKTtcclxuICAgICAgICB0aGlzLmF1dG9BcHBseUluRmxpZ2h0LnNldChsaWJJZCwgcCk7XHJcbiAgICAgICAgcC5maW5hbGx5KCgpID0+IHtcclxuICAgICAgICAgIGlmICh0aGlzLmF1dG9BcHBseUluRmxpZ2h0LmdldChsaWJJZCkgPT09IHApIHtcclxuICAgICAgICAgICAgdGhpcy5hdXRvQXBwbHlJbkZsaWdodC5kZWxldGUobGliSWQpO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH0pO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBJZiBub3RoaW5nIGlzIGJlaW5nIHByZXZpZXdlZCB5ZXQsIGF1dG8tYWN0aXZhdGUgdGhlIGZpcnN0IGxpYnJhcnlcclxuICAgICAgLy8gdGhlIHVzZXIganVzdCBhZGRlZCBzbyB0aGUgZW1iZWRkZWQgUElEL1ZNIGVkaXRvciBvcGVucyBpbW1lZGlhdGVseVxyXG4gICAgICAvLyAoZXNwZWNpYWxseSByZWxldmFudCB3aGVuIGFkZGluZyB0aGUgRklSU1QgbGlicmFyeSB0byBhbiBlbXB0eVxyXG4gICAgICAvLyBtdWx0aXNlbGVjdCDigJQgcHJldmlvdXNseSB0aGUgY2hpcCBzdHJpcCBzaG93ZWQgaXQgYnV0IHRoZSBwcmV2aWV3XHJcbiAgICAgIC8vIHBhbmUgc3RheWVkIGJsYW5rIHVudGlsIHRoZSB1c2VyIGNsaWNrZWQgdGhlIGNoaXApLlxyXG4gICAgICBpZiAoIXRoaXMuc2VsZWN0ZWRMaWJyYXJ5SWRJbk1hcCkge1xyXG4gICAgICAgIGNvbnN0IGZpcnN0QWN0aXZlID0gYWRkZWQuZmluZCgoaWQpID0+ICEhaWQpIHx8IG5leHQuZmluZCgoaWQpID0+ICEhaWQpO1xyXG4gICAgICAgIGlmIChmaXJzdEFjdGl2ZSkgdGhpcy5vbkxpYnJhcnlNYXBTZWxlY3QoZmlyc3RBY3RpdmUpO1xyXG4gICAgICB9XHJcbiAgICAgIH0pO1xyXG4gICAgaWYgKHJlZnNTdWIpIHRoaXMuc2xvdFN1YnMucHVzaChyZWZzU3ViKTtcclxuXHJcbiAgICAvLyBXaGVuIGFueSBwbGFjZW1lbnQgaW4gdGhlIFwiTG9vayBhbmQgVmlzdWFsIE1lcmNoYW5kaXNpbmcgUGxhY2VtZW50c1wiXHJcbiAgICAvLyBsaXN0IGNoYW5nZXMsIHJlLWRlcml2ZSBldmVyeSBhc3NpZ25lZCBsaWJyYXJ5J3Mgc25hcHNob3Qgc28gdGhlIGVkaXRcclxuICAgIC8vIHByb3BhZ2F0ZXMgdG8gYWxsIG9mIHRoZW0uIERlYm91bmNlZCBzbyByYXBpZCB0eXBpbmcgY29sbGFwc2VzIGludG8gYVxyXG4gICAgLy8gc2luZ2xlIHJlLWFwcGx5LlxyXG4gICAgY29uc3QgcGxhY2VtZW50c0FyciA9IHNsb3QuZ2V0KCdwbGFjZW1lbnRzJykgYXMgRm9ybUFycmF5IHwgbnVsbDtcclxuICAgIGNvbnN0IHBsYWNlbWVudHNTdWIgPSBwbGFjZW1lbnRzQXJyPy52YWx1ZUNoYW5nZXNcclxuICAgICAgLnBpcGUoZGVib3VuY2VUaW1lKDQwMCksIHRha2VVbnRpbCh0aGlzLmRlc3Ryb3kkKSlcclxuICAgICAgLnN1YnNjcmliZSgoKSA9PiB0aGlzLmFwcGx5UGxhY2VtZW50c1RvQXNzaWduZWRMaWJyYXJpZXMoKSk7XHJcbiAgICBpZiAocGxhY2VtZW50c1N1YikgdGhpcy5zbG90U3Vicy5wdXNoKHBsYWNlbWVudHNTdWIpO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogV2hlbiBhIG5ldyBsaWJyYXJ5IGlzIGFkZGVkIHRvIHRoZSBzbG90LCB3YWxrIGl0cyBzaGVsZkNvbmZpZyBhbmQgZm9yXHJcbiAgICogZWFjaCBzaGVsZiB3aG9zZSBzZWN0aW9uIGN1cnJlbnRseSBoYXMgbm8gYnJhbmQsIGNvcHkgdGhlIHJhd1ZhbHVlIG9mXHJcbiAgICogdGhlIHNsb3QncyBQSUQgcGxhY2VtZW50IHdob3NlIGBwb3NpdGlvbmAgbWF0Y2hlcyB0aGUgc2hlbGYnc1xyXG4gICAqIGB6b25lYC9gbGFiZWxgLiBSZXN1bHQgaXMgc2F2ZWQgYXMgdGhlIGxpYnJhcnkncyBzbmFwc2hvdCBzbyB0aGVcclxuICAgKiBlbWJlZGRlZCBmaXh0dXJlLXRlbXBsYXRlIGVkaXRvciBwaWNrcyBpdCB1cCB0aGUgbmV4dCB0aW1lIHRoZSBjaGlwXHJcbiAgICogaXMgb3BlbmVkLlxyXG4gICAqL1xyXG4gIHByaXZhdGUgYXN5bmMgYXV0b0FwcGx5UGlkc1RvTGlicmFyeShsaWJJZDogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7XHJcbiAgICBpZiAoIWxpYklkKSByZXR1cm47XHJcbiAgICBjb25zdCBzbG90ID0gdGhpcy5zZWxlY3RlZFNsb3RHcm91cDtcclxuICAgIGlmICghc2xvdCkgcmV0dXJuO1xyXG5cclxuICAgIGNvbnN0IHBsYWNlbWVudHNBcnIgPSBzbG90LmdldCgncGxhY2VtZW50cycpIGFzIEZvcm1BcnJheSB8IG51bGw7XHJcbiAgICBjb25zdCBwbGFjZW1lbnRzOiBhbnlbXSA9IHBsYWNlbWVudHNBcnI/LnZhbHVlIHx8IFtdO1xyXG4gICAgY29uc3QgcGlkUGxhY2VtZW50cyA9IHBsYWNlbWVudHMuZmlsdGVyKFxyXG4gICAgICAocCkgPT4gcD8ua2luZCA9PT0gJ3BpZCcgJiYgcD8ucG9zaXRpb24gJiYgcD8ucmF3VmFsdWUsXHJcbiAgICApO1xyXG5cclxuICAgIGNvbnN0IG5vcm0gPSAoczogYW55KTogc3RyaW5nID0+IFN0cmluZyhzID8/ICcnKS50cmltKCkudG9Mb3dlckNhc2UoKTtcclxuXHJcbiAgICBjb25zdCBwbGFjZW1lbnRNYXAgPSBuZXcgTWFwPHN0cmluZywgc3RyaW5nPigpO1xyXG4gICAgZm9yIChjb25zdCBwIG9mIHBpZFBsYWNlbWVudHMpIHtcclxuICAgICAgcGxhY2VtZW50TWFwLnNldChub3JtKHAucG9zaXRpb24pLCBTdHJpbmcocC5yYXdWYWx1ZSkpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFN0YXJ0IGZyb20gYW4gZXhpc3Rpbmcgc25hcHNob3QgaWYgd2UgYWxyZWFkeSBzYXZlZCBvbmUgZm9yIHRoaXMgc2xvdFxyXG4gICAgLy8gKyBsaWJyYXJ5OyBvdGhlcndpc2UgZmV0Y2ggdGhlIGZyZXNoIGxpYnJhcnkgZG9jLiBUaGUgcGVyLWZpZWxkIGd1YXJkc1xyXG4gICAgLy8gYmVsb3cgc3RpbGwgZW5zdXJlIHdlIG5ldmVyIG92ZXJ3cml0ZSB1c2VyLXNldCBicmFuZHMgb3IgVk1zLlxyXG4gICAgbGV0IGxpYkRhdGE6IGFueSA9IHRoaXMuZ2V0TGlicmFyeVNuYXBzaG90KGxpYklkKTtcclxuICAgIGlmICghbGliRGF0YSkge1xyXG4gICAgICB0cnkge1xyXG4gICAgICAgIGNvbnN0IHJlczogYW55ID0gYXdhaXQgbGFzdFZhbHVlRnJvbShcclxuICAgICAgICAgIHRoaXMuYnVpbGRlclNlcnZpY2UuZ2V0Rml4dHVyZUxpYnJhcnlEZXRhaWxzKGxpYklkKSxcclxuICAgICAgICApO1xyXG4gICAgICAgIGxpYkRhdGEgPSByZXM/LmRhdGE7XHJcbiAgICAgIH0gY2F0Y2ggKGVycikge1xyXG4gICAgICAgIGNvbnNvbGUubG9nKCdAQCB+IGF1dG9BcHBseVBpZHNUb0xpYnJhcnkgW0VSUl06JywgZXJyKTtcclxuICAgICAgICByZXR1cm47XHJcbiAgICAgIH1cclxuICAgIH1cclxuICAgIGlmICghbGliRGF0YSkgcmV0dXJuO1xyXG5cclxuICAgIGNvbnN0IHNoZWxmQ29uZmlnOiBhbnlbXSA9IEFycmF5LmlzQXJyYXkobGliRGF0YS5zaGVsZkNvbmZpZykgPyBsaWJEYXRhLnNoZWxmQ29uZmlnIDogW107XHJcbiAgICBsZXQgcGlkc0FwcGxpZWQgPSBmYWxzZTtcclxuICAgIGNvbnN0IG5ld1NoZWxmQ29uZmlnID0gc2hlbGZDb25maWcubWFwKChzaGVsZjogYW55KSA9PiB7XHJcbiAgICAgIGlmIChBcnJheS5pc0FycmF5KHNoZWxmPy5wcm9kdWN0QnJhbmROYW1lKSAmJiBzaGVsZi5wcm9kdWN0QnJhbmROYW1lLmxlbmd0aCA+IDApIHtcclxuICAgICAgICByZXR1cm4gc2hlbGY7XHJcbiAgICAgIH1cclxuICAgICAgY29uc3Qgc291cmNlTGFiZWwgPSBzaGVsZj8uem9uZSB8fCBzaGVsZj8ubGFiZWwgfHwgJyc7XHJcbiAgICAgIGNvbnN0IG1hdGNoS2V5ID0gbm9ybShzb3VyY2VMYWJlbCk7XHJcbiAgICAgIGlmICghbWF0Y2hLZXkpIHJldHVybiBzaGVsZjtcclxuICAgICAgY29uc3QgbWF0Y2ggPSBwbGFjZW1lbnRNYXAuZ2V0KG1hdGNoS2V5KTtcclxuICAgICAgaWYgKCFtYXRjaCkgcmV0dXJuIHNoZWxmO1xyXG4gICAgICBwaWRzQXBwbGllZCA9IHRydWU7XHJcbiAgICAgIC8vIGdyb3VwU2hlbHZlc0J5Wm9uZSgpIGluIFRlbXBsYXRlUHJvZHVjdHNDb21wb25lbnQgU0tJUFMgYW55IHNoZWxmXHJcbiAgICAgIC8vIHdob3NlIGB6b25lYCBpcyBlbXB0eSwgc28gd2UgbXVzdCBzZXQgem9uZSAodXNpbmcgdGhlIHNoZWxmJ3MgbGFiZWxcclxuICAgICAgLy8gaWYgaXQgaXNuJ3QgYWxyZWFkeSBzZXQpIGZvciB0aGUgc2VjdGlvbiB0byBmb3JtLlxyXG4gICAgICByZXR1cm4ge1xyXG4gICAgICAgIC4uLnNoZWxmLFxyXG4gICAgICAgIHpvbmU6IHNoZWxmPy56b25lIHx8IHNvdXJjZUxhYmVsLFxyXG4gICAgICAgIHByb2R1Y3RCcmFuZE5hbWU6IFttYXRjaF0sXHJcbiAgICAgIH07XHJcbiAgICB9KTtcclxuXHJcbiAgICAvLyAtLS0gVk0gYXV0by1hcHBseSAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG4gICAgLy8gSWYgdGhlIGxpYnJhcnkgaGFzIG5vIFZNcyBjb25maWd1cmVkIHlldCwgY29weSBlYWNoIG9mIHRoZSBzbG90J3MgVk1cclxuICAgIC8vIHBsYWNlbWVudHMgb3ZlciBhcyBhIHZtQ29uZmlnIGVudHJ5LiBObyBwb3NpdGlvbi1iYXNlZCBtYXRjaGluZyBoZXJlIOKAlFxyXG4gICAgLy8gdGhlIHBsYWNlbWVudCdzIGByYXdWYWx1ZWAgYmVjb21lcyB0aGUgVk0gYXJ0d29yayBhbmQgYHBvc2l0aW9uYFxyXG4gICAgLy8gYmVjb21lcyB0aGUgVk0gdHlwZSBsYWJlbC5cclxuICAgIGNvbnN0IGV4aXN0aW5nVm1zID0gQXJyYXkuaXNBcnJheShsaWJEYXRhLnZtQ29uZmlnKSA/IGxpYkRhdGEudm1Db25maWcgOiBbXTtcclxuICAgIGxldCBuZXdWbUNvbmZpZyA9IGV4aXN0aW5nVm1zO1xyXG4gICAgbGV0IHZtc0FwcGxpZWQgPSBmYWxzZTtcclxuICAgIGlmIChleGlzdGluZ1Ztcy5sZW5ndGggPT09IDApIHtcclxuICAgICAgY29uc3Qgdm1QbGFjZW1lbnRzID0gcGxhY2VtZW50cy5maWx0ZXIoXHJcbiAgICAgICAgKHApID0+IHA/LmtpbmQgPT09ICd2bScgJiYgcD8ucmF3VmFsdWUsXHJcbiAgICAgICk7XHJcbiAgICAgIGlmICh2bVBsYWNlbWVudHMubGVuZ3RoID4gMCkge1xyXG4gICAgICAgIG5ld1ZtQ29uZmlnID0gdm1QbGFjZW1lbnRzLm1hcCgocCkgPT4gKHtcclxuICAgICAgICAgIHZtVHlwZTogU3RyaW5nKHA/LnBvc2l0aW9uIHx8ICcnKSxcclxuICAgICAgICAgIHZtSWQ6IFN0cmluZyhwPy5yYXdWYWx1ZSB8fCAnJyksXHJcbiAgICAgICAgICBzdGFydFlQb3NpdGlvbjogMSxcclxuICAgICAgICAgIGVuZFlQb3NpdGlvbjogMSxcclxuICAgICAgICAgIHhab25lOiAnJyxcclxuICAgICAgICAgIHlab25lOiAnJyxcclxuICAgICAgICAgIHBvc2l0aW9uOiAnJyxcclxuICAgICAgICB9KSk7XHJcbiAgICAgICAgdm1zQXBwbGllZCA9IHRydWU7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICBpZiAoIXBpZHNBcHBsaWVkICYmICF2bXNBcHBsaWVkKSByZXR1cm47XHJcblxyXG4gICAgLy8gVGhlIGVtYmVkZGVkIFRlbXBsYXRlUHJvZHVjdHNDb21wb25lbnQgb25seSByZWFkcyBzZWN0aW9uLWxldmVsIGJyYW5kXHJcbiAgICAvLyB2YWx1ZXMgd2hlbiBwcm9kdWN0UmVzb2x1dGlvbkxldmVsID09PSAnTDMnLlxyXG4gICAgY29uc3QgdXBkYXRlZExpYiA9IHtcclxuICAgICAgLi4ubGliRGF0YSxcclxuICAgICAgc2hlbGZDb25maWc6IG5ld1NoZWxmQ29uZmlnLFxyXG4gICAgICB2bUNvbmZpZzogbmV3Vm1Db25maWcsXHJcbiAgICAgIHByb2R1Y3RSZXNvbHV0aW9uTGV2ZWw6ICdMMycsXHJcbiAgICB9O1xyXG4gICAgdGhpcy5jYXB0dXJlTGlicmFyeVNuYXBzaG90KGxpYklkLCB1cGRhdGVkTGliKTtcclxuICB9XHJcblxyXG4gIGFzeW5jIGxvYWREZXRhaWxzKCkge1xyXG4gICAgaWYgKCF0aGlzLmNvbGxlY3Rpb25JZCkgcmV0dXJuO1xyXG4gICAgdGhpcy5sb2FkaW5nID0gdHJ1ZTtcclxuICAgIHRyeSB7XHJcbiAgICAgIGNvbnN0IHJlczogYW55ID0gYXdhaXQgbGFzdFZhbHVlRnJvbShcclxuICAgICAgICB0aGlzLmJ1aWxkZXJTZXJ2aWNlLmdldExvb2tQbGFub0NvbGxlY3Rpb25EZXRhaWxzKHRoaXMuY29sbGVjdGlvbklkKSxcclxuICAgICAgKTtcclxuICAgICAgY29uc3QgZGF0YSA9IHJlcz8uZGF0YTtcclxuICAgICAgaWYgKGRhdGEpIHtcclxuICAgICAgICB0aGlzLmZvcm0ucGF0Y2hWYWx1ZSh7XHJcbiAgICAgICAgICBuYW1lOiBkYXRhLm5hbWUgfHwgJycsXHJcbiAgICAgICAgICBkZXNjcmlwdGlvbjogZGF0YS5kZXNjcmlwdGlvbiB8fCAnJyxcclxuICAgICAgICAgIGlzQWN0aXZlOiAhIWRhdGEuaXNBY3RpdmUsXHJcbiAgICAgICAgfSk7XHJcbiAgICAgICAgdGhpcy5sb29rcy5jbGVhcigpO1xyXG4gICAgICAgIChkYXRhLmxvb2tzIHx8IFtdKS5mb3JFYWNoKChsOiBhbnkpID0+IHRoaXMubG9va3MucHVzaCh0aGlzLmNyZWF0ZUxvb2tHcm91cChsKSkpO1xyXG4gICAgICAgIHRoaXMuc2VsZWN0ZWRMb29rSW5kZXggPSB0aGlzLmxvb2tzLmxlbmd0aCA/IDAgOiAtMTtcclxuICAgICAgICBjb25zdCBzbG90cyA9IHRoaXMuc2VsZWN0ZWRMb29rSW5kZXggPj0gMCA/IHRoaXMuZml4dHVyZVNsb3RzKHRoaXMuc2VsZWN0ZWRMb29rSW5kZXgpIDogbnVsbDtcclxuICAgICAgICB0aGlzLnNlbGVjdGVkU2xvdEluZGV4ID0gc2xvdHMgJiYgc2xvdHMubGVuZ3RoID8gMCA6IC0xO1xyXG4gICAgICAgIHRoaXMucmVzZXRMaWJyYXJ5TWFwKCk7XHJcbiAgICAgICAgdGhpcy5iaW5kQWN0aXZlU2xvdExpc3RlbmVycygpO1xyXG4gICAgICAgIHRoaXMuYXV0b1NlbGVjdEZpcnN0TGlicmFyeSgpO1xyXG4gICAgICB9XHJcbiAgICB9IGNhdGNoIChlcnIpIHtcclxuICAgICAgY29uc29sZS5sb2coJ0BAIH4gbG9hZERldGFpbHMgW0VSUl06JywgZXJyKTtcclxuICAgICAgdGhpcy50b2FzdC5nZXRFcnJvclRvYXN0Py4oJ0ZhaWxlZCB0byBsb2FkIExvb2sgY29sbGVjdGlvbicpO1xyXG4gICAgfSBmaW5hbGx5IHtcclxuICAgICAgdGhpcy5sb2FkaW5nID0gZmFsc2U7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBhZGRMb29rKCkge1xyXG4gICAgY29uc3QgbmV4dCA9IHRoaXMuY3JlYXRlTG9va0dyb3VwKHsgbWJxQnVja2V0OiAnJywgZml4dHVyZUNvdW50OiAxIH0pO1xyXG4gICAgdGhpcy5sb29rcy5wdXNoKG5leHQpO1xyXG4gICAgdGhpcy5zZWxlY3RlZExvb2tJbmRleCA9IHRoaXMubG9va3MubGVuZ3RoIC0gMTtcclxuICAgIHRoaXMuc2VsZWN0ZWRTbG90SW5kZXggPSB0aGlzLmZpeHR1cmVTbG90cyh0aGlzLnNlbGVjdGVkTG9va0luZGV4KS5sZW5ndGggPyAwIDogLTE7XHJcbiAgICB0aGlzLmJpbmRBY3RpdmVTbG90TGlzdGVuZXJzKCk7XHJcbiAgfVxyXG5cclxuICByZW1vdmVMb29rKGluZGV4OiBudW1iZXIpIHtcclxuICAgIHRoaXMubG9va3MucmVtb3ZlQXQoaW5kZXgpO1xyXG4gICAgaWYgKHRoaXMuc2VsZWN0ZWRMb29rSW5kZXggPT09IGluZGV4KSB7XHJcbiAgICAgIHRoaXMuc2VsZWN0ZWRMb29rSW5kZXggPSB0aGlzLmxvb2tzLmxlbmd0aCA/IDAgOiAtMTtcclxuICAgICAgdGhpcy5zZWxlY3RlZFNsb3RJbmRleCA9IC0xO1xyXG4gICAgfSBlbHNlIGlmICh0aGlzLnNlbGVjdGVkTG9va0luZGV4ID4gaW5kZXgpIHtcclxuICAgICAgdGhpcy5zZWxlY3RlZExvb2tJbmRleCAtPSAxO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgc2VsZWN0TG9vayhpbmRleDogbnVtYmVyKSB7XHJcbiAgICB0aGlzLnNlbGVjdGVkTG9va0luZGV4ID0gaW5kZXg7XHJcbiAgICBjb25zdCBzbG90cyA9IHRoaXMuZml4dHVyZVNsb3RzKGluZGV4KTtcclxuICAgIHRoaXMuc2VsZWN0ZWRTbG90SW5kZXggPSBzbG90cy5sZW5ndGggPyAwIDogLTE7XHJcbiAgICB0aGlzLnJlc2V0TGlicmFyeU1hcCgpO1xyXG4gICAgdGhpcy5iaW5kQWN0aXZlU2xvdExpc3RlbmVycygpO1xyXG4gICAgdGhpcy5hdXRvU2VsZWN0Rmlyc3RMaWJyYXJ5KCk7XHJcbiAgfVxyXG5cclxuICBhZGRTbG90KCkge1xyXG4gICAgaWYgKHRoaXMuc2VsZWN0ZWRMb29rSW5kZXggPCAwKSByZXR1cm47XHJcbiAgICBjb25zdCBsb29rR3JvdXAgPSB0aGlzLmxvb2tzLmF0KHRoaXMuc2VsZWN0ZWRMb29rSW5kZXgpIGFzIEZvcm1Hcm91cDtcclxuICAgIGNvbnN0IHNsb3RzID0gdGhpcy5maXh0dXJlU2xvdHModGhpcy5zZWxlY3RlZExvb2tJbmRleCk7XHJcbiAgICBzbG90cy5wdXNoKHRoaXMuY3JlYXRlU2xvdEdyb3VwKHsgc2xvdEluZGV4OiBzbG90cy5sZW5ndGggKyAxIH0pKTtcclxuICAgIGxvb2tHcm91cC5nZXQoJ2ZpeHR1cmVDb3VudCcpIS5zZXRWYWx1ZShzbG90cy5sZW5ndGgsIHsgZW1pdEV2ZW50OiBmYWxzZSB9KTtcclxuICAgIHRoaXMuc2VsZWN0ZWRTbG90SW5kZXggPSBzbG90cy5sZW5ndGggLSAxO1xyXG4gICAgdGhpcy5iaW5kQWN0aXZlU2xvdExpc3RlbmVycygpO1xyXG4gIH1cclxuXHJcbiAgcmVtb3ZlU2xvdChzbG90SW5kZXg6IG51bWJlcikge1xyXG4gICAgaWYgKHRoaXMuc2VsZWN0ZWRMb29rSW5kZXggPCAwKSByZXR1cm47XHJcbiAgICBjb25zdCBsb29rR3JvdXAgPSB0aGlzLmxvb2tzLmF0KHRoaXMuc2VsZWN0ZWRMb29rSW5kZXgpIGFzIEZvcm1Hcm91cDtcclxuICAgIGNvbnN0IHNsb3RzID0gdGhpcy5maXh0dXJlU2xvdHModGhpcy5zZWxlY3RlZExvb2tJbmRleCk7XHJcbiAgICBzbG90cy5yZW1vdmVBdChzbG90SW5kZXgpO1xyXG4gICAgdGhpcy5yZW51bWJlclNsb3RzRm9yR3JvdXAobG9va0dyb3VwKTtcclxuICAgIGxvb2tHcm91cC5nZXQoJ2ZpeHR1cmVDb3VudCcpIS5zZXRWYWx1ZShzbG90cy5sZW5ndGgsIHsgZW1pdEV2ZW50OiBmYWxzZSB9KTtcclxuICAgIGlmICh0aGlzLnNlbGVjdGVkU2xvdEluZGV4ID09PSBzbG90SW5kZXgpIHtcclxuICAgICAgdGhpcy5zZWxlY3RlZFNsb3RJbmRleCA9IHNsb3RzLmxlbmd0aCA/IE1hdGgubWluKHNsb3RJbmRleCwgc2xvdHMubGVuZ3RoIC0gMSkgOiAtMTtcclxuICAgIH0gZWxzZSBpZiAodGhpcy5zZWxlY3RlZFNsb3RJbmRleCA+IHNsb3RJbmRleCkge1xyXG4gICAgICB0aGlzLnNlbGVjdGVkU2xvdEluZGV4IC09IDE7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICByZW51bWJlclNsb3RzRm9yR3JvdXAobG9va0dyb3VwOiBGb3JtR3JvdXApIHtcclxuICAgIGNvbnN0IHNsb3RzQXJyID0gbG9va0dyb3VwLmdldCgnZml4dHVyZVNsb3RzJykgYXMgRm9ybUFycmF5O1xyXG4gICAgc2xvdHNBcnIuY29udHJvbHMuZm9yRWFjaCgoc2xvdCwgaSkgPT4ge1xyXG4gICAgICAoc2xvdCBhcyBGb3JtR3JvdXApLmdldCgnc2xvdEluZGV4Jyk/LnNldFZhbHVlKGkgKyAxLCB7IGVtaXRFdmVudDogZmFsc2UgfSk7XHJcbiAgICB9KTtcclxuICB9XHJcblxyXG4gIHNlbGVjdFNsb3Qoc2xvdEluZGV4OiBudW1iZXIpIHtcclxuICAgIHRoaXMuc2VsZWN0ZWRTbG90SW5kZXggPSBzbG90SW5kZXg7XHJcbiAgICB0aGlzLnJlc2V0TGlicmFyeU1hcCgpO1xyXG4gICAgdGhpcy5iaW5kQWN0aXZlU2xvdExpc3RlbmVycygpO1xyXG4gICAgdGhpcy5hdXRvU2VsZWN0Rmlyc3RMaWJyYXJ5KCk7XHJcbiAgfVxyXG5cclxuICBsb29rVGl0bGUobG9va0dyb3VwOiBGb3JtR3JvdXApOiBzdHJpbmcge1xyXG4gICAgY29uc3Qga2V5VHlwZSA9IGxvb2tHcm91cC5nZXQoJ2tleVR5cGUnKT8udmFsdWU7XHJcbiAgICBjb25zdCBrZXkgPSBrZXlUeXBlID09PSAnYnJhbmRDYXRlZ29yeSdcclxuICAgICAgPyBsb29rR3JvdXAuZ2V0KCdicmFuZENhdGVnb3J5Jyk/LnZhbHVlXHJcbiAgICAgIDogbG9va0dyb3VwLmdldCgnbWJxQnVja2V0Jyk/LnZhbHVlO1xyXG4gICAgY29uc3QgY291bnQgPSBsb29rR3JvdXAuZ2V0KCdmaXh0dXJlQ291bnQnKT8udmFsdWU7XHJcbiAgICByZXR1cm4gYCR7a2V5IHx8ICcodW5uYW1lZCknfSDigJQgJHtjb3VudCB8fCAwfSBmaXh0dXJlc2A7XHJcbiAgfVxyXG5cclxuICBidWNrZXRLZXkobG9va0dyb3VwOiBGb3JtR3JvdXApOiBzdHJpbmcge1xyXG4gICAgY29uc3Qga2V5VHlwZSA9IGxvb2tHcm91cC5nZXQoJ2tleVR5cGUnKT8udmFsdWU7XHJcbiAgICBjb25zdCBrZXkgPSBrZXlUeXBlID09PSAnYnJhbmRDYXRlZ29yeSdcclxuICAgICAgPyBsb29rR3JvdXAuZ2V0KCdicmFuZENhdGVnb3J5Jyk/LnZhbHVlXHJcbiAgICAgIDogbG9va0dyb3VwLmdldCgnbWJxQnVja2V0Jyk/LnZhbHVlO1xyXG4gICAgcmV0dXJuIChrZXkgfHwgJycpLnRyaW0oKTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIEFzc2lnbiBhIGNvbG91ciB0byBlYWNoIHVuaXF1ZSBidWNrZXQga2V5IGJ5ICoqaW5zZXJ0aW9uIG9yZGVyKiosIG5vdCBieSBoYXNoLlxyXG4gICAqIFRoZSBOdGggZGlzdGluY3QgYnVja2V0IChjb3VudGVkIHRvcC10by1ib3R0b20gdGhyb3VnaCB0aGUgbG9va3MgYXJyYXkpIGdldHNcclxuICAgKiBgQlVDS0VUX1BBTEVUVEVbTl1gLiBPbmx5IGFmdGVyIGFsbCAyMCBwYWxldHRlIHNsb3RzIGFyZSB1c2VkIGRvZXMgdGhlIGFzc2lnbm1lbnRcclxuICAgKiB3cmFwIGFyb3VuZCDigJQgc28gbm8gY29sb3VyIGlzIGV2ZXIgcmV1c2VkIHdoaWxlIDwgMjAgZGlzdGluY3QgYnVja2V0cyBleGlzdC5cclxuICAgKlxyXG4gICAqIFJlY29tcHV0ZWQgb24gZXZlcnkgY2FsbCBzbyBsaXZlIGVkaXRzIHRvIHRoZSBidWNrZXQgbmFtZSByZS1mbG93IGNvbG91cnMuXHJcbiAgICovXHJcbiAgYnVja2V0Q29sb3IobG9va0dyb3VwOiBGb3JtR3JvdXApOiBzdHJpbmcge1xyXG4gICAgY29uc3Qga2V5ID0gdGhpcy5idWNrZXRLZXkobG9va0dyb3VwKTtcclxuICAgIGlmICgha2V5KSByZXR1cm4gJyNmOWZhZmInO1xyXG4gICAgY29uc3QgcGFsZXR0ZSA9IExvb2tQbGFub0NvbGxlY3Rpb25Gb3JtQ29tcG9uZW50LkJVQ0tFVF9QQUxFVFRFO1xyXG4gICAgbGV0IG5leHRJbmRleCA9IDA7XHJcbiAgICBjb25zdCBhc3NpZ25lZCA9IG5ldyBNYXA8c3RyaW5nLCBzdHJpbmc+KCk7XHJcbiAgICBmb3IgKGNvbnN0IGdyb3VwIG9mIHRoaXMubG9va3MuY29udHJvbHMpIHtcclxuICAgICAgY29uc3QgayA9IHRoaXMuYnVja2V0S2V5KGdyb3VwIGFzIEZvcm1Hcm91cCk7XHJcbiAgICAgIGlmIChrICYmICFhc3NpZ25lZC5oYXMoaykpIHtcclxuICAgICAgICBhc3NpZ25lZC5zZXQoaywgcGFsZXR0ZVtuZXh0SW5kZXggJSBwYWxldHRlLmxlbmd0aF0pO1xyXG4gICAgICAgIG5leHRJbmRleCArPSAxO1xyXG4gICAgICB9XHJcbiAgICAgIGlmIChrID09PSBrZXkpIHtcclxuICAgICAgICByZXR1cm4gYXNzaWduZWQuZ2V0KGspITtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gICAgcmV0dXJuICcjZjlmYWZiJztcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIFJlb3JkZXIgdGhlIGxvb2tzIEZvcm1BcnJheSBzbyB0aGF0IHRoZSBidWNrZXQgd2l0aCB0aGUgKiptb3N0KiogbG9va3NcclxuICAgKiBjb21lcyBmaXJzdCBhbmQgdGhlIG9uZSB3aXRoIHRoZSBmZXdlc3QgY29tZXMgbGFzdCAoYWxwaGFiZXRpY2FsIHRpZS1icmVha1xyXG4gICAqIHdpdGhpbiB0aGUgc2FtZSBjb3VudCkuIExvb2tzIHdpdGhpbiB0aGUgc2FtZSBidWNrZXQgYXJlIHNvcnRlZCBieVxyXG4gICAqIGFzY2VuZGluZyBmaXh0dXJlQ291bnQuIFNlbGVjdGlvbiBpcyBwcmVzZXJ2ZWQgYnkgcmVmZXJlbmNlLCBub3QgYnkgaW5kZXguXHJcbiAgICovXHJcbiAgcHJpdmF0ZSBhcHBseVNvcnRlZE9yZGVyKCk6IHZvaWQge1xyXG4gICAgY29uc3QgZ3JvdXBzID0gdGhpcy5sb29rcy5jb250cm9scyBhcyBGb3JtR3JvdXBbXTtcclxuICAgIGlmIChncm91cHMubGVuZ3RoIDw9IDEpIHJldHVybjtcclxuXHJcbiAgICAvLyBUYWxseSBob3cgbWFueSBsb29rcyBlYWNoIGJ1Y2tldCBoYXMgc28gd2UgY2FuIHNvcnQgYnVja2V0cyBieSBmcmVxdWVuY3kuXHJcbiAgICBjb25zdCBidWNrZXRDb3VudHMgPSBuZXcgTWFwPHN0cmluZywgbnVtYmVyPigpO1xyXG4gICAgZm9yIChjb25zdCBnIG9mIGdyb3Vwcykge1xyXG4gICAgICBjb25zdCBrID0gdGhpcy5idWNrZXRLZXkoZyk7XHJcbiAgICAgIGlmICghaykgY29udGludWU7XHJcbiAgICAgIGJ1Y2tldENvdW50cy5zZXQoaywgKGJ1Y2tldENvdW50cy5nZXQoaykgfHwgMCkgKyAxKTtcclxuICAgIH1cclxuXHJcbiAgICBjb25zdCBzb3J0ZWQgPSBbLi4uZ3JvdXBzXS5zb3J0KChhLCBiKSA9PiB7XHJcbiAgICAgIGNvbnN0IGFLZXkgPSB0aGlzLmJ1Y2tldEtleShhKTtcclxuICAgICAgY29uc3QgYktleSA9IHRoaXMuYnVja2V0S2V5KGIpO1xyXG4gICAgICAvLyBFbXB0eSBidWNrZXQga2V5cyBnbyB0byB0aGUgZW5kIHNvIHVuZmluaXNoZWQgbG9va3MgZG9uJ3QgZGlzcnVwdCB0aGUgZ3JvdXBzXHJcbiAgICAgIGlmIChhS2V5ICYmICFiS2V5KSByZXR1cm4gLTE7XHJcbiAgICAgIGlmICghYUtleSAmJiBiS2V5KSByZXR1cm4gMTtcclxuXHJcbiAgICAgIC8vIFByaW1hcnk6IGJ1Y2tldCBmcmVxdWVuY3ksIGRlc2NlbmRpbmcgKG1vc3QtcG9wdWxhdGVkIGJ1Y2tldCBmaXJzdClcclxuICAgICAgY29uc3QgYUNvdW50ID0gYnVja2V0Q291bnRzLmdldChhS2V5KSB8fCAwO1xyXG4gICAgICBjb25zdCBiQ291bnQgPSBidWNrZXRDb3VudHMuZ2V0KGJLZXkpIHx8IDA7XHJcbiAgICAgIGlmIChhQ291bnQgIT09IGJDb3VudCkgcmV0dXJuIGJDb3VudCAtIGFDb3VudDtcclxuXHJcbiAgICAgIC8vIFRpZS1icmVhazogYWxwaGFiZXRpY2FsIGJ1Y2tldCBuYW1lXHJcbiAgICAgIGlmIChhS2V5ICE9PSBiS2V5KSByZXR1cm4gYUtleS5sb2NhbGVDb21wYXJlKGJLZXkpO1xyXG5cclxuICAgICAgLy8gV2l0aGluIHRoZSBzYW1lIGJ1Y2tldDogYXNjZW5kaW5nIGZpeHR1cmVDb3VudFxyXG4gICAgICBjb25zdCBhRkMgPSBOdW1iZXIoYS5nZXQoJ2ZpeHR1cmVDb3VudCcpPy52YWx1ZSkgfHwgMDtcclxuICAgICAgY29uc3QgYkZDID0gTnVtYmVyKGIuZ2V0KCdmaXh0dXJlQ291bnQnKT8udmFsdWUpIHx8IDA7XHJcbiAgICAgIHJldHVybiBhRkMgLSBiRkM7XHJcbiAgICB9KTtcclxuXHJcbiAgICBjb25zdCBvcmRlckNoYW5nZWQgPSBzb3J0ZWQuc29tZSgoZywgaSkgPT4gZyAhPT0gZ3JvdXBzW2ldKTtcclxuICAgIGlmICghb3JkZXJDaGFuZ2VkKSByZXR1cm47XHJcblxyXG4gICAgY29uc3QgY3VycmVudExvb2sgPSB0aGlzLnNlbGVjdGVkTG9va0dyb3VwO1xyXG4gICAgY29uc3QgY3VycmVudFNsb3QgPSB0aGlzLnNlbGVjdGVkU2xvdEdyb3VwO1xyXG5cclxuICAgIHRoaXMubG9va3MuY2xlYXIoeyBlbWl0RXZlbnQ6IGZhbHNlIH0pO1xyXG4gICAgc29ydGVkLmZvckVhY2goKGcpID0+IHRoaXMubG9va3MucHVzaChnLCB7IGVtaXRFdmVudDogZmFsc2UgfSkpO1xyXG5cclxuICAgIGlmIChjdXJyZW50TG9vaykge1xyXG4gICAgICBjb25zdCBuZXdMb29rSWR4ID0gc29ydGVkLmluZGV4T2YoY3VycmVudExvb2spO1xyXG4gICAgICB0aGlzLnNlbGVjdGVkTG9va0luZGV4ID0gbmV3TG9va0lkeDtcclxuICAgICAgaWYgKHRoaXMuc2VsZWN0ZWRMb29rSW5kZXggPj0gMCAmJiBjdXJyZW50U2xvdCkge1xyXG4gICAgICAgIGNvbnN0IHNsb3RzQXJyID0gdGhpcy5maXh0dXJlU2xvdHModGhpcy5zZWxlY3RlZExvb2tJbmRleCk7XHJcbiAgICAgICAgY29uc3QgbmV3U2xvdElkeCA9IHNsb3RzQXJyLmNvbnRyb2xzLmluZGV4T2YoY3VycmVudFNsb3QpO1xyXG4gICAgICAgIHRoaXMuc2VsZWN0ZWRTbG90SW5kZXggPSBuZXdTbG90SWR4O1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBhc3luYyBzYXZlKCkge1xyXG4gICAgaWYgKHRoaXMuZm9ybS5pbnZhbGlkKSB7XHJcbiAgICAgIHRoaXMudG9hc3QuZ2V0RXJyb3JUb2FzdD8uKCdQbGVhc2UgZmlsbCBhbGwgcmVxdWlyZWQgZmllbGRzJyk7XHJcbiAgICAgIHJldHVybjtcclxuICAgIH1cclxuICAgIHRoaXMuc2F2aW5nID0gdHJ1ZTtcclxuICAgIHRyeSB7XHJcbiAgICAgIC8vIFNvcnQgdGhlIGxvb2tzIGJlZm9yZSBzZXJpYWxpc2luZyBzbyBib3RoIHRoZSBwZXJzaXN0ZWQgcGF5bG9hZFxyXG4gICAgICAvLyBhbmQgdGhlIG9uLXNjcmVlbiBsaXN0IHJlZmxlY3QgZ3JvdXBpbmcgYnkgTUJRIGJ1Y2tldCAvIGJyYW5kIGNhdGVnb3J5XHJcbiAgICAgIC8vIGFuZCBhc2NlbmRpbmcgZml4dHVyZSBjb3VudC5cclxuICAgICAgdGhpcy5hcHBseVNvcnRlZE9yZGVyKCk7XHJcblxyXG4gICAgICBjb25zdCBwYXlsb2FkID0ge1xyXG4gICAgICAgIC4uLnRoaXMuZm9ybS52YWx1ZSxcclxuICAgICAgICBjbGllbnRJZDogdGhpcy5jbGllbnRJZCxcclxuICAgICAgfTtcclxuICAgICAgaWYgKHRoaXMuaXNOZXcpIHtcclxuICAgICAgICBjb25zdCByZXM6IGFueSA9IGF3YWl0IGxhc3RWYWx1ZUZyb20odGhpcy5idWlsZGVyU2VydmljZS5jcmVhdGVMb29rUGxhbm9Db2xsZWN0aW9uKHBheWxvYWQpKTtcclxuICAgICAgICBjb25zdCBuZXdJZCA9IHJlcz8uZGF0YT8uX2lkO1xyXG4gICAgICAgIHRoaXMudG9hc3QuZ2V0U3VjY2Vzc1RvYXN0Py4oJ0xvb2sgY29sbGVjdGlvbiBjcmVhdGVkJyk7XHJcbiAgICAgICAgaWYgKG5ld0lkKSB7XHJcbiAgICAgICAgICB0aGlzLnJvdXRlci5uYXZpZ2F0ZShbJy9tYW5hZ2UvcGxhbm9ncmFtL2xvb2tzJywgbmV3SWRdKTtcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgdGhpcy5yb3V0ZXIubmF2aWdhdGUoWycvbWFuYWdlL3BsYW5vZ3JhbS9sb29rcyddKTtcclxuICAgICAgICB9XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgYXdhaXQgbGFzdFZhbHVlRnJvbShcclxuICAgICAgICAgIHRoaXMuYnVpbGRlclNlcnZpY2UudXBkYXRlTG9va1BsYW5vQ29sbGVjdGlvbih7IC4uLnBheWxvYWQsIGNvbGxlY3Rpb25JZDogdGhpcy5jb2xsZWN0aW9uSWQgfSksXHJcbiAgICAgICAgKTtcclxuICAgICAgICB0aGlzLnRvYXN0LmdldFN1Y2Nlc3NUb2FzdD8uKCdMb29rIGNvbGxlY3Rpb24gdXBkYXRlZCcpO1xyXG4gICAgICB9XHJcbiAgICB9IGNhdGNoIChlcnIpIHtcclxuICAgICAgY29uc29sZS5sb2coJ0BAIH4gc2F2ZSBbRVJSXTonLCBlcnIpO1xyXG4gICAgICB0aGlzLnRvYXN0LmdldEVycm9yVG9hc3Q/LignRmFpbGVkIHRvIHNhdmUgTG9vayBjb2xsZWN0aW9uJyk7XHJcbiAgICB9IGZpbmFsbHkge1xyXG4gICAgICB0aGlzLnNhdmluZyA9IGZhbHNlO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgY2FuY2VsKCkge1xyXG4gICAgdGhpcy5yb3V0ZXIubmF2aWdhdGUoWycvbWFuYWdlL3BsYW5vZ3JhbS9sb29rcyddKTtcclxuICB9XHJcblxyXG4gIHRyYWNrQnlJbmRleChpbmRleDogbnVtYmVyKSB7XHJcbiAgICByZXR1cm4gaW5kZXg7XHJcbiAgfVxyXG5cclxuICBuZ09uRGVzdHJveSgpOiB2b2lkIHtcclxuICAgIHRoaXMuZGVzdHJveSQubmV4dCgpO1xyXG4gICAgdGhpcy5kZXN0cm95JC5jb21wbGV0ZSgpO1xyXG4gICAgLy8gUmVsZWFzZSB0aGUgc2hhcmVkIEJlaGF2aW9yU3ViamVjdCBzbyBvdGhlciBwYWdlcyBkb24ndCBpbmhlcml0IGEgc3RhbGUgbGlicmFyeS5cclxuICAgIHRoaXMucGxhbm9EYXRhU2VydmljZS5maXh0dXJlVGVtcGxhdGVEZXRhaWxzLm5leHQobnVsbCk7XHJcbiAgfVxyXG59XHJcbiIsIjxzZWN0aW9uIGNsYXNzPVwibG9vay1mb3JtXCI+XHJcbiAgPCEtLSBUb3AgYmFyIChib3VuZCB0byB0aGUgb3V0ZXIgZm9ybSkgLS0+XHJcbiAgPGRpdiBjbGFzcz1cImNhcmQgcC00IG1iLTRcIiBbZm9ybUdyb3VwXT1cImZvcm1cIj5cclxuICAgIDxkaXYgY2xhc3M9XCJyb3cgYWxpZ24taXRlbXMtZW5kXCI+XHJcbiAgICAgIDxkaXYgY2xhc3M9XCJjb2wtbWQtNFwiPlxyXG4gICAgICAgIDxsYWJlbCBjbGFzcz1cImZvcm0tbGFiZWwgZnctYm9sZFwiPk5hbWUgKjwvbGFiZWw+XHJcbiAgICAgICAgPGlucHV0IHR5cGU9XCJ0ZXh0XCIgY2xhc3M9XCJmb3JtLWNvbnRyb2xcIiBmb3JtQ29udHJvbE5hbWU9XCJuYW1lXCIgcGxhY2Vob2xkZXI9XCJlLmcuIE1hc3RlciBMb29rIFBsYW4gRlkyNlwiIC8+XHJcbiAgICAgIDwvZGl2PlxyXG4gICAgICA8ZGl2IGNsYXNzPVwiY29sLW1kLTVcIj5cclxuICAgICAgICA8bGFiZWwgY2xhc3M9XCJmb3JtLWxhYmVsIGZ3LWJvbGRcIj5EZXNjcmlwdGlvbjwvbGFiZWw+XHJcbiAgICAgICAgPGlucHV0IHR5cGU9XCJ0ZXh0XCIgY2xhc3M9XCJmb3JtLWNvbnRyb2xcIiBmb3JtQ29udHJvbE5hbWU9XCJkZXNjcmlwdGlvblwiIHBsYWNlaG9sZGVyPVwiT3B0aW9uYWwgZGVzY3JpcHRpb25cIiAvPlxyXG4gICAgICA8L2Rpdj5cclxuICAgICAgPGRpdiBjbGFzcz1cImNvbC1tZC0xIHRleHQtY2VudGVyXCI+XHJcbiAgICAgICAgPGxhYmVsIGNsYXNzPVwiZm9ybS1sYWJlbCBmdy1ib2xkIGQtYmxvY2tcIj5BY3RpdmU8L2xhYmVsPlxyXG4gICAgICAgIDxpbnB1dCB0eXBlPVwiY2hlY2tib3hcIiBjbGFzcz1cImZvcm0tY2hlY2staW5wdXRcIiBmb3JtQ29udHJvbE5hbWU9XCJpc0FjdGl2ZVwiIC8+XHJcbiAgICAgIDwvZGl2PlxyXG4gICAgICA8ZGl2IGNsYXNzPVwiY29sLW1kLTIgdGV4dC1lbmRcIj5cclxuICAgICAgICA8YnV0dG9uIHR5cGU9XCJidXR0b25cIiBjbGFzcz1cImJ0biBidG4tbGlnaHQgbWUtMlwiIChjbGljayk9XCJjYW5jZWwoKVwiPkNhbmNlbDwvYnV0dG9uPlxyXG4gICAgICAgIDxidXR0b24gdHlwZT1cImJ1dHRvblwiIGNsYXNzPVwiYnRuIGJ0bi1wcmltYXJ5XCIgW2Rpc2FibGVkXT1cInNhdmluZ1wiIChjbGljayk9XCJzYXZlKClcIj5cclxuICAgICAgICAgIHt7IHNhdmluZyA/ICdTYXZpbmfigKYnIDogJ1NhdmUnIH19XHJcbiAgICAgICAgPC9idXR0b24+XHJcbiAgICAgIDwvZGl2PlxyXG4gICAgPC9kaXY+XHJcbiAgPC9kaXY+XHJcblxyXG4gIDwhLS0gVGhyZWUtcGFuZSBlZGl0b3IgLS0+XHJcbiAgPGRpdiBjbGFzcz1cInJvdyBteC0wIGctM1wiPlxyXG4gICAgPCEtLSBMZWZ0OiBMb29rcyBsaXN0IChubyBmb3JtIGJpbmRpbmcgbmVlZGVkIOKAlCBqdXN0IG5hdmlnYXRpb24pIC0tPlxyXG4gICAgPGRpdiBjbGFzcz1cImNvbC1tZC0zXCI+XHJcbiAgICAgIDxkaXYgY2xhc3M9XCJjYXJkIHAtMyBoLTEwMFwiPlxyXG4gICAgICAgIDxkaXYgY2xhc3M9XCJkLWZsZXgganVzdGlmeS1jb250ZW50LWJldHdlZW4gYWxpZ24taXRlbXMtY2VudGVyIG1iLTNcIj5cclxuICAgICAgICAgIDxoNiBjbGFzcz1cIm0tMFwiPk1CUSBCdWNrZXQgLSBGaXh0dXJlIENvbWJpbmF0aW9uczwvaDY+XHJcbiAgICAgICAgICA8YnV0dG9uIHR5cGU9XCJidXR0b25cIiBjbGFzcz1cImJ0biBidG4tc20gYnRuLXByaW1hcnlcIiAoY2xpY2spPVwiYWRkTG9vaygpXCI+KyBBZGQgTG9vazwvYnV0dG9uPlxyXG4gICAgICAgIDwvZGl2PlxyXG4gICAgICAgIDxkaXYgKm5nSWY9XCJsb29rcy5sZW5ndGggPT09IDBcIiBjbGFzcz1cInRleHQtbXV0ZWQgc21hbGxcIj5ObyBsb29rcyB5ZXQuIEFkZCBvbmUgdG8gc3RhcnQuPC9kaXY+XHJcbiAgICAgICAgPGRpdiBjbGFzcz1cImxvb2tzLXRyZWVcIj5cclxuICAgICAgICAgIDxkaXZcclxuICAgICAgICAgICAgKm5nRm9yPVwibGV0IGxvb2sgb2YgbG9va3MuY29udHJvbHM7IGxldCBpID0gaW5kZXg7IHRyYWNrQnk6IHRyYWNrQnlJbmRleFwiXHJcbiAgICAgICAgICAgIGNsYXNzPVwibG9vay1yb3cgZC1mbGV4IGp1c3RpZnktY29udGVudC1iZXR3ZWVuIGFsaWduLWl0ZW1zLWNlbnRlciBweC0yIHB5LTIgbWItMSByb3VuZGVkXCJcclxuICAgICAgICAgICAgW2NsYXNzLnNlbGVjdGVkXT1cInNlbGVjdGVkTG9va0luZGV4ID09PSBpXCJcclxuICAgICAgICAgICAgW3N0eWxlLmJhY2tncm91bmQtY29sb3JdPVwiYnVja2V0Q29sb3IoJGFueShsb29rKSlcIlxyXG4gICAgICAgICAgICAoY2xpY2spPVwic2VsZWN0TG9vayhpKVwiXHJcbiAgICAgICAgICA+XHJcbiAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwiZC1mbGV4IGFsaWduLWl0ZW1zLWNlbnRlciBnYXAtMiB0ZXh0LXRydW5jYXRlXCI+XHJcbiAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJidWNrZXQtZG90XCIgW3N0eWxlLmJhY2tncm91bmQtY29sb3JdPVwiYnVja2V0Q29sb3IoJGFueShsb29rKSlcIj48L3NwYW4+XHJcbiAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJ0ZXh0LXRydW5jYXRlXCI+e3sgbG9va1RpdGxlKCRhbnkobG9vaykpIH19PC9zcGFuPlxyXG4gICAgICAgICAgICA8L3NwYW4+XHJcbiAgICAgICAgICAgIDxidXR0b24gdHlwZT1cImJ1dHRvblwiIGNsYXNzPVwiYnRuIGJ0bi1zbSBidG4tbGlnaHQtZGFuZ2VyIG1zLTJcIiAoY2xpY2spPVwiJGV2ZW50LnN0b3BQcm9wYWdhdGlvbigpOyByZW1vdmVMb29rKGkpXCI+w5c8L2J1dHRvbj5cclxuICAgICAgICAgIDwvZGl2PlxyXG4gICAgICAgIDwvZGl2PlxyXG4gICAgICA8L2Rpdj5cclxuICAgIDwvZGl2PlxyXG5cclxuICAgIDwhLS0gQ2VudHJlOiBzZWxlY3RlZCBMb29rIG1ldGFkYXRhICsgc2xvdHMgLS0+XHJcbiAgICA8ZGl2IGNsYXNzPVwiY29sLW1kLTNcIj5cclxuICAgICAgPG5nLWNvbnRhaW5lciAqbmdJZj1cInNlbGVjdGVkTG9va0dyb3VwIGFzIGxvb2tHcm91cDsgZWxzZSBub0xvb2tcIj5cclxuICAgICAgICA8ZGl2IGNsYXNzPVwiY2FyZCBwLTMgaC0xMDBcIiBbZm9ybUdyb3VwXT1cImxvb2tHcm91cFwiPlxyXG4gICAgICAgICAgPGg2IGNsYXNzPVwibWItM1wiPkZpeHR1cmUgQ29tYmluYXRpb24gRGV0YWlsczwvaDY+XHJcblxyXG4gICAgICAgICAgPGRpdiBjbGFzcz1cInJvdyBnLTIgbWItM1wiPlxyXG4gICAgICAgICAgICA8ZGl2IGNsYXNzPVwiY29sLW1kLTZcIj5cclxuICAgICAgICAgICAgICA8bGFiZWwgY2xhc3M9XCJmb3JtLWxhYmVsIHNtYWxsXCI+TUJRIGJ1Y2tldDwvbGFiZWw+XHJcbiAgICAgICAgICAgICAgPGlucHV0IHR5cGU9XCJ0ZXh0XCIgY2xhc3M9XCJmb3JtLWNvbnRyb2wgZm9ybS1jb250cm9sLXNtXCIgZm9ybUNvbnRyb2xOYW1lPVwibWJxQnVja2V0XCIgcGxhY2Vob2xkZXI9XCJlLmcuIEpKIC8gT0QgRXllXCIgLz5cclxuICAgICAgICAgICAgPC9kaXY+XHJcbiAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJjb2wtbWQtNlwiPlxyXG4gICAgICAgICAgICAgIDxsYWJlbCBjbGFzcz1cImZvcm0tbGFiZWwgc21hbGxcIj5GaXh0dXJlIGNvdW50ICo8L2xhYmVsPlxyXG4gICAgICAgICAgICAgIDxpbnB1dCB0eXBlPVwibnVtYmVyXCIgbWluPVwiMFwiIG1heD1cIjMwXCIgY2xhc3M9XCJmb3JtLWNvbnRyb2wgZm9ybS1jb250cm9sLXNtXCIgZm9ybUNvbnRyb2xOYW1lPVwiZml4dHVyZUNvdW50XCIgLz5cclxuICAgICAgICAgICAgPC9kaXY+XHJcbiAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJjb2wtbWQtMTJcIj5cclxuICAgICAgICAgICAgICA8bGFiZWwgY2xhc3M9XCJmb3JtLWxhYmVsIHNtYWxsXCI+Rml4dHVyZSBQb3NpdGlvbnM8L2xhYmVsPlxyXG4gICAgICAgICAgICAgIDxtdWx0aXNlbGVjdC1jaGlwLWRyb3Bkb3duXHJcbiAgICAgICAgICAgICAgICBbaXRlbXNdPVwiZml4dHVyZVR5cGVPcHRpb25zXCJcclxuICAgICAgICAgICAgICAgIGlkRmllbGQ9XCJpZFwiXHJcbiAgICAgICAgICAgICAgICBuYW1lRmllbGQ9XCJuYW1lXCJcclxuICAgICAgICAgICAgICAgIHBsYWNlaG9sZGVyPVwiU2VsZWN0IGZpeHR1cmUgcG9zaXRpb25cIlxyXG4gICAgICAgICAgICAgICAgZm9ybUNvbnRyb2xOYW1lPVwiZml4dHVyZVR5cGVcIj5cclxuICAgICAgICAgICAgICA8L211bHRpc2VsZWN0LWNoaXAtZHJvcGRvd24+XHJcbiAgICAgICAgICAgIDwvZGl2PlxyXG4gICAgICAgICAgPC9kaXY+XHJcblxyXG4gICAgICAgICAgPGhyIC8+XHJcblxyXG4gICAgICAgICAgPGRpdiBjbGFzcz1cImQtZmxleCBqdXN0aWZ5LWNvbnRlbnQtYmV0d2VlbiBhbGlnbi1pdGVtcy1jZW50ZXIgbWItMlwiPlxyXG4gICAgICAgICAgICA8aDYgY2xhc3M9XCJtLTBcIj5GaXh0dXJlczwvaDY+XHJcbiAgICAgICAgICAgIDxidXR0b24gdHlwZT1cImJ1dHRvblwiIGNsYXNzPVwiYnRuIGJ0bi1zbSBidG4tbGlnaHRcIiAoY2xpY2spPVwiYWRkU2xvdCgpXCI+KyBBZGQgRml4dHVyZTwvYnV0dG9uPlxyXG4gICAgICAgICAgPC9kaXY+XHJcbiAgICAgICAgICA8ZGl2IGNsYXNzPVwic2xvdHMtbGlzdFwiPlxyXG4gICAgICAgICAgICA8ZGl2XHJcbiAgICAgICAgICAgICAgKm5nRm9yPVwibGV0IHNsb3Qgb2YgKHNlbGVjdGVkU2xvdHNBcnJheT8uY29udHJvbHMgfHwgW10pOyBsZXQgcyA9IGluZGV4OyB0cmFja0J5OiB0cmFja0J5SW5kZXhcIlxyXG4gICAgICAgICAgICAgIGNsYXNzPVwic2xvdC1yb3cgZC1mbGV4IGp1c3RpZnktY29udGVudC1iZXR3ZWVuIGFsaWduLWl0ZW1zLWNlbnRlciBweC0yIHB5LTIgbWItMSByb3VuZGVkXCJcclxuICAgICAgICAgICAgICBbY2xhc3Muc2VsZWN0ZWRdPVwic2VsZWN0ZWRTbG90SW5kZXggPT09IHNcIlxyXG4gICAgICAgICAgICAgIChjbGljayk9XCJzZWxlY3RTbG90KHMpXCJcclxuICAgICAgICAgICAgPlxyXG4gICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJkLWZsZXggZmxleC1jb2x1bW5cIj5cclxuICAgICAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwiZnctYm9sZCBzbWFsbFwiPlxyXG4gICAgICAgICAgICAgICAgICBGaXh0dXJlIHt7ICRhbnkoc2xvdCkuZ2V0KCdzbG90SW5kZXgnKT8udmFsdWUgfX0g4oCUIHt7ICRhbnkoc2xvdCkuZ2V0KCdzbG90VHlwZScpPy52YWx1ZSB9fVxyXG4gICAgICAgICAgICAgICAgPC9zcGFuPlxyXG4gICAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJ0ZXh0LW11dGVkIHNtYWxsXCI+XHJcbiAgICAgICAgICAgICAgICAgIHt7ICRhbnkoc2xvdCkuZ2V0KCdicmFuZCcpPy52YWx1ZSB8fCAnKG5vIGJyYW5kKScgfX0gwrdcclxuICAgICAgICAgICAgICAgICAge3sgJGFueShzbG90KS5nZXQoJ2ZpeHR1cmVMZXZlbFpvbmUnKT8udmFsdWUgfHwgJyhubyB6b25lKScgfX1cclxuICAgICAgICAgICAgICAgIDwvc3Bhbj5cclxuICAgICAgICAgICAgICA8L2Rpdj5cclxuICAgICAgICAgICAgICA8YnV0dG9uIHR5cGU9XCJidXR0b25cIiBjbGFzcz1cImJ0biBidG4tc20gYnRuLWxpZ2h0LWRhbmdlciBtcy0yXCIgKGNsaWNrKT1cIiRldmVudC5zdG9wUHJvcGFnYXRpb24oKTsgcmVtb3ZlU2xvdChzKVwiPsOXPC9idXR0b24+XHJcbiAgICAgICAgICAgIDwvZGl2PlxyXG4gICAgICAgICAgPC9kaXY+XHJcbiAgICAgICAgPC9kaXY+XHJcbiAgICAgIDwvbmctY29udGFpbmVyPlxyXG4gICAgICA8bmctdGVtcGxhdGUgI25vTG9vaz5cclxuICAgICAgICA8ZGl2IGNsYXNzPVwiY2FyZCBwLTUgaC0xMDAgdGV4dC1jZW50ZXIgdGV4dC1tdXRlZFwiPlNlbGVjdCBvciBhZGQgYSBMb29rIHRvIGVkaXQgaXQuPC9kaXY+XHJcbiAgICAgIDwvbmctdGVtcGxhdGU+XHJcbiAgICA8L2Rpdj5cclxuXHJcbiAgICA8IS0tIFJpZ2h0OiBzZWxlY3RlZCBzbG90IOKAlCBwbGFjZW1lbnRzIGVkaXRvciAtLT5cclxuICAgIDxkaXYgY2xhc3M9XCJjb2wtbWQtNlwiPlxyXG4gICAgICA8bmctY29udGFpbmVyICpuZ0lmPVwic2VsZWN0ZWRTbG90R3JvdXAgYXMgc2xvdEdyb3VwOyBlbHNlIG5vU2xvdFwiPlxyXG4gICAgICAgIDxkaXYgY2xhc3M9XCJjYXJkIHAtMyBoLTEwMFwiIFtmb3JtR3JvdXBdPVwic2xvdEdyb3VwXCI+XHJcbiAgICAgICAgICA8aDYgY2xhc3M9XCJtYi0zXCI+Rml4dHVyZSB7eyBzZWxlY3RlZFNsb3RJbmRleCArIDEgfX0gLSBEZWZpbml0aW9uPC9oNj5cclxuXHJcbiAgICAgICAgICA8ZGl2IGNsYXNzPVwicm93IGctMiBtYi0zXCI+XHJcbiAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJjb2wtbWQtMTJcIj5cclxuICAgICAgICAgICAgICA8bGFiZWwgY2xhc3M9XCJmb3JtLWxhYmVsIHNtYWxsIHRleHQtbXV0ZWRcIj5TbG90IGluZGV4IChhdXRvKTwvbGFiZWw+XHJcbiAgICAgICAgICAgICAgPGlucHV0IHR5cGU9XCJ0ZXh0XCIgY2xhc3M9XCJmb3JtLWNvbnRyb2wgZm9ybS1jb250cm9sLXNtXCIgW3ZhbHVlXT1cInNlbGVjdGVkU2xvdEluZGV4ICsgMVwiIHJlYWRvbmx5IGRpc2FibGVkIC8+XHJcbiAgICAgICAgICAgIDwvZGl2PlxyXG4gICAgICAgICAgICA8ZGl2IGNsYXNzPVwiY29sLW1kLTZcIj5cclxuICAgICAgICAgICAgICA8bGFiZWwgY2xhc3M9XCJmb3JtLWxhYmVsIHNtYWxsXCI+Rml4dHVyZSBUeXBlPC9sYWJlbD5cclxuICAgICAgICAgICAgICA8c2VsZWN0IGNsYXNzPVwiZm9ybS1zZWxlY3QgZm9ybS1zZWxlY3Qtc21cIiBmb3JtQ29udHJvbE5hbWU9XCJzbG90VHlwZVwiPlxyXG4gICAgICAgICAgICAgICAgPG9wdGlvbiAqbmdGb3I9XCJsZXQgb3B0IG9mIGF2YWlsYWJsZVNsb3RUeXBlc1wiIFt2YWx1ZV09XCJvcHQuaWRcIj57eyBvcHQubmFtZSB9fTwvb3B0aW9uPlxyXG4gICAgICAgICAgICAgIDwvc2VsZWN0PlxyXG4gICAgICAgICAgICA8L2Rpdj5cclxuICAgICAgICAgICAgPGRpdiBjbGFzcz1cImNvbC1tZC02XCI+XHJcbiAgICAgICAgICAgICAgPGxhYmVsIGNsYXNzPVwiZm9ybS1sYWJlbCBzbWFsbFwiPkJyYW5kPC9sYWJlbD5cclxuICAgICAgICAgICAgICA8aW5wdXQgdHlwZT1cInRleHRcIiBjbGFzcz1cImZvcm0tY29udHJvbCBmb3JtLWNvbnRyb2wtc21cIiBmb3JtQ29udHJvbE5hbWU9XCJicmFuZFwiIHBsYWNlaG9sZGVyPVwiSm9obiBKYWNvYnNcIiAvPlxyXG4gICAgICAgICAgICA8L2Rpdj5cclxuICAgICAgICAgICAgPGRpdiBjbGFzcz1cImNvbC1tZC0xMlwiPlxyXG4gICAgICAgICAgICAgIDxsYWJlbCBjbGFzcz1cImZvcm0tbGFiZWwgc21hbGxcIj5GaXh0dXJlIEhlYWRlcjwvbGFiZWw+XHJcbiAgICAgICAgICAgICAgPGlucHV0IHR5cGU9XCJ0ZXh0XCIgY2xhc3M9XCJmb3JtLWNvbnRyb2wgZm9ybS1jb250cm9sLXNtXCIgZm9ybUNvbnRyb2xOYW1lPVwiZml4dHVyZUxldmVsWm9uZVwiIHBsYWNlaG9sZGVyPVwiUHJlbWl1bSBUcmVuZGluZ1wiIC8+XHJcbiAgICAgICAgICAgIDwvZGl2PlxyXG4gICAgICAgICAgICA8ZGl2IGNsYXNzPVwiY29sLW1kLTEyXCI+XHJcbiAgICAgICAgICAgICAgPGxhYmVsIGNsYXNzPVwiZm9ybS1sYWJlbCBzbWFsbFwiPkNBRCBIZWFkZXIgVmFyaWVudHM8L2xhYmVsPlxyXG4gICAgICAgICAgICAgIDxsaWItY2hpcHMtaW5wdXRcclxuICAgICAgICAgICAgICAgIGZvcm1Db250cm9sTmFtZT1cImNhZEhlYWRlclZhcmlhbnRzXCJcclxuICAgICAgICAgICAgICAgIHBsYWNlaG9sZGVyPVwiVHlwZSBhIHZhcmlhbnQgYW5kIHByZXNzIEVudGVyXCI+XHJcbiAgICAgICAgICAgICAgPC9saWItY2hpcHMtaW5wdXQ+XHJcbiAgICAgICAgICAgIDwvZGl2PlxyXG4gICAgICAgICAgICA8ZGl2IGNsYXNzPVwiY29sLW1kLTEyXCI+XHJcbiAgICAgICAgICAgICAgPGxhYmVsIGNsYXNzPVwiZm9ybS1sYWJlbCBzbWFsbFwiPkZpeHR1cmUgVGVtcGxhdGVzPC9sYWJlbD5cclxuICAgICAgICAgICAgICA8bXVsdGlzZWxlY3QtY2hpcC1kcm9wZG93blxyXG4gICAgICAgICAgICAgICAgY2xhc3M9XCJmaXh0dXJlLWxpYnJhcmllcy1zZWxlY3RcIlxyXG4gICAgICAgICAgICAgICAgW2l0ZW1zXT1cImZpeHR1cmVMaWJyYXJ5SXRlbXNGb3JTbG90XCJcclxuICAgICAgICAgICAgICAgIGlkRmllbGQ9XCJpZFwiXHJcbiAgICAgICAgICAgICAgICBuYW1lRmllbGQ9XCJuYW1lXCJcclxuICAgICAgICAgICAgICAgIFtzZWFyY2hdPVwidHJ1ZVwiXHJcbiAgICAgICAgICAgICAgICBzZWFyY2hGaWVsZD1cIm5hbWVcIlxyXG4gICAgICAgICAgICAgICAgcGxhY2Vob2xkZXI9XCJTZWxlY3QgZml4dHVyZSB0ZW1wbGF0ZXNcIlxyXG4gICAgICAgICAgICAgICAgZm9ybUNvbnRyb2xOYW1lPVwiZml4dHVyZUxpYnJhcnlSZWZzXCI+XHJcbiAgICAgICAgICAgICAgPC9tdWx0aXNlbGVjdC1jaGlwLWRyb3Bkb3duPlxyXG4gICAgICAgICAgICAgIDxzbWFsbCBjbGFzcz1cInRleHQtbXV0ZWRcIiAqbmdJZj1cInNsb3RHcm91cC5nZXQoJ3Nsb3RUeXBlJyk/LnZhbHVlID09PSAnZXVyb2NlbnRlcidcIj5cclxuICAgICAgICAgICAgICAgIFNob3dpbmcgZmxvb3IgZml4dHVyZXMgKGV1cm9jZW50ZXIgc2xvdCkuXHJcbiAgICAgICAgICAgICAgPC9zbWFsbD5cclxuICAgICAgICAgICAgICA8c21hbGwgY2xhc3M9XCJ0ZXh0LW11dGVkXCIgKm5nSWY9XCJzbG90R3JvdXAuZ2V0KCdzbG90VHlwZScpPy52YWx1ZSAhPT0gJ2V1cm9jZW50ZXInXCI+XHJcbiAgICAgICAgICAgICAgICBTaG93aW5nIHdhbGwgZml4dHVyZXMgKHNoZWxmIHNsb3QpLlxyXG4gICAgICAgICAgICAgIDwvc21hbGw+XHJcbiAgICAgICAgICAgIDwvZGl2PlxyXG4gICAgICAgICAgPC9kaXY+XHJcblxyXG4gICAgICAgICAgPGhyIC8+XHJcblxyXG4gICAgICAgICAgPGRpdiBjbGFzcz1cImQtZmxleCBqdXN0aWZ5LWNvbnRlbnQtYmV0d2VlbiBhbGlnbi1pdGVtcy1jZW50ZXIgbWItMlwiPlxyXG4gICAgICAgICAgICA8aDYgY2xhc3M9XCJtLTBcIj5Mb29rIGFuZCBWaXN1YWwgTWVyY2hhbmRpc2luZyBQbGFjZW1lbnRzPC9oNj5cclxuICAgICAgICAgICAgPGJ1dHRvbiB0eXBlPVwiYnV0dG9uXCIgY2xhc3M9XCJidG4gYnRuLXNtIGJ0bi1saWdodFwiIChjbGljayk9XCJhZGRQbGFjZW1lbnQoKVwiPisgQWRkIHBsYWNlbWVudDwvYnV0dG9uPlxyXG4gICAgICAgICAgPC9kaXY+XHJcbiAgICAgICAgICA8ZGl2ICpuZ0lmPVwiKHNlbGVjdGVkUGxhY2VtZW50cz8ubGVuZ3RoIHx8IDApID09PSAwXCIgY2xhc3M9XCJ0ZXh0LW11dGVkIHNtYWxsIG1iLTJcIj5cclxuICAgICAgICAgICAgTm8gcGxhY2VtZW50cyB5ZXQuIENsaWNrIDxzdHJvbmc+KyBBZGQgcGxhY2VtZW50PC9zdHJvbmc+IHRvIGFkZCBvbmUuXHJcbiAgICAgICAgICA8L2Rpdj5cclxuICAgICAgICAgIDxkaXYgY2xhc3M9XCJwbGFjZW1lbnRzLXNjcm9sbFwiIGZvcm1BcnJheU5hbWU9XCJwbGFjZW1lbnRzXCI+XHJcbiAgICAgICAgICAgIDxkaXZcclxuICAgICAgICAgICAgICAqbmdGb3I9XCJsZXQgcCBvZiAoc2VsZWN0ZWRQbGFjZW1lbnRzPy5jb250cm9scyB8fCBbXSk7IGxldCBwaSA9IGluZGV4OyB0cmFja0J5OiB0cmFja0J5SW5kZXhcIlxyXG4gICAgICAgICAgICAgIGNsYXNzPVwicGxhY2VtZW50LXJvdyBtYi0yXCJcclxuICAgICAgICAgICAgICBbZm9ybUdyb3VwTmFtZV09XCJwaVwiXHJcbiAgICAgICAgICAgID5cclxuICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwiZC1mbGV4IGFsaWduLWl0ZW1zLXN0YXJ0IGdhcC0yIHBsYWNlbWVudC1maWVsZHNcIj5cclxuICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJwaC1maWVsZFwiPlxyXG4gICAgICAgICAgICAgICAgICA8c2VsZWN0IGNsYXNzPVwiZm9ybS1zZWxlY3QgZm9ybS1zZWxlY3Qtc21cIiBmb3JtQ29udHJvbE5hbWU9XCJraW5kXCI+XHJcbiAgICAgICAgICAgICAgICAgICAgPG9wdGlvbiB2YWx1ZT1cInBpZFwiPlByb2R1Y3QgTWVyY2hhbmRpc2luZzwvb3B0aW9uPlxyXG4gICAgICAgICAgICAgICAgICAgIDxvcHRpb24gdmFsdWU9XCJ2bVwiPlZpc3VhbCBNZXJjaGFuZGlzaW5nPC9vcHRpb24+XHJcbiAgICAgICAgICAgICAgICAgIDwvc2VsZWN0PlxyXG4gICAgICAgICAgICAgICAgPC9kaXY+XHJcblxyXG4gICAgICAgICAgICAgICAgPCEtLSBWaXN1YWwgTWVyY2hhbmRpc2luZyByb3dzOiBWTSBUeXBlIChzaW5nbGUpICsgVk0gQXJ0d29yayAoc2luZ2xlKSAtLT5cclxuICAgICAgICAgICAgICAgIDxuZy1jb250YWluZXIgKm5nSWY9XCIkYW55KHApLmdldCgna2luZCcpPy52YWx1ZSA9PT0gJ3ZtJzsgZWxzZSBwaWRJbnB1dHNcIj5cclxuICAgICAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cInBoLWZpZWxkXCI+XHJcbiAgICAgICAgICAgICAgICAgICAgPGxpYi1zZWFyY2hhYmxlLXNlbGVjdFxyXG4gICAgICAgICAgICAgICAgICAgICAgW2l0ZW1zXT1cInZtVHlwZU9wdGlvbnNcIlxyXG4gICAgICAgICAgICAgICAgICAgICAgaWRGaWVsZD1cInZhbHVlXCJcclxuICAgICAgICAgICAgICAgICAgICAgIG5hbWVGaWVsZD1cImxhYmVsXCJcclxuICAgICAgICAgICAgICAgICAgICAgIHBsYWNlaG9sZGVyPVwiVmlzdWFsIE1lcmNoYW5kaXNpbmcgVHlwZVwiXHJcbiAgICAgICAgICAgICAgICAgICAgICBmb3JtQ29udHJvbE5hbWU9XCJwb3NpdGlvblwiPlxyXG4gICAgICAgICAgICAgICAgICAgIDwvbGliLXNlYXJjaGFibGUtc2VsZWN0PlxyXG4gICAgICAgICAgICAgICAgICA8L2Rpdj5cclxuICAgICAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cInBoLWZpZWxkXCI+XHJcbiAgICAgICAgICAgICAgICAgICAgPGxpYi1zZWFyY2hhYmxlLXNlbGVjdFxyXG4gICAgICAgICAgICAgICAgICAgICAgW2l0ZW1zXT1cInZtQXJ0d29ya09wdGlvbnNGb3IoJGFueShwKS5nZXQoJ3Bvc2l0aW9uJyk/LnZhbHVlKVwiXHJcbiAgICAgICAgICAgICAgICAgICAgICBpZEZpZWxkPVwidmFsdWVcIlxyXG4gICAgICAgICAgICAgICAgICAgICAgbmFtZUZpZWxkPVwibGFiZWxcIlxyXG4gICAgICAgICAgICAgICAgICAgICAgcGxhY2Vob2xkZXI9XCJWaXN1YWwgTWVyY2hhbmRpc2luZyBBcnR3b3JrXCJcclxuICAgICAgICAgICAgICAgICAgICAgIGZvcm1Db250cm9sTmFtZT1cInJhd1ZhbHVlXCI+XHJcbiAgICAgICAgICAgICAgICAgICAgPC9saWItc2VhcmNoYWJsZS1zZWxlY3Q+XHJcbiAgICAgICAgICAgICAgICAgIDwvZGl2PlxyXG4gICAgICAgICAgICAgICAgPC9uZy1jb250YWluZXI+XHJcblxyXG4gICAgICAgICAgICAgICAgPCEtLSBQcm9kdWN0IE1lcmNoYW5kaXNpbmcgcm93czogVG9wL01pZC9Cb3R0b20gcG9zaXRpb24gKyBtdWx0aS1zZWxlY3QgcHJvZHVjdC9TS1UgLS0+XHJcbiAgICAgICAgICAgICAgICA8bmctdGVtcGxhdGUgI3BpZElucHV0cz5cclxuICAgICAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cInBoLWZpZWxkXCI+XHJcbiAgICAgICAgICAgICAgICAgICAgPHNlbGVjdCBjbGFzcz1cImZvcm0tc2VsZWN0IGZvcm0tc2VsZWN0LXNtXCIgZm9ybUNvbnRyb2xOYW1lPVwicG9zaXRpb25cIj5cclxuICAgICAgICAgICAgICAgICAgICAgIDxvcHRpb24gdmFsdWU9XCJcIj5Qb3NpdGlvbjwvb3B0aW9uPlxyXG4gICAgICAgICAgICAgICAgICAgICAgPG9wdGlvbiB2YWx1ZT1cIlRvcFwiPlRvcDwvb3B0aW9uPlxyXG4gICAgICAgICAgICAgICAgICAgICAgPG9wdGlvbiB2YWx1ZT1cIk1pZFwiPk1pZDwvb3B0aW9uPlxyXG4gICAgICAgICAgICAgICAgICAgICAgPG9wdGlvbiB2YWx1ZT1cIkJvdHRvbVwiPkJvdHRvbTwvb3B0aW9uPlxyXG4gICAgICAgICAgICAgICAgICAgIDwvc2VsZWN0PlxyXG4gICAgICAgICAgICAgICAgICA8L2Rpdj5cclxuICAgICAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cInBoLWZpZWxkXCI+XHJcbiAgICAgICAgICAgICAgICAgICAgPGxpYi1zZWFyY2hhYmxlLXNlbGVjdFxyXG4gICAgICAgICAgICAgICAgICAgICAgW2l0ZW1zXT1cInByb2R1Y3RPcHRpb25zXCJcclxuICAgICAgICAgICAgICAgICAgICAgIGlkRmllbGQ9XCJ2YWx1ZVwiXHJcbiAgICAgICAgICAgICAgICAgICAgICBuYW1lRmllbGQ9XCJsYWJlbFwiXHJcbiAgICAgICAgICAgICAgICAgICAgICBbbXVsdGlwbGVdPVwidHJ1ZVwiXHJcbiAgICAgICAgICAgICAgICAgICAgICBwbGFjZWhvbGRlcj1cIlByb2R1Y3QgLyBTS1VcIlxyXG4gICAgICAgICAgICAgICAgICAgICAgZm9ybUNvbnRyb2xOYW1lPVwicmF3VmFsdWVzXCI+XHJcbiAgICAgICAgICAgICAgICAgICAgPC9saWItc2VhcmNoYWJsZS1zZWxlY3Q+XHJcbiAgICAgICAgICAgICAgICAgIDwvZGl2PlxyXG4gICAgICAgICAgICAgICAgPC9uZy10ZW1wbGF0ZT5cclxuXHJcbiAgICAgICAgICAgICAgICA8YnV0dG9uIHR5cGU9XCJidXR0b25cIiBjbGFzcz1cImJ0biBidG4tc20gYnRuLWxpZ2h0LWRhbmdlciBwaC1yZW1vdmVcIiAoY2xpY2spPVwicmVtb3ZlUGxhY2VtZW50KHBpKVwiPsOXPC9idXR0b24+XHJcbiAgICAgICAgICAgICAgPC9kaXY+XHJcbiAgICAgICAgICAgIDwvZGl2PlxyXG4gICAgICAgICAgPC9kaXY+XHJcbiAgICAgICAgPC9kaXY+XHJcbiAgICAgIDwvbmctY29udGFpbmVyPlxyXG4gICAgICA8bmctdGVtcGxhdGUgI25vU2xvdD5cclxuICAgICAgICA8ZGl2IGNsYXNzPVwiY2FyZCBwLTUgaC0xMDAgdGV4dC1jZW50ZXIgdGV4dC1tdXRlZFwiPlNlbGVjdCBhIGZpeHR1cmUgc2xvdCB0byBlZGl0IHBsYWNlbWVudHMuPC9kaXY+XHJcbiAgICAgIDwvbmctdGVtcGxhdGU+XHJcbiAgICA8L2Rpdj5cclxuICA8L2Rpdj5cclxuXHJcbiAgPCEtLSBQZXItc2xvdCBGaXh0dXJlIExpYnJhcnkgQ29uZmlndXJhdGlvbiBjYXJkIC0tPlxyXG4gIDxuZy1jb250YWluZXIgKm5nSWY9XCJzZWxlY3RlZFNsb3RHcm91cCBhcyBzbG90R3JvdXBGb3JNYXBcIj5cclxuICAgIDxkaXYgY2xhc3M9XCJjYXJkIHAtNCBtdC00IGxpYnJhcnktY29uZmlnLWNhcmRcIiBbZm9ybUdyb3VwXT1cInNsb3RHcm91cEZvck1hcFwiPlxyXG4gICAgICA8ZGl2IGNsYXNzPVwibWItNFwiPlxyXG4gICAgICAgIDxoNSBjbGFzcz1cImZvcm0tbGFiZWwgZC1ibG9jayBtYi0zXCI+Rml4dHVyZSBsaWJyYXJ5PC9oNT5cclxuICAgICAgICA8ZGl2IGNsYXNzPVwibGlicmFyeS1jaGlwc1wiPlxyXG4gICAgICAgICAgPGJ1dHRvblxyXG4gICAgICAgICAgICAqbmdGb3I9XCJsZXQgbGliIG9mIHNlbGVjdGVkU2xvdExpYnJhcmllc0ZvckRyb3Bkb3duXCJcclxuICAgICAgICAgICAgdHlwZT1cImJ1dHRvblwiXHJcbiAgICAgICAgICAgIGNsYXNzPVwibGlicmFyeS1jaGlwXCJcclxuICAgICAgICAgICAgW2NsYXNzLmFjdGl2ZV09XCJzZWxlY3RlZExpYnJhcnlJZEluTWFwID09PSBsaWIuaWRcIlxyXG4gICAgICAgICAgICAoY2xpY2spPVwib25MaWJyYXJ5TWFwU2VsZWN0KHNlbGVjdGVkTGlicmFyeUlkSW5NYXAgPT09IGxpYi5pZCA/ICcnIDogbGliLmlkKVwiPlxyXG4gICAgICAgICAgICB7eyBsaWIubmFtZSB9fVxyXG4gICAgICAgICAgPC9idXR0b24+XHJcbiAgICAgICAgPC9kaXY+XHJcbiAgICAgICAgPHNtYWxsICpuZ0lmPVwic2VsZWN0ZWRTbG90TGlicmFyaWVzRm9yRHJvcGRvd24ubGVuZ3RoID09PSAwXCIgY2xhc3M9XCJ0ZXh0LW11dGVkXCI+XHJcbiAgICAgICAgICBObyBsaWJyYXJpZXMgbGlua2VkIHRvIHRoaXMgc2xvdCB5ZXQuIEFkZCBzb21lIGluIHRoZSBcIkZpeHR1cmUgbGlicmFyaWVzXCIgbXVsdGlzZWxlY3QgYWJvdmUuXHJcbiAgICAgICAgPC9zbWFsbD5cclxuICAgICAgPC9kaXY+XHJcblxyXG4gICAgICA8ZGl2ICpuZ0lmPVwibG9hZGluZ0xpYnJhcnlEZXRhaWxzXCIgY2xhc3M9XCJ0ZXh0LW11dGVkXCI+TG9hZGluZyBmaXh0dXJlIGRldGFpbHPigKY8L2Rpdj5cclxuXHJcbiAgICAgIDwhLS1cclxuICAgICAgICBVc2UgKm5nRm9yICsgdHJhY2tCeSBrZXllZCBvbiAobG9vaywgc2xvdCwgbGlicmFyeSkgc28gQW5ndWxhciB0cmVhdHNcclxuICAgICAgICBhIHN3aXRjaCBhcyBhIG5ldyBpdGVtIOKAlCB0aGF0IGZvcmNlcyB0aGUgZW1iZWRkZWQgdGVtcGxhdGUtcHJvZHVjdHNcclxuICAgICAgICAvIHRlbXBsYXRlLXZtcyBjb21wb25lbnRzIHRvIHJlbW91bnQgYW5kIHJlcnVuIHRoZWlyIG5nT25Jbml0XHJcbiAgICAgICAgKG90aGVyd2lzZSB0aGVpciBgaXNQYWdlTG9hZGluZ2AgZ3VhcmQgc2tpcHMgdGhlIGZvcm0gcmVidWlsZCkuXHJcbiAgICAgIC0tPlxyXG4gICAgICA8bmctY29udGFpbmVyICpuZ0Zvcj1cImxldCBfIG9mIGVtYmVkZGVkSG9zdEtleXM7IHRyYWNrQnk6IHRyYWNrQnlFbWJlZGRlZEtleVwiPlxyXG4gICAgICAgIDx1bCBjbGFzcz1cIm5hdiBuYXYtdGFicyBjdXN0b20tdGFicyBtYi0zXCI+XHJcbiAgICAgICAgICA8bGkgY2xhc3M9XCJuYXYtaXRlbVwiPlxyXG4gICAgICAgICAgICA8YnV0dG9uIHR5cGU9XCJidXR0b25cIiBjbGFzcz1cIm5hdi1saW5rXCJcclxuICAgICAgICAgICAgICBbY2xhc3MuYWN0aXZlXT1cImVtYmVkZGVkVGFiID09PSAncHJvZHVjdHMnXCJcclxuICAgICAgICAgICAgICAoY2xpY2spPVwiZW1iZWRkZWRUYWIgPSAncHJvZHVjdHMnXCI+UHJvZHVjdCBNZXJjaGFuZGlzaW5nPC9idXR0b24+XHJcbiAgICAgICAgICA8L2xpPlxyXG4gICAgICAgICAgPGxpIGNsYXNzPVwibmF2LWl0ZW1cIj5cclxuICAgICAgICAgICAgPGJ1dHRvbiB0eXBlPVwiYnV0dG9uXCIgY2xhc3M9XCJuYXYtbGlua1wiXHJcbiAgICAgICAgICAgICAgW2NsYXNzLmFjdGl2ZV09XCJlbWJlZGRlZFRhYiA9PT0gJ3ZtcydcIlxyXG4gICAgICAgICAgICAgIChjbGljayk9XCJlbWJlZGRlZFRhYiA9ICd2bXMnXCI+VmlzdWFsIE1lcmNoYW5kaXNpbmc8L2J1dHRvbj5cclxuICAgICAgICAgIDwvbGk+XHJcbiAgICAgICAgPC91bD5cclxuXHJcbiAgICAgICAgPGRpdiAqbmdJZj1cImVtYmVkZGVkVGFiID09PSAncHJvZHVjdHMnXCI+XHJcbiAgICAgICAgICA8bGliLXRlbXBsYXRlLXByb2R1Y3RzIFtsb29rc01vZGVdPVwidHJ1ZVwiPjwvbGliLXRlbXBsYXRlLXByb2R1Y3RzPlxyXG4gICAgICAgIDwvZGl2PlxyXG4gICAgICAgIDxkaXYgKm5nSWY9XCJlbWJlZGRlZFRhYiA9PT0gJ3ZtcydcIj5cclxuICAgICAgICAgIDxsaWItdGVtcGxhdGUtdm1zIFtsb29rc01vZGVdPVwidHJ1ZVwiPjwvbGliLXRlbXBsYXRlLXZtcz5cclxuICAgICAgICA8L2Rpdj5cclxuICAgICAgPC9uZy1jb250YWluZXI+XHJcbiAgICA8L2Rpdj5cclxuICA8L25nLWNvbnRhaW5lcj5cclxuPC9zZWN0aW9uPlxyXG4iXX0=