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.
- package/esm2022/lib/components/chips-input/chips-input.component.mjs +101 -0
- package/esm2022/lib/components/collection-update-ai/find-replace-layout/prepare-template/prepare-template.component.mjs +2 -2
- package/esm2022/lib/components/create-fixture/create-fixture.component.mjs +66 -25
- package/esm2022/lib/components/create-vm/create-vm.component.mjs +2 -2
- package/esm2022/lib/components/fixture-template/template-basic-details/template-basic-details.component.mjs +1 -1
- package/esm2022/lib/components/fixture-template/template-products/template-products.component.mjs +15 -5
- package/esm2022/lib/components/fixture-template/template-vms/template-vms.component.mjs +31 -12
- package/esm2022/lib/components/fixture-template-table/popups/create-fixture-template/create-fixture-template.component.mjs +1 -1
- package/esm2022/lib/components/look-plano-collection/look-plano-collection.component.mjs +156 -0
- package/esm2022/lib/components/look-plano-collection-form/look-plano-collection-form.component.mjs +1204 -0
- package/esm2022/lib/components/manage-store-plano/manage-store-plano.component.mjs +1 -1
- package/esm2022/lib/components/manage-store-plano/plano-rollout/plano-rollout.component.mjs +1 -1
- package/esm2022/lib/components/manage-store-plano/template-basic-details/template-basic-details.component.mjs +1 -1
- package/esm2022/lib/components/manage-store-plano/template-products/template-products.component.mjs +2 -2
- package/esm2022/lib/components/manage-store-plano/template-vms/template-vms.component.mjs +2 -2
- package/esm2022/lib/components/manage-store-plano/verification-feedback/zone-editable-fixture/zone-editable-fixture.component.mjs +1 -1
- package/esm2022/lib/components/multiselect-chip-dropdown/multiselect-chip-dropdown.component.mjs +27 -4
- package/esm2022/lib/components/onboard-store-plano/create-planogram/create-planogram.component.mjs +2 -2
- package/esm2022/lib/components/onboard-store-plano/onboard-store-plano.component.mjs +1 -1
- package/esm2022/lib/components/plano-library/fixture-library/popups/create-fixture-modal/create-fixture-modal.component.mjs +1 -1
- package/esm2022/lib/components/plano-tools/delete-floor/delete-floor.component.mjs +3 -3
- package/esm2022/lib/components/plano-tools/move-bucket/move-bucket.component.mjs +1 -1
- package/esm2022/lib/components/plano-tools/swap-template/swap-template.component.mjs +1 -1
- package/esm2022/lib/components/planogram/plano-details-parent/plano-details-parent.component.mjs +1 -1
- package/esm2022/lib/components/planogram/plano-overview/plano-overview.component.mjs +1 -1
- package/esm2022/lib/components/popups/publish-plano-modal/publish-plano-modal.component.mjs +1 -1
- package/esm2022/lib/components/reactive-select/reactive-select.component.mjs +22 -3
- package/esm2022/lib/components/searchable-select/searchable-select.component.mjs +265 -0
- package/esm2022/lib/components/store-plano/store-plano.component.mjs +1 -1
- package/esm2022/lib/interfaces/fixture-library.interface.mjs +1 -1
- package/esm2022/lib/services/store-builder.service.mjs +28 -3
- package/esm2022/lib/tango-store-builder-routing.module.mjs +11 -1
- package/esm2022/lib/tango-store-builder.module.mjs +23 -4
- package/fesm2022/tango-app-ui-store-builder.mjs +1914 -69
- package/fesm2022/tango-app-ui-store-builder.mjs.map +1 -1
- package/lib/components/chips-input/chips-input.component.d.ts +35 -0
- package/lib/components/create-fixture/create-fixture.component.d.ts +3 -0
- package/lib/components/fixture-template/template-products/template-products.component.d.ts +9 -1
- package/lib/components/fixture-template/template-vms/template-vms.component.d.ts +9 -1
- package/lib/components/look-plano-collection/look-plano-collection.component.d.ts +53 -0
- package/lib/components/look-plano-collection-form/look-plano-collection-form.component.d.ts +237 -0
- package/lib/components/manage-plano/rollout-table/rollout-table.component.d.ts +4 -4
- package/lib/components/manage-plano/verification-table/verification-table.component.d.ts +5 -5
- package/lib/components/multiselect-chip-dropdown/multiselect-chip-dropdown.component.d.ts +12 -1
- package/lib/components/reactive-select/reactive-select.component.d.ts +12 -1
- package/lib/components/searchable-select/searchable-select.component.d.ts +56 -0
- package/lib/interfaces/fixture-library.interface.d.ts +1 -0
- package/lib/services/store-builder.service.d.ts +7 -1
- package/lib/tango-store-builder.module.d.ts +39 -34
- package/package.json +1 -1
package/esm2022/lib/components/look-plano-collection-form/look-plano-collection-form.component.mjs
ADDED
|
@@ -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=
|