@c8y/ngx-components
Version:
Angular modules for Cumulocity IoT applications
143 lines • 40.5 kB
JavaScript
import { Component, ViewChild } from '@angular/core';
import { InventoryService } from '@c8y/client';
import { PluginsService } from '@c8y/ngx-components';
import { EcosystemService } from '@c8y/ngx-components/ecosystem/shared';
import { PluginsExportScopes } from '@c8y/ngx-components';
import { BehaviorSubject } from 'rxjs';
import * as i0 from "@angular/core";
import * as i1 from "@c8y/client";
import * as i2 from "@c8y/ngx-components/ecosystem/shared";
import * as i3 from "@c8y/ngx-components";
import * as i4 from "@angular/common";
import * as i5 from "../../application-plugins/plugin-list.component";
export class UpdateApplicationModalComponent {
constructor(inventoryService, ecosystemService, pluginsService) {
this.inventoryService = inventoryService;
this.ecosystemService = ecosystemService;
this.pluginsService = pluginsService;
this.isUpdateOngoing = false;
this.updateFailure = false;
this.result = new Promise((resolve, reject) => {
this._resolve = resolve;
this._reject = reject;
});
this.orphanedPlugins$ = new BehaviorSubject([]);
this.newPlugins$ = new BehaviorSubject([]);
}
ngOnInit() {
const hasDelta = this.getRemoteDelta();
if (!hasDelta) {
// start update directly if no remote delta detected
this.updateApplication();
}
}
/**
* Checks if there is a delta between the current application and the source package remotes.
* @returns {boolean} true if there is a delta between the current application and the source package remotes.
*/
getRemoteDelta() {
const currentRemotes = this.pluginsService.getMFExports(this.application, []);
const possibleNewRemotes = this.pluginsService.getMFExports(this.sourcePackage, []);
const installedRemotes = this.pluginsService.getMFRemotes(this.application);
const installedRemotesIds = PluginsService.convertInstalledRemotesToIds(installedRemotes);
const allRemotesToRemove = this.getAllRemotesToRemove(currentRemotes, possibleNewRemotes, installedRemotesIds);
const allRemotesToAdd = this.getAllRemotesToAdd(possibleNewRemotes, currentRemotes);
this.orphanedPlugins$.next(allRemotesToRemove);
this.newPlugins$.next(allRemotesToAdd);
return allRemotesToRemove.length !== 0 || allRemotesToAdd.length !== 0;
}
close() {
this._reject();
this.modal._dismiss();
}
done() {
if (!this.updateFailure) {
this._resolve();
this.modal._dismiss();
return;
}
this._reject();
this.modal._dismiss();
}
async updateApplication() {
try {
this.isUpdateOngoing = true;
const toInstallPlugins = this.newPlugins$.value.filter(({ selected }) => selected === true);
const toRemovePlugins = this.orphanedPlugins$.value;
this.orphanedPlugins$.next([]);
this.newPlugins$.next([]);
if (toRemovePlugins.length > 0) {
const remotes = await this.pluginsService.removeRemotes(this.application, toRemovePlugins);
this.application.config.remotes = remotes;
}
if (toInstallPlugins.length > 0) {
const remotes = await this.pluginsService.addRemotes(this.application, toInstallPlugins);
this.application.config.remotes = remotes;
}
const binaryMoId = this.sourcePackage.activeVersionId;
await this.inventoryService.detail(binaryMoId); // only trying if we can access it
await this.ecosystemService.uploadBinaryFromOtherPackage(this.sourcePackage, this.application, this.sourcePackage.activeVersionId);
}
catch (e) {
if (e.res?.status === 404) {
try {
this.updateFailure = !(await this.ecosystemService.fallbackToClone(this.application, this.sourcePackage));
}
catch (ex) {
this.updateFailure = true;
this.ecosystemService.alertError(e);
}
}
else {
this.updateFailure = true;
this.ecosystemService.alertError(e);
}
}
finally {
this.isUpdateOngoing = false;
}
}
getAllRemotesToAdd(possibleNewRemotes, currentRemotes) {
return possibleNewRemotes
.filter(possibleNewRemote => {
const isUnchanged = !!currentRemotes.some(currentRemote => PluginsService.createPluginId(this.application.contextPath, possibleNewRemote.module, '', true) === currentRemote.idLatest);
const isSelf = possibleNewRemote.scope === PluginsExportScopes.SELF ||
possibleNewRemote.scope === PluginsExportScopes.SELF_OPTIONAL;
return !isUnchanged && isSelf;
})
.map(newRemote => {
newRemote.contextPath = this.application.contextPath;
newRemote.id = `${newRemote.contextPath}/${newRemote.module}`;
newRemote.selected = newRemote.scope === PluginsExportScopes.SELF;
return newRemote;
});
}
getAllRemotesToRemove(currentRemotes, possibleNewRemotes, installedRemotesIds) {
return currentRemotes
.filter(currentRemote => {
const isUnchanged = !!possibleNewRemotes.some(newRemote => PluginsService.createPluginId(this.application.contextPath, newRemote.module, '', true) === currentRemote.idLatest);
const isInstalled = installedRemotesIds
? !!installedRemotesIds.some(currentInstalled => currentRemote.id === currentInstalled || currentRemote.idLatest === currentInstalled)
: false;
const isSelf = currentRemote.scope === PluginsExportScopes.SELF ||
currentRemote.scope === PluginsExportScopes.SELF_OPTIONAL;
return !isUnchanged && isInstalled && isSelf;
})
.map(toRemoveRemote => {
toRemoveRemote.contextPath = this.application.contextPath;
toRemoveRemote.id = `${toRemoveRemote.contextPath}/${toRemoveRemote.module}`;
toRemoveRemote.selected = true;
return toRemoveRemote;
});
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: UpdateApplicationModalComponent, deps: [{ token: i1.InventoryService }, { token: i2.EcosystemService }, { token: i3.PluginsService }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: UpdateApplicationModalComponent, selector: "c8y-update-application-modal", viewQueries: [{ propertyName: "modal", first: true, predicate: ["modal"], descendants: true }], ngImport: i0, template: "<c8y-modal\n [title]=\"'Update application' | translate\"\n [headerClasses]=\"'dialog-header'\"\n [customFooter]=\"true\"\n #modal\n>\n <ng-container c8y-modal-title>\n <span class=\"dlt-c8y-icon-installing-updates\"></span>\n </ng-container>\n\n <ng-container\n *ngIf=\"\n (orphanedPlugins$ | async).length > 0 || (newPlugins$ | async).length > 0;\n else updateProgress\n \"\n >\n <p\n class=\"text-center text-break-word p-24 text-14\"\n translate\n >\n Updating this blueprint will change the default plugins. Review the plugin changes before\n proceeding.\n </p>\n <c8y-list-group *ngIf=\"(orphanedPlugins$ | async).length > 0\">\n <c8y-li [collapsed]=\"true\">\n <c8y-li-icon>\n <span class=\"badge badge-danger\">{{ (orphanedPlugins$ | async).length }}</span>\n </c8y-li-icon>\n <c8y-li-body>\n <div translate>Orphaned plugins</div>\n </c8y-li-body>\n <c8y-li-footer translate>\n Some plugins are not contained in the new version of this blueprint and will therefore get\n removed.\n </c8y-li-footer>\n <c8y-li-collapse>\n <c8y-plugin-list\n class=\"m-t-16\"\n [emptyListText]=\"'No plugins available' | translate\"\n [plugins$]=\"orphanedPlugins$\"\n [selectable]=\"false\"\n [hideSource]=\"true\"\n ></c8y-plugin-list>\n </c8y-li-collapse>\n </c8y-li>\n </c8y-list-group>\n\n <c8y-list-group *ngIf=\"(newPlugins$ | async).length > 0\">\n <c8y-li [collapsed]=\"false\">\n <c8y-li-icon>\n <span class=\"badge badge-success\">{{ (newPlugins$ | async).length }}</span>\n </c8y-li-icon>\n <c8y-li-body>\n <div translate>New plugins added</div>\n </c8y-li-body>\n <c8y-li-footer translate>\n This blueprint will add new plugins. Please choose which you want to install.\n </c8y-li-footer>\n <c8y-li-collapse>\n <c8y-plugin-list\n class=\"m-t-16\"\n [emptyListText]=\"'No plugins available' | translate\"\n [plugins$]=\"newPlugins$\"\n [selectable]=\"true\"\n [hideSource]=\"false\"\n ></c8y-plugin-list>\n </c8y-li-collapse>\n </c8y-li>\n </c8y-list-group>\n </ng-container>\n\n <ng-container c8y-modal-footer-custom>\n <div\n class=\"modal-footer\"\n *ngIf=\"\n (orphanedPlugins$ | async).length > 0 || (newPlugins$ | async).length > 0;\n else updateProgressButtons\n \"\n >\n <button\n class=\"btn btn-default\"\n title=\"{{ 'Close' | translate }}\"\n (click)=\"close()\"\n [disabled]=\"isUpdateOngoing\"\n >\n {{ 'Close' | translate }}\n </button>\n <button\n class=\"btn btn-primary\"\n title=\"{{ 'Continue' | translate }}\"\n (click)=\"updateApplication()\"\n *ngIf=\"(orphanedPlugins$ | async).length > 0 || (newPlugins$ | async).length > 0\"\n [disabled]=\"isUpdateOngoing\"\n >\n {{ 'Continue' | translate }}\n </button>\n </div>\n </ng-container>\n\n <ng-template #updateProgressButtons>\n <ng-container c8y-modal-footer-custom>\n <div class=\"modal-footer\">\n <button\n class=\"btn btn-default\"\n title=\"{{ 'Close' | translate }}\"\n (click)=\"done()\"\n [disabled]=\"isUpdateOngoing\"\n >\n {{ 'Close' | translate }}\n </button>\n </div>\n </ng-container>\n </ng-template>\n\n <ng-template #updateProgress>\n <c8y-loading\n class=\"text-center d-block p-t-56 p-b-56 m-t-4 m-b-4\"\n style=\"min-height: 180px\"\n layout=\"application\"\n *ngIf=\"isUpdateOngoing\"\n [message]=\"'Updating\u2026' | translate\"\n ></c8y-loading>\n\n <c8y-operation-result\n type=\"success\"\n *ngIf=\"!isUpdateOngoing && !updateFailure\"\n text=\"{{ 'Update completed' | translate }}\"\n [size]=\"120\"\n [vertical]=\"true\"\n ></c8y-operation-result>\n <c8y-operation-result\n type=\"error\"\n *ngIf=\"!isUpdateOngoing && updateFailure\"\n text=\"{{ 'Failed to update application.' | translate }}\"\n [size]=\"120\"\n [vertical]=\"true\"\n ></c8y-operation-result>\n </ng-template>\n</c8y-modal>\n", dependencies: [{ kind: "directive", type: i3.C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: i4.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { 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.ModalComponent, selector: "c8y-modal", inputs: ["disabled", "close", "dismiss", "title", "body", "customFooter", "headerClasses", "labels"], outputs: ["onDismiss", "onClose"] }, { kind: "component", type: i3.ListGroupComponent, selector: "c8y-list-group" }, { 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.ListItemBodyComponent, selector: "c8y-list-item-body, c8y-li-body", inputs: ["body"] }, { kind: "component", type: i3.ListItemFooterComponent, selector: "c8y-list-item-footer, c8y-li-footer", inputs: ["footer"] }, { kind: "component", type: i3.ListItemCollapseComponent, selector: "c8y-list-item-collapse, c8y-li-collapse", inputs: ["collapseWay"] }, { kind: "component", type: i5.PluginListComponent, selector: "c8y-plugin-list", inputs: ["plugins$", "emptyListText", "selectable", "hideSource", "installable", "package"], outputs: ["selectedItems"] }, { 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: UpdateApplicationModalComponent, decorators: [{
type: Component,
args: [{ selector: 'c8y-update-application-modal', template: "<c8y-modal\n [title]=\"'Update application' | translate\"\n [headerClasses]=\"'dialog-header'\"\n [customFooter]=\"true\"\n #modal\n>\n <ng-container c8y-modal-title>\n <span class=\"dlt-c8y-icon-installing-updates\"></span>\n </ng-container>\n\n <ng-container\n *ngIf=\"\n (orphanedPlugins$ | async).length > 0 || (newPlugins$ | async).length > 0;\n else updateProgress\n \"\n >\n <p\n class=\"text-center text-break-word p-24 text-14\"\n translate\n >\n Updating this blueprint will change the default plugins. Review the plugin changes before\n proceeding.\n </p>\n <c8y-list-group *ngIf=\"(orphanedPlugins$ | async).length > 0\">\n <c8y-li [collapsed]=\"true\">\n <c8y-li-icon>\n <span class=\"badge badge-danger\">{{ (orphanedPlugins$ | async).length }}</span>\n </c8y-li-icon>\n <c8y-li-body>\n <div translate>Orphaned plugins</div>\n </c8y-li-body>\n <c8y-li-footer translate>\n Some plugins are not contained in the new version of this blueprint and will therefore get\n removed.\n </c8y-li-footer>\n <c8y-li-collapse>\n <c8y-plugin-list\n class=\"m-t-16\"\n [emptyListText]=\"'No plugins available' | translate\"\n [plugins$]=\"orphanedPlugins$\"\n [selectable]=\"false\"\n [hideSource]=\"true\"\n ></c8y-plugin-list>\n </c8y-li-collapse>\n </c8y-li>\n </c8y-list-group>\n\n <c8y-list-group *ngIf=\"(newPlugins$ | async).length > 0\">\n <c8y-li [collapsed]=\"false\">\n <c8y-li-icon>\n <span class=\"badge badge-success\">{{ (newPlugins$ | async).length }}</span>\n </c8y-li-icon>\n <c8y-li-body>\n <div translate>New plugins added</div>\n </c8y-li-body>\n <c8y-li-footer translate>\n This blueprint will add new plugins. Please choose which you want to install.\n </c8y-li-footer>\n <c8y-li-collapse>\n <c8y-plugin-list\n class=\"m-t-16\"\n [emptyListText]=\"'No plugins available' | translate\"\n [plugins$]=\"newPlugins$\"\n [selectable]=\"true\"\n [hideSource]=\"false\"\n ></c8y-plugin-list>\n </c8y-li-collapse>\n </c8y-li>\n </c8y-list-group>\n </ng-container>\n\n <ng-container c8y-modal-footer-custom>\n <div\n class=\"modal-footer\"\n *ngIf=\"\n (orphanedPlugins$ | async).length > 0 || (newPlugins$ | async).length > 0;\n else updateProgressButtons\n \"\n >\n <button\n class=\"btn btn-default\"\n title=\"{{ 'Close' | translate }}\"\n (click)=\"close()\"\n [disabled]=\"isUpdateOngoing\"\n >\n {{ 'Close' | translate }}\n </button>\n <button\n class=\"btn btn-primary\"\n title=\"{{ 'Continue' | translate }}\"\n (click)=\"updateApplication()\"\n *ngIf=\"(orphanedPlugins$ | async).length > 0 || (newPlugins$ | async).length > 0\"\n [disabled]=\"isUpdateOngoing\"\n >\n {{ 'Continue' | translate }}\n </button>\n </div>\n </ng-container>\n\n <ng-template #updateProgressButtons>\n <ng-container c8y-modal-footer-custom>\n <div class=\"modal-footer\">\n <button\n class=\"btn btn-default\"\n title=\"{{ 'Close' | translate }}\"\n (click)=\"done()\"\n [disabled]=\"isUpdateOngoing\"\n >\n {{ 'Close' | translate }}\n </button>\n </div>\n </ng-container>\n </ng-template>\n\n <ng-template #updateProgress>\n <c8y-loading\n class=\"text-center d-block p-t-56 p-b-56 m-t-4 m-b-4\"\n style=\"min-height: 180px\"\n layout=\"application\"\n *ngIf=\"isUpdateOngoing\"\n [message]=\"'Updating\u2026' | translate\"\n ></c8y-loading>\n\n <c8y-operation-result\n type=\"success\"\n *ngIf=\"!isUpdateOngoing && !updateFailure\"\n text=\"{{ 'Update completed' | translate }}\"\n [size]=\"120\"\n [vertical]=\"true\"\n ></c8y-operation-result>\n <c8y-operation-result\n type=\"error\"\n *ngIf=\"!isUpdateOngoing && updateFailure\"\n text=\"{{ 'Failed to update application.' | translate }}\"\n [size]=\"120\"\n [vertical]=\"true\"\n ></c8y-operation-result>\n </ng-template>\n</c8y-modal>\n" }]
}], ctorParameters: () => [{ type: i1.InventoryService }, { type: i2.EcosystemService }, { type: i3.PluginsService }], propDecorators: { modal: [{
type: ViewChild,
args: ['modal', { static: false }]
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXBkYXRlLWFwcGxpY2F0aW9uLW1vZGFsLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL2Vjb3N5c3RlbS9hcHBsaWNhdGlvbi1wcm9wZXJ0aWVzL3VwZGF0ZS1hcHBsaWNhdGlvbi1tb2RhbC91cGRhdGUtYXBwbGljYXRpb24tbW9kYWwuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vLi4vZWNvc3lzdGVtL2FwcGxpY2F0aW9uLXByb3BlcnRpZXMvdXBkYXRlLWFwcGxpY2F0aW9uLW1vZGFsL3VwZGF0ZS1hcHBsaWNhdGlvbi1tb2RhbC5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsU0FBUyxFQUFVLFNBQVMsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUM3RCxPQUFPLEVBQWdCLGdCQUFnQixFQUFFLE1BQU0sYUFBYSxDQUFDO0FBQzdELE9BQU8sRUFBcUIsY0FBYyxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDeEUsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sc0NBQXNDLENBQUM7QUFDeEUsT0FBTyxFQUFFLG1CQUFtQixFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDMUQsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLE1BQU0sQ0FBQzs7Ozs7OztBQU12QyxNQUFNLE9BQU8sK0JBQStCO0lBZ0IxQyxZQUNVLGdCQUFrQyxFQUNsQyxnQkFBa0MsRUFDbEMsY0FBOEI7UUFGOUIscUJBQWdCLEdBQWhCLGdCQUFnQixDQUFrQjtRQUNsQyxxQkFBZ0IsR0FBaEIsZ0JBQWdCLENBQWtCO1FBQ2xDLG1CQUFjLEdBQWQsY0FBYyxDQUFnQjtRQWpCeEMsb0JBQWUsR0FBRyxLQUFLLENBQUM7UUFDeEIsa0JBQWEsR0FBRyxLQUFLLENBQUM7UUFHdEIsV0FBTSxHQUFrQixJQUFJLE9BQU8sQ0FBQyxDQUFDLE9BQU8sRUFBRSxNQUFNLEVBQUUsRUFBRTtZQUN0RCxJQUFJ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QztZQUMvQixPQUFPLGNBQWMsQ0FBQztRQUN4QixDQUFDLENBQUMsQ0FBQztJQUNQLENBQUM7K0dBaExVLCtCQUErQjttR0FBL0IsK0JBQStCLG9LQ1g1QyxpMUlBMklBOzs0RkRoSWEsK0JBQStCO2tCQUozQyxTQUFTOytCQUNFLDhCQUE4QjtpSkFJTyxLQUFLO3NCQUFuRCxTQUFTO3VCQUFDLE9BQU8sRUFBRSxFQUFFLE1BQU0sRUFBRSxLQUFLLEVBQUUiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDb21wb25lbnQsIE9uSW5pdCwgVmlld0NoaWxkIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBJQXBwbGljYXRpb24sIEludmVudG9yeVNlcnZpY2UgfSBmcm9tICdAYzh5L2NsaWVudCc7XG5pbXBvcnQgeyBBcHBsaWNhdGlvblBsdWdpbiwgUGx1Z2luc1NlcnZpY2UgfSBmcm9tICdAYzh5L25neC1jb21wb25lbnRzJztcbmltcG9ydCB7IEVjb3N5c3RlbVNlcnZpY2UgfSBmcm9tICdAYzh5L25neC1jb21wb25lbnRzL2Vjb3N5c3RlbS9zaGFyZWQnO1xuaW1wb3J0IHsgUGx1Z2luc0V4cG9ydFNjb3BlcyB9IGZyb20gJ0BjOHkvbmd4LWNvbXBvbmVudHMnO1xuaW1wb3J0IHsgQmVoYXZpb3JTdWJqZWN0IH0gZnJvbSAncnhqcyc7XG5cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ2M4eS11cGRhdGUtYXBwbGljYXRpb24tbW9kYWwnLFxuICB0ZW1wbGF0ZVVybDogJy4vdXBkYXRlLWFwcGxpY2F0aW9uLW1vZGFsLmNvbXBvbmVudC5odG1sJ1xufSlcbmV4cG9ydCBjbGFzcyBVcGRhdGVBcHBsaWNhdGlvbk1vZGFsQ29tcG9uZW50IGltcGxlbWVudHMgT25Jbml0IHtcbiAgQFZpZXdDaGlsZCgnbW9kYWwnLCB7IHN0YXRpYzogZmFsc2UgfSkgcHJpdmF0ZSBtb2RhbDtcbiAgaXNVcGRhdGVPbmdvaW5nID0gZmFsc2U7XG4gIHVwZGF0ZUZhaWx1cmUgPSBmYWxzZTtcbiAgc291cmNlUGFja2FnZTogSUFwcGxpY2F0aW9uO1xuICBhcHBsaWNhdGlvbjogSUFwcGxpY2F0aW9uO1xuICByZXN1bHQ6IFByb21pc2U8dm9pZD4gPSBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgdGhpcy5fcmVzb2x2ZSA9IHJlc29sdmU7XG4gICAgdGhpcy5fcmVqZWN0ID0gcmVqZWN0O1xuICB9KTtcbiAgb3JwaGFuZWRQbHVnaW5zJDogQmVoYXZpb3JTdWJqZWN0PEFwcGxpY2F0aW9uUGx1Z2luW10+ID0gbmV3IEJlaGF2aW9yU3ViamVjdChbXSk7XG4gIG5ld1BsdWdpbnMkOiBCZWhhdmlvclN1YmplY3Q8QXBwbGljYXRpb25QbHVnaW5bXT4gPSBuZXcgQmVoYXZpb3JTdWJqZWN0KFtdKTtcblxuICBwcml2YXRlIF9yZXNvbHZlOiAodmFsdWU6IHZvaWQgfCBQcm9taXNlTGlrZTx2b2lkPikgPT4gdm9pZDtcbiAgcHJpdmF0ZSBfcmVqZWN0OiAodmFsdWU6IHZvaWQgfCBQcm9taXNlTGlrZTx2b2lkPikgPT4gdm9pZDtcblxuICBjb25zdHJ1Y3RvcihcbiAgICBwcml2YXRlIGludmVudG9yeVNlcnZpY2U6IEludmVudG9yeVNlcnZpY2UsXG4gICAgcHJpdmF0ZSBlY29zeXN0ZW1TZXJ2aWNlOiBFY29zeXN0ZW1TZXJ2aWNlLFxuICAgIHByaXZhdGUgcGx1Z2luc1NlcnZpY2U6IFBsdWdpbnNTZXJ2aWNlXG4gICkge31cblxuICBuZ09uSW5pdCgpOiB2b2lkIHtcbiAgICBjb25zdCBoYXNEZWx0YSA9IHRoaXMuZ2V0UmVtb3RlRGVsdGEoKTtcbiAgICBpZiAoIWhhc0RlbHRhKSB7XG4gICAgICAvLyBzdGFydCB1cGRhdGUgZGlyZWN0bHkgaWYgbm8gcmVtb3RlIGRlbHRhIGRldGVjdGVkXG4gICAgICB0aGlzLnVwZGF0ZUFwcGxpY2F0aW9uKCk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIENoZWNrcyBpZiB0aGVyZSBpcyBhIGRlbHRhIGJldHdlZW4gdGhlIGN1cnJlbnQgYXBwbGljYXRpb24gYW5kIHRoZSBzb3VyY2UgcGFja2FnZSByZW1vdGVzLlxuICAgKiBAcmV0dXJucyB7Ym9vbGVhbn0gdHJ1ZSBpZiB0aGVyZSBpcyBhIGRlbHRhIGJldHdlZW4gdGhlIGN1cnJlbnQgYXBwbGljYXRpb24gYW5kIHRoZSBzb3VyY2UgcGFja2FnZSByZW1vdGVzLlxuICAgKi9cbiAgZ2V0UmVtb3RlRGVsdGEoKSB7XG4gICAgY29uc3QgY3VycmVudFJlbW90ZXMgPSB0aGlzLnBsdWdpbnNTZXJ2aWNlLmdldE1GRXhwb3J0cyh0aGlzLmFwcGxpY2F0aW9uLCBbXSk7XG4gICAgY29uc3QgcG9zc2libGVOZXdSZW1vdGVzID0gdGhpcy5wbHVnaW5zU2VydmljZS5nZXRNRkV4cG9ydHModGhpcy5zb3VyY2VQYWNrYWdlLCBbXSk7XG4gICAgY29uc3QgaW5zdGFsbGVkUmVtb3RlcyA9IHRoaXMucGx1Z2luc1NlcnZpY2UuZ2V0TUZSZW1vdGVzKHRoaXMuYXBwbGljYXRpb24pO1xuICAgIGNvbnN0IGluc3RhbGxlZFJlbW90ZXNJZHMgPSBQbHVnaW5zU2VydmljZS5jb252ZXJ0SW5zdGFsbGVkUmVtb3Rlc1RvSWRzKGluc3RhbGxlZFJlbW90ZXMpO1xuXG4gICAgY29uc3QgYWxsUmVtb3Rlc1RvUmVtb3ZlID0gdGhpcy5nZXRBbGxSZW1vdGVzVG9SZW1vdmUoXG4gICAgICBjdXJyZW50UmVtb3RlcyxcbiAgICAgIHBvc3NpYmxlTmV3UmVtb3RlcyxcbiAgICAgIGluc3RhbGxlZFJlbW90ZXNJZHNcbiAgICApO1xuXG4gICAgY29uc3QgYWxsUmVtb3Rlc1RvQWRkID0gdGhpcy5nZXRBbGxSZW1vdGVzVG9BZGQocG9zc2libGVOZXdSZW1vdGVzLCBjdXJyZW50UmVtb3Rlcyk7XG5cbiAgICB0aGlzLm9ycGhhbmVkUGx1Z2lucyQubmV4dChhbGxSZW1vdGVzVG9SZW1vdmUpO1xuICAgIHRoaXMubmV3UGx1Z2lucyQubmV4dChhbGxSZW1vdGVzVG9BZGQpO1xuXG4gICAgcmV0dXJuIGFsbFJlbW90ZXNUb1JlbW92ZS5sZW5ndGggIT09IDAgfHwgYWxsUmVtb3Rlc1RvQWRkLmxlbmd0aCAhPT0gMDtcbiAgfVxuXG4gIGNsb3NlKCkge1xuICAgIHRoaXMuX3JlamVjdCgpO1xuICAgIHRoaXMubW9kYWwuX2Rpc21pc3MoKTtcbiAgfVxuXG4gIGRvbmUoKSB7XG4gICAgaWYgKCF0aGlzLnVwZGF0ZUZhaWx1cmUpIHtcbiAgICAgIHRoaXMuX3Jlc29sdmUoKTtcbiAgICAgIHRoaXMubW9kYWwuX2Rpc21pc3MoKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgdGhpcy5fcmVqZWN0KCk7XG4gICAgdGhpcy5tb2RhbC5fZGlzbWlzcygpO1xuICB9XG5cbiAgYXN5bmMgdXBkYXRlQXBwbGljYXRpb24oKSB7XG4gICAgdHJ5IHtcbiAgICAgIHRoaXMuaXNVcGRhdGVPbmdvaW5nID0gdHJ1ZTtcbiAgICAgIGNvbnN0IHRvSW5zdGFsbFBsdWdpbnMgPSB0aGlzLm5ld1BsdWdpbnMkLnZhbHVlLmZpbHRlcigoeyBzZWxlY3RlZCB9KSA9PiBzZWxlY3RlZCA9PT0gdHJ1ZSk7XG4gICAgICBjb25zdCB0b1JlbW92ZVBsdWdpbnMgPSB0aGlzLm9ycGhhbmVkUGx1Z2lucyQudmFsdWU7XG4gICAgICB0aGlzLm9ycGhhbmVkUGx1Z2lucyQubmV4dChbXSk7XG4gICAgICB0aGlzLm5ld1BsdWdpbnMkLm5leHQoW10pO1xuICAgICAgaWYgKHRvUmVtb3ZlUGx1Z2lucy5sZW5ndGggPiAwKSB7XG4gICAgICAgIGNvbnN0IHJlbW90ZXMgPSBhd2FpdCB0aGlzLnBsdWdpbnNTZXJ2aWNlLnJlbW92ZVJlbW90ZXModGhpcy5hcHBsaWNhdGlvbiwgdG9SZW1vdmVQbHVnaW5zKTtcbiAgICAgICAgdGhpcy5hcHBsaWNhdGlvbi5jb25maWcucmVtb3RlcyA9IHJlbW90ZXM7XG4gICAgICB9XG4gICAgICBpZiAodG9JbnN0YWxsUGx1Z2lucy5sZW5ndGggPiAwKSB7XG4gICAgICAgIGNvbnN0IHJlbW90ZXMgPSBhd2FpdCB0aGlzLnBsdWdpbnNTZXJ2aWNlLmFkZFJlbW90ZXModGhpcy5hcHBsaWNhdGlvbiwgdG9JbnN0YWxsUGx1Z2lucyk7XG4gICAgICAgIHRoaXMuYXBwbGljYXRpb24uY29uZmlnLnJlbW90ZXMgPSByZW1vdGVzO1xuICAgICAgfVxuICAgICAgY29uc3QgYmluYXJ5TW9JZCA9IHRoaXMuc291cmNlUGFja2FnZS5hY3RpdmVWZXJzaW9uSWQ7XG4gICAgICBhd2FpdCB0aGlzLmludmVudG9yeVNlcnZpY2UuZGV0YWlsKGJpbmFyeU1vSWQpOyAvLyBvbmx5IHRyeWluZyBpZiB3ZSBjYW4gYWNjZXNzIGl0XG4gICAgICBhd2FpdCB0aGlzLmVjb3N5c3RlbVNlcnZpY2UudXBsb2FkQmluYXJ5RnJvbU90aGVyUGFja2FnZShcbiAgICAgICAgdGhpcy5zb3VyY2VQYWNrYWdlLFxuICAgICAgICB0aGlzLmFwcGxpY2F0aW9uLFxuICAgICAgICB0aGlzLnNvdXJjZVBhY2thZ2UuYWN0aXZlVmVyc2lvbklkXG4gICAgICApO1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIGlmIChlLnJlcz8uc3RhdHVzID09PSA0MDQpIHtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICB0aGlzLnVwZGF0ZUZhaWx1cmUgPSAhKGF3YWl0IHRoaXMuZWNvc3lzdGVtU2VydmljZS5mYWxsYmFja1RvQ2xvbmUoXG4gICAgICAgICAgICB0aGlzLmFwcGxpY2F0aW9uLFxuICAgICAgICAgICAgdGhpcy5zb3VyY2VQYWNrYWdlXG4gICAgICAgICAgKSk7XG4gICAgICAgIH0gY2F0Y2ggKGV4KSB7XG4gICAgICAgICAgdGhpcy51cGRhdGVGYWlsdXJlID0gdHJ1ZTtcbiAgICAgICAgICB0aGlzLmVjb3N5c3RlbVNlcnZpY2UuYWxlcnRFcnJvcihlKTtcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdGhpcy51cGRhdGVGYWlsdXJlID0gdHJ1ZTtcbiAgICAgICAgdGhpcy5lY29zeXN0ZW1TZXJ2aWNlLmFsZXJ0RXJyb3IoZSk7XG4gICAgICB9XG4gICAgfSBmaW5hbGx5IHtcbiAgICAgIHRoaXMuaXNVcGRhdGVPbmdvaW5nID0gZmFsc2U7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBnZXRBbGxSZW1vdGVzVG9BZGQoXG4gICAgcG9zc2libGVOZXdSZW1vdGVzOiBBcHBsaWNhdGlvblBsdWdpbltdLFxuICAgIGN1cnJlbnRSZW1vdGVzOiBBcHBsaWNhdGlvblBsdWdpbltdXG4gICkge1xuICAgIHJldHVybiBwb3NzaWJsZU5ld1JlbW90ZXNcbiAgICAgIC5maWx0ZXIocG9zc2libGVOZXdSZW1vdGUgPT4ge1xuICAgICAgICBjb25zdCBpc1VuY2hhbmdlZCA9ICEhY3VycmVudFJlbW90ZXMuc29tZShcbiAgICAgICAgICBjdXJyZW50UmVtb3RlID0+XG4gICAgICAgICAgICBQbHVnaW5zU2VydmljZS5jcmVhdGVQbHVnaW5JZChcbiAgICAgICAgICAgICAgdGhpcy5hcHBsaWNhdGlvbi5jb250ZXh0UGF0aCxcbiAgICAgICAgICAgICAgcG9zc2libGVOZXdSZW1vdGUubW9kdWxlLFxuICAgICAgICAgICAgICAnJyxcbiAgICAgICAgICAgICAgdHJ1ZVxuICAgICAgICAgICAgKSA9PT0gY3VycmVudFJlbW90ZS5pZExhdGVzdFxuICAgICAgICApO1xuXG4gICAgICAgIGNvbnN0IGlzU2VsZiA9XG4gICAgICAgICAgcG9zc2libGVOZXdSZW1vdGUuc2NvcGUgPT09IFBsdWdpbnNFeHBvcnRTY29wZXMuU0VMRiB8fFxuICAgICAgICAgIHBvc3NpYmxlTmV3UmVtb3RlLnNjb3BlID09PSBQbHVnaW5zRXhwb3J0U2NvcGVzLlNFTEZfT1BUSU9OQUw7XG5cbiAgICAgICAgcmV0dXJuICFpc1VuY2hhbmdlZCAmJiBpc1NlbGY7XG4gICAgICB9KVxuICAgICAgLm1hcChuZXdSZW1vdGUgPT4ge1xuICAgICAgICBuZXdSZW1vdGUuY29udGV4dFBhdGggPSB0aGlzLmFwcGxpY2F0aW9uLmNvbnRleHRQYXRoO1xuICAgICAgICBuZXdSZW1vdGUuaWQgPSBgJHtuZXdSZW1vdGUuY29udGV4dFBhdGh9LyR7bmV3UmVtb3RlLm1vZHVsZX1gO1xuICAgICAgICBuZXdSZW1vdGUuc2VsZWN0ZWQgPSBuZXdSZW1vdGUuc2NvcGUgPT09IFBsdWdpbnNFeHBvcnRTY29wZXMuU0VMRjtcbiAgICAgICAgcmV0dXJuIG5ld1JlbW90ZTtcbiAgICAgIH0pO1xuICB9XG5cbiAgcHJpdmF0ZSBnZXRBbGxSZW1vdGVzVG9SZW1vdmUoXG4gICAgY3VycmVudFJlbW90ZXM6IEFwcGxpY2F0aW9uUGx1Z2luW10sXG4gICAgcG9zc2libGVOZXdSZW1vdGVzOiBBcHBsaWNhdGlvblBsdWdpbltdLFxuICAgIGluc3RhbGxlZFJlbW90ZXNJZHM6IHN0cmluZ1tdXG4gICkge1xuICAgIHJldHVybiBjdXJyZW50UmVtb3Rlc1xuICAgICAgLmZpbHRlcihjdXJyZW50UmVtb3RlID0+IHtcbiAgICAgICAgY29uc3QgaXNVbmNoYW5nZWQgPSAhIXBvc3NpYmxlTmV3UmVtb3Rlcy5zb21lKFxuICAgICAgICAgIG5ld1JlbW90ZSA9PlxuICAgICAgICAgICAgUGx1Z2luc1NlcnZpY2UuY3JlYXRlUGx1Z2luSWQoXG4gICAgICAgICAgICAgIHRoaXMuYXBwbGljYXRpb24uY29udGV4dFBhdGgsXG4gICAgICAgICAgICAgIG5ld1JlbW90ZS5tb2R1bGUsXG4gICAgICAgICAgICAgICcnLFxuICAgICAgICAgICAgICB0cnVlXG4gICAgICAgICAgICApID09PSBjdXJyZW50UmVtb3RlLmlkTGF0ZXN0XG4gICAgICAgICk7XG4gICAgICAgIGNvbnN0IGlzSW5zdGFsbGVkID0gaW5zdGFsbGVkUmVtb3Rlc0lkc1xuICAgICAgICAgID8gISFpbnN0YWxsZWRSZW1vdGVzSWRzLnNvbWUoXG4gICAgICAgICAgICAgIGN1cnJlbnRJbnN0YWxsZWQgPT5cbiAgICAgICAgICAgICAgICBjdXJyZW50UmVtb3RlLmlkID09PSBjdXJyZW50SW5zdGFsbGVkIHx8IGN1cnJlbnRSZW1vdGUuaWRMYXRlc3QgPT09IGN1cnJlbnRJbnN0YWxsZWRcbiAgICAgICAgICAgIClcbiAgICAgICAgICA6IGZhbHNlO1xuXG4gICAgICAgIGNvbnN0IGlzU2VsZiA9XG4gICAgICAgICAgY3VycmVudFJlbW90ZS5zY29wZSA9PT0gUGx1Z2luc0V4cG9ydFNjb3Blcy5TRUxGIHx8XG4gICAgICAgICAgY3VycmVudFJlbW90ZS5zY29wZSA9PT0gUGx1Z2luc0V4cG9ydFNjb3Blcy5TRUxGX09QVElPTkFMO1xuXG4gICAgICAgIHJldHVybiAhaXNVbmNoYW5nZWQgJiYgaXNJbnN0YWxsZWQgJiYgaXNTZWxmO1xuICAgICAgfSlcbiAgICAgIC5tYXAodG9SZW1vdmVSZW1vdGUgPT4ge1xuICAgICAgICB0b1JlbW92ZVJlbW90ZS5jb250ZXh0UGF0aCA9IHRoaXMuYXBwbGljYXRpb24uY29udGV4dFBhdGg7XG4gICAgICAgIHRvUmVtb3ZlUmVtb3RlLmlkID0gYCR7dG9SZW1vdmVSZW1vdGUuY29udGV4dFBhdGh9LyR7dG9SZW1vdmVSZW1vdGUubW9kdWxlfWA7XG4gICAgICAgIHRvUmVtb3ZlUmVtb3RlLnNlbGVjdGVkID0gdHJ1ZTtcbiAgICAgICAgcmV0dXJuIHRvUmVtb3ZlUmVtb3RlO1xuICAgICAgfSk7XG4gIH1cbn1cbiIsIjxjOHktbW9kYWxcbiAgW3RpdGxlXT1cIidVcGRhdGUgYXBwbGljYXRpb24nIHwgdHJhbnNsYXRlXCJcbiAgW2hlYWRlckNsYXNzZXNdPVwiJ2RpYWxvZy1oZWFkZXInXCJcbiAgW2N1c3RvbUZvb3Rlcl09XCJ0cnVlXCJcbiAgI21vZGFsXG4+XG4gIDxuZy1jb250YWluZXIgYzh5LW1vZGFsLXRpdGxlPlxuICAgIDxzcGFuIGNsYXNzPVwiZGx0LWM4eS1pY29uLWluc3RhbGxpbmctdXBkYXRlc1wiPjwvc3Bhbj5cbiAgPC9uZy1jb250YWluZXI+XG5cbiAgPG5nLWNvbnRhaW5lclxuICAgICpuZ0lmPVwiXG4gICAgICAob3JwaGFuZWRQbHVnaW5zJCB8IGFzeW5jKS5sZW5ndGggPiAwIHx8IChuZXdQbHVnaW5zJCB8IGFzeW5jKS5sZW5ndGggPiAwO1xuICAgICAgZWxzZSB1cGRhdGVQcm9ncmVzc1xuICAgIFwiXG4gID5cbiAgICA8cFxuICAgICAgY2xhc3M9XCJ0ZXh0LWNlbnRlciB0ZXh0LWJyZWFrLXdvcmQgcC0yNCB0ZXh0LTE0XCJcbiAgICAgIHRyYW5zbGF0ZVxuICAgID5cbiAgICAgIFVwZGF0aW5nIHRoaXMgYmx1ZXByaW50IHdpbGwgY2hhbmdlIHRoZSBkZWZhdWx0IHBsdWdpbnMuIFJldmlldyB0aGUgcGx1Z2luIGNoYW5nZXMgYmVmb3JlXG4gICAgICBwcm9jZWVkaW5nLlxuICAgIDwvcD5cbiAgICA8Yzh5LWxpc3QtZ3JvdXAgKm5nSWY9XCIob3JwaGFuZWRQbHVnaW5zJCB8IGFzeW5jKS5sZW5ndGggPiAwXCI+XG4gICAgICA8Yzh5LWxpIFtjb2xsYXBzZWRdPVwidHJ1ZVwiPlxuICAgICAgICA8Yzh5LWxpLWljb24+XG4gICAgICAgICAgPHNwYW4gY2xhc3M9XCJiYWRnZSBiYWRnZS1kYW5nZXJcIj57eyAob3JwaGFuZWRQbHVnaW5zJCB8IGFzeW5jKS5sZW5ndGggfX08L3NwYW4+XG4gICAgICAgIDwvYzh5LWxpLWljb24+XG4gICAgICAgIDxjOHktbGktYm9keT5cbiAgICAgICAgICA8ZGl2IHRyYW5zbGF0ZT5PcnBoYW5lZCBwbHVnaW5zPC9kaXY+XG4gICAgICAgIDwvYzh5LWxpLWJvZHk+XG4gICAgICAgIDxjOHktbGktZm9vdGVyIHRyYW5zbGF0ZT5cbiAgICAgICAgICBTb21lIHBsdWdpbnMgYXJlIG5vdCBjb250YWluZWQgaW4gdGhlIG5ldyB2ZXJzaW9uIG9mIHRoaXMgYmx1ZXByaW50IGFuZCB3aWxsIHRoZXJlZm9yZSBnZXRcbiAgICAgICAgICByZW1vdmVkLlxuICAgICAgICA8L2M4eS1saS1mb290ZXI+XG4gICAgICAgIDxjOHktbGktY29sbGFwc2U+XG4gICAgICAgICAgPGM4eS1wbHVnaW4tbGlzdFxuICAgICAgICAgICAgY2xhc3M9XCJtLXQtMTZcIlxuICAgICAgICAgICAgW2VtcHR5TGlzdFRleHRdPVwiJ05vIHBsdWdpbnMgYXZhaWxhYmxlJyB8IHRyYW5zbGF0ZVwiXG4gICAgICAgICAgICBbcGx1Z2lucyRdPVwib3JwaGFuZWRQbHVnaW5zJFwiXG4gICAgICAgICAgICBbc2VsZWN0YWJsZV09XCJmYWxzZVwiXG4gICAgICAgICAgICBbaGlkZVNvdXJjZV09XCJ0cnVlXCJcbiAgICAgICAgICA+PC9jOHktcGx1Z2luLWxpc3Q+XG4gICAgICAgIDwvYzh5LWxpLWNvbGxhcHNlPlxuICAgICAgPC9jOHktbGk+XG4gICAgPC9jOHktbGlzdC1ncm91cD5cblxuICAgIDxjOHktbGlzdC1ncm91cCAqbmdJZj1cIihuZXdQbHVnaW5zJCB8IGFzeW5jKS5sZW5ndGggPiAwXCI+XG4gICAgICA8Yzh5LWxpIFtjb2xsYXBzZWRdPVwiZmFsc2VcIj5cbiAgICAgICAgPGM4eS1saS1pY29uPlxuICAgICAgICAgIDxzcGFuIGNsYXNzPVwiYmFkZ2UgYmFkZ2Utc3VjY2Vzc1wiPnt7IChuZXdQbHVnaW5zJCB8IGFzeW5jKS5sZW5ndGggfX08L3NwYW4+XG4gICAgICAgIDwvYzh5LWxpLWljb24+XG4gICAgICAgIDxjOHktbGktYm9keT5cbiAgICAgICAgICA8ZGl2IHRyYW5zbGF0ZT5OZXcgcGx1Z2lucyBhZGRlZDwvZGl2PlxuICAgICAgICA8L2M4eS1saS1ib2R5PlxuICAgICAgICA8Yzh5LWxpLWZvb3RlciB0cmFuc2xhdGU+XG4gICAgICAgICAgVGhpcyBibHVlcHJpbnQgd2lsbCBhZGQgbmV3IHBsdWdpbnMuIFBsZWFzZSBjaG9vc2Ugd2hpY2ggeW91IHdhbnQgdG8gaW5zdGFsbC5cbiAgICAgICAgPC9jOHktbGktZm9vdGVyPlxuICAgICAgICA8Yzh5LWxpLWNvbGxhcHNlPlxuICAgICAgICAgIDxjOHktcGx1Z2luLWxpc3RcbiAgICAgICAgICAgIGNsYXNzPVwibS10LTE2XCJcbiAgICAgICAgICAgIFtlbXB0eUxpc3RUZXh0XT1cIidObyBwbHVnaW5zIGF2YWlsYWJsZScgfCB0cmFuc2xhdGVcIlxuICAgICAgICAgICAgW3BsdWdpbnMkXT1cIm5ld1BsdWdpbnMkXCJcbiAgICAgICAgICAgIFtzZWxlY3RhYmxlXT1cInRydWVcIlxuICAgICAgICAgICAgW2hpZGVTb3VyY2VdPVwiZmFsc2VcIlxuICAgICAgICAgID48L2M4eS1wbHVnaW4tbGlzdD5cbiAgICAgICAgPC9jOHktbGktY29sbGFwc2U+XG4gICAgICA8L2M4eS1saT5cbiAgICA8L2M4eS1saXN0LWdyb3VwPlxuICA8L25nLWNvbnRhaW5lcj5cblxuICA8bmctY29udGFpbmVyIGM4eS1tb2RhbC1mb290ZXItY3VzdG9tPlxuICAgIDxkaXZcbiAgICAgIGNsYXNzPVwibW9kYWwtZm9vdGVyXCJcbiAgICAgICpuZ0lmPVwiXG4gICAgICAgIChvcnBoYW5lZFBsdWdpbnMkIHwgYXN5bmMpLmxlbmd0aCA+IDAgfHwgKG5ld1BsdWdpbnMkIHwgYXN5bmMpLmxlbmd0aCA+IDA7XG4gICAgICAgIGVsc2UgdXBkYXRlUHJvZ3Jlc3NCdXR0b25zXG4gICAgICBcIlxuICAgID5cbiAgICAgIDxidXR0b25cbiAgICAgICAgY2xhc3M9XCJidG4gYnRuLWRlZmF1bHRcIlxuICAgICAgICB0aXRsZT1cInt7ICdDbG9zZScgfCB0cmFuc2xhdGUgfX1cIlxuICAgICAgICAoY2xpY2spPVwiY2xvc2UoKVwiXG4gICAgICAgIFtkaXNhYmxlZF09XCJpc1VwZGF0ZU9uZ29pbmdcIlxuICAgICAgPlxuICAgICAgICB7eyAnQ2xvc2UnIHwgdHJhbnNsYXRlIH19XG4gICAgICA8L2J1dHRvbj5cbiAgICAgIDxidXR0b25cbiAgICAgICAgY2xhc3M9XCJidG4gYnRuLXByaW1hcnlcIlxuICAgICAgICB0aXRsZT1cInt7ICdDb250aW51ZScgfCB0cmFuc2xhdGUgfX1cIlxuICAgICAgICAoY2xpY2spPVwidXBkYXRlQXBwbGljYXRpb24oKVwiXG4gICAgICAgICpuZ0lmPVwiKG9ycGhhbmVkUGx1Z2lucyQgfCBhc3luYykubGVuZ3RoID4gMCB8fCAobmV3UGx1Z2lucyQgfCBhc3luYykubGVuZ3RoID4gMFwiXG4gICAgICAgIFtkaXNhYmxlZF09XCJpc1VwZGF0ZU9uZ29pbmdcIlxuICAgICAgPlxuICAgICAgICB7eyAnQ29udGludWUnIHwgdHJhbnNsYXRlIH19XG4gICAgICA8L2J1dHRvbj5cbiAgICA8L2Rpdj5cbiAgPC9uZy1jb250YWluZXI+XG5cbiAgPG5nLXRlbXBsYXRlICN1cGRhdGVQcm9ncmVzc0J1dHRvbnM+XG4gICAgPG5nLWNvbnRhaW5lciBjOHktbW9kYWwtZm9vdGVyLWN1c3RvbT5cbiAgICAgIDxkaXYgY2xhc3M9XCJtb2RhbC1mb290ZXJcIj5cbiAgICAgICAgPGJ1dHRvblxuICAgICAgICAgIGNsYXNzPVwiYnRuIGJ0bi1kZWZhdWx0XCJcbiAgICAgICAgICB0aXRsZT1cInt7ICdDbG9zZScgfCB0cmFuc2xhdGUgfX1cIlxuICAgICAgICAgIChjbGljayk9XCJkb25lKClcIlxuICAgICAgICAgIFtkaXNhYmxlZF09XCJpc1VwZGF0ZU9uZ29pbmdcIlxuICAgICAgICA+XG4gICAgICAgICAge3sgJ0Nsb3NlJyB8IHRyYW5zbGF0ZSB9fVxuICAgICAgICA8L2J1dHRvbj5cbiAgICAgIDwvZGl2PlxuICAgIDwvbmctY29udGFpbmVyPlxuICA8L25nLXRlbXBsYXRlPlxuXG4gIDxuZy10ZW1wbGF0ZSAjdXBkYXRlUHJvZ3Jlc3M+XG4gICAgPGM4eS1sb2FkaW5nXG4gICAgICBjbGFzcz1cInRleHQtY2VudGVyIGQtYmxvY2sgcC10LTU2IHAtYi01NiBtLXQtNCBtLWItNFwiXG4gICAgICBzdHlsZT1cIm1pbi1oZWlnaHQ6IDE4MHB4XCJcbiAgICAgIGxheW91dD1cImFwcGxpY2F0aW9uXCJcbiAgICAgICpuZ0lmPVwiaXNVcGRhdGVPbmdvaW5nXCJcbiAgICAgIFttZXNzYWdlXT1cIidVcGRhdGluZ+KApicgfCB0cmFuc2xhdGVcIlxuICAgID48L2M4eS1sb2FkaW5nPlxuXG4gICAgPGM4eS1vcGVyYXRpb24tcmVzdWx0XG4gICAgICB0eXBlPVwic3VjY2Vzc1wiXG4gICAgICAqbmdJZj1cIiFpc1VwZGF0ZU9uZ29pbmcgJiYgIXVwZGF0ZUZhaWx1cmVcIlxuICAgICAgdGV4dD1cInt7ICdVcGRhdGUgY29tcGxldGVkJyB8IHRyYW5zbGF0ZSB9fVwiXG4gICAgICBbc2l6ZV09XCIxMjBcIlxuICAgICAgW3ZlcnRpY2FsXT1cInRydWVcIlxuICAgID48L2M4eS1vcGVyYXRpb24tcmVzdWx0PlxuICAgIDxjOHktb3BlcmF0aW9uLXJlc3VsdFxuICAgICAgdHlwZT1cImVycm9yXCJcbiAgICAgICpuZ0lmPVwiIWlzVXBkYXRlT25nb2luZyAmJiB1cGRhdGVGYWlsdXJlXCJcbiAgICAgIHRleHQ9XCJ7eyAnRmFpbGVkIHRvIHVwZGF0ZSBhcHBsaWNhdGlvbi4nIHwgdHJhbnNsYXRlIH19XCJcbiAgICAgIFtzaXplXT1cIjEyMFwiXG4gICAgICBbdmVydGljYWxdPVwidHJ1ZVwiXG4gICAgPjwvYzh5LW9wZXJhdGlvbi1yZXN1bHQ+XG4gIDwvbmctdGVtcGxhdGU+XG48L2M4eS1tb2RhbD5cbiJdfQ==