ngx-dynamic-entity 0.0.1 → 1.1.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.
- package/README.md +129 -0
- package/esm2022/lib/field-types/array-field.component.mjs +160 -0
- package/esm2022/lib/field-types/boolean-field.component.mjs +100 -0
- package/esm2022/lib/field-types/checkbox-field.component.mjs +25 -17
- package/esm2022/lib/field-types/currency-field.component.mjs +101 -0
- package/esm2022/lib/field-types/date-field.component.mjs +21 -13
- package/esm2022/lib/field-types/dropdown-field.component.mjs +120 -29
- package/esm2022/lib/field-types/email-field.component.mjs +101 -0
- package/esm2022/lib/field-types/entity-ref-field.component.mjs +96 -32
- package/esm2022/lib/field-types/file-field.component.mjs +156 -0
- package/esm2022/lib/field-types/group-field.component.mjs +89 -0
- package/esm2022/lib/field-types/image-field.component.mjs +168 -0
- package/esm2022/lib/field-types/month-year-field.component.mjs +151 -0
- package/esm2022/lib/field-types/multi-select-field.component.mjs +79 -25
- package/esm2022/lib/field-types/number-field.component.mjs +60 -17
- package/esm2022/lib/field-types/password-field.component.mjs +109 -0
- package/esm2022/lib/field-types/radio-field.component.mjs +152 -0
- package/esm2022/lib/field-types/text-field.component.mjs +58 -18
- package/esm2022/lib/field-types/textarea-field.component.mjs +26 -15
- package/esm2022/lib/form/dynamic-field/dynamic-field.component.mjs +44 -26
- package/esm2022/lib/form/dynamic-form.component.mjs +676 -69
- package/esm2022/lib/form/dynamic-record-form.component.mjs +494 -0
- package/esm2022/lib/providers/provide-field-types.mjs +72 -0
- package/esm2022/lib/providers/provide-ngx-dynamic-entity.mjs +4 -5
- package/esm2022/lib/services/cascade-data.service.mjs +129 -0
- package/esm2022/lib/services/config-source.service.mjs +67 -0
- package/esm2022/lib/services/entity-ref-cache.mjs +20 -0
- package/esm2022/lib/services/entity-ref-registry.service.mjs +3 -3
- package/esm2022/lib/services/entity-ref-selection.service.mjs +27 -0
- package/esm2022/lib/services/entity-reference.service.mjs +168 -0
- package/esm2022/lib/services/field-registry.service.mjs +35 -30
- package/esm2022/lib/services/file-upload.service.mjs +89 -0
- package/esm2022/lib/services/lookup-registry.service.mjs +246 -0
- package/esm2022/lib/services/rbac.service.mjs +5 -11
- package/esm2022/lib/services/rules-evaluation.service.mjs +27 -0
- package/esm2022/lib/services/validator-registry.service.mjs +35 -7
- package/esm2022/lib/tokens/injection-tokens.mjs +104 -7
- package/esm2022/public-api.mjs +31 -6
- package/fesm2022/ngx-dynamic-entity.mjs +4094 -759
- package/fesm2022/ngx-dynamic-entity.mjs.map +1 -1
- package/lib/field-types/array-field.component.d.ts +22 -0
- package/lib/field-types/boolean-field.component.d.ts +18 -0
- package/lib/field-types/checkbox-field.component.d.ts +3 -2
- package/lib/field-types/currency-field.component.d.ts +17 -0
- package/lib/field-types/date-field.component.d.ts +3 -2
- package/lib/field-types/dropdown-field.component.d.ts +24 -4
- package/lib/field-types/email-field.component.d.ts +15 -0
- package/lib/field-types/entity-ref-field.component.d.ts +24 -11
- package/lib/field-types/file-field.component.d.ts +25 -0
- package/lib/field-types/group-field.component.d.ts +17 -0
- package/lib/field-types/image-field.component.d.ts +30 -0
- package/lib/field-types/month-year-field.component.d.ts +28 -0
- package/lib/field-types/multi-select-field.component.d.ts +18 -4
- package/lib/field-types/number-field.component.d.ts +5 -2
- package/lib/field-types/password-field.component.d.ts +17 -0
- package/lib/field-types/radio-field.component.d.ts +33 -0
- package/lib/field-types/text-field.component.d.ts +5 -3
- package/lib/field-types/textarea-field.component.d.ts +4 -2
- package/lib/form/dynamic-field/dynamic-field.component.d.ts +20 -7
- package/lib/form/dynamic-form.component.d.ts +203 -24
- package/lib/form/dynamic-record-form.component.d.ts +180 -0
- package/lib/providers/provide-field-types.d.ts +24 -0
- package/lib/providers/provide-ngx-dynamic-entity.d.ts +19 -8
- package/lib/services/cascade-data.service.d.ts +45 -0
- package/lib/services/config-source.service.d.ts +14 -0
- package/lib/services/entity-ref-cache.d.ts +27 -0
- package/lib/services/entity-ref-registry.service.d.ts +4 -3
- package/lib/services/entity-ref-selection.service.d.ts +24 -0
- package/lib/services/entity-reference.service.d.ts +49 -0
- package/lib/services/field-registry.service.d.ts +17 -7
- package/lib/services/file-upload.service.d.ts +27 -0
- package/lib/services/lookup-registry.service.d.ts +94 -0
- package/lib/services/rbac.service.d.ts +4 -9
- package/lib/services/rules-evaluation.service.d.ts +17 -0
- package/lib/services/validator-registry.service.d.ts +5 -4
- package/lib/tokens/injection-tokens.d.ts +113 -8
- package/package.json +18 -8
- package/public-api.d.ts +21 -4
- package/esm2022/lib/services/config.service.mjs +0 -58
- package/esm2022/lib/services/version.service.mjs +0 -40
- package/esm2022/lib/table/dynamic-table.component.mjs +0 -160
- package/lib/services/config.service.d.ts +0 -25
- package/lib/services/version.service.d.ts +0 -26
- package/lib/table/dynamic-table.component.d.ts +0 -56
|
@@ -1,130 +1,719 @@
|
|
|
1
|
-
import { Component, Input, Output, EventEmitter, signal, inject, } from '@angular/core';
|
|
2
|
-
import {
|
|
1
|
+
import { Component, Input, Output, EventEmitter, signal, computed, inject, isDevMode, 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, migrateRecord, 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, RECORD_MIGRATIONS } 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
|
|
13
|
-
*
|
|
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
|
+
migrations = inject(RECORD_MIGRATIONS, { optional: true }) ?? [];
|
|
66
|
+
Object = Object;
|
|
38
67
|
// ─── Signals (local reactive state) ───────────────────────────────────────
|
|
39
68
|
activeTab = signal('');
|
|
40
|
-
|
|
69
|
+
activeSubTab = signal('');
|
|
70
|
+
isSaving = signal(false);
|
|
71
|
+
formValues = signal({});
|
|
72
|
+
/** Baseline captured at first build, used when `originalData` is not supplied. */
|
|
73
|
+
sessionBaseline = signal({});
|
|
74
|
+
/** Critical fields the user has explicitly unlocked for editing. */
|
|
75
|
+
unlockedFields = signal(new Set());
|
|
41
76
|
// ─── Form ─────────────────────────────────────────────────────────────────
|
|
42
77
|
form;
|
|
78
|
+
valueSub;
|
|
79
|
+
selectionSub;
|
|
80
|
+
/** Previous values, for detecting `patchOnTrue` false→true transitions. */
|
|
81
|
+
previousValues = {};
|
|
82
|
+
// ─── Keyboard Shortcuts ───────────────────────────────────────────────────
|
|
83
|
+
handleKeyboardEvent(event) {
|
|
84
|
+
if ((event.ctrlKey || event.metaKey) && event.key.toLowerCase() === 's') {
|
|
85
|
+
event.preventDefault();
|
|
86
|
+
if (!this.readonly && this.canSubmit && this.form?.valid) {
|
|
87
|
+
this.submit();
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
43
91
|
// ─── Computed ─────────────────────────────────────────────────────────────
|
|
92
|
+
ruleResult = computed(() => this.rulesEvaluation.evaluate(this.rules, this.formValues(), this.baseline()));
|
|
93
|
+
/**
|
|
94
|
+
* Critical fields whose value differs from the session baseline.
|
|
95
|
+
* These drive the deferred `VALUE_CHANGED` banner — a critical edit is announced once,
|
|
96
|
+
* against the value the record had when the session started, not per keystroke.
|
|
97
|
+
*/
|
|
98
|
+
changedCriticalFields = computed(() => {
|
|
99
|
+
const baseline = this.baseline();
|
|
100
|
+
if (!baseline || Object.keys(baseline).length === 0)
|
|
101
|
+
return [];
|
|
102
|
+
const values = this.formValues();
|
|
103
|
+
return this.allFields().filter(f => f.criticalField && !this.sameValue(values[f.id], baseline[f.id]));
|
|
104
|
+
});
|
|
44
105
|
get tabs() {
|
|
45
|
-
return
|
|
106
|
+
return this.config?.tabs || [];
|
|
46
107
|
}
|
|
47
|
-
get
|
|
108
|
+
get visibleTabs() {
|
|
109
|
+
const hidden = this.ruleResult().hiddenTabs;
|
|
110
|
+
return this.tabs.filter(tab => tab.visibility !== false && !hidden.includes(tab.id));
|
|
111
|
+
}
|
|
112
|
+
get activeTabConfig() {
|
|
48
113
|
const tabId = this.activeTab();
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
114
|
+
if (!tabId)
|
|
115
|
+
return this.visibleTabs[0] ?? null;
|
|
116
|
+
return findTab(this.tabs, tabId);
|
|
117
|
+
}
|
|
118
|
+
get visibleSubTabs() {
|
|
119
|
+
const active = this.activeTabConfig;
|
|
120
|
+
if (!active?.children || active.children.length === 0)
|
|
121
|
+
return [];
|
|
122
|
+
const hidden = this.ruleResult().hiddenTabs;
|
|
123
|
+
return active.children.filter(tab => tab.visibility !== false && !hidden.includes(tab.id));
|
|
124
|
+
}
|
|
125
|
+
get activeSubTabConfig() {
|
|
126
|
+
const subTabs = this.visibleSubTabs;
|
|
127
|
+
if (!subTabs.length)
|
|
128
|
+
return null;
|
|
129
|
+
const subId = this.activeSubTab();
|
|
130
|
+
return subTabs.find(s => s.id === subId) ?? subTabs[0];
|
|
131
|
+
}
|
|
132
|
+
get activeTabModuleComponent() {
|
|
133
|
+
const active = this.activeSubTabConfig ?? this.activeTabConfig;
|
|
134
|
+
if (!active?.moduleName || !this.commonModulesRegistry)
|
|
135
|
+
return null;
|
|
136
|
+
const entry = this.commonModulesRegistry.find(m => m.id === active.moduleName || m.component === active.moduleName);
|
|
137
|
+
return entry ? entry.component : null;
|
|
138
|
+
}
|
|
139
|
+
get fieldsForActiveTab() {
|
|
140
|
+
const active = this.activeSubTabConfig ?? this.activeTabConfig;
|
|
141
|
+
if (active?.moduleName)
|
|
142
|
+
return [];
|
|
143
|
+
const rawFields = active ? (active.fields || []) : ((this.config?.tabs || []).flatMap(t => t.fields || []));
|
|
144
|
+
const currentValues = this.formValues();
|
|
145
|
+
const hiddenFields = this.ruleResult().hiddenFields;
|
|
146
|
+
return rawFields.filter(field => evaluateFieldVisibility(field, currentValues) && !hiddenFields.includes(field.id));
|
|
54
147
|
}
|
|
148
|
+
/**
|
|
149
|
+
* Entity-level permissions for the current roles.
|
|
150
|
+
*
|
|
151
|
+
* Cached rather than recomputed: this is read from the template several times per change
|
|
152
|
+
* detection pass, and a fresh object each time is both wasted allocation and a new
|
|
153
|
+
* identity for anything comparing by reference. Invalidated in `ngOnChanges` when
|
|
154
|
+
* `config` or `userRoles` change, which are its only inputs.
|
|
155
|
+
*/
|
|
55
156
|
get permissions() {
|
|
56
|
-
return this.rbacService.getPermissions(this.config, this.userRoles);
|
|
157
|
+
return (this.permissionsCache ??= this.rbacService.getPermissions(this.config, this.userRoles));
|
|
57
158
|
}
|
|
58
|
-
|
|
59
|
-
|
|
159
|
+
permissionsCache = null;
|
|
160
|
+
/**
|
|
161
|
+
* Whether the current roles may see this record at all.
|
|
162
|
+
*
|
|
163
|
+
* `permissions.view` used to be computed and thrown away — a user whose roles failed it
|
|
164
|
+
* still received the complete form with every value in the DOM. It is honoured now.
|
|
165
|
+
*
|
|
166
|
+
* As with masking, this is presentational: it stops the browser rendering data, it does
|
|
167
|
+
* not stop the data reaching the browser. Authorize on the server.
|
|
168
|
+
*/
|
|
169
|
+
get canView() {
|
|
170
|
+
return this.permissions.canView;
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Whether the current roles may delete this record.
|
|
174
|
+
*
|
|
175
|
+
* The library ships no delete affordance, so this is surfaced for the consumer to gate
|
|
176
|
+
* their own — exposed rather than dropped, because a permission the schema declares
|
|
177
|
+
* should be answerable.
|
|
178
|
+
*/
|
|
179
|
+
get canDelete() {
|
|
180
|
+
return this.permissions.canDelete;
|
|
60
181
|
}
|
|
61
182
|
get canSubmit() {
|
|
62
|
-
return
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
183
|
+
return this.canView && this.permissions.canEdit && !this.readonly;
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Errors raised by `validation` rules, keyed by the target they point at.
|
|
187
|
+
*
|
|
188
|
+
* A rule can declare the record invalid independently of Angular's validators, so form
|
|
189
|
+
* validity alone is not the whole picture. `DynamicRecordFormComponent.saveSection()`
|
|
190
|
+
* has always honoured these; `submit()` did not, which meant the same rule blocked one
|
|
191
|
+
* save path and merely painted a banner on the other — and anything wiring
|
|
192
|
+
* `(formSubmit)` to persistence wrote records the rules engine had already rejected.
|
|
193
|
+
*/
|
|
194
|
+
get ruleValidationErrors() {
|
|
195
|
+
return this.ruleResult().validationErrors;
|
|
196
|
+
}
|
|
197
|
+
/** True when a `validation` rule is currently blocking submission. */
|
|
198
|
+
get hasRuleErrors() {
|
|
199
|
+
return Object.keys(this.ruleValidationErrors).length > 0;
|
|
200
|
+
}
|
|
201
|
+
/** Single source of truth for both the submit guard and the button's disabled state. */
|
|
202
|
+
get submitBlocked() {
|
|
203
|
+
return this.form.invalid || this.hasRuleErrors;
|
|
204
|
+
}
|
|
205
|
+
ngOnInit() {
|
|
206
|
+
this.selectionSub = this.entityRefSelection.selection$.subscribe(({ fieldId, option }) => {
|
|
207
|
+
this.runAutoPatch(fieldId, option?.record);
|
|
208
|
+
});
|
|
66
209
|
}
|
|
67
|
-
// ─── Lifecycle ────────────────────────────────────────────────────────────
|
|
68
210
|
ngOnChanges(changes) {
|
|
211
|
+
if (changes['config'] || changes['userRoles']) {
|
|
212
|
+
this.permissionsCache = null;
|
|
213
|
+
}
|
|
69
214
|
if (changes['config'] && this.config) {
|
|
215
|
+
// Configs arrive as plain JSON from storage or an API, where TypeScript cannot enforce
|
|
216
|
+
// the option shape. Normalise here, at the library boundary, so everything downstream
|
|
217
|
+
// can rely on an option being a LocalizedText. Returns the same object when it already
|
|
218
|
+
// is, so a well-formed config costs nothing.
|
|
219
|
+
this.config = normalizeConfigOptions(this.config);
|
|
220
|
+
}
|
|
221
|
+
if (changes['config'] || changes['initialData']) {
|
|
70
222
|
this.buildForm();
|
|
223
|
+
if (this.visibleTabs.length > 0 && !this.activeTab()) {
|
|
224
|
+
this.setActiveTab(this.visibleTabs[0].id);
|
|
225
|
+
}
|
|
71
226
|
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
227
|
+
}
|
|
228
|
+
ngOnDestroy() {
|
|
229
|
+
this.valueSub?.unsubscribe();
|
|
230
|
+
this.selectionSub?.unsubscribe();
|
|
231
|
+
}
|
|
232
|
+
setActiveTab(tabId) {
|
|
233
|
+
if (this.activeTab() !== tabId)
|
|
234
|
+
this.activeTabChange.emit(tabId);
|
|
235
|
+
this.activeTab.set(tabId);
|
|
236
|
+
const parent = findTab(this.tabs, tabId);
|
|
237
|
+
if (parent?.children?.length) {
|
|
238
|
+
this.activeSubTab.set(parent.children[0].id);
|
|
75
239
|
}
|
|
76
|
-
|
|
77
|
-
this.
|
|
240
|
+
else {
|
|
241
|
+
this.activeSubTab.set('');
|
|
78
242
|
}
|
|
79
243
|
}
|
|
244
|
+
setActiveSubTab(subTabId) {
|
|
245
|
+
this.activeSubTab.set(subTabId);
|
|
246
|
+
}
|
|
247
|
+
getFieldSpan(field) {
|
|
248
|
+
const span = field.colSpan ?? 12;
|
|
249
|
+
return `span ${Math.min(12, Math.max(1, span))}`;
|
|
250
|
+
}
|
|
251
|
+
// ─── criticalField locking ────────────────────────────────────────────────
|
|
252
|
+
/** A critical field stays read-only until the user deliberately unlocks it. */
|
|
253
|
+
isFieldLocked(field) {
|
|
254
|
+
return !!field.criticalField && !this.unlockedFields().has(field.id);
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* Whether this field renders read-only, from any of the four reasons: the whole form,
|
|
258
|
+
* the field's own flag, a caller-supplied `readOnlyFields` entry, or a criticalField lock.
|
|
259
|
+
*/
|
|
260
|
+
isFieldReadonly(field) {
|
|
261
|
+
return (this.readonly ||
|
|
262
|
+
!!field.readonly ||
|
|
263
|
+
this.readOnlyFields.includes(field.id) ||
|
|
264
|
+
this.isFieldLocked(field));
|
|
265
|
+
}
|
|
266
|
+
toggleFieldLock(field) {
|
|
267
|
+
if (!field.criticalField || this.readonly)
|
|
268
|
+
return;
|
|
269
|
+
const next = new Set(this.unlockedFields());
|
|
270
|
+
if (next.has(field.id))
|
|
271
|
+
next.delete(field.id);
|
|
272
|
+
else
|
|
273
|
+
next.add(field.id);
|
|
274
|
+
this.unlockedFields.set(next);
|
|
275
|
+
}
|
|
276
|
+
resolveFieldLabel(field) {
|
|
277
|
+
return resolveLabel(field.label, this.language);
|
|
278
|
+
}
|
|
279
|
+
// ─── Form construction ────────────────────────────────────────────────────
|
|
80
280
|
buildForm() {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
const
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
281
|
+
if (!this.config)
|
|
282
|
+
return;
|
|
283
|
+
const group = {};
|
|
284
|
+
const buildTabControls = (tabs, parentGroup) => {
|
|
285
|
+
for (const tab of tabs) {
|
|
286
|
+
if (tab.flatData) {
|
|
287
|
+
for (const field of tab.fields || []) {
|
|
288
|
+
this.buildFieldControl(field, parentGroup);
|
|
289
|
+
}
|
|
290
|
+
if (tab.children)
|
|
291
|
+
buildTabControls(tab.children, parentGroup);
|
|
292
|
+
}
|
|
293
|
+
else {
|
|
294
|
+
const tabGroup = {};
|
|
295
|
+
for (const field of tab.fields || []) {
|
|
296
|
+
this.buildFieldControl(field, tabGroup);
|
|
297
|
+
}
|
|
298
|
+
if (tab.children)
|
|
299
|
+
buildTabControls(tab.children, tabGroup);
|
|
300
|
+
parentGroup[tab.id] = this.fb.group(tabGroup);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
};
|
|
304
|
+
buildTabControls(this.config.tabs || [], group);
|
|
305
|
+
this.form = this.fb.group(group);
|
|
92
306
|
if (this.initialData) {
|
|
93
|
-
this.patchForm(this.initialData);
|
|
307
|
+
this.patchForm(this.upgradeRecord(this.initialData));
|
|
308
|
+
}
|
|
309
|
+
const initialFlattened = this.flattenFormValues();
|
|
310
|
+
this.formValues.set(initialFlattened);
|
|
311
|
+
this.previousValues = { ...initialFlattened };
|
|
312
|
+
this.sessionBaseline.set({ ...initialFlattened });
|
|
313
|
+
this.unlockedFields.set(new Set());
|
|
314
|
+
this.syncHiddenFieldState(initialFlattened);
|
|
315
|
+
if (this.preview) {
|
|
316
|
+
// Show what an array field looks like rather than an empty slot, then freeze.
|
|
317
|
+
for (const field of this.allFields()) {
|
|
318
|
+
if (field.type !== 'array')
|
|
319
|
+
continue;
|
|
320
|
+
const array = this.getArrayControl(field.id);
|
|
321
|
+
if (array && array.length === 0)
|
|
322
|
+
array.push(this.buildArrayRow(field, undefined));
|
|
323
|
+
}
|
|
324
|
+
this.form.disable({ emitEvent: false });
|
|
325
|
+
}
|
|
326
|
+
// Rebuilding must not stack subscriptions on successive config/data changes.
|
|
327
|
+
this.valueSub?.unsubscribe();
|
|
328
|
+
const changes$ = this.changeDebounceMs > 0
|
|
329
|
+
? this.form.valueChanges.pipe(debounceTime(this.changeDebounceMs))
|
|
330
|
+
: this.form.valueChanges;
|
|
331
|
+
this.valueSub = changes$.subscribe(() => {
|
|
332
|
+
const flattened = this.flattenFormValues();
|
|
333
|
+
this.formValues.set(flattened);
|
|
334
|
+
this.runPatchOnTrue(flattened);
|
|
335
|
+
this.syncHiddenFieldState(flattened);
|
|
336
|
+
this.previousValues = { ...flattened };
|
|
337
|
+
this.formChange.emit(this.extractRecord());
|
|
338
|
+
});
|
|
339
|
+
}
|
|
340
|
+
buildFieldControl(field, group) {
|
|
341
|
+
if (field.type === 'group') {
|
|
342
|
+
const subGroup = {};
|
|
343
|
+
for (const child of field.children || []) {
|
|
344
|
+
this.buildFieldControl(child, subGroup);
|
|
345
|
+
}
|
|
346
|
+
group[field.id] = this.fb.group(subGroup);
|
|
347
|
+
}
|
|
348
|
+
else if (field.type === 'array') {
|
|
349
|
+
group[field.id] = this.fb.array([]);
|
|
350
|
+
}
|
|
351
|
+
else {
|
|
352
|
+
const validators = this.validatorRegistry.resolveFromConfig(field.validators);
|
|
353
|
+
group[field.id] = this.fb.control({ value: field.defaultValue ?? null, disabled: field.disabled ?? false }, validators);
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
/** One row of an `array` field: a FormGroup when the field declares columns, else a bare control. */
|
|
357
|
+
/**
|
|
358
|
+
* The `FormArray` behind an `array` field, for callers that manage rows themselves —
|
|
359
|
+
* the record editor's inline row drawer.
|
|
360
|
+
*/
|
|
361
|
+
getArrayControl(fieldId, tabId) {
|
|
362
|
+
const ctrl = this.getControl(fieldId, tabId);
|
|
363
|
+
return ctrl instanceof FormArray ? ctrl : null;
|
|
364
|
+
}
|
|
365
|
+
/**
|
|
366
|
+
* Build one detached row for an `array` field, with the field's own validators applied.
|
|
367
|
+
* Exposed so a row can be edited outside the form and pushed on save.
|
|
368
|
+
*/
|
|
369
|
+
createArrayRow(field, value) {
|
|
370
|
+
return this.buildArrayRow(field, value);
|
|
371
|
+
}
|
|
372
|
+
buildArrayRow(field, item) {
|
|
373
|
+
if (!field?.children?.length)
|
|
374
|
+
return this.fb.control(item);
|
|
375
|
+
const rowGroup = {};
|
|
376
|
+
for (const child of field.children) {
|
|
377
|
+
this.buildFieldControl(child, rowGroup);
|
|
94
378
|
}
|
|
95
|
-
|
|
96
|
-
|
|
379
|
+
const group = this.fb.group(rowGroup);
|
|
380
|
+
if (item && typeof item === 'object')
|
|
381
|
+
group.patchValue(item);
|
|
382
|
+
return group;
|
|
383
|
+
}
|
|
384
|
+
/**
|
|
385
|
+
* Bring a record up to the config's `version` before it reaches the form.
|
|
386
|
+
*
|
|
387
|
+
* Done here because this is the one place a record enters the renderer, so a consumer
|
|
388
|
+
* cannot forget it. Migration is a no-op unless the consumer registered steps *and* the
|
|
389
|
+
* record is behind — an unstamped record is deliberately left alone (see `migrateRecord`).
|
|
390
|
+
*
|
|
391
|
+
* A missing or broken step throws from core. That is not swallowed: rendering a
|
|
392
|
+
* half-understood record would write it back in a shape matching neither schema.
|
|
393
|
+
*/
|
|
394
|
+
upgradeRecord(data) {
|
|
395
|
+
if (!this.migrations.length || !this.config)
|
|
396
|
+
return data;
|
|
397
|
+
const result = migrateRecord(data, this.config, this.migrations);
|
|
398
|
+
if (result.applied.length && isDevMode()) {
|
|
399
|
+
console.info(`[ngx-dynamic-entity] Migrated a "${this.config.entity}" record from config version ` +
|
|
400
|
+
`${result.from} to ${result.to} (steps: ${result.applied.join(', ')}).`);
|
|
97
401
|
}
|
|
402
|
+
return result.record;
|
|
98
403
|
}
|
|
99
404
|
patchForm(data) {
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
this.
|
|
405
|
+
if (!data || !this.form)
|
|
406
|
+
return;
|
|
407
|
+
const fieldsById = new Map(this.allFields().map(f => [f.id, f]));
|
|
408
|
+
const patchedFieldIds = new Set();
|
|
409
|
+
const walkTabs = (tabs) => {
|
|
410
|
+
for (const tab of tabs) {
|
|
411
|
+
const tabData = getTabData(tab.id, data, this.config);
|
|
412
|
+
for (const field of tab.fields || []) {
|
|
413
|
+
let val = tabData && typeof tabData === 'object' ? tabData[field.id] : undefined;
|
|
414
|
+
if (field.refererField) {
|
|
415
|
+
const refVal = getValueByPath(data, field.refererField);
|
|
416
|
+
if (refVal !== undefined)
|
|
417
|
+
val = refVal;
|
|
418
|
+
}
|
|
419
|
+
if (val === undefined)
|
|
420
|
+
continue;
|
|
421
|
+
const ctrl = this.getControl(field.id, tab.id);
|
|
422
|
+
if (!ctrl)
|
|
423
|
+
continue;
|
|
424
|
+
if (ctrl instanceof FormArray && Array.isArray(val)) {
|
|
425
|
+
ctrl.clear();
|
|
426
|
+
for (const item of val) {
|
|
427
|
+
ctrl.push(this.buildArrayRow(fieldsById.get(field.id), item));
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
else {
|
|
431
|
+
ctrl.patchValue(val, { emitEvent: false });
|
|
432
|
+
}
|
|
433
|
+
patchedFieldIds.add(field.id);
|
|
434
|
+
}
|
|
435
|
+
if (tab.children)
|
|
436
|
+
walkTabs(tab.children);
|
|
437
|
+
}
|
|
438
|
+
};
|
|
439
|
+
walkTabs(this.config.tabs || []);
|
|
440
|
+
this.warnUnconsumedInitialData(data, fieldsById, patchedFieldIds);
|
|
103
441
|
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
442
|
+
/**
|
|
443
|
+
* A record is nested by tab id (`{ tabId: { fieldId: value } }`) unless the tab sets
|
|
444
|
+
* `flatData: true`. Handing a flat record to a nested tab finds nothing, so the fields
|
|
445
|
+
* stay empty — with no error and no clue. That silent miss is the most expensive way to
|
|
446
|
+
* lose an hour with this library, so name it in dev builds.
|
|
447
|
+
*
|
|
448
|
+
* Only top-level keys that match a known field id are reported: anything else is assumed
|
|
449
|
+
* to be the consumer's own record metadata (ids, timestamps, `_configVersion`) and is not
|
|
450
|
+
* our business.
|
|
451
|
+
*/
|
|
452
|
+
warnUnconsumedInitialData(data, fieldsById, patchedFieldIds) {
|
|
453
|
+
if (!isDevMode() || !this.config)
|
|
454
|
+
return;
|
|
455
|
+
const tabIds = new Set();
|
|
456
|
+
const collectTabIds = (tabs) => {
|
|
457
|
+
for (const tab of tabs) {
|
|
458
|
+
tabIds.add(tab.id);
|
|
459
|
+
if (tab.children)
|
|
460
|
+
collectTabIds(tab.children);
|
|
461
|
+
}
|
|
462
|
+
};
|
|
463
|
+
collectTabIds(this.config.tabs || []);
|
|
464
|
+
const unconsumed = Object.keys(data).filter(key => !tabIds.has(key) && // a tab id at the root is the nested container, not a stray field
|
|
465
|
+
data[key] !== undefined &&
|
|
466
|
+
fieldsById.has(key) &&
|
|
467
|
+
!patchedFieldIds.has(key) &&
|
|
468
|
+
!this.warnedUnconsumedKeys.has(key));
|
|
469
|
+
if (!unconsumed.length)
|
|
470
|
+
return;
|
|
471
|
+
for (const key of unconsumed)
|
|
472
|
+
this.warnedUnconsumedKeys.add(key);
|
|
473
|
+
const shown = unconsumed.slice(0, 5).join(', ');
|
|
474
|
+
const more = unconsumed.length > 5 ? ` (+${unconsumed.length - 5} more)` : '';
|
|
475
|
+
const plural = unconsumed.length === 1;
|
|
476
|
+
console.warn(`[ngx-dynamic-entity] initialData has top-level ${plural ? 'key' : 'keys'} matching ` +
|
|
477
|
+
`${plural ? 'a field that was' : 'fields that were'} not populated: ${shown}${more}. ` +
|
|
478
|
+
`A record is nested by tab id ({ tabId: { fieldId: value } }) unless the tab sets ` +
|
|
479
|
+
`flatData: true. Either nest the value under its tab id, or set flatData: true on ` +
|
|
480
|
+
`the tab holding ${plural ? 'that field' : 'those fields'}.`);
|
|
481
|
+
}
|
|
482
|
+
/** Warn once per key per form instance — patchForm re-runs on every initialData change. */
|
|
483
|
+
warnedUnconsumedKeys = new Set();
|
|
484
|
+
/** Assemble full nested record from per-tab FormGroups, respecting flatData, refererField & arrays. */
|
|
485
|
+
extractRecord() {
|
|
486
|
+
if (!this.form || !this.config)
|
|
487
|
+
return {};
|
|
488
|
+
let record = {};
|
|
489
|
+
const walkTabs = (tabs) => {
|
|
490
|
+
for (const tab of tabs) {
|
|
491
|
+
const fieldValBag = {};
|
|
492
|
+
for (const field of tab.fields || []) {
|
|
493
|
+
const ctrl = this.getControl(field.id, tab.id);
|
|
494
|
+
if (ctrl) {
|
|
495
|
+
fieldValBag[field.id] = ctrl.value;
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
setTabData(record, tab.id, fieldValBag, this.config);
|
|
499
|
+
for (const field of tab.fields || []) {
|
|
500
|
+
if (field.refererField) {
|
|
501
|
+
const ctrl = this.getControl(field.id, tab.id);
|
|
502
|
+
if (ctrl) {
|
|
503
|
+
setValueByPath(record, field.refererField, ctrl.value);
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
if (tab.children)
|
|
508
|
+
walkTabs(tab.children);
|
|
509
|
+
}
|
|
510
|
+
};
|
|
511
|
+
walkTabs(this.config.tabs || []);
|
|
512
|
+
record = normalizeArrayStructures(record, this.config);
|
|
513
|
+
return record;
|
|
514
|
+
}
|
|
515
|
+
flattenFormValues() {
|
|
516
|
+
const out = {};
|
|
517
|
+
for (const field of this.allFields()) {
|
|
518
|
+
const ctrl = this.getControl(field.id);
|
|
519
|
+
if (ctrl)
|
|
520
|
+
out[field.id] = ctrl.value;
|
|
521
|
+
}
|
|
522
|
+
return out;
|
|
523
|
+
}
|
|
524
|
+
getTabGroup(tabId) {
|
|
525
|
+
const path = getTabPath(this.config?.tabs, tabId);
|
|
526
|
+
if (!path || path.length === 0)
|
|
527
|
+
return this.form;
|
|
528
|
+
let curr = this.form;
|
|
529
|
+
for (const p of path) {
|
|
530
|
+
if (!curr || !(curr instanceof FormGroup))
|
|
531
|
+
return null;
|
|
532
|
+
curr = curr.get(p);
|
|
533
|
+
}
|
|
534
|
+
return curr instanceof FormGroup ? curr : null;
|
|
535
|
+
}
|
|
536
|
+
// ─── autoPatch / patchOnTrue ──────────────────────────────────────────────
|
|
537
|
+
/**
|
|
538
|
+
* `autoPatch` — copy mapped fields out of the record the user just selected in an
|
|
539
|
+
* entity-ref field into the configured target tab's controls.
|
|
540
|
+
*/
|
|
541
|
+
runAutoPatch(fieldId, record) {
|
|
542
|
+
if (!record)
|
|
543
|
+
return;
|
|
544
|
+
const field = this.allFields().find(f => f.id === fieldId);
|
|
545
|
+
const autoPatch = field?.autoPatch;
|
|
546
|
+
if (!autoPatch)
|
|
547
|
+
return;
|
|
548
|
+
const patch = applyAutoPatch(autoPatch, record);
|
|
549
|
+
for (const [targetId, value] of Object.entries(patch)) {
|
|
550
|
+
const control = this.resolveTargetControl(autoPatch, targetId);
|
|
551
|
+
control?.patchValue(value);
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
/**
|
|
555
|
+
* `patchOnTrue` — when a boolean/checkbox field transitions to `true`,
|
|
556
|
+
* copy `from` → `to` within the current record.
|
|
557
|
+
*/
|
|
558
|
+
runPatchOnTrue(values) {
|
|
559
|
+
for (const field of this.allFields()) {
|
|
560
|
+
const mappings = field.patchOnTrue;
|
|
561
|
+
if (!mappings?.length)
|
|
562
|
+
continue;
|
|
563
|
+
const wasTrue = this.previousValues[field.id] === true;
|
|
564
|
+
const isTrue = values[field.id] === true;
|
|
565
|
+
if (!isTrue || wasTrue)
|
|
566
|
+
continue;
|
|
567
|
+
const patch = applyPatchOnTrue(mappings, values);
|
|
568
|
+
for (const [targetId, value] of Object.entries(patch)) {
|
|
569
|
+
this.getControl(targetId)?.patchValue(value, { emitEvent: false });
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
/** Prefer a control declared on the configured target tab; fall back to a top-level control. */
|
|
574
|
+
resolveTargetControl(autoPatch, targetId) {
|
|
575
|
+
const tab = findTab(this.tabs, autoPatch.targetTab);
|
|
576
|
+
const inTargetTab = (tab?.fields ?? []).some(f => f.id === targetId);
|
|
577
|
+
if (tab && !inTargetTab)
|
|
578
|
+
return null;
|
|
579
|
+
return this.getControl(targetId, autoPatch.targetTab);
|
|
580
|
+
}
|
|
581
|
+
// ─── Helpers ──────────────────────────────────────────────────────────────
|
|
582
|
+
/**
|
|
583
|
+
* The fields the render filter operates on — a tab's own fields, at every tab depth.
|
|
584
|
+
* Deliberately not `allFields()`: `group` and `array` children are shown or hidden with
|
|
585
|
+
* their parent, and toggling a child's state independently would fight the parent's.
|
|
586
|
+
*/
|
|
587
|
+
tabFields() {
|
|
588
|
+
const out = [];
|
|
589
|
+
const walk = (tabs) => {
|
|
590
|
+
for (const tab of tabs ?? []) {
|
|
591
|
+
out.push(...(tab.fields ?? []));
|
|
592
|
+
walk(tab.children);
|
|
593
|
+
}
|
|
594
|
+
};
|
|
595
|
+
walk(this.config?.tabs);
|
|
596
|
+
return out;
|
|
597
|
+
}
|
|
598
|
+
/**
|
|
599
|
+
* Keep a hidden field's control out of form validity.
|
|
600
|
+
*
|
|
601
|
+
* A field hidden by a rule or a `showWhen` condition is filtered out of the render, but
|
|
602
|
+
* its validators stay attached — so a hidden *required* field holds `form.invalid` true
|
|
603
|
+
* forever, permanently disabling Save with nothing on screen to explain why.
|
|
604
|
+
*
|
|
605
|
+
* Disabling is the fix rather than stripping validators: Angular excludes disabled
|
|
606
|
+
* controls from validity, and the field's own validators survive intact for when it
|
|
607
|
+
* comes back. Values are untouched — `flattenFormValues` and `extractRecord` both read
|
|
608
|
+
* `control.value`, which a disabled control still carries, so rule evaluation and the
|
|
609
|
+
* emitted record see exactly what they saw before. That also keeps this from feeding
|
|
610
|
+
* back on itself: hiding a field cannot change the values the rules are evaluated over.
|
|
611
|
+
*
|
|
612
|
+
* The visibility predicate is the same one `fieldsForActiveTab` filters with, so what is
|
|
613
|
+
* rendered and what counts toward validity cannot drift apart.
|
|
614
|
+
*/
|
|
615
|
+
syncHiddenFieldState(values) {
|
|
616
|
+
if (this.preview)
|
|
617
|
+
return; // preview freezes the whole form on purpose
|
|
618
|
+
const hiddenByRule = new Set(this.ruleResult().hiddenFields);
|
|
619
|
+
for (const field of this.tabFields()) {
|
|
620
|
+
const ctrl = this.getControl(field.id);
|
|
621
|
+
if (!ctrl)
|
|
622
|
+
continue;
|
|
623
|
+
const hidden = hiddenByRule.has(field.id) || !evaluateFieldVisibility(field, values);
|
|
624
|
+
if (hidden) {
|
|
625
|
+
if (ctrl.enabled)
|
|
626
|
+
ctrl.disable({ emitEvent: false });
|
|
627
|
+
}
|
|
628
|
+
else if (ctrl.disabled && !field.disabled) {
|
|
629
|
+
ctrl.enable({ emitEvent: false });
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
/** Every field in the config, including `group`/`array` children. */
|
|
634
|
+
allFields() {
|
|
635
|
+
const out = [];
|
|
636
|
+
const walkFields = (fields) => {
|
|
637
|
+
for (const f of fields ?? []) {
|
|
638
|
+
out.push(f);
|
|
639
|
+
if (f.children?.length)
|
|
640
|
+
walkFields(f.children);
|
|
641
|
+
}
|
|
642
|
+
};
|
|
643
|
+
const walkTabs = (tabs) => {
|
|
644
|
+
for (const t of tabs ?? []) {
|
|
645
|
+
walkFields(t.fields);
|
|
646
|
+
walkTabs(t.children);
|
|
647
|
+
}
|
|
648
|
+
};
|
|
649
|
+
walkTabs(this.config?.tabs);
|
|
650
|
+
return out;
|
|
651
|
+
}
|
|
652
|
+
/** An empty `originalData` counts as "not supplied" — fall back to the captured baseline. */
|
|
653
|
+
baseline() {
|
|
654
|
+
const supplied = this.originalData;
|
|
655
|
+
if (supplied && Object.keys(supplied).length > 0)
|
|
656
|
+
return supplied;
|
|
657
|
+
return this.sessionBaseline();
|
|
658
|
+
}
|
|
659
|
+
sameValue(a, b) {
|
|
660
|
+
if (a === b)
|
|
661
|
+
return true;
|
|
662
|
+
const aEmpty = a === null || a === undefined || a === '';
|
|
663
|
+
const bEmpty = b === null || b === undefined || b === '';
|
|
664
|
+
if (aEmpty && bEmpty)
|
|
665
|
+
return true;
|
|
666
|
+
if (typeof a === 'object' || typeof b === 'object') {
|
|
667
|
+
return JSON.stringify(a ?? null) === JSON.stringify(b ?? null);
|
|
668
|
+
}
|
|
669
|
+
return false;
|
|
670
|
+
}
|
|
671
|
+
getControl(fieldId, currentTabId) {
|
|
672
|
+
if (!this.form)
|
|
673
|
+
return null;
|
|
674
|
+
if (currentTabId) {
|
|
675
|
+
const tabGrp = this.getTabGroup(currentTabId);
|
|
676
|
+
const ctrl = tabGrp?.get(fieldId);
|
|
677
|
+
if (ctrl)
|
|
678
|
+
return ctrl;
|
|
679
|
+
}
|
|
680
|
+
const rootCtrl = this.form.get(fieldId);
|
|
681
|
+
if (rootCtrl)
|
|
682
|
+
return rootCtrl;
|
|
683
|
+
const findInGroup = (group) => {
|
|
684
|
+
for (const key of Object.keys(group.controls)) {
|
|
685
|
+
const c = group.controls[key];
|
|
686
|
+
if (key === fieldId)
|
|
687
|
+
return c;
|
|
688
|
+
if (c instanceof FormGroup) {
|
|
689
|
+
const found = findInGroup(c);
|
|
690
|
+
if (found)
|
|
691
|
+
return found;
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
return null;
|
|
695
|
+
};
|
|
696
|
+
return findInGroup(this.form);
|
|
697
|
+
}
|
|
698
|
+
resolveTabLabel(tab) {
|
|
699
|
+
return resolveLabel(tab.label, this.language);
|
|
107
700
|
}
|
|
108
701
|
async submit() {
|
|
109
|
-
if (!this.canSubmit || this.
|
|
702
|
+
if (!this.canSubmit || this.submitBlocked) {
|
|
110
703
|
this.form.markAllAsTouched();
|
|
111
704
|
return;
|
|
112
705
|
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
706
|
+
const rawData = this.extractRecord();
|
|
707
|
+
let processedData = rawData;
|
|
708
|
+
const hookKey = `${this.config?.entity}:beforeSave`;
|
|
709
|
+
if (this.hookRegistry.has(hookKey)) {
|
|
710
|
+
processedData = await this.hookRegistry.run(hookKey, processedData);
|
|
711
|
+
}
|
|
116
712
|
this.isSaving.set(true);
|
|
117
713
|
try {
|
|
118
|
-
|
|
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);
|
|
714
|
+
this.formSubmit.emit(processedData);
|
|
125
715
|
}
|
|
126
716
|
finally {
|
|
127
|
-
// Reset saving lock in the consumer's success/error handler — here we just unblock
|
|
128
717
|
this.isSaving.set(false);
|
|
129
718
|
}
|
|
130
719
|
}
|
|
@@ -132,36 +721,54 @@ export class DynamicFormComponent {
|
|
|
132
721
|
this.form.reset();
|
|
133
722
|
if (this.initialData)
|
|
134
723
|
this.patchForm(this.initialData);
|
|
724
|
+
const values = this.flattenFormValues();
|
|
725
|
+
this.formValues.set(values);
|
|
726
|
+
this.previousValues = { ...values };
|
|
727
|
+
this.unlockedFields.set(new Set());
|
|
135
728
|
this.formReset.emit();
|
|
136
729
|
}
|
|
137
|
-
getControl(fieldId) {
|
|
138
|
-
return this.form?.get(fieldId);
|
|
139
|
-
}
|
|
140
730
|
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
|
|
731
|
+
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: "@if (canView) {\n <form [formGroup]=\"form\" (ngSubmit)=\"submit()\" class=\"ngx-form\" novalidate>\n\n <!-- Error message banner -->\n @if (error) {\n <div class=\"ngx-form__error-banner\" role=\"alert\" data-testid=\"form-error\">{{ error }}</div>\n }\n\n <!-- Rules Info Banners -->\n @for (infoKey of showInfoBanners ? Object.keys(ruleResult().infoBanners) : []; track infoKey) {\n <div class=\"ngx-form__info-banner\" role=\"status\" [attr.data-testid]=\"'info-banner-' + infoKey\">\n \u2139\uFE0F {{ ruleResult().infoBanners[infoKey] }}\n </div>\n }\n\n <!-- Rules Validation Errors & Warnings -->\n @for (errKey of Object.keys(ruleResult().validationErrors); track errKey) {\n <div class=\"ngx-form__error-banner\" role=\"alert\" [attr.data-testid]=\"'rule-error-' + errKey\">\n \u26A0\uFE0F {{ ruleResult().validationErrors[errKey] }}\n </div>\n }\n @for (warnKey of Object.keys(ruleResult().validationWarnings); track warnKey) {\n <div class=\"ngx-form__warning-banner\" role=\"status\" [attr.data-testid]=\"'rule-warning-' + warnKey\">\n \u26A1 {{ ruleResult().validationWarnings[warnKey] }}\n </div>\n }\n\n <!-- Deferred VALUE_CHANGED notice for criticalField edits (vs session baseline) -->\n @if (changedCriticalFields().length > 0) {\n <div class=\"ngx-form__warning-banner\" role=\"status\" data-testid=\"critical-change-banner\">\n \uD83D\uDD12 Critical field changed:\n @for (field of changedCriticalFields(); track field.id) {\n <span>{{ resolveFieldLabel(field) }}{{ $last ? '' : ', ' }}</span>\n }\n \u2014 this differs from the value at the start of this session.\n </div>\n }\n\n <!-- Primary Tab bar \u2014 only if visible tabs defined -->\n @if (visibleTabs.length > 0) {\n <div class=\"ngx-form__tabs\" role=\"tablist\" data-testid=\"tab-strip\">\n @for (tab of visibleTabs; track tab.id) {\n <button\n type=\"button\"\n class=\"ngx-form__tab\"\n [attr.data-testid]=\"'tab-' + tab.id\"\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 {{ resolveTabLabel(tab) }}\n </button>\n }\n </div>\n }\n\n <!-- Sub-tab bar \u2014 only if active tab has sub-tabs -->\n @if (visibleSubTabs.length > 0) {\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;\">\n @for (subTab of visibleSubTabs; track subTab.id) {\n <button\n type=\"button\"\n class=\"ngx-form__tab ngx-form__tab--sub\"\n [attr.data-testid]=\"'subtab-' + subTab.id\"\n [class.ngx-form__tab--active]=\"(activeSubTabConfig?.id) === subTab.id\"\n (click)=\"setActiveSubTab(subTab.id)\"\n role=\"tab\"\n [attr.aria-selected]=\"(activeSubTabConfig?.id) === subTab.id\"\n >\n {{ resolveTabLabel(subTab) }}\n </button>\n }\n </div>\n }\n\n <!-- Module tab component OR Fields for active tab -->\n @if (activeTabModuleComponent) {\n <div class=\"ngx-form__module-panel\" data-testid=\"module-panel\">\n <ng-container *ngComponentOutlet=\"activeTabModuleComponent; inputs: (activeSubTabConfig || activeTabConfig)?.moduleInputs\"></ng-container>\n </div>\n } @else {\n <!-- Fields for active tab (Responsive 12-column grid) -->\n <div class=\"ngx-form__panel\" data-testid=\"form-panel\">\n @for (field of fieldsForActiveTab; track field.id) {\n <div\n class=\"ngx-form__field-slot\"\n [style.gridColumn]=\"getFieldSpan(field)\"\n [attr.id]=\"'field-container-' + field.id\"\n >\n <ngx-dynamic-field\n [field]=\"field\"\n [control]=\"getControl(field.id, (activeSubTabConfig || activeTabConfig)?.id)!\"\n [config]=\"config\"\n [currentTabId]=\"(activeSubTabConfig || activeTabConfig)?.id\"\n [language]=\"language\"\n [readonly]=\"isFieldReadonly(field)\"\n [userRoles]=\"userRoles\"\n />\n @if (field.criticalField && !readonly) {\n <button\n type=\"button\"\n class=\"ngx-form__lock\"\n [attr.data-testid]=\"'lock-' + field.id\"\n [attr.aria-pressed]=\"!isFieldLocked(field)\"\n [attr.aria-label]=\"\n (isFieldLocked(field) ? 'Unlock ' : 'Lock ') + resolveFieldLabel(field)\n \"\n [title]=\"\n isFieldLocked(field)\n ? 'Critical field \u2014 click to unlock for editing'\n : 'Critical field \u2014 click to lock'\n \"\n (click)=\"toggleFieldLock(field)\"\n >\n {{ isFieldLocked(field) ? '\uD83D\uDD12' : '\uD83D\uDD13' }}\n </button>\n }\n </div>\n }\n </div>\n }\n\n <!-- Submit button \u2014 gated by RBAC and isSaving lock -->\n @if (!readonly && permissions.canEdit) {\n <div class=\"ngx-form__actions\" data-testid=\"form-actions\">\n <button\n type=\"button\"\n class=\"ngx-form__reset\"\n data-testid=\"form-reset\"\n (click)=\"reset()\"\n [disabled]=\"isSaving()\"\n >\n Reset\n </button>\n <button\n type=\"submit\"\n class=\"ngx-form__submit\"\n data-testid=\"form-submit\"\n [disabled]=\"submitBlocked\"\n title=\"Shortcut: Ctrl+S\"\n >\n @if (isSaving() || loading) {\n Saving\u2026\n } @else {\n Save\n }\n </button>\n </div>\n }\n\n </form>\n} @else {\n <!-- permissions.view denied: render nothing of the record.\n Presentational only \u2014 the server must not send data this user may not see. -->\n <div class=\"ngx-form__denied\" role=\"status\" data-testid=\"form-access-denied\">\n You do not have permission to view this record.\n </div>\n}\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
732
|
}
|
|
143
733
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: DynamicFormComponent, decorators: [{
|
|
144
734
|
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
|
|
735
|
+
args: [{ selector: 'ngx-dynamic-form', standalone: true, imports: [ReactiveFormsModule, DynamicFieldComponent, NgComponentOutlet], providers: [EntityRefSelectionService], template: "@if (canView) {\n <form [formGroup]=\"form\" (ngSubmit)=\"submit()\" class=\"ngx-form\" novalidate>\n\n <!-- Error message banner -->\n @if (error) {\n <div class=\"ngx-form__error-banner\" role=\"alert\" data-testid=\"form-error\">{{ error }}</div>\n }\n\n <!-- Rules Info Banners -->\n @for (infoKey of showInfoBanners ? Object.keys(ruleResult().infoBanners) : []; track infoKey) {\n <div class=\"ngx-form__info-banner\" role=\"status\" [attr.data-testid]=\"'info-banner-' + infoKey\">\n \u2139\uFE0F {{ ruleResult().infoBanners[infoKey] }}\n </div>\n }\n\n <!-- Rules Validation Errors & Warnings -->\n @for (errKey of Object.keys(ruleResult().validationErrors); track errKey) {\n <div class=\"ngx-form__error-banner\" role=\"alert\" [attr.data-testid]=\"'rule-error-' + errKey\">\n \u26A0\uFE0F {{ ruleResult().validationErrors[errKey] }}\n </div>\n }\n @for (warnKey of Object.keys(ruleResult().validationWarnings); track warnKey) {\n <div class=\"ngx-form__warning-banner\" role=\"status\" [attr.data-testid]=\"'rule-warning-' + warnKey\">\n \u26A1 {{ ruleResult().validationWarnings[warnKey] }}\n </div>\n }\n\n <!-- Deferred VALUE_CHANGED notice for criticalField edits (vs session baseline) -->\n @if (changedCriticalFields().length > 0) {\n <div class=\"ngx-form__warning-banner\" role=\"status\" data-testid=\"critical-change-banner\">\n \uD83D\uDD12 Critical field changed:\n @for (field of changedCriticalFields(); track field.id) {\n <span>{{ resolveFieldLabel(field) }}{{ $last ? '' : ', ' }}</span>\n }\n \u2014 this differs from the value at the start of this session.\n </div>\n }\n\n <!-- Primary Tab bar \u2014 only if visible tabs defined -->\n @if (visibleTabs.length > 0) {\n <div class=\"ngx-form__tabs\" role=\"tablist\" data-testid=\"tab-strip\">\n @for (tab of visibleTabs; track tab.id) {\n <button\n type=\"button\"\n class=\"ngx-form__tab\"\n [attr.data-testid]=\"'tab-' + tab.id\"\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 {{ resolveTabLabel(tab) }}\n </button>\n }\n </div>\n }\n\n <!-- Sub-tab bar \u2014 only if active tab has sub-tabs -->\n @if (visibleSubTabs.length > 0) {\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;\">\n @for (subTab of visibleSubTabs; track subTab.id) {\n <button\n type=\"button\"\n class=\"ngx-form__tab ngx-form__tab--sub\"\n [attr.data-testid]=\"'subtab-' + subTab.id\"\n [class.ngx-form__tab--active]=\"(activeSubTabConfig?.id) === subTab.id\"\n (click)=\"setActiveSubTab(subTab.id)\"\n role=\"tab\"\n [attr.aria-selected]=\"(activeSubTabConfig?.id) === subTab.id\"\n >\n {{ resolveTabLabel(subTab) }}\n </button>\n }\n </div>\n }\n\n <!-- Module tab component OR Fields for active tab -->\n @if (activeTabModuleComponent) {\n <div class=\"ngx-form__module-panel\" data-testid=\"module-panel\">\n <ng-container *ngComponentOutlet=\"activeTabModuleComponent; inputs: (activeSubTabConfig || activeTabConfig)?.moduleInputs\"></ng-container>\n </div>\n } @else {\n <!-- Fields for active tab (Responsive 12-column grid) -->\n <div class=\"ngx-form__panel\" data-testid=\"form-panel\">\n @for (field of fieldsForActiveTab; track field.id) {\n <div\n class=\"ngx-form__field-slot\"\n [style.gridColumn]=\"getFieldSpan(field)\"\n [attr.id]=\"'field-container-' + field.id\"\n >\n <ngx-dynamic-field\n [field]=\"field\"\n [control]=\"getControl(field.id, (activeSubTabConfig || activeTabConfig)?.id)!\"\n [config]=\"config\"\n [currentTabId]=\"(activeSubTabConfig || activeTabConfig)?.id\"\n [language]=\"language\"\n [readonly]=\"isFieldReadonly(field)\"\n [userRoles]=\"userRoles\"\n />\n @if (field.criticalField && !readonly) {\n <button\n type=\"button\"\n class=\"ngx-form__lock\"\n [attr.data-testid]=\"'lock-' + field.id\"\n [attr.aria-pressed]=\"!isFieldLocked(field)\"\n [attr.aria-label]=\"\n (isFieldLocked(field) ? 'Unlock ' : 'Lock ') + resolveFieldLabel(field)\n \"\n [title]=\"\n isFieldLocked(field)\n ? 'Critical field \u2014 click to unlock for editing'\n : 'Critical field \u2014 click to lock'\n \"\n (click)=\"toggleFieldLock(field)\"\n >\n {{ isFieldLocked(field) ? '\uD83D\uDD12' : '\uD83D\uDD13' }}\n </button>\n }\n </div>\n }\n </div>\n }\n\n <!-- Submit button \u2014 gated by RBAC and isSaving lock -->\n @if (!readonly && permissions.canEdit) {\n <div class=\"ngx-form__actions\" data-testid=\"form-actions\">\n <button\n type=\"button\"\n class=\"ngx-form__reset\"\n data-testid=\"form-reset\"\n (click)=\"reset()\"\n [disabled]=\"isSaving()\"\n >\n Reset\n </button>\n <button\n type=\"submit\"\n class=\"ngx-form__submit\"\n data-testid=\"form-submit\"\n [disabled]=\"submitBlocked\"\n title=\"Shortcut: Ctrl+S\"\n >\n @if (isSaving() || loading) {\n Saving\u2026\n } @else {\n Save\n }\n </button>\n </div>\n }\n\n </form>\n} @else {\n <!-- permissions.view denied: render nothing of the record.\n Presentational only \u2014 the server must not send data this user may not see. -->\n <div class=\"ngx-form__denied\" role=\"status\" data-testid=\"form-access-denied\">\n You do not have permission to view this record.\n </div>\n}\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
736
|
}], propDecorators: { config: [{
|
|
147
737
|
type: Input
|
|
738
|
+
}], rules: [{
|
|
739
|
+
type: Input
|
|
148
740
|
}], initialData: [{
|
|
149
741
|
type: Input
|
|
742
|
+
}], originalData: [{
|
|
743
|
+
type: Input
|
|
150
744
|
}], userRoles: [{
|
|
151
745
|
type: Input
|
|
152
746
|
}], language: [{
|
|
153
747
|
type: Input
|
|
154
748
|
}], readonly: [{
|
|
155
749
|
type: Input
|
|
750
|
+
}], readOnlyFields: [{
|
|
751
|
+
type: Input
|
|
752
|
+
}], showInfoBanners: [{
|
|
753
|
+
type: Input
|
|
156
754
|
}], loading: [{
|
|
157
755
|
type: Input
|
|
158
756
|
}], error: [{
|
|
159
757
|
type: Input
|
|
758
|
+
}], changeDebounceMs: [{
|
|
759
|
+
type: Input
|
|
760
|
+
}], preview: [{
|
|
761
|
+
type: Input
|
|
160
762
|
}], formSubmit: [{
|
|
161
763
|
type: Output
|
|
162
764
|
}], formChange: [{
|
|
163
765
|
type: Output
|
|
164
766
|
}], formReset: [{
|
|
165
767
|
type: Output
|
|
768
|
+
}], activeTabChange: [{
|
|
769
|
+
type: Output
|
|
770
|
+
}], handleKeyboardEvent: [{
|
|
771
|
+
type: HostListener,
|
|
772
|
+
args: ['window:keydown', ['$event']]
|
|
166
773
|
}] } });
|
|
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
|
|
774
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZHluYW1pYy1mb3JtLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9saWIvZm9ybS9keW5hbWljLWZvcm0uY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vc3JjL2xpYi9mb3JtL2R5bmFtaWMtZm9ybS5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQ0wsU0FBUyxFQUNULEtBQUssRUFDTCxNQUFNLEVBQ04sWUFBWSxFQUtaLE1BQU0sRUFDTixRQUFRLEVBQ1IsTUFBTSxFQUNOLFNBQVMsRUFDVCxZQUFZLEdBQ2IsTUFBTSxlQUFlLENBQUM7QUFDdkIsT0FBTyxFQUFFLGlCQUFpQixFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDcEQsT0FBTyxFQUFtQixTQUFTLEVBQUUsV0FBVyxFQUFFLFNBQVMsRUFBRSxtQkFBbUIsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBRXpHLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQVE5QyxPQUFPLEVBQ0wsY0FBYyxFQUNkLGdCQUFnQixFQUNoQixhQUFhLEVBQ2IsdUJBQXVCLEVBQ3ZCLE9BQU8sRUFDUCxVQUFVLEVBQ1YsVUFBVSxFQUNWLGNBQWMsRUFDZCx3QkFBd0IsRUFDeEIsc0JBQXNCLEVBQ3RCLFlBQVksRUFDWixVQUFVLEVBQ1YsY0FBYyxHQUNmLE1BQU0sc0JBQXNCLENBQUM7QUFDOUIsT0FBTyxFQUFFLHFCQUFxQixFQUFFLE1BQU0seUNBQXlDLENBQUM7QUFDaEYsT0FBTyxFQUFFLHVCQUF1QixFQUFFLGlCQUFpQixFQUFFLE1BQU0sNEJBQTRCLENBQUM7QUFDeEYsT0FBTyxFQUFFLHdCQUF3QixFQUFFLE1BQU0sd0NBQXdDLENBQUM7QUFDbEYsT0FBTyxFQUFFLG1CQUFtQixFQUFFLE1BQU0sbUNBQW1DLENBQUM7QUFDeEUsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLDBCQUEwQixDQUFD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QUFrQixjQUNoQixJQUFJLFdBQ1AsQ0FBQyxtQkFBbUIsRUFBRSxxQkFBcUIsRUFBRSxpQkFBaUIsQ0FBQyxhQUU3RCxDQUFDLHlCQUF5QixDQUFDOzhCQWdEN0IsTUFBTTtzQkFBZCxLQUFLO2dCQUNHLEtBQUs7c0JBQWIsS0FBSztnQkFDRyxXQUFXO3NCQUFuQixLQUFLO2dCQUVHLFlBQVk7c0JBQXBCLEtBQUs7Z0JBQ0csU0FBUztzQkFBakIsS0FBSztnQkFDRyxRQUFRO3NCQUFoQixLQUFLO2dCQUNHLFFBQVE7c0JBQWhCLEtBQUs7Z0JBRUcsY0FBYztzQkFBdEIsS0FBSztnQkFLRyxlQUFlO3NCQUF2QixLQUFLO2dCQUNHLE9BQU87c0JBQWYsS0FBSztnQkFDRyxLQUFLO3NCQUFiLEtBQUs7Z0JBTUcsZ0JBQWdCO3NCQUF4QixLQUFLO2dCQUtHLE9BQU87c0JBQWYsS0FBSztnQkFHSSxVQUFVO3NCQUFuQixNQUFNO2dCQUNHLFVBQVU7c0JBQW5CLE1BQU07Z0JBQ0csU0FBUztzQkFBbEIsTUFBTTtnQkFFRyxlQUFlO3NCQUF4QixNQUFNO2dCQWtDUCxtQkFBbUI7c0JBRGxCLFlBQVk7dUJBQUMsZ0JBQWdCLEVBQUUsQ0FBQyxRQUFRLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xuICBDb21wb25lbnQsXG4gIElucHV0LFxuICBPdXRwdXQsXG4gIEV2ZW50RW1pdHRlcixcbiAgT25DaGFuZ2VzLFxuICBPbkRlc3Ryb3ksXG4gIE9uSW5pdCxcbiAgU2ltcGxlQ2hhbmdlcyxcbiAgc2lnbmFsLFxuICBjb21wdXRlZCxcbiAgaW5qZWN0LFxuICBpc0Rldk1vZGUsXG4gIEhvc3RMaXN0ZW5lcixcbn0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBOZ0NvbXBvbmVudE91dGxldCB9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbic7XG5pbXBvcnQgeyBBYnN0cmFjdENvbnRyb2wsIEZvcm1BcnJheSwgRm9ybUJ1aWxkZXIsIEZvcm1Hcm91cCwgUmVhY3RpdmVGb3Jtc01vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL2Zvcm1zJztcbmltcG9ydCB7IFN1YnNjcmlwdGlvbiB9IGZyb20gJ3J4anMnO1xuaW1wb3J0IHsgZGVib3VuY2VUaW1lIH0gZnJvbSAncnhqcy9vcGVyYXRvcnMnO1xuaW1wb3J0IHR5cGUge1xuICBBdXRvUGF0Y2hDb25maWcsXG4gIEVudGl0eUZvcm1Db25maWcsXG4gIEZvcm1SdWxlLFxuICBOZXN0ZWRGaWVsZENvbmZpZyxcbiAgTmVzdGVkVGFiQ29uZmlnLFxufSBmcm9tICdAZHluYW1pYy1lbnRpdHkvY29yZSc7XG5pbXBvcnQge1xuICBhcHBseUF1dG9QYXRjaCxcbiAgYXBwbHlQYXRjaE9uVHJ1ZSxcbiAgbWlncmF0ZVJlY29yZCxcbiAgZXZhbHVhdGVGaWVsZFZpc2liaWxpdHksXG4gIGZpbmRUYWIsXG4gIGdldFRhYkRhdGEsXG4gIGdldFRhYlBhdGgsXG4gIGdldFZhbHVlQnlQYXRoLFxuICBub3JtYWxpemVBcnJheVN0cnVjdHVyZXMsXG4gIG5vcm1hbGl6ZUNvbmZpZ09wdGlvbnMsXG4gIHJlc29sdmVMYWJlbCxcbiAgc2V0VGFiRGF0YSxcbiAgc2V0VmFsdWVCeVBhdGgsXG59IGZyb20gJ0BkeW5hbWljLWVudGl0eS9jb3JlJztcbmltcG9ydCB7IER5bmFtaWNGaWVsZENvbXBvbmVudCB9IGZyb20gJy4vZHluYW1pYy1maWVsZC9keW5hbWljLWZpZWxkLmNvbXBvbmVudCc7XG5pbXBvcnQgeyBDT01NT05fTU9EVUxFU19SRUdJU1RSWSwgUkVDT1JEX01JR1JBVElPTlMgfSBmcm9tICcuLi90b2tlbnMvaW5qZWN0aW9uLXRva2Vucyc7XG5pbXBvcnQgeyBWYWxpZGF0b3JSZWdpc3RyeVNlcnZpY2UgfSBmcm9tICcuLi9zZXJ2aWNlcy92YWxpZGF0b3ItcmVnaXN0cnkuc2VydmljZSc7XG5pbXBvcnQgeyBIb29rUmVnaXN0cnlTZXJ2aWNlIH0gZnJvbSAnLi4vc2VydmljZXMvaG9vay1yZWdpc3RyeS5zZXJ2aWNlJztcbmltcG9ydCB7IFJiYWNTZXJ2aWNlIH0gZnJvbSAnLi4vc2VydmljZXMvcmJhYy5zZXJ2aWNlJztcbmltcG9ydCB7IFJ1bGVzRXZhbHVhdGlvblNlcnZpY2UgfSBmcm9tICcuLi9zZXJ2aWNlcy9ydWxlcy1ldmFsdWF0aW9uLnNlcnZpY2UnO1xuaW1wb3J0IHsgRW50aXR5UmVmU2VsZWN0aW9uU2VydmljZSB9IGZyb20gJy4uL3NlcnZpY2VzL2VudGl0eS1yZWYtc2VsZWN0aW9uLnNlcnZpY2UnO1xuXG4vKipcbiAqIER5bmFtaWNGb3JtQ29tcG9uZW50IOKAlCB0aGUgbWFpbiBmb3JtIGNvbXBvbmVudC5cbiAqIFJlbmRlcnMgYSByZWFjdGl2ZSBmb3JtIGZyb20gRW50aXR5Rm9ybUNvbmZpZyB3aXRoIHRhYiBzdXBwb3J0LCByZXNwb25zaXZlIDEyLWNvbCBncmlkLFxuICogcnVsZXMgZXZhbHVhdGlvbiwgY29uZGl0aW9uYWwgdmlzaWJpbGl0eSwgYXV0b1BhdGNoL3BhdGNoT25UcnVlLCBjcml0aWNhbEZpZWxkIGxvY2tpbmcsXG4gKiBrZXlib2FyZCBzaG9ydGN1dHMgKEN0cmwrUywgRXNjKSwgYW5kIFJCQUMtZ2F0ZWQgc3VibWlzc2lvbi5cbiAqL1xuQENvbXBvbmVudCh7XG4gIHNlbGVjdG9yOiAnbmd4LWR5bmFtaWMtZm9ybScsXG4gIHN0YW5kYWxvbmU6IHRydWUsXG4gIGltcG9ydHM6IFtSZWFjdGl2ZUZvcm1zTW9kdWxlLCBEeW5hbWljRmllbGRDb21wb25lbnQsIE5nQ29tcG9uZW50T3V0bGV0XSxcbiAgLy8gU2NvcGVkIHBlciBmb3JtIGluc3RhbmNlOiBlbnRpdHktcmVmIHNlbGVjdGlvbnMgbXVzdCBub3QgbGVhayBiZXR3ZWVuIGNvbmN1cnJlbnQgZm9ybXMuXG4gIHByb3ZpZGVyczogW0VudGl0eVJlZlNlbGVjdGlvblNlcnZpY2VdLFxuICB0ZW1wbGF0ZVVybDogJy4vZHluYW1pYy1mb3JtLmNvbXBvbmVudC5odG1sJyxcbiAgc3R5bGVzOiBbXG4gICAgYFxuICAgICAgLm5neC1mb3JtX19wYW5lbCB7XG4gICAgICAgIGRpc3BsYXk6IGdyaWQ7XG4gICAgICAgIGdyaWQtdGVtcGxhdGUtY29sdW1uczogcmVwZWF0KDEyLCBtaW5tYXgoMCwgMWZyKSk7XG4gICAgICAgIGdhcDogMTZweCAyMHB4O1xuICAgICAgICBhbGlnbi1pdGVtczogc3RhcnQ7XG4gICAgICB9XG4gICAgICAubmd4LWZvcm1fX2ZpZWxkLXNsb3Qge1xuICAgICAgICBkaXNwbGF5OiBmbGV4O1xuICAgICAgICBhbGlnbi1pdGVtczogZmxleC1zdGFydDtcbiAgICAgICAgZ2FwOiA2cHg7XG4gICAgICAgIG1pbi13aWR0aDogMDtcbiAgICAgIH1cbiAgICAgIC5uZ3gtZm9ybV9fZmllbGQtc2xvdCBuZ3gtZHluYW1pYy1maWVsZCB7XG4gICAgICAgIGZsZXg6IDE7XG4gICAgICAgIG1pbi13aWR0aDogMDtcbiAgICAgIH1cbiAgICAgIC5uZ3gtZm9ybV9fbG9jayB7XG4gICAgICAgIGZsZXg6IDAgMCBhdXRvO1xuICAgICAgICBtYXJnaW4tdG9wOiAyMnB4O1xuICAgICAgICBiYWNrZ3JvdW5kOiBub25lO1xuICAgICAgICBib3JkZXI6IDFweCBzb2xpZCB0cmFuc3BhcmVudDtcbiAgICAgICAgYm9yZGVyLXJhZGl1czogNnB4O1xuICAgICAgICBjdXJzb3I6IHBvaW50ZXI7XG4gICAgICAgIGZvbnQtc2l6ZTogMTRweDtcbiAgICAgICAgbGluZS1oZWlnaHQ6IDE7XG4gICAgICAgIHBhZGRpbmc6IDRweCA2cHg7XG4gICAgICB9XG4gICAgICAubmd4LWZvcm1fX2xvY2s6aG92ZXIge1xuICAgICAgICBib3JkZXItY29sb3I6ICNkMWQ1ZGI7XG4gICAgICAgIGJhY2tncm91bmQ6ICNmOWZhZmI7XG4gICAgICB9XG4gICAgICBAbWVkaWEgKG1heC13aWR0aDogNzY4cHgpIHtcbiAgICAgICAgLm5neC1mb3JtX19wYW5lbCB7XG4gICAgICAgICAgZ3JpZC10ZW1wbGF0ZS1jb2x1bW5zOiAxZnI7XG4gICAgICAgIH1cbiAgICAgICAgLm5neC1mb3JtX19maWVsZC1zbG90IHtcbiAgICAgICAgICBncmlkLWNvbHVtbjogc3BhbiAxMiAhaW1wb3J0YW50O1xuICAgICAgICB9XG4gICAgICB9XG4gICAgYCxcbiAgXSxcbn0pXG5leHBvcnQgY2xhc3MgRHluYW1pY0Zvcm1Db21wb25lbnQgaW1wbGVtZW50cyBPbkluaXQsIE9uQ2hhbmdlcywgT25EZXN0cm95IHtcbiAgLy8g4pSA4pSA4pSAIElucHV0cyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcbiAgQElucHV0KCkgY29uZmlnITogRW50aXR5Rm9ybUNvbmZpZztcbiAgQElucHV0KCkgcnVsZXM/OiBGb3JtUnVsZVtdO1xuICBASW5wdXQoKSBpbml0aWFsRGF0YT86IFJlY29yZDxzdHJpbmcsIGFueT47XG4gIC8qKiBTZXNzaW9uLW9yaWdpbmFsIHZhbHVlcyBmb3IgYFZBTFVFX0NIQU5HRURgIHJ1bGVzLiBDYXB0dXJlZCBmcm9tIHRoZSBmaXJzdCBidWlsZCB3aGVuIG9taXR0ZWQuICovXG4gIEBJbnB1dCgpIG9yaWdpbmFsRGF0YT86IFJlY29yZDxzdHJpbmcsIGFueT47XG4gIEBJbnB1dCgpIHVzZXJSb2xlczogc3RyaW5nW10gPSBbXTtcbiAgQElucHV0KCkgbGFuZ3VhZ2U6IHN0cmluZyA9ICdlbic7XG4gIEBJbnB1dCgpIHJlYWRvbmx5OiBib29sZWFuID0gZmFsc2U7XG4gIC8qKiBGaWVsZCBpZHMgZm9yY2VkIHJlYWQtb25seSB3aGlsZSB0aGUgcmVzdCBvZiB0aGUgZm9ybSBzdGF5cyBlZGl0YWJsZS4gKi9cbiAgQElucHV0KCkgcmVhZE9ubHlGaWVsZHM6IHN0cmluZ1tdID0gW107XG4gIC8qKlxuICAgKiBSZW5kZXIgcnVsZSBgaW5mb2AgYmFubmVycyBpbmxpbmUuIFRoZSByZWNvcmQgZWRpdG9yIHNldHMgdGhpcyBmYWxzZSBhbmQgcmVuZGVycyBpdHNcbiAgICogb3duIGRpc21pc3NpYmxlIHZlcnNpb25zLCBzbyB0aGUgdHdvIGRvIG5vdCBkb3VibGUgdXAuXG4gICAqL1xuICBASW5wdXQoKSBzaG93SW5mb0Jhbm5lcnM6IGJvb2xlYW4gPSB0cnVlO1xuICBASW5wdXQoKSBsb2FkaW5nOiBib29sZWFuID0gZmFsc2U7XG4gIEBJbnB1dCgpIGVycm9yOiBzdHJpbmcgfCBudWxsID0gbnVsbDtcbiAgLyoqXG4gICAqIE1pbGxpc2Vjb25kcyB0byBkZWJvdW5jZSBgZm9ybUNoYW5nZWAuIFRoZSByZWZlcmVuY2UgZGVib3VuY2VzIGF0IDMwMG1zIHNvIGEgY29uc3VtZXJcbiAgICogcmUtcmVuZGVyaW5nIG9uIGV2ZXJ5IHZhbHVlIGNoYW5nZSBpcyBub3QgZHJpdmVuIHBlciBrZXlzdHJva2UuIFplcm8gZW1pdHNcbiAgICogc3luY2hyb25vdXNseSwgd2hpY2ggdGhlIHJlY29yZCBlZGl0b3IgcmVsaWVzIG9uIGZvciBpdHMgb3duIGJvb2trZWVwaW5nLlxuICAgKi9cbiAgQElucHV0KCkgY2hhbmdlRGVib3VuY2VNczogbnVtYmVyID0gMDtcbiAgLyoqXG4gICAqIFByZXZpZXcgbW9kZTogc2VlZCBvbmUgZW1wdHkgcm93IHBlciBgYXJyYXlgIGZpZWxkIHNvIHRoZSBzdHJ1Y3R1cmUgaXMgdmlzaWJsZSwgdGhlblxuICAgKiBkaXNhYmxlIHRoZSBmb3JtLiBVc2VkIGJ5IHRoZSBidWlsZGVyJ3MgbGl2ZSBwcmV2aWV3LlxuICAgKi9cbiAgQElucHV0KCkgcHJldmlldzogYm9vbGVhbiA9IGZhbHNlO1xuXG4gIC8vIOKUgOKUgOKUgCBPdXRwdXRzIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxuICBAT3V0cHV0KCkgZm9ybVN1Ym1pdCA9IG5ldyBFdmVudEVtaXR0ZXI8UmVjb3JkPHN0cmluZywgYW55Pj4oKTtcbiAgQE91dHB1dCgpIGZvcm1DaGFuZ2UgPSBuZXcgRXZlbnRFbWl0dGVyPFJlY29yZDxzdHJpbmcsIGFueT4+KCk7XG4gIEBPdXRwdXQoKSBmb3JtUmVzZXQgPSBuZXcgRXZlbnRFbWl0dGVyPHZvaWQ+KCk7XG4gIC8qKiBUaGUgdmlzaWJsZSB0YWIgY2hhbmdlZC4gTGV0cyBhIGhvc3QgdHJhY2sgaXQgd2l0aG91dCByZWFjaGluZyBpbnRvIHRoaXMgY29tcG9uZW50LiAqL1xuICBAT3V0cHV0KCkgYWN0aXZlVGFiQ2hhbmdlID0gbmV3IEV2ZW50RW1pdHRlcjxzdHJpbmc+KCk7XG5cbiAgLy8g4pSA4pSA4pSAIFNlcnZpY2VzIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxuICBwcml2YXRlIHJlYWRvbmx5IGZiID0gaW5qZWN0KEZvcm1CdWlsZGVyKTtcbiAgcHJpdmF0ZSByZWFkb25seSB2YWxpZGF0b3JSZWdpc3RyeSA9IGluamVjdChWYWxpZGF0b3JSZWdpc3RyeVNlcnZpY2UpO1xuICBwcml2YXRlIHJlYWRvbmx5IGhvb2tSZWdpc3RyeSA9IGluamVjdChIb29rUmVnaXN0cnlTZXJ2aWNlKTtcbiAgcHJpdmF0ZSByZWFkb25seSByYmFjU2VydmljZSA9IGluamVjdChSYmFjU2VydmljZSk7XG4gIHByaXZhdGUgcmVhZG9ubHkgcnVsZXNFdmFsdWF0aW9uID0gaW5qZWN0KFJ1bGVzRXZhbHVhdGlvblNlcnZpY2UpO1xuICBwcml2YXRlIHJlYWRvbmx5IGVudGl0eVJlZlNlbGVjdGlvbiA9IGluamVjdChFbnRpdHlSZWZTZWxlY3Rpb25TZXJ2aWNlKTtcbiAgcHJpdmF0ZSByZWFkb25seSBjb21tb25Nb2R1bGVzUmVnaXN0cnkgPSBpbmplY3QoQ09NTU9OX01PRFVMRVNfUkVHSVNUUlksIHsgb3B0aW9uYWw6IHRydWUgfSk7XG4gIHByaXZhdGUgcmVhZG9ubHkgbWlncmF0aW9ucyA9IGluamVjdChSRUNPUkRfTUlHUkFUSU9OUywgeyBvcHRpb25hbDogdHJ1ZSB9KSA/PyBbXTtcblxuICBwcm90ZWN0ZWQgcmVhZG9ubHkgT2JqZWN0ID0gT2JqZWN0O1xuXG4gIC8vIOKUgOKUgOKUgCBTaWduYWxzIChsb2NhbCByZWFjdGl2ZSBzdGF0ZSkg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG4gIHJlYWRvbmx5IGFjdGl2ZVRhYiA9IHNpZ25hbDxzdHJpbmc+KCcnKTtcbiAgcmVhZG9ubHkgYWN0aXZlU3ViVGFiID0gc2lnbmFsPHN0cmluZz4oJycpO1xuICByZWFkb25seSBpc1NhdmluZyA9IHNpZ25hbChmYWxzZSk7XG4gIHJlYWRvbmx5IGZvcm1WYWx1ZXMgPSBzaWduYWw8UmVjb3JkPHN0cmluZywgYW55Pj4oe30pO1xuICAvKiogQmFzZWxpbmUgY2FwdHVyZWQgYXQgZmlyc3QgYnVpbGQsIHVzZWQgd2hlbiBgb3JpZ2luYWxEYXRhYCBpcyBub3Qgc3VwcGxpZWQuICovXG4gIHJlYWRvbmx5IHNlc3Npb25CYXNlbGluZSA9IHNpZ25hbDxSZWNvcmQ8c3RyaW5nLCBhbnk+Pih7fSk7XG4gIC8qKiBDcml0aWNhbCBmaWVsZHMgdGhlIHVzZXIgaGFzIGV4cGxpY2l0bHkgdW5sb2NrZWQgZm9yIGVkaXRpbmcuICovXG4gIHJlYWRvbmx5IHVubG9ja2VkRmllbGRzID0gc2lnbmFsPFJlYWRvbmx5U2V0PHN0cmluZz4+KG5ldyBTZXQ8c3RyaW5nPigpKTtcblxuICAvLyDilIDilIDilIAgRm9ybSDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcbiAgZm9ybSE6IEZvcm1Hcm91cDtcblxuICBwcml2YXRlIHZhbHVlU3ViPzogU3Vic2NyaXB0aW9uO1xuICBwcml2YXRlIHNlbGVjdGlvblN1Yj86IFN1YnNjcmlwdGlvbjtcbiAgLyoqIFByZXZpb3VzIHZhbHVlcywgZm9yIGRldGVjdGluZyBgcGF0Y2hPblRydWVgIGZhbHNl4oaSdHJ1ZSB0cmFuc2l0aW9ucy4gKi9cbiAgcHJpdmF0ZSBwcmV2aW91c1ZhbHVlczogUmVjb3JkPHN0cmluZywgYW55PiA9IHt9O1xuXG4gIC8vIOKUgOKUgOKUgCBLZXlib2FyZCBTaG9ydGN1dHMg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG4gIEBIb3N0TGlzdGVuZXIoJ3dpbmRvdzprZXlkb3duJywgWyckZXZlbnQnXSlcbiAgaGFuZGxlS2V5Ym9hcmRFdmVudChldmVudDogS2V5Ym9hcmRFdmVudCk6IHZvaWQge1xuICAgIGlmICgoZXZlbnQuY3RybEtleSB8fCBldmVudC5tZXRhS2V5KSAmJiBldmVudC5rZXkudG9Mb3dlckNhc2UoKSA9PT0gJ3MnKSB7XG4gICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgaWYgKCF0aGlzLnJlYWRvbmx5ICYmIHRoaXMuY2FuU3VibWl0ICYmIHRoaXMuZm9ybT8udmFsaWQpIHtcbiAgICAgICAgdGhpcy5zdWJtaXQoKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICAvLyDilIDilIDilIAgQ29tcHV0ZWQg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG4gIHJlYWRvbmx5IHJ1bGVSZXN1bHQgPSBjb21wdXRlZCgoKSA9PlxuICAgIHRoaXMucnVsZXNFdmFsdWF0aW9uLmV2YWx1YXRlKHRoaXMucnVsZXMsIHRoaXMuZm9ybVZhbHVlcygpLCB0aGlzLmJhc2VsaW5lKCkpLFxuICApO1xuXG4gIC8qKlxuICAgKiBDcml0aWNhbCBmaWVsZHMgd2hvc2UgdmFsdWUgZGlmZmVycyBmcm9tIHRoZSBzZXNzaW9uIGJhc2VsaW5lLlxuICAgKiBUaGVzZSBkcml2ZSB0aGUgZGVmZXJyZWQgYFZBTFVFX0NIQU5HRURgIGJhbm5lciDigJQgYSBjcml0aWNhbCBlZGl0IGlzIGFubm91bmNlZCBvbmNlLFxuICAgKiBhZ2FpbnN0IHRoZSB2YWx1ZSB0aGUgcmVjb3JkIGhhZCB3aGVuIHRoZSBzZXNzaW9uIHN0YXJ0ZWQsIG5vdCBwZXIga2V5c3Ryb2tlLlxuICAgKi9cbiAgcmVhZG9ubHkgY2hhbmdlZENyaXRpY2FsRmllbGRzID0gY29tcHV0ZWQ8TmVzdGVkRmllbGRDb25maWdbXT4oKCkgPT4ge1xuICAgIGNvbnN0IGJhc2VsaW5lID0gdGhpcy5iYXNlbGluZSgpO1xuICAgIGlmICghYmFzZWxpbmUgfHwgT2JqZWN0LmtleXMoYmFzZWxpbmUpLmxlbmd0aCA9PT0gMCkgcmV0dXJuIFtdO1xuICAgIGNvbnN0IHZhbHVlcyA9IHRoaXMuZm9ybVZhbHVlcygpO1xuICAgIHJldHVybiB0aGlzLmFsbEZpZWxkcygpLmZpbHRlcihcbiAgICAgIGYgPT4gZi5jcml0aWNhbEZpZWxkICYmICF0aGlzLnNhbWVWYWx1ZSh2YWx1ZXNbZi5pZF0sIGJhc2VsaW5lW2YuaWRdKSxcbiAgICApO1xuICB9KTtcblxuICBnZXQgdGFicygpOiBOZXN0ZWRUYWJDb25maWdbXSB7XG4gICAgcmV0dXJuIHRoaXMuY29uZmlnPy50YWJzIHx8IFtdO1xuICB9XG5cbiAgZ2V0IHZpc2libGVUYWJzKCk6IE5lc3RlZFRhYkNvbmZpZ1tdIHtcbiAgICBjb25zdCBoaWRkZW4gPSB0aGlzLnJ1bGVSZXN1bHQoKS5oaWRkZW5UYWJzO1xuICAgIHJldHVybiB0aGlzLnRhYnMuZmlsdGVyKHRhYiA9PiB0YWIudmlzaWJpbGl0eSAhPT0gZmFsc2UgJiYgIWhpZGRlbi5pbmNsdWRlcyh0YWIuaWQpKTtcbiAgfVxuXG4gIGdldCBhY3RpdmVUYWJDb25maWcoKTogTmVzdGVkVGFiQ29uZmlnIHwgbnVsbCB7XG4gICAgY29uc3QgdGFiSWQgPSB0aGlzLmFjdGl2ZVRhYigpO1xuICAgIGlmICghdGFiSWQpIHJldHVybiB0aGlzLnZpc2libGVUYWJzWzBdID8/IG51bGw7XG4gICAgcmV0dXJuIGZpbmRUYWIodGhpcy50YWJzLCB0YWJJZCk7XG4gIH1cblxuICBnZXQgdmlzaWJsZVN1YlRhYnMoKTogTmVzdGVkVGFiQ29uZmlnW10ge1xuICAgIGNvbnN0IGFjdGl2ZSA9IHRoaXMuYWN0aXZlVGFiQ29uZmlnO1xuICAgIGlmICghYWN0aXZlPy5jaGlsZHJlbiB8fCBhY3RpdmUuY2hpbGRyZW4ubGVuZ3RoID09PSAwKSByZXR1cm4gW107XG4gICAgY29uc3QgaGlkZGVuID0gdGhpcy5ydWxlUmVzdWx0KCkuaGlkZGVuVGFicztcbiAgICByZXR1cm4gYWN0aXZlLmNoaWxkcmVuLmZpbHRlcih0YWIgPT4gdGFiLnZpc2liaWxpdHkgIT09IGZhbHNlICYmICFoaWRkZW4uaW5jbHVkZXModGFiLmlkKSk7XG4gIH1cblxuICBnZXQgYWN0aXZlU3ViVGFiQ29uZmlnKCk6IE5lc3RlZFRhYkNvbmZpZyB8IG51bGwge1xuICAgIGNvbnN0IHN1YlRhYnMgPSB0aGlzLnZpc2libGVTdWJUYWJzO1xuICAgIGlmICghc3ViVGFicy5sZW5ndGgpIHJldHVybiBudWxsO1xuICAgIGNvbnN0IHN1YklkID0gdGhpcy5hY3RpdmVTdWJUYWIoKTtcbiAgICByZXR1cm4gc3ViVGFicy5maW5kKHMgPT4gcy5pZCA9PT0gc3ViSWQpID8/IHN1YlRhYnNbMF07XG4gIH1cblxuICBnZXQgYWN0aXZlVGFiTW9kdWxlQ29tcG9uZW50KCk6IGFueSB8IG51bGwge1xuICAgIGNvbnN0IGFjdGl2ZSA9IHRoaXMuYWN0aXZlU3ViVGFiQ29uZmlnID8/IHRoaXMuYWN0aXZlVGFiQ29uZmlnO1xuICAgIGlmICghYWN0aXZlPy5tb2R1bGVOYW1lIHx8ICF0aGlzLmNvbW1vbk1vZHVsZXNSZWdpc3RyeSkgcmV0dXJuIG51bGw7XG4gICAgY29uc3QgZW50cnkgPSB0aGlzLmNvbW1vbk1vZHVsZXNSZWdpc3RyeS5maW5kKFxuICAgICAgbSA9PiBtLmlkID09PSBhY3RpdmUubW9kdWxlTmFtZSB8fCBtLmNvbXBvbmVudCA9PT0gYWN0aXZlLm1vZHVsZU5hbWUsXG4gICAgKTtcbiAgICByZXR1cm4gZW50cnkgPyBlbnRyeS5jb21wb25lbnQgOiBudWxsO1xuICB9XG5cbiAgZ2V0IGZpZWxkc0ZvckFjdGl2ZVRhYigpOiBOZXN0ZWRGaWVsZENvbmZpZ1tdIHtcbiAgICBjb25zdCBhY3RpdmUgPSB0aGlzLmFjdGl2ZVN1YlRhYkNvbmZpZyA/PyB0aGlzLmFjdGl2ZVRhYkNvbmZpZztcbiAgICBpZiAoYWN0aXZlPy5tb2R1bGVOYW1lKSByZXR1cm4gW107XG4gICAgY29uc3QgcmF3RmllbGRzID0gYWN0aXZlID8gKGFjdGl2ZS5maWVsZHMgfHwgW10pIDogKCh0aGlzLmNvbmZpZz8udGFicyB8fCBbXSkuZmxhdE1hcCh0ID0+IHQuZmllbGRzIHx8IFtdKSk7XG4gICAgY29uc3QgY3VycmVudFZhbHVlcyA9IHRoaXMuZm9ybVZhbHVlcygpO1xuICAgIGNvbnN0IGhpZGRlbkZpZWxkcyA9IHRoaXMucnVsZVJlc3VsdCgpLmhpZGRlbkZpZWxkcztcblxuICAgIHJldHVybiByYXdGaWVsZHMuZmlsdGVyKFxuICAgICAgZmllbGQgPT4gZXZhbHVhdGVGaWVsZFZpc2liaWxpdHkoZmllbGQsIGN1cnJlbnRWYWx1ZXMpICYmICFoaWRkZW5GaWVsZHMuaW5jbHVkZXMoZmllbGQuaWQpLFxuICAgICk7XG4gIH1cblxuICAvKipcbiAgICogRW50aXR5LWxldmVsIHBlcm1pc3Npb25zIGZvciB0aGUgY3VycmVudCByb2xlcy5cbiAgICpcbiAgICogQ2FjaGVkIHJhdGhlciB0aGFuIHJlY29tcHV0ZWQ6IHRoaXMgaXMgcmVhZCBmcm9tIHRoZSB0ZW1wbGF0ZSBzZXZlcmFsIHRpbWVzIHBlciBjaGFuZ2VcbiAgICogZGV0ZWN0aW9uIHBhc3MsIGFuZCBhIGZyZXNoIG9iamVjdCBlYWNoIHRpbWUgaXMgYm90aCB3YXN0ZWQgYWxsb2NhdGlvbiBhbmQgYSBuZXdcbiAgICogaWRlbnRpdHkgZm9yIGFueXRoaW5nIGNvbXBhcmluZyBieSByZWZlcmVuY2UuIEludmFsaWRhdGVkIGluIGBuZ09uQ2hhbmdlc2Agd2hlblxuICAgKiBgY29uZmlnYCBvciBgdXNlclJvbGVzYCBjaGFuZ2UsIHdoaWNoIGFyZSBpdHMgb25seSBpbnB1dHMuXG4gICAqL1xuICBnZXQgcGVybWlzc2lvbnMoKTogUmV0dXJuVHlwZTxSYmFjU2VydmljZVsnZ2V0UGVybWlzc2lvbnMnXT4ge1xuICAgIHJldHVybiAodGhpcy5wZXJtaXNzaW9uc0NhY2hlID8/PSB0aGlzLnJiYWNTZXJ2aWNlLmdldFBlcm1pc3Npb25zKHRoaXMuY29uZmlnLCB0aGlzLnVzZXJSb2xlcykpO1xuICB9XG5cbiAgcHJpdmF0ZSBwZXJtaXNzaW9uc0NhY2hlOiBSZXR1cm5UeXBlPFJiYWNTZXJ2aWNlWydnZXRQZXJtaXNzaW9ucyddPiB8IG51bGwgPSBudWxsO1xuXG4gIC8qKlxuICAgKiBXaGV0aGVyIHRoZSBjdXJyZW50IHJvbGVzIG1heSBzZWUgdGhpcyByZWNvcmQgYXQgYWxsLlxuICAgKlxuICAgKiBgcGVybWlzc2lvbnMudmlld2AgdXNlZCB0byBiZSBjb21wdXRlZCBhbmQgdGhyb3duIGF3YXkg4oCUIGEgdXNlciB3aG9zZSByb2xlcyBmYWlsZWQgaXRcbiAgICogc3RpbGwgcmVjZWl2ZWQgdGhlIGNvbXBsZXRlIGZvcm0gd2l0aCBldmVyeSB2YWx1ZSBpbiB0aGUgRE9NLiBJdCBpcyBob25vdXJlZCBub3cuXG4gICAqXG4gICAqIEFzIHdpdGggbWFza2luZywgdGhpcyBpcyBwcmVzZW50YXRpb25hbDogaXQgc3RvcHMgdGhlIGJyb3dzZXIgcmVuZGVyaW5nIGRhdGEsIGl0IGRvZXNcbiAgICogbm90IHN0b3AgdGhlIGRhdGEgcmVhY2hpbmcgdGhlIGJyb3dzZXIuIEF1dGhvcml6ZSBvbiB0aGUgc2VydmVyLlxuICAgKi9cbiAgZ2V0IGNhblZpZXcoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMucGVybWlzc2lvbnMuY2FuVmlldztcbiAgfVxuXG4gIC8qKlxuICAgKiBXaGV0aGVyIHRoZSBjdXJyZW50IHJvbGVzIG1heSBkZWxldGUgdGhpcyByZWNvcmQuXG4gICAqXG4gICAqIFRoZSBsaWJyYXJ5IHNoaXBzIG5vIGRlbGV0ZSBhZmZvcmRhbmNlLCBzbyB0aGlzIGlzIHN1cmZhY2VkIGZvciB0aGUgY29uc3VtZXIgdG8gZ2F0ZVxuICAgKiB0aGVpciBvd24g4oCUIGV4cG9zZWQgcmF0aGVyIHRoYW4gZHJvcHBlZCwgYmVjYXVzZSBhIHBlcm1pc3Npb24gdGhlIHNjaGVtYSBkZWNsYXJlc1xuICAgKiBzaG91bGQgYmUgYW5zd2VyYWJsZS5cbiAgICovXG4gIGdldCBjYW5EZWxldGUoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMucGVybWlzc2lvbnMuY2FuRGVsZXRlO1xuICB9XG5cbiAgZ2V0IGNhblN1Ym1pdCgpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy5jYW5WaWV3ICYmIHRoaXMucGVybWlzc2lvbnMuY2FuRWRpdCAmJiAhdGhpcy5yZWFkb25seTtcbiAgfVxuXG4gIC8qKlxuICAgKiBFcnJvcnMgcmFpc2VkIGJ5IGB2YWxpZGF0aW9uYCBydWxlcywga2V5ZWQgYnkgdGhlIHRhcmdldCB0aGV5IHBvaW50IGF0LlxuICAgKlxuICAgKiBBIHJ1bGUgY2FuIGRlY2xhcmUgdGhlIHJlY29yZCBpbnZhbGlkIGluZGVwZW5kZW50bHkgb2YgQW5ndWxhcidzIHZhbGlkYXRvcnMsIHNvIGZvcm1cbiAgICogdmFsaWRpdHkgYWxvbmUgaXMgbm90IHRoZSB3aG9sZSBwaWN0dXJlLiBgRHluYW1pY1JlY29yZEZvcm1Db21wb25lbnQuc2F2ZVNlY3Rpb24oKWBcbiAgICogaGFzIGFsd2F5cyBob25vdXJlZCB0aGVzZTsgYHN1Ym1pdCgpYCBkaWQgbm90LCB3aGljaCBtZWFudCB0aGUgc2FtZSBydWxlIGJsb2NrZWQgb25lXG4gICAqIHNhdmUgcGF0aCBhbmQgbWVyZWx5IHBhaW50ZWQgYSBiYW5uZXIgb24gdGhlIG90aGVyIOKAlCBhbmQgYW55dGhpbmcgd2lyaW5nXG4gICAqIGAoZm9ybVN1Ym1pdClgIHRvIHBlcnNpc3RlbmNlIHdyb3RlIHJlY29yZHMgdGhlIHJ1bGVzIGVuZ2luZSBoYWQgYWxyZWFkeSByZWplY3RlZC5cbiAgICovXG4gIGdldCBydWxlVmFsaWRhdGlvbkVycm9ycygpOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+IHtcbiAgICByZXR1cm4gdGhpcy5ydWxlUmVzdWx0KCkudmFsaWRhdGlvbkVycm9ycztcbiAgfVxuXG4gIC8qKiBUcnVlIHdoZW4gYSBgdmFsaWRhdGlvbmAgcnVsZSBpcyBjdXJyZW50bHkgYmxvY2tpbmcgc3VibWlzc2lvbi4gKi9cbiAgZ2V0IGhhc1J1bGVFcnJvcnMoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIE9iamVjdC5rZXlzKHRoaXMucnVsZVZhbGlkYXRpb25FcnJvcnMpLmxlbmd0aCA+IDA7XG4gIH1cblxuICAvKiogU2luZ2xlIHNvdXJjZSBvZiB0cnV0aCBmb3IgYm90aCB0aGUgc3VibWl0IGd1YXJkIGFuZCB0aGUgYnV0dG9uJ3MgZGlzYWJsZWQgc3RhdGUuICovXG4gIGdldCBzdWJtaXRCbG9ja2VkKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLmZvcm0uaW52YWxpZCB8fCB0aGlzLmhhc1J1bGVFcnJvcnM7XG4gIH1cblxuICBuZ09uSW5pdCgpOiB2b2lkIHtcbiAgICB0aGlzLnNlbGVjdGlvblN1YiA9IHRoaXMuZW50aXR5UmVmU2VsZWN0aW9uLnNlbGVjdGlvbiQuc3Vic2NyaWJlKCh7IGZpZWxkSWQsIG9wdGlvbiB9KSA9PiB7XG4gICAgICB0aGlzLnJ1bkF1dG9QYXRjaChmaWVsZElkLCBvcHRpb24/LnJlY29yZCk7XG4gICAgfSk7XG4gIH1cblxuICBuZ09uQ2hhbmdlcyhjaGFuZ2VzOiBTaW1wbGVDaGFuZ2VzKTogdm9pZCB7XG4gICAgaWYgKGNoYW5nZXNbJ2NvbmZpZyddIHx8IGNoYW5nZXNbJ3VzZXJSb2xlcyddKSB7XG4gICAgICB0aGlzLnBlcm1pc3Npb25zQ2FjaGUgPSBudWxsO1xuICAgIH1cbiAgICBpZiAoY2hhbmdlc1snY29uZmlnJ10gJiYgdGhpcy5jb25maWcpIHtcbiAgICAgIC8vIENvbmZpZ3MgYXJyaXZlIGFzIHBsYWluIEpTT04gZnJvbSBzdG9yYWdlIG9yIGFuIEFQSSwgd2hlcmUgVHlwZVNjcmlwdCBjYW5ub3QgZW5mb3JjZVxuICAgICAgLy8gdGhlIG9wdGlvbiBzaGFwZS4gTm9ybWFsaXNlIGhlcmUsIGF0IHRoZSBsaWJyYXJ5IGJvdW5kYXJ5LCBzbyBldmVyeXRoaW5nIGRvd25zdHJlYW1cbiAgICAgIC8vIGNhbiByZWx5IG9uIGFuIG9wdGlvbiBiZWluZyBhIExvY2FsaXplZFRleHQuIFJldHVybnMgdGhlIHNhbWUgb2JqZWN0IHdoZW4gaXQgYWxyZWFkeVxuICAgICAgLy8gaXMsIHNvIGEgd2VsbC1mb3JtZWQgY29uZmlnIGNvc3RzIG5vdGhpbmcuXG4gICAgICB0aGlzLmNvbmZpZyA9IG5vcm1hbGl6ZUNvbmZpZ09wdGlvbnModGhpcy5jb25maWcpO1xuICAgIH1cbiAgICBpZiAoY2hhbmdlc1snY29uZmlnJ10gfHwgY2hhbmdlc1snaW5pdGlhbERhdGEnXSkge1xuICAgICAgdGhpcy5idWlsZEZvcm0oKTtcbiAgICAgIGlmICh0aGlzLnZpc2libGVUYWJzLmxlbmd0aCA+IDAgJiYgIXRoaXMuYWN0aXZlVGFiKCkpIHtcbiAgICAgICAgdGhpcy5zZXRBY3RpdmVUYWIodGhpcy52aXNpYmxlVGFic1swXS5pZCk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgbmdPbkRlc3Ryb3koKTogdm9pZCB7XG4gICAgdGhpcy52YWx1ZVN1Yj8udW5zdWJzY3JpYmUoKTtcbiAgICB0aGlzLnNlbGVjdGlvblN1Yj8udW5zdWJzY3JpYmUoKTtcbiAgfVxuXG4gIHNldEFjdGl2ZVRhYih0YWJJZDogc3RyaW5nKTogdm9pZCB7XG4gICAgaWYgKHRoaXMuYWN0aXZlVGFiKCkgIT09IHRhYklkKSB0aGlzLmFjdGl2ZVRhYkNoYW5nZS5lbWl0KHRhYklkKTtcbiAgICB0aGlzLmFjdGl2ZVRhYi5zZXQodGFiSWQpO1xuICAgIGNvbnN0IHBhcmVudCA9IGZpbmRUYWIodGhpcy50YWJzLCB0YWJJZCk7XG4gICAgaWYgKHBhcmVudD8uY2hpbGRyZW4/Lmxlbmd0aCkge1xuICAgICAgdGhpcy5hY3RpdmVTdWJUYWIuc2V0KHBhcmVudC5jaGlsZHJlblswXS5pZCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMuYWN0aXZlU3ViVGFiLnNldCgnJyk7XG4gICAgfVxuICB9XG5cbiAgc2V0QWN0aXZlU3ViVGFiKHN1YlRhYklkOiBzdHJpbmcpOiB2b2lkIHtcbiAgICB0aGlzLmFjdGl2ZVN1YlRhYi5zZXQoc3ViVGFiSWQpO1xuICB9XG5cbiAgZ2V0RmllbGRTcGFuKGZpZWxkOiBOZXN0ZWRGaWVsZENvbmZpZyk6IHN0cmluZyB7XG4gICAgY29uc3Qgc3BhbiA9IGZpZWxkLmNvbFNwYW4gPz8gMTI7XG4gICAgcmV0dXJuIGBzcGFuICR7TWF0aC5taW4oMTIsIE1hdGgubWF4KDEsIHNwYW4pKX1gO1xuICB9XG5cbiAgLy8g4pSA4pSA4pSAIGNyaXRpY2FsRmllbGQgbG9ja2luZyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcblxuICAvKiogQSBjcml0aWNhbCBmaWVsZCBzdGF5cyByZWFkLW9ubHkgdW50aWwgdGhlIHVzZXIgZGVsaWJlcmF0ZWx5IHVubG9ja3MgaXQuICovXG4gIGlzRmllbGRMb2NrZWQoZmllbGQ6IE5lc3RlZEZpZWxkQ29uZmlnKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuICEhZmllbGQuY3JpdGljYWxGaWVsZCAmJiAhdGhpcy51bmxvY2tlZEZpZWxkcygpLmhhcyhmaWVsZC5pZCk7XG4gIH1cblxuICAvKipcbiAgICogV2hldGhlciB0aGlzIGZpZWxkIHJlbmRlcnMgcmVhZC1vbmx5LCBmcm9tIGFueSBvZiB0aGUgZm91ciByZWFzb25zOiB0aGUgd2hvbGUgZm9ybSxcbiAgICogdGhlIGZpZWxkJ3Mgb3duIGZsYWcsIGEgY2FsbGVyLXN1cHBsaWVkIGByZWFkT25seUZpZWxkc2AgZW50cnksIG9yIGEgY3JpdGljYWxGaWVsZCBsb2NrLlxuICAgKi9cbiAgaXNGaWVsZFJlYWRvbmx5KGZpZWxkOiBOZXN0ZWRGaWVsZENvbmZpZyk6IGJvb2xlYW4ge1xuICAgIHJldHVybiAoXG4gICAgICB0aGlzLnJlYWRvbmx5IHx8XG4gICAgICAhIWZpZWxkLnJlYWRvbmx5IHx8XG4gICAgICB0aGlzLnJlYWRPbmx5RmllbGRzLmluY2x1ZGVzKGZpZWxkLmlkKSB8fFxuICAgICAgdGhpcy5pc0ZpZWxkTG9ja2VkKGZpZWxkKVxuICAgICk7XG4gIH1cblxuICB0b2dnbGVGaWVsZExvY2soZmllbGQ6IE5lc3RlZEZpZWxkQ29uZmlnKTogdm9pZCB7XG4gICAgaWYgKCFmaWVsZC5jcml0aWNhbEZpZWxkIHx8IHRoaXMucmVhZG9ubHkpIHJldHVybjtcbiAgICBjb25zdCBuZXh0ID0gbmV3IFNldCh0aGlzLnVubG9ja2VkRmllbGRzKCkpO1xuICAgIGlmIChuZXh0LmhhcyhmaWVsZC5pZCkpIG5leHQuZGVsZXRlKGZpZWxkLmlkKTtcbiAgICBlbHNlIG5leHQuYWRkKGZpZWxkLmlkKTtcbiAgICB0aGlzLnVubG9ja2VkRmllbGRzLnNldChuZXh0KTtcbiAgfVxuXG4gIHJlc29sdmVGaWVsZExhYmVsKGZpZWxkOiBOZXN0ZWRGaWVsZENvbmZpZyk6IHN0cmluZyB7XG4gICAgcmV0dXJuIHJlc29sdmVMYWJlbChmaWVsZC5sYWJlbCwgdGhpcy5sYW5ndWFnZSk7XG4gIH1cblxuICAvLyDilIDilIDilIAgRm9ybSBjb25zdHJ1Y3Rpb24g4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG5cbiAgcHJpdmF0ZSBidWlsZEZvcm0oKTogdm9pZCB7XG4gICAgaWYgKCF0aGlzLmNvbmZpZykgcmV0dXJuO1xuICAgIGNvbnN0IGdyb3VwOiBSZWNvcmQ8c3RyaW5nLCBBYnN0cmFjdENvbnRyb2w+ID0ge307XG5cbiAgICBjb25zdCBidWlsZFRhYkNvbnRyb2xzID0gKHRhYnM6IE5lc3RlZFRhYkNvbmZpZ1tdLCBwYXJlbnRHcm91cDogUmVjb3JkPHN0cmluZywgQWJzdHJhY3RDb250cm9sPikgPT4ge1xuICAgICAgZm9yIChjb25zdCB0YWIgb2YgdGFicykge1xuICAgICAgICBpZiAodGFiLmZsYXREYXRhKSB7XG4gICAgICAgICAgZm9yIChjb25zdCBmaWVsZCBvZiB0YWIuZmllbGRzIHx8IFtdKSB7XG4gICAgICAgICAgICB0aGlzLmJ1aWxkRmllbGRDb250cm9sKGZpZWxkLCBwYXJlbnRHcm91cCk7XG4gICAgICAgICAgfVxuICAgICAgICAgIGlmICh0YWIuY2hpbGRyZW4pIGJ1aWxkVGFiQ29udHJvbHModGFiLmNoaWxkcmVuLCBwYXJlbnRHcm91cCk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgY29uc3QgdGFiR3JvdXA6IFJlY29yZDxzdHJpbmcsIEFic3RyYWN0Q29udHJvbD4gPSB7fTtcbiAgICAgICAgICBmb3IgKGNvbnN0IGZpZWxkIG9mIHRhYi5maWVsZHMgfHwgW10pIHtcbiAgICAgICAgICAgIHRoaXMuYnVpbGRGaWVsZENvbnRyb2woZmllbGQsIHRhYkdyb3VwKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgaWYgKHRhYi5jaGlsZHJlbikgYnVpbGRUYWJDb250cm9scyh0YWIuY2hpbGRyZW4sIHRhYkdyb3VwKTtcbiAgICAgICAgICBwYXJlbnRHcm91cFt0YWIuaWRdID0gdGhpcy5mYi5ncm91cCh0YWJHcm91cCk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9O1xuXG4gICAgYnVpbGRUYWJDb250cm9scyh0aGlzLmNvbmZpZy50YWJzIHx8IFtdLCBncm91cCk7XG4gICAgdGhpcy5mb3JtID0gdGhpcy5mYi5ncm91cChncm91cCk7XG5cbiAgICBpZiAodGhpcy5pbml0aWFsRGF0YSkge1xuICAgICAgdGhpcy5wYXRjaEZvcm0odGhpcy51cGdyYWRlUmVjb3JkKHRoaXMuaW5pdGlhbERhdGEpKTtcbiAgICB9XG5cbiAgICBjb25zdCBpbml0aWFsRmxhdHRlbmVkID0gdGhpcy5mbGF0dGVuRm9ybVZhbHVlcygpO1xuICAgIHRoaXMuZm9ybVZhbHVlcy5zZXQoaW5pdGlhbEZsYXR0ZW5lZCk7XG4gICAgdGhpcy5wcmV2aW91c1ZhbHVlcyA9IHsgLi4uaW5pdGlhbEZsYXR0ZW5lZCB9O1xuICAgIHRoaXMuc2Vzc2lvbkJhc2VsaW5lLnNldCh7IC4uLmluaXRpYWxGbGF0dGVuZWQgfSk7XG4gICAgdGhpcy51bmxvY2tlZEZpZWxkcy5zZXQobmV3IFNldDxzdHJpbmc+KCkpO1xuICAgIHRoaXMuc3luY0hpZGRlbkZpZWxkU3RhdGUoaW5pdGlhbEZsYXR0ZW5lZCk7XG5cbiAgICBpZiAodGhpcy5wcmV2aWV3KSB7XG4gICAgICAvLyBTaG93IHdoYXQgYW4gYXJyYXkgZmllbGQgbG9va3MgbGlrZSByYXRoZXIgdGhhbiBhbiBlbXB0eSBzbG90LCB0aGVuIGZyZWV6ZS5cbiAgICAgIGZvciAoY29uc3QgZmllbGQgb2YgdGhpcy5hbGxGaWVsZHMoKSkge1xuICAgICAgICBpZiAoZmllbGQudHlwZSAhPT0gJ2FycmF5JykgY29udGludWU7XG4gICAgICAgIGNvbnN0IGFycmF5ID0gdGhpcy5nZXRBcnJheUNvbnRyb2woZmllbGQuaWQpO1xuICAgICAgICBpZiAoYXJyYXkgJiYgYXJyYXkubGVuZ3RoID09PSAwKSBhcnJheS5wdXNoKHRoaXMuYnVpbGRBcnJheVJvdyhmaWVsZCwgdW5kZWZpbmVkKSk7XG4gICAgICB9XG4gICAgICB0aGlzLmZvcm0uZGlzYWJsZSh7IGVtaXRFdmVudDogZmFsc2UgfSk7XG4gICAgfVxuXG4gICAgLy8gUmVidWlsZGluZyBtdXN0IG5vdCBzdGFjayBzdWJzY3JpcHRpb25zIG9uIHN1Y2Nlc3NpdmUgY29uZmlnL2RhdGEgY2hhbmdlcy5cbiAgICB0aGlzLnZhbHVlU3ViPy51bnN1YnNjcmliZSgpO1xuICAgIGNvbnN0IGNoYW5nZXMkID0gdGhpcy5jaGFuZ2VEZWJvdW5jZU1zID4gMFxuICAgICAgPyB0aGlzLmZvcm0udmFsdWVDaGFuZ2VzLnBpcGUoZGVib3VuY2VUaW1lKHRoaXMuY2hhbmdlRGVib3VuY2VNcykpXG4gICAgICA6IHRoaXMuZm9ybS52YWx1ZUNoYW5nZXM7XG4gICAgdGhpcy52YWx1ZVN1YiA9IGNoYW5nZXMkLnN1YnNjcmliZSgoKSA9PiB7XG4gICAgICBjb25zdCBmbGF0dGVuZWQgPSB0aGlzLmZsYXR0ZW5Gb3JtVmFsdWVzKCk7XG4gICAgICB0aGlzLmZvcm1WYWx1ZXMuc2V0KGZsYXR0ZW5lZCk7XG4gICAgICB0aGlzLnJ1blBhdGNoT25UcnVlKGZsYXR0ZW5lZCk7XG4gICAgICB0aGlzLnN5bmNIaWRkZW5GaWVsZFN0YXRlKGZsYXR0ZW5lZCk7XG4gICAgICB0aGlzLnByZXZpb3VzVmFsdWVzID0geyAuLi5mbGF0dGVuZWQgfTtcbiAgICAgIHRoaXMuZm9ybUNoYW5nZS5lbWl0KHRoaXMuZXh0cmFjdFJlY29yZCgpKTtcbiAgICB9KTtcbiAgfVxuXG4gIHByaXZhdGUgYnVpbGRGaWVsZENvbnRyb2woZmllbGQ6IE5lc3RlZEZpZWxkQ29uZmlnLCBncm91cDogUmVjb3JkPHN0cmluZywgQWJzdHJhY3RDb250cm9sPik6IHZvaWQge1xuICAgIGlmIChmaWVsZC50eXBlID09PSAnZ3JvdXAnKSB7XG4gICAgICBjb25zdCBzdWJHcm91cDogUmVjb3JkPHN0cmluZywgQWJzdHJhY3RDb250cm9sPiA9IHt9O1xuICAgICAgZm9yIChjb25zdCBjaGlsZCBvZiBmaWVsZC5jaGlsZHJlbiB8fCBbXSkge1xuICAgICAgICB0aGlzLmJ1aWxkRmllbGRDb250cm9sKGNoaWxkLCBzdWJHcm91cCk7XG4gICAgICB9XG4gICAgICBncm91cFtmaWVsZC5pZF0gPSB0aGlzLmZiLmdyb3VwKHN1Ykdyb3VwKTtcbiAgICB9IGVsc2UgaWYgKGZpZWxkLnR5cGUgPT09ICdhcnJheScpIHtcbiAgICAgIGdyb3VwW2ZpZWxkLmlkXSA9IHRoaXMuZmIuYXJyYXkoW10pO1xuICAgIH0gZWxzZSB7XG4gICAgICBjb25zdCB2YWxpZGF0b3JzID0gdGhpcy52YWxpZGF0b3JSZWdpc3RyeS5yZXNvbHZlRnJvbUNvbmZpZyhmaWVsZC52YWxpZGF0b3JzKTtcbiAgICAgIGdyb3VwW2ZpZWxkLmlkXSA9IHRoaXMuZmIuY29udHJvbChcbiAgICAgICAgeyB2YWx1ZTogZmllbGQuZGVmYXVsdFZhbHVlID8/IG51bGwsIGRpc2FibGVkOiBmaWVsZC5kaXNhYmxlZCA/PyBmYWxzZSB9LFxuICAgICAgICB2YWxpZGF0b3JzLFxuICAgICAgKTtcbiAgICB9XG4gIH1cblxuICAvKiogT25lIHJvdyBvZiBhbiBgYXJyYXlgIGZpZWxkOiBhIEZvcm1Hcm91cCB3aGVuIHRoZSBmaWVsZCBkZWNsYXJlcyBjb2x1bW5zLCBlbHNlIGEgYmFyZSBjb250cm9sLiAqL1xuICAvKipcbiAgICogVGhlIGBGb3JtQXJyYXlgIGJlaGluZCBhbiBgYXJyYXlgIGZpZWxkLCBmb3IgY2FsbGVycyB0aGF0IG1hbmFnZSByb3dzIHRoZW1zZWx2ZXMg4oCUXG4gICAqIHRoZSByZWNvcmQgZWRpdG9yJ3MgaW5saW5lIHJvdyBkcmF3ZXIuXG4gICAqL1xuICBnZXRBcnJheUNvbnRyb2woZmllbGRJZDogc3RyaW5nLCB0YWJJZD86IHN0cmluZyk6IEZvcm1BcnJheSB8IG51bGwge1xuICAgIGNvbnN0IGN0cmwgPSB0aGlzLmdldENvbnRyb2woZmllbGRJZCwgdGFiSWQpO1xuICAgIHJldHVybiBjdHJsIGluc3RhbmNlb2YgRm9ybUFycmF5ID8gY3RybCA6IG51bGw7XG4gIH1cblxuICAvKipcbiAgICogQnVpbGQgb25lIGRldGFjaGVkIHJvdyBmb3IgYW4gYGFycmF5YCBmaWVsZCwgd2l0aCB0aGUgZmllbGQncyBvd24gdmFsaWRhdG9ycyBhcHBsaWVkLlxuICAgKiBFeHBvc2VkIHNvIGEgcm93IGNhbiBiZSBlZGl0ZWQgb3V0c2lkZSB0aGUgZm9ybSBhbmQgcHVzaGVkIG9uIHNhdmUuXG4gICAqL1xuICBjcmVhdGVBcnJheVJvdyhmaWVsZDogTmVzdGVkRmllbGRDb25maWcsIHZhbHVlPzogdW5rbm93bik6IEFic3RyYWN0Q29udHJvbCB7XG4gICAgcmV0dXJuIHRoaXMuYnVpbGRBcnJheVJvdyhmaWVsZCwgdmFsdWUpO1xuICB9XG5cbiAgcHJpdmF0ZSBidWlsZEFycmF5Um93KGZpZWxkOiBOZXN0ZWRGaWVsZENvbmZpZyB8IHVuZGVmaW5lZCwgaXRlbTogdW5rbm93bik6IEFic3RyYWN0Q29udHJvbCB7XG4gICAgaWYgKCFmaWVsZD8uY2hpbGRyZW4/Lmxlbmd0aCkgcmV0dXJuIHRoaXMuZmIuY29udHJvbChpdGVtKTtcblxuICAgIGNvbnN0IHJvd0dyb3VwOiBSZWNvcmQ8c3RyaW5nLCBBYnN0cmFjdENvbnRyb2w+ID0ge307XG4gICAgZm9yIChjb25zdCBjaGlsZCBvZiBmaWVsZC5jaGlsZHJlbikge1xuICAgICAgdGhpcy5idWlsZEZpZWxkQ29udHJvbChjaGlsZCwgcm93R3JvdXApO1xuICAgIH1cbiAgICBjb25zdCBncm91cCA9IHRoaXMuZmIuZ3JvdXAocm93R3JvdXApO1xuICAgIGlmIChpdGVtICYmIHR5cGVvZiBpdGVtID09PSAnb2JqZWN0JykgZ3JvdXAucGF0Y2hWYWx1ZShpdGVtIGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+KTtcbiAgICByZXR1cm4gZ3JvdXA7XG4gIH1cblxuICAvKipcbiAgICogQnJpbmcgYSByZWNvcmQgdXAgdG8gdGhlIGNvbmZpZydzIGB2ZXJzaW9uYCBiZWZvcmUgaXQgcmVhY2hlcyB0aGUgZm9ybS5cbiAgICpcbiAgICogRG9uZSBoZXJlIGJlY2F1c2UgdGhpcyBpcyB0aGUgb25lIHBsYWNlIGEgcmVjb3JkIGVudGVycyB0aGUgcmVuZGVyZXIsIHNvIGEgY29uc3VtZXJcbiAgICogY2Fubm90IGZvcmdldCBpdC4gTWlncmF0aW9uIGlzIGEgbm8tb3AgdW5sZXNzIHRoZSBjb25zdW1lciByZWdpc3RlcmVkIHN0ZXBzICphbmQqIHRoZVxuICAgKiByZWNvcmQgaXMgYmVoaW5kIOKAlCBhbiB1bnN0YW1wZWQgcmVjb3JkIGlzIGRlbGliZXJhdGVseSBsZWZ0IGFsb25lIChzZWUgYG1pZ3JhdGVSZWNvcmRgKS5cbiAgICpcbiAgICogQSBtaXNzaW5nIG9yIGJyb2tlbiBzdGVwIHRocm93cyBmcm9tIGNvcmUuIFRoYXQgaXMgbm90IHN3YWxsb3dlZDogcmVuZGVyaW5nIGFcbiAgICogaGFsZi11bmRlcnN0b29kIHJlY29yZCB3b3VsZCB3cml0ZSBpdCBiYWNrIGluIGEgc2hhcGUgbWF0Y2hpbmcgbmVpdGhlciBzY2hlbWEuXG4gICAqL1xuICBwcml2YXRlIHVwZ3JhZGVSZWNvcmQoZGF0YTogUmVjb3JkPHN0cmluZywgYW55Pik6IFJlY29yZDxzdHJpbmcsIGFueT4ge1xuICAgIGlmICghdGhpcy5taWdyYXRpb25zLmxlbmd0aCB8fCAhdGhpcy5jb25maWcpIHJldHVybiBkYXRhO1xuXG4gICAgY29uc3QgcmVzdWx0ID0gbWlncmF0ZVJlY29yZChkYXRhLCB0aGlzLmNvbmZpZywgdGhpcy5taWdyYXRpb25zKTtcbiAgICBpZiAocmVzdWx0LmFwcGxpZWQubGVuZ3RoICYmIGlzRGV2TW9kZSgpKSB7XG4gICAgICBjb25zb2xlLmluZm8oXG4gICAgICAgIGBbbmd4LWR5bmFtaWMtZW50aXR5XSBNaWdyYXRlZCBhIFwiJHt0aGlzLmNvbmZpZy5lbnRpdHl9XCIgcmVjb3JkIGZyb20gY29uZmlnIHZlcnNpb24gYCArXG4gICAgICAgICAgYCR7cmVzdWx0LmZyb219IHRvICR7cmVzdWx0LnRvfSAoc3RlcHM6ICR7cmVzdWx0LmFwcGxpZWQuam9pbignLCAnKX0pLmAsXG4gICAgICApO1xuICAgIH1cbiAgICByZXR1cm4gcmVzdWx0LnJlY29yZDtcbiAgfVxuXG4gIHByaXZhdGUgcGF0Y2hGb3JtKGRhdGE6IFJlY29yZDxzdHJpbmcsIGFueT4pOiB2b2lkIHtcbiAgICBpZiAoIWRhdGEgfHwgIXRoaXMuZm9ybSkgcmV0dXJuO1xuICAgIGNvbnN0IGZpZWxkc0J5SWQgPSBuZXcgTWFwKHRoaXMuYWxsRmllbGRzKCkubWFwKGYgPT4gW2YuaWQsIGZdKSk7XG4gICAgY29uc3QgcGF0Y2hlZEZpZWxkSWRzID0gbmV3IFNldDxzdHJpbmc+KCk7XG5cbiAgICBjb25zdCB3YWxrVGFicyA9ICh0YWJzOiBOZXN0ZWRUYWJDb25maWdbXSkgPT4ge1xuICAgICAgZm9yIChjb25zdCB0YWIgb2YgdGFicykge1xuICAgICAgICBjb25zdCB0YWJEYXRhID0gZ2V0VGFiRGF0YSh0YWIuaWQsIGRhdGEsIHRoaXMuY29uZmlnKTtcbiAgICAgICAgZm9yIChjb25zdCBmaWVsZCBvZiB0YWIuZmllbGRzIHx8IFtdKSB7XG4gICAgICAgICAgbGV0IHZhbCA9IHRhYkRhdGEgJiYgdHlwZW9mIHRhYkRhdGEgPT09ICdvYmplY3QnID8gdGFiRGF0YVtmaWVsZC5pZF0gOiB1bmRlZmluZWQ7XG4gICAgICAgICAgaWYgKGZpZWxkLnJlZmVyZXJGaWVsZCkge1xuICAgICAgICAgICAgY29uc3QgcmVmVmFsID0gZ2V0VmFsdWVCeVBhdGgoZGF0YSwgZmllbGQucmVmZXJlckZpZWxkKTtcbiAgICAgICAgICAgIGlmIChyZWZWYWwgIT09IHVuZGVmaW5lZCkgdmFsID0gcmVmVmFsO1xuICAgICAgICAgIH1cbiAgICAgICAgICBpZiAodmFsID09PSB1bmRlZmluZWQpIGNvbnRpbnVlO1xuXG4gICAgICAgICAgY29uc3QgY3RybCA9IHRoaXMuZ2V0Q29udHJvbChmaWVsZC5pZCwgdGFiLmlkKTtcbiAgICAgICAgICBpZiAoIWN0cmwpIGNvbnRpbnVlO1xuXG4gICAgICAgICAgaWYgKGN0cmwgaW5zdGFuY2VvZiBGb3JtQXJyYXkgJiYgQXJyYXkuaXNBcnJheSh2YWwpKSB7XG4gICAgICAgICAgICBjdHJsLmNsZWFyKCk7XG4gICAgICAgICAgICBmb3IgKGNvbnN0IGl0ZW0gb2YgdmFsKSB7XG4gICAgICAgICAgICAgIGN0cmwucHVzaCh0aGlzLmJ1aWxkQXJyYXlSb3coZmllbGRzQnlJZC5nZXQoZmllbGQuaWQpLCBpdGVtKSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGN0cmwucGF0Y2hWYWx1ZSh2YWwsIHsgZW1pdEV2ZW50OiBmYWxzZSB9KTtcbiAgICAgICAgICB9XG4gICAgICAgICAgcGF0Y2hlZEZpZWxkSWRzLmFkZChmaWVsZC5pZCk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHRhYi5jaGlsZHJlbikgd2Fsa1RhYnModGFiLmNoaWxkcmVuKTtcbiAgICAgIH1cbiAgICB9O1xuXG4gICAgd2Fsa1RhYnModGhpcy5jb25maWcudGFicyB8fCBbXSk7XG4gICAgdGhpcy53YXJuVW5jb25zdW1lZEluaXRpYWxEYXRhKGRhdGEsIGZpZWxkc0J5SWQsIHBhdGNoZWRGaWVsZElkcyk7XG4gIH1cblxuICAvKipcbiAgICogQSByZWNvcmQgaXMgbmVzdGVkIGJ5IHRhYiBpZCAoYHsgdGFiSWQ6IHsgZmllbGRJZDogdmFsdWUgfSB9YCkgdW5sZXNzIHRoZSB0YWIgc2V0c1xuICAgKiBgZmxhdERhdGE6IHRydWVgLiBIYW5kaW5nIGEgZmxhdCByZWNvcmQgdG8gYSBuZXN0ZWQgdGFiIGZpbmRzIG5vdGhpbmcsIHNvIHRoZSBmaWVsZHNcbiAgICogc3RheSBlbXB0eSDigJQgd2l0aCBubyBlcnJvciBhbmQgbm8gY2x1ZS4gVGhhdCBzaWxlbnQgbWlzcyBpcyB0aGUgbW9zdCBleHBlbnNpdmUgd2F5IHRvXG4gICAqIGxvc2UgYW4gaG91ciB3aXRoIHRoaXMgbGlicmFyeSwgc28gbmFtZSBpdCBpbiBkZXYgYnVpbGRzLlxuICAgKlxuICAgKiBPbmx5IHRvcC1sZXZlbCBrZXlzIHRoYXQgbWF0Y2ggYSBrbm93biBmaWVsZCBpZCBhcmUgcmVwb3J0ZWQ6IGFueXRoaW5nIGVsc2UgaXMgYXNzdW1lZFxuICAgKiB0byBiZSB0aGUgY29uc3VtZXIncyBvd24gcmVjb3JkIG1ldGFkYXRhIChpZHMsIHRpbWVzdGFtcHMsIGBfY29uZmlnVmVyc2lvbmApIGFuZCBpcyBub3RcbiAgICogb3VyIGJ1c2luZXNzLlxuICAgKi9cbiAgcHJpdmF0ZSB3YXJuVW5jb25zdW1lZEluaXRpYWxEYXRhKFxuICAgIGRhdGE6IFJlY29yZDxzdHJpbmcsIGFueT4sXG4gICAgZmllbGRzQnlJZDogTWFwPHN0cmluZywgTmVzdGVkRmllbGRDb25maWc+LFxuICAgIHBhdGNoZWRGaWVsZElkczogU2V0PHN0cmluZz4sXG4gICk6IHZvaWQge1xuICAgIGlmICghaXNEZXZNb2RlKCkgfHwgIXRoaXMuY29uZmlnKSByZXR1cm47XG5cbiAgICBjb25zdCB0YWJJZHMgPSBuZXcgU2V0PHN0cmluZz4oKTtcbiAgICBjb25zdCBjb2xsZWN0VGFiSWRzID0gKHRhYnM6IE5lc3RlZFRhYkNvbmZpZ1tdKSA9PiB7XG4gICAgICBmb3IgKGNvbnN0IHRhYiBvZiB0YWJzKSB7XG4gICAgICAgIHRhYklkcy5hZGQodGFiLmlkKTtcbiAgICAgICAgaWYgKHRhYi5jaGlsZHJlbikgY29sbGVjdFRhYklkcyh0YWIuY2hpbGRyZW4pO1xuICAgICAgfVxuICAgIH07XG4gICAgY29sbGVjdFRhYklkcyh0aGlzLmNvbmZpZy50YWJzIHx8IFtdKTtcblxuICAgIGNvbnN0IHVuY29uc3VtZWQgPSBPYmplY3Qua2V5cyhkYXRhKS5maWx0ZXIoXG4gICAgICBrZXkgPT5cbiAgICAgICAgIXRhYklkcy5oYXMoa2V5KSAmJiAvLyBhIHRhYiBpZCBhdCB0aGUgcm9vdCBpcyB0aGUgbmVzdGVkIGNvbnRhaW5lciwgbm90IGEgc3RyYXkgZmllbGRcbiAgICAgICAgZGF0YVtrZXldICE9PSB1bmRlZmluZWQgJiZcbiAgICAgICAgZmllbGRzQnlJZC5oYXMoa2V5KSAmJlxuICAgICAgICAhcGF0Y2hlZEZpZWxkSWRzLmhhcyhrZXkpICYmXG4gICAgICAgICF0aGlzLndhcm5lZFVuY29uc3VtZWRLZXlzLmhhcyhrZXkpLFxuICAgICk7XG4gICAgaWYgKCF1bmNvbnN1bWVkLmxlbmd0aCkgcmV0dXJuO1xuXG4gICAgZm9yIChjb25zdCBrZXkgb2YgdW5jb25zdW1lZCkgdGhpcy53YXJuZWRVbmNvbnN1bWVkS2V5cy5hZGQoa2V5KTtcblxuICAgIGNvbnN0IHNob3duID0gdW5jb25zdW1lZC5zbGljZSgwLCA1KS5qb2luKCcsICcpO1xuICAgIGNvbnN0IG1vcmUgPSB1bmNvbnN1bWVkLmxlbmd0aCA+IDUgPyBgICgrJHt1bmNvbnN1bWVkLmxlbmd0aCAtIDV9IG1vcmUpYCA6ICcnO1xuICAgIGNvbnN0IHBsdXJhbCA9IHVuY29uc3VtZWQubGVuZ3RoID09PSAxO1xuICAgIGNvbnNvbGUud2FybihcbiAgICAgIGBbbmd4LWR5bmFtaWMtZW50aXR5XSBpbml0aWFsRGF0YSBoYXMgdG9wLWxldmVsICR7cGx1cmFsID8gJ2tleScgOiAna2V5cyd9IG1hdGNoaW5nIGAgK1xuICAgICAgICBgJHtwbHVyYWwgPyAnYSBmaWVsZCB0aGF0IHdhcycgOiAnZmllbGRzIHRoYXQgd2VyZSd9IG5vdCBwb3B1bGF0ZWQ6ICR7c2hvd259JHttb3JlfS4gYCArXG4gICAgICAgIGBBIHJlY29yZCBpcyBuZXN0ZWQgYnkgdGFiIGlkICh7IHRhYklkOiB7IGZpZWxkSWQ6IHZhbHVlIH0gfSkgdW5sZXNzIHRoZSB0YWIgc2V0cyBgICtcbiAgICAgICAgYGZsYXREYXRhOiB0cnVlLiBFaXRoZXIgbmVzdCB0aGUgdmFsdWUgdW5kZXIgaXRzIHRhYiBpZCwgb3Igc2V0IGZsYXREYXRhOiB0cnVlIG9uIGAgK1xuICAgICAgICBgdGhlIHRhYiBob2xkaW5nICR7cGx1cmFsID8gJ3RoYXQgZmllbGQnIDogJ3Rob3NlIGZpZWxkcyd9LmAsXG4gICAgKTtcbiAgfVxuXG4gIC8qKiBXYXJuIG9uY2UgcGVyIGtleSBwZXIgZm9ybSBpbnN0YW5jZSDigJQgcGF0Y2hGb3JtIHJlLXJ1bnMgb24gZXZlcnkgaW5pdGlhbERhdGEgY2hhbmdlLiAqL1xuICBwcml2YXRlIHJlYWRvbmx5IHdhcm5lZFVuY29uc3VtZWRLZXlzID0gbmV3IFNldDxzdHJpbmc+KCk7XG5cbiAgLyoqIEFzc2VtYmxlIGZ1bGwgbmVzdGVkIHJlY29yZCBmcm9tIHBlci10YWIgRm9ybUdyb3VwcywgcmVzcGVjdGluZyBmbGF0RGF0YSwgcmVmZXJlckZpZWxkICYgYXJyYXlzLiAqL1xuICBleHRyYWN0UmVjb3JkKCk6IFJlY29yZDxzdHJpbmcsIGFueT4ge1xuICAgIGlmICghdGhpcy5mb3JtIHx8ICF0aGlzLmNvbmZpZykgcmV0dXJuIHt9O1xuICAgIGxldCByZWNvcmQ6IFJlY29yZDxzdHJpbmcsIGFueT4gPSB7fTtcblxuICAgIGNvbnN0IHdhbGtUYWJzID0gKHRhYnM6IE5lc3RlZFRhYkNvbmZpZ1tdKSA9PiB7XG4gICAgICBmb3IgKGNvbnN0IHRhYiBvZiB0YWJzKSB7XG4gICAgICAgIGNvbnN0IGZpZWxkVmFsQmFnOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiA9IHt9O1xuICAgICAgICBmb3IgKGNvbnN0IGZpZWxkIG9mIHRhYi5maWVsZHMgfHwgW10pIHtcbiAgICAgICAgICBjb25zdCBjdHJsID0gdGhpcy5nZXRDb250cm9sKGZpZWxkLmlkLCB0YWIuaWQpO1xuICAgICAgICAgIGlmIChjdHJsKSB7XG4gICAgICAgICAgICBmaWVsZFZhbEJhZ1tmaWVsZC5pZF0gPSBjdHJsLnZhbHVlO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIHNldFRhYkRhdGEocmVjb3JkLCB0YWIuaWQsIGZpZWxkVmFsQmFnLCB0aGlzLmNvbmZpZyk7XG5cbiAgICAgICAgZm9yIChjb25zdCBmaWVsZCBvZiB0YWIuZmllbGRzIHx8IFtdKSB7XG4gICAgICAgICAgaWYgKGZpZWxkLnJlZmVyZXJGaWVsZCkge1xuICAgICAgICAgICAgY29uc3QgY3RybCA9IHRoaXMuZ2V0Q29udHJvbChmaWVsZC5pZCwgdGFiLmlkKTtcbiAgICAgICAgICAgIGlmIChjdHJsKSB7XG4gICAgICAgICAgICAgIHNldFZhbHVlQnlQYXRoKHJlY29yZCwgZmllbGQucmVmZXJlckZpZWxkLCBjdHJsLnZhbHVlKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBpZiAodGFiLmNoaWxkcmVuKSB3YWxrVGFicyh0YWIuY2hpbGRyZW4pO1xuICAgICAgfVxuICAgIH07XG5cbiAgICB3YWxrVGFicyh0aGlzLmNvbmZpZy50YWJzIHx8IFtdKTtcbiAgICByZWNvcmQgPSBub3JtYWxpemVBcnJheVN0cnVjdHVyZXMocmVjb3JkLCB0aGlzLmNvbmZpZyk7XG4gICAgcmV0dXJuIHJlY29yZDtcbiAgfVxuXG4gIHByaXZhdGUgZmxhdHRlbkZvcm1WYWx1ZXMoKTogUmVjb3JkPHN0cmluZywgYW55PiB7XG4gICAgY29uc3Qgb3V0OiBSZWNvcmQ8c3RyaW5nLCBhbnk+ID0ge307XG4gICAgZm9yIChjb25zdCBmaWVsZCBvZiB0aGlzLmFsbEZpZWxkcygpKSB7XG4gICAgICBjb25zdCBjdHJsID0gdGhpcy5nZXRDb250cm9sKGZpZWxkLmlkKTtcbiAgICAgIGlmIChjdHJsKSBvdXRbZmllbGQuaWRdID0gY3RybC52YWx1ZTtcbiAgICB9XG4gICAgcmV0dXJuIG91dDtcbiAgfVxuXG4gIHByaXZhdGUgZ2V0VGFiR3JvdXAodGFiSWQ6IHN0cmluZyk6IEZvcm1Hcm91cCB8IG51bGwge1xuICAgIGNvbnN0IHBhdGggPSBnZXRUYWJQYXRoKHRoaXMuY29uZmlnPy50YWJzLCB0YWJJZCk7XG4gICAgaWYgKCFwYXRoIHx8IHBhdGgubGVuZ3RoID09PSAwKSByZXR1cm4gdGhpcy5mb3JtO1xuICAgIGxldCBjdXJyOiBBYnN0cmFjdENvbnRyb2wgfCBudWxsID0gdGhpcy5mb3JtO1xuICAgIGZvciAoY29uc3QgcCBvZiBwYXRoKSB7XG4gICAgICBpZiAoIWN1cnIgfHwgIShjdXJyIGluc3RhbmNlb2YgRm9ybUdyb3VwKSkgcmV0dXJuIG51bGw7XG4gICAgICBjdXJyID0gY3Vyci5nZXQocCk7XG4gICAgfVxuICAgIHJldHVybiBjdXJyIGluc3RhbmNlb2YgRm9ybUdyb3VwID8gY3VyciA6IG51bGw7XG4gIH1cblxuICAvLyDilIDilIDilIAgYXV0b1BhdGNoIC8gcGF0Y2hPblRydWUg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG5cbiAgLyoqXG4gICAqIGBhdXRvUGF0Y2hgIOKAlCBjb3B5IG1hcHBlZCBmaWVsZHMgb3V0IG9mIHRoZSByZWNvcmQgdGhlIHVzZXIganVzdCBzZWxlY3RlZCBpbiBhblxuICAgKiBlbnRpdHktcmVmIGZpZWxkIGludG8gdGhlIGNvbmZpZ3VyZWQgdGFyZ2V0IHRhYidzIGNvbnRyb2xzLlxuICAgKi9cbiAgcHJpdmF0ZSBydW5BdXRvUGF0Y2goZmllbGRJZDogc3RyaW5nLCByZWNvcmQ6IFJlY29yZDxzdHJpbmcsIHVua25vd24+IHwgdW5kZWZpbmVkKTogdm9pZCB7XG4gICAgaWYgKCFyZWNvcmQpIHJldHVybjtcbiAgICBjb25zdCBmaWVsZCA9IHRoaXMuYWxsRmllbGRzKCkuZmluZChmID0+IGYuaWQgPT09IGZpZWxkSWQpO1xuICAgIGNvbnN0IGF1dG9QYXRjaCA9IGZpZWxkPy5hdXRvUGF0Y2g7XG4gICAgaWYgKCFhdXRvUGF0Y2gpIHJldHVybjtcblxuICAgIGNvbnN0IHBhdGNoID0gYXBwbHlBdXRvUGF0Y2goYXV0b1BhdGNoLCByZWNvcmQpO1xuICAgIGZvciAoY29uc3QgW3RhcmdldElkLCB2YWx1ZV0gb2YgT2JqZWN0LmVudHJpZXMocGF0Y2gpKSB7XG4gICAgICBjb25zdCBjb250cm9sID0gdGhpcy5yZXNvbHZlVGFyZ2V0Q29udHJvbChhdXRvUGF0Y2gsIHRhcmdldElkKTtcbiAgICAgIGNvbnRyb2w/LnBhdGNoVmFsdWUodmFsdWUpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBgcGF0Y2hPblRydWVgIOKAlCB3aGVuIGEgYm9vbGVhbi9jaGVja2JveCBmaWVsZCB0cmFuc2l0aW9ucyB0byBgdHJ1ZWAsXG4gICAqIGNvcHkgYGZyb21gIOKGkiBgdG9gIHdpdGhpbiB0aGUgY3VycmVudCByZWNvcmQuXG4gICAqL1xuICBwcml2YXRlIHJ1blBhdGNoT25UcnVlKHZhbHVlczogUmVjb3JkPHN0cmluZywgYW55Pik6IHZvaWQge1xuICAgIGZvciAoY29uc3QgZmllbGQgb2YgdGhpcy5hbGxGaWVsZHMoKSkge1xuICAgICAgY29uc3QgbWFwcGluZ3MgPSBmaWVsZC5wYXRjaE9uVHJ1ZTtcbiAgICAgIGlmICghbWFwcGluZ3M/Lmxlbmd0aCkgY29udGludWU7XG5cbiAgICAgIGNvbnN0IHdhc1RydWUgPSB0aGlzLnByZXZpb3VzVmFsdWVzW2ZpZWxkLmlkXSA9PT0gdHJ1ZTtcbiAgICAgIGNvbnN0IGlzVHJ1ZSA9IHZhbHVlc1tmaWVsZC5pZF0gPT09IHRydWU7XG4gICAgICBpZiAoIWlzVHJ1ZSB8fCB3YXNUcnVlKSBjb250aW51ZTtcblxuICAgICAgY29uc3QgcGF0Y2ggPSBhcHBseVBhdGNoT25UcnVlKG1hcHBpbmdzLCB2YWx1ZXMpO1xuICAgICAgZm9yIChjb25zdCBbdGFyZ2V0SWQsIHZhbHVlXSBvZiBPYmplY3QuZW50cmllcyhwYXRjaCkpIHtcbiAgICAgICAgdGhpcy5nZXRDb250cm9sKHRhcmdldElkKT8ucGF0Y2hWYWx1ZSh2YWx1ZSwgeyBlbWl0RXZlbnQ6IGZhbHNlIH0pO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIC8qKiBQcmVmZXIgYSBjb250cm9sIGRlY2xhcmVkIG9uIHRoZSBjb25maWd1cmVkIHRhcmdldCB0YWI7IGZhbGwgYmFjayB0byBhIHRvcC1sZXZlbCBjb250cm9sLiAqL1xuICBwcml2YXRlIHJlc29sdmVUYXJnZXRDb250cm9sKGF1dG9QYXRjaDogQXV0b1BhdGNoQ29uZmlnLCB0YXJnZXRJZDogc3RyaW5nKTogQWJzdHJhY3RDb250cm9sIHwgbnVsbCB7XG4gICAgY29uc3QgdGFiID0gZmluZFRhYih0aGlzLnRhYnMsIGF1dG9QYXRjaC50YXJnZXRUYWIpO1xuICAgIGNvbnN0IGluVGFyZ2V0VGFiID0gKHRhYj8uZmllbGRzID8/IFtdKS5zb21lKGYgPT4gZi5pZCA9PT0gdGFyZ2V0SWQpO1xuICAgIGlmICh0YWIgJiYgIWluVGFyZ2V0VGFiKSByZXR1cm4gbnVsbDtcbiAgICByZXR1cm4gdGhpcy5nZXRDb250cm9sKHRhcmdldElkLCBhdXRvUGF0Y2gudGFyZ2V0VGFiKTtcbiAgfVxuXG4gIC8vIOKUgOKUgOKUgCBIZWxwZXJzIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxuXG4gIC8qKlxuICAgKiBUaGUgZmllbGRzIHRoZSByZW5kZXIgZmlsdGVyIG9wZXJhdGVzIG9uIOKAlCBhIHRhYidzIG93biBmaWVsZHMsIGF0IGV2ZXJ5IHRhYiBkZXB0aC5cbiAgICogRGVsaWJlcmF0ZWx5IG5vdCBgYWxsRmllbGRzKClgOiBgZ3JvdXBgIGFuZCBgYXJyYXlgIGNoaWxkcmVuIGFyZSBzaG93biBvciBoaWRkZW4gd2l0aFxuICAgKiB0aGVpciBwYXJlbnQsIGFuZCB0b2dnbGluZyBhIGNoaWxkJ3Mgc3RhdGUgaW5kZXBlbmRlbnRseSB3b3VsZCBmaWdodCB0aGUgcGFyZW50J3MuXG4gICAqL1xuICBwcml2YXRlIHRhYkZpZWxkcygpOiBOZXN0ZWRGaWVsZENvbmZpZ1tdIHtcbiAgICBjb25zdCBvdXQ6IE5lc3RlZEZpZWxkQ29uZmlnW10gPSBbXTtcbiAgICBjb25zdCB3YWxrID0gKHRhYnM6IE5lc3RlZFRhYkNvbmZpZ1tdIHwgdW5kZWZpbmVkKSA9PiB7XG4gICAgICBmb3IgKGNvbnN0IHRhYiBvZiB0YWJzID8/IFtdKSB7XG4gICAgICAgIG91dC5wdXNoKC4uLih0YWIuZmllbGRzID8/IFtdKSk7XG4gICAgICAgIHdhbGsodGFiLmNoaWxkcmVuKTtcbiAgICAgIH1cbiAgICB9O1xuICAgIHdhbGsodGhpcy5jb25maWc/LnRhYnMpO1xuICAgIHJldHVybiBvdXQ7XG4gIH1cblxuICAvKipcbiAgICogS2VlcCBhIGhpZGRlbiBmaWVsZCdzIGNvbnRyb2wgb3V0IG9mIGZvcm0gdmFsaWRpdHkuXG4gICAqXG4gICAqIEEgZmllbGQgaGlkZGVuIGJ5IGEgcnVsZSBvciBhIGBzaG93V2hlbmAgY29uZGl0aW9uIGlzIGZpbHRlcmVkIG91dCBvZiB0aGUgcmVuZGVyLCBidXRcbiAgICogaXRzIHZhbGlkYXRvcnMgc3RheSBhdHRhY2hlZCDigJQgc28gYSBoaWRkZW4gKnJlcXVpcmVkKiBmaWVsZCBob2xkcyBgZm9ybS5pbnZhbGlkYCB0cnVlXG4gICAqIGZvcmV2ZXIsIHBlcm1hbmVudGx5IGRpc2FibGluZyBTYXZlIHdpdGggbm90aGluZyBvbiBzY3JlZW4gdG8gZXhwbGFpbiB3aHkuXG4gICAqXG4gICAqIERpc2FibGluZyBpcyB0aGUgZml4IHJhdGhlciB0aGFuIHN0cmlwcGluZyB2YWxpZGF0b3JzOiBBbmd1bGFyIGV4Y2x1ZGVzIGRpc2FibGVkXG4gICAqIGNvbnRyb2xzIGZyb20gdmFsaWRpdHksIGFuZCB0aGUgZmllbGQncyBvd24gdmFsaWRhdG9ycyBzdXJ2aXZlIGludGFjdCBmb3Igd2hlbiBpdFxuICAgKiBjb21lcyBiYWNrLiBWYWx1ZXMgYXJlIHVudG91Y2hlZCDigJQgYGZsYXR0ZW5Gb3JtVmFsdWVzYCBhbmQgYGV4dHJhY3RSZWNvcmRgIGJvdGggcmVhZFxuICAgKiBgY29udHJvbC52YWx1ZWAsIHdoaWNoIGEgZGlzYWJsZWQgY29udHJvbCBzdGlsbCBjYXJyaWVzLCBzbyBydWxlIGV2YWx1YXRpb24gYW5kIHRoZVxuICAgKiBlbWl0dGVkIHJlY29yZCBzZWUgZXhhY3RseSB3aGF0IHRoZXkgc2F3IGJlZm9yZS4gVGhhdCBhbHNvIGtlZXBzIHRoaXMgZnJvbSBmZWVkaW5nXG4gICAqIGJhY2sgb24gaXRzZWxmOiBoaWRpbmcgYSBmaWVsZCBjYW5ub3QgY2hhbmdlIHRoZSB2YWx1ZXMgdGhlIHJ1bGVzIGFyZSBldmFsdWF0ZWQgb3Zlci5cbiAgICpcbiAgICogVGhlIHZpc2liaWxpdHkgcHJlZGljYXRlIGlzIHRoZSBzYW1lIG9uZSBgZmllbGRzRm9yQWN0aXZlVGFiYCBmaWx0ZXJzIHdpdGgsIHNvIHdoYXQgaXNcbiAgICogcmVuZGVyZWQgYW5kIHdoYXQgY291bnRzIHRvd2FyZCB2YWxpZGl0eSBjYW5ub3QgZHJpZnQgYXBhcnQuXG4gICAqL1xuICBwcml2YXRlIHN5bmNIaWRkZW5GaWVsZFN0YXRlKHZhbHVlczogUmVjb3JkPHN0cmluZywgYW55Pik6IHZvaWQge1xuICAgIGlmICh0aGlzLnByZXZpZXcpIHJldHVybjsgLy8gcHJldmlldyBmcmVlemVzIHRoZSB3aG9sZSBmb3JtIG9uIHB1cnBvc2VcblxuICAgIGNvbnN0IGhpZGRlbkJ5UnVsZSA9IG5ldyBTZXQodGhpcy5ydWxlUmVzdWx0KCkuaGlkZGVuRmllbGRzKTtcblxuICAgIGZvciAoY29uc3QgZmllbGQgb2YgdGhpcy50YWJGaWVsZHMoKSkge1xuICAgICAgY29uc3QgY3RybCA9IHRoaXMuZ2V0Q29udHJvbChmaWVsZC5pZCk7XG4gICAgICBpZiAoIWN0cmwpIGNvbnRpbnVlO1xuXG4gICAgICBjb25zdCBoaWRkZW4gPSBoaWRkZW5CeVJ1bGUuaGFzKGZpZWxkLmlkKSB8fCAhZXZhbHVhdGVGaWVsZFZpc2liaWxpdHkoZmllbGQsIHZhbHVlcyk7XG5cbiAgICAgIGlmIChoaWRkZW4pIHtcbiAgICAgICAgaWYgKGN0cmwuZW5hYmxlZCkgY3RybC5kaXNhYmxlKHsgZW1pdEV2ZW50OiBmYWxzZSB9KTtcbiAgICAgIH0gZWxzZSBpZiAoY3RybC5kaXNhYmxlZCAmJiAhZmllbGQuZGlzYWJsZWQpIHtcbiAgICAgICAgY3RybC5lbmFibGUoeyBlbWl0RXZlbnQ6IGZhbHNlIH0pO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIC8qKiBFdmVyeSBmaWVsZCBpbiB0aGUgY29uZmlnLCBpbmNsdWRpbmcgYGdyb3VwYC9gYXJyYXlgIGNoaWxkcmVuLiAqL1xuICBwcml2YXRlIGFsbEZpZWxkcygpOiBOZXN0ZWRGaWVsZENvbmZpZ1tdIHtcbiAgICBjb25zdCBvdXQ6IE5lc3RlZEZpZWxkQ29uZmlnW10gPSBbXTtcbiAgICBjb25zdCB3YWxrRmllbGRzID0gKGZpZWxkczogTmVzdGVkRmllbGRDb25maWdbXSB8IHVuZGVmaW5lZCkgPT4ge1xuICAgICAgZm9yIChjb25zdCBmIG9mIGZpZWxkcyA/PyBbXSkge1xuICAgICAgICBvdXQucHVzaChmKTtcbiAgICAgICAgaWYgKGYuY2hpbGRyZW4/Lmxlbmd0aCkgd2Fsa0ZpZWxkcyhmLmNoaWxkcmVuKTtcbiAgICAgIH1cbiAgICB9O1xuICAgIGNvbnN0IHdhbGtUYWJzID0gKHRhYnM6IE5lc3RlZFRhYkNvbmZpZ1tdIHwgdW5kZWZpbmVkKSA9PiB7XG4gICAgICBmb3IgKGNvbnN0IHQgb2YgdGFicyA/PyBbXSkge1xuICAgICAgICB3YWxrRmllbGRzKHQuZmllbGRzKTtcbiAgICAgICAgd2Fsa1RhYnModC5jaGlsZHJlbik7XG4gICAgICB9XG4gICAgfTtcbiAgICB3YWxrVGFicyh0aGlzLmNvbmZpZz8udGFicyk7XG4gICAgcmV0dXJuIG91dDtcbiAgfVxuXG4gIC8qKiBBbiBlbXB0eSBgb3JpZ2luYWxEYXRhYCBjb3VudHMgYXMgXCJub3Qgc3VwcGxpZWRcIiDigJQgZmFsbCBiYWNrIHRvIHRoZSBjYXB0dXJlZCBiYXNlbGluZS4gKi9cbiAgcHJpdmF0ZSBiYXNlbGluZSgpOiBSZWNvcmQ8c3RyaW5nLCBhbnk+IHtcbiAgICBjb25zdCBzdXBwbGllZCA9IHRoaXMub3JpZ2luYWxEYXRhO1xuICAgIGlmIChzdXBwbGllZCAmJiBPYmplY3Qua2V5cyhzdXBwbGllZCkubGVuZ3RoID4gMCkgcmV0dXJuIHN1cHBsaWVkO1xuICAgIHJldHVybiB0aGlzLnNlc3Npb25CYXNlbGluZSgpO1xuICB9XG5cbiAgcHJpdmF0ZSBzYW1lVmFsdWUoYTogdW5rbm93biwgYjogdW5rbm93bik6IGJvb2xlYW4ge1xuICAgIGlmIChhID09PSBiKSByZXR1cm4gdHJ1ZTtcbiAgICBjb25zdCBhRW1wdHkgPSBhID09PSBudWxsIHx8IGEgPT09IHVuZGVmaW5lZCB8fCBhID09PSAnJztcbiAgICBjb25zdCBiRW1wdHkgPSBiID09PSBudWxsIHx8IGIgPT09IHVuZGVmaW5lZCB8fCBiID09PSAnJztcbiAgICBpZiAoYUVtcHR5ICYmIGJFbXB0eSkgcmV0dXJuIHRydWU7XG4gICAgaWYgKHR5cGVvZiBhID09PSAnb2JqZWN0JyB8fCB0eXBlb2YgYiA9PT0gJ29iamVjdCcpIHtcbiAgICAgIHJldHVybiBKU09OLnN0cmluZ2lmeShhID8/IG51bGwpID09PSBKU09OLnN0cmluZ2lmeShiID8/IG51bGwpO1xuICAgIH1cbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cblxuICBnZXRDb250cm9sKGZpZWxkSWQ6IHN0cmluZywgY3VycmVudFRhYklkPzogc3RyaW5nKTogQWJzdHJhY3RDb250cm9sIHwgbnVsbCB7XG4gICAgaWYgKCF0aGlzLmZvcm0pIHJldHVybiBudWxsO1xuXG4gICAgaWYgKGN1cnJlbnRUYWJJZCkge1xuICAgICAgY29uc3QgdGFiR3JwID0gdGhpcy5nZXRUYWJHcm91cChjdXJyZW50VGFiSWQpO1xuICAgICAgY29uc3QgY3RybCA9IHRhYkdycD8uZ2V0KGZpZWxkSWQpO1xuICAgICAgaWYgKGN0cmwpIHJldHVybiBjdHJsO1xuICAgIH1cblxuICAgIGNvbnN0IHJvb3RDdHJsID0gdGhpcy5mb3JtLmdldChmaWVsZElkKTtcbiAgICBpZiAocm9vdEN0cmwpIHJldHVybiByb290Q3RybDtcblxuICAgIGNvbnN0IGZpbmRJbkdyb3VwID0gKGdyb3VwOiBGb3JtR3JvdXApOiBBYnN0cmFjdENvbnRyb2wgfCBudWxsID0+IHtcbiAgICAgIGZvciAoY29uc3Qga2V5IG9mIE9iamVjdC5rZXlzKGdyb3VwLmNvbnRyb2xzKSkge1xuICAgICAgICBjb25zdCBjID0gZ3JvdXAuY29udHJvbHNba2V5XTtcbiAgICAgICAgaWYgKGtleSA9PT0gZmllbGRJZCkgcmV0dXJuIGM7XG4gICAgICAgIGlmIChjIGluc3RhbmNlb2YgRm9ybUdyb3VwKSB7XG4gICAgICAgICAgY29uc3QgZm91bmQgPSBmaW5kSW5Hcm91cChjKTtcbiAgICAgICAgICBpZiAoZm91bmQpIHJldHVybiBmb3VuZDtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgcmV0dXJuIG51bGw7XG4gICAgfTtcblxuICAgIHJldHVybiBmaW5kSW5Hcm91cCh0aGlzLmZvcm0pO1xuICB9XG5cbiAgcmVzb2x2ZVRhYkxhYmVsKHRhYjogTmVzdGVkVGFiQ29uZmlnKTogc3RyaW5nIHtcbiAgICByZXR1cm4gcmVzb2x2ZUxhYmVsKHRhYi5sYWJlbCwgdGhpcy5sYW5ndWFnZSk7XG4gIH1cblxuICBhc3luYyBzdWJtaXQoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgaWYgKCF0aGlzLmNhblN1Ym1pdCB8fCB0aGlzLnN1Ym1pdEJsb2NrZWQpIHtcbiAgICAgIHRoaXMuZm9ybS5tYXJrQWxsQXNUb3VjaGVkKCk7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgY29uc3QgcmF3RGF0YSA9IHRoaXMuZXh0cmFjdFJlY29yZCgpO1xuICAgIGxldCBwcm9jZXNzZWREYXRhID0gcmF3RGF0YTtcblxuICAgIGNvbnN0IGhvb2tLZXkgPSBgJHt0aGlzLmNvbmZpZz8uZW50aXR5fTpiZWZvcmVTYXZlYDtcbiAgICBpZiAodGhpcy5ob29rUmVnaXN0cnkuaGFzKGhvb2tLZXkpKSB7XG4gICAgICBwcm9jZXNzZWREYXRhID0gYXdhaXQgdGhpcy5ob29rUmVnaXN0cnkucnVuKGhvb2tLZXksIHByb2Nlc3NlZERhdGEpO1xuICAgIH1cblxuICAgIHRoaXMuaXNTYXZpbmcuc2V0KHRydWUpO1xuICAgIHRyeSB7XG4gICAgICB0aGlzLmZvcm1TdWJtaXQuZW1pdChwcm9jZXNzZWREYXRhKTtcbiAgICB9IGZpbmFsbHkge1xuICAgICAgdGhpcy5pc1NhdmluZy5zZXQoZmFsc2UpO1xuICAgIH1cbiAgfVxuXG4gIHJlc2V0KCk6IHZvaWQge1xuICAgIHRoaXMuZm9ybS5yZXNldCgpO1xuICAgIGlmICh0aGlzLmluaXRpYWxEYXRhKSB0aGlzLnBhdGNoRm9ybSh0aGlzLmluaXRpYWxEYXRhKTtcbiAgICBjb25zdCB2YWx1ZXMgPSB0aGlzLmZsYXR0ZW5Gb3JtVmFsdWVzKCk7XG4gICAgdGhpcy5mb3JtVmFsdWVzLnNldCh2YWx1ZXMpO1xuICAgIHRoaXMucHJldmlvdXNWYWx1ZXMgPSB7IC4uLnZhbHVlcyB9O1xuICAgIHRoaXMudW5sb2NrZWRGaWVsZHMuc2V0KG5ldyBTZXQ8c3RyaW5nPigpKTtcbiAgICB0aGlzLmZvcm1SZXNldC5lbWl0KCk7XG4gIH1cbn1cbiIsIkBpZiAoY2FuVmlldykge1xuICA8Zm9ybSBbZm9ybUdyb3VwXT1cImZvcm1cIiAobmdTdWJtaXQpPVwic3VibWl0KClcIiBjbGFzcz1cIm5neC1mb3JtXCIgbm92YWxpZGF0ZT5cblxuICAgIDwhLS0gRXJyb3IgbWVzc2FnZSBiYW5uZXIgLS0+XG4gICAgQGlmIChlcnJvcikge1xuICAgICAgPGRpdiBjbGFzcz1cIm5neC1mb3JtX19lcnJvci1iYW5uZXJcIiByb2xlPVwiYWxlcnRcIiBkYXRhLXRlc3RpZD1cImZvcm0tZXJyb3JcIj57eyBlcnJvciB9fTwvZGl2PlxuICAgIH1cblxuICAgIDwhLS0gUnVsZXMgSW5mbyBCYW5uZXJzIC0tPlxuICAgIEBmb3IgKGluZm9LZXkgb2Ygc2hvd0luZm9CYW5uZXJzID8gT2JqZWN0LmtleXMocnVsZVJlc3VsdCgpLmluZm9CYW5uZXJzKSA6IFtdOyB0cmFjayBpbmZvS2V5KSB7XG4gICAgICA8ZGl2IGNsYXNzPVwibmd4LWZvcm1fX2luZm8tYmFubmVyXCIgcm9sZT1cInN0YXR1c1wiIFthdHRyLmRhdGEtdGVzdGlkXT1cIidpbmZvLWJhbm5lci0nICsgaW5mb0tleVwiPlxuICAgICAgICDihLnvuI8ge3sgcnVsZVJlc3VsdCgpLmluZm9CYW5uZXJzW2luZm9LZXldIH19XG4gICAgICA8L2Rpdj5cbiAgICB9XG5cbiAgICA8IS0tIFJ1bGVzIFZhbGlkYXRpb24gRXJyb3JzICYgV2FybmluZ3MgLS0+XG4gICAgQGZvciAoZXJyS2V5IG9mIE9iamVjdC5rZXlzKHJ1bGVSZXN1bHQoKS52YWxpZGF0aW9uRXJyb3JzKTsgdHJhY2sgZXJyS2V5KSB7XG4gICAgICA8ZGl2IGNsYXNzPVwibmd4LWZvcm1fX2Vycm9yLWJhbm5lclwiIHJvbGU9XCJhbGVydFwiIFthdHRyLmRhdGEtdGVzdGlkXT1cIidydWxlLWVycm9yLScgKyBlcnJLZXlcIj5cbiAgICAgICAg4pqg77iPIHt7IHJ1bGVSZXN1bHQoKS52YWxpZGF0aW9uRXJyb3JzW2VycktleV0gfX1cbiAgICAgIDwvZGl2PlxuICAgIH1cbiAgICBAZm9yICh3YXJuS2V5IG9mIE9iamVjdC5rZXlzKHJ1bGVSZXN1bHQoKS52YWxpZGF0aW9uV2FybmluZ3MpOyB0cmFjayB3YXJuS2V5KSB7XG4gICAgICA8ZGl2IGNsYXNzPVwibmd4LWZvcm1fX3dhcm5pbmctYmFubmVyXCIgcm9sZT1cInN0YXR1c1wiIFthdHRyLmRhdGEtdGVzdGlkXT1cIidydWxlLXdhcm5pbmctJyArIHdhcm5LZXlcIj5cbiAgICAgICAg4pqhIHt7IHJ1bGVSZXN1bHQoKS52YWxpZGF0aW9uV2FybmluZ3Nbd2FybktleV0gfX1cbiAgICAgIDwvZGl2PlxuICAgIH1cblxuICAgIDwhLS0gRGVmZXJyZWQgVkFMVUVfQ0hBTkdFRCBub3RpY2UgZm9yIGNyaXRpY2FsRmllbGQgZWRpdHMgKHZzIHNlc3Npb24gYmFzZWxpbmUpIC0tPlxuICAgIEBpZiAoY2hhbmdlZENyaXRpY2FsRmllbGRzKCkubGVuZ3RoID4gMCkge1xuICAgICAgPGRpdiBjbGFzcz1cIm5neC1mb3JtX193YXJuaW5nLWJhbm5lclwiIHJvbGU9XCJzdGF0dXNcIiBkYXRhLXRlc3RpZD1cImNyaXRpY2FsLWNoYW5nZS1iYW5uZXJcIj5cbiAgICAgICAg8J+UkiBDcml0aWNhbCBmaWVsZCBjaGFuZ2VkOlxuICAgICAgICBAZm9yIChmaWVsZCBvZiBjaGFuZ2VkQ3JpdGljYWxGaWVsZHMoKTsgdHJhY2sgZmllbGQuaWQpIHtcbiAgICAgICAgICA8c3Bhbj57eyByZXNvbHZlRmllbGRMYWJlbChmaWVsZCkgfX17eyAkbGFzdCA/ICcnIDogJywgJyB9fTwvc3Bhbj5cbiAgICAgICAgfVxuICAgICAgICDigJQgdGhpcyBkaWZmZXJzIGZyb20gdGhlIHZhbHVlIGF0IHRoZSBzdGFydCBvZiB0aGlzIHNlc3Npb24uXG4gICAgICA8L2Rpdj5cbiAgICB9XG5cbiAgICA8IS0tIFByaW1hcnkgVGFiIGJhciDigJQgb25seSBpZiB2aXNpYmxlIHRhYnMgZGVmaW5lZCAtLT5cbiAgICBAaWYgKHZpc2libGVUYWJzLmxlbmd0aCA+IDApIHtcbiAgICAgIDxkaXYgY2xhc3M9XCJuZ3gtZm9ybV9fdGFic1wiIHJvbGU9XCJ0YWJsaXN0XCIgZGF0YS10ZXN0aWQ9XCJ0YWItc3RyaXBcIj5cbiAgICAgICAgQGZvciAodGFiIG9mIHZpc2libGVUYWJzOyB0cmFjayB0YWIuaWQpIHtcbiAgICAgICAgICA8YnV0dG9uXG4gICAgICAgICAgICB0eXBlPVwiYnV0dG9uXCJcbiAgICAgICAgICAgIGNsYXNzPVwibmd4LWZvcm1fX3RhYlwiXG4gICAgICAgICAgICBbYXR0ci5kYXRhLXRlc3RpZF09XCIndGFiLScgKyB0YWIuaWRcIlxuICAgICAgICAgICAgW2NsYXNzLm5neC1mb3JtX190YWItLWFjdGl2ZV09XCJhY3RpdmVUYWIoKSA9PT0gdGFiLmlkXCJcbiAgICAgICAgICAgIChjbGljayk9XCJzZXRBY3RpdmVUYWIodGFiLmlkKVwiXG4gICAgICAgICAgICByb2xlPVwidGFiXCJcbiAgICAgICAgICAgIFthdHRyLmFyaWEtc2VsZWN0ZWRdPVwiYWN0aXZlVGFiKCkgPT09IHRhYi5pZFwiXG4gICAgICAgICAgPlxuICAgICAgICAgICAge3sgcmVzb2x2ZVRhYkxhYmVsKHRhYikgfX1cbiAgICAgICAgICA8L2J1dHRvbj5cbiAgICAgICAgfVxuICAgICAgPC9kaXY+XG4gICAgfVxuXG4gICAgPCEtLSBTdWItdGFiIGJhciDigJQgb25seSBpZiBhY3RpdmUgdGFiIGhhcyBzdWItdGFicyAtLT5cbiAgICBAaWYgKHZpc2libGVTdWJUYWJzLmxlbmd0aCA+IDApIHtcbiAgICAgIDxkaXYgY2xhc3M9XCJuZ3gtZm9ybV9fdGFicyBuZ3gtZm9ybV9fdGFicy0tc3ViXCIgcm9sZT1cInRhYmxpc3RcIiBkYXRhLXRlc3RpZD1cInN1YnRhYi1zdHJpcFwiIHN0eWxlPVwibWFyZ2luLXRvcDogLTEycHg7IG1hcmdpbi1ib3R0b206IDEycHg7IGZvbnQtc2l6ZTogMTNweDtcIj5cbiAgICAgICAgQGZvciAoc3ViVGFiIG9mIHZpc2libGVTdWJUYWJzOyB0cmFjayBzdWJUYWIuaWQpIHtcbiAgICAgICAgICA8YnV0dG9uXG4gICAgICAgICAgICB0eXBlPVwiYnV0dG9uXCJcbiAgICAgICAgICAgIGNsYXNzPVwibmd4LWZvcm1fX3RhYiBuZ3gtZm9ybV9fdGFiLS1zdWJcIlxuICAgICAgICAgICAgW2F0dHIuZGF0YS10ZXN0aWRdPVwiJ3N1YnRhYi0nICsgc3ViVGFiLmlkXCJcbiAgICAgICAgICAgIFtjbGFzcy5uZ3gtZm9ybV9fdGFiLS1hY3RpdmVdPVwiKGFjdGl2ZVN1YlRhYkNvbmZpZz8uaWQpID09PSBzdWJUYWIuaWRcIlxuICAgICAgICAgICAgKGNsaWNrKT1cInNldEFjdGl2ZVN1YlRhYihzdWJUYWIuaWQpXCJcbiAgICAgICAgICAgIHJvbGU9XCJ0YWJcIlxuICAgICAgICAgICAgW2F0dHIuYXJpYS1zZWxlY3RlZF09XCIoYWN0aXZlU3ViVGFiQ29uZmlnPy5pZCkgPT09IHN1YlRhYi5pZFwiXG4gICAgICAgICAgPlxuICAgICAgICAgICAge3sgcmVzb2x2ZVRhYkxhYmVsKHN1YlRhYikgfX1cbiAgICAgICAgICA8L2J1dHRvbj5cbiAgICAgICAgfVxuICAgICAgPC9kaXY+XG4gICAgfVxuXG4gICAgPCEtLSBNb2R1bGUgdGFiIGNvbXBvbmVudCBPUiBGaWVsZHMgZm9yIGFjdGl2ZSB0YWIgLS0+XG4gICAgQGlmIChhY3RpdmVUYWJNb2R1bGVDb21wb25lbnQpIHtcbiAgICAgIDxkaXYgY2xhc3M9XCJuZ3gtZm9ybV9fbW9kdWxlLXBhbmVsXCIgZGF0YS10ZXN0aWQ9XCJtb2R1bGUtcGFuZWxcIj5cbiAgICAgICAgPG5nLWNvbnRhaW5lciAqbmdDb21wb25lbnRPdXRsZXQ9XCJhY3RpdmVUYWJNb2R1bGVDb21wb25lbnQ7IGlucHV0czogKGFjdGl2ZVN1YlRhYkNvbmZpZyB8fCBhY3RpdmVUYWJDb25maWcpPy5tb2R1bGVJbnB1dHNcIj48L25nLWNvbnRhaW5lcj5cbiAgICAgIDwvZGl2PlxuICAgIH0gQGVsc2Uge1xuICAgICAgPCEtLSBGaWVsZHMgZm9yIGFjdGl2ZSB0YWIgKFJlc3BvbnNpdmUgMTItY29sdW1uIGdyaWQpIC0tPlxuICAgICAgPGRpdiBjbGFzcz1cIm5neC1mb3JtX19wYW5lbFwiIGRhdGEtdGVzdGlkPVwiZm9ybS1wYW5lbFwiPlxuICAgICAgICBAZm9yIChmaWVsZCBvZiBmaWVsZHNGb3JBY3RpdmVUYWI7IHRyYWNrIGZpZWxkLmlkKSB7XG4gICAgICAgICAgPGRpdlxuICAgICAgICAgICAgY2xhc3M9XCJuZ3gtZm9ybV9fZmllbGQtc2xvdFwiXG4gICAgICAgICAgICBbc3R5bGUuZ3JpZENvbHVtbl09XCJnZXRGaWVsZFNwYW4oZmllbGQpXCJcbiAgICAgICAgICAgIFthdHRyLmlkXT1cIidmaWVsZC1jb250YWluZXItJyArIGZpZWxkLmlkXCJcbiAgICAgICAgICA+XG4gICAgICAgICAgICA8bmd4LWR5bmFtaWMtZmllbGRcbiAgICAgICAgICAgICAgW2ZpZWxkXT1cImZpZWxkXCJcbiAgICAgICAgICAgICAgW2NvbnRyb2xdPVwiZ2V0Q29udHJvbChmaWVsZC5pZCwgKGFjdGl2ZVN1YlRhYkNvbmZpZyB8fCBhY3RpdmVUYWJDb25maWcpPy5pZCkhXCJcbiAgICAgICAgICAgICAgW2NvbmZpZ109XCJjb25maWdcIlxuICAgICAgICAgICAgICBbY3VycmVudFRhYklkXT1cIihhY3RpdmVTdWJUYWJDb25maWcgfHwgYWN0aXZlVGFiQ29uZmlnKT8uaWRcIlxuICAgICAgICAgICAgICBbbGFuZ3VhZ2VdPVwibGFuZ3VhZ2VcIlxuICAgICAgICAgICAgICBbcmVhZG9ubHldPVwiaXNGaWVsZFJlYWRvbmx5KGZpZWxkKVwiXG4gICAgICAgICAgICAgIFt1c2VyUm9sZXNdPVwidXNlclJvbGVzXCJcbiAgICAgICAgICAgIC8+XG4gICAgICAgICAgICBAaWYgKGZpZWxkLmNyaXRpY2FsRmllbGQgJiYgIXJlYWRvbmx5KSB7XG4gICAgICAgICAgICAgIDxidXR0b25cbiAgICAgICAgICAgICAgICB0eXBlPVwiYnV0dG9uXCJcbiAgICAgICAgICAgICAgICBjbGFzcz1cIm5neC1mb3JtX19sb2NrXCJcbiAgICAgICAgICAgICAgICBbYXR0ci5kYXRhLXRlc3RpZF09XCInbG9jay0nICsgZmllbGQuaWRcIlxuICAgICAgICAgICAgICAgIFthdHRyLmFyaWEtcHJlc3NlZF09XCIhaXNGaWVsZExvY2tlZChmaWVsZClcIlxuICAgICAgICAgICAgICAgIFthdHRyLmFyaWEtbGFiZWxdPVwiXG4gICAgICAgICAgICAgICAgICAoaXNGaWVsZExvY2tlZChmaWVsZCkgPyAnVW5sb2NrICcgOiAnTG9jayAnKSArIHJlc29sdmVGaWVsZExhYmVsKGZpZWxkKVxuICAgICAgICAgICAgICAgIFwiXG4gICAgICAgICAgICAgICAgW3RpdGxlXT1cIlxuICAgICAgICAgICAgICAgICAgaXNGaWVsZExvY2tlZChmaWVsZClcbiAgICAgICAgICAgICAgICAgICAgPyAnQ3JpdGljYWwgZmllbGQg4oCUIGNsaWNrIHRvIHVubG9jayBmb3IgZWRpdGluZydcbiAgICAgICAgICAgICAgICAgICAgOiAnQ3JpdGljYWwgZmllbGQg4oCUIGNsaWNrIHRvIGxvY2snXG4gICAgICAgICAgICAgICAgXCJcbiAgICAgICAgICAgICAgICAoY2xpY2spPVwidG9nZ2xlRmllbGRMb2NrKGZpZWxkKVwiXG4gICAgICAgICAgICAgID5cbiAgICAgICAgICAgICAgICB7eyBpc0ZpZWxkTG9ja2VkKGZpZWxkKSA/ICfwn5SSJyA6ICfwn5STJyB9fVxuICAgICAgICAgICAgICA8L2J1dHRvbj5cbiAgICAgICAgICAgIH1cbiAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgfVxuICAgICAgPC9kaXY+XG4gICAgfVxuXG4gICAgPCEtLSBTdWJtaXQgYnV0dG9uIOKAlCBnYXRlZCBieSBSQkFDIGFuZCBpc1NhdmluZyBsb2NrIC0tPlxuICAgIEBpZiAoIXJlYWRvbmx5ICYmIHBlcm1pc3Npb25zLmNhbkVkaXQpIHtcbiAgICAgIDxkaXYgY2xhc3M9XCJuZ3gtZm9ybV9fYWN0aW9uc1wiIGRhdGEtdGVzdGlkPVwiZm9ybS1hY3Rpb25zXCI+XG4gICAgICAgIDxidXR0b25cbiAgICAgICAgICB0eXBlPVwiYnV0dG9uXCJcbiAgICAgICAgICBjbGFzcz1cIm5neC1mb3JtX19yZXNldFwiXG4gICAgICAgICAgZGF0YS10ZXN0aWQ9XCJmb3JtLXJlc2V0XCJcbiAgICAgICAgICAoY2xpY2spPVwicmVzZXQoKVwiXG4gICAgICAgICAgW2Rpc2FibGVkXT1cImlzU2F2aW5nKClcIlxuICAgICAgICA+XG4gICAgICAgICAgUmVzZXRcbiAgICAgICAgPC9idXR0b24+XG4gICAgICAgIDxidXR0b25cbiAgICAgICAgICB0eXBlPVwic3VibWl0XCJcbiAgICAgICAgICBjbGFzcz1cIm5neC1mb3JtX19zdWJtaXRcIlxuICAgICAgICAgIGRhdGEtdGVzdGlkPVwiZm9ybS1zdWJtaXRcIlxuICAgICAgICAgIFtkaXNhYmxlZF09XCJzdWJtaXRCbG9ja2VkXCJcbiAgICAgICAgICB0aXRsZT1cIlNob3J0Y3V0OiBDdHJsK1NcIlxuICAgICAgICA+XG4gICAgICAgICAgQGlmIChpc1NhdmluZygpIHx8IGxvYWRpbmcpIHtcbiAgICAgICAgICAgIFNhdmluZ+KAplxuICAgICAgICAgIH0gQGVsc2Uge1xuICAgICAgICAgICAgU2F2ZVxuICAgICAgICAgIH1cbiAgICAgICAgPC9idXR0b24+XG4gICAgICA8L2Rpdj5cbiAgICB9XG5cbiAgPC9mb3JtPlxufSBAZWxzZSB7XG4gIDwhLS0gcGVybWlzc2lvbnMudmlldyBkZW5pZWQ6IHJlbmRlciBub3RoaW5nIG9mIHRoZSByZWNvcmQuXG4gICAgICAgUHJlc2VudGF0aW9uYWwgb25seSDigJQgdGhlIHNlcnZlciBtdXN0IG5vdCBzZW5kIGRhdGEgdGhpcyB1c2VyIG1heSBub3Qgc2VlLiAtLT5cbiAgPGRpdiBjbGFzcz1cIm5neC1mb3JtX19kZW5pZWRcIiByb2xlPVwic3RhdHVzXCIgZGF0YS10ZXN0aWQ9XCJmb3JtLWFjY2Vzcy1kZW5pZWRcIj5cbiAgICBZb3UgZG8gbm90IGhhdmUgcGVybWlzc2lvbiB0byB2aWV3IHRoaXMgcmVjb3JkLlxuICA8L2Rpdj5cbn1cbiJdfQ==
|