ngx-dynamic-entity 0.0.1 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. package/README.md +139 -0
  2. package/esm2022/lib/field-types/array-field.component.mjs +160 -0
  3. package/esm2022/lib/field-types/boolean-field.component.mjs +100 -0
  4. package/esm2022/lib/field-types/checkbox-field.component.mjs +49 -41
  5. package/esm2022/lib/field-types/currency-field.component.mjs +101 -0
  6. package/esm2022/lib/field-types/date-field.component.mjs +47 -39
  7. package/esm2022/lib/field-types/dropdown-field.component.mjs +145 -54
  8. package/esm2022/lib/field-types/email-field.component.mjs +101 -0
  9. package/esm2022/lib/field-types/entity-ref-field.component.mjs +134 -70
  10. package/esm2022/lib/field-types/file-field.component.mjs +156 -0
  11. package/esm2022/lib/field-types/group-field.component.mjs +89 -0
  12. package/esm2022/lib/field-types/image-field.component.mjs +168 -0
  13. package/esm2022/lib/field-types/month-year-field.component.mjs +151 -0
  14. package/esm2022/lib/field-types/multi-select-field.component.mjs +110 -56
  15. package/esm2022/lib/field-types/number-field.component.mjs +84 -41
  16. package/esm2022/lib/field-types/password-field.component.mjs +109 -0
  17. package/esm2022/lib/field-types/radio-field.component.mjs +152 -0
  18. package/esm2022/lib/field-types/text-field.component.mjs +82 -42
  19. package/esm2022/lib/field-types/textarea-field.component.mjs +52 -41
  20. package/esm2022/lib/form/dynamic-field/dynamic-field.component.mjs +44 -26
  21. package/esm2022/lib/form/dynamic-form.component.mjs +501 -67
  22. package/esm2022/lib/form/dynamic-record-form.component.mjs +469 -0
  23. package/esm2022/lib/providers/provide-field-types.mjs +72 -0
  24. package/esm2022/lib/providers/provide-ngx-dynamic-entity.mjs +3 -5
  25. package/esm2022/lib/services/cascade-data.service.mjs +129 -0
  26. package/esm2022/lib/services/config-source.service.mjs +67 -0
  27. package/esm2022/lib/services/entity-ref-cache.mjs +20 -0
  28. package/esm2022/lib/services/entity-ref-registry.service.mjs +3 -3
  29. package/esm2022/lib/services/entity-ref-selection.service.mjs +27 -0
  30. package/esm2022/lib/services/entity-reference.service.mjs +168 -0
  31. package/esm2022/lib/services/field-registry.service.mjs +35 -30
  32. package/esm2022/lib/services/file-upload.service.mjs +89 -0
  33. package/esm2022/lib/services/lookup-registry.service.mjs +246 -0
  34. package/esm2022/lib/services/rbac.service.mjs +5 -11
  35. package/esm2022/lib/services/rules-evaluation.service.mjs +27 -0
  36. package/esm2022/lib/services/validator-registry.service.mjs +24 -7
  37. package/esm2022/lib/tokens/injection-tokens.mjs +88 -7
  38. package/esm2022/public-api.mjs +14 -5
  39. package/fesm2022/ngx-dynamic-entity.mjs +3985 -876
  40. package/fesm2022/ngx-dynamic-entity.mjs.map +1 -1
  41. package/lib/field-types/array-field.component.d.ts +22 -0
  42. package/lib/field-types/boolean-field.component.d.ts +18 -0
  43. package/lib/field-types/checkbox-field.component.d.ts +3 -2
  44. package/lib/field-types/currency-field.component.d.ts +17 -0
  45. package/lib/field-types/date-field.component.d.ts +3 -2
  46. package/lib/field-types/dropdown-field.component.d.ts +24 -4
  47. package/lib/field-types/email-field.component.d.ts +15 -0
  48. package/lib/field-types/entity-ref-field.component.d.ts +24 -11
  49. package/lib/field-types/file-field.component.d.ts +25 -0
  50. package/lib/field-types/group-field.component.d.ts +17 -0
  51. package/lib/field-types/image-field.component.d.ts +30 -0
  52. package/lib/field-types/month-year-field.component.d.ts +28 -0
  53. package/lib/field-types/multi-select-field.component.d.ts +18 -4
  54. package/lib/field-types/number-field.component.d.ts +5 -2
  55. package/lib/field-types/password-field.component.d.ts +17 -0
  56. package/lib/field-types/radio-field.component.d.ts +33 -0
  57. package/lib/field-types/text-field.component.d.ts +5 -3
  58. package/lib/field-types/textarea-field.component.d.ts +4 -2
  59. package/lib/form/dynamic-field/dynamic-field.component.d.ts +20 -7
  60. package/lib/form/dynamic-form.component.d.ts +111 -19
  61. package/lib/form/dynamic-record-form.component.d.ts +169 -0
  62. package/lib/providers/provide-field-types.d.ts +24 -0
  63. package/lib/providers/provide-ngx-dynamic-entity.d.ts +12 -7
  64. package/lib/services/cascade-data.service.d.ts +45 -0
  65. package/lib/services/config-source.service.d.ts +14 -0
  66. package/lib/services/entity-ref-cache.d.ts +27 -0
  67. package/lib/services/entity-ref-registry.service.d.ts +4 -3
  68. package/lib/services/entity-ref-selection.service.d.ts +24 -0
  69. package/lib/services/entity-reference.service.d.ts +49 -0
  70. package/lib/services/field-registry.service.d.ts +17 -7
  71. package/lib/services/file-upload.service.d.ts +27 -0
  72. package/lib/services/lookup-registry.service.d.ts +94 -0
  73. package/lib/services/rbac.service.d.ts +4 -9
  74. package/lib/services/rules-evaluation.service.d.ts +17 -0
  75. package/lib/services/validator-registry.service.d.ts +5 -4
  76. package/lib/tokens/injection-tokens.d.ts +90 -7
  77. package/package.json +14 -3
  78. package/public-api.d.ts +11 -4
  79. package/esm2022/lib/services/config.service.mjs +0 -58
  80. package/esm2022/lib/services/version.service.mjs +0 -40
  81. package/esm2022/lib/table/dynamic-table.component.mjs +0 -160
  82. package/lib/services/config.service.d.ts +0 -25
  83. package/lib/services/version.service.d.ts +0 -26
  84. package/lib/table/dynamic-table.component.d.ts +0 -56
@@ -1,130 +1,546 @@
1
- import { Component, Input, Output, EventEmitter, signal, inject, } from '@angular/core';
2
- import { FormBuilder, ReactiveFormsModule } from '@angular/forms';
1
+ import { Component, Input, Output, EventEmitter, signal, computed, inject, HostListener, } from '@angular/core';
2
+ import { NgComponentOutlet } from '@angular/common';
3
+ import { FormArray, FormBuilder, FormGroup, ReactiveFormsModule } from '@angular/forms';
4
+ import { debounceTime } from 'rxjs/operators';
5
+ import { applyAutoPatch, applyPatchOnTrue, evaluateFieldVisibility, findTab, getTabData, getTabPath, getValueByPath, normalizeArrayStructures, normalizeConfigOptions, resolveLabel, setTabData, setValueByPath, } from '@dynamic-entity/core';
3
6
  import { DynamicFieldComponent } from './dynamic-field/dynamic-field.component';
7
+ import { COMMON_MODULES_REGISTRY } from '../tokens/injection-tokens';
4
8
  import { ValidatorRegistryService } from '../services/validator-registry.service';
5
9
  import { HookRegistryService } from '../services/hook-registry.service';
6
- import { VersionService } from '../services/version.service';
7
10
  import { RbacService } from '../services/rbac.service';
11
+ import { RulesEvaluationService } from '../services/rules-evaluation.service';
12
+ import { EntityRefSelectionService } from '../services/entity-ref-selection.service';
8
13
  import * as i0 from "@angular/core";
9
14
  import * as i1 from "@angular/forms";
10
15
  /**
11
16
  * DynamicFormComponent — the main form component.
12
- * Renders a reactive form from EntityConfig with tab support, dependencies,
13
- * migration banner, and RBAC-gated submission.
14
- *
15
- * ONEHERMES pattern: isSaving state lock prevents subscription cyclones (ADR-002).
16
- * ONEHERMES bug fix: visibility rules re-evaluated after initialData loads (form-fixes doc).
17
- * ONEHERMES bug fix: use @for + @if separately, not both on same element (form-fixes doc).
17
+ * Renders a reactive form from EntityFormConfig with tab support, responsive 12-col grid,
18
+ * rules evaluation, conditional visibility, autoPatch/patchOnTrue, criticalField locking,
19
+ * keyboard shortcuts (Ctrl+S, Esc), and RBAC-gated submission.
18
20
  */
