UNPKG

@c8y/ngx-components

Version:

Angular modules for Cumulocity IoT applications

180 lines 54.6 kB
import { Component } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { InventoryService, OperationStatus } from '@c8y/client'; import { GainsightService, gettext, ModalSelectionMode } from '@c8y/ngx-components'; import { PRODUCT_EXPERIENCE_REPOSITORY_SHARED, RepositorySelectModalComponent, RepositoryService, RepositoryType } from '@c8y/ngx-components/repository/shared'; import { assign, get, isEmpty } from 'lodash-es'; import { BsModalService } from 'ngx-bootstrap/modal'; import { BehaviorSubject, combineLatest, from, of } from 'rxjs'; import { distinctUntilChanged, filter, map, shareReplay, switchMap, take } from 'rxjs/operators'; import * as i0 from "@angular/core"; import * as i1 from "@angular/router"; import * as i2 from "@c8y/ngx-components/repository/shared"; import * as i3 from "@c8y/client"; import * as i4 from "ngx-bootstrap/modal"; import * as i5 from "@c8y/ngx-components"; import * as i6 from "@angular/common"; import * as i7 from "@c8y/ngx-components/operations/operation-details"; export class FirmwareDeviceTabComponent { constructor(route, repository, inventory, bsModal, gainsightService) { this.route = route; this.repository = repository; this.inventory = inventory; this.bsModal = bsModal; this.gainsightService = gainsightService; this.PRODUCT_EXPERIENCE = PRODUCT_EXPERIENCE_REPOSITORY_SHARED; this.isEmpty = isEmpty; this.reloading = false; this.device$ = new BehaviorSubject(this.route.parent.snapshot.data.contextData); this.deviceFirmwareFragment$ = this.device$.pipe(map(device => device.c8y_Firmware)); this.firmwareBinary$ = this.deviceFirmwareFragment$.pipe(filter(deviceFirmwareFragment => !isEmpty(deviceFirmwareFragment)), switchMap(deviceFirmwareFragment => from(this.repository.getRepositoryBinaryMoByVersion(deviceFirmwareFragment, RepositoryType.FIRMWARE))), shareReplay(1)); this.repositoryEntry$ = this.firmwareBinary$.pipe(switchMap(mo => this.repository.getRepositoryEntryMO$(mo)), shareReplay(1)); this.patches$ = combineLatest(this.firmwareBinary$, this.repositoryEntry$).pipe(switchMap(([firmwareBinary, repositoryEntry]) => { if (repositoryEntry && firmwareBinary) { const version = this.repository.getBaseVersionFromMO(firmwareBinary); return from(this.repository.listPatchVersions(repositoryEntry, version)).pipe(map(({ data }) => data)); } else { return of([]); } }), shareReplay(1)); this.supportsFirmwareOperations$ = this.device$.pipe(map((device) => get(device, 'c8y_SupportedOperations', []).indexOf('c8y_Firmware') > -1)); this.changesOperation$ = new BehaviorSubject(null); this.changesInProgress$ = this.changesOperation$.pipe(map(operation => this.isInProgress(operation))); } async ngOnInit() { // TODO check route snapshot, why is not refreshing device. // Scenario: missing deviceFirmwareFragment => install new version => switch tabs. // Expected: device should be set. await this.loadDevice(); await this.loadOperation(); } installFirmware() { const initialState = { repositoryEntriesWithVersions$: of([]), repositoryEntriesWithVersionsFn$: modal => this.getRepositoryEntriesWithVersions$(modal.content.searchTerm), repositoryType: RepositoryType.FIRMWARE, title: gettext('Install firmware'), subTitle: gettext('Available firmwares matching the device type'), icon: 'c8y-firmware', mode: ModalSelectionMode.SINGLE, labels: { ok: gettext('Install') }, disableSelected: false }; this.deviceFirmwareFragment$ .pipe(take(1), switchMap(deviceFirmwareFragment => { if (deviceFirmwareFragment) { const { name, version } = deviceFirmwareFragment; const selected = [{ name, version }]; assign(initialState, { selected }); } const modal = this.bsModal.show(RepositorySelectModalComponent, { ignoreBackdropClick: true, initialState }); if (initialState.repositoryEntriesWithVersionsFn$) { modal.content.repositoryEntriesWithVersions$ = initialState.repositoryEntriesWithVersionsFn$(modal); } modal.content.load.next(); return modal.content.resultEmitter; })) .subscribe(([selectedFirmware]) => { this.handleOperation(selectedFirmware); }); } getRepositoryEntriesWithVersions$(searchTerm$) { return searchTerm$.pipe(distinctUntilChanged(), switchMap(searchTerm => this.repository.listRepositoryEntries(RepositoryType.FIRMWARE, { query: this.repository.getDeviceTypeQuery(RepositoryType.FIRMWARE, this.device$.value), partialName: searchTerm?.name, params: { pageSize: 100 } })), map(({ data }) => data), map(mos => this.getAndAssignRepositoryBinaries(mos)), shareReplay(1)); } getAndAssignRepositoryBinaries(mos) { mos.forEach(mo => { mo.versions = this.repository.listBaseVersions(mo); }); return mos; } addPatch() { const initialState = { repositoryType: RepositoryType.FIRMWARE, repositoryEntriesWithVersions$: this.getRepositoryEntryWithPatches$(), title: gettext('Install firmware'), subTitle: gettext('Available firmwares matching the device type'), icon: 'c8y-firmware', mode: ModalSelectionMode.SINGLE, labels: { ok: gettext('Install') }, disableSelected: false }; this.deviceFirmwareFragment$ .pipe(take(1), switchMap(deviceFirmwareFragment => { if (deviceFirmwareFragment) { const { name, version } = deviceFirmwareFragment; const selected = [{ name, version }]; assign(initialState, { selected }); } const modal = this.bsModal.show(RepositorySelectModalComponent, { ignoreBackdropClick: true, initialState }); modal.content.load.next(); return modal.content.resultEmitter; })) .subscribe(([selectedOption]) => { this.handleOperation(selectedOption); }); } getRepositoryEntryWithPatches$() { return combineLatest(this.repositoryEntry$, this.patches$).pipe(map(([repositoryEntry, patches]) => { return [{ ...repositoryEntry, versions: patches }]; })); } async loadDevice() { this.reloading = true; const deviceId = this.device$.value.id; const device = (await this.inventory.detail(deviceId, { withChildren: false })).data; this.device$.next(device); this.reloading = false; } async handleOperation(selectedFirmware) { const operation = await this.repository.createFirmwareUpdateOperation(this.device$.value, selectedFirmware); this.trackOperation(operation); this.gainsightService.triggerEvent(PRODUCT_EXPERIENCE_REPOSITORY_SHARED.FIRMWARE.EVENTS.DEVICE_TAB, { component: PRODUCT_EXPERIENCE_REPOSITORY_SHARED.FIRMWARE.COMPONENTS.FIRMWARE_DEVICE_TAB, result: PRODUCT_EXPERIENCE_REPOSITORY_SHARED.FIRMWARE.RESULTS.CREATE_FIRMWARE_UPDATE_OPERATION }); } async loadOperation() { const deviceId = this.device$.value.id; const operation = await this.repository.getLastFirmwareUpdateOperation(deviceId); this.trackOperation(operation); } trackOperation(operation) { if ([OperationStatus.SUCCESSFUL, OperationStatus.FAILED].includes(operation?.status)) { this.changesOperation$.next(undefined); } else this.changesOperation$.next(operation); if (this.isInProgress(operation)) { this.repository.observeOperation(operation).subscribe(operationUpdate => { this.changesOperation$.next(operationUpdate); if (operationUpdate.status === OperationStatus.SUCCESSFUL) { this.loadDevice(); } }, operationUpdate => { this.changesOperation$.next(operationUpdate); }); } } isInProgress(operation) { return (operation && [OperationStatus.PENDING, OperationStatus.EXECUTING].includes(operation.status)); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: FirmwareDeviceTabComponent, deps: [{ token: i1.ActivatedRoute }, { token: i2.RepositoryService }, { token: i3.InventoryService }, { token: i4.BsModalService }, { token: i5.GainsightService }], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: FirmwareDeviceTabComponent, selector: "c8y-firmware-device-tab", ngImport: i0, template: "<div class=\"row\">\n <div class=\"col-lg-12 col-lg-max\">\n <div class=\"card split-view--7-5 m-b-0\">\n <div class=\"d-flex d-col flex-grow split-view__list\">\n <div class=\"card-header separator\">\n <div\n class=\"card-title\"\n translate\n >\n Current firmware\n </div>\n </div>\n <div class=\"inner-scroll\">\n <div class=\"card-block p-t-0 p-b-0\">\n <!-- EMPTY STATE -->\n <ng-container *ngIf=\"isEmpty(deviceFirmwareFragment$ | async); else firmwareBlock\">\n <div class=\"c8y-empty-state text-center\">\n <div\n class=\"h1 c8y-icon-duocolor\"\n c8yIcon=\"c8y-firmware\"\n ></div>\n <p>\n <strong translate>No firmware installed.</strong>\n <br />\n <small translate>Click below to install firmware into this device.</small>\n </p>\n </div>\n </ng-container>\n\n <!-- FIRMWARE -->\n <ng-template #firmwareBlock>\n <c8y-list-group class=\"no-border-last\">\n <c8y-li>\n <c8y-li-icon>\n <i c8yIcon=\"c8y-firmware\"></i>\n </c8y-li-icon>\n\n <c8y-li-body *ngIf=\"deviceFirmwareFragment$ | async as deviceFirmwareFragment\">\n <!-- Firmware title -->\n <p class=\"text-medium\">\n {{ deviceFirmwareFragment.name }}\n </p>\n <!-- Firmware description -->\n <div *ngIf=\"repositoryEntry$ | async as repositoryEntry\">\n <span\n class=\"text-label-small m-r-4\"\n translate\n >\n Description\n </span>\n <span>\n {{ repositoryEntry.description }}\n </span>\n </div>\n\n <!-- BASE/PATCH VERSION -->\n <div class=\"d-flex a-i-baseline\">\n <p\n class=\"text-label-small m-r-4\"\n translate\n >\n Version\n </p>\n <p *ngIf=\"deviceFirmwareFragment.version; else versionNotSpecified\">\n {{ deviceFirmwareFragment.version }}\n </p>\n <ng-template #versionNotSpecified>\n <p>\n <em class=\"text-muted\">({{ 'not specified`version`' | translate }})</em>\n </p>\n </ng-template>\n </div>\n\n <!-- ADD PATCH -->\n <button\n class=\"btn btn-xs btn-primary\"\n title=\"{{ 'Patches available' | translate }}\"\n *ngIf=\"\n (supportsFirmwareOperations$ | async) && (this.patches$ | async)?.length > 0\n \"\n (click)=\"addPatch()\"\n [disabled]=\"changesInProgress$ | async\"\n c8yProductExperience\n [actionName]=\"PRODUCT_EXPERIENCE.FIRMWARE.EVENTS.DEVICE_TAB\"\n [actionData]=\"{\n component: PRODUCT_EXPERIENCE.FIRMWARE.COMPONENTS.FIRMWARE_DEVICE_TAB,\n action:\n PRODUCT_EXPERIENCE.FIRMWARE.ACTIONS.OPEN_INSTALL_FIRMWARE_PATCH_DIALOG\n }\"\n >\n {{ 'Patches available' | translate }}\n </button>\n </c8y-li-body>\n </c8y-li>\n </c8y-list-group>\n </ng-template>\n </div>\n </div>\n <div\n class=\"card-footer separator-top\"\n *ngIf=\"supportsFirmwareOperations$ | async\"\n >\n <!-- INSTALL FIRMWARE -->\n <button\n class=\"btn btn-primary\"\n title=\"{{ 'Install firmware' | translate }}\"\n *ngIf=\"isEmpty(deviceFirmwareFragment$ | async)\"\n (click)=\"installFirmware()\"\n c8yProductExperience\n [actionName]=\"PRODUCT_EXPERIENCE.FIRMWARE.EVENTS.DEVICE_TAB\"\n [actionData]=\"{\n component: PRODUCT_EXPERIENCE.FIRMWARE.COMPONENTS.FIRMWARE_DEVICE_TAB,\n action: PRODUCT_EXPERIENCE.FIRMWARE.ACTIONS.OPEN_INSTALL_FIRMWARE_DIALOG\n }\"\n >\n {{ 'Install firmware' | translate }}\n </button>\n\n <!-- REPLACE FIRMWARE -->\n <button\n class=\"btn btn-primary\"\n title=\"{{ 'Replace firmware' | translate }}\"\n *ngIf=\"!isEmpty(deviceFirmwareFragment$ | async)\"\n (click)=\"installFirmware()\"\n [disabled]=\"changesInProgress$ | async\"\n c8yProductExperience\n [actionName]=\"PRODUCT_EXPERIENCE.FIRMWARE.EVENTS.DEVICE_TAB\"\n [actionData]=\"{\n component: PRODUCT_EXPERIENCE.FIRMWARE.COMPONENTS.FIRMWARE_DEVICE_TAB,\n action: PRODUCT_EXPERIENCE.FIRMWARE.ACTIONS.OPEN_REPLACE_FIRMWARE_DIALOG\n }\"\n >\n {{ 'Replace firmware' | translate }}\n </button>\n </div>\n </div>\n <div class=\"inner-scroll d-flex d-col bg-level-1 split-view__detail\">\n <div class=\"card-header separator large-padding sticky-top\">\n <div\n class=\"card-title\"\n translate\n >\n Firmware changes\n </div>\n </div>\n <div class=\"flex-grow\">\n <fieldset\n class=\"card-block large-padding bg-level-2 p-0\"\n id=\"operation-block\"\n *ngIf=\"changesOperation$ | async\"\n >\n <c8y-operation-details [operation]=\"changesOperation$ | async\"></c8y-operation-details>\n </fieldset>\n </div>\n </div>\n </div>\n </div>\n</div>\n", dependencies: [{ kind: "directive", type: i6.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i5.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: i5.C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "component", type: i5.ListGroupComponent, selector: "c8y-list-group" }, { kind: "component", type: i5.ListItemComponent, selector: "c8y-list-item, c8y-li", inputs: ["active", "highlighted", "emptyActions", "dense", "collapsed", "selectable"], outputs: ["collapsedChange"] }, { kind: "component", type: i5.ListItemIconComponent, selector: "c8y-list-item-icon, c8y-li-icon", inputs: ["icon", "status"] }, { kind: "component", type: i5.ListItemBodyComponent, selector: "c8y-list-item-body, c8y-li-body", inputs: ["body"] }, { kind: "directive", type: i5.ProductExperienceDirective, selector: "[c8yProductExperience]", inputs: ["actionName", "actionData", "inherit", "suppressDataOverriding"] }, { kind: "component", type: i7.OperationDetailsComponent, selector: "c8y-operation-details", inputs: ["operation"] }, { kind: "pipe", type: i6.AsyncPipe, name: "async" }, { kind: "pipe", type: i5.C8yTranslatePipe, name: "translate" }] }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: FirmwareDeviceTabComponent, decorators: [{ type: Component, args: [{ selector: 'c8y-firmware-device-tab', template: "<div class=\"row\">\n <div class=\"col-lg-12 col-lg-max\">\n <div class=\"card split-view--7-5 m-b-0\">\n <div class=\"d-flex d-col flex-grow split-view__list\">\n <div class=\"card-header separator\">\n <div\n class=\"card-title\"\n translate\n >\n Current firmware\n </div>\n </div>\n <div class=\"inner-scroll\">\n <div class=\"card-block p-t-0 p-b-0\">\n <!-- EMPTY STATE -->\n <ng-container *ngIf=\"isEmpty(deviceFirmwareFragment$ | async); else firmwareBlock\">\n <div class=\"c8y-empty-state text-center\">\n <div\n class=\"h1 c8y-icon-duocolor\"\n c8yIcon=\"c8y-firmware\"\n ></div>\n <p>\n <strong translate>No firmware installed.</strong>\n <br />\n <small translate>Click below to install firmware into this device.</small>\n </p>\n </div>\n </ng-container>\n\n <!-- FIRMWARE -->\n <ng-template #firmwareBlock>\n <c8y-list-group class=\"no-border-last\">\n <c8y-li>\n <c8y-li-icon>\n <i c8yIcon=\"c8y-firmware\"></i>\n </c8y-li-icon>\n\n <c8y-li-body *ngIf=\"deviceFirmwareFragment$ | async as deviceFirmwareFragment\">\n <!-- Firmware title -->\n <p class=\"text-medium\">\n {{ deviceFirmwareFragment.name }}\n </p>\n <!-- Firmware description -->\n <div *ngIf=\"repositoryEntry$ | async as repositoryEntry\">\n <span\n class=\"text-label-small m-r-4\"\n translate\n >\n Description\n </span>\n <span>\n {{ repositoryEntry.description }}\n </span>\n </div>\n\n <!-- BASE/PATCH VERSION -->\n <div class=\"d-flex a-i-baseline\">\n <p\n class=\"text-label-small m-r-4\"\n translate\n >\n Version\n </p>\n <p *ngIf=\"deviceFirmwareFragment.version; else versionNotSpecified\">\n {{ deviceFirmwareFragment.version }}\n </p>\n <ng-template #versionNotSpecified>\n <p>\n <em class=\"text-muted\">({{ 'not specified`version`' | translate }})</em>\n </p>\n </ng-template>\n </div>\n\n <!-- ADD PATCH -->\n <button\n class=\"btn btn-xs btn-primary\"\n title=\"{{ 'Patches available' | translate }}\"\n *ngIf=\"\n (supportsFirmwareOperations$ | async) && (this.patches$ | async)?.length > 0\n \"\n (click)=\"addPatch()\"\n [disabled]=\"changesInProgress$ | async\"\n c8yProductExperience\n [actionName]=\"PRODUCT_EXPERIENCE.FIRMWARE.EVENTS.DEVICE_TAB\"\n [actionData]=\"{\n component: PRODUCT_EXPERIENCE.FIRMWARE.COMPONENTS.FIRMWARE_DEVICE_TAB,\n action:\n PRODUCT_EXPERIENCE.FIRMWARE.ACTIONS.OPEN_INSTALL_FIRMWARE_PATCH_DIALOG\n }\"\n >\n {{ 'Patches available' | translate }}\n </button>\n </c8y-li-body>\n </c8y-li>\n </c8y-list-group>\n </ng-template>\n </div>\n </div>\n <div\n class=\"card-footer separator-top\"\n *ngIf=\"supportsFirmwareOperations$ | async\"\n >\n <!-- INSTALL FIRMWARE -->\n <button\n class=\"btn btn-primary\"\n title=\"{{ 'Install firmware' | translate }}\"\n *ngIf=\"isEmpty(deviceFirmwareFragment$ | async)\"\n (click)=\"installFirmware()\"\n c8yProductExperience\n [actionName]=\"PRODUCT_EXPERIENCE.FIRMWARE.EVENTS.DEVICE_TAB\"\n [actionData]=\"{\n component: PRODUCT_EXPERIENCE.FIRMWARE.COMPONENTS.FIRMWARE_DEVICE_TAB,\n action: PRODUCT_EXPERIENCE.FIRMWARE.ACTIONS.OPEN_INSTALL_FIRMWARE_DIALOG\n }\"\n >\n {{ 'Install firmware' | translate }}\n </button>\n\n <!-- REPLACE FIRMWARE -->\n <button\n class=\"btn btn-primary\"\n title=\"{{ 'Replace firmware' | translate }}\"\n *ngIf=\"!isEmpty(deviceFirmwareFragment$ | async)\"\n (click)=\"installFirmware()\"\n [disabled]=\"changesInProgress$ | async\"\n c8yProductExperience\n [actionName]=\"PRODUCT_EXPERIENCE.FIRMWARE.EVENTS.DEVICE_TAB\"\n [actionData]=\"{\n component: PRODUCT_EXPERIENCE.FIRMWARE.COMPONENTS.FIRMWARE_DEVICE_TAB,\n action: PRODUCT_EXPERIENCE.FIRMWARE.ACTIONS.OPEN_REPLACE_FIRMWARE_DIALOG\n }\"\n >\n {{ 'Replace firmware' | translate }}\n </button>\n </div>\n </div>\n <div class=\"inner-scroll d-flex d-col bg-level-1 split-view__detail\">\n <div class=\"card-header separator large-padding sticky-top\">\n <div\n class=\"card-title\"\n translate\n >\n Firmware changes\n </div>\n </div>\n <div class=\"flex-grow\">\n <fieldset\n class=\"card-block large-padding bg-level-2 p-0\"\n id=\"operation-block\"\n *ngIf=\"changesOperation$ | async\"\n >\n <c8y-operation-details [operation]=\"changesOperation$ | async\"></c8y-operation-details>\n </fieldset>\n </div>\n </div>\n </div>\n </div>\n</div>\n" }] }], ctorParameters: () => [{ type: i1.ActivatedRoute }, { type: i2.RepositoryService }, { type: i3.InventoryService }, { type: i4.BsModalService }, { type: i5.GainsightService }] }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmlybXdhcmUtZGV2aWNlLXRhYi5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9yZXBvc2l0b3J5L2Zpcm13YXJlL2RldmljZS10YWIvZmlybXdhcmUtZGV2aWNlLXRhYi5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi8uLi9yZXBvc2l0b3J5L2Zpcm13YXJlL2RldmljZS10YWIvZmlybXdhcmUtZGV2aWNlLXRhYi5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQzFDLE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUNqRCxPQUFPLEVBQWtCLGdCQUFnQixFQUFjLGVBQWUsRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUM1RixPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDcEYsT0FBTyxFQUlMLG9DQUFvQyxFQUNwQyw4QkFBOEIsRUFDOUIsaUJBQWlCLEVBQ2pCLGNBQWMsRUFDZixNQUFNLHVDQUF1QyxDQUFDO0FBQy9DLE9BQU8sRUFBRSxNQUFNLEVBQUUsR0FBRyxFQUFFLE9BQU8sRUFBRSxNQUFNLFdBQVcsQ0FBQztBQUNqRCxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDckQsT0FBTyxFQUFFLGVBQWUsRUFBRSxhQUFhLEVBQUUsSUFBSSxFQUFjLEVBQUUsRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUM1RSxPQUFPLEVBQUUsb0JBQW9CLEVBQUUsTUFBTSxFQUFFLEdBQUcsRUFBRSxXQUFXLEVBQUUsU0FBUyxFQUFFLElBQUksRUFBRSxNQUFNLGdCQUFnQixDQUFDOzs7Ozs7Ozs7QUFNakcsTUFBTSxPQUFPLDBCQUEwQjtJQXdEckMsWUFDVSxLQUFxQixFQUNyQixVQUE2QixFQUM3QixTQUEyQixF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LGVBQWUsQ0FBQyxFQUFFO2dCQUNoQixJQUFJLENBQUMsaUJBQWlCLENBQUMsSUFBSSxDQUFDLGVBQWUsQ0FBQyxDQUFDO2dCQUM3QyxJQUFJLGVBQWUsQ0FBQyxNQUFNLEtBQUssZUFBZSxDQUFDLFVBQVUsRUFBRSxDQUFDO29CQUMxRCxJQUFJLENBQUMsVUFBVSxFQUFFLENBQUM7Z0JBQ3BCLENBQUM7WUFDSCxDQUFDLEVBQ0QsZUFBZSxDQUFDLEVBQUU7Z0JBQ2hCLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxJQUFJLENBQUMsZUFBZSxDQUFDLENBQUM7WUFDL0MsQ0FBQyxDQUNGLENBQUM7UUFDSixDQUFDO0lBQ0gsQ0FBQztJQUVPLFlBQVksQ0FBQyxTQUFxQjtRQUN4QyxPQUFPLENBQ0wsU0FBUyxJQUFJLENBQUMsZUFBZSxDQUFDLE9BQU8sRUFBRSxlQUFlLENBQUMsU0FBUyxDQUFDLENBQUMsUUFBUSxDQUFDLFNBQVMsQ0FBQyxNQUFNLENBQUMsQ0FDN0YsQ0FBQztJQUNKLENBQUM7K0dBalBVLDBCQUEwQjttR0FBMUIsMEJBQTBCLCtEQ3RCdkMsNHNNQThKQTs7NEZEeElhLDBCQUEwQjtrQkFKdEMsU0FBUzsrQkFDRSx5QkFBeUIiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDb21wb25lbnQgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IEFjdGl2YXRlZFJvdXRlIH0gZnJvbSAnQGFuZ3VsYXIvcm91dGVyJztcbmltcG9ydCB7IElNYW5hZ2VkT2JqZWN0LCBJbnZlbnRvcnlTZXJ2aWNlLCBJT3BlcmF0aW9uLCBPcGVyYXRpb25TdGF0dXMgfSBmcm9tICdAYzh5L2NsaWVudCc7XG5pbXBvcnQgeyBHYWluc2lnaHRTZXJ2aWNlLCBnZXR0ZXh0LCBNb2RhbFNlbGVjdGlvbk1vZGUgfSBmcm9tICdAYzh5L25neC1jb21wb25lbnRzJztcbmltcG9ydCB7XG4gIERldmljZUZpcm13YXJlLFxuICBGaWx0ZXJDcml0ZXJpYSxcbiAgRmlybXdhcmVCaW5hcnksXG4gIFBST0RVQ1RfRVhQRVJJRU5DRV9SRVBPU0lUT1JZX1NIQVJFRCxcbiAgUmVwb3NpdG9yeVNlbGVjdE1vZGFsQ29tcG9uZW50LFxuICBSZXBvc2l0b3J5U2VydmljZSxcbiAgUmVwb3NpdG9yeVR5cGVcbn0gZnJvbSAnQGM4eS9uZ3gtY29tcG9uZW50cy9yZXBvc2l0b3J5L3NoYXJlZCc7XG5pbXBvcnQgeyBhc3NpZ24sIGdldCwgaXNFbXB0eSB9IGZyb20gJ2xvZGFzaC1lcyc7XG5pbXBvcnQgeyBCc01vZGFsU2VydmljZSB9IGZyb20gJ25neC1ib290c3RyYXAvbW9kYWwnO1xuaW1wb3J0IHsgQmVoYXZpb3JTdWJqZWN0LCBjb21iaW5lTGF0ZXN0LCBmcm9tLCBPYnNlcnZhYmxlLCBvZiB9IGZyb20gJ3J4anMnO1xuaW1wb3J0IHsgZGlzdGluY3RVbnRpbENoYW5nZWQsIGZpbHRlciwgbWFwLCBzaGFyZVJlcGxheSwgc3dpdGNoTWFwLCB0YWtlIH0gZnJvbSAncnhqcy9vcGVyYXRvcnMnO1xuXG5AQ29tcG9uZW50KHtcbiAgc2VsZWN0b3I6ICdjOHktZmlybXdhcmUtZGV2aWNlLXRhYicsXG4gIHRlbXBsYXRlVXJsOiAnZmlybXdhcmUtZGV2aWNlLXRhYi5jb21wb25lbnQuaHRtbCdcbn0pXG5leHBvcnQgY2xhc3MgRmlybXdhcmVEZXZpY2VUYWJDb21wb25lbnQge1xuICBQUk9EVUNUX0VYUEVSSUVOQ0UgPSBQUk9EVUNUX0VYUEVSSUVOQ0VfUkVQT1NJVE9SWV9TSEFSRUQ7XG4gIGlzRW1wdHkgPSBpc0VtcHR5O1xuICByZWxvYWRpbmcgPSBmYWxzZTtcbiAgZGV2aWNlJDogQmVoYXZpb3JTdWJqZWN0PElNYW5hZ2VkT2JqZWN0PiA9IG5ldyBCZWhhdmlvclN1YmplY3QoXG4gICAgdGhpcy5yb3V0ZS5wYXJlbnQuc25hcHNob3QuZGF0YS5jb250ZXh0RGF0YVxuICApO1xuICBkZXZpY2VGaXJtd2FyZUZyYWdtZW50JDogT2JzZXJ2YWJsZTxEZXZpY2VGaXJtd2FyZT4gPSB0aGlzLmRldmljZSQucGlwZShcbiAgICBtYXAoZGV2aWNlID0+IGRldmljZS5jOHlfRmlybXdhcmUpXG4gICk7XG4gIGZpcm13YXJlQmluYXJ5JDogT2JzZXJ2YWJsZTxJTWFuYWdlZE9iamVjdD4gPSB0aGlzLmRldmljZUZpcm13YXJlRnJhZ21lbnQkLnBpcGUoXG4gICAgZmlsdGVyKGRldmljZUZpcm13YXJlRnJhZ21lbnQgPT4gIWlzRW1wdHkoZGV2aWNlRmlybXdhcmVGcmFnbWVudCkpLFxuICAgIHN3aXRjaE1hcChkZXZpY2VGaXJtd2FyZUZyYWdtZW50ID0+XG4gICAgICBmcm9tKFxuICAgICAgICB0aGlzLnJlcG9zaXRvcnkuZ2V0UmVwb3NpdG9yeUJpbmFyeU1vQnlWZXJzaW9uKFxuICAgICAgICAgIGRldmljZUZpcm13YXJlRnJhZ21lbnQsXG4gICAgICAgICAgUmVwb3NpdG9yeVR5cGUuRklSTVdBUkVcbiAgICAgICAgKVxuICAgICAgKVxuICAgICksXG4gICAgc2hhcmVSZXBsYXkoMSlcbiAgKTtcbiAgcmVwb3NpdG9yeUVudHJ5JDogT2JzZXJ2YWJsZTxJTWFuYWdlZE9iamVjdD4gPSB0aGlzLmZpcm13YXJlQmluYXJ5JC5waXBlKFxuICAgIHN3aXRjaE1hcChtbyA9PiB0aGlzLnJlcG9zaXRvcnkuZ2V0UmVwb3NpdG9yeUVudHJ5TU8kKG1vKSksXG4gICAgc2hhcmVSZXBsYXkoMSlcbiAgKTtcbiAgcGF0Y2hlcyQ6IE9ic2VydmFibGU8SU1hbmFnZWRPYmplY3RbXT4gPSBjb21iaW5lTGF0ZXN0KFxuICAgIHRoaXMuZmlybXdhcmVCaW5hcnkkLFxuICAgIHRoaXMucmVwb3NpdG9yeUVudHJ5JFxuICApLnBpcGUoXG4gICAgc3dpdGNoTWFwKChbZmlybXdhcmVCaW5hcnksIHJlcG9zaXRvcnlFbnRyeV0pID0+IHtcbiAgICAgIGlmIChyZXBvc2l0b3J5RW50cnkgJiYgZmlybXdhcmVCaW5hcnkpIHtcbiAgICAgICAgY29uc3QgdmVyc2lvbjogc3RyaW5nID0gdGhpcy5yZXBvc2l0b3J5LmdldEJhc2VWZXJzaW9uRnJvbU1PKFxuICAgICAgICAgIGZpcm13YXJlQmluYXJ5IGFzIEZpcm13YXJlQmluYXJ5XG4gICAgICAgICk7XG5cbiAgICAgICAgcmV0dXJuIGZyb20odGhpcy5yZXBvc2l0b3J5Lmxpc3RQYXRjaFZlcnNpb25zKHJlcG9zaXRvcnlFbnRyeSwgdmVyc2lvbikpLnBpcGUoXG4gICAgICAgICAgbWFwKCh7IGRhdGEgfSkgPT4gZGF0YSlcbiAgICAgICAgKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHJldHVybiBvZihbXSk7XG4gICAgICB9XG4gICAgfSksXG4gICAgc2hhcmVSZXBsYXkoMSlcbiAgKTtcbiAgc3VwcG9ydHNGaXJtd2FyZU9wZXJhdGlvbnMkOiBPYnNlcnZhYmxlPGJvb2xlYW4+ID0gdGhpcy5kZXZpY2UkLnBpcGUoXG4gICAgbWFwKFxuICAgICAgKGRldmljZTogSU1hbmFnZWRPYmplY3QpID0+XG4gICAgICAgIGdldChkZXZpY2UsICdjOHlfU3VwcG9ydGVkT3BlcmF0aW9ucycsIFtdKS5pbmRleE9mKCdjOHlfRmlybXdhcmUnKSA+IC0xXG4gICAgKVxuICApO1xuICBjaGFuZ2VzT3BlcmF0aW9uJCA9IG5ldyBCZWhhdmlvclN1YmplY3Q8SU9wZXJhdGlvbj4obnVsbCk7XG4gIGNoYW5nZXNJblByb2dyZXNzJDogT2JzZXJ2YWJsZTxib29sZWFuPiA9IHRoaXMuY2hhbmdlc09wZXJhdGlvbiQucGlwZShcbiAgICBtYXAob3BlcmF0aW9uID0+IHRoaXMuaXNJblByb2dyZXNzKG9wZXJhdGlvbikpXG4gICk7XG5cbiAgY29uc3RydWN0b3IoXG4gICAgcHJpdmF0ZSByb3V0ZTogQWN0aXZhdGVkUm91dGUsXG4gICAgcHJpdmF0ZSByZXBvc2l0b3J5OiBSZXBvc2l0b3J5U2VydmljZSxcbiAgICBwcml2YXRlIGludmVudG9yeTogSW52ZW50b3J5U2VydmljZSxcbiAgICBwcml2YXRlIGJzTW9kYWw6IEJzTW9kYWxTZXJ2aWNlLFxuICAgIHByaXZhdGUgZ2FpbnNpZ2h0U2VydmljZTogR2FpbnNpZ2h0U2VydmljZVxuICApIHt9XG5cbiAgYXN5bmMgbmdPbkluaXQoKSB7XG4gICAgLy8gVE9ETyBjaGVjayByb3V0ZSBzbmFwc2hvdCwgd2h5IGlzIG5vdCByZWZyZXNoaW5nIGRldmljZS5cbiAgICAvLyBTY2VuYXJpbzogbWlzc2luZyBkZXZpY2VGaXJtd2FyZUZyYWdtZW50ID0+IGluc3RhbGwgbmV3IHZlcnNpb24gPT4gc3dpdGNoIHRhYnMuXG4gICAgLy8gRXhwZWN0ZWQ6IGRldmljZSBzaG91bGQgYmUgc2V0LlxuICAgIGF3YWl0IHRoaXMubG9hZERldmljZSgpO1xuICAgIGF3YWl0IHRoaXMubG9hZE9wZXJhdGlvbigpO1xuICB9XG5cbiAgaW5zdGFsbEZpcm13YXJlKCkge1xuICAgIGNvbnN0IGluaXRpYWxTdGF0ZTogUGFydGlhbDxSZXBvc2l0b3J5U2VsZWN0TW9kYWxDb21wb25lbnQ+ICYge1xuICAgICAgcmVwb3NpdG9yeUVudHJpZXNXaXRoVmVyc2lvbnNGbiQ6IChtb2RhbDogYW55KSA9PiBPYnNlcnZhYmxlPElNYW5hZ2VkT2JqZWN0W10+O1xuICAgIH0gPSB7XG4gICAgICByZXBvc2l0b3J5RW50cmllc1dpdGhWZXJzaW9ucyQ6IG9mKFtdKSxcbiAgICAgIHJlcG9zaXRvcnlFbnRyaWVzV2l0aFZlcnNpb25zRm4kOiBtb2RhbCA9PlxuICAgICAgICB0aGlzLmdldFJlcG9zaXRvcnlFbnRyaWVzV2l0aFZlcnNpb25zJChtb2RhbC5jb250ZW50LnNlYXJjaFRlcm0pLFxuICAgICAgcmVwb3NpdG9yeVR5cGU6IFJlcG9zaXRvcnlUeXBlLkZJUk1XQVJFLFxuICAgICAgdGl0bGU6IGdldHRleHQoJ0luc3RhbGwgZmlybXdhcmUnKSxcbiAgICAgIHN1YlRpdGxlOiBnZXR0ZXh0KCdBdmFpbGFibGUgZmlybXdhcmVzIG1hdGNoaW5nIHRoZSBkZXZpY2UgdHlwZScpLFxuICAgICAgaWNvbjogJ2M4eS1maXJtd2FyZScsXG4gICAgICBtb2RlOiBNb2RhbFNlbGVjdGlvbk1vZGUuU0lOR0xFLFxuICAgICAgbGFiZWxzOiB7IG9rOiBnZXR0ZXh0KCdJbnN0YWxsJykgfSxcbiAgICAgIGRpc2FibGVTZWxlY3RlZDogZmFsc2VcbiAgICB9O1xuXG4gICAgdGhpcy5kZXZpY2VGaXJtd2FyZUZyYWdtZW50JFxuICAgICAgLnBpcGUoXG4gICAgICAgIHRha2UoMSksXG4gICAgICAgIHN3aXRjaE1hcChkZXZpY2VGaXJtd2FyZUZyYWdtZW50ID0+IHtcbiAgICAgICAgICBpZiAoZGV2aWNlRmlybXdhcmVGcmFnbWVudCkge1xuICAgICAgICAgICAgY29uc3QgeyBuYW1lLCB2ZXJzaW9uIH0gPSBkZXZpY2VGaXJtd2FyZUZyYWdtZW50O1xuICAgICAgICAgICAgY29uc3Qgc2VsZWN0ZWQgPSBbeyBuYW1lLCB2ZXJzaW9uIH1dO1xuICAgICAgICAgICAgYXNzaWduKGluaXRpYWxTdGF0ZSwgeyBzZWxlY3RlZCB9KTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBjb25zdCBtb2RhbCA9IHRoaXMuYnNNb2RhbC5zaG93KFJlcG9zaXRvcnlTZWxlY3RNb2RhbENvbXBvbmVudCwge1xuICAgICAgICAgICAgaWdub3JlQmFja2Ryb3BDbGljazogdHJ1ZSxcbiAgICAgICAgICAgIGluaXRpYWxTdGF0ZVxuICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgaWYgKGluaXRpYWxTdGF0ZS5yZXBvc2l0b3J5RW50cmllc1dpdGhWZXJzaW9uc0ZuJCkge1xuICAgICAgICAgICAgbW9kYWwuY29udGVudC5yZXBvc2l0b3J5RW50cmllc1dpdGhWZXJzaW9ucyQgPVxuICAgICAgICAgICAgICBpbml0aWFsU3RhdGUucmVwb3NpdG9yeUVudHJpZXNXaXRoVmVyc2lvbnNGbiQobW9kYWwpO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIG1vZGFsLmNvbnRlbnQubG9hZC5uZXh0KCk7XG5cbiAgICAgICAgICByZXR1cm4gbW9kYWwuY29udGVudC5yZXN1bHRFbWl0dGVyO1xuICAgICAgICB9KVxuICAgICAgKVxuICAgICAgLnN1YnNjcmliZSgoW3NlbGVjdGVkRmlybXdhcmVdKSA9PiB7XG4gICAgICAgIHRoaXMuaGFuZGxlT3BlcmF0aW9uKHNlbGVjdGVkRmlybXdhcmUpO1xuICAgICAgfSk7XG4gIH1cblxuICBnZXRSZXBvc2l0b3J5RW50cmllc1dpdGhWZXJzaW9ucyQoc2VhcmNoVGVybSQ6IEJlaGF2aW9yU3ViamVjdDxGaWx0ZXJDcml0ZXJpYT4pIHtcbiAgICByZXR1cm4gc2VhcmNoVGVybSQucGlwZShcbiAgICAgIGRpc3RpbmN0VW50aWxDaGFuZ2VkKCksXG4gICAgICBzd2l0Y2hNYXAoc2VhcmNoVGVybSA9PlxuICAgICAgICB0aGlzLnJlcG9zaXRvcnkubGlzdFJlcG9zaXRvcnlFbnRyaWVzKFJlcG9zaXRvcnlUeXBlLkZJUk1XQVJFLCB7XG4gICAgICAgICAgcXVlcnk6IHRoaXMucmVwb3NpdG9yeS5nZXREZXZpY2VUeXBlUXVlcnkoUmVwb3NpdG9yeVR5cGUuRklSTVdBUkUsIHRoaXMuZGV2aWNlJC52YWx1ZSksXG4gICAgICAgICAgcGFydGlhbE5hbWU6IHNlYXJjaFRlcm0/Lm5hbWUsXG4gICAgICAgICAgcGFyYW1zOiB7IHBhZ2VTaXplOiAxMDAgfVxuICAgICAgICB9KVxuICAgICAgKSxcbiAgICAgIG1hcCgoeyBkYXRhIH0pID0+IGRhdGEpLFxuICAgICAgbWFwKG1vcyA9PiB0aGlzLmdldEFuZEFzc2lnblJlcG9zaXRvcnlCaW5hcmllcyhtb3MpKSxcbiAgICAgIHNoYXJlUmVwbGF5KDEpXG4gICAgKTtcbiAgfVxuXG4gIGdldEFuZEFzc2lnblJlcG9zaXRvcnlCaW5hcmllcyhtb3M6IElNYW5hZ2VkT2JqZWN0W10pIHtcbiAgICBtb3MuZm9yRWFjaChtbyA9PiB7XG4gICAgICBtby52ZXJzaW9ucyA9IHRoaXMucmVwb3NpdG9yeS5saXN0QmFzZVZlcnNpb25zKG1vKTtcbiAgICB9KTtcbiAgICByZXR1cm4gbW9zO1xuICB9XG5cbiAgYWRkUGF0Y2goKSB7XG4gICAgY29uc3QgaW5pdGlhbFN0YXRlOiBQYXJ0aWFsPFJlcG9zaXRvcnlTZWxlY3RNb2RhbENvbXBvbmVudD4gJiB7XG4gICAgICByZXBvc2l0b3J5RW50cmllc1dpdGhWZXJzaW9ucyQ6IE9ic2VydmFibGU8SU1hbmFnZWRPYmplY3RbXT47XG4gICAgfSA9IHtcbiAgICAgIHJlcG9zaXRvcnlUeXBlOiBSZXBvc2l0b3J5VHlwZS5GSVJNV0FSRSxcbiAgICAgIHJlcG9zaXRvcnlFbnRyaWVzV2l0aFZlcnNpb25zJDogdGhpcy5nZXRSZXBvc2l0b3J5RW50cnlXaXRoUGF0Y2hlcyQoKSxcbiAgICAgIHRpdGxlOiBnZXR0ZXh0KCdJbnN0YWxsIGZpcm13YXJlJyksXG4gICAgICBzdWJUaXRsZTogZ2V0dGV4dCgnQXZhaWxhYmxlIGZpcm13YXJlcyBtYXRjaGluZyB0aGUgZGV2aWNlIHR5cGUnKSxcbiAgICAgIGljb246ICdjOHktZmlybXdhcmUnLFxuICAgICAgbW9kZTogTW9kYWxTZWxlY3Rpb25Nb2RlLlNJTkdMRSxcbiAgICAgIGxhYmVsczogeyBvazogZ2V0dGV4dCgnSW5zdGFsbCcpIH0sXG4gICAgICBkaXNhYmxlU2VsZWN0ZWQ6IGZhbHNlXG4gICAgfTtcblxuICAgIHRoaXMuZGV2aWNlRmlybXdhcmVGcmFnbWVudCRcbiAgICAgIC5waXBlKFxuICAgICAgICB0YWtlKDEpLFxuICAgICAgICBzd2l0Y2hNYXAoZGV2aWNlRmlybXdhcmVGcmFnbWVudCA9PiB7XG4gICAgICAgICAgaWYgKGRldmljZUZpcm13YXJlRnJhZ21lbnQpIHtcbiAgICAgICAgICAgIGNvbnN0IHsgbmFtZSwgdmVyc2lvbiB9ID0gZGV2aWNlRmlybXdhcmVGcmFnbWVudDtcbiAgICAgICAgICAgIGNvbnN0IHNlbGVjdGVkID0gW3sgbmFtZSwgdmVyc2lvbiB9XTtcbiAgICAgICAgICAgIGFzc2lnbihpbml0aWFsU3RhdGUsIHsgc2VsZWN0ZWQgfSk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgY29uc3QgbW9kYWwgPSB0aGlzLmJzTW9kYWwuc2hvdyhSZXBvc2l0b3J5U2VsZWN0TW9kYWxDb21wb25lbnQsIHtcbiAgICAgICAgICAgIGlnbm9yZUJhY2tkcm9wQ2xpY2s6IHRydWUsXG4gICAgICAgICAgICBpbml0aWFsU3RhdGVcbiAgICAgICAgICB9KTtcbiAgICAgICAgICBtb2RhbC5jb250ZW50LmxvYWQubmV4dCgpO1xuXG4gICAgICAgICAgcmV0dXJuIG1vZGFsLmNvbnRlbnQucmVzdWx0RW1pdHRlcjtcbiAgICAgICAgfSlcbiAgICAgIClcbiAgICAgIC5zdWJzY3JpYmUoKFtzZWxlY3RlZE9wdGlvbl0pID0+IHtcbiAgICAgICAgdGhpcy5oYW5kbGVPcGVyYXRpb24oc2VsZWN0ZWRPcHRpb24pO1xuICAgICAgfSk7XG4gIH1cblxuICBnZXRSZXBvc2l0b3J5RW50cnlXaXRoUGF0Y2hlcyQoKSB7XG4gICAgcmV0dXJuIGNvbWJpbmVMYXRlc3QodGhpcy5yZXBvc2l0b3J5RW50cnkkLCB0aGlzLnBhdGNoZXMkKS5waXBlKFxuICAgICAgbWFwKChbcmVwb3NpdG9yeUVudHJ5LCBwYXRjaGVzXSkgPT4ge1xuICAgICAgICByZXR1cm4gW3sgLi4ucmVwb3NpdG9yeUVudHJ5LCB2ZXJzaW9uczogcGF0Y2hlcyB9XTtcbiAgICAgIH0pXG4gICAgKTtcbiAgfVxuXG4gIGFzeW5jIGxvYWREZXZpY2UoKSB7XG4gICAgdGhpcy5yZWxvYWRpbmcgPSB0cnVlO1xuICAgIGNvbnN0IGRldmljZUlkID0gdGhpcy5kZXZpY2UkLnZhbHVlLmlkO1xuICAgIGNvbnN0IGRldmljZSA9IChhd2FpdCB0aGlzLmludmVudG9yeS5kZXRhaWwoZGV2aWNlSWQsIHsgd2l0aENoaWxkcmVuOiBmYWxzZSB9KSkuZGF0YTtcbiAgICB0aGlzLmRldmljZSQubmV4dChkZXZpY2UpO1xuICAgIHRoaXMucmVsb2FkaW5nID0gZmFsc2U7XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIGhhbmRsZU9wZXJhdGlvbihzZWxlY3RlZEZpcm13YXJlKSB7XG4gICAgY29uc3Qgb3BlcmF0aW9uID0gYXdhaXQgdGhpcy5yZXBvc2l0b3J5LmNyZWF0ZUZpcm13YXJlVXBkYXRlT3BlcmF0aW9uKFxuICAgICAgdGhpcy5kZXZpY2UkLnZhbHVlLFxuICAgICAgc2VsZWN0ZWRGaXJtd2FyZVxuICAgICk7XG4gICAgdGhpcy50cmFja09wZXJhdGlvbihvcGVyYXRpb24pO1xuICAgIHRoaXMuZ2FpbnNpZ2h0U2VydmljZS50cmlnZ2VyRXZlbnQoXG4gICAgICBQUk9EVUNUX0VYUEVSSUVOQ0VfUkVQT1NJVE9SWV9TSEFSRUQuRklSTVdBUkUuRVZFTlRTLkRFVklDRV9UQUIsXG4gICAgICB7XG4gICAgICAgIGNvbXBvbmVudDogUFJPRFVDVF9FWFBFUklFTkNFX1JFUE9TSVRPUllfU0hBUkVELkZJUk1XQVJFLkNPTVBPTkVOVFMuRklSTVdBUkVfREVWSUNFX1RBQixcbiAgICAgICAgcmVzdWx0OlxuICAgICAgICAgIFBST0RVQ1RfRVhQRVJJRU5DRV9SRVBPU0lUT1JZX1NIQVJFRC5GSVJNV0FSRS5SRVNVTFRTLkNSRUFURV9GSVJNV0FSRV9VUERBVEVfT1BFUkFUSU9OXG4gICAgICB9XG4gICAgKTtcbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgbG9hZE9wZXJhdGlvbigpIHtcbiAgICBjb25zdCBkZXZpY2VJZCA9IHRoaXMuZGV2aWNlJC52YWx1ZS5pZDtcbiAgICBjb25zdCBvcGVyYXRpb24gPSBhd2FpdCB0aGlzLnJlcG9zaXRvcnkuZ2V0TGFzdEZpcm13YXJlVXBkYXRlT3BlcmF0aW9uKGRldmljZUlkKTtcbiAgICB0aGlzLnRyYWNrT3BlcmF0aW9uKG9wZXJhdGlvbik7XG4gIH1cblxuICBwcml2YXRlIHRyYWNrT3BlcmF0aW9uKG9wZXJhdGlvbjogSU9wZXJhdGlvbikge1xuICAgIGlmIChbT3BlcmF0aW9uU3RhdHVzLlNVQ0NFU1NGVUwsIE9wZXJhdGlvblN0YXR1cy5GQUlMRURdLmluY2x1ZGVzKG9wZXJhdGlvbj8uc3RhdHVzKSkge1xuICAgICAgdGhpcy5jaGFuZ2VzT3BlcmF0aW9uJC5uZXh0KHVuZGVmaW5lZCk7XG4gICAgfSBlbHNlIHRoaXMuY2hhbmdlc09wZXJhdGlvbiQubmV4dChvcGVyYXRpb24pO1xuXG4gICAgaWYgKHRoaXMuaXNJblByb2dyZXNzKG9wZXJhdGlvbikpIHtcbiAgICAgIHRoaXMucmVwb3NpdG9yeS5vYnNlcnZlT3BlcmF0aW9uKG9wZXJhdGlvbikuc3Vic2NyaWJlKFxuICAgICAgICBvcGVyYXRpb25VcGRhdGUgPT4ge1xuICAgICAgICAgIHRoaXMuY2hhbmdlc09wZXJhdGlvbiQubmV4dChvcGVyYXRpb25VcGRhdGUpO1xuICAgICAgICAgIGlmIChvcGVyYXRpb25VcGRhdGUuc3RhdHVzID09PSBPcGVyYXRpb25TdGF0dXMuU1VDQ0VTU0ZVTCkge1xuICAgICAgICAgICAgdGhpcy5sb2FkRGV2aWNlKCk7XG4gICAgICAgICAgfVxuICAgICAgICB9LFxuICAgICAgICBvcGVyYXRpb25VcGRhdGUgPT4ge1xuICAgICAgICAgIHRoaXMuY2hhbmdlc09wZXJhdGlvbiQubmV4dChvcGVyYXRpb25VcGRhdGUpO1xuICAgICAgICB9XG4gICAgICApO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgaXNJblByb2dyZXNzKG9wZXJhdGlvbjogSU9wZXJhdGlvbikge1xuICAgIHJldHVybiAoXG4gICAgICBvcGVyYXRpb24gJiYgW09wZXJhdGlvblN0YXR1cy5QRU5ESU5HLCBPcGVyYXRpb25TdGF0dXMuRVhFQ1VUSU5HXS5pbmNsdWRlcyhvcGVyYXRpb24uc3RhdHVzKVxuICAgICk7XG4gIH1cbn1cbiIsIjxkaXYgY2xhc3M9XCJyb3dcIj5cbiAgPGRpdiBjbGFzcz1cImNvbC1sZy0xMiBjb2wtbGctbWF4XCI+XG4gICAgPGRpdiBjbGFzcz1cImNhcmQgc3BsaXQtdmlldy0tNy01IG0tYi0wXCI+XG4gICAgICA8ZGl2IGNsYXNzPVwiZC1mbGV4IGQtY29sIGZsZXgtZ3JvdyBzcGxpdC12aWV3X19saXN0XCI+XG4gICAgICAgIDxkaXYgY2xhc3M9XCJjYXJkLWhlYWRlciBzZXBhcmF0b3JcIj5cbiAgICAgICAgICA8ZGl2XG4gICAgICAgICAgICBjbGFzcz1cImNhcmQtdGl0bGVcIlxuICAgICAgICAgICAgdHJhbnNsYXRlXG4gICAgICAgICAgPlxuICAgICAgICAgICAgQ3VycmVudCBmaXJtd2FyZVxuICAgICAgICAgIDwvZGl2PlxuICAgICAgICA8L2Rpdj5cbiAgICAgICAgPGRpdiBjbGFzcz1cImlubmVyLXNjcm9sbFwiPlxuICAgICAgICAgIDxkaXYgY2xhc3M9XCJjYXJkLWJsb2NrIHAtdC0wIHAtYi0wXCI+XG4gICAgICAgICAgICA8IS0tIEVNUFRZIFNUQVRFIC0tPlxuICAgICAgICAgICAgPG5nLWNvbnRhaW5lciAqbmdJZj1cImlzRW1wdHkoZGV2aWNlRmlybXdhcmVGcmFnbWVudCQgfCBhc3luYyk7IGVsc2UgZmlybXdhcmVCbG9ja1wiPlxuICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwiYzh5LWVtcHR5LXN0YXRlIHRleHQtY2VudGVyXCI+XG4gICAgICAgICAgICAgICAgPGRpdlxuICAgICAgICAgICAgICAgICAgY2xhc3M9XCJoMSBjOHktaWNvbi1kdW9jb2xvclwiXG4gICAgICAgICAgICAgICAgICBjOHlJY29uPVwiYzh5LWZpcm13YXJlXCJcbiAgICAgICAgICAgICAgICA+PC9kaXY+XG4gICAgICAgICAgICAgICAgPHA+XG4gICAgICAgICAgICAgICAgICA8c3Ryb25nIHRyYW5zbGF0ZT5ObyBmaXJtd2FyZSBpbnN0YWxsZWQuPC9zdHJvbmc+XG4gICAgICAgICAgICAgICAgICA8YnIgLz5cbiAgICAgICAgICAgICAgICAgIDxzbWFsbCB0cmFuc2xhdGU+Q2xpY2sgYmVsb3cgdG8gaW5zdGFsbCBmaXJtd2FyZSBpbnRvIHRoaXMgZGV2aWNlLjwvc21hbGw+XG4gICAgICAgICAgICAgICAgPC9wPlxuICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgIDwvbmctY29udGFpbmVyPlxuXG4gICAgICAgICAgICA8IS0tIEZJUk1XQVJFIC0tPlxuICAgICAgICAgICAgPG5nLXRlbXBsYXRlICNmaXJtd2FyZUJsb2NrPlxuICAgICAgICAgICAgICA8Yzh5LWxpc3QtZ3JvdXAgY2xhc3M9XCJuby1ib3JkZXItbGFzdFwiPlxuICAgICAgICAgICAgICAgIDxjOHktbGk+XG4gICAgICAgICAgICAgICAgICA8Yzh5LWxpLWljb24+XG4gICAgICAgICAgICAgICAgICAgIDxpIGM4eUljb249XCJjOHktZmlybXdhcmVcIj48L2k+XG4gICAgICAgICAgICAgICAgICA8L2M4eS1saS1pY29uPlxuXG4gICAgICAgICAgICAgICAgICA8Yzh5LWxpLWJvZHkgKm5nSWY9XCJkZXZpY2VGaXJtd2FyZUZyYWdtZW50JCB8IGFzeW5jIGFzIGRldmljZUZpcm13YXJlRnJhZ21lbnRcIj5cbiAgICAgICAgICAgICAgICAgICAgPCEtLSBGaXJtd2FyZSB0aXRsZSAtLT5cbiAgICAgICAgICAgICAgICAgICAgPHAgY2xhc3M9XCJ0ZXh0LW1lZGl1bVwiPlxuICAgICAgICAgICAgICAgICAgICAgIHt7IGRldmljZUZpcm13YXJlRnJhZ21lbnQubmFtZSB9fVxuICAgICAgICAgICAgICAgICAgICA8L3A+XG4gICAgICAgICAgICAgICAgICAgIDwhLS0gRmlybXdhcmUgZGVzY3JpcHRpb24gLS0+XG4gICAgICAgICAgICAgICAgICAgIDxkaXYgKm5nSWY9XCJyZXBvc2l0b3J5RW50cnkkIHwgYXN5bmMgYXMgcmVwb3NpdG9yeUVudHJ5XCI+XG4gICAgICAgICAgICAgICAgICAgICAgPHNwYW5cbiAgICAgICAgICAgICAgICAgICAgICAgIGNsYXNzPVwidGV4dC1sYWJlbC1zbWFsbCBtLXItNFwiXG4gICAgICAgICAgICAgICAgICAgICAgICB0cmFuc2xhdGVcbiAgICAgICAgICAgICAgICAgICAgICA+XG4gICAgICAgICAgICAgICAgICAgICAgICBEZXNjcmlwdGlvblxuICAgICAgICAgICAgICAgICAgICAgIDwvc3Bhbj5cbiAgICAgICAgICAgICAgICAgICAgICA8c3Bhbj5cbiAgICAgICAgICAgICAgICAgICAgICAgIHt7IHJlcG9zaXRvcnlFbnRyeS5kZXNjcmlwdGlvbiB9fVxuICAgICAgICAgICAgICAgICAgICAgIDwvc3Bhbj5cbiAgICAgICAgICAgICAgICAgICAgPC9kaXY+XG5cbiAgICAgICAgICAgICAgICAgICAgPCEtLSBCQVNFL1BBVENIIFZFUlNJT04gLS0+XG4gICAgICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJkLWZsZXggYS1pLWJhc2VsaW5lXCI+XG4gICAgICAgICAgICAgICAgICAgICAgPHBcbiAgICAgICAgICAgICAgICAgICAgICAgIGNsYXNzPVwidGV4dC1sYWJlbC1zbWFsbCBtLXItNFwiXG4gICAgICAgICAgICAgICAgICAgICAgICB0cmFuc2xhdGVcbiAgICAgICAgICAgICAgICAgICAgICA+XG4gICAgICAgICAgICAgICAgICAgICAgICBWZXJzaW9uXG4gICAgICAgICAgICAgICAgICAgICAgPC9wPlxuICAgICAgICAgICAgICAgICAgICAgIDxwICpuZ0lmPVwiZGV2aWNlRmlybXdhcmVGcmFnbWVudC52ZXJzaW9uOyBlbHNlIHZlcnNpb25Ob3RTcGVjaWZpZWRcIj5cbiAgICAgICAgICAgICAgICAgICAgICAgIHt7IGRldmljZUZpcm13YXJlRnJhZ21lbnQudmVyc2lvbiB9fVxuICAgICAgICAgICAgICAgICAgICAgIDwvcD5cbiAgICAgICAgICAgICAgICAgICAgICA8bmctdGVtcGxhdGUgI3ZlcnNpb25Ob3RTcGVjaWZpZWQ+XG4gICAgICAgICAgICAgICAgICAgICAgICA8cD5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgPGVtIGNsYXNzPVwidGV4dC1tdXRlZFwiPih7eyAnbm90IHNwZWNpZmllZGB2ZXJzaW9uYCcgfCB0cmFuc2xhdGUgfX0pPC9lbT5cbiAgICAgICAgICAgICAgICAgICAgICAgIDwvcD5cbiAgICAgICAgICAgICAgICAgICAgICA8L25nLXRlbXB