@c8y/ngx-components
Version:
Angular modules for Cumulocity IoT applications
94 lines • 46.6 kB
JavaScript
import { Component } from '@angular/core';
import { gettext } from '@c8y/ngx-components';
import { BaseStepperComponent } from '@c8y/ngx-components/operations/bulk-operation-stepper';
import { BulkOperationsService, BulkOperationType } from '@c8y/ngx-components/operations/bulk-operations-service';
import { RepositoryService, RepositoryType } from '@c8y/ngx-components/repository/shared';
import { TranslateService } from '@ngx-translate/core';
import { get, isEqual, uniqWith } from 'lodash-es';
import { BehaviorSubject, combineLatest, from } from 'rxjs';
import { debounceTime, distinctUntilChanged, shareReplay, switchMap } from 'rxjs/operators';
import * as i0 from "@angular/core";
import * as i1 from "@c8y/ngx-components/operations/bulk-operations-service";
import * as i2 from "@c8y/ngx-components/repository/shared";
import * as i3 from "@ngx-translate/core";
import * as i4 from "@c8y/ngx-components";
import * as i5 from "@angular/common";
import * as i6 from "@angular/forms";
import * as i7 from "@c8y/ngx-components/operations/bulk-operation-stepper";
import * as i8 from "@c8y/ngx-components/operations/stepper-frames";
export class StepperBulkTypeConfigurationComponent extends BaseStepperComponent {
constructor(bulkOperationService, repositoryService, translate) {
super();
this.bulkOperationService = bulkOperationService;
this.repositoryService = repositoryService;
this.translate = translate;
this.type = BulkOperationType.CONFIGURATION;
this.NO_DEVICE_TYPE_AVAILABLE = gettext('Undefined`device type`');
this.DD_LOW_COUNT = 10;
this.textFilter$ = new BehaviorSubject('');
this.configType$ = new BehaviorSubject('');
this.configTypes = [];
this.selectedConfigType = { name: '' };
this.configurations$ = combineLatest(this.textFilter$, this.configType$).pipe(switchMap(([name, configType]) => this.getConfiguration(name, configType)), shareReplay(1));
this.DD_LOW_COUNT = this.bulkOperationService.DD_LOW_COUNT;
this.loadConfigurationTypes();
}
loadConfigurationTypes() {
this.configTypeSubscription = this.configType$
.pipe(debounceTime(300), distinctUntilChanged(), switchMap(searchStr => {
const query = { configurationType: `*${searchStr}*` };
return from(this.repositoryService.listRepositoryEntries(RepositoryType.CONFIGURATION, { query }));
}))
.subscribe(result => {
const { data } = result;
this.configTypes = uniqWith(data.map(val => ({ name: val.configurationType })), isEqual);
});
}
ngOnDestroy() {
this.configTypeSubscription.unsubscribe();
}
selectConfiguration(configuration) {
this.selectedConfiguration = configuration;
}
goToSecondStep($event) {
$event.stepper.next();
this.getConfigBinary();
this.deviceTypes = this.selectedConfiguration.deviceType;
}
async getConfigBinary() {
if (this.selectedConfiguration.url) {
this.selectedConfiguration.binary = await this.repositoryService.getBinaryText(this.selectedConfiguration.url, { allowExternal: true, noAlerts: true });
}
}
getDeviceTypeTitle(configuration) {
return get(configuration, 'deviceType', this.translate.instant(this.NO_DEVICE_TYPE_AVAILABLE));
}
retrieveOperationPrototype() {
const configuration = {
type: this.selectedConfiguration.configurationType,
url: this.selectedConfiguration.url
};
return {
name: gettext('Configuration update'),
description: get(this.selectedConfiguration, 'name'),
prototype: {
description: `Update configuration to: ${this.selectedConfiguration.name}.`,
c8y_DownloadConfigFile: configuration
}
};
}
getConfiguration(name, configurationType) {
const query = name ? { name: `*${name}*` } : {};
if (configurationType) {
query.__or = [{ configurationType }, { __not: { __has: `configurationType` } }];
}
return this.repositoryService.listRepositoryEntries(RepositoryType.CONFIGURATION, { query });
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: StepperBulkTypeConfigurationComponent, deps: [{ token: i1.BulkOperationsService }, { token: i2.RepositoryService }, { token: i3.TranslateService }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: StepperBulkTypeConfigurationComponent, selector: "c8y-stepper-bulk-type-configuration", usesInheritance: true, ngImport: i0, template: "<c8y-bulk-operation-stepper [type]=\"type\">\n <ng-container\n *customStep=\"\n 'Select configuration' | translate;\n completed: !!selectedConfiguration;\n buttonsDisabled: !selectedConfiguration;\n onNext: goToSecondStep.bind(this)\n \"\n >\n <c8y-select-step-frame\n [header]=\"'Select configuration' | translate\"\n [noResults]=\"\n ((textFilter$ | async)?.length || (configType$ | async)?.length) &&\n (configurations$ | async)?.data.length === 0\n \"\n >\n <div\n class=\"row\"\n filters\n >\n <div class=\"col-md-6\">\n <div class=\"input-group input-group-search\">\n <input\n class=\"form-control\"\n title=\"{{ 'Filter\u2026' | translate }}\"\n placeholder=\"{{ 'Filter\u2026' | translate }}\"\n type=\"search\"\n [ngModel]=\"textFilter$ | async\"\n (ngModelChange)=\"textFilter$.next($event)\"\n />\n <span class=\"input-group-addon\">\n <i\n c8yIcon=\"search\"\n *ngIf=\"(textFilter$ | async).length === 0\"\n ></i>\n <i\n class=\"text-muted\"\n c8yIcon=\"times\"\n *ngIf=\"(textFilter$ | async).length > 0\"\n (click)=\"textFilter$.next('')\"\n ></i>\n </span>\n </div>\n </div>\n <div class=\"col-xs-12 p-b-8 visible-xs visible-sm\"></div>\n <div class=\"col-md-6\">\n <c8y-form-group class=\"m-0\">\n <c8y-typeahead\n placeholder=\"{{ 'Type to filter configuration types\u2026' | translate }}\"\n name=\"configType\"\n [(ngModel)]=\"selectedConfigType\"\n (onSearch)=\"configType$.next($event)\"\n >\n <c8y-li\n class=\"p-l-8 p-r-8 c8y-list__item--link\"\n (click)=\"selectedConfigType = { name: '' }; configType$.next('')\"\n >\n <span>{{ 'All configuration types' | translate }}</span>\n </c8y-li>\n <c8y-li\n class=\"p-l-8 p-r-8 c8y-list__item--link\"\n *ngFor=\"let configType of configTypes\"\n (click)=\"selectedConfigType = configType; configType$.next(configType.name)\"\n [active]=\"selectedConfigType === configType\"\n >\n <c8y-highlight\n [text]=\"configType.name\"\n [pattern]=\"configType$ | async\"\n ></c8y-highlight>\n </c8y-li>\n </c8y-typeahead>\n </c8y-form-group>\n </div>\n </div>\n <c8y-li\n class=\"hidden-sm hidden-xs m-r-8 m-l-8\"\n header\n >\n <c8y-li-icon><i class=\"p-l-32 p-r-40\"></i></c8y-li-icon>\n <c8y-li-body class=\"content-flex-40\">\n <div class=\"col-5\">\n <span\n class=\"text-truncate\"\n title=\" {{ 'Name' | translate }} \"\n >\n {{ 'Name' | translate }}\n </span>\n </div>\n <div class=\"col-4\">\n <span\n class=\"text-truncate\"\n title=\"{{ 'Device type' | translate }}\"\n >\n {{ 'Device type' | translate }}\n </span>\n </div>\n <div class=\"col-3\">\n <span\n class=\"text-truncate\"\n title=\"{{ 'Configuration type' | translate }}\"\n >\n {{ 'Configuration type' | translate }}\n </span>\n </div>\n </c8y-li-body>\n </c8y-li>\n <c8y-list-group list>\n <c8y-li\n #listItem\n *c8yFor=\"let configuration of configurations$ | async\"\n >\n <c8y-li-radio (onSelect)=\"selectConfiguration(configuration)\"></c8y-li-radio>\n <c8y-li-icon icon=\"gears\"></c8y-li-icon>\n <c8y-li-body class=\"content-flex-40\">\n <div class=\"col-5 m-b-xs-8\">\n <div\n class=\"text-truncate\"\n title=\"{{ configuration.name || '-' }}\"\n >\n <c8y-highlight\n [text]=\"configuration.name || '-'\"\n [pattern]=\"textFilter$ | async\"\n ></c8y-highlight>\n </div>\n </div>\n <div class=\"col-4 m-b-xs-8\">\n <div\n class=\"text-truncate\"\n title=\"{{ 'Device type' | translate }}: {{ getDeviceTypeTitle(configuration) }}\"\n >\n <span\n class=\"text-label-small m-r-8 visible-xs visible-sm\"\n translate\n >\n Device type\n </span>\n {{ configuration.deviceType }}\n <em\n class=\"text-muted\"\n *ngIf=\"!configuration.deviceType\"\n >\n {{ 'Undefined`device type`' | translate }}\n </em>\n </div>\n </div>\n <div class=\"col-3 m-b-xs-8\">\n <span\n class=\"text-label-small m-r-8 visible-xs visible-sm\"\n translate\n >\n Configuration type\n </span>\n <span\n class=\"label label-info\"\n title=\"{{ 'Configuration type' | translate }}: {{\n configuration.configurationType\n }}\"\n *ngIf=\"configuration.configurationType\"\n >\n <c8y-highlight\n [text]=\"configuration.configurationType\"\n elementClass=\"text-gray-lighter\"\n [pattern]=\"configType$ | async\"\n ></c8y-highlight>\n </span>\n <span\n class=\"label label-default\"\n title=\"{{ 'Configuration type' | translate }}: {{ 'Undefined' | translate }}\"\n *ngIf=\"!configuration.configurationType\"\n >\n {{ 'Undefined' | translate }}\n </span>\n </div>\n </c8y-li-body>\n </c8y-li>\n </c8y-list-group>\n </c8y-select-step-frame>\n </ng-container>\n <ng-container *customStep=\"'Preview configuration' | translate\">\n <c8y-preview-selection-frame\n [header]=\"'Preview configuration' | translate\"\n [name]=\"selectedConfiguration?.name\"\n [type]=\"selectedConfiguration?.configurationType\"\n >\n <ng-container *previewBlock=\"'Device type' | translate\">\n <ng-container *ngIf=\"selectedConfiguration?.deviceType; else noType\">\n <span>{{ selectedConfiguration?.deviceType }}</span>\n </ng-container>\n <ng-template #noType>\n <em\n class=\"text-muted\"\n translate\n >\n Undefined`device type`\n </em>\n </ng-template>\n </ng-container>\n <ng-container *previewBlock=\"'Updated' | translate\">\n <span>{{ selectedConfiguration?.lastUpdated | c8yDate }}</span>\n </ng-container>\n <ng-container *previewBlock=\"'Preview' | translate\">\n <c8y-ui-empty-state\n [icon]=\"'file-code-o'\"\n [title]=\"'No preview available.' | translate\"\n [subtitle]=\"'Could not fetch the file.' | translate\"\n *ngIf=\"!this.selectedConfiguration?.binary; else binaryPreview\"\n ></c8y-ui-empty-state>\n <ng-template #binaryPreview>\n <pre style=\"min-height: 98px\"><code>{{ this.selectedConfiguration?.binary }}</code></pre>\n </ng-template>\n </ng-container>\n </c8y-preview-selection-frame>\n </ng-container>\n</c8y-bulk-operation-stepper>\n", dependencies: [{ kind: "component", type: i4.EmptyStateComponent, selector: "c8y-ui-empty-state", inputs: ["icon", "title", "subtitle", "horizontal"] }, { kind: "directive", type: i4.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: i4.C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: i5.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i4.ForOfDirective, selector: "[c8yFor]", inputs: ["c8yForOf", "c8yForLoadMore", "c8yForPipe", "c8yForNotFound", "c8yForMaxIterations", "c8yForLoadingTemplate", "c8yForLoadNextLabel", "c8yForLoadingLabel", "c8yForRealtime", "c8yForRealtimeOptions", "c8yForComparator", "c8yForEnableVirtualScroll", "c8yForVirtualScrollElementSize", "c8yForVirtualScrollStrategy", "c8yForVirtualScrollContainerHeight"], outputs: ["c8yForCount", "c8yForChange", "c8yForLoadMoreComponent"] }, { kind: "component", type: i4.HighlightComponent, selector: "c8y-highlight", inputs: ["pattern", "text", "elementClass", "shouldTrimPattern"] }, { kind: "component", type: i4.TypeaheadComponent, selector: "c8y-typeahead", inputs: ["required", "maxlength", "disabled", "allowFreeEntries", "placeholder", "displayProperty", "icon", "name", "autoClose", "hideNew", "container", "selected", "highlightFirstItem"], outputs: ["onSearch", "onIconClick"] }, { kind: "directive", type: i6.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: i6.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i6.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: i4.FormGroupComponent, selector: "c8y-form-group", inputs: ["hasError", "hasWarning", "hasSuccess", "novalidation", "status"] }, { kind: "component", type: i4.ListGroupComponent, selector: "c8y-list-group" }, { kind: "component", type: i4.ListItemComponent, selector: "c8y-list-item, c8y-li", inputs: ["active", "highlighted", "emptyActions", "dense", "collapsed", "selectable"], outputs: ["collapsedChange"] }, { kind: "component", type: i4.ListItemIconComponent, selector: "c8y-list-item-icon, c8y-li-icon", inputs: ["icon", "status"] }, { kind: "component", type: i4.ListItemBodyComponent, selector: "c8y-list-item-body, c8y-li-body", inputs: ["body"] }, { kind: "component", type: i4.ListItemRadioComponent, selector: "c8y-list-item-radio, c8y-li-radio", inputs: ["selected", "name", "disabled", "value"], outputs: ["onSelect"] }, { kind: "component", type: i7.BulkOperationStepper, selector: "c8y-bulk-operation-stepper", inputs: ["type"], outputs: ["selectionChange"] }, { kind: "directive", type: i7.CustomStep, selector: "[customStep]", inputs: ["customStep", "customStepCompleted", "customStepButtonsDisabled", "customStepOnNext"] }, { kind: "component", type: i8.PreviewSelectionFrameComponent, selector: "c8y-preview-selection-frame", inputs: ["header", "name", "description", "type"] }, { kind: "component", type: i8.SelectStepFrameComponent, selector: "c8y-select-step-frame", inputs: ["header", "noResults"] }, { kind: "directive", type: i8.PreviewBlockDirective, selector: "[previewBlock]", inputs: ["previewBlock", "previewBlockIf"] }, { kind: "pipe", type: i4.C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: i5.AsyncPipe, name: "async" }, { kind: "pipe", type: i4.DatePipe, name: "c8yDate" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: StepperBulkTypeConfigurationComponent, decorators: [{
type: Component,
args: [{ selector: 'c8y-stepper-bulk-type-configuration', template: "<c8y-bulk-operation-stepper [type]=\"type\">\n <ng-container\n *customStep=\"\n 'Select configuration' | translate;\n completed: !!selectedConfiguration;\n buttonsDisabled: !selectedConfiguration;\n onNext: goToSecondStep.bind(this)\n \"\n >\n <c8y-select-step-frame\n [header]=\"'Select configuration' | translate\"\n [noResults]=\"\n ((textFilter$ | async)?.length || (configType$ | async)?.length) &&\n (configurations$ | async)?.data.length === 0\n \"\n >\n <div\n class=\"row\"\n filters\n >\n <div class=\"col-md-6\">\n <div class=\"input-group input-group-search\">\n <input\n class=\"form-control\"\n title=\"{{ 'Filter\u2026' | translate }}\"\n placeholder=\"{{ 'Filter\u2026' | translate }}\"\n type=\"search\"\n [ngModel]=\"textFilter$ | async\"\n (ngModelChange)=\"textFilter$.next($event)\"\n />\n <span class=\"input-group-addon\">\n <i\n c8yIcon=\"search\"\n *ngIf=\"(textFilter$ | async).length === 0\"\n ></i>\n <i\n class=\"text-muted\"\n c8yIcon=\"times\"\n *ngIf=\"(textFilter$ | async).length > 0\"\n (click)=\"textFilter$.next('')\"\n ></i>\n </span>\n </div>\n </div>\n <div class=\"col-xs-12 p-b-8 visible-xs visible-sm\"></div>\n <div class=\"col-md-6\">\n <c8y-form-group class=\"m-0\">\n <c8y-typeahead\n placeholder=\"{{ 'Type to filter configuration types\u2026' | translate }}\"\n name=\"configType\"\n [(ngModel)]=\"selectedConfigType\"\n (onSearch)=\"configType$.next($event)\"\n >\n <c8y-li\n class=\"p-l-8 p-r-8 c8y-list__item--link\"\n (click)=\"selectedConfigType = { name: '' }; configType$.next('')\"\n >\n <span>{{ 'All configuration types' | translate }}</span>\n </c8y-li>\n <c8y-li\n class=\"p-l-8 p-r-8 c8y-list__item--link\"\n *ngFor=\"let configType of configTypes\"\n (click)=\"selectedConfigType = configType; configType$.next(configType.name)\"\n [active]=\"selectedConfigType === configType\"\n >\n <c8y-highlight\n [text]=\"configType.name\"\n [pattern]=\"configType$ | async\"\n ></c8y-highlight>\n </c8y-li>\n </c8y-typeahead>\n </c8y-form-group>\n </div>\n </div>\n <c8y-li\n class=\"hidden-sm hidden-xs m-r-8 m-l-8\"\n header\n >\n <c8y-li-icon><i class=\"p-l-32 p-r-40\"></i></c8y-li-icon>\n <c8y-li-body class=\"content-flex-40\">\n <div class=\"col-5\">\n <span\n class=\"text-truncate\"\n title=\" {{ 'Name' | translate }} \"\n >\n {{ 'Name' | translate }}\n </span>\n </div>\n <div class=\"col-4\">\n <span\n class=\"text-truncate\"\n title=\"{{ 'Device type' | translate }}\"\n >\n {{ 'Device type' | translate }}\n </span>\n </div>\n <div class=\"col-3\">\n <span\n class=\"text-truncate\"\n title=\"{{ 'Configuration type' | translate }}\"\n >\n {{ 'Configuration type' | translate }}\n </span>\n </div>\n </c8y-li-body>\n </c8y-li>\n <c8y-list-group list>\n <c8y-li\n #listItem\n *c8yFor=\"let configuration of configurations$ | async\"\n >\n <c8y-li-radio (onSelect)=\"selectConfiguration(configuration)\"></c8y-li-radio>\n <c8y-li-icon icon=\"gears\"></c8y-li-icon>\n <c8y-li-body class=\"content-flex-40\">\n <div class=\"col-5 m-b-xs-8\">\n <div\n class=\"text-truncate\"\n title=\"{{ configuration.name || '-' }}\"\n >\n <c8y-highlight\n [text]=\"configuration.name || '-'\"\n [pattern]=\"textFilter$ | async\"\n ></c8y-highlight>\n </div>\n </div>\n <div class=\"col-4 m-b-xs-8\">\n <div\n class=\"text-truncate\"\n title=\"{{ 'Device type' | translate }}: {{ getDeviceTypeTitle(configuration) }}\"\n >\n <span\n class=\"text-label-small m-r-8 visible-xs visible-sm\"\n translate\n >\n Device type\n </span>\n {{ configuration.deviceType }}\n <em\n class=\"text-muted\"\n *ngIf=\"!configuration.deviceType\"\n >\n {{ 'Undefined`device type`' | translate }}\n </em>\n </div>\n </div>\n <div class=\"col-3 m-b-xs-8\">\n <span\n class=\"text-label-small m-r-8 visible-xs visible-sm\"\n translate\n >\n Configuration type\n </span>\n <span\n class=\"label label-info\"\n title=\"{{ 'Configuration type' | translate }}: {{\n configuration.configurationType\n }}\"\n *ngIf=\"configuration.configurationType\"\n >\n <c8y-highlight\n [text]=\"configuration.configurationType\"\n elementClass=\"text-gray-lighter\"\n [pattern]=\"configType$ | async\"\n ></c8y-highlight>\n </span>\n <span\n class=\"label label-default\"\n title=\"{{ 'Configuration type' | translate }}: {{ 'Undefined' | translate }}\"\n *ngIf=\"!configuration.configurationType\"\n >\n {{ 'Undefined' | translate }}\n </span>\n </div>\n </c8y-li-body>\n </c8y-li>\n </c8y-list-group>\n </c8y-select-step-frame>\n </ng-container>\n <ng-container *customStep=\"'Preview configuration' | translate\">\n <c8y-preview-selection-frame\n [header]=\"'Preview configuration' | translate\"\n [name]=\"selectedConfiguration?.name\"\n [type]=\"selectedConfiguration?.configurationType\"\n >\n <ng-container *previewBlock=\"'Device type' | translate\">\n <ng-container *ngIf=\"selectedConfiguration?.deviceType; else noType\">\n <span>{{ selectedConfiguration?.deviceType }}</span>\n </ng-container>\n <ng-template #noType>\n <em\n class=\"text-muted\"\n translate\n >\n Undefined`device type`\n </em>\n </ng-template>\n </ng-container>\n <ng-container *previewBlock=\"'Updated' | translate\">\n <span>{{ selectedConfiguration?.lastUpdated | c8yDate }}</span>\n </ng-container>\n <ng-container *previewBlock=\"'Preview' | translate\">\n <c8y-ui-empty-state\n [icon]=\"'file-code-o'\"\n [title]=\"'No preview available.' | translate\"\n [subtitle]=\"'Could not fetch the file.' | translate\"\n *ngIf=\"!this.selectedConfiguration?.binary; else binaryPreview\"\n ></c8y-ui-empty-state>\n <ng-template #binaryPreview>\n <pre style=\"min-height: 98px\"><code>{{ this.selectedConfiguration?.binary }}</code></pre>\n </ng-template>\n </ng-container>\n </c8y-preview-selection-frame>\n </ng-container>\n</c8y-bulk-operation-stepper>\n" }]
}], ctorParameters: () => [{ type: i1.BulkOperationsService }, { type: i2.RepositoryService }, { type: i3.TranslateService }] });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3RlcHBlci1idWxrLXR5cGUtY29uZmlndXJhdGlvbi5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9vcGVyYXRpb25zL3N0ZXBwZXItYnVsay10eXBlLWNvbmZpZ3VyYXRpb24vc3RlcHBlci1idWxrLXR5cGUtY29uZmlndXJhdGlvbi5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi9vcGVyYXRpb25zL3N0ZXBwZXItYnVsay10eXBlLWNvbmZpZ3VyYXRpb24vc3RlcHBlci1idWxrLXR5cGUtY29uZmlndXJhdGlvbi5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFDQSxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBRTFDLE9BQU8sRUFBYyxPQUFPLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQUMxRCxPQUFPLEVBQUUsb0JBQW9CLEVBQUUsTUFBTSx1REFBdUQsQ0FBQztBQUM3RixPQUFPLEVBQ0wscUJBQXFCLEVBQ3JCLGlCQUFpQixFQUVsQixNQUFNLHdEQUF3RCxDQUFDO0FBQ2hFLE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxjQUFjLEVBQUUsTUFBTSx1Q0FBdUMsQ0FBQztBQUMxRixPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQUN2RCxPQUFPLEVBQUUsR0FBRyxFQUFFLE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSxXQUFXLENBQUM7QUFDbkQsT0FBTyxFQUFFLGVBQWUsRUFBRSxhQUFhLEVBQUUsSUFBSSxFQUE0QixNQUFNLE1BQU0sQ0FBQztBQUN0RixPQUFPLEVBQUUsWUFBWSxFQUFFLG9CQUFvQixFQUFFLFdBQVcsRUFBRSxTQUFTLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQzs7Ozs7Ozs7OztBQU01RixNQUFNLE9BQU8scUNBQXNDLFNBQVEsb0JBQW9CO0lBa0I3RSxZQUNVLG9CQUEyQyxFQUMzQyxpQkFBb0MsRUFDcEMsU0FBMkI7UUFFbkMsS0FBSyxFQUFFLENBQUM7UUFKQSx5QkFBb0IsR0FBcEIsb0JBQW9CLENBQXVCO1FBQzNDLHNCQUFpQixHQUFqQixpQkFBaUIsQ0FBbUI7UUFDcEMsY0FBUyxHQUFULFNBQVMsQ0FBa0I7UUFwQjVCLFNBQUksR0FBc0IsaUJBQWlCLENBQUMsYUFBYSxDQUFDO1FBQzFELDZCQUF3QixHQUFHLE9BQU8sQ0FBQyx3QkFBd0IsQ0FBQyxDQUFDO1FBRXRFLGlCQUFZLEdBQUcsRUFBRSxDQUFDO1FBQ2xCLGdCQUFXLEdBQTRCLElBQUksZUFBZSxDQUFDLEVBQUUsQ0FBQyxDQUFDO1FBQy9ELGdCQUFXLEdBQTRCLElBQUksZUFBZSxDQUFDLEVBQUUsQ0FBQyxDQUFDO1FBQy9ELGdCQUFXLEdBQUcsRUFBRSxDQUFDO1FBQ2pCLHVCQUFrQixHQUFHLEVBQUUsSUFBSSxFQUFFLEVBQUUsRUFBRSxDQUFDO1FBQ2xDLG9CQUFlLEdBQTRDLGFBQWEsQ0FDdEUsSUFBSSxDQUFDLFdBQVcsRUFDaEIsSUFBSSxDQUFDLFdBQVcsQ0FDakIsQ0FBQyxJQUFJLENBQ0osU0FBUyxDQUFDLENBQUMsQ0FBQyxJQUFJLEVBQUUsVUFBVSxDQUFDLEVBQUUsRUFBRSxDQUFDLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxJQUFJLEVBQUUsVUFBVSxDQUFDLENBQUMsRUFDMUUsV0FBVyxDQUFDLENBQUMsQ0FBQyxDQUNmLENBQUM7UUFTQSxJQUFJLENBQUMsWUFBWSxHQUFHLElBQUksQ0FBQyxvQkFBb0IsQ0FBQyxZQUFZLENBQUM7UUFDM0QsSUFBSSxDQUFDLHNCQUFzQixFQUFFLENBQUM7SUFDaEMsQ0FBQztJQUVELHNCQUFzQjtRQUNwQixJQUFJLENBQUMsc0JBQXNCLEdBQUcsSUFBSSxDQUFDLFdBQVc7YUFDM0MsSUFBSSxDQUNILFlBQVksQ0FBQyxHQUFHLENBQUMsRUFDakIsb0JBQW9CLEVBQUUsRUFDdEIsU0FBUyxDQUFDLFNBQVMsQ0FBQyxFQUFFO1lBQ3BCLE1BQU0sS0FBSyxHQUFHLEVBQUUsaUJBQWlCLEVBQUUsSUFBSSxTQUFTLEdBQUcsRUFBRSxDQUFDO1lBQ3RELE9BQU8sSUFBSSxDQUNULElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxxQkFBcUIsQ0FBQyxjQUFjLENBQUMsYUFBYSxFQUFFLEVBQUUsS0FBSyxFQUFFLENBQUMsQ0FDdEYsQ0FBQztRQUNKLENBQUMsQ0FBQyxDQUNIO2FBQ0EsU0FBUyxDQUFDLE1BQU0sQ0FBQyxFQUFFO1lBQ2xCLE1BQU0sRUFBRSxJQUFJLEVBQUUsR0FBRyxNQUFNLENBQUM7WUFDeEIsSUFBSSxDQUFDLFdBQVcsR0FBRyxRQUFRLENBQ3pCLElBQUksQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxDQUFDLEVBQUUsSUFBSSxFQUFFLEdBQUcsQ0FBQyxpQkFBaUIsRUFBRSxDQUFDLENBQUMsRUFDbEQsT0FBTyxDQUNSLENBQUM7UUFDSixDQUFDLENBQUMsQ0FBQztJQUNQLENBQUM7SUFDRCxXQUFXO1FBQ1QsSUFBSSxDQUFDLHNCQUFzQixDQUFDLFdBQVcsRUFBRSxDQUFDO0lBQzVDLENBQUM7SUFFRCxtQkFBbUIsQ0FBQyxhQUE2QjtRQUMvQyxJQUFJLENBQUMscUJBQXFCLEdBQUcsYUFBYSxDQUFDO0lBQzdDLENBQUM7SUFFRCxjQUFjLENBQUMsTUFBOEM7UUFDM0QsTUFBTSxDQUFDLE9BQU8sQ0FBQyxJQUFJLEVBQUUsQ0FBQztRQUN0QixJQUFJLENBQUMsZUFBZSxFQUFFLENBQUM7UUFDdkIsSUFBSSxDQUFDLFdBQVcsR0FBRyxJQUFJLENBQUMscUJBQXFCLENBQUMsVUFBVSxDQUFDO0lBQzNELENBQUM7SUFFRCxLQUFLLENBQUMsZUFBZTtRQUNuQixJQUFJLElBQUksQ0FBQyxxQkFBcUIsQ0FBQyxHQUFHLEVBQUUsQ0FBQztZQUNuQyxJQUFJLENBQUMscUJBQXFCLENBQUMsTUFBTSxHQUFHLE1BQU0sSUFBSSxDQUFDLGlCQUFpQixDQUFDLGFBQWEsQ0FDNUUsSUFBSSxDQUFDLHFCQUFxQixDQUFDLEdBQUcsRUFDOUIsRUFBRSxhQUFhLEVBQUUsSUFBSSxFQUFFLFFBQVEsRUFBRSxJQUFJLEVBQUUsQ0FDeEMsQ0FBQztRQUNKLENBQUM7SUFDSCxDQUFDO0lBRUQsa0JBQWtCLENBQUMsYUFBNkI7UUFDOUMsT0FBTyxHQUFHLENBQUMsYUFBYSxFQUFFLFlBQVksRUFBRSxJQUFJLENBQUMsU0FBUyxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsd0JBQXdCLENBQUMsQ0FBQyxDQUFDO0lBQ2pHLENBQUM7SUFFUywwQkFBMEI7UUFDbEMsTUFBTSxhQUFhLEdBQUc7WUFDcEIsSUFBSSxFQUFFLElBQUksQ0FBQyxxQkFBcUIsQ0FBQyxpQkFBaUI7WUFDbEQsR0FBRyxFQUFFLElBQUksQ0FBQyxxQkFBcUIsQ0FBQyxHQUFHO1NBQ3BDLENBQUM7UUFFRixPQUFPO1lBQ0wsSUFBSSxFQUFFLE9BQU8sQ0FBQyxzQkFBc0IsQ0FBQztZQUNyQyxXQUFXLEVBQUUsR0FBRyxDQUFDLElBQUksQ0FBQyxxQkFBcUIsRUFBRSxNQUFNLENBQUM7WUFDcEQsU0FBUyxFQUFFO2dCQUNULFdBQVcsRUFBRSw0QkFBNEIsSUFBSSxDQUFDLHFCQUFxQixDQUFDLElBQUksR0FBRztnQkFDM0Usc0JBQXNCLEVBQUUsYUFBYTthQUNiO1NBQzNCLENBQUM7SUFDSixDQUFDO0lBRU8sZ0JBQWdCLENBQUMsSUFBYSxFQUFFLGlCQUEwQjtRQUNoRSxNQUFNLEtBQUssR0FBUSxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsSUFBSSxFQUFFLElBQUksSUFBSSxHQUFHLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDO1FBQ3JELElBQUksaUJBQWlCLEVBQUUsQ0FBQztZQUN0QixLQUFLLENBQUMsSUFBSSxHQUFHLENBQUMsRUFBRSxpQkFBaUIsRUFBRSxFQUFFLEVBQUUsS0FBSyxFQUFFLEVBQUUsS0FBSyxFQUFFLG1CQUFtQixFQUFFLEVBQUUsQ0FBQyxDQUFDO1FBQ2xGLENBQUM7UUFDRCxPQUFPLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxxQkFBcUIsQ0FBQyxjQUFjLENBQUMsYUFBYSxFQUFFLEVBQUUsS0FBSyxFQUFFLENBQUMsQ0FBQztJQUMvRixDQUFDOytHQWpHVSxxQ0FBcUM7bUdBQXJDLHFDQUFxQyxrR0NwQmxELGcwUEFzTkE7OzRGRGxNYSxxQ0FBcUM7a0JBSmpELFNBQVM7K0JBQ0UscUNBQXFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQ2RrU3RlcCB9IGZyb20gJ0Bhbmd1bGFyL2Nkay9zdGVwcGVyJztcbmltcG9ydCB7IENvbXBvbmVudCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgSU1hbmFnZWRPYmplY3QsIElPcGVyYXRpb24sIElSZXN1bHRMaXN0IH0gZnJvbSAnQGM4eS9jbGllbnQnO1xuaW1wb3J0IHsgQzh5U3RlcHBlciwgZ2V0dGV4dCB9IGZyb20gJ0BjOHkvbmd4LWNvbXBvbmVudHMnO1xuaW1wb3J0IHsgQmFzZVN0ZXBwZXJDb21wb25lbnQgfSBmcm9tICdAYzh5L25neC1jb21wb25lbnRzL29wZXJhdGlvbnMvYnVsay1vcGVyYXRpb24tc3RlcHBlcic7XG5pbXBvcnQge1xuICBCdWxrT3BlcmF0aW9uc1NlcnZpY2UsXG4gIEJ1bGtPcGVyYXRpb25UeXBlLFxuICBPcGVyYXRpb25EZXRhaWxzXG59IGZyb20gJ0BjOHkvbmd4LWNvbXBvbmVudHMvb3BlcmF0aW9ucy9idWxrLW9wZXJhdGlvbnMtc2VydmljZSc7XG5pbXBvcnQgeyBSZXBvc2l0b3J5U2VydmljZSwgUmVwb3NpdG9yeVR5cGUgfSBmcm9tICdAYzh5L25neC1jb21wb25lbnRzL3JlcG9zaXRvcnkvc2hhcmVkJztcbmltcG9ydCB7IFRyYW5zbGF0ZVNlcnZpY2UgfSBmcm9tICdAbmd4LXRyYW5zbGF0ZS9jb3JlJztcbmltcG9ydCB7IGdldCwgaXNFcXVhbCwgdW5pcVdpdGggfSBmcm9tICdsb2Rhc2gtZXMnO1xuaW1wb3J0IHsgQmVoYXZpb3JTdWJqZWN0LCBjb21iaW5lTGF0ZXN0LCBmcm9tLCBPYnNlcnZhYmxlLCBTdWJzY3JpcHRpb24gfSBmcm9tICdyeGpzJztcbmltcG9ydCB7IGRlYm91bmNlVGltZSwgZGlzdGluY3RVbnRpbENoYW5nZWQsIHNoYXJlUmVwbGF5LCBzd2l0Y2hNYXAgfSBmcm9tICdyeGpzL29wZXJhdG9ycyc7XG5cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ2M4eS1zdGVwcGVyLWJ1bGstdHlwZS1jb25maWd1cmF0aW9uJyxcbiAgdGVtcGxhdGVVcmw6ICdzdGVwcGVyLWJ1bGstdHlwZS1jb25maWd1cmF0aW9uLmNvbXBvbmVudC5odG1sJ1xufSlcbmV4cG9ydCBjbGFzcyBTdGVwcGVyQnVsa1R5cGVDb25maWd1cmF0aW9uQ29tcG9uZW50IGV4dGVuZHMgQmFzZVN0ZXBwZXJDb21wb25lbnQge1xuICByZWFkb25seSB0eXBlOiBCdWxrT3BlcmF0aW9uVHlwZSA9IEJ1bGtPcGVyYXRpb25UeXBlLkNPTkZJR1VSQVRJT047XG4gIHJlYWRvbmx5IE5PX0RFVklDRV9UWVBFX0FWQUlMQUJMRSA9IGdldHRleHQoJ1VuZGVmaW5lZGBkZXZpY2UgdHlwZWAnKTtcbiAgc2VsZWN0ZWRDb25maWd1cmF0aW9uOiBJTWFuYWdlZE9iamVjdDtcbiAgRERfTE9XX0NPVU5UID0gMTA7XG4gIHRleHRGaWx0ZXIkOiBCZWhhdmlvclN1YmplY3Q8c3RyaW5nPiA9IG5ldyBCZWhhdmlvclN1YmplY3QoJycpO1xuICBjb25maWdUeXBlJDogQmVoYXZpb3JTdWJqZWN0PHN0cmluZz4gPSBuZXcgQmVoYXZpb3JTdWJqZWN0KCcnKTtcbiAgY29uZmlnVHlwZXMgPSBbXTtcbiAgc2VsZWN0ZWRDb25maWdUeXBlID0geyBuYW1lOiAnJyB9O1xuICBjb25maWd1cmF0aW9ucyQ6IE9ic2VydmFibGU8SVJlc3VsdExpc3Q8SU1hbmFnZWRPYmplY3Q+PiA9IGNvbWJpbmVMYXRlc3QoXG4gICAgdGhpcy50ZXh0RmlsdGVyJCxcbiAgICB0aGlzLmNvbmZpZ1R5cGUkXG4gICkucGlwZShcbiAgICBzd2l0Y2hNYXAoKFtuYW1lLCBjb25maWdUeXBlXSkgPT4gdGhpcy5nZXRDb25maWd1cmF0aW9uKG5hbWUsIGNvbmZpZ1R5cGUpKSxcbiAgICBzaGFyZVJlcGxheSgxKVxuICApO1xuICBwcml2YXRlIGNvbmZpZ1R5cGVTdWJzY3JpcHRpb246IFN1YnNjcmlwdGlvbjtcblxuICBjb25zdHJ1Y3RvcihcbiAgICBwcml2YXRlIGJ1bGtPcGVyYXRpb25TZXJ2aWNlOiBCdWxrT3BlcmF0aW9uc1NlcnZpY2UsXG4gICAgcHJpdmF0ZSByZXBvc2l0b3J5U2VydmljZTogUmVwb3NpdG9yeVNlcnZpY2UsXG4gICAgcHJpdmF0ZSB0cmFuc2xhdGU6IFRyYW5zbGF0ZVNlcnZpY2VcbiAgKSB7XG4gICAgc3VwZXIoKTtcbiAgICB0aGlzLkREX0xPV19DT1VOVCA9IHRoaXMuYnVsa09wZXJhdGlvblNlcnZpY2UuRERfTE9XX0NPVU5UO1xuICAgIHRoaXMubG9hZENvbmZpZ3VyYXRpb25UeXBlcygpO1xuICB9XG5cbiAgbG9hZENvbmZpZ3VyYXRpb25UeXBlcygpIHtcbiAgICB0aGlzLmNvbmZpZ1R5cGVTdWJzY3JpcHRpb24gPSB0aGlzLmNvbmZpZ1R5cGUkXG4gICAgICAucGlwZShcbiAgICAgICAgZGVib3VuY2VUaW1lKDMwMCksXG4gICAgICAgIGRpc3RpbmN0VW50aWxDaGFuZ2VkKCksXG4gICAgICAgIHN3aXRjaE1hcChzZWFyY2hTdHIgPT4ge1xuICAgICAgICAgIGNvbnN0IHF1ZXJ5ID0geyBjb25maWd1cmF0aW9uVHlwZTogYCoke3NlYXJjaFN0cn0qYCB9O1xuICAgICAgICAgIHJldHVybiBmcm9tKFxuICAgICAgICAgICAgdGhpcy5yZXBvc2l0b3J5U2VydmljZS5saXN0UmVwb3NpdG9yeUVudHJpZXMoUmVwb3NpdG9yeVR5cGUuQ09ORklHVVJBVElPTiwgeyBxdWVyeSB9KVxuICAgICAgICAgICk7XG4gICAgICAgIH0pXG4gICAgICApXG4gICAgICAuc3Vic2NyaWJlKHJlc3VsdCA9PiB7XG4gICAgICAgIGNvbnN0IHsgZGF0YSB9ID0gcmVzdWx0O1xuICAgICAgICB0aGlzLmNvbmZpZ1R5cGVzID0gdW5pcVdpdGgoXG4gICAgICAgICAgZGF0YS5tYXAodmFsID0+ICh7IG5hbWU6IHZhbC5jb25maWd1cmF0aW9uVHlwZSB9KSksXG4gICAgICAgICAgaXNFcXVhbFxuICAgICAgICApO1xuICAgICAgfSk7XG4gIH1cbiAgbmdPbkRlc3Ryb3koKTogdm9pZCB7XG4gICAgdGhpcy5jb25maWdUeXBlU3Vic2NyaXB0aW9uLnVuc3Vic2NyaWJlKCk7XG4gIH1cblxuICBzZWxlY3RDb25maWd1cmF0aW9uKGNvbmZpZ3VyYXRpb246IElNYW5hZ2VkT2JqZWN0KSB7XG4gICAgdGhpcy5zZWxlY3RlZENvbmZpZ3VyYXRpb24gPSBjb25maWd1cmF0aW9uO1xuICB9XG5cbiAgZ29Ub1NlY29uZFN0ZXAoJGV2ZW50OiB7IHN0ZXBwZXI6IEM4eVN0ZXBwZXI7IHN0ZXA6IENka1N0ZXAgfSkge1xuICAgICRldmVudC5zdGVwcGVyLm5leHQoKTtcbiAgICB0aGlzLmdldENvbmZpZ0JpbmFyeSgpO1xuICAgIHRoaXMuZGV2aWNlVHlwZXMgPSB0aGlzLnNlbGVjdGVkQ29uZmlndXJhdGlvbi5kZXZpY2VUeXBlO1xuICB9XG5cbiAgYXN5bmMgZ2V0Q29uZmlnQmluYXJ5KCkge1xuICAgIGlmICh0aGlzLnNlbGVjdGVkQ29uZmlndXJhdGlvbi51cmwpIHtcbiAgICAgIHRoaXMuc2VsZWN0ZWRDb25maWd1cmF0aW9uLmJpbmFyeSA9IGF3YWl0IHRoaXMucmVwb3NpdG9yeVNlcnZpY2UuZ2V0QmluYXJ5VGV4dChcbiAgICAgICAgdGhpcy5zZWxlY3RlZENvbmZpZ3VyYXRpb24udXJsLFxuICAgICAgICB7IGFsbG93RXh0ZXJuYWw6IHRydWUsIG5vQWxlcnRzOiB0cnVlIH1cbiAgICAgICk7XG4gICAgfVxuICB9XG5cbiAgZ2V0RGV2aWNlVHlwZVRpdGxlKGNvbmZpZ3VyYXRpb246IElNYW5hZ2VkT2JqZWN0KTogc3RyaW5nIHtcbiAgICByZXR1cm4gZ2V0KGNvbmZpZ3VyYXRpb24sICdkZXZpY2VUeXBlJywgdGhpcy50cmFuc2xhdGUuaW5zdGFudCh0aGlzLk5PX0RFVklDRV9UWVBFX0FWQUlMQUJMRSkpO1xuICB9XG5cbiAgcHJvdGVjdGVkIHJldHJpZXZlT3BlcmF0aW9uUHJvdG90eXBlKCk6IE9wZXJhdGlvbkRldGFpbHMge1xuICAgIGNvbnN0IGNvbmZpZ3VyYXRpb24gPSB7XG4gICAgICB0eXBlOiB0aGlzLnNlbGVjdGVkQ29uZmlndXJhdGlvbi5jb25maWd1cmF0aW9uVHlwZSxcbiAgICAgIHVybDogdGhpcy5zZWxlY3RlZENvbmZpZ3VyYXRpb24udXJsXG4gICAgfTtcblxuICAgIHJldHVybiB7XG4gICAgICBuYW1lOiBnZXR0ZXh0KCdDb25maWd1cmF0aW9uIHVwZGF0ZScpLFxuICAgICAgZGVzY3JpcHRpb246IGdldCh0aGlzLnNlbGVjdGVkQ29uZmlndXJhdGlvbiwgJ25hbWUnKSxcbiAgICAgIHByb3RvdHlwZToge1xuICAgICAgICBkZXNjcmlwdGlvbjogYFVwZGF0ZSBjb25maWd1cmF0aW9uIHRvOiAke3RoaXMuc2VsZWN0ZWRDb25maWd1cmF0aW9uLm5hbWV9LmAsXG4gICAgICAgIGM4eV9Eb3dubG9hZENvbmZpZ0ZpbGU6IGNvbmZpZ3VyYXRpb25cbiAgICAgIH0gYXMgdW5rbm93biBhcyBJT3BlcmF0aW9uXG4gICAgfTtcbiAgfVxuXG4gIHByaXZhdGUgZ2V0Q29uZmlndXJhdGlvbihuYW1lPzogc3RyaW5nLCBjb25maWd1cmF0aW9uVHlwZT86IHN0cmluZykge1xuICAgIGNvbnN0IHF1ZXJ5OiBhbnkgPSBuYW1lID8geyBuYW1lOiBgKiR7bmFtZX0qYCB9IDoge307XG4gICAgaWYgKGNvbmZpZ3VyYXRpb25UeXBlKSB7XG4gICAgICBxdWVyeS5fX29yID0gW3sgY29uZmlndXJhdGlvblR5cGUgfSwgeyBfX25vdDogeyBfX2hhczogYGNvbmZpZ3VyYXRpb25UeXBlYCB9IH1dO1xuICAgIH1cbiAgICByZXR1cm4gdGhpcy5yZXBvc2l0b3J5U2VydmljZS5saXN0UmVwb3NpdG9yeUVudHJpZXMoUmVwb3NpdG9yeVR5cGUuQ09ORklHVVJBVElPTiwgeyBxdWVyeSB9KTtcbiAgfVxufVxuIiwiPGM4eS1idWxrLW9wZXJhdGlvbi1zdGVwcGVyIFt0eXBlXT1cInR5cGVcIj5cbiAgPG5nLWNvbnRhaW5lclxuICAgICpjdXN0b21TdGVwPVwiXG4gICAgICAnU2VsZWN0IGNvbmZpZ3VyYXRpb24nIHwgdHJhbnNsYXRlO1xuICAgICAgY29tcGxldGVkOiAhIXNlbGVjdGVkQ29uZmlndXJhdGlvbjtcbiAgICAgIGJ1dHRvbnNEaXNhYmxlZDogIXNlbGVjdGVkQ29uZmlndXJhdGlvbjtcbiAgICAgIG9uTmV4dDogZ29Ub1NlY29uZFN0ZXAuYmluZCh0aGlzKVxuICAgIFwiXG4gID5cbiAgICA8Yzh5LXNlbGVjdC1zdGVwLWZyYW1lXG4gICAgICBbaGVhZGVyXT1cIidTZWxlY3QgY29uZmlndXJhdGlvbicgfCB0cmFuc2xhdGVcIlxuICAgICAgW25vUmVzdWx0c109XCJcbiAgICAgICAgKCh0ZXh0RmlsdGVyJCB8IGFzeW5jKT8ubGVuZ3RoIHx8IChjb25maWdUeXBlJCB8IGFzeW5jKT8ubGVuZ3RoKSAmJlxuICAgICAgICAoY29uZmlndXJhdGlvbnMkIHwgYXN5bmMpPy5kYXRhLmxlbmd0aCA9PT0gMFxuICAgICAgXCJcbiAgICA+XG4gICAgICA8ZGl2XG4gICAgICAgIGNsYXNzPVwicm93XCJcbiAgICAgICAgZmlsdGVyc1xuICAgICAgPlxuICAgICAgICA8ZGl2IGNsYXNzPVwiY29sLW1kLTZcIj5cbiAgICAgICAgICA8ZGl2IGNsYXNzPVwiaW5wdXQtZ3JvdXAgaW5wdXQtZ3JvdXAtc2VhcmNoXCI+XG4gICAgICAgICAgICA8aW5wdXRcbiAgICAgICAgICAgICAgY2xhc3M9XCJmb3JtLWNvbnRyb2xcIlxuICAgICAgICAgICAgICB0aXRsZT1cInt7ICdGaWx0ZXLigKYnIHwgdHJhbnNsYXRlIH19XCJcbiAgICAgICAgICAgICAgcGxhY2Vob2xkZXI9XCJ7eyAnRmlsdGVy4oCmJyB8IHRyYW5zbGF0ZSB9fVwiXG4gICAgICAgICAgICAgIHR5cGU9XCJzZWFyY2hcIlxuICAgICAgICAgICAgICBbbmdNb2RlbF09XCJ0ZXh0RmlsdGVyJCB8IGFzeW5jXCJcbiAgICAgICAgICAgICAgKG5nTW9kZWxDaGFuZ2UpPVwidGV4dEZpbHRlciQubmV4dCgkZXZlbnQpXCJcbiAgICAgICAgICAgIC8+XG4gICAgICAgICAgICA8c3BhbiBjbGFzcz1cImlucHV0LWdyb3VwLWFkZG9uXCI+XG4gICAgICAgICAgICAgIDxpXG4gICAgICAgICAgICAgICAgYzh5SWNvbj1cInNlYXJjaFwiXG4gICAgICAgICAgICAgICAgKm5nSWY9XCIodGV4dEZpbHRlciQgfCBhc3luYykubGVuZ3RoID09PSAwXCJcbiAgICAgICAgICAgICAgPjwvaT5cbiAgICAgICAgICAgICAgPGlcbiAgICAgICAgICAgICAgICBjbGFzcz1cInRleHQtbXV0ZWRcIlxuICAgICAgICAgICAgICAgIGM4eUljb249XCJ0aW1lc1wiXG4gICAgICAgICAgICAgICAgKm5nSWY9XCIodGV4dEZpbHRlciQgfCBhc3luYykubGVuZ3RoID4gMFwiXG4gICAgICAgICAgICAgICAgKGNsaWNrKT1cInRleHRGaWx0ZXIkLm5leHQoJycpXCJcbiAgICAgICAgICAgICAgPjwvaT5cbiAgICAgICAgICAgIDwvc3Bhbj5cbiAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgPC9kaXY+XG4gICAgICAgIDxkaXYgY2xhc3M9XCJjb2wteHMtMTIgcC1iLTggdmlzaWJsZS14cyB2aXNpYmxlLXNtXCI+PC9kaXY+XG4gICAgICAgIDxkaXYgY2xhc3M9XCJjb2wtbWQtNlwiPlxuICAgICAgICAgIDxjOHktZm9ybS1ncm91cCBjbGFzcz1cIm0tMFwiPlxuICAgICAgICAgICAgPGM4eS10eXBlYWhlYWRcbiAgICAgICAgICAgICAgcGxhY2Vob2xkZXI9XCJ7eyAnVHlwZSB0byBmaWx0ZXIgY29uZmlndXJhdGlvbiB0eXBlc+KApicgfCB0cmFuc2xhdGUgfX1cIlxuICAgICAgICAgICAgICBuYW1lPVwiY29uZmlnVHlwZVwiXG4gICAgICAgICAgICAgIFsobmdNb2RlbCldPVwic2VsZWN0ZWRDb25maWdUeXBlXCJcbiAgICAgICAgICAgICAgKG9uU2VhcmNoKT1cImNvbmZpZ1R5cGUkLm5leHQoJGV2ZW50KVwiXG4gICAgICAgICAgICA+XG4gICAgICAgICAgICAgIDxjOHktbGlcbiAgICAgICAgICAgICAgICBjbGFzcz1cInAtbC04IHAtci04IGM4eS1saXN0X19pdGVtLS1saW5rXCJcbiAgICAgICAgICAgICAgICAoY2xpY2spPVwic2VsZWN0ZWRDb25maWdUeXBlID0geyBuYW1lOiAnJyB9OyBjb25maWdUeXBlJC5uZXh0KCcnKVwiXG4gICAgICAgICAgICAgID5cbiAgICAgICAgICAgICAgICA8c3Bhbj57eyAnQWxsIGNvbmZpZ3VyYXRpb24gdHlwZXMnIHwgdHJhbnNsYXRlIH19PC9zcGFuPlxuICAgICAgICAgICAgICA8L2M4eS1saT5cbiAgICAgICAgICAgICAgPGM4eS1saVxuICAgICAgICAgICAgICAgIGNsYXNzPVwicC1sLTggcC1yLTggYzh5LWxpc3RfX2l0ZW0tLWxpbmtcIlxuICAgICAgICAgICAgICAgICpuZ0Zvcj1cImxldCBjb25maWdUeXBlIG9mIGNvbmZpZ1R5cGVzXCJcbiAgICAgICAgICAgICAgICAoY2xpY2spPVwic2VsZWN0ZWRDb25maWdUeXBlID0gY29uZmlnVHlwZTsgY29uZmlnVHlwZSQubmV4dChjb25maWdUeXBlLm5hbWUpXCJcbiAgICAgICAgICAgICAgICBbYWN0aXZlXT1cInNlbGVjdGVkQ29uZmlnVHlwZSA9PT0gY29uZmlnVHlwZVwiXG4gICAgICAgICAgICAgID5cbiAgICAgICAgICAgICAgICA8Yzh5LWhpZ2hsaWdodFxuICAgICAgICAgICAgICAgICAgW3RleHRdPVwiY29uZmlnVHlwZS5uYW1lXCJcbiAgICAgICAgICAgICAgICAgIFtwYXR0ZXJuXT1cImNvbmZpZ1R5cGUkIHwgYXN5bmNcIlxuICAgICAgICAgICAgICAgID48L2M4eS1oaWdobGlnaHQ+XG4gICAgICAgICAgICAgIDwvYzh5LWxpPlxuICAgICAgICAgICAgPC9jOHktdHlwZWFoZWFkPlxuICAgICAgICAgIDwvYzh5LWZvcm0tZ3JvdXA+XG4gICAgICAgIDwvZGl2PlxuICAgICAgPC9kaXY+XG4gICAgICA8Yzh5LWxpXG4gICAgICAgIGNsYXNzPVwiaGlkZGVuLXNtIGhpZGRlbi14cyBtLXItOCBtLWwtOFwiXG4gICAgICAgIGhlYWRlclxuICAgICAgPlxuICAgICAgICA8Yzh5LWxpLWljb24+PGkgY2xhc3M9XCJwLWwtMzIgcC1yLTQwXCI+PC9pPjwvYzh5LWxpLWljb24+XG4gICAgICAgIDxjOHktbGktYm9keSBjbGFzcz1cImNvbnRlbnQtZmxleC00MFwiPlxuICAgICAgICAgIDxkaXYgY2xhc3M9XCJjb2wtNVwiPlxuICAgICAgICAgICAgPHNwYW5cbiAgICAgICAgICAgICAgY2xhc3M9XCJ0ZXh0LXRydW5jYXRlXCJcbiAgICAgICAgICAgICAgdGl0bGU9XCIge3sgJ05hbWUnIHwgdHJhbnNsYXRlIH19IFwiXG4gICAgICAgICAgICA+XG4gICAgICAgICAgICAgIHt7ICdOYW1lJyB8IHRyYW5zbGF0ZSB9fVxuICAgICAgICAgICAgPC9zcGFuPlxuICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgIDxkaXYgY2xhc3M9XCJjb2wtNFwiPlxuICAgICAgICAgICAgPHNwYW5cbiAgICAgICAgICAgICAgY2xhc3M9XCJ0ZXh0LXRydW5jYXRlXCJcbiAgICAgICAgICAgICAgdGl0bGU9XCJ7eyAnRGV2aWNlIHR5cGUnIHwgdHJhbnNsYXRlIH19XCJcbiAgICAgICAgICAgID5cbiAgICAgICAgICAgICAge3sgJ0RldmljZSB0eXBlJyB8IHRyYW5zbGF0ZSB9fVxuICAgICAgICAgICAgPC9zcGFuPlxuICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgIDxkaXYgY2xhc3M9XCJjb2wtM1wiPlxuICAgICAgICAgICAgPHNwYW5cbiAgICAgICAgICAgICAgY2xhc3M9XCJ0ZXh0LXRydW5jYXRlXCJcbiAgICAgICAgICAgICAgdGl0bGU9XCJ7eyAnQ29uZmlndXJhdGlvbiB0eXBlJyB8IHRyYW5zbGF0ZSB9fVwiXG4gICAgICAgICAgICA+XG4gICAgICAgICAgICAgIHt7ICdDb25maWd1cmF0aW9uIHR5cGUnIHwgdHJhbnNsYXRlIH19XG4gICAgICAgICAgICA8L3NwYW4+XG4gICAgICAgICAgPC9kaXY+XG4gICAgICAgIDwvYzh5LWxpLWJvZHk+XG4gICAgICA8L2M4eS1saT5cbiAgICAgIDxjOHktbGlzdC1ncm91cCBsaXN0PlxuICAgICAgICA8Yzh5LWxpXG4gICAgICAgICAgI2xpc3RJdGVtXG4gICAgICAgICAgKmM4eUZvcj1cImxldCBjb25maWd1cmF0aW9uIG9mIGNvbmZpZ3VyYXRpb25zJCB8IGFzeW5jXCJcbiAgICAgICAgPlxuICAgICAgICAgIDxjOHktbGktcmFkaW8gKG9uU2VsZWN0KT1cInNlbGVjdENvbmZpZ3VyYXRpb24oY29uZmlndXJhdGlvbilcIj48L2M4eS1saS1yYWRpbz5cbiAgICAgICAgICA8Yzh5LWxpLWljb24gaWNvbj1cImdlYXJzXCI+PC9jOHktbGktaWNvbj5cbiAgICAgICAgICA8Yzh5LWxpLWJvZHkgY2xhc3M9XCJjb250ZW50LWZsZXgtNDBcIj5cbiAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJjb2wtNSBtLWIteHMtOFwiPlxuICAgICAgICAgICAgICA8ZGl2XG4gICAgICAgICAgICAgICAgY2xhc3M9XCJ0ZXh0LXRydW5jYXRlXCJcbiAgICAgICAgICAgICAgICB0aXRsZT1cInt7IGNvbmZpZ3VyYXRpb24ubmFtZSB8fCAnLScgfX1cIlxuICAgICAgICAgICAgICA+XG4gICAgICAgICAgICAgICAgPGM4eS1oaWdobGlnaHRcbiAgICAgICAgICAgICAgICAgIFt0ZXh0XT1cImNvbmZpZ3VyYXRpb24ubmFtZSB8fCAnLSdcIlxuICAgICAgICAgICAgICAgICAgW3BhdHRlcm5dPVwidGV4dEZpbHRlciQgfCBhc3luY1wiXG4gICAgICAgICAgICAgICAgPjwvYzh5LWhpZ2hsaWdodD5cbiAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJjb2wtNCBtLWIteHMtOFwiPlxuICAgICAgICAgICAgICA8ZGl2XG4gICAgICAgICAgICAgICAgY2xhc3M9XCJ0ZXh0LXRydW5jYXRlXCJcbiAgICAgICAgICAgICAgICB0aXRsZT1cInt7ICdEZXZpY2UgdHlwZScgfCB0cmFuc2xhdGUgfX06IHt7IGdldERldmljZVR5cGVUaXRsZShjb25maWd1cmF0aW9uKSB9fVwiXG4gICAgICAgICAgICAgID5cbiAgICAgICAgICAgICAgICA8c3BhblxuICAgICAgICAgICAgICAgICAgY2xhc3M9XCJ0ZXh0LWxhYmVsLXNtYWxsIG0tci04IHZpc2libGUteHMgdmlzaWJsZS1zbVwiXG4gICAgICAgICAgICAgICAgICB0cmFuc2xhdGVcbiAgICAgICAgICAgICAgICA+XG4gICAgICAgICAgICAgICAgICBEZXZpY2UgdHlwZVxuICAgICAgICAgICAgICAgIDwvc3Bhbj5cbiAgICAgICAgICAgICAgICB7eyBjb25maWd1cmF0aW9uLmRldmljZVR5cGUgfX1cbiAgICAgICAgICAgICAgICA8ZW1cbiAgICAgICAgICAgICAgICAgIGNsYXNzPVwidGV4dC1tdXRlZFwiXG4gICAgICAgICAgICAgICAgICAqbmdJZj1cIiFjb25maWd1cmF0aW9uLmRldmljZVR5cGVcIlxuICAgICAgICAgICAgICAgID5cbiAgICAgICAgICAgICAgICAgIHt7ICdVbmRlZmluZWRgZGV2aWNlIHR5cGVgJyB8IHRyYW5zbGF0ZSB9fVxuICAgICAgICAgICAgICAgIDwvZW0+XG4gICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICA8ZGl2IGNsYXNzPVwiY29sLTMgbS1iLXhzLThcIj5cbiAgICAgICAgICAgICAgPHNwYW5cbiAgICAgICAgICAgICAgICBjbGFzcz1cInRleHQtbGFiZWwtc21hbGwgbS1yLTggdmlzaWJsZS14cyB2aXNpYmxlLXNtXCJcbiAgICAgICAgICAgICAgICB0cmFuc2xhdGVcbiAgICAgICAgICAgICAgPlxuICAgICAgICAgICAgICAgIENvbmZpZ3VyYXRpb24gdHlwZVxuICAgICAgICAgICAgICA8L3NwYW4+XG4gICAgICAgICAgICAgIDxzcGFuXG4gICAgICAgICAgICAgICAgY2xhc3M9XCJsYWJlbCBsYWJlbC1pbmZvXCJcbiAgICAgICAgICAgICAgICB0aXRsZT1cInt7ICdDb25maWd1cmF0aW9uIHR5cGUnIHwgdHJhbnNsYXRlIH19OiB7e1xuICAgICAgICAgICAgICAgICAgY29uZmlndXJhdGlvbi5jb25maWd1cmF0aW9uVHlwZVxuICAgICAgICAgICAgICAgIH19XCJcbiAgICAgICAgICAgICAgICAqbmdJZj1cImNvbmZpZ3VyYXRpb24uY29uZmlndXJhdGlvblR5cGVcIlxuICAgICAgICAgICAgICA+XG4gICAgICAgICAgICAgICAgPGM4eS1oaWdobGlnaHRcbiAgICAgICAgICAgICAgICAgIFt0ZXh0XT1cImNvbmZpZ3VyYXRpb24uY29uZmlndXJhdGlvblR5cGVcIlxuICAgICAgICAgICAgICAgICAgZWxlbWVudENsYXNzPVwidGV4dC1ncmF5LWxpZ2h0ZXJcIlxuICAgICAgICAgICAgICAgICAgW3BhdHRlcm5dPVwiY29uZmlnVHlwZSQgfCBhc3luY1wiXG4gICAgICAgICAgICAgICAgPjwvYzh5LWhpZ2hsaWdodD5cbiAgICAgICAgICAgICAgPC9zcGFuPlxuICAgICAgICAgICAgICA8c3BhblxuICAgICAgICAgICAgICAgIGNsYXNzPVwibGFiZWwgbGFiZWwtZGVmYXVsdFwiXG4gICAgICAgICAgICAgICAgdGl0bGU9XCJ7eyAnQ29uZmlndXJhdGlvbiB0eXBlJyB8IHRyYW5zbGF0ZSB9fToge3sgJ1VuZGVmaW5lZCcgfCB0cmFuc2xhdGUgfX1cIlxuICAgICAgICAgICAgICAgICpuZ0lmPVwiIWNvbmZpZ3VyYXRpb24uY29uZmlndXJhdGlvblR5cGVcIlxuICAgICAgICAgICAgICA+XG4gICAgICAgICAgICAgICAge3sgJ1VuZGVmaW5lZCcgfCB0cmFuc2xhdGUgfX1cbiAgICAgICAgICAgICAgPC9zcGFuPlxuICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgPC9jOHktbGktYm9keT5cbiAgICAgICAgPC9jOHktbGk+XG4gICAgICA8L2M4eS1saXN0LWdyb3VwPlxuICAgIDwvYzh5LXNlbGVjdC1zdGVwLWZyYW1lPlxuICA8L25nLWNvbnRhaW5lcj5cbiAgPG5nLWNvbnRhaW5lciAqY3VzdG9tU3RlcD1cIidQcmV2aWV3IGNvbmZpZ3VyYXRpb24nIHwgdHJhbnNsYXRlXCI+XG4gICAgPGM4eS1wcmV2aWV3LXNlbGVjdGlvbi1mcmFtZVxuICAgICAgW2hlYWRlcl09XCInUHJldmlldyBjb25maWd1cmF0aW9uJyB8IHRyYW5zbGF0ZVwiXG4gICAgICBbbmFtZV09XCJzZWxlY3RlZENvbmZpZ3VyYXRpb24/Lm5hbWVcIlxuICAgICAgW3R5cGVdPVwic2VsZWN0ZWRDb25maWd1cmF0aW9uPy5jb25maWd1cmF0aW9uVHlwZVwiXG4gICAgPlxuICAgICAgPG5nLWNvbnRhaW5lciAqcHJldmlld0Jsb2NrPVwiJ0RldmljZSB0eXBlJyB8IHRyYW5zbGF0ZVwiPlxuICAgICAgICA8bmctY29udGFpbmVyICpuZ0lmPVwic2VsZWN0ZWRDb25maWd1cmF0aW9uPy5kZXZpY2VUeXBlOyBlbHNlIG5vVHlwZVwiPlxuICAgICAgICAgIDxzcGFuPnt7IHNlbGVjdGVkQ29uZmlndXJhdGlvbj8uZGV2aWNlVHlwZSB9fTwvc3Bhbj5cbiAgICAgICAgPC9uZy1jb250YWluZXI+XG4gICAgICAgIDxuZy10ZW1wbGF0ZSAjbm9UeXBlPlxuICAgICAgICAgIDxlbVxuICAgICAgICAgICAgY2xhc3M9XCJ0ZXh0LW11dGVkXCJcbiAgICAgICAgICAgIHRyYW5zbGF0ZVxuICAgICAgICAgID5cbiAgICAgICAgICAgIFVuZGVmaW5lZGBkZXZpY2UgdHlwZWBcbiAgICAgICAgICA8L2VtPlxuICAgICAgICA8L25nLXRlbXBsYXRlPlxuICAgICAgPC9uZy1jb250YWluZXI+XG4gICAgICA8bmctY29udGFpbmVyICpwcmV2aWV3QmxvY2s9XCInVXBkYXRlZCcgfCB0cmFuc2xhdGVcIj5cbiAgICAgICAgPHNwYW4+e3sgc2VsZWN0ZWRDb25maWd1cmF0aW9uPy5sYXN0VXBkYXRlZCB8IGM4eURhdGUgfX08L3NwYW4+XG4gICAgICA8L25nLWNvbnRhaW5lcj5cbiAgICAgIDxuZy1jb250YWluZXIgKnByZXZpZXdCbG9jaz1cIidQcmV2aWV3JyB8IHRyYW5zbGF0ZVwiPlxuICAgICAgICA8Yzh5LXVpLWVtcHR5LXN0YXRlXG4gICAgICAgICAgW2ljb25dPVwiJ2ZpbGUtY29kZS1vJ1wiXG4gICAgICAgICAgW3RpdGxlXT1cIidObyBwcmV2aWV3IGF2YWlsYWJsZS4nIHwgdHJhbnNsYXRlXCJcbiAgICAgICAgICBbc3VidGl0bGVdPVwiJ0NvdWxkIG5vdCBmZXRjaCB0aGUgZmlsZS4nIHwgdHJhbnNsYXRlXCJcbiAgICAgICAgICAqbmdJZj1cIiF0aGlzLnNlbGVjdGVkQ29uZmlndXJhdGlvbj8uYmluYXJ5OyBlbHNlIGJpbmFyeVByZXZpZXdcIlxuICAgICAgICA+PC9jOHktdWktZW1wdHktc3RhdGU+XG4gICAgICAgIDxuZy10ZW1wbGF0ZSAjYmluYXJ5UHJldmlldz5cbiAgICAgICAgICA8cHJlIHN0eWxlPVwibWluLWhlaWdodDogOThweFwiPjxjb2RlPnt7IHRoaXMuc2VsZWN0ZWRDb25maWd1cmF0aW9uPy5iaW5hcnkgfX08L2NvZGU+PC9wcmU+XG4gICAgICAgIDwvbmctdGVtcGxhdGU+XG4gICAgICA8L25nLWNvbnRhaW5lcj5cbiAgICA8L2M4eS1wcmV2aWV3LXNlbGVjdGlvbi1mcmFtZT5cbiAgPC9uZy1jb250YWluZXI+XG48L2M4eS1idWxrLW9wZXJhdGlvbi1zdGVwcGVyPlxuIl19