@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
170 lines • 34.9 kB
JavaScript
// © 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 { ChangeDetectorRef, Component, EventEmitter, Input, Output, ViewChild, } from "@angular/core";
import { FormBuilder, Validators } from "@angular/forms";
// eslint-disable-next-line import/no-deprecated
import { combineLatest, Subject } from "rxjs";
import { filter, takeUntil, tap } from "rxjs/operators";
import { LoggerService } from "@nova-ui/bits";
import { RefreshRateConfiguratorComponent } from "./refresh-rate-configurator/refresh-rate-configurator.component";
import { TimeUnit, TIME_UNITS_SHORT, } from "./refresh-rate-configurator/time-units";
import { RefresherSettingsService } from "../../../../../components/providers/refresher-settings.service";
import * as i0 from "@angular/core";
import * as i1 from "@angular/forms";
import * as i2 from "@nova-ui/bits";
import * as i3 from "../../../../../components/providers/refresher-settings.service";
import * as i4 from "@angular/common";
import * as i5 from "../../../widget-editor-accordion/widget-editor-accordion.component";
import * as i6 from "./refresh-rate-configurator/refresh-rate-configurator.component";
import * as i7 from "../../../../pipe/widget-editor-accordion-form-state.pipe";
import * as i8 from "../../../../pipe/widget-editor-accordion-header-icon.pipe";
export class RefresherConfigurationComponent {
static { this.lateLoadKey = "RefresherConfigurationComponent"; }
constructor(changeDetector, formBuilder, logger, refresherSettings, cd) {
this.changeDetector = changeDetector;
this.formBuilder = formBuilder;
this.logger = logger;
this.refresherSettings = refresherSettings;
this.cd = cd;
this.minSeconds = 1;
this.maxSeconds = 86400;
this.overrideDefaultSettingsCaption = $localize `Custom refresh rate`;
this.overrideDefaultSettings = true;
this.formReady = new EventEmitter();
this.destroyed$ = new Subject();
this.resetInterval = () => {
this.refreshRateComp.resetUnits();
this.form.get("interval")?.setValue(this.interval || this.minSeconds);
};
}
ngOnInit() {
this.form = this.formBuilder.group({
enabled: [true, [Validators.required]],
overrideDefaultSettings: [
this.overrideDefaultSettings,
[Validators.required],
],
interval: [this.interval ?? 0, [Validators.required]],
});
this.form.statusChanges
.pipe(takeUntil(this.destroyed$))
.subscribe(() => {
this.form.markAllAsTouched();
this.cd.detectChanges();
});
// eslint-disable-next-line import/no-deprecated
combineLatest([
this.form.controls["enabled"].valueChanges,
this.form.controls["overrideDefaultSettings"].valueChanges,
])
.pipe(filter((values) => values.some((v) => !v)), tap(this.resetInterval), takeUntil(this.destroyed$))
.subscribe();
this.formReady.emit(this.form);
}
ngOnChanges(changes) {
if (changes.enabled) {
this.form?.get("enabled")?.patchValue(this.enabled);
}
if (changes.interval) {
this.form?.get("interval")?.patchValue(this.interval);
}
if (changes.overrideDefaultSettings) {
this.form
?.get("overrideDefaultSettings")
?.patchValue(this.overrideDefaultSettings);
}
}
ngOnDestroy() {
this.destroyed$.next();
this.destroyed$.complete();
}
getHeaderSubtitle() {
let result = "";
if (this.form.get("enabled")?.value) {
result += $localize `Enabled`;
result += ", ";
if (this.form.get("overrideDefaultSettings")?.value) {
result += this.getDurationLabel(this.form.get("interval")?.value);
}
else {
result +=
$localize `Use default value` +
" (" +
this.getDurationLabel(this.refresherSettings.refreshRateSeconds) +
")";
}
}
else {
result += $localize `Disabled`;
}
return result;
}
// TODO: make reusable
getDurationLabel(seconds) {
let totalSeconds = seconds;
let result = "";
const hours = Math.floor(totalSeconds / 3600);
totalSeconds %= 3600;
const minutes = Math.floor(totalSeconds / 60);
const calculatedSeconds = totalSeconds % 60;
if (hours > 0) {
result += hours + " " + TIME_UNITS_SHORT[TimeUnit.Hour] + " ";
}
if (minutes > 0) {
result += minutes + " " + TIME_UNITS_SHORT[TimeUnit.Minute] + " ";
}
if (calculatedSeconds > 0) {
result +=
calculatedSeconds +
" " +
TIME_UNITS_SHORT[TimeUnit.Second] +
" ";
}
result = result.trim();
if (result === "") {
return "0 " + TIME_UNITS_SHORT[TimeUnit.Second];
}
return result;
}
/** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: RefresherConfigurationComponent, deps: [{ token: i0.ChangeDetectorRef }, { token: i1.FormBuilder }, { token: i2.LoggerService }, { token: i3.RefresherSettingsService }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
/** @nocollapse */ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: RefresherConfigurationComponent, selector: "nui-refresher-configuration", inputs: { enabled: "enabled", interval: "interval", minSeconds: "minSeconds", maxSeconds: "maxSeconds", overrideDefaultSettingsCaption: "overrideDefaultSettingsCaption", overrideDefaultSettings: "overrideDefaultSettings" }, outputs: { formReady: "formReady" }, viewQueries: [{ propertyName: "refreshRateComp", first: true, predicate: RefreshRateConfiguratorComponent, descendants: true }], 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 px-4 py-2\">\n <nui-icon\n class=\"align-self-start pt-2\"\n iconColor=\"gray\"\n [icon]=\"form | nuiFormHeaderIconPipe : 'reset' | async\"\n ></nui-icon>\n <div class=\"d-flex flex-column ml-4 pt-1\">\n <span class=\"nui-text-label\" i18n>Refresh</span>\n <div class=\"nui-text-secondary\" [title]=\"getHeaderSubtitle()\">\n {{ getHeaderSubtitle() }}\n </div>\n </div>\n </div>\n <div\n class=\"d-flex flex-column nui-refresher-configuration__accordion-content\"\n >\n <div>\n <nui-form-field [control]=\"form.get('enabled')\">\n <nui-switch formControlName=\"enabled\" i18n\n >Refresh widget periodically</nui-switch\n >\n </nui-form-field>\n </div>\n <div [class.hidden]=\"!form.get('enabled')?.value\">\n <div class=\"mt-4\">\n <nui-form-field [control]=\"form.get('overrideDefaultSettings')\">\n <nui-switch formControlName=\"overrideDefaultSettings\"\n >{{ overrideDefaultSettingsCaption }}\n <div\n class=\"nui-help-hint\"\n *ngIf=\"!form.get('overrideDefaultSettings')?.value\"\n i18n\n >\n By default, the widget will refresh every\n {{\n getDurationLabel(\n refresherSettings.refreshRateSeconds\n )\n }}.\n </div>\n </nui-switch>\n </nui-form-field>\n </div>\n <div\n [class.hidden]=\"!form.get('overrideDefaultSettings')?.value\"\n class=\"mt-4\"\n >\n <nui-form-field [control]=\"form.get('interval')\">\n <nui-refresh-rate-configurator\n [minSeconds]=\"minSeconds\"\n [maxSeconds]=\"maxSeconds\"\n formControlName=\"interval\"\n ></nui-refresh-rate-configurator>\n </nui-form-field>\n </div>\n </div>\n </div>\n</nui-widget-editor-accordion>\n", styles: [".nui-refresher-configuration__accordion-content{padding:15px 15px 15px 46px}\n"], dependencies: [{ kind: "directive", type: i4.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { 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.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: i2.IconComponent, selector: "nui-icon", inputs: ["iconColor", "brushType", "iconHoverColor", "iconSize", "cssClass", "fillContainer", "status", "childStatus", "icon", "counter"] }, { kind: "component", type: i2.FormFieldComponent, selector: "nui-form-field", inputs: ["control", "caption", "info", "infoTemplate", "hint", "hintTemplate", "customBoxWidth", "showOptionalText"] }, { kind: "component", type: i2.SwitchComponent, selector: "nui-switch", inputs: ["value", "disabled", "ariaLabel"], outputs: ["valueChange"] }, { kind: "component", type: i5.WidgetEditorAccordionComponent, selector: "nui-widget-editor-accordion", inputs: ["showOpenStateIcon", "state"], outputs: ["openToggle"] }, { kind: "component", type: i6.RefreshRateConfiguratorComponent, selector: "nui-refresh-rate-configurator", inputs: ["minSeconds", "maxSeconds"] }, { kind: "pipe", type: i4.AsyncPipe, name: "async" }, { kind: "pipe", type: i7.WidgetEditorAccordionFormStatePipe, name: "nuiWidgetEditorAccordionFormState" }, { kind: "pipe", type: i8.FormHeaderIconPipePipe, name: "nuiFormHeaderIconPipe" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: RefresherConfigurationComponent, decorators: [{
type: Component,
args: [{ selector: "nui-refresher-configuration", template: "<nui-widget-editor-accordion\n [formGroup]=\"form\"\n [state]=\"form | nuiWidgetEditorAccordionFormState | async\"\n>\n <div accordionHeader class=\"d-flex align-items-center px-4 py-2\">\n <nui-icon\n class=\"align-self-start pt-2\"\n iconColor=\"gray\"\n [icon]=\"form | nuiFormHeaderIconPipe : 'reset' | async\"\n ></nui-icon>\n <div class=\"d-flex flex-column ml-4 pt-1\">\n <span class=\"nui-text-label\" i18n>Refresh</span>\n <div class=\"nui-text-secondary\" [title]=\"getHeaderSubtitle()\">\n {{ getHeaderSubtitle() }}\n </div>\n </div>\n </div>\n <div\n class=\"d-flex flex-column nui-refresher-configuration__accordion-content\"\n >\n <div>\n <nui-form-field [control]=\"form.get('enabled')\">\n <nui-switch formControlName=\"enabled\" i18n\n >Refresh widget periodically</nui-switch\n >\n </nui-form-field>\n </div>\n <div [class.hidden]=\"!form.get('enabled')?.value\">\n <div class=\"mt-4\">\n <nui-form-field [control]=\"form.get('overrideDefaultSettings')\">\n <nui-switch formControlName=\"overrideDefaultSettings\"\n >{{ overrideDefaultSettingsCaption }}\n <div\n class=\"nui-help-hint\"\n *ngIf=\"!form.get('overrideDefaultSettings')?.value\"\n i18n\n >\n By default, the widget will refresh every\n {{\n getDurationLabel(\n refresherSettings.refreshRateSeconds\n )\n }}.\n </div>\n </nui-switch>\n </nui-form-field>\n </div>\n <div\n [class.hidden]=\"!form.get('overrideDefaultSettings')?.value\"\n class=\"mt-4\"\n >\n <nui-form-field [control]=\"form.get('interval')\">\n <nui-refresh-rate-configurator\n [minSeconds]=\"minSeconds\"\n [maxSeconds]=\"maxSeconds\"\n formControlName=\"interval\"\n ></nui-refresh-rate-configurator>\n </nui-form-field>\n </div>\n </div>\n </div>\n</nui-widget-editor-accordion>\n", styles: [".nui-refresher-configuration__accordion-content{padding:15px 15px 15px 46px}\n"] }]
}], ctorParameters: () => [{ type: i0.ChangeDetectorRef }, { type: i1.FormBuilder }, { type: i2.LoggerService }, { type: i3.RefresherSettingsService }, { type: i0.ChangeDetectorRef }], propDecorators: { enabled: [{
type: Input
}], interval: [{
type: Input
}], minSeconds: [{
type: Input
}], maxSeconds: [{
type: Input
}], overrideDefaultSettingsCaption: [{
type: Input
}], overrideDefaultSettings: [{
type: Input
}], formReady: [{
type: Output
}], refreshRateComp: [{
type: ViewChild,
args: [RefreshRateConfiguratorComponent]
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVmcmVzaGVyLWNvbmZpZ3VyYXRpb24uY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vc3JjL2xpYi9jb25maWd1cmF0b3IvY29tcG9uZW50cy93aWRnZXRzL2NvbmZpZ3VyYXRvci1pdGVtcy9yZWZyZXNoZXItY29uZmlndXJhdGlvbi9yZWZyZXNoZXItY29uZmlndXJhdGlvbi5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi9zcmMvbGliL2NvbmZpZ3VyYXRvci9jb21wb25lbnRzL3dpZGdldHMvY29uZmlndXJhdG9yLWl0ZW1zL3JlZnJlc2hlci1jb25maWd1cmF0aW9uL3JlZnJlc2hlci1jb25maWd1cmF0aW9uLmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLHlEQUF5RDtBQUN6RCxFQUFFO0FBQ0YsK0VBQStFO0FBQy9FLDRFQUE0RTtBQUM1RSw4RUFBOEU7QUFDOUUsK0VBQStFO0FBQy9FLDhFQUE4RTtBQUM5RSw0REFBNEQ7QUFDNUQsRUFBRTtBQUNGLDZFQUE2RTtBQUM3RSx1REFBdUQ7QUFDdkQsRUFBRTtBQUNGLDZFQUE2RTtBQUM3RSw0RUFBNEU7QUFDNUUsK0VBQStFO0FBQy9FLDBFQUEwRTtBQUMxRSxpRkFBaUY7QUFDakYsNkVBQTZFO0FBQzdFLGlCQUFpQjtBQUVqQixPQUFPLEVBQ0gsaUJBQWlCLEVBQ2pCLFNBQVMsRUFDVCxZQUFZLEVBQ1osS0FBSyxFQUlMLE1BQU0sRUFFTixTQUFTLEdBQ1osTUFBTSxlQUFlLENBQUM7QUFDdkIsT0FBTyxFQUFFLFdBQVcsRUFBYSxVQUFVLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUNwRSxnREFBZ0Q7QUFDaEQsT0FBTyxFQUFFLGFBQWEsRUFBRSxPQUFPLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFDOUMsT0FBTyxFQUFFLE1BQU0sRUFBRSxTQUFTLEVBQUUsR0FBRyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFFeEQsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUU5QyxPQUFPLEVBQUUsZ0NBQWdDLEVBQUUsTUFBTSxpRUFBaUUsQ0FBQztBQUNuSCxPQUFPLEVBQ0gsUUFBUSxFQUNSLGdCQUFnQixHQUNuQixNQUFNLHdDQUF3QyxDQUFDO0FBQ2hELE9BQU8sRUFBRSx3QkFBd0IsRUFBRSxNQUFNLGdFQUFnRSxDQUFDOzs7Ozs7Ozs7O0FBUTFHLE1BQU0sT0FBTywrQkFBK0I7YUFHMUIsZ0JBQVcsR0FBRyxpQ0FBaUMsQUFBcEMsQ0FBcUM7SUFnQjlELFlBQ1csY0FBaUMsRUFDaEMsV0FBd0IsRUFDeEIsTUFBcUIsRUFDdEIsaUJBQTJDLEVBQzFDLEVBQXFCO1FBSnRCLG1CQUFjLEdBQWQsY0FBYyxDQUFtQjtRQUNoQyxnQkFBVyxHQUFYLFdBQVcsQ0FBYTtRQUN4QixXQUFNLEdBQU4sTUFBTSxDQUFlO1FBQ3RCLHNCQUFpQixHQUFqQixpQkFBaUIsQ0FBMEI7UUFDMUMsT0FBRSxHQUFGLEVBQUUsQ0FBbUI7UUFqQnhCLGVBQVUsR0FBVyxDQUFDLENBQUM7UUFDdkIsZUFBVSxHQUFXLEtBQUssQ0FBQztRQUMzQixtQ0FBOEIsR0FBRyxTQUFTLENBQUEscUJBQXFCLENBQUM7UUFDaEUsNEJBQXVCLEdBQUcsSUFBSSxDQUFDO1FBQzlCLGNBQVMsR0FBRyxJQUFJLFlBQVksRUFBYSxDQUFDO1FBSTVDLGVBQVUsR0FBRyxJQUFJLE9BQU8sRUFBUSxDQUFDO1FBNEhqQyxrQkFBYSxHQUFHLEdBQUcsRUFBRTtZQUN6QixJQUFJLENBQUMsZUFBZSxDQUFDLFVBQVUsRUFBRSxDQUFDO1lBQ2xDLElBQUksQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLFVBQVUsQ0FBQyxFQUFFLFFBQVEsQ0FBQyxJQUFJLENBQUMsUUFBUSxJQUFJLElBQUksQ0FBQyxVQUFVLENBQUMsQ0FBQztRQUMxRSxDQUFDLENBQUM7SUFySEMsQ0FBQztJQUVHLFFBQVE7UUFDWCxJQUFJLENBQUMsSUFBSSxHQUFHLElBQUksQ0FBQyxXQUFXLENBQUMsS0FBSyxDQUFDO1lBQy9CLE9BQU8sRUFBRSxDQUFDLElBQUksRUFBRSxDQUFDLFVBQVUsQ0FBQyxRQUFRLENBQUMsQ0FBQztZQUN0Qyx1QkFBdUIsRUFBRTtnQkFDckIsSUFBSSxDQUFDLHVCQUF1QjtnQkFDNUIsQ0FBQyxVQUFVLENBQUMsUUFBUSxDQUFDO2FBQ3hCO1lBQ0QsUUFBUSxFQUFFLENBQUMsSUFBSSxDQUFDLFFBQVEsSUFBSSxDQUFDLEVBQUUsQ0FBQyxVQUFVLENBQUMsUUFBUSxDQUFDLENBQUM7U0FDeEQsQ0FBQyxDQUFDO1FBRUgsSUFBSSxDQUFDLElBQUksQ0FBQyxhQUFhO2FBQ2xCLElBQUksQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxDQUFDO2FBQ2hDLFNBQVMsQ0FBQyxHQUFHLEVBQUU7WUFDWixJQUFJLENBQUMsSUFBSSxDQUFDLGdCQUFnQixFQUFFLENBQUM7WUFDN0IsSUFBSSxDQUFDLEVBQUUsQ0FBQyxhQUFhLEVBQUUsQ0FBQztRQUM1QixDQUFDLENBQUMsQ0FBQztRQUVQLGdEQUFnRDtRQUNoRCxhQUFhLENBQUM7WUFDVixJQUFJLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxTQUFTLENBQUMsQ0FBQyxZQUFZO1lBQzFDLElBQUksQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLHlCQUF5QixDQUFDLENBQUMsWUFBWTtTQUM3RCxDQUFDO2FBQ0csSUFBSSxDQUNELE1BQU0sQ0FBQyxDQUFDLE1BQU0sRUFBRSxFQUFFLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUMxQyxHQUFHLENBQUMsSUFBSSxDQUFDLGFBQWEsQ0FBQyxFQUN2QixTQUFTLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxDQUM3QjthQUNBLFNBQVMsRUFBRSxDQUFDO1FBRWpCLElBQUksQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUNuQyxDQUFDO0lBRU0sV0FBVyxDQUFDLE9BQXNCO1FBQ3JDLElBQUksT0FBTyxDQUFDLE9BQU8sRUFBRTtZQUNqQixJQUFJLENBQUMsSUFBSSxFQUFFLEdBQUcsQ0FBQyxTQUFTLENBQUMsRUFBRSxVQUFVLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxDQUFDO1NBQ3ZEO1FBQ0QsSUFBSSxPQUFPLENBQUMsUUFBUSxFQUFFO1lBQ2xCLElBQUksQ0FBQyxJQUFJLEVBQUUsR0FBRyxDQUFDLFVBQVUsQ0FBQyxFQUFFLFVBQVUsQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUM7U0FDekQ7UUFDRCxJQUFJLE9BQU8sQ0FBQyx1QkFBdUIsRUFBRTtZQUNqQyxJQUFJLENBQUMsSUFBSTtnQkFDTCxFQUFFLEdBQUcsQ0FBQyx5QkFBeUIsQ0FBQztnQkFDaEMsRUFBRSxVQUFVLENBQUMsSUFBSSxDQUFDLHVCQUF1QixDQUFDLENBQUM7U0FDbEQ7SUFDTCxDQUFDO0lBRU0sV0FBVztRQUNkLElBQUksQ0FBQyxVQUFVLENBQUMsSUFBSSxFQUFFLENBQUM7UUFDdkIsSUFBSSxDQUFDLFVBQVUsQ0FBQyxRQUFRLEVBQUUsQ0FBQztJQUMvQixDQUFDO0lBRU0saUJBQWlCO1FBQ3BCLElBQUksTUFBTSxHQUFHLEVBQUUsQ0FBQztRQUNoQixJQUFJLElBQUksQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLFNBQVMsQ0FBQyxFQUFFLEtBQUssRUFBRTtZQUNqQyxNQUFNLElBQUksU0FBUyxDQUFBLFNBQVMsQ0FBQztZQUM3QixNQUFNLElBQUksSUFBSSxDQUFDO1lBQ2YsSUFBSSxJQUFJLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyx5QkFBeUIsQ0FBQyxFQUFFLEtBQUssRUFBRTtnQkFDakQsTUFBTSxJQUFJLElBQUksQ0FBQyxnQkFBZ0IsQ0FDM0IsSUFBSSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsVUFBVSxDQUFDLEVBQUUsS0FBSyxDQUNuQyxDQUFDO2FBQ0w7aUJBQU07Z0JBQ0gsTUFBTTtvQkFDRixTQUFTLENBQUEsbUJBQW1CO3dCQUM1QixJQUFJO3dCQUNKLElBQUksQ0FBQyxnQkFBZ0IsQ0FDakIsSUFBSSxDQUFDLGlCQUFpQixDQUFDLGtCQUFrQixDQUM1Qzt3QkFDRCxHQUFHLENBQUM7YUFDWDtTQUNKO2FBQU07WUFDSCxNQUFNLElBQUksU0FBUyxDQUFBLFVBQVUsQ0FBQztTQUNqQztRQUVELE9BQU8sTUFBTSxDQUFDO0lBQ2xCLENBQUM7SUFFRCxzQkFBc0I7SUFDZixnQkFBZ0IsQ0FBQyxPQUFlO1FBQ25DLElBQUksWUFBWSxHQUFHLE9BQU8sQ0FBQztRQUMzQixJQUFJLE1BQU0sR0FBVyxFQUFFLENBQUM7UUFDeEIsTUFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxZQUFZLEdBQUcsSUFBSSxDQUFDLENBQUM7UUFFOUMsWUFBWSxJQUFJLElBQUksQ0FBQztRQUNyQixNQUFNLE9BQU8sR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLFlBQVksR0FBRyxFQUFFLENBQUMsQ0FBQztRQUU5QyxNQUFNLGlCQUFpQixHQUFHLFlBQVksR0FBRyxFQUFFLENBQUM7UUFFNUMsSUFBSSxLQUFLLEdBQUcsQ0FBQyxFQUFFO1lBQ1gsTUFBTSxJQUFJLEtBQUssR0FBRyxHQUFHLEdBQUcsZ0JBQWdCLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxHQUFHLEdBQUcsQ0FBQztTQUNqRTtRQUVELElBQUksT0FBTyxHQUFHLENBQUMsRUFBRTtZQUNiLE1BQU0sSUFBSSxPQUFPLEdBQUcsR0FBRyxHQUFHLGdCQUFnQixDQUFDLFFBQVEsQ0FBQyxNQUFNLENBQUMsR0FBRyxHQUFHLENBQUM7U0FDckU7UUFFRCxJQUFJLGlCQUFpQixHQUFHLENBQUMsRUFBRTtZQUN2QixNQUFNO2dCQUNGLGlCQUFpQjtvQkFDakIsR0FBRztvQkFDSCxnQkFBZ0IsQ0FBQyxRQUFRLENBQUMsTUFBTSxDQUFDO29CQUNqQyxHQUFHLENBQUM7U0FDWDtRQUVELE1BQU0sR0FBRyxNQUFNLENBQUMsSUFBSSxFQUFFLENBQUM7UUFFdkIsSUFBSSxNQUFNLEtBQUssRUFBRSxFQUFFO1lBQ2YsT0FBTyxJQUFJLEdBQUcsZ0JBQWdCLENBQUMsUUFBUSxDQUFDLE1BQU0sQ0FBQyxDQUFDO1NBQ25EO1FBRUQsT0FBTyxNQUFNLENBQUM7SUFDbEIsQ0FBQztrSUF6SVEsK0JBQStCO3NIQUEvQiwrQkFBK0IseVhBZ0I3QixnQ0FBZ0MscUVDcEUvQyxrakZBOERBOzs0RkRWYSwrQkFBK0I7a0JBTDNDLFNBQVM7K0JBQ0ksNkJBQTZCO21OQVM5QixPQUFPO3NCQUFmLEtBQUs7Z0JBQ0csUUFBUTtzQkFBaEIsS0FBSztnQkFDRyxVQUFVO3NCQUFsQixLQUFLO2dCQUNHLFVBQVU7c0JBQWxCLEtBQUs7Z0JBQ0csOEJBQThCO3NCQUF0QyxLQUFLO2dCQUNHLHVCQUF1QjtzQkFBL0IsS0FBSztnQkFDSSxTQUFTO3NCQUFsQixNQUFNO2dCQU1DLGVBQWU7c0JBRHRCLFNBQVM7dUJBQUMsZ0NBQWdDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gwqkgMjAyMiBTb2xhcldpbmRzIFdvcmxkd2lkZSwgTExDLiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuLy9cbi8vIFBlcm1pc3Npb24gaXMgaGVyZWJ5IGdyYW50ZWQsIGZyZWUgb2YgY2hhcmdlLCB0byBhbnkgcGVyc29uIG9idGFpbmluZyBhIGNvcHlcbi8vICBvZiB0aGlzIHNvZnR3YXJlIGFuZCBhc3NvY2lhdGVkIGRvY3VtZW50YXRpb24gZmlsZXMgKHRoZSBcIlNvZnR3YXJlXCIpLCB0b1xuLy8gIGRlYWwgaW4gdGhlIFNvZnR3YXJlIHdpdGhvdXQgcmVzdHJpY3Rpb24sIGluY2x1ZGluZyB3aXRob3V0IGxpbWl0YXRpb24gdGhlXG4vLyAgcmlnaHRzIHRvIHVzZSwgY29weSwgbW9kaWZ5LCBtZXJnZSwgcHVibGlzaCwgZGlzdHJpYnV0ZSwgc3VibGljZW5zZSwgYW5kL29yXG4vLyAgc2VsbCBjb3BpZXMgb2YgdGhlIFNvZnR3YXJlLCBhbmQgdG8gcGVybWl0IHBlcnNvbnMgdG8gd2hvbSB0aGUgU29mdHdhcmUgaXNcbi8vICBmdXJuaXNoZWQgdG8gZG8gc28sIHN1YmplY3QgdG8gdGhlIGZvbGxvd2luZyBjb25kaXRpb25zOlxuLy9cbi8vIFRoZSBhYm92ZSBjb3B5cmlnaHQgbm90aWNlIGFuZCB0aGlzIHBlcm1pc3Npb24gbm90aWNlIHNoYWxsIGJlIGluY2x1ZGVkIGluXG4vLyAgYWxsIGNvcGllcyBvciBzdWJzdGFudGlhbCBwb3J0aW9ucyBvZiB0aGUgU29mdHdhcmUuXG4vL1xuLy8gVEhFIFNPRlRXQVJFIElTIFBST1ZJREVEIFwiQVMgSVNcIiwgV0lUSE9VVCBXQVJSQU5UWSBPRiBBTlkgS0lORCwgRVhQUkVTUyBPUlxuLy8gIElNUExJRUQsIElOQ0xVRElORyBCVVQgTk9UIExJTUlURUQgVE8gVEhFIFdBUlJBTlRJRVMgT0YgTUVSQ0hBTlRBQklMSVRZLFxuLy8gIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFIEFORCBOT05JTkZSSU5HRU1FTlQuIElOIE5PIEVWRU5UIFNIQUxMIFRIRVxuLy8gIEFVVEhPUlMgT1IgQ09QWVJJR0hUIEhPTERFUlMgQkUgTElBQkxFIEZPUiBBTlkgQ0xBSU0sIERBTUFHRVMgT1IgT1RIRVJcbi8vICBMSUFCSUxJVFksIFdIRVRIRVIgSU4gQU4gQUNUSU9OIE9GIENPTlRSQUNULCBUT1JUIE9SIE9USEVSV0lTRSwgQVJJU0lORyBGUk9NLFxuLy8gIE9VVCBPRiBPUiBJTiBDT05ORUNUSU9OIFdJVEggVEhFIFNPRlRXQVJFIE9SIFRIRSBVU0UgT1IgT1RIRVIgREVBTElOR1MgSU5cbi8vICBUSEUgU09GVFdBUkUuXG5cbmltcG9ydCB7XG4gICAgQ2hhbmdlRGV0ZWN0b3JSZWYsXG4gICAgQ29tcG9uZW50LFxuICAgIEV2ZW50RW1pdHRlcixcbiAgICBJbnB1dCxcbiAgICBPbkNoYW5nZXMsXG4gICAgT25EZXN0cm95LFxuICAgIE9uSW5pdCxcbiAgICBPdXRwdXQsXG4gICAgU2ltcGxlQ2hhbmdlcyxcbiAgICBWaWV3Q2hpbGQsXG59IGZyb20gXCJAYW5ndWxhci9jb3JlXCI7XG5pbXBvcnQgeyBGb3JtQnVpbGRlciwgRm9ybUdyb3VwLCBWYWxpZGF0b3JzIH0gZnJvbSBcIkBhbmd1bGFyL2Zvcm1zXCI7XG4vLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgaW1wb3J0L25vLWRlcHJlY2F0ZWRcbmltcG9ydCB7IGNvbWJpbmVMYXRlc3QsIFN1YmplY3QgfSBmcm9tIFwicnhqc1wiO1xuaW1wb3J0IHsgZmlsdGVyLCB0YWtlVW50aWwsIHRhcCB9IGZyb20gXCJyeGpzL29wZXJhdG9yc1wiO1xuXG5pbXBvcnQgeyBMb2dnZXJTZXJ2aWNlIH0gZnJvbSBcIkBub3ZhLXVpL2JpdHNcIjtcblxuaW1wb3J0IHsgUmVmcmVzaFJhdGVDb25maWd1cmF0b3JDb21wb25lbnQgfSBmcm9tIFwiLi9yZWZyZXNoLXJhdGUtY29uZmlndXJhdG9yL3JlZnJlc2gtcmF0ZS1jb25maWd1cmF0b3IuY29tcG9uZW50XCI7XG5pbXBvcnQge1xuICAgIFRpbWVVbml0LFxuICAgIFRJTUVfVU5JVFNfU0hPUlQsXG59IGZyb20gXCIuL3JlZnJlc2gtcmF0ZS1jb25maWd1cmF0b3IvdGltZS11bml0c1wiO1xuaW1wb3J0IHsgUmVmcmVzaGVyU2V0dGluZ3NTZXJ2aWNlIH0gZnJvbSBcIi4uLy4uLy4uLy4uLy4uL2NvbXBvbmVudHMvcHJvdmlkZXJzL3JlZnJlc2hlci1zZXR0aW5ncy5zZXJ2aWNlXCI7XG5pbXBvcnQgeyBJSGFzQ2hhbmdlRGV0ZWN0b3IsIElIYXNGb3JtIH0gZnJvbSBcIi4uLy4uLy4uLy4uLy4uL3R5cGVzXCI7XG5cbkBDb21wb25lbnQoe1xuICAgIHNlbGVjdG9yOiBcIm51aS1yZWZyZXNoZXItY29uZmlndXJhdGlvblwiLFxuICAgIHRlbXBsYXRlVXJsOiBcIi4vcmVmcmVzaGVyLWNvbmZpZ3VyYXRpb24uY29tcG9uZW50Lmh0bWxcIixcbiAgICBzdHlsZVVybHM6IFtcIi4vcmVmcmVzaGVyLWNvbmZpZ3VyYXRpb24uY29tcG9uZW50Lmxlc3NcIl0sXG59KVxuZXhwb3J0IGNsYXNzIFJlZnJlc2hlckNvbmZpZ3VyYXRpb25Db21wb25lbnRcbiAgICBpbXBsZW1lbnRzIE9uSW5pdCwgT25DaGFuZ2VzLCBPbkRlc3Ryb3ksIElIYXNDaGFuZ2VEZXRlY3RvciwgSUhhc0Zvcm1cbntcbiAgICBwdWJsaWMgc3RhdGljIGxhdGVMb2FkS2V5ID0gXCJSZWZyZXNoZXJDb25maWd1cmF0aW9uQ29tcG9uZW50XCI7XG5cbiAgICBASW5wdXQoKSBlbmFibGVkOiBib29sZWFuO1xuICAgIEBJbnB1dCgpIGludGVydmFsOiBudW1iZXI7XG4gICAgQElucHV0KCkgbWluU2Vjb25kczogbnVtYmVyID0gMTtcbiAgICBASW5wdXQoKSBtYXhTZWNvbmRzOiBudW1iZXIgPSA4NjQwMDtcbiAgICBASW5wdXQoKSBvdmVycmlkZURlZmF1bHRTZXR0aW5nc0NhcHRpb24gPSAkbG9jYWxpemVgQ3VzdG9tIHJlZnJlc2ggcmF0ZWA7XG4gICAgQElucHV0KCkgb3ZlcnJpZGVEZWZhdWx0U2V0dGluZ3MgPSB0cnVlO1xuICAgIEBPdXRwdXQoKSBmb3JtUmVhZHkgPSBuZXcgRXZlbnRFbWl0dGVyPEZvcm1Hcm91cD4oKTtcblxuICAgIHB1YmxpYyBmb3JtOiBGb3JtR3JvdXA7XG5cbiAgICBwcml2YXRlIGRlc3Ryb3llZCQgPSBuZXcgU3ViamVjdDx2b2lkPigpO1xuICAgIEBWaWV3Q2hpbGQoUmVmcmVzaFJhdGVDb25maWd1cmF0b3JDb21wb25lbnQpXG4gICAgcHJpdmF0ZSByZWZyZXNoUmF0ZUNvbXA6IFJlZnJlc2hSYXRlQ29uZmlndXJhdG9yQ29tcG9uZW50O1xuXG4gICAgY29uc3RydWN0b3IoXG4gICAgICAgIHB1YmxpYyBjaGFuZ2VEZXRlY3RvcjogQ2hhbmdlRGV0ZWN0b3JSZWYsXG4gICAgICAgIHByaXZhdGUgZm9ybUJ1aWxkZXI6IEZvcm1CdWlsZGVyLFxuICAgICAgICBwcml2YXRlIGxvZ2dlcjogTG9nZ2VyU2VydmljZSxcbiAgICAgICAgcHVibGljIHJlZnJlc2hlclNldHRpbmdzOiBSZWZyZXNoZXJTZXR0aW5nc1NlcnZpY2UsXG4gICAgICAgIHByaXZhdGUgY2Q6IENoYW5nZURldGVjdG9yUmVmXG4gICAgKSB7fVxuXG4gICAgcHVibGljIG5nT25Jbml0KCk6IHZvaWQge1xuICAgICAgICB0aGlzLmZvcm0gPSB0aGlzLmZvcm1CdWlsZGVyLmdyb3VwKHtcbiAgICAgICAgICAgIGVuYWJsZWQ6IFt0cnVlLCBbVmFsaWRhdG9ycy5yZXF1aXJlZF1dLFxuICAgICAgICAgICAgb3ZlcnJpZGVEZWZhdWx0U2V0dGluZ3M6IFtcbiAgICAgICAgICAgICAgICB0aGlzLm92ZXJyaWRlRGVmYXVsdFNldHRpbmdzLFxuICAgICAgICAgICAgICAgIFtWYWxpZGF0b3JzLnJlcXVpcmVkXSxcbiAgICAgICAgICAgIF0sXG4gICAgICAgICAgICBpbnRlcnZhbDogW3RoaXMuaW50ZXJ2YWwgPz8gMCwgW1ZhbGlkYXRvcnMucmVxdWlyZWRdXSxcbiAgICAgICAgfSk7XG5cbiAgICAgICAgdGhpcy5mb3JtLnN0YXR1c0NoYW5nZXNcbiAgICAgICAgICAgIC5waXBlKHRha2VVbnRpbCh0aGlzLmRlc3Ryb3llZCQpKVxuICAgICAgICAgICAgLnN1YnNjcmliZSgoKSA9PiB7XG4gICAgICAgICAgICAgICAgdGhpcy5mb3JtLm1hcmtBbGxBc1RvdWNoZWQoKTtcbiAgICAgICAgICAgICAgICB0aGlzLmNkLmRldGVjdENoYW5nZXMoKTtcbiAgICAgICAgICAgIH0pO1xuXG4gICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBpbXBvcnQvbm8tZGVwcmVjYXRlZFxuICAgICAgICBjb21iaW5lTGF0ZXN0KFtcbiAgICAgICAgICAgIHRoaXMuZm9ybS5jb250cm9sc1tcImVuYWJsZWRcIl0udmFsdWVDaGFuZ2VzLFxuICAgICAgICAgICAgdGhpcy5mb3JtLmNvbnRyb2xzW1wib3ZlcnJpZGVEZWZhdWx0U2V0dGluZ3NcIl0udmFsdWVDaGFuZ2VzLFxuICAgICAgICBdKVxuICAgICAgICAgICAgLnBpcGUoXG4gICAgICAgICAgICAgICAgZmlsdGVyKCh2YWx1ZXMpID0+IHZhbHVlcy5zb21lKCh2KSA9PiAhdikpLFxuICAgICAgICAgICAgICAgIHRhcCh0aGlzLnJlc2V0SW50ZXJ2YWwpLFxuICAgICAgICAgICAgICAgIHRha2VVbnRpbCh0aGlzLmRlc3Ryb3llZCQpXG4gICAgICAgICAgICApXG4gICAgICAgICAgICAuc3Vic2NyaWJlKCk7XG5cbiAgICAgICAgdGhpcy5mb3JtUmVhZHkuZW1pdCh0aGlzLmZvcm0pO1xuICAgIH1cblxuICAgIHB1YmxpYyBuZ09uQ2hhbmdlcyhjaGFuZ2VzOiBTaW1wbGVDaGFuZ2VzKTogdm9pZCB7XG4gICAgICAgIGlmIChjaGFuZ2VzLmVuYWJsZWQpIHtcbiAgICAgICAgICAgIHRoaXMuZm9ybT8uZ2V0KFwiZW5hYmxlZFwiKT8ucGF0Y2hWYWx1ZSh0aGlzLmVuYWJsZWQpO1xuICAgICAgICB9XG4gICAgICAgIGlmIChjaGFuZ2VzLmludGVydmFsKSB7XG4gICAgICAgICAgICB0aGlzLmZvcm0/LmdldChcImludGVydmFsXCIpPy5wYXRjaFZhbHVlKHRoaXMuaW50ZXJ2YWwpO1xuICAgICAgICB9XG4gICAgICAgIGlmIChjaGFuZ2VzLm92ZXJyaWRlRGVmYXVsdFNldHRpbmdzKSB7XG4gICAgICAgICAgICB0aGlzLmZvcm1cbiAgICAgICAgICAgICAgICA/LmdldChcIm92ZXJyaWRlRGVmYXVsdFNldHRpbmdzXCIpXG4gICAgICAgICAgICAgICAgPy5wYXRjaFZhbHVlKHRoaXMub3ZlcnJpZGVEZWZhdWx0U2V0dGluZ3MpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcHVibGljIG5nT25EZXN0cm95KCk6IHZvaWQge1xuICAgICAgICB0aGlzLmRlc3Ryb3llZCQubmV4dCgpO1xuICAgICAgICB0aGlzLmRlc3Ryb3llZCQuY29tcGxldGUoKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgZ2V0SGVhZGVyU3VidGl0bGUoKTogc3RyaW5nIHtcbiAgICAgICAgbGV0IHJlc3VsdCA9IFwiXCI7XG4gICAgICAgIGlmICh0aGlzLmZvcm0uZ2V0KFwiZW5hYmxlZFwiKT8udmFsdWUpIHtcbiAgICAgICAgICAgIHJlc3VsdCArPSAkbG9jYWxpemVgRW5hYmxlZGA7XG4gICAgICAgICAgICByZXN1bHQgKz0gXCIsIFwiO1xuICAgICAgICAgICAgaWYgKHRoaXMuZm9ybS5nZXQoXCJvdmVycmlkZURlZmF1bHRTZXR0aW5nc1wiKT8udmFsdWUpIHtcbiAgICAgICAgICAgICAgICByZXN1bHQgKz0gdGhpcy5nZXREdXJhdGlvbkxhYmVsKFxuICAgICAgICAgICAgICAgICAgICB0aGlzLmZvcm0uZ2V0KFwiaW50ZXJ2YWxcIik/LnZhbHVlXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgcmVzdWx0ICs9XG4gICAgICAgICAgICAgICAgICAgICRsb2NhbGl6ZWBVc2UgZGVmYXVsdCB2YWx1ZWAgK1xuICAgICAgICAgICAgICAgICAgICBcIiAoXCIgK1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmdldER1cmF0aW9uTGFiZWwoXG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLnJlZnJlc2hlclNldHRpbmdzLnJlZnJlc2hSYXRlU2Vjb25kc1xuICAgICAgICAgICAgICAgICAgICApICtcbiAgICAgICAgICAgICAgICAgICAgXCIpXCI7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICByZXN1bHQgKz0gJGxvY2FsaXplYERpc2FibGVkYDtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgfVxuXG4gICAgLy8gVE9ETzogbWFrZSByZXVzYWJsZVxuICAgIHB1YmxpYyBnZXREdXJhdGlvbkxhYmVsKHNlY29uZHM6IG51bWJlcik6IHN0cmluZyB7XG4gICAgICAgIGxldCB0b3RhbFNlY29uZHMgPSBzZWNvbmRzO1xuICAgICAgICBsZXQgcmVzdWx0OiBzdHJpbmcgPSBcIlwiO1xuICAgICAgICBjb25zdCBob3VycyA9IE1hdGguZmxvb3IodG90YWxTZWNvbmRzIC8gMzYwMCk7XG5cbiAgICAgICAgdG90YWxTZWNvbmRzICU9IDM2MDA7XG4gICAgICAgIGNvbnN0IG1pbnV0ZXMgPSBNYXRoLmZsb29yKHRvdGFsU2Vjb25kcyAvIDYwKTtcblxuICAgICAgICBjb25zdCBjYWxjdWxhdGVkU2Vjb25kcyA9IHRvdGFsU2Vjb25kcyAlIDYwO1xuXG4gICAgICAgIGlmIChob3VycyA+IDApIHtcbiAgICAgICAgICAgIHJlc3VsdCArPSBob3VycyArIFwiIFwiICsgVElNRV9VTklUU19TSE9SVFtUaW1lVW5pdC5Ib3VyXSArIFwiIFwiO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKG1pbnV0ZXMgPiAwKSB7XG4gICAgICAgICAgICByZXN1bHQgKz0gbWludXRlcyArIFwiIFwiICsgVElNRV9VTklUU19TSE9SVFtUaW1lVW5pdC5NaW51dGVdICsgXCIgXCI7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoY2FsY3VsYXRlZFNlY29uZHMgPiAwKSB7XG4gICAgICAgICAgICByZXN1bHQgKz1cbiAgICAgICAgICAgICAgICBjYWxjdWxhdGVkU2Vjb25kcyArXG4gICAgICAgICAgICAgICAgXCIgXCIgK1xuICAgICAgICAgICAgICAgIFRJTUVfVU5JVFNfU0hPUlRbVGltZVVuaXQuU2Vjb25kXSArXG4gICAgICAgICAgICAgICAgXCIgXCI7XG4gICAgICAgIH1cblxuICAgICAgICByZXN1bHQgPSByZXN1bHQudHJpbSgpO1xuXG4gICAgICAgIGlmIChyZXN1bHQgPT09IFwiXCIpIHtcbiAgICAgICAgICAgIHJldHVybiBcIjAgXCIgKyBUSU1FX1VOSVRTX1NIT1JUW1RpbWVVbml0LlNlY29uZF07XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gcmVzdWx0O1xuICAgIH1cblxuICAgIHByaXZhdGUgcmVzZXRJbnRlcnZhbCA9ICgpID0+IHtcbiAgICAgICAgdGhpcy5yZWZyZXNoUmF0ZUNvbXAucmVzZXRVbml0cygpO1xuICAgICAgICB0aGlzLmZvcm0uZ2V0KFwiaW50ZXJ2YWxcIik/LnNldFZhbHVlKHRoaXMuaW50ZXJ2YWwgfHwgdGhpcy5taW5TZWNvbmRzKTtcbiAgICB9O1xufVxuIiwiPG51aS13aWRnZXQtZWRpdG9yLWFjY29yZGlvblxuICAgIFtmb3JtR3JvdXBdPVwiZm9ybVwiXG4gICAgW3N0YXRlXT1cImZvcm0gfCBudWlXaWRnZXRFZGl0b3JBY2NvcmRpb25Gb3JtU3RhdGUgfCBhc3luY1wiXG4+XG4gICAgPGRpdiBhY2NvcmRpb25IZWFkZXIgY2xhc3M9XCJkLWZsZXggYWxpZ24taXRlbXMtY2VudGVyIHB4LTQgcHktMlwiPlxuICAgICAgICA8bnVpLWljb25cbiAgICAgICAgICAgIGNsYXNzPVwiYWxpZ24tc2VsZi1zdGFydCBwdC0yXCJcbiAgICAgICAgICAgIGljb25Db2xvcj1cImdyYXlcIlxuICAgICAgICAgICAgW2ljb25dPVwiZm9ybSB8IG51aUZvcm1IZWFkZXJJY29uUGlwZSA6ICdyZXNldCcgfCBhc3luY1wiXG4gICAgICAgID48L251aS1pY29uPlxuICAgICAgICA8ZGl2IGNsYXNzPVwiZC1mbGV4IGZsZXgtY29sdW1uIG1sLTQgcHQtMVwiPlxuICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJudWktdGV4dC1sYWJlbFwiIGkxOG4+UmVmcmVzaDwvc3Bhbj5cbiAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJudWktdGV4dC1zZWNvbmRhcnlcIiBbdGl0bGVdPVwiZ2V0SGVhZGVyU3VidGl0bGUoKVwiPlxuICAgICAgICAgICAgICAgIHt7IGdldEhlYWRlclN1YnRpdGxlKCkgfX1cbiAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICA8L2Rpdj5cbiAgICA8L2Rpdj5cbiAgICA8ZGl2XG4gICAgICAgIGNsYXNzPVwiZC1mbGV4IGZsZXgtY29sdW1uIG51aS1yZWZyZXNoZXItY29uZmlndXJhdGlvbl9fYWNjb3JkaW9uLWNvbnRlbnRcIlxuICAgID5cbiAgICAgICAgPGRpdj5cbiAgICAgICAgICAgIDxudWktZm9ybS1maWVsZCBbY29udHJvbF09XCJmb3JtLmdldCgnZW5hYmxlZCcpXCI+XG4gICAgICAgICAgICAgICAgPG51aS1zd2l0Y2ggZm9ybUNvbnRyb2xOYW1lPVwiZW5hYmxlZFwiIGkxOG5cbiAgICAgICAgICAgICAgICAgICAgPlJlZnJlc2ggd2lkZ2V0IHBlcmlvZGljYWxseTwvbnVpLXN3aXRjaFxuICAgICAgICAgICAgICAgID5cbiAgICAgICAgICAgIDwvbnVpLWZvcm0tZmllbGQ+XG4gICAgICAgIDwvZGl2PlxuICAgICAgICA8ZGl2IFtjbGFzcy5oaWRkZW5dPVwiIWZvcm0uZ2V0KCdlbmFibGVkJyk/LnZhbHVlXCI+XG4gICAgICAgICAgICA8ZGl2IGNsYXNzPVwibXQtNFwiPlxuICAgICAgICAgICAgICAgIDxudWktZm9ybS1maWVsZCBbY29udHJvbF09XCJmb3JtLmdldCgnb3ZlcnJpZGVEZWZhdWx0U2V0dGluZ3MnKVwiPlxuICAgICAgICAgICAgICAgICAgICA8bnVpLXN3aXRjaCBmb3JtQ29udHJvbE5hbWU9XCJvdmVycmlkZURlZmF1bHRTZXR0aW5nc1wiXG4gICAgICAgICAgICAgICAgICAgICAgICA+e3sgb3ZlcnJpZGVEZWZhdWx0U2V0dGluZ3NDYXB0aW9uIH19XG4gICAgICAgICAgICAgICAgICAgICAgICA8ZGl2XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY2xhc3M9XCJudWktaGVscC1oaW50XCJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAqbmdJZj1cIiFmb3JtLmdldCgnb3ZlcnJpZGVEZWZhdWx0U2V0dGluZ3MnKT8udmFsdWVcIlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGkxOG5cbiAgICAgICAgICAgICAgICAgICAgICAgID5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBCeSBkZWZhdWx0LCB0aGUgd2lkZ2V0IHdpbGwgcmVmcmVzaCBldmVyeVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHt7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdldER1cmF0aW9uTGFiZWwoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZWZyZXNoZXJTZXR0aW5ncy5yZWZyZXNoUmF0ZVNlY29uZHNcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH19LlxuICAgICAgICAgICAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICAgICAgICAgIDwvbnVpLXN3aXRjaD5cbiAgICAgICAgICAgICAgICA8L251aS1mb3JtLWZpZWxkPlxuICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICA8ZGl2XG4gICAgICAgICAgICAgICAgW2NsYXNzLmhpZGRlbl09XCIhZm9ybS5nZXQoJ292ZXJyaWRlRGVmYXVsdFNldHRpbmdzJyk/LnZhbHVlXCJcbiAgICAgICAgICAgICAgICBjbGFzcz1cIm10LTRcIlxuICAgICAgICAgICAgPlxuICAgICAgICAgICAgICAgIDxudWktZm9ybS1maWVsZCBbY29udHJvbF09XCJmb3JtLmdldCgnaW50ZXJ2YWwnKVwiPlxuICAgICAgICAgICAgICAgICAgICA8bnVpLXJlZnJlc2gtcmF0ZS1jb25maWd1cmF0b3JcbiAgICAgICAgICAgICAgICAgICAgICAgIFttaW5TZWNvbmRzXT1cIm1pblNlY29uZHNcIlxuICAgICAgICAgICAgICAgICAgICAgICAgW21heFNlY29uZHNdPVwibWF4U2Vjb25kc1wiXG4gICAgICAgICAgICAgICAgICAgICAgICBmb3JtQ29udHJvbE5hbWU9XCJpbnRlcnZhbFwiXG4gICAgICAgICAgICAgICAgICAgID48L251aS1yZWZyZXNoLXJhdGUtY29uZmlndXJhdG9yPlxuICAgICAgICAgICAgICAgIDwvbnVpLWZvcm0tZmllbGQ+XG4gICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgPC9kaXY+XG4gICAgPC9kaXY+XG48L251aS13aWRnZXQtZWRpdG9yLWFjY29yZGlvbj5cbiJdfQ==