UNPKG

@nova-ui/dashboards

Version:

Nova Dashboards is a framework designed to provide feature developers with a common solution for presenting data coming from various sources within a single view, as well as a set of predefined widget visualizations that are 100% configuration-driven and

133 lines 30.1 kB
// © 2022 SolarWinds Worldwide, LLC. All rights reserved. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to // deal in the Software without restriction, including without limitation the // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or // sell copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, Input, Output, } from "@angular/core"; import { FormBuilder } from "@angular/forms"; import { Subject } from "rxjs"; import { takeUntil } from "rxjs/operators"; import { EmbeddedContentMode, } from "../../../../../components/types"; import * as i0 from "@angular/core"; import * as i1 from "@angular/forms"; import * as i2 from "@angular/cdk/portal"; import * as i3 from "../../../../../pizzagna/directives/component-portal/component-portal.directive"; import * as i4 from "@nova-ui/bits"; import * as i5 from "../../../widget-editor-accordion/widget-editor-accordion.component"; import * as i6 from "@angular/common"; import * as i7 from "../../../../pipe/widget-editor-accordion-form-state.pipe"; import * as i8 from "../../../../pipe/widget-editor-accordion-header-icon.pipe"; export class EmbeddedContentConfigurationComponent { static { this.lateLoadKey = "EmbeddedContentConfigurationComponent"; } get urlCustomContent() { return this.form.get("urlCustomContent"); } get htmlCustomContent() { return this.form.get("htmlCustomContent"); } get modeValue() { return this.form.get("mode"); } get customEmbeddedContentValue() { return this.form.get("customEmbeddedContent"); } constructor(changeDetector, formBuilder) { this.changeDetector = changeDetector; this.formBuilder = formBuilder; this.mode = EmbeddedContentMode.URL; this.formReady = new EventEmitter(); this.destroy$ = new Subject(); this.form = this.formBuilder.group({ mode: [this.mode], urlCustomContent: [""], htmlCustomContent: [""], customEmbeddedContent: [""], }); this.modes = [ { value: EmbeddedContentMode.URL, displayValue: $localize `Show the contents of a specific URL`, }, { value: EmbeddedContentMode.HTML, displayValue: $localize `Show the exact HTML I supply below`, }, ]; } ngOnInit() { this.initializeForm(); this.formReady.emit(this.form); } ngOnChanges(changes) { if (changes.customEmbeddedContent) { if (this.mode === EmbeddedContentMode.URL) { this.urlCustomContent?.setValue(this.customEmbeddedContent); } else if (this.mode === EmbeddedContentMode.HTML) { this.htmlCustomContent?.setValue(this.customEmbeddedContent); } } if (changes.mode) { this.modeValue?.setValue(changes.mode.currentValue); } } ngOnDestroy() { this.destroy$.next(); this.destroy$.complete(); } initializeForm() { this.modeValue?.valueChanges .pipe(takeUntil(this.destroy$)) .subscribe((value) => { if (value === EmbeddedContentMode.URL) { this.customEmbeddedContentValue?.setValue(this.form.get("urlCustomContent")?.value); this.htmlCustomContent?.disable(); this.urlCustomContent?.enable(); } else if (value === EmbeddedContentMode.HTML) { this.customEmbeddedContentValue?.setValue(this.form.get("htmlCustomContent")?.value); this.urlCustomContent?.disable(); this.htmlCustomContent?.enable(); } }); this.urlCustomContent?.valueChanges .pipe(takeUntil(this.destroy$)) .subscribe((value) => { this.customEmbeddedContentValue?.setValue(value); }); this.htmlCustomContent?.valueChanges .pipe(takeUntil(this.destroy$)) .subscribe((value) => { this.customEmbeddedContentValue?.setValue(value); }); } /** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: EmbeddedContentConfigurationComponent, deps: [{ token: i0.ChangeDetectorRef }, { token: i1.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); } /** @nocollapse */ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: EmbeddedContentConfigurationComponent, selector: "nui-embedded-content-configuration", inputs: { mode: "mode", messageComponent: "messageComponent", customEmbeddedContent: "customEmbeddedContent" }, outputs: { formReady: "formReady" }, usesOnChanges: true, ngImport: i0, template: "<nui-widget-editor-accordion\n [formGroup]=\"form\"\n [state]=\"form | nuiWidgetEditorAccordionFormState | async\"\n>\n <div accordionHeader class=\"d-flex align-items-center pl-4 py-2\">\n <nui-icon\n class=\"align-self-start pt-2\"\n [icon]=\"form | nuiFormHeaderIconPipe : 'tag' | async\"\n ></nui-icon>\n <div class=\"d-flex flex-column ml-4 pt1\">\n <span class=\"nui-text-label\" i18n>Embedded Content</span>\n <div class=\"nui-text-secondary\">\n Show the specific HTML I supply\n </div>\n </div>\n </div>\n <div class=\"embedded-configurator-section__accordion-content\">\n <ng-container\n nuiComponentPortal\n #componentPortal=\"nuiComponentPortal\"\n [componentType]=\"messageComponent.componentType\"\n [properties]=\"messageComponent.properties\"\n >\n <ng-template\n [cdkPortalOutlet]=\"componentPortal.portal\"\n (attached)=\"componentPortal.attached($event)\"\n ></ng-template>\n </ng-container>\n <nui-form-field\n [control]=\"form.get('mode')\"\n caption=\"What do you want to show in the widget?\"\n i18n-caption\n >\n <nui-radio-group\n formControlName=\"mode\"\n [(value)]=\"mode\"\n name=\"mode\"\n required\n >\n <nui-radio [value]=\"modes[0].value\">\n {{ modes[0].displayValue }}\n </nui-radio>\n <nui-form-field [control]=\"form.get('urlCustomContent')\">\n <nui-textbox formControlName=\"urlCustomContent\">\n </nui-textbox>\n </nui-form-field>\n <nui-radio [value]=\"modes[1].value\">\n {{ modes[1].displayValue }}\n </nui-radio>\n <nui-form-field [control]=\"form.get('htmlCustomContent')\">\n <nui-textbox\n class=\"textarea-scrollable\"\n formControlName=\"htmlCustomContent\"\n rows=\"7\"\n >\n </nui-textbox>\n </nui-form-field>\n </nui-radio-group>\n </nui-form-field>\n </div>\n</nui-widget-editor-accordion>\n", styles: [".embedded-configurator-section__accordion-content{padding:15px 15px 15px 46px}\n"], dependencies: [{ kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i2.CdkPortalOutlet, selector: "[cdkPortalOutlet]", inputs: ["cdkPortalOutlet"], outputs: ["attached"], exportAs: ["cdkPortalOutlet"] }, { kind: "directive", type: i3.ComponentPortalDirective, selector: "[nuiComponentPortal]", inputs: ["componentId", "componentType", "properties", "providers", "outputs"], outputs: ["output"], exportAs: ["nuiComponentPortal"] }, { kind: "component", type: i4.IconComponent, selector: "nui-icon", inputs: ["iconColor", "brushType", "iconHoverColor", "iconSize", "cssClass", "fillContainer", "status", "childStatus", "icon", "counter"] }, { kind: "component", type: i4.TextboxComponent, selector: "nui-textbox", inputs: ["caption", "autocomplete", "info", "customBoxWidth", "disabled", "hint", "name", "placeholder", "readonly", "rows", "type", "value", "isInErrorState", "ariaLabel", "isBusy"], outputs: ["textChange", "blurred"] }, { kind: "component", type: i4.FormFieldComponent, selector: "nui-form-field", inputs: ["control", "caption", "info", "infoTemplate", "hint", "hintTemplate", "customBoxWidth", "showOptionalText"] }, { kind: "component", type: i4.RadioComponent, selector: "nui-radio", inputs: ["value", "hovered", "checked", "hint", "disabled", "ariaLabel"], outputs: ["valueChange"] }, { kind: "component", type: i4.RadioGroupComponent, selector: "nui-radio-group", inputs: ["ariaLabel", "name", "value", "disabled"], outputs: ["valueChange"] }, { kind: "component", type: i5.WidgetEditorAccordionComponent, selector: "nui-widget-editor-accordion", inputs: ["showOpenStateIcon", "state"], outputs: ["openToggle"] }, { kind: "pipe", type: i6.AsyncPipe, name: "async" }, { kind: "pipe", type: i7.WidgetEditorAccordionFormStatePipe, name: "nuiWidgetEditorAccordionFormState" }, { kind: "pipe", type: i8.FormHeaderIconPipePipe, name: "nuiFormHeaderIconPipe" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: EmbeddedContentConfigurationComponent, decorators: [{ type: Component, args: [{ selector: "nui-embedded-content-configuration", changeDetection: ChangeDetectionStrategy.OnPush, template: "<nui-widget-editor-accordion\n [formGroup]=\"form\"\n [state]=\"form | nuiWidgetEditorAccordionFormState | async\"\n>\n <div accordionHeader class=\"d-flex align-items-center pl-4 py-2\">\n <nui-icon\n class=\"align-self-start pt-2\"\n [icon]=\"form | nuiFormHeaderIconPipe : 'tag' | async\"\n ></nui-icon>\n <div class=\"d-flex flex-column ml-4 pt1\">\n <span class=\"nui-text-label\" i18n>Embedded Content</span>\n <div class=\"nui-text-secondary\">\n Show the specific HTML I supply\n </div>\n </div>\n </div>\n <div class=\"embedded-configurator-section__accordion-content\">\n <ng-container\n nuiComponentPortal\n #componentPortal=\"nuiComponentPortal\"\n [componentType]=\"messageComponent.componentType\"\n [properties]=\"messageComponent.properties\"\n >\n <ng-template\n [cdkPortalOutlet]=\"componentPortal.portal\"\n (attached)=\"componentPortal.attached($event)\"\n ></ng-template>\n </ng-container>\n <nui-form-field\n [control]=\"form.get('mode')\"\n caption=\"What do you want to show in the widget?\"\n i18n-caption\n >\n <nui-radio-group\n formControlName=\"mode\"\n [(value)]=\"mode\"\n name=\"mode\"\n required\n >\n <nui-radio [value]=\"modes[0].value\">\n {{ modes[0].displayValue }}\n </nui-radio>\n <nui-form-field [control]=\"form.get('urlCustomContent')\">\n <nui-textbox formControlName=\"urlCustomContent\">\n </nui-textbox>\n </nui-form-field>\n <nui-radio [value]=\"modes[1].value\">\n {{ modes[1].displayValue }}\n </nui-radio>\n <nui-form-field [control]=\"form.get('htmlCustomContent')\">\n <nui-textbox\n class=\"textarea-scrollable\"\n formControlName=\"htmlCustomContent\"\n rows=\"7\"\n >\n </nui-textbox>\n </nui-form-field>\n </nui-radio-group>\n </nui-form-field>\n </div>\n</nui-widget-editor-accordion>\n", styles: [".embedded-configurator-section__accordion-content{padding:15px 15px 15px 46px}\n"] }] }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }, { type: i1.FormBuilder }], propDecorators: { mode: [{ type: Input }], messageComponent: [{ type: Input }], customEmbeddedContent: [{ type: Input }], formReady: [{ type: Output }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZW1iZWRkZWQtY29udGVudC1jb25maWd1cmF0aW9uLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uLy4uLy4uL3NyYy9saWIvY29uZmlndXJhdG9yL2NvbXBvbmVudHMvd2lkZ2V0cy9jb25maWd1cmF0b3ItaXRlbXMvZW1iZWRkZWQtY29udGVudC1jb25maWd1cmF0aW9uL2VtYmVkZGVkLWNvbnRlbnQtY29uZmlndXJhdGlvbi5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi9zcmMvbGliL2NvbmZpZ3VyYXRvci9jb21wb25lbnRzL3dpZGdldHMvY29uZmlndXJhdG9yLWl0ZW1zL2VtYmVkZGVkLWNvbnRlbnQtY29uZmlndXJhdGlvbi9lbWJlZGRlZC1jb250ZW50LWNvbmZpZ3VyYXRpb24uY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEseURBQXlEO0FBQ3pELEVBQUU7QUFDRiwrRUFBK0U7QUFDL0UsNEVBQTRFO0FBQzVFLDhFQUE4RTtBQUM5RSwrRUFBK0U7QUFDL0UsOEVBQThFO0FBQzlFLDREQUE0RDtBQUM1RCxFQUFFO0FBQ0YsNkVBQTZFO0FBQzdFLHVEQUF1RDtBQUN2RCxFQUFFO0FBQ0YsNkVBQTZFO0FBQzdFLDRFQUE0RTtBQUM1RSwrRUFBK0U7QUFDL0UsMEVBQTBFO0FBQzFFLGlGQUFpRjtBQUNqRiw2RUFBNkU7QUFDN0UsaUJBQWlCO0FBRWpCLE9BQU8sRUFDSCx1QkFBdUIsRUFDdkIsaUJBQWlCLEVBQ2pCLFNBQVMsRUFDVCxZQUFZLEVBQ1osS0FBSyxFQUlMLE1BQU0sR0FFVCxNQUFNLGVBQWUsQ0FBQztBQUN2QixPQUFPLEVBQW1CLFdBQVcsRUFBYSxNQUFNLGdCQUFnQixDQUFDO0FBQ3pFLE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFDL0IsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLGdCQUFnQixDQUFD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Q0FBQztrSUExR1EscUNBQXFDO3NIQUFyQyxxQ0FBcUMsb1BDaERsRCxnNUVBNkRBOzs0RkRiYSxxQ0FBcUM7a0JBTmpELFNBQVM7K0JBQ0ksb0NBQW9DLG1CQUc3Qix1QkFBdUIsQ0FBQyxNQUFNO2dIQU90QyxJQUFJO3NCQUFaLEtBQUs7Z0JBQ0csZ0JBQWdCO3NCQUF4QixLQUFLO2dCQUNHLHFCQUFxQjtzQkFBN0IsS0FBSztnQkFFSSxTQUFTO3NCQUFsQixNQUFNIiwic291cmNlc0NvbnRlbnQiOlsiLy8gwqkgMjAyMiBTb2xhcldpbmRzIFdvcmxkd2lkZSwgTExDLiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuLy9cbi8vIFBlcm1pc3Npb24gaXMgaGVyZWJ5IGdyYW50ZWQsIGZyZWUgb2YgY2hhcmdlLCB0byBhbnkgcGVyc29uIG9idGFpbmluZyBhIGNvcHlcbi8vICBvZiB0aGlzIHNvZnR3YXJlIGFuZCBhc3NvY2lhdGVkIGRvY3VtZW50YXRpb24gZmlsZXMgKHRoZSBcIlNvZnR3YXJlXCIpLCB0b1xuLy8gIGRlYWwgaW4gdGhlIFNvZnR3YXJlIHdpdGhvdXQgcmVzdHJpY3Rpb24sIGluY2x1ZGluZyB3aXRob3V0IGxpbWl0YXRpb24gdGhlXG4vLyAgcmlnaHRzIHRvIHVzZSwgY29weSwgbW9kaWZ5LCBtZXJnZSwgcHVibGlzaCwgZGlzdHJpYnV0ZSwgc3VibGljZW5zZSwgYW5kL29yXG4vLyAgc2VsbCBjb3BpZXMgb2YgdGhlIFNvZnR3YXJlLCBhbmQgdG8gcGVybWl0IHBlcnNvbnMgdG8gd2hvbSB0aGUgU29mdHdhcmUgaXNcbi8vICBmdXJuaXNoZWQgdG8gZG8gc28sIHN1YmplY3QgdG8gdGhlIGZvbGxvd2luZyBjb25kaXRpb25zOlxuLy9cbi8vIFRoZSBhYm92ZSBjb3B5cmlnaHQgbm90aWNlIGFuZCB0aGlzIHBlcm1pc3Npb24gbm90aWNlIHNoYWxsIGJlIGluY2x1ZGVkIGluXG4vLyAgYWxsIGNvcGllcyBvciBzdWJzdGFudGlhbCBwb3J0aW9ucyBvZiB0aGUgU29mdHdhcmUuXG4vL1xuLy8gVEhFIFNPRlRXQVJFIElTIFBST1ZJREVEIFwiQVMgSVNcIiwgV0lUSE9VVCBXQVJSQU5UWSBPRiBBTlkgS0lORCwgRVhQUkVTUyBPUlxuLy8gIElNUExJRUQsIElOQ0xVRElORyBCVVQgTk9UIExJTUlURUQgVE8gVEhFIFdBUlJBTlRJRVMgT0YgTUVSQ0hBTlRBQklMSVRZLFxuLy8gIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFIEFORCBOT05JTkZSSU5HRU1FTlQuIElOIE5PIEVWRU5UIFNIQUxMIFRIRVxuLy8gIEFVVEhPUlMgT1IgQ09QWVJJR0hUIEhPTERFUlMgQkUgTElBQkxFIEZPUiBBTlkgQ0xBSU0sIERBTUFHRVMgT1IgT1RIRVJcbi8vICBMSUFCSUxJVFksIFdIRVRIRVIgSU4gQU4gQUNUSU9OIE9GIENPTlRSQUNULCBUT1JUIE9SIE9USEVSV0lTRSwgQVJJU0lORyBGUk9NLFxuLy8gIE9VVCBPRiBPUiBJTiBDT05ORUNUSU9OIFdJVEggVEhFIFNPRlRXQVJFIE9SIFRIRSBVU0UgT1IgT1RIRVIgREVBTElOR1MgSU5cbi8vICBUSEUgU09GVFdBUkUuXG5cbmltcG9ydCB7XG4gICAgQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3ksXG4gICAgQ2hhbmdlRGV0ZWN0b3JSZWYsXG4gICAgQ29tcG9uZW50LFxuICAgIEV2ZW50RW1pdHRlcixcbiAgICBJbnB1dCxcbiAgICBPbkNoYW5nZXMsXG4gICAgT25EZXN0cm95LFxuICAgIE9uSW5pdCxcbiAgICBPdXRwdXQsXG4gICAgU2ltcGxlQ2hhbmdlcyxcbn0gZnJvbSBcIkBhbmd1bGFyL2NvcmVcIjtcbmltcG9ydCB7IEFic3RyYWN0Q29udHJvbCwgRm9ybUJ1aWxkZXIsIEZvcm1Hcm91cCB9IGZyb20gXCJAYW5ndWxhci9mb3Jtc1wiO1xuaW1wb3J0IHsgU3ViamVjdCB9IGZyb20gXCJyeGpzXCI7XG5pbXBvcnQgeyB0YWtlVW50aWwgfSBmcm9tIFwicnhqcy9vcGVyYXRvcnNcIjtcblxuaW1wb3J0IHtcbiAgICBFbWJlZGRlZENvbnRlbnRNb2RlLFxuICAgIElJbmZvTWVzc2FnZSxcbn0gZnJvbSBcIi4uLy4uLy4uLy4uLy4uL2NvbXBvbmVudHMvdHlwZXNcIjtcbmltcG9ydCB7IElIYXNDaGFuZ2VEZXRlY3RvciwgSUhhc0Zvcm0gfSBmcm9tIFwiLi4vLi4vLi4vLi4vLi4vdHlwZXNcIjtcblxuQENvbXBvbmVudCh7XG4gICAgc2VsZWN0b3I6IFwibnVpLWVtYmVkZGVkLWNvbnRlbnQtY29uZmlndXJhdGlvblwiLFxuICAgIHRlbXBsYXRlVXJsOiBcIi4vZW1iZWRkZWQtY29udGVudC1jb25maWd1cmF0aW9uLmNvbXBvbmVudC5odG1sXCIsXG4gICAgc3R5bGVVcmxzOiBbXCIuL2VtYmVkZGVkLWNvbnRlbnQtY29uZmlndXJhdGlvbi5jb21wb25lbnQubGVzc1wiXSxcbiAgICBjaGFuZ2VEZXRlY3Rpb246IENoYW5nZURldGVjdGlvblN0cmF0ZWd5Lk9uUHVzaCxcbn0pXG5leHBvcnQgY2xhc3MgRW1iZWRkZWRDb250ZW50Q29uZmlndXJhdGlvbkNvbXBvbmVudFxuICAgIGltcGxlbWVudHMgT25Jbml0LCBPbkNoYW5nZXMsIElIYXNDaGFuZ2VEZXRlY3RvciwgSUhhc0Zvcm0sIE9uRGVzdHJveVxue1xuICAgIHB1YmxpYyBzdGF0aWMgbGF0ZUxvYWRLZXkgPSBcIkVtYmVkZGVkQ29udGVudENvbmZpZ3VyYXRpb25Db21wb25lbnRcIjtcblxuICAgIEBJbnB1dCgpIG1vZGUgPSBFbWJlZGRlZENvbnRlbnRNb2RlLlVSTDtcbiAgICBASW5wdXQoKSBtZXNzYWdlQ29tcG9uZW50OiBJSW5mb01lc3NhZ2U7XG4gICAgQElucHV0KCkgY3VzdG9tRW1iZWRkZWRDb250ZW50OiBzdHJpbmc7XG5cbiAgICBAT3V0cHV0KCkgZm9ybVJlYWR5ID0gbmV3IEV2ZW50RW1pdHRlcjxGb3JtR3JvdXA+KCk7XG5cbiAgICBwcml2YXRlIHJlYWRvbmx5IGRlc3Ryb3kkID0gbmV3IFN1YmplY3Q8dm9pZD4oKTtcblxuICAgIHB1YmxpYyBmb3JtOiBGb3JtR3JvdXAgPSB0aGlzLmZvcm1CdWlsZGVyLmdyb3VwKHtcbiAgICAgICAgbW9kZTogW3RoaXMubW9kZV0sXG4gICAgICAgIHVybEN1c3RvbUNvbnRlbnQ6IFtcIlwiXSxcbiAgICAgICAgaHRtbEN1c3RvbUNvbnRlbnQ6IFtcIlwiXSxcbiAgICAgICAgY3VzdG9tRW1iZWRkZWRDb250ZW50OiBbXCJcIl0sXG4gICAgfSk7XG5cbiAgICBwdWJsaWMgbW9kZXMgPSBbXG4gICAgICAgIHtcbiAgICAgICAgICAgIHZhbHVlOiBFbWJlZGRlZENvbnRlbnRNb2RlLlVSTCxcbiAgICAgICAgICAgIGRpc3BsYXlWYWx1ZTogJGxvY2FsaXplYFNob3cgdGhlIGNvbnRlbnRzIG9mIGEgc3BlY2lmaWMgVVJMYCxcbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgICAgdmFsdWU6IEVtYmVkZGVkQ29udGVudE1vZGUuSFRNTCxcbiAgICAgICAgICAgIGRpc3BsYXlWYWx1ZTogJGxvY2FsaXplYFNob3cgdGhlIGV4YWN0IEhUTUwgSSBzdXBwbHkgYmVsb3dgLFxuICAgICAgICB9LFxuICAgIF07XG5cbiAgICBnZXQgdXJsQ3VzdG9tQ29udGVudCgpOiBBYnN0cmFjdENvbnRyb2wgfCBudWxsIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZm9ybS5nZXQoXCJ1cmxDdXN0b21Db250ZW50XCIpO1xuICAgIH1cblxuICAgIGdldCBodG1sQ3VzdG9tQ29udGVudCgpOiBBYnN0cmFjdENvbnRyb2wgfCBudWxsIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZm9ybS5nZXQoXCJodG1sQ3VzdG9tQ29udGVudFwiKTtcbiAgICB9XG5cbiAgICBnZXQgbW9kZVZhbHVlKCk6IEFic3RyYWN0Q29udHJvbCB8IG51bGwge1xuICAgICAgICByZXR1cm4gdGhpcy5mb3JtLmdldChcIm1vZGVcIik7XG4gICAgfVxuXG4gICAgZ2V0IGN1c3RvbUVtYmVkZGVkQ29udGVudFZhbHVlKCk6IEFic3RyYWN0Q29udHJvbCB8IG51bGwge1xuICAgICAgICByZXR1cm4gdGhpcy5mb3JtLmdldChcImN1c3RvbUVtYmVkZGVkQ29udGVudFwiKTtcbiAgICB9XG5cbiAgICBjb25zdHJ1Y3RvcihcbiAgICAgICAgcHVibGljIGNoYW5nZURldGVjdG9yOiBDaGFuZ2VEZXRlY3RvclJlZixcbiAgICAgICAgcHJpdmF0ZSBmb3JtQnVpbGRlcjogRm9ybUJ1aWxkZXJcbiAgICApIHt9XG5cbiAgICBwdWJsaWMgbmdPbkluaXQoKTogdm9pZCB7XG4gICAgICAgIHRoaXMuaW5pdGlhbGl6ZUZvcm0oKTtcbiAgICAgICAgdGhpcy5mb3JtUmVhZHkuZW1pdCh0aGlzLmZvcm0pO1xuICAgIH1cblxuICAgIHB1YmxpYyBuZ09uQ2hhbmdlcyhjaGFuZ2VzOiBTaW1wbGVDaGFuZ2VzKTogdm9pZCB7XG4gICAgICAgIGlmIChjaGFuZ2VzLmN1c3RvbUVtYmVkZGVkQ29udGVudCkge1xuICAgICAgICAgICAgaWYgKHRoaXMubW9kZSA9PT0gRW1iZWRkZWRDb250ZW50TW9kZS5VUkwpIHtcbiAgICAgICAgICAgICAgICB0aGlzLnVybEN1c3RvbUNvbnRlbnQ/LnNldFZhbHVlKHRoaXMuY3VzdG9tRW1iZWRkZWRDb250ZW50KTtcbiAgICAgICAgICAgIH0gZWxzZSBpZiAodGhpcy5tb2RlID09PSBFbWJlZGRlZENvbnRlbnRNb2RlLkhUTUwpIHtcbiAgICAgICAgICAgICAgICB0aGlzLmh0bWxDdXN0b21Db250ZW50Py5zZXRWYWx1ZSh0aGlzLmN1c3RvbUVtYmVkZGVkQ29udGVudCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoY2hhbmdlcy5tb2RlKSB7XG4gICAgICAgICAgICB0aGlzLm1vZGVWYWx1ZT8uc2V0VmFsdWUoY2hhbmdlcy5tb2RlLmN1cnJlbnRWYWx1ZSk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBwdWJsaWMgbmdPbkRlc3Ryb3koKTogdm9pZCB7XG4gICAgICAgIHRoaXMuZGVzdHJveSQubmV4dCgpO1xuICAgICAgICB0aGlzLmRlc3Ryb3kkLmNvbXBsZXRlKCk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBpbml0aWFsaXplRm9ybSgpIHtcbiAgICAgICAgdGhpcy5tb2RlVmFsdWU/LnZhbHVlQ2hhbmdlc1xuICAgICAgICAgICAgLnBpcGUodGFrZVVudGlsKHRoaXMuZGVzdHJveSQpKVxuICAgICAgICAgICAgLnN1YnNjcmliZSgodmFsdWUpID0+IHtcbiAgICAgICAgICAgICAgICBpZiAodmFsdWUgPT09IEVtYmVkZGVkQ29udGVudE1vZGUuVVJMKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuY3VzdG9tRW1iZWRkZWRDb250ZW50VmFsdWU/LnNldFZhbHVlKFxuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5mb3JtLmdldChcInVybEN1c3RvbUNvbnRlbnRcIik/LnZhbHVlXG4gICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuaHRtbEN1c3RvbUNvbnRlbnQ/LmRpc2FibGUoKTtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy51cmxDdXN0b21Db250ZW50Py5lbmFibGUoKTtcbiAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKHZhbHVlID09PSBFbWJlZGRlZENvbnRlbnRNb2RlLkhUTUwpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5jdXN0b21FbWJlZGRlZENvbnRlbnRWYWx1ZT8uc2V0VmFsdWUoXG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmZvcm0uZ2V0KFwiaHRtbEN1c3RvbUNvbnRlbnRcIik/LnZhbHVlXG4gICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMudXJsQ3VzdG9tQ29udGVudD8uZGlzYWJsZSgpO1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmh0bWxDdXN0b21Db250ZW50Py5lbmFibGUoKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KTtcblxuICAgICAgICB0aGlzLnVybEN1c3RvbUNvbnRlbnQ/LnZhbHVlQ2hhbmdlc1xuICAgICAgICAgICAgLnBpcGUodGFrZVVudGlsKHRoaXMuZGVzdHJveSQpKVxuICAgICAgICAgICAgLnN1YnNjcmliZSgodmFsdWUpID0+IHtcbiAgICAgICAgICAgICAgICB0aGlzLmN1c3RvbUVtYmVkZGVkQ29udGVudFZhbHVlPy5zZXRWYWx1ZSh2YWx1ZSk7XG4gICAgICAgICAgICB9KTtcblxuICAgICAgICB0aGlzLmh0bWxDdXN0b21Db250ZW50Py52YWx1ZUNoYW5nZXNcbiAgICAgICAgICAgIC5waXBlKHRha2VVbnRpbCh0aGlzLmRlc3Ryb3kkKSlcbiAgICAgICAgICAgIC5zdWJzY3JpYmUoKHZhbHVlKSA9PiB7XG4gICAgICAgICAgICAgICAgdGhpcy5jdXN0b21FbWJlZGRlZENvbnRlbnRWYWx1ZT8uc2V0VmFsdWUodmFsdWUpO1xuICAgICAgICAgICAgfSk7XG4gICAgfVxufVxuIiwiPG51aS13aWRnZXQtZWRpdG9yLWFjY29yZGlvblxuICAgIFtmb3JtR3JvdXBdPVwiZm9ybVwiXG4gICAgW3N0YXRlXT1cImZvcm0gfCBudWlXaWRnZXRFZGl0b3JBY2NvcmRpb25Gb3JtU3RhdGUgfCBhc3luY1wiXG4+XG4gICAgPGRpdiBhY2NvcmRpb25IZWFkZXIgY2xhc3M9XCJkLWZsZXggYWxpZ24taXRlbXMtY2VudGVyIHBsLTQgcHktMlwiPlxuICAgICAgICA8bnVpLWljb25cbiAgICAgICAgICAgIGNsYXNzPVwiYWxpZ24tc2VsZi1zdGFydCBwdC0yXCJcbiAgICAgICAgICAgIFtpY29uXT1cImZvcm0gfCBudWlGb3JtSGVhZGVySWNvblBpcGUgOiAndGFnJyB8IGFzeW5jXCJcbiAgICAgICAgPjwvbnVpLWljb24+XG4gICAgICAgIDxkaXYgY2xhc3M9XCJkLWZsZXggZmxleC1jb2x1bW4gbWwtNCBwdDFcIj5cbiAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwibnVpLXRleHQtbGFiZWxcIiBpMThuPkVtYmVkZGVkIENvbnRlbnQ8L3NwYW4+XG4gICAgICAgICAgICA8ZGl2IGNsYXNzPVwibnVpLXRleHQtc2Vjb25kYXJ5XCI+XG4gICAgICAgICAgICAgICAgU2hvdyB0aGUgc3BlY2lmaWMgSFRNTCBJIHN1cHBseVxuICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgIDwvZGl2PlxuICAgIDwvZGl2PlxuICAgIDxkaXYgY2xhc3M9XCJlbWJlZGRlZC1jb25maWd1cmF0b3Itc2VjdGlvbl9fYWNjb3JkaW9uLWNvbnRlbnRcIj5cbiAgICAgICAgPG5nLWNvbnRhaW5lclxuICAgICAgICAgICAgbnVpQ29tcG9uZW50UG9ydGFsXG4gICAgICAgICAgICAjY29tcG9uZW50UG9ydGFsPVwibnVpQ29tcG9uZW50UG9ydGFsXCJcbiAgICAgICAgICAgIFtjb21wb25lbnRUeXBlXT1cIm1lc3NhZ2VDb21wb25lbnQuY29tcG9uZW50VHlwZVwiXG4gICAgICAgICAgICBbcHJvcGVydGllc109XCJtZXNzYWdlQ29tcG9uZW50LnByb3BlcnRpZXNcIlxuICAgICAgICA+XG4gICAgICAgICAgICA8bmctdGVtcGxhdGVcbiAgICAgICAgICAgICAgICBbY2RrUG9ydGFsT3V0bGV0XT1cImNvbXBvbmVudFBvcnRhbC5wb3J0YWxcIlxuICAgICAgICAgICAgICAgIChhdHRhY2hlZCk9XCJjb21wb25lbnRQb3J0YWwuYXR0YWNoZWQoJGV2ZW50KVwiXG4gICAgICAgICAgICA+PC9uZy10ZW1wbGF0ZT5cbiAgICAgICAgPC9uZy1jb250YWluZXI+XG4gICAgICAgIDxudWktZm9ybS1maWVsZFxuICAgICAgICAgICAgW2NvbnRyb2xdPVwiZm9ybS5nZXQoJ21vZGUnKVwiXG4gICAgICAgICAgICBjYXB0aW9uPVwiV2hhdCBkbyB5b3Ugd2FudCB0byBzaG93IGluIHRoZSB3aWRnZXQ/XCJcbiAgICAgICAgICAgIGkxOG4tY2FwdGlvblxuICAgICAgICA+XG4gICAgICAgICAgICA8bnVpLXJhZGlvLWdyb3VwXG4gICAgICAgICAgICAgICAgZm9ybUNvbnRyb2xOYW1lPVwibW9kZVwiXG4gICAgICAgICAgICAgICAgWyh2YWx1ZSldPVwibW9kZVwiXG4gICAgICAgICAgICAgICAgbmFtZT1cIm1vZGVcIlxuICAgICAgICAgICAgICAgIHJlcXVpcmVkXG4gICAgICAgICAgICA+XG4gICAgICAgICAgICAgICAgPG51aS1yYWRpbyBbdmFsdWVdPVwibW9kZXNbMF0udmFsdWVcIj5cbiAgICAgICAgICAgICAgICAgICAge3sgbW9kZXNbMF0uZGlzcGxheVZhbHVlIH19XG4gICAgICAgICAgICAgICAgPC9udWktcmFkaW8+XG4gICAgICAgICAgICAgICAgPG51aS1mb3JtLWZpZWxkIFtjb250cm9sXT1cImZvcm0uZ2V0KCd1cmxDdXN0b21Db250ZW50JylcIj5cbiAgICAgICAgICAgICAgICAgICAgPG51aS10ZXh0Ym94IGZvcm1Db250cm9sTmFtZT1cInVybEN1c3RvbUNvbnRlbnRcIj5cbiAgICAgICAgICAgICAgICAgICAgPC9udWktdGV4dGJveD5cbiAgICAgICAgICAgICAgICA8L251aS1mb3JtLWZpZWxkPlxuICAgICAgICAgICAgICAgIDxudWktcmFkaW8gW3ZhbHVlXT1cIm1vZGVzWzFdLnZhbHVlXCI+XG4gICAgICAgICAgICAgICAgICAgIHt7IG1vZGVzWzFdLmRpc3BsYXlWYWx1ZSB9fVxuICAgICAgICAgICAgICAgIDwvbnVpLXJhZGlvPlxuICAgICAgICAgICAgICAgIDxudWktZm9ybS1maWVsZCBbY29udHJvbF09XCJmb3JtLmdldCgnaHRtbEN1c3RvbUNvbnRlbnQnKVwiPlxuICAgICAgICAgICAgICAgICAgICA8bnVpLXRleHRib3hcbiAgICAgICAgICAgICAgICAgICAgICAgIGNsYXNzPVwidGV4dGFyZWEtc2Nyb2xsYWJsZVwiXG4gICAgICAgICAgICAgICAgICAgICAgICBmb3JtQ29udHJvbE5hbWU9XCJodG1sQ3VzdG9tQ29udGVudFwiXG4gICAgICAgICAgICAgICAgICAgICAgICByb3dzPVwiN1wiXG4gICAgICAgICAgICAgICAgICAgID5cbiAgICAgICAgICAgICAgICAgICAgPC9udWktdGV4dGJveD5cbiAgICAgICAgICAgICAgICA8L251aS1mb3JtLWZpZWxkPlxuICAgICAgICAgICAgPC9udWktcmFkaW8tZ3JvdXA+XG4gICAgICAgIDwvbnVpLWZvcm0tZmllbGQ+XG4gICAgPC9kaXY+XG48L251aS13aWRnZXQtZWRpdG9yLWFjY29yZGlvbj5cbiJdfQ==