19
21
  export class DynamicFormComponent {
20
22
  // ─── Inputs ───────────────────────────────────────────────────────────────
21
23
  config;
24
+ rules;
22
25
  initialData;
26
+ /** Session-original values for `VALUE_CHANGED` rules. Captured from the first build when omitted. */
27
+ originalData;
23
28
  userRoles = [];
24
29
  language = 'en';
25
30
  readonly = false;
31
+ /** Field ids forced read-only while the rest of the form stays editable. */
32
+ readOnlyFields = [];
33
+ /**
34
+ * Render rule `info` banners inline. The record editor sets this false and renders its
35
+ * own dismissible versions, so the two do not double up.
36
+ */
37
+ showInfoBanners = true;
26
38
  loading = false;
27
39
  error = null;
40
+ /**
41
+ * Milliseconds to debounce `formChange`. The reference debounces at 300ms so a consumer
42
+ * re-rendering on every value change is not driven per keystroke. Zero emits
43
+ * synchronously, which the record editor relies on for its own bookkeeping.
44
+ */
45
+ changeDebounceMs = 0;
46
+ /**
47
+ * Preview mode: seed one empty row per `array` field so the structure is visible, then
48
+ * disable the form. Used by the builder's live preview.
49
+ */
50
+ preview = false;
28
51
  // ─── Outputs ──────────────────────────────────────────────────────────────
29
52
  formSubmit = new EventEmitter();
30
53
  formChange = new EventEmitter();
31
54
  formReset = new EventEmitter();
55
+ /** The visible tab changed. Lets a host track it without reaching into this component. */
56
+ activeTabChange = new EventEmitter();
32
57
  // ─── Services ─────────────────────────────────────────────────────────────
33
58
  fb = inject(FormBuilder);
34
59
  validatorRegistry = inject(ValidatorRegistryService);
35
60
  hookRegistry = inject(HookRegistryService);
36
- versionService = inject(VersionService);
37
61
  rbacService = inject(RbacService);
62
+ rulesEvaluation = inject(RulesEvaluationService);
63
+ entityRefSelection = inject(EntityRefSelectionService);
64
+ commonModulesRegistry = inject(COMMON_MODULES_REGISTRY, { optional: true });
65
+ Object = Object;
38
66
  // ─── Signals (local reactive state) ───────────────────────────────────────
39
67
  activeTab = signal('');
40
- isSaving = signal(false); // ADR-002: isSaving lock prevents API spam
68
+ activeSubTab = signal('');
69
+ isSaving = signal(false);
70
+ formValues = signal({});
71
+ /** Baseline captured at first build, used when `originalData` is not supplied. */
72
+ sessionBaseline = signal({});
73
+ /** Critical fields the user has explicitly unlocked for editing. */
74
+ unlockedFields = signal(new Set());
41
75
  // ─── Form ─────────────────────────────────────────────────────────────────
42
76
  form;
77
+ valueSub;
78
+ selectionSub;
79
+ /** Previous values, for detecting `patchOnTrue` false→true transitions. */
80
+ previousValues = {};
81
+ // ─── Keyboard Shortcuts ───────────────────────────────────────────────────
82
+ handleKeyboardEvent(event) {
83
+ if ((event.ctrlKey || event.metaKey) && event.key.toLowerCase() === 's') {
84
+ event.preventDefault();
85
+ if (!this.readonly && this.canSubmit && this.form?.valid) {
86
+ this.submit();
87
+ }
88
+ }
89
+ }
43
90
  // ─── Computed ─────────────────────────────────────────────────────────────
91
+ ruleResult = computed(() => this.rulesEvaluation.evaluate(this.rules, this.formValues(), this.baseline()));
92
+ /**
93
+ * Critical fields whose value differs from the session baseline.
94
+ * These drive the deferred `VALUE_CHANGED` banner — a critical edit is announced once,
95
+ * against the value the record had when the session started, not per keystroke.
96
+ */
97
+ changedCriticalFields = computed(() => {
98
+ const baseline = this.baseline();
99
+ if (!baseline || Object.keys(baseline).length === 0)
100
+ return [];
101
+ const values = this.formValues();
102
+ return this.allFields().filter(f => f.criticalField && !this.sameValue(values[f.id], baseline[f.id]));
103
+ });
44
104
  get tabs() {
45
- return (this.config?.tabs || []).sort((a, b) => a.order - b.order);
105
+ return this.config?.tabs || [];
46
106
  }
47
- get fieldsForActiveTab() {
107
+ get visibleTabs() {
108
+ const hidden = this.ruleResult().hiddenTabs;
109
+ return this.tabs.filter(tab => tab.visibility !== false && !hidden.includes(tab.id));
110
+ }
111
+ get activeTabConfig() {
48
112
  const tabId = this.activeTab();
49
- return (this.config?.fields || []).filter(f => {
50
- if (!this.tabs.length)
51
- return true; // No tabs — show all
52
- return f.tab === tabId || (!f.tab && tabId === this.tabs[0]?.id);
53
- });
113
+ if (!tabId)
114
+ return this.visibleTabs[0] ?? null;
115
+ return findTab(this.tabs, tabId);
116
+ }
117
+ get visibleSubTabs() {
118
+ const active = this.activeTabConfig;
119
+ if (!active?.children || active.children.length === 0)
120
+ return [];
121
+ const hidden = this.ruleResult().hiddenTabs;
122
+ return active.children.filter(tab => tab.visibility !== false && !hidden.includes(tab.id));
123
+ }
124
+ get activeSubTabConfig() {
125
+ const subTabs = this.visibleSubTabs;
126
+ if (!subTabs.length)
127
+ return null;
128
+ const subId = this.activeSubTab();
129
+ return subTabs.find(s => s.id === subId) ?? subTabs[0];
130
+ }
131
+ get activeTabModuleComponent() {
132
+ const active = this.activeSubTabConfig ?? this.activeTabConfig;
133
+ if (!active?.moduleName || !this.commonModulesRegistry)
134
+ return null;
135
+ const entry = this.commonModulesRegistry.find(m => m.id === active.moduleName || m.component === active.moduleName);
136
+ return entry ? entry.component : null;
137
+ }
138
+ get fieldsForActiveTab() {
139
+ const active = this.activeSubTabConfig ?? this.activeTabConfig;
140
+ if (active?.moduleName)
141
+ return [];
142
+ const rawFields = active ? (active.fields || []) : ((this.config?.tabs || []).flatMap(t => t.fields || []));
143
+ const currentValues = this.formValues();
144
+ const hiddenFields = this.ruleResult().hiddenFields;
145
+ return rawFields.filter(field => evaluateFieldVisibility(field, currentValues) && !hiddenFields.includes(field.id));
54
146
  }
55
147
  get permissions() {
56
148
  return this.rbacService.getPermissions(this.config, this.userRoles);
57
149
  }
58
- get needsMigration() {
59
- return this.versionService.needsMigration(this.initialData || {}, this.config);
60
- }
61
150
  get canSubmit() {
62
- return (this.permissions.canEdit &&
63
- !this.readonly &&
64
- !this.isSaving() &&
65
- !this.versionService.shouldBlockSubmit(this.initialData || {}, this.config));
151
+ return this.permissions.canEdit && !this.readonly;
152
+ }
153
+ ngOnInit() {
154
+ this.selectionSub = this.entityRefSelection.selection$.subscribe(({ fieldId, option }) => {
155
+ this.runAutoPatch(fieldId, option?.record);
156
+ });
66
157
  }
67
- // ─── Lifecycle ────────────────────────────────────────────────────────────
68
158
  ngOnChanges(changes) {
69
159
  if (changes['config'] && this.config) {
160
+ // Configs arrive as plain JSON from storage or an API, where TypeScript cannot enforce
161
+ // the option shape. Normalise here, at the library boundary, so everything downstream
162
+ // can rely on an option being a LocalizedText. Returns the same object when it already
163
+ // is, so a well-formed config costs nothing.
164
+ this.config = normalizeConfigOptions(this.config);
165
+ }
166
+ if (changes['config'] || changes['initialData']) {
70
167
  this.buildForm();
168
+ if (this.visibleTabs.length > 0 && !this.activeTab()) {
169
+ this.setActiveTab(this.visibleTabs[0].id);
170
+ }
71
171
  }
72
- // ONEHERMES fix: re-apply data after initialData loads (form-fixes doc)
73
- if (changes['initialData'] && this.form && this.initialData) {
74
- this.patchForm(this.initialData);
172
+ }
173
+ ngOnDestroy() {
174
+ this.valueSub?.unsubscribe();
175
+ this.selectionSub?.unsubscribe();
176
+ }
177
+ setActiveTab(tabId) {
178
+ if (this.activeTab() !== tabId)
179
+ this.activeTabChange.emit(tabId);
180
+ this.activeTab.set(tabId);
181
+ const parent = findTab(this.tabs, tabId);
182
+ if (parent?.children?.length) {
183
+ this.activeSubTab.set(parent.children[0].id);
75
184
  }
76
- if (changes['config'] && this.tabs.length) {
77
- this.activeTab.set(this.tabs[0]?.id || '');
185
+ else {
186
+ this.activeSubTab.set('');
78
187
  }
79
188
  }
189
+ setActiveSubTab(subTabId) {
190
+ this.activeSubTab.set(subTabId);
191
+ }
192
+ getFieldSpan(field) {
193
+ const span = field.colSpan ?? 12;
194
+ return `span ${Math.min(12, Math.max(1, span))}`;
195
+ }
196
+ // ─── criticalField locking ────────────────────────────────────────────────
197
+ /** A critical field stays read-only until the user deliberately unlocks it. */
198
+ isFieldLocked(field) {
199
+ return !!field.criticalField && !this.unlockedFields().has(field.id);
200
+ }
201
+ /**
202
+ * Whether this field renders read-only, from any of the four reasons: the whole form,
203
+ * the field's own flag, a caller-supplied `readOnlyFields` entry, or a criticalField lock.
204
+ */
205
+ isFieldReadonly(field) {
206
+ return (this.readonly ||
207
+ !!field.readonly ||
208
+ this.readOnlyFields.includes(field.id) ||
209
+ this.isFieldLocked(field));
210
+ }
211
+ toggleFieldLock(field) {
212
+ if (!field.criticalField || this.readonly)
213
+ return;
214
+ const next = new Set(this.unlockedFields());
215
+ if (next.has(field.id))
216
+ next.delete(field.id);
217
+ else
218
+ next.add(field.id);
219
+ this.unlockedFields.set(next);
220
+ }
221
+ resolveFieldLabel(field) {
222
+ return resolveLabel(field.label, this.language);
223
+ }
224
+ // ─── Form construction ────────────────────────────────────────────────────
80
225
  buildForm() {
81
- const controls = {};
82
- for (const field of this.config.fields || []) {
83
- if (field.isSystem)
84
- continue; // System fields not in form controls
85
- const validators = this.validatorRegistry.resolveAll(field.validators);
86
- controls[field.id] = [field.defaultValue ?? null, validators];
87
- }
88
- this.form = this.fb.group(controls);
89
- // Emit changes via formChange output
90
- this.form.valueChanges.subscribe(value => this.formChange.emit(value));
91
- // Apply initial data after form builds
226
+ if (!this.config)
227
+ return;
228
+ const group = {};
229
+ const buildTabControls = (tabs, parentGroup) => {
230
+ for (const tab of tabs) {
231
+ if (tab.flatData) {
232
+ for (const field of tab.fields || []) {
233
+ this.buildFieldControl(field, parentGroup);
234
+ }
235
+ if (tab.children)
236
+ buildTabControls(tab.children, parentGroup);
237
+ }
238
+ else {
239
+ const tabGroup = {};
240
+ for (const field of tab.fields || []) {
241
+ this.buildFieldControl(field, tabGroup);
242
+ }
243
+ if (tab.children)
244
+ buildTabControls(tab.children, tabGroup);
245
+ parentGroup[tab.id] = this.fb.group(tabGroup);
246
+ }
247
+ }
248
+ };
249
+ buildTabControls(this.config.tabs || [], group);
250
+ this.form = this.fb.group(group);
92
251
  if (this.initialData) {
93
252
  this.patchForm(this.initialData);
94
253
  }
95
- if (this.tabs.length && !this.activeTab()) {
96
- this.activeTab.set(this.tabs[0].id);
254
+ const initialFlattened = this.flattenFormValues();
255
+ this.formValues.set(initialFlattened);
256
+ this.previousValues = { ...initialFlattened };
257
+ this.sessionBaseline.set({ ...initialFlattened });
258
+ this.unlockedFields.set(new Set());
259
+ if (this.preview) {
260
+ // Show what an array field looks like rather than an empty slot, then freeze.
261
+ for (const field of this.allFields()) {
262
+ if (field.type !== 'array')
263
+ continue;
264
+ const array = this.getArrayControl(field.id);
265
+ if (array && array.length === 0)
266
+ array.push(this.buildArrayRow(field, undefined));
267
+ }
268
+ this.form.disable({ emitEvent: false });
269
+ }
270
+ // Rebuilding must not stack subscriptions on successive config/data changes.
271
+ this.valueSub?.unsubscribe();
272
+ const changes$ = this.changeDebounceMs > 0
273
+ ? this.form.valueChanges.pipe(debounceTime(this.changeDebounceMs))
274
+ : this.form.valueChanges;
275
+ this.valueSub = changes$.subscribe(() => {
276
+ const flattened = this.flattenFormValues();
277
+ this.formValues.set(flattened);
278
+ this.runPatchOnTrue(flattened);
279
+ this.previousValues = { ...flattened };
280
+ this.formChange.emit(this.extractRecord());
281
+ });
282
+ }
283
+ buildFieldControl(field, group) {
284
+ if (field.type === 'group') {
285
+ const subGroup = {};
286
+ for (const child of field.children || []) {
287
+ this.buildFieldControl(child, subGroup);
288
+ }
289
+ group[field.id] = this.fb.group(subGroup);
290
+ }
291
+ else if (field.type === 'array') {
292
+ group[field.id] = this.fb.array([]);
293
+ }
294
+ else {
295
+ const validators = this.validatorRegistry.resolveFromConfig(field.validators);
296
+ group[field.id] = this.fb.control({ value: field.defaultValue ?? null, disabled: field.disabled ?? false }, validators);
97
297
  }
98
298
  }
299
+ /** One row of an `array` field: a FormGroup when the field declares columns, else a bare control. */
300
+ /**
301
+ * The `FormArray` behind an `array` field, for callers that manage rows themselves —
302
+ * the record editor's inline row drawer.
303
+ */
304
+ getArrayControl(fieldId, tabId) {
305
+ const ctrl = this.getControl(fieldId, tabId);
306
+ return ctrl instanceof FormArray ? ctrl : null;
307
+ }
308
+ /**
309
+ * Build one detached row for an `array` field, with the field's own validators applied.
310
+ * Exposed so a row can be edited outside the form and pushed on save.
311
+ */
312
+ createArrayRow(field, value) {
313
+ return this.buildArrayRow(field, value);
314
+ }
315
+ buildArrayRow(field, item) {
316
+ if (!field?.children?.length)
317
+ return this.fb.control(item);
318
+ const rowGroup = {};
319
+ for (const child of field.children) {
320
+ this.buildFieldControl(child, rowGroup);
321
+ }
322
+ const group = this.fb.group(rowGroup);
323
+ if (item && typeof item === 'object')
324
+ group.patchValue(item);
325
+ return group;
326
+ }
99
327
  patchForm(data) {
100
- // Filter empty objects (ONEHERMES array field empty row bug fix)
101
- const cleanData = Object.fromEntries(Object.entries(data).filter(([, v]) => v !== undefined));
102
- this.form.patchValue(cleanData, { emitEvent: false });
328
+ if (!data || !this.form)
329
+ return;
330
+ const fieldsById = new Map(this.allFields().map(f => [f.id, f]));
331
+ const walkTabs = (tabs) => {
332
+ for (const tab of tabs) {
333
+ const tabData = getTabData(tab.id, data, this.config);
334
+ for (const field of tab.fields || []) {
335
+ let val = tabData && typeof tabData === 'object' ? tabData[field.id] : undefined;
336
+ if (field.refererField) {
337
+ const refVal = getValueByPath(data, field.refererField);
338
+ if (refVal !== undefined)
339
+ val = refVal;
340
+ }
341
+ if (val === undefined)
342
+ continue;
343
+ const ctrl = this.getControl(field.id, tab.id);
344
+ if (!ctrl)
345
+ continue;
346
+ if (ctrl instanceof FormArray && Array.isArray(val)) {
347
+ ctrl.clear();
348
+ for (const item of val) {
349
+ ctrl.push(this.buildArrayRow(fieldsById.get(field.id), item));
350
+ }
351
+ }
352
+ else {
353
+ ctrl.patchValue(val, { emitEvent: false });
354
+ }
355
+ }
356
+ if (tab.children)
357
+ walkTabs(tab.children);
358
+ }
359
+ };
360
+ walkTabs(this.config.tabs || []);
103
361
  }
104
- // ─── Actions ──────────────────────────────────────────────────────────────
105
- setActiveTab(tabId) {
106
- this.activeTab.set(tabId);
362
+ /** Assemble full nested record from per-tab FormGroups, respecting flatData, refererField & arrays. */
363
+ extractRecord() {
364
+ if (!this.form || !this.config)
365
+ return {};
366
+ let record = {};
367
+ const walkTabs = (tabs) => {
368
+ for (const tab of tabs) {
369
+ const fieldValBag = {};
370
+ for (const field of tab.fields || []) {
371
+ const ctrl = this.getControl(field.id, tab.id);
372
+ if (ctrl) {
373
+ fieldValBag[field.id] = ctrl.value;
374
+ }
375
+ }
376
+ setTabData(record, tab.id, fieldValBag, this.config);
377
+ for (const field of tab.fields || []) {
378
+ if (field.refererField) {
379
+ const ctrl = this.getControl(field.id, tab.id);
380
+ if (ctrl) {
381
+ setValueByPath(record, field.refererField, ctrl.value);
382
+ }
383
+ }
384
+ }
385
+ if (tab.children)
386
+ walkTabs(tab.children);
387
+ }
388
+ };
389
+ walkTabs(this.config.tabs || []);
390
+ record = normalizeArrayStructures(record, this.config);
391
+ return record;
392
+ }
393
+ flattenFormValues() {
394
+ const out = {};
395
+ for (const field of this.allFields()) {
396
+ const ctrl = this.getControl(field.id);
397
+ if (ctrl)
398
+ out[field.id] = ctrl.value;
399
+ }
400
+ return out;
401
+ }
402
+ getTabGroup(tabId) {
403
+ const path = getTabPath(this.config?.tabs, tabId);
404
+ if (!path || path.length === 0)
405
+ return this.form;
406
+ let curr = this.form;
407
+ for (const p of path) {
408
+ if (!curr || !(curr instanceof FormGroup))
409
+ return null;
410
+ curr = curr.get(p);
411
+ }
412
+ return curr instanceof FormGroup ? curr : null;
413
+ }
414
+ // ─── autoPatch / patchOnTrue ──────────────────────────────────────────────
415
+ /**
416
+ * `autoPatch` — copy mapped fields out of the record the user just selected in an
417
+ * entity-ref field into the configured target tab's controls.
418
+ */
419
+ runAutoPatch(fieldId, record) {
420
+ if (!record)
421
+ return;
422
+ const field = this.allFields().find(f => f.id === fieldId);
423
+ const autoPatch = field?.autoPatch;
424
+ if (!autoPatch)
425
+ return;
426
+ const patch = applyAutoPatch(autoPatch, record);
427
+ for (const [targetId, value] of Object.entries(patch)) {
428
+ const control = this.resolveTargetControl(autoPatch, targetId);
429
+ control?.patchValue(value);
430
+ }
431
+ }
432
+ /**
433
+ * `patchOnTrue` — when a boolean/checkbox field transitions to `true`,
434
+ * copy `from` → `to` within the current record.
435
+ */
436
+ runPatchOnTrue(values) {
437
+ for (const field of this.allFields()) {
438
+ const mappings = field.patchOnTrue;
439
+ if (!mappings?.length)
440
+ continue;
441
+ const wasTrue = this.previousValues[field.id] === true;
442
+ const isTrue = values[field.id] === true;
443
+ if (!isTrue || wasTrue)
444
+ continue;
445
+ const patch = applyPatchOnTrue(mappings, values);
446
+ for (const [targetId, value] of Object.entries(patch)) {
447
+ this.getControl(targetId)?.patchValue(value, { emitEvent: false });
448
+ }
449
+ }
450
+ }
451
+ /** Prefer a control declared on the configured target tab; fall back to a top-level control. */
452
+ resolveTargetControl(autoPatch, targetId) {
453
+ const tab = findTab(this.tabs, autoPatch.targetTab);
454
+ const inTargetTab = (tab?.fields ?? []).some(f => f.id === targetId);
455
+ if (tab && !inTargetTab)
456
+ return null;
457
+ return this.getControl(targetId, autoPatch.targetTab);
458
+ }
459
+ // ─── Helpers ──────────────────────────────────────────────────────────────
460
+ /** Every field in the config, including `group`/`array` children. */
461
+ allFields() {
462
+ const out = [];
463
+ const walkFields = (fields) => {
464
+ for (const f of fields ?? []) {
465
+ out.push(f);
466
+ if (f.children?.length)
467
+ walkFields(f.children);
468
+ }
469
+ };
470
+ const walkTabs = (tabs) => {
471
+ for (const t of tabs ?? []) {
472
+ walkFields(t.fields);
473
+ walkTabs(t.children);
474
+ }
475
+ };
476
+ walkTabs(this.config?.tabs);
477
+ return out;
478
+ }
479
+ /** An empty `originalData` counts as "not supplied" — fall back to the captured baseline. */
480
+ baseline() {
481
+ const supplied = this.originalData;
482
+ if (supplied && Object.keys(supplied).length > 0)
483
+ return supplied;
484
+ return this.sessionBaseline();
485
+ }
486
+ sameValue(a, b) {
487
+ if (a === b)
488
+ return true;
489
+ const aEmpty = a === null || a === undefined || a === '';
490
+ const bEmpty = b === null || b === undefined || b === '';
491
+ if (aEmpty && bEmpty)
492
+ return true;
493
+ if (typeof a === 'object' || typeof b === 'object') {
494
+ return JSON.stringify(a ?? null) === JSON.stringify(b ?? null);
495
+ }
496
+ return false;
497
+ }
498
+ getControl(fieldId, currentTabId) {
499
+ if (!this.form)
500
+ return null;
501
+ if (currentTabId) {
502
+ const tabGrp = this.getTabGroup(currentTabId);
503
+ const ctrl = tabGrp?.get(fieldId);
504
+ if (ctrl)
505
+ return ctrl;
506
+ }
507
+ const rootCtrl = this.form.get(fieldId);
508
+ if (rootCtrl)
509
+ return rootCtrl;
510
+ const findInGroup = (group) => {
511
+ for (const key of Object.keys(group.controls)) {
512
+ const c = group.controls[key];
513
+ if (key === fieldId)
514
+ return c;
515
+ if (c instanceof FormGroup) {
516
+ const found = findInGroup(c);
517
+ if (found)
518
+ return found;
519
+ }
520
+ }
521
+ return null;
522
+ };
523
+ return findInGroup(this.form);
524
+ }
525
+ resolveTabLabel(tab) {
526
+ return resolveLabel(tab.label, this.language);
107
527
  }
108
528
  async submit() {
109
529
  if (!this.canSubmit || this.form.invalid) {
110
530
  this.form.markAllAsTouched();
111
531
  return;
112
532
  }
113
- // ADR-002: isSaving lock — prevents subscription cyclones / duplicate API calls
114
- if (this.isSaving())
115
- return;
533
+ const rawData = this.extractRecord();
534
+ let processedData = rawData;
535
+ const hookKey = `${this.config?.entity}:beforeSave`;
536
+ if (this.hookRegistry.has(hookKey)) {
537
+ processedData = await this.hookRegistry.run(hookKey, processedData);
538
+ }
116
539
  this.isSaving.set(true);
117
540
  try {
118
- let data = { ...this.form.value };
119
- // Run pre-submit hook (Angular-side)
120
- data = await this.hookRegistry.run(`${this.config.entity}:beforeSave`, data, {
121
- config: this.config,
122
- userRoles: this.userRoles,
123
- });
124
- this.formSubmit.emit(data);
541
+ this.formSubmit.emit(processedData);
125
542
  }
126
543
  finally {
127
- // Reset saving lock in the consumer's success/error handler — here we just unblock
128
544
  this.isSaving.set(false);
129
545
  }
130
546
  }
@@ -132,36 +548,54 @@ export class DynamicFormComponent {
132
548
  this.form.reset();
133
549
  if (this.initialData)
134
550
  this.patchForm(this.initialData);
551
+ const values = this.flattenFormValues();
552
+ this.formValues.set(values);
553
+ this.previousValues = { ...values };
554
+ this.unlockedFields.set(new Set());
135
555
  this.formReset.emit();
136
556
  }
137
- getControl(fieldId) {
138
- return this.form?.get(fieldId);
139
- }
140
557
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: DynamicFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
141
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.12", type: DynamicFormComponent, isStandalone: true, selector: "ngx-dynamic-form", inputs: { config: "config", initialData: "initialData", userRoles: "userRoles", language: "language", readonly: "readonly", loading: "loading", error: "error" }, outputs: { formSubmit: "formSubmit", formChange: "formChange", formReset: "formReset" }, usesOnChanges: true, ngImport: i0, template: "<form [formGroup]=\"form\" (ngSubmit)=\"submit()\" class=\"ngx-form\" novalidate>\n\n <!-- Migration banner \u2014 visible in graceful mode when record is stale -->\n @if (needsMigration) {\n <div class=\"ngx-form__migration-banner\" role=\"alert\">\n \u26A0\uFE0F This record was created with an older configuration version.\n @if (versionService.shouldBlockSubmit(initialData || {}, config)) {\n Please run migration before editing.\n } @else {\n It will be updated to the latest version on save.\n }\n </div>\n }\n\n <!-- Error message -->\n @if (error) {\n <div class=\"ngx-form__error-banner\" role=\"alert\">{{ error }}</div>\n }\n\n <!-- Tab bar \u2014 only if tabs defined -->\n @if (tabs.length > 0) {\n <div class=\"ngx-form__tabs\" role=\"tablist\">\n <!-- ONEHERMES fix: @for and @if on separate elements, not same (form-fixes doc) -->\n @for (tab of tabs; track tab.id) {\n <button\n type=\"button\"\n class=\"ngx-form__tab\"\n [class.ngx-form__tab--active]=\"activeTab() === tab.id\"\n (click)=\"setActiveTab(tab.id)\"\n role=\"tab\"\n [attr.aria-selected]=\"activeTab() === tab.id\"\n >\n {{ tab.label[language] || tab.label['en'] }}\n </button>\n }\n </div>\n }\n\n <!-- Fields for active tab -->\n <div class=\"ngx-form__panel\">\n @for (field of fieldsForActiveTab; track field.id) {\n @if (field.visible !== false) {\n <ngx-dynamic-field\n [field]=\"field\"\n [control]=\"getControl(field.id)!\"\n [config]=\"config\"\n [language]=\"language\"\n [readonly]=\"readonly || !!field.readonly\"\n [userRoles]=\"userRoles\"\n />\n }\n }\n </div>\n\n <!-- Submit button \u2014 gated by RBAC and isSaving lock -->\n @if (!readonly && permissions.canEdit) {\n <div class=\"ngx-form__actions\">\n <button\n type=\"button\"\n class=\"ngx-form__reset\"\n (click)=\"reset()\"\n [disabled]=\"isSaving()\"\n >\n Reset\n </button>\n <button\n type=\"submit\"\n class=\"ngx-form__submit\"\n [disabled]=\"!canSubmit || form.invalid\"\n >\n @if (isSaving() || loading) {\n Saving\u2026\n } @else {\n Save\n }\n </button>\n </div>\n }\n\n</form>\n", dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: DynamicFieldComponent, selector: "ngx-dynamic-field", inputs: ["field", "control", "config", "language", "readonly", "userRoles"] }] });
558
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.12", type: DynamicFormComponent, isStandalone: true, selector: "ngx-dynamic-form", inputs: { config: "config", rules: "rules", initialData: "initialData", originalData: "originalData", userRoles: "userRoles", language: "language", readonly: "readonly", readOnlyFields: "readOnlyFields", showInfoBanners: "showInfoBanners", loading: "loading", error: "error", changeDebounceMs: "changeDebounceMs", preview: "preview" }, outputs: { formSubmit: "formSubmit", formChange: "formChange", formReset: "formReset", activeTabChange: "activeTabChange" }, host: { listeners: { "window:keydown": "handleKeyboardEvent($event)" } }, providers: [EntityRefSelectionService], usesOnChanges: true, ngImport: i0, template: "<form [formGroup]=\"form\" (ngSubmit)=\"submit()\" class=\"ngx-form\" novalidate>\r\n\r\n <!-- Error message banner -->\r\n @if (error) {\r\n <div class=\"ngx-form__error-banner\" role=\"alert\" data-testid=\"form-error\">{{ error }}</div>\r\n }\r\n\r\n <!-- Rules Info Banners -->\r\n @for (infoKey of showInfoBanners ? Object.keys(ruleResult().infoBanners) : []; track infoKey) {\r\n <div class=\"ngx-form__info-banner\" role=\"status\" [attr.data-testid]=\"'info-banner-' + infoKey\">\r\n \u2139\uFE0F {{ ruleResult().infoBanners[infoKey] }}\r\n </div>\r\n }\r\n\r\n <!-- Rules Validation Errors & Warnings -->\r\n @for (errKey of Object.keys(ruleResult().validationErrors); track errKey) {\r\n <div class=\"ngx-form__error-banner\" role=\"alert\" [attr.data-testid]=\"'rule-error-' + errKey\">\r\n \u26A0\uFE0F {{ ruleResult().validationErrors[errKey] }}\r\n </div>\r\n }\r\n @for (warnKey of Object.keys(ruleResult().validationWarnings); track warnKey) {\r\n <div class=\"ngx-form__warning-banner\" role=\"status\" [attr.data-testid]=\"'rule-warning-' + warnKey\">\r\n \u26A1 {{ ruleResult().validationWarnings[warnKey] }}\r\n </div>\r\n }\r\n\r\n <!-- Deferred VALUE_CHANGED notice for criticalField edits (vs session baseline) -->\r\n @if (changedCriticalFields().length > 0) {\r\n <div class=\"ngx-form__warning-banner\" role=\"status\" data-testid=\"critical-change-banner\">\r\n \uD83D\uDD12 Critical field changed:\r\n @for (field of changedCriticalFields(); track field.id) {\r\n <span>{{ resolveFieldLabel(field) }}{{ $last ? '' : ', ' }}</span>\r\n }\r\n \u2014 this differs from the value at the start of this session.\r\n </div>\r\n }\r\n\r\n <!-- Primary Tab bar \u2014 only if visible tabs defined -->\r\n @if (visibleTabs.length > 0) {\r\n <div class=\"ngx-form__tabs\" role=\"tablist\" data-testid=\"tab-strip\">\r\n @for (tab of visibleTabs; track tab.id) {\r\n <button\r\n type=\"button\"\r\n class=\"ngx-form__tab\"\r\n [attr.data-testid]=\"'tab-' + tab.id\"\r\n [class.ngx-form__tab--active]=\"activeTab() === tab.id\"\r\n (click)=\"setActiveTab(tab.id)\"\r\n role=\"tab\"\r\n [attr.aria-selected]=\"activeTab() === tab.id\"\r\n >\r\n {{ resolveTabLabel(tab) }}\r\n </button>\r\n }\r\n </div>\r\n }\r\n\r\n <!-- Sub-tab bar \u2014 only if active tab has sub-tabs -->\r\n @if (visibleSubTabs.length > 0) {\r\n <div class=\"ngx-form__tabs ngx-form__tabs--sub\" role=\"tablist\" data-testid=\"subtab-strip\" style=\"margin-top: -12px; margin-bottom: 12px; font-size: 13px;\">\r\n @for (subTab of visibleSubTabs; track subTab.id) {\r\n <button\r\n type=\"button\"\r\n class=\"ngx-form__tab ngx-form__tab--sub\"\r\n [attr.data-testid]=\"'subtab-' + subTab.id\"\r\n [class.ngx-form__tab--active]=\"(activeSubTabConfig?.id) === subTab.id\"\r\n (click)=\"setActiveSubTab(subTab.id)\"\r\n role=\"tab\"\r\n [attr.aria-selected]=\"(activeSubTabConfig?.id) === subTab.id\"\r\n >\r\n {{ resolveTabLabel(subTab) }}\r\n </button>\r\n }\r\n </div>\r\n }\r\n\r\n <!-- Module tab component OR Fields for active tab -->\r\n @if (activeTabModuleComponent) {\r\n <div class=\"ngx-form__module-panel\" data-testid=\"module-panel\">\r\n <ng-container *ngComponentOutlet=\"activeTabModuleComponent; inputs: (activeSubTabConfig || activeTabConfig)?.moduleInputs\"></ng-container>\r\n </div>\r\n } @else {\r\n <!-- Fields for active tab (Responsive 12-column grid) -->\r\n <div class=\"ngx-form__panel\" data-testid=\"form-panel\">\r\n @for (field of fieldsForActiveTab; track field.id) {\r\n <div\r\n class=\"ngx-form__field-slot\"\r\n [style.gridColumn]=\"getFieldSpan(field)\"\r\n [attr.id]=\"'field-container-' + field.id\"\r\n >\r\n <ngx-dynamic-field\r\n [field]=\"field\"\r\n [control]=\"getControl(field.id, (activeSubTabConfig || activeTabConfig)?.id)!\"\r\n [config]=\"config\"\r\n [currentTabId]=\"(activeSubTabConfig || activeTabConfig)?.id\"\r\n [language]=\"language\"\r\n [readonly]=\"isFieldReadonly(field)\"\r\n [userRoles]=\"userRoles\"\r\n />\r\n @if (field.criticalField && !readonly) {\r\n <button\r\n type=\"button\"\r\n class=\"ngx-form__lock\"\r\n [attr.data-testid]=\"'lock-' + field.id\"\r\n [attr.aria-pressed]=\"!isFieldLocked(field)\"\r\n [attr.aria-label]=\"\r\n (isFieldLocked(field) ? 'Unlock ' : 'Lock ') + resolveFieldLabel(field)\r\n \"\r\n [title]=\"\r\n isFieldLocked(field)\r\n ? 'Critical field \u2014 click to unlock for editing'\r\n : 'Critical field \u2014 click to lock'\r\n \"\r\n (click)=\"toggleFieldLock(field)\"\r\n >\r\n {{ isFieldLocked(field) ? '\uD83D\uDD12' : '\uD83D\uDD13' }}\r\n </button>\r\n }\r\n </div>\r\n }\r\n </div>\r\n }\r\n\r\n <!-- Submit button \u2014 gated by RBAC and isSaving lock -->\r\n @if (!readonly && permissions.canEdit) {\r\n <div class=\"ngx-form__actions\" data-testid=\"form-actions\">\r\n <button\r\n type=\"button\"\r\n class=\"ngx-form__reset\"\r\n data-testid=\"form-reset\"\r\n (click)=\"reset()\"\r\n [disabled]=\"isSaving()\"\r\n >\r\n Reset\r\n </button>\r\n <button\r\n type=\"submit\"\r\n class=\"ngx-form__submit\"\r\n data-testid=\"form-submit\"\r\n [disabled]=\"form.invalid\"\r\n title=\"Shortcut: Ctrl+S\"\r\n >\r\n @if (isSaving() || loading) {\r\n Saving\u2026\r\n } @else {\r\n Save\r\n }\r\n </button>\r\n </div>\r\n }\r\n\r\n</form>\r\n", styles: [".ngx-form__panel{display:grid;grid-template-columns:repeat(12,minmax(0,1fr));gap:16px 20px;align-items:start}.ngx-form__field-slot{display:flex;align-items:flex-start;gap:6px;min-width:0}.ngx-form__field-slot ngx-dynamic-field{flex:1;min-width:0}.ngx-form__lock{flex:0 0 auto;margin-top:22px;background:none;border:1px solid transparent;border-radius:6px;cursor:pointer;font-size:14px;line-height:1;padding:4px 6px}.ngx-form__lock:hover{border-color:#d1d5db;background:#f9fafb}@media (max-width: 768px){.ngx-form__panel{grid-template-columns:1fr}.ngx-form__field-slot{grid-column:span 12!important}}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: DynamicFieldComponent, selector: "ngx-dynamic-field", inputs: ["field", "control", "config", "currentTabId", "language", "readonly", "userRoles"] }, { kind: "directive", type: NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletContent", "ngComponentOutletNgModule", "ngComponentOutletNgModuleFactory"] }] });
142
559
  }
