UNPKG

@c8y/ngx-components

Version:

Angular modules for Cumulocity IoT applications

153 lines 45.3 kB
import { Component, ViewChild } from '@angular/core'; import { ApplicationService } from '@c8y/client'; import { PluginsService, WizardComponent } from '@c8y/ngx-components'; import { BehaviorSubject, combineLatest, from, of } from 'rxjs'; import { map } from 'rxjs/operators'; import { EcosystemService } from '@c8y/ngx-components/ecosystem/shared'; import { ApplicationPropertiesFormComponent } from '@c8y/ngx-components/ecosystem/shared'; import * as i0 from "@angular/core"; import * as i1 from "@c8y/ngx-components/ecosystem/shared"; import * as i2 from "@c8y/client"; import * as i3 from "@c8y/ngx-components"; import * as i4 from "@angular/common"; import * as i5 from "@angular/forms"; export class InstallFromPackageComponent { constructor(ecosystemService, applicationService, wizardComponent, pluginsService) { this.ecosystemService = ecosystemService; this.applicationService = applicationService; this.wizardComponent = wizardComponent; this.pluginsService = pluginsService; this.deployedWithSuccess = false; this.isDeployed = false; this.model = { selected: undefined, binary: { id: undefined } }; this.canDeploy = false; this.onInput = new BehaviorSubject(''); } async ngOnInit() { this.loadPackages(); } back() { this.wizardComponent.reset(); } clean() { this.selectedPackage = undefined; this.versions$ = undefined; this.model = { selected: undefined, binary: { id: undefined } }; } cancel() { this.wizardComponent.close(); } async deployApp() { this.inProgress = true; const formGroupValue = this.applicationPropertiesForm.formGroup.getRawValue(); const { contextPath, license, name } = this.selectedPackage; const type = this.pluginsService.getPackageType(this.selectedPackage); const licensedApp = { contextPath, license, name, type, version: this.model.selected.version }; const isArchived = await this.ecosystemService.verifyArchived([licensedApp]); if (!isArchived) { this.cancel(); return; } const licensesVerifiedByUser = await this.ecosystemService.verifyLicenses([licensedApp]); if (!licensesVerifiedByUser) { this.cancel(); return; } // Verify if selected package version is compatible with current platform versions. this.selectedPackage.manifest.version = this.model.selected.version; const verifyVersionCompatibility = await this.ecosystemService.verifyBlueprintVersionsCompatibility(this.selectedPackage.manifest); if (!verifyVersionCompatibility) { this.cancel(); return; } try { await this.ecosystemService.deployApp(this.selectedPackage, formGroupValue, this.model); this.deployedWithSuccess = true; } catch (error) { this.ecosystemService.alertError(error); } finally { this.markAsDeployed(); } } onAppVersionSelect(appVersion) { Object.assign(this.model, { selected: appVersion }); this.canDeploy = true; } async selectPackage(selectedPackage) { const apps = await this.ecosystemService.getHostedAndPackageApplications(); this.newAppConfig = this.ecosystemService.getUniqueAppConfig(selectedPackage, apps); this.selectedPackage = selectedPackage; this.loadSelectedPackageVersions(); } loadSelectedPackageVersions() { this.versions$ = combineLatest([ this.getAppVersions(this.selectPackage), this.onInput.asObservable() ]).pipe(map(([resultList, filterStr]) => { this.canDeploy = false; const versionsFilteredByStr = this.filterAppVersions(resultList.data, filterStr); const sortedAppVersions = this.pluginsService.sortVersions({ list: versionsFilteredByStr, path: ['version'] }, 'desc'); this.setInitialValueForInput(sortedAppVersions); return { data: sortedAppVersions, res: resultList.res }; })); } getAppVersions(mo) { const versions = mo?.applicationVersions; return versions && versions.length > 0 ? of({ data: versions, res: undefined }) : from(this.applicationService.listVersions(this.selectedPackage.id)); } setInitialValueForInput(versions) { if (!this.model.selected && versions.length > 0) { const latest = versions.find(v => v.tags.includes('latest')); this.model.selected = latest || versions[0]; this.canDeploy = true; } } filterAppVersions(appVersions, filterStr) { return filterStr === '' ? appVersions : appVersions.filter(appVersion => appVersion.version.includes(filterStr)); } markAsDeployed() { this.isDeployed = true; this.inProgress = false; } async loadPackages() { const applications = await this.ecosystemService.getPackageApplications(); this.packages = applications.filter(app => this.ecosystemService.isPackageBlueprint(app)); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: InstallFromPackageComponent, deps: [{ token: i1.EcosystemService }, { token: i2.ApplicationService }, { token: i3.WizardComponent }, { token: i3.PluginsService }], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: InstallFromPackageComponent, selector: "c8y-install-from-package", viewQueries: [{ propertyName: "applicationPropertiesForm", first: true, predicate: ApplicationPropertiesFormComponent, descendants: true }], ngImport: i0, template: "<c8y-wizard-header>\n <i [c8yIcon]=\"'big-parcel'\"></i>\n <h4\n id=\"modal-title\"\n translate\n >\n Install from extension package\n </h4>\n</c8y-wizard-header>\n<c8y-wizard-body>\n <ng-container *ngIf=\"!selectedPackage\">\n <div\n class=\"modal-inner-scroll\"\n id=\"modal-body\"\n >\n <p class=\"p-16 text-medium text-center separator-bottom sticky-top bg-level-0\">\n {{ 'Select from available extension packages' | translate }}\n </p>\n\n <c8y-ui-empty-state\n [icon]=\"'big-parcel'\"\n [title]=\"'No extension packages to display.' | translate\"\n *ngIf=\"!packages?.length\"\n [horizontal]=\"true\"\n ></c8y-ui-empty-state>\n\n <div\n class=\"c8y-wizard-list-nav\"\n style=\"min-height: 257px\"\n *ngIf=\"packages?.length\"\n >\n <button\n class=\"list-group-item text-truncate\"\n title=\"{{ package.name }}\"\n type=\"button\"\n *ngFor=\"let package of packages\"\n (click)=\"selectPackage(package)\"\n >\n <i\n class=\"list-group-icon\"\n c8yIcon=\"big-parcel\"\n ></i>\n <span [innerText]=\"package.name\"></span>\n </button>\n </div>\n </div>\n </ng-container>\n <ng-container *ngIf=\"!isDeployed && selectedPackage\">\n <p class=\"p-16 text-center text-medium separator-bottom sticky-top bg-level-0\">\n {{ 'Provide application details' | translate }}\n </p>\n <div\n class=\"d-flex d-col a-i-center j-c-center\"\n style=\"min-height: 257px\"\n >\n <c8y-application-properties-form\n class=\"d-block fit-w\"\n *ngIf=\"!inProgress\"\n [application]=\"newAppConfig\"\n ></c8y-application-properties-form>\n\n <ng-container *ngIf=\"!inProgress\">\n <div\n class=\"d-block fit-w bg-gray-white\"\n [ngStyle]=\"{ padding: '0 16px' }\"\n >\n <label\n for=\"packageVersion\"\n translate\n >\n Use extension package version\n </label>\n <c8y-form-group>\n <c8y-typeahead\n placeholder=\"{{ 'Select or enter' | translate }}\"\n name=\"packageVersion\"\n [(ngModel)]=\"model.selected\"\n (onSearch)=\"onInput.next($event)\"\n [displayProperty]=\"'version'\"\n [required]=\"true\"\n [hideNew]=\"true\"\n [container]=\"'body'\"\n >\n <c8y-li\n class=\"p-l-8 p-r-8 c8y-list__item--link\"\n *c8yFor=\"let version of versions$; loadMore: 'auto'; notFound: notFoundTemplate\"\n (click)=\"onAppVersionSelect(version)\"\n [active]=\"model.selected === version\"\n >\n <c8y-li-icon icon=\"big-parcel\"></c8y-li-icon>\n <span\n [ngStyle]=\"{\n display: 'flex',\n 'flex-direction': 'row',\n 'align-content': 'center',\n 'justify-content': 'space-between',\n 'align-items': 'center'\n }\"\n >\n <c8y-highlight\n [text]=\"version.version || '--'\"\n [pattern]=\"onInput | async\"\n ></c8y-highlight>\n\n <span>\n <span\n class=\"label label-info m-l-4\"\n *ngFor=\"let tag of version.tags\"\n >\n {{ tag }}\n </span>\n </span>\n </span>\n </c8y-li>\n <ng-template #notFoundTemplate>\n <c8y-li\n class=\"bg-gray-lighter p-8\"\n *ngIf=\"(onInput | async)?.length > 0 && (versions$ | async)?.data?.length === 0\"\n >\n <span translate>No match found.</span>\n </c8y-li>\n </ng-template>\n </c8y-typeahead>\n </c8y-form-group>\n </div>\n </ng-container>\n\n <c8y-loading\n class=\"text-center d-block\"\n [message]=\"'Installing\u2026' | translate\"\n *ngIf=\"inProgress\"\n layout=\"application\"\n ></c8y-loading>\n </div>\n </ng-container>\n\n <ng-container *ngIf=\"isDeployed\">\n <div\n class=\"d-flex a-i-center j-c-center\"\n style=\"min-height: 257px\"\n *ngIf=\"deployedWithSuccess; else failedDeploy\"\n >\n <c8y-operation-result\n class=\"lead\"\n type=\"success\"\n text=\"{{ 'Application created' | translate }}\"\n [size]=\"84\"\n [vertical]=\"true\"\n ></c8y-operation-result>\n </div>\n <ng-template #failedDeploy>\n <div\n class=\"d-flex a-i-center j-c-center\"\n style=\"min-height: 257px\"\n >\n <c8y-operation-result\n class=\"lead\"\n type=\"error\"\n text=\"{{ 'Application creation failed' | translate }}\"\n [size]=\"84\"\n [vertical]=\"true\"\n ></c8y-operation-result>\n </div>\n </ng-template>\n </ng-container>\n</c8y-wizard-body>\n\n<c8y-wizard-footer>\n <button\n class=\"btn btn-default\"\n title=\"{{ 'Back' | translate }}\"\n type=\"button\"\n *ngIf=\"!isDeployed\"\n (click)=\"selectedPackage ? clean() : back()\"\n [disabled]=\"inProgress\"\n >\n {{ 'Back' | translate }}\n </button>\n <button\n class=\"btn btn-default\"\n title=\"{{ isDeployed && deployedWithSuccess ? ('Close' | translate) : ('Cancel' | translate) }}\"\n type=\"button\"\n (click)=\"cancel()\"\n >\n {{ isDeployed && deployedWithSuccess ? ('Close' | translate) : ('Cancel' | translate) }}\n </button>\n\n <button\n class=\"btn btn-primary\"\n title=\"{{ 'Install' | translate }}\"\n type=\"button\"\n (click)=\"deployApp()\"\n [disabled]=\"inProgress || !packages?.length\"\n *ngIf=\"!isDeployed\"\n >\n {{ 'Install' | translate }}\n </button>\n</c8y-wizard-footer>\n", dependencies: [{ kind: "component", type: i3.EmptyStateComponent, selector: "c8y-ui-empty-state", inputs: ["icon", "title", "subtitle", "horizontal"] }, { kind: "directive", type: i3.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: i3.C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: i4.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i4.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i4.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: i3.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: i3.LoadingComponent, selector: "c8y-loading", inputs: ["layout", "progress", "message"] }, { kind: "component", type: i3.OperationResultComponent, selector: "c8y-operation-result", inputs: ["text", "vertical", "size", "type"] }, { kind: "component", type: i3.HighlightComponent, selector: "c8y-highlight", inputs: ["pattern", "text", "elementClass", "shouldTrimPattern"] }, { kind: "component", type: i3.TypeaheadComponent, selector: "c8y-typeahead", inputs: ["required", "maxlength", "disabled", "allowFreeEntries", "placeholder", "displayProperty", "icon", "name", "autoClose", "hideNew", "container", "selected", "highlightFirstItem"], outputs: ["onSearch", "onIconClick"] }, { kind: "directive", type: i5.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i5.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i5.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: i3.FormGroupComponent, selector: "c8y-form-group", inputs: ["hasError", "hasWarning", "hasSuccess", "novalidation", "status"] }, { kind: "component", type: i3.ListItemComponent, selector: "c8y-list-item, c8y-li", inputs: ["active", "highlighted", "emptyActions", "dense", "collapsed", "selectable"], outputs: ["collapsedChange"] }, { kind: "component", type: i3.ListItemIconComponent, selector: "c8y-list-item-icon, c8y-li-icon", inputs: ["icon", "status"] }, { kind: "component", type: i3.WizardHeaderComponent, selector: "c8y-wizard-header" }, { kind: "component", type: i3.WizardBodyComponent, selector: "c8y-wizard-body" }, { kind: "component", type: i3.WizardFooterComponent, selector: "c8y-wizard-footer" }, { kind: "component", type: i1.ApplicationPropertiesFormComponent, selector: "c8y-application-properties-form", inputs: ["application", "disabled"] }, { kind: "pipe", type: i3.C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: i4.AsyncPipe, name: "async" }] }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: InstallFromPackageComponent, decorators: [{ type: Component, args: [{ selector: 'c8y-install-from-package', template: "<c8y-wizard-header>\n <i [c8yIcon]=\"'big-parcel'\"></i>\n <h4\n id=\"modal-title\"\n translate\n >\n Install from extension package\n </h4>\n</c8y-wizard-header>\n<c8y-wizard-body>\n <ng-container *ngIf=\"!selectedPackage\">\n <div\n class=\"modal-inner-scroll\"\n id=\"modal-body\"\n >\n <p class=\"p-16 text-medium text-center separator-bottom sticky-top bg-level-0\">\n {{ 'Select from available extension packages' | translate }}\n </p>\n\n <c8y-ui-empty-state\n [icon]=\"'big-parcel'\"\n [title]=\"'No extension packages to display.' | translate\"\n *ngIf=\"!packages?.length\"\n [horizontal]=\"true\"\n ></c8y-ui-empty-state>\n\n <div\n class=\"c8y-wizard-list-nav\"\n style=\"min-height: 257px\"\n *ngIf=\"packages?.length\"\n >\n <button\n class=\"list-group-item text-truncate\"\n title=\"{{ package.name }}\"\n type=\"button\"\n *ngFor=\"let package of packages\"\n (click)=\"selectPackage(package)\"\n >\n <i\n class=\"list-group-icon\"\n c8yIcon=\"big-parcel\"\n ></i>\n <span [innerText]=\"package.name\"></span>\n </button>\n </div>\n </div>\n </ng-container>\n <ng-container *ngIf=\"!isDeployed && selectedPackage\">\n <p class=\"p-16 text-center text-medium separator-bottom sticky-top bg-level-0\">\n {{ 'Provide application details' | translate }}\n </p>\n <div\n class=\"d-flex d-col a-i-center j-c-center\"\n style=\"min-height: 257px\"\n >\n <c8y-application-properties-form\n class=\"d-block fit-w\"\n *ngIf=\"!inProgress\"\n [application]=\"newAppConfig\"\n ></c8y-application-properties-form>\n\n <ng-container *ngIf=\"!inProgress\">\n <div\n class=\"d-block fit-w bg-gray-white\"\n [ngStyle]=\"{ padding: '0 16px' }\"\n >\n <label\n for=\"packageVersion\"\n translate\n >\n Use extension package version\n </label>\n <c8y-form-group>\n <c8y-typeahead\n placeholder=\"{{ 'Select or enter' | translate }}\"\n name=\"packageVersion\"\n [(ngModel)]=\"model.selected\"\n (onSearch)=\"onInput.next($event)\"\n [displayProperty]=\"'version'\"\n [required]=\"true\"\n [hideNew]=\"true\"\n [container]=\"'body'\"\n >\n <c8y-li\n class=\"p-l-8 p-r-8 c8y-list__item--link\"\n *c8yFor=\"let version of versions$; loadMore: 'auto'; notFound: notFoundTemplate\"\n (click)=\"onAppVersionSelect(version)\"\n [active]=\"model.selected === version\"\n >\n <c8y-li-icon icon=\"big-parcel\"></c8y-li-icon>\n <span\n [ngStyle]=\"{\n display: 'flex',\n 'flex-direction': 'row',\n 'align-content': 'center',\n 'justify-content': 'space-between',\n 'align-items': 'center'\n }\"\n >\n <c8y-highlight\n [text]=\"version.version || '--'\"\n [pattern]=\"onInput | async\"\n ></c8y-highlight>\n\n <span>\n <span\n class=\"label label-info m-l-4\"\n *ngFor=\"let tag of version.tags\"\n >\n {{ tag }}\n </span>\n </span>\n </span>\n </c8y-li>\n <ng-template #notFoundTemplate>\n <c8y-li\n class=\"bg-gray-lighter p-8\"\n *ngIf=\"(onInput | async)?.length > 0 && (versions$ | async)?.data?.length === 0\"\n >\n <span translate>No match found.</span>\n </c8y-li>\n </ng-template>\n </c8y-typeahead>\n </c8y-form-group>\n </div>\n </ng-container>\n\n <c8y-loading\n class=\"text-center d-block\"\n [message]=\"'Installing\u2026' | translate\"\n *ngIf=\"inProgress\"\n layout=\"application\"\n ></c8y-loading>\n </div>\n </ng-container>\n\n <ng-container *ngIf=\"isDeployed\">\n <div\n class=\"d-flex a-i-center j-c-center\"\n style=\"min-height: 257px\"\n *ngIf=\"deployedWithSuccess; else failedDeploy\"\n >\n <c8y-operation-result\n class=\"lead\"\n type=\"success\"\n text=\"{{ 'Application created' | translate }}\"\n [size]=\"84\"\n [vertical]=\"true\"\n ></c8y-operation-result>\n </div>\n <ng-template #failedDeploy>\n <div\n class=\"d-flex a-i-center j-c-center\"\n style=\"min-height: 257px\"\n >\n <c8y-operation-result\n class=\"lead\"\n type=\"error\"\n text=\"{{ 'Application creation failed' | translate }}\"\n [size]=\"84\"\n [vertical]=\"true\"\n ></c8y-operation-result>\n </div>\n </ng-template>\n </ng-container>\n</c8y-wizard-body>\n\n<c8y-wizard-footer>\n <button\n class=\"btn btn-default\"\n title=\"{{ 'Back' | translate }}\"\n type=\"button\"\n *ngIf=\"!isDeployed\"\n (click)=\"selectedPackage ? clean() : back()\"\n [disabled]=\"inProgress\"\n >\n {{ 'Back' | translate }}\n </button>\n <button\n class=\"btn btn-default\"\n title=\"{{ isDeployed && deployedWithSuccess ? ('Close' | translate) : ('Cancel' | translate) }}\"\n type=\"button\"\n (click)=\"cancel()\"\n >\n {{ isDeployed && deployedWithSuccess ? ('Close' | translate) : ('Cancel' | translate) }}\n </button>\n\n <button\n class=\"btn btn-primary\"\n title=\"{{ 'Install' | translate }}\"\n type=\"button\"\n (click)=\"deployApp()\"\n [disabled]=\"inProgress || !packages?.length\"\n *ngIf=\"!isDeployed\"\n >\n {{ 'Install' | translate }}\n </button>\n</c8y-wizard-footer>\n" }] }], ctorParameters: () => [{ type: i1.EcosystemService }, { type: i2.ApplicationService }, { type: i3.WizardComponent }, { type: i3.PluginsService }], propDecorators: { applicationPropertiesForm: [{ type: ViewChild, args: [ApplicationPropertiesFormComponent] }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5zdGFsbC1mcm9tLXBhY2thZ2UuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vZWNvc3lzdGVtL2FwcGxpY2F0aW9ucy9pbnN0YWxsLWZyb20tcGFja2FnZS9pbnN0YWxsLWZyb20tcGFja2FnZS5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi8uLi9lY29zeXN0ZW0vYXBwbGljYXRpb25zL2luc3RhbGwtZnJvbS1wYWNrYWdlL2luc3RhbGwtZnJvbS1wYWNrYWdlLmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxTQUFTLEVBQVUsU0FBUyxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQzdELE9BQU8sRUFBRSxrQkFBa0IsRUFBa0QsTUFBTSxhQUFhLENBQUM7QUFDakcsT0FBTyxFQUFFLGNBQWMsRUFBRSxlQUFlLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQUN0RSxPQUFPLEVBQUUsZUFBZSxFQUFFLGFBQWEsRUFBRSxJQUFJLEVBQWMsRUFBRSxFQUFFLE1BQU0sTUFBTSxDQUFDO0FBQzVFLE9BQU8sRUFBRSxHQUFHLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUNyQyxPQUFPLEVBQUUsZ0JBQWdCLEVBQTZCLE1BQU0sc0NBQXNDLENBQUM7QUFDbkcsT0FBTyxFQUFFLGtDQUFrQyxFQUFFLE1BQU0sc0NBQXNDLENBQUM7Ozs7Ozs7QUFNMUYsTUFBTSxPQUFPLDJCQUEyQjtJQW9CdEMsWUFDVSxnQkFBa0MsRUFDbEMsa0JBQXNDLEVBQ3RDLGVBQWdDLEVBQ2hDLGNBQThCO1FBSDlCLHFCQUFnQixHQUFoQixnQkFBZ0IsQ0FBa0I7UUFDbEMsdUJBQWtCLEdBQWxCLGtCQUFrQixDQUFvQjtRQUN0QyxvQkFBZSxHQUFmLGVBQWUsQ0FBaUI7UUFDaEMsbUJBQWMsR0FBZCxjQUFjLENBQWdCO1FBbkJ4Qyx3QkFBbUIsR0FBRyxLQUFLLENBQUM7UUFDNUIsZUFBVSxHQUFH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LENBQUMsQ0FBQyxXQUFXO1lBQ2IsQ0FBQyxDQUFDLFdBQVcsQ0FBQyxNQUFNLENBQUMsVUFBVSxDQUFDLEVBQUUsQ0FBQyxVQUFVLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDO0lBQy9FLENBQUM7SUFFTyxjQUFjO1FBQ3BCLElBQUksQ0FBQyxVQUFVLEdBQUcsSUFBSSxDQUFDO1FBQ3ZCLElBQUksQ0FBQyxVQUFVLEdBQUcsS0FBSyxDQUFDO0lBQzFCLENBQUM7SUFFTyxLQUFLLENBQUMsWUFBWTtRQUN4QixNQUFNLFlBQVksR0FBRyxNQUFNLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxzQkFBc0IsRUFBRSxDQUFDO1FBQzFFLElBQUksQ0FBQyxRQUFRLEdBQUcsWUFBWSxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxrQkFBa0IsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDO0lBQzVGLENBQUM7K0dBcktVLDJCQUEyQjttR0FBM0IsMkJBQTJCLDJIQWlCM0Isa0NBQWtDLGdEQzdCL0MseWxNQXNNQTs7NEZEMUxhLDJCQUEyQjtrQkFKdkMsU0FBUzsrQkFDRSwwQkFBMEI7aUxBcUJwQyx5QkFBeUI7c0JBRHhCLFNBQVM7dUJBQUMsa0NBQWtDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQ29tcG9uZW50LCBPbkluaXQsIFZpZXdDaGlsZCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgQXBwbGljYXRpb25TZXJ2aWNlLCBJQXBwbGljYXRpb24sIElBcHBsaWNhdGlvblZlcnNpb24sIElSZXN1bHRMaXN0IH0gZnJvbSAnQGM4eS9jbGllbnQnO1xuaW1wb3J0IHsgUGx1Z2luc1NlcnZpY2UsIFdpemFyZENvbXBvbmVudCB9IGZyb20gJ0BjOHkvbmd4LWNvbXBvbmVudHMnO1xuaW1wb3J0IHsgQmVoYXZpb3JTdWJqZWN0LCBjb21iaW5lTGF0ZXN0LCBmcm9tLCBPYnNlcnZhYmxlLCBvZiB9IGZyb20gJ3J4anMnO1xuaW1wb3J0IHsgbWFwIH0gZnJvbSAncnhqcy9vcGVyYXRvcnMnO1xuaW1wb3J0IHsgRWNvc3lzdGVtU2VydmljZSwgTGljZW5zZWRBcHBsaWNhdGlvblBsdWdpbiB9IGZyb20gJ0BjOHkvbmd4LWNvbXBvbmVudHMvZWNvc3lzdGVtL3NoYXJlZCc7XG5pbXBvcnQgeyBBcHBsaWNhdGlvblByb3BlcnRpZXNGb3JtQ29tcG9uZW50IH0gZnJvbSAnQGM4eS9uZ3gtY29tcG9uZW50cy9lY29zeXN0ZW0vc2hhcmVkJztcblxuQENvbXBvbmVudCh7XG4gIHNlbGVjdG9yOiAnYzh5LWluc3RhbGwtZnJvbS1wYWNrYWdlJyxcbiAgdGVtcGxhdGVVcmw6ICcuL2luc3RhbGwtZnJvbS1wYWNrYWdlLmNvbXBvbmVudC5odG1sJ1xufSlcbmV4cG9ydCBjbGFzcyBJbnN0YWxsRnJvbVBhY2thZ2VDb21wb25lbnQgaW1wbGVtZW50cyBPbkluaXQge1xuICBuZXdBcHBDb25maWc6IElBcHBsaWNhdGlvbjtcbiAgc2VsZWN0ZWRQYWNrYWdlOiBJQXBwbGljYXRpb247XG4gIHBhY2thZ2VzOiBJQXBwbGljYXRpb25bXTtcbiAgaW5Qcm9ncmVzczogYm9vbGVhbjtcbiAgZGVwbG95ZWRXaXRoU3VjY2VzcyA9IGZhbHNlO1xuICBpc0RlcGxveWVkID0gZmFsc2U7XG5cbiAgbW9kZWwgPSB7XG4gICAgc2VsZWN0ZWQ6IHVuZGVmaW5lZCxcbiAgICBiaW5hcnk6IHtcbiAgICAgIGlkOiB1bmRlZmluZWRcbiAgICB9XG4gIH07XG4gIGNhbkRlcGxveSA9IGZhbHNlO1xuICBvbklucHV0OiBCZWhhdmlvclN1YmplY3Q8c3RyaW5nPiA9IG5ldyBCZWhhdmlvclN1YmplY3Q8c3RyaW5nPignJyk7XG4gIHZlcnNpb25zJDogT2JzZXJ2YWJsZTxJUmVzdWx0TGlzdDxJQXBwbGljYXRpb25WZXJzaW9uPj47XG4gIEBWaWV3Q2hpbGQoQXBwbGljYXRpb25Qcm9wZXJ0aWVzRm9ybUNvbXBvbmVudClcbiAgYXBwbGljYXRpb25Qcm9wZXJ0aWVzRm9ybTogQXBwbGljYXRpb25Qcm9wZXJ0aWVzRm9ybUNvbXBvbmVudDtcblxuICBjb25zdHJ1Y3RvcihcbiAgICBwcml2YXRlIGVjb3N5c3RlbVNlcnZpY2U6IEVjb3N5c3RlbVNlcnZpY2UsXG4gICAgcHJpdmF0ZSBhcHBsaWNhdGlvblNlcnZpY2U6IEFwcGxpY2F0aW9uU2VydmljZSxcbiAgICBwcml2YXRlIHdpemFyZENvbXBvbmVudDogV2l6YXJkQ29tcG9uZW50LFxuICAgIHByaXZhdGUgcGx1Z2luc1NlcnZpY2U6IFBsdWdpbnNTZXJ2aWNlXG4gICkge31cblxuICBhc3luYyBuZ09uSW5pdCgpIHtcbiAgICB0aGlzLmxvYWRQYWNrYWdlcygpO1xuICB9XG5cbiAgYmFjaygpIHtcbiAgICB0aGlzLndpemFyZENvbXBvbmVudC5yZXNldCgpO1xuICB9XG5cbiAgY2xlYW4oKSB7XG4gICAgdGhpcy5zZWxlY3RlZFBhY2thZ2UgPSB1bmRlZmluZWQ7XG4gICAgdGhpcy52ZXJzaW9ucyQgPSB1bmRlZmluZWQ7XG4gICAgdGhpcy5tb2RlbCA9IHtcbiAgICAgIHNlbGVjdGVkOiB1bmRlZmluZWQsXG4gICAgICBiaW5hcnk6IHtcbiAgICAgICAgaWQ6IHVuZGVmaW5lZFxuICAgICAgfVxuICAgIH07XG4gIH1cblxuICBjYW5jZWwoKSB7XG4gICAgdGhpcy53aXphcmRDb21wb25lbnQuY2xvc2UoKTtcbiAgfVxuXG4gIGFzeW5jIGRlcGxveUFwcCgpIHtcbiAgICB0aGlzLmluUHJvZ3Jlc3MgPSB0cnVlO1xuICAgIGNvbnN0IGZvcm1Hcm91cFZhbHVlID0gdGhpcy5hcHBsaWNhdGlvblByb3BlcnRpZXNGb3JtLmZvcm1Hcm91cC5nZXRSYXdWYWx1ZSgpO1xuICAgIGNvbnN0IHsgY29udGV4dFBhdGgsIGxpY2Vuc2UsIG5hbWUgfSA9IHRoaXMuc2VsZWN0ZWRQYWNrYWdlO1xuICAgIGNvbnN0IHR5cGUgPSB0aGlzLnBsdWdpbnNTZXJ2aWNlLmdldFBhY2thZ2VUeXBlKHRoaXMuc2VsZWN0ZWRQYWNrYWdlKTtcbiAgICBjb25zdCBsaWNlbnNlZEFwcDogTGljZW5zZWRBcHBsaWNhdGlvblBsdWdpbiA9IHtcbiAgICAgIGNvbnRleHRQYXRoLFxuICAgICAgbGljZW5zZSxcbiAgICAgIG5hbWUsXG4gICAgICB0eXBlLFxuICAgICAgdmVyc2lvbjogdGhpcy5tb2RlbC5zZWxlY3RlZC52ZXJzaW9uXG4gICAgfTtcbiAgICBjb25zdCBpc0FyY2hpdmVkID0gYXdhaXQgdGhpcy5lY29zeXN0ZW1TZXJ2aWNlLnZlcmlmeUFyY2hpdmVkKFtsaWNlbnNlZEFwcF0pO1xuICAgIGlmICghaXNBcmNoaXZlZCkge1xuICAgICAgdGhpcy5jYW5jZWwoKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBjb25zdCBsaWNlbnNlc1ZlcmlmaWVkQnlVc2VyID0gYXdhaXQgdGhpcy5lY29zeXN0ZW1TZXJ2aWNlLnZlcmlmeUxpY2Vuc2VzKFtsaWNlbnNlZEFwcF0pO1xuICAgIGlmICghbGljZW5zZXNWZXJpZmllZEJ5VXNlcikge1xuICAgICAgdGhpcy5jYW5jZWwoKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICAvLyBWZXJpZnkgaWYgc2VsZWN0ZWQgcGFja2FnZSB2ZXJzaW9uIGlzIGNvbXBhdGlibGUgd2l0aCBjdXJyZW50IHBsYXRmb3JtIHZlcnNpb25zLlxuICAgIHRoaXMuc2VsZWN0ZWRQYWNrYWdlLm1hbmlmZXN0LnZlcnNpb24gPSB0aGlzLm1vZGVsLnNlbGVjdGVkLnZlcnNpb247XG4gICAgY29uc3QgdmVyaWZ5VmVyc2lvbkNvbXBhdGliaWxpdHkgPVxuICAgICAgYXdhaXQgdGhpcy5lY29zeXN0ZW1TZXJ2aWNlLnZlcmlmeUJsdWVwcmludFZlcnNpb25zQ29tcGF0aWJpbGl0eShcbiAgICAgICAgdGhpcy5zZWxlY3RlZFBhY2thZ2UubWFuaWZlc3RcbiAgICAgICk7XG5cbiAgICBpZiAoIXZlcmlmeVZlcnNpb25Db21wYXRpYmlsaXR5KSB7XG4gICAgICB0aGlzLmNhbmNlbCgpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIHRyeSB7XG4gICAgICBhd2FpdCB0aGlzLmVjb3N5c3RlbVNlcnZpY2UuZGVwbG95QXBwKHRoaXMuc2VsZWN0ZWRQYWNrYWdlLCBmb3JtR3JvdXBWYWx1ZSwgdGhpcy5tb2RlbCk7XG4gICAgICB0aGlzLmRlcGxveWVkV2l0aFN1Y2Nlc3MgPSB0cnVlO1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICB0aGlzLmVjb3N5c3RlbVNlcnZpY2UuYWxlcnRFcnJvcihlcnJvcik7XG4gICAgfSBmaW5hbGx5IHtcbiAgICAgIHRoaXMubWFya0FzRGVwbG95ZWQoKTtcbiAgICB9XG4gIH1cblxuICBvbkFwcFZlcnNpb25TZWxlY3QoYXBwVmVyc2lvbjogSUFwcGxpY2F0aW9uVmVyc2lvbikge1xuICAgIE9iamVjdC5hc3NpZ24odGhpcy5tb2RlbCwge1xuICAgICAgc2VsZWN0ZWQ6IGFwcFZlcnNpb25cbiAgICB9KTtcbiAgICB0aGlzLmNhbkRlcGxveSA9IHRydWU7XG4gIH1cblxuICBhc3luYyBzZWxlY3RQYWNrYWdlKHNlbGVjdGVkUGFja2FnZTogSUFwcGxpY2F0aW9uKSB7XG4gICAgY29uc3QgYXBwcyA9IGF3YWl0IHRoaXMuZWNvc3lzdGVtU2VydmljZS5nZXRIb3N0ZWRBbmRQYWNrYWdlQXBwbGljYXRpb25zKCk7XG4gICAgdGhpcy5uZXdBcHBDb25maWcgPSB0aGlzLmVjb3N5c3RlbVNlcnZpY2UuZ2V0VW5pcXVlQXBwQ29uZmlnKHNlbGVjdGVkUGFja2FnZSwgYXBwcyk7XG4gICAgdGhpcy5zZWxlY3RlZFBhY2thZ2UgPSBzZWxlY3RlZFBhY2thZ2U7XG5cbiAgICB0aGlzLmxvYWRTZWxlY3RlZFBhY2thZ2VWZXJzaW9ucygpO1xuICB9XG5cbiAgcHJpdmF0ZSBsb2FkU2VsZWN0ZWRQYWNrYWdlVmVyc2lvbnMoKSB7XG4gICAgdGhpcy52ZXJzaW9ucyQgPSBjb21iaW5lTGF0ZXN0KFtcbiAgICAgIHRoaXMuZ2V0QXBwVmVyc2lvbnModGhpcy5zZWxlY3RQYWNrYWdlKSxcbiAgICAgIHRoaXMub25JbnB1dC5hc09ic2VydmFibGUoKVxuICAgIF0pLnBpcGUoXG4gICAgICBtYXAoKFtyZXN1bHRMaXN0LCBmaWx0ZXJTdHJdKSA9PiB7XG4gICAgICAgIHRoaXMuY2FuRGVwbG95ID0gZmFsc2U7XG4gICAgICAgIGNvbnN0IHZlcnNpb25zRmlsdGVyZWRCeVN0ciA9IHRoaXMuZmlsdGVyQXBwVmVyc2lvbnMocmVzdWx0TGlzdC5kYXRhLCBmaWx0ZXJTdHIpO1xuICAgICAgICBjb25zdCBzb3J0ZWRBcHBWZXJzaW9ucyA9IHRoaXMucGx1Z2luc1NlcnZpY2Uuc29ydFZlcnNpb25zKFxuICAgICAgICAgIHtcbiAgICAgICAgICAgIGxpc3Q6IHZlcnNpb25zRmlsdGVyZWRCeVN0cixcbiAgICAgICAgICAgIHBhdGg6IFsndmVyc2lvbiddXG4gICAgICAgICAgfSxcbiAgICAgICAgICAnZGVzYydcbiAgICAgICAgKTtcblxuICAgICAgICB0aGlzLnNldEluaXRpYWxWYWx1ZUZvcklucHV0KHNvcnRlZEFwcFZlcnNpb25zKTtcbiAgICAgICAgcmV0dXJuIHsgZGF0YTogc29ydGVkQXBwVmVyc2lvbnMsIHJlczogcmVzdWx0TGlzdC5yZXMgfTtcbiAgICAgIH0pXG4gICAgKTtcbiAgfVxuXG4gIHByaXZhdGUgZ2V0QXBwVmVyc2lvbnMobW86IElBcHBsaWNhdGlvbikge1xuICAgIGNvbnN0IHZlcnNpb25zID0gbW8/LmFwcGxpY2F0aW9uVmVyc2lvbnM7XG4gICAgcmV0dXJuIHZlcnNpb25zICYmIHZlcnNpb25zLmxlbmd0aCA+IDBcbiAgICAgID8gb2YoeyBkYXRhOiB2ZXJzaW9ucywgcmVzOiB1bmRlZmluZWQgfSlcbiAgICAgIDogZnJvbSh0aGlzLmFwcGxpY2F0aW9uU2VydmljZS5saXN0VmVyc2lvbnModGhpcy5zZWxlY3RlZFBhY2thZ2UuaWQpKTtcbiAgfVxuXG4gIHByaXZhdGUgc2V0SW5pdGlhbFZhbHVlRm9ySW5wdXQodmVyc2lvbnM6IElBcHBsaWNhdGlvblZlcnNpb25bXSkge1xuICAgIGlmICghdGhpcy5tb2RlbC5zZWxlY3RlZCAmJiB2ZXJzaW9ucy5sZW5ndGggPiAwKSB7XG4gICAgICBjb25zdCBsYXRlc3QgPSB2ZXJzaW9ucy5maW5kKHYgPT4gdi50YWdzLmluY2x1ZGVzKCdsYXRlc3QnKSk7XG4gICAgICB0aGlzLm1vZGVsLnNlbGVjdGVkID0gbGF0ZXN0IHx8IHZlcnNpb25zWzBdO1xuICAgICAgdGhpcy5jYW5EZXBsb3kgPSB0cnVlO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgZmlsdGVyQXBwVmVyc2lvbnMoXG4gICAgYXBwVmVyc2lvbnM6IElBcHBsaWNhdGlvblZlcnNpb25bXSxcbiAgICBmaWx0ZXJTdHI6IHN0cmluZ1xuICApOiBJQXBwbGljYXRpb25WZXJzaW9uW10ge1xuICAgIHJldHVybiBmaWx0ZXJTdHIgPT09ICcnXG4gICAgICA/IGFwcFZlcnNpb25zXG4gICAgICA6IGFwcFZlcnNpb25zLmZpbHRlcihhcHBWZXJzaW9uID0+IGFwcFZlcnNpb24udmVyc2lvbi5pbmNsdWRlcyhmaWx0ZXJTdHIpKTtcbiAgfVxuXG4gIHByaXZhdGUgbWFya0FzRGVwbG95ZWQoKSB7XG4gICAgdGhpcy5pc0RlcGxveWVkID0gdHJ1ZTtcbiAgICB0aGlzLmluUHJvZ3Jlc3MgPSBmYWxzZTtcbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgbG9hZFBhY2thZ2VzKCk6IFByb21pc2U8dm9pZD4ge1xuICAgIGNvbnN0IGFwcGxpY2F0aW9ucyA9IGF3YWl0IHRoaXMuZWNvc3lzdGVtU2VydmljZS5nZXRQYWNrYWdlQXBwbGljYXRpb25zKCk7XG4gICAgdGhpcy5wYWNrYWdlcyA9IGFwcGxpY2F0aW9ucy5maWx0ZXIoYXBwID0+IHRoaXMuZWNvc3lzdGVtU2VydmljZS5pc1BhY2thZ2VCbHVlcHJpbnQoYXBwKSk7XG4gIH1cbn1cbiIsIjxjOHktd2l6YXJkLWhlYWRlcj5cbiAgPGkgW2M4eUljb25dPVwiJ2JpZy1wYXJjZWwnXCI+PC9pPlxuICA8aDRcbiAgICBpZD1cIm1vZGFsLXRpdGxlXCJcbiAgICB0cmFuc2xhdGVcbiAgPlxuICAgIEluc3RhbGwgZnJvbSBleHRlbnNpb24gcGFja2FnZVxuICA8L2g0PlxuPC9jOHktd2l6YXJkLWhlYWRlcj5cbjxjOHktd2l6YXJkLWJvZHk+XG4gIDxuZy1jb250YWluZXIgKm5nSWY9XCIhc2VsZWN0ZWRQYWNrYWdlXCI+XG4gICAgPGRpdlxuICAgICAgY2xhc3M9XCJtb2RhbC1pbm5lci1zY3JvbGxcIlxuICAgICAgaWQ9XCJtb2RhbC1ib2R5XCJcbiAgICA+XG4gICAgICA8cCBjbGFzcz1cInAtMTYgdGV4dC1tZWRpdW0gdGV4dC1jZW50ZXIgc2VwYXJhdG9yLWJvdHRvbSBzdGlja3ktdG9wIGJnLWxldmVsLTBcIj5cbiAgICAgICAge3sgJ1NlbGVjdCBmcm9tIGF2YWlsYWJsZSBleHRlbnNpb24gcGFja2FnZXMnIHwgdHJhbnNsYXRlIH19XG4gICAgICA8L3A+XG5cbiAgICAgIDxjOHktdWktZW1wdHktc3RhdGVcbiAgICAgICAgW2ljb25dPVwiJ2JpZy1wYXJjZWwnXCJcbiAgICAgICAgW3RpdGxlXT1cIidObyBleHRlbnNpb24gcGFja2FnZXMgdG8gZGlzcGxheS4nIHwgdHJhbnNsYXRlXCJcbiAgICAgICAgKm5nSWY9XCIhcGFja2FnZXM/Lmxlbmd0aFwiXG4gICAgICAgIFtob3Jpem9udGFsXT1cInRydWVcIlxuICAgICAgPjwvYzh5LXVpLWVtcHR5LXN0YXRlPlxuXG4gICAgICA8ZGl2XG4gICAgICAgIGNsYXNzPVwiYzh5LXdpemFyZC1saXN0LW5hdlwiXG4gICAgICAgIHN0eWxlPVwibWluLWhlaWdodDogMjU3cHhcIlxuICAgICAgICAqbmdJZj1cInBhY2thZ2VzPy5sZW5ndGhcIlxuICAgICAgPlxuICAgICAgICA8YnV0dG9uXG4gICAgICAgICAgY2xhc3M9XCJsaXN0LWdyb3VwLWl0ZW0gdGV4dC10cnVuY2F0ZVwiXG4gICAgICAgICAgdGl0bGU9XCJ7eyBwYWNrYWdlLm5hbWUgfX1cIlxuICAgICAgICAgIHR5cGU9XCJidXR0b25cIlxuICAgICAgICAgICpuZ0Zvcj1cImxldCBwYWNrYWdlIG9mIHBhY2thZ2VzXCJcbiAgICAgICAgICAoY2xpY2spPVwic2VsZWN0UGFja2FnZShwYWNrYWdlKVwiXG4gICAgICAgID5cbiAgICAgICAgICA8aVxuICAgICAgICAgICAgY2xhc3M9XCJsaXN0LWdyb3VwLWljb25cIlxuICAgICAgICAgICAgYzh5SWNvbj1cImJpZy1wYXJjZWxcIlxuICAgICAgICAgID48L2k+XG4gICAgICAgICAgPHNwYW4gW2lubmVyVGV4dF09XCJwYWNrYWdlLm5hbWVcIj48L3NwYW4+XG4gICAgICAgIDwvYnV0dG9uPlxuICAgICAgPC9kaXY+XG4gICAgPC9kaXY+XG4gIDwvbmctY29udGFpbmVyPlxuICA8bmctY29udGFpbmVyICpuZ0lmPVwiIWlzRGVwbG95ZWQgJiYgc2VsZWN0ZWRQYWNrYWdlXCI+XG4gICAgPHAgY2xhc3M9XCJwLTE2IHRleHQtY2VudGVyIHRleHQtbWVkaXVtIHNlcGFyYXRvci1ib3R0b20gc3RpY2t5LXRvcCBiZy1sZXZlbC0wXCI+XG4gICAgICB7eyAnUHJvdmlkZSBhcHBsaWNhdGlvbiBkZXRhaWxzJyB8IHRyYW5zbGF0ZSB9fVxuICAgIDwvcD5cbiAgICA8ZGl2XG4gICAgICBjbGFzcz1cImQtZmxleCBkLWNvbCBhLWktY2VudGVyIGotYy1jZW50ZXJcIlxuICAgICAgc3R5bGU9XCJtaW4taGVpZ2h0OiAyNTdweFwiXG4gICAgPlxuICAgICAgPGM4eS1hcHBsaWNhdGlvbi1wcm9wZXJ0aWVzLWZvcm1cbiAgICAgICAgY2xhc3M9XCJkLWJsb2NrIGZpdC13XCJcbiAgICAgICAgKm5nSWY9XCIhaW5Qcm9ncmVzc1wiXG4gICAgICAgIFthcHBsaWNhdGlvbl09XCJuZXdBcHBDb25maWdcIlxuICAgICAgPjwvYzh5LWFwcGxpY2F0aW9uLXByb3BlcnRpZXMtZm9ybT5cblxuICAgICAgPG5nLWNvbnRhaW5lciAqbmdJZj1cIiFpblByb2dyZXNzXCI+XG4gICAgICAgIDxkaXZcbiAgICAgICAgICBjbGFzcz1cImQtYmxvY2sgZml0LXcgYmctZ3JheS13aGl0ZVwiXG4gICAgICAgICAgW25nU3R5bGVdPVwieyBwYWRkaW5nOiAnMCAxNnB4JyB9XCJcbiAgICAgICAgPlxuICAgICAgICAgIDxsYWJlbFxuICAgICAgICAgICAgZm9yPVwicGFja2FnZVZlcnNpb25cIlxuICAgICAgICAgICAgdHJhbnNsYXRlXG4gICAgICAgICAgPlxuICAgICAgICAgICAgVXNlIGV4dGVuc2lvbiBwYWNrYWdlIHZlcnNpb25cbiAgICAgICAgICA8L2xhYmVsPlxuICAgICAgICAgIDxjOHktZm9ybS1ncm91cD5cbiAgICAgICAgICAgIDxjOHktdHlwZWFoZWFkXG4gICAgICAgICAgICAgIHBsYWNlaG9sZGVyPVwie3sgJ1NlbGVjdCBvciBlbnRlcicgfCB0cmFuc2xhdGUgfX1cIlxuICAgICAgICAgICAgICBuYW1lPVwicGFja2FnZVZlcnNpb25cIlxuICAgICAgICAgICAgICBbKG5nTW9kZWwpXT1cIm1vZGVsLnNlbGVjdGVkXCJcbiAgICAgICAgICAgICAgKG9uU2VhcmNoKT1cIm9uSW5wdXQubmV4dCgkZXZlbnQpXCJcbiAgICAgICAgICAgICAgW2Rpc3BsYXlQcm9wZXJ0eV09XCIndmVyc2lvbidcIlxuICAgICAgICAgICAgICBbcmVxdWlyZWRdPVwidHJ1ZVwiXG4gICAgICAgICAgICAgIFtoaWRlTmV3XT1cInRydWVcIlxuICAgICAgICAgICAgICBbY29udGFpbmVyXT1cIidib2R5J1wiXG4gICAgICAgICAgICA+XG4gICAgICAgICAgICAgIDxjOHktbGlcbiAgICAgICAgICAgICAgICBjbGFzcz1cInAtbC04IHAtci04IGM4eS1saXN0X19pdGVtLS1saW5rXCJcbiAgICAgICAgICAgICAgICAqYzh5Rm9yPVwibGV0IHZlcnNpb24gb2YgdmVyc2lvbnMkOyBsb2FkTW9yZTogJ2F1dG8nOyBub3RGb3VuZDogbm90Rm91bmRUZW1wbGF0ZVwiXG4gICAgICAgICAgICAgICAgKGNsaWNrKT1cIm9uQXBwVmVyc2lvblNlbGVjdCh2ZXJzaW9uKVwiXG4gICAgICAgICAgICAgICAgW2FjdGl2ZV09XCJtb2RlbC5zZWxlY3RlZCA9PT0gdmVyc2lvblwiXG4gICAgICAgICAgICAgID5cbiAgICAgICAgICAgICAgICA8Yzh5LWxpLWljb24gaWNvbj1cImJpZy1wYXJjZWxcIj48L2M4eS1saS1pY29uPlxuICAgICAgICAgICAgICAgIDxzcGFuXG4gICAgICAgICAgICAgICAgICBbbmdTdHlsZV09XCJ7XG4gICAgICAgICAgICAgICAgICAgIGRpc3BsYXk6ICdmbGV4JyxcbiAgICAgICAgICAgICAgICAgICAgJ2ZsZXgtZGlyZWN0aW9uJzogJ3JvdycsXG4gICAgICAgICAgICAgICAgICAgICdhbGlnbi1jb250ZW50JzogJ2NlbnRlcicsXG4gICAgICAgICAgICAgICAgICAgICdqdXN0aWZ5LWNvbnRlbnQnOiAnc3BhY2UtYmV0d2VlbicsXG4gICAgICAgICAgICAgICAgICAgICdhbGlnbi1pdGVtcyc6ICdjZW50ZXInXG4gICAgICAgICAgICAgICAgICB9XCJcbiAgICAgICAgICAgICAgICA+XG4gICAgICAgICAgICAgICAgICA8Yzh5LWhpZ2hsaWdodFxuICAgICAgICAgICAgICAgICAgICBbdGV4dF09XCJ2ZXJzaW9uLnZlcnNpb24gfHwgJy0tJ1wiXG4gICAgICAgICAgICAgICAgICAgIFtwYXR0ZXJuXT1cIm9uSW5wdXQgfCBhc3luY1wiXG4gICAgICAgICAgICAgICAgICA+PC9jOHktaGlnaGxpZ2h0PlxuXG4gICAgICAgICAgICAgICAgICA8c3Bhbj5cbiAgICAgICAgICAgICAgICAgICAgPHNwYW5cbiAgICAgICAgICAgICAgICAgICAgICBjbGFzcz1cImxhYmVsIGxhYmVsLWluZm8gbS1sLTRcIlxuICAgICAgICAgICAgICAgICAgICAgICpuZ0Zvcj1cImxldCB0YWcgb2YgdmVyc2lvbi50YWdzXCJcbiAgICAgICAgICAgICAgICAgICAgPlxuICAgICAgICAgICAgICAgICAgICAgIHt7IHRhZyB9fVxuICAgICAgICAgICAgICAgICAgICA8L3NwYW4+XG4gICAgICAgICAgICAgICAgICA8L3NwYW4+XG4gICAgICAgICAgICAgICAgPC9zcGFuPlxuICAgICAgICAgICAgICA8L2M4eS1saT5cbiAgICAgICAgICAgICAgPG5nLXRlbXBsYXRlICNub3RGb3VuZFRlbXBsYXRlPlxuICAgICAgICAgICAgICAgIDxjOHktbGlcbiAgICAgICAgICAgICAgICAgIGNsYXNzPVwiYmctZ3JheS1saWdodGVyIHAtOFwiXG4gICAgICAgICAgICAgICAgICAqbmdJZj1cIihvbklucHV0IHwgYXN5bmMpPy5sZW5ndGggPiAwICYmICh2ZXJzaW9ucyQgfCBhc3luYyk/LmRhdGE/Lmxlbmd0aCA9PT0gMFwiXG4gICAgICAgICAgICAgICAgPlxuICAgICAgICAgICAgICAgICAgPHNwYW4gdHJhbnNsYXRlPk5vIG1hdGNoIGZvdW5kLjwvc3Bhbj5cbiAgICAgICAgICAgICAgICA8L2M4eS1saT5cbiAgICAgICAgICAgICAgPC9uZy10ZW1wbGF0ZT5cbiAgICAgICAgICAgIDwvYzh5LXR5cGVhaGVhZD5cbiAgICAgICAgICA8L2M4eS1mb3JtLWdyb3VwPlxuICAgICAgICA8L2Rpdj5cbiAgICAgIDwvbmctY29udGFpbmVyPlxuXG4gICAgICA8Yzh5LWxvYWRpbmdcbiAgICAgICAgY2xhc3M9XCJ0ZXh0LWNlbnRlciBkLWJsb2NrXCJcbiAgICAgICAgW21lc3NhZ2VdPVwiJ0luc3RhbGxpbmfigKYnIHwgdHJhbnNsYXRlXCJcbiAgICAgICAgKm5nSWY9XCJpblByb2dyZXNzXCJcbiAgICAgICAgbGF5b3V0PVwiYXBwbGljYXRpb25cIlxuICAgICAgPjwvYzh5LWxvYWRpbmc+XG4gICAgPC9kaXY+XG4gIDwvbmctY29udGFpbmVyPlxuXG4gIDxuZy1jb250YWluZXIgKm5nSWY9XCJpc0RlcGxveWVkXCI+XG4gICAgPGRpdlxuICAgICAgY2xhc3M9XCJkLWZsZXggYS1pLWNlbnRlciBqLWMtY2VudGVyXCJcbiAgICAgIHN0eWxlPVwibWluLWhlaWdodDogMjU3cHhcIlxuICAgICAgKm5nSWY9XCJkZXBsb3llZFdpdGhTdWNjZXNzOyBlbHNlIGZhaWxlZERlcGxveVwiXG4gICAgPlxuICAgICAgPGM4eS1vcGVyYXRpb24tcmVzdWx0XG4gICAgICAgIGNsYXNzPVwibGVhZFwiXG4gICAgICAgIHR5cGU9XCJzdWNjZXNzXCJcbiAgICAgICAgdGV4dD1cInt7ICdBcHBsaWNhdGlvbiBjcmVhdGVkJyB8IHRyYW5zbGF0ZSB9fVwiXG4gICAgICAgIFtzaXplXT1cIjg0XCJcbiAgICAgICAgW3ZlcnRpY2FsXT1cInRydWVcIlxuICAgICAgPjwvYzh5LW9wZXJhdGlvbi1yZXN1bHQ+XG4gICAgPC9kaXY+XG4gICAgPG5nLXRlbXBsYXRlICNmYWlsZWREZXBsb3k+XG4gICAgICA8ZGl2XG4gICAgICAgIGNsYXNzPVwiZC1mbGV4IGEtaS1jZW50ZXIgai1jLWNlbnRlclwiXG4gICAgICAgIHN0eWxlPVwibWluLWhlaWdodDogMjU3cHhcIlxuICAgICAgPlxuICAgICAgICA8Yzh5LW9wZXJhdGlvbi1yZXN1bHRcbiAgICAgICAgICBjbGFzcz1cImxlYWRcIlxuICAgICAgICAgIHR5cGU9XCJlcnJvclwiXG4gICAgICAgICAgdGV4dD1cInt7ICdBcHBsaWNhdGlvbiBjcmVhdGlvbiBmYWlsZWQnIHwgdHJhbnNsYXRlIH19XCJcbiAgICAgICAgICBbc2l6ZV09XCI4NFwiXG4gICAgICAgICAgW3ZlcnRpY2FsXT1cInRydWVcIlxuICAgICAgICA+PC9jOHktb3BlcmF0aW9uLXJlc3VsdD5cbiAgICAgIDwvZGl2PlxuICAgIDwvbmctdGVtcGxhdGU+XG4gIDwvbmctY29udGFpbmVyPlxuPC9jOHktd2l6YXJkLWJvZHk+XG5cbjxjOHktd2l6YXJkLWZvb3Rlcj5cbiAgPGJ1dHRvblxuICAgIGNsYXNzPVwiYnRuIGJ0bi1kZWZhdWx0XCJcbiAgICB0aXRsZT1cInt7ICdCYWNrJyB8IHRyYW5zbGF0ZSB9fVwiXG4gICAgdHlwZT1cImJ1dHRvblwiXG4gICAgKm5nSWY9XCIhaXNEZXBsb3llZFwiXG4gICAgKGNsaWNrKT1cInNlbGVjdGVkUGFja2FnZSA/IGNsZWFuKCkgOiBiYWNrKClcIlxuICAgIFtkaXNhYmxlZF09XCJpblByb2dyZXNzXCJcbiAgPlxuICAgIHt7ICdCYWNrJyB8IHRyYW5zbGF0ZSB9fVxuICA8L2J1dHRvbj5cbiAgPGJ1dHRvblxuICAgIGNsYXNzPVwiYnRuIGJ0bi1kZWZhdWx0XCJcbiAgICB0aXRsZT1cInt7IGlzRGVwbG95ZWQgJiYgZGVwbG95ZWRXaXRoU3VjY2VzcyA/ICgnQ2xvc2UnIHwgdHJhbnNsYXRlKSA6ICgnQ2FuY2VsJyB8IHRyYW5zbGF0ZSkgfX1cIlxuICAgIHR5cGU9XCJidXR0b25cIlxuICAgIChjbGljayk9XCJjYW5jZWwoKVwiXG4gID5cbiAgICB7eyBpc0RlcGxveWVkICYmIGRlcGxveWVkV2l0aFN1Y2Nlc3MgPyAoJ0Nsb3NlJyB8IHRyYW5zbGF0ZSkgOiAoJ0NhbmNlbCcgfCB0cmFuc2xhdGUpIH19XG4gIDwvYnV0dG9uPlxuXG4gIDxidXR0b25cbiAgICBjbGFzcz1cImJ0biBidG4tcHJpbWFyeVwiXG4gICAgdGl0bGU9XCJ7eyAnSW5zdGFsbCcgfCB0cmFuc2xhdGUgfX1cIlxuICAgIHR5cGU9XCJidXR0b25cIlxuICAgIChjbGljayk9XCJkZXBsb3lBcHAoKVwiXG4gICAgW2Rpc2FibGVkXT1cImluUHJvZ3Jlc3MgfHwgIXBhY2thZ2VzPy5sZW5ndGhcIlxuICAgICpuZ0lmPVwiIWlzRGVwbG95ZWRcIlxuICA+XG4gICAge3sgJ0luc3RhbGwnIHwgdHJhbnNsYXRlIH19XG4gIDwvYnV0dG9uPlxuPC9jOHktd2l6YXJkLWZvb3Rlcj5cbiJdfQ==