UNPKG

@c8y/ngx-components

Version:

Angular modules for Cumulocity IoT applications

238 lines 44.6 kB
import { Component, EventEmitter, Input, Output } from '@angular/core'; import { InventoryBinaryService, InventoryService } from '@c8y/client'; import { AlertService, AssetTypesRealtimeService, gettext } from '@c8y/ngx-components'; import { sortBy, toPairs, fromPairs, find } from 'lodash-es'; import { firstValueFrom } from 'rxjs'; import * as i0 from "@angular/core"; import * as i1 from "@c8y/ngx-components"; import * as i2 from "@c8y/client"; import * as i3 from "@angular/common"; import * as i4 from "ngx-bootstrap/tooltip"; import * as i5 from "./asset-properties-item.component"; import * as i6 from "./location/asset-location.component"; export class AssetPropertiesComponent { constructor(assetTypes, inventory, inventoryBinary, alert) { this.assetTypes = assetTypes; this.inventory = inventory; this.inventoryBinary = inventoryBinary; this.alert = alert; this.assetChange = new EventEmitter(); this.properties = []; this.customProperties = []; this.isEdit = false; this.isLoading = false; } ngOnChanges(changes) { if (changes.asset) { // Back button handling, as component is not destroyed this.assetType = undefined; this.customProperties = []; this.loadAsset(); } } async loadAsset() { this.isLoading = true; const assetType$ = this.assetTypes.getAssetTypeByName$(this.asset.type); this.assetType = await firstValueFrom(assetType$); try { this.properties = this.keepOrder(this.assetType?.c8y_IsAssetType?.properties, this.properties); } catch (ex) { console.warn(ex); } this.customProperties = await this.resolveCustomProperties(this.properties); this.isLoading = false; } async resolveCustomProperties(managedObjects) { const properties = []; for (const mo of managedObjects) { if (mo.c8y_JsonSchema) { const [item] = await this.parseItem(mo, mo.c8y_JsonSchema.properties, this.asset); this.setItemRequired(item, mo); properties.push(item); } } return properties; } deleteTitleFromMOJsonSchema(mo) { const schemaProperties = mo?.c8y_JsonSchema?.properties; const property = Object.keys(schemaProperties || {})[0]; delete (mo?.c8y_JsonSchema?.properties[property] || {}).title; } /** * This method is used to order the complex properties in the order specified by the user in asset properties screen. * @param mo - Managed object of the complex property associated with the asset. */ orderComplexProperties(mo) { const complexProperties = mo.c8y_JsonSchema.properties[mo.name]?.['properties']; const keyValuesArray = toPairs(complexProperties); const orderedProperties = sortBy(keyValuesArray, ([, value]) => value.order); mo.c8y_JsonSchema.properties[mo.name]['properties'] = fromPairs(orderedProperties); } async parseItem(mo, properties, asset) { if (!asset) { return []; } const keys = Object.keys(properties); const items = []; for (const key of keys) { const type = properties[key].type; const title = properties[key].title; let value = this.getTypeValue(type, asset[key]); let file; if (type === 'file' && value) { const fileId = typeof value === 'object' ? value[0]?.file?.id : value; const fileData = await this.getFileManagedObject(fileId); file = fileData; value = [fileData]; } else if (type === 'date') { const valueDate = new Date(value); value = !isNaN(valueDate.getTime()) ? valueDate : ''; } if (type === 'object') { // remove title to avoid excessive property name on asset complex properties form this.deleteTitleFromMOJsonSchema(mo); this.orderComplexProperties(mo); if (!value) { value = {}; for (const prop in properties[key].properties) { value[prop] = this.getTypeValue(properties[key].properties[prop].type, null); } } } items.push({ key, value, label: title || mo.label, type, description: mo.description, file, complex: type === 'object' ? await this.parseItem(mo, properties[key].properties, value) : undefined, isEdit: false, jsonSchema: mo.c8y_JsonSchema }); } return items; } toggleEdit(prop) { prop.isEdit = !prop.isEdit; } async getFileManagedObject(id) { try { const { data } = await this.inventory.detail(id); return data; } catch (ex) { this.alert.addServerFailure(ex); } } async save(propertyValue, prop) { try { if (prop.type === 'object') { this.updateUndefinedToPropTypeValue(prop, propertyValue[prop.key]); } else { this.updateUndefinedToPropTypeValue(prop, propertyValue); } propertyValue = await this.uploadFiles(propertyValue, prop.value); // Avoid making a PUT request containing just the id, as response body might be incomplete const hasValues = Object.values(propertyValue).some(value => value !== undefined); if (!hasValues) { this.toggleEdit(prop); return; } const updatedAsset = { id: this.asset.id, ...propertyValue }; const { data } = await this.inventory.update(updatedAsset); this.toggleEdit(prop); this.asset = data; this.assetChange.emit(this.asset); await this.loadAsset(); this.alert.success(gettext('Asset properties updated.')); } catch (ex) { this.alert.addServerFailure(ex); this.toggleEdit(prop); } } updateUndefinedToPropTypeValue(prop, propertyValue) { for (const [key, value] of Object.entries(propertyValue)) { const property = prop.complex ? find(prop.complex, { key: key }) : prop; propertyValue[key] = this.getTypeValue(property.type, value); } } getTypeValue(propType, value) { if (value || (propType === 'boolean' && value !== undefined)) return value; switch (propType) { case 'number': case 'boolean': return value || value === 0 ? value : null; default: return ''; } } keepOrder(correctOrderedIds, properties) { const orderedProperties = correctOrderedIds.map(({ id }) => { const foundProperty = properties.find(property => property.id === id); if (!foundProperty) { throw new Error('Custom property mismatch'); } return foundProperty; }); return orderedProperties; } async uploadFiles(model, moId) { const keys = Object.keys(model); for (const key of keys) { if (Array.isArray(model[key]) && model[key][0]?.file instanceof File) { try { const upload = await this.inventoryBinary.create(model[key][0].file); try { if (moId && moId[0]) { await this.inventory.childAdditionsRemove(moId[0], this.asset.id); } } catch (ex) { throw ex; } model[key] = upload.data.id; await this.inventory.childAdditionsAdd(upload.data.id, this.asset.id); } catch (ex) { throw ex; } } } return model; } setItemRequired(item, mo) { const isAssetPropertyRequired = !!this.assetType?.c8y_IsAssetType?.properties.find(p => p.id === mo.id)?.isRequired; if (!isAssetPropertyRequired) { return; } const isComplexProperty = !!item?.complex?.length; if (isComplexProperty) { const complexProperty = item.jsonSchema?.properties?.[mo.c8y_JsonSchema.key]; complexProperty.required = item.complex.map(({ key }) => key); } else { item.jsonSchema.required = [mo.c8y_JsonSchema.key]; } } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: AssetPropertiesComponent, deps: [{ token: i1.AssetTypesRealtimeService }, { token: i2.InventoryService }, { token: i2.InventoryBinaryService }, { token: i1.AlertService }], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: AssetPropertiesComponent, selector: "c8y-asset-properties", inputs: { asset: "asset", properties: "properties" }, outputs: { assetChange: "assetChange" }, usesOnChanges: true, ngImport: i0, template: "<ng-container>\n <div class=\"card-header bg-inherit separator sticky-top\">\n <h1\n class=\"card-title p-t-4 p-b-4\"\n ngNonBindable\n translate\n [translateParams]=\"{ label: assetType?.label || '' | translate }\"\n >\n {{ label }} properties\n </h1>\n </div>\n <div class=\"card-block\">\n <div\n class=\"text-center\"\n *ngIf=\"isLoading\"\n >\n <c8y-loading></c8y-loading>\n </div>\n\n <ng-container *ngIf=\"!isLoading\">\n <div\n class=\"card m-b-8\"\n title=\"{{ prop.description | translate }}\"\n *ngFor=\"let prop of customProperties\"\n [ngClass]=\"{ 'card-highlight': prop.isEdit }\"\n >\n <div\n class=\"card-block\"\n [ngClass]=\"{ 'p-b-0': prop.isEdit }\"\n >\n <div\n class=\"d-flex p-b-8 a-i-center\"\n *ngIf=\"!prop.isEdit\"\n >\n <p\n class=\"text-medium text-truncate\"\n title=\"{{ prop?.label | translate }}\"\n >\n {{ prop?.label | translate }}\n </p>\n <button\n class=\"btn btn-dot m-l-auto text-12\"\n [attr.aria-label]=\"'Edit' | translate\"\n tooltip=\"{{ 'Edit' | translate }}\"\n type=\"button\"\n [delay]=\"500\"\n (click)=\"toggleEdit(prop)\"\n >\n <i c8yIcon=\"pencil\"></i>\n </button>\n </div>\n <c8y-asset-properties-item\n #assetProps\n [file]=\"prop.file\"\n [key]=\"prop.key\"\n [type]=\"prop.type\"\n [value]=\"prop.value\"\n [complex]=\"prop.complex\"\n [isEdit]=\"prop.isEdit\"\n [jsonSchema]=\"prop.jsonSchema\"\n ></c8y-asset-properties-item>\n <div *ngIf=\"prop.key === 'c8y_Position'\">\n <c8y-asset-location\n [locationMO]=\"asset\"\n [isEdit]=\"prop.isEdit\"\n [form]=\"assetProps.form\"\n ></c8y-asset-location>\n </div>\n </div>\n <div\n class=\"card-footer p-t-0\"\n *ngIf=\"prop.isEdit\"\n >\n <button\n class=\"btn btn-default btn-sm\"\n title=\"{{ 'Cancel' | translate }}\"\n type=\"button\"\n (click)=\"toggleEdit(prop)\"\n >\n {{ 'Cancel' | translate }}\n </button>\n <button\n class=\"btn btn-primary btn-sm\"\n title=\"{{ 'Save' | translate }}\"\n type=\"button\"\n [disabled]=\"!assetProps?.form?.valid || !assetProps?.form?.dirty \"\n (click)=\"save(assetProps.form.value, prop)\"\n >\n {{ 'Save' | translate }}\n </button>\n </div>\n </div>\n </ng-container>\n </div>\n</ng-container>\n", dependencies: [{ kind: "directive", type: i1.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: i1.C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: i3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i3.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i1.LoadingComponent, selector: "c8y-loading", inputs: ["layout", "progress", "message"] }, { kind: "directive", type: i4.TooltipDirective, selector: "[tooltip], [tooltipHtml]", inputs: ["adaptivePosition", "tooltip", "placement", "triggers", "container", "containerClass", "boundariesElement", "isOpen", "isDisabled", "delay", "tooltipHtml", "tooltipPlacement", "tooltipIsOpen", "tooltipEnable", "tooltipAppendToBody", "tooltipAnimation", "tooltipClass", "tooltipContext", "tooltipPopupDelay", "tooltipFadeDuration", "tooltipTrigger"], outputs: ["tooltipChange", "onShown", "onHidden", "tooltipStateChanged"], exportAs: ["bs-tooltip"] }, { kind: "component", type: i5.AssetPropertiesItemComponent, selector: "c8y-asset-properties-item", inputs: ["key", "value", "label", "type", "file", "complex", "isEdit", "jsonSchema"] }, { kind: "component", type: i6.AssetLocationComponent, selector: "c8y-asset-location", inputs: ["isEdit", "locationMO", "form"] }, { kind: "pipe", type: i1.C8yTranslatePipe, name: "translate" }] }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: AssetPropertiesComponent, decorators: [{ type: Component, args: [{ selector: 'c8y-asset-properties', template: "<ng-container>\n <div class=\"card-header bg-inherit separator sticky-top\">\n <h1\n class=\"card-title p-t-4 p-b-4\"\n ngNonBindable\n translate\n [translateParams]=\"{ label: assetType?.label || '' | translate }\"\n >\n {{ label }} properties\n </h1>\n </div>\n <div class=\"card-block\">\n <div\n class=\"text-center\"\n *ngIf=\"isLoading\"\n >\n <c8y-loading></c8y-loading>\n </div>\n\n <ng-container *ngIf=\"!isLoading\">\n <div\n class=\"card m-b-8\"\n title=\"{{ prop.description | translate }}\"\n *ngFor=\"let prop of customProperties\"\n [ngClass]=\"{ 'card-highlight': prop.isEdit }\"\n >\n <div\n class=\"card-block\"\n [ngClass]=\"{ 'p-b-0': prop.isEdit }\"\n >\n <div\n class=\"d-flex p-b-8 a-i-center\"\n *ngIf=\"!prop.isEdit\"\n >\n <p\n class=\"text-medium text-truncate\"\n title=\"{{ prop?.label | translate }}\"\n >\n {{ prop?.label | translate }}\n </p>\n <button\n class=\"btn btn-dot m-l-auto text-12\"\n [attr.aria-label]=\"'Edit' | translate\"\n tooltip=\"{{ 'Edit' | translate }}\"\n type=\"button\"\n [delay]=\"500\"\n (click)=\"toggleEdit(prop)\"\n >\n <i c8yIcon=\"pencil\"></i>\n </button>\n </div>\n <c8y-asset-properties-item\n #assetProps\n [file]=\"prop.file\"\n [key]=\"prop.key\"\n [type]=\"prop.type\"\n [value]=\"prop.value\"\n [complex]=\"prop.complex\"\n [isEdit]=\"prop.isEdit\"\n [jsonSchema]=\"prop.jsonSchema\"\n ></c8y-asset-properties-item>\n <div *ngIf=\"prop.key === 'c8y_Position'\">\n <c8y-asset-location\n [locationMO]=\"asset\"\n [isEdit]=\"prop.isEdit\"\n [form]=\"assetProps.form\"\n ></c8y-asset-location>\n </div>\n </div>\n <div\n class=\"card-footer p-t-0\"\n *ngIf=\"prop.isEdit\"\n >\n <button\n class=\"btn btn-default btn-sm\"\n title=\"{{ 'Cancel' | translate }}\"\n type=\"button\"\n (click)=\"toggleEdit(prop)\"\n >\n {{ 'Cancel' | translate }}\n </button>\n <button\n class=\"btn btn-primary btn-sm\"\n title=\"{{ 'Save' | translate }}\"\n type=\"button\"\n [disabled]=\"!assetProps?.form?.valid || !assetProps?.form?.dirty \"\n (click)=\"save(assetProps.form.value, prop)\"\n >\n {{ 'Save' | translate }}\n </button>\n </div>\n </div>\n </ng-container>\n </div>\n</ng-container>\n" }] }], ctorParameters: () => [{ type: i1.AssetTypesRealtimeService }, { type: i2.InventoryService }, { type: i2.InventoryBinaryService }, { type: i1.AlertService }], propDecorators: { asset: [{ type: Input }], assetChange: [{ type: Output }], properties: [{ type: Input }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXNzZXQtcHJvcGVydGllcy5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zdWItYXNzZXRzL2Fzc2V0LXByb3BlcnRpZXMuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vc3ViLWFzc2V0cy9hc3NldC1wcm9wZXJ0aWVzLmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxTQUFTLEVBQUUsWUFBWSxFQUFFLEtBQUssRUFBYSxNQUFNLEVBQWlCLE1BQU0sZUFBZSxDQUFDO0FBQ2pHLE9BQU8sRUFHTCxzQkFBc0IsRUFDdEIsZ0JBQWdCLEVBQ2pCLE1BQU0sYUFBYSxDQUFDO0FBQ3JCLE9BQU8sRUFBRSxZQUFZLEVBQUUseUJBQXlCLEVBQUUsT0FBTyxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFHdkYsT0FBTyxFQUFFLE1BQU0sRUFBRSxPQUFPLEVBQUUsU0FBUyxFQUFFLElBQUksRUFBRSxNQUFNLFdBQVcsQ0FBQztBQUM3RCxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0sTUFBTSxDQUFDOzs7Ozs7OztBQU10QyxNQUFNLE9BQU8sd0JBQXdCO0lBWW5DLFlBQ1UsVUFBcUMsRUFDckMsU0FBMkIsRUFDM0IsZUFBdUMsRUFDdkMsS0FBbUI7UUFIbkIsZUFBVSxHQUFWLFVBQVUsQ0FBMkI7UUFDckMsY0FBUyxHQUFULFNBQVMsQ0FBa0I7UUFDM0Isb0JBQWUsR0FBZixlQUFlLENBQXdCO1FBQ3ZDLFVBQUssR0FBTCxLQUFLLENBQWM7UUFkbkIsZ0JBQVcsR0FBRyxJQUFJLFlBQVksRUFBa0IsQ0FBQztRQUczRCxlQUFVLEdBQXFCLEVBQUUsQ0FBQztRQUdsQyxxQkFBZ0IsR0FBMEIsRUFBRSxDQUFDO1FBQzdDLFdBQU0sR0FBRyxLQUFLLENBQUM7UUFDZixjQUFTLEdBQUcsS0FBSyxDQUFDO0lBT2YsQ0FBQztJQUVKLFdBQVcsQ0FBQyxPQUFzQjtRQUNoQyxJQUFJLE9BQU8sQ0FB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T0FBTztRQUNULENBQUM7UUFDRCxNQUFNLGlCQUFpQixHQUFHLENBQUMsQ0FBQyxJQUFJLEVBQUUsT0FBTyxFQUFFLE1BQU0sQ0FBQztRQUNsRCxJQUFJLGlCQUFpQixFQUFFLENBQUM7WUFDdEIsTUFBTSxlQUFlLEdBQUcsSUFBSSxDQUFDLFVBQVUsRUFBRSxVQUFVLEVBQUUsQ0FBQyxFQUFFLENBQUMsY0FBYyxDQUFDLEdBQUcsQ0FBZ0IsQ0FBQztZQUM1RixlQUFlLENBQUMsUUFBUSxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxHQUFHLEVBQUUsRUFBRSxFQUFFLENBQUMsR0FBRyxDQUFDLENBQUM7UUFDaEUsQ0FBQzthQUFNLENBQUM7WUFDTixJQUFJLENBQUMsVUFBVSxDQUFDLFFBQVEsR0FBRyxDQUFDLEVBQUUsQ0FBQyxjQUFjLENBQUMsR0FBRyxDQUFDLENBQUM7UUFDckQsQ0FBQztJQUNILENBQUM7K0dBek9VLHdCQUF3QjttR0FBeEIsd0JBQXdCLGdMQ2pCckMsKzNGQStGQTs7NEZEOUVhLHdCQUF3QjtrQkFKcEMsU0FBUzsrQkFDRSxzQkFBc0I7NkxBSXZCLEtBQUs7c0JBQWIsS0FBSztnQkFDSSxXQUFXO3NCQUFwQixNQUFNO2dCQUdQLFVBQVU7c0JBRFQsS0FBSyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENvbXBvbmVudCwgRXZlbnRFbWl0dGVyLCBJbnB1dCwgT25DaGFuZ2VzLCBPdXRwdXQsIFNpbXBsZUNoYW5nZXMgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7XG4gIElNYW5hZ2VkT2JqZWN0LFxuICBJTWFuYWdlZE9iamVjdEJpbmFyeSxcbiAgSW52ZW50b3J5QmluYXJ5U2VydmljZSxcbiAgSW52ZW50b3J5U2VydmljZVxufSBmcm9tICdAYzh5L2NsaWVudCc7XG5pbXBvcnQgeyBBbGVydFNlcnZpY2UsIEFzc2V0VHlwZXNSZWFsdGltZVNlcnZpY2UsIGdldHRleHQgfSBmcm9tICdAYzh5L25neC1jb21wb25lbnRzJztcbmltcG9ydCB7IEFzc2V0UHJvcGVydGllc0l0ZW0gfSBmcm9tICcuL2Fzc2V0LXByb3BlcnRpZXMubW9kZWwnO1xuaW1wb3J0IHsgSlNPTlNjaGVtYTcgfSBmcm9tICdqc29uLXNjaGVtYSc7XG5pbXBvcnQgeyBzb3J0QnksIHRvUGFpcnMsIGZyb21QYWlycywgZmluZCB9IGZyb20gJ2xvZGFzaC1lcyc7XG5pbXBvcnQgeyBmaXJzdFZhbHVlRnJvbSB9IGZyb20gJ3J4anMnO1xuXG5AQ29tcG9uZW50KHtcbiAgc2VsZWN0b3I6ICdjOHktYXNzZXQtcHJvcGVydGllcycsXG4gIHRlbXBsYXRlVXJsOiAnLi9hc3NldC1wcm9wZXJ0aWVzLmNvbXBvbmVudC5odG1sJ1xufSlcbmV4cG9ydCBjbGFzcyBBc3NldFByb3BlcnRpZXNDb21wb25lbnQgaW1wbGVtZW50cyBPbkNoYW5nZXMge1xuICBASW5wdXQoKSBhc3NldDogSU1hbmFnZWRPYmplY3Q7XG4gIEBPdXRwdXQoKSBhc3NldENoYW5nZSA9IG5ldyBFdmVudEVtaXR0ZXI8SU1hbmFnZWRPYmplY3Q+KCk7XG5cbiAgQElucHV0KClcbiAgcHJvcGVydGllczogSU1hbmFnZWRPYmplY3RbXSA9IFtdO1xuXG4gIGFzc2V0VHlwZTogSU1hbmFnZWRPYmplY3Q7XG4gIGN1c3RvbVByb3BlcnRpZXM6IEFzc2V0UHJvcGVydGllc0l0ZW1bXSA9IFtdO1xuICBpc0VkaXQgPSBmYWxzZTtcbiAgaXNMb2FkaW5nID0gZmFsc2U7XG5cbiAgY29uc3RydWN0b3IoXG4gICAgcHJpdmF0ZSBhc3NldFR5cGVzOiBBc3NldFR5cGVzUmVhbHRpbWVTZXJ2aWNlLFxuICAgIHByaXZhdGUgaW52ZW50b3J5OiBJbnZlbnRvcnlTZXJ2aWNlLFxuICAgIHByaXZhdGUgaW52ZW50b3J5QmluYXJ5OiBJbnZlbnRvcnlCaW5hcnlTZXJ2aWNlLFxuICAgIHByaXZhdGUgYWxlcnQ6IEFsZXJ0U2VydmljZVxuICApIHt9XG5cbiAgbmdPbkNoYW5nZXMoY2hhbmdlczogU2ltcGxlQ2hhbmdlcyk6IHZvaWQge1xuICAgIGlmIChjaGFuZ2VzLmFzc2V0KSB7XG4gICAgICAvLyBCYWNrIGJ1dHRvbiBoYW5kbGluZywgYXMgY29tcG9uZW50IGlzIG5vdCBkZXN0cm95ZWRcbiAgICAgIHRoaXMuYXNzZXRUeXBlID0gdW5kZWZpbmVkO1xuICAgICAgdGhpcy5jdXN0b21Qcm9wZXJ0aWVzID0gW107XG4gICAgICB0aGlzLmxvYWRBc3NldCgpO1xuICAgIH1cbiAgfVxuXG4gIGFzeW5jIGxvYWRBc3NldCgpIHtcbiAgICB0aGlzLmlzTG9hZGluZyA9IHRydWU7XG4gICAgY29uc3QgYXNzZXRUeXBlJCA9IHRoaXMuYXNzZXRUeXBlcy5nZXRBc3NldFR5cGVCeU5hbWUkKHRoaXMuYXNzZXQudHlwZSk7XG4gICAgdGhpcy5hc3NldFR5cGUgPSBhd2FpdCBmaXJzdFZhbHVlRnJvbShhc3NldFR5cGUkKTtcbiAgICB0cnkge1xuICAgICAgdGhpcy5wcm9wZXJ0aWVzID0gdGhpcy5rZWVwT3JkZXIoXG4gICAgICAgIHRoaXMuYXNzZXRUeXBlPy5jOHlfSXNBc3NldFR5cGU/LnByb3BlcnRpZXMsXG4gICAgICAgIHRoaXMucHJvcGVydGllc1xuICAgICAgKTtcbiAgICB9IGNhdGNoIChleCkge1xuICAgICAgY29uc29sZS53YXJuKGV4KTtcbiAgICB9XG4gICAgdGhpcy5jdXN0b21Qcm9wZXJ0aWVzID0gYXdhaXQgdGhpcy5yZXNvbHZlQ3VzdG9tUHJvcGVydGllcyh0aGlzLnByb3BlcnRpZXMpO1xuICAgIHRoaXMuaXNMb2FkaW5nID0gZmFsc2U7XG4gIH1cblxuICBhc3luYyByZXNvbHZlQ3VzdG9tUHJvcGVydGllcyhtYW5hZ2VkT2JqZWN0czogSU1hbmFnZWRPYmplY3RbXSkge1xuICAgIGNvbnN0IHByb3BlcnRpZXMgPSBbXTtcbiAgICBmb3IgKGNvbnN0IG1vIG9mIG1hbmFnZWRPYmplY3RzKSB7XG4gICAgICBpZiAobW8uYzh5X0pzb25TY2hlbWEpIHtcbiAgICAgICAgY29uc3QgW2l0ZW1dID0gYXdhaXQgdGhpcy5wYXJzZUl0ZW0obW8sIG1vLmM4eV9Kc29uU2NoZW1hLnByb3BlcnRpZXMsIHRoaXMuYXNzZXQpO1xuICAgICAgICB0aGlzLnNldEl0ZW1SZXF1aXJlZChpdGVtLCBtbyk7XG4gICAgICAgIHByb3BlcnRpZXMucHVzaChpdGVtKTtcbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIHByb3BlcnRpZXM7XG4gIH1cblxuICBkZWxldGVUaXRsZUZyb21NT0pzb25TY2hlbWEobW86IElNYW5hZ2VkT2JqZWN0KSB7XG4gICAgY29uc3Qgc2NoZW1hUHJvcGVydGllcyA9IG1vPy5jOHlfSnNvblNjaGVtYT8ucHJvcGVydGllcztcbiAgICBjb25zdCBwcm9wZXJ0eSA9IE9iamVjdC5rZXlzKHNjaGVtYVByb3BlcnRpZXMgfHwge30pWzBdO1xuICAgIGRlbGV0ZSAobW8/LmM4eV9Kc29uU2NoZW1hPy5wcm9wZXJ0aWVzW3Byb3BlcnR5XSB8fCB7fSkudGl0bGU7XG4gIH1cblxuICAvKipcbiAgICogVGhpcyBtZXRob2QgaXMgdXNlZCB0byBvcmRlciB0aGUgY29tcGxleCBwcm9wZXJ0aWVzIGluIHRoZSBvcmRlciBzcGVjaWZpZWQgYnkgdGhlIHVzZXIgaW4gYXNzZXQgcHJvcGVydGllcyBzY3JlZW4uXG4gICAqIEBwYXJhbSBtbyAtIE1hbmFnZWQgb2JqZWN0IG9mIHRoZSBjb21wbGV4IHByb3BlcnR5IGFzc29jaWF0ZWQgd2l0aCB0aGUgYXNzZXQuXG4gICAqL1xuICBvcmRlckNvbXBsZXhQcm9wZXJ0aWVzKG1vOiBJTWFuYWdlZE9iamVjdCkge1xuICAgIGNvbnN0IGNvbXBsZXhQcm9wZXJ0aWVzID0gbW8uYzh5X0pzb25TY2hlbWEucHJvcGVydGllc1ttby5uYW1lXT8uWydwcm9wZXJ0aWVzJ107XG4gICAgY29uc3Qga2V5VmFsdWVzQXJyYXkgPSB0b1BhaXJzKGNvbXBsZXhQcm9wZXJ0aWVzKTtcbiAgICBjb25zdCBvcmRlcmVkUHJvcGVydGllcyA9IHNvcnRCeShrZXlWYWx1ZXNBcnJheSwgKFssIHZhbHVlXSkgPT4gdmFsdWUub3JkZXIpO1xuICAgIG1vLmM4eV9Kc29uU2NoZW1hLnByb3BlcnRpZXNbbW8ubmFtZV1bJ3Byb3BlcnRpZXMnXSA9IGZyb21QYWlycyhvcmRlcmVkUHJvcGVydGllcyk7XG4gIH1cblxuICBhc3luYyBwYXJzZUl0ZW0obW86IElNYW5hZ2VkT2JqZWN0LCBwcm9wZXJ0aWVzLCBhc3NldCk6IFByb21pc2U8QXNzZXRQcm9wZXJ0aWVzSXRlbVtdPiB7XG4gICAgaWYgKCFhc3NldCkge1xuICAgICAgcmV0dXJuIFtdO1xuICAgIH1cbiAgICBjb25zdCBrZXlzID0gT2JqZWN0LmtleXMocHJvcGVydGllcyk7XG4gICAgY29uc3QgaXRlbXM6IEFzc2V0UHJvcGVydGllc0l0ZW1bXSA9IFtdO1xuXG4gICAgZm9yIChjb25zdCBrZXkgb2Yga2V5cykge1xuICAgICAgY29uc3QgdHlwZSA9IHByb3BlcnRpZXNba2V5XS50eXBlO1xuICAgICAgY29uc3QgdGl0bGUgPSBwcm9wZXJ0aWVzW2tleV0udGl0bGU7XG4gICAgICBsZXQgdmFsdWUgPSB0aGlzLmdldFR5cGVWYWx1ZSh0eXBlLCBhc3NldFtrZXldKTtcbiAgICAgIGxldCBmaWxlO1xuICAgICAgaWYgKHR5cGUgPT09ICdmaWxlJyAmJiB2YWx1ZSkge1xuICAgICAgICBjb25zdCBmaWxlSWQgPSB0eXBlb2YgdmFsdWUgPT09ICdvYmplY3QnID8gdmFsdWVbMF0/LmZpbGU/LmlkIDogdmFsdWU7XG4gICAgICAgIGNvbnN0IGZpbGVEYXRhID0gYXdhaXQgdGhpcy5nZXRGaWxlTWFuYWdlZE9iamVjdChmaWxlSWQpO1xuICAgICAgICBmaWxlID0gZmlsZURhdGE7XG4gICAgICAgIHZhbHVlID0gW2ZpbGVEYXRhXTtcbiAgICAgIH0gZWxzZSBpZiAodHlwZSA9PT0gJ2RhdGUnKSB7XG4gICAgICAgIGNvbnN0IHZhbHVlRGF0ZSA9IG5ldyBEYXRlKHZhbHVlKTtcbiAgICAgICAgdmFsdWUgPSAhaXNOYU4odmFsdWVEYXRlLmdldFRpbWUoKSkgPyB2YWx1ZURhdGUgOiAnJztcbiAgICAgIH1cbiAgICAgIGlmICh0eXBlID09PSAnb2JqZWN0Jykge1xuICAgICAgICAvLyByZW1vdmUgdGl0bGUgdG8gYXZvaWQgZXhjZXNzaXZlIHByb3BlcnR5IG5hbWUgb24gYXNzZXQgY29tcGxleCBwcm9wZXJ0aWVzIGZvcm1cbiAgICAgICAgdGhpcy5kZWxldGVUaXRsZUZyb21NT0pzb25TY2hlbWEobW8pO1xuICAgICAgICB0aGlzLm9yZGVyQ29tcGxleFByb3BlcnRpZXMobW8pO1xuICAgICAgICBpZiAoIXZhbHVlKSB7XG4gICAgICAgICAgdmFsdWUgPSB7fTtcbiAgICAgICAgICBmb3IgKGNvbnN0IHByb3AgaW4gcHJvcGVydGllc1trZXldLnByb3BlcnRpZXMpIHtcbiAgICAgICAgICAgIHZhbHVlW3Byb3BdID0gdGhpcy5nZXRUeXBlVmFsdWUocHJvcGVydGllc1trZXldLnByb3BlcnRpZXNbcHJvcF0udHlwZSwgbnVsbCk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG4gICAgICBpdGVtcy5wdXNoKHtcbiAgICAgICAga2V5LFxuICAgICAgICB2YWx1ZSxcbiAgICAgICAgbGFiZWw6IHRpdGxlIHx8IG1vLmxhYmVsLFxuICAgICAgICB0eXBlLFxuICAgICAgICBkZXNjcmlwdGlvbjogbW8uZGVzY3JpcHRpb24sXG4gICAgICAgIGZpbGUsXG4gICAgICAgIGNvbXBsZXg6XG4gICAgICAgICAgdHlwZSA9PT0gJ29iamVjdCdcbiAgICAgICAgICAgID8gYXdhaXQgdGhpcy5wYXJzZUl0ZW0obW8sIHByb3BlcnRpZXNba2V5XS5wcm9wZXJ0aWVzLCB2YWx1ZSlcbiAgICAgICAgICAgIDogdW5kZWZpbmVkLFxuICAgICAgICBpc0VkaXQ6IGZhbHNlLFxuICAgICAgICBqc29uU2NoZW1hOiBtby5jOHlfSnNvblNjaGVtYVxuICAgICAgfSk7XG4gICAgfVxuICAgIHJldHVybiBpdGVtcztcbiAgfVxuXG4gIHRvZ2dsZUVkaXQocHJvcDogQXNzZXRQcm9wZXJ0aWVzSXRlbSkge1xuICAgIHByb3AuaXNFZGl0ID0gIXByb3AuaXNFZGl0O1xuICB9XG5cbiAgYXN5bmMgZ2V0RmlsZU1hbmFnZWRPYmplY3QoaWQ6IHN0cmluZykge1xuICAgIHRyeSB7XG4gICAgICBjb25zdCB7IGRhdGEgfSA9IGF3YWl0IHRoaXMuaW52ZW50b3J5LmRldGFpbChpZCk7XG4gICAgICByZXR1cm4gZGF0YTtcbiAgICB9IGNhdGNoIChleCkge1xuICAgICAgdGhpcy5hbGVydC5hZGRTZXJ2ZXJGYWlsdXJlKGV4KTtcbiAgICB9XG4gIH1cblxuICBhc3luYyBzYXZlKHByb3BlcnR5VmFsdWUsIHByb3A6IEFzc2V0UHJvcGVydGllc0l0ZW0pOiBQcm9taXNlPHZvaWQ+IHtcbiAgICB0cnkge1xuICAgICAgaWYgKHByb3AudHlwZSA9PT0gJ29iamVjdCcpIHtcbiAgICAgICAgdGhpcy51cGRhdGVVbmRlZmluZWRUb1Byb3BUeXBlVmFsdWUocHJvcCwgcHJvcGVydHlWYWx1ZVtwcm9wLmtleV0pO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdGhpcy51cGRhdGVVbmRlZmluZWRUb1Byb3BUeXBlVmFsdWUocHJvcCwgcHJvcGVydHlWYWx1ZSk7XG4gICAgICB9XG5cbiAgICAgIHByb3BlcnR5VmFsdWUgPSBhd2FpdCB0aGlzLnVwbG9hZEZpbGVzKHByb3BlcnR5VmFsdWUsIHByb3AudmFsdWUpO1xuXG4gICAgICAvLyBBdm9pZCBtYWtpbmcgYSBQVVQgcmVxdWVzdCBjb250YWluaW5nIGp1c3QgdGhlIGlkLCBhcyByZXNwb25zZSBib2R5IG1pZ2h0IGJlIGluY29tcGxldGVcbiAgICAgIGNvbnN0IGhhc1ZhbHVlcyA9IE9iamVjdC52YWx1ZXMocHJvcGVydHlWYWx1ZSkuc29tZSh2YWx1ZSA9PiB2YWx1ZSAhPT0gdW5kZWZpbmVkKTtcbiAgICAgIGlmICghaGFzVmFsdWVzKSB7XG4gICAgICAgIHRoaXMudG9nZ2xlRWRpdChwcm9wKTtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuICAgICAgY29uc3QgdXBkYXRlZEFzc2V0ID0geyBpZDogdGhpcy5hc3NldC5pZCwgLi4ucHJvcGVydHlWYWx1ZSB9O1xuICAgICAgY29uc3QgeyBkYXRhIH0gPSBhd2FpdCB0aGlzLmludmVudG9yeS51cGRhdGUodXBkYXRlZEFzc2V0KTtcbiAgICAgIHRoaXMudG9nZ2xlRWRpdChwcm9wKTtcbiAgICAgIHRoaXMuYXNzZXQgPSBkYXRhO1xuICAgICAgdGhpcy5hc3NldENoYW5nZS5lbWl0KHRoaXMuYXNzZXQpO1xuICAgICAgYXdhaXQgdGhpcy5sb2FkQXNzZXQoKTtcbiAgICAgIHRoaXMuYWxlcnQuc3VjY2VzcyhnZXR0ZXh0KCdBc3NldCBwcm9wZXJ0aWVzIHVwZGF0ZWQuJykpO1xuICAgIH0gY2F0Y2ggKGV4KSB7XG4gICAgICB0aGlzLmFsZXJ0LmFkZFNlcnZlckZhaWx1cmUoZXgpO1xuICAgICAgdGhpcy50b2dnbGVFZGl0KHByb3ApO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgdXBkYXRlVW5kZWZpbmVkVG9Qcm9wVHlwZVZhbHVlKHByb3AsIHByb3BlcnR5VmFsdWUpIHtcbiAgICBmb3IgKGNvbnN0IFtrZXksIHZhbHVlXSBvZiBPYmplY3QuZW50cmllcyhwcm9wZXJ0eVZhbHVlKSkge1xuICAgICAgY29uc3QgcHJvcGVydHkgPSBwcm9wLmNvbXBsZXggPyBmaW5kKHByb3AuY29tcGxleCwgeyBrZXk6IGtleSB9KSA6IHByb3A7XG4gICAgICBwcm9wZXJ0eVZhbHVlW2tleV0gPSB0aGlzLmdldFR5cGVWYWx1ZShwcm9wZXJ0eS50eXBlLCB2YWx1ZSk7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBnZXRUeXBlVmFsdWUocHJvcFR5cGU6IHN0cmluZywgdmFsdWUpIHtcbiAgICBpZiAodmFsdWUgfHwgKHByb3BUeXBlID09PSAnYm9vbGVhbicgJiYgdmFsdWUgIT09IHVuZGVmaW5lZCkpIHJldHVybiB2YWx1ZTtcblxuICAgIHN3aXRjaCAocHJvcFR5cGUpIHtcbiAgICAgIGNhc2UgJ251bWJlcic6XG4gICAgICBjYXNlICdib29sZWFuJzpcbiAgICAgICAgcmV0dXJuIHZhbHVlIHx8IHZhbHVlID09PSAwID8gdmFsdWUgOiBudWxsO1xuXG4gICAgICBkZWZhdWx0OlxuICAgICAgICByZXR1cm4gJyc7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBrZWVwT3JkZXIoY29ycmVjdE9yZGVyZWRJZHMsIHByb3BlcnRpZXMpIHtcbiAgICBjb25zdCBvcmRlcmVkUHJvcGVydGllcyA9IGNvcnJlY3RPcmRlcmVkSWRzLm1hcCgoeyBpZCB9KSA9PiB7XG4gICAgICBjb25zdCBmb3VuZFByb3BlcnR5ID0gcHJvcGVydGllcy5maW5kKHByb3BlcnR5ID0+IHByb3BlcnR5LmlkID09PSBpZCk7XG4gICAgICBpZiAoIWZvdW5kUHJvcGVydHkpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdDdXN0b20gcHJvcGVydHkgbWlzbWF0Y2gnKTtcbiAgICAgIH1cbiAgICAgIHJldHVybiBmb3VuZFByb3BlcnR5O1xuICAgIH0pO1xuICAgIHJldHVybiBvcmRlcmVkUHJvcGVydGllcztcbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgdXBsb2FkRmlsZXMobW9kZWw6IG9iamVjdCwgbW9JZD86IElNYW5hZ2VkT2JqZWN0QmluYXJ5W10pOiBQcm9taXNlPG9iamVjdD4ge1xuICAgIGNvbnN0IGtleXMgPSBPYmplY3Qua2V5cyhtb2RlbCk7XG4gICAgZm9yIChjb25zdCBrZXkgb2Yga2V5cykge1xuICAgICAgaWYgKEFycmF5LmlzQXJyYXkobW9kZWxba2V5XSkgJiYgbW9kZWxba2V5XVswXT8uZmlsZSBpbnN0YW5jZW9mIEZpbGUpIHtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICBjb25zdCB1cGxvYWQgPSBhd2FpdCB0aGlzLmludmVudG9yeUJpbmFyeS5jcmVhdGUobW9kZWxba2V5XVswXS5maWxlKTtcbiAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgaWYgKG1vSWQgJiYgbW9JZFswXSkge1xuICAgICAgICAgICAgICBhd2FpdCB0aGlzLmludmVudG9yeS5jaGlsZEFkZGl0aW9uc1JlbW92ZShtb0lkWzBdLCB0aGlzLmFzc2V0LmlkKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9IGNhdGNoIChleCkge1xuICAgICAgICAgICAgdGhyb3cgZXg7XG4gICAgICAgICAgfVxuICAgICAgICAgIG1vZGVsW2tleV0gPSB1cGxvYWQuZGF0YS5pZDtcbiAgICAgICAgICBhd2FpdCB0aGlzLmludmVudG9yeS5jaGlsZEFkZGl0aW9uc0FkZCh1cGxvYWQuZGF0YS5pZCwgdGhpcy5hc3NldC5pZCk7XG4gICAgICAgIH0gY2F0Y2ggKGV4KSB7XG4gICAgICAgICAgdGhyb3cgZXg7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIG1vZGVsO1xuICB9XG5cbiAgcHJpdmF0ZSBzZXRJdGVtUmVxdWlyZWQoaXRlbTogQXNzZXRQcm9wZXJ0aWVzSXRlbSwgbW86IElNYW5hZ2VkT2JqZWN0KTogdm9pZCB7XG4gICAgY29uc3QgaXNBc3NldFByb3BlcnR5UmVxdWlyZWQgPSAhIXRoaXMuYXNzZXRUeXBlPy5jOHlfSXNBc3NldFR5cGU/LnByb3BlcnRpZXMuZmluZChcbiAgICAgIHAgPT4gcC5pZCA9PT0gbW8uaWRcbiAgICApPy5pc1JlcXVpcmVkO1xuICAgIGlmICghaXNBc3NldFByb3BlcnR5UmVxdWlyZWQpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgY29uc3QgaXNDb21wbGV4UHJvcGVydHkgPSAhIWl0ZW0/LmNvbXBsZXg/Lmxlbmd0aDtcbiAgICBpZiAoaXNDb21wbGV4UHJvcGVydHkpIHtcbiAgICAgIGNvbnN0IGNvbXBsZXhQcm9wZXJ0eSA9IGl0ZW0uanNvblNjaGVtYT8ucHJvcGVydGllcz8uW21vLmM4eV9Kc29uU2NoZW1hLmtleV0gYXMgSlNPTlNjaGVtYTc7XG4gICAgICBjb21wbGV4UHJvcGVydHkucmVxdWlyZWQgPSBpdGVtLmNvbXBsZXgubWFwKCh7IGtleSB9KSA9PiBrZXkpO1xuICAgIH0gZWxzZSB7XG4gICAgICBpdGVtLmpzb25TY2hlbWEucmVxdWlyZWQgPSBbbW8uYzh5X0pzb25TY2hlbWEua2V5XTtcbiAgICB9XG4gIH1cbn1cbiIsIjxuZy1jb250YWluZXI+XG4gIDxkaXYgY2xhc3M9XCJjYXJkLWhlYWRlciBiZy1pbmhlcml0IHNlcGFyYXRvciBzdGlja3ktdG9wXCI+XG4gICAgPGgxXG4gICAgICBjbGFzcz1cImNhcmQtdGl0bGUgcC10LTQgcC1iLTRcIlxuICAgICAgbmdOb25CaW5kYWJsZVxuICAgICAgdHJhbnNsYXRlXG4gICAgICBbdHJhbnNsYXRlUGFyYW1zXT1cInsgbGFiZWw6IGFzc2V0VHlwZT8ubGFiZWwgfHwgJycgfCB0cmFuc2xhdGUgfVwiXG4gICAgPlxuICAgICAge3sgbGFiZWwgfX0gcHJvcGVydGllc1xuICAgIDwvaDE+XG4gIDwvZGl2PlxuICA8ZGl2IGNsYXNzPVwiY2FyZC1ibG9ja1wiPlxuICAgIDxkaXZcbiAgICAgIGNsYXNzPVwidGV4dC1jZW50ZXJcIlxuICAgICAgKm5nSWY9XCJpc0xvYWRpbmdcIlxuICAgID5cbiAgICAgIDxjOHktbG9hZGluZz48L2M4eS1sb2FkaW5nPlxuICAgIDwvZGl2PlxuXG4gICAgPG5nLWNvbnRhaW5lciAqbmdJZj1cIiFpc0xvYWRpbmdcIj5cbiAgICAgIDxkaXZcbiAgICAgICAgY2xhc3M9XCJjYXJkIG0tYi04XCJcbiAgICAgICAgdGl0bGU9XCJ7eyBwcm9wLmRlc2NyaXB0aW9uIHwgdHJhbnNsYXRlIH19XCJcbiAgICAgICAgKm5nRm9yPVwibGV0IHByb3Agb2YgY3VzdG9tUHJvcGVydGllc1wiXG4gICAgICAgIFtuZ0NsYXNzXT1cInsgJ2NhcmQtaGlnaGxpZ2h0JzogcHJvcC5pc0VkaXQgfVwiXG4gICAgICA+XG4gICAgICAgIDxkaXZcbiAgICAgICAgICBjbGFzcz1cImNhcmQtYmxvY2tcIlxuICAgICAgICAgIFtuZ0NsYXNzXT1cInsgJ3AtYi0wJzogcHJvcC5pc0VkaXQgfVwiXG4gICAgICAgID5cbiAgICAgICAgICA8ZGl2XG4gICAgICAgICAgICBjbGFzcz1cImQtZmxleCBwLWItOCBhLWktY2VudGVyXCJcbiAgICAgICAgICAgICpuZ0lmPVwiIXByb3AuaXNFZGl0XCJcbiAgICAgICAgICA+XG4gICAgICAgICAgICA8cFxuICAgICAgICAgICAgICBjbGFzcz1cInRleHQtbWVkaXVtIHRleHQtdHJ1bmNhdGVcIlxuICAgICAgICAgICAgICB0aXRsZT1cInt7IHByb3A/LmxhYmVsIHwgdHJhbnNsYXRlIH19XCJcbiAgICAgICAgICAgID5cbiAgICAgICAgICAgICAge3sgcHJvcD8ubGFiZWwgfCB0cmFuc2xhdGUgfX1cbiAgICAgICAgICAgIDwvcD5cbiAgICAgICAgICAgIDxidXR0b25cbiAgICAgICAgICAgICAgY2xhc3M9XCJidG4gYnRuLWRvdCBtLWwtYXV0byB0ZXh0LTEyXCJcbiAgICAgICAgICAgICAgW2F0dHIuYXJpYS1sYWJlbF09XCInRWRpdCcgfCB0cmFuc2xhdGVcIlxuICAgICAgICAgICAgICB0b29sdGlwPVwie3sgJ0VkaXQnIHwgdHJhbnNsYXRlIH19XCJcbiAgICAgICAgICAgICAgdHlwZT1cImJ1dHRvblwiXG4gICAgICAgICAgICAgIFtkZWxheV09XCI1MDBcIlxuICAgICAgICAgICAgICAoY2xpY2spPVwidG9nZ2xlRWRpdChwcm9wKVwiXG4gICAgICAgICAgICA+XG4gICAgICAgICAgICAgIDxpIGM4eUljb249XCJwZW5jaWxcIj48L2k+XG4gICAgICAgICAgICA8L2J1dHRvbj5cbiAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICA8Yzh5LWFzc2V0LXByb3BlcnRpZXMtaXRlbVxuICAgICAgICAgICAgI2Fzc2V0UHJvcHNcbiAgICAgICAgICAgIFtmaWxlXT1cInByb3AuZmlsZVwiXG4gICAgICAgICAgICBba2V5XT1cInByb3Aua2V5XCJcbiAgICAgICAgICAgIFt0eXBlXT1cInByb3AudHlwZVwiXG4gICAgICAgICAgICBbdmFsdWVdPVwicHJvcC52YWx1ZVwiXG4gICAgICAgICAgICBbY29tcGxleF09XCJwcm9wLmNvbXBsZXhcIlxuICAgICAgICAgICAgW2lzRWRpdF09XCJwcm9wLmlzRWRpdFwiXG4gICAgICAgICAgICBbanNvblNjaGVtYV09XCJwcm9wLmpzb25TY2hlbWFcIlxuICAgICAgICAgID48L2M4eS1hc3NldC1wcm9wZXJ0aWVzLWl0ZW0+XG4gICAgICAgICAgPGRpdiAqbmdJZj1cInByb3Aua2V5ID09PSAnYzh5X1Bvc2l0aW9uJ1wiPlxuICAgICAgICAgICAgPGM4eS1hc3NldC1sb2NhdGlvblxuICAgICAgICAgICAgICBbbG9jYXRpb25NT109XCJhc3NldFwiXG4gICAgICAgICAgICAgIFtpc0VkaXRdPVwicHJvcC5pc0VkaXRcIlxuICAgICAgICAgICAgICBbZm9ybV09XCJhc3NldFByb3BzLmZvcm1cIlxuICAgICAgICAgICAgPjwvYzh5LWFzc2V0LWxvY2F0aW9uPlxuICAgICAgICAgIDwvZGl2PlxuICAgICAgICA8L2Rpdj5cbiAgICAgICAgPGRpdlxuICAgICAgICAgIGNsYXNzPVwiY2FyZC1mb290ZXIgcC10LTBcIlxuICAgICAgICAgICpuZ0lmPVwicHJvcC5pc0VkaXRcIlxuICAgICAgICA+XG4gICAgICAgICAgPGJ1dHRvblxuICAgICAgICAgICAgY2xhc3M9XCJidG4gYnRuLWRlZmF1bHQgYnRuLXNtXCJcbiAgICAgICAgICAgIHRpdGxlPVwie3sgJ0NhbmNlbCcgfCB0cmFuc2xhdGUgfX1cIlxuICAgICAgICAgICAgdHlwZT1cImJ1dHRvblwiXG4gICAgICAgICAgICAoY2xpY2spPVwidG9nZ2xlRWRpdChwcm9wKVwiXG4gICAgICAgICAgPlxuICAgICAgICAgICAge3sgJ0NhbmNlbCcgfCB0cmFuc2xhdGUgfX1cbiAgICAgICAgICA8L2J1dHRvbj5cbiAgICAgICAgICA8YnV0dG9uXG4gICAgICAgICAgICBjbGFzcz1cImJ0biBidG4tcHJpbWFyeSBidG4tc21cIlxuICAgICAgICAgICAgdGl0bGU9XCJ7eyAnU2F2ZScgfCB0cmFuc2xhdGUgfX1cIlxuICAgICAgICAgICAgdHlwZT1cImJ1dHRvblwiXG4gICAgICAgICAgICBbZGlzYWJsZWRdPVwiIWFzc2V0UHJvcHM/LmZvcm0/LnZhbGlkIHx8ICFhc3NldFByb3BzPy5mb3JtPy5kaXJ0eSBcIlxuICAgICAgICAgICAgKGNsaWNrKT1cInNhdmUoYXNzZXRQcm9wcy5mb3JtLnZhbHVlLCBwcm9wKVwiXG4gICAgICAgICAgPlxuICAgICAgICAgICAge3sgJ1NhdmUnIHwgdHJhbnNsYXRlIH19XG4gICAgICAgICAgPC9idXR0b24+XG4gICAgICAgIDwvZGl2PlxuICAgICAgPC9kaXY+XG4gICAgPC9uZy1jb250YWluZXI+XG4gIDwvZGl2PlxuPC9uZy1jb250YWluZXI+XG4iXX0=