143
560
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: DynamicFormComponent, decorators: [{
144
561
  type: Component,
145
- args: [{ selector: 'ngx-dynamic-form', standalone: true, imports: [ReactiveFormsModule, DynamicFieldComponent], template: "<form [formGroup]=\"form\" (ngSubmit)=\"submit()\" class=\"ngx-form\" novalidate>\n\n <!-- Migration banner \u2014 visible in graceful mode when record is stale -->\n @if (needsMigration) {\n <div class=\"ngx-form__migration-banner\" role=\"alert\">\n \u26A0\uFE0F This record was created with an older configuration version.\n @if (versionService.shouldBlockSubmit(initialData || {}, config)) {\n Please run migration before editing.\n } @else {\n It will be updated to the latest version on save.\n }\n </div>\n }\n\n <!-- Error message -->\n @if (error) {\n <div class=\"ngx-form__error-banner\" role=\"alert\">{{ error }}</div>\n }\n\n <!-- Tab bar \u2014 only if tabs defined -->\n @if (tabs.length > 0) {\n <div class=\"ngx-form__tabs\" role=\"tablist\">\n <!-- ONEHERMES fix: @for and @if on separate elements, not same (form-fixes doc) -->\n @for (tab of tabs; track tab.id) {\n <button\n type=\"button\"\n class=\"ngx-form__tab\"\n [class.ngx-form__tab--active]=\"activeTab() === tab.id\"\n (click)=\"setActiveTab(tab.id)\"\n role=\"tab\"\n [attr.aria-selected]=\"activeTab() === tab.id\"\n >\n {{ tab.label[language] || tab.label['en'] }}\n </button>\n }\n </div>\n }\n\n <!-- Fields for active tab -->\n <div class=\"ngx-form__panel\">\n @for (field of fieldsForActiveTab; track field.id) {\n @if (field.visible !== false) {\n <ngx-dynamic-field\n [field]=\"field\"\n [control]=\"getControl(field.id)!\"\n [config]=\"config\"\n [language]=\"language\"\n [readonly]=\"readonly || !!field.readonly\"\n [userRoles]=\"userRoles\"\n />\n }\n }\n </div>\n\n <!-- Submit button \u2014 gated by RBAC and isSaving lock -->\n @if (!readonly && permissions.canEdit) {\n <div class=\"ngx-form__actions\">\n <button\n type=\"button\"\n class=\"ngx-form__reset\"\n (click)=\"reset()\"\n [disabled]=\"isSaving()\"\n >\n Reset\n </button>\n <button\n type=\"submit\"\n class=\"ngx-form__submit\"\n [disabled]=\"!canSubmit || form.invalid\"\n >\n @if (isSaving() || loading) {\n Saving\u2026\n } @else {\n Save\n }\n </button>\n </div>\n }\n\n</form>\n" }]
562
+ args: [{ selector: 'ngx-dynamic-form', standalone: true, imports: [ReactiveFormsModule, DynamicFieldComponent, NgComponentOutlet], providers: [EntityRefSelectionService], template: "<form [formGroup]=\"form\" (ngSubmit)=\"submit()\" class=\"ngx-form\" novalidate>\r\n\r\n <!-- Error message banner -->\r\n @if (error) {\r\n <div class=\"ngx-form__error-banner\" role=\"alert\" data-testid=\"form-error\">{{ error }}</div>\r\n }\r\n\r\n <!-- Rules Info Banners -->\r\n @for (infoKey of showInfoBanners ? Object.keys(ruleResult().infoBanners) : []; track infoKey) {\r\n <div class=\"ngx-form__info-banner\" role=\"status\" [attr.data-testid]=\"'info-banner-' + infoKey\">\r\n \u2139\uFE0F {{ ruleResult().infoBanners[infoKey] }}\r\n </div>\r\n }\r\n\r\n <!-- Rules Validation Errors & Warnings -->\r\n @for (errKey of Object.keys(ruleResult().validationErrors); track errKey) {\r\n <div class=\"ngx-form__error-banner\" role=\"alert\" [attr.data-testid]=\"'rule-error-' + errKey\">\r\n \u26A0\uFE0F {{ ruleResult().validationErrors[errKey] }}\r\n </div>\r\n }\r\n @for (warnKey of Object.keys(ruleResult().validationWarnings); track warnKey) {\r\n <div class=\"ngx-form__warning-banner\" role=\"status\" [attr.data-testid]=\"'rule-warning-' + warnKey\">\r\n \u26A1 {{ ruleResult().validationWarnings[warnKey] }}\r\n </div>\r\n }\r\n\r\n <!-- Deferred VALUE_CHANGED notice for criticalField edits (vs session baseline) -->\r\n @if (changedCriticalFields().length > 0) {\r\n <div class=\"ngx-form__warning-banner\" role=\"status\" data-testid=\"critical-change-banner\">\r\n \uD83D\uDD12 Critical field changed:\r\n @for (field of changedCriticalFields(); track field.id) {\r\n <span>{{ resolveFieldLabel(field) }}{{ $last ? '' : ', ' }}</span>\r\n }\r\n \u2014 this differs from the value at the start of this session.\r\n </div>\r\n }\r\n\r\n <!-- Primary Tab bar \u2014 only if visible tabs defined -->\r\n @if (visibleTabs.length > 0) {\r\n <div class=\"ngx-form__tabs\" role=\"tablist\" data-testid=\"tab-strip\">\r\n @for (tab of visibleTabs; track tab.id) {\r\n <button\r\n type=\"button\"\r\n class=\"ngx-form__tab\"\r\n [attr.data-testid]=\"'tab-' + tab.id\"\r\n [class.ngx-form__tab--active]=\"activeTab() === tab.id\"\r\n (click)=\"setActiveTab(tab.id)\"\r\n role=\"tab\"\r\n [attr.aria-selected]=\"activeTab() === tab.id\"\r\n >\r\n {{ resolveTabLabel(tab) }}\r\n </button>\r\n }\r\n </div>\r\n }\r\n\r\n <!-- Sub-tab bar \u2014 only if active tab has sub-tabs -->\r\n @if (visibleSubTabs.length > 0) {\r\n <div class=\"ngx-form__tabs ngx-form__tabs--sub\" role=\"tablist\" data-testid=\"subtab-strip\" style=\"margin-top: -12px; margin-bottom: 12px; font-size: 13px;\">\r\n @for (subTab of visibleSubTabs; track subTab.id) {\r\n <button\r\n type=\"button\"\r\n class=\"ngx-form__tab ngx-form__tab--sub\"\r\n [attr.data-testid]=\"'subtab-' + subTab.id\"\r\n [class.ngx-form__tab--active]=\"(activeSubTabConfig?.id) === subTab.id\"\r\n (click)=\"setActiveSubTab(subTab.id)\"\r\n role=\"tab\"\r\n [attr.aria-selected]=\"(activeSubTabConfig?.id) === subTab.id\"\r\n >\r\n {{ resolveTabLabel(subTab) }}\r\n </button>\r\n }\r\n </div>\r\n }\r\n\r\n <!-- Module tab component OR Fields for active tab -->\r\n @if (activeTabModuleComponent) {\r\n <div class=\"ngx-form__module-panel\" data-testid=\"module-panel\">\r\n <ng-container *ngComponentOutlet=\"activeTabModuleComponent; inputs: (activeSubTabConfig || activeTabConfig)?.moduleInputs\"></ng-container>\r\n </div>\r\n } @else {\r\n <!-- Fields for active tab (Responsive 12-column grid) -->\r\n <div class=\"ngx-form__panel\" data-testid=\"form-panel\">\r\n @for (field of fieldsForActiveTab; track field.id) {\r\n <div\r\n class=\"ngx-form__field-slot\"\r\n [style.gridColumn]=\"getFieldSpan(field)\"\r\n [attr.id]=\"'field-container-' + field.id\"\r\n >\r\n <ngx-dynamic-field\r\n [field]=\"field\"\r\n [control]=\"getControl(field.id, (activeSubTabConfig || activeTabConfig)?.id)!\"\r\n [config]=\"config\"\r\n [currentTabId]=\"(activeSubTabConfig || activeTabConfig)?.id\"\r\n [language]=\"language\"\r\n [readonly]=\"isFieldReadonly(field)\"\r\n [userRoles]=\"userRoles\"\r\n />\r\n @if (field.criticalField && !readonly) {\r\n <button\r\n type=\"button\"\r\n class=\"ngx-form__lock\"\r\n [attr.data-testid]=\"'lock-' + field.id\"\r\n [attr.aria-pressed]=\"!isFieldLocked(field)\"\r\n [attr.aria-label]=\"\r\n (isFieldLocked(field) ? 'Unlock ' : 'Lock ') + resolveFieldLabel(field)\r\n \"\r\n [title]=\"\r\n isFieldLocked(field)\r\n ? 'Critical field \u2014 click to unlock for editing'\r\n : 'Critical field \u2014 click to lock'\r\n \"\r\n (click)=\"toggleFieldLock(field)\"\r\n >\r\n {{ isFieldLocked(field) ? '\uD83D\uDD12' : '\uD83D\uDD13' }}\r\n </button>\r\n }\r\n </div>\r\n }\r\n </div>\r\n }\r\n\r\n <!-- Submit button \u2014 gated by RBAC and isSaving lock -->\r\n @if (!readonly && permissions.canEdit) {\r\n <div class=\"ngx-form__actions\" data-testid=\"form-actions\">\r\n <button\r\n type=\"button\"\r\n class=\"ngx-form__reset\"\r\n data-testid=\"form-reset\"\r\n (click)=\"reset()\"\r\n [disabled]=\"isSaving()\"\r\n >\r\n Reset\r\n </button>\r\n <button\r\n type=\"submit\"\r\n class=\"ngx-form__submit\"\r\n data-testid=\"form-submit\"\r\n [disabled]=\"form.invalid\"\r\n title=\"Shortcut: Ctrl+S\"\r\n >\r\n @if (isSaving() || loading) {\r\n Saving\u2026\r\n } @else {\r\n Save\r\n }\r\n </button>\r\n </div>\r\n }\r\n\r\n</form>\r\n", styles: [".ngx-form__panel{display:grid;grid-template-columns:repeat(12,minmax(0,1fr));gap:16px 20px;align-items:start}.ngx-form__field-slot{display:flex;align-items:flex-start;gap:6px;min-width:0}.ngx-form__field-slot ngx-dynamic-field{flex:1;min-width:0}.ngx-form__lock{flex:0 0 auto;margin-top:22px;background:none;border:1px solid transparent;border-radius:6px;cursor:pointer;font-size:14px;line-height:1;padding:4px 6px}.ngx-form__lock:hover{border-color:#d1d5db;background:#f9fafb}@media (max-width: 768px){.ngx-form__panel{grid-template-columns:1fr}.ngx-form__field-slot{grid-column:span 12!important}}\n"] }]
146
563
  }], propDecorators: { config: [{
147
564
  type: Input
565
+ }], rules: [{
566
+ type: Input
148
567
  }], initialData: [{
149
568
  type: Input
569
+ }], originalData: [{
570
+ type: Input
150
571
  }], userRoles: [{
151
572
  type: Input
152
573
  }], language: [{
153
574
  type: Input
154
575
  }], readonly: [{
155
576
  type: Input
577
+ }], readOnlyFields: [{
578
+ type: Input
579
+ }], showInfoBanners: [{
580
+ type: Input
156
581
  }], loading: [{
157
582
  type: Input
158
583
  }], error: [{
159
584
  type: Input
585
+ }], changeDebounceMs: [{
586
+ type: Input
587
+ }], preview: [{
588
+ type: Input
160
589
  }], formSubmit: [{
161
590
  type: Output
162
591
  }], formChange: [{
163
592
  type: Output
164
593
  }], formReset: [{
165
594
  type: Output
595
+ }], activeTabChange: [{
596
+ type: Output
597
+ }], handleKeyboardEvent: [{
598
+ type: HostListener,
599
+ args: ['window:keydown', ['$event']]
166
600
  }] } });
