UNPKG

@c8y/ngx-components

Version:

Angular modules for Cumulocity IoT applications

190 lines 36 kB
import { Component, Input } from '@angular/core'; import { OperationService, OperationStatus, UserService } from '@c8y/client'; import { AlertService, AppStateService, OperationRealtimeService, Permissions } from '@c8y/ngx-components'; import { DeviceConfigurationOperation, RepositoryService } from '@c8y/ngx-components/repository/shared'; import { saveAs } from 'file-saver'; import { cloneDeep } from 'lodash-es'; import { BsModalService } from 'ngx-bootstrap/modal'; import { map } from 'rxjs/operators'; import { DeviceConfigurationService } from './device-configuration.service'; import { SaveToRepositoryComponent } from './save-to-repository.component'; import * as i0 from "@angular/core"; import * as i1 from "./device-configuration.service"; import * as i2 from "@c8y/ngx-components"; import * as i3 from "ngx-bootstrap/modal"; import * as i4 from "@c8y/client"; import * as i5 from "@c8y/ngx-components/repository/shared"; import * as i6 from "@angular/common"; import * as i7 from "@c8y/ngx-components/operations/operation-details"; import * as i8 from "./source-code-preview.component"; export class ConfigurationPreviewComponent { set configurationType(type) { this._configurationType = type; this.setOperation(type); } get configurationType() { return this._configurationType; } constructor(deviceConfigurationService, operationRealtime, bsModal, user, appState, repositoryService, operationService, alertService) { this.deviceConfigurationService = deviceConfigurationService; this.operationRealtime = operationRealtime; this.bsModal = bsModal; this.user = user; this.appState = appState; this.repositoryService = repositoryService; this.operationService = operationService; this.alertService = alertService; this.isLegacy = false; this.canCallAction = true; this.deviceConfigurationOperation = DeviceConfigurationOperation; } async ngOnInit() { this.setCanCallAction(); this.setOperation(this._configurationType); this.operationsSubscription = this.operationRealtime .onAll$(this.device.id) .pipe(map(({ data }) => data)) .subscribe(operation => { this.updatePreview(operation); }); } async setOperation(configType) { const operationList = await this.repositoryService.getConfigFileOperationList(this.device.id, this.operationToTrigger); const operation = this.isLegacy ? operationList.find(op => op[this.operationToTrigger] && !op[this.operationToTrigger].type) : operationList.find(op => op[this.operationToTrigger].type === configType); this.operation = operation && operation.status !== OperationStatus.SUCCESSFUL ? operation : undefined; } setCanCallAction() { this.canCallAction = this.deviceConfigurationService.hasAnySupportedOperation(this.device, this.operationToTrigger); } async createDeviceOperation() { let operationCfg; if (this.operationToTrigger === DeviceConfigurationOperation.DOWNLOAD_CONFIG) { operationCfg = this.repositoryService.getDownloadConfigurationFileOperation(this.device, this._configurationType, this.configSnapshot, this.isLegacy); } if (this.operationToTrigger === DeviceConfigurationOperation.UPLOAD_CONFIG) { operationCfg = this.repositoryService.getUploadConfigurationFileOperation(this.device, this._configurationType, this.isLegacy); } try { this.operation = (await this.operationService.create(operationCfg)).data; } catch (ex) { this.alertService.addServerFailure(ex); } } showOperation() { if (this.operationToTrigger === DeviceConfigurationOperation.DOWNLOAD_CONFIG) { return !!this.operation; } return (this.operation && [OperationStatus.PENDING, OperationStatus.EXECUTING].includes(this.operation.status)); } showBinary() { if (this.operationToTrigger === DeviceConfigurationOperation.DOWNLOAD_CONFIG) { return true; } return !this.showOperation(); } isCreateOperationDisabled() { return (this.operation && [OperationStatus.PENDING, OperationStatus.EXECUTING].includes(this.operation.status)); } updatePreview(operation) { if (operation && operation[this.operationToTrigger] && (this.isLegacy || (operation[this.operationToTrigger].type && operation[this.operationToTrigger].type === this.configurationType))) { this.operation = operation; this.updateSnapshotsOnConfigUpload(operation); } } download() { const blob = new Blob([this.configSnapshot.binary], { type: this.configSnapshot.binaryType }); let fileName = this.configSnapshot.name; switch (this.configSnapshot.binaryType) { case 'text/csv': case 'application/csv': fileName = fileName.concat('.csv'); break; case 'text/yaml': case 'application/x-yaml': fileName = fileName.concat('.yaml'); break; case 'application/json': fileName = fileName.concat('.json'); break; } saveAs(blob, fileName); } async saveToRepository() { const initialState = { configSnapshot: cloneDeep(this.configSnapshot) }; const modal = this.bsModal.show(SaveToRepositoryComponent, { class: 'modal-sm', ariaDescribedby: 'modal-body', ariaLabelledBy: 'modal-title', initialState, ignoreBackdropClick: true }).content; try { await modal.result; this.deviceConfigurationService.updateConfigurations(true); modal.close(); } catch (ex) { // do nothing } } hasPermission() { return (this.user.hasAnyRole(this.appState.currentUser.value, [ Permissions.ROLE_INVENTORY_ADMIN, Permissions.ROLE_INVENTORY_CREATE ]) || (this.user.hasAnyRole(this.appState.currentUser.value, [ Permissions.ROLE_MANAGED_OBJECT_ADMIN, Permissions.ROLE_MANAGED_OBJECT_CREATE ]) && this.user.hasAnyRole(this.appState.currentUser.value, [ Permissions.ROLE_BINARY_ADMIN, Permissions.ROLE_BINARY_CREATE ]))); } ngOnDestroy() { if (this.operationsSubscription) { this.operationsSubscription.unsubscribe(); } } async updateSnapshotsOnConfigUpload(operation) { if (operation[DeviceConfigurationOperation.UPLOAD_CONFIG] && operation.status === OperationStatus.SUCCESSFUL) { this.deviceConfigurationService.updateConfigurations(); } } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ConfigurationPreviewComponent, deps: [{ token: i1.DeviceConfigurationService }, { token: i2.OperationRealtimeService }, { token: i3.BsModalService }, { token: i4.UserService }, { token: i2.AppStateService }, { token: i5.RepositoryService }, { token: i4.OperationService }, { token: i2.AlertService }], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: ConfigurationPreviewComponent, selector: "c8y-device-configuration-preview", inputs: { device: "device", configurationType: "configurationType", configSnapshot: "configSnapshot", canSaveSnapshot: "canSaveSnapshot", actionButtonText: "actionButtonText", actionButtonIcon: "actionButtonIcon", isLegacy: "isLegacy", operationToTrigger: "operationToTrigger" }, ngImport: i0, template: "<div class=\"content-flex-55 p-b-16\">\n <div class=\"col-7 p-t-4\">\n <p>\n <span class=\"text-label-small text-uppercase m-r-4\" translate>Configuration</span>\n <span *ngIf=\"configSnapshot?.name; else emptyText\">\n <strong>{{ configSnapshot.name }}</strong>\n </span>\n <ng-template #emptyText>---</ng-template>\n </p>\n <p>\n <span class=\"text-label-small text-uppercase m-r-4\" translate>Last updated</span>\n <small *ngIf=\"configSnapshot?.time; else emptyDate\">\n {{ configSnapshot.time | c8yDate }}\n </small>\n <ng-template #emptyDate>---</ng-template>\n </p>\n </div>\n <div class=\"col-5\">\n <button\n id=\"action-btn\"\n class=\"btn btn-default btn-sm pull-right\"\n type=\"button\"\n title=\"{{ actionButtonText | translate }}\"\n (click)=\"createDeviceOperation()\"\n [disabled]=\"isCreateOperationDisabled()\"\n *ngIf=\"canCallAction\"\n >\n <i [c8yIcon]=\"actionButtonIcon\"></i>\n {{ actionButtonText | translate }}\n </button>\n </div>\n</div>\n<div class=\"c8y-empty-state text-left\" *ngIf=\"!configSnapshot?.binary && showBinary()\">\n <h1 [c8yIcon]=\"'file-image-o'\"></h1>\n <p>\n <strong translate>No preview available.</strong>\n <br />\n <small *ngIf=\"configSnapshot?.binary !== ''; else emptyFile\" translate>\n The file is not available.\n </small>\n <ng-template #emptyFile>\n <small translate>The file is empty.</small>\n </ng-template>\n </p>\n</div>\n<div *ngIf=\"configSnapshot?.binary && showBinary()\" class=\"flex-grow d-flex d-col\">\n <c8y-source-code-preview\n [text]=\"configSnapshot.binary\"\n [isDisabled]=\"true\"\n class=\"d-contents\"\n ></c8y-source-code-preview>\n <div *ngIf=\"canSaveSnapshot\" class=\"p-t-16\">\n <button\n title=\"{{ 'Download' | translate }}\"\n type=\"button\"\n class=\"btn btn-primary btn-sm pull-right m-l-8\"\n (click)=\"download()\"\n >\n {{ 'Download' | translate }}\n </button>\n <button\n title=\"{{ 'Save to repository' | translate }}\"\n *ngIf=\"hasPermission()\"\n type=\"button\"\n class=\"btn btn-default btn-sm pull-right\"\n (click)=\"saveToRepository()\"\n >\n {{ 'Save to repository' | translate }}\n </button>\n </div>\n</div>\n<div *ngIf=\"showOperation()\">\n <c8y-operation-details [operation]=\"operation\"></c8y-operation-details>\n</div>\n", dependencies: [{ kind: "directive", type: i6.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: i2.C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "component", type: i7.OperationDetailsComponent, selector: "c8y-operation-details", inputs: ["operation"] }, { kind: "component", type: i8.SourceCodePreviewComponent, selector: "c8y-source-code-preview", inputs: ["isDisabled", "text"] }, { kind: "pipe", type: i2.C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: i2.DatePipe, name: "c8yDate" }] }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ConfigurationPreviewComponent, decorators: [{ type: Component, args: [{ selector: 'c8y-device-configuration-preview', template: "<div class=\"content-flex-55 p-b-16\">\n <div class=\"col-7 p-t-4\">\n <p>\n <span class=\"text-label-small text-uppercase m-r-4\" translate>Configuration</span>\n <span *ngIf=\"configSnapshot?.name; else emptyText\">\n <strong>{{ configSnapshot.name }}</strong>\n </span>\n <ng-template #emptyText>---</ng-template>\n </p>\n <p>\n <span class=\"text-label-small text-uppercase m-r-4\" translate>Last updated</span>\n <small *ngIf=\"configSnapshot?.time; else emptyDate\">\n {{ configSnapshot.time | c8yDate }}\n </small>\n <ng-template #emptyDate>---</ng-template>\n </p>\n </div>\n <div class=\"col-5\">\n <button\n id=\"action-btn\"\n class=\"btn btn-default btn-sm pull-right\"\n type=\"button\"\n title=\"{{ actionButtonText | translate }}\"\n (click)=\"createDeviceOperation()\"\n [disabled]=\"isCreateOperationDisabled()\"\n *ngIf=\"canCallAction\"\n >\n <i [c8yIcon]=\"actionButtonIcon\"></i>\n {{ actionButtonText | translate }}\n </button>\n </div>\n</div>\n<div class=\"c8y-empty-state text-left\" *ngIf=\"!configSnapshot?.binary && showBinary()\">\n <h1 [c8yIcon]=\"'file-image-o'\"></h1>\n <p>\n <strong translate>No preview available.</strong>\n <br />\n <small *ngIf=\"configSnapshot?.binary !== ''; else emptyFile\" translate>\n The file is not available.\n </small>\n <ng-template #emptyFile>\n <small translate>The file is empty.</small>\n </ng-template>\n </p>\n</div>\n<div *ngIf=\"configSnapshot?.binary && showBinary()\" class=\"flex-grow d-flex d-col\">\n <c8y-source-code-preview\n [text]=\"configSnapshot.binary\"\n [isDisabled]=\"true\"\n class=\"d-contents\"\n ></c8y-source-code-preview>\n <div *ngIf=\"canSaveSnapshot\" class=\"p-t-16\">\n <button\n title=\"{{ 'Download' | translate }}\"\n type=\"button\"\n class=\"btn btn-primary btn-sm pull-right m-l-8\"\n (click)=\"download()\"\n >\n {{ 'Download' | translate }}\n </button>\n <button\n title=\"{{ 'Save to repository' | translate }}\"\n *ngIf=\"hasPermission()\"\n type=\"button\"\n class=\"btn btn-default btn-sm pull-right\"\n (click)=\"saveToRepository()\"\n >\n {{ 'Save to repository' | translate }}\n </button>\n </div>\n</div>\n<div *ngIf=\"showOperation()\">\n <c8y-operation-details [operation]=\"operation\"></c8y-operation-details>\n</div>\n" }] }], ctorParameters: () => [{ type: i1.DeviceConfigurationService }, { type: i2.OperationRealtimeService }, { type: i3.BsModalService }, { type: i4.UserService }, { type: i2.AppStateService }, { type: i5.RepositoryService }, { type: i4.OperationService }, { type: i2.AlertService }], propDecorators: { device: [{ type: Input }], configurationType: [{ type: Input }], configSnapshot: [{ type: Input }], canSaveSnapshot: [{ type: Input }], actionButtonText: [{ type: Input }], actionButtonIcon: [{ type: Input }], isLegacy: [{ type: Input }], operationToTrigger: [{ type: Input }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29uZmlndXJhdGlvbi1wcmV2aWV3LmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3JlcG9zaXRvcnkvY29uZmlndXJhdGlvbi9kZXZpY2UtdGFiL2NvbmZpZ3VyYXRpb24tcHJldmlldy5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi8uLi9yZXBvc2l0b3J5L2NvbmZpZ3VyYXRpb24vZGV2aWNlLXRhYi9jb25maWd1cmF0aW9uLXByZXZpZXcuY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFNBQVMsRUFBRSxLQUFLLEVBQXFCLE1BQU0sZUFBZSxDQUFDO0FBQ3BFLE9BQU8sRUFHTCxnQkFBZ0IsRUFDaEIsZUFBZSxFQUNmLFdBQVcsRUFDWixNQUFNLGFBQWEsQ0FBQztBQUNyQixPQUFPLEVBQ0wsWUFBWSxFQUNaLGVBQWUsRUFDZix3QkFBd0IsRUFDeEIsV0FBVyxFQUNaLE1BQU0scUJBQXFCLENBQUM7QUFDN0IsT0FBTyxFQUVMLDRCQUE0QixFQUM1QixpQkFBaUIsRUFDbEIsTUFBTSx1Q0FBdUMsQ0FBQztBQUMvQyxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sWUFBWSxDQUFDO0FBQ3BDLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxXQUFXLENBQUM7QUFDdEMsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBRXJELE9BQU8sRUFBRSxHQUFHLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUNyQyxPQUFPLEVBQUUsMEJBQTBCLEVBQUUsTUFBTSxnQ0FBZ0MsQ0FBQztBQUM1RSxPQUFPLEVBQUUseUJBQXlCLEVBQUUsTUFBTSxnQ0FBZ0MsQ0FBQzs7Ozs7Ozs7OztBQU0zRSxNQUFNLE9BQU8sNkJBQTZCO0lBR3hDLElBQWEsaUJBQWlCLENBQUMsSUFBWTtRQUN6QyxJQUFJLENBQUMsa0JBQWtCLEdBQUcsSUFBSSxDQUFDO1FBQy9CLElB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RTtnQkFDckQsV0FBVyxDQUFDLHlCQUF5QjtnQkFDckMsV0FBVyxDQUFDLDBCQUEwQjthQUN2QyxDQUFDO2dCQUNBLElBQUksQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsV0FBVyxDQUFDLEtBQUssRUFBRTtvQkFDcEQsV0FBVyxDQUFDLGlCQUFpQjtvQkFDN0IsV0FBVyxDQUFDLGtCQUFrQjtpQkFDL0IsQ0FBQyxDQUFDLENBQ04sQ0FBQztJQUNKLENBQUM7SUFFRCxXQUFXO1FBQ1QsSUFBSSxJQUFJLENBQUMsc0JBQXNCLEVBQUUsQ0FBQztZQUNoQyxJQUFJLENBQUMsc0JBQXNCLENBQUMsV0FBVyxFQUFFLENBQUM7UUFDNUMsQ0FBQztJQUNILENBQUM7SUFFTyxLQUFLLENBQUMsNkJBQTZCLENBQUMsU0FBUztRQUNuRCxJQUNFLFNBQVMsQ0FBQyw0QkFBNEIsQ0FBQyxhQUFhLENBQUM7WUFDckQsU0FBUyxDQUFDLE1BQU0sS0FBSyxlQUFlLENBQUMsVUFBVSxFQUMvQyxDQUFDO1lBQ0QsSUFBSSxDQUFDLDBCQUEwQixDQUFDLG9CQUFvQixFQUFFLENBQUM7UUFDekQsQ0FBQztJQUNILENBQUM7K0dBeE1VLDZCQUE2QjttR0FBN0IsNkJBQTZCLGdXQy9CMUMsazdFQTBFQTs7NEZEM0NhLDZCQUE2QjtrQkFKekMsU0FBUzsrQkFDRSxrQ0FBa0M7cVRBSW5DLE1BQU07c0JBQWQsS0FBSztnQkFFTyxpQkFBaUI7c0JBQTdCLEtBQUs7Z0JBU0csY0FBYztzQkFBdEIsS0FBSztnQkFDRyxlQUFlO3NCQUF2QixLQUFLO2dCQUNHLGdCQUFnQjtzQkFBeEIsS0FBSztnQkFDRyxnQkFBZ0I7c0JBQXhCLEtBQUs7Z0JBQ0csUUFBUTtzQkFBaEIsS0FBSztnQkFDRyxrQkFBa0I7c0JBQTFCLEtBQUsiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDb21wb25lbnQsIElucHV0LCBPbkRlc3Ryb3ksIE9uSW5pdCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHtcbiAgSU1hbmFnZWRPYmplY3QsXG4gIElPcGVyYXRpb24sXG4gIE9wZXJhdGlvblNlcnZpY2UsXG4gIE9wZXJhdGlvblN0YXR1cyxcbiAgVXNlclNlcnZpY2Vcbn0gZnJvbSAnQGM4eS9jbGllbnQnO1xuaW1wb3J0IHtcbiAgQWxlcnRTZXJ2aWNlLFxuICBBcHBTdGF0ZVNlcnZpY2UsXG4gIE9wZXJhdGlvblJlYWx0aW1lU2VydmljZSxcbiAgUGVybWlzc2lvbnNcbn0gZnJvbSAnQGM4eS9uZ3gtY29tcG9uZW50cyc7XG5pbXBvcnQge1xuICBDb25maWd1cmF0aW9uU25hcHNob3QsXG4gIERldmljZUNvbmZpZ3VyYXRpb25PcGVyYXRpb24sXG4gIFJlcG9zaXRvcnlTZXJ2aWNlXG59IGZyb20gJ0BjOHkvbmd4LWNvbXBvbmVudHMvcmVwb3NpdG9yeS9zaGFyZWQnO1xuaW1wb3J0IHsgc2F2ZUFzIH0gZnJvbSAnZmlsZS1zYXZlcic7XG5pbXBvcnQgeyBjbG9uZURlZXAgfSBmcm9tICdsb2Rhc2gtZXMnO1xuaW1wb3J0IHsgQnNNb2RhbFNlcnZpY2UgfSBmcm9tICduZ3gtYm9vdHN0cmFwL21vZGFsJztcbmltcG9ydCB7IFN1YnNjcmlwdGlvbiB9IGZyb20gJ3J4anMnO1xuaW1wb3J0IHsgbWFwIH0gZnJvbSAncnhqcy9vcGVyYXRvcnMnO1xuaW1wb3J0IHsgRGV2aWNlQ29uZmlndXJhdGlvblNlcnZpY2UgfSBmcm9tICcuL2RldmljZS1jb25maWd1cmF0aW9uLnNlcnZpY2UnO1xuaW1wb3J0IHsgU2F2ZVRvUmVwb3NpdG9yeUNvbXBvbmVudCB9IGZyb20gJy4vc2F2ZS10by1yZXBvc2l0b3J5LmNvbXBvbmVudCc7XG5cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ2M4eS1kZXZpY2UtY29uZmlndXJhdGlvbi1wcmV2aWV3JyxcbiAgdGVtcGxhdGVVcmw6ICcuL2NvbmZpZ3VyYXRpb24tcHJldmlldy5jb21wb25lbnQuaHRtbCdcbn0pXG5leHBvcnQgY2xhc3MgQ29uZmlndXJhdGlvblByZXZpZXdDb21wb25lbnQgaW1wbGVtZW50cyBPbkluaXQsIE9uRGVzdHJveSB7XG4gIEBJbnB1dCgpIGRldmljZTogSU1hbmFnZWRPYmplY3Q7XG5cbiAgQElucHV0KCkgc2V0IGNvbmZpZ3VyYXRpb25UeXBlKHR5cGU6IHN0cmluZykge1xuICAgIHRoaXMuX2NvbmZpZ3VyYXRpb25UeXBlID0gdHlwZTtcbiAgICB0aGlzLnNldE9wZXJhdGlvbih0eXBlKTtcbiAgfVxuXG4gIGdldCBjb25maWd1cmF0aW9uVHlwZSgpOiBzdHJpbmcge1xuICAgIHJldHVybiB0aGlzLl9jb25maWd1cmF0aW9uVHlwZTtcbiAgfVxuXG4gIEBJbnB1dCgpIGNvbmZpZ1NuYXBzaG90OiBDb25maWd1cmF0aW9uU25hcHNob3Q7XG4gIEBJbnB1dCgpIGNhblNhdmVTbmFwc2hvdDogYm9vbGVhbjtcbiAgQElucHV0KCkgYWN0aW9uQnV0dG9uVGV4dDogc3RyaW5nO1xuICBASW5wdXQoKSBhY3Rpb25CdXR0b25JY29uOiBzdHJpbmc7XG4gIEBJbnB1dCgpIGlzTGVnYWN5ID0gZmFsc2U7XG4gIEBJbnB1dCgpIG9wZXJhdGlvblRvVHJpZ2dlcjpcbiAgICB8IERldmljZUNvbmZpZ3VyYXRpb25PcGVyYXRpb24uVVBMT0FEX0NPTkZJR1xuICAgIHwgRGV2aWNlQ29uZmlndXJhdGlvbk9wZXJhdGlvbi5ET1dOTE9BRF9DT05GSUc7XG5cbiAgb3BlcmF0aW9uOiBJT3BlcmF0aW9uO1xuICBjYW5DYWxsQWN0aW9uID0gdHJ1ZTtcbiAgZGV2aWNlQ29uZmlndXJhdGlvbk9wZXJhdGlvbiA9IERldmljZUNvbmZpZ3VyYXRpb25PcGVyYXRpb247XG4gIHByaXZhdGUgX2NvbmZpZ3VyYXRpb25UeXBlOiBzdHJpbmc7XG4gIHByaXZhdGUgb3BlcmF0aW9uc1N1YnNjcmlwdGlvbjogU3Vic2NyaXB0aW9uO1xuXG4gIGNvbnN0cnVjdG9yKFxuICAgIHByaXZhdGUgZGV2aWNlQ29uZmlndXJhdGlvblNlcnZpY2U6IERldmljZUNvbmZpZ3VyYXRpb25TZXJ2aWNlLFxuICAgIHByaXZhdGUgb3BlcmF0aW9uUmVhbHRpbWU6IE9wZXJhdGlvblJlYWx0aW1lU2VydmljZSxcbiAgICBwcml2YXRlIGJzTW9kYWw6IEJzTW9kYWxTZXJ2aWNlLFxuICAgIHByaXZhdGUgdXNlcjogVXNlclNlcnZpY2UsXG4gICAgcHJpdmF0ZSBhcHBTdGF0ZTogQXBwU3RhdGVTZXJ2aWNlLFxuICAgIHByaXZhdGUgcmVwb3NpdG9yeVNlcnZpY2U6IFJlcG9zaXRvcnlTZXJ2aWNlLFxuICAgIHByaXZhdGUgb3BlcmF0aW9uU2VydmljZTogT3BlcmF0aW9uU2VydmljZSxcbiAgICBwcml2YXRlIGFsZXJ0U2VydmljZTogQWxlcnRTZXJ2aWNlXG4gICkge31cblxuICBhc3luYyBuZ09uSW5pdCgpIHtcbiAgICB0aGlzLnNldENhbkNhbGxBY3Rpb24oKTtcbiAgICB0aGlzLnNldE9wZXJhdGlvbih0aGlzLl9jb25maWd1cmF0aW9uVHlwZSk7XG4gICAgdGhpcy5vcGVyYXRpb25zU3Vic2NyaXB0aW9uID0gdGhpcy5vcGVyYXRpb25SZWFsdGltZVxuICAgICAgLm9uQWxsJCh0aGlzLmRldmljZS5pZClcbiAgICAgIC5waXBlKG1hcCgoeyBkYXRhIH0pID0+IGRhdGEgYXMgSU9wZXJhdGlvbikpXG4gICAgICAuc3Vic2NyaWJlKG9wZXJhdGlvbiA9PiB7XG4gICAgICAgIHRoaXMudXBkYXRlUHJldmlldyhvcGVyYXRpb24pO1xuICAgICAgfSk7XG4gIH1cblxuICBhc3luYyBzZXRPcGVyYXRpb24oY29uZmlnVHlwZSk6IFByb21pc2U8dm9pZD4ge1xuICAgIGNvbnN0IG9wZXJhdGlvbkxpc3QgPSBhd2FpdCB0aGlzLnJlcG9zaXRvcnlTZXJ2aWNlLmdldENvbmZpZ0ZpbGVPcGVyYXRpb25MaXN0KFxuICAgICAgdGhpcy5kZXZpY2UuaWQsXG4gICAgICB0aGlzLm9wZXJhdGlvblRvVHJpZ2dlclxuICAgICk7XG5cbiAgICBjb25zdCBvcGVyYXRpb24gPSB0aGlzLmlzTGVnYWN5XG4gICAgICA/IG9wZXJhdGlvbkxpc3QuZmluZChvcCA9PiBvcFt0aGlzLm9wZXJhdGlvblRvVHJpZ2dlcl0gJiYgIW9wW3RoaXMub3BlcmF0aW9uVG9UcmlnZ2VyXS50eXBlKVxuICAgICAgOiBvcGVyYXRpb25MaXN0LmZpbmQob3AgPT4gb3BbdGhpcy5vcGVyYXRpb25Ub1RyaWdnZXJdLnR5cGUgPT09IGNvbmZpZ1R5cGUpO1xuXG4gICAgdGhpcy5vcGVyYXRpb24gPVxuICAgICAgb3BlcmF0aW9uICYmIG9wZXJhdGlvbi5zdGF0dXMgIT09IE9wZXJhdGlvblN0YXR1cy5TVUNDRVNTRlVMID8gb3BlcmF0aW9uIDogdW5kZWZpbmVkO1xuICB9XG5cbiAgc2V0Q2FuQ2FsbEFjdGlvbigpOiB2b2lkIHtcbiAgICB0aGlzLmNhbkNhbGxBY3Rpb24gPSB0aGlzLmRldmljZUNvbmZpZ3VyYXRpb25TZXJ2aWNlLmhhc0FueVN1cHBvcnRlZE9wZXJhdGlvbihcbiAgICAgIHRoaXMuZGV2aWNlLFxuICAgICAgdGhpcy5vcGVyYXRpb25Ub1RyaWdnZXJcbiAgICApO1xuICB9XG5cbiAgYXN5bmMgY3JlYXRlRGV2aWNlT3BlcmF0aW9uKCkge1xuICAgIGxldCBvcGVyYXRpb25DZmc7XG4gICAgaWYgKHRoaXMub3BlcmF0aW9uVG9UcmlnZ2VyID09PSBEZXZpY2VDb25maWd1cmF0aW9uT3BlcmF0aW9uLkRPV05MT0FEX0NPTkZJRykge1xuICAgICAgb3BlcmF0aW9uQ2ZnID0gdGhpcy5yZXBvc2l0b3J5U2VydmljZS5nZXREb3dubG9hZENvbmZpZ3VyYXRpb25GaWxlT3BlcmF0aW9uKFxuICAgICAgICB0aGlzLmRldmljZSxcbiAgICAgICAgdGhpcy5fY29uZmlndXJhdGlvblR5cGUsXG4gICAgICAgIHRoaXMuY29uZmlnU25hcHNob3QsXG4gICAgICAgIHRoaXMuaXNMZWdhY3lcbiAgICAgICk7XG4gICAgfVxuICAgIGlmICh0aGlzLm9wZXJhdGlvblRvVHJpZ2dlciA9PT0gRGV2aWNlQ29uZmlndXJhdGlvbk9wZXJhdGlvbi5VUExPQURfQ09ORklHKSB7XG4gICAgICBvcGVyYXRpb25DZmcgPSB0aGlzLnJlcG9zaXRvcnlTZXJ2aWNlLmdldFVwbG9hZENvbmZpZ3VyYXRpb25GaWxlT3BlcmF0aW9uKFxuICAgICAgICB0aGlzLmRldmljZSxcbiAgICAgICAgdGhpcy5fY29uZmlndXJhdGlvblR5cGUsXG4gICAgICAgIHRoaXMuaXNMZWdhY3lcbiAgICAgICk7XG4gICAgfVxuICAgIHRyeSB7XG4gICAgICB0aGlzLm9wZXJhdGlvbiA9IChhd2FpdCB0aGlzLm9wZXJhdGlvblNlcnZpY2UuY3JlYXRlKG9wZXJhdGlvbkNmZykpLmRhdGE7XG4gICAgfSBjYXRjaCAoZXgpIHtcbiAgICAgIHRoaXMuYWxlcnRTZXJ2aWNlLmFkZFNlcnZlckZhaWx1cmUoZXgpO1xuICAgIH1cbiAgfVxuXG4gIHNob3dPcGVyYXRpb24oKTogYm9vbGVhbiB7XG4gICAgaWYgKHRoaXMub3BlcmF0aW9uVG9UcmlnZ2VyID09PSBEZXZpY2VDb25maWd1cmF0aW9uT3BlcmF0aW9uLkRPV05MT0FEX0NPTkZJRykge1xuICAgICAgcmV0dXJuICEhdGhpcy5vcGVyYXRpb247XG4gICAgfVxuICAgIHJldHVybiAoXG4gICAgICB0aGlzLm9wZXJhdGlvbiAmJlxuICAgICAgW09wZXJhdGlvblN0YXR1cy5QRU5ESU5HLCBPcGVyYXRpb25TdGF0dXMuRVhFQ1VUSU5HXS5pbmNsdWRlcyh0aGlzLm9wZXJhdGlvbi5zdGF0dXMpXG4gICAgKTtcbiAgfVxuXG4gIHNob3dCaW5hcnkoKTogYm9vbGVhbiB7XG4gICAgaWYgKHRoaXMub3BlcmF0aW9uVG9UcmlnZ2VyID09PSBEZXZpY2VDb25maWd1cmF0aW9uT3BlcmF0aW9uLkRPV05MT0FEX0NPTkZJRykge1xuICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuICAgIHJldHVybiAhdGhpcy5zaG93T3BlcmF0aW9uKCk7XG4gIH1cblxuICBpc0NyZWF0ZU9wZXJhdGlvbkRpc2FibGVkKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiAoXG4gICAgICB0aGlzLm9wZXJhdGlvbiAmJlxuICAgICAgW09wZXJhdGlvblN0YXR1cy5QRU5ESU5HLCBPcGVyYXRpb25TdGF0dXMuRVhFQ1VUSU5HXS5pbmNsdWRlcyh0aGlzLm9wZXJhdGlvbi5zdGF0dXMpXG4gICAgKTtcbiAgfVxuXG4gIHVwZGF0ZVByZXZpZXcob3BlcmF0aW9uOiBJT3BlcmF0aW9uKSB7XG4gICAgaWYgKFxuICAgICAgb3BlcmF0aW9uICYmXG4gICAgICBvcGVyYXRpb25bdGhpcy5vcGVyYXRpb25Ub1RyaWdnZXJdICYmXG4gICAgICAodGhpcy5pc0xlZ2FjeSB8fFxuICAgICAgICAob3BlcmF0aW9uW3RoaXMub3BlcmF0aW9uVG9UcmlnZ2VyXS50eXBlICYmXG4gICAgICAgICAgb3BlcmF0aW9uW3RoaXMub3BlcmF0aW9uVG9UcmlnZ2VyXS50eXBlID09PSB0aGlzLmNvbmZpZ3VyYXRpb25UeXBlKSlcbiAgICApIHtcbiAgICAgIHRoaXMub3BlcmF0aW9uID0gb3BlcmF0aW9uO1xuICAgICAgdGhpcy51cGRhdGVTbmFwc2hvdHNPbkNvbmZpZ1VwbG9hZChvcGVyYXRpb24pO1xuICAgIH1cbiAgfVxuXG4gIGRvd25sb2FkKCkge1xuICAgIGNvbnN0IGJsb2IgPSBuZXcgQmxvYihbdGhpcy5jb25maWdTbmFwc2hvdC5iaW5hcnldLCB7IHR5cGU6IHRoaXMuY29uZmlnU25hcHNob3QuYmluYXJ5VHlwZSB9KTtcbiAgICBsZXQgZmlsZU5hbWUgPSB0aGlzLmNvbmZpZ1NuYXBzaG90Lm5hbWU7XG4gICAgc3dpdGNoICh0aGlzLmNvbmZpZ1NuYXBzaG90LmJpbmFyeVR5cGUpIHtcbiAgICAgIGNhc2UgJ3RleHQvY3N2JzpcbiAgICAgIGNhc2UgJ2FwcGxpY2F0aW9uL2Nzdic6XG4gICAgICAgIGZpbGVOYW1lID0gZmlsZU5hbWUuY29uY2F0KCcuY3N2Jyk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSAndGV4dC95YW1sJzpcbiAgICAgIGNhc2UgJ2FwcGxpY2F0aW9uL3gteWFtbCc6XG4gICAgICAgIGZpbGVOYW1lID0gZmlsZU5hbWUuY29uY2F0KCcueWFtbCcpO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgJ2FwcGxpY2F0aW9uL2pzb24nOlxuICAgICAgICBmaWxlTmFtZSA9IGZpbGVOYW1lLmNvbmNhdCgnLmpzb24nKTtcbiAgICAgICAgYnJlYWs7XG4gICAgfVxuICAgIHNhdmVBcyhibG9iLCBmaWxlTmFtZSk7XG4gIH1cblxuICBhc3luYyBzYXZlVG9SZXBvc2l0b3J5KCkge1xuICAgIGNvbnN0IGluaXRpYWxTdGF0ZSA9IHtcbiAgICAgIGNvbmZpZ1NuYXBzaG90OiBjbG9uZURlZXAodGhpcy5jb25maWdTbmFwc2hvdClcbiAgICB9O1xuICAgIGNvbnN0IG1vZGFsID0gdGhpcy5ic01vZGFsLnNob3coU2F2ZVRvUmVwb3NpdG9yeUNvbXBvbmVudCwge1xuICAgICAgY2xhc3M6ICdtb2RhbC1zbScsXG4gICAgICBhcmlhRGVzY3JpYmVkYnk6ICdtb2RhbC1ib2R5JyxcbiAgICAgIGFyaWFMYWJlbGxlZEJ5OiAnbW9kYWwtdGl0bGUnLFxuICAgICAgaW5pdGlhbFN0YXRlLFxuICAgICAgaWdub3JlQmFja2Ryb3BDbGljazogdHJ1ZVxuICAgIH0pLmNvbnRlbnQgYXMgU2F2ZVRvUmVwb3NpdG9yeUNvbXBvbmVudDtcbiAgICB0cnkge1xuICAgICAgYXdhaXQgbW9kYWwucmVzdWx0O1xuICAgICAgdGhpcy5kZXZpY2VDb25maWd1cmF0aW9uU2VydmljZS51cGRhdGVDb25maWd1cmF0aW9ucyh0cnVlKTtcbiAgICAgIG1vZGFsLmNsb3NlKCk7XG4gICAgfSBjYXRjaCAoZXgpIHtcbiAgICAgIC8vIGRvIG5vdGhpbmdcbiAgICB9XG4gIH1cblxuICBoYXNQZXJtaXNzaW9uKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiAoXG4gICAgICB0aGlzLnVzZXIuaGFzQW55Um9sZSh0aGlzLmFwcFN0YXRlLmN1cnJlbnRVc2VyLnZhbHVlLCBbXG4gICAgICAgIFBlcm1pc3Npb25zLlJPTEVfSU5WRU5UT1JZX0FETUlOLFxuICAgICAgICBQZXJtaXNzaW9ucy5ST0xFX0lOVkVOVE9SWV9DUkVBVEVcbiAgICAgIF0pIHx8XG4gICAgICAodGhpcy51c2VyLmhhc0FueVJvbGUodGhpcy5hcHBTdGF0ZS5jdXJyZW50VXNlci52YWx1ZSwgW1xuICAgICAgICBQZXJtaXNzaW9ucy5ST0xFX01BTkFHRURfT0JKRUNUX0FETUlOLFxuICAgICAgICBQZXJtaXNzaW9ucy5ST0xFX01BTkFHRURfT0JKRUNUX0NSRUFURVxuICAgICAgXSkgJiZcbiAgICAgICAgdGhpcy51c2VyLmhhc0FueVJvbGUodGhpcy5hcHBTdGF0ZS5jdXJyZW50VXNlci52YWx1ZSwgW1xuICAgICAgICAgIFBlcm1pc3Npb25zLlJPTEVfQklOQVJZX0FETUlOLFxuICAgICAgICAgIFBlcm1pc3Npb25zLlJPTEVfQklOQVJZX0NSRUFURVxuICAgICAgICBdKSlcbiAgICApO1xuICB9XG5cbiAgbmdPbkRlc3Ryb3koKSB7XG4gICAgaWYgKHRoaXMub3BlcmF0aW9uc1N1YnNjcmlwdGlvbikge1xuICAgICAgdGhpcy5vcGVyYXRpb25zU3Vic2NyaXB0aW9uLnVuc3Vic2NyaWJlKCk7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyB1cGRhdGVTbmFwc2hvdHNPbkNvbmZpZ1VwbG9hZChvcGVyYXRpb24pIHtcbiAgICBpZiAoXG4gICAgICBvcGVyYXRpb25bRGV2aWNlQ29uZmlndXJhdGlvbk9wZXJhdGlvbi5VUExPQURfQ09ORklHXSAmJlxuICAgICAgb3BlcmF0aW9uLnN0YXR1cyA9PT0gT3BlcmF0aW9uU3RhdHVzLlNVQ0NFU1NGVUxcbiAgICApIHtcbiAgICAgIHRoaXMuZGV2aWNlQ29uZmlndXJhdGlvblNlcnZpY2UudXBkYXRlQ29uZmlndXJhdGlvbnMoKTtcbiAgICB9XG4gIH1cbn1cbiIsIjxkaXYgY2xhc3M9XCJjb250ZW50LWZsZXgtNTUgcC1iLTE2XCI+XG4gIDxkaXYgY2xhc3M9XCJjb2wtNyBwLXQtNFwiPlxuICAgIDxwPlxuICAgICAgPHNwYW4gY2xhc3M9XCJ0ZXh0LWxhYmVsLXNtYWxsIHRleHQtdXBwZXJjYXNlIG0tci00XCIgdHJhbnNsYXRlPkNvbmZpZ3VyYXRpb248L3NwYW4+XG4gICAgICA8c3BhbiAqbmdJZj1cImNvbmZpZ1NuYXBzaG90Py5uYW1lOyBlbHNlIGVtcHR5VGV4dFwiPlxuICAgICAgICA8c3Ryb25nPnt7IGNvbmZpZ1NuYXBzaG90Lm5hbWUgfX08L3N0cm9uZz5cbiAgICAgIDwvc3Bhbj5cbiAgICAgIDxuZy10ZW1wbGF0ZSAjZW1wdHlUZXh0Pi0tLTwvbmctdGVtcGxhdGU+XG4gICAgPC9wPlxuICAgIDxwPlxuICAgICAgPHNwYW4gY2xhc3M9XCJ0ZXh0LWxhYmVsLXNtYWxsIHRleHQtdXBwZXJjYXNlIG0tci00XCIgdHJhbnNsYXRlPkxhc3QgdXBkYXRlZDwvc3Bhbj5cbiAgICAgIDxzbWFsbCAqbmdJZj1cImNvbmZpZ1NuYXBzaG90Py50aW1lOyBlbHNlIGVtcHR5RGF0ZVwiPlxuICAgICAgICB7eyBjb25maWdTbmFwc2hvdC50aW1lIHwgYzh5RGF0ZSB9fVxuICAgICAgPC9zbWFsbD5cbiAgICAgIDxuZy10ZW1wbGF0ZSAjZW1wdHlEYXRlPi0tLTwvbmctdGVtcGxhdGU+XG4gICAgPC9wPlxuICA8L2Rpdj5cbiAgPGRpdiBjbGFzcz1cImNvbC01XCI+XG4gICAgPGJ1dHRvblxuICAgICAgaWQ9XCJhY3Rpb24tYnRuXCJcbiAgICAgIGNsYXNzPVwiYnRuIGJ0bi1kZWZhdWx0IGJ0bi1zbSBwdWxsLXJpZ2h0XCJcbiAgICAgIHR5cGU9XCJidXR0b25cIlxuICAgICAgdGl0bGU9XCJ7eyBhY3Rpb25CdXR0b25UZXh0IHwgdHJhbnNsYXRlIH19XCJcbiAgICAgIChjbGljayk9XCJjcmVhdGVEZXZpY2VPcGVyYXRpb24oKVwiXG4gICAgICBbZGlzYWJsZWRdPVwiaXNDcmVhdGVPcGVyYXRpb25EaXNhYmxlZCgpXCJcbiAgICAgICpuZ0lmPVwiY2FuQ2FsbEFjdGlvblwiXG4gICAgPlxuICAgICAgPGkgW2M4eUljb25dPVwiYWN0aW9uQnV0dG9uSWNvblwiPjwvaT5cbiAgICAgIHt7IGFjdGlvbkJ1dHRvblRleHQgfCB0cmFuc2xhdGUgfX1cbiAgICA8L2J1dHRvbj5cbiAgPC9kaXY+XG48L2Rpdj5cbjxkaXYgY2xhc3M9XCJjOHktZW1wdHktc3RhdGUgdGV4dC1sZWZ0XCIgKm5nSWY9XCIhY29uZmlnU25hcHNob3Q/LmJpbmFyeSAmJiBzaG93QmluYXJ5KClcIj5cbiAgPGgxIFtjOHlJY29uXT1cIidmaWxlLWltYWdlLW8nXCI+PC9oMT5cbiAgPHA+XG4gICAgPHN0cm9uZyB0cmFuc2xhdGU+Tm8gcHJldmlldyBhdmFpbGFibGUuPC9zdHJvbmc+XG4gICAgPGJyIC8+XG4gICAgPHNtYWxsICpuZ0lmPVwiY29uZmlnU25hcHNob3Q/LmJpbmFyeSAhPT0gJyc7IGVsc2UgZW1wdHlGaWxlXCIgdHJhbnNsYXRlPlxuICAgICAgVGhlIGZpbGUgaXMgbm90IGF2YWlsYWJsZS5cbiAgICA8L3NtYWxsPlxuICAgIDxuZy10ZW1wbGF0ZSAjZW1wdHlGaWxlPlxuICAgICAgPHNtYWxsIHRyYW5zbGF0ZT5UaGUgZmlsZSBpcyBlbXB0eS48L3NtYWxsPlxuICAgIDwvbmctdGVtcGxhdGU+XG4gIDwvcD5cbjwvZGl2PlxuPGRpdiAqbmdJZj1cImNvbmZpZ1NuYXBzaG90Py5iaW5hcnkgJiYgc2hvd0JpbmFyeSgpXCIgY2xhc3M9XCJmbGV4LWdyb3cgZC1mbGV4IGQtY29sXCI+XG4gIDxjOHktc291cmNlLWNvZGUtcHJldmlld1xuICAgIFt0ZXh0XT1cImNvbmZpZ1NuYXBzaG90LmJpbmFyeVwiXG4gICAgW2lzRGlzYWJsZWRdPVwidHJ1ZVwiXG4gICAgY2xhc3M9XCJkLWNvbnRlbnRzXCJcbiAgPjwvYzh5LXNvdXJjZS1jb2RlLXByZXZpZXc+XG4gIDxkaXYgKm5nSWY9XCJjYW5TYXZlU25hcHNob3RcIiBjbGFzcz1cInAtdC0xNlwiPlxuICAgIDxidXR0b25cbiAgICAgIHRpdGxlPVwie3sgJ0Rvd25sb2FkJyB8IHRyYW5zbGF0ZSB9fVwiXG4gICAgICB0eXBlPVwiYnV0dG9uXCJcbiAgICAgIGNsYXNzPVwiYnRuIGJ0bi1wcmltYXJ5IGJ0bi1zbSBwdWxsLXJpZ2h0IG0tbC04XCJcbiAgICAgIChjbGljayk9XCJkb3dubG9hZCgpXCJcbiAgICA+XG4gICAgICB7eyAnRG93bmxvYWQnIHwgdHJhbnNsYXRlIH19XG4gICAgPC9idXR0b24+XG4gICAgPGJ1dHRvblxuICAgICAgdGl0bGU9XCJ7eyAnU2F2ZSB0byByZXBvc2l0b3J5JyB8IHRyYW5zbGF0ZSB9fVwiXG4gICAgICAqbmdJZj1cImhhc1Blcm1pc3Npb24oKVwiXG4gICAgICB0eXBlPVwiYnV0dG9uXCJcbiAgICAgIGNsYXNzPVwiYnRuIGJ0bi1kZWZhdWx0IGJ0bi1zbSBwdWxsLXJpZ2h0XCJcbiAgICAgIChjbGljayk9XCJzYXZlVG9SZXBvc2l0b3J5KClcIlxuICAgID5cbiAgICAgIHt7ICdTYXZlIHRvIHJlcG9zaXRvcnknIHwgdHJhbnNsYXRlIH19XG4gICAgPC9idXR0b24+XG4gIDwvZGl2PlxuPC9kaXY+XG48ZGl2ICpuZ0lmPVwic2hvd09wZXJhdGlvbigpXCI+XG4gIDxjOHktb3BlcmF0aW9uLWRldGFpbHMgW29wZXJhdGlvbl09XCJvcGVyYXRpb25cIj48L2M4eS1vcGVyYXRpb24tZGV0YWlscz5cbjwvZGl2PlxuIl19