@c8y/ngx-components
Version:
Angular modules for Cumulocity IoT applications
174 lines • 49.8 kB
JavaScript
import { A11yModule } from '@angular/cdk/a11y';
import { Component, EventEmitter, inject, Input, Output } from '@angular/core';
import { FormBuilder, FormsModule } from '@angular/forms';
import { ClipboardService, ContextRouteService, CoreModule, gettext, ViewContext } from '@c8y/ngx-components';
import { BsDropdownModule } from 'ngx-bootstrap/dropdown';
import { TooltipModule } from 'ngx-bootstrap/tooltip';
import { WorkspaceConfigurationService } from './workspace-configuration.service';
import { ActivatedRoute, Router } from '@angular/router';
import { NameGeneratorService } from './name-generator.service';
import * as i0 from "@angular/core";
import * as i1 from "@c8y/ngx-components";
import * as i2 from "@angular/common";
import * as i3 from "@angular/forms";
import * as i4 from "ngx-bootstrap/dropdown";
import * as i5 from "@angular/cdk/a11y";
import * as i6 from "ngx-bootstrap/tooltip";
export class WorkspaceConfigComponent {
constructor() {
this.onConfigurationChange = new EventEmitter();
this.configurations = [];
this.activeConfigTooltip = gettext('Active configuration cannot be removed');
this.removeConfigTooltip = gettext('Remove configuration');
this.formBuilder = inject(FormBuilder);
this.workspaceConfigurationService = inject(WorkspaceConfigurationService);
this.contextRouteService = inject(ContextRouteService);
this.clipboardService = inject(ClipboardService);
this.activatedRoute = inject(ActivatedRoute);
this.router = inject(Router);
this.nameGeneratorService = inject(NameGeneratorService);
}
ngOnInit() {
this.initializeContextSourceId();
this.initializeConfigurations();
this.initWorkspaceForm();
}
ngOnChanges(changes) {
if (changes.updatedConfig && !changes.updatedConfig.firstChange) {
this.updateConfigurations();
}
}
addConfig(duplicatedConfig) {
const name = this.nameGeneratorService.generateName();
const workspace = {
id: new Date().toISOString(),
label: name,
config: { datapoints: [], alarmsEventsConfigs: [] }
};
if (duplicatedConfig) {
workspace.config = duplicatedConfig;
}
this.configurations = [workspace, ...this.configurations];
this.initWorkspaceForm();
this.changeConfiguration(true, workspace);
}
changeConfiguration(selected, configuration) {
if (!selected) {
return;
}
this.currentConfiguration = configuration;
localStorage.setItem(this.workspaceConfigurationService.LOCAL_STORAGE_DEFAULT_ID_KEY, this.currentConfiguration.id);
this.onConfigurationChange.emit(configuration.config);
}
updateConfigurationLabel(configuration) {
this.configurations = this.configurations.map(c => c.id === configuration.id ? configuration : c);
this.workspaceConfigurationService.saveConfigurations(this.configurations, this.currentConfiguration?.id || '');
this.currentConfiguration = configuration;
this.onConfigurationChange.emit(configuration.config);
}
deleteConfiguration(configuration) {
this.configurations = this.configurations.filter(c => c.id !== configuration.id);
this.initWorkspaceForm();
this.workspaceConfigurationService.saveConfigurations(this.configurations, this.currentConfiguration?.id || '');
}
clearAll() {
this.configurations = [this.currentConfiguration];
this.initWorkspaceForm();
this.workspaceConfigurationService.saveConfigurations(this.configurations, this.currentConfiguration?.id || '');
}
async shareConfig(configuration) {
await this.clipboardService.writeText(JSON.stringify(configuration.config));
}
addConfigFromUrl(queryParams) {
this.addConfig();
const config = JSON.parse(queryParams.config);
this.onConfigurationChange.emit(config);
}
updateConfigurations() {
this.currentConfiguration.config = this.updatedConfig;
this.configurations = this.configurations.map(currentConfig => currentConfig.id === this.currentConfiguration.id ? this.currentConfiguration : currentConfig);
const queryParams = {
configId: this.currentConfiguration.id,
label: this.currentConfiguration.label,
config: JSON.stringify(this.updatedConfig)
};
this.workspaceConfigurationService.saveConfigurations(this.configurations, this.currentConfiguration.id);
const control = this.configurationsFormGroup.controls['configurations'];
const index = this.configurations.findIndex(c => c.id === this.currentConfiguration.id);
if (index !== -1) {
control.at(index).patchValue({
label: this.currentConfiguration.label,
config: this.currentConfiguration.config,
id: this.currentConfiguration.id
});
}
this.router.navigate([], { queryParams });
}
initializeConfigurations() {
const configurations = this.workspaceConfigurationService.getConfigurations();
const defaultId = this.workspaceConfigurationService.getDefaultConfigurationId();
const queryParams = this.router.parseUrl(this.router.url).queryParams;
if (configurations.length) {
this.configurations = configurations;
this.currentConfiguration =
this.configurations.find(c => c.id === defaultId) || this.configurations[0];
this.onConfigurationChange.emit(this.currentConfiguration.config);
if (queryParams?.configId && !this.configurations.find(c => c.id === queryParams.configId)) {
this.addConfigFromUrl(queryParams);
}
else if (queryParams?.configId &&
this.configurations.find(c => c.id === queryParams.configId) &&
this.currentConfiguration.id !== queryParams.configId) {
this.currentConfiguration = this.configurations.find(c => c.id === queryParams.configId);
this.changeConfiguration(true, this.currentConfiguration);
}
}
if (!this.currentConfiguration) {
if (Object.keys(queryParams).length === 0) {
this.addConfig();
return;
}
this.addConfigFromUrl(queryParams);
}
}
initWorkspaceForm() {
this.configurationsFormGroup = this.formBuilder.group({
configurations: this.formBuilder.array([])
});
this.patchForm();
}
patchForm() {
const control = this.configurationsFormGroup.controls['configurations'];
this.configurations.forEach(workspace => {
control.push(this.patchValues(workspace));
});
}
patchValues(workspace) {
return this.formBuilder.group({
label: [workspace.label],
config: [workspace.config],
id: [workspace.id]
});
}
initializeContextSourceId() {
const routeContext = this.contextRouteService.getContextData(this.activatedRoute);
if (!routeContext) {
return;
}
const { context, contextData } = routeContext;
if ([ViewContext.Device, ViewContext.Group].includes(context)) {
this.workspaceConfigurationService.contextIdSignal.set(contextData?.id);
}
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: WorkspaceConfigComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: WorkspaceConfigComponent, isStandalone: true, selector: "c8y-workspace-config", inputs: { updatedConfig: "updatedConfig" }, outputs: { onConfigurationChange: "onConfigurationChange" }, usesOnChanges: true, ngImport: i0, template: "<div\n class=\"dropdown\"\n #actionbar_dropdown=\"bs-dropdown\"\n [cdkTrapFocus]=\"actionbar_dropdown.isOpen\"\n dropdown\n [insideClick]=\"true\"\n>\n\n <button\n class=\"dropdown-toggle form-control l-h-tight d-flex a-i-center\"\n attr.aria-label=\"{{ currentConfiguration.label }}\"\n tooltip=\"{{ 'Selected configuration' | translate }}\"\n placement=\"top\"\n container=\"body\"\n data-cy=\"current-configuration-dropdown-button\"\n [adaptivePosition]=\"false\"\n [delay]=\"500\"\n dropdownToggle\n >\n <i\n class=\"m-r-4\"\n c8yIcon=\"list\"\n ></i>\n <div class=\"d-col text-left fit-w\">\n <span class=\"text-12\">\n {{ 'Configuration' | translate }}\n </span>\n <span class=\"text-10 text-muted text-truncate\">\n {{ currentConfiguration.label }}\n </span>\n </div>\n <span class=\"caret m-r-16 m-l-4\"></span>\n </button>\n <div\n class=\"dropdown-menu dropdown-menu-wide dropdown-menu-action-bar\"\n *dropdownMenu\n >\n <div class=\"sticky-top separator-bottom p-t-8 p-b-8 p-l-16 p-r-16\">\n <p>\n <strong>{{ 'Data explorer configurations' | translate }}</strong>\n </p>\n <p>\n <small>{{ 'Easily switch and manage configurations.' | translate }}</small>\n </p>\n </div>\n <c8y-list-group class=\"no-border-last\">\n <form [formGroup]=\"configurationsFormGroup\">\n <div formArrayName=\"configurations\">\n <c8y-li\n class=\"p-0\"\n *ngFor=\"\n let configuration of configurationsFormGroup.controls.configurations['controls'];\n let i = index\n \"\n [dense]=\"true\"\n >\n <c8y-li-radio\n [selected]=\"configuration.value.id === currentConfiguration.id\"\n (onSelect)=\"changeConfiguration($event, configuration.value)\"\n ></c8y-li-radio>\n <div class=\"d-flex a-i-center gap-8\">\n <div\n class=\"flex-grow min-width-0\"\n [formGroupName]=\"i\"\n >\n <label\n class=\"editable\"\n [ngClass]=\"{\n updated:\n configuration.controls.label.touched && configuration.controls.label.dirty\n }\"\n >\n <input\n class=\"form-control\"\n [style.width.ch]=\"configuration.value.label || 25\"\n [attr.aria-label]=\"'Configuration label' | translate\"\n placeholder=\"{{ 'Configuration 1' | translate }}\"\n type=\"text\"\n autocomplete=\"off\"\n required\n formControlName=\"label\"\n (blur)=\"updateConfigurationLabel(configuration.value)\"\n />\n </label>\n </div>\n <div class=\"flex-nogrow d-flex gap-8\">\n <button\n class=\"btn-dot btn\"\n [attr.aria-label]=\"'Duplicate configuration' | translate\"\n tooltip=\"{{ 'Duplicate configuration' | translate }}\"\n placement=\"left\"\n (click)=\"addConfig(configuration.value.config)\"\n [delay]=\"500\"\n >\n <i c8yIcon=\"copy\"></i>\n </button>\n\n <button\n class=\"btn-dot btn btn-dot--danger\"\n [attr.aria-label]=\"'Remove configurations' | translate\"\n tooltip=\"{{\n (configuration.value.id === currentConfiguration.id\n ? activeConfigTooltip\n : removeConfigTooltip\n ) | translate\n }}\"\n placement=\"left\"\n [delay]=\"500\"\n (click)=\"$event.stopPropagation(); deleteConfiguration(configuration.value)\"\n [disabled]=\"configuration.value.id === currentConfiguration.id\"\n >\n <i c8yIcon=\"minus-circle\"></i>\n </button>\n </div>\n </div>\n </c8y-li>\n </div>\n </form>\n </c8y-list-group>\n <div class=\"sticky-bottom separator-top\">\n <div class=\"d-flex p-l-16 p-r-16 p-t-8 p-b-8\">\n <button\n class=\"btn btn-danger btn-sm flex-grow\"\n (click)=\"clearAll()\"\n [disabled]=\"configurations.length < 2\"\n >\n <i [c8yIcon]=\"'delete'\"></i>\n {{ 'Delete all configurations' | translate }}\n </button>\n <button\n class=\"btn btn-default btn-sm flex-grow\"\n type=\"button\"\n (click)=\"addConfig()\"\n >\n <i [c8yIcon]=\"'add-circle-outline'\"></i>\n {{ 'Add configuration' | translate }}\n </button>\n </div>\n </div>\n </div>\n</div>\n", dependencies: [{ kind: "ngmodule", type: CoreModule }, { kind: "directive", type: i1.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "pipe", type: i1.C8yTranslatePipe, name: "translate" }, { kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i3.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i3.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: i3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i3.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1.RequiredInputPlaceholderDirective, selector: "input[required], input[formControlName]" }, { kind: "component", type: i1.ListGroupComponent, selector: "c8y-list-group" }, { kind: "component", type: i1.ListItemComponent, selector: "c8y-list-item, c8y-li", inputs: ["active", "highlighted", "emptyActions", "dense", "collapsed", "selectable"], outputs: ["collapsedChange"] }, { kind: "component", type: i1.ListItemRadioComponent, selector: "c8y-list-item-radio, c8y-li-radio", inputs: ["selected", "name", "disabled", "value"], outputs: ["onSelect"] }, { kind: "directive", type: i3.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i3.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i3.FormGroupName, selector: "[formGroupName]", inputs: ["formGroupName"] }, { kind: "directive", type: i3.FormArrayName, selector: "[formArrayName]", inputs: ["formArrayName"] }, { kind: "ngmodule", type: BsDropdownModule }, { kind: "directive", type: i4.BsDropdownMenuDirective, selector: "[bsDropdownMenu],[dropdownMenu]", exportAs: ["bs-dropdown-menu"] }, { kind: "directive", type: i4.BsDropdownToggleDirective, selector: "[bsDropdownToggle],[dropdownToggle]", exportAs: ["bs-dropdown-toggle"] }, { kind: "directive", type: i4.BsDropdownDirective, selector: "[bsDropdown], [dropdown]", inputs: ["placement", "triggers", "container", "dropup", "autoClose", "isAnimated", "insideClick", "isDisabled", "isOpen"], outputs: ["isOpenChange", "onShown", "onHidden"], exportAs: ["bs-dropdown"] }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: A11yModule }, { kind: "directive", type: i5.CdkTrapFocus, selector: "[cdkTrapFocus]", inputs: ["cdkTrapFocus", "cdkTrapFocusAutoCapture"], exportAs: ["cdkTrapFocus"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i6.TooltipDirective, selector: "[tooltip], [tooltipHtml]", inputs: ["adaptivePosition", "tooltip", "placement", "triggers", "container", "containerClass", "boundariesElement", "isOpen", "isDisabled", "delay", "tooltipHtml", "tooltipPlacement", "tooltipIsOpen", "tooltipEnable", "tooltipAppendToBody", "tooltipAnimation", "tooltipClass", "tooltipContext", "tooltipPopupDelay", "tooltipFadeDuration", "tooltipTrigger"], outputs: ["tooltipChange", "onShown", "onHidden", "tooltipStateChanged"], exportAs: ["bs-tooltip"] }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: WorkspaceConfigComponent, decorators: [{
type: Component,
args: [{ selector: 'c8y-workspace-config', standalone: true, imports: [CoreModule, BsDropdownModule, FormsModule, A11yModule, TooltipModule], template: "<div\n class=\"dropdown\"\n #actionbar_dropdown=\"bs-dropdown\"\n [cdkTrapFocus]=\"actionbar_dropdown.isOpen\"\n dropdown\n [insideClick]=\"true\"\n>\n\n <button\n class=\"dropdown-toggle form-control l-h-tight d-flex a-i-center\"\n attr.aria-label=\"{{ currentConfiguration.label }}\"\n tooltip=\"{{ 'Selected configuration' | translate }}\"\n placement=\"top\"\n container=\"body\"\n data-cy=\"current-configuration-dropdown-button\"\n [adaptivePosition]=\"false\"\n [delay]=\"500\"\n dropdownToggle\n >\n <i\n class=\"m-r-4\"\n c8yIcon=\"list\"\n ></i>\n <div class=\"d-col text-left fit-w\">\n <span class=\"text-12\">\n {{ 'Configuration' | translate }}\n </span>\n <span class=\"text-10 text-muted text-truncate\">\n {{ currentConfiguration.label }}\n </span>\n </div>\n <span class=\"caret m-r-16 m-l-4\"></span>\n </button>\n <div\n class=\"dropdown-menu dropdown-menu-wide dropdown-menu-action-bar\"\n *dropdownMenu\n >\n <div class=\"sticky-top separator-bottom p-t-8 p-b-8 p-l-16 p-r-16\">\n <p>\n <strong>{{ 'Data explorer configurations' | translate }}</strong>\n </p>\n <p>\n <small>{{ 'Easily switch and manage configurations.' | translate }}</small>\n </p>\n </div>\n <c8y-list-group class=\"no-border-last\">\n <form [formGroup]=\"configurationsFormGroup\">\n <div formArrayName=\"configurations\">\n <c8y-li\n class=\"p-0\"\n *ngFor=\"\n let configuration of configurationsFormGroup.controls.configurations['controls'];\n let i = index\n \"\n [dense]=\"true\"\n >\n <c8y-li-radio\n [selected]=\"configuration.value.id === currentConfiguration.id\"\n (onSelect)=\"changeConfiguration($event, configuration.value)\"\n ></c8y-li-radio>\n <div class=\"d-flex a-i-center gap-8\">\n <div\n class=\"flex-grow min-width-0\"\n [formGroupName]=\"i\"\n >\n <label\n class=\"editable\"\n [ngClass]=\"{\n updated:\n configuration.controls.label.touched && configuration.controls.label.dirty\n }\"\n >\n <input\n class=\"form-control\"\n [style.width.ch]=\"configuration.value.label || 25\"\n [attr.aria-label]=\"'Configuration label' | translate\"\n placeholder=\"{{ 'Configuration 1' | translate }}\"\n type=\"text\"\n autocomplete=\"off\"\n required\n formControlName=\"label\"\n (blur)=\"updateConfigurationLabel(configuration.value)\"\n />\n </label>\n </div>\n <div class=\"flex-nogrow d-flex gap-8\">\n <button\n class=\"btn-dot btn\"\n [attr.aria-label]=\"'Duplicate configuration' | translate\"\n tooltip=\"{{ 'Duplicate configuration' | translate }}\"\n placement=\"left\"\n (click)=\"addConfig(configuration.value.config)\"\n [delay]=\"500\"\n >\n <i c8yIcon=\"copy\"></i>\n </button>\n\n <button\n class=\"btn-dot btn btn-dot--danger\"\n [attr.aria-label]=\"'Remove configurations' | translate\"\n tooltip=\"{{\n (configuration.value.id === currentConfiguration.id\n ? activeConfigTooltip\n : removeConfigTooltip\n ) | translate\n }}\"\n placement=\"left\"\n [delay]=\"500\"\n (click)=\"$event.stopPropagation(); deleteConfiguration(configuration.value)\"\n [disabled]=\"configuration.value.id === currentConfiguration.id\"\n >\n <i c8yIcon=\"minus-circle\"></i>\n </button>\n </div>\n </div>\n </c8y-li>\n </div>\n </form>\n </c8y-list-group>\n <div class=\"sticky-bottom separator-top\">\n <div class=\"d-flex p-l-16 p-r-16 p-t-8 p-b-8\">\n <button\n class=\"btn btn-danger btn-sm flex-grow\"\n (click)=\"clearAll()\"\n [disabled]=\"configurations.length < 2\"\n >\n <i [c8yIcon]=\"'delete'\"></i>\n {{ 'Delete all configurations' | translate }}\n </button>\n <button\n class=\"btn btn-default btn-sm flex-grow\"\n type=\"button\"\n (click)=\"addConfig()\"\n >\n <i [c8yIcon]=\"'add-circle-outline'\"></i>\n {{ 'Add configuration' | translate }}\n </button>\n </div>\n </div>\n </div>\n</div>\n" }]
}], propDecorators: { updatedConfig: [{
type: Input
}], onConfigurationChange: [{
type: Output
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid29ya3NwYWNlLWNvbmZpZ3VyYXRpb24uY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vZGF0YXBvaW50LWV4cGxvcmVyL3ZpZXcvY29uZmlndXJhdGlvbi93b3Jrc3BhY2UtY29uZmlndXJhdGlvbi5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi8uLi9kYXRhcG9pbnQtZXhwbG9yZXIvdmlldy9jb25maWd1cmF0aW9uL3dvcmtzcGFjZS1jb25maWd1cmF0aW9uLmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxtQkFBbUIsQ0FBQztBQUMvQyxPQUFPLEVBQ0wsU0FBUyxFQUNULFlBQVksRUFDWixNQUFNLEVBQ04sS0FBSyxFQUdMLE1BQU0sRUFFUCxNQUFNLGVBQWUsQ0FBQztBQUN2QixPQUFPLEVBQWEsV0FBVyxFQUFhLFdBQVcsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQ2hGLE9BQU8sRUFDTCxnQkFBZ0IsRUFDaEIsbUJBQW1CLEVBQ25CLFVBQVUsRUFDVixPQUFPLEVBQ1AsV0FBVyxFQUNaLE1BQU0scUJBQXFCLENBQUM7QUFDN0IsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFDMUQsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLHVCQUF1QixDQUFDO0FBR3RELE9BQU8sRUFBRSw2QkFBNkIsRUFBRSxNQUFNLG1DQUFtQyxDQUFDO0FBQ2xGLE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDekQsT0FBTyxFQUFFLG9CQUFvQixFQUFFLE1BQU0sMEJBQTBCLENBQUM7Ozs7Ozs7O0FBUWhFLE1BQU0sT0FBTyx3QkFBd0I7SUFOckM7UUFRWSwwQkFBcUIsR0FBRyxJQUFJLFlBQVksRUFBK0IsQ0FBQztRQUdsRixtQkFBYyxHQUE2QixFQUFFLENBQUM7UUFFOUMs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OEJBR3RFLGFBQWE7c0JBQXJCLEtBQUs7Z0JBQ0kscUJBQXFCO3NCQUE5QixNQUFNIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQTExeU1vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL2Nkay9hMTF5JztcbmltcG9ydCB7XG4gIENvbXBvbmVudCxcbiAgRXZlbnRFbWl0dGVyLFxuICBpbmplY3QsXG4gIElucHV0LFxuICBPbkNoYW5nZXMsXG4gIE9uSW5pdCxcbiAgT3V0cHV0LFxuICBTaW1wbGVDaGFuZ2VzXG59IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgRm9ybUFycmF5LCBGb3JtQnVpbGRlciwgRm9ybUdyb3VwLCBGb3Jtc01vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL2Zvcm1zJztcbmltcG9ydCB7XG4gIENsaXBib2FyZFNlcnZpY2UsXG4gIENvbnRleHRSb3V0ZVNlcnZpY2UsXG4gIENvcmVNb2R1bGUsXG4gIGdldHRleHQsXG4gIFZpZXdDb250ZXh0XG59IGZyb20gJ0BjOHkvbmd4LWNvbXBvbmVudHMnO1xuaW1wb3J0IHsgQnNEcm9wZG93bk1vZHVsZSB9IGZyb20gJ25neC1ib290c3RyYXAvZHJvcGRvd24nO1xuaW1wb3J0IHsgVG9vbHRpcE1vZHVsZSB9IGZyb20gJ25neC1ib290c3RyYXAvdG9vbHRpcCc7XG5pbXBvcnQgeyBXb3Jrc3BhY2VDb25maWd1cmF0aW9uIH0gZnJvbSAnLi93b3Jrc3BhY2UtY29uZmlndXJhdGlvbi5tb2RlbCc7XG5pbXBvcnQgeyBEYXRhcG9pbnRzR3JhcGhXaWRnZXRDb25maWcgfSBmcm9tICdAYzh5L25neC1jb21wb25lbnRzL2VjaGFydCc7XG5pbXBvcnQgeyBXb3Jrc3BhY2VDb25maWd1cmF0aW9uU2VydmljZSB9IGZyb20gJy4vd29ya3NwYWNlLWNvbmZpZ3VyYXRpb24uc2VydmljZSc7XG5pbXBvcnQgeyBBY3RpdmF0ZWRSb3V0ZSwgUm91dGVyIH0gZnJvbSAnQGFuZ3VsYXIvcm91dGVyJztcbmltcG9ydCB7IE5hbWVHZW5lcmF0b3JTZXJ2aWNlIH0gZnJvbSAnLi9uYW1lLWdlbmVyYXRvci5zZXJ2aWNlJztcblxuQENvbXBvbmVudCh7XG4gIHNlbGVjdG9yOiAnYzh5LXdvcmtzcGFjZS1jb25maWcnLFxuICB0ZW1wbGF0ZVVybDogJy4vd29ya3NwYWNlLWNvbmZpZ3VyYXRpb24uY29tcG9uZW50Lmh0bWwnLFxuICBzdGFuZGFsb25lOiB0cnVlLFxuICBpbXBvcnRzOiBbQ29yZU1vZHVsZSwgQnNEcm9wZG93bk1vZHVsZSwgRm9ybXNNb2R1bGUsIEExMXlNb2R1bGUsIFRvb2x0aXBNb2R1bGVdXG59KVxuZXhwb3J0IGNsYXNzIFdvcmtzcGFjZUNvbmZpZ0NvbXBvbmVudCBpbXBsZW1lbnRzIE9uSW5pdCwgT25DaGFuZ2VzIHtcbiAgQElucHV0KCkgdXBkYXRlZENvbmZpZzogRGF0YXBvaW50c0dyYXBoV2lkZ2V0Q29uZmlnO1xuICBAT3V0cHV0KCkgb25Db25maWd1cmF0aW9uQ2hhbmdlID0gbmV3IEV2ZW50RW1pdHRlcjxEYXRhcG9pbnRzR3JhcGhXaWRnZXRDb25maWc+KCk7XG5cbiAgY3VycmVudENvbmZpZ3VyYXRpb246IFdvcmtzcGFjZUNvbmZpZ3VyYXRpb247XG4gIGNvbmZpZ3VyYXRpb25zOiBXb3Jrc3BhY2VDb25maWd1cmF0aW9uW10gPSBbXTtcbiAgY29uZmlndXJhdGlvbnNGb3JtR3JvdXA6IEZvcm1Hcm91cDtcbiAgYWN0aXZlQ29uZmlnVG9vbHRpcCA9IGdldHRleHQoJ0FjdGl2ZSBjb25maWd1cmF0aW9uIGNhbm5vdCBiZSByZW1vdmVkJyk7XG4gIHJlbW92ZUNvbmZpZ1Rvb2x0aXAgPSBnZXR0ZXh0KCdSZW1vdmUgY29uZmlndXJhdGlvbicpO1xuXG4gIHByaXZhdGUgcmVhZG9ubHkgZm9ybUJ1aWxkZXIgPSBpbmplY3QoRm9ybUJ1aWxkZXIpO1xuICBwcml2YXRlIHJlYWRvbmx5IHdvcmtzcGFjZUNvbmZpZ3VyYXRpb25TZXJ2aWNlID0gaW5qZWN0KFdvcmtzcGFjZUNvbmZpZ3VyYXRpb25TZXJ2aWNlKTtcbiAgcHJpdmF0ZSByZWFkb25seSBjb250ZXh0Um91dGVTZXJ2aWNlID0gaW5qZWN0KENvbnRleHRSb3V0ZVNlcnZpY2UpO1xuICBwcml2YXRlIHJlYWRvbmx5IGNsaXBib2FyZFNlcnZpY2UgPSBpbmplY3QoQ2xpcGJvYXJkU2VydmljZSk7XG4gIHByaXZhdGUgcmVhZG9ubHkgYWN0aXZhdGVkUm91dGUgPSBpbmplY3QoQWN0aXZhdGVkUm91dGUpO1xuICBwcml2YXRlIHJlYWRvbmx5IHJvdXRlciA9IGluamVjdChSb3V0ZXIpO1xuICBwcml2YXRlIHJlYWRvbmx5IG5hbWVHZW5lcmF0b3JTZXJ2aWNlID0gaW5qZWN0KE5hbWVHZW5lcmF0b3JTZXJ2aWNlKTtcblxuICBuZ09uSW5pdCgpOiB2b2lkIHtcbiAgICB0aGlzLmluaXRpYWxpemVDb250ZXh0U291cmNlSWQoKTtcbiAgICB0aGlzLmluaXRpYWxpemVDb25maWd1cmF0aW9ucygpO1xuICAgIHRoaXMuaW5pdFdvcmtzcGFjZUZvcm0oKTtcbiAgfVxuXG4gIG5nT25DaGFuZ2VzKGNoYW5nZXM6IFNpbXBsZUNoYW5nZXMpOiB2b2lkIHtcbiAgICBpZiAoY2hhbmdlcy51cGRhdGVkQ29uZmlnICYmICFjaGFuZ2VzLnVwZGF0ZWRDb25maWcuZmlyc3RDaGFuZ2UpIHtcbiAgICAgIHRoaXMudXBkYXRlQ29uZmlndXJhdGlvbnMoKTtcbiAgICB9XG4gIH1cblxuICBhZGRDb25maWcoZHVwbGljYXRlZENvbmZpZz86IERhdGFwb2ludHNHcmFwaFdpZGdldENvbmZpZyk6IHZvaWQge1xuICAgIGNvbnN0IG5hbWUgPSB0aGlzLm5hbWVHZW5lcmF0b3JTZXJ2aWNlLmdlbmVyYXRlTmFtZSgpO1xuICAgIGNvbnN0IHdvcmtzcGFjZTogV29ya3NwYWNlQ29uZmlndXJhdGlvbiA9IHtcbiAgICAgIGlkOiBuZXcgRGF0ZSgpLnRvSVNPU3RyaW5nKCksXG4gICAgICBsYWJlbDogbmFtZSxcbiAgICAgIGNvbmZpZzogeyBkYXRhcG9pbnRzOiBbXSwgYWxhcm1zRXZlbnRzQ29uZmlnczogW10gfVxuICAgIH07XG4gICAgaWYgKGR1cGxpY2F0ZWRDb25maWcpIHtcbiAgICAgIHdvcmtzcGFjZS5jb25maWcgPSBkdXBsaWNhdGVkQ29uZmlnO1xuICAgIH1cbiAgICB0aGlzLmNvbmZpZ3VyYXRpb25zID0gW3dvcmtzcGFjZSwgLi4udGhpcy5jb25maWd1cmF0aW9uc107XG4gICAgdGhpcy5pbml0V29ya3NwYWNlRm9ybSgpO1xuICAgIHRoaXMuY2hhbmdlQ29uZmlndXJhdGlvbih0cnVlLCB3b3Jrc3BhY2UpO1xuICB9XG5cbiAgY2hhbmdlQ29uZmlndXJhdGlvbihzZWxlY3RlZDogYm9vbGVhbiwgY29uZmlndXJhdGlvbjogV29ya3NwYWNlQ29uZmlndXJhdGlvbik6IHZvaWQge1xuICAgIGlmICghc2VsZWN0ZWQpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgdGhpcy5jdXJyZW50Q29uZmlndXJhdGlvbiA9IGNvbmZpZ3VyYXRpb247XG4gICAgbG9jYWxTdG9yYWdlLnNldEl0ZW0oXG4gICAgICB0aGlzLndvcmtzcGFjZUNvbmZpZ3VyYXRpb25TZXJ2aWNlLkxPQ0FMX1NUT1JBR0VfREVGQVVMVF9JRF9LRVksXG4gICAgICB0aGlzLmN1cnJlbnRDb25maWd1cmF0aW9uLmlkXG4gICAgKTtcbiAgICB0aGlzLm9uQ29uZmlndXJhdGlvbkNoYW5nZS5lbWl0KGNvbmZpZ3VyYXRpb24uY29uZmlnKTtcbiAgfVxuXG4gIHVwZGF0ZUNvbmZpZ3VyYXRpb25MYWJlbChjb25maWd1cmF0aW9uOiBXb3Jrc3BhY2VDb25maWd1cmF0aW9uKTogdm9pZCB7XG4gICAgdGhpcy5jb25maWd1cmF0aW9ucyA9IHRoaXMuY29uZmlndXJhdGlvbnMubWFwKGMgPT5cbiAgICAgIGMuaWQgPT09IGNvbmZpZ3VyYXRpb24uaWQgPyBjb25maWd1cmF0aW9uIDogY1xuICAgICk7XG4gICAgdGhpcy53b3Jrc3BhY2VDb25maWd1cmF0aW9uU2VydmljZS5zYXZlQ29uZmlndXJhdGlvbnMoXG4gICAgICB0aGlzLmNvbmZpZ3VyYXRpb25zLFxuICAgICAgdGhpcy5jdXJyZW50Q29uZmlndXJhdGlvbj8uaWQgfHwgJydcbiAgICApO1xuICAgIHRoaXMuY3VycmVudENvbmZpZ3VyYXRpb24gPSBjb25maWd1cmF0aW9uO1xuICAgIHRoaXMub25Db25maWd1cmF0aW9uQ2hhbmdlLmVtaXQoY29uZmlndXJhdGlvbi5jb25maWcpO1xuICB9XG5cbiAgZGVsZXRlQ29uZmlndXJhdGlvbihjb25maWd1cmF0aW9uOiBXb3Jrc3BhY2VDb25maWd1cmF0aW9uKTogdm9pZCB7XG4gICAgdGhpcy5jb25maWd1cmF0aW9ucyA9IHRoaXMuY29uZmlndXJhdGlvbnMuZmlsdGVyKGMgPT4gYy5pZCAhPT0gY29uZmlndXJhdGlvbi5pZCk7XG4gICAgdGhpcy5pbml0V29ya3NwYWNlRm9ybSgpO1xuICAgIHRoaXMud29ya3NwYWNlQ29uZmlndXJhdGlvblNlcnZpY2Uuc2F2ZUNvbmZpZ3VyYXRpb25zKFxuICAgICAgdGhpcy5jb25maWd1cmF0aW9ucyxcbiAgICAgIHRoaXMuY3VycmVudENvbmZpZ3VyYXRpb24/LmlkIHx8ICcnXG4gICAgKTtcbiAgfVxuXG4gIGNsZWFyQWxsKCk6IHZvaWQge1xuICAgIHRoaXMuY29uZmlndXJhdGlvbnMgPSBbdGhpcy5jdXJyZW50Q29uZmlndXJhdGlvbl07XG4gICAgdGhpcy5pbml0V29ya3NwYWNlRm9ybSgpO1xuICAgIHRoaXMud29ya3NwYWNlQ29uZmlndXJhdGlvblNlcnZpY2Uuc2F2ZUNvbmZpZ3VyYXRpb25zKFxuICAgICAgdGhpcy5jb25maWd1cmF0aW9ucyxcbiAgICAgIHRoaXMuY3VycmVudENvbmZpZ3VyYXRpb24/LmlkIHx8ICcnXG4gICAgKTtcbiAgfVxuXG4gIGFzeW5jIHNoYXJlQ29uZmlnKGNvbmZpZ3VyYXRpb246IFdvcmtzcGFjZUNvbmZpZ3VyYXRpb24pOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBhd2FpdCB0aGlzLmNsaXBib2FyZFNlcnZpY2Uud3JpdGVUZXh0KEpTT04uc3RyaW5naWZ5KGNvbmZpZ3VyYXRpb24uY29uZmlnKSk7XG4gIH1cblxuICBwcml2YXRlIGFkZENvbmZpZ0Zyb21VcmwocXVlcnlQYXJhbXM6IGFueSk6IHZvaWQge1xuICAgIHRoaXMuYWRkQ29uZmlnKCk7XG4gICAgY29uc3QgY29uZmlnID0gSlNPTi5wYXJzZShxdWVyeVBhcmFtcy5jb25maWcpO1xuICAgIHRoaXMub25Db25maWd1cmF0aW9uQ2hhbmdlLmVtaXQoY29uZmlnKTtcbiAgfVxuXG4gIHByaXZhdGUgdXBkYXRlQ29uZmlndXJhdGlvbnMoKTogdm9pZCB7XG4gICAgdGhpcy5jdXJyZW50Q29uZmlndXJhdGlvbi5jb25maWcgPSB0aGlzLnVwZGF0ZWRDb25maWc7XG4gICAgdGhpcy5jb25maWd1cmF0aW9ucyA9IHRoaXMuY29uZmlndXJhdGlvbnMubWFwKGN1cnJlbnRDb25maWcgPT5cbiAgICAgIGN1cnJlbnRDb25maWcuaWQgPT09IHRoaXMuY3VycmVudENvbmZpZ3VyYXRpb24uaWQgPyB0aGlzLmN1cnJlbnRDb25maWd1cmF0aW9uIDogY3VycmVudENvbmZpZ1xuICAgICk7XG4gICAgY29uc3QgcXVlcnlQYXJhbXMgPSB7XG4gICAgICBjb25maWdJZDogdGhpcy5jdXJyZW50Q29uZmlndXJhdGlvbi5pZCxcbiAgICAgIGxhYmVsOiB0aGlzLmN1cnJlbnRDb25maWd1cmF0aW9uLmxhYmVsLFxuICAgICAgY29uZmlnOiBKU09OLnN0cmluZ2lmeSh0aGlzLnVwZGF0ZWRDb25maWcpXG4gICAgfTtcbiAgICB0aGlzLndvcmtzcGFjZUNvbmZpZ3VyYXRpb25TZXJ2aWNlLnNhdmVDb25maWd1cmF0aW9ucyhcbiAgICAgIHRoaXMuY29uZmlndXJhdGlvbnMsXG4gICAgICB0aGlzLmN1cnJlbnRDb25maWd1cmF0aW9uLmlkXG4gICAgKTtcbiAgICBjb25zdCBjb250cm9sID0gPEZvcm1BcnJheT50aGlzLmNvbmZpZ3VyYXRpb25zRm9ybUdyb3VwLmNvbnRyb2xzWydjb25maWd1cmF0aW9ucyddO1xuICAgIGNvbnN0IGluZGV4ID0gdGhpcy5jb25maWd1cmF0aW9ucy5maW5kSW5kZXgoYyA9PiBjLmlkID09PSB0aGlzLmN1cnJlbnRDb25maWd1cmF0aW9uLmlkKTtcbiAgICBpZiAoaW5kZXggIT09IC0xKSB7XG4gICAgICBjb250cm9sLmF0KGluZGV4KS5wYXRjaFZhbHVlKHtcbiAgICAgICAgbGFiZWw6IHRoaXMuY3VycmVudENvbmZpZ3VyYXRpb24ubGFiZWwsXG4gICAgICAgIGNvbmZpZzogdGhpcy5jdXJyZW50Q29uZmlndXJhdGlvbi5jb25maWcsXG4gICAgICAgIGlkOiB0aGlzLmN1cnJlbnRDb25maWd1cmF0aW9uLmlkXG4gICAgICB9KTtcbiAgICB9XG4gICAgdGhpcy5yb3V0ZXIubmF2aWdhdGUoW10sIHsgcXVlcnlQYXJhbXMgfSk7XG4gIH1cblxuICBwcml2YXRlIGluaXRpYWxpemVDb25maWd1cmF0aW9ucygpOiB2b2lkIHtcbiAgICBjb25zdCBjb25maWd1cmF0aW9ucyA9IHRoaXMud29ya3NwYWNlQ29uZmlndXJhdGlvblNlcnZpY2UuZ2V0Q29uZmlndXJhdGlvbnMoKTtcbiAgICBjb25zdCBkZWZhdWx0SWQgPSB0aGlzLndvcmtzcGFjZUNvbmZpZ3VyYXRpb25TZXJ2aWNlLmdldERlZmF1bHRDb25maWd1cmF0aW9uSWQoKTtcbiAgICBjb25zdCBxdWVyeVBhcmFtcyA9IHRoaXMucm91dGVyLnBhcnNlVXJsKHRoaXMucm91dGVyLnVybCkucXVlcnlQYXJhbXM7XG4gICAgaWYgKGNvbmZpZ3VyYXRpb25zLmxlbmd0aCkge1xuICAgICAgdGhpcy5jb25maWd1cmF0aW9ucyA9IGNvbmZpZ3VyYXRpb25zO1xuICAgICAgdGhpcy5jdXJyZW50Q29uZmlndXJhdGlvbiA9XG4gICAgICAgIHRoaXMuY29uZmlndXJhdGlvbnMuZmluZChjID0+IGMuaWQgPT09IGRlZmF1bHRJZCkgfHwgdGhpcy5jb25maWd1cmF0aW9uc1swXTtcblxuICAgICAgdGhpcy5vbkNvbmZpZ3VyYXRpb25DaGFuZ2UuZW1pdCh0aGlzLmN1cnJlbnRDb25maWd1cmF0aW9uLmNvbmZpZyk7XG4gICAgICBpZiAocXVlcnlQYXJhbXM/LmNvbmZpZ0lkICYmICF0aGlzLmNvbmZpZ3VyYXRpb25zLmZpbmQoYyA9PiBjLmlkID09PSBxdWVyeVBhcmFtcy5jb25maWdJZCkpIHtcbiAgICAgICAgdGhpcy5hZGRDb25maWdGcm9tVXJsKHF1ZXJ5UGFyYW1zKTtcbiAgICAgIH0gZWxzZSBpZiAoXG4gICAgICAgIHF1ZXJ5UGFyYW1zPy5jb25maWdJZCAmJlxuICAgICAgICB0aGlzLmNvbmZpZ3VyYXRpb25zLmZpbmQoYyA9PiBjLmlkID09PSBxdWVyeVBhcmFtcy5jb25maWdJZCkgJiZcbiAgICAgICAgdGhpcy5jdXJyZW50Q29uZmlndXJhdGlvbi5pZCAhPT0gcXVlcnlQYXJhbXMuY29uZmlnSWRcbiAgICAgICkge1xuICAgICAgICB0aGlzLmN1cnJlbnRDb25maWd1cmF0aW9uID0gdGhpcy5jb25maWd1cmF0aW9ucy5maW5kKGMgPT4gYy5pZCA9PT0gcXVlcnlQYXJhbXMuY29uZmlnSWQpO1xuICAgICAgICB0aGlzLmNoYW5nZUNvbmZpZ3VyYXRpb24odHJ1ZSwgdGhpcy5jdXJyZW50Q29uZmlndXJhdGlvbik7XG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKCF0aGlzLmN1cnJlbnRDb25maWd1cmF0aW9uKSB7XG4gICAgICBpZiAoT2JqZWN0LmtleXMocXVlcnlQYXJhbXMpLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICB0aGlzLmFkZENvbmZpZygpO1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG4gICAgICB0aGlzLmFkZENvbmZpZ0Zyb21VcmwocXVlcnlQYXJhbXMpO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgaW5pdFdvcmtzcGFjZUZvcm0oKTogdm9pZCB7XG4gICAgdGhpcy5jb25maWd1cmF0aW9uc0Zvcm1Hcm91cCA9IHRoaXMuZm9ybUJ1aWxkZXIuZ3JvdXAoe1xuICAgICAgY29uZmlndXJhdGlvbnM6IHRoaXMuZm9ybUJ1aWxkZXIuYXJyYXkoW10pXG4gICAgfSk7XG5cbiAgICB0aGlzLnBhdGNoRm9ybSgpO1xuICB9XG5cbiAgcHJpdmF0ZSBwYXRjaEZvcm0oKTogdm9pZCB7XG4gICAgY29uc3QgY29udHJvbCA9IDxGb3JtQXJyYXk+dGhpcy5jb25maWd1cmF0aW9uc0Zvcm1Hcm91cC5jb250cm9sc1snY29uZmlndXJhdGlvbnMnXTtcbiAgICB0aGlzLmNvbmZpZ3VyYXRpb25zLmZvckVhY2god29ya3NwYWNlID0+IHtcbiAgICAgIGNvbnRyb2wucHVzaCh0aGlzLnBhdGNoVmFsdWVzKHdvcmtzcGFjZSkpO1xuICAgIH0pO1xuICB9XG5cbiAgcHJpdmF0ZSBwYXRjaFZhbHVlcyh3b3Jrc3BhY2U6IFdvcmtzcGFjZUNvbmZpZ3VyYXRpb24pOiBGb3JtR3JvdXAge1xuICAgIHJldHVybiB0aGlzLmZvcm1CdWlsZGVyLmdyb3VwKHtcbiAgICAgIGxhYmVsOiBbd29ya3NwYWNlLmxhYmVsXSxcbiAgICAgIGNvbmZpZzogW3dvcmtzcGFjZS5jb25maWddLFxuICAgICAgaWQ6IFt3b3Jrc3BhY2UuaWRdXG4gICAgfSk7XG4gIH1cblxuICBwcml2YXRlIGluaXRpYWxpemVDb250ZXh0U291cmNlSWQoKTogdm9pZCB7XG4gICAgY29uc3Qgcm91dGVDb250ZXh0ID0gdGhpcy5jb250ZXh0Um91dGVTZXJ2aWNlLmdldENvbnRleHREYXRhKHRoaXMuYWN0aXZhdGVkUm91dGUpO1xuICAgIGlmICghcm91dGVDb250ZXh0KSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGNvbnN0IHsgY29udGV4dCwgY29udGV4dERhdGEgfSA9IHJvdXRlQ29udGV4dDtcbiAgICBpZiAoW1ZpZXdDb250ZXh0LkRldmljZSwgVmlld0NvbnRleHQuR3JvdXBdLmluY2x1ZGVzKGNvbnRleHQpKSB7XG4gICAgICB0aGlzLndvcmtzcGFjZUNvbmZpZ3VyYXRpb25TZXJ2aWNlLmNvbnRleHRJZFNpZ25hbC5zZXQoY29udGV4dERhdGE/LmlkKTtcbiAgICB9XG4gIH1cbn1cbiIsIjxkaXZcbiAgY2xhc3M9XCJkcm9wZG93blwiXG4gICNhY3Rpb25iYXJfZHJvcGRvd249XCJicy1kcm9wZG93blwiXG4gIFtjZGtUcmFwRm9jdXNdPVwiYWN0aW9uYmFyX2Ryb3Bkb3duLmlzT3BlblwiXG4gIGRyb3Bkb3duXG4gIFtpbnNpZGVDbGlja109XCJ0cnVlXCJcbj5cblxuICA8YnV0dG9uXG4gICAgY2xhc3M9XCJkcm9wZG93bi10b2dnbGUgZm9ybS1jb250cm9sIGwtaC10aWdodCBkLWZsZXggYS1pLWNlbnRlclwiXG4gICAgYXR0ci5hcmlhLWxhYmVsPVwie3sgY3VycmVudENvbmZpZ3VyYXRpb24ubGFiZWwgfX1cIlxuICAgIHRvb2x0aXA9XCJ7eyAnU2VsZWN0ZWQgY29uZmlndXJhdGlvbicgfCB0cmFuc2xhdGUgfX1cIlxuICAgIHBsYWNlbWVudD1cInRvcFwiXG4gICAgY29udGFpbmVyPVwiYm9keVwiXG4gICAgZGF0YS1jeT1cImN1cnJlbnQtY29uZmlndXJhdGlvbi1kcm9wZG93bi1idXR0b25cIlxuICAgIFthZGFwdGl2ZVBvc2l0aW9uXT1cImZhbHNlXCJcbiAgICBbZGVsYXldPVwiNTAwXCJcbiAgICBkcm9wZG93blRvZ2dsZVxuICA+XG4gICAgPGlcbiAgICAgIGNsYXNzPVwibS1yLTRcIlxuICAgICAgYzh5SWNvbj1cImxpc3RcIlxuICAgID48L2k+XG4gICAgPGRpdiBjbGFzcz1cImQtY29sIHRleHQtbGVmdCBmaXQtd1wiPlxuICAgICAgPHNwYW4gY2xhc3M9XCJ0ZXh0LTEyXCI+XG4gICAgICAgIHt7ICdDb25maWd1cmF0aW9uJyB8IHRyYW5zbGF0ZSB9fVxuICAgICAgPC9zcGFuPlxuICAgICAgPHNwYW4gY2xhc3M9XCJ0ZXh0LTEwIHRleHQtbXV0ZWQgdGV4dC10cnVuY2F0ZVwiPlxuICAgICAgICB7eyBjdXJyZW50Q29uZmlndXJhdGlvbi5sYWJlbCB9fVxuICAgICAgPC9zcGFuPlxuICAgIDwvZGl2PlxuICAgIDxzcGFuIGNsYXNzPVwiY2FyZXQgbS1yLTE2IG0tbC00XCI+PC9zcGFuPlxuICA8L2J1dHRvbj5cbiAgPGRpdlxuICAgIGNsYXNzPVwiZHJvcGRvd24tbWVudSBkcm9wZG93bi1tZW51LXdpZGUgZHJvcGRvd24tbWVudS1hY3Rpb24tYmFyXCJcbiAgICAqZHJvcGRvd25NZW51XG4gID5cbiAgICA8ZGl2IGNsYXNzPVwic3RpY2t5LXRvcCBzZXBhcmF0b3ItYm90dG9tIHAtdC04IHAtYi04IHAtbC0xNiBwLXItMTZcIj5cbiAgICAgIDxwPlxuICAgICAgICA8c3Ryb25nPnt7ICdEYXRhIGV4cGxvcmVyIGNvbmZpZ3VyYXRpb25zJyB8IHRyYW5zbGF0ZSB9fTwvc3Ryb25nPlxuICAgICAgPC9wPlxuICAgICAgPHA+XG4gICAgICAgIDxzbWFsbD57eyAnRWFzaWx5IHN3aXRjaCBhbmQgbWFuYWdlIGNvbmZpZ3VyYXRpb25zLicgfCB0cmFuc2xhdGUgfX08L3NtYWxsPlxuICAgICAgPC9wPlxuICAgIDwvZGl2PlxuICAgIDxjOHktbGlzdC1ncm91cCBjbGFzcz1cIm5vLWJvcmRlci1sYXN0XCI+XG4gICAgICA8Zm9ybSBbZm9ybUdyb3VwXT1cImNvbmZpZ3VyYXRpb25zRm9ybUdyb3VwXCI+XG4gICAgICAgIDxkaXYgZm9ybUFycmF5TmFtZT1cImNvbmZpZ3VyYXRpb25zXCI+XG4gICAgICAgICAgPGM4eS1saVxuICAgICAgICAgICAgY2xhc3M9XCJwLTBcIlxuICAgICAgICAgICAgKm5nRm9yPVwiXG4gICAgICAgICAgICAgIGxldCBjb25maWd1cmF0aW9uIG9mIGNvbmZpZ3VyYXRpb25zRm9ybUdyb3VwLmNvbnRyb2xzLmNvbmZpZ3VyYXRpb25zWydjb250cm9scyddO1xuICAgICAgICAgICAgICBsZXQgaSA9IGluZGV4XG4gICAgICAgICAgICBcIlxuICAgICAgICAgICAgW2RlbnNlXT1cInRydWVcIlxuICAgICAgICAgID5cbiAgICAgICAgICAgIDxjOHktbGktcmFkaW9cbiAgICAgICAgICAgICAgW3NlbGVjdGVkXT1cImNvbmZpZ3VyYXRpb24udmFsdWUuaWQgPT09IGN1cnJlbnRDb25maWd1cmF0aW9uLmlkXCJcbiAgICAgICAgICAgICAgKG9uU2VsZWN0KT1cImNoYW5nZUNvbmZpZ3VyYXRpb24oJGV2ZW50LCBjb25maWd1cmF0aW9uLnZhbHVlKVwiXG4gICAgICAgICAgICA+PC9jOHktbGktcmFkaW8+XG4gICAgICAgICAgICA8ZGl2IGNsYXNzPVwiZC1mbGV4IGEtaS1jZW50ZXIgZ2FwLThcIj5cbiAgICAgICAgICAgICAgPGRpdlxuICAgICAgICAgICAgICAgIGNsYXNzPVwiZmxleC1ncm93IG1pbi13aWR0aC0wXCJcbiAgICAgICAgICAgICAgICBbZm9ybUdyb3VwTmFtZV09XCJpXCJcbiAgICAgICAgICAgICAgPlxuICAgICAgICAgICAgICAgIDxsYWJlbFxuICAgICAgICAgICAgICAgICAgY2xhc3M9XCJlZGl0YWJsZVwiXG4gICAgICAgICAgICAgICAgICBbbmdDbGFzc109XCJ7XG4gICAgICAgICAgICAgICAgICAgIHVwZGF0ZWQ6XG4gICAgICAgICAgICAgICAgICAgICAgY29uZmlndXJhdGlvbi5jb250cm9scy5sYWJlbC50b3VjaGVkICYmIGNvbmZpZ3VyYXRpb24uY29udHJvbHMubGFiZWwuZGlydHlcbiAgICAgICAgICAgICAgICAgIH1cIlxuICAgICAgICAgICAgICAgID5cbiAgICAgICAgICAgICAgICAgIDxpbnB1dFxuICAgICAgICAgICAgICAgICAgICBjbGFzcz1cImZvcm0tY29udHJvbFwiXG4gICAgICAgICAgICAgICAgICAgIFtzdHlsZS53aWR0aC5jaF09XCJjb25maWd1cmF0aW9uLnZhbHVlLmxhYmVsIHx8IDI1XCJcbiAgICAgICAgICAgICAgICAgICAgW2F0dHIuYXJpYS1sYWJlbF09XCInQ29uZmlndXJhdGlvbiBsYWJlbCcgfCB0cmFuc2xhdGVcIlxuICAgICAgICAgICAgICAgICAgICBwbGFjZWhvbGRlcj1cInt7ICdDb25maWd1cmF0aW9uIDEnIHwgdHJhbnNsYXRlIH19XCJcbiAgICAgICAgICAgICAgICAgICAgdHlwZT1cInRleHRcIlxuICAgICAgICAgICAgICAgICAgICBhdXRvY29tcGxldGU9XCJvZmZcIlxuICAgICAgICAgICAgICAgICAgICByZXF1aXJlZFxuICAgICAgICAgICAgICAgICAgICBmb3JtQ29udHJvbE5hbWU9XCJsYWJlbFwiXG4gICAgICAgICAgICAgICAgICAgIChibHVyKT1cInVwZGF0ZUNvbmZpZ3VyYXRpb25MYWJlbChjb25maWd1cmF0aW9uLnZhbHVlKVwiXG4gICAgICAgICAgICAgICAgICAvPlxuICAgICAgICAgICAgICAgIDwvbGFiZWw+XG4gICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwiZmxleC1ub2dyb3cgZC1mbGV4IGdhcC04XCI+XG4gICAgICAgICAgICAgICAgPGJ1dHRvblxuICAgICAgICAgICAgICAgICAgY2xhc3M9XCJidG4tZG90IGJ0blwiXG4gICAgICAgICAgICAgICAgICBbYXR0ci5hcmlhLWxhYmVsXT1cIidEdXBsaWNhdGUgY29uZmlndXJhdGlvbicgfCB0cmFuc2xhdGVcIlxuICAgICAgICAgICAgICAgICAgdG9vbHRpcD1cInt7ICdEdXBsaWNhdGUgY29uZmlndXJhdGlvbicgfCB0cmFuc2xhdGUgfX1cIlxuICAgICAgICAgICAgICAgICAgcGxhY2VtZW50PVwibGVmdFwiXG4gICAgICAgICAgICAgICAgICAoY2xpY2spPVwiYWRkQ29uZmlnKGNvbmZpZ3VyYXRpb24udmFsdWUuY29uZmlnKVwiXG4gICAgICAgICAgICAgICAgICBbZGVsYXldPVwiNTAwXCJcbiAgICAgICAgICAgICAgICA+XG4gICAgICAgICAgICAgICAgICA8aSBjOHlJY29uPVwiY29weVwiPjwvaT5cbiAgICAgICAgICAgICAgICA8L2J1dHRvbj5cblxuICAgICAgICAgICAgICAgIDxidXR0b25cbiAgICAgICAgICAgICAgICAgIGNsYXNzPVwiYnRuLWRvdCBidG4gYnRuLWRvdC0tZGFuZ2VyXCJcbiAgICAgICAgICAgICAgICAgIFthdHRyLmFyaWEtbGFiZWxdPVwiJ1JlbW92ZSBjb25maWd1cmF0aW9ucycgfCB0cmFuc2xhdGVcIlxuICAgICAgICAgICAgICAgICAgdG9vbHRpcD1cInt7XG4gICAgICAgICAgICAgICAgICAgIChjb25maWd1cmF0aW9uLnZhbHVlLmlkID09PSBjdXJyZW50Q29uZmlndXJhdGlvbi5pZFxuICAgICAgICAgICAgICAgICAgICAgID8gYWN0aXZlQ29uZmlnVG9vbHRpcFxuICAgICAgICAgICAgICAgICAgICAgIDogcmVtb3ZlQ29uZmlnVG9vbHRpcFxuICAgICAgICAgICAgICAgICAgICApIHwgdHJhbnNsYXRlXG4gICAgICAgICAgICAgICAgICB9fVwiXG4gICAgICAgICAgICAgICAgICBwbGFjZW1lbnQ9XCJsZWZ0XCJcbiAgICAgICAgICAgICAgICAgIFtkZWxheV09XCI1MDBcIlxuICAgICAgICAgICAgICAgICAgKGNsaWNrKT1cIiRldmVudC5zdG9wUHJvcGFnYXRpb24oKTsgZGVsZXRlQ29uZmlndXJhdGlvbihjb25maWd1cmF0aW9uLnZhbHVlKVwiXG4gICAgICAgICAgICAgICAgICBbZGlzYWJsZWRdPVwiY29uZmlndXJhdGlvbi52YWx1ZS5pZCA9PT0gY3VycmVudENvbmZpZ3VyYXRpb24uaWRcIlxuICAgICAgICAgICAgICAgID5cbiAgICAgICAgICAgICAgICAgIDxpIGM4eUljb249XCJtaW51cy1jaXJjbGVcIj48L2k+XG4gICAgICAgICAgICAgICAgPC9idXR0b24+XG4gICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgPC9jOHktbGk+XG4gICAgICAgIDwvZGl2PlxuICAgICAgPC9mb3JtPlxuICAgIDwvYzh5LWxpc3QtZ3JvdXA+XG4gICAgPGRpdiBjbGFzcz1cInN0aWNreS1ib3R0b20gc2VwYXJhdG9yLXRvcFwiPlxuICAgICAgPGRpdiBjbGFzcz1cImQtZmxleCBwLWwtMTYgcC1yLTE2IHAtdC04IHAtYi04XCI+XG4gICAgICAgIDxidXR0b25cbiAgICAgICAgICBjbGFzcz1cImJ0biBidG4tZGFuZ2VyIGJ0bi1zbSBmbGV4LWdyb3dcIlxuICAgICAgICAgIChjbGljayk9XCJjbGVhckFsbCgpXCJcbiAgICAgICAgICBbZGlzYWJsZWRdPVwiY29uZmlndXJhdGlvbnMubGVuZ3RoIDwgMlwiXG4gICAgICAgID5cbiAgICAgICAgICA8aSBbYzh5SWNvbl09XCInZGVsZXRlJ1wiPjwvaT5cbiAgICAgICAgICB7eyAnRGVsZXRlIGFsbCBjb25maWd1cmF0aW9ucycgfCB0cmFuc2xhdGUgfX1cbiAgICAgICAgPC9idXR0b24+XG4gICAgICAgIDxidXR0b25cbiAgICAgICAgICBjbGFzcz1cImJ0biBidG4tZGVmYXVsdCBidG4tc20gZmxleC1ncm93XCJcbiAgICAgICAgICB0eXBlPVwiYnV0dG9uXCJcbiAgICAgICAgICAoY2xpY2spPVwiYWRkQ29uZmlnKClcIlxuICAgICAgICA+XG4gICAgICAgICAgPGkgW2M4eUljb25dPVwiJ2FkZC1jaXJjbGUtb3V0bGluZSdcIj48L2k+XG4gICAgICAgICAge3sgJ0FkZCBjb25maWd1cmF0aW9uJyB8IHRyYW5zbGF0ZSB9fVxuICAgICAgICA8L2J1dHRvbj5cbiAgICAgIDwvZGl2PlxuICAgIDwvZGl2PlxuICA8L2Rpdj5cbjwvZGl2PlxuIl19