167
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZHluYW1pYy1mb3JtLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9saWIvZm9ybS9keW5hbWljLWZvcm0uY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vc3JjL2xpYi9mb3JtL2R5bmFtaWMtZm9ybS5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQ0wsU0FBUyxFQUNULEtBQUssRUFDTCxNQUFNLEVBQ04sWUFBWSxFQUdaLE1BQU0sRUFFTixNQUFNLEdBQ1AsTUFBTSxlQUFlLENBQUM7QUFDdkIsT0FBTyxFQUFFLFdBQVcsRUFBYSxtQkFBbUIsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBRTdFLE9BQU8sRUFBRSxxQkFBcUIsRUFBRSxNQUFNLHlDQUF5QyxDQUFDO0FBQ2hGLE9BQU8sRUFBRSx3QkFBd0IsRUFBRSxNQUFNLHdDQUF3QyxDQUFDO0FBQ2xGLE9BQU8sRUFBRSxtQkFBbUIsRUFBRSxNQUFNLG1DQUFtQyxDQUFDO0FBQ3hFLE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSw2QkFBNkIsQ0FBQztBQUM3RCxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sMEJBQTBCLENBQUM7OztBQUV2RDs7Ozs7Ozs7R0FRRztBQU9ILE1BQU0sT0FBTyxvQkFBb0I7SUFDL0IsNkVBQTZFO0lBQ3BFLE1BQU0sQ0FBZ0I7SUFDdEIsV0FBVyxDQUF1QjtJQUNsQyxTQUFTLEdBQWEsRUFBRSxDQUFDO0lBQ3pCLFFBQVEsR0FBVyxJQUFJLENBQUM7SUFDeEIsUUFBUSxHQUFZLEtBQUssQ0FBQztJQUMxQixPQUFPLEdBQVksS0FBSyxDQUFDO0lBQ3pCLEtBQUssR0FBa0IsSUFBSSxDQUFDO0lBRXJDLDZFQUE2RTtJQUNuRSxVQUFVLEdBQUcsSUFBSSxZQUFZLEVBQXVCLENBQUM7SUFDckQsVUFBVSxHQUFHLElBQUksWUFBWSxFQUF1QixDQUFDO0lBQ3JELFNBQVMsR0FBRyxJQUFJ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XG4gIEV2ZW50RW1pdHRlcixcbiAgT25DaGFuZ2VzLFxuICBTaW1wbGVDaGFuZ2VzLFxuICBzaWduYWwsXG4gIGNvbXB1dGVkLFxuICBpbmplY3QsXG59IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgRm9ybUJ1aWxkZXIsIEZvcm1Hcm91cCwgUmVhY3RpdmVGb3Jtc01vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL2Zvcm1zJztcbmltcG9ydCB0eXBlIHsgRW50aXR5Q29uZmlnLCBWZXJzaW9uZWRSZWNvcmQgfSBmcm9tICdAZHluYW1pYy1lbnRpdHkvY29yZSc7XG5pbXBvcnQgeyBEeW5hbWljRmllbGRDb21wb25lbnQgfSBmcm9tICcuL2R5bmFtaWMtZmllbGQvZHluYW1pYy1maWVsZC5jb21wb25lbnQnO1xuaW1wb3J0IHsgVmFsaWRhdG9yUmVnaXN0cnlTZXJ2aWNlIH0gZnJvbSAnLi4vc2VydmljZXMvdmFsaWRhdG9yLXJlZ2lzdHJ5LnNlcnZpY2UnO1xuaW1wb3J0IHsgSG9va1JlZ2lzdHJ5U2VydmljZSB9IGZyb20gJy4uL3NlcnZpY2VzL2hvb2stcmVnaXN0cnkuc2VydmljZSc7XG5pbXBvcnQgeyBWZXJzaW9uU2VydmljZSB9IGZyb20gJy4uL3NlcnZpY2VzL3ZlcnNpb24uc2VydmljZSc7XG5pbXBvcnQgeyBSYmFjU2VydmljZSB9IGZyb20gJy4uL3NlcnZpY2VzL3JiYWMuc2VydmljZSc7XG5cbi8qKlxuICogRHluYW1pY0Zvcm1Db21wb25lbnQg4oCUIHRoZSBtYWluIGZvcm0gY29tcG9uZW50LlxuICogUmVuZGVycyBhIHJlYWN0aXZlIGZvcm0gZnJvbSBFbnRpdHlDb25maWcgd2l0aCB0YWIgc3VwcG9ydCwgZGVwZW5kZW5jaWVzLFxuICogbWlncmF0aW9uIGJhbm5lciwgYW5kIFJCQUMtZ2F0ZWQgc3VibWlzc2lvbi5cbiAqXG4gKiBPTkVIRVJNRVMgcGF0dGVybjogaXNTYXZpbmcgc3RhdGUgbG9jayBwcmV2ZW50cyBzdWJzY3JpcHRpb24gY3ljbG9uZXMgKEFEUi0wMDIpLlxuICogT05FSEVSTUVTIGJ1ZyBmaXg6IHZpc2liaWxpdHkgcnVsZXMgcmUtZXZhbHVhdGVkIGFmdGVyIGluaXRpYWxEYXRhIGxvYWRzIChmb3JtLWZpeGVzIGRvYykuXG4gKiBPTkVIRVJNRVMgYnVnIGZpeDogdXNlIEBmb3IgKyBAaWYgc2VwYXJhdGVseSwgbm90IGJvdGggb24gc2FtZSBlbGVtZW50IChmb3JtLWZpeGVzIGRvYykuXG4gKi9cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ25neC1keW5hbWljLWZvcm0nLFxuICBzdGFuZGFsb25lOiB0cnVlLFxuICBpbXBvcnRzOiBbUmVhY3RpdmVGb3Jtc01vZHVsZSwgRHluYW1pY0ZpZWxkQ29tcG9uZW50XSxcbiAgdGVtcGxhdGVVcmw6ICcuL2R5bmFtaWMtZm9ybS5jb21wb25lbnQuaHRtbCcsXG59KVxuZXhwb3J0IGNsYXNzIER5bmFtaWNGb3JtQ29tcG9uZW50IGltcGxlbWVudHMgT25DaGFuZ2VzIHtcbiAgLy8g4pSA4pSA4pSAIElucHV0cyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcbiAgQElucHV0KCkgY29uZmlnITogRW50aXR5Q29uZmlnO1xuICBASW5wdXQoKSBpbml0aWFsRGF0YT86IFJlY29yZDxzdHJpbmcsIGFueT47XG4gIEBJbnB1dCgpIHVzZXJSb2xlczogc3RyaW5nW10gPSBbXTtcbiAgQElucHV0KCkgbGFuZ3VhZ2U6IHN0cmluZyA9ICdlbic7XG4gIEBJbnB1dCgpIHJlYWRvbmx5OiBib29sZWFuID0gZmFsc2U7XG4gIEBJbnB1dCgpIGxvYWRpbmc6IGJvb2xlYW4gPSBmYWxzZTtcbiAgQElucHV0KCkgZXJyb3I6IHN0cmluZyB8IG51bGwgPSBudWxsO1xuXG4gIC8vIOKUgOKUgOKUgCBPdXRwdXRzIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxuICBAT3V0cHV0KCkgZm9ybVN1Ym1pdCA9IG5ldyBFdmVudEVtaXR0ZXI8UmVjb3JkPHN0cmluZywgYW55Pj4oKTtcbiAgQE91dHB1dCgpIGZvcm1DaGFuZ2UgPSBuZXcgRXZlbnRFbWl0dGVyPFJlY29yZDxzdHJpbmcsIGFueT4+KCk7XG4gIEBPdXRwdXQoKSBmb3JtUmVzZXQgPSBuZXcgRXZlbnRFbWl0dGVyPHZvaWQ+KCk7XG5cbiAgLy8g4pSA4pSA4pSAIFNlcnZpY2VzIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxuICBwcml2YXRlIHJlYWRvbmx5IGZiID0gaW5qZWN0KEZvcm1CdWlsZGVyKTtcbiAgcHJpdmF0ZSByZWFkb25seSB2YWxpZGF0b3JSZWdpc3RyeSA9IGluamVjdChWYWxpZGF0b3JSZWdpc3RyeVNlcnZpY2UpO1xuICBwcml2YXRlIHJlYWRvbmx5IGhvb2tSZWdpc3RyeSA9IGluamVjdChIb29rUmVnaXN0cnlTZXJ2aWNlKTtcbiAgcHJvdGVjdGVkIHJlYWRvbmx5IHZlcnNpb25TZXJ2aWNlID0gaW5qZWN0KFZlcnNpb25TZXJ2aWNlKTtcbiAgcHJpdmF0ZSByZWFkb25seSByYmFjU2VydmljZSA9IGluamVjdChSYmFjU2VydmljZSk7XG5cbiAgLy8g4pSA4pSA4pSAIFNpZ25hbHMgKGxvY2FsIHJlYWN0aXZlIHN0YXRlKSDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcbiAgcmVhZG9ubHkgYWN0aXZlVGFiID0gc2lnbmFsPHN0cmluZz4oJycpO1xuICByZWFkb25seSBpc1NhdmluZyA9IHNpZ25hbChmYWxzZSk7IC8vIEFEUi0wMDI6IGlzU2F2aW5nIGxvY2sgcHJldmVudHMgQVBJIHNwYW1cblxuICAvLyDilIDilIDilIAgRm9ybSDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcbiAgZm9ybSE6IEZvcm1Hcm91cDtcblxuICAvLyDilIDilIDilIAgQ29tcHV0ZWQg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG4gIGdldCB0YWJzKCkge1xuICAgIHJldHVybiAodGhpcy5jb25maWc/LnRhYnMgfHwgW10pLnNvcnQoKGEsIGIpID0+IGEub3JkZXIgLSBiLm9yZGVyKTtcbiAgfVxuXG4gIGdldCBmaWVsZHNGb3JBY3RpdmVUYWIoKSB7XG4gICAgY29uc3QgdGFiSWQgPSB0aGlzLmFjdGl2ZVRhYigpO1xuICAgIHJldHVybiAodGhpcy5jb25maWc/LmZpZWxkcyB8fCBbXSkuZmlsdGVyKGYgPT4ge1xuICAgICAgaWYgKCF0aGlzLnRhYnMubGVuZ3RoKSByZXR1cm4gdHJ1ZTsgLy8gTm8gdGFicyDigJQgc2hvdyBhbGxcbiAgICAgIHJldHVybiBmLnRhYiA9PT0gdGFiSWQgfHwgKCFmLnRhYiAmJiB0YWJJZCA9PT0gdGhpcy50YWJzWzBdPy5pZCk7XG4gICAgfSk7XG4gIH1cblxuICBnZXQgcGVybWlzc2lvbnMoKSB7XG4gICAgcmV0dXJuIHRoaXMucmJhY1NlcnZpY2UuZ2V0UGVybWlzc2lvbnModGhpcy5jb25maWcsIHRoaXMudXNlclJvbGVzKTtcbiAgfVxuXG4gIGdldCBuZWVkc01pZ3JhdGlvbigpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy52ZXJzaW9uU2VydmljZS5uZWVkc01pZ3JhdGlvbih0aGlzLmluaXRpYWxEYXRhIHx8IHt9LCB0aGlzLmNvbmZpZyk7XG4gIH1cblxuICBnZXQgY2FuU3VibWl0KCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiAoXG4gICAgICB0aGlzLnBlcm1pc3Npb25zLmNhbkVkaXQgJiZcbiAgICAgICF0aGlzLnJlYWRvbmx5ICYmXG4gICAgICAhdGhpcy5pc1NhdmluZygpICYmXG4gICAgICAhdGhpcy52ZXJzaW9uU2VydmljZS5zaG91bGRCbG9ja1N1Ym1pdCh0aGlzLmluaXRpYWxEYXRhIHx8IHt9LCB0aGlzLmNvbmZpZylcbiAgICApO1xuICB9XG5cbiAgLy8g4pSA4pSA4pSAIExpZmVjeWNsZSDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcblxuICBuZ09uQ2hhbmdlcyhjaGFuZ2VzOiBTaW1wbGVDaGFuZ2VzKTogdm9pZCB7XG4gICAgaWYgKGNoYW5nZXNbJ2NvbmZpZyddICYmIHRoaXMuY29uZmlnKSB7XG4gICAgICB0aGlzLmJ1aWxkRm9ybSgpO1xuICAgIH1cbiAgICAvLyBPTkVIRVJNRVMgZml4OiByZS1hcHBseSBkYXRhIGFmdGVyIGluaXRpYWxEYXRhIGxvYWRzIChmb3JtLWZpeGVzIGRvYylcbiAgICBpZiAoY2hhbmdlc1snaW5pdGlhbERhdGEnXSAmJiB0aGlzLmZvcm0gJiYgdGhpcy5pbml0aWFsRGF0YSkge1xuICAgICAgdGhpcy5wYXRjaEZvcm0odGhpcy5pbml0aWFsRGF0YSk7XG4gICAgfVxuICAgIGlmIChjaGFuZ2VzWydjb25maWcnXSAmJiB0aGlzLnRhYnMubGVuZ3RoKSB7XG4gICAgICB0aGlzLmFjdGl2ZVRhYi5zZXQodGhpcy50YWJzWzBdPy5pZCB8fCAnJyk7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBidWlsZEZvcm0oKTogdm9pZCB7XG4gICAgY29uc3QgY29udHJvbHM6IFJlY29yZDxzdHJpbmcsIGFueT4gPSB7fTtcbiAgICBmb3IgKGNvbnN0IGZpZWxkIG9mIHRoaXMuY29uZmlnLmZpZWxkcyB8fCBbXSkge1xuICAgICAgaWYgKGZpZWxkLmlzU3lzdGVtKSBjb250aW51ZTsgLy8gU3lzdGVtIGZpZWxkcyBub3QgaW4gZm9ybSBjb250cm9sc1xuICAgICAgY29uc3QgdmFsaWRhdG9ycyA9IHRoaXMudmFsaWRhdG9yUmVnaXN0cnkucmVzb2x2ZUFsbChmaWVsZC52YWxpZGF0b3JzKTtcbiAgICAgIGNvbnRyb2xzW2ZpZWxkLmlkXSA9IFtmaWVsZC5kZWZhdWx0VmFsdWUgPz8gbnVsbCwgdmFsaWRhdG9yc107XG4gICAgfVxuICAgIHRoaXMuZm9ybSA9IHRoaXMuZmIuZ3JvdXAoY29udHJvbHMpO1xuXG4gICAgLy8gRW1pdCBjaGFuZ2VzIHZpYSBmb3JtQ2hhbmdlIG91dHB1dFxuICAgIHRoaXMuZm9ybS52YWx1ZUNoYW5nZXMuc3Vic2NyaWJlKHZhbHVlID0+IHRoaXMuZm9ybUNoYW5nZS5lbWl0KHZhbHVlKSk7XG5cbiAgICAvLyBBcHBseSBpbml0aWFsIGRhdGEgYWZ0ZXIgZm9ybSBidWlsZHNcbiAgICBpZiAodGhpcy5pbml0aWFsRGF0YSkge1xuICAgICAgdGhpcy5wYXRjaEZvcm0odGhpcy5pbml0aWFsRGF0YSk7XG4gICAgfVxuXG4gICAgaWYgKHRoaXMudGFicy5sZW5ndGggJiYgIXRoaXMuYWN0aXZlVGFiKCkpIHtcbiAgICAgIHRoaXMuYWN0aXZlVGFiLnNldCh0aGlzLnRhYnNbMF0uaWQpO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgcGF0Y2hGb3JtKGRhdGE6IFJlY29yZDxzdHJpbmcsIGFueT4pOiB2b2lkIHtcbiAgICAvLyBGaWx0ZXIgZW1wdHkgb2JqZWN0cyAoT05FSEVSTUVTIGFycmF5IGZpZWxkIGVtcHR5IHJvdyBidWcgZml4KVxuICAgIGNvbnN0IGNsZWFuRGF0YSA9IE9iamVjdC5mcm9tRW50cmllcyhcbiAgICAgIE9iamVjdC5lbnRyaWVzKGRhdGEpLmZpbHRlcigoWywgdl0pID0+IHYgIT09IHVuZGVmaW5lZCksXG4gICAgKTtcbiAgICB0aGlzLmZvcm0ucGF0Y2hWYWx1ZShjbGVhbkRhdGEsIHsgZW1pdEV2ZW50OiBmYWxzZSB9KTtcbiAgfVxuXG4gIC8vIOKUgOKUgOKUgCBBY3Rpb25zIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxuXG4gIHNldEFjdGl2ZVRhYih0YWJJZDogc3RyaW5nKTogdm9pZCB7XG4gICAgdGhpcy5hY3RpdmVUYWIuc2V0KHRhYklkKTtcbiAgfVxuXG4gIGFzeW5jIHN1Ym1pdCgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBpZiAoIXRoaXMuY2FuU3VibWl0IHx8IHRoaXMuZm9ybS5pbnZhbGlkKSB7XG4gICAgICB0aGlzLmZvcm0ubWFya0FsbEFzVG91Y2hlZCgpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIC8vIEFEUi0wMDI6IGlzU2F2aW5nIGxvY2sg4oCUIHByZXZlbnRzIHN1YnNjcmlwdGlvbiBjeWNsb25lcyAvIGR1cGxpY2F0ZSBBUEkgY2FsbHNcbiAgICBpZiAodGhpcy5pc1NhdmluZygpKSByZXR1cm47XG4gICAgdGhpcy5pc1NhdmluZy5zZXQodHJ1ZSk7XG5cbiAgICB0cnkge1xuICAgICAgbGV0IGRhdGEgPSB7IC4uLnRoaXMuZm9ybS52YWx1ZSB9O1xuXG4gICAgICAvLyBSdW4gcHJlLXN1Ym1pdCBob29rIChBbmd1bGFyLXNpZGUpXG4gICAgICBkYXRhID0gYXdhaXQgdGhpcy5ob29rUmVnaXN0cnkucnVuKGAke3RoaXMuY29uZmlnLmVudGl0eX06YmVmb3JlU2F2ZWAsIGRhdGEsIHtcbiAgICAgICAgY29uZmlnOiB0aGlzLmNvbmZpZyxcbiAgICAgICAgdXNlclJvbGVzOiB0aGlzLnVzZXJSb2xlcyxcbiAgICAgIH0pO1xuXG4gICAgICB0aGlzLmZvcm1TdWJtaXQuZW1pdChkYXRhKTtcbiAgICB9IGZpbmFsbHkge1xuICAgICAgLy8gUmVzZXQgc2F2aW5nIGxvY2sgaW4gdGhlIGNvbnN1bWVyJ3Mgc3VjY2Vzcy9lcnJvciBoYW5kbGVyIOKAlCBoZXJlIHdlIGp1c3QgdW5ibG9ja1xuICAgICAgdGhpcy5pc1NhdmluZy5zZXQoZmFsc2UpO1xuICAgIH1cbiAgfVxuXG4gIHJlc2V0KCk6IHZvaWQge1xuICAgIHRoaXMuZm9ybS5yZXNldCgpO1xuICAgIGlmICh0aGlzLmluaXRpYWxEYXRhKSB0aGlzLnBhdGNoRm9ybSh0aGlzLmluaXRpYWxEYXRhKTtcbiAgICB0aGlzLmZvcm1SZXNldC5lbWl0KCk7XG4gIH1cblxuICBnZXRDb250cm9sKGZpZWxkSWQ6IHN0cmluZykge1xuICAgIHJldHVybiB0aGlzLmZvcm0/LmdldChmaWVsZElkKTtcbiAgfVxufVxuIiwiPGZvcm0gW2Zvcm1Hcm91cF09XCJmb3JtXCIgKG5nU3VibWl0KT1cInN1Ym1pdCgpXCIgY2xhc3M9XCJuZ3gtZm9ybVwiIG5vdmFsaWRhdGU+XG5cbiAgPCEtLSBNaWdyYXRpb24gYmFubmVyIOKAlCB2aXNpYmxlIGluIGdyYWNlZnVsIG1vZGUgd2hlbiByZWNvcmQgaXMgc3RhbGUgLS0+XG4gIEBpZiAobmVlZHNNaWdyYXRpb24pIHtcbiAgICA8ZGl2IGNsYXNzPVwibmd4LWZvcm1fX21pZ3JhdGlvbi1iYW5uZXJcIiByb2xlPVwiYWxlcnRcIj5cbiAgICAgIOKaoO+4jyBUaGlzIHJlY29yZCB3YXMgY3JlYXRlZCB3aXRoIGFuIG9sZGVyIGNvbmZpZ3VyYXRpb24gdmVyc2lvbi5cbiAgICAgIEBpZiAodmVyc2lvblNlcnZpY2Uuc2hvdWxkQmxvY2tTdWJtaXQoaW5pdGlhbERhdGEgfHwge30sIGNvbmZpZykpIHtcbiAgICAgICAgUGxlYXNlIHJ1biBtaWdyYXRpb24gYmVmb3JlIGVkaXRpbmcuXG4gICAgICB9IEBlbHNlIHtcbiAgICAgICAgSXQgd2lsbCBiZSB1cGRhdGVkIHRvIHRoZSBsYXRlc3QgdmVyc2lvbiBvbiBzYXZlLlxuICAgICAgfVxuICAgIDwvZGl2PlxuICB9XG5cbiAgPCEtLSBFcnJvciBtZXNzYWdlIC0tPlxuICBAaWYgKGVycm9yKSB7XG4gICAgPGRpdiBjbGFzcz1cIm5neC1mb3JtX19lcnJvci1iYW5uZXJcIiByb2xlPVwiYWxlcnRcIj57eyBlcnJvciB9fTwvZGl2PlxuICB9XG5cbiAgPCEtLSBUYWIgYmFyIOKAlCBvbmx5IGlmIHRhYnMgZGVmaW5lZCAtLT5cbiAgQGlmICh0YWJzLmxlbmd0aCA+IDApIHtcbiAgICA8ZGl2IGNsYXNzPVwibmd4LWZvcm1fX3RhYnNcIiByb2xlPVwidGFibGlzdFwiPlxuICAgICAgPCEtLSBPTkVIRVJNRVMgZml4OiBAZm9yIGFuZCBAaWYgb24gc2VwYXJhdGUgZWxlbWVudHMsIG5vdCBzYW1lIChmb3JtLWZpeGVzIGRvYykgLS0+XG4gICAgICBAZm9yICh0YWIgb2YgdGFiczsgdHJhY2sgdGFiLmlkKSB7XG4gICAgICAgIDxidXR0b25cbiAgICAgICAgICB0eXBlPVwiYnV0dG9uXCJcbiAgICAgICAgICBjbGFzcz1cIm5neC1mb3JtX190YWJcIlxuICAgICAgICAgIFtjbGFzcy5uZ3gtZm9ybV9fdGFiLS1hY3RpdmVdPVwiYWN0aXZlVGFiKCkgPT09IHRhYi5pZFwiXG4gICAgICAgICAgKGNsaWNrKT1cInNldEFjdGl2ZVRhYih0YWIuaWQpXCJcbiAgICAgICAgICByb2xlPVwidGFiXCJcbiAgICAgICAgICBbYXR0ci5hcmlhLXNlbGVjdGVkXT1cImFjdGl2ZVRhYigpID09PSB0YWIuaWRcIlxuICAgICAgICA+XG4gICAgICAgICAge3sgdGFiLmxhYmVsW2xhbmd1YWdlXSB8fCB0YWIubGFiZWxbJ2VuJ10gfX1cbiAgICAgICAgPC9idXR0b24+XG4gICAgICB9XG4gICAgPC9kaXY+XG4gIH1cblxuICA8IS0tIEZpZWxkcyBmb3IgYWN0aXZlIHRhYiAtLT5cbiAgPGRpdiBjbGFzcz1cIm5neC1mb3JtX19wYW5lbFwiPlxuICAgIEBmb3IgKGZpZWxkIG9mIGZpZWxkc0ZvckFjdGl2ZVRhYjsgdHJhY2sgZmllbGQuaWQpIHtcbiAgICAgIEBpZiAoZmllbGQudmlzaWJsZSAhPT0gZmFsc2UpIHtcbiAgICAgICAgPG5neC1keW5hbWljLWZpZWxkXG4gICAgICAgICAgW2ZpZWxkXT1cImZpZWxkXCJcbiAgICAgICAgICBbY29udHJvbF09XCJnZXRDb250cm9sKGZpZWxkLmlkKSFcIlxuICAgICAgICAgIFtjb25maWddPVwiY29uZmlnXCJcbiAgICAgICAgICBbbGFuZ3VhZ2VdPVwibGFuZ3VhZ2VcIlxuICAgICAgICAgIFtyZWFkb25seV09XCJyZWFkb25seSB8fCAhIWZpZWxkLnJlYWRvbmx5XCJcbiAgICAgICAgICBbdXNlclJvbGVzXT1cInVzZXJSb2xlc1wiXG4gICAgICAgIC8+XG4gICAgICB9XG4gICAgfVxuICA8L2Rpdj5cblxuICA8IS0tIFN1Ym1pdCBidXR0b24g4oCUIGdhdGVkIGJ5IFJCQUMgYW5kIGlzU2F2aW5nIGxvY2sgLS0+XG4gIEBpZiAoIXJlYWRvbmx5ICYmIHBlcm1pc3Npb25zLmNhbkVkaXQpIHtcbiAgICA8ZGl2IGNsYXNzPVwibmd4LWZvcm1fX2FjdGlvbnNcIj5cbiAgICAgIDxidXR0b25cbiAgICAgICAgdHlwZT1cImJ1dHRvblwiXG4gICAgICAgIGNsYXNzPVwibmd4LWZvcm1fX3Jlc2V0XCJcbiAgICAgICAgKGNsaWNrKT1cInJlc2V0KClcIlxuICAgICAgICBbZGlzYWJsZWRdPVwiaXNTYXZpbmcoKVwiXG4gICAgICA+XG4gICAgICAgIFJlc2V0XG4gICAgICA8L2J1dHRvbj5cbiAgICAgIDxidXR0b25cbiAgICAgICAgdHlwZT1cInN1Ym1pdFwiXG4gICAgICAgIGNsYXNzPVwibmd4LWZvcm1fX3N1Ym1pdFwiXG4gICAgICAgIFtkaXNhYmxlZF09XCIhY2FuU3VibWl0IHx8IGZvcm0uaW52YWxpZFwiXG4gICAgICA+XG4gICAgICAgIEBpZiAoaXNTYXZpbmcoKSB8fCBsb2FkaW5nKSB7XG4gICAgICAgICAgU2F2aW5n4oCmXG4gICAgICAgIH0gQGVsc2Uge1xuICAgICAgICAgIFNhdmVcbiAgICAgICAgfVxuICAgICAgPC9idXR0b24+XG4gICAgPC9kaXY+XG4gIH1cblxuPC9mb3JtPlxuIl19
601
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZHluYW1pYy1mb3JtLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9saWIvZm9ybS9keW5hbWljLWZvcm0uY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vc3JjL2xpYi9mb3JtL2R5bmFtaWMtZm9ybS5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQ0wsU0FBUyxFQUNULEtBQUssRUFDTCxNQUFNLEVBQ04sWUFBWSxFQUtaLE1BQU0sRUFDTixRQUFRLEVBQ1IsTUFBTSxFQUNOLFlBQVksR0FDYixNQUFNLGVBQWUsQ0FBQztBQUN2QixPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUNwRCxPQUFPLEVBQW1CLFNBQVMsRUFBRSxXQUFXLEVBQUUsU0FBUyxFQUFFLG1CQUFtQixFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFFekcsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBUTlDLE9BQU8sRUFDTCxjQUFjLEVBQ2QsZ0JBQWdCLEVBQ2hCLHVCQUF1QixFQUN2QixPQUFPLEVBQ1AsVUFBVSxFQUNWLFVBQVUsRUFDVixjQUFjLEVBQ2Qsd0JBQXdCLEVBQ3hCLHNCQUFzQixFQUN0QixZQUFZLEVBQ1osVUFBVSxFQUNWLGNBQWMsR0FDZixNQUFNLHNCQUFzQixDQUFDO0FBQzlCLE9BQU8sRUFBRSxxQkFBcUIsRUFBRSxNQUFNLHlDQUF5QyxDQUFDO0FBQ2hGLE9BQU8sRUFBRSx1QkFBdUIsRUFBRSxNQUFNLDRCQUE0QixDQUFDO0FBQ3JFLE9BQU8sRUFBRSx3QkFBd0IsRUFBRSxNQUFNLHdDQUF3QyxDQUFDO0FBQ2xGLE9BQU8sRUFBRSxtQkFBbUIsRUFBRSxNQUFNLG1DQUFtQyxDQUFDO0FBQ3hFLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQUN2RCxPQUFPLEVBQUUsc0JBQXNCLEVBQUUsTUFB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UUFBUSxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcclxuICBDb21wb25lbnQsXHJcbiAgSW5wdXQsXHJcbiAgT3V0cHV0LFxyXG4gIEV2ZW50RW1pdHRlcixcclxuICBPbkNoYW5nZXMsXHJcbiAgT25EZXN0cm95LFxyXG4gIE9uSW5pdCxcclxuICBTaW1wbGVDaGFuZ2VzLFxyXG4gIHNpZ25hbCxcclxuICBjb21wdXRlZCxcclxuICBpbmplY3QsXHJcbiAgSG9zdExpc3RlbmVyLFxyXG59IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xyXG5pbXBvcnQgeyBOZ0NvbXBvbmVudE91dGxldCB9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbic7XHJcbmltcG9ydCB7IEFic3RyYWN0Q29udHJvbCwgRm9ybUFycmF5LCBGb3JtQnVpbGRlciwgRm9ybUdyb3VwLCBSZWFjdGl2ZUZvcm1zTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvZm9ybXMnO1xyXG5pbXBvcnQgeyBTdWJzY3JpcHRpb24gfSBmcm9tICdyeGpzJztcclxuaW1wb3J0IHsgZGVib3VuY2VUaW1lIH0gZnJvbSAncnhqcy9vcGVyYXRvcnMnO1xyXG5pbXBvcnQgdHlwZSB7XHJcbiAgQXV0b1BhdGNoQ29uZmlnLFxyXG4gIEVudGl0eUZvcm1Db25maWcsXHJcbiAgRm9ybVJ1bGUsXHJcbiAgTmVzdGVkRmllbGRDb25maWcsXHJcbiAgTmVzdGVkVGFiQ29uZmlnLFxyXG59IGZyb20gJ0BkeW5hbWljLWVudGl0eS9jb3JlJztcclxuaW1wb3J0IHtcclxuICBhcHBseUF1dG9QYXRjaCxcclxuICBhcHBseVBhdGNoT25UcnVlLFxyXG4gIGV2YWx1YXRlRmllbGRWaXNpYmlsaXR5LFxyXG4gIGZpbmRUYWIsXHJcbiAgZ2V0VGFiRGF0YSxcclxuICBnZXRUYWJQYXRoLFxyXG4gIGdldFZhbHVlQnlQYXRoLFxyXG4gIG5vcm1hbGl6ZUFycmF5U3RydWN0dXJlcyxcclxuICBub3JtYWxpemVDb25maWdPcHRpb25zLFxyXG4gIHJlc29sdmVMYWJlbCxcclxuICBzZXRUYWJEYXRhLFxyXG4gIHNldFZhbHVlQnlQYXRoLFxyXG59IGZyb20gJ0BkeW5hbWljLWVudGl0eS9jb3JlJztcclxuaW1wb3J0IHsgRHluYW1pY0ZpZWxkQ29tcG9uZW50IH0gZnJvbSAnLi9keW5hbWljLWZpZWxkL2R5bmFtaWMtZmllbGQuY29tcG9uZW50JztcclxuaW1wb3J0IHsgQ09NTU9OX01PRFVMRVNfUkVHSVNUUlkgfSBmcm9tICcuLi90b2tlbnMvaW5qZWN0aW9uLXRva2Vucyc7XHJcbmltcG9ydCB7IFZhbGlkYXRvclJlZ2lzdHJ5U2VydmljZSB9IGZyb20gJy4uL3NlcnZpY2VzL3ZhbGlkYXRvci1yZWdpc3RyeS5zZXJ2aWNlJztcclxuaW1wb3J0IHsgSG9va1JlZ2lzdHJ5U2VydmljZSB9IGZyb20gJy4uL3NlcnZpY2VzL2hvb2stcmVnaXN0cnkuc2VydmljZSc7XHJcbmltcG9ydCB7IFJiYWNTZXJ2aWNlIH0gZnJvbSAnLi4vc2VydmljZXMvcmJhYy5zZXJ2aWNlJztcclxuaW1wb3J0IHsgUnVsZXNFdmFsdWF0aW9uU2VydmljZSB9IGZyb20gJy4uL3NlcnZpY2VzL3J1bGVzLWV2YWx1YXRpb24uc2VydmljZSc7XHJcbmltcG9ydCB7IEVudGl0eVJlZlNlbGVjdGlvblNlcnZpY2UgfSBmcm9tICcuLi9zZXJ2aWNlcy9lbnRpdHktcmVmLXNlbGVjdGlvbi5zZXJ2aWNlJztcclxuXHJcbi8qKlxyXG4gKiBEeW5hbWljRm9ybUNvbXBvbmVudCDigJQgdGhlIG1haW4gZm9ybSBjb21wb25lbnQuXHJcbiAqIFJlbmRlcnMgYSByZWFjdGl2ZSBmb3JtIGZyb20gRW50aXR5Rm9ybUNvbmZpZyB3aXRoIHRhYiBzdXBwb3J0LCByZXNwb25zaXZlIDEyLWNvbCBncmlkLFxyXG4gKiBydWxlcyBldmFsdWF0aW9uLCBjb25kaXRpb25hbCB2aXNpYmlsaXR5LCBhdXRvUGF0Y2gvcGF0Y2hPblRydWUsIGNyaXRpY2FsRmllbGQgbG9ja2luZyxcclxuICoga2V5Ym9hcmQgc2hvcnRjdXRzIChDdHJsK1MsIEVzYyksIGFuZCBSQkFDLWdhdGVkIHN1Ym1pc3Npb24uXHJcbiAqL1xyXG5AQ29tcG9uZW50KHtcclxuICBzZWxlY3RvcjogJ25neC1keW5hbWljLWZvcm0nLFxyXG4gIHN0YW5kYWxvbmU6IHRydWUsXHJcbiAgaW1wb3J0czogW1JlYWN0aXZlRm9ybXNNb2R1bGUsIER5bmFtaWNGaWVsZENvbXBvbmVudCwgTmdDb21wb25lbnRPdXRsZXRdLFxyXG4gIC8vIFNjb3BlZCBwZXIgZm9ybSBpbnN0YW5jZTogZW50aXR5LXJlZiBzZWxlY3Rpb25zIG11c3Qgbm90IGxlYWsgYmV0d2VlbiBjb25jdXJyZW50IGZvcm1zLlxyXG4gIHByb3ZpZGVyczogW0VudGl0eVJlZlNlbGVjdGlvblNlcnZpY2VdLFxyXG4gIHRlbXBsYXRlVXJsOiAnLi9keW5hbWljLWZvcm0uY29tcG9uZW50Lmh0bWwnLFxyXG4gIHN0eWxlczogW1xyXG4gICAgYFxyXG4gICAgICAubmd4LWZvcm1fX3BhbmVsIHtcclxuICAgICAgICBkaXNwbGF5OiBncmlkO1xyXG4gICAgICAgIGdyaWQtdGVtcGxhdGUtY29sdW1uczogcmVwZWF0KDEyLCBtaW5tYXgoMCwgMWZyKSk7XHJcbiAgICAgICAgZ2FwOiAxNnB4IDIwcHg7XHJcbiAgICAgICAgYWxpZ24taXRlbXM6IHN0YXJ0O1xyXG4gICAgICB9XHJcbiAgICAgIC5uZ3gtZm9ybV9fZmllbGQtc2xvdCB7XHJcbiAgICAgICAgZGlzcGxheTogZmxleDtcclxuICAgICAgICBhbGlnbi1pdGVtczogZmxleC1zdGFydDtcclxuICAgICAgICBnYXA6IDZweDtcclxuICAgICAgICBtaW4td2lkdGg6IDA7XHJcbiAgICAgIH1cclxuICAgICAgLm5neC1mb3JtX19maWVsZC1zbG90IG5neC1keW5hbWljLWZpZWxkIHtcclxuICAgICAgICBmbGV4OiAxO1xyXG4gICAgICAgIG1pbi13aWR0aDogMDtcclxuICAgICAgfVxyXG4gICAgICAubmd4LWZvcm1fX2xvY2sge1xyXG4gICAgICAgIGZsZXg6IDAgMCBhdXRvO1xyXG4gICAgICAgIG1hcmdpbi10b3A6IDIycHg7XHJcbiAgICAgICAgYmFja2dyb3VuZDogbm9uZTtcclxuICAgICAgICBib3JkZXI6IDFweCBzb2xpZCB0cmFuc3BhcmVudDtcclxuICAgICAgICBib3JkZXItcmFkaXVzOiA2cHg7XHJcbiAgICAgICAgY3Vyc29yOiBwb2ludGVyO1xyXG4gICAgICAgIGZvbnQtc2l6ZTogMTRweDtcclxuICAgICAgICBsaW5lLWhlaWdodDogMTtcclxuICAgICAgICBwYWRkaW5nOiA0cHggNnB4O1xyXG4gICAgICB9XHJcbiAgICAgIC5uZ3gtZm9ybV9fbG9jazpob3ZlciB7XHJcbiAgICAgICAgYm9yZGVyLWNvbG9yOiAjZDFkNWRiO1xyXG4gICAgICAgIGJhY2tncm91bmQ6ICNmOWZhZmI7XHJcbiAgICAgIH1cclxuICAgICAgQG1lZGlhIChtYXgtd2lkdGg6IDc2OHB4KSB7XHJcbiAgICAgICAgLm5neC1mb3JtX19wYW5lbCB7XHJcbiAgICAgICAgICBncmlkLXRlbXBsYXRlLWNvbHVtbnM6IDFmcjtcclxuICAgICAgICB9XHJcbiAgICAgICAgLm5neC1mb3JtX19maWVsZC1zbG90IHtcclxuICAgICAgICAgIGdyaWQtY29sdW1uOiBzcGFuIDEyICFpbXBvcnRhbnQ7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICBgLFxyXG4gIF0sXHJcbn0pXHJcbmV4cG9ydCBjbGFzcyBEeW5hbWljRm9ybUNvbXBvbmVudCBpbXBsZW1lbnRzIE9uSW5pdCwgT25DaGFuZ2VzLCBPbkRlc3Ryb3kge1xyXG4gIC8vIOKUgOKUgOKUgCBJbnB1dHMg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXHJcbiAgQElucHV0KCkgY29uZmlnITogRW50aXR5Rm9ybUNvbmZpZztcclxuICBASW5wdXQoKSBydWxlcz86IEZvcm1SdWxlW107XHJcbiAgQElucHV0KCkgaW5pdGlhbERhdGE/OiBSZWNvcmQ8c3RyaW5nLCBhbnk+O1xyXG4gIC8qKiBTZXNzaW9uLW9yaWdpbmFsIHZhbHVlcyBmb3IgYFZBTFVFX0NIQU5HRURgIHJ1bGVzLiBDYXB0dXJlZCBmcm9tIHRoZSBmaXJzdCBidWlsZCB3aGVuIG9taXR0ZWQuICovXHJcbiAgQElucHV0KCkgb3JpZ2luYWxEYXRhPzogUmVjb3JkPHN0cmluZywgYW55PjtcclxuICBASW5wdXQoKSB1c2VyUm9sZXM6IHN0cmluZ1tdID0gW107XHJcbiAgQElucHV0KCkgbGFuZ3VhZ2U6IHN0cmluZyA9ICdlbic7XHJcbiAgQElucHV0KCkgcmVhZG9ubHk6IGJvb2xlYW4gPSBmYWxzZTtcclxuICAvKiogRmllbGQgaWRzIGZvcmNlZCByZWFkLW9ubHkgd2hpbGUgdGhlIHJlc3Qgb2YgdGhlIGZvcm0gc3RheXMgZWRpdGFibGUuICovXHJcbiAgQElucHV0KCkgcmVhZE9ubHlGaWVsZHM6IHN0cmluZ1tdID0gW107XHJcbiAgLyoqXHJcbiAgICogUmVuZGVyIHJ1bGUgYGluZm9gIGJhbm5lcnMgaW5saW5lLiBUaGUgcmVjb3JkIGVkaXRvciBzZXRzIHRoaXMgZmFsc2UgYW5kIHJlbmRlcnMgaXRzXHJcbiAgICogb3duIGRpc21pc3NpYmxlIHZlcnNpb25zLCBzbyB0aGUgdHdvIGRvIG5vdCBkb3VibGUgdXAuXHJcbiAgICovXHJcbiAgQElucHV0KCkgc2hvd0luZm9CYW5uZXJzOiBib29sZWFuID0gdHJ1ZTtcclxuICBASW5wdXQoKSBsb2FkaW5nOiBib29sZWFuID0gZmFsc2U7XHJcbiAgQElucHV0KCkgZXJyb3I6IHN0cmluZyB8IG51bGwgPSBudWxsO1xyXG4gIC8qKlxyXG4gICAqIE1pbGxpc2Vjb25kcyB0byBkZWJvdW5jZSBgZm9ybUNoYW5nZWAuIFRoZSByZWZlcmVuY2UgZGVib3VuY2VzIGF0IDMwMG1zIHNvIGEgY29uc3VtZXJcclxuICAgKiByZS1yZW5kZXJpbmcgb24gZXZlcnkgdmFsdWUgY2hhbmdlIGlzIG5vdCBkcml2ZW4gcGVyIGtleXN0cm9rZS4gWmVybyBlbWl0c1xyXG4gICAqIHN5bmNocm9ub3VzbHksIHdoaWNoIHRoZSByZWNvcmQgZWRpdG9yIHJlbGllcyBvbiBmb3IgaXRzIG93biBib29ra2VlcGluZy5cclxuICAgKi9cclxuICBASW5wdXQoKSBjaGFuZ2VEZWJvdW5jZU1zOiBudW1iZXIgPSAwO1xyXG4gIC8qKlxyXG4gICAqIFByZXZpZXcgbW9kZTogc2VlZCBvbmUgZW1wdHkgcm93IHBlciBgYXJyYXlgIGZpZWxkIHNvIHRoZSBzdHJ1Y3R1cmUgaXMgdmlzaWJsZSwgdGhlblxyXG4gICAqIGRpc2FibGUgdGhlIGZvcm0uIFVzZWQgYnkgdGhlIGJ1aWxkZXIncyBsaXZlIHByZXZpZXcuXHJcbiAgICovXHJcbiAgQElucHV0KCkgcHJldmlldzogYm9vbGVhbiA9IGZhbHNlO1xyXG5cclxuICAvLyDilIDilIDilIAgT3V0cHV0cyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcclxuICBAT3V0cHV0KCkgZm9ybVN1Ym1pdCA9IG5ldyBFdmVudEVtaXR0ZXI8UmVjb3JkPHN0cmluZywgYW55Pj4oKTtcclxuICBAT3V0cHV0KCkgZm9ybUNoYW5nZSA9IG5ldyBFdmVudEVtaXR0ZXI8UmVjb3JkPHN0cmluZywgYW55Pj4oKTtcclxuICBAT3V0cHV0KCkgZm9ybVJlc2V0ID0gbmV3IEV2ZW50RW1pdHRlcjx2b2lkPigpO1xyXG4gIC8qKiBUaGUgdmlzaWJsZSB0YWIgY2hhbmdlZC4gTGV0cyBhIGhvc3QgdHJhY2sgaXQgd2l0aG91dCByZWFjaGluZyBpbnRvIHRoaXMgY29tcG9uZW50LiAqL1xyXG4gIEBPdXRwdXQoKSBhY3RpdmVUYWJDaGFuZ2UgPSBuZXcgRXZlbnRFbWl0dGVyPHN0cmluZz4oKTtcclxuXHJcbiAgLy8g4pSA4pSA4pSAIFNlcnZpY2VzIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxyXG4gIHByaXZhdGUgcmVhZG9ubHkgZmIgPSBpbmplY3QoRm9ybUJ1aWxkZXIpO1xyXG4gIHByaXZhdGUgcmVhZG9ubHkgdmFsaWRhdG9yUmVnaXN0cnkgPSBpbmplY3QoVmFsaWRhdG9yUmVnaXN0cnlTZXJ2aWNlKTtcclxuICBwcml2YXRlIHJlYWRvbmx5IGhvb2tSZWdpc3RyeSA9IGluamVjdChIb29rUmVnaXN0cnlTZXJ2aWNlKTtcclxuICBwcml2YXRlIHJlYWRvbmx5IHJiYWNTZXJ2aWNlID0gaW5qZWN0KFJiYWNTZXJ2aWNlKTtcclxuICBwcml2YXRlIHJlYWRvbmx5IHJ1bGVzRXZhbHVhdGlvbiA9IGluamVjdChSdWxlc0V2YWx1YXRpb25TZXJ2aWNlKTtcclxuICBwcml2YXRlIHJlYWRvbmx5IGVudGl0eVJlZlNlbGVjdGlvbiA9IGluamVjdChFbnRpdHlSZWZTZWxlY3Rpb25TZXJ2aWNlKTtcclxuICBwcml2YXRlIHJlYWRvbmx5IGNvbW1vbk1vZHVsZXNSZWdpc3RyeSA9IGluamVjdChDT01NT05fTU9EVUxFU19SRUdJU1RSWSwgeyBvcHRpb25hbDogdHJ1ZSB9KTtcclxuXHJcbiAgcHJvdGVjdGVkIHJlYWRvbmx5IE9iamVjdCA9IE9iamVjdDtcclxuXHJcbiAgLy8g4pSA4pSA4pSAIFNpZ25hbHMgKGxvY2FsIHJlYWN0aXZlIHN0YXRlKSDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcclxuICByZWFkb25seSBhY3RpdmVUYWIgPSBzaWduYWw8c3RyaW5nPignJyk7XHJcbiAgcmVhZG9ubHkgYWN0aXZlU3ViVGFiID0gc2lnbmFsPHN0cmluZz4oJycpO1xyXG4gIHJlYWRvbmx5IGlzU2F2aW5nID0gc2lnbmFsKGZhbHNlKTtcclxuICByZWFkb25seSBmb3JtVmFsdWVzID0gc2lnbmFsPFJlY29yZDxzdHJpbmcsIGFueT4+KHt9KTtcclxuICAvKiogQmFzZWxpbmUgY2FwdHVyZWQgYXQgZmlyc3QgYnVpbGQsIHVzZWQgd2hlbiBgb3JpZ2luYWxEYXRhYCBpcyBub3Qgc3VwcGxpZWQuICovXHJcbiAgcmVhZG9ubHkgc2Vzc2lvbkJhc2VsaW5lID0gc2lnbmFsPFJlY29yZDxzdHJpbmcsIGFueT4+KHt9KTtcclxuICAvKiogQ3JpdGljYWwgZmllbGRzIHRoZSB1c2VyIGhhcyBleHBsaWNpdGx5IHVubG9ja2VkIGZvciBlZGl0aW5nLiAqL1xyXG4gIHJlYWRvbmx5IHVubG9ja2VkRmllbGRzID0gc2lnbmFsPFJlYWRvbmx5U2V0PHN0cmluZz4+KG5ldyBTZXQ8c3RyaW5nPigpKTtcclxuXHJcbiAgLy8g4pSA4pSA4pSAIEZvcm0g4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXHJcbiAgZm9ybSE6IEZvcm1Hcm91cDtcclxuXHJcbiAgcHJpdmF0ZSB2YWx1ZVN1Yj86IFN1YnNjcmlwdGlvbjtcclxuICBwcml2YXRlIHNlbGVjdGlvblN1Yj86IFN1YnNjcmlwdGlvbjtcclxuICAvKiogUHJldmlvdXMgdmFsdWVzLCBmb3IgZGV0ZWN0aW5nIGBwYXRjaE9uVHJ1ZWAgZmFsc2XihpJ0cnVlIHRyYW5zaXRpb25zLiAqL1xyXG4gIHByaXZhdGUgcHJldmlvdXNWYWx1ZXM6IFJlY29yZDxzdHJpbmcsIGFueT4gPSB7fTtcclxuXHJcbiAgLy8g4pSA4pSA4pSAIEtleWJvYXJkIFNob3J0Y3V0cyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcclxuICBASG9zdExpc3RlbmVyKCd3aW5kb3c6a2V5ZG93bicsIFsnJGV2ZW50J10pXHJcbiAgaGFuZGxlS2V5Ym9hcmRFdmVudChldmVudDogS2V5Ym9hcmRFdmVudCk6IHZvaWQge1xyXG4gICAgaWYgKChldmVudC5jdHJsS2V5IHx8IGV2ZW50Lm1ldGFLZXkpICYmIGV2ZW50LmtleS50b0xvd2VyQ2FzZSgpID09PSAncycpIHtcclxuICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcclxuICAgICAgaWYgKCF0aGlzLnJlYWRvbmx5ICYmIHRoaXMuY2FuU3VibWl0ICYmIHRoaXMuZm9ybT8udmFsaWQpIHtcclxuICAgICAgICB0aGlzLnN1Ym1pdCgpO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyDilIDilIDilIAgQ29tcHV0ZWQg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXHJcbiAgcmVhZG9ubHkgcnVsZVJlc3VsdCA9IGNvbXB1dGVkKCgpID0+XHJcbiAgICB0aGlzLnJ1bGVzRXZhbHVhdGlvbi5ldmFsdWF0ZSh0aGlzLnJ1bGVzLCB0aGlzLmZvcm1WYWx1ZXMoKSwgdGhpcy5iYXNlbGluZSgpKSxcclxuICApO1xyXG5cclxuICAvKipcclxuICAgKiBDcml0aWNhbCBmaWVsZHMgd2hvc2UgdmFsdWUgZGlmZmVycyBmcm9tIHRoZSBzZXNzaW9uIGJhc2VsaW5lLlxyXG4gICAqIFRoZXNlIGRyaXZlIHRoZSBkZWZlcnJlZCBgVkFMVUVfQ0hBTkdFRGAgYmFubmVyIOKAlCBhIGNyaXRpY2FsIGVkaXQgaXMgYW5ub3VuY2VkIG9uY2UsXHJcbiAgICogYWdhaW5zdCB0aGUgdmFsdWUgdGhlIHJlY29yZCBoYWQgd2hlbiB0aGUgc2Vzc2lvbiBzdGFydGVkLCBub3QgcGVyIGtleXN0cm9rZS5cclxuICAgKi9cclxuICByZWFkb25seSBjaGFuZ2VkQ3JpdGljYWxGaWVsZHMgPSBjb21wdXRlZDxOZXN0ZWRGaWVsZENvbmZpZ1tdPigoKSA9PiB7XHJcbiAgICBjb25zdCBiYXNlbGluZSA9IHRoaXMuYmFzZWxpbmUoKTtcclxuICAgIGlmICghYmFzZWxpbmUgfHwgT2JqZWN0LmtleXMoYmFzZWxpbmUpLmxlbmd0aCA9PT0gMCkgcmV0dXJuIFtdO1xyXG4gICAgY29uc3QgdmFsdWVzID0gdGhpcy5mb3JtVmFsdWVzKCk7XHJcbiAgICByZXR1cm4gdGhpcy5hbGxGaWVsZHMoKS5maWx0ZXIoXHJcbiAgICAgIGYgPT4gZi5jcml0aWNhbEZpZWxkICYmICF0aGlzLnNhbWVWYWx1ZSh2YWx1ZXNbZi5pZF0sIGJhc2VsaW5lW2YuaWRdKSxcclxuICAgICk7XHJcbiAgfSk7XHJcblxyXG4gIGdldCB0YWJzKCk6IE5lc3RlZFRhYkNvbmZpZ1tdIHtcclxuICAgIHJldHVybiB0aGlzLmNvbmZpZz8udGFicyB8fCBbXTtcclxuICB9XHJcblxyXG4gIGdldCB2aXNpYmxlVGFicygpOiBOZXN0ZWRUYWJDb25maWdbXSB7XHJcbiAgICBjb25zdCBoaWRkZW4gPSB0aGlzLnJ1bGVSZXN1bHQoKS5oaWRkZW5UYWJzO1xyXG4gICAgcmV0dXJuIHRoaXMudGFicy5maWx0ZXIodGFiID0+IHRhYi52aXNpYmlsaXR5ICE9PSBmYWxzZSAmJiAhaGlkZGVuLmluY2x1ZGVzKHRhYi5pZCkpO1xyXG4gIH1cclxuXHJcbiAgZ2V0IGFjdGl2ZVRhYkNvbmZpZygpOiBOZXN0ZWRUYWJDb25maWcgfCBudWxsIHtcclxuICAgIGNvbnN0IHRhYklkID0gdGhpcy5hY3RpdmVUYWIoKTtcclxuICAgIGlmICghdGFiSWQpIHJldHVybiB0aGlzLnZpc2libGVUYWJzWzBdID8/IG51bGw7XHJcbiAgICByZXR1cm4gZmluZFRhYih0aGlzLnRhYnMsIHRhYklkKTtcclxuICB9XHJcblxyXG4gIGdldCB2aXNpYmxlU3ViVGFicygpOiBOZXN0ZWRUYWJDb25maWdbXSB7XHJcbiAgICBjb25zdCBhY3RpdmUgPSB0aGlzLmFjdGl2ZVRhYkNvbmZpZztcclxuICAgIGlmICghYWN0aXZlPy5jaGlsZHJlbiB8fCBhY3RpdmUuY2hpbGRyZW4ubGVuZ3RoID09PSAwKSByZXR1cm4gW107XHJcbiAgICBjb25zdCBoaWRkZW4gPSB0aGlzLnJ1bGVSZXN1bHQoKS5oaWRkZW5UYWJzO1xyXG4gICAgcmV0dXJuIGFjdGl2ZS5jaGlsZHJlbi5maWx0ZXIodGFiID0+IHRhYi52aXNpYmlsaXR5ICE9PSBmYWxzZSAmJiAhaGlkZGVuLmluY2x1ZGVzKHRhYi5pZCkpO1xyXG4gIH1cclxuXHJcbiAgZ2V0IGFjdGl2ZVN1YlRhYkNvbmZpZygpOiBOZXN0ZWRUYWJDb25maWcgfCBudWxsIHtcclxuICAgIGNvbnN0IHN1YlRhYnMgPSB0aGlzLnZpc2libGVTdWJUYWJzO1xyXG4gICAgaWYgKCFzdWJUYWJzLmxlbmd0aCkgcmV0dXJuIG51bGw7XHJcbiAgICBjb25zdCBzdWJJZCA9IHRoaXMuYWN0aXZlU3ViVGFiKCk7XHJcbiAgICByZXR1cm4gc3ViVGFicy5maW5kKHMgPT4gcy5pZCA9PT0gc3ViSWQpID8/IHN1YlRhYnNbMF07XHJcbiAgfVxyXG5cclxuICBnZXQgYWN0aXZlVGFiTW9kdWxlQ29tcG9uZW50KCk6IGFueSB8IG51bGwge1xyXG4gICAgY29uc3QgYWN0aXZlID0gdGhpcy5hY3RpdmVTdWJUYWJDb25maWcgPz8gdGhpcy5hY3RpdmVUYWJDb25maWc7XHJcbiAgICBpZiAoIWFjdGl2ZT8ubW9kdWxlTmFtZSB8fCAhdGhpcy5jb21tb25Nb2R1bGVzUmVnaXN0cnkpIHJldHVybiBudWxsO1xyXG4gICAgY29uc3QgZW50cnkgPSB0aGlzLmNvbW1vbk1vZHVsZXNSZWdpc3RyeS5maW5kKFxyXG4gICAgICBtID0+IG0uaWQgPT09IGFjdGl2ZS5tb2R1bGVOYW1lIHx8IG0uY29tcG9uZW50ID09PSBhY3RpdmUubW9kdWxlTmFtZSxcclxuICAgICk7XHJcbiAgICByZXR1cm4gZW50cnkgPyBlbnRyeS5jb21wb25lbnQgOiBudWxsO1xyXG4gIH1cclxuXHJcbiAgZ2V0IGZpZWxkc0ZvckFjdGl2ZVRhYigpOiBOZXN0ZWRGaWVsZENvbmZpZ1tdIHtcclxuICAgIGNvbnN0IGFjdGl2ZSA9IHRoaXMuYWN0aXZlU3ViVGFiQ29uZmlnID8/IHRoaXMuYWN0aXZlVGFiQ29uZmlnO1xyXG4gICAgaWYgKGFjdGl2ZT8ubW9kdWxlTmFtZSkgcmV0dXJuIFtdO1xyXG4gICAgY29uc3QgcmF3RmllbGRzID0gYWN0aXZlID8gKGFjdGl2ZS5maWVsZHMgfHwgW10pIDogKCh0aGlzLmNvbmZpZz8udGFicyB8fCBbXSkuZmxhdE1hcCh0ID0+IHQuZmllbGRzIHx8IFtdKSk7XHJcbiAgICBjb25zdCBjdXJyZW50VmFsdWVzID0gdGhpcy5mb3JtVmFsdWVzKCk7XHJcbiAgICBjb25zdCBoaWRkZW5GaWVsZHMgPSB0aGlzLnJ1bGVSZXN1bHQoKS5oaWRkZW5GaWVsZHM7XHJcblxyXG4gICAgcmV0dXJuIHJhd0ZpZWxkcy5maWx0ZXIoXHJcbiAgICAgIGZpZWxkID0+IGV2YWx1YXRlRmllbGRWaXNpYmlsaXR5KGZpZWxkLCBjdXJyZW50VmFsdWVzKSAmJiAhaGlkZGVuRmllbGRzLmluY2x1ZGVzKGZpZWxkLmlkKSxcclxuICAgICk7XHJcbiAgfVxyXG5cclxuICBnZXQgcGVybWlzc2lvbnMoKSB7XHJcbiAgICByZXR1cm4gdGhpcy5yYmFjU2VydmljZS5nZXRQZXJtaXNzaW9ucyh0aGlzLmNvbmZpZywgdGhpcy51c2VyUm9sZXMpO1xyXG4gIH1cclxuXHJcbiAgZ2V0IGNhblN1Ym1pdCgpOiBib29sZWFuIHtcclxuICAgIHJldHVybiB0aGlzLnBlcm1pc3Npb25zLmNhbkVkaXQgJiYgIXRoaXMucmVhZG9ubHk7XHJcbiAgfVxyXG5cclxuICBuZ09uSW5pdCgpOiB2b2lkIHtcclxuICAgIHRoaXMuc2VsZWN0aW9uU3ViID0gdGhpcy5lbnRpdHlSZWZTZWxlY3Rpb24uc2VsZWN0aW9uJC5zdWJzY3JpYmUoKHsgZmllbGRJZCwgb3B0aW9uIH0pID0+IHtcclxuICAgICAgdGhpcy5ydW5BdXRvUGF0Y2goZmllbGRJZCwgb3B0aW9uPy5yZWNvcmQpO1xyXG4gICAgfSk7XHJcbiAgfVxyXG5cclxuICBuZ09uQ2hhbmdlcyhjaGFuZ2VzOiBTaW1wbGVDaGFuZ2VzKTogdm9pZCB7XHJcbiAgICBpZiAoY2hhbmdlc1snY29uZmlnJ10gJiYgdGhpcy5jb25maWcpIHtcclxuICAgICAgLy8gQ29uZmlncyBhcnJpdmUgYXMgcGxhaW4gSlNPTiBmcm9tIHN0b3JhZ2Ugb3IgYW4gQVBJLCB3aGVyZSBUeXBlU2NyaXB0IGNhbm5vdCBlbmZvcmNlXHJcbiAgICAgIC8vIHRoZSBvcHRpb24gc2hhcGUuIE5vcm1hbGlzZSBoZXJlLCBhdCB0aGUgbGlicmFyeSBib3VuZGFyeSwgc28gZXZlcnl0aGluZyBkb3duc3RyZWFtXHJcbiAgICAgIC8vIGNhbiByZWx5IG9uIGFuIG9wdGlvbiBiZWluZyBhIExvY2FsaXplZFRleHQuIFJldHVybnMgdGhlIHNhbWUgb2JqZWN0IHdoZW4gaXQgYWxyZWFkeVxyXG4gICAgICAvLyBpcywgc28gYSB3ZWxsLWZvcm1lZCBjb25maWcgY29zdHMgbm90aGluZy5cclxuICAgICAgdGhpcy5jb25maWcgPSBub3JtYWxpemVDb25maWdPcHRpb25zKHRoaXMuY29uZmlnKTtcclxuICAgIH1cclxuICAgIGlmIChjaGFuZ2VzWydjb25maWcnXSB8fCBjaGFuZ2VzWydpbml0aWFsRGF0YSddKSB7XHJcbiAgICAgIHRoaXMuYnVpbGRGb3JtKCk7XHJcbiAgICAgIGlmICh0aGlzLnZpc2libGVUYWJzLmxlbmd0aCA+IDAgJiYgIXRoaXMuYWN0aXZlVGFiKCkpIHtcclxuICAgICAgICB0aGlzLnNldEFjdGl2ZVRhYih0aGlzLnZpc2libGVUYWJzWzBdLmlkKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgbmdPbkRlc3Ryb3koKTogdm9pZCB7XHJcbiAgICB0aGlzLnZhbHVlU3ViPy51bnN1YnNjcmliZSgpO1xyXG4gICAgdGhpcy5zZWxlY3Rpb25TdWI/LnVuc3Vic2NyaWJlKCk7XHJcbiAgfVxyXG5cclxuICBzZXRBY3RpdmVUYWIodGFiSWQ6IHN0cmluZyk6IHZvaWQge1xyXG4gICAgaWYgKHRoaXMuYWN0aXZlVGFiKCkgIT09IHRhYklkKSB0aGlzLmFjdGl2ZVRhYkNoYW5nZS5lbWl0KHRhYklkKTtcclxuICAgIHRoaXMuYWN0aXZlVGFiLnNldCh0YWJJZCk7XHJcbiAgICBjb25zdCBwYXJlbnQgPSBmaW5kVGFiKHRoaXMudGFicywgdGFiSWQpO1xyXG4gICAgaWYgKHBhcmVudD8uY2hpbGRyZW4/Lmxlbmd0aCkge1xyXG4gICAgICB0aGlzLmFjdGl2ZVN1YlRhYi5zZXQocGFyZW50LmNoaWxkcmVuWzBdLmlkKTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIHRoaXMuYWN0aXZlU3ViVGFiLnNldCgnJyk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBzZXRBY3RpdmVTdWJUYWIoc3ViVGFiSWQ6IHN0cmluZyk6IHZvaWQge1xyXG4gICAgdGhpcy5hY3RpdmVTdWJUYWIuc2V0KHN1YlRhYklkKTtcclxuICB9XHJcblxyXG4gIGdldEZpZWxkU3BhbihmaWVsZDogTmVzdGVkRmllbGRDb25maWcpOiBzdHJpbmcge1xyXG4gICAgY29uc3Qgc3BhbiA9IGZpZWxkLmNvbFNwYW4gPz8gMTI7XHJcbiAgICByZXR1cm4gYHNwYW4gJHtNYXRoLm1pbigxMiwgTWF0aC5tYXgoMSwgc3BhbikpfWA7XHJcbiAgfVxyXG5cclxuICAvLyDilIDilIDilIAgY3JpdGljYWxGaWVsZCBsb2NraW5nIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxyXG5cclxuICAvKiogQSBjcml0aWNhbCBmaWVsZCBzdGF5cyByZWFkLW9ubHkgdW50aWwgdGhlIHVzZXIgZGVsaWJlcmF0ZWx5IHVubG9ja3MgaXQuICovXHJcbiAgaXNGaWVsZExvY2tlZChmaWVsZDogTmVzdGVkRmllbGRDb25maWcpOiBib29sZWFuIHtcclxuICAgIHJldHVybiAhIWZpZWxkLmNyaXRpY2FsRmllbGQgJiYgIXRoaXMudW5sb2NrZWRGaWVsZHMoKS5oYXMoZmllbGQuaWQpO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogV2hldGhlciB0aGlzIGZpZWxkIHJlbmRlcnMgcmVhZC1vbmx5LCBmcm9tIGFueSBvZiB0aGUgZm91ciByZWFzb25zOiB0aGUgd2hvbGUgZm9ybSxcclxuICAgKiB0aGUgZmllbGQncyBvd24gZmxhZywgYSBjYWxsZXItc3VwcGxpZWQgYHJlYWRPbmx5RmllbGRzYCBlbnRyeSwgb3IgYSBjcml0aWNhbEZpZWxkIGxvY2suXHJcbiAgICovXHJcbiAgaXNGaWVsZFJlYWRvbmx5KGZpZWxkOiBOZXN0ZWRGaWVsZENvbmZpZyk6IGJvb2xlYW4ge1xyXG4gICAgcmV0dXJuIChcclxuICAgICAgdGhpcy5yZWFkb25seSB8fFxyXG4gICAgICAhIWZpZWxkLnJlYWRvbmx5IHx8XHJcbiAgICAgIHRoaXMucmVhZE9ubHlGaWVsZHMuaW5jbHVkZXMoZmllbGQuaWQpIHx8XHJcbiAgICAgIHRoaXMuaXNGaWVsZExvY2tlZChmaWVsZClcclxuICAgICk7XHJcbiAgfVxyXG5cclxuICB0b2dnbGVGaWVsZExvY2soZmllbGQ6IE5lc3RlZEZpZWxkQ29uZmlnKTogdm9pZCB7XHJcbiAgICBpZiAoIWZpZWxkLmNyaXRpY2FsRmllbGQgfHwgdGhpcy5yZWFkb25seSkgcmV0dXJuO1xyXG4gICAgY29uc3QgbmV4dCA9IG5ldyBTZXQodGhpcy51bmxvY2tlZEZpZWxkcygpKTtcclxuICAgIGlmIChuZXh0LmhhcyhmaWVsZC5pZCkpIG5leHQuZGVsZXRlKGZpZWxkLmlkKTtcclxuICAgIGVsc2UgbmV4dC5hZGQoZmllbGQuaWQpO1xyXG4gICAgdGhpcy51bmxvY2tlZEZpZWxkcy5zZXQobmV4dCk7XHJcbiAgfVxyXG5cclxuICByZXNvbHZlRmllbGRMYWJlbChmaWVsZDogTmVzdGVkRmllbGRDb25maWcpOiBzdHJpbmcge1xyXG4gICAgcmV0dXJuIHJlc29sdmVMYWJlbChmaWVsZC5sYWJlbCwgdGhpcy5sYW5ndWFnZSk7XHJcbiAgfVxyXG5cclxuICAvLyDilIDilIDilIAgRm9ybSBjb25zdHJ1Y3Rpb24g4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXHJcblxyXG4gIHByaXZhdGUgYnVpbGRGb3JtKCk6IHZvaWQge1xyXG4gICAgaWYgKCF0aGlzLmNvbmZpZykgcmV0dXJuO1xyXG4gICAgY29uc3QgZ3JvdXA6IFJlY29yZDxzdHJpbmcsIEFic3RyYWN0Q29udHJvbD4gPSB7fTtcclxuXHJcbiAgICBjb25zdCBidWlsZFRhYkNvbnRyb2xzID0gKHRhYnM6IE5lc3RlZFRhYkNvbmZpZ1tdLCBwYXJlbnRHcm91cDogUmVjb3JkPHN0cmluZywgQWJzdHJhY3RDb250cm9sPikgPT4ge1xyXG4gICAgICBmb3IgKGNvbnN0IHRhYiBvZiB0YWJzKSB7XHJcbiAgICAgICAgaWYgKHRhYi5mbGF0RGF0YSkge1xyXG4gICAgICAgICAgZm9yIChjb25zdCBmaWVsZCBvZiB0YWIuZmllbGRzIHx8IFtdKSB7XHJcbiAgICAgICAgICAgIHRoaXMuYnVpbGRGaWVsZENvbnRyb2woZmllbGQsIHBhcmVudEdyb3VwKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICAgIGlmICh0YWIuY2hpbGRyZW4pIGJ1aWxkVGFiQ29udHJvbHModGFiLmNoaWxkcmVuLCBwYXJlbnRHcm91cCk7XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgIGNvbnN0IHRhYkdyb3VwOiBSZWNvcmQ8c3RyaW5nLCBBYnN0cmFjdENvbnRyb2w+ID0ge307XHJcbiAgICAgICAgICBmb3IgKGNvbnN0IGZpZWxkIG9mIHRhYi5maWVsZHMgfHwgW10pIHtcclxuICAgICAgICAgICAgdGhpcy5idWlsZEZpZWxkQ29udHJvbChmaWVsZCwgdGFiR3JvdXApO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgICAgaWYgKHRhYi5jaGlsZHJlbikgYnVpbGRUYWJDb250cm9scyh0YWIuY2hpbGRyZW4sIHRhYkdyb3VwKTtcclxuICAgICAgICAgIHBhcmVudEdyb3VwW3RhYi5pZF0gPSB0aGlzLmZiLmdyb3VwKHRhYkdyb3VwKTtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH07XHJcblxyXG4gICAgYnVpbGRUYWJDb250cm9scyh0aGlzLmNvbmZpZy50YWJzIHx8IFtdLCBncm91cCk7XHJcbiAgICB0aGlzLmZvcm0gPSB0aGlzLmZiLmdyb3VwKGdyb3VwKTtcclxuXHJcbiAgICBpZiAodGhpcy5pbml0aWFsRGF0YSkge1xyXG4gICAgICB0aGlzLnBhdGNoRm9ybSh0aGlzLmluaXRpYWxEYXRhKTtcclxuICAgIH1cclxuXHJcbiAgICBjb25zdCBpbml0aWFsRmxhdHRlbmVkID0gdGhpcy5mbGF0dGVuRm9ybVZhbHVlcygpO1xyXG4gICAgdGhpcy5mb3JtVmFsdWVzLnNldChpbml0aWFsRmxhdHRlbmVkKTtcclxuICAgIHRoaXMucHJldmlvdXNWYWx1ZXMgPSB7IC4uLmluaXRpYWxGbGF0dGVuZWQgfTtcclxuICAgIHRoaXMuc2Vzc2lvbkJhc2VsaW5lLnNldCh7IC4uLmluaXRpYWxGbGF0dGVuZWQgfSk7XHJcbiAgICB0aGlzLnVubG9ja2VkRmllbGRzLnNldChuZXcgU2V0PHN0cmluZz4oKSk7XHJcblxyXG4gICAgaWYgKHRoaXMucHJldmlldykge1xyXG4gICAgICAvLyBTaG93IHdoYXQgYW4gYXJyYXkgZmllbGQgbG9va3MgbGlrZSByYXRoZXIgdGhhbiBhbiBlbXB0eSBzbG90LCB0aGVuIGZyZWV6ZS5cclxuICAgICAgZm9yIChjb25zdCBmaWVsZCBvZiB0aGlzLmFsbEZpZWxkcygpKSB7XHJcbiAgICAgICAgaWYgKGZpZWxkLnR5cGUgIT09ICdhcnJheScpIGNvbnRpbnVlO1xyXG4gICAgICAgIGNvbnN0IGFycmF5ID0gdGhpcy5nZXRBcnJheUNvbnRyb2woZmllbGQuaWQpO1xyXG4gICAgICAgIGlmIChhcnJheSAmJiBhcnJheS5sZW5ndGggPT09IDApIGFycmF5LnB1c2godGhpcy5idWlsZEFycmF5Um93KGZpZWxkLCB1bmRlZmluZWQpKTtcclxuICAgICAgfVxyXG4gICAgICB0aGlzLmZvcm0uZGlzYWJsZSh7IGVtaXRFdmVudDogZmFsc2UgfSk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gUmVidWlsZGluZyBtdXN0IG5vdCBzdGFjayBzdWJzY3JpcHRpb25zIG9uIHN1Y2Nlc3NpdmUgY29uZmlnL2RhdGEgY2hhbmdlcy5cclxuICAgIHRoaXMudmFsdWVTdWI/LnVuc3Vic2NyaWJlKCk7XHJcbiAgICBjb25zdCBjaGFuZ2VzJCA9IHRoaXMuY2hhbmdlRGVib3VuY2VNcyA+IDBcclxuICAgICAgPyB0aGlzLmZvcm0udmFsdWVDaGFuZ2VzLnBpcGUoZGVib3VuY2VUaW1lKHRoaXMuY2hhbmdlRGVib3VuY2VNcykpXHJcbiAgICAgIDogdGhpcy5mb3JtLnZhbHVlQ2hhbmdlcztcclxuICAgIHRoaXMudmFsdWVTdWIgPSBjaGFuZ2VzJC5zdWJzY3JpYmUoKCkgPT4ge1xyXG4gICAgICBjb25zdCBmbGF0dGVuZWQgPSB0aGlzLmZsYXR0ZW5Gb3JtVmFsdWVzKCk7XHJcbiAgICAgIHRoaXMuZm9ybVZhbHVlcy5zZXQoZmxhdHRlbmVkKTtcclxuICAgICAgdGhpcy5ydW5QYXRjaE9uVHJ1ZShmbGF0dGVuZWQpO1xyXG4gICAgICB0aGlzLnByZXZpb3VzVmFsdWVzID0geyAuLi5mbGF0dGVuZWQgfTtcclxuICAgICAgdGhpcy5mb3JtQ2hhbmdlLmVtaXQodGhpcy5leHRyYWN0UmVjb3JkKCkpO1xyXG4gICAgfSk7XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIGJ1aWxkRmllbGRDb250cm9sKGZpZWxkOiBOZXN0ZWRGaWVsZENvbmZpZywgZ3JvdXA6IFJlY29yZDxzdHJpbmcsIEFic3RyYWN0Q29udHJvbD4pOiB2b2lkIHtcclxuICAgIGlmIChmaWVsZC50eXBlID09PSAnZ3JvdXAnKSB7XHJcbiAgICAgIGNvbnN0IHN1Ykdyb3VwOiBSZWNvcmQ8c3RyaW5nLCBBYnN0cmFjdENvbnRyb2w+ID0ge307XHJcbiAgICAgIGZvciAoY29uc3QgY2hpbGQgb2YgZmllbGQuY2hpbGRyZW4gfHwgW10pIHtcclxuICAgICAgICB0aGlzLmJ1aWxkRmllbGRDb250cm9sKGNoaWxkLCBzdWJHcm91cCk7XHJcbiAgICAgIH1cclxuICAgICAgZ3JvdXBbZmllbGQuaWRdID0gdGhpcy5mYi5ncm91cChzdWJHcm91cCk7XHJcbiAgICB9IGVsc2UgaWYgKGZpZWxkLnR5cGUgPT09ICdhcnJheScpIHtcclxuICAgICAgZ3JvdXBbZmllbGQuaWRdID0gdGhpcy5mYi5hcnJheShbXSk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICBjb25zdCB2YWxpZGF0b3JzID0gdGhpcy52YWxpZGF0b3JSZWdpc3RyeS5yZXNvbHZlRnJvbUNvbmZpZyhmaWVsZC52YWxpZGF0b3JzKTtcclxuICAgICAgZ3JvdXBbZmllbGQuaWRdID0gdGhpcy5mYi5jb250cm9sKFxyXG4gICAgICAgIHsgdmFsdWU6IGZpZWxkLmRlZmF1bHRWYWx1ZSA/PyBudWxsLCBkaXNhYmxlZDogZmllbGQuZGlzYWJsZWQgPz8gZmFsc2UgfSxcclxuICAgICAgICB2YWxpZGF0b3JzLFxyXG4gICAgICApO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLyoqIE9uZSByb3cgb2YgYW4gYGFycmF5YCBmaWVsZDogYSBGb3JtR3JvdXAgd2hlbiB0aGUgZmllbGQgZGVjbGFyZXMgY29sdW1ucywgZWxzZSBhIGJhcmUgY29udHJvbC4gKi9cclxuICAvKipcclxuICAgKiBUaGUgYEZvcm1BcnJheWAgYmVoaW5kIGFuIGBhcnJheWAgZmllbGQsIGZvciBjYWxsZXJzIHRoYXQgbWFuYWdlIHJvd3MgdGhlbXNlbHZlcyDigJRcclxuICAgKiB0aGUgcmVjb3JkIGVkaXRvcidzIGlubGluZSByb3cgZHJhd2VyLlxyXG4gICAqL1xyXG4gIGdldEFycmF5Q29udHJvbChmaWVsZElkOiBzdHJpbmcsIHRhYklkPzogc3RyaW5nKTogRm9ybUFycmF5IHwgbnVsbCB7XHJcbiAgICBjb25zdCBjdHJsID0gdGhpcy5nZXRDb250cm9sKGZpZWxkSWQsIHRhYklkKTtcclxuICAgIHJldHVybiBjdHJsIGluc3RhbmNlb2YgRm9ybUFycmF5ID8gY3RybCA6IG51bGw7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBCdWlsZCBvbmUgZGV0YWNoZWQgcm93IGZvciBhbiBgYXJyYXlgIGZpZWxkLCB3aXRoIHRoZSBmaWVsZCdzIG93biB2YWxpZGF0b3JzIGFwcGxpZWQuXHJcbiAgICogRXhwb3NlZCBzbyBhIHJvdyBjYW4gYmUgZWRpdGVkIG91dHNpZGUgdGhlIGZvcm0gYW5kIHB1c2hlZCBvbiBzYXZlLlxyXG4gICAqL1xyXG4gIGNyZWF0ZUFycmF5Um93KGZpZWxkOiBOZXN0ZWRGaWVsZENvbmZpZywgdmFsdWU/OiB1bmtub3duKTogQWJzdHJhY3RDb250cm9sIHtcclxuICAgIHJldHVybiB0aGlzLmJ1aWxkQXJyYXlSb3coZmllbGQsIHZhbHVlKTtcclxuICB9XHJcblxyXG4gIHByaXZhdGUgYnVpbGRBcnJheVJvdyhmaWVsZDogTmVzdGVkRmllbGRDb25maWcgfCB1bmRlZmluZWQsIGl0ZW06IHVua25vd24pOiBBYnN0cmFjdENvbnRyb2wge1xyXG4gICAgaWYgKCFmaWVsZD8uY2hpbGRyZW4/Lmxlbmd0aCkgcmV0dXJuIHRoaXMuZmIuY29udHJvbChpdGVtKTtcclxuXHJcbiAgICBjb25zdCByb3dHcm91cDogUmVjb3JkPHN0cmluZywgQWJzdHJhY3RDb250cm9sPiA9IHt9O1xyXG4gICAgZm9yIChjb25zdCBjaGlsZCBvZiBmaWVsZC5jaGlsZHJlbikge1xyXG4gICAgICB0aGlzLmJ1aWxkRmllbGRDb250cm9sKGNoaWxkLCByb3dHcm91cCk7XHJcbiAgICB9XHJcbiAgICBjb25zdCBncm91cCA9IHRoaXMuZmIuZ3JvdXAocm93R3JvdXApO1xyXG4gICAgaWYgKGl0ZW0gJiYgdHlwZW9mIGl0ZW0gPT09ICdvYmplY3QnKSBncm91cC5wYXRjaFZhbHVlKGl0ZW0gYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj4pO1xyXG4gICAgcmV0dXJuIGdyb3VwO1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBwYXRjaEZvcm0oZGF0YTogUmVjb3JkPHN0cmluZywgYW55Pik6IHZvaWQge1xyXG4gICAgaWYgKCFkYXRhIHx8ICF0aGlzLmZvcm0pIHJldHVybjtcclxuICAgIGNvbnN0IGZpZWxkc0J5SWQgPSBuZXcgTWFwKHRoaXMuYWxsRmllbGRzKCkubWFwKGYgPT4gW2YuaWQsIGZdKSk7XHJcblxyXG4gICAgY29uc3Qgd2Fsa1RhYnMgPSAodGFiczogTmVzdGVkVGFiQ29uZmlnW10pID0+IHtcclxuICAgICAgZm9yIChjb25zdCB0YWIgb2YgdGFicykge1xyXG4gICAgICAgIGNvbnN0IHRhYkRhdGEgPSBnZXRUYWJEYXRhKHRhYi5pZCwgZGF0YSwgdGhpcy5jb25maWcpO1xyXG4gICAgICAgIGZvciAoY29uc3QgZmllbGQgb2YgdGFiLmZpZWxkcyB8fCBbXSkge1xyXG4gICAgICAgICAgbGV0IHZhbCA9IHRhYkRhdGEgJiYgdHlwZW9mIHRhYkRhdGEgPT09ICdvYmplY3QnID8gdGFiRGF0YVtmaWVsZC5pZF0gOiB1bmRlZmluZWQ7XHJcbiAgICAgICAgICBpZiAoZmllbGQucmVmZXJlckZpZWxkKSB7XHJcbiAgICAgICAgICAgIGNvbnN0IHJlZlZhbCA9IGdldFZhbHVlQnlQYXRoKGRhdGEsIGZpZWxkLnJlZmVyZXJGaWVsZCk7XHJcbiAgICAgICAgICAgIGlmIChyZWZWYWwgIT09IHVuZGVmaW5lZCkgdmFsID0gcmVmVmFsO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgICAgaWYgKHZhbCA9PT0gdW5kZWZpbmVkKSBjb250aW51ZTtcclxuXHJcbiAgICAgICAgICBjb25zdCBjdHJsID0gdGhpcy5nZXRDb250cm9sKGZpZWxkLmlkLCB0YWIuaWQpO1xyXG4gICAgICAgICAgaWYgKCFjdHJsKSBjb250aW51ZTtcclxuXHJcbiAgICAgICAgICBpZiAoY3RybCBpbnN0YW5jZW9mIEZvcm1BcnJheSAmJiBBcnJheS5pc0FycmF5KHZhbCkpIHtcclxuICAgICAgICAgICAgY3RybC5jbGVhcigpO1xyXG4gICAgICAgICAgICBmb3IgKGNvbnN0IGl0ZW0gb2YgdmFsKSB7XHJcbiAgICAgICAgICAgICAgY3RybC5wdXNoKHRoaXMuYnVpbGRBcnJheVJvdyhmaWVsZHNCeUlkLmdldChmaWVsZC5pZCksIGl0ZW0pKTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgY3RybC5wYXRjaFZhbHVlKHZhbCwgeyBlbWl0RXZlbnQ6IGZhbHNlIH0pO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgICBpZiAodGFiLmNoaWxkcmVuKSB3YWxrVGFicyh0YWIuY2hpbGRyZW4pO1xyXG4gICAgICB9XHJcbiAgICB9O1xyXG5cclxuICAgIHdhbGtUYWJzKHRoaXMuY29uZmlnLnRhYnMgfHwgW10pO1xyXG4gIH1cclxuXHJcbiAgLyoqIEFzc2VtYmxlIGZ1bGwgbmVzdGVkIHJlY29yZCBmcm9tIHBlci10YWIgRm9ybUdyb3VwcywgcmVzcGVjdGluZyBmbGF0RGF0YSwgcmVmZXJlckZpZWxkICYgYXJyYXlzLiAqL1xyXG4gIGV4dHJhY3RSZWNvcmQoKTogUmVjb3JkPHN0cmluZywgYW55PiB7XHJcbiAgICBpZiAoIXRoaXMuZm9ybSB8fCAhdGhpcy5jb25maWcpIHJldHVybiB7fTtcclxuICAgIGxldCByZWNvcmQ6IFJlY29yZDxzdHJpbmcsIGFueT4gPSB7fTtcclxuXHJcbiAgICBjb25zdCB3YWxrVGFicyA9ICh0YWJzOiBOZXN0ZWRUYWJDb25maWdbXSkgPT4ge1xyXG4gICAgICBmb3IgKGNvbnN0IHRhYiBvZiB0YWJzKSB7XHJcbiAgICAgICAgY29uc3QgZmllbGRWYWxCYWc6IFJlY29yZDxzdHJpbmcsIHVua25vd24+ID0ge307XHJcbiAgICAgICAgZm9yIChjb25zdCBmaWVsZCBvZiB0YWIuZmllbGRzIHx8IFtdKSB7XHJcbiAgICAgICAgICBjb25zdCBjdHJsID0gdGhpcy5nZXRDb250cm9sKGZpZWxkLmlkLCB0YWIuaWQpO1xyXG4gICAgICAgICAgaWYgKGN0cmwpIHtcclxuICAgICAgICAgICAgZmllbGRWYWxCYWdbZmllbGQuaWRdID0gY3RybC52YWx1ZTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIHNldFRhYkRhdGEocmVjb3JkLCB0YWIuaWQsIGZpZWxkVmFsQmFnLCB0aGlzLmNvbmZpZyk7XHJcblxyXG4gICAgICAgIGZvciAoY29uc3QgZmllbGQgb2YgdGFiLmZpZWxkcyB8fCBbXSkge1xyXG4gICAgICAgICAgaWYgKGZpZWxkLnJlZmVyZXJGaWVsZCkge1xyXG4gICAgICAgICAgICBjb25zdCBjdHJsID0gdGhpcy5nZXRDb250cm9sKGZpZWxkLmlkLCB0YWIuaWQpO1xyXG4gICAgICAgICAgICBpZiAoY3RybCkge1xyXG4gICAgICAgICAgICAgIHNldFZhbHVlQnlQYXRoKHJlY29yZCwgZmllbGQucmVmZXJlckZpZWxkLCBjdHJsLnZhbHVlKTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgaWYgKHRhYi5jaGlsZHJlbikgd2Fsa1RhYnModGFiLmNoaWxkcmVuKTtcclxuICAgICAgfVxyXG4gICAgfTtcclxuXHJcbiAgICB3YWxrVGFicyh0aGlzLmNvbmZpZy50YWJzIHx8IFtdKTtcclxuICAgIHJlY29yZCA9IG5vcm1hbGl6ZUFycmF5U3RydWN0dXJlcyhyZWNvcmQsIHRoaXMuY29uZmlnKTtcclxuICAgIHJldHVybiByZWNvcmQ7XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIGZsYXR0ZW5Gb3JtVmFsdWVzKCk6IFJlY29yZDxzdHJpbmcsIGFueT4ge1xyXG4gICAgY29uc3Qgb3V0OiBSZWNvcmQ8c3RyaW5nLCBhbnk+ID0ge307XHJcbiAgICBmb3IgKGNvbnN0IGZpZWxkIG9mIHRoaXMuYWxsRmllbGRzKCkpIHtcclxuICAgICAgY29uc3QgY3RybCA9IHRoaXMuZ2V0Q29udHJvbChmaWVsZC5pZCk7XHJcbiAgICAgIGlmIChjdHJsKSBvdXRbZmllbGQuaWRdID0gY3RybC52YWx1ZTtcclxuICAgIH1cclxuICAgIHJldHVybiBvdXQ7XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIGdldFRhYkdyb3VwKHRhYklkOiBzdHJpbmcpOiBGb3JtR3JvdXAgfCBudWxsIHtcclxuICAgIGNvbnN0IHBhdGggPSBnZXRUYWJQYXRoKHRoaXMuY29uZmlnPy50YWJzLCB0YWJJZCk7XHJcbiAgICBpZiAoIXBhdGggfHwgcGF0aC5sZW5ndGggPT09IDApIHJldHVybiB0aGlzLmZvcm07XHJcbiAgICBsZXQgY3VycjogQWJzdHJhY3RDb250cm9sIHwgbnVsbCA9IHRoaXMuZm9ybTtcclxuICAgIGZvciAoY29uc3QgcCBvZiBwYXRoKSB7XHJcbiAgICAgIGlmICghY3VyciB8fCAhKGN1cnIgaW5zdGFuY2VvZiBGb3JtR3JvdXApKSByZXR1cm4gbnVsbDtcclxuICAgICAgY3VyciA9IGN1cnIuZ2V0KHApO1xyXG4gICAgfVxyXG4gICAgcmV0dXJuIGN1cnIgaW5zdGFuY2VvZiBGb3JtR3JvdXAgPyBjdXJyIDogbnVsbDtcclxuICB9XHJcblxyXG4gIC8vIOKUgOKUgOKUgCBhdXRvUGF0Y2ggLyBwYXRjaE9uVHJ1ZSDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcclxuXHJcbiAgLyoqXHJcbiAgICogYGF1dG9QYXRjaGAg4oCUIGNvcHkgbWFwcGVkIGZpZWxkcyBvdXQgb2YgdGhlIHJlY29yZCB0aGUgdXNlciBqdXN0IHNlbGVjdGVkIGluIGFuXHJcbiAgICogZW50aXR5LXJlZiBmaWVsZCBpbnRvIHRoZSBjb25maWd1cmVkIHRhcmdldCB0YWIncyBjb250cm9scy5cclxuICAgKi9cclxuICBwcml2YXRlIHJ1bkF1dG9QYXRjaChmaWVsZElkOiBzdHJpbmcsIHJlY29yZDogUmVjb3JkPHN0cmluZywgdW5rbm93bj4gfCB1bmRlZmluZWQpOiB2b2lkIHtcclxuICAgIGlmICghcmVjb3JkKSByZXR1cm47XHJcbiAgICBjb25zdCBmaWVsZCA9IHRoaXMuYWxsRmllbGRzKCkuZmluZChmID0+IGYuaWQgPT09IGZpZWxkSWQpO1xyXG4gICAgY29uc3QgYXV0b1BhdGNoID0gZmllbGQ/LmF1dG9QYXRjaDtcclxuICAgIGlmICghYXV0b1BhdGNoKSByZXR1cm47XHJcblxyXG4gICAgY29uc3QgcGF0Y2ggPSBhcHBseUF1dG9QYXRjaChhdXRvUGF0Y2gsIHJlY29yZCk7XHJcbiAgICBmb3IgKGNvbnN0IFt0YXJnZXRJZCwgdmFsdWVdIG9mIE9iamVjdC5lbnRyaWVzKHBhdGNoKSkge1xyXG4gICAgICBjb25zdCBjb250cm9sID0gdGhpcy5yZXNvbHZlVGFyZ2V0Q29udHJvbChhdXRvUGF0Y2gsIHRhcmdldElkKTtcclxuICAgICAgY29udHJvbD8ucGF0Y2hWYWx1ZSh2YWx1ZSk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBgcGF0Y2hPblRydWVgIOKAlCB3aGVuIGEgYm9vbGVhbi9jaGVja2JveCBmaWVsZCB0cmFuc2l0aW9ucyB0byBgdHJ1ZWAsXHJcbiAgICogY29weSBgZnJvbWAg4oaSIGB0b2Agd2l0aGluIHRoZSBjdXJyZW50IHJlY29yZC5cclxuICAgKi9cclxuICBwcml2YXRlIHJ1blBhdGNoT25UcnVlKHZhbHVlczogUmVjb3JkPHN0cmluZywgYW55Pik6IHZvaWQge1xyXG4gICAgZm9yIChjb25zdCBmaWVsZCBvZiB0aGlzLmFsbEZpZWxkcygpKSB7XHJcbiAgICAgIGNvbnN0IG1hcHBpbmdzID0gZmllbGQucGF0Y2hPblRydWU7XHJcbiAgICAgIGlmICghbWFwcGluZ3M/Lmxlbmd0aCkgY29udGludWU7XHJcblxyXG4gICAgICBjb25zdCB3YXNUcnVlID0gdGhpcy5wcmV2aW91c1ZhbHVlc1tmaWVsZC5pZF0gPT09IHRydWU7XHJcbiAgICAgIGNvbnN0IGlzVHJ1ZSA9IHZhbHVlc1tmaWVsZC5pZF0gPT09IHRydWU7XHJcbiAgICAgIGlmICghaXNUcnVlIHx8IHdhc1RydWUpIGNvbnRpbnVlO1xyXG5cclxuICAgICAgY29uc3QgcGF0Y2ggPSBhcHBseVBhdGNoT25UcnVlKG1hcHBpbmdzLCB2YWx1ZXMpO1xyXG4gICAgICBmb3IgKGNvbnN0IFt0YXJnZXRJZCwgdmFsdWVdIG9mIE9iamVjdC5lbnRyaWVzKHBhdGNoKSkge1xyXG4gICAgICAgIHRoaXMuZ2V0Q29udHJvbCh0YXJnZXRJZCk/LnBhdGNoVmFsdWUodmFsdWUsIHsgZW1pdEV2ZW50OiBmYWxzZSB9KTtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLyoqIFByZWZlciBhIGNvbnRyb2wgZGVjbGFyZWQgb24gdGhlIGNvbmZpZ3VyZWQgdGFyZ2V0IHRhYjsgZmFsbCBiYWNrIHRvIGEgdG9wLWxldmVsIGNvbnRyb2wuICovXHJcbiAgcHJpdmF0ZSByZXNvbHZlVGFyZ2V0Q29udHJvbChhdXRvUGF0Y2g6IEF1dG9QYXRjaENvbmZpZywgdGFyZ2V0SWQ6IHN0cmluZyk6IEFic3RyYWN0Q29udHJvbCB8IG51bGwge1xyXG4gICAgY29uc3QgdGFiID0gZmluZFRhYih0aGlzLnRhYnMsIGF1dG9QYXRjaC50YXJnZXRUYWIpO1xyXG4gICAgY29uc3QgaW5UYXJnZXRUYWIgPSAodGFiPy5maWVsZHMgPz8gW10pLnNvbWUoZiA9PiBmLmlkID09PSB0YXJnZXRJZCk7XHJcbiAgICBpZiAodGFiICYmICFpblRhcmdldFRhYikgcmV0dXJuIG51bGw7XHJcbiAgICByZXR1cm4gdGhpcy5nZXRDb250cm9sKHRhcmdldElkLCBhdXRvUGF0Y2gudGFyZ2V0VGFiKTtcclxuICB9XHJcblxyXG4gIC8vIOKUgOKUgOKUgCBIZWxwZXJzIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxyXG5cclxuICAvKiogRXZlcnkgZmllbGQgaW4gdGhlIGNvbmZpZywgaW5jbHVkaW5nIGBncm91cGAvYGFycmF5YCBjaGlsZHJlbi4gKi9cclxuICBwcml2YXRlIGFsbEZpZWxkcygpOiBOZXN0ZWRGaWVsZENvbmZpZ1tdIHtcclxuICAgIGNvbnN0IG91dDogTmVzdGVkRmllbGRDb25maWdbXSA9IFtdO1xyXG4gICAgY29uc3Qgd2Fsa0ZpZWxkcyA9IChmaWVsZHM6IE5lc3RlZEZpZWxkQ29uZmlnW10gfCB1bmRlZmluZWQpID0+IHtcclxuICAgICAgZm9yIChjb25zdCBmIG9mIGZpZWxkcyA/PyBbXSkge1xyXG4gICAgICAgIG91dC5wdXNoKGYpO1xyXG4gICAgICAgIGlmIChmLmNoaWxkcmVuPy5sZW5ndGgpIHdhbGtGaWVsZHMoZi5jaGlsZHJlbik7XHJcbiAgICAgIH1cclxuICAgIH07XHJcbiAgICBjb25zdCB3YWxrVGFicyA9ICh0YWJzOiBOZXN0ZWRUYWJDb25maWdbXSB8IHVuZGVmaW5lZCkgPT4ge1xyXG4gICAgICBmb3IgKGNvbnN0IHQgb2YgdGFicyA/PyBbXSkge1xyXG4gICAgICAgIHdhbGtGaWVsZHModC5maWVsZHMpO1xyXG4gICAgICAgIHdhbGtUYWJzKHQuY2hpbGRyZW4pO1xyXG4gICAgICB9XHJcbiAgICB9O1xyXG4gICAgd2Fsa1RhYnModGhpcy5jb25maWc/LnRhYnMpO1xyXG4gICAgcmV0dXJuIG91dDtcclxuICB9XHJcblxyXG4gIC8qKiBBbiBlbXB0eSBgb3JpZ2luYWxEYXRhYCBjb3VudHMgYXMgXCJub3Qgc3VwcGxpZWRcIiDigJQgZmFsbCBiYWNrIHRvIHRoZSBjYXB0dXJlZCBiYXNlbGluZS4gKi9cclxuICBwcml2YXRlIGJhc2VsaW5lKCk6IFJlY29yZDxzdHJpbmcsIGFueT4ge1xyXG4gICAgY29uc3Qgc3VwcGxpZWQgPSB0aGlzLm9yaWdpbmFsRGF0YTtcclxuICAgIGlmIChzdXBwbGllZCAmJiBPYmplY3Qua2V5cyhzdXBwbGllZCkubGVuZ3RoID4gMCkgcmV0dXJuIHN1cHBsaWVkO1xyXG4gICAgcmV0dXJuIHRoaXMuc2Vzc2lvbkJhc2VsaW5lKCk7XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIHNhbWVWYWx1ZShhOiB1bmtub3duLCBiOiB1bmtub3duKTogYm9vbGVhbiB7XHJcbiAgICBpZiAoYSA9PT0gYikgcmV0dXJuIHRydWU7XHJcbiAgICBjb25zdCBhRW1wdHkgPSBhID09PSBudWxsIHx8IGEgPT09IHVuZGVmaW5lZCB8fCBhID09PSAnJztcclxuICAgIGNvbnN0IGJFbXB0eSA9IGIgPT09IG51bGwgfHwgYiA9PT0gdW5kZWZpbmVkIHx8IGIgPT09ICcnO1xyXG4gICAgaWYgKGFFbXB0eSAmJiBiRW1wdHkpIHJldHVybiB0cnVlO1xyXG4gICAgaWYgKHR5cGVvZiBhID09PSAnb2JqZWN0JyB8fCB0eXBlb2YgYiA9PT0gJ29iamVjdCcpIHtcclxuICAgICAgcmV0dXJuIEpTT04uc3RyaW5naWZ5KGEgPz8gbnVsbCkgPT09IEpTT04uc3RyaW5naWZ5KGIgPz8gbnVsbCk7XHJcbiAgICB9XHJcbiAgICByZXR1cm4gZmFsc2U7XHJcbiAgfVxyXG5cclxuICBnZXRDb250cm9sKGZpZWxkSWQ6IHN0cmluZywgY3VycmVudFRhYklkPzogc3RyaW5nKTogQWJzdHJhY3RDb250cm9sIHwgbnVsbCB7XHJcbiAgICBpZiAoIXRoaXMuZm9ybSkgcmV0dXJuIG51bGw7XHJcblxyXG4gICAgaWYgKGN1cnJlbnRUYWJJZCkge1xyXG4gICAgICBjb25zdCB0YWJHcnAgPSB0aGlzLmdldFRhYkdyb3VwKGN1cnJlbnRUYWJJZCk7XHJcbiAgICAgIGNvbnN0IGN0cmwgPSB0YWJHcnA/LmdldChmaWVsZElkKTtcclxuICAgICAgaWYgKGN0cmwpIHJldHVybiBjdHJsO1xyXG4gICAgfVxyXG5cclxuICAgIGNvbnN0IHJvb3RDdHJsID0gdGhpcy5mb3JtLmdldChmaWVsZElkKTtcclxuICAgIGlmIChyb290Q3RybCkgcmV0dXJuIHJvb3RDdHJsO1xyXG5cclxuICAgIGNvbnN0IGZpbmRJbkdyb3VwID0gKGdyb3VwOiBGb3JtR3JvdXApOiBBYnN0cmFjdENvbnRyb2wgfCBudWxsID0+IHtcclxuICAgICAgZm9yIChjb25zdCBrZXkgb2YgT2JqZWN0LmtleXMoZ3JvdXAuY29udHJvbHMpKSB7XHJcbiAgICAgICAgY29uc3QgYyA9IGdyb3VwLmNvbnRyb2xzW2tleV07XHJcbiAgICAgICAgaWYgKGtleSA9PT0gZmllbGRJZCkgcmV0dXJuIGM7XHJcbiAgICAgICAgaWYgKGMgaW5zdGFuY2VvZiBGb3JtR3JvdXApIHtcclxuICAgICAgICAgIGNvbnN0IGZvdW5kID0gZmluZEluR3JvdXAoYyk7XHJcbiAgICAgICAgICBpZiAoZm91bmQpIHJldHVybiBmb3VuZDtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgICAgcmV0dXJuIG51bGw7XHJcbiAgICB9O1xyXG5cclxuICAgIHJldHVybiBmaW5kSW5Hcm91cCh0aGlzLmZvcm0pO1xyXG4gIH1cclxuXHJcbiAgcmVzb2x2ZVRhYkxhYmVsKHRhYjogTmVzdGVkVGFiQ29uZmlnKTogc3RyaW5nIHtcclxuICAgIHJldHVybiByZXNvbHZlTGFiZWwodGFiLmxhYmVsLCB0aGlzLmxhbmd1YWdlKTtcclxuICB9XHJcblxyXG4gIGFzeW5jIHN1Ym1pdCgpOiBQcm9taXNlPHZvaWQ+IHtcclxuICAgIGlmICghdGhpcy5jYW5TdWJtaXQgfHwgdGhpcy5mb3JtLmludmFsaWQpIHtcclxuICAgICAgdGhpcy5mb3JtLm1hcmtBbGxBc1RvdWNoZWQoKTtcclxuICAgICAgcmV0dXJuO1xyXG4gICAgfVxyXG5cclxuICAgIGNvbnN0IHJhd0RhdGEgPSB0aGlzLmV4dHJhY3RSZWNvcmQoKTtcclxuICAgIGxldCBwcm9jZXNzZWREYXRhID0gcmF3RGF0YTtcclxuXHJcbiAgICBjb25zdCBob29rS2V5ID0gYCR7dGhpcy5jb25maWc/LmVudGl0eX06YmVmb3JlU2F2ZWA7XHJcbiAgICBpZiAodGhpcy5ob29rUmVnaXN0cnkuaGFzKGhvb2tLZXkpKSB7XHJcbiAgICAgIHByb2Nlc3NlZERhdGEgPSBhd2FpdCB0aGlzLmhvb2tSZWdpc3RyeS5ydW4oaG9va0tleSwgcHJvY2Vzc2VkRGF0YSk7XHJcbiAgICB9XHJcblxyXG4gICAgdGhpcy5pc1NhdmluZy5zZXQodHJ1ZSk7XHJcbiAgICB0cnkge1xyXG4gICAgICB0aGlzLmZvcm1TdWJtaXQuZW1pdChwcm9jZXNzZWREYXRhKTtcclxuICAgIH0gZmluYWxseSB7XHJcbiAgICAgIHRoaXMuaXNTYXZpbmcuc2V0KGZhbHNlKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIHJlc2V0KCk6IHZvaWQge1xyXG4gICAgdGhpcy5mb3JtLnJlc2V0KCk7XHJcbiAgICBpZiAodGhpcy5pbml0aWFsRGF0YSkgdGhpcy5wYXRjaEZvcm0odGhpcy5pbml0aWFsRGF0YSk7XHJcbiAgICBjb25zdCB2YWx1ZXMgPSB0aGlzLmZsYXR0ZW5Gb3JtVmFsdWVzKCk7XHJcbiAgICB0aGlzLmZvcm1WYWx1ZXMuc2V0KHZhbHVlcyk7XHJcbiAgICB0aGlzLnByZXZpb3VzVmFsdWVzID0geyAuLi52YWx1ZXMgfTtcclxuICAgIHRoaXMudW5sb2NrZWRGaWVsZHMuc2V0KG5ldyBTZXQ8c3RyaW5nPigpKTtcclxuICAgIHRoaXMuZm9ybVJlc2V0LmVtaXQoKTtcclxuICB9XHJcbn1cclxuIiwiPGZvcm0gW2Zvcm1Hcm91cF09XCJmb3JtXCIgKG5nU3VibWl0KT1cInN1Ym1pdCgpXCIgY2xhc3M9XCJuZ3gtZm9ybVwiIG5vdmFsaWRhdGU+XHJcblxyXG4gIDwhLS0gRXJyb3IgbWVzc2FnZSBiYW5uZXIgLS0+XHJcbiAgQGlmIChlcnJvcikge1xyXG4gICAgPGRpdiBjbGFzcz1cIm5neC1mb3JtX19lcnJvci1iYW5uZXJcIiByb2xlPVwiYWxlcnRcIiBkYXRhLXRlc3RpZD1cImZvcm0tZXJyb3JcIj57eyBlcnJvciB9fTwvZGl2PlxyXG4gIH1cclxuXHJcbiAgPCEtLSBSdWxlcyBJbmZvIEJhbm5lcnMgLS0+XHJcbiAgQGZvciAoaW5mb0tleSBvZiBzaG93SW5mb0Jhbm5lcnMgPyBPYmplY3Qua2V5cyhydWxlUmVzdWx0KCkuaW5mb0Jhbm5lcnMpIDogW107IHRyYWNrIGluZm9LZXkpIHtcclxuICAgIDxkaXYgY2xhc3M9XCJuZ3gtZm9ybV9faW5mby1iYW5uZXJcIiByb2xlPVwic3RhdHVzXCIgW2F0dHIuZGF0YS10ZXN0aWRdPVwiJ2luZm8tYmFubmVyLScgKyBpbmZvS2V5XCI+XHJcbiAgICAgIOKEue+4jyB7eyBydWxlUmVzdWx0KCkuaW5mb0Jhbm5lcnNbaW5mb0tleV0gfX1cclxuICAgIDwvZGl2PlxyXG4gIH1cclxuXHJcbiAgPCEtLSBSdWxlcyBWYWxpZGF0aW9uIEVycm9ycyAmIFdhcm5pbmdzIC0tPlxyXG4gIEBmb3IgKGVycktleSBvZiBPYmplY3Qua2V5cyhydWxlUmVzdWx0KCkudmFsaWRhdGlvbkVycm9ycyk7IHRyYWNrIGVycktleSkge1xyXG4gICAgPGRpdiBjbGFzcz1cIm5neC1mb3JtX19lcnJvci1iYW5uZXJcIiByb2xlPVwiYWxlcnRcIiBbYXR0ci5kYXRhLXRlc3RpZF09XCIncnVsZS1lcnJvci0nICsgZXJyS2V5XCI+XHJcbiAgICAgIOKaoO+4jyB7eyBydWxlUmVzdWx0KCkudmFsaWRhdGlvbkVycm9yc1tlcnJLZXldIH19XHJcbiAgICA8L2Rpdj5cclxuICB9XHJcbiAgQGZvciAod2FybktleSBvZiBPYmplY3Qua2V5cyhydWxlUmVzdWx0KCkudmFsaWRhdGlvbldhcm5pbmdzKTsgdHJhY2sgd2FybktleSkge1xyXG4gICAgPGRpdiBjbGFzcz1cIm5neC1mb3JtX193YXJuaW5nLWJhbm5lclwiIHJvbGU9XCJzdGF0dXNcIiBbYXR0ci5kYXRhLXRlc3RpZF09XCIncnVsZS13YXJuaW5nLScgKyB3YXJuS2V5XCI+XHJcbiAgICAgIOKaoSB7eyBydWxlUmVzdWx0KCkudmFsaWRhdGlvbldhcm5pbmdzW3dhcm5LZXldIH19XHJcbiAgICA8L2Rpdj5cclxuICB9XHJcblxyXG4gIDwhLS0gRGVmZXJyZWQgVkFMVUVfQ0hBTkdFRCBub3RpY2UgZm9yIGNyaXRpY2FsRmllbGQgZWRpdHMgKHZzIHNlc3Npb24gYmFzZWxpbmUpIC0tPlxyXG4gIEBpZiAoY2hhbmdlZENyaXRpY2FsRmllbGRzKCkubGVuZ3RoID4gMCkge1xyXG4gICAgPGRpdiBjbGFzcz1cIm5neC1mb3JtX193YXJuaW5nLWJhbm5lclwiIHJvbGU9XCJzdGF0dXNcIiBkYXRhLXRlc3RpZD1cImNyaXRpY2FsLWNoYW5nZS1iYW5uZXJcIj5cclxuICAgICAg8J+UkiBDcml0aWNhbCBmaWVsZCBjaGFuZ2VkOlxyXG4gICAgICBAZm9yIChmaWVsZCBvZiBjaGFuZ2VkQ3JpdGljYWxGaWVsZHMoKTsgdHJhY2sgZmllbGQuaWQpIHtcclxuICAgICAgICA8c3Bhbj57eyByZXNvbHZlRmllbGRMYWJlbChmaWVsZCkgfX17eyAkbGFzdCA/ICcnIDogJywgJyB9fTwvc3Bhbj5cclxuICAgICAgfVxyXG4gICAgICDigJQgdGhpcyBkaWZmZXJzIGZyb20gdGhlIHZhbHVlIGF0IHRoZSBzdGFydCBvZiB0aGlzIHNlc3Npb24uXHJcbiAgICA8L2Rpdj5cclxuICB9XHJcblxyXG4gIDwhLS0gUHJpbWFyeSBUYWIgYmFyIOKAlCBvbmx5IGlmIHZpc2libGUgdGFicyBkZWZpbmVkIC0tPlxyXG4gIEBpZiAodmlzaWJsZVRhYnMubGVuZ3RoID4gMCkge1xyXG4gICAgPGRpdiBjbGFzcz1cIm5neC1mb3JtX190YWJzXCIgcm9sZT1cInRhYmxpc3RcIiBkYXRhLXRlc3RpZD1cInRhYi1zdHJpcFwiPlxyXG4gICAgICBAZm9yICh0YWIgb2YgdmlzaWJsZVRhYnM7IHRyYWNrIHRhYi5pZCkge1xyXG4gICAgICAgIDxidXR0b25cclxuICAgICAgICAgIHR5cGU9XCJidXR0b25cIlxyXG4gICAgICAgICAgY2xhc3M9XCJuZ3gtZm9ybV9fdGFiXCJcclxuICAgICAgICAgIFthdHRyLmRhdGEtdGVzdGlkXT1cIid0YWItJyArIHRhYi5pZFwiXHJcbiAgICAgICAgICBbY2xhc3Mubmd4LWZvcm1fX3RhYi0tYWN0aXZlXT1cImFjdGl2ZVRhYigpID09PSB0YWIuaWRcIlxyXG4gICAgICAgICAgKGNsaWNrKT1cInNldEFjdGl2ZVRhYih0YWIuaWQpXCJcclxuICAgICAgICAgIHJvbGU9XCJ0YWJcIlxyXG4gICAgICAgICAgW2F0dHIuYXJpYS1zZWxlY3RlZF09XCJhY3RpdmVUYWIoKSA9PT0gdGFiLmlkXCJcclxuICAgICAgICA+XHJcbiAgICAgICAgICB7eyByZXNvbHZlVGFiTGFiZWwodGFiKSB9fVxyXG4gICAgICAgIDwvYnV0dG9uPlxyXG4gICAgICB9XHJcbiAgICA8L2Rpdj5cclxuICB9XHJcblxyXG4gIDwhLS0gU3ViLXRhYiBiYXIg4oCUIG9ubHkgaWYgYWN0aXZlIHRhYiBoYXMgc3ViLXRhYnMgLS0+XHJcbiAgQGlmICh2aXNpYmxlU3ViVGFicy5sZW5ndGggPiAwKSB7XHJcbiAgICA8ZGl2IGNsYXNzPVwibmd4LWZvcm1fX3RhYnMgbmd4LWZvcm1fX3RhYnMtLXN1YlwiIHJvbGU9XCJ0YWJsaXN0XCIgZGF0YS10ZXN0aWQ9XCJzdWJ0YWItc3RyaXBcIiBzdHlsZT1cIm1hcmdpbi10b3A6IC0xMnB4OyBtYXJnaW4tYm90dG9tOiAxMnB4OyBmb250LXNpemU6IDEzcHg7XCI+XHJcbiAgICAgIEBmb3IgKHN1YlRhYiBvZiB2aXNpYmxlU3ViVGFiczsgdHJhY2sgc3ViVGFiLmlkKSB7XHJcbiAgICAgICAgPGJ1dHRvblxyXG4gICAgICAgICAgdHlwZT1cImJ1dHRvblwiXHJcbiAgICAgICAgICBjbGFzcz1cIm5neC1mb3JtX190YWIgbmd4LWZvcm1fX3RhYi0tc3ViXCJcclxuICAgICAgICAgIFthdHRyLmRhdGEtdGVzdGlkXT1cIidzdWJ0YWItJyArIHN1YlRhYi5pZFwiXHJcbiAgICAgICAgICBbY2xhc3Mubmd4LWZvcm1fX3RhYi0tYWN0aXZlXT1cIihhY3RpdmVTdWJUYWJDb25maWc/LmlkKSA9PT0gc3ViVGFiLmlkXCJcclxuICAgICAgICAgIChjbGljayk9XCJzZXRBY3RpdmVTdWJUYWIoc3ViVGFiLmlkKVwiXHJcbiAgICAgICAgICByb2xlPVwidGFiXCJcclxuICAgICAgICAgIFthdHRyLmFyaWEtc2VsZWN0ZWRdPVwiKGFjdGl2ZVN1YlRhYkNvbmZpZz8uaWQpID09PSBzdWJUYWIuaWRcIlxyXG4gICAgICAgID5cclxuICAgICAgICAgIHt7IHJlc29sdmVUYWJMYWJlbChzdWJUYWIpIH19XHJcbiAgICAgICAgPC9idXR0b24+XHJcbiAgICAgIH1cclxuICAgIDwvZGl2PlxyXG4gIH1cclxuXHJcbiAgPCEtLSBNb2R1bGUgdGFiIGNvbXBvbmVudCBPUiBGaWVsZHMgZm9yIGFjdGl2ZSB0YWIgLS0+XHJcbiAgQGlmIChhY3RpdmVUYWJNb2R1bGVDb21wb25lbnQpIHtcclxuICAgIDxkaXYgY2xhc3M9XCJuZ3gtZm9ybV9fbW9kdWxlLXBhbmVsXCIgZGF0YS10ZXN0aWQ9XCJtb2R1bGUtcGFuZWxcIj5cclxuICAgICAgPG5nLWNvbnRhaW5lciAqbmdDb21wb25lbnRPdXRsZXQ9XCJhY3RpdmVUYWJNb2R1bGVDb21wb25lbnQ7IGlucHV0czogKGFjdGl2ZVN1YlRhYkNvbmZpZyB8fCBhY3RpdmVUYWJDb25maWcpPy5tb2R1bGVJbnB1dHNcIj48L25nLWNvbnRhaW5lcj5cclxuICAgIDwvZGl2PlxyXG4gIH0gQGVsc2Uge1xyXG4gICAgPCEtLSBGaWVsZHMgZm9yIGFjdGl2ZSB0YWIgKFJlc3BvbnNpdmUgMTItY29sdW1uIGdyaWQpIC0tPlxyXG4gICAgPGRpdiBjbGFzcz1cIm5neC1mb3JtX19wYW5lbFwiIGRhdGEtdGVzdGlkPVwiZm9ybS1wYW5lbFwiPlxyXG4gICAgICBAZm9yIChmaWVsZCBvZiBmaWVsZHNGb3JBY3RpdmVUYWI7IHRyYWNrIGZpZWxkLmlkKSB7XHJcbiAgICAgICAgPGRpdlxyXG4gICAgICAgICAgY2xhc3M9XCJuZ3gtZm9ybV9fZmllbGQtc2xvdFwiXHJcbiAgICAgICAgICBbc3R5bGUuZ3JpZENvbHVtbl09XCJnZXRGaWVsZFNwYW4oZmllbGQpXCJcclxuICAgICAgICAgIFthdHRyLmlkXT1cIidmaWVsZC1jb250YWluZXItJyArIGZpZWxkLmlkXCJcclxuICAgICAgICA+XHJcbiAgICAgICAgICA8bmd4LWR5bmFtaWMtZmllbGRcclxuICAgICAgICAgICAgW2ZpZWxkXT1cImZpZWxkXCJcclxuICAgICAgICAgICAgW2NvbnRyb2xdPVwiZ2V0Q29udHJvbChmaWVsZC5pZCwgKGFjdGl2ZVN1YlRhYkNvbmZpZyB8fCBhY3RpdmVUYWJDb25maWcpPy5pZCkhXCJcclxuICAgICAgICAgICAgW2NvbmZpZ109XCJjb25maWdcIlxyXG4gICAgICAgICAgICBbY3VycmVudFRhYklkXT1cIihhY3RpdmVTdWJUYWJDb25maWcgfHwgYWN0aXZlVGFiQ29uZmlnKT8uaWRcIlxyXG4gICAgICAgICAgICBbbGFuZ3VhZ2VdPVwibGFuZ3VhZ2VcIlxyXG4gICAgICAgICAgICBbcmVhZG9ubHldPVwiaXNGaWVsZFJlYWRvbmx5KGZpZWxkKVwiXHJcbiAgICAgICAgICAgIFt1c2VyUm9sZXNdPVwidXNlclJvbGVzXCJcclxuICAgICAgICAgIC8+XHJcbiAgICAgICAgICBAaWYgKGZpZWxkLmNyaXRpY2FsRmllbGQgJiYgIXJlYWRvbmx5KSB7XHJcbiAgICAgICAgICAgIDxidXR0b25cclxuICAgICAgICAgICAgICB0eXBlPVwiYnV0dG9uXCJcclxuICAgICAgICAgICAgICBjbGFzcz1cIm5neC1mb3JtX19sb2NrXCJcclxuICAgICAgICAgICAgICBbYXR0ci5kYXRhLXRlc3RpZF09XCInbG9jay0nICsgZmllbGQuaWRcIlxyXG4gICAgICAgICAgICAgIFthdHRyLmFyaWEtcHJlc3NlZF09XCIhaXNGaWVsZExvY2tlZChmaWVsZClcIlxyXG4gICAgICAgICAgICAgIFthdHRyLmFyaWEtbGFiZWxdPVwiXHJcbiAgICAgICAgICAgICAgICAoaXNGaWVsZExvY2tlZChmaWVsZCkgPyAnVW5sb2NrICcgOiAnTG9jayAnKSArIHJlc29sdmVGaWVsZExhYmVsKGZpZWxkKVxyXG4gICAgICAgICAgICAgIFwiXHJcbiAgICAgICAgICAgICAgW3RpdGxlXT1cIlxyXG4gICAgICAgICAgICAgICAgaXNGaWVsZExvY2tlZChmaWVsZClcclxuICAgICAgICAgICAgICAgICAgPyAnQ3JpdGljYWwgZmllbGQg4oCUIGNsaWNrIHRvIHVubG9jayBmb3IgZWRpdGluZydcclxuICAgICAgICAgICAgICAgICAgOiAnQ3JpdGljYWwgZmllbGQg4oCUIGNsaWNrIHRvIGxvY2snXHJcbiAgICAgICAgICAgICAgXCJcclxuICAgICAgICAgICAgICAoY2xpY2spPVwidG9nZ2xlRmllbGRMb2NrKGZpZWxkKVwiXHJcbiAgICAgICAgICAgID5cclxuICAgICAgICAgICAgICB7eyBpc0ZpZWxkTG9ja2VkKGZpZWxkKSA/ICfwn5SSJyA6ICfwn5STJyB9fVxyXG4gICAgICAgICAgICA8L2J1dHRvbj5cclxuICAgICAgICAgIH1cclxuICAgICAgICA8L2Rpdj5cclxuICAgICAgfVxyXG4gICAgPC9kaXY+XHJcbiAgfVxyXG5cclxuICA8IS0tIFN1Ym1pdCBidXR0b24g4oCUIGdhdGVkIGJ5IFJCQUMgYW5kIGlzU2F2aW5nIGxvY2sgLS0+XHJcbiAgQGlmICghcmVhZG9ubHkgJiYgcGVybWlzc2lvbnMuY2FuRWRpdCkge1xyXG4gICAgPGRpdiBjbGFzcz1cIm5neC1mb3JtX19hY3Rpb25zXCIgZGF0YS10ZXN0aWQ9XCJmb3JtLWFjdGlvbnNcIj5cclxuICAgICAgPGJ1dHRvblxyXG4gICAgICAgIHR5cGU9XCJidXR0b25cIlxyXG4gICAgICAgIGNsYXNzPVwibmd4LWZvcm1fX3Jlc2V0XCJcclxuICAgICAgICBkYXRhLXRlc3RpZD1cImZvcm0tcmVzZXRcIlxyXG4gICAgICAgIChjbGljayk9XCJyZXNldCgpXCJcclxuICAgICAgICBbZGlzYWJsZWRdPVwiaXNTYXZpbmcoKVwiXHJcbiAgICAgID5cclxuICAgICAgICBSZXNldFxyXG4gICAgICA8L2J1dHRvbj5cclxuICAgICAgPGJ1dHRvblxyXG4gICAgICAgIHR5cGU9XCJzdWJtaXRcIlxyXG4gICAgICAgIGNsYXNzPVwibmd4LWZvcm1fX3N1Ym1pdFwiXHJcbiAgICAgICAgZGF0YS10ZXN0aWQ9XCJmb3JtLXN1Ym1pdFwiXHJcbiAgICAgICAgW2Rpc2FibGVkXT1cImZvcm0uaW52YWxpZFwiXHJcbiAgICAgICAgdGl0bGU9XCJTaG9ydGN1dDogQ3RybCtTXCJcclxuICAgICAgPlxyXG4gICAgICAgIEBpZiAoaXNTYXZpbmcoKSB8fCBsb2FkaW5nKSB7XHJcbiAgICAgICAgICBTYXZpbmfigKZcclxuICAgICAgICB9IEBlbHNlIHtcclxuICAgICAgICAgIFNhdmVcclxuICAgICAgICB9XHJcbiAgICAgIDwvYnV0dG9uPlxyXG4gICAgPC9kaXY+XHJcbiAgfVxyXG5cclxuPC9mb3JtPlxyXG4iXX0=