ngx-dynamic-entity-builder 1.2.0 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/README.md +3 -2
  2. package/fesm2022/ngx-dynamic-entity-builder.mjs +421 -116
  3. package/fesm2022/ngx-dynamic-entity-builder.mjs.map +1 -1
  4. package/package.json +7 -7
  5. package/types/ngx-dynamic-entity-builder.d.ts +523 -0
  6. package/esm2022/lib/builder-store.service.mjs +0 -1057
  7. package/esm2022/lib/clone.mjs +0 -14
  8. package/esm2022/lib/components/entity-builder-canvas.component.mjs +0 -83
  9. package/esm2022/lib/components/entity-builder-tree-node.component.mjs +0 -191
  10. package/esm2022/lib/components/entity-reference-config.component.mjs +0 -405
  11. package/esm2022/lib/components/field-inspector.component.mjs +0 -139
  12. package/esm2022/lib/components/field-palette.component.mjs +0 -57
  13. package/esm2022/lib/components/field-rules-list.component.mjs +0 -224
  14. package/esm2022/lib/components/referenced-field-config.component.mjs +0 -234
  15. package/esm2022/lib/components/rule-form.component.mjs +0 -201
  16. package/esm2022/lib/components/tab-manager.component.mjs +0 -354
  17. package/esm2022/lib/entity-builder.component.mjs +0 -176
  18. package/esm2022/lib/field-catalog.mjs +0 -6
  19. package/esm2022/ngx-dynamic-entity-builder.mjs +0 -5
  20. package/esm2022/public-api.mjs +0 -16
  21. package/index.d.ts +0 -5
  22. package/lib/builder-store.service.d.ts +0 -206
  23. package/lib/clone.d.ts +0 -9
  24. package/lib/components/entity-builder-canvas.component.d.ts +0 -9
  25. package/lib/components/entity-builder-tree-node.component.d.ts +0 -17
  26. package/lib/components/entity-reference-config.component.d.ts +0 -29
  27. package/lib/components/field-inspector.component.d.ts +0 -33
  28. package/lib/components/field-palette.component.d.ts +0 -13
  29. package/lib/components/field-rules-list.component.d.ts +0 -19
  30. package/lib/components/referenced-field-config.component.d.ts +0 -24
  31. package/lib/components/rule-form.component.d.ts +0 -16
  32. package/lib/components/tab-manager.component.d.ts +0 -28
  33. package/lib/entity-builder.component.d.ts +0 -53
  34. package/lib/field-catalog.d.ts +0 -5
  35. package/public-api.d.ts +0 -12
