ngx-dynamic-entity-builder 1.0.0 → 1.2.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 +75 -54
- package/esm2022/lib/builder-store.service.mjs +166 -32
- package/esm2022/lib/clone.mjs +1 -1
- package/esm2022/lib/components/entity-builder-tree-node.component.mjs +21 -3
- package/esm2022/lib/components/entity-reference-config.component.mjs +301 -301
- package/esm2022/lib/components/field-inspector.component.mjs +3 -3
- package/esm2022/lib/components/field-palette.component.mjs +33 -33
- package/esm2022/lib/components/field-rules-list.component.mjs +157 -157
- package/esm2022/lib/components/referenced-field-config.component.mjs +8 -2
- package/esm2022/lib/components/rule-form.component.mjs +1 -1
- package/esm2022/lib/components/tab-manager.component.mjs +301 -288
- package/esm2022/lib/entity-builder.component.mjs +27 -4
- package/esm2022/public-api.mjs +1 -2
- package/fesm2022/ngx-dynamic-entity-builder.mjs +999 -926
- package/fesm2022/ngx-dynamic-entity-builder.mjs.map +1 -1
- package/lib/builder-store.service.d.ts +41 -0
- package/lib/components/referenced-field-config.component.d.ts +6 -0
- package/lib/components/tab-manager.component.d.ts +11 -2
- package/lib/entity-builder.component.d.ts +12 -1
- package/package.json +22 -13
- package/public-api.d.ts +0 -1
- package/esm2022/lib/components/connection-source-config.component.mjs +0 -121
- package/lib/components/connection-source-config.component.d.ts +0 -16
|
@@ -116,7 +116,7 @@ export class FieldInspectorComponent {
|
|
|
116
116
|
return String(value);
|
|
117
117
|
}
|
|
118
118
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: FieldInspectorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
119
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.12", type: FieldInspectorComponent, isStandalone: true, selector: "ngx-field-inspector", ngImport: i0, template: "@if (field(); as f) {\r\n <div class=\"deb-inspector\">\r\n <!-- Identity -->\r\n <div class=\"deb-row\">\r\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\">\r\n <mat-label>Field id</mat-label>\r\n <input matInput data-testid=\"field-id\" [value]=\"f.id\" disabled />\r\n @if (store.hasManualId(f.id)) {\r\n <mat-hint>The stored data key for this saved field \u2014 fixed.</mat-hint>\r\n } @else {\r\n <mat-hint>Derived from the label. Used as the data key.</mat-hint>\r\n }\r\n </mat-form-field>\r\n <span class=\"deb-chip\">{{ meta()?.label || f.type }}</span>\r\n </div>\r\n\r\n <!-- Localised text (active language) -->\r\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\" class=\"deb-full\">\r\n <mat-label>Label ({{ lang() }})</mat-label>\r\n <input\r\n matInput\r\n [ngModel]=\"labelValue(f)\"\r\n (ngModelChange)=\"store.setFieldLabel(f.id, lang(), $event)\"\r\n />\r\n </mat-form-field>\r\n\r\n @if (meta()?.supportsPlaceholder) {\r\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\" class=\"deb-full\">\r\n <mat-label>Placeholder ({{ lang() }})</mat-label>\r\n <input\r\n matInput\r\n [ngModel]=\"placeholderValue(f)\"\r\n (ngModelChange)=\"store.setFieldPlaceholder(f.id, lang(), $event)\"\r\n />\r\n </mat-form-field>\r\n }\r\n\r\n @if (meta()?.supportsDefaultValue) {\r\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\" class=\"deb-full\">\r\n <mat-label>Default value</mat-label>\r\n <input\r\n matInput\r\n [ngModel]=\"f.defaultValue ?? ''\"\r\n (ngModelChange)=\"store.updateField(f.id, { defaultValue: $event })\"\r\n />\r\n </mat-form-field>\r\n }\r\n\r\n <!-- Entity reference, cascade, and autoPatch -->\r\n @if (meta()?.isEntityRef) {\r\n <mat-divider></mat-divider>\r\n <ngx-entity-reference-config />\r\n }\r\n\r\n <mat-divider></mat-divider>\r\n\r\n <!-- Validators -->\r\n @if (meta(); as m) {\r\n @if (m.flagValidators.length || m.paramValidators.length) {\r\n <span class=\"deb-section-title\">Validation</span>\r\n <div class=\"deb-toggles\">\r\n @for (v of m.flagValidators; track v) {\r\n <mat-checkbox\r\n [ngModel]=\"store.hasFlagValidator(f, v)\"\r\n (ngModelChange)=\"store.toggleFlagValidator(f.id, v, $event)\"\r\n >{{ v }}</mat-checkbox>\r\n }\r\n </div>\r\n @for (v of m.paramValidators; track v) {\r\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\" class=\"deb-full\">\r\n <mat-label>{{ v }}</mat-label>\r\n <input\r\n matInput\r\n type=\"number\"\r\n [ngModel]=\"store.getParamValidator(f, v)\"\r\n (ngModelChange)=\"store.setParamValidator(f.id, v, toNum($event))\"\r\n />\r\n </mat-form-field>\r\n }\r\n }\r\n }\r\n\r\n <!-- Options (dropdown / radio / multiSelect) -->\r\n @if (meta()?.hasOptions) {\r\n <mat-divider></mat-divider>\r\n <span class=\"deb-section-title\">Data source</span>\r\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\" class=\"deb-full\">\r\n <mat-label>Options come from</mat-label>\r\n <mat-select\r\n data-testid=\"data-source\"\r\n [ngModel]=\"store.fieldDataSource(f)\"\r\n (ngModelChange)=\"store.setFieldDataSource(f.id, $event)\"\r\n >\r\n <mat-option value=\"none\">Nothing yet</mat-option>\r\n <mat-option value=\"manual\">Options authored here</mat-option>\r\n <mat-option value=\"lookup\">A named list</mat-option>\r\n </mat-select>\r\n </mat-form-field>\r\n }\r\n\r\n <!-- Named lookup list -->\r\n @if (meta()?.hasOptions && store.fieldDataSource(f) === 'lookup') {\r\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\" class=\"deb-full\">\r\n <mat-label>List name</mat-label>\r\n <input\r\n matInput\r\n data-testid=\"list-name\"\r\n [ngModel]=\"f.listName ?? ''\"\r\n (ngModelChange)=\"store.setListName(f.id, $event)\"\r\n />\r\n </mat-form-field>\r\n <p class=\"deb-hint\">\r\n The consuming app resolves this name through its lookup registry. Options are not\r\n authored here.\r\n </p>\r\n }\r\n\r\n <!-- Inline options -->\r\n @if (meta()?.hasOptions && store.fieldDataSource(f) !== 'lookup') {\r\n <div class=\"deb-row\" style=\"justify-content: space-between;\">\r\n <span class=\"deb-section-title\">Options</span>\r\n <button mat-stroked-button type=\"button\" (click)=\"store.addOption(f.id)\">\r\n <mat-icon>add</mat-icon> Option\r\n </button>\r\n </div>\r\n @for (opt of f.options ?? []; track $index) {\r\n <div class=\"deb-option-row\" data-testid=\"option-row\">\r\n <!-- One input: the displayed text is the stored value. -->\r\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\" class=\"deb-full\">\r\n <mat-label>Option ({{ lang() }})</mat-label>\r\n <input\r\n matInput\r\n [attr.data-testid]=\"'option-' + $index\"\r\n [ngModel]=\"optionLabel(opt)\"\r\n (ngModelChange)=\"store.setOptionLabel(f.id, $index, lang(), $event)\"\r\n />\r\n </mat-form-field>\r\n <button mat-icon-button type=\"button\" color=\"warn\"\r\n (click)=\"store.removeOption(f.id, $index)\" matTooltip=\"Remove option\">\r\n <mat-icon>delete</mat-icon>\r\n </button>\r\n </div>\r\n }\r\n @if (!(f.options ?? []).length) {\r\n <p class=\"deb-hint\">No options yet \u2014 add at least one.</p>\r\n }\r\n }\r\n\r\n <mat-divider></mat-divider>\r\n\r\n <!-- Flags -->\r\n <span class=\"deb-section-title\">Display</span>\r\n <div class=\"deb-toggles\">\r\n <mat-slide-toggle\r\n [ngModel]=\"f.visibility ?? true\"\r\n (ngModelChange)=\"store.updateField(f.id, { visibility: $event })\"\r\n >Visible</mat-slide-toggle>\r\n <mat-slide-toggle\r\n [ngModel]=\"f.table?.visible ?? false\"\r\n (ngModelChange)=\"store.updateField(f.id, { table: { visible: $event } })\"\r\n >Table column</mat-slide-toggle>\r\n <mat-slide-toggle\r\n [ngModel]=\"f.readonly ?? false\"\r\n (ngModelChange)=\"store.updateField(f.id, { readonly: $event })\"\r\n >Read-only</mat-slide-toggle>\r\n <mat-slide-toggle\r\n [ngModel]=\"f.disabled ?? false\"\r\n (ngModelChange)=\"store.updateField(f.id, { disabled: $event })\"\r\n >Disabled</mat-slide-toggle>\r\n <mat-slide-toggle\r\n [ngModel]=\"f.maskData ?? false\"\r\n (ngModelChange)=\"store.updateField(f.id, { maskData: $event })\"\r\n >Mask data (RBAC)</mat-slide-toggle>\r\n <mat-slide-toggle\r\n data-testid=\"toggle-critical\"\r\n [ngModel]=\"f.criticalField ?? false\"\r\n (ngModelChange)=\"store.updateField(f.id, { criticalField: $event })\"\r\n matTooltip=\"Renders locked; editing it announces a change against the session baseline.\"\r\n >Critical field</mat-slide-toggle>\r\n <mat-slide-toggle\r\n [ngModel]=\"f.showOnMinimize ?? false\"\r\n (ngModelChange)=\"store.updateField(f.id, { showOnMinimize: $event })\"\r\n matTooltip=\"Shown in the record editor's summary panel.\"\r\n >Show in summary</mat-slide-toggle>\r\n </div>\r\n\r\n <mat-divider></mat-divider>\r\n\r\n <!-- Conditional visibility (static showWhen) -->\r\n <div class=\"deb-row deb-row--split\">\r\n <span class=\"deb-section-title\">Show when</span>\r\n <button mat-stroked-button type=\"button\" data-testid=\"add-show-when\" (click)=\"addShowWhen(f)\">\r\n <mat-icon>add</mat-icon> Condition\r\n </button>\r\n </div>\r\n @for (entry of showWhenEntries(f); track entry.key) {\r\n <div class=\"deb-option-row\" data-testid=\"option-row\">\r\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\">\r\n <mat-label>Field id</mat-label>\r\n <input matInput [ngModel]=\"entry.key\" (ngModelChange)=\"renameShowWhen(f, entry.key, $event)\" />\r\n </mat-form-field>\r\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\">\r\n <mat-label>Equals</mat-label>\r\n <input matInput [ngModel]=\"entry.display\" (ngModelChange)=\"setShowWhenValue(f, entry.key, $event)\" />\r\n </mat-form-field>\r\n <button mat-icon-button type=\"button\" color=\"warn\" matTooltip=\"Remove condition\"\r\n (click)=\"removeShowWhen(f, entry.key)\">\r\n <mat-icon>delete</mat-icon>\r\n </button>\r\n </div>\r\n }\r\n @if (!showWhenEntries(f).length) {\r\n <p class=\"deb-hint\">Always visible. Add a condition to show this field only for certain values.</p>\r\n }\r\n\r\n <!-- patchOnTrue (boolean/checkbox only) -->\r\n @if (f.type === 'boolean' || f.type === 'checkbox') {\r\n <mat-divider></mat-divider>\r\n <div class=\"deb-row deb-row--split\">\r\n <span class=\"deb-section-title\">Copy on true</span>\r\n <button mat-stroked-button type=\"button\" data-testid=\"add-patch-on-true\"\r\n (click)=\"store.addPatchOnTrueMapping(f.id)\">\r\n <mat-icon>add</mat-icon> Mapping\r\n </button>\r\n </div>\r\n @for (mapping of f.patchOnTrue ?? []; track $index) {\r\n <div class=\"deb-option-row\" data-testid=\"option-row\">\r\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\">\r\n <mat-label>From field</mat-label>\r\n <input matInput [ngModel]=\"mapping.from\"\r\n (ngModelChange)=\"store.updatePatchOnTrueMapping(f.id, $index, { from: $event })\" />\r\n </mat-form-field>\r\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\">\r\n <mat-label>To field</mat-label>\r\n <input matInput [ngModel]=\"mapping.to\"\r\n (ngModelChange)=\"store.updatePatchOnTrueMapping(f.id, $index, { to: $event })\" />\r\n </mat-form-field>\r\n <button mat-icon-button type=\"button\" color=\"warn\" matTooltip=\"Remove mapping\"\r\n (click)=\"store.removePatchOnTrueMapping(f.id, $index)\">\r\n <mat-icon>delete</mat-icon>\r\n </button>\r\n </div>\r\n }\r\n @if (!(f.patchOnTrue ?? []).length) {\r\n <p class=\"deb-hint\">When this flips to true, copy one field's value into another.</p>\r\n }\r\n }\r\n\r\n <mat-divider></mat-divider>\r\n\r\n <!-- Rules attached to this field -->\r\n <ngx-field-rules-list />\r\n\r\n <mat-divider></mat-divider>\r\n\r\n <!-- Cross-entity field reference & drift management (Phase 8) -->\r\n <ngx-referenced-field-config />\r\n </div>\r\n} @else {\r\n <div class=\"deb-inspector__empty\">\r\n <mat-icon>touch_app</mat-icon>\r\n <p>Select a field to edit its properties.</p>\r\n </div>\r\n}\r\n", styles: [".deb-inspector{display:flex;flex-direction:column;gap:12px}.deb-inspector__empty{color:var(--deb-muted, #6b7280);text-align:center;padding:24px 8px}.deb-full{width:100%}.deb-row{display:flex;gap:8px;align-items:center}.deb-row>*{flex:1}.deb-row--split{justify-content:space-between}.deb-row--split>*{flex:0 0 auto}.deb-toggles{display:grid;grid-template-columns:1fr 1fr;gap:8px 12px}.deb-option-row{display:flex;gap:6px;align-items:center}.deb-chip{display:inline-block;padding:2px 8px;border-radius:12px;background:var(--deb-accent-soft, #eef2ff);color:var(--deb-accent, #6366f1);font-size:12px;font-weight:600}\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.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { 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: MatDividerModule }, { kind: "component", type: i4.MatDivider, selector: "mat-divider", inputs: ["vertical", "inset"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i5.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i5.MatLabel, selector: "mat-label" }, { kind: "directive", type: i5.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i6.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i7.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: MatSelectModule }, { kind: "component", type: i8.MatSelect, selector: "mat-select", inputs: ["aria-describedby", "panelClass", "disabled", "disableRipple", "tabIndex", "hideSingleSelectionIndicator", "placeholder", "required", "multiple", "disableOptionCentering", "compareWith", "value", "aria-label", "aria-labelledby", "errorStateMatcher", "typeaheadDebounceInterval", "sortComparator", "id", "panelWidth"], outputs: ["openedChange", "opened", "closed", "selectionChange", "valueChange"], exportAs: ["matSelect"] }, { kind: "component", type: i9.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "ngmodule", type: MatSlideToggleModule }, { kind: "component", type: i10.MatSlideToggle, selector: "mat-slide-toggle", inputs: ["name", "id", "labelPosition", "aria-label", "aria-labelledby", "aria-describedby", "required", "color", "disabled", "disableRipple", "tabIndex", "checked", "hideIcon"], outputs: ["change", "toggleChange"], exportAs: ["matSlideToggle"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i11.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "component", type: EntityReferenceConfigComponent, selector: "ngx-entity-reference-config" }, { kind: "component", type: FieldRulesListComponent, selector: "ngx-field-rules-list" }, { kind: "component", type: ReferencedFieldConfigComponent, selector: "ngx-referenced-field-config" }] });
|
|
119
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.12", type: FieldInspectorComponent, isStandalone: true, selector: "ngx-field-inspector", ngImport: i0, template: "@if (field(); as f) {\n <div class=\"deb-inspector\">\n <!-- Identity -->\n <div class=\"deb-row\">\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\">\n <mat-label>Field id</mat-label>\n <input matInput data-testid=\"field-id\" [value]=\"f.id\" disabled />\n @if (store.hasManualId(f.id)) {\n <mat-hint>The stored data key for this saved field \u2014 fixed.</mat-hint>\n } @else {\n <mat-hint>Derived from the label. Used as the data key.</mat-hint>\n }\n </mat-form-field>\n <span class=\"deb-chip\">{{ meta()?.label || f.type }}</span>\n </div>\n\n <!-- Localised text (active language) -->\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\" class=\"deb-full\">\n <mat-label>Label ({{ lang() }})</mat-label>\n <input\n matInput\n [ngModel]=\"labelValue(f)\"\n (ngModelChange)=\"store.setFieldLabel(f.id, lang(), $event)\"\n />\n </mat-form-field>\n\n @if (meta()?.supportsPlaceholder) {\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\" class=\"deb-full\">\n <mat-label>Placeholder ({{ lang() }})</mat-label>\n <input\n matInput\n [ngModel]=\"placeholderValue(f)\"\n (ngModelChange)=\"store.setFieldPlaceholder(f.id, lang(), $event)\"\n />\n </mat-form-field>\n }\n\n @if (meta()?.supportsDefaultValue) {\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\" class=\"deb-full\">\n <mat-label>Default value</mat-label>\n <input\n matInput\n [ngModel]=\"f.defaultValue ?? ''\"\n (ngModelChange)=\"store.updateField(f.id, { defaultValue: $event })\"\n />\n </mat-form-field>\n }\n\n <!-- Entity reference, cascade, and autoPatch -->\n @if (meta()?.isEntityRef) {\n <mat-divider></mat-divider>\n <ngx-entity-reference-config />\n }\n\n <mat-divider></mat-divider>\n\n <!-- Validators -->\n @if (meta(); as m) {\n @if (m.flagValidators.length || m.paramValidators.length) {\n <span class=\"deb-section-title\">Validation</span>\n <div class=\"deb-toggles\">\n @for (v of m.flagValidators; track v) {\n <mat-checkbox\n [ngModel]=\"store.hasFlagValidator(f, v)\"\n (ngModelChange)=\"store.toggleFlagValidator(f.id, v, $event)\"\n >{{ v }}</mat-checkbox>\n }\n </div>\n @for (v of m.paramValidators; track v) {\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\" class=\"deb-full\">\n <mat-label>{{ v }}</mat-label>\n <input\n matInput\n type=\"number\"\n [ngModel]=\"store.getParamValidator(f, v)\"\n (ngModelChange)=\"store.setParamValidator(f.id, v, toNum($event))\"\n />\n </mat-form-field>\n }\n }\n }\n\n <!-- Options (dropdown / radio / multiSelect) -->\n @if (meta()?.hasOptions) {\n <mat-divider></mat-divider>\n <span class=\"deb-section-title\">Data source</span>\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\" class=\"deb-full\">\n <mat-label>Options come from</mat-label>\n <mat-select\n data-testid=\"data-source\"\n [ngModel]=\"store.fieldDataSource(f)\"\n (ngModelChange)=\"store.setFieldDataSource(f.id, $event)\"\n >\n <mat-option value=\"none\">Nothing yet</mat-option>\n <mat-option value=\"manual\">Options authored here</mat-option>\n <mat-option value=\"lookup\">A named list</mat-option>\n </mat-select>\n </mat-form-field>\n }\n\n <!-- Named lookup list -->\n @if (meta()?.hasOptions && store.fieldDataSource(f) === 'lookup') {\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\" class=\"deb-full\">\n <mat-label>List name</mat-label>\n <input\n matInput\n data-testid=\"list-name\"\n [ngModel]=\"f.listName ?? ''\"\n (ngModelChange)=\"store.setListName(f.id, $event)\"\n />\n </mat-form-field>\n <p class=\"deb-hint\">\n The consuming app resolves this name through its lookup registry. Options are not\n authored here.\n </p>\n }\n\n <!-- Inline options -->\n @if (meta()?.hasOptions && store.fieldDataSource(f) !== 'lookup') {\n <div class=\"deb-row\" style=\"justify-content: space-between;\">\n <span class=\"deb-section-title\">Options</span>\n <button mat-stroked-button type=\"button\" (click)=\"store.addOption(f.id)\">\n <mat-icon>add</mat-icon> Option\n </button>\n </div>\n @for (opt of f.options ?? []; track $index) {\n <div class=\"deb-option-row\" data-testid=\"option-row\">\n <!-- One input: the displayed text is the stored value. -->\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\" class=\"deb-full\">\n <mat-label>Option ({{ lang() }})</mat-label>\n <input\n matInput\n [attr.data-testid]=\"'option-' + $index\"\n [ngModel]=\"optionLabel(opt)\"\n (ngModelChange)=\"store.setOptionLabel(f.id, $index, lang(), $event)\"\n />\n </mat-form-field>\n <button mat-icon-button type=\"button\" color=\"warn\"\n (click)=\"store.removeOption(f.id, $index)\" matTooltip=\"Remove option\">\n <mat-icon>delete</mat-icon>\n </button>\n </div>\n }\n @if (!(f.options ?? []).length) {\n <p class=\"deb-hint\">No options yet \u2014 add at least one.</p>\n }\n }\n\n <mat-divider></mat-divider>\n\n <!-- Flags -->\n <span class=\"deb-section-title\">Display</span>\n <div class=\"deb-toggles\">\n <mat-slide-toggle\n [ngModel]=\"f.visibility ?? true\"\n (ngModelChange)=\"store.updateField(f.id, { visibility: $event })\"\n >Visible</mat-slide-toggle>\n <mat-slide-toggle\n [ngModel]=\"f.table?.visible ?? false\"\n (ngModelChange)=\"store.updateField(f.id, { table: { visible: $event } })\"\n >Table column</mat-slide-toggle>\n <mat-slide-toggle\n [ngModel]=\"f.readonly ?? false\"\n (ngModelChange)=\"store.updateField(f.id, { readonly: $event })\"\n >Read-only</mat-slide-toggle>\n <mat-slide-toggle\n [ngModel]=\"f.disabled ?? false\"\n (ngModelChange)=\"store.updateField(f.id, { disabled: $event })\"\n >Disabled</mat-slide-toggle>\n <mat-slide-toggle\n [ngModel]=\"f.maskData ?? false\"\n (ngModelChange)=\"store.updateField(f.id, { maskData: $event })\"\n >Mask data (RBAC)</mat-slide-toggle>\n <mat-slide-toggle\n data-testid=\"toggle-critical\"\n [ngModel]=\"f.criticalField ?? false\"\n (ngModelChange)=\"store.updateField(f.id, { criticalField: $event })\"\n matTooltip=\"Renders locked; editing it announces a change against the session baseline.\"\n >Critical field</mat-slide-toggle>\n <mat-slide-toggle\n [ngModel]=\"f.showOnMinimize ?? false\"\n (ngModelChange)=\"store.updateField(f.id, { showOnMinimize: $event })\"\n matTooltip=\"Shown in the record editor's summary panel.\"\n >Show in summary</mat-slide-toggle>\n </div>\n\n <mat-divider></mat-divider>\n\n <!-- Conditional visibility (static showWhen) -->\n <div class=\"deb-row deb-row--split\">\n <span class=\"deb-section-title\">Show when</span>\n <button mat-stroked-button type=\"button\" data-testid=\"add-show-when\" (click)=\"addShowWhen(f)\">\n <mat-icon>add</mat-icon> Condition\n </button>\n </div>\n @for (entry of showWhenEntries(f); track entry.key) {\n <div class=\"deb-option-row\" data-testid=\"option-row\">\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\">\n <mat-label>Field id</mat-label>\n <input matInput [ngModel]=\"entry.key\" (ngModelChange)=\"renameShowWhen(f, entry.key, $event)\" />\n </mat-form-field>\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\">\n <mat-label>Equals</mat-label>\n <input matInput [ngModel]=\"entry.display\" (ngModelChange)=\"setShowWhenValue(f, entry.key, $event)\" />\n </mat-form-field>\n <button mat-icon-button type=\"button\" color=\"warn\" matTooltip=\"Remove condition\"\n (click)=\"removeShowWhen(f, entry.key)\">\n <mat-icon>delete</mat-icon>\n </button>\n </div>\n }\n @if (!showWhenEntries(f).length) {\n <p class=\"deb-hint\">Always visible. Add a condition to show this field only for certain values.</p>\n }\n\n <!-- patchOnTrue (boolean/checkbox only) -->\n @if (f.type === 'boolean' || f.type === 'checkbox') {\n <mat-divider></mat-divider>\n <div class=\"deb-row deb-row--split\">\n <span class=\"deb-section-title\">Copy on true</span>\n <button mat-stroked-button type=\"button\" data-testid=\"add-patch-on-true\"\n (click)=\"store.addPatchOnTrueMapping(f.id)\">\n <mat-icon>add</mat-icon> Mapping\n </button>\n </div>\n @for (mapping of f.patchOnTrue ?? []; track $index) {\n <div class=\"deb-option-row\" data-testid=\"option-row\">\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\">\n <mat-label>From field</mat-label>\n <input matInput [ngModel]=\"mapping.from\"\n (ngModelChange)=\"store.updatePatchOnTrueMapping(f.id, $index, { from: $event })\" />\n </mat-form-field>\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\">\n <mat-label>To field</mat-label>\n <input matInput [ngModel]=\"mapping.to\"\n (ngModelChange)=\"store.updatePatchOnTrueMapping(f.id, $index, { to: $event })\" />\n </mat-form-field>\n <button mat-icon-button type=\"button\" color=\"warn\" matTooltip=\"Remove mapping\"\n (click)=\"store.removePatchOnTrueMapping(f.id, $index)\">\n <mat-icon>delete</mat-icon>\n </button>\n </div>\n }\n @if (!(f.patchOnTrue ?? []).length) {\n <p class=\"deb-hint\">When this flips to true, copy one field's value into another.</p>\n }\n }\n\n <mat-divider></mat-divider>\n\n <!-- Rules attached to this field -->\n <ngx-field-rules-list />\n\n <mat-divider></mat-divider>\n\n <!-- Cross-entity field reference & drift management (Phase 8) -->\n <ngx-referenced-field-config />\n </div>\n} @else {\n <div class=\"deb-inspector__empty\">\n <mat-icon>touch_app</mat-icon>\n <p>Select a field to edit its properties.</p>\n </div>\n}\n", styles: [".deb-inspector{display:flex;flex-direction:column;gap:12px}.deb-inspector__empty{color:var(--deb-muted, #6b7280);text-align:center;padding:24px 8px}.deb-full{width:100%}.deb-row{display:flex;gap:8px;align-items:center}.deb-row>*{flex:1}.deb-row--split{justify-content:space-between}.deb-row--split>*{flex:0 0 auto}.deb-toggles{display:grid;grid-template-columns:1fr 1fr;gap:8px 12px}.deb-option-row{display:flex;gap:6px;align-items:center}.deb-chip{display:inline-block;padding:2px 8px;border-radius:12px;background:var(--deb-accent-soft, #eef2ff);color:var(--deb-accent, #6366f1);font-size:12px;font-weight:600}\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.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { 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: MatDividerModule }, { kind: "component", type: i4.MatDivider, selector: "mat-divider", inputs: ["vertical", "inset"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i5.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i5.MatLabel, selector: "mat-label" }, { kind: "directive", type: i5.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i6.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i7.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: MatSelectModule }, { kind: "component", type: i8.MatSelect, selector: "mat-select", inputs: ["aria-describedby", "panelClass", "disabled", "disableRipple", "tabIndex", "hideSingleSelectionIndicator", "placeholder", "required", "multiple", "disableOptionCentering", "compareWith", "value", "aria-label", "aria-labelledby", "errorStateMatcher", "typeaheadDebounceInterval", "sortComparator", "id", "panelWidth"], outputs: ["openedChange", "opened", "closed", "selectionChange", "valueChange"], exportAs: ["matSelect"] }, { kind: "component", type: i9.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "ngmodule", type: MatSlideToggleModule }, { kind: "component", type: i10.MatSlideToggle, selector: "mat-slide-toggle", inputs: ["name", "id", "labelPosition", "aria-label", "aria-labelledby", "aria-describedby", "required", "color", "disabled", "disableRipple", "tabIndex", "checked", "hideIcon"], outputs: ["change", "toggleChange"], exportAs: ["matSlideToggle"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i11.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "component", type: EntityReferenceConfigComponent, selector: "ngx-entity-reference-config" }, { kind: "component", type: FieldRulesListComponent, selector: "ngx-field-rules-list" }, { kind: "component", type: ReferencedFieldConfigComponent, selector: "ngx-referenced-field-config" }] });
|
|
120
120
|
}
|
|
121
121
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: FieldInspectorComponent, decorators: [{
|
|
122
122
|
type: Component,
|
|
@@ -134,6 +134,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
|
|
|
134
134
|
EntityReferenceConfigComponent,
|
|
135
135
|
FieldRulesListComponent,
|
|
136
136
|
ReferencedFieldConfigComponent,
|
|
137
|
-
], template: "@if (field(); as f) {\r\n <div class=\"deb-inspector\">\r\n <!-- Identity -->\r\n <div class=\"deb-row\">\r\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\">\r\n <mat-label>Field id</mat-label>\r\n <input matInput data-testid=\"field-id\" [value]=\"f.id\" disabled />\r\n @if (store.hasManualId(f.id)) {\r\n <mat-hint>The stored data key for this saved field \u2014 fixed.</mat-hint>\r\n } @else {\r\n <mat-hint>Derived from the label. Used as the data key.</mat-hint>\r\n }\r\n </mat-form-field>\r\n <span class=\"deb-chip\">{{ meta()?.label || f.type }}</span>\r\n </div>\r\n\r\n <!-- Localised text (active language) -->\r\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\" class=\"deb-full\">\r\n <mat-label>Label ({{ lang() }})</mat-label>\r\n <input\r\n matInput\r\n [ngModel]=\"labelValue(f)\"\r\n (ngModelChange)=\"store.setFieldLabel(f.id, lang(), $event)\"\r\n />\r\n </mat-form-field>\r\n\r\n @if (meta()?.supportsPlaceholder) {\r\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\" class=\"deb-full\">\r\n <mat-label>Placeholder ({{ lang() }})</mat-label>\r\n <input\r\n matInput\r\n [ngModel]=\"placeholderValue(f)\"\r\n (ngModelChange)=\"store.setFieldPlaceholder(f.id, lang(), $event)\"\r\n />\r\n </mat-form-field>\r\n }\r\n\r\n @if (meta()?.supportsDefaultValue) {\r\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\" class=\"deb-full\">\r\n <mat-label>Default value</mat-label>\r\n <input\r\n matInput\r\n [ngModel]=\"f.defaultValue ?? ''\"\r\n (ngModelChange)=\"store.updateField(f.id, { defaultValue: $event })\"\r\n />\r\n </mat-form-field>\r\n }\r\n\r\n <!-- Entity reference, cascade, and autoPatch -->\r\n @if (meta()?.isEntityRef) {\r\n <mat-divider></mat-divider>\r\n <ngx-entity-reference-config />\r\n }\r\n\r\n <mat-divider></mat-divider>\r\n\r\n <!-- Validators -->\r\n @if (meta(); as m) {\r\n @if (m.flagValidators.length || m.paramValidators.length) {\r\n <span class=\"deb-section-title\">Validation</span>\r\n <div class=\"deb-toggles\">\r\n @for (v of m.flagValidators; track v) {\r\n <mat-checkbox\r\n [ngModel]=\"store.hasFlagValidator(f, v)\"\r\n (ngModelChange)=\"store.toggleFlagValidator(f.id, v, $event)\"\r\n >{{ v }}</mat-checkbox>\r\n }\r\n </div>\r\n @for (v of m.paramValidators; track v) {\r\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\" class=\"deb-full\">\r\n <mat-label>{{ v }}</mat-label>\r\n <input\r\n matInput\r\n type=\"number\"\r\n [ngModel]=\"store.getParamValidator(f, v)\"\r\n (ngModelChange)=\"store.setParamValidator(f.id, v, toNum($event))\"\r\n />\r\n </mat-form-field>\r\n }\r\n }\r\n }\r\n\r\n <!-- Options (dropdown / radio / multiSelect) -->\r\n @if (meta()?.hasOptions) {\r\n <mat-divider></mat-divider>\r\n <span class=\"deb-section-title\">Data source</span>\r\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\" class=\"deb-full\">\r\n <mat-label>Options come from</mat-label>\r\n <mat-select\r\n data-testid=\"data-source\"\r\n [ngModel]=\"store.fieldDataSource(f)\"\r\n (ngModelChange)=\"store.setFieldDataSource(f.id, $event)\"\r\n >\r\n <mat-option value=\"none\">Nothing yet</mat-option>\r\n <mat-option value=\"manual\">Options authored here</mat-option>\r\n <mat-option value=\"lookup\">A named list</mat-option>\r\n </mat-select>\r\n </mat-form-field>\r\n }\r\n\r\n <!-- Named lookup list -->\r\n @if (meta()?.hasOptions && store.fieldDataSource(f) === 'lookup') {\r\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\" class=\"deb-full\">\r\n <mat-label>List name</mat-label>\r\n <input\r\n matInput\r\n data-testid=\"list-name\"\r\n [ngModel]=\"f.listName ?? ''\"\r\n (ngModelChange)=\"store.setListName(f.id, $event)\"\r\n />\r\n </mat-form-field>\r\n <p class=\"deb-hint\">\r\n The consuming app resolves this name through its lookup registry. Options are not\r\n authored here.\r\n </p>\r\n }\r\n\r\n <!-- Inline options -->\r\n @if (meta()?.hasOptions && store.fieldDataSource(f) !== 'lookup') {\r\n <div class=\"deb-row\" style=\"justify-content: space-between;\">\r\n <span class=\"deb-section-title\">Options</span>\r\n <button mat-stroked-button type=\"button\" (click)=\"store.addOption(f.id)\">\r\n <mat-icon>add</mat-icon> Option\r\n </button>\r\n </div>\r\n @for (opt of f.options ?? []; track $index) {\r\n <div class=\"deb-option-row\" data-testid=\"option-row\">\r\n <!-- One input: the displayed text is the stored value. -->\r\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\" class=\"deb-full\">\r\n <mat-label>Option ({{ lang() }})</mat-label>\r\n <input\r\n matInput\r\n [attr.data-testid]=\"'option-' + $index\"\r\n [ngModel]=\"optionLabel(opt)\"\r\n (ngModelChange)=\"store.setOptionLabel(f.id, $index, lang(), $event)\"\r\n />\r\n </mat-form-field>\r\n <button mat-icon-button type=\"button\" color=\"warn\"\r\n (click)=\"store.removeOption(f.id, $index)\" matTooltip=\"Remove option\">\r\n <mat-icon>delete</mat-icon>\r\n </button>\r\n </div>\r\n }\r\n @if (!(f.options ?? []).length) {\r\n <p class=\"deb-hint\">No options yet \u2014 add at least one.</p>\r\n }\r\n }\r\n\r\n <mat-divider></mat-divider>\r\n\r\n <!-- Flags -->\r\n <span class=\"deb-section-title\">Display</span>\r\n <div class=\"deb-toggles\">\r\n <mat-slide-toggle\r\n [ngModel]=\"f.visibility ?? true\"\r\n (ngModelChange)=\"store.updateField(f.id, { visibility: $event })\"\r\n >Visible</mat-slide-toggle>\r\n <mat-slide-toggle\r\n [ngModel]=\"f.table?.visible ?? false\"\r\n (ngModelChange)=\"store.updateField(f.id, { table: { visible: $event } })\"\r\n >Table column</mat-slide-toggle>\r\n <mat-slide-toggle\r\n [ngModel]=\"f.readonly ?? false\"\r\n (ngModelChange)=\"store.updateField(f.id, { readonly: $event })\"\r\n >Read-only</mat-slide-toggle>\r\n <mat-slide-toggle\r\n [ngModel]=\"f.disabled ?? false\"\r\n (ngModelChange)=\"store.updateField(f.id, { disabled: $event })\"\r\n >Disabled</mat-slide-toggle>\r\n <mat-slide-toggle\r\n [ngModel]=\"f.maskData ?? false\"\r\n (ngModelChange)=\"store.updateField(f.id, { maskData: $event })\"\r\n >Mask data (RBAC)</mat-slide-toggle>\r\n <mat-slide-toggle\r\n data-testid=\"toggle-critical\"\r\n [ngModel]=\"f.criticalField ?? false\"\r\n (ngModelChange)=\"store.updateField(f.id, { criticalField: $event })\"\r\n matTooltip=\"Renders locked; editing it announces a change against the session baseline.\"\r\n >Critical field</mat-slide-toggle>\r\n <mat-slide-toggle\r\n [ngModel]=\"f.showOnMinimize ?? false\"\r\n (ngModelChange)=\"store.updateField(f.id, { showOnMinimize: $event })\"\r\n matTooltip=\"Shown in the record editor's summary panel.\"\r\n >Show in summary</mat-slide-toggle>\r\n </div>\r\n\r\n <mat-divider></mat-divider>\r\n\r\n <!-- Conditional visibility (static showWhen) -->\r\n <div class=\"deb-row deb-row--split\">\r\n <span class=\"deb-section-title\">Show when</span>\r\n <button mat-stroked-button type=\"button\" data-testid=\"add-show-when\" (click)=\"addShowWhen(f)\">\r\n <mat-icon>add</mat-icon> Condition\r\n </button>\r\n </div>\r\n @for (entry of showWhenEntries(f); track entry.key) {\r\n <div class=\"deb-option-row\" data-testid=\"option-row\">\r\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\">\r\n <mat-label>Field id</mat-label>\r\n <input matInput [ngModel]=\"entry.key\" (ngModelChange)=\"renameShowWhen(f, entry.key, $event)\" />\r\n </mat-form-field>\r\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\">\r\n <mat-label>Equals</mat-label>\r\n <input matInput [ngModel]=\"entry.display\" (ngModelChange)=\"setShowWhenValue(f, entry.key, $event)\" />\r\n </mat-form-field>\r\n <button mat-icon-button type=\"button\" color=\"warn\" matTooltip=\"Remove condition\"\r\n (click)=\"removeShowWhen(f, entry.key)\">\r\n <mat-icon>delete</mat-icon>\r\n </button>\r\n </div>\r\n }\r\n @if (!showWhenEntries(f).length) {\r\n <p class=\"deb-hint\">Always visible. Add a condition to show this field only for certain values.</p>\r\n }\r\n\r\n <!-- patchOnTrue (boolean/checkbox only) -->\r\n @if (f.type === 'boolean' || f.type === 'checkbox') {\r\n <mat-divider></mat-divider>\r\n <div class=\"deb-row deb-row--split\">\r\n <span class=\"deb-section-title\">Copy on true</span>\r\n <button mat-stroked-button type=\"button\" data-testid=\"add-patch-on-true\"\r\n (click)=\"store.addPatchOnTrueMapping(f.id)\">\r\n <mat-icon>add</mat-icon> Mapping\r\n </button>\r\n </div>\r\n @for (mapping of f.patchOnTrue ?? []; track $index) {\r\n <div class=\"deb-option-row\" data-testid=\"option-row\">\r\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\">\r\n <mat-label>From field</mat-label>\r\n <input matInput [ngModel]=\"mapping.from\"\r\n (ngModelChange)=\"store.updatePatchOnTrueMapping(f.id, $index, { from: $event })\" />\r\n </mat-form-field>\r\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\">\r\n <mat-label>To field</mat-label>\r\n <input matInput [ngModel]=\"mapping.to\"\r\n (ngModelChange)=\"store.updatePatchOnTrueMapping(f.id, $index, { to: $event })\" />\r\n </mat-form-field>\r\n <button mat-icon-button type=\"button\" color=\"warn\" matTooltip=\"Remove mapping\"\r\n (click)=\"store.removePatchOnTrueMapping(f.id, $index)\">\r\n <mat-icon>delete</mat-icon>\r\n </button>\r\n </div>\r\n }\r\n @if (!(f.patchOnTrue ?? []).length) {\r\n <p class=\"deb-hint\">When this flips to true, copy one field's value into another.</p>\r\n }\r\n }\r\n\r\n <mat-divider></mat-divider>\r\n\r\n <!-- Rules attached to this field -->\r\n <ngx-field-rules-list />\r\n\r\n <mat-divider></mat-divider>\r\n\r\n <!-- Cross-entity field reference & drift management (Phase 8) -->\r\n <ngx-referenced-field-config />\r\n </div>\r\n} @else {\r\n <div class=\"deb-inspector__empty\">\r\n <mat-icon>touch_app</mat-icon>\r\n <p>Select a field to edit its properties.</p>\r\n </div>\r\n}\r\n", styles: [".deb-inspector{display:flex;flex-direction:column;gap:12px}.deb-inspector__empty{color:var(--deb-muted, #6b7280);text-align:center;padding:24px 8px}.deb-full{width:100%}.deb-row{display:flex;gap:8px;align-items:center}.deb-row>*{flex:1}.deb-row--split{justify-content:space-between}.deb-row--split>*{flex:0 0 auto}.deb-toggles{display:grid;grid-template-columns:1fr 1fr;gap:8px 12px}.deb-option-row{display:flex;gap:6px;align-items:center}.deb-chip{display:inline-block;padding:2px 8px;border-radius:12px;background:var(--deb-accent-soft, #eef2ff);color:var(--deb-accent, #6366f1);font-size:12px;font-weight:600}\n"] }]
|
|
137
|
+
], template: "@if (field(); as f) {\n <div class=\"deb-inspector\">\n <!-- Identity -->\n <div class=\"deb-row\">\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\">\n <mat-label>Field id</mat-label>\n <input matInput data-testid=\"field-id\" [value]=\"f.id\" disabled />\n @if (store.hasManualId(f.id)) {\n <mat-hint>The stored data key for this saved field \u2014 fixed.</mat-hint>\n } @else {\n <mat-hint>Derived from the label. Used as the data key.</mat-hint>\n }\n </mat-form-field>\n <span class=\"deb-chip\">{{ meta()?.label || f.type }}</span>\n </div>\n\n <!-- Localised text (active language) -->\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\" class=\"deb-full\">\n <mat-label>Label ({{ lang() }})</mat-label>\n <input\n matInput\n [ngModel]=\"labelValue(f)\"\n (ngModelChange)=\"store.setFieldLabel(f.id, lang(), $event)\"\n />\n </mat-form-field>\n\n @if (meta()?.supportsPlaceholder) {\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\" class=\"deb-full\">\n <mat-label>Placeholder ({{ lang() }})</mat-label>\n <input\n matInput\n [ngModel]=\"placeholderValue(f)\"\n (ngModelChange)=\"store.setFieldPlaceholder(f.id, lang(), $event)\"\n />\n </mat-form-field>\n }\n\n @if (meta()?.supportsDefaultValue) {\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\" class=\"deb-full\">\n <mat-label>Default value</mat-label>\n <input\n matInput\n [ngModel]=\"f.defaultValue ?? ''\"\n (ngModelChange)=\"store.updateField(f.id, { defaultValue: $event })\"\n />\n </mat-form-field>\n }\n\n <!-- Entity reference, cascade, and autoPatch -->\n @if (meta()?.isEntityRef) {\n <mat-divider></mat-divider>\n <ngx-entity-reference-config />\n }\n\n <mat-divider></mat-divider>\n\n <!-- Validators -->\n @if (meta(); as m) {\n @if (m.flagValidators.length || m.paramValidators.length) {\n <span class=\"deb-section-title\">Validation</span>\n <div class=\"deb-toggles\">\n @for (v of m.flagValidators; track v) {\n <mat-checkbox\n [ngModel]=\"store.hasFlagValidator(f, v)\"\n (ngModelChange)=\"store.toggleFlagValidator(f.id, v, $event)\"\n >{{ v }}</mat-checkbox>\n }\n </div>\n @for (v of m.paramValidators; track v) {\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\" class=\"deb-full\">\n <mat-label>{{ v }}</mat-label>\n <input\n matInput\n type=\"number\"\n [ngModel]=\"store.getParamValidator(f, v)\"\n (ngModelChange)=\"store.setParamValidator(f.id, v, toNum($event))\"\n />\n </mat-form-field>\n }\n }\n }\n\n <!-- Options (dropdown / radio / multiSelect) -->\n @if (meta()?.hasOptions) {\n <mat-divider></mat-divider>\n <span class=\"deb-section-title\">Data source</span>\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\" class=\"deb-full\">\n <mat-label>Options come from</mat-label>\n <mat-select\n data-testid=\"data-source\"\n [ngModel]=\"store.fieldDataSource(f)\"\n (ngModelChange)=\"store.setFieldDataSource(f.id, $event)\"\n >\n <mat-option value=\"none\">Nothing yet</mat-option>\n <mat-option value=\"manual\">Options authored here</mat-option>\n <mat-option value=\"lookup\">A named list</mat-option>\n </mat-select>\n </mat-form-field>\n }\n\n <!-- Named lookup list -->\n @if (meta()?.hasOptions && store.fieldDataSource(f) === 'lookup') {\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\" class=\"deb-full\">\n <mat-label>List name</mat-label>\n <input\n matInput\n data-testid=\"list-name\"\n [ngModel]=\"f.listName ?? ''\"\n (ngModelChange)=\"store.setListName(f.id, $event)\"\n />\n </mat-form-field>\n <p class=\"deb-hint\">\n The consuming app resolves this name through its lookup registry. Options are not\n authored here.\n </p>\n }\n\n <!-- Inline options -->\n @if (meta()?.hasOptions && store.fieldDataSource(f) !== 'lookup') {\n <div class=\"deb-row\" style=\"justify-content: space-between;\">\n <span class=\"deb-section-title\">Options</span>\n <button mat-stroked-button type=\"button\" (click)=\"store.addOption(f.id)\">\n <mat-icon>add</mat-icon> Option\n </button>\n </div>\n @for (opt of f.options ?? []; track $index) {\n <div class=\"deb-option-row\" data-testid=\"option-row\">\n <!-- One input: the displayed text is the stored value. -->\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\" class=\"deb-full\">\n <mat-label>Option ({{ lang() }})</mat-label>\n <input\n matInput\n [attr.data-testid]=\"'option-' + $index\"\n [ngModel]=\"optionLabel(opt)\"\n (ngModelChange)=\"store.setOptionLabel(f.id, $index, lang(), $event)\"\n />\n </mat-form-field>\n <button mat-icon-button type=\"button\" color=\"warn\"\n (click)=\"store.removeOption(f.id, $index)\" matTooltip=\"Remove option\">\n <mat-icon>delete</mat-icon>\n </button>\n </div>\n }\n @if (!(f.options ?? []).length) {\n <p class=\"deb-hint\">No options yet \u2014 add at least one.</p>\n }\n }\n\n <mat-divider></mat-divider>\n\n <!-- Flags -->\n <span class=\"deb-section-title\">Display</span>\n <div class=\"deb-toggles\">\n <mat-slide-toggle\n [ngModel]=\"f.visibility ?? true\"\n (ngModelChange)=\"store.updateField(f.id, { visibility: $event })\"\n >Visible</mat-slide-toggle>\n <mat-slide-toggle\n [ngModel]=\"f.table?.visible ?? false\"\n (ngModelChange)=\"store.updateField(f.id, { table: { visible: $event } })\"\n >Table column</mat-slide-toggle>\n <mat-slide-toggle\n [ngModel]=\"f.readonly ?? false\"\n (ngModelChange)=\"store.updateField(f.id, { readonly: $event })\"\n >Read-only</mat-slide-toggle>\n <mat-slide-toggle\n [ngModel]=\"f.disabled ?? false\"\n (ngModelChange)=\"store.updateField(f.id, { disabled: $event })\"\n >Disabled</mat-slide-toggle>\n <mat-slide-toggle\n [ngModel]=\"f.maskData ?? false\"\n (ngModelChange)=\"store.updateField(f.id, { maskData: $event })\"\n >Mask data (RBAC)</mat-slide-toggle>\n <mat-slide-toggle\n data-testid=\"toggle-critical\"\n [ngModel]=\"f.criticalField ?? false\"\n (ngModelChange)=\"store.updateField(f.id, { criticalField: $event })\"\n matTooltip=\"Renders locked; editing it announces a change against the session baseline.\"\n >Critical field</mat-slide-toggle>\n <mat-slide-toggle\n [ngModel]=\"f.showOnMinimize ?? false\"\n (ngModelChange)=\"store.updateField(f.id, { showOnMinimize: $event })\"\n matTooltip=\"Shown in the record editor's summary panel.\"\n >Show in summary</mat-slide-toggle>\n </div>\n\n <mat-divider></mat-divider>\n\n <!-- Conditional visibility (static showWhen) -->\n <div class=\"deb-row deb-row--split\">\n <span class=\"deb-section-title\">Show when</span>\n <button mat-stroked-button type=\"button\" data-testid=\"add-show-when\" (click)=\"addShowWhen(f)\">\n <mat-icon>add</mat-icon> Condition\n </button>\n </div>\n @for (entry of showWhenEntries(f); track entry.key) {\n <div class=\"deb-option-row\" data-testid=\"option-row\">\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\">\n <mat-label>Field id</mat-label>\n <input matInput [ngModel]=\"entry.key\" (ngModelChange)=\"renameShowWhen(f, entry.key, $event)\" />\n </mat-form-field>\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\">\n <mat-label>Equals</mat-label>\n <input matInput [ngModel]=\"entry.display\" (ngModelChange)=\"setShowWhenValue(f, entry.key, $event)\" />\n </mat-form-field>\n <button mat-icon-button type=\"button\" color=\"warn\" matTooltip=\"Remove condition\"\n (click)=\"removeShowWhen(f, entry.key)\">\n <mat-icon>delete</mat-icon>\n </button>\n </div>\n }\n @if (!showWhenEntries(f).length) {\n <p class=\"deb-hint\">Always visible. Add a condition to show this field only for certain values.</p>\n }\n\n <!-- patchOnTrue (boolean/checkbox only) -->\n @if (f.type === 'boolean' || f.type === 'checkbox') {\n <mat-divider></mat-divider>\n <div class=\"deb-row deb-row--split\">\n <span class=\"deb-section-title\">Copy on true</span>\n <button mat-stroked-button type=\"button\" data-testid=\"add-patch-on-true\"\n (click)=\"store.addPatchOnTrueMapping(f.id)\">\n <mat-icon>add</mat-icon> Mapping\n </button>\n </div>\n @for (mapping of f.patchOnTrue ?? []; track $index) {\n <div class=\"deb-option-row\" data-testid=\"option-row\">\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\">\n <mat-label>From field</mat-label>\n <input matInput [ngModel]=\"mapping.from\"\n (ngModelChange)=\"store.updatePatchOnTrueMapping(f.id, $index, { from: $event })\" />\n </mat-form-field>\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\">\n <mat-label>To field</mat-label>\n <input matInput [ngModel]=\"mapping.to\"\n (ngModelChange)=\"store.updatePatchOnTrueMapping(f.id, $index, { to: $event })\" />\n </mat-form-field>\n <button mat-icon-button type=\"button\" color=\"warn\" matTooltip=\"Remove mapping\"\n (click)=\"store.removePatchOnTrueMapping(f.id, $index)\">\n <mat-icon>delete</mat-icon>\n </button>\n </div>\n }\n @if (!(f.patchOnTrue ?? []).length) {\n <p class=\"deb-hint\">When this flips to true, copy one field's value into another.</p>\n }\n }\n\n <mat-divider></mat-divider>\n\n <!-- Rules attached to this field -->\n <ngx-field-rules-list />\n\n <mat-divider></mat-divider>\n\n <!-- Cross-entity field reference & drift management (Phase 8) -->\n <ngx-referenced-field-config />\n </div>\n} @else {\n <div class=\"deb-inspector__empty\">\n <mat-icon>touch_app</mat-icon>\n <p>Select a field to edit its properties.</p>\n </div>\n}\n", styles: [".deb-inspector{display:flex;flex-direction:column;gap:12px}.deb-inspector__empty{color:var(--deb-muted, #6b7280);text-align:center;padding:24px 8px}.deb-full{width:100%}.deb-row{display:flex;gap:8px;align-items:center}.deb-row>*{flex:1}.deb-row--split{justify-content:space-between}.deb-row--split>*{flex:0 0 auto}.deb-toggles{display:grid;grid-template-columns:1fr 1fr;gap:8px 12px}.deb-option-row{display:flex;gap:6px;align-items:center}.deb-chip{display:inline-block;padding:2px 8px;border-radius:12px;background:var(--deb-accent-soft, #eef2ff);color:var(--deb-accent, #6366f1);font-size:12px;font-weight:600}\n"] }]
|
|
138
138
|
}] });
|
|
139
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmllbGQtaW5zcGVjdG9yLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9saWIvY29tcG9uZW50cy9maWVsZC1pbnNwZWN0b3IuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vc3JjL2xpYi9jb21wb25lbnRzL2ZpZWxkLWluc3BlY3Rvci5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsU0FBUyxFQUFFLFFBQVEsRUFBRSxNQUFNLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDNUQsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQzdDLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQUMzRCxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQztBQUMvRCxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSwyQkFBMkIsQ0FBQztBQUM3RCxPQUFPLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSw4QkFBOEIsQ0FBQztBQUNsRSxPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFDdkQsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBQ3pELE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQUMzRCxPQUFPLEVBQUUsb0JBQW9CLEVBQUUsTUFBTSxnQ0FBZ0MsQ0FBQztBQUN0RSxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSwyQkFBMkIsQ0FBQztBQUU3RCxPQUFPLEVBQXdCLFlBQVksRUFBRSxrQkFBa0IsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBQzlGLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQUN4RCxPQUFPLEVBQUUsZ0JBQWdCLEVBQXNCLE1BQU0sa0JBQWtCLENBQUM7QUFDeEUsT0FBTyxFQUFFLDhCQUE4QixFQUFFLE1BQU0scUNBQXFDLENBQUM7QUFDckYsT0FBTyxFQUFFLHVCQUF1QixFQUFFLE1BQU0sOEJBQThCLENBQUM7QUFDdkUsT0FBTyxFQUFFLDhCQUE4QixFQUFFLE1BQU0scUNBQXFDLENBQUM7Ozs7Ozs7Ozs7Ozs7QUFFckY7O0dBRUc7QUF1RUgsTUFBTSxPQUFPLHVCQUF1QjtJQUNmLEtBQUssR0FBRyxNQUFNLENBQUMsWUFBWSxDQUFDLENBQUM7SUFFN0IsS0FBSyxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsYUFBYSxDQUFDO0lBQ2pDLElBQUksR0FBRyxRQUFRLENBQTRCLEdBQUcsRUFBRTtRQUNqRSxNQUFNLENBQUMsR0FBRyxJQUFJLENBQUMsS0FBSyxFQUFFLENBQUM7UUFDdkIsT0FBTyxDQUFDLENBQUMsQ0FBQyxDQUFDLGdCQUFnQixDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDO0lBQ2xELENBQUMsQ0FBQyxDQUFDO0lBRU8sSUFBSTtRQUNaLE9BQU8sSUFBSSxDQUFDLEtBQUssQ0FBQyxjQUFjLEVBQUUsQ0FBQztJQUNyQyxDQUFDO0lBR1MsS0FBSyxDQUFDLEtBQWM7UUFDNUIsSUFBSSxLQUFLLEtBQUssRUFBRSxJQUFJLEtBQUssS0FBSyxJQUFJLElBQUksS0FBSyxLQUFLLFNBQVM7WUFBRSxPQUFPLElBQUksQ0FBQztRQUN2RSxNQUFNLENBQUMsR0FBRyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDeEIsT0FBTyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUNwQyxDQUFDO0lBRVMsVUFBVSxDQUFDLEtBQXdCO1FBQzNDLE9BQU8sWUFBWSxDQUFDLEtBQUssQ0FBQyxLQUFLLEVBQUUsSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDLENBQUM7SUFDaEQsQ0FBQztJQUVTLGdCQUFnQixDQUFDLEtBQXdCO1FBQ2pELE9BQU8sWUFBWSxDQUFDLEtBQUssQ0FBQyxXQUFXLEVBQUUsSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDLENBQUM7SUFDdEQsQ0FBQztJQUVTLFdBQVcsQ0FBQyxNQUFzQjtRQUMxQyxPQUFPLGtCQUFrQixDQUFDLE1BQU0sRUFBRSxJQUFJLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQztJQUNqRCxDQUFDO0lBRUQsK0VBQStFO0lBRXJFLGVBQWUsQ0FBQyxLQUF3QjtRQUNoRCxPQUFPLE1BQU0sQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLFFBQVEsSUFBSSxFQUFFLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEdBQUcsRUFBRSxLQUFLLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQztZQUNqRSxHQUFHO1lBQ0gsT0FBTyxFQUFFLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxLQUFLLENBQUM7U0FDdkMsQ0FBQyxDQUFDLENBQUM7SUFDTixDQUFDO0lBRVMsV0FBVyxDQUFDLEtBQXdCO1FBQzVDLE1BQU0sSUFBSSxHQUFHLEVBQUUsR0FBRyxDQUFDLEtBQUssQ0FBQyxRQUFRLElBQUksRUFBRSxDQUFDLEVBQUUsQ0FBQztRQUMzQyxJQUFJLEdBQUcsR0FBRyxPQUFPLENBQUM7UUFDbEIsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBQ1YsT0FBTyxHQUFHLElBQUksSUFBSTtZQUFFLEdBQUcsR0FBRyxTQUFTLEVBQUUsQ0FBQyxFQUFFLENBQUM7UUFDekMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxHQUFHLElBQUksQ0FBQztRQUNqQixJQUFJLENBQUMsS0FBSyxDQUFDLFdBQVcsQ0FBQyxLQUFLLENBQUMsRUFBRSxFQUFFLElBQUksQ0FBQyxDQUFDO0lBQ3pDLENBQUM7SUFFUyxjQUFjLENBQUMsS0FBd0IsRUFBRSxNQUFjLEVBQUUsTUFBYztRQUMvRSxNQUFNLE9BQU8sR0FBRyxNQUFNLENBQUMsSUFBSSxFQUFFLENBQUM7UUFDOUIsSUFBSSxDQUFDLE9BQU8sSUFBSSxPQUFPLEtBQUssTUFBTTtZQUFFLE9BQU87UUFDM0MsTUFBTSxPQUFPLEdBQUcsS0FBSyxDQUFDLFFBQVEsSUFBSSxFQUFFLENBQUM7UUFDckMsSUFBSSxPQUFPLElBQUksT0FBTztZQUFFLE9BQU87UUFDL0IsTUFBTSxJQUFJLEdBQTRCLEVBQUUsQ0FBQztRQUN6QyxzRUFBc0U7UUFDdEUsS0FBSyxNQUFNLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxJQUFJLE1BQU0sQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDO1lBQUUsSUFBSSxDQUFDLENBQUMsS0FBSyxNQUFNLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBQ25GLElBQUksQ0FBQyxLQUFLLENBQUMsV0FBVyxDQUFDLEtBQUssQ0FBQyxFQUFFLEVBQUUsSUFBSSxDQUFDLENBQUM7SUFDekMsQ0FBQztJQUVTLGdCQUFnQixDQUFDLEtBQXdCLEVBQUUsR0FBVyxFQUFFLEdBQVc7UUFDM0UsSUFBSSxDQUFDLEtBQUssQ0FBQyxXQUFXLENBQUMsS0FBSyxDQUFDLEVBQUUsRUFBRSxFQUFFLEdBQUcsQ0FBQyxLQUFLLENBQUMsUUFBUSxJQUFJLEVBQUUsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsSUFBSSxDQUFDLGFBQWEsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLENBQUM7SUFDbEcsQ0FBQztJQUVTLGNBQWMsQ0FBQyxLQUF3QixFQUFFLEdBQVc7UUFDNUQsTUFBTSxJQUFJLEdBQUcsRUFBRSxHQUFHLENBQUMsS0FBSyxDQUFDLFFBQVEsSUFBSSxFQUFFLENBQUMsRUFBRSxDQUFDO1FBQzNDLE9BQU8sSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBQ2pCLElBQUksQ0FBQyxLQUFLLENBQUMsV0FBVyxDQUFDLEtBQUssQ0FBQyxFQUFFLEVBQUUsSUFBSSxDQUFDLENBQUM7SUFDekMsQ0FBQztJQUVEOzs7T0FHRztJQUNLLGFBQWEsQ0FBQyxHQUFXO1FBQy9CLE1BQU0sT0FBTyxHQUFHLEdBQUcsQ0FBQyxJQUFJLEVBQUUsQ0FBQztRQUMzQixJQUFJLE9BQU8sS0FBSyxNQUFNO1lBQUUsT0FBTyxJQUFJLENBQUM7UUFDcEMsSUFBSSxPQUFPLEtBQUssT0FBTztZQUFFLE9BQU8sS0FBSyxDQUFDO1FBQ3RDLElBQUksT0FBTyxLQUFLLE1BQU07WUFBRSxPQUFPLElBQUksQ0FBQztRQUNwQyxJQUFJLE9BQU8sS0FBSyxFQUFFLElBQUksQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsQ0FBQztZQUFFLE9BQU8sTUFBTSxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQzdFLE9BQU8sR0FBRyxDQUFDO0lBQ2IsQ0FBQztJQUVPLGlCQUFpQixDQUFDLEtBQWM7UUFDdEMsSUFBSSxLQUFLLEtBQUssSUFBSTtZQUFFLE9BQU8sTUFBTSxDQUFDO1FBQ2xDLElBQUksT0FBTyxLQUFLLEtBQUssUUFBUTtZQUFFLE9BQU8sSUFBSSxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUM1RCxPQUFPLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUN2QixDQUFDO3dHQXhGVSx1QkFBdUI7NEZBQXZCLHVCQUF1QiwrRUM1RnBDLDByV0F3UUEsK3BCRDlPSSxXQUFXLGd4QkFDWCxlQUFlLHdVQUNmLGlCQUFpQiw2V0FDakIsZ0JBQWdCLGtJQUNoQixrQkFBa0Isa1lBQ2xCLGFBQWEsbUxBQ2IsY0FBYywwV0FDZCxlQUFlLG1yQkFDZixvQkFBb0IsbVdBQ3BCLGdCQUFnQiw4VEFDaEIsOEJBQThCLHdFQUM5Qix1QkFBdUIsaUVBQ3ZCLDhCQUE4Qjs7NEZBc0RyQix1QkFBdUI7a0JBdEVuQyxTQUFTOytCQUNFLHFCQUFxQixjQUNuQixJQUFJLFdBQ1A7d0JBQ1AsV0FBVzt3QkFDWCxlQUFlO3dCQUNmLGlCQUFpQjt3QkFDakIsZ0JBQWdCO3dCQUNoQixrQkFBa0I7d0JBQ2xCLGFBQWE7d0JBQ2IsY0FBYzt3QkFDZCxlQUFlO3dCQUNmLG9CQUFvQjt3QkFDcEIsZ0JBQWdCO3dCQUNoQiw4QkFBOEI7d0JBQzlCLHVCQUF1Qjt3QkFDdkIsOEJBQThCO3FCQUMvQiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENvbXBvbmVudCwgY29tcHV0ZWQsIGluamVjdCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xyXG5pbXBvcnQgeyBGb3Jtc01vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL2Zvcm1zJztcclxuaW1wb3J0IHsgTWF0QnV0dG9uTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvbWF0ZXJpYWwvYnV0dG9uJztcclxuaW1wb3J0IHsgTWF0Q2hlY2tib3hNb2R1bGUgfSBmcm9tICdAYW5ndWxhci9tYXRlcmlhbC9jaGVja2JveCc7XHJcbmltcG9ydCB7IE1hdERpdmlkZXJNb2R1bGUgfSBmcm9tICdAYW5ndWxhci9tYXRlcmlhbC9kaXZpZGVyJztcclxuaW1wb3J0IHsgTWF0Rm9ybUZpZWxkTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvbWF0ZXJpYWwvZm9ybS1maWVsZCc7XHJcbmltcG9ydCB7IE1hdEljb25Nb2R1bGUgfSBmcm9tICdAYW5ndWxhci9tYXRlcmlhbC9pY29uJztcclxuaW1wb3J0IHsgTWF0SW5wdXRNb2R1bGUgfSBmcm9tICdAYW5ndWxhci9tYXRlcmlhbC9pbnB1dCc7XHJcbmltcG9ydCB7IE1hdFNlbGVjdE1vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL21hdGVyaWFsL3NlbGVjdCc7XHJcbmltcG9ydCB7IE1hdFNsaWRlVG9nZ2xlTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvbWF0ZXJpYWwvc2xpZGUtdG9nZ2xlJztcclxuaW1wb3J0IHsgTWF0VG9vbHRpcE1vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL21hdGVyaWFsL3Rvb2x0aXAnO1xyXG5pbXBvcnQgdHlwZSB7IERyb3Bkb3duT3B0aW9uLCBOZXN0ZWRGaWVsZENvbmZpZyB9IGZyb20gJ0BkeW5hbWljLWVudGl0eS9jb3JlJztcclxuaW1wb3J0IHsgZ2V0T3B0aW9uU3RvcmVkVmFsdWUsIHJlc29sdmVMYWJlbCwgcmVzb2x2ZU9wdGlvbkxhYmVsIH0gZnJvbSAnQGR5bmFtaWMtZW50aXR5L2NvcmUnO1xyXG5pbXBvcnQgeyBCdWlsZGVyU3RvcmUgfSBmcm9tICcuLi9idWlsZGVyLXN0b3JlLnNlcnZpY2UnO1xyXG5pbXBvcnQgeyBnZXRGaWVsZFR5cGVNZXRhLCB0eXBlIEZpZWxkVHlwZU1ldGEgfSBmcm9tICcuLi9maWVsZC1jYXRhbG9nJztcclxuaW1wb3J0IHsgRW50aXR5UmVmZXJlbmNlQ29uZmlnQ29tcG9uZW50IH0gZnJvbSAnLi9lbnRpdHktcmVmZXJlbmNlLWNvbmZpZy5jb21wb25lbnQnO1xyXG5pbXBvcnQgeyBGaWVsZFJ1bGVzTGlzdENvbXBvbmVudCB9IGZyb20gJy4vZmllbGQtcnVsZXMtbGlzdC5jb21wb25lbnQnO1xyXG5pbXBvcnQgeyBSZWZlcmVuY2VkRmllbGRDb25maWdDb21wb25lbnQgfSBmcm9tICcuL3JlZmVyZW5jZWQtZmllbGQtY29uZmlnLmNvbXBvbmVudCc7XHJcblxyXG4vKipcclxuICogRmllbGRJbnNwZWN0b3JDb21wb25lbnQg4oCUIGVkaXRzIGV2ZXJ5IHByb3BlcnR5IG9mIHRoZSBjdXJyZW50bHkgc2VsZWN0ZWQgZmllbGQuXHJcbiAqL1xyXG5AQ29tcG9uZW50KHtcclxuICBzZWxlY3RvcjogJ25neC1maWVsZC1pbnNwZWN0b3InLFxyXG4gIHN0YW5kYWxvbmU6IHRydWUsXHJcbiAgaW1wb3J0czogW1xyXG4gICAgRm9ybXNNb2R1bGUsXHJcbiAgICBNYXRCdXR0b25Nb2R1bGUsXHJcbiAgICBNYXRDaGVja2JveE1vZHVsZSxcclxuICAgIE1hdERpdmlkZXJNb2R1bGUsXHJcbiAgICBNYXRGb3JtRmllbGRNb2R1bGUsXHJcbiAgICBNYXRJY29uTW9kdWxlLFxyXG4gICAgTWF0SW5wdXRNb2R1bGUsXHJcbiAgICBNYXRTZWxlY3RNb2R1bGUsXHJcbiAgICBNYXRTbGlkZVRvZ2dsZU1vZHVsZSxcclxuICAgIE1hdFRvb2x0aXBNb2R1bGUsXHJcbiAgICBFbnRpdHlSZWZlcmVuY2VDb25maWdDb21wb25lbnQsXHJcbiAgICBGaWVsZFJ1bGVzTGlzdENvbXBvbmVudCxcclxuICAgIFJlZmVyZW5jZWRGaWVsZENvbmZpZ0NvbXBvbmVudCxcclxuICBdLFxyXG4gIHRlbXBsYXRlVXJsOiAnLi9maWVsZC1pbnNwZWN0b3IuY29tcG9uZW50Lmh0bWwnLFxyXG4gIHN0eWxlczogW1xyXG4gICAgYFxyXG4gICAgICAuZGViLWluc3BlY3RvciB7XHJcbiAgICAgICAgZGlzcGxheTogZmxleDtcclxuICAgICAgICBmbGV4LWRpcmVjdGlvbjogY29sdW1uO1xyXG4gICAgICAgIGdhcDogMTJweDtcclxuICAgICAgfVxyXG4gICAgICAuZGViLWluc3BlY3Rvcl9fZW1wdHkge1xyXG4gICAgICAgIGNvbG9yOiB2YXIoLS1kZWItbXV0ZWQsICM2YjcyODApO1xyXG4gICAgICAgIHRleHQtYWxpZ246IGNlbnRlcjtcclxuICAgICAgICBwYWRkaW5nOiAyNHB4IDhweDtcclxuICAgICAgfVxyXG4gICAgICAuZGViLWZ1bGwge1xyXG4gICAgICAgIHdpZHRoOiAxMDAlO1xyXG4gICAgICB9XHJcbiAgICAgIC5kZWItcm93IHtcclxuICAgICAgICBkaXNwbGF5OiBmbGV4O1xyXG4gICAgICAgIGdhcDogOHB4O1xyXG4gICAgICAgIGFsaWduLWl0ZW1zOiBjZW50ZXI7XHJcbiAgICAgIH1cclxuICAgICAgLmRlYi1yb3cgPiAqIHtcclxuICAgICAgICBmbGV4OiAxO1xyXG4gICAgICB9XHJcbiAgICAgIC5kZWItcm93LS1zcGxpdCB7XHJcbiAgICAgICAganVzdGlmeS1jb250ZW50OiBzcGFjZS1iZXR3ZWVuO1xyXG4gICAgICB9XHJcbiAgICAgIC5kZWItcm93LS1zcGxpdCA+ICoge1xyXG4gICAgICAgIGZsZXg6IDAgMCBhdXRvO1xyXG4gICAgICB9XHJcbiAgICAgIC5kZWItdG9nZ2xlcyB7XHJcbiAgICAgICAgZGlzcGxheTogZ3JpZDtcclxuICAgICAgICBncmlkLXRlbXBsYXRlLWNvbHVtbnM6IDFmciAxZnI7XHJcbiAgICAgICAgZ2FwOiA4cHggMTJweDtcclxuICAgICAgfVxyXG4gICAgICAuZGViLW9wdGlvbi1yb3cge1xyXG4gICAgICAgIGRpc3BsYXk6IGZsZXg7XHJcbiAgICAgICAgZ2FwOiA2cHg7XHJcbiAgICAgICAgYWxpZ24taXRlbXM6IGNlbnRlcjtcclxuICAgICAgfVxyXG4gICAgICAuZGViLWNoaXAge1xyXG4gICAgICAgIGRpc3BsYXk6IGlubGluZS1ibG9jaztcclxuICAgICAgICBwYWRkaW5nOiAycHggOHB4O1xyXG4gICAgICAgIGJvcmRlci1yYWRpdXM6IDEycHg7XHJcbiAgICAgICAgYmFja2dyb3VuZDogdmFyKC0tZGViLWFjY2VudC1zb2Z0LCAjZWVmMmZmKTtcclxuICAgICAgICBjb2xvcjogdmFyKC0tZGViLWFjY2VudCwgIzYzNjZmMSk7XHJcbiAgICAgICAgZm9udC1zaXplOiAxMnB4O1xyXG4gICAgICAgIGZvbnQtd2VpZ2h0OiA2MDA7XHJcbiAgICAgIH1cclxuICAgIGAsXHJcbiAgXSxcclxufSlcclxuZXhwb3J0IGNsYXNzIEZpZWxkSW5zcGVjdG9yQ29tcG9uZW50IHtcclxuICBwcm90ZWN0ZWQgcmVhZG9ubHkgc3RvcmUgPSBpbmplY3QoQnVpbGRlclN0b3JlKTtcclxuXHJcbiAgcHJvdGVjdGVkIHJlYWRvbmx5IGZpZWxkID0gdGhpcy5zdG9yZS5zZWxlY3RlZEZpZWxkO1xyXG4gIHByb3RlY3RlZCByZWFkb25seSBtZXRhID0gY29tcHV0ZWQ8RmllbGRUeXBlTWV0YSB8IHVuZGVmaW5lZD4oKCkgPT4ge1xyXG4gICAgY29uc3QgZiA9IHRoaXMuZmllbGQoKTtcclxuICAgIHJldHVybiBmID8gZ2V0RmllbGRUeXBlTWV0YShmLnR5cGUpIDogdW5kZWZpbmVkO1xyXG4gIH0pO1xyXG5cclxuICBwcm90ZWN0ZWQgbGFuZygpOiBzdHJpbmcge1xyXG4gICAgcmV0dXJuIHRoaXMuc3RvcmUuYWN0aXZlTGFuZ3VhZ2UoKTtcclxuICB9XHJcblxyXG5cclxuICBwcm90ZWN0ZWQgdG9OdW0odmFsdWU6IHVua25vd24pOiBudW1iZXIgfCBudWxsIHtcclxuICAgIGlmICh2YWx1ZSA9PT0gJycgfHwgdmFsdWUgPT09IG51bGwgfHwgdmFsdWUgPT09IHVuZGVmaW5lZCkgcmV0dXJuIG51bGw7XHJcbiAgICBjb25zdCBuID0gTnVtYmVyKHZhbHVlKTtcclxuICAgIHJldHVybiBOdW1iZXIuaXNOYU4obikgPyBudWxsIDogbjtcclxuICB9XHJcblxyXG4gIHByb3RlY3RlZCBsYWJlbFZhbHVlKGZpZWxkOiBOZXN0ZWRGaWVsZENvbmZpZyk6IHN0cmluZyB7XHJcbiAgICByZXR1cm4gcmVzb2x2ZUxhYmVsKGZpZWxkLmxhYmVsLCB0aGlzLmxhbmcoKSk7XHJcbiAgfVxyXG5cclxuICBwcm90ZWN0ZWQgcGxhY2Vob2xkZXJWYWx1ZShmaWVsZDogTmVzdGVkRmllbGRDb25maWcpOiBzdHJpbmcge1xyXG4gICAgcmV0dXJuIHJlc29sdmVMYWJlbChmaWVsZC5wbGFjZWhvbGRlciwgdGhpcy5sYW5nKCkpO1xyXG4gIH1cclxuXHJcbiAgcHJvdGVjdGVkIG9wdGlvbkxhYmVsKG9wdGlvbjogRHJvcGRvd25PcHRpb24pOiBzdHJpbmcge1xyXG4gICAgcmV0dXJuIHJlc29sdmVPcHRpb25MYWJlbChvcHRpb24sIHRoaXMubGFuZygpKTtcclxuICB9XHJcblxyXG4gIC8vIOKUgOKUgOKUgCBzaG93V2hlbiBlZGl0aW5nIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxyXG5cclxuICBwcm90ZWN0ZWQgc2hvd1doZW5FbnRyaWVzKGZpZWxkOiBOZXN0ZWRGaWVsZENvbmZpZyk6IHsga2V5OiBzdHJpbmc7IGRpc3BsYXk6IHN0cmluZyB9W10ge1xyXG4gICAgcmV0dXJuIE9iamVjdC5lbnRyaWVzKGZpZWxkLnNob3dXaGVuID8/IHt9KS5tYXAoKFtrZXksIHZhbHVlXSkgPT4gKHtcclxuICAgICAga2V5LFxyXG4gICAgICBkaXNwbGF5OiB0aGlzLnN0cmluZ2lmeVNob3dXaGVuKHZhbHVlKSxcclxuICAgIH0pKTtcclxuICB9XHJcblxyXG4gIHByb3RlY3RlZCBhZGRTaG93V2hlbihmaWVsZDogTmVzdGVkRmllbGRDb25maWcpOiB2b2lkIHtcclxuICAgIGNvbnN0IG5leHQgPSB7IC4uLihmaWVsZC5zaG93V2hlbiA/PyB7fSkgfTtcclxuICAgIGxldCBrZXkgPSAnZmllbGQnO1xyXG4gICAgbGV0IG4gPSAxO1xyXG4gICAgd2hpbGUgKGtleSBpbiBuZXh0KSBrZXkgPSBgZmllbGRfJHsrK259YDtcclxuICAgIG5leHRba2V5XSA9IHRydWU7XHJcbiAgICB0aGlzLnN0b3JlLnNldFNob3dXaGVuKGZpZWxkLmlkLCBuZXh0KTtcclxuICB9XHJcblxyXG4gIHByb3RlY3RlZCByZW5hbWVTaG93V2hlbihmaWVsZDogTmVzdGVkRmllbGRDb25maWcsIG9sZEtleTogc3RyaW5nLCBuZXdLZXk6IHN0cmluZyk6IHZvaWQge1xyXG4gICAgY29uc3QgdHJpbW1lZCA9IG5ld0tleS50cmltKCk7XHJcbiAgICBpZiAoIXRyaW1tZWQgfHwgdHJpbW1lZCA9PT0gb2xkS2V5KSByZXR1cm47XHJcbiAgICBjb25zdCBjdXJyZW50ID0gZmllbGQuc2hvd1doZW4gPz8ge307XHJcbiAgICBpZiAodHJpbW1lZCBpbiBjdXJyZW50KSByZXR1cm47XHJcbiAgICBjb25zdCBuZXh0OiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiA9IHt9O1xyXG4gICAgLy8gUmVidWlsZCBpbiBvcmRlciBzbyB0aGUgcm93IGRvZXMgbm90IGp1bXAgd2hpbGUgdGhlIHVzZXIgaXMgdHlwaW5nLlxyXG4gICAgZm9yIChjb25zdCBbaywgdl0gb2YgT2JqZWN0LmVudHJpZXMoY3VycmVudCkpIG5leHRbayA9PT0gb2xkS2V5ID8gdHJpbW1lZCA6IGtdID0gdjtcclxuICAgIHRoaXMuc3RvcmUuc2V0U2hvd1doZW4oZmllbGQuaWQsIG5leHQpO1xyXG4gIH1cclxuXHJcbiAgcHJvdGVjdGVkIHNldFNob3dXaGVuVmFsdWUoZmllbGQ6IE5lc3RlZEZpZWxkQ29uZmlnLCBrZXk6IHN0cmluZywgcmF3OiBzdHJpbmcpOiB2b2lkIHtcclxuICAgIHRoaXMuc3RvcmUuc2V0U2hvd1doZW4oZmllbGQuaWQsIHsgLi4uKGZpZWxkLnNob3dXaGVuID8/IHt9KSwgW2tleV06IHRoaXMucGFyc2VTaG93V2hlbihyYXcpIH0pO1xyXG4gIH1cclxuXHJcbiAgcHJvdGVjdGVkIHJlbW92ZVNob3dXaGVuKGZpZWxkOiBOZXN0ZWRGaWVsZENvbmZpZywga2V5OiBzdHJpbmcpOiB2b2lkIHtcclxuICAgIGNvbnN0IG5leHQgPSB7IC4uLihmaWVsZC5zaG93V2hlbiA/PyB7fSkgfTtcclxuICAgIGRlbGV0ZSBuZXh0W2tleV07XHJcbiAgICB0aGlzLnN0b3JlLnNldFNob3dXaGVuKGZpZWxkLmlkLCBuZXh0KTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIGBzaG93V2hlbmAgY29tcGFyZXMgd2l0aCBgIT09YCwgc28gdGhlIGF1dGhvcmVkIHR5cGUgaGFzIHRvIHN1cnZpdmUgdGhlIHJvdW5kIHRyaXA6XHJcbiAgICogXCJ0cnVlXCIvXCJmYWxzZVwiIGJlY29tZSBib29sZWFucyBhbmQgbnVtZXJpYyB0ZXh0IGJlY29tZXMgYSBudW1iZXIuXHJcbiAgICovXHJcbiAgcHJpdmF0ZSBwYXJzZVNob3dXaGVuKHJhdzogc3RyaW5nKTogdW5rbm93biB7XHJcbiAgICBjb25zdCB0cmltbWVkID0gcmF3LnRyaW0oKTtcclxuICAgIGlmICh0cmltbWVkID09PSAndHJ1ZScpIHJldHVybiB0cnVlO1xyXG4gICAgaWYgKHRyaW1tZWQgPT09ICdmYWxzZScpIHJldHVybiBmYWxzZTtcclxuICAgIGlmICh0cmltbWVkID09PSAnbnVsbCcpIHJldHVybiBudWxsO1xyXG4gICAgaWYgKHRyaW1tZWQgIT09ICcnICYmICFOdW1iZXIuaXNOYU4oTnVtYmVyKHRyaW1tZWQpKSkgcmV0dXJuIE51bWJlcih0cmltbWVkKTtcclxuICAgIHJldHVybiByYXc7XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIHN0cmluZ2lmeVNob3dXaGVuKHZhbHVlOiB1bmtub3duKTogc3RyaW5nIHtcclxuICAgIGlmICh2YWx1ZSA9PT0gbnVsbCkgcmV0dXJuICdudWxsJztcclxuICAgIGlmICh0eXBlb2YgdmFsdWUgPT09ICdvYmplY3QnKSByZXR1cm4gSlNPTi5zdHJpbmdpZnkodmFsdWUpO1xyXG4gICAgcmV0dXJuIFN0cmluZyh2YWx1ZSk7XHJcbiAgfVxyXG59XHJcbiIsIkBpZiAoZmllbGQoKTsgYXMgZikge1xyXG4gIDxkaXYgY2xhc3M9XCJkZWItaW5zcGVjdG9yXCI+XHJcbiAgICA8IS0tIElkZW50aXR5IC0tPlxyXG4gICAgPGRpdiBjbGFzcz1cImRlYi1yb3dcIj5cclxuICAgICAgPG1hdC1mb3JtLWZpZWxkIGFwcGVhcmFuY2U9XCJvdXRsaW5lXCIgc3Vic2NyaXB0U2l6aW5nPVwiZHluYW1pY1wiPlxyXG4gICAgICAgIDxtYXQtbGFiZWw+RmllbGQgaWQ8L21hdC1sYWJlbD5cclxuICAgICAgICA8aW5wdXQgbWF0SW5wdXQgZGF0YS10ZXN0aWQ9XCJmaWVsZC1pZFwiIFt2YWx1ZV09XCJmLmlkXCIgZGlzYWJsZWQgLz5cclxuICAgICAgICBAaWYgKHN0b3JlLmhhc01hbnVhbElkKGYuaWQpKSB7XHJcbiAgICAgICAgICA8bWF0LWhpbnQ+VGhlIHN0b3JlZCBkYXRhIGtleSBmb3IgdGhpcyBzYXZlZCBmaWVsZCDigJQgZml4ZWQuPC9tYXQtaGludD5cclxuICAgICAgICB9IEBlbHNlIHtcclxuICAgICAgICAgIDxtYXQtaGludD5EZXJpdmVkIGZyb20gdGhlIGxhYmVsLiBVc2VkIGFzIHRoZSBkYXRhIGtleS48L21hdC1oaW50PlxyXG4gICAgICAgIH1cclxuICAgICAgPC9tYXQtZm9ybS1maWVsZD5cclxuICAgICAgPHNwYW4gY2xhc3M9XCJkZWItY2hpcFwiPnt7IG1ldGEoKT8ubGFiZWwgfHwgZi50eXBlIH19PC9zcGFuPlxyXG4gICAgPC9kaXY+XHJcblxyXG4gICAgPCEtLSBMb2NhbGlzZWQgdGV4dCAoYWN0aXZlIGxhbmd1YWdlKSAtLT5cclxuICAgIDxtYXQtZm9ybS1maWVsZCBhcHBlYXJhbmNlPVwib3V0bGluZVwiIHN1YnNjcmlwdFNpemluZz1cImR5bmFtaWNcIiBjbGFzcz1cImRlYi1mdWxsXCI+XHJcbiAgICAgIDxtYXQtbGFiZWw+TGFiZWwgKHt7IGxhbmcoKSB9fSk8L21hdC1sYWJlbD5cclxuICAgICAgPGlucHV0XHJcbiAgICAgICAgbWF0SW5wdXRcclxuICAgICAgICBbbmdNb2RlbF09XCJsYWJlbFZhbHVlKGYpXCJcclxuICAgICAgICAobmdNb2RlbENoYW5nZSk9XCJzdG9yZS5zZXRGaWVsZExhYmVsKGYuaWQsIGxhbmcoKSwgJGV2ZW50KVwiXHJcbiAgICAgIC8+XHJcbiAgICA8L21hdC1mb3JtLWZpZWxkPlxyXG5cclxuICAgIEBpZiAobWV0YSgpPy5zdXBwb3J0c1BsYWNlaG9sZGVyKSB7XHJcbiAgICAgIDxtYXQtZm9ybS1maWVsZCBhcHBlYXJhbmNlPVwib3V0bGluZVwiIHN1YnNjcmlwdFNpemluZz1cImR5bmFtaWNcIiBjbGFzcz1cImRlYi1mdWxsXCI+XHJcbiAgICAgICAgPG1hdC1sYWJlbD5QbGFjZWhvbGRlciAoe3sgbGFuZygpIH19KTwvbWF0LWxhYmVsPlxyXG4gICAgICAgIDxpbnB1dFxyXG4gICAgICAgICAgbWF0SW5wdXRcclxuICAgICAgICAgIFtuZ01vZGVsXT1cInBsYWNlaG9sZGVyVmFsdWUoZilcIlxyXG4gICAgICAgICAgKG5nTW9kZWxDaGFuZ2UpPVwic3RvcmUuc2V0RmllbGRQbGFjZWhvbGRlcihmLmlkLCBsYW5nKCksICRldmVudClcIlxyXG4gICAgICAgIC8+XHJcbiAgICAgIDwvbWF0LWZvcm0tZmllbGQ+XHJcbiAgICB9XHJcblxyXG4gICAgQGlmIChtZXRhKCk/LnN1cHBvcnRzRGVmYXVsdFZhbHVlKSB7XHJcbiAgICAgIDxtYXQtZm9ybS1maWVsZCBhcHBlYXJhbmNlPVwib3V0bGluZVwiIHN1YnNjcmlwdFNpemluZz1cImR5bmFtaWNcIiBjbGFzcz1cImRlYi1mdWxsXCI+XHJcbiAgICAgICAgPG1hdC1sYWJlbD5EZWZhdWx0IHZhbHVlPC9tYXQtbGFiZWw+XHJcbiAgICAgICAgPGlucHV0XHJcbiAgICAgICAgICBtYXRJbnB1dFxyXG4gICAgICAgICAgW25nTW9kZWxdPVwiZi5kZWZhdWx0VmFsdWUgPz8gJydcIlxyXG4gICAgICAgICAgKG5nTW9kZWxDaGFuZ2UpPVwic3RvcmUudXBkYXRlRmllbGQoZi5pZCwgeyBkZWZhdWx0VmFsdWU6ICRldmVudCB9KVwiXHJcbiAgICAgICAgLz5cclxuICAgICAgPC9tYXQtZm9ybS1maWVsZD5cclxuICAgIH1cclxuXHJcbiAgICA8IS0tIEVudGl0eSByZWZlcmVuY2UsIGNhc2NhZGUsIGFuZCBhdXRvUGF0Y2ggLS0+XHJcbiAgICBAaWYgKG1ldGEoKT8uaXNFbnRpdHlSZWYpIHtcclxuICAgICAgPG1hdC1kaXZpZGVyPjwvbWF0LWRpdmlkZXI+XHJcbiAgICAgIDxuZ3gtZW50aXR5LXJlZmVyZW5jZS1jb25maWcgLz5cclxuICAgIH1cclxuXHJcbiAgICA8bWF0LWRpdmlkZXI+PC9tYXQtZGl2aWRlcj5cclxuXHJcbiAgICA8IS0tIFZhbGlkYXRvcnMgLS0+XHJcbiAgICBAaWYgKG1ldGEoKTsgYXMgbSkge1xyXG4gICAgICBAaWYgKG0uZmxhZ1ZhbGlkYXRvcnMubGVuZ3RoIHx8IG0ucGFyYW1WYWxpZGF0b3JzLmxlbmd0aCkge1xyXG4gICAgICAgIDxzcGFuIGNsYXNzPVwiZGViLXNlY3Rpb24tdGl0bGVcIj5WYWxpZGF0aW9uPC9zcGFuPlxyXG4gICAgICAgIDxkaXYgY2xhc3M9XCJkZWItdG9nZ2xlc1wiPlxyXG4gICAgICAgICAgQGZvciAodiBvZiBtLmZsYWdWYWxpZGF0b3JzOyB0cmFjayB2KSB7XHJcbiAgICAgICAgICAgIDxtYXQtY2hlY2tib3hcclxuICAgICAgICAgICAgICBbbmdNb2RlbF09XCJzdG9yZS5oYXNGbGFnVmFsaWRhdG9yKGYsIHYpXCJcclxuICAgICAgICAgICAgICAobmdNb2RlbENoYW5nZSk9XCJzdG9yZS50b2dnbGVGbGFnVmFsaWRhdG9yKGYuaWQsIHYsICRldmVudClcIlxyXG4gICAgICAgICAgICA+e3sgdiB9fTwvbWF0LWNoZWNrYm94PlxyXG4gICAgICAgICAgfVxyXG4gICAgICAgIDwvZGl2PlxyXG4gICAgICAgIEBmb3IgKHYgb2YgbS5wYXJhbVZhbGlkYXRvcnM7IHRyYWNrIHYpIHtcclxuICAgICAgICAgIDxtYXQtZm9ybS1maWVsZCBhcHBlYXJhbmNlPVwib3V0bGluZVwiIHN1YnNjcmlwdFNpemluZz1cImR5bmFtaWNcIiBjbGFzcz1cImRlYi1mdWxsXCI+XHJcbiAgICAgICAgICAgIDxtYXQtbGFiZWw+e3sgdiB9fTwvbWF0LWxhYmVsPlxyXG4gICAgICAgICAgICA8aW5wdXRcclxuICAgICAgICAgICAgICBtYXRJbnB1dFxyXG4gICAgICAgICAgICAgIHR5cGU9XCJudW1iZXJcIlxyXG4gICAgICAgICAgICAgIFtuZ01vZGVsXT1cInN0b3JlLmdldFBhcmFtVmFsaWRhdG9yKGYsIHYpXCJcclxuICAgICAgICAgICAgICAobmdNb2RlbENoYW5nZSk9XCJzdG9yZS5zZXRQYXJhbVZhbGlkYXRvcihmLmlkLCB2LCB0b051bSgkZXZlbnQpKVwiXHJcbiAgICAgICAgICAgIC8+XHJcbiAgICAgICAgICA8L21hdC1mb3JtLWZpZWxkPlxyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIDwhLS0gT3B0aW9ucyAoZHJvcGRvd24gLyByYWRpbyAvIG11bHRpU2VsZWN0KSAtLT5cclxuICAgIEBpZiAobWV0YSgpPy5oYXNPcHRpb25zKSB7XHJcbiAgICAgIDxtYXQtZGl2aWRlcj48L21hdC1kaXZpZGVyPlxyXG4gICAgICA8c3BhbiBjbGFzcz1cImRlYi1zZWN0aW9uLXRpdGxlXCI+RGF0YSBzb3VyY2U8L3NwYW4+XHJcbiAgICAgIDxtYXQtZm9ybS1maWVsZCBhcHBlYXJhbmNlPVwib3V0bGluZVwiIHN1YnNjcmlwdFNpemluZz1cImR5bmFtaWNcIiBjbGFzcz1cImRlYi1mdWxsXCI+XHJcbiAgICAgICAgPG1hdC1sYWJlbD5PcHRpb25zIGNvbWUgZnJvbTwvbWF0LWxhYmVsPlxyXG4gICAgICAgIDxtYXQtc2VsZWN0XHJcbiAgICAgICAgICBkYXRhLXRlc3RpZD1cImRhdGEtc291cmNlXCJcclxuICAgICAgICAgIFtuZ01vZGVsXT1cInN0b3JlLmZpZWxkRGF0YVNvdXJjZShmKVwiXHJcbiAgICAgICAgICAobmdNb2RlbENoYW5nZSk9XCJzdG9yZS5zZXRGaWVsZERhdGFTb3VyY2UoZi5pZCwgJGV2ZW50KVwiXHJcbiAgICAgICAgPlxyXG4gICAgICAgICAgPG1hdC1vcHRpb24gdmFsdWU9XCJub25lXCI+Tm90aGluZyB5ZXQ8L21hdC1vcHRpb24+XHJcbiAgICAgICAgICA8bWF0LW9wdGlvbiB2YWx1ZT1cIm1hbnVhbFwiPk9wdGlvbnMgYXV0aG9yZWQgaGVyZTwvbWF0LW9wdGlvbj5cclxuICAgICAgICAgIDxtYXQtb3B0aW9uIHZhbHVlPVwibG9va3VwXCI+QSBuYW1lZCBsaXN0PC9tYXQtb3B0aW9uPlxyXG4gICAgICAgIDwvbWF0LXNlbGVjdD5cclxuICAgICAgPC9tYXQtZm9ybS1maWVsZD5cclxuICAgIH1cclxuXHJcbiAgICA8IS0tIE5hbWVkIGxvb2t1cCBsaXN0IC0tPlxyXG4gICAgQGlmIChtZXRhKCk/Lmhhc09wdGlvbnMgJiYgc3RvcmUuZmllbGREYXRhU291cmNlKGYpID09PSAnbG9va3VwJykge1xyXG4gICAgICA8bWF0LWZvcm0tZmllbGQgYXBwZWFyYW5jZT1cIm91dGxpbmVcIiBzdWJzY3JpcHRTaXppbmc9XCJkeW5hbWljXCIgY2xhc3M9XCJkZWItZnVsbFwiPlxyXG4gICAgICAgIDxtYXQtbGFiZWw+TGlzdCBuYW1lPC9tYXQtbGFiZWw+XHJcbiAgICAgICAgPGlucHV0XHJcbiAgICAgICAgICBtYXRJbnB1dFxyXG4gICAgICAgICAgZGF0YS10ZXN0aWQ9XCJsaXN0LW5hbWVcIlxyXG4gICAgICAgICAgW25nTW9kZWxdPVwiZi5saXN0TmFtZSA/PyAnJ1wiXHJcbiAgICAgICAgICAobmdNb2RlbENoYW5nZSk9XCJzdG9yZS5zZXRMaXN0TmFtZShmLmlkLCAkZXZlbnQpXCJcclxuICAgICAgICAvPlxyXG4gICAgICA8L21hdC1mb3JtLWZpZWxkPlxyXG4gICAgICA8cCBjbGFzcz1cImRlYi1oaW50XCI+XHJcbiAgICAgICAgVGhlIGNvbnN1bWluZyBhcHAgcmVzb2x2ZXMgdGhpcyBuYW1lIHRocm91Z2ggaXRzIGxvb2t1cCByZWdpc3RyeS4gT3B0aW9ucyBhcmUgbm90XHJcbiAgICAgICAgYXV0aG9yZWQgaGVyZS5cclxuICAgICAgPC9wPlxyXG4gICAgfVxyXG5cclxuICAgIDwhLS0gSW5saW5lIG9wdGlvbnMgLS0+XHJcbiAgICBAaWYgKG1ldGEoKT8uaGFzT3B0aW9ucyAmJiBzdG9yZS5maWVsZERhdGFTb3VyY2UoZikgIT09ICdsb29rdXAnKSB7XHJcbiAgICAgIDxkaXYgY2xhc3M9XCJkZWItcm93XCIgc3R5bGU9XCJqdXN0aWZ5LWNvbnRlbnQ6IHNwYWNlLWJldHdlZW47XCI+XHJcbiAgICAgICAgPHNwYW4gY2xhc3M9XCJkZWItc2VjdGlvbi10aXRsZVwiPk9wdGlvbnM8L3NwYW4+XHJcbiAgICAgICAgPGJ1dHRvbiBtYXQtc3Ryb2tlZC1idXR0b24gdHlwZT1cImJ1dHRvblwiIChjbGljayk9XCJzdG9yZS5hZGRPcHRpb24oZi5pZClcIj5cclxuICAgICAgICAgIDxtYXQtaWNvbj5hZGQ8L21hdC1pY29uPiBPcHRpb25cclxuICAgICAgICA8L2J1dHRvbj5cclxuICAgICAgPC9kaXY+XHJcbiAgICAgIEBmb3IgKG9wdCBvZiBmLm9wdGlvbnMgPz8gW107IHRyYWNrICRpbmRleCkge1xyXG4gICAgICAgIDxkaXYgY2xhc3M9XCJkZWItb3B0aW9uLXJvd1wiIGRhdGEtdGVzdGlkPVwib3B0aW9uLXJvd1wiPlxyXG4gICAgICAgICAgPCEtLSBPbmUgaW5wdXQ6IHRoZSBkaXNwbGF5ZWQgdGV4dCBpcyB0aGUgc3RvcmVkIHZhbHVlLiAtLT5cclxuICAgICAgICAgIDxtYXQtZm9ybS1maWVsZCBhcHBlYXJhbmNlPVwib3V0bGluZVwiIHN1YnNjcmlwdFNpemluZz1cImR5bmFtaWNcIiBjbGFzcz1cImRlYi1mdWxsXCI+XHJcbiAgICAgICAgICAgIDxtYXQtbGFiZWw+T3B0aW9uICh7eyBsYW5nKCkgfX0pPC9tYXQtbGFiZWw+XHJcbiAgICAgICAgICAgIDxpbnB1dFxyXG4gICAgICAgICAgICAgIG1hdElucHV0XHJcbiAgICAgICAgICAgICAgW2F0dHIuZGF0YS10ZXN0aWRdPVwiJ29wdGlvbi0nICsgJGluZGV4XCJcclxuICAgICAgICAgICAgICBbbmdNb2RlbF09XCJvcHRpb25MYWJlbChvcHQpXCJcclxuICAgICAgICAgICAgICAobmdNb2RlbENoYW5nZSk9XCJzdG9yZS5zZXRPcHRpb25MYWJlbChmLmlkLCAkaW5kZXgsIGxhbmcoKSwgJGV2ZW50KVwiXHJcbiAgICAgICAgICAgIC8+XHJcbiAgICAgICAgICA8L21hdC1mb3JtLWZpZWxkPlxyXG4gICAgICAgICAgPGJ1dHRvbiBtYXQtaWNvbi1idXR0b24gdHlwZT1cImJ1dHRvblwiIGNvbG9yPVwid2FyblwiXHJcbiAgICAgICAgICAgIChjbGljayk9XCJzdG9yZS5yZW1vdmVPcHRpb24oZi5pZCwgJGluZGV4KVwiIG1hdFRvb2x0aXA9XCJSZW1vdmUgb3B0aW9uXCI+XHJcbiAgICAgICAgICAgIDxtYXQtaWNvbj5kZWxldGU8L21hdC1pY29uPlxyXG4gICAgICAgICAgPC9idXR0b24+XHJcbiAgICAgICAgPC9kaXY+XHJcbiAgICAgIH1cclxuICAgICAgQGlmICghKGYub3B0aW9ucyA/PyBbXSkubGVuZ3RoKSB7XHJcbiAgICAgICAgPHAgY2xhc3M9XCJkZWItaGludFwiPk5vIG9wdGlvbnMgeWV0IOKAlCBhZGQgYXQgbGVhc3Qgb25lLjwvcD5cclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIDxtYXQtZGl2aWRlcj48L21hdC1kaXZpZGVyPlxyXG5cclxuICAgIDwhLS0gRmxhZ3MgLS0+XHJcbiAgICA8c3BhbiBjbGFzcz1cImRlYi1zZWN0aW9uLXRpdGxlXCI+RGlzcGxheTwvc3Bhbj5cclxuICAgIDxkaXYgY2xhc3M9XCJkZWItdG9nZ2xlc1wiPlxyXG4gICAgICA8bWF0LXNsaWRlLXRvZ2dsZVxyXG4gICAgICAgIFtuZ01vZGVsXT1cImYudmlzaWJpbGl0eSA/PyB0cnVlXCJcclxuICAgICAgICAobmdNb2RlbENoYW5nZSk9XCJzdG9yZS51cGRhdGVGaWVsZChmLmlkLCB7IHZpc2liaWxpdHk6ICRldmVudCB9KVwiXHJcbiAgICAgID5WaXNpYmxlPC9tYXQtc2xpZGUtdG9nZ2xlPlxyXG4gICAgICA8bWF0LXNsaWRlLXRvZ2dsZVxyXG4gICAgICAgIFtuZ01vZGVsXT1cImYudGFibGU/LnZpc2libGUgPz8gZmFsc2VcIlxyXG4gICAgICAgIChuZ01vZGVsQ2hhbmdlKT1cInN0b3JlLnVwZGF0ZUZpZWxkKGYuaWQsIHsgdGFibGU6IHsgdmlzaWJsZTogJGV2ZW50IH0gfSlcIlxyXG4gICAgICA+VGFibGUgY29sdW1uPC9tYXQtc2xpZGUtdG9nZ2xlPlxyXG4gICAgICA8bWF0LXNsaWRlLXRvZ2dsZVxyXG4gICAgICAgIFtuZ01vZGVsXT1cImYucmVhZG9ubHkgPz8gZmFsc2VcIlxyXG4gICAgICAgIChuZ01vZGVsQ2hhbmdlKT1cInN0b3JlLnVwZGF0ZUZpZWxkKGYuaWQsIHsgcmVhZG9ubHk6ICRldmVudCB9KVwiXHJcbiAgICAgID5SZWFkLW9ubHk8L21hdC1zbGlkZS10b2dnbGU+XHJcbiAgICAgIDxtYXQtc2xpZGUtdG9nZ2xlXHJcbiAgICAgICAgW25nTW9kZWxdPVwiZi5kaXNhYmxlZCA/PyBmYWxzZVwiXHJcbiAgICAgICAgKG5nTW9kZWxDaGFuZ2UpPVwic3RvcmUudXBkYXRlRmllbGQoZi5pZCwgeyBkaXNhYmxlZDogJGV2ZW50IH0pXCJcclxuICAgICAgPkRpc2FibGVkPC9tYXQtc2xpZGUtdG9nZ2xlPlxyXG4gICAgICA8bWF0LXNsaWRlLXRvZ2dsZVxyXG4gICAgICAgIFtuZ01vZGVsXT1cImYubWFza0RhdGEgPz8gZmFsc2VcIlxyXG4gICAgICAgIChuZ01vZGVsQ2hhbmdlKT1cInN0b3JlLnVwZGF0ZUZpZWxkKGYuaWQsIHsgbWFza0RhdGE6ICRldmVudCB9KVwiXHJcbiAgICAgID5NYXNrIGRhdGEgKFJCQUMpPC9tYXQtc2xpZGUtdG9nZ2xlPlxyXG4gICAgICA8bWF0LXNsaWRlLXRvZ2dsZVxyXG4gICAgICAgIGRhdGEtdGVzdGlkPVwidG9nZ2xlLWNyaXRpY2FsXCJcclxuICAgICAgICBbbmdNb2RlbF09XCJmLmNyaXRpY2FsRmllbGQgPz8gZmFsc2VcIlxyXG4gICAgICAgIChuZ01vZGVsQ2hhbmdlKT1cInN0b3JlLnVwZGF0ZUZpZWxkKGYuaWQsIHsgY3JpdGljYWxGaWVsZDogJGV2ZW50IH0pXCJcclxuICAgICAgICBtYXRUb29sdGlwPVwiUmVuZGVycyBsb2NrZWQ7IGVkaXRpbmcgaXQgYW5ub3VuY2VzIGEgY2hhbmdlIGFnYWluc3QgdGhlIHNlc3Npb24gYmFzZWxpbmUuXCJcclxuICAgICAgPkNyaXRpY2FsIGZpZWxkPC9tYXQtc2xpZGUtdG9nZ2xlPlxyXG4gICAgICA8bWF0LXNsaWRlLXRvZ2dsZVxyXG4gICAgICAgIFtuZ01vZGVsXT1cImYuc2hvd09uTWluaW1pemUgPz8gZmFsc2VcIlxyXG4gICAgICAgIChuZ01vZGVsQ2hhbmdlKT1cInN0b3JlLnVwZGF0ZUZpZWxkKGYuaWQsIHsgc2hvd09uTWluaW1pemU6ICRldmVudCB9KVwiXHJcbiAgICAgICAgbWF0VG9vbHRpcD1cIlNob3duIGluIHRoZSByZWNvcmQgZWRpdG9yJ3Mgc3VtbWFyeSBwYW5lbC5cIlxyXG4gICAgICA+U2hvdyBpbiBzdW1tYXJ5PC9tYXQtc2xpZGUtdG9nZ2xlPlxyXG4gICAgPC9kaXY+XHJcblxyXG4gICAgPG1hdC1kaXZpZGVyPjwvbWF0LWRpdmlkZXI+XHJcblxyXG4gICAgPCEtLSBDb25kaXRpb25hbCB2aXNpYmlsaXR5IChzdGF0aWMgc2hvd1doZW4pIC0tPlxyXG4gICAgPGRpdiBjbGFzcz1cImRlYi1yb3cgZGViLXJvdy0tc3BsaXRcIj5cclxuICAgICAgPHNwYW4gY2xhc3M9XCJkZWItc2VjdGlvbi10aXRsZVwiPlNob3cgd2hlbjwvc3Bhbj5cclxuICAgICAgPGJ1dHRvbiBtYXQtc3Ryb2tlZC1idXR0b24gdHlwZT1cImJ1dHRvblwiIGRhdGEtdGVzdGlkPVwiYWRkLXNob3ctd2hlblwiIChjbGljayk9XCJhZGRTaG93V2hlbihmKVwiPlxyXG4gICAgICAgIDxtYXQtaWNvbj5hZGQ8L21hdC1pY29uPiBDb25kaXRpb25cclxuICAgICAgPC9idXR0b24+XHJcbiAgICA8L2Rpdj5cclxuICAgIEBmb3IgKGVudHJ5IG9mIHNob3dXaGVuRW50cmllcyhmKTsgdHJhY2sgZW50cnkua2V5KSB7XHJcbiAgICAgIDxkaXYgY2xhc3M9XCJkZWItb3B0aW9uLXJvd1wiIGRhdGEtdGVzdGlkPVwib3B0aW9uLXJvd1wiPlxyXG4gICAgICAgIDxtYXQtZm9ybS1maWVsZCBhcHBlYXJhbmNlPVwib3V0bGluZVwiIHN1YnNjcmlwdFNpemluZz1cImR5bmFtaWNcIj5cclxuICAgICAgICAgIDxtYXQtbGFiZWw+RmllbGQgaWQ8L21hdC1sYWJlbD5cclxuICAgICAgICAgIDxpbnB1dCBtYXRJbnB1dCBbbmdNb2RlbF09XCJlbnRyeS5rZXlcIiAobmdNb2RlbENoYW5nZSk9XCJyZW5hbWVTaG93V2hlbihmLCBlbnRyeS5rZXksICRldmVudClcIiAvPlxyXG4gICAgICAgIDwvbWF0LWZvcm0tZmllbGQ+XHJcbiAgICAgICAgPG1hdC1mb3JtLWZpZWxkIGFwcGVhcmFuY2U9XCJvdXRsaW5lXCIgc3Vic2NyaXB0U2l6aW5nPVwiZHluYW1pY1wiPlxyXG4gICAgICAgICAgPG1hdC1sYWJlbD5FcXVhbHM8L21hdC1sYWJlbD5cclxuICAgICAgICAgIDxpbnB1dCBtYXRJbnB1dCBbbmdNb2RlbF09XCJlbnRyeS5kaXNwbGF5XCIgKG5nTW9kZWxDaGFuZ2UpPVwic2V0U2hvd1doZW5WYWx1ZShmLCBlbnRyeS5rZXksICRldmVudClcIiAvPlxyXG4gICAgICAgIDwvbWF0LWZvcm0tZmllbGQ+XHJcbiAgICAgICAgPGJ1dHRvbiBtYXQtaWNvbi1idXR0b24gdHlwZT1cImJ1dHRvblwiIGNvbG9yPVwid2FyblwiIG1hdFRvb2x0aXA9XCJSZW1vdmUgY29uZGl0aW9uXCJcclxuICAgICAgICAgIChjbGljayk9XCJyZW1vdmVTaG93V2hlbihmLCBlbnRyeS5rZXkpXCI+XHJcbiAgICAgICAgICA8bWF0LWljb24+ZGVsZXRlPC9tYXQtaWNvbj5cclxuICAgICAgICA8L2J1dHRvbj5cclxuICAgICAgPC9kaXY+XHJcbiAgICB9XHJcbiAgICBAaWYgKCFzaG93V2hlbkVudHJpZXMoZikubGVuZ3RoKSB7XHJcbiAgICAgIDxwIGNsYXNzPVwiZGViLWhpbnRcIj5BbHdheXMgdmlzaWJsZS4gQWRkIGEgY29uZGl0aW9uIHRvIHNob3cgdGhpcyBmaWVsZCBvbmx5IGZvciBjZXJ0YWluIHZhbHVlcy48L3A+XHJcbiAgICB9XHJcblxyXG4gICAgPCEtLSBwYXRjaE9uVHJ1ZSAoYm9vbGVhbi9jaGVja2JveCBvbmx5KSAtLT5cclxuICAgIEBpZiAoZi50eXBlID09PSAnYm9vbGVhbicgfHwgZi50eXBlID09PSAnY2hlY2tib3gnKSB7XHJcbiAgICAgIDxtYXQtZGl2aWRlcj48L21hdC1kaXZpZGVyPlxyXG4gICAgICA8ZGl2IGNsYXNzPVwiZGViLXJvdyBkZWItcm93LS1zcGxpdFwiPlxyXG4gICAgICAgIDxzcGFuIGNsYXNzPVwiZGViLXNlY3Rpb24tdGl0bGVcIj5Db3B5IG9uIHRydWU8L3NwYW4+XHJcbiAgICAgICAgPGJ1dHRvbiBtYXQtc3Ryb2tlZC1idXR0b24gdHlwZT1cImJ1dHRvblwiIGRhdGEtdGVzdGlkPVwiYWRkLXBhdGNoLW9uLXRydWVcIlxyXG4gICAgICAgICAgKGNsaWNrKT1cInN0b3JlLmFkZFBhdGNoT25UcnVlTWFwcGluZyhmLmlkKVwiPlxyXG4gICAgICAgICAgPG1hdC1pY29uPmFkZDwvbWF0LWljb24+IE1hcHBpbmdcclxuICAgICAgICA8L2J1dHRvbj5cclxuICAgICAgPC9kaXY+XHJcbiAgICAgIEBmb3IgKG1hcHBpbmcgb2YgZi5wYXRjaE9uVHJ1ZSA/PyBbXTsgdHJhY2sgJGluZGV4KSB7XHJcbiAgICAgICAgPGRpdiBjbGFzcz1cImRlYi1vcHRpb24tcm93XCIgZGF0YS10ZXN0aWQ9XCJvcHRpb24tcm93XCI+XHJcbiAgICAgICAgICA8bWF0LWZvcm0tZmllbGQgYXBwZWFyYW5jZT1cIm91dGxpbmVcIiBzdWJzY3JpcHRTaXppbmc9XCJkeW5hbWljXCI+XHJcbiAgICAgICAgICAgIDxtYXQtbGFiZWw+RnJvbSBmaWVsZDwvbWF0LWxhYmVsPlxyXG4gICAgICAgICAgICA8aW5wdXQgbWF0SW5wdXQgW25nTW9kZWxdPVwibWFwcGluZy5mcm9tXCJcclxuICAgICAgICAgICAgICAobmdNb2RlbENoYW5nZSk9XCJzdG9yZS51cGRhdGVQYXRjaE9uVHJ1ZU1hcHBpbmcoZi5pZCwgJGluZGV4LCB7IGZyb206ICRldmVudCB9KVwiIC8+XHJcbiAgICAgICAgICA8L21hdC1mb3JtLWZpZWxkPlxyXG4gICAgICAgICAgPG1hdC1mb3JtLWZpZWxkIGFwcGVhcmFuY2U9XCJvdXRsaW5lXCIgc3Vic2NyaXB0U2l6aW5nPVwiZHluYW1pY1wiPlxyXG4gICAgICAgICAgICA8bWF0LWxhYmVsPlRvIGZpZWxkPC9tYXQtbGFiZWw+XHJcbiAgICAgICAgICAgIDxpbnB1dCBtYXRJbnB1dCBbbmdNb2RlbF09XCJtYXBwaW5nLnRvXCJcclxuICAgICAgICAgICAgICAobmdNb2RlbENoYW5nZSk9XCJzdG9yZS51cGRhdGVQYXRjaE9uVHJ1ZU1hcHBpbmcoZi5pZCwgJGluZGV4LCB7IHRvOiAkZXZlbnQgfSlcIiAvPlxyXG4gICAgICAgICAgPC9tYXQtZm9ybS1maWVsZD5cclxuICAgICAgICAgIDxidXR0b24gbWF0LWljb24tYnV0dG9uIHR5cGU9XCJidXR0b25cIiBjb2xvcj1cIndhcm5cIiBtYXRUb29sdGlwPVwiUmVtb3ZlIG1hcHBpbmdcIlxyXG4gICAgICAgICAgICAoY2xpY2spPVwic3RvcmUucmVtb3ZlUGF0Y2hPblRydWVNYXBwaW5nKGYuaWQsICRpbmRleClcIj5cclxuICAgICAgICAgICAgPG1hdC1pY29uPmRlbGV0ZTwvbWF0LWljb24+XHJcbiAgICAgICAgICA8L2J1dHRvbj5cclxuICAgICAgICA8L2Rpdj5cclxuICAgICAgfVxyXG4gICAgICBAaWYgKCEoZi5wYXRjaE9uVHJ1ZSA/PyBbXSkubGVuZ3RoKSB7XHJcbiAgICAgICAgPHAgY2xhc3M9XCJkZWItaGludFwiPldoZW4gdGhpcyBmbGlwcyB0byB0cnVlLCBjb3B5IG9uZSBmaWVsZCdzIHZhbHVlIGludG8gYW5vdGhlci48L3A+XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICA8bWF0LWRpdmlkZXI+PC9tYXQtZGl2aWRlcj5cclxuXHJcbiAgICA8IS0tIFJ1bGVzIGF0dGFjaGVkIHRvIHRoaXMgZmllbGQgLS0+XHJcbiAgICA8bmd4LWZpZWxkLXJ1bGVzLWxpc3QgLz5cclxuXHJcbiAgICA8bWF0LWRpdmlkZXI+PC9tYXQtZGl2aWRlcj5cclxuXHJcbiAgICA8IS0tIENyb3NzLWVudGl0eSBmaWVsZCByZWZlcmVuY2UgJiBkcmlmdCBtYW5hZ2VtZW50IChQaGFzZSA4KSAtLT5cclxuICAgIDxuZ3gtcmVmZXJlbmNlZC1maWVsZC1jb25maWcgLz5cclxuICA8L2Rpdj5cclxufSBAZWxzZSB7XHJcbiAgPGRpdiBjbGFzcz1cImRlYi1pbnNwZWN0b3JfX2VtcHR5XCI+XHJcbiAgICA8bWF0LWljb24+dG91Y2hfYXBwPC9tYXQtaWNvbj5cclxuICAgIDxwPlNlbGVjdCBhIGZpZWxkIHRvIGVkaXQgaXRzIHByb3BlcnRpZXMuPC9wPlxyXG4gIDwvZGl2PlxyXG59XHJcbiJdfQ==
|
|
139
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmllbGQtaW5zcGVjdG9yLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9saWIvY29tcG9uZW50cy9maWVsZC1pbnNwZWN0b3IuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vc3JjL2xpYi9jb21wb25lbnRzL2ZpZWxkLWluc3BlY3Rvci5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsU0FBUyxFQUFFLFFBQVEsRUFBRSxNQUFNLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDNUQsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQzdDLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQUMzRCxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQztBQUMvRCxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSwyQkFBMkIsQ0FBQztBQUM3RCxPQUFPLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSw4QkFBOEIsQ0FBQztBQUNsRSxPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFDdkQsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBQ3pELE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQUMzRCxPQUFPLEVBQUUsb0JBQW9CLEVBQUUsTUFBTSxnQ0FBZ0MsQ0FBQztBQUN0RSxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSwyQkFBMkIsQ0FBQztBQUU3RCxPQUFPLEVBQUUsWUFBWSxFQUFFLGtCQUFrQixFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFDeEUsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLDBCQUEwQixDQUFDO0FBQ3hELE9BQU8sRUFBRSxnQkFBZ0IsRUFBc0IsTUFBTSxrQkFBa0IsQ0FBQztBQUN4RSxPQUFPLEVBQUUsOEJBQThCLEVBQUUs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QkFBOEI7cUJBQy9CIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQ29tcG9uZW50LCBjb21wdXRlZCwgaW5qZWN0IH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBGb3Jtc01vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL2Zvcm1zJztcbmltcG9ydCB7IE1hdEJ1dHRvbk1vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL21hdGVyaWFsL2J1dHRvbic7XG5pbXBvcnQgeyBNYXRDaGVja2JveE1vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL21hdGVyaWFsL2NoZWNrYm94JztcbmltcG9ydCB7IE1hdERpdmlkZXJNb2R1bGUgfSBmcm9tICdAYW5ndWxhci9tYXRlcmlhbC9kaXZpZGVyJztcbmltcG9ydCB7IE1hdEZvcm1GaWVsZE1vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL21hdGVyaWFsL2Zvcm0tZmllbGQnO1xuaW1wb3J0IHsgTWF0SWNvbk1vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL21hdGVyaWFsL2ljb24nO1xuaW1wb3J0IHsgTWF0SW5wdXRNb2R1bGUgfSBmcm9tICdAYW5ndWxhci9tYXRlcmlhbC9pbnB1dCc7XG5pbXBvcnQgeyBNYXRTZWxlY3RNb2R1bGUgfSBmcm9tICdAYW5ndWxhci9tYXRlcmlhbC9zZWxlY3QnO1xuaW1wb3J0IHsgTWF0U2xpZGVUb2dnbGVNb2R1bGUgfSBmcm9tICdAYW5ndWxhci9tYXRlcmlhbC9zbGlkZS10b2dnbGUnO1xuaW1wb3J0IHsgTWF0VG9vbHRpcE1vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL21hdGVyaWFsL3Rvb2x0aXAnO1xuaW1wb3J0IHR5cGUgeyBEcm9wZG93bk9wdGlvbiwgTmVzdGVkRmllbGRDb25maWcgfSBmcm9tICdAZHluYW1pYy1lbnRpdHkvY29yZSc7XG5pbXBvcnQgeyByZXNvbHZlTGFiZWwsIHJlc29sdmVPcHRpb25MYWJlbCB9IGZyb20gJ0BkeW5hbWljLWVudGl0eS9jb3JlJztcbmltcG9ydCB7IEJ1aWxkZXJTdG9yZSB9IGZyb20gJy4uL2J1aWxkZXItc3RvcmUuc2VydmljZSc7XG5pbXBvcnQgeyBnZXRGaWVsZFR5cGVNZXRhLCB0eXBlIEZpZWxkVHlwZU1ldGEgfSBmcm9tICcuLi9maWVsZC1jYXRhbG9nJztcbmltcG9ydCB7IEVudGl0eVJlZmVyZW5jZUNvbmZpZ0NvbXBvbmVudCB9IGZyb20gJy4vZW50aXR5LXJlZmVyZW5jZS1jb25maWcuY29tcG9uZW50JztcbmltcG9ydCB7IEZpZWxkUnVsZXNMaXN0Q29tcG9uZW50IH0gZnJvbSAnLi9maWVsZC1ydWxlcy1saXN0LmNvbXBvbmVudCc7XG5pbXBvcnQgeyBSZWZlcmVuY2VkRmllbGRDb25maWdDb21wb25lbnQgfSBmcm9tICcuL3JlZmVyZW5jZWQtZmllbGQtY29uZmlnLmNvbXBvbmVudCc7XG5cbi8qKlxuICogRmllbGRJbnNwZWN0b3JDb21wb25lbnQg4oCUIGVkaXRzIGV2ZXJ5IHByb3BlcnR5IG9mIHRoZSBjdXJyZW50bHkgc2VsZWN0ZWQgZmllbGQuXG4gKi9cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ25neC1maWVsZC1pbnNwZWN0b3InLFxuICBzdGFuZGFsb25lOiB0cnVlLFxuICBpbXBvcnRzOiBbXG4gICAgRm9ybXNNb2R1bGUsXG4gICAgTWF0QnV0dG9uTW9kdWxlLFxuICAgIE1hdENoZWNrYm94TW9kdWxlLFxuICAgIE1hdERpdmlkZXJNb2R1bGUsXG4gICAgTWF0Rm9ybUZpZWxkTW9kdWxlLFxuICAgIE1hdEljb25Nb2R1bGUsXG4gICAgTWF0SW5wdXRNb2R1bGUsXG4gICAgTWF0U2VsZWN0TW9kdWxlLFxuICAgIE1hdFNsaWRlVG9nZ2xlTW9kdWxlLFxuICAgIE1hdFRvb2x0aXBNb2R1bGUsXG4gICAgRW50aXR5UmVmZXJlbmNlQ29uZmlnQ29tcG9uZW50LFxuICAgIEZpZWxkUnVsZXNMaXN0Q29tcG9uZW50LFxuICAgIFJlZmVyZW5jZWRGaWVsZENvbmZpZ0NvbXBvbmVudCxcbiAgXSxcbiAgdGVtcGxhdGVVcmw6ICcuL2ZpZWxkLWluc3BlY3Rvci5jb21wb25lbnQuaHRtbCcsXG4gIHN0eWxlczogW1xuICAgIGBcbiAgICAgIC5kZWItaW5zcGVjdG9yIHtcbiAgICAgICAgZGlzcGxheTogZmxleDtcbiAgICAgICAgZmxleC1kaXJlY3Rpb246IGNvbHVtbjtcbiAgICAgICAgZ2FwOiAxMnB4O1xuICAgICAgfVxuICAgICAgLmRlYi1pbnNwZWN0b3JfX2VtcHR5IHtcbiAgICAgICAgY29sb3I6IHZhcigtLWRlYi1tdXRlZCwgIzZiNzI4MCk7XG4gICAgICAgIHRleHQtYWxpZ246IGNlbnRlcjtcbiAgICAgICAgcGFkZGluZzogMjRweCA4cHg7XG4gICAgICB9XG4gICAgICAuZGViLWZ1bGwge1xuICAgICAgICB3aWR0aDogMTAwJTtcbiAgICAgIH1cbiAgICAgIC5kZWItcm93IHtcbiAgICAgICAgZGlzcGxheTogZmxleDtcbiAgICAgICAgZ2FwOiA4cHg7XG4gICAgICAgIGFsaWduLWl0ZW1zOiBjZW50ZXI7XG4gICAgICB9XG4gICAgICAuZGViLXJvdyA+ICoge1xuICAgICAgICBmbGV4OiAxO1xuICAgICAgfVxuICAgICAgLmRlYi1yb3ctLXNwbGl0IHtcbiAgICAgICAganVzdGlmeS1jb250ZW50OiBzcGFjZS1iZXR3ZWVuO1xuICAgICAgfVxuICAgICAgLmRlYi1yb3ctLXNwbGl0ID4gKiB7XG4gICAgICAgIGZsZXg6IDAgMCBhdXRvO1xuICAgICAgfVxuICAgICAgLmRlYi10b2dnbGVzIHtcbiAgICAgICAgZGlzcGxheTogZ3JpZDtcbiAgICAgICAgZ3JpZC10ZW1wbGF0ZS1jb2x1bW5zOiAxZnIgMWZyO1xuICAgICAgICBnYXA6IDhweCAxMnB4O1xuICAgICAgfVxuICAgICAgLmRlYi1vcHRpb24tcm93IHtcbiAgICAgICAgZGlzcGxheTogZmxleDtcbiAgICAgICAgZ2FwOiA2cHg7XG4gICAgICAgIGFsaWduLWl0ZW1zOiBjZW50ZXI7XG4gICAgICB9XG4gICAgICAuZGViLWNoaXAge1xuICAgICAgICBkaXNwbGF5OiBpbmxpbmUtYmxvY2s7XG4gICAgICAgIHBhZGRpbmc6IDJweCA4cHg7XG4gICAgICAgIGJvcmRlci1yYWRpdXM6IDEycHg7XG4gICAgICAgIGJhY2tncm91bmQ6IHZhcigtLWRlYi1hY2NlbnQtc29mdCwgI2VlZjJmZik7XG4gICAgICAgIGNvbG9yOiB2YXIoLS1kZWItYWNjZW50LCAjNjM2NmYxKTtcbiAgICAgICAgZm9udC1zaXplOiAxMnB4O1xuICAgICAgICBmb250LXdlaWdodDogNjAwO1xuICAgICAgfVxuICAgIGAsXG4gIF0sXG59KVxuZXhwb3J0IGNsYXNzIEZpZWxkSW5zcGVjdG9yQ29tcG9uZW50IHtcbiAgcHJvdGVjdGVkIHJlYWRvbmx5IHN0b3JlID0gaW5qZWN0KEJ1aWxkZXJTdG9yZSk7XG5cbiAgcHJvdGVjdGVkIHJlYWRvbmx5IGZpZWxkID0gdGhpcy5zdG9yZS5zZWxlY3RlZEZpZWxkO1xuICBwcm90ZWN0ZWQgcmVhZG9ubHkgbWV0YSA9IGNvbXB1dGVkPEZpZWxkVHlwZU1ldGEgfCB1bmRlZmluZWQ+KCgpID0+IHtcbiAgICBjb25zdCBmID0gdGhpcy5maWVsZCgpO1xuICAgIHJldHVybiBmID8gZ2V0RmllbGRUeXBlTWV0YShmLnR5cGUpIDogdW5kZWZpbmVkO1xuICB9KTtcblxuICBwcm90ZWN0ZWQgbGFuZygpOiBzdHJpbmcge1xuICAgIHJldHVybiB0aGlzLnN0b3JlLmFjdGl2ZUxhbmd1YWdlKCk7XG4gIH1cblxuXG4gIHByb3RlY3RlZCB0b051bSh2YWx1ZTogdW5rbm93bik6IG51bWJlciB8IG51bGwge1xuICAgIGlmICh2YWx1ZSA9PT0gJycgfHwgdmFsdWUgPT09IG51bGwgfHwgdmFsdWUgPT09IHVuZGVmaW5lZCkgcmV0dXJuIG51bGw7XG4gICAgY29uc3QgbiA9IE51bWJlcih2YWx1ZSk7XG4gICAgcmV0dXJuIE51bWJlci5pc05hTihuKSA/IG51bGwgOiBuO1xuICB9XG5cbiAgcHJvdGVjdGVkIGxhYmVsVmFsdWUoZmllbGQ6IE5lc3RlZEZpZWxkQ29uZmlnKTogc3RyaW5nIHtcbiAgICByZXR1cm4gcmVzb2x2ZUxhYmVsKGZpZWxkLmxhYmVsLCB0aGlzLmxhbmcoKSk7XG4gIH1cblxuICBwcm90ZWN0ZWQgcGxhY2Vob2xkZXJWYWx1ZShmaWVsZDogTmVzdGVkRmllbGRDb25maWcpOiBzdHJpbmcge1xuICAgIHJldHVybiByZXNvbHZlTGFiZWwoZmllbGQucGxhY2Vob2xkZXIsIHRoaXMubGFuZygpKTtcbiAgfVxuXG4gIHByb3RlY3RlZCBvcHRpb25MYWJlbChvcHRpb246IERyb3Bkb3duT3B0aW9uKTogc3RyaW5nIHtcbiAgICByZXR1cm4gcmVzb2x2ZU9wdGlvbkxhYmVsKG9wdGlvbiwgdGhpcy5sYW5nKCkpO1xuICB9XG5cbiAgLy8g4pSA4pSA4pSAIHNob3dXaGVuIGVkaXRpbmcg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG5cbiAgcHJvdGVjdGVkIHNob3dXaGVuRW50cmllcyhmaWVsZDogTmVzdGVkRmllbGRDb25maWcpOiB7IGtleTogc3RyaW5nOyBkaXNwbGF5OiBzdHJpbmcgfVtdIHtcbiAgICByZXR1cm4gT2JqZWN0LmVudHJpZXMoZmllbGQuc2hvd1doZW4gPz8ge30pLm1hcCgoW2tleSwgdmFsdWVdKSA9PiAoe1xuICAgICAga2V5LFxuICAgICAgZGlzcGxheTogdGhpcy5zdHJpbmdpZnlTaG93V2hlbih2YWx1ZSksXG4gICAgfSkpO1xuICB9XG5cbiAgcHJvdGVjdGVkIGFkZFNob3dXaGVuKGZpZWxkOiBOZXN0ZWRGaWVsZENvbmZpZyk6IHZvaWQge1xuICAgIGNvbnN0IG5leHQgPSB7IC4uLihmaWVsZC5zaG93V2hlbiA/PyB7fSkgfTtcbiAgICBsZXQga2V5ID0gJ2ZpZWxkJztcbiAgICBsZXQgbiA9IDE7XG4gICAgd2hpbGUgKGtleSBpbiBuZXh0KSBrZXkgPSBgZmllbGRfJHsrK259YDtcbiAgICBuZXh0W2tleV0gPSB0cnVlO1xuICAgIHRoaXMuc3RvcmUuc2V0U2hvd1doZW4oZmllbGQuaWQsIG5leHQpO1xuICB9XG5cbiAgcHJvdGVjdGVkIHJlbmFtZVNob3dXaGVuKGZpZWxkOiBOZXN0ZWRGaWVsZENvbmZpZywgb2xkS2V5OiBzdHJpbmcsIG5ld0tleTogc3RyaW5nKTogdm9pZCB7XG4gICAgY29uc3QgdHJpbW1lZCA9IG5ld0tleS50cmltKCk7XG4gICAgaWYgKCF0cmltbWVkIHx8IHRyaW1tZWQgPT09IG9sZEtleSkgcmV0dXJuO1xuICAgIGNvbnN0IGN1cnJlbnQgPSBmaWVsZC5zaG93V2hlbiA/PyB7fTtcbiAgICBpZiAodHJpbW1lZCBpbiBjdXJyZW50KSByZXR1cm47XG4gICAgY29uc3QgbmV4dDogUmVjb3JkPHN0cmluZywgdW5rbm93bj4gPSB7fTtcbiAgICAvLyBSZWJ1aWxkIGluIG9yZGVyIHNvIHRoZSByb3cgZG9lcyBub3QganVtcCB3aGlsZSB0aGUgdXNlciBpcyB0eXBpbmcuXG4gICAgZm9yIChjb25zdCBbaywgdl0gb2YgT2JqZWN0LmVudHJpZXMoY3VycmVudCkpIG5leHRbayA9PT0gb2xkS2V5ID8gdHJpbW1lZCA6IGtdID0gdjtcbiAgICB0aGlzLnN0b3JlLnNldFNob3dXaGVuKGZpZWxkLmlkLCBuZXh0KTtcbiAgfVxuXG4gIHByb3RlY3RlZCBzZXRTaG93V2hlblZhbHVlKGZpZWxkOiBOZXN0ZWRGaWVsZENvbmZpZywga2V5OiBzdHJpbmcsIHJhdzogc3RyaW5nKTogdm9pZCB7XG4gICAgdGhpcy5zdG9yZS5zZXRTaG93V2hlbihmaWVsZC5pZCwgeyAuLi4oZmllbGQuc2hvd1doZW4gPz8ge30pLCBba2V5XTogdGhpcy5wYXJzZVNob3dXaGVuKHJhdykgfSk7XG4gIH1cblxuICBwcm90ZWN0ZWQgcmVtb3ZlU2hvd1doZW4oZmllbGQ6IE5lc3RlZEZpZWxkQ29uZmlnLCBrZXk6IHN0cmluZyk6IHZvaWQge1xuICAgIGNvbnN0IG5leHQgPSB7IC4uLihmaWVsZC5zaG93V2hlbiA/PyB7fSkgfTtcbiAgICBkZWxldGUgbmV4dFtrZXldO1xuICAgIHRoaXMuc3RvcmUuc2V0U2hvd1doZW4oZmllbGQuaWQsIG5leHQpO1xuICB9XG5cbiAgLyoqXG4gICAqIGBzaG93V2hlbmAgY29tcGFyZXMgd2l0aCBgIT09YCwgc28gdGhlIGF1dGhvcmVkIHR5cGUgaGFzIHRvIHN1cnZpdmUgdGhlIHJvdW5kIHRyaXA6XG4gICAqIFwidHJ1ZVwiL1wiZmFsc2VcIiBiZWNvbWUgYm9vbGVhbnMgYW5kIG51bWVyaWMgdGV4dCBiZWNvbWVzIGEgbnVtYmVyLlxuICAgKi9cbiAgcHJpdmF0ZSBwYXJzZVNob3dXaGVuKHJhdzogc3RyaW5nKTogdW5rbm93biB7XG4gICAgY29uc3QgdHJpbW1lZCA9IHJhdy50cmltKCk7XG4gICAgaWYgKHRyaW1tZWQgPT09ICd0cnVlJykgcmV0dXJuIHRydWU7XG4gICAgaWYgKHRyaW1tZWQgPT09ICdmYWxzZScpIHJldHVybiBmYWxzZTtcbiAgICBpZiAodHJpbW1lZCA9PT0gJ251bGwnKSByZXR1cm4gbnVsbDtcbiAgICBpZiAodHJpbW1lZCAhPT0gJycgJiYgIU51bWJlci5pc05hTihOdW1iZXIodHJpbW1lZCkpKSByZXR1cm4gTnVtYmVyKHRyaW1tZWQpO1xuICAgIHJldHVybiByYXc7XG4gIH1cblxuICBwcml2YXRlIHN0cmluZ2lmeVNob3dXaGVuKHZhbHVlOiB1bmtub3duKTogc3RyaW5nIHtcbiAgICBpZiAodmFsdWUgPT09IG51bGwpIHJldHVybiAnbnVsbCc7XG4gICAgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gJ29iamVjdCcpIHJldHVybiBKU09OLnN0cmluZ2lmeSh2YWx1ZSk7XG4gICAgcmV0dXJuIFN0cmluZyh2YWx1ZSk7XG4gIH1cbn1cbiIsIkBpZiAoZmllbGQoKTsgYXMgZikge1xuICA8ZGl2IGNsYXNzPVwiZGViLWluc3BlY3RvclwiPlxuICAgIDwhLS0gSWRlbnRpdHkgLS0+XG4gICAgPGRpdiBjbGFzcz1cImRlYi1yb3dcIj5cbiAgICAgIDxtYXQtZm9ybS1maWVsZCBhcHBlYXJhbmNlPVwib3V0bGluZVwiIHN1YnNjcmlwdFNpemluZz1cImR5bmFtaWNcIj5cbiAgICAgICAgPG1hdC1sYWJlbD5GaWVsZCBpZDwvbWF0LWxhYmVsPlxuICAgICAgICA8aW5wdXQgbWF0SW5wdXQgZGF0YS10ZXN0aWQ9XCJmaWVsZC1pZFwiIFt2YWx1ZV09XCJmLmlkXCIgZGlzYWJsZWQgLz5cbiAgICAgICAgQGlmIChzdG9yZS5oYXNNYW51YWxJZChmLmlkKSkge1xuICAgICAgICAgIDxtYXQtaGludD5UaGUgc3RvcmVkIGRhdGEga2V5IGZvciB0aGlzIHNhdmVkIGZpZWxkIOKAlCBmaXhlZC48L21hdC1oaW50PlxuICAgICAgICB9IEBlbHNlIHtcbiAgICAgICAgICA8bWF0LWhpbnQ+RGVyaXZlZCBmcm9tIHRoZSBsYWJlbC4gVXNlZCBhcyB0aGUgZGF0YSBrZXkuPC9tYXQtaGludD5cbiAgICAgICAgfVxuICAgICAgPC9tYXQtZm9ybS1maWVsZD5cbiAgICAgIDxzcGFuIGNsYXNzPVwiZGViLWNoaXBcIj57eyBtZXRhKCk/LmxhYmVsIHx8IGYudHlwZSB9fTwvc3Bhbj5cbiAgICA8L2Rpdj5cblxuICAgIDwhLS0gTG9jYWxpc2VkIHRleHQgKGFjdGl2ZSBsYW5ndWFnZSkgLS0+XG4gICAgPG1hdC1mb3JtLWZpZWxkIGFwcGVhcmFuY2U9XCJvdXRsaW5lXCIgc3Vic2NyaXB0U2l6aW5nPVwiZHluYW1pY1wiIGNsYXNzPVwiZGViLWZ1bGxcIj5cbiAgICAgIDxtYXQtbGFiZWw+TGFiZWwgKHt7IGxhbmcoKSB9fSk8L21hdC1sYWJlbD5cbiAgICAgIDxpbnB1dFxuICAgICAgICBtYXRJbnB1dFxuICAgICAgICBbbmdNb2RlbF09XCJsYWJlbFZhbHVlKGYpXCJcbiAgICAgICAgKG5nTW9kZWxDaGFuZ2UpPVwic3RvcmUuc2V0RmllbGRMYWJlbChmLmlkLCBsYW5nKCksICRldmVudClcIlxuICAgICAgLz5cbiAgICA8L21hdC1mb3JtLWZpZWxkPlxuXG4gICAgQGlmIChtZXRhKCk/LnN1cHBvcnRzUGxhY2Vob2xkZXIpIHtcbiAgICAgIDxtYXQtZm9ybS1maWVsZCBhcHBlYXJhbmNlPVwib3V0bGluZVwiIHN1YnNjcmlwdFNpemluZz1cImR5bmFtaWNcIiBjbGFzcz1cImRlYi1mdWxsXCI+XG4gICAgICAgIDxtYXQtbGFiZWw+UGxhY2Vob2xkZXIgKHt7IGxhbmcoKSB9fSk8L21hdC1sYWJlbD5cbiAgICAgICAgPGlucHV0XG4gICAgICAgICAgbWF0SW5wdXRcbiAgICAgICAgICBbbmdNb2RlbF09XCJwbGFjZWhvbGRlclZhbHVlKGYpXCJcbiAgICAgICAgICAobmdNb2RlbENoYW5nZSk9XCJzdG9yZS5zZXRGaWVsZFBsYWNlaG9sZGVyKGYuaWQsIGxhbmcoKSwgJGV2ZW50KVwiXG4gICAgICAgIC8+XG4gICAgICA8L21hdC1mb3JtLWZpZWxkPlxuICAgIH1cblxuICAgIEBpZiAobWV0YSgpPy5zdXBwb3J0c0RlZmF1bHRWYWx1ZSkge1xuICAgICAgPG1hdC1mb3JtLWZpZWxkIGFwcGVhcmFuY2U9XCJvdXRsaW5lXCIgc3Vic2NyaXB0U2l6aW5nPVwiZHluYW1pY1wiIGNsYXNzPVwiZGViLWZ1bGxcIj5cbiAgICAgICAgPG1hdC1sYWJlbD5EZWZhdWx0IHZhbHVlPC9tYXQtbGFiZWw+XG4gICAgICAgIDxpbnB1dFxuICAgICAgICAgIG1hdElucHV0XG4gICAgICAgICAgW25nTW9kZWxdPVwiZi5kZWZhdWx0VmFsdWUgPz8gJydcIlxuICAgICAgICAgIChuZ01vZGVsQ2hhbmdlKT1cInN0b3JlLnVwZGF0ZUZpZWxkKGYuaWQsIHsgZGVmYXVsdFZhbHVlOiAkZXZlbnQgfSlcIlxuICAgICAgICAvPlxuICAgICAgPC9tYXQtZm9ybS1maWVsZD5cbiAgICB9XG5cbiAgICA8IS0tIEVudGl0eSByZWZlcmVuY2UsIGNhc2NhZGUsIGFuZCBhdXRvUGF0Y2ggLS0+XG4gICAgQGlmIChtZXRhKCk/LmlzRW50aXR5UmVmKSB7XG4gICAgICA8bWF0LWRpdmlkZXI+PC9tYXQtZGl2aWRlcj5cbiAgICAgIDxuZ3gtZW50aXR5LXJlZmVyZW5jZS1jb25maWcgLz5cbiAgICB9XG5cbiAgICA8bWF0LWRpdmlkZXI+PC9tYXQtZGl2aWRlcj5cblxuICAgIDwhLS0gVmFsaWRhdG9ycyAtLT5cbiAgICBAaWYgKG1ldGEoKTsgYXMgbSkge1xuICAgICAgQGlmIChtLmZsYWdWYWxpZGF0b3JzLmxlbmd0aCB8fCBtLnBhcmFtVmFsaWRhdG9ycy5sZW5ndGgpIHtcbiAgICAgICAgPHNwYW4gY2xhc3M9XCJkZWItc2VjdGlvbi10aXRsZVwiPlZhbGlkYXRpb248L3NwYW4+XG4gICAgICAgIDxkaXYgY2xhc3M9XCJkZWItdG9nZ2xlc1wiPlxuICAgICAgICAgIEBmb3IgKHYgb2YgbS5mbGFnVmFsaWRhdG9yczsgdHJhY2sgdikge1xuICAgICAgICAgICAgPG1hdC1jaGVja2JveFxuICAgICAgICAgICAgICBbbmdNb2RlbF09XCJzdG9yZS5oYXNGbGFnVmFsaWRhdG9yKGYsIHYpXCJcbiAgICAgICAgICAgICAgKG5nTW9kZWxDaGFuZ2UpPVwic3RvcmUudG9nZ2xlRmxhZ1ZhbGlkYXRvcihmLmlkLCB2LCAkZXZlbnQpXCJcbiAgICAgICAgICAgID57eyB2IH19PC9tYXQtY2hlY2tib3g+XG4gICAgICAgICAgfVxuICAgICAgICA8L2Rpdj5cbiAgICAgICAgQGZvciAodiBvZiBtLnBhcmFtVmFsaWRhdG9yczsgdHJhY2sgdikge1xuICAgICAgICAgIDxtYXQtZm9ybS1maWVsZCBhcHBlYXJhbmNlPVwib3V0bGluZVwiIHN1YnNjcmlwdFNpemluZz1cImR5bmFtaWNcIiBjbGFzcz1cImRlYi1mdWxsXCI+XG4gICAgICAgICAgICA8bWF0LWxhYmVsPnt7IHYgfX08L21hdC1sYWJlbD5cbiAgICAgICAgICAgIDxpbnB1dFxuICAgICAgICAgICAgICBtYXRJbnB1dFxuICAgICAgICAgICAgICB0eXBlPVwibnVtYmVyXCJcbiAgICAgICAgICAgICAgW25nTW9kZWxdPVwic3RvcmUuZ2V0UGFyYW1WYWxpZGF0b3IoZiwgdilcIlxuICAgICAgICAgICAgICAobmdNb2RlbENoYW5nZSk9XCJzdG9yZS5zZXRQYXJhbVZhbGlkYXRvcihmLmlkLCB2LCB0b051bSgkZXZlbnQpKVwiXG4gICAgICAgICAgICAvPlxuICAgICAgICAgIDwvbWF0LWZvcm0tZmllbGQ+XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG5cbiAgICA8IS0tIE9wdGlvbnMgKGRyb3Bkb3duIC8gcmFkaW8gLyBtdWx0aVNlbGVjdCkgLS0+XG4gICAgQGlmIChtZXRhKCk/Lmhhc09wdGlvbnMpIHtcbiAgICAgIDxtYXQtZGl2aWRlcj48L21hdC1kaXZpZGVyPlxuICAgICAgPHNwYW4gY2xhc3M9XCJkZWItc2VjdGlvbi10aXRsZVwiPkRhdGEgc291cmNlPC9zcGFuPlxuICAgICAgPG1hdC1mb3JtLWZpZWxkIGFwcGVhcmFuY2U9XCJvdXRsaW5lXCIgc3Vic2NyaXB0U2l6aW5nPVwiZHluYW1pY1wiIGNsYXNzPVwiZGViLWZ1bGxcIj5cbiAgICAgICAgPG1hdC1sYWJlbD5PcHRpb25zIGNvbWUgZnJvbTwvbWF0LWxhYmVsPlxuICAgICAgICA8bWF0LXNlbGVjdFxuICAgICAgICAgIGRhdGEtdGVzdGlkPVwiZGF0YS1zb3VyY2VcIlxuICAgICAgICAgIFtuZ01vZGVsXT1cInN0b3JlLmZpZWxkRGF0YVNvdXJjZShmKVwiXG4gICAgICAgICAgKG5nTW9kZWxDaGFuZ2UpPVwic3RvcmUuc2V0RmllbGREYXRhU291cmNlKGYuaWQsICRldmVudClcIlxuICAgICAgICA+XG4gICAgICAgICAgPG1hdC1vcHRpb24gdmFsdWU9XCJub25lXCI+Tm90aGluZyB5ZXQ8L21hdC1vcHRpb24+XG4gICAgICAgICAgPG1hdC1vcHRpb24gdmFsdWU9XCJtYW51YWxcIj5PcHRpb25zIGF1dGhvcmVkIGhlcmU8L21hdC1vcHRpb24+XG4gICAgICAgICAgPG1hdC1vcHRpb24gdmFsdWU9XCJsb29rdXBcIj5BIG5hbWVkIGxpc3Q8L21hdC1vcHRpb24+XG4gICAgICAgIDwvbWF0LXNlbGVjdD5cbiAgICAgIDwvbWF0LWZvcm0tZmllbGQ+XG4gICAgfVxuXG4gICAgPCEtLSBOYW1lZCBsb29rdXAgbGlzdCAtLT5cbiAgICBAaWYgKG1ldGEoKT8uaGFzT3B0aW9ucyAmJiBzdG9yZS5maWVsZERhdGFTb3VyY2UoZikgPT09ICdsb29rdXAnKSB7XG4gICAgICA8bWF0LWZvcm0tZmllbGQgYXBwZWFyYW5jZT1cIm91dGxpbmVcIiBzdWJzY3JpcHRTaXppbmc9XCJkeW5hbWljXCIgY2xhc3M9XCJkZWItZnVsbFwiPlxuICAgICAgICA8bWF0LWxhYmVsPkxpc3QgbmFtZTwvbWF0LWxhYmVsPlxuICAgICAgICA8aW5wdXRcbiAgICAgICAgICBtYXRJbnB1dFxuICAgICAgICAgIGRhdGEtdGVzdGlkPVwibGlzdC1uYW1lXCJcbiAgICAgICAgICBbbmdNb2RlbF09XCJmLmxpc3ROYW1lID8/ICcnXCJcbiAgICAgICAgICAobmdNb2RlbENoYW5nZSk9XCJzdG9yZS5zZXRMaXN0TmFtZShmLmlkLCAkZXZlbnQpXCJcbiAgICAgICAgLz5cbiAgICAgIDwvbWF0LWZvcm0tZmllbGQ+XG4gICAgICA8cCBjbGFzcz1cImRlYi1oaW50XCI+XG4gICAgICAgIFRoZSBjb25zdW1pbmcgYXBwIHJlc29sdmVzIHRoaXMgbmFtZSB0aHJvdWdoIGl0cyBsb29rdXAgcmVnaXN0cnkuIE9wdGlvbnMgYXJlIG5vdFxuICAgICAgICBhdXRob3JlZCBoZXJlLlxuICAgICAgPC9wPlxuICAgIH1cblxuICAgIDwhLS0gSW5saW5lIG9wdGlvbnMgLS0+XG4gICAgQGlmIChtZXRhKCk/Lmhhc09wdGlvbnMgJiYgc3RvcmUuZmllbGREYXRhU291cmNlKGYpICE9PSAnbG9va3VwJykge1xuICAgICAgPGRpdiBjbGFzcz1cImRlYi1yb3dcIiBzdHlsZT1cImp1c3RpZnktY29udGVudDogc3BhY2UtYmV0d2VlbjtcIj5cbiAgICAgICAgPHNwYW4gY2xhc3M9XCJkZWItc2VjdGlvbi10aXRsZVwiPk9wdGlvbnM8L3NwYW4+XG4gICAgICAgIDxidXR0b24gbWF0LXN0cm9rZWQtYnV0dG9uIHR5cGU9XCJidXR0b25cIiAoY2xpY2spPVwic3RvcmUuYWRkT3B0aW9uKGYuaWQpXCI+XG4gICAgICAgICAgPG1hdC1pY29uPmFkZDwvbWF0LWljb24+IE9wdGlvblxuICAgICAgICA8L2J1dHRvbj5cbiAgICAgIDwvZGl2PlxuICAgICAgQGZvciAob3B0IG9mIGYub3B0aW9ucyA/PyBbXTsgdHJhY2sgJGluZGV4KSB7XG4gICAgICAgIDxkaXYgY2xhc3M9XCJkZWItb3B0aW9uLXJvd1wiIGRhdGEtdGVzdGlkPVwib3B0aW9uLXJvd1wiPlxuICAgICAgICAgIDwhLS0gT25lIGlucHV0OiB0aGUgZGlzcGxheWVkIHRleHQgaXMgdGhlIHN0b3JlZCB2YWx1ZS4gLS0+XG4gICAgICAgICAgPG1hdC1mb3JtLWZpZWxkIGFwcGVhcmFuY2U9XCJvdXRsaW5lXCIgc3Vic2NyaXB0U2l6aW5nPVwiZHluYW1pY1wiIGNsYXNzPVwiZGViLWZ1bGxcIj5cbiAgICAgICAgICAgIDxtYXQtbGFiZWw+T3B0aW9uICh7eyBsYW5nKCkgfX0pPC9tYXQtbGFiZWw+XG4gICAgICAgICAgICA8aW5wdXRcbiAgICAgICAgICAgICAgbWF0SW5wdXRcbiAgICAgICAgICAgICAgW2F0dHIuZGF0YS10ZXN0aWRdPVwiJ29wdGlvbi0nICsgJGluZGV4XCJcbiAgICAgICAgICAgICAgW25nTW9kZWxdPVwib3B0aW9uTGFiZWwob3B0KVwiXG4gICAgICAgICAgICAgIChuZ01vZGVsQ2hhbmdlKT1cInN0b3JlLnNldE9wdGlvbkxhYmVsKGYuaWQsICRpbmRleCwgbGFuZygpLCAkZXZlbnQpXCJcbiAgICAgICAgICAgIC8+XG4gICAgICAgICAgPC9tYXQtZm9ybS1maWVsZD5cbiAgICAgICAgICA8YnV0dG9uIG1hdC1pY29uLWJ1dHRvbiB0eXBlPVwiYnV0dG9uXCIgY29sb3I9XCJ3YXJuXCJcbiAgICAgICAgICAgIChjbGljayk9XCJzdG9yZS5yZW1vdmVPcHRpb24oZi5pZCwgJGluZGV4KVwiIG1hdFRvb2x0aXA9XCJSZW1vdmUgb3B0aW9uXCI+XG4gICAgICAgICAgICA8bWF0LWljb24+ZGVsZXRlPC9tYXQtaWNvbj5cbiAgICAgICAgICA8L2J1dHRvbj5cbiAgICAgICAgPC9kaXY+XG4gICAgICB9XG4gICAgICBAaWYgKCEoZi5vcHRpb25zID8/IFtdKS5sZW5ndGgpIHtcbiAgICAgICAgPHAgY2xhc3M9XCJkZWItaGludFwiPk5vIG9wdGlvbnMgeWV0IOKAlCBhZGQgYXQgbGVhc3Qgb25lLjwvcD5cbiAgICAgIH1cbiAgICB9XG5cbiAgICA8bWF0LWRpdmlkZXI+PC9tYXQtZGl2aWRlcj5cblxuICAgIDwhLS0gRmxhZ3MgLS0+XG4gICAgPHNwYW4gY2xhc3M9XCJkZWItc2VjdGlvbi10aXRsZVwiPkRpc3BsYXk8L3NwYW4+XG4gICAgPGRpdiBjbGFzcz1cImRlYi10b2dnbGVzXCI+XG4gICAgICA8bWF0LXNsaWRlLXRvZ2dsZVxuICAgICAgICBbbmdNb2RlbF09XCJmLnZpc2liaWxpdHkgPz8gdHJ1ZVwiXG4gICAgICAgIChuZ01vZGVsQ2hhbmdlKT1cInN0b3JlLnVwZGF0ZUZpZWxkKGYuaWQsIHsgdmlzaWJpbGl0eTogJGV2ZW50IH0pXCJcbiAgICAgID5WaXNpYmxlPC9tYXQtc2xpZGUtdG9nZ2xlPlxuICAgICAgPG1hdC1zbGlkZS10b2dnbGVcbiAgICAgICAgW25nTW9kZWxdPVwiZi50YWJsZT8udmlzaWJsZSA/PyBmYWxzZVwiXG4gICAgICAgIChuZ01vZGVsQ2hhbmdlKT1cInN0b3JlLnVwZGF0ZUZpZWxkKGYuaWQsIHsgdGFibGU6IHsgdmlzaWJsZTogJGV2ZW50IH0gfSlcIlxuICAgICAgPlRhYmxlIGNvbHVtbjwvbWF0LXNsaWRlLXRvZ2dsZT5cbiAgICAgIDxtYXQtc2xpZGUtdG9nZ2xlXG4gICAgICAgIFtuZ01vZGVsXT1cImYucmVhZG9ubHkgPz8gZmFsc2VcIlxuICAgICAgICAobmdNb2RlbENoYW5nZSk9XCJzdG9yZS51cGRhdGVGaWVsZChmLmlkLCB7IHJlYWRvbmx5OiAkZXZlbnQgfSlcIlxuICAgICAgPlJlYWQtb25seTwvbWF0LXNsaWRlLXRvZ2dsZT5cbiAgICAgIDxtYXQtc2xpZGUtdG9nZ2xlXG4gICAgICAgIFtuZ01vZGVsXT1cImYuZGlzYWJsZWQgPz8gZmFsc2VcIlxuICAgICAgICAobmdNb2RlbENoYW5nZSk9XCJzdG9yZS51cGRhdGVGaWVsZChmLmlkLCB7IGRpc2FibGVkOiAkZXZlbnQgfSlcIlxuICAgICAgPkRpc2FibGVkPC9tYXQtc2xpZGUtdG9nZ2xlPlxuICAgICAgPG1hdC1zbGlkZS10b2dnbGVcbiAgICAgICAgW25nTW9kZWxdPVwiZi5tYXNrRGF0YSA/PyBmYWxzZVwiXG4gICAgICAgIChuZ01vZGVsQ2hhbmdlKT1cInN0b3JlLnVwZGF0ZUZpZWxkKGYuaWQsIHsgbWFza0RhdGE6ICRldmVudCB9KVwiXG4gICAgICA+TWFzayBkYXRhIChSQkFDKTwvbWF0LXNsaWRlLXRvZ2dsZT5cbiAgICAgIDxtYXQtc2xpZGUtdG9nZ2xlXG4gICAgICAgIGRhdGEtdGVzdGlkPVwidG9nZ2xlLWNyaXRpY2FsXCJcbiAgICAgICAgW25nTW9kZWxdPVwiZi5jcml0aWNhbEZpZWxkID8/IGZhbHNlXCJcbiAgICAgICAgKG5nTW9kZWxDaGFuZ2UpPVwic3RvcmUudXBkYXRlRmllbGQoZi5pZCwgeyBjcml0aWNhbEZpZWxkOiAkZXZlbnQgfSlcIlxuICAgICAgICBtYXRUb29sdGlwPVwiUmVuZGVycyBsb2NrZWQ7IGVkaXRpbmcgaXQgYW5ub3VuY2VzIGEgY2hhbmdlIGFnYWluc3QgdGhlIHNlc3Npb24gYmFzZWxpbmUuXCJcbiAgICAgID5Dcml0aWNhbCBmaWVsZDwvbWF0LXNsaWRlLXRvZ2dsZT5cbiAgICAgIDxtYXQtc2xpZGUtdG9nZ2xlXG4gICAgICAgIFtuZ01vZGVsXT1cImYuc2hvd09uTWluaW1pemUgPz8gZmFsc2VcIlxuICAgICAgICAobmdNb2RlbENoYW5nZSk9XCJzdG9yZS51cGRhdGVGaWVsZChmLmlkLCB7IHNob3dPbk1pbmltaXplOiAkZXZlbnQgfSlcIlxuICAgICAgICBtYXRUb29sdGlwPVwiU2hvd24gaW4gdGhlIHJlY29yZCBlZGl0b3IncyBzdW1tYXJ5IHBhbmVsLlwiXG4gICAgICA+U2hvdyBpbiBzdW1tYXJ5PC9tYXQtc2xpZGUtdG9nZ2xlPlxuICAgIDwvZGl2PlxuXG4gICAgPG1hdC1kaXZpZGVyPjwvbWF0LWRpdmlkZXI+XG5cbiAgICA8IS0tIENvbmRpdGlvbmFsIHZpc2liaWxpdHkgKHN0YXRpYyBzaG93V2hlbikgLS0+XG4gICAgPGRpdiBjbGFzcz1cImRlYi1yb3cgZGViLXJvdy0tc3BsaXRcIj5cbiAgICAgIDxzcGFuIGNsYXNzPVwiZGViLXNlY3Rpb24tdGl0bGVcIj5TaG93IHdoZW48L3NwYW4+XG4gICAgICA8YnV0dG9uIG1hdC1zdHJva2VkLWJ1dHRvbiB0eXBlPVwiYnV0dG9uXCIgZGF0YS10ZXN0aWQ9XCJhZGQtc2hvdy13aGVuXCIgKGNsaWNrKT1cImFkZFNob3dXaGVuKGYpXCI+XG4gICAgICAgIDxtYXQtaWNvbj5hZGQ8L21hdC1pY29uPiBDb25kaXRpb25cbiAgICAgIDwvYnV0dG9uPlxuICAgIDwvZGl2PlxuICAgIEBmb3IgKGVudHJ5IG9mIHNob3dXaGVuRW50cmllcyhmKTsgdHJhY2sgZW50cnkua2V5KSB7XG4gICAgICA8ZGl2IGNsYXNzPVwiZGViLW9wdGlvbi1yb3dcIiBkYXRhLXRlc3RpZD1cIm9wdGlvbi1yb3dcIj5cbiAgICAgICAgPG1hdC1mb3JtLWZpZWxkIGFwcGVhcmFuY2U9XCJvdXRsaW5lXCIgc3Vic2NyaXB0U2l6aW5nPVwiZHluYW1pY1wiPlxuICAgICAgICAgIDxtYXQtbGFiZWw+RmllbGQgaWQ8L21hdC1sYWJlbD5cbiAgICAgICAgICA8aW5wdXQgbWF0SW5wdXQgW25nTW9kZWxdPVwiZW50cnkua2V5XCIgKG5nTW9kZWxDaGFuZ2UpPVwicmVuYW1lU2hvd1doZW4oZiwgZW50cnkua2V5LCAkZXZlbnQpXCIgLz5cbiAgICAgICAgPC9tYXQtZm9ybS1maWVsZD5cbiAgICAgICAgPG1hdC1mb3JtLWZpZWxkIGFwcGVhcmFuY2U9XCJvdXRsaW5lXCIgc3Vic2NyaXB0U2l6aW5nPVwiZHluYW1pY1wiPlxuICAgICAgICAgIDxtYXQtbGFiZWw+RXF1YWxzPC9tYXQtbGFiZWw+XG4gICAgICAgICAgPGlucHV0IG1hdElucHV0IFtuZ01vZGVsXT1cImVudHJ5LmRpc3BsYXlcIiAobmdNb2RlbENoYW5nZSk9XCJzZXRTaG93V2hlblZhbHVlKGYsIGVudHJ5LmtleSwgJGV2ZW50KVwiIC8+XG4gICAgICAgIDwvbWF0LWZvcm0tZmllbGQ+XG4gICAgICAgIDxidXR0b24gbWF0LWljb24tYnV0dG9uIHR5cGU9XCJidXR0b25cIiBjb2xvcj1cIndhcm5cIiBtYXRUb29sdGlwPVwiUmVtb3ZlIGNvbmRpdGlvblwiXG4gICAgICAgICAgKGNsaWNrKT1cInJlbW92ZVNob3dXaGVuKGYsIGVudHJ5LmtleSlcIj5cbiAgICAgICAgICA8bWF0LWljb24+ZGVsZXRlPC9tYXQtaWNvbj5cbiAgICAgICAgPC9idXR0b24+XG4gICAgICA8L2Rpdj5cbiAgICB9XG4gICAgQGlmICghc2hvd1doZW5FbnRyaWVzKGYpLmxlbmd0aCkge1xuICAgICAgPHAgY2xhc3M9XCJkZWItaGludFwiPkFsd2F5cyB2aXNpYmxlLiBBZGQgYSBjb25kaXRpb24gdG8gc2hvdyB0aGlzIGZpZWxkIG9ubHkgZm9yIGNlcnRhaW4gdmFsdWVzLjwvcD5cbiAgICB9XG5cbiAgICA8IS0tIHBhdGNoT25UcnVlIChib29sZWFuL2NoZWNrYm94IG9ubHkpIC0tPlxuICAgIEBpZiAoZi50eXBlID09PSAnYm9vbGVhbicgfHwgZi50eXBlID09PSAnY2hlY2tib3gnKSB7XG4gICAgICA8bWF0LWRpdmlkZXI+PC9tYXQtZGl2aWRlcj5cbiAgICAgIDxkaXYgY2xhc3M9XCJkZWItcm93IGRlYi1yb3ctLXNwbGl0XCI+XG4gICAgICAgIDxzcGFuIGNsYXNzPVwiZGViLXNlY3Rpb24tdGl0bGVcIj5Db3B5IG9uIHRydWU8L3NwYW4+XG4gICAgICAgIDxidXR0b24gbWF0LXN0cm9rZWQtYnV0dG9uIHR5cGU9XCJidXR0b25cIiBkYXRhLXRlc3RpZD1cImFkZC1wYXRjaC1vbi10cnVlXCJcbiAgICAgICAgICAoY2xpY2spPVwic3RvcmUuYWRkUGF0Y2hPblRydWVNYXBwaW5nKGYuaWQpXCI+XG4gICAgICAgICAgPG1hdC1pY29uPmFkZDwvbWF0LWljb24+IE1hcHBpbmdcbiAgICAgICAgPC9idXR0b24+XG4gICAgICA8L2Rpdj5cbiAgICAgIEBmb3IgKG1hcHBpbmcgb2YgZi5wYXRjaE9uVHJ1ZSA/PyBbXTsgdHJhY2sgJGluZGV4KSB7XG4gICAgICAgIDxkaXYgY2xhc3M9XCJkZWItb3B0aW9uLXJvd1wiIGRhdGEtdGVzdGlkPVwib3B0aW9uLXJvd1wiPlxuICAgICAgICAgIDxtYXQtZm9ybS1maWVsZCBhcHBlYXJhbmNlPVwib3V0bGluZVwiIHN1YnNjcmlwdFNpemluZz1cImR5bmFtaWNcIj5cbiAgICAgICAgICAgIDxtYXQtbGFiZWw+RnJvbSBmaWVsZDwvbWF0LWxhYmVsPlxuICAgICAgICAgICAgPGlucHV0IG1hdElucHV0IFtuZ01vZGVsXT1cIm1hcHBpbmcuZnJvbVwiXG4gICAgICAgICAgICAgIChuZ01vZGVsQ2hhbmdlKT1cInN0b3JlLnVwZGF0ZVBhdGNoT25UcnVlTWFwcGluZyhmLmlkLCAkaW5kZXgsIHsgZnJvbTogJGV2ZW50IH0pXCIgLz5cbiAgICAgICAgICA8L21hdC1mb3JtLWZpZWxkPlxuICAgICAgICAgIDxtYXQtZm9ybS1maWVsZCBhcHBlYXJhbmNlPVwib3V0bGluZVwiIHN1YnNjcmlwdFNpemluZz1cImR5bmFtaWNcIj5cbiAgICAgICAgICAgIDxtYXQtbGFiZWw+VG8gZmllbGQ8L21hdC1sYWJlbD5cbiAgICAgICAgICAgIDxpbnB1dCBtYXRJbnB1dCBbbmdNb2RlbF09XCJtYXBwaW5nLnRvXCJcbiAgICAgICAgICAgICAgKG5nTW9kZWxDaGFuZ2UpPVwic3RvcmUudXBkYXRlUGF0Y2hPblRydWVNYXBwaW5nKGYuaWQsICRpbmRleCwgeyB0bzogJGV2ZW50IH0pXCIgLz5cbiAgICAgICAgICA8L21hdC1mb3JtLWZpZWxkPlxuICAgICAgICAgIDxidXR0b24gbWF0LWljb24tYnV0dG9uIHR5cGU9XCJidXR0b25cIiBjb2xvcj1cIndhcm5cIiBtYXRUb29sdGlwPVwiUmVtb3ZlIG1hcHBpbmdcIlxuICAgICAgICAgICAgKGNsaWNrKT1cInN0b3JlLnJlbW92ZVBhdGNoT25UcnVlTWFwcGluZyhmLmlkLCAkaW5kZXgpXCI+XG4gICAgICAgICAgICA8bWF0LWljb24+ZGVsZXRlPC9tYXQtaWNvbj5cbiAgICAgICAgICA8L2J1dHRvbj5cbiAgICAgICAgPC9kaXY+XG4gICAgICB9XG4gICAgICBAaWYgKCEoZi5wYXRjaE9uVHJ1ZSA/PyBbXSkubGVuZ3RoKSB7XG4gICAgICAgIDxwIGNsYXNzPVwiZGViLWhpbnRcIj5XaGVuIHRoaXMgZmxpcHMgdG8gdHJ1ZSwgY29weSBvbmUgZmllbGQncyB2YWx1ZSBpbnRvIGFub3RoZXIuPC9wPlxuICAgICAgfVxuICAgIH1cblxuICAgIDxtYXQtZGl2aWRlcj48L21hdC1kaXZpZGVyPlxuXG4gICAgPCEtLSBSdWxlcyBhdHRhY2hlZCB0byB0aGlzIGZpZWxkIC0tPlxuICAgIDxuZ3gtZmllbGQtcnVsZXMtbGlzdCAvPlxuXG4gICAgPG1hdC1kaXZpZGVyPjwvbWF0LWRpdmlkZXI+XG5cbiAgICA8IS0tIENyb3NzLWVudGl0eSBmaWVsZCByZWZlcmVuY2UgJiBkcmlmdCBtYW5hZ2VtZW50IChQaGFzZSA4KSAtLT5cbiAgICA8bmd4LXJlZmVyZW5jZWQtZmllbGQtY29uZmlnIC8+XG4gIDwvZGl2PlxufSBAZWxzZSB7XG4gIDxkaXYgY2xhc3M9XCJkZWItaW5zcGVjdG9yX19lbXB0eVwiPlxuICAgIDxtYXQtaWNvbj50b3VjaF9hcHA8L21hdC1pY29uPlxuICAgIDxwPlNlbGVjdCBhIGZpZWxkIHRvIGVkaXQgaXRzIHByb3BlcnRpZXMuPC9wPlxuICA8L2Rpdj5cbn1cbiJdfQ==
|
|
@@ -14,44 +14,44 @@ export class FieldPaletteComponent {
|
|
|
14
14
|
catalog = FIELD_TYPE_CATALOG;
|
|
15
15
|
pick = new EventEmitter();
|
|
16
16
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: FieldPaletteComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
17
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.12", type: FieldPaletteComponent, isStandalone: true, selector: "ngx-field-palette", outputs: { pick: "pick" }, ngImport: i0, template: `
|
|
18
|
-
<div class="deb-palette">
|
|
19
|
-
@for (meta of catalog; track meta.type) {
|
|
20
|
-
<button
|
|
21
|
-
mat-stroked-button
|
|
22
|
-
type="button"
|
|
23
|
-
class="deb-palette__item"
|
|
24
|
-
[attr.data-testid]="'palette-' + meta.type"
|
|
25
|
-
[matTooltip]="meta.description"
|
|
26
|
-
(click)="pick.emit(meta.type)"
|
|
27
|
-
>
|
|
28
|
-
<mat-icon>{{ meta.icon }}</mat-icon>
|
|
29
|
-
<span>{{ meta.label }}</span>
|
|
30
|
-
</button>
|
|
31
|
-
}
|
|
32
|
-
</div>
|
|
17
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.12", type: FieldPaletteComponent, isStandalone: true, selector: "ngx-field-palette", outputs: { pick: "pick" }, ngImport: i0, template: `
|
|
18
|
+
<div class="deb-palette">
|
|
19
|
+
@for (meta of catalog; track meta.type) {
|
|
20
|
+
<button
|
|
21
|
+
mat-stroked-button
|
|
22
|
+
type="button"
|
|
23
|
+
class="deb-palette__item"
|
|
24
|
+
[attr.data-testid]="'palette-' + meta.type"
|
|
25
|
+
[matTooltip]="meta.description"
|
|
26
|
+
(click)="pick.emit(meta.type)"
|
|
27
|
+
>
|
|
28
|
+
<mat-icon>{{ meta.icon }}</mat-icon>
|
|
29
|
+
<span>{{ meta.label }}</span>
|
|
30
|
+
</button>
|
|
31
|
+
}
|
|
32
|
+
</div>
|
|
33
33
|
`, isInline: true, styles: [".deb-palette{display:grid;grid-template-columns:1fr 1fr;gap:8px}.deb-palette__item{justify-content:flex-start;overflow:hidden;border-radius:8px!important;border:1px solid var(--border, #e2e8f0)!important;padding:8px 12px!important;font-family:var(--font-heading, inherit)!important;font-weight:600!important;font-size:13px!important;transition:all .18s cubic-bezier(.16,1,.3,1)!important;background:#fff!important}.deb-palette__item:hover{border-color:#6366f1!important;background:#f5f3ff!important;color:#4f46e5!important;transform:translateY(-1px);box-shadow:0 4px 12px #6366f126!important}.deb-palette__item mat-icon{color:#6366f1;margin-right:6px;font-size:18px;width:18px;height:18px}.deb-palette__item span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n"], dependencies: [{ kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i1.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i2.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i3.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }] });
|
|
34
34
|
}
|
|
35
35
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: FieldPaletteComponent, decorators: [{
|
|
36
36
|
type: Component,
|
|
37
|
-
args: [{ selector: 'ngx-field-palette', standalone: true, imports: [MatButtonModule, MatIconModule, MatTooltipModule], template: `
|
|
38
|
-
<div class="deb-palette">
|
|
39
|
-
@for (meta of catalog; track meta.type) {
|
|
40
|
-
<button
|
|
41
|
-
mat-stroked-button
|
|
42
|
-
type="button"
|
|
43
|
-
class="deb-palette__item"
|
|
44
|
-
[attr.data-testid]="'palette-' + meta.type"
|
|
45
|
-
[matTooltip]="meta.description"
|
|
46
|
-
(click)="pick.emit(meta.type)"
|
|
47
|
-
>
|
|
48
|
-
<mat-icon>{{ meta.icon }}</mat-icon>
|
|
49
|
-
<span>{{ meta.label }}</span>
|
|
50
|
-
</button>
|
|
51
|
-
}
|
|
52
|
-
</div>
|
|
37
|
+
args: [{ selector: 'ngx-field-palette', standalone: true, imports: [MatButtonModule, MatIconModule, MatTooltipModule], template: `
|
|
38
|
+
<div class="deb-palette">
|
|
39
|
+
@for (meta of catalog; track meta.type) {
|
|
40
|
+
<button
|
|
41
|
+
mat-stroked-button
|
|
42
|
+
type="button"
|
|
43
|
+
class="deb-palette__item"
|
|
44
|
+
[attr.data-testid]="'palette-' + meta.type"
|
|
45
|
+
[matTooltip]="meta.description"
|
|
46
|
+
(click)="pick.emit(meta.type)"
|
|
47
|
+
>
|
|
48
|
+
<mat-icon>{{ meta.icon }}</mat-icon>
|
|
49
|
+
<span>{{ meta.label }}</span>
|
|
50
|
+
</button>
|
|
51
|
+
}
|
|
52
|
+
</div>
|
|
53
53
|
`, styles: [".deb-palette{display:grid;grid-template-columns:1fr 1fr;gap:8px}.deb-palette__item{justify-content:flex-start;overflow:hidden;border-radius:8px!important;border:1px solid var(--border, #e2e8f0)!important;padding:8px 12px!important;font-family:var(--font-heading, inherit)!important;font-weight:600!important;font-size:13px!important;transition:all .18s cubic-bezier(.16,1,.3,1)!important;background:#fff!important}.deb-palette__item:hover{border-color:#6366f1!important;background:#f5f3ff!important;color:#4f46e5!important;transform:translateY(-1px);box-shadow:0 4px 12px #6366f126!important}.deb-palette__item mat-icon{color:#6366f1;margin-right:6px;font-size:18px;width:18px;height:18px}.deb-palette__item span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n"] }]
|
|
54
54
|
}], propDecorators: { pick: [{
|
|
55
55
|
type: Output
|
|
56
56
|
}] } });
|
|
57
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
57
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmllbGQtcGFsZXR0ZS5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvbGliL2NvbXBvbmVudHMvZmllbGQtcGFsZXR0ZS5jb21wb25lbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFNBQVMsRUFBRSxZQUFZLEVBQUUsTUFBTSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQ2hFLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQUMzRCxPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFDdkQsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sMkJBQTJCLENBQUM7QUFFN0QsT0FBTyxFQUFFLGtCQUFrQixFQUFzQixNQUFNLGtCQUFrQixDQUFDOzs7OztBQUUxRTs7R0FFRztBQStESCxNQUFNLE9BQU8scUJBQXFCO0lBQ3ZCLE9BQU8sR0FBNkIsa0JBQWtCLENBQUM7SUFFdEQsSUFBSSxHQUFHLElBQUksWUFBWSxFQUFpQixDQUFDO3dHQUh4QyxxQkFBcUI7NEZBQXJCLHFCQUFxQix3R0ExRHRCOzs7Ozs7Ozs7Ozs7Ozs7O0dBZ0JULDgwQkFqQlMsZUFBZSwyTkFBRSxhQUFhLG1MQUFFLGdCQUFnQjs7NEZBMkQvQyxxQkFBcUI7a0JBOURqQyxTQUFTOytCQUNFLG1CQUFtQixjQUNqQixJQUFJLFdBQ1AsQ0FBQyxlQUFlLEVBQUUsYUFBYSxFQUFFLGdCQUFnQixDQUFDLFlBQ2pEOzs7Ozs7Ozs7Ozs7Ozs7O0dBZ0JUOzhCQTZDUyxJQUFJO3NCQUFiLE1BQU0iLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDb21wb25lbnQsIEV2ZW50RW1pdHRlciwgT3V0cHV0IH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBNYXRCdXR0b25Nb2R1bGUgfSBmcm9tICdAYW5ndWxhci9tYXRlcmlhbC9idXR0b24nO1xuaW1wb3J0IHsgTWF0SWNvbk1vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL21hdGVyaWFsL2ljb24nO1xuaW1wb3J0IHsgTWF0VG9vbHRpcE1vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL21hdGVyaWFsL3Rvb2x0aXAnO1xuaW1wb3J0IHR5cGUgeyBSaWNoRmllbGRUeXBlIH0gZnJvbSAnQGR5bmFtaWMtZW50aXR5L2NvcmUnO1xuaW1wb3J0IHsgRklFTERfVFlQRV9DQVRBTE9HLCB0eXBlIEZpZWxkVHlwZU1ldGEgfSBmcm9tICcuLi9maWVsZC1jYXRhbG9nJztcblxuLyoqXG4gKiBGaWVsZFBhbGV0dGVDb21wb25lbnQg4oCUIHRoZSBsaXN0IG9mIGJ1aWxkYWJsZSBmaWVsZCB0eXBlcyAoQW5ndWxhciBNYXRlcmlhbCkuXG4gKi9cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ25neC1maWVsZC1wYWxldHRlJyxcbiAgc3RhbmRhbG9uZTogdHJ1ZSxcbiAgaW1wb3J0czogW01hdEJ1dHRvbk1vZHVsZSwgTWF0SWNvbk1vZHVsZSwgTWF0VG9vbHRpcE1vZHVsZV0sXG4gIHRlbXBsYXRlOiBgXG4gICAgPGRpdiBjbGFzcz1cImRlYi1wYWxldHRlXCI+XG4gICAgICBAZm9yIChtZXRhIG9mIGNhdGFsb2c7IHRyYWNrIG1ldGEudHlwZSkge1xuICAgICAgICA8YnV0dG9uXG4gICAgICAgICAgbWF0LXN0cm9rZWQtYnV0dG9uXG4gICAgICAgICAgdHlwZT1cImJ1dHRvblwiXG4gICAgICAgICAgY2xhc3M9XCJkZWItcGFsZXR0ZV9faXRlbVwiXG4gICAgICAgICAgW2F0dHIuZGF0YS10ZXN0aWRdPVwiJ3BhbGV0dGUtJyArIG1ldGEudHlwZVwiXG4gICAgICAgICAgW21hdFRvb2x0aXBdPVwibWV0YS5kZXNjcmlwdGlvblwiXG4gICAgICAgICAgKGNsaWNrKT1cInBpY2suZW1pdChtZXRhLnR5cGUpXCJcbiAgICAgICAgPlxuICAgICAgICAgIDxtYXQtaWNvbj57eyBtZXRhLmljb24gfX08L21hdC1pY29uPlxuICAgICAgICAgIDxzcGFuPnt7IG1ldGEubGFiZWwgfX08L3NwYW4+XG4gICAgICAgIDwvYnV0dG9uPlxuICAgICAgfVxuICAgIDwvZGl2PlxuICBgLFxuICBzdHlsZXM6IFtcbiAgICBgXG4gICAgICAuZGViLXBhbGV0dGUge1xuICAgICAgICBkaXNwbGF5OiBncmlkO1xuICAgICAgICBncmlkLXRlbXBsYXRlLWNvbHVtbnM6IDFmciAxZnI7XG4gICAgICAgIGdhcDogOHB4O1xuICAgICAgfVxuICAgICAgLmRlYi1wYWxldHRlX19pdGVtIHtcbiAgICAgICAganVzdGlmeS1jb250ZW50OiBmbGV4LXN0YXJ0O1xuICAgICAgICBvdmVyZmxvdzogaGlkZGVuO1xuICAgICAgICBib3JkZXItcmFkaXVzOiA4cHggIWltcG9ydGFudDtcbiAgICAgICAgYm9yZGVyOiAxcHggc29saWQgdmFyKC0tYm9yZGVyLCAjZTJlOGYwKSAhaW1wb3J0YW50O1xuICAgICAgICBwYWRkaW5nOiA4cHggMTJweCAhaW1wb3J0YW50O1xuICAgICAgICBmb250LWZhbWlseTogdmFyKC0tZm9udC1oZWFkaW5nLCBpbmhlcml0KSAhaW1wb3J0YW50O1xuICAgICAgICBmb250LXdlaWdodDogNjAwICFpbXBvcnRhbnQ7XG4gICAgICAgIGZvbnQtc2l6ZTogMTNweCAhaW1wb3J0YW50O1xuICAgICAgICB0cmFuc2l0aW9uOiBhbGwgMC4xOHMgY3ViaWMtYmV6aWVyKDAuMTYsIDEsIDAuMywgMSkgIWltcG9ydGFudDtcbiAgICAgICAgYmFja2dyb3VuZDogI2ZmZmZmZiAhaW1wb3J0YW50O1xuICAgICAgfVxuICAgICAgLmRlYi1wYWxldHRlX19pdGVtOmhvdmVyIHtcbiAgICAgICAgYm9yZGVyLWNvbG9yOiAjNjM2NmYxICFpbXBvcnRhbnQ7XG4gICAgICAgIGJhY2tncm91bmQ6ICNmNWYzZmYgIWltcG9ydGFudDtcbiAgICAgICAgY29sb3I6ICM0ZjQ2ZTUgIWltcG9ydGFudDtcbiAgICAgICAgdHJhbnNmb3JtOiB0cmFuc2xhdGVZKC0xcHgpO1xuICAgICAgICBib3gtc2hhZG93OiAwIDRweCAxMnB4IHJnYmEoOTksIDEwMiwgMjQxLCAwLjE1KSAhaW1wb3J0YW50O1xuICAgICAgfVxuICAgICAgLmRlYi1wYWxldHRlX19pdGVtIG1hdC1pY29uIHtcbiAgICAgICAgY29sb3I6ICM2MzY2ZjE7XG4gICAgICAgIG1hcmdpbi1yaWdodDogNnB4O1xuICAgICAgICBmb250LXNpemU6IDE4cHg7XG4gICAgICAgIHdpZHRoOiAxOHB4O1xuICAgICAgICBoZWlnaHQ6IDE4cHg7XG4gICAgICB9XG4gICAgICAuZGViLXBhbGV0dGVfX2l0ZW0gc3BhbiB7XG4gICAgICAgIG92ZXJmbG93OiBoaWRkZW47XG4gICAgICAgIHRleHQtb3ZlcmZsb3c6IGVsbGlwc2lzO1xuICAgICAgICB3aGl0ZS1zcGFjZTogbm93cmFwO1xuICAgICAgfVxuICAgIGAsXG4gIF0sXG59KVxuZXhwb3J0IGNsYXNzIEZpZWxkUGFsZXR0ZUNvbXBvbmVudCB7XG4gIHJlYWRvbmx5IGNhdGFsb2c6IHJlYWRvbmx5IEZpZWxkVHlwZU1ldGFbXSA9IEZJRUxEX1RZUEVfQ0FUQUxPRztcblxuICBAT3V0cHV0KCkgcGljayA9IG5ldyBFdmVudEVtaXR0ZXI8UmljaEZpZWxkVHlwZT4oKTtcbn1cbiJdfQ==
|