UNPKG

@c8y/ngx-components

Version:

Angular modules for Cumulocity IoT applications

203 lines 41.4 kB
import { Component, ViewChildren, QueryList, ChangeDetectorRef } from '@angular/core'; import { Router } from '@angular/router'; import { OpcuaService } from './opcuaService'; import { AlertService, gettext } from '@c8y/ngx-components'; import { find, assign, omit, findIndex, pick, get, isNil } from 'lodash-es'; import { OpcuaDeviceProtocolMapping } from './opcua-device-protocol-mapping.component'; import * as i0 from "@angular/core"; import * as i1 from "./opcuaService"; import * as i2 from "@c8y/ngx-components"; import * as i3 from "@angular/router"; import * as i4 from "@angular/common"; import * as i5 from "@angular/forms"; import * as i6 from "./opcua-device-protocol-description.component"; import * as i7 from "./opcua-device-protocol-data-reporting.component"; import * as i8 from "./opcua-device-protocol-mapping.component"; import * as i9 from "./opcua-auto-apply-settings.component"; export class OpcuaDeviceProtocolDetailComponent { constructor(changeDetectorRef, opcuaService, alertService, router) { this.changeDetectorRef = changeDetectorRef; this.opcuaService = opcuaService; this.alertService = alertService; this.router = router; this.initialModel = { id: '', fieldbusType: 'opcuaV2', description: '', unit: '', fieldbusVersion: 4, name: '', referencedServerId: '', referencedRootNodeId: '', subscriptionType: { type: 'None' }, mappings: [], overriddenSubscriptions: [], applyConstraints: { browsePathMatchesRegex: '', matchesNodeIds: [], serverObjectHasFragment: '', matchesServerIds: [] }, enabled: '' }; this.isLoaded = true; this.getParentAttr = key => get(this.model, key); } ngAfterContentChecked() { this.changeDetectorRef.detectChanges(); } getMapping() { return this.model.mappings; } getEmptyMappingObject() { const { mappings } = this.model; return { id: mappings.length > 0 ? Math.max(...mappings.map(m => m.id)) + 1 : 0, browsePath: [] }; } getOverriddenSubscriptionsByPath(browsePath) { if (isNil(browsePath) || browsePath.length === 0) { return undefined; } return find(this.model.overriddenSubscriptions, { browsePath }); } getStructuredResource(resource) { const overriddenSubscriptions = this.getOverriddenSubscriptionsByPath(resource.browsePath); let result = assign({}, resource); if (overriddenSubscriptions) { result = assign({}, resource, { subscriptionType: overriddenSubscriptions.subscriptionType }); } return result; } async ngOnInit() { const id = this.opcuaService.getId(); if (id) { const res = await this.opcuaService.getDeviceProtocol(id); if (res && res.status !== 200) { const data = res.json ? await res.json() : undefined; this.alertService.addServerFailure({ data, res }); this.isLoaded = false; } else { const data = await res.json(); if (data && data.applyConstraints === null) { delete data.applyConstraints; } if (data && data.subscriptionType === null) { delete data.subscriptionType; } this.model = assign(this.initialModel, data); if (!this.model.mappings) { this.model.mappings = []; } this.model = assign(this.initialModel, this.updateViableMapping(data)); this.isLoaded = false; } } } updateViableMapping(model) { const { mappings } = model; let result = []; if (mappings) { result = mappings.map((item, i) => { return assign(this.getStructuredResource(item), { id: i }); }); } return assign(model, { mappings: result }); } trackById(_index, el) { return get(el, 'id'); } addVariable() { this.model.mappings.push(this.getEmptyMappingObject()); } updateVariable(mappingObject) { const { mappings } = this.model; const { id } = mappingObject; const index = findIndex(mappings, { id }); mappings[index > -1 ? index : 0] = mappingObject; } removeVariable(mappingObject) { const { mappings } = this.model; const { id } = mappingObject; let index = -1; // id typeof string || number if (!isNil(id) && (id.length > 0 || id > -1)) { index = findIndex(mappings, { id }); } if (index > -1) { mappings.splice(index, 1); } } actionHandler(actionObject) { switch (actionObject.action) { case 'save': this.updateVariable(actionObject.data); break; case 'delete': this.removeVariable(actionObject.data); break; } } extractOverridSubscriptionType(_mapping) { const overriddenSubscriptions = []; const variableMapping = []; _mapping.forEach(element => { if (element.id !== 'new') { if (element.subscriptionType) { overriddenSubscriptions.push(assign({ browsePath: element.browsePath }, { subscriptionType: element.subscriptionType })); } variableMapping.push(omit(element, ['subscriptionType'])); } }); return [variableMapping, overriddenSubscriptions]; } prepareRequestJson(_model) { let requestJson = {}; const [mappings, overriddenSubscriptions] = this.extractOverridSubscriptionType(_model.mappings); requestJson = assign(requestJson, pick(_model, Object.keys(this.initialModel)), { mappings, overriddenSubscriptions }); return requestJson; } async save() { try { const res = await this.opcuaService.updateDeviceProtocol(this.prepareRequestJson(this.model)); const data = await res.json(); if (res && res.status === 200) { this.router.navigate(['deviceprotocols']); this.alertService.success(gettext('Device protocol saved.')); } else { const { details } = data; this.alertService.addServerFailure({ res, data: details }); } } catch (ex) { this.alertService.danger(gettext('Failed to save. Try again.')); } } canSave(deviceTypeForm) { if (this.instanceList) { const activeInstances = this.instanceList.filter(item => item.isActive()); if (activeInstances.length > 0) { return true; } } return !deviceTypeForm.form.valid; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: OpcuaDeviceProtocolDetailComponent, deps: [{ token: i0.ChangeDetectorRef }, { token: i1.OpcuaService }, { token: i2.AlertService }, { token: i3.Router }], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: OpcuaDeviceProtocolDetailComponent, selector: "opcua-device-protocol-detail", viewQueries: [{ propertyName: "instanceList", predicate: OpcuaDeviceProtocolMapping, descendants: true }], ngImport: i0, template: "<c8y-title *ngIf=\"!isLoaded\">{{ model.name }}</c8y-title>\n<c8y-breadcrumb>\n <c8y-breadcrumb-item\n [icon]=\"'c8y-device-protocols'\"\n [label]=\"'Device types' | translate\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item\n [icon]=\"'c8y-device-protocols'\"\n [label]=\"'Device protocols' | translate\"\n [path]=\"'deviceprotocols'\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item [icon]=\"'c8y-device-protocols'\" [label]=\"model?.name\"></c8y-breadcrumb-item>\n</c8y-breadcrumb>\n<div class=\"row\">\n <div class=\"col-lg-12 col-lg-max\">\n <form #deviceTypeForm=\"ngForm\" name=\"detailForm\" *ngIf=\"!isLoaded\" class=\"card card--fullpage\">\n <opcua-device-protocol-description [model]=\"model\"></opcua-device-protocol-description>\n <div class=\"inner-scroll\">\n <div class=\"d-contents\">\n <div class=\"card-header separator-top-bottom bg-component sticky-top\">\n <div class=\"h4\" translate>Variables</div>\n </div>\n <div class=\"p-l-16 p-r-16\">\n <div class=\"c8y-list__group\" *ngIf=\"model.mappings.length > 0\" ngModelGroup=\"variable\">\n <opcua-device-protocol-mapping\n *ngFor=\"let resource of getMapping(); index as i; trackBy: trackById\"\n [index]=\"i\"\n [referencedServerId]=\"model.referencedServerId\"\n [referencedRootNodeId]=\"model.referencedRootNodeId\"\n [resource]=\"getStructuredResource(resource)\"\n [getParentAttr]=\"getParentAttr\"\n (onAction)=\"actionHandler($event)\"\n ></opcua-device-protocol-mapping>\n </div>\n </div>\n <div class=\"p-l-16 p-r-16 p-t-16\">\n <c8y-ui-empty-state\n *ngIf=\"model.mappings.length === 0\"\n [icon]=\"'sliders'\"\n [title]=\"'No variables to display.' | translate\"\n [subtitle]=\"'Click below to add your first variable.' | translate\"\n ></c8y-ui-empty-state>\n\n <div class=\"card-footer\">\n <button\n type=\"button\"\n title=\"{{ 'Add variable' | translate }}\"\n class=\"btn btn-default addVariableBtn\"\n (click)=\"addVariable()\"\n >\n <i c8yIcon=\"plus-circle\"></i>\n {{ 'Add variable' | translate }}\n </button>\n </div>\n </div>\n </div>\n <div class=\"d-contents\">\n <div class=\"card-header separator-top-bottom bg-component sticky-top\">\n <div class=\"h4\" translate>Data reporting</div>\n </div>\n <div class=\"p-l-16 p-r-16 p-t-16\" ngModelGroup=\"subscription\">\n <opcua-device-protocol-data-reporting\n [groupName]=\"'subscription'\"\n [model]=\"model\"\n ></opcua-device-protocol-data-reporting>\n </div>\n </div>\n <div class=\"d-contents\">\n <div class=\"card-header separator-top-bottom sticky-top\">\n <div class=\"h4\" translate>Auto apply constraints</div>\n </div>\n <div class=\"p-l-16 p-r-16 p-t-16 overflow-visible\" ngModelGroup=\"autoApply\">\n <opcua-auto-apply [model]=\"model\"></opcua-auto-apply>\n </div>\n </div>\n\n <div class=\"card-footer sticky-bottom separator\" style=\"z-index: 101\">\n <button\n title=\"{{ 'Save' | translate }}\"\n id=\"deviceTypeSave\"\n class=\"btn btn-primary\"\n (click)=\"save()\"\n [disabled]=\"canSave(deviceTypeForm)\"\n type=\"button\"\n >\n {{ 'Save' | translate }}\n </button>\n </div>\n </div>\n </form>\n </div>\n</div>\n", dependencies: [{ kind: "component", type: i2.BreadcrumbComponent, selector: "c8y-breadcrumb" }, { kind: "component", type: i2.BreadcrumbItemComponent, selector: "c8y-breadcrumb-item", inputs: ["icon", "translate", "label", "path", "injector"] }, { kind: "component", type: i2.EmptyStateComponent, selector: "c8y-ui-empty-state", inputs: ["icon", "title", "subtitle", "horizontal"] }, { kind: "directive", type: i2.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: i2.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: "component", type: i2.TitleComponent, selector: "c8y-title", inputs: ["pageTitleUpdate"] }, { kind: "directive", type: i5.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i5.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i5.NgModelGroup, selector: "[ngModelGroup]", inputs: ["ngModelGroup"], exportAs: ["ngModelGroup"] }, { kind: "directive", type: i5.NgForm, selector: "form:not([ngNoForm]):not([formGroup]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: i6.OpcuaDeviceProtocolDescription, selector: "opcua-device-protocol-description", inputs: ["model"] }, { kind: "component", type: i7.OpcuaDeviceProtocolDataReportingComponent, selector: "opcua-device-protocol-data-reporting", inputs: ["model", "groupName"], outputs: ["onSubscriptionChange"] }, { kind: "component", type: i8.OpcuaDeviceProtocolMapping, selector: "opcua-device-protocol-mapping", inputs: ["resource", "index", "getParentAttr", "referencedServerId", "referencedRootNodeId"], outputs: ["onAction"] }, { kind: "component", type: i9.OpcuaAutoApplySettingsComponent, selector: "opcua-auto-apply", inputs: ["model"] }, { kind: "pipe", type: i2.C8yTranslatePipe, name: "translate" }] }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: OpcuaDeviceProtocolDetailComponent, decorators: [{ type: Component, args: [{ selector: 'opcua-device-protocol-detail', template: "<c8y-title *ngIf=\"!isLoaded\">{{ model.name }}</c8y-title>\n<c8y-breadcrumb>\n <c8y-breadcrumb-item\n [icon]=\"'c8y-device-protocols'\"\n [label]=\"'Device types' | translate\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item\n [icon]=\"'c8y-device-protocols'\"\n [label]=\"'Device protocols' | translate\"\n [path]=\"'deviceprotocols'\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item [icon]=\"'c8y-device-protocols'\" [label]=\"model?.name\"></c8y-breadcrumb-item>\n</c8y-breadcrumb>\n<div class=\"row\">\n <div class=\"col-lg-12 col-lg-max\">\n <form #deviceTypeForm=\"ngForm\" name=\"detailForm\" *ngIf=\"!isLoaded\" class=\"card card--fullpage\">\n <opcua-device-protocol-description [model]=\"model\"></opcua-device-protocol-description>\n <div class=\"inner-scroll\">\n <div class=\"d-contents\">\n <div class=\"card-header separator-top-bottom bg-component sticky-top\">\n <div class=\"h4\" translate>Variables</div>\n </div>\n <div class=\"p-l-16 p-r-16\">\n <div class=\"c8y-list__group\" *ngIf=\"model.mappings.length > 0\" ngModelGroup=\"variable\">\n <opcua-device-protocol-mapping\n *ngFor=\"let resource of getMapping(); index as i; trackBy: trackById\"\n [index]=\"i\"\n [referencedServerId]=\"model.referencedServerId\"\n [referencedRootNodeId]=\"model.referencedRootNodeId\"\n [resource]=\"getStructuredResource(resource)\"\n [getParentAttr]=\"getParentAttr\"\n (onAction)=\"actionHandler($event)\"\n ></opcua-device-protocol-mapping>\n </div>\n </div>\n <div class=\"p-l-16 p-r-16 p-t-16\">\n <c8y-ui-empty-state\n *ngIf=\"model.mappings.length === 0\"\n [icon]=\"'sliders'\"\n [title]=\"'No variables to display.' | translate\"\n [subtitle]=\"'Click below to add your first variable.' | translate\"\n ></c8y-ui-empty-state>\n\n <div class=\"card-footer\">\n <button\n type=\"button\"\n title=\"{{ 'Add variable' | translate }}\"\n class=\"btn btn-default addVariableBtn\"\n (click)=\"addVariable()\"\n >\n <i c8yIcon=\"plus-circle\"></i>\n {{ 'Add variable' | translate }}\n </button>\n </div>\n </div>\n </div>\n <div class=\"d-contents\">\n <div class=\"card-header separator-top-bottom bg-component sticky-top\">\n <div class=\"h4\" translate>Data reporting</div>\n </div>\n <div class=\"p-l-16 p-r-16 p-t-16\" ngModelGroup=\"subscription\">\n <opcua-device-protocol-data-reporting\n [groupName]=\"'subscription'\"\n [model]=\"model\"\n ></opcua-device-protocol-data-reporting>\n </div>\n </div>\n <div class=\"d-contents\">\n <div class=\"card-header separator-top-bottom sticky-top\">\n <div class=\"h4\" translate>Auto apply constraints</div>\n </div>\n <div class=\"p-l-16 p-r-16 p-t-16 overflow-visible\" ngModelGroup=\"autoApply\">\n <opcua-auto-apply [model]=\"model\"></opcua-auto-apply>\n </div>\n </div>\n\n <div class=\"card-footer sticky-bottom separator\" style=\"z-index: 101\">\n <button\n title=\"{{ 'Save' | translate }}\"\n id=\"deviceTypeSave\"\n class=\"btn btn-primary\"\n (click)=\"save()\"\n [disabled]=\"canSave(deviceTypeForm)\"\n type=\"button\"\n >\n {{ 'Save' | translate }}\n </button>\n </div>\n </div>\n </form>\n </div>\n</div>\n" }] }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }, { type: i1.OpcuaService }, { type: i2.AlertService }, { type: i3.Router }], propDecorators: { instanceList: [{ type: ViewChildren, args: [OpcuaDeviceProtocolMapping] }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib3BjdWEtZGV2aWNlLXByb3RvY29sLWRldGFpbC5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9wcm90b2NvbC1vcGN1YS9vcGN1YS1kZXZpY2UtcHJvdG9jb2wtZGV0YWlsLmNvbXBvbmVudC50cyIsIi4uLy4uLy4uL3Byb3RvY29sLW9wY3VhL29wY3VhLWRldmljZS1wcm90b2NvbC1kZXRhaWwuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsU0FBUyxFQUFVLFlBQVksRUFBRSxTQUFTLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDOUYsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQ3pDLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUM5QyxPQUFPLEVBQUUsWUFBWSxFQUFFLE9BQU8sRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBRTVELE9BQU8sRUFBRSxJQUFJLEVBQUUsTUFBTSxFQUFFLElBQUksRUFBRSxTQUFTLEVBQUUsSUFBSSxFQUFFLEdBQUcsRUFBRSxLQUFLLEVBQUUsTUFBTSxXQUFXLENBQUM7QUFDNUUsT0FBTyxFQUFFLDBCQUEwQixFQUFFLE1BQU0sMkNBQTJDLENBQUM7Ozs7Ozs7Ozs7O0FBTXZGLE1BQU0sT0FBTyxrQ0FBa0M7SUErQjdDLFlBQ1UsaUJBQW9DLEVBQ3BDLFlBQTBCLEVBQzFCLFlBQTBCLEVBQzFCLE1BQWM7UUFIZCxzQkFBaUIsR0FBakIsaUJBQWlCLENBQW1CO1FBQ3BDLGlCQUFZLEdBQVosWUFBWSxDQUFjO1FBQzFCLGlCQUFZLEdBQVosWUFBWSxDQUFjO1FBQzFCLFdBQU0sR0FBTixNQUFNLENBQVE7UUFoQ3hCLGlCQUFZLEdBQW9CO1lBQzlCLEVBQUUsRUFBRSxFQUFFO1lBQ04sWUFBWSxFQUFFLFNBQVM7WUFDdkIsV0FBVyxFQUFFLEVBQUU7WUFDZixJQUFJLEVBQUUsRUFBRTtZQUNSLGVBQWUsRUFBRSxDQUFDO1lBQ2xCLElBQUksRUFBRSxFQUFFO1lBQ1Isa0JBQWtCLEVBQUUsRUFBRTtZQUN0QixvQkFBb0IsRUFBRSxFQUFFO1lBQ3hCLGdCQUFnQixFQUFFO2dCQUNoQixJQUFJLEVBQUUsTUFBTTthQUNiO1lBQ0QsUUFBUSxFQUFFLEVBQUU7WUFDWix1QkFBdUIsRUFBRSxFQUFFO1lBQzNCLGdCQUFnQixFQUFFO2dCQUNoQixzQkFBc0IsRUFBRSxFQUFFO2dCQUMxQixjQUFjLEVBQUUsRUFBRTtnQkFDbEIsdUJBQXVCLEVBQUUsRUFBRTtnQkFDM0IsZ0JBQWdCLEVBQUUsRUFBRTthQUNyQjtZQUNELE9BQU8sRUFBRSxFQUFFO1NBQ1osQ0FBQztRQUtGLGFBQVEsR0FBRyxJQUFJLENBQUM7UUFhaEIsa0JBQWEsR0FBRyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsS0FBSyxFQUFFLEdBQUcsQ0FBQyxDQUFDO0lBTnpDLENBQUM7SUFFSixxQkFBcUI7UUFDbkIsSUFBSSxDQUFDLGlCQUFpQixDQUFDLGFBQWEsRUFBRSxDQUFDO0lBQ3pDLENBQUM7SUFJRCxVQUFVO1FBQ1IsT0FBTyxJQUFJLENBQUMsS0FBSyxDQUFDLFFBQVEsQ0FBQztJQUM3QixDQUFDO0lBRUQscUJBQXFCO1FBQ25CLE1BQU0sRUFBRSxRQUFRLEVBQUUsR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDO1FBQ2hDLE9BQU87WUFDTCxFQUFFLEVBQUUsUUFBUSxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsR0FBRyxRQUFRLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBQ3RFLFVBQVUsRUFBRSxFQUFFO1NBQ2YsQ0FBQztJQUNKLENBQUM7SUFFRCxnQ0FBZ0MsQ0FBQyxVQUFvQjtRQUNuRCxJQUFJLEtBQUssQ0FBQyxVQUFVLENBQUMsSUFBSSxVQUFVLENBQUMsTUFBTSxLQUFLLENBQUMsRUFBRSxDQUFDO1lBQ2pELE9BQU8sU0FBUyxDQUFDO1FBQ25CLENBQUM7UUFDRCxPQUFPLElBQUksQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLHVCQUF1QixFQUFFLEVBQUUsVUFBVSxFQUFFLENBQUMsQ0FBQztJQUNsRSxDQUFDO0lBRUQscUJBQXFCLENBQUMsUUFBUTtRQUM1QixNQUFNLHVCQUF1QixHQUFRLElBQUksQ0FBQyxnQ0FBZ0MsQ0FBQyxRQUFRLENBQUMsVUFBVSxDQUFDLENBQUM7UUFDaEcsSUFBSSxNQUFNLEdBQUcsTUFBTSxDQUFDLEVBQUUsRUFBRSxRQUFRLENBQUMsQ0FBQztRQUNsQyxJQUFJLHVCQUF1QixFQUFFLENBQUM7WUFDNUIsTUFBTSxHQUFHLE1BQU0sQ0FBQyxFQUFFLEVBQUUsUUFBUSxFQUFFLEVBQUUsZ0JBQWdCLEVBQUUsdUJBQXVCLENBQUMsZ0JBQWdCLEVBQUUsQ0FBQyxDQUFDO1FBQ2hHLENBQUM7UUFDRCxPQUFPLE1BQU0sQ0FBQztJQUNoQixDQUFDO0lBRUQsS0FBSyxDQUFDLFFBQVE7UUFDWixNQUFNLEVBQUUsR0FBRyxJQUFJLENBQUMsWUFBWSxDQUFDLEtBQUssRUFBRSxDQUFDO1FBRXJDLElBQUksRUFBRSxFQUFFLENBQUM7WUFDUCxNQUFNLEdBQUcsR0FBRyxNQUFNLElBQUksQ0FBQyxZQUFZLENBQUMsaUJBQWlCLENBQUMsRUFBRSxDQUFDLENBQUM7WUFDMUQsSUFBSSxHQUFHLElBQUksR0FBRyxDQUFDLE1BQU0sS0FBSyxHQUFHLEVBQUUsQ0FBQztnQkFDOUIsTUFBTSxJQUFJLEdBQUcsR0FBRyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsTUFBTSxHQUFHLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQztnQkFDckQsSUFBSSxDQUFDLFlBQVksQ0FBQyxnQkFBZ0IsQ0FBQyxFQUFFLElBQUksRUFBRSxHQUFHLEVBQUUsQ0FBQyxDQUFDO2dCQUNsRCxJQUFJLENBQUMsUUFBUSxHQUFHLEtBQUssQ0FBQztZQUN4QixDQUFDO2lCQUFNLENBQUM7Z0JBQ04sTUFBTSxJQUFJLEdBQUcsTUFBTSxHQUFHLENBQUMsSUFBSSxFQUFFLENBQUM7Z0JBQzlCLElBQUksSUFBSSxJQUFJLElBQUksQ0FBQyxnQkFBZ0IsS0FBSyxJQUFJLEVBQUUsQ0FBQztvQkFDM0MsT0FBTyxJQUFJLENBQUMsZ0JBQWdCLENBQUM7Z0JBQy9CLENBQUM7Z0JBQ0QsSUFBSSxJQUFJLElBQUksSUFBSSxDQUFDLGdCQUFnQixLQUFLLElBQUksRUFBRSxDQUFDO29CQUMzQyxPQUFPLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQztnQkFDL0IsQ0FBQztnQkFDRCxJQUFJLENBQUMsS0FBSyxHQUFHLE1BQU0sQ0FBQyxJQUFJLENBQUMsWUFBWSxFQUFFLElBQUksQ0FBQyxDQUFDO2dCQUM3QyxJQUFJLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxRQUFRLEVBQUUsQ0FBQztvQkFDekIsSUFBSSxDQUFDLEtBQUssQ0FBQyxRQUFRLEdBQUcsRUFBRSxDQUFDO2dCQUMzQixDQUFDO2dCQUNELElBQUksQ0FBQyxLQUFLLEdBQUcsTUFBTSxDQUFDLElBQUksQ0FBQyxZQUFZLEVBQUUsSUFBSSxDQUFDLG1CQUFtQixDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7Z0JBQ3ZFLElBQUksQ0FBQyxRQUFRLEdBQUcsS0FBSyxDQUFDO1lBQ3hCLENBQUM7UUFDSCxDQUFDO0lBQ0gsQ0FBQztJQUVELG1CQUFtQixDQUFDLEtBQUs7UUFDdkIsTUFBTSxFQUFFLFFBQVEsRUFBRSxHQUFHLEtBQUssQ0FBQztRQUMzQixJQUFJLE1BQU0sR0FBRyxFQUFFLENBQUM7UUFDaEIsSUFBSSxRQUFRLEVBQUUsQ0FBQztZQUNiLE1BQU0sR0FBRyxRQUFRLENBQUMsR0FBRyxDQUFDLENBQUMsSUFBSSxFQUFFLENBQUMsRUFBRSxFQUFFO2dCQUNoQyxPQUFPLE1BQU0sQ0FBQyxJQUFJLENBQUMscUJBQXFCLENBQUMsSUFBSSxDQUFDLEVBQUUsRUFBRSxFQUFFLEVBQUUsQ0FBQyxFQUFFLENBQUMsQ0FBQztZQUM3RCxDQUFDLENBQUMsQ0FBQztRQUNMLENBQUM7UUFDRCxPQUFPLE1BQU0sQ0FBQyxLQUFLLEVBQUUsRUFBRSxRQUFRLEVBQUUsTUFBTSxFQUFFLENBQUMsQ0FBQztJQUM3QyxDQUFDO0lBRUQsU0FBUyxDQUFDLE1BQWMsRUFBRSxFQUFPO1FBQy9CLE9BQU8sR0FBRyxDQUFDLEVBQUUsRUFBRSxJQUFJLENBQUMsQ0FBQztJQUN2QixDQUFDO0lBRUQsV0FBVztRQUNULElBQUksQ0FBQyxLQUFLLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMscUJBQXFCLEVBQUUsQ0FBQyxDQUFDO0lBQ3pELENBQUM7SUFFRCxjQUFjLENBQUMsYUFBYTtRQUMxQixNQUFNLEVBQUUsUUFBUSxFQUFFLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQztRQUNoQyxNQUFNLEVBQUUsRUFBRSxFQUFFLEdBQUcsYUFBYSxDQUFDO1FBQzdCLE1BQU0sS0FBSyxHQUFHLFNBQVMsQ0FBQyxRQUFRLEVBQUUsRUFBRSxFQUFFLEVBQUUsQ0FBQyxDQUFDO1FBQzFDLFFBQVEsQ0FBQyxLQUFLLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsYUFBYSxDQUFDO0lBQ25ELENBQUM7SUFFRCxjQUFjLENBQUMsYUFBYTtRQUMxQixNQUFNLEVBQUUsUUFBUSxFQUFFLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQztRQUNoQyxNQUFNLEVBQUUsRUFBRSxFQUFFLEdBQUcsYUFBYSxDQUFDO1FBQzdCLElBQUksS0FBSyxHQUFHLENBQUMsQ0FBQyxDQUFDO1FBRWYsNkJBQTZCO1FBQzdCLElBQUksQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsTUFBTSxHQUFHLENBQUMsSUFBSSxFQUFFLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDO1lBQzdDLEtBQUssR0FBRyxTQUFTLENBQUMsUUFBUSxFQUFFLEVBQUUsRUFBRSxFQUFFLENBQUMsQ0FBQztRQUN0QyxDQUFDO1FBRUQsSUFBSSxLQUFLLEdBQUcsQ0FBQyxDQUFDLEVBQUUsQ0FBQztZQUNmLFFBQVEsQ0FBQyxNQUFNLENBQUMsS0FBSyxFQUFFLENBQUMsQ0FBQyxDQUFDO1FBQzVCLENBQUM7SUFDSCxDQUFDO0lBRUQsYUFBYSxDQUFDLFlBQVk7UUFDeEIsUUFBUSxZQUFZLENBQUMsTUFBTSxFQUFFLENBQUM7WUFDNUIsS0FBSyxNQUFNO2dCQUNULElBQUksQ0FBQyxjQUFjLENBQUMsWUFBWSxDQUFDLElBQUksQ0FBQyxDQUFDO2dCQUN2QyxNQUFNO1lBQ1IsS0FBSyxRQUFRO2dCQUNYLElBQUksQ0FBQyxjQUFjLENBQUMsWUFBWSxDQUFDLElBQUksQ0FBQyxDQUFDO2dCQUN2QyxNQUFNO1FBQ1YsQ0FBQztJQUNILENBQUM7SUFFRCw4QkFBOEIsQ0FBQyxRQUFRO1FBQ3JDLE1BQU0sdUJBQXVCLEdBQUcsRUFBRSxDQUFDO1FBRW5DLE1BQU0sZUFBZSxHQUFHLEVBQUUsQ0FBQztRQUMzQixRQUFRLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxFQUFFO1lBQ3pCLElBQUksT0FBTyxDQUFDLEVBQUUsS0FBSyxLQUFLLEVBQUUsQ0FBQztnQkFDekIsSUFBSSxPQUFPLENBQUMsZ0JBQWdCLEVBQUUsQ0FBQztvQkFDN0IsdUJBQXVCLENBQUMsSUFBSSxDQUMxQixNQUFNLENBQ0osRUFBRSxVQUFVLEVBQUUsT0FBTyxDQUFDLFVBQVUsRUFBRSxFQUNsQyxFQUFFLGdCQUFnQixFQUFFLE9BQU8sQ0FBQyxnQkFBZ0IsRUFBRSxDQUMvQyxDQUNGLENBQUM7Z0JBQ0osQ0FBQztnQkFDRCxlQUFlLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxPQUFPLEVBQUUsQ0FBQyxrQkFBa0IsQ0FBQyxDQUFDLENBQUMsQ0FBQztZQUM1RCxDQUFDO1FBQ0gsQ0FBQyxDQUFDLENBQUM7UUFDSCxPQUFPLENBQUMsZUFBZSxFQUFFLHVCQUF1QixDQUFDLENBQUM7SUFDcEQsQ0FBQztJQUVELGtCQUFrQixDQUFDLE1BQU07UUFDdkIsSUFBSSxXQUFXLEdBQUcsRUFBRSxDQUFDO1FBQ3JCLE1BQU0sQ0FBQyxRQUFRLEVBQUUsdUJBQXVCLENBQUMsR0FBRyxJQUFJLENBQUMsOEJBQThCLENBQzdFLE1BQU0sQ0FBQyxRQUFRLENBQ2hCLENBQUM7UUFDRixXQUFXLEdBQUcsTUFBTSxDQUFDLFdBQVcsRUFBRSxJQUFJLENBQUMsTUFBTSxFQUFFLE1BQU0sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLFlBQVksQ0FBQyxDQUFDLEVBQUU7WUFDOUUsUUFBUTtZQUNSLHVCQUF1QjtTQUN4QixDQUFDLENBQUM7UUFDSCxPQUFPLFdBQVcsQ0FBQztJQUNyQixDQUFDO0lBRUQsS0FBSyxDQUFDLElBQUk7UUFDUixJQUFJLENBQUM7WUFDSCxNQUFNLEdBQUcsR0FBRyxNQUFNLElBQUksQ0FBQyxZQUFZLENBQUMsb0JBQW9CLENBQUMsSUFBSSxDQUFDLGtCQUFrQixDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDO1lBQzlGLE1BQU0sSUFBSSxHQUFHLE1BQU0sR0FBRyxDQUFDLElBQUksRUFBRSxDQUFDO1lBRTlCLElBQUksR0FBRyxJQUFJLEdBQUcsQ0FBQyxNQUFNLEtBQUssR0FBRyxFQUFFLENBQUM7Z0JBQzlCLElBQUksQ0FBQyxNQUFNLENBQUMsUUFBUSxDQUFDLENBQUMsaUJBQWlCLENBQUMsQ0FBQyxDQUFDO2dCQUMxQyxJQUFJLENBQUMsWUFBWSxDQUFDLE9BQU8sQ0FBQyxPQUFPLENBQUMsd0JBQXdCLENBQUMsQ0FBQyxDQUFDO1lBQy9ELENBQUM7aUJBQU0sQ0FBQztnQkFDTixNQUFNLEVBQUUsT0FBTyxFQUFFLEdBQUcsSUFBSSxDQUFDO2dCQUN6QixJQUFJLENBQUMsWUFBWSxDQUFDLGdCQUFnQixDQUFDLEVBQUUsR0FBRyxFQUFFLElBQUksRUFBRSxPQUFPLEVBQUUsQ0FBQyxDQUFDO1lBQzdELENBQUM7UUFDSCxDQUFDO1FBQUMsT0FBTyxFQUFFLEVBQUUsQ0FBQztZQUNaLElBQUksQ0FBQyxZQUFZLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyw0QkFBNEIsQ0FBQyxDQUFDLENBQUM7UUFDbEUsQ0FBQztJQUNILENBQUM7SUFFRCxPQUFPLENBQUMsY0FBYztRQUNwQixJQUFJLElBQUksQ0FBQyxZQUFZLEVBQUUsQ0FBQztZQUN0QixNQUFNLGVBQWUsR0FBRyxJQUFJLENBQUMsWUFBWSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxRQUFRLEVBQUUsQ0FBQyxDQUFDO1lBRTFFLElBQUksZUFBZSxDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUUsQ0FBQztnQkFDL0IsT0FBTyxJQUFJLENBQUM7WUFDZCxDQUFDO1FBQ0gsQ0FBQztRQUNELE9BQU8sQ0FBQyxjQUFjLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQztJQUNwQyxDQUFDOytHQWpOVSxrQ0FBa0M7bUdBQWxDLGtDQUFrQyxxR0FDL0IsMEJBQTBCLGdEQ2IxQywreUhBNEZBOzs0RkRoRmEsa0NBQWtDO2tCQUo5QyxTQUFTOytCQUNFLDhCQUE4QjtpS0FJRSxZQUFZO3NCQUFyRCxZQUFZO3VCQUFDLDBCQUEwQiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENvbXBvbmVudCwgT25Jbml0LCBWaWV3Q2hpbGRyZW4sIFF1ZXJ5TGlzdCwgQ2hhbmdlRGV0ZWN0b3JSZWYgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IFJvdXRlciB9IGZyb20gJ0Bhbmd1bGFyL3JvdXRlcic7XG5pbXBvcnQgeyBPcGN1YVNlcnZpY2UgfSBmcm9tICcuL29wY3VhU2VydmljZSc7XG5pbXBvcnQgeyBBbGVydFNlcnZpY2UsIGdldHRleHQgfSBmcm9tICdAYzh5L25neC1jb21wb25lbnRzJztcbmltcG9ydCB7IE9wY3VhRGV2aWNlVHlwZSB9IGZyb20gJy4vb3BjdWEtcHJvdG9jb2wtZGV2aWNlLXR5cGUuaW50ZXJmYWNlJztcbmltcG9ydCB7IGZpbmQsIGFzc2lnbiwgb21pdCwgZmluZEluZGV4LCBwaWNrLCBnZXQsIGlzTmlsIH0gZnJvbSAnbG9kYXNoLWVzJztcbmltcG9ydCB7IE9wY3VhRGV2aWNlUHJvdG9jb2xNYXBwaW5nIH0gZnJvbSAnLi9vcGN1YS1kZXZpY2UtcHJvdG9jb2wtbWFwcGluZy5jb21wb25lbnQnO1xuXG5AQ29tcG9uZW50KHtcbiAgc2VsZWN0b3I6ICdvcGN1YS1kZXZpY2UtcHJvdG9jb2wtZGV0YWlsJyxcbiAgdGVtcGxhdGVVcmw6ICcuL29wY3VhLWRldmljZS1wcm90b2NvbC1kZXRhaWwuaHRtbCdcbn0pXG5leHBvcnQgY2xhc3MgT3BjdWFEZXZpY2VQcm90b2NvbERldGFpbENvbXBvbmVudCBpbXBsZW1lbnRzIE9uSW5pdCB7XG4gIEBWaWV3Q2hpbGRyZW4oT3BjdWFEZXZpY2VQcm90b2NvbE1hcHBpbmcpIGluc3RhbmNlTGlzdDogUXVlcnlMaXN0PE9wY3VhRGV2aWNlUHJvdG9jb2xNYXBwaW5nPjtcblxuICBpbml0aWFsTW9kZWw6IE9wY3VhRGV2aWNlVHlwZSA9IHtcbiAgICBpZDogJycsXG4gICAgZmllbGRidXNUeXBlOiAnb3BjdWFWMicsXG4gICAgZGVzY3JpcHRpb246ICcnLFxuICAgIHVuaXQ6ICcnLFxuICAgIGZpZWxkYnVzVmVyc2lvbjogNCxcbiAgICBuYW1lOiAnJyxcbiAgICByZWZlcmVuY2VkU2VydmVySWQ6ICcnLFxuICAgIHJlZmVyZW5jZWRSb290Tm9kZUlkOiAnJyxcbiAgICBzdWJzY3JpcHRpb25UeXBlOiB7XG4gICAgICB0eXBlOiAnTm9uZSdcbiAgICB9LFxuICAgIG1hcHBpbmdzOiBbXSxcbiAgICBvdmVycmlkZGVuU3Vic2NyaXB0aW9uczogW10sXG4gICAgYXBwbHlDb25zdHJhaW50czoge1xuICAgICAgYnJvd3NlUGF0aE1hdGNoZXNSZWdleDogJycsXG4gICAgICBtYXRjaGVzTm9kZUlkczogW10sXG4gICAgICBzZXJ2ZXJPYmplY3RIYXNGcmFnbWVudDogJycsXG4gICAgICBtYXRjaGVzU2VydmVySWRzOiBbXVxuICAgIH0sXG4gICAgZW5hYmxlZDogJydcbiAgfTtcblxuICBtb2RlbDogYW55O1xuICBzZXJ2ZXI6IGFueTtcbiAgc2VsZWN0ZWROb2RlOiBhbnk7XG4gIGlzTG9hZGVkID0gdHJ1ZTtcblxuICBjb25zdHJ1Y3RvcihcbiAgICBwcml2YXRlIGNoYW5nZURldGVjdG9yUmVmOiBDaGFuZ2VEZXRlY3RvclJlZixcbiAgICBwcml2YXRlIG9wY3VhU2VydmljZTogT3BjdWFTZXJ2aWNlLFxuICAgIHByaXZhdGUgYWxlcnRTZXJ2aWNlOiBBbGVydFNlcnZpY2UsXG4gICAgcHJpdmF0ZSByb3V0ZXI6IFJvdXRlclxuICApIHt9XG5cbiAgbmdBZnRlckNvbnRlbnRDaGVja2VkKCkge1xuICAgIHRoaXMuY2hhbmdlRGV0ZWN0b3JSZWYuZGV0ZWN0Q2hhbmdlcygpO1xuICB9XG5cbiAgZ2V0UGFyZW50QXR0ciA9IGtleSA9PiBnZXQodGhpcy5tb2RlbCwga2V5KTtcblxuICBnZXRNYXBwaW5nKCkge1xuICAgIHJldHVybiB0aGlzLm1vZGVsLm1hcHBpbmdzO1xuICB9XG5cbiAgZ2V0RW1wdHlNYXBwaW5nT2JqZWN0KCkge1xuICAgIGNvbnN0IHsgbWFwcGluZ3MgfSA9IHRoaXMubW9kZWw7XG4gICAgcmV0dXJuIHtcbiAgICAgIGlkOiBtYXBwaW5ncy5sZW5ndGggPiAwID8gTWF0aC5tYXgoLi4ubWFwcGluZ3MubWFwKG0gPT4gbS5pZCkpICsgMSA6IDAsXG4gICAgICBicm93c2VQYXRoOiBbXVxuICAgIH07XG4gIH1cblxuICBnZXRPdmVycmlkZGVuU3Vic2NyaXB0aW9uc0J5UGF0aChicm93c2VQYXRoOiBzdHJpbmdbXSk6IGFueSB7XG4gICAgaWYgKGlzTmlsKGJyb3dzZVBhdGgpIHx8IGJyb3dzZVBhdGgubGVuZ3RoID09PSAwKSB7XG4gICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgIH1cbiAgICByZXR1cm4gZmluZCh0aGlzLm1vZGVsLm92ZXJyaWRkZW5TdWJzY3JpcHRpb25zLCB7IGJyb3dzZVBhdGggfSk7XG4gIH1cblxuICBnZXRTdHJ1Y3R1cmVkUmVzb3VyY2UocmVzb3VyY2UpIHtcbiAgICBjb25zdCBvdmVycmlkZGVuU3Vic2NyaXB0aW9uczogYW55ID0gdGhpcy5nZXRPdmVycmlkZGVuU3Vic2NyaXB0aW9uc0J5UGF0aChyZXNvdXJjZS5icm93c2VQYXRoKTtcbiAgICBsZXQgcmVzdWx0ID0gYXNzaWduKHt9LCByZXNvdXJjZSk7XG4gICAgaWYgKG92ZXJyaWRkZW5TdWJzY3JpcHRpb25zKSB7XG4gICAgICByZXN1bHQgPSBhc3NpZ24oe30sIHJlc291cmNlLCB7IHN1YnNjcmlwdGlvblR5cGU6IG92ZXJyaWRkZW5TdWJzY3JpcHRpb25zLnN1YnNjcmlwdGlvblR5cGUgfSk7XG4gICAgfVxuICAgIHJldHVybiByZXN1bHQ7XG4gIH1cblxuICBhc3luYyBuZ09uSW5pdCgpIHtcbiAgICBjb25zdCBpZCA9IHRoaXMub3BjdWFTZXJ2aWNlLmdldElkKCk7XG5cbiAgICBpZiAoaWQpIHtcbiAgICAgIGNvbnN0IHJlcyA9IGF3YWl0IHRoaXMub3BjdWFTZXJ2aWNlLmdldERldmljZVByb3RvY29sKGlkKTtcbiAgICAgIGlmIChyZXMgJiYgcmVzLnN0YXR1cyAhPT0gMjAwKSB7XG4gICAgICAgIGNvbnN0IGRhdGEgPSByZXMuanNvbiA/IGF3YWl0IHJlcy5qc29uKCkgOiB1bmRlZmluZWQ7XG4gICAgICAgIHRoaXMuYWxlcnRTZXJ2aWNlLmFkZFNlcnZlckZhaWx1cmUoeyBkYXRhLCByZXMgfSk7XG4gICAgICAgIHRoaXMuaXNMb2FkZWQgPSBmYWxzZTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGNvbnN0IGRhdGEgPSBhd2FpdCByZXMuanNvbigpO1xuICAgICAgICBpZiAoZGF0YSAmJiBkYXRhLmFwcGx5Q29uc3RyYWludHMgPT09IG51bGwpIHtcbiAgICAgICAgICBkZWxldGUgZGF0YS5hcHBseUNvbnN0cmFpbnRzO1xuICAgICAgICB9XG4gICAgICAgIGlmIChkYXRhICYmIGRhdGEuc3Vic2NyaXB0aW9uVHlwZSA9PT0gbnVsbCkge1xuICAgICAgICAgIGRlbGV0ZSBkYXRhLnN1YnNjcmlwdGlvblR5cGU7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5tb2RlbCA9IGFzc2lnbih0aGlzLmluaXRpYWxNb2RlbCwgZGF0YSk7XG4gICAgICAgIGlmICghdGhpcy5tb2RlbC5tYXBwaW5ncykge1xuICAgICAgICAgIHRoaXMubW9kZWwubWFwcGluZ3MgPSBbXTtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLm1vZGVsID0gYXNzaWduKHRoaXMuaW5pdGlhbE1vZGVsLCB0aGlzLnVwZGF0ZVZpYWJsZU1hcHBpbmcoZGF0YSkpO1xuICAgICAgICB0aGlzLmlzTG9hZGVkID0gZmFsc2U7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgdXBkYXRlVmlhYmxlTWFwcGluZyhtb2RlbCkge1xuICAgIGNvbnN0IHsgbWFwcGluZ3MgfSA9IG1vZGVsO1xuICAgIGxldCByZXN1bHQgPSBbXTtcbiAgICBpZiAobWFwcGluZ3MpIHtcbiAgICAgIHJlc3VsdCA9IG1hcHBpbmdzLm1hcCgoaXRlbSwgaSkgPT4ge1xuICAgICAgICByZXR1cm4gYXNzaWduKHRoaXMuZ2V0U3RydWN0dXJlZFJlc291cmNlKGl0ZW0pLCB7IGlkOiBpIH0pO1xuICAgICAgfSk7XG4gICAgfVxuICAgIHJldHVybiBhc3NpZ24obW9kZWwsIHsgbWFwcGluZ3M6IHJlc3VsdCB9KTtcbiAgfVxuXG4gIHRyYWNrQnlJZChfaW5kZXg6IG51bWJlciwgZWw6IGFueSk6IG51bWJlciB7XG4gICAgcmV0dXJuIGdldChlbCwgJ2lkJyk7XG4gIH1cblxuICBhZGRWYXJpYWJsZSgpIHtcbiAgICB0aGlzLm1vZGVsLm1hcHBpbmdzLnB1c2godGhpcy5nZXRFbXB0eU1hcHBpbmdPYmplY3QoKSk7XG4gIH1cblxuICB1cGRhdGVWYXJpYWJsZShtYXBwaW5nT2JqZWN0KSB7XG4gICAgY29uc3QgeyBtYXBwaW5ncyB9ID0gdGhpcy5tb2RlbDtcbiAgICBjb25zdCB7IGlkIH0gPSBtYXBwaW5nT2JqZWN0O1xuICAgIGNvbnN0IGluZGV4ID0gZmluZEluZGV4KG1hcHBpbmdzLCB7IGlkIH0pO1xuICAgIG1hcHBpbmdzW2luZGV4ID4gLTEgPyBpbmRleCA6IDBdID0gbWFwcGluZ09iamVjdDtcbiAgfVxuXG4gIHJlbW92ZVZhcmlhYmxlKG1hcHBpbmdPYmplY3QpIHtcbiAgICBjb25zdCB7IG1hcHBpbmdzIH0gPSB0aGlzLm1vZGVsO1xuICAgIGNvbnN0IHsgaWQgfSA9IG1hcHBpbmdPYmplY3Q7XG4gICAgbGV0IGluZGV4ID0gLTE7XG5cbiAgICAvLyBpZCB0eXBlb2Ygc3RyaW5nIHx8IG51bWJlclxuICAgIGlmICghaXNOaWwoaWQpICYmIChpZC5sZW5ndGggPiAwIHx8IGlkID4gLTEpKSB7XG4gICAgICBpbmRleCA9IGZpbmRJbmRleChtYXBwaW5ncywgeyBpZCB9KTtcbiAgICB9XG5cbiAgICBpZiAoaW5kZXggPiAtMSkge1xuICAgICAgbWFwcGluZ3Muc3BsaWNlKGluZGV4LCAxKTtcbiAgICB9XG4gIH1cblxuICBhY3Rpb25IYW5kbGVyKGFjdGlvbk9iamVjdCkge1xuICAgIHN3aXRjaCAoYWN0aW9uT2JqZWN0LmFjdGlvbikge1xuICAgICAgY2FzZSAnc2F2ZSc6XG4gICAgICAgIHRoaXMudXBkYXRlVmFyaWFibGUoYWN0aW9uT2JqZWN0LmRhdGEpO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgJ2RlbGV0ZSc6XG4gICAgICAgIHRoaXMucmVtb3ZlVmFyaWFibGUoYWN0aW9uT2JqZWN0LmRhdGEpO1xuICAgICAgICBicmVhaztcbiAgICB9XG4gIH1cblxuICBleHRyYWN0T3ZlcnJpZFN1YnNjcmlwdGlvblR5cGUoX21hcHBpbmcpIHtcbiAgICBjb25zdCBvdmVycmlkZGVuU3Vic2NyaXB0aW9ucyA9IFtdO1xuXG4gICAgY29uc3QgdmFyaWFibGVNYXBwaW5nID0gW107XG4gICAgX21hcHBpbmcuZm9yRWFjaChlbGVtZW50ID0+IHtcbiAgICAgIGlmIChlbGVtZW50LmlkICE9PSAnbmV3Jykge1xuICAgICAgICBpZiAoZWxlbWVudC5zdWJzY3JpcHRpb25UeXBlKSB7XG4gICAgICAgICAgb3ZlcnJpZGRlblN1YnNjcmlwdGlvbnMucHVzaChcbiAgICAgICAgICAgIGFzc2lnbihcbiAgICAgICAgICAgICAgeyBicm93c2VQYXRoOiBlbGVtZW50LmJyb3dzZVBhdGggfSxcbiAgICAgICAgICAgICAgeyBzdWJzY3JpcHRpb25UeXBlOiBlbGVtZW50LnN1YnNjcmlwdGlvblR5cGUgfVxuICAgICAgICAgICAgKVxuICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICAgICAgdmFyaWFibGVNYXBwaW5nLnB1c2gob21pdChlbGVtZW50LCBbJ3N1YnNjcmlwdGlvblR5cGUnXSkpO1xuICAgICAgfVxuICAgIH0pO1xuICAgIHJldHVybiBbdmFyaWFibGVNYXBwaW5nLCBvdmVycmlkZGVuU3Vic2NyaXB0aW9uc107XG4gIH1cblxuICBwcmVwYXJlUmVxdWVzdEpzb24oX21vZGVsKSB7XG4gICAgbGV0IHJlcXVlc3RKc29uID0ge307XG4gICAgY29uc3QgW21hcHBpbmdzLCBvdmVycmlkZGVuU3Vic2NyaXB0aW9uc10gPSB0aGlzLmV4dHJhY3RPdmVycmlkU3Vic2NyaXB0aW9uVHlwZShcbiAgICAgIF9tb2RlbC5tYXBwaW5nc1xuICAgICk7XG4gICAgcmVxdWVzdEpzb24gPSBhc3NpZ24ocmVxdWVzdEpzb24sIHBpY2soX21vZGVsLCBPYmplY3Qua2V5cyh0aGlzLmluaXRpYWxNb2RlbCkpLCB7XG4gICAgICBtYXBwaW5ncyxcbiAgICAgIG92ZXJyaWRkZW5TdWJzY3JpcHRpb25zXG4gICAgfSk7XG4gICAgcmV0dXJuIHJlcXVlc3RKc29uO1xuICB9XG5cbiAgYXN5bmMgc2F2ZSgpIHtcbiAgICB0cnkge1xuICAgICAgY29uc3QgcmVzID0gYXdhaXQgdGhpcy5vcGN1YVNlcnZpY2UudXBkYXRlRGV2aWNlUHJvdG9jb2wodGhpcy5wcmVwYXJlUmVxdWVzdEpzb24odGhpcy5tb2RlbCkpO1xuICAgICAgY29uc3QgZGF0YSA9IGF3YWl0IHJlcy5qc29uKCk7XG5cbiAgICAgIGlmIChyZXMgJiYgcmVzLnN0YXR1cyA9PT0gMjAwKSB7XG4gICAgICAgIHRoaXMucm91dGVyLm5hdmlnYXRlKFsnZGV2aWNlcHJvdG9jb2xzJ10pO1xuICAgICAgICB0aGlzLmFsZXJ0U2VydmljZS5zdWNjZXNzKGdldHRleHQoJ0RldmljZSBwcm90b2NvbCBzYXZlZC4nKSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBjb25zdCB7IGRldGFpbHMgfSA9IGRhdGE7XG4gICAgICAgIHRoaXMuYWxlcnRTZXJ2aWNlLmFkZFNlcnZlckZhaWx1cmUoeyByZXMsIGRhdGE6IGRldGFpbHMgfSk7XG4gICAgICB9XG4gICAgfSBjYXRjaCAoZXgpIHtcbiAgICAgIHRoaXMuYWxlcnRTZXJ2aWNlLmRhbmdlcihnZXR0ZXh0KCdGYWlsZWQgdG8gc2F2ZS4gVHJ5IGFnYWluLicpKTtcbiAgICB9XG4gIH1cblxuICBjYW5TYXZlKGRldmljZVR5cGVGb3JtKSB7XG4gICAgaWYgKHRoaXMuaW5zdGFuY2VMaXN0KSB7XG4gICAgICBjb25zdCBhY3RpdmVJbnN0YW5jZXMgPSB0aGlzLmluc3RhbmNlTGlzdC5maWx0ZXIoaXRlbSA9PiBpdGVtLmlzQWN0aXZlKCkpO1xuXG4gICAgICBpZiAoYWN0aXZlSW5zdGFuY2VzLmxlbmd0aCA+IDApIHtcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiAhZGV2aWNlVHlwZUZvcm0uZm9ybS52YWxpZDtcbiAgfVxufVxuIiwiPGM4eS10aXRsZSAqbmdJZj1cIiFpc0xvYWRlZFwiPnt7IG1vZGVsLm5hbWUgfX08L2M4eS10aXRsZT5cbjxjOHktYnJlYWRjcnVtYj5cbiAgPGM4eS1icmVhZGNydW1iLWl0ZW1cbiAgICBbaWNvbl09XCInYzh5LWRldmljZS1wcm90b2NvbHMnXCJcbiAgICBbbGFiZWxdPVwiJ0RldmljZSB0eXBlcycgfCB0cmFuc2xhdGVcIlxuICA+PC9jOHktYnJlYWRjcnVtYi1pdGVtPlxuICA8Yzh5LWJyZWFkY3J1bWItaXRlbVxuICAgIFtpY29uXT1cIidjOHktZGV2aWNlLXByb3RvY29scydcIlxuICAgIFtsYWJlbF09XCInRGV2aWNlIHByb3RvY29scycgfCB0cmFuc2xhdGVcIlxuICAgIFtwYXRoXT1cIidkZXZpY2Vwcm90b2NvbHMnXCJcbiAgPjwvYzh5LWJyZWFkY3J1bWItaXRlbT5cbiAgPGM4eS1icmVhZGNydW1iLWl0ZW0gW2ljb25dPVwiJ2M4eS1kZXZpY2UtcHJvdG9jb2xzJ1wiIFtsYWJlbF09XCJtb2RlbD8ubmFtZVwiPjwvYzh5LWJyZWFkY3J1bWItaXRlbT5cbjwvYzh5LWJyZWFkY3J1bWI+XG48ZGl2IGNsYXNzPVwicm93XCI+XG4gIDxkaXYgY2xhc3M9XCJjb2wtbGctMTIgY29sLWxnLW1heFwiPlxuICAgIDxmb3JtICNkZXZpY2VUeXBlRm9ybT1cIm5nRm9ybVwiIG5hbWU9XCJkZXRhaWxGb3JtXCIgKm5nSWY9XCIhaXNMb2FkZWRcIiBjbGFzcz1cImNhcmQgY2FyZC0tZnVsbHBhZ2VcIj5cbiAgICAgIDxvcGN1YS1kZXZpY2UtcHJvdG9jb2wtZGVzY3JpcHRpb24gW21vZGVsXT1cIm1vZGVsXCI+PC9vcGN1YS1kZXZpY2UtcHJvdG9jb2wtZGVzY3JpcHRpb24+XG4gICAgICA8ZGl2IGNsYXNzPVwiaW5uZXItc2Nyb2xsXCI+XG4gICAgICAgIDxkaXYgY2xhc3M9XCJkLWNvbnRlbnRzXCI+XG4gICAgICAgICAgPGRpdiBjbGFzcz1cImNhcmQtaGVhZGVyIHNlcGFyYXRvci10b3AtYm90dG9tIGJnLWNvbXBvbmVudCBzdGlja3ktdG9wXCI+XG4gICAgICAgICAgICA8ZGl2IGNsYXNzPVwiaDRcIiB0cmFuc2xhdGU+VmFyaWFibGVzPC9kaXY+XG4gICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgPGRpdiBjbGFzcz1cInAtbC0xNiBwLXItMTZcIj5cbiAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJjOHktbGlzdF9fZ3JvdXBcIiAqbmdJZj1cIm1vZGVsLm1hcHBpbmdzLmxlbmd0aCA+IDBcIiBuZ01vZGVsR3JvdXA9XCJ2YXJpYWJsZVwiPlxuICAgICAgICAgICAgICA8b3BjdWEtZGV2aWNlLXByb3RvY29sLW1hcHBpbmdcbiAgICAgICAgICAgICAgICAqbmdGb3I9XCJsZXQgcmVzb3VyY2Ugb2YgZ2V0TWFwcGluZygpOyBpbmRleCBhcyBpOyB0cmFja0J5OiB0cmFja0J5SWRcIlxuICAgICAgICAgICAgICAgIFtpbmRleF09XCJpXCJcbiAgICAgICAgICAgICAgICBbcmVmZXJlbmNlZFNlcnZlcklkXT1cIm1vZGVsLnJlZmVyZW5jZWRTZXJ2ZXJJZFwiXG4gICAgICAgICAgICAgICAgW3JlZmVyZW5jZWRSb290Tm9kZUlkXT1cIm1vZGVsLnJlZmVyZW5jZWRSb290Tm9kZUlkXCJcbiAgICAgICAgICAgICAgICBbcmVzb3VyY2VdPVwiZ2V0U3RydWN0dXJlZFJlc291cmNlKHJlc291cmNlKVwiXG4gICAgICAgICAgICAgICAgW2dldFBhcmVudEF0dHJdPVwiZ2V0UGFyZW50QXR0clwiXG4gICAgICAgICAgICAgICAgKG9uQWN0aW9uKT1cImFjdGlvbkhhbmRsZXIoJGV2ZW50KVwiXG4gICAgICAgICAgICAgID48L29wY3VhLWRldmljZS1wcm90b2NvbC1tYXBwaW5nPlxuICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgPGRpdiBjbGFzcz1cInAtbC0xNiBwLXItMTYgcC10LTE2XCI+XG4gICAgICAgICAgICA8Yzh5LXVpLWVtcHR5LXN0YXRlXG4gICAgICAgICAgICAgICpuZ0lmPVwibW9kZWwubWFwcGluZ3MubGVuZ3RoID09PSAwXCJcbiAgICAgICAgICAgICAgW2ljb25dPVwiJ3NsaWRlcnMnXCJcbiAgICAgICAgICAgICAgW3RpdGxlXT1cIidObyB2YXJpYWJsZXMgdG8gZGlzcGxheS4nIHwgdHJhbnNsYXRlXCJcbiAgICAgICAgICAgICAgW3N1YnRpdGxlXT1cIidDbGljayBiZWxvdyB0byBhZGQgeW91ciBmaXJzdCB2YXJpYWJsZS4nIHwgdHJhbnNsYXRlXCJcbiAgICAgICAgICAgID48L2M4eS11aS1lbXB0eS1zdGF0ZT5cblxuICAgICAgICAgICAgPGRpdiBjbGFzcz1cImNhcmQtZm9vdGVyXCI+XG4gICAgICAgICAgICAgIDxidXR0b25cbiAgICAgICAgICAgICAgICB0eXBlPVwiYnV0dG9uXCJcbiAgICAgICAgICAgICAgICB0aXRsZT1cInt7ICdBZGQgdmFyaWFibGUnIHwgdHJhbnNsYXRlIH19XCJcbiAgICAgICAgICAgICAgICBjbGFzcz1cImJ0biBidG4tZGVmYXVsdCBhZGRWYXJpYWJsZUJ0blwiXG4gICAgICAgICAgICAgICAgKGNsaWNrKT1cImFkZFZhcmlhYmxlKClcIlxuICAgICAgICAgICAgICA+XG4gICAgICAgICAgICAgICAgPGkgYzh5SWNvbj1cInBsdXMtY2lyY2xlXCI+PC9pPlxuICAgICAgICAgICAgICAgIHt7ICdBZGQgdmFyaWFibGUnIHwgdHJhbnNsYXRlIH19XG4gICAgICAgICAgICAgIDwvYnV0dG9uPlxuICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgPC9kaXY+XG4gICAgICAgIDwvZGl2PlxuICAgICAgICA8ZGl2IGNsYXNzPVwiZC1jb250ZW50c1wiPlxuICAgICAgICAgIDxkaXYgY2xhc3M9XCJjYXJkLWhlYWRlciBzZXBhcmF0b3ItdG9wLWJvdHRvbSBiZy1jb21wb25lbnQgc3RpY2t5LXRvcFwiPlxuICAgICAgICAgICAgPGRpdiBjbGFzcz1cImg0XCIgdHJhbnNsYXRlPkRhdGEgcmVwb3J0aW5nPC9kaXY+XG4gICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgPGRpdiBjbGFzcz1cInAtbC0xNiBwLXItMTYgcC10LTE2XCIgbmdNb2RlbEdyb3VwPVwic3Vic2NyaXB0aW9uXCI+XG4gICAgICAgICAgICA8b3BjdWEtZGV2aWNlLXByb3RvY29sLWRhdGEtcmVwb3J0aW5nXG4gICAgICAgICAgICAgIFtncm91cE5hbWVdPVwiJ3N1YnNjcmlwdGlvbidcIlxuICAgICAgICAgICAgICBbbW9kZWxdPVwibW9kZWxcIlxuICAgICAgICAgICAgPjwvb3BjdWEtZGV2aWNlLXByb3RvY29sLWRhdGEtcmVwb3J0aW5nPlxuICAgICAgICAgIDwvZGl2PlxuICAgICAgICA8L2Rpdj5cbiAgICAgICAgPGRpdiBjbGFzcz1cImQtY29udGVudHNcIj5cbiAgICAgICAgICA8ZGl2IGNsYXNzPVwiY2FyZC1oZWFkZXIgc2VwYXJhdG9yLXRvcC1ib3R0b20gc3RpY2t5LXRvcFwiPlxuICAgICAgICAgICAgPGRpdiBjbGFzcz1cImg0XCIgdHJhbnNsYXRlPkF1dG8gYXBwbHkgY29uc3RyYWludHM8L2Rpdj5cbiAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICA8ZGl2IGNsYXNzPVwicC1sLTE2IHAtci0xNiBwLXQtMTYgb3ZlcmZsb3ctdmlzaWJsZVwiIG5nTW9kZWxHcm91cD1cImF1dG9BcHBseVwiPlxuICAgICAgICAgICAgPG9wY3VhLWF1dG8tYXBwbHkgW21vZGVsXT1cIm1vZGVsXCI+PC9vcGN1YS1hdXRvLWFwcGx5PlxuICAgICAgICAgIDwvZGl2PlxuICAgICAgICA8L2Rpdj5cblxuICAgICAgICA8ZGl2IGNsYXNzPVwiY2FyZC1mb290ZXIgc3RpY2t5LWJvdHRvbSBzZXBhcmF0b3JcIiBzdHlsZT1cInotaW5kZXg6IDEwMVwiPlxuICAgICAgICAgIDxidXR0b25cbiAgICAgICAgICAgIHRpdGxlPVwie3sgJ1NhdmUnIHwgdHJhbnNsYXRlIH19XCJcbiAgICAgICAgICAgIGlkPVwiZGV2aWNlVHlwZVNhdmVcIlxuICAgICAgICAgICAgY2xhc3M9XCJidG4gYnRuLXByaW1hcnlcIlxuICAgICAgICAgICAgKGNsaWNrKT1cInNhdmUoKVwiXG4gICAgICAgICAgICBbZGlzYWJsZWRdPVwiY2FuU2F2ZShkZXZpY2VUeXBlRm9ybSlcIlxuICAgICAgICAgICAgdHlwZT1cImJ1dHRvblwiXG4gICAgICAgICAgPlxuICAgICAgICAgICAge3sgJ1NhdmUnIHwgdHJhbnNsYXRlIH19XG4gICAgICAgICAgPC9idXR0b24+XG4gICAgICAgIDwvZGl2PlxuICAgICAgPC9kaXY+XG4gICAgPC9mb3JtPlxuICA8L2Rpdj5cbjwvZGl2PlxuIl19