@@ -1,354 +0,0 @@
1
- import { Component, inject } from '@angular/core';
2
- import { FormsModule } from '@angular/forms';
3
- import { MatButtonModule } from '@angular/material/button';
4
- import { MatCheckboxModule } from '@angular/material/checkbox';
5
- import { MatFormFieldModule } from '@angular/material/form-field';
6
- import { MatIconModule } from '@angular/material/icon';
7
- import { MatInputModule } from '@angular/material/input';
8
- import { MatSlideToggleModule } from '@angular/material/slide-toggle';
9
- import { MatTooltipModule } from '@angular/material/tooltip';
10
- import { resolveLabel } from '@dynamic-entity/core';
11
- import { SYSTEM_DEFAULT_CAN_EDIT } from 'ngx-dynamic-entity';
12
- import { BuilderStore } from '../builder-store.service';
13
- import * as i0 from "@angular/core";
14
- import * as i1 from "@angular/forms";
15
- import * as i2 from "@angular/material/button";
16
- import * as i3 from "@angular/material/checkbox";
17
- import * as i4 from "@angular/material/form-field";
18
- import * as i5 from "@angular/material/icon";
19
- import * as i6 from "@angular/material/input";
20
- import * as i7 from "@angular/material/tooltip";
21
- /**
22
- * Re-exported so existing imports from this package keep working.
23
- *
24
- * This file used to declare its own `new InjectionToken('SYSTEM_DEFAULT_CAN_EDIT')` while
25
- * `ngx-dynamic-entity` exported another under the same name. InjectionToken identity is by
26
- * object reference, so a consumer providing the renderer's — the documented one — was
27
- * providing a token nothing injected, and the predicate silently never ran. One token now,
28
- * defined in the lower-level package that both depend on.
29
- */
30
- export { SYSTEM_DEFAULT_CAN_EDIT };
31
- /**
32
- * TabManagerComponent — add / rename / reorder / remove tabs & sub-tabs with systemDefault protection.
33
- */
34
- export class TabManagerComponent {
35
- store = inject(BuilderStore);
36
- canEditSystemDefaultsFn = inject(SYSTEM_DEFAULT_CAN_EDIT, { optional: true });
37
- lang() {
38
- return this.store.activeLanguage();
39
- }
40
- tabLabel(tab) {
41
- return resolveLabel(tab.label, this.lang());
42
- }
43
- canEditTab(tab) {
44
- if (!tab.systemDefault)
45
- return true;
46
- if (this.canEditSystemDefaultsFn) {
47
- // The predicate's entire contract is (roles) => boolean. This passed a hardcoded []
48
- // regardless of who was using the builder, so any predicate that actually inspected
49
- // roles answered false for everyone and locked every system-default tab.
50
- return this.canEditSystemDefaultsFn(this.store.userRoles());
51
- }
52
- return true;
53
- }
54
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: TabManagerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
55
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.12", type: TabManagerComponent, isStandalone: true, selector: "ngx-tab-manager", ngImport: i0, template: `
56
- <div class="deb-tabs">
57
- <div class="deb-tabs__head">
58
- <span class="deb-section-title">Tabs Manager</span>
59
- <button mat-stroked-button type="button" (click)="store.addTab()">
60
- <mat-icon>add</mat-icon> Add Tab
61
- </button>
62
- </div>
63
-
64
- @if (store.tabs().length === 0) {
65
- <p class="deb-hint">No tabs — all fields render in a single section.</p>
66
- }
67
-
68
- @for (tab of store.tabs(); track tab.id; let i = $index, count = $count) {
69
- <div class="deb-tab-card" [class.deb-tab-card--system]="tab.systemDefault">
70
- <div class="deb-tabs__row" [attr.data-testid]="'tab-row-' + tab.id">
71
- <mat-form-field appearance="outline" subscriptSizing="dynamic" class="deb-grow">
72
- <mat-label>{{ tab.id }} {{ tab.systemDefault ? '(System)' : '' }}</mat-label>
73
- <input
74
- matInput
75
- [disabled]="!canEditTab(tab)"
76
- [ngModel]="tabLabel(tab)"
77
- (ngModelChange)="store.setTabLabel(tab.id, lang(), $event)"
78
- />
79
- </mat-form-field>
80
- <button
81
- mat-icon-button
82
- type="button"
83
- [disabled]="i === 0 || !canEditTab(tab)"
84
- (click)="store.moveTab(tab.id, -1)"
85
- matTooltip="Move up" aria-label="Move tab up"
86
- >
87
- <mat-icon>arrow_upward</mat-icon>
88
- </button>
89
- <button
90
- mat-icon-button
91
- type="button"
92
- [disabled]="i === count - 1 || !canEditTab(tab)"
93
- (click)="store.moveTab(tab.id, 1)"
94
- matTooltip="Move down" aria-label="Move tab down"
95
- >
96
- <mat-icon>arrow_downward</mat-icon>
97
- </button>
98
- <button
99
- mat-icon-button
100
- type="button"
101
- color="warn"
102
- [disabled]="!canEditTab(tab)"
103
- (click)="store.removeTab(tab.id)"
104
- matTooltip="Remove tab" aria-label="Remove tab"
105
- >
106
- <mat-icon>delete</mat-icon>
107
- </button>
108
- </div>
109
-
110
- <!-- Tab settings row -->
111
- <div class="deb-tab-settings">
112
- <mat-checkbox
113
- [disabled]="!canEditTab(tab)"
114
- [ngModel]="tab.flatData"
115
- (ngModelChange)="store.updateTab(tab.id, { flatData: $event })"
116
- >
117
- Flat Data
118
- </mat-checkbox>
119
- <mat-checkbox
120
- [disabled]="!canEditTab(tab)"
121
- [ngModel]="tab.isPrimaryTab"
122
- (ngModelChange)="$event ? store.setPrimaryTab(tab.id) : store.updateTab(tab.id, { isPrimaryTab: false })"
123
- >
124
- Primary Tab
125
- </mat-checkbox>
126
- <mat-checkbox
127
- [disabled]="!canEditTab(tab)"
128
- [ngModel]="tab.maskData"
129
- (ngModelChange)="store.updateTab(tab.id, { maskData: $event })"
130
- >
131
- Mask Tab Data
132
- </mat-checkbox>
133
- <mat-checkbox
134
- [disabled]="!canEditTab(tab)"
135
- [ngModel]="tab.systemDefault"
136
- (ngModelChange)="store.updateTab(tab.id, { systemDefault: $event })"
137
- >
138
- System Default
139
- </mat-checkbox>
140
- <button
141
- mat-button
142
- type="button"
143
- color="primary"
144
- [disabled]="!canEditTab(tab)"
145
- (click)="store.addSubTab(tab.id)"
146
- >
147
- + Sub-tab
148
- </button>
149
- </div>
150
-
151
- <!-- Module tab configuration -->
152
- <div class="deb-tab-module">
153
- <mat-form-field appearance="outline" subscriptSizing="dynamic" class="deb-grow">
154
- <mat-label>Consumer Module Name (Optional)</mat-label>
155
- <input
156
- matInput
157
- placeholder="e.g. documents-view"
158
- [disabled]="!canEditTab(tab)"
159
- [ngModel]="tab.moduleName"
160
- (ngModelChange)="store.updateTab(tab.id, { moduleName: $event || undefined })"
161
- />
162
- </mat-form-field>
163
- </div>
164
-
165
- <!-- Sub-tabs recursive render (Level 2) -->
166
- @if (tab.children && tab.children.length > 0) {
167
- <div class="deb-subtabs">
168
- <span class="deb-subtabs__title">Sub-tabs:</span>
169
- @for (sub of tab.children; track sub.id) {
170
- <div class="deb-tabs__row deb-subtab-row" [attr.data-testid]="'subtab-row-' + sub.id">
171
- <mat-form-field appearance="outline" subscriptSizing="dynamic" class="deb-grow">
172
- <mat-label>{{ sub.id }}</mat-label>
173
- <input
174
- matInput
175
- [disabled]="!canEditTab(sub)"
176
- [ngModel]="tabLabel(sub)"
177
- (ngModelChange)="store.setTabLabel(sub.id, lang(), $event)"
178
- />
179
- </mat-form-field>
180
- <button
181
- mat-icon-button
182
- type="button"
183
- color="warn"
184
- [disabled]="!canEditTab(sub)"
185
- (click)="store.removeTab(sub.id)"
186
- matTooltip="Remove sub-tab" aria-label="Remove sub-tab"
187
- >
188
- <mat-icon>delete</mat-icon>
189
- </button>
190
- </div>
191
- }
192
- </div>
193
- }
194
- </div>
195
- }
196
- </div>
197
- `, isInline: true, styles: [".deb-tabs__head{display:flex;align-items:center;justify-content:space-between;margin-bottom:12px}.deb-tab-card{border:1px solid var(--deb-border, #e5e7eb);border-radius:8px;padding:10px;margin-bottom:10px;background:var(--deb-bg-surface, #ffffff)}.deb-tab-card--system{border-left:4px solid var(--deb-accent, #6366f1)}.deb-tabs__row{display:flex;align-items:center;gap:4px}.deb-tab-settings{display:flex;flex-wrap:wrap;gap:8px 16px;align-items:center;margin-top:8px;font-size:13px}.deb-tab-module{margin-top:8px}.deb-subtabs{margin-top:8px;padding-left:16px;border-left:2px dashed var(--deb-border, #e5e7eb)}.deb-subtabs__title{font-size:12px;font-weight:600;color:var(--deb-muted, #6b7280)}.deb-subtab-row{margin-top:6px}.deb-grow{flex:1}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }, { kind: "component", type: i2.MatIconButton, selector: "button[mat-icon-button]", exportAs: ["matButton"] }, { kind: "ngmodule", type: MatCheckboxModule }, { kind: "component", type: i3.MatCheckbox, selector: "mat-checkbox", inputs: ["aria-label", "aria-labelledby", "aria-describedby", "id", "required", "labelPosition", "name", "value", "disableRipple", "tabIndex", "color", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i4.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i4.MatLabel, selector: "mat-label" }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i5.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i6.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }, { kind: "ngmodule", type: MatSlideToggleModule }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i7.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }] });
198
- }
199
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: TabManagerComponent, decorators: [{
200
- type: Component,
201
- args: [{ selector: 'ngx-tab-manager', standalone: true, imports: [
202
- FormsModule,
203
- MatButtonModule,
204
- MatCheckboxModule,
205
- MatFormFieldModule,
206
- MatIconModule,
207
- MatInputModule,
208
- MatSlideToggleModule,
209
- MatTooltipModule,
210
- ], template: `
211
- <div class="deb-tabs">
212
- <div class="deb-tabs__head">
213
- <span class="deb-section-title">Tabs Manager</span>
214
- <button mat-stroked-button type="button" (click)="store.addTab()">
215
- <mat-icon>add</mat-icon> Add Tab
216
- </button>
217
- </div>
218
-
219
- @if (store.tabs().length === 0) {
220
- <p class="deb-hint">No tabs — all fields render in a single section.</p>
221
- }
222
-
223
- @for (tab of store.tabs(); track tab.id; let i = $index, count = $count) {
224
- <div class="deb-tab-card" [class.deb-tab-card--system]="tab.systemDefault">
225
- <div class="deb-tabs__row" [attr.data-testid]="'tab-row-' + tab.id">
226
- <mat-form-field appearance="outline" subscriptSizing="dynamic" class="deb-grow">
227
- <mat-label>{{ tab.id }} {{ tab.systemDefault ? '(System)' : '' }}</mat-label>
228
- <input
229
- matInput
230
- [disabled]="!canEditTab(tab)"
231
- [ngModel]="tabLabel(tab)"
232
- (ngModelChange)="store.setTabLabel(tab.id, lang(), $event)"
233
- />
234
- </mat-form-field>
235
- <button
236
- mat-icon-button
237
- type="button"
238
- [disabled]="i === 0 || !canEditTab(tab)"
239
- (click)="store.moveTab(tab.id, -1)"
240
- matTooltip="Move up" aria-label="Move tab up"
241
- >
242
- <mat-icon>arrow_upward</mat-icon>
243
- </button>
244
- <button
245
- mat-icon-button
246
- type="button"
247
- [disabled]="i === count - 1 || !canEditTab(tab)"
248
- (click)="store.moveTab(tab.id, 1)"
249
- matTooltip="Move down" aria-label="Move tab down"
250
- >
251
- <mat-icon>arrow_downward</mat-icon>
252
- </button>
253
- <button
254
- mat-icon-button
255
- type="button"
256
- color="warn"
257
- [disabled]="!canEditTab(tab)"
258
- (click)="store.removeTab(tab.id)"
259
- matTooltip="Remove tab" aria-label="Remove tab"
260
- >
261
- <mat-icon>delete</mat-icon>
262
- </button>
263
- </div>
264
-
265
- <!-- Tab settings row -->
266
- <div class="deb-tab-settings">
267
- <mat-checkbox
268
- [disabled]="!canEditTab(tab)"
269
- [ngModel]="tab.flatData"
270
- (ngModelChange)="store.updateTab(tab.id, { flatData: $event })"
271
- >
272
- Flat Data
273
- </mat-checkbox>
274
- <mat-checkbox
275
- [disabled]="!canEditTab(tab)"
276
- [ngModel]="tab.isPrimaryTab"
277
- (ngModelChange)="$event ? store.setPrimaryTab(tab.id) : store.updateTab(tab.id, { isPrimaryTab: false })"
278
- >
279
- Primary Tab
280
- </mat-checkbox>
281
- <mat-checkbox
282
- [disabled]="!canEditTab(tab)"
283
- [ngModel]="tab.maskData"
284
- (ngModelChange)="store.updateTab(tab.id, { maskData: $event })"
285
- >
286
- Mask Tab Data
287
- </mat-checkbox>
288
- <mat-checkbox
289
- [disabled]="!canEditTab(tab)"
290
- [ngModel]="tab.systemDefault"
291
- (ngModelChange)="store.updateTab(tab.id, { systemDefault: $event })"
292
- >
293
- System Default
294
- </mat-checkbox>
295
- <button
296
- mat-button
297
- type="button"
298
- color="primary"
299
- [disabled]="!canEditTab(tab)"
300
- (click)="store.addSubTab(tab.id)"
301
- >
302
- + Sub-tab
303
- </button>
304
- </div>
305
-
306
- <!-- Module tab configuration -->
307
- <div class="deb-tab-module">
308
- <mat-form-field appearance="outline" subscriptSizing="dynamic" class="deb-grow">
309
- <mat-label>Consumer Module Name (Optional)</mat-label>
310
- <input
311
- matInput
312
- placeholder="e.g. documents-view"
313
- [disabled]="!canEditTab(tab)"
314
- [ngModel]="tab.moduleName"
315
- (ngModelChange)="store.updateTab(tab.id, { moduleName: $event || undefined })"
316
- />
317
- </mat-form-field>
318
- </div>
319
-
320
- <!-- Sub-tabs recursive render (Level 2) -->
321
- @if (tab.children && tab.children.length > 0) {
322
- <div class="deb-subtabs">
323
- <span class="deb-subtabs__title">Sub-tabs:</span>
324
- @for (sub of tab.children; track sub.id) {
325
- <div class="deb-tabs__row deb-subtab-row" [attr.data-testid]="'subtab-row-' + sub.id">
326
- <mat-form-field appearance="outline" subscriptSizing="dynamic" class="deb-grow">
327
- <mat-label>{{ sub.id }}</mat-label>
328
- <input
329
- matInput
330
- [disabled]="!canEditTab(sub)"
331
- [ngModel]="tabLabel(sub)"
332
- (ngModelChange)="store.setTabLabel(sub.id, lang(), $event)"
333
- />
334
- </mat-form-field>
335
- <button
336
- mat-icon-button
337
- type="button"
338
- color="warn"
339
- [disabled]="!canEditTab(sub)"
340
- (click)="store.removeTab(sub.id)"
341
- matTooltip="Remove sub-tab" aria-label="Remove sub-tab"
342
- >
343
- <mat-icon>delete</mat-icon>
344
- </button>
345
- </div>
346
- }
347
- </div>
348
- }
349
- </div>
350
- }
351
- </div>
352
- `, styles: [".deb-tabs__head{display:flex;align-items:center;justify-content:space-between;margin-bottom:12px}.deb-tab-card{border:1px solid var(--deb-border, #e5e7eb);border-radius:8px;padding:10px;margin-bottom:10px;background:var(--deb-bg-surface, #ffffff)}.deb-tab-card--system{border-left:4px solid var(--deb-accent, #6366f1)}.deb-tabs__row{display:flex;align-items:center;gap:4px}.deb-tab-settings{display:flex;flex-wrap:wrap;gap:8px 16px;align-items:center;margin-top:8px;font-size:13px}.deb-tab-module{margin-top:8px}.deb-subtabs{margin-top:8px;padding-left:16px;border-left:2px dashed var(--deb-border, #e5e7eb)}.deb-subtabs__title{font-size:12px;font-weight:600;color:var(--deb-muted, #6b7280)}.deb-subtab-row{margin-top:6px}.deb-grow{flex:1}\n"] }]
353
- }] });
354
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGFiLW1hbmFnZXIuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL2xpYi9jb21wb25lbnRzL3RhYi1tYW5hZ2VyLmNvbXBvbmVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUNsRCxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDN0MsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLDBCQUEwQixDQUFDO0FBQzNELE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxNQUFNLDRCQUE0QixDQUFDO0FBQy9ELE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLDhCQUE4QixDQUFDO0FBQ2xFLE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUN2RCxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0seUJBQXlCLENBQUM7QUFDekQsT0FBTyxFQUFFLG9CQUFvQixFQUFFLE1BQU0sZ0NBQWdDLENBQUM7QUFDdEUsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sMkJBQTJCLENBQUM7QUFFN0QsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBQ3BELE9BQU8sRUFBRSx1QkFBdUIsRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBQzdELE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQzs7Ozs7Ozs7O0FBRXhEOzs7Ozs7OztHQVFHO0FBQ0gsT0FBTyxFQUFFLHVCQUF1QixFQUFFLENBQUM7QUFFbkM7O0dBRUc7QUFrTkgsTUFBTSxPQUFPLG1CQUFtQjtJQUNYLEtBQUssR0FBRyxNQUFNLENBQUMsWUFBWSxDQUFDLENBQUM7SUFDL0IsdUJBQXVCLEdBQUcsTUFBTSxDQUErQix1QkFBdUIsRUFBRSxFQUFFLFFBQVEsRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFDO0lBRW5ILElBQUk7UUFDWixPQUFPLElBQUksQ0FBQyxLQUFLLENBQUMsY0FBYyxFQUFFLENBQUM7SUFDckMsQ0FBQztJQUVTLFFBQVEsQ0FBQyxHQUFvQjtRQUNyQyxPQUFPLFlBQVksQ0FBQyxHQUFHLENBQUMsS0FBSyxFQUFFLElBQUksQ0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDO0lBQzlDLENBQUM7SUFFUyxVQUFVLENBQUMsR0FBb0I7UUFDdkMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxhQUFhO1lBQUUsT0FBTyxJQUFJLENBQUM7UUFDcEMsSUFBSSxJQUFJLENBQUMsdUJBQXVCLEVBQUUsQ0FBQztZQUNqQyxvRkFBb0Y7WUFDcEYsb0ZBQW9GO1lBQ3BGLHlFQUF5RTtZQUN6RSxPQUFPLElBQUksQ0FBQyx1QkFBdUIsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLFNBQVMsRUFBRSxDQUFDLENBQUM7UUFDOUQsQ0FBQztRQUNELE9BQU8sSUFBSSxDQUFDO0lBQ2QsQ0FBQzt3R0FyQlUsbUJBQW1COzRGQUFuQixtQkFBbUIsMkVBcE1wQjs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQThJVCw4eUJBdkpDLFdBQVcsOG1CQUNYLGVBQWUsd1VBQ2YsaUJBQWlCLDZXQUNqQixrQkFBa0IsMFNBQ2xCLGFBQWEsbUxBQ2IsY0FBYywwV0FDZCxvQkFBb0IsOEJBQ3BCLGdCQUFnQjs7NEZBc01QLG1CQUFtQjtrQkFqTi9CLFNBQVM7K0JBQ0UsaUJBQWlCLGNBQ2YsSUFBSSxXQUNQO3dCQUNQLFdBQVc7d0JBQ1gsZUFBZTt3QkFDZixpQkFBaUI7d0JBQ2pCLGtCQUFrQjt3QkFDbEIsYUFBYTt3QkFDYixjQUFjO3dCQUNkLG9CQUFvQjt3QkFDcEIsZ0JBQWdCO3FCQUNqQixZQUNTOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBOElUIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQ29tcG9uZW50LCBpbmplY3QgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IEZvcm1zTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvZm9ybXMnO1xuaW1wb3J0IHsgTWF0QnV0dG9uTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvbWF0ZXJpYWwvYnV0dG9uJztcbmltcG9ydCB7IE1hdENoZWNrYm94TW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvbWF0ZXJpYWwvY2hlY2tib3gnO1xuaW1wb3J0IHsgTWF0Rm9ybUZpZWxkTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvbWF0ZXJpYWwvZm9ybS1maWVsZCc7XG5pbXBvcnQgeyBNYXRJY29uTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvbWF0ZXJpYWwvaWNvbic7XG5pbXBvcnQgeyBNYXRJbnB1dE1vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL21hdGVyaWFsL2lucHV0JztcbmltcG9ydCB7IE1hdFNsaWRlVG9nZ2xlTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvbWF0ZXJpYWwvc2xpZGUtdG9nZ2xlJztcbmltcG9ydCB7IE1hdFRvb2x0aXBNb2R1bGUgfSBmcm9tICdAYW5ndWxhci9tYXRlcmlhbC90b29sdGlwJztcbmltcG9ydCB0eXBlIHsgTmVzdGVkVGFiQ29uZmlnIH0gZnJvbSAnQGR5bmFtaWMtZW50aXR5L2NvcmUnO1xuaW1wb3J0IHsgcmVzb2x2ZUxhYmVsIH0gZnJvbSAnQGR5bmFtaWMtZW50aXR5L2NvcmUnO1xuaW1wb3J0IHsgU1lTVEVNX0RFRkFVTFRfQ0FOX0VESVQgfSBmcm9tICduZ3gtZHluYW1pYy1lbnRpdHknO1xuaW1wb3J0IHsgQnVpbGRlclN0b3JlIH0gZnJvbSAnLi4vYnVpbGRlci1zdG9yZS5zZXJ2aWNlJztcblxuLyoqXG4gKiBSZS1leHBvcnRlZCBzbyBleGlzdGluZyBpbXBvcnRzIGZyb20gdGhpcyBwYWNrYWdlIGtlZXAgd29ya2luZy5cbiAqXG4gKiBUaGlzIGZpbGUgdXNlZCB0byBkZWNsYXJlIGl0cyBvd24gYG5ldyBJbmplY3Rpb25Ub2tlbignU1lTVEVNX0RFRkFVTFRfQ0FOX0VESVQnKWAgd2hpbGVcbiAqIGBuZ3gtZHluYW1pYy1lbnRpdHlgIGV4cG9ydGVkIGFub3RoZXIgdW5kZXIgdGhlIHNhbWUgbmFtZS4gSW5qZWN0aW9uVG9rZW4gaWRlbnRpdHkgaXMgYnlcbiAqIG9iamVjdCByZWZlcmVuY2UsIHNvIGEgY29uc3VtZXIgcHJvdmlkaW5nIHRoZSByZW5kZXJlcidzIOKAlCB0aGUgZG9jdW1lbnRlZCBvbmUg4oCUIHdhc1xuICogcHJvdmlkaW5nIGEgdG9rZW4gbm90aGluZyBpbmplY3RlZCwgYW5kIHRoZSBwcmVkaWNhdGUgc2lsZW50bHkgbmV2ZXIgcmFuLiBPbmUgdG9rZW4gbm93LFxuICogZGVmaW5lZCBpbiB0aGUgbG93ZXItbGV2ZWwgcGFja2FnZSB0aGF0IGJvdGggZGVwZW5kIG9uLlxuICovXG5leHBvcnQgeyBTWVNURU1fREVGQVVMVF9DQU5fRURJVCB9O1xuXG4vKipcbiAqIFRhYk1hbmFnZXJDb21wb25lbnQg4oCUIGFkZCAvIHJlbmFtZSAvIHJlb3JkZXIgLyByZW1vdmUgdGFicyAmIHN1Yi10YWJzIHdpdGggc3lzdGVtRGVmYXVsdCBwcm90ZWN0aW9uLlxuICovXG5AQ29tcG9uZW50KHtcbiAgc2VsZWN0b3I6ICduZ3gtdGFiLW1hbmFnZXInLFxuICBzdGFuZGFsb25lOiB0cnVlLFxuICBpbXBvcnRzOiBbXG4gICAgRm9ybXNNb2R1bGUsXG4gICAgTWF0QnV0dG9uTW9kdWxlLFxuICAgIE1hdENoZWNrYm94TW9kdWxlLFxuICAgIE1hdEZvcm1GaWVsZE1vZHVsZSxcbiAgICBNYXRJY29uTW9kdWxlLFxuICAgIE1hdElucHV0TW9kdWxlLFxuICAgIE1hdFNsaWRlVG9nZ2xlTW9kdWxlLFxuICAgIE1hdFRvb2x0aXBNb2R1bGUsXG4gIF0sXG4gIHRlbXBsYXRlOiBgXG4gICAgPGRpdiBjbGFzcz1cImRlYi10YWJzXCI+XG4gICAgICA8ZGl2IGNsYXNzPVwiZGViLXRhYnNfX2hlYWRcIj5cbiAgICAgICAgPHNwYW4gY2xhc3M9XCJkZWItc2VjdGlvbi10aXRsZVwiPlRhYnMgTWFuYWdlcjwvc3Bhbj5cbiAgICAgICAgPGJ1dHRvbiBtYXQtc3Ryb2tlZC1idXR0b24gdHlwZT1cImJ1dHRvblwiIChjbGljayk9XCJzdG9yZS5hZGRUYWIoKVwiPlxuICAgICAgICAgIDxtYXQtaWNvbj5hZGQ8L21hdC1pY29uPiBBZGQgVGFiXG4gICAgICAgIDwvYnV0dG9uPlxuICAgICAgPC9kaXY+XG5cbiAgICAgIEBpZiAoc3RvcmUudGFicygpLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICA8cCBjbGFzcz1cImRlYi1oaW50XCI+Tm8gdGFicyDigJQgYWxsIGZpZWxkcyByZW5kZXIgaW4gYSBzaW5nbGUgc2VjdGlvbi48L3A+XG4gICAgICB9XG5cbiAgICAgIEBmb3IgKHRhYiBvZiBzdG9yZS50YWJzKCk7IHRyYWNrIHRhYi5pZDsgbGV0IGkgPSAkaW5kZXgsIGNvdW50ID0gJGNvdW50KSB7XG4gICAgICAgIDxkaXYgY2xhc3M9XCJkZWItdGFiLWNhcmRcIiBbY2xhc3MuZGViLXRhYi1jYXJkLS1zeXN0ZW1dPVwidGFiLnN5c3RlbURlZmF1bHRcIj5cbiAgICAgICAgICA8ZGl2IGNsYXNzPVwiZGViLXRhYnNfX3Jvd1wiIFthdHRyLmRhdGEtdGVzdGlkXT1cIid0YWItcm93LScgKyB0YWIuaWRcIj5cbiAgICAgICAgICAgIDxtYXQtZm9ybS1maWVsZCBhcHBlYXJhbmNlPVwib3V0bGluZVwiIHN1YnNjcmlwdFNpemluZz1cImR5bmFtaWNcIiBjbGFzcz1cImRlYi1ncm93XCI+XG4gICAgICAgICAgICAgIDxtYXQtbGFiZWw+e3sgdGFiLmlkIH19IHt7IHRhYi5zeXN0ZW1EZWZhdWx0ID8gJyhTeXN0ZW0pJyA6ICcnIH19PC9tYXQtbGFiZWw+XG4gICAgICAgICAgICAgIDxpbnB1dFxuICAgICAgICAgICAgICAgIG1hdElucHV0XG4gICAgICAgICAgICAgICAgW2Rpc2FibGVkXT1cIiFjYW5FZGl0VGFiKHRhYilcIlxuICAgICAgICAgICAgICAgIFtuZ01vZGVsXT1cInRhYkxhYmVsKHRhYilcIlxuICAgICAgICAgICAgICAgIChuZ01vZGVsQ2hhbmdlKT1cInN0b3JlLnNldFRhYkxhYmVsKHRhYi5pZCwgbGFuZygpLCAkZXZlbnQpXCJcbiAgICAgICAgICAgICAgLz5cbiAgICAgICAgICAgIDwvbWF0LWZvcm0tZmllbGQ+XG4gICAgICAgICAgICA8YnV0dG9uXG4gICAgICAgICAgICAgIG1hdC1pY29uLWJ1dHRvblxuICAgICAgICAgICAgICB0eXBlPVwiYnV0dG9uXCJcbiAgICAgICAgICAgICAgW2Rpc2FibGVkXT1cImkgPT09IDAgfHwgIWNhbkVkaXRUYWIodGFiKVwiXG4gICAgICAgICAgICAgIChjbGljayk9XCJzdG9yZS5tb3ZlVGFiKHRhYi5pZCwgLTEpXCJcbiAgICAgICAgICAgICAgbWF0VG9vbHRpcD1cIk1vdmUgdXBcIiBhcmlhLWxhYmVsPVwiTW92ZSB0YWIgdXBcIlxuICAgICAgICAgICAgPlxuICAgICAgICAgICAgICA8bWF0LWljb24+YXJyb3dfdXB3YXJkPC9tYXQtaWNvbj5cbiAgICAgICAgICAgIDwvYnV0dG9uPlxuICAgICAgICAgICAgPGJ1dHRvblxuICAgICAgICAgICAgICBtYXQtaWNvbi1idXR0b25cbiAgICAgICAgICAgICAgdHlwZT1cImJ1dHRvblwiXG4gICAgICAgICAgICAgIFtkaXNhYmxlZF09XCJpID09PSBjb3VudCAtIDEgfHwgIWNhbkVkaXRUYWIodGFiKVwiXG4gICAgICAgICAgICAgIChjbGljayk9XCJzdG9yZS5tb3ZlVGFiKHRhYi5pZCwgMSlcIlxuICAgICAgICAgICAgICBtYXRUb29sdGlwPVwiTW92ZSBkb3duXCIgYXJpYS1sYWJlbD1cIk1vdmUgdGFiIGRvd25cIlxuICAgICAgICAgICAgPlxuICAgICAgICAgICAgICA8bWF0LWljb24+YXJyb3dfZG93bndhcmQ8L21hdC1pY29uPlxuICAgICAgICAgICAgPC9idXR0b24+XG4gICAgICAgICAgICA8YnV0dG9uXG4gICAgICAgICAgICAgIG1hdC1pY29uLWJ1dHRvblxuICAgICAgICAgICAgICB0eXBlPVwiYnV0dG9uXCJcbiAgICAgICAgICAgICAgY29sb3I9XCJ3YXJuXCJcbiAgICAgICAgICAgICAgW2Rpc2FibGVkXT1cIiFjYW5FZGl0VGFiKHRhYilcIlxuICAgICAgICAgICAgICAoY2xpY2spPVwic3RvcmUucmVtb3ZlVGFiKHRhYi5pZClcIlxuICAgICAgICAgICAgICBtYXRUb29sdGlwPVwiUmVtb3ZlIHRhYlwiIGFyaWEtbGFiZWw9XCJSZW1vdmUgdGFiXCJcbiAgICAgICAgICAgID5cbiAgICAgICAgICAgICAgPG1hdC1pY29uPmRlbGV0ZTwvbWF0LWljb24+XG4gICAgICAgICAgICA8L2J1dHRvbj5cbiAgICAgICAgICA8L2Rpdj5cblxuICAgICAgICAgIDwhLS0gVGFiIHNldHRpbmdzIHJvdyAtLT5cbiAgICAgICAgICA8ZGl2IGNsYXNzPVwiZGViLXRhYi1zZXR0aW5nc1wiPlxuICAgICAgICAgICAgPG1hdC1jaGVja2JveFxuICAgICAgICAgICAgICBbZGlzYWJsZWRdPVwiIWNhbkVkaXRUYWIodGFiKVwiXG4gICAgICAgICAgICAgIFtuZ01vZGVsXT1cInRhYi5mbGF0RGF0YVwiXG4gICAgICAgICAgICAgIChuZ01vZGVsQ2hhbmdlKT1cInN0b3JlLnVwZGF0ZVRhYih0YWIuaWQsIHsgZmxhdERhdGE6ICRldmVudCB9KVwiXG4gICAgICAgICAgICA+XG4gICAgICAgICAgICAgIEZsYXQgRGF0YVxuICAgICAgICAgICAgPC9tYXQtY2hlY2tib3g+XG4gICAgICAgICAgICA8bWF0LWNoZWNrYm94XG4gICAgICAgICAgICAgIFtkaXNhYmxlZF09XCIhY2FuRWRpdFRhYih0YWIpXCJcbiAgICAgICAgICAgICAgW25nTW9kZWxdPVwidGFiLmlzUHJpbWFyeVRhYlwiXG4gICAgICAgICAgICAgIChuZ01vZGVsQ2hhbmdlKT1cIiRldmVudCA/IHN0b3JlLnNldFByaW1hcnlUYWIodGFiLmlkKSA6IHN0b3JlLnVwZGF0ZVRhYih0YWIuaWQsIHsgaXNQcmltYXJ5VGFiOiBmYWxzZSB9KVwiXG4gICAgICAgICAgICA+XG4gICAgICAgICAgICAgIFByaW1hcnkgVGFiXG4gICAgICAgICAgICA8L21hdC1jaGVja2JveD5cbiAgICAgICAgICAgIDxtYXQtY2hlY2tib3hcbiAgICAgICAgICAgICAgW2Rpc2FibGVkXT1cIiFjYW5FZGl0VGFiKHRhYilcIlxuICAgICAgICAgICAgICBbbmdNb2RlbF09XCJ0YWIubWFza0RhdGFcIlxuICAgICAgICAgICAgICAobmdNb2RlbENoYW5nZSk9XCJzdG9yZS51cGRhdGVUYWIodGFiLmlkLCB7IG1hc2tEYXRhOiAkZXZlbnQgfSlcIlxuICAgICAgICAgICAgPlxuICAgICAgICAgICAgICBNYXNrIFRhYiBEYXRhXG4gICAgICAgICAgICA8L21hdC1jaGVja2JveD5cbiAgICAgICAgICAgIDxtYXQtY2hlY2tib3hcbiAgICAgICAgICAgICAgW2Rpc2FibGVkXT1cIiFjYW5FZGl0VGFiKHRhYilcIlxuICAgICAgICAgICAgICBbbmdNb2RlbF09XCJ0YWIuc3lzdGVtRGVmYXVsdFwiXG4gICAgICAgICAgICAgIChuZ01vZGVsQ2hhbmdlKT1cInN0b3JlLnVwZGF0ZVRhYih0YWIuaWQsIHsgc3lzdGVtRGVmYXVsdDogJGV2ZW50IH0pXCJcbiAgICAgICAgICAgID5cbiAgICAgICAgICAgICAgU3lzdGVtIERlZmF1bHRcbiAgICAgICAgICAgIDwvbWF0LWNoZWNrYm94PlxuICAgICAgICAgICAgPGJ1dHRvblxuICAgICAgICAgICAgICBtYXQtYnV0dG9uXG4gICAgICAgICAgICAgIHR5cGU9XCJidXR0b25cIlxuICAgICAgICAgICAgICBjb2xvcj1cInByaW1hcnlcIlxuICAgICAgICAgICAgICBbZGlzYWJsZWRdPVwiIWNhbkVkaXRUYWIodGFiKVwiXG4gICAgICAgICAgICAgIChjbGljayk9XCJzdG9yZS5hZGRTdWJUYWIodGFiLmlkKVwiXG4gICAgICAgICAgICA+XG4gICAgICAgICAgICAgICsgU3ViLXRhYlxuICAgICAgICAgICAgPC9idXR0b24+XG4gICAgICAgICAgPC9kaXY+XG5cbiAgICAgICAgICA8IS0tIE1vZHVsZSB0YWIgY29uZmlndXJhdGlvbiAtLT5cbiAgICAgICAgICA8ZGl2IGNsYXNzPVwiZGViLXRhYi1tb2R1bGVcIj5cbiAgICAgICAgICAgIDxtYXQtZm9ybS1maWVsZCBhcHBlYXJhbmNlPVwib3V0bGluZVwiIHN1YnNjcmlwdFNpemluZz1cImR5bmFtaWNcIiBjbGFzcz1cImRlYi1ncm93XCI+XG4gICAgICAgICAgICAgIDxtYXQtbGFiZWw+Q29uc3VtZXIgTW9kdWxlIE5hbWUgKE9wdGlvbmFsKTwvbWF0LWxhYmVsPlxuICAgICAgICAgICAgICA8aW5wdXRcbiAgICAgICAgICAgICAgICBtYXRJbnB1dFxuICAgICAgICAgICAgICAgIHBsYWNlaG9sZGVyPVwiZS5nLiBkb2N1bWVudHMtdmlld1wiXG4gICAgICAgICAgICAgICAgW2Rpc2FibGVkXT1cIiFjYW5FZGl0VGFiKHRhYilcIlxuICAgICAgICAgICAgICAgIFtuZ01vZGVsXT1cInRhYi5tb2R1bGVOYW1lXCJcbiAgICAgICAgICAgICAgICAobmdNb2RlbENoYW5nZSk9XCJzdG9yZS51cGRhdGVUYWIodGFiLmlkLCB7IG1vZHVsZU5hbWU6ICRldmVudCB8fCB1bmRlZmluZWQgfSlcIlxuICAgICAgICAgICAgICAvPlxuICAgICAgICAgICAgPC9tYXQtZm9ybS1maWVsZD5cbiAgICAgICAgICA8L2Rpdj5cblxuICAgICAgICAgIDwhLS0gU3ViLXRhYnMgcmVjdXJzaXZlIHJlbmRlciAoTGV2ZWwgMikgLS0+XG4gICAgICAgICAgQGlmICh0YWIuY2hpbGRyZW4gJiYgdGFiLmNoaWxkcmVuLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJkZWItc3VidGFic1wiPlxuICAgICAgICAgICAgICA8c3BhbiBjbGFzcz1cImRlYi1zdWJ0YWJzX190aXRsZVwiPlN1Yi10YWJzOjwvc3Bhbj5cbiAgICAgICAgICAgICAgQGZvciAoc3ViIG9mIHRhYi5jaGlsZHJlbjsgdHJhY2sgc3ViLmlkKSB7XG4gICAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cImRlYi10YWJzX19yb3cgZGViLXN1YnRhYi1yb3dcIiBbYXR0ci5kYXRhLXRlc3RpZF09XCInc3VidGFiLXJvdy0nICsgc3ViLmlkXCI+XG4gICAgICAgICAgICAgICAgICA8bWF0LWZvcm0tZmllbGQgYXBwZWFyYW5jZT1cIm91dGxpbmVcIiBzdWJzY3JpcHRTaXppbmc9XCJkeW5hbWljXCIgY2xhc3M9XCJkZWItZ3Jvd1wiPlxuICAgICAgICAgICAgICAgICAgICA8bWF0LWxhYmVsPnt7IHN1Yi5pZCB9fTwvbWF0LWxhYmVsPlxuICAgICAgICAgICAgICAgICAgICA8aW5wdXRcbiAgICAgICAgICAgICAgICAgICAgICBtYXRJbnB1dFxuICAgICAgICAgICAgICAgICAgICAgIFtkaXNhYmxlZF09XCIhY2FuRWRpdFRhYihzdWIpXCJcbiAgICAgICAgICAgICAgICAgICAgICBbbmdNb2RlbF09XCJ0YWJMYWJlbChzdWIpXCJcbiAgICAgICAgICAgICAgICAgICAgICAobmdNb2RlbENoYW5nZSk9XCJzdG9yZS5zZXRUYWJMYWJlbChzdWIuaWQsIGxhbmcoKSwgJGV2ZW50KVwiXG4gICAgICAgICAgICAgICAgICAgIC8+XG4gICAgICAgICAgICAgICAgICA8L21hdC1mb3JtLWZpZWxkPlxuICAgICAgICAgICAgICAgICAgPGJ1dHRvblxuICAgICAgICAgICAgICAgICAgICBtYXQtaWNvbi1idXR0b25cbiAgICAgICAgICAgICAgICAgICAgdHlwZT1cImJ1dHRvblwiXG4gICAgICAgICAgICAgICAgICAgIGNvbG9yPVwid2FyblwiXG4gICAgICAgICAgICAgICAgICAgIFtkaXNhYmxlZF09XCIhY2FuRWRpdFRhYihzdWIpXCJcbiAgICAgICAgICAgICAgICAgICAgKGNsaWNrKT1cInN0b3JlLnJlbW92ZVRhYihzdWIuaWQpXCJcbiAgICAgICAgICAgICAgICAgICAgbWF0VG9vbHRpcD1cIlJlbW92ZSBzdWItdGFiXCIgYXJpYS1sYWJlbD1cIlJlbW92ZSBzdWItdGFiXCJcbiAgICAgICAgICAgICAgICAgID5cbiAgICAgICAgICAgICAgICAgICAgPG1hdC1pY29uPmRlbGV0ZTwvbWF0LWljb24+XG4gICAgICAgICAgICAgICAgICA8L2J1dHRvbj5cbiAgICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgfVxuICAgICAgICA8L2Rpdj5cbiAgICAgIH1cbiAgICA8L2Rpdj5cbiAgYCxcbiAgc3R5bGVzOiBbXG4gICAgYFxuICAgICAgLmRlYi10YWJzX19oZWFkIHtcbiAgICAgICAgZGlzcGxheTogZmxleDtcbiAgICAgICAgYWxpZ24taXRlbXM6IGNlbnRlcjtcbiAgICAgICAganVzdGlmeS1jb250ZW50OiBzcGFjZS1iZXR3ZWVuO1xuICAgICAgICBtYXJnaW4tYm90dG9tOiAxMnB4O1xuICAgICAgfVxuICAgICAgLmRlYi10YWItY2FyZCB7XG4gICAgICAgIGJvcmRlcjogMXB4IHNvbGlkIHZhcigtLWRlYi1ib3JkZXIsICNlNWU3ZWIpO1xuICAgICAgICBib3JkZXItcmFkaXVzOiA4cHg7XG4gICAgICAgIHBhZGRpbmc6IDEwcHg7XG4gICAgICAgIG1hcmdpbi1ib3R0b206IDEwcHg7XG4gICAgICAgIGJhY2tncm91bmQ6IHZhcigtLWRlYi1iZy1zdXJmYWNlLCAjZmZmZmZmKTtcbiAgICAgIH1cbiAgICAgIC5kZWItdGFiLWNhcmQtLXN5c3RlbSB7XG4gICAgICAgIGJvcmRlci1sZWZ0OiA0cHggc29saWQgdmFyKC0tZGViLWFjY2VudCwgIzYzNjZmMSk7XG4gICAgICB9XG4gICAgICAuZGViLXRhYnNfX3JvdyB7XG4gICAgICAgIGRpc3BsYXk6IGZsZXg7XG4gICAgICAgIGFsaWduLWl0ZW1zOiBjZW50ZXI7XG4gICAgICAgIGdhcDogNHB4O1xuICAgICAgfVxuICAgICAgLmRlYi10YWItc2V0dGluZ3Mge1xuICAgICAgICBkaXNwbGF5OiBmbGV4O1xuICAgICAgICBmbGV4LXdyYXA6IHdyYXA7XG4gICAgICAgIGdhcDogOHB4IDE2cHg7XG4gICAgICAgIGFsaWduLWl0ZW1zOiBjZW50ZXI7XG4gICAgICAgIG1hcmdpbi10b3A6IDhweDtcbiAgICAgICAgZm9udC1zaXplOiAxM3B4O1xuICAgICAgfVxuICAgICAgLmRlYi10YWItbW9kdWxlIHtcbiAgICAgICAgbWFyZ2luLXRvcDogOHB4O1xuICAgICAgfVxuICAgICAgLmRlYi1zdWJ0YWJzIHtcbiAgICAgICAgbWFyZ2luLXRvcDogOHB4O1xuICAgICAgICBwYWRkaW5nLWxlZnQ6IDE2cHg7XG4gICAgICAgIGJvcmRlci1sZWZ0OiAycHggZGFzaGVkIHZhcigtLWRlYi1ib3JkZXIsICNlNWU3ZWIpO1xuICAgICAgfVxuICAgICAgLmRlYi1zdWJ0YWJzX190aXRsZSB7XG4gICAgICAgIGZvbnQtc2l6ZTogMTJweDtcbiAgICAgICAgZm9udC13ZWlnaHQ6IDYwMDtcbiAgICAgICAgY29sb3I6IHZhcigtLWRlYi1tdXRlZCwgIzZiNzI4MCk7XG4gICAgICB9XG4gICAgICAuZGViLXN1YnRhYi1yb3cge1xuICAgICAgICBtYXJnaW4tdG9wOiA2cHg7XG4gICAgICB9XG4gICAgICAuZGViLWdyb3cge1xuICAgICAgICBmbGV4OiAxO1xuICAgICAgfVxuICAgIGAsXG4gIF0sXG59KVxuZXhwb3J0IGNsYXNzIFRhYk1hbmFnZXJDb21wb25lbnQge1xuICBwcm90ZWN0ZWQgcmVhZG9ubHkgc3RvcmUgPSBpbmplY3QoQnVpbGRlclN0b3JlKTtcbiAgcHJpdmF0ZSByZWFkb25seSBjYW5FZGl0U3lzdGVtRGVmYXVsdHNGbiA9IGluamVjdDwocm9sZXM6IHN0cmluZ1tdKSA9PiBib29sZWFuPihTWVNURU1fREVGQVVMVF9DQU5fRURJVCwgeyBvcHRpb25hbDogdHJ1ZSB9KTtcblxuICBwcm90ZWN0ZWQgbGFuZygpOiBzdHJpbmcge1xuICAgIHJldHVybiB0aGlzLnN0b3JlLmFjdGl2ZUxhbmd1YWdlKCk7XG4gIH1cblxuICBwcm90ZWN0ZWQgdGFiTGFiZWwodGFiOiB7IGxhYmVsPzogYW55IH0pOiBzdHJpbmcge1xuICAgIHJldHVybiByZXNvbHZlTGFiZWwodGFiLmxhYmVsLCB0aGlzLmxhbmcoKSk7XG4gIH1cblxuICBwcm90ZWN0ZWQgY2FuRWRpdFRhYih0YWI6IE5lc3RlZFRhYkNvbmZpZyk6IGJvb2xlYW4ge1xuICAgIGlmICghdGFiLnN5c3RlbURlZmF1bHQpIHJldHVybiB0cnVlO1xuICAgIGlmICh0aGlzLmNhbkVkaXRTeXN0ZW1EZWZhdWx0c0ZuKSB7XG4gICAgICAvLyBUaGUgcHJlZGljYXRlJ3MgZW50aXJlIGNvbnRyYWN0IGlzIChyb2xlcykgPT4gYm9vbGVhbi4gVGhpcyBwYXNzZWQgYSBoYXJkY29kZWQgW11cbiAgICAgIC8vIHJlZ2FyZGxlc3Mgb2Ygd2hvIHdhcyB1c2luZyB0aGUgYnVpbGRlciwgc28gYW55IHByZWRpY2F0ZSB0aGF0IGFjdHVhbGx5IGluc3BlY3RlZFxuICAgICAgLy8gcm9sZXMgYW5zd2VyZWQgZmFsc2UgZm9yIGV2ZXJ5b25lIGFuZCBsb2NrZWQgZXZlcnkgc3lzdGVtLWRlZmF1bHQgdGFiLlxuICAgICAgcmV0dXJuIHRoaXMuY2FuRWRpdFN5c3RlbURlZmF1bHRzRm4odGhpcy5zdG9yZS51c2VyUm9sZXMoKSk7XG4gICAgfVxuICAgIHJldHVybiB0cnVlO1xuICB9XG59XG4iXX0=