UNPKG

@c8y/ngx-components

Version:

Angular modules for Cumulocity IoT applications

156 lines 31.9 kB
import { Component, EventEmitter, HostListener, Input, Output, TemplateRef, ViewChild } from '@angular/core'; import { InventoryService } from '@c8y/client'; import { AlertService, DATA_GRID_CONFIGURATION_CONTEXT, DATA_GRID_CONFIGURATION_STRATEGY, GainsightService, gettext, UserPreferencesConfigurationStrategy } from '@c8y/ngx-components'; import { PRODUCT_EXPERIENCE_SUB_ASSETS_SHARED } from '../shared/sub-assets.model'; import { SubAssetsService } from '../sub-assets.service'; import * as i0 from "@angular/core"; import * as i1 from "@c8y/ngx-components"; import * as i2 from "../sub-assets.service"; import * as i3 from "@c8y/client"; import * as i4 from "@angular/common"; import * as i5 from "@angular/forms"; import * as i6 from "@c8y/ngx-components/device-grid"; import * as i7 from "ngx-bootstrap/popover"; export class AssignDevicesComponent { static { this.GRID_CONFIG_CONTEXT = { key: 'assign-devices-grid', configFilter: { filter: false } }; } constructor(alert, subAssetsService, inventoryService, gainsightService) { this.alert = alert; this.subAssetsService = subAssetsService; this.inventoryService = inventoryService; this.gainsightService = gainsightService; this.CURRENT_LOCATION = location.href; this.PRODUCT_EXPERIENCE = PRODUCT_EXPERIENCE_SUB_ASSETS_SHARED; this.refresh = new EventEmitter(); this.onCancel = new EventEmitter(); this.onShowChildDevices = new EventEmitter(); this.selectedDevice = new EventEmitter(); this.pendingStatus = false; this.pagination = { pageSize: 20, currentPage: 1 }; this.selected = []; this.canAssignDevice = false; this.actionControls = []; this.headerActionControls = []; this.showChildren = false; this.isSelectable = true; } onEnterKeyDown(_event) { if (this.selected.length > 0) { this.assignDevices(); } } async ngOnInit() { this.setNotIncludedInGroupQuery(); this.canAssignDevice = await this.subAssetsService.canAssignDevice({ id: this.currentGroupId }); this.setHeaderActionControls(); } setNotIncludedInGroupQuery() { const notIncludedInGroupQuery = { __not: { __bygroupid: this.currentGroupId } }; this.baseQuery = notIncludedInGroupQuery; } setHeaderActionControls() { const headerActionControls = []; const showChildDevices = { type: 'DISPLAY_CHILD_DEVICES_BUTTON', text: gettext('Enable child devices selection'), template: this.showDevicesToggle, callback: () => { this.showChildren = !this.showChildren; this.setActionControls(this.showChildren); this.gainsightService.triggerEvent(PRODUCT_EXPERIENCE_SUB_ASSETS_SHARED.EVENT, { component: PRODUCT_EXPERIENCE_SUB_ASSETS_SHARED.ASSIGN_DEVICES.COMPONENTS.ASSIGN_DEVICES, action: PRODUCT_EXPERIENCE_SUB_ASSETS_SHARED.ASSIGN_DEVICES.ACTIONS.DISPLAY_CHILD_DEVICES, url: this.CURRENT_LOCATION }); } }; headerActionControls.push(showChildDevices); this.headerActionControls = headerActionControls; } setActionControls(showChildren) { const actionControls = []; const selectChildrenAction = { type: 'SHOW_TARGET_CHILD_DEVICES', icon: 'enter-bottom', text: gettext('Select target child devices'), callback: (asset) => this.selectChildren(asset), showIf: (asset) => asset.childDevices.references.length > 0 }; if (showChildren) { actionControls.push(selectChildrenAction); } this.actionControls = actionControls; this.refresh.emit(); } async assignDevices() { if (this.canAssignDevice === false) { return; } this.pendingStatus = true; try { await this.inventoryService.childAssetsBulkAdd(this.selected, this.currentGroupId); this.refresh.emit(); this.alert.success(gettext('Devices assigned.')); } catch (error) { this.alert.danger(gettext('Could not assign devices.'), error); } this.pendingStatus = false; this.selected = []; this.onCancel.emit(); } onSelected(selectedDevicesIDs) { this.selected = selectedDevicesIDs; } selectChildren(asset) { this.onShowChildDevices.emit(true); this.selectedDevice.emit(asset); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: AssignDevicesComponent, deps: [{ token: i1.AlertService }, { token: i2.SubAssetsService }, { token: i3.InventoryService }, { token: i1.GainsightService }], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: AssignDevicesComponent, selector: "c8y-assign-devices", inputs: { currentGroupId: "currentGroupId", refresh: "refresh" }, outputs: { onCancel: "onCancel", onShowChildDevices: "onShowChildDevices", selectedDevice: "selectedDevice" }, host: { listeners: { "document:keydown.enter": "onEnterKeyDown($event)" } }, providers: [ { provide: DATA_GRID_CONFIGURATION_STRATEGY, useClass: UserPreferencesConfigurationStrategy }, { provide: DATA_GRID_CONFIGURATION_CONTEXT, useValue: AssignDevicesComponent.GRID_CONFIG_CONTEXT } ], viewQueries: [{ propertyName: "showDevicesToggle", first: true, predicate: ["showDevicesToggle"], descendants: true, read: TemplateRef }], ngImport: i0, template: "<div class=\"card-block flex-no-shrink separator-bottom col-xs-12 large-padding p-t-24 p-b-24\">\n <div class=\"row\">\n <div class=\"col-md-6 col-md-offset-3 col-lg-4 col-lg-offset-4\">\n <div class=\"h4 text-center text-medium\">\n {{ 'Assign devices' | translate }}\n </div>\n </div>\n </div>\n</div>\n<c8y-device-grid\n class=\"flex-grow col-xs-12 no-gutter\"\n [title]=\"''\"\n [actionControls]=\"actionControls\"\n [infiniteScroll]=\"'auto'\"\n [selectable]=\"isSelectable\"\n [pagination]=\"pagination\"\n (itemsSelect)=\"onSelected($event)\"\n [refresh]=\"refresh\"\n [baseQuery]=\"baseQuery\"\n [headerActionControls]=\"headerActionControls\"\n [withChildren]=\"true\"\n c8yProductExperience\n [actionName]=\"PRODUCT_EXPERIENCE.EVENT\"\n [actionData]=\"{ component: PRODUCT_EXPERIENCE.ASSIGN_DEVICES.COMPONENTS.ASSIGN_DEVICES }\"\n></c8y-device-grid>\n\n<div class=\"text-center card-footer p-24 separator\">\n <button\n class=\"btn btn-default\"\n title=\"{{ 'Cancel' | translate }}\"\n type=\"button\"\n (click)=\"onCancel.emit()\"\n c8yProductExperience\n [actionName]=\"PRODUCT_EXPERIENCE.EVENT\"\n [actionData]=\"{\n component: PRODUCT_EXPERIENCE.ASSIGN_DEVICES.COMPONENTS.ASSIGN_DEVICES,\n action: PRODUCT_EXPERIENCE.ASSIGN_DEVICES.ACTIONS.CANCEL\n }\"\n >\n <span>{{ 'Cancel' | translate }}</span>\n </button>\n <button\n class=\"btn btn-primary\"\n title=\"{{ 'Assign' | translate }}\"\n type=\"button\"\n [ngClass]=\"{ 'btn-pending': pendingStatus }\"\n (click)=\"assignDevices()\"\n [disabled]=\"selected.length === 0 || !canAssignDevice\"\n c8yProductExperience\n [actionName]=\"PRODUCT_EXPERIENCE.EVENT\"\n [actionData]=\"{\n component: PRODUCT_EXPERIENCE.ASSIGN_DEVICES.COMPONENTS.ASSIGN_DEVICES,\n action: PRODUCT_EXPERIENCE.ASSIGN_DEVICES.ACTIONS.ASSIGN\n }\"\n >\n <span>{{ 'Assign' | translate }}</span>\n </button>\n</div>\n\n<ng-template\n #showDevicesToggle\n let-control=\"headerActionControl\"\n>\n <label\n class=\"c8y-switch a-s-center\"\n title=\"{{ control.text | translate }}\"\n >\n <input\n type=\"checkbox\"\n [(ngModel)]=\"showChildren\"\n (click)=\"control.callback()\"\n />\n <span></span>\n <span>{{ control.text | translate }}</span>\n </label>\n <button\n class=\"btn-help m-r-16 a-s-center\"\n [attr.aria-label]=\"'Help' | translate\"\n [popover]=\"childDevicesPop\"\n placement=\"bottom\"\n triggers=\"focus\"\n type=\"button\"\n ></button>\n <ng-template #childDevicesPop>\n <span translate>\n Displays the button\n <span\n class=\"btn btn-dot btn-icon no-pointer\"\n title=\"Child devices icon\"\n >\n <i class=\"text-primary dlt-c8y-icon-enter-bottom\"></i>\n </span>\n next to target devices with children. Clicking it displays a list with all child devices of\n the selected target device.\n </span>\n </ng-template>\n</ng-template>\n", dependencies: [{ kind: "directive", type: i1.C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: i4.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i5.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i5.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i5.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i1.ProductExperienceDirective, selector: "[c8yProductExperience]", inputs: ["actionName", "actionData", "inherit", "suppressDataOverriding"] }, { kind: "component", type: i6.DeviceGridComponent, selector: "c8y-device-grid", inputs: ["dataCallback", "refresh", "title", "loadMoreItemsLabel", "loadingItemsLabel", "legacyConfigKey", "legacyFilterKey", "columns", "pagination", "infiniteScroll", "actionControls", "selectable", "singleSelection", "baseQuery", "bulkActionControls", "headerActionControls", "childDeviceGrid", "parentDeviceId", "withChildren", "showSearch", "activeClassName"], outputs: ["onColumnsChange", "onFilterChange", "onDeviceQueryStringChange", "itemsSelect"] }, { kind: "directive", type: i7.PopoverDirective, selector: "[popover]", inputs: ["adaptivePosition", "boundariesElement", "popover", "popoverContext", "popoverTitle", "placement", "outsideClick", "triggers", "container", "containerClass", "isOpen", "delay"], outputs: ["onShown", "onHidden"], exportAs: ["bs-popover"] }, { kind: "pipe", type: i1.C8yTranslatePipe, name: "translate" }] }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: AssignDevicesComponent, decorators: [{ type: Component, args: [{ selector: 'c8y-assign-devices', providers: [ { provide: DATA_GRID_CONFIGURATION_STRATEGY, useClass: UserPreferencesConfigurationStrategy }, { provide: DATA_GRID_CONFIGURATION_CONTEXT, useValue: AssignDevicesComponent.GRID_CONFIG_CONTEXT } ], template: "<div class=\"card-block flex-no-shrink separator-bottom col-xs-12 large-padding p-t-24 p-b-24\">\n <div class=\"row\">\n <div class=\"col-md-6 col-md-offset-3 col-lg-4 col-lg-offset-4\">\n <div class=\"h4 text-center text-medium\">\n {{ 'Assign devices' | translate }}\n </div>\n </div>\n </div>\n</div>\n<c8y-device-grid\n class=\"flex-grow col-xs-12 no-gutter\"\n [title]=\"''\"\n [actionControls]=\"actionControls\"\n [infiniteScroll]=\"'auto'\"\n [selectable]=\"isSelectable\"\n [pagination]=\"pagination\"\n (itemsSelect)=\"onSelected($event)\"\n [refresh]=\"refresh\"\n [baseQuery]=\"baseQuery\"\n [headerActionControls]=\"headerActionControls\"\n [withChildren]=\"true\"\n c8yProductExperience\n [actionName]=\"PRODUCT_EXPERIENCE.EVENT\"\n [actionData]=\"{ component: PRODUCT_EXPERIENCE.ASSIGN_DEVICES.COMPONENTS.ASSIGN_DEVICES }\"\n></c8y-device-grid>\n\n<div class=\"text-center card-footer p-24 separator\">\n <button\n class=\"btn btn-default\"\n title=\"{{ 'Cancel' | translate }}\"\n type=\"button\"\n (click)=\"onCancel.emit()\"\n c8yProductExperience\n [actionName]=\"PRODUCT_EXPERIENCE.EVENT\"\n [actionData]=\"{\n component: PRODUCT_EXPERIENCE.ASSIGN_DEVICES.COMPONENTS.ASSIGN_DEVICES,\n action: PRODUCT_EXPERIENCE.ASSIGN_DEVICES.ACTIONS.CANCEL\n }\"\n >\n <span>{{ 'Cancel' | translate }}</span>\n </button>\n <button\n class=\"btn btn-primary\"\n title=\"{{ 'Assign' | translate }}\"\n type=\"button\"\n [ngClass]=\"{ 'btn-pending': pendingStatus }\"\n (click)=\"assignDevices()\"\n [disabled]=\"selected.length === 0 || !canAssignDevice\"\n c8yProductExperience\n [actionName]=\"PRODUCT_EXPERIENCE.EVENT\"\n [actionData]=\"{\n component: PRODUCT_EXPERIENCE.ASSIGN_DEVICES.COMPONENTS.ASSIGN_DEVICES,\n action: PRODUCT_EXPERIENCE.ASSIGN_DEVICES.ACTIONS.ASSIGN\n }\"\n >\n <span>{{ 'Assign' | translate }}</span>\n </button>\n</div>\n\n<ng-template\n #showDevicesToggle\n let-control=\"headerActionControl\"\n>\n <label\n class=\"c8y-switch a-s-center\"\n title=\"{{ control.text | translate }}\"\n >\n <input\n type=\"checkbox\"\n [(ngModel)]=\"showChildren\"\n (click)=\"control.callback()\"\n />\n <span></span>\n <span>{{ control.text | translate }}</span>\n </label>\n <button\n class=\"btn-help m-r-16 a-s-center\"\n [attr.aria-label]=\"'Help' | translate\"\n [popover]=\"childDevicesPop\"\n placement=\"bottom\"\n triggers=\"focus\"\n type=\"button\"\n ></button>\n <ng-template #childDevicesPop>\n <span translate>\n Displays the button\n <span\n class=\"btn btn-dot btn-icon no-pointer\"\n title=\"Child devices icon\"\n >\n <i class=\"text-primary dlt-c8y-icon-enter-bottom\"></i>\n </span>\n next to target devices with children. Clicking it displays a list with all child devices of\n the selected target device.\n </span>\n </ng-template>\n</ng-template>\n" }] }], ctorParameters: () => [{ type: i1.AlertService }, { type: i2.SubAssetsService }, { type: i3.InventoryService }, { type: i1.GainsightService }], propDecorators: { currentGroupId: [{ type: Input }], refresh: [{ type: Input }], onCancel: [{ type: Output }], onShowChildDevices: [{ type: Output }], selectedDevice: [{ type: Output }], showDevicesToggle: [{ type: ViewChild, args: ['showDevicesToggle', { read: TemplateRef }] }], onEnterKeyDown: [{ type: HostListener, args: ['document:keydown.enter', ['$event']] }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXNzaWduLWRldmljZXMuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3ViLWFzc2V0cy9hc3NpZ24tZGV2aWNlcy9hc3NpZ24tZGV2aWNlcy5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi9zdWItYXNzZXRzL2Fzc2lnbi1kZXZpY2VzL2Fzc2lnbi1kZXZpY2VzLmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFDTCxTQUFTLEVBQ1QsWUFBWSxFQUNaLFlBQVksRUFDWixLQUFLLEVBQ0wsTUFBTSxFQUNOLFdBQVcsRUFDWCxTQUFTLEVBQ1YsTUFBTSxlQUFlLENBQUM7QUFDdkIsT0FBTyxFQUFrQixnQkFBZ0IsRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUMvRCxPQUFPLEVBRUwsWUFBWSxFQUNaLCtCQUErQixFQUMvQixnQ0FBZ0MsRUFDaEMsZ0JBQWdCLEVBQ2hCLE9BQU8sRUFJUCxvQ0FBb0MsRUFFckMsTUFBTSxxQkFBcUIsQ0FBQztBQUM3QixPQUFPLEVBQUUsb0NBQW9DLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQztBQUNsRixPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSx1QkFBdUIsQ0FBQzs7Ozs7Ozs7O0FBZ0J6RCxNQUFNLE9BQU8sc0JBQXNCO2FBQ2pCLHdCQUFtQixHQUFxQztRQUN0RSxHQUFHLEVBQUUscUJBQXFCO1FBQzFCLFlBQVksRUFBRTtZQUNaLE1BQU0sRUFBRSxLQUFLO1NBQ2Q7S0FDRixBQUxrQyxDQUtqQztJQXVCRixZQUNVLEtBQW1CLEVBQ25CLGdCQUFrQyxFQUNsQyxnQkFBa0MsRUFDbEMsZ0JBQWtDO1FBSGxDLFVBQUssR0FBTCxLQUFLLENBQWM7UUFDbkIscUJBQWdCLEdBQWhCLGdCQUFnQixDQUFrQjtRQUNsQyxxQkFBZ0IsR0FBaEIsZ0JBQWdCLENBQWtCO1FBQ2xDLHFCQUFnQixHQUFoQixnQkFBZ0IsQ0FBa0I7UUF6QjVDLHFCQUFn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QUFRLEdBQUcsa0JBQWtCLENBQUM7SUFDckMsQ0FBQztJQUVELGNBQWMsQ0FBQyxLQUFxQjtRQUNsQyxJQUFJLENBQUMsa0JBQWtCLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO1FBQ25DLElBQUksQ0FBQyxjQUFjLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQ2xDLENBQUM7K0dBdkhVLHNCQUFzQjttR0FBdEIsc0JBQXNCLDJTQVh0QjtZQUNUO2dCQUNFLE9BQU8sRUFBRSxnQ0FBZ0M7Z0JBQ3pDLFFBQVEsRUFBRSxvQ0FBb0M7YUFDL0M7WUFDRDtnQkFDRSxPQUFPLEVBQUUsK0JBQStCO2dCQUN4QyxRQUFRLEVBQUUsc0JBQXNCLENBQUMsbUJBQW1CO2FBQ3JEO1NBQ0YsNkhBa0J1QyxXQUFXLDZCQ3hEckQsczlGQWlHQTs7NEZEekRhLHNCQUFzQjtrQkFkbEMsU0FBUzsrQkFDRSxvQkFBb0IsYUFFbkI7d0JBQ1Q7NEJBQ0UsT0FBTyxFQUFFLGdDQUFnQzs0QkFDekMsUUFBUSxFQUFFLG9DQUFvQzt5QkFDL0M7d0JBQ0Q7NEJBQ0UsT0FBTyxFQUFFLCtCQUErQjs0QkFDeEMsUUFBUSxFQUFFLHVCQUF1QixtQkFBbUI7eUJBQ3JEO3FCQUNGOzhLQWFRLGNBQWM7c0JBQXRCLEtBQUs7Z0JBQ0csT0FBTztzQkFBZixLQUFLO2dCQUNJLFFBQVE7c0JBQWpCLE1BQU07Z0JBQ0csa0JBQWtCO3NCQUEzQixNQUFNO2dCQUNHLGNBQWM7c0JBQXZCLE1BQU07Z0JBQ2dELGlCQUFpQjtzQkFBdkUsU0FBUzt1QkFBQyxtQkFBbUIsRUFBRSxFQUFFLElBQUksRUFBRSxXQUFXLEVBQUU7Z0JBb0JELGNBQWM7c0JBQWpFLFlBQVk7dUJBQUMsd0JBQXdCLEVBQUUsQ0FBQyxRQUFRLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xuICBDb21wb25lbnQsXG4gIEV2ZW50RW1pdHRlcixcbiAgSG9zdExpc3RlbmVyLFxuICBJbnB1dCxcbiAgT3V0cHV0LFxuICBUZW1wbGF0ZVJlZixcbiAgVmlld0NoaWxkXG59IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgSU1hbmFnZWRPYmplY3QsIEludmVudG9yeVNlcnZpY2UgfSBmcm9tICdAYzh5L2NsaWVudCc7XG5pbXBvcnQge1xuICBBY3Rpb25Db250cm9sLFxuICBBbGVydFNlcnZpY2UsXG4gIERBVEFfR1JJRF9DT05GSUdVUkFUSU9OX0NPTlRFWFQsXG4gIERBVEFfR1JJRF9DT05GSUdVUkFUSU9OX1NUUkFURUdZLFxuICBHYWluc2lnaHRTZXJ2aWNlLFxuICBnZXR0ZXh0LFxuICBIZWFkZXJBY3Rpb25Db250cm9sLFxuICBQYWdpbmF0aW9uLFxuICBSb3csXG4gIFVzZXJQcmVmZXJlbmNlc0NvbmZpZ3VyYXRpb25TdHJhdGVneSxcbiAgVXNlclByZWZlcmVuY2VzR3JpZENvbmZpZ0NvbnRleHRcbn0gZnJvbSAnQGM4eS9uZ3gtY29tcG9uZW50cyc7XG5pbXBvcnQgeyBQUk9EVUNUX0VYUEVSSUVOQ0VfU1VCX0FTU0VUU19TSEFSRUQgfSBmcm9tICcuLi9zaGFyZWQvc3ViLWFzc2V0cy5tb2RlbCc7XG5pbXBvcnQgeyBTdWJBc3NldHNTZXJ2aWNlIH0gZnJvbSAnLi4vc3ViLWFzc2V0cy5zZXJ2aWNlJztcblxuQENvbXBvbmVudCh7XG4gIHNlbGVjdG9yOiAnYzh5LWFzc2lnbi1kZXZpY2VzJyxcbiAgdGVtcGxhdGVVcmw6ICcuL2Fzc2lnbi1kZXZpY2VzLmNvbXBvbmVudC5odG1sJyxcbiAgcHJvdmlkZXJzOiBbXG4gICAge1xuICAgICAgcHJvdmlkZTogREFUQV9HUklEX0NPTkZJR1VSQVRJT05fU1RSQVRFR1ksXG4gICAgICB1c2VDbGFzczogVXNlclByZWZlcmVuY2VzQ29uZmlndXJhdGlvblN0cmF0ZWd5XG4gICAgfSxcbiAgICB7XG4gICAgICBwcm92aWRlOiBEQVRBX0dSSURfQ09ORklHVVJBVElPTl9DT05URVhULFxuICAgICAgdXNlVmFsdWU6IEFzc2lnbkRldmljZXNDb21wb25lbnQuR1JJRF9DT05GSUdfQ09OVEVYVFxuICAgIH1cbiAgXVxufSlcbmV4cG9ydCBjbGFzcyBBc3NpZ25EZXZpY2VzQ29tcG9uZW50IHtcbiAgc3RhdGljIHJlYWRvbmx5IEdSSURfQ09ORklHX0NPTlRFWFQ6IFVzZXJQcmVmZXJlbmNlc0dyaWRDb25maWdDb250ZXh0ID0ge1xuICAgIGtleTogJ2Fzc2lnbi1kZXZpY2VzLWdyaWQnLFxuICAgIGNvbmZpZ0ZpbHRlcjoge1xuICAgICAgZmlsdGVyOiBmYWxzZVxuICAgIH1cbiAgfTtcblxuICBDVVJSRU5UX0xPQ0FUSU9OID0gbG9jYXRpb24uaHJlZjtcbiAgUFJPRFVDVF9FWFBFUklFTkNFID0gUFJPRFVDVF9FWFBFUklFTkNFX1NVQl9BU1NFVFNfU0hBUkVEO1xuXG4gIEBJbnB1dCgpIGN1cnJlbnRHcm91cElkOiBzdHJpbmc7XG4gIEBJbnB1dCgpIHJlZnJlc2ggPSBuZXcgRXZlbnRFbWl0dGVyPGFueT4oKTtcbiAgQE91dHB1dCgpIG9uQ2FuY2VsID0gbmV3IEV2ZW50RW1pdHRlcjxhbnk+KCk7XG4gIEBPdXRwdXQoKSBvblNob3dDaGlsZERldmljZXMgPSBuZXcgRXZlbnRFbWl0dGVyPGJvb2xlYW4+KCk7XG4gIEBPdXRwdXQoKSBzZWxlY3RlZERldmljZSA9IG5ldyBFdmVudEVtaXR0ZXI8SU1hbmFnZWRPYmplY3Q+KCk7XG4gIEBWaWV3Q2hpbGQoJ3Nob3dEZXZpY2VzVG9nZ2xlJywgeyByZWFkOiBUZW1wbGF0ZVJlZiB9KSBzaG93RGV2aWNlc1RvZ2dsZTogVGVtcGxhdGVSZWY8YW55PjtcblxuICBkZXZpY2VRdWVyeVN0cmluZ091dHB1dDogc3RyaW5nO1xuICBwZW5kaW5nU3RhdHVzID0gZmFsc2U7XG4gIHBhZ2luYXRpb246IFBhZ2luYXRpb24gPSB7IHBhZ2VTaXplOiAyMCwgY3VycmVudFBhZ2U6IDEgfTtcbiAgc2VsZWN0ZWQ6IHN0cmluZ1tdID0gW107XG4gIGJhc2VRdWVyeTogYW55O1xuICBjYW5Bc3NpZ25EZXZpY2UgPSBmYWxzZTtcbiAgYWN0aW9uQ29udHJvbHM6IEFjdGlvbkNvbnRyb2xbXSA9IFtdO1xuICBoZWFkZXJBY3Rpb25Db250cm9sczogSGVhZGVyQWN0aW9uQ29udHJvbFtdID0gW107XG4gIHNob3dDaGlsZHJlbiA9IGZhbHNlO1xuICByZWFkb25seSBpc1NlbGVjdGFibGUgPSB0cnVlO1xuXG4gIGNvbnN0cnVjdG9yKFxuICAgIHByaXZhdGUgYWxlcnQ6IEFsZXJ0U2VydmljZSxcbiAgICBwcml2YXRlIHN1YkFzc2V0c1NlcnZpY2U6IFN1YkFzc2V0c1NlcnZpY2UsXG4gICAgcHJpdmF0ZSBpbnZlbnRvcnlTZXJ2aWNlOiBJbnZlbnRvcnlTZXJ2aWNlLFxuICAgIHByaXZhdGUgZ2FpbnNpZ2h0U2VydmljZTogR2FpbnNpZ2h0U2VydmljZVxuICApIHt9XG5cbiAgQEhvc3RMaXN0ZW5lcignZG9jdW1lbnQ6a2V5ZG93bi5lbnRlcicsIFsnJGV2ZW50J10pIG9uRW50ZXJLZXlEb3duKF9ldmVudDogS2V5Ym9hcmRFdmVudCkge1xuICAgIGlmICh0aGlzLnNlbGVjdGVkLmxlbmd0aCA+IDApIHtcbiAgICAgIHRoaXMuYXNzaWduRGV2aWNlcygpO1xuICAgIH1cbiAgfVxuXG4gIGFzeW5jIG5nT25Jbml0KCkge1xuICAgIHRoaXMuc2V0Tm90SW5jbHVkZWRJbkdyb3VwUXVlcnkoKTtcbiAgICB0aGlzLmNhbkFzc2lnbkRldmljZSA9IGF3YWl0IHRoaXMuc3ViQXNzZXRzU2VydmljZS5jYW5Bc3NpZ25EZXZpY2Uoe1xuICAgICAgaWQ6IHRoaXMuY3VycmVudEdyb3VwSWRcbiAgICB9IGFzIElNYW5hZ2VkT2JqZWN0KTtcbiAgICB0aGlzLnNldEhlYWRlckFjdGlvbkNvbnRyb2xzKCk7XG4gIH1cblxuICBzZXROb3RJbmNsdWRlZEluR3JvdXBRdWVyeSgpIHtcbiAgICBjb25zdCBub3RJbmNsdWRlZEluR3JvdXBRdWVyeSA9IHsgX19ub3Q6IHsgX19ieWdyb3VwaWQ6IHRoaXMuY3VycmVudEdyb3VwSWQgfSB9O1xuICAgIHRoaXMuYmFzZVF1ZXJ5ID0gbm90SW5jbHVkZWRJbkdyb3VwUXVlcnk7XG4gIH1cblxuICBzZXRIZWFkZXJBY3Rpb25Db250cm9scygpIHtcbiAgICBjb25zdCBoZWFkZXJBY3Rpb25Db250cm9sczogSGVhZGVyQWN0aW9uQ29udHJvbFtdID0gW107XG4gICAgY29uc3Qgc2hvd0NoaWxkRGV2aWNlcyA9IHtcbiAgICAgIHR5cGU6ICdESVNQTEFZX0NISUxEX0RFVklDRVNfQlVUVE9OJyxcbiAgICAgIHRleHQ6IGdldHRleHQoJ0VuYWJsZSBjaGlsZCBkZXZpY2VzIHNlbGVjdGlvbicpLFxuICAgICAgdGVtcGxhdGU6IHRoaXMuc2hvd0RldmljZXNUb2dnbGUsXG4gICAgICBjYWxsYmFjazogKCkgPT4ge1xuICAgICAgICB0aGlzLnNob3dDaGlsZHJlbiA9ICF0aGlzLnNob3dDaGlsZHJlbjtcbiAgICAgICAgdGhpcy5zZXRBY3Rpb25Db250cm9scyh0aGlzLnNob3dDaGlsZHJlbik7XG4gICAgICAgIHRoaXMuZ2FpbnNpZ2h0U2VydmljZS50cmlnZ2VyRXZlbnQoUFJPRFVDVF9FWFBFUklFTkNFX1NVQl9BU1NFVFNfU0hBUkVELkVWRU5ULCB7XG4gICAgICAgICAgY29tcG9uZW50OiBQUk9EVUNUX0VYUEVSSUVOQ0VfU1VCX0FTU0VUU19TSEFSRUQuQVNTSUdOX0RFVklDRVMuQ09NUE9ORU5UUy5BU1NJR05fREVWSUNFUyxcbiAgICAgICAgICBhY3Rpb246IFBST0RVQ1RfRVhQRVJJRU5DRV9TVUJfQVNTRVRTX1NIQVJFRC5BU1NJR05fREVWSUNFUy5BQ1RJT05TLkRJU1BMQVlfQ0hJTERfREVWSUNFUyxcbiAgICAgICAgICB1cmw6IHRoaXMuQ1VSUkVOVF9MT0NBVElPTlxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9O1xuICAgIGhlYWRlckFjdGlvbkNvbnRyb2xzLnB1c2goc2hvd0NoaWxkRGV2aWNlcyk7XG4gICAgdGhpcy5oZWFkZXJBY3Rpb25Db250cm9scyA9IGhlYWRlckFjdGlvbkNvbnRyb2xzO1xuICB9XG5cbiAgc2V0QWN0aW9uQ29udHJvbHMoc2hvd0NoaWxkcmVuOiBib29sZWFuKSB7XG4gICAgY29uc3QgYWN0aW9uQ29udHJvbHM6IEFjdGlvbkNvbnRyb2xbXSA9IFtdO1xuXG4gICAgY29uc3Qgc2VsZWN0Q2hpbGRyZW5BY3Rpb246IEFjdGlvbkNvbnRyb2wgPSB7XG4gICAgICB0eXBlOiAnU0hPV19UQVJHRVRfQ0hJTERfREVWSUNFUycsXG4gICAgICBpY29uOiAnZW50ZXItYm90dG9tJyxcbiAgICAgIHRleHQ6IGdldHRleHQoJ1NlbGVjdCB0YXJnZXQgY2hpbGQgZGV2aWNlcycpLFxuICAgICAgY2FsbGJhY2s6IChhc3NldDogUm93KSA9PiB0aGlzLnNlbGVjdENoaWxkcmVuKGFzc2V0IGFzIElNYW5hZ2VkT2JqZWN0KSxcbiAgICAgIHNob3dJZjogKGFzc2V0OiBSb3cpID0+IGFzc2V0LmNoaWxkRGV2aWNlcy5yZWZlcmVuY2VzLmxlbmd0aCA+IDBcbiAgICB9O1xuXG4gICAgaWYgKHNob3dDaGlsZHJlbikge1xuICAgICAgYWN0aW9uQ29udHJvbHMucHVzaChzZWxlY3RDaGlsZHJlbkFjdGlvbik7XG4gICAgfVxuXG4gICAgdGhpcy5hY3Rpb25Db250cm9scyA9IGFjdGlvbkNvbnRyb2xzO1xuICAgIHRoaXMucmVmcmVzaC5lbWl0KCk7XG4gIH1cblxuICBhc3luYyBhc3NpZ25EZXZpY2VzKCkge1xuICAgIGlmICh0aGlzLmNhbkFzc2lnbkRldmljZSA9PT0gZmFsc2UpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgdGhpcy5wZW5kaW5nU3RhdHVzID0gdHJ1ZTtcblxuICAgIHRyeSB7XG4gICAgICBhd2FpdCB0aGlzLmludmVudG9yeVNlcnZpY2UuY2hpbGRBc3NldHNCdWxrQWRkKHRoaXMuc2VsZWN0ZWQsIHRoaXMuY3VycmVudEdyb3VwSWQpO1xuICAgICAgdGhpcy5yZWZyZXNoLmVtaXQoKTtcbiAgICAgIHRoaXMuYWxlcnQuc3VjY2VzcyhnZXR0ZXh0KCdEZXZpY2VzIGFzc2lnbmVkLicpKTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgdGhpcy5hbGVydC5kYW5nZXIoZ2V0dGV4dCgnQ291bGQgbm90IGFzc2lnbiBkZXZpY2VzLicpLCBlcnJvcik7XG4gICAgfVxuICAgIHRoaXMucGVuZGluZ1N0YXR1cyA9IGZhbHNlO1xuICAgIHRoaXMuc2VsZWN0ZWQgPSBbXTtcbiAgICB0aGlzLm9uQ2FuY2VsLmVtaXQoKTtcbiAgfVxuXG4gIG9uU2VsZWN0ZWQoc2VsZWN0ZWREZXZpY2VzSURzOiBzdHJpbmdbXSkge1xuICAgIHRoaXMuc2VsZWN0ZWQgPSBzZWxlY3RlZERldmljZXNJRHM7XG4gIH1cblxuICBzZWxlY3RDaGlsZHJlbihhc3NldDogSU1hbmFnZWRPYmplY3QpIHtcbiAgICB0aGlzLm9uU2hvd0NoaWxkRGV2aWNlcy5lbWl0KHRydWUpO1xuICAgIHRoaXMuc2VsZWN0ZWREZXZpY2UuZW1pdChhc3NldCk7XG4gIH1cbn1cbiIsIjxkaXYgY2xhc3M9XCJjYXJkLWJsb2NrIGZsZXgtbm8tc2hyaW5rIHNlcGFyYXRvci1ib3R0b20gY29sLXhzLTEyIGxhcmdlLXBhZGRpbmcgcC10LTI0IHAtYi0yNFwiPlxuICA8ZGl2IGNsYXNzPVwicm93XCI+XG4gICAgPGRpdiBjbGFzcz1cImNvbC1tZC02IGNvbC1tZC1vZmZzZXQtMyBjb2wtbGctNCBjb2wtbGctb2Zmc2V0LTRcIj5cbiAgICAgIDxkaXYgY2xhc3M9XCJoNCB0ZXh0LWNlbnRlciB0ZXh0LW1lZGl1bVwiPlxuICAgICAgICB7eyAnQXNzaWduIGRldmljZXMnIHwgdHJhbnNsYXRlIH19XG4gICAgICA8L2Rpdj5cbiAgICA8L2Rpdj5cbiAgPC9kaXY+XG48L2Rpdj5cbjxjOHktZGV2aWNlLWdyaWRcbiAgY2xhc3M9XCJmbGV4LWdyb3cgY29sLXhzLTEyIG5vLWd1dHRlclwiXG4gIFt0aXRsZV09XCInJ1wiXG4gIFthY3Rpb25Db250cm9sc109XCJhY3Rpb25Db250cm9sc1wiXG4gIFtpbmZpbml0ZVNjcm9sbF09XCInYXV0bydcIlxuICBbc2VsZWN0YWJsZV09XCJpc1NlbGVjdGFibGVcIlxuICBbcGFnaW5hdGlvbl09XCJwYWdpbmF0aW9uXCJcbiAgKGl0ZW1zU2VsZWN0KT1cIm9uU2VsZWN0ZWQoJGV2ZW50KVwiXG4gIFtyZWZyZXNoXT1cInJlZnJlc2hcIlxuICBbYmFzZVF1ZXJ5XT1cImJhc2VRdWVyeVwiXG4gIFtoZWFkZXJBY3Rpb25Db250cm9sc109XCJoZWFkZXJBY3Rpb25Db250cm9sc1wiXG4gIFt3aXRoQ2hpbGRyZW5dPVwidHJ1ZVwiXG4gIGM4eVByb2R1Y3RFeHBlcmllbmNlXG4gIFthY3Rpb25OYW1lXT1cIlBST0RVQ1RfRVhQRVJJRU5DRS5FVkVOVFwiXG4gIFthY3Rpb25EYXRhXT1cInsgY29tcG9uZW50OiBQUk9EVUNUX0VYUEVSSUVOQ0UuQVNTSUdOX0RFVklDRVMuQ09NUE9ORU5UUy5BU1NJR05fREVWSUNFUyB9XCJcbj48L2M4eS1kZXZpY2UtZ3JpZD5cblxuPGRpdiBjbGFzcz1cInRleHQtY2VudGVyIGNhcmQtZm9vdGVyIHAtMjQgc2VwYXJhdG9yXCI+XG4gIDxidXR0b25cbiAgICBjbGFzcz1cImJ0biBidG4tZGVmYXVsdFwiXG4gICAgdGl0bGU9XCJ7eyAnQ2FuY2VsJyB8IHRyYW5zbGF0ZSB9fVwiXG4gICAgdHlwZT1cImJ1dHRvblwiXG4gICAgKGNsaWNrKT1cIm9uQ2FuY2VsLmVtaXQoKVwiXG4gICAgYzh5UHJvZHVjdEV4cGVyaWVuY2VcbiAgICBbYWN0aW9uTmFtZV09XCJQUk9EVUNUX0VYUEVSSUVOQ0UuRVZFTlRcIlxuICAgIFthY3Rpb25EYXRhXT1cIntcbiAgICAgIGNvbXBvbmVudDogUFJPRFVDVF9FWFBFUklFTkNFLkFTU0lHTl9ERVZJQ0VTLkNPTVBPTkVOVFMuQVNTSUdOX0RFVklDRVMsXG4gICAgICBhY3Rpb246IFBST0RVQ1RfRVhQRVJJRU5DRS5BU1NJR05fREVWSUNFUy5BQ1RJT05TLkNBTkNFTFxuICAgIH1cIlxuICA+XG4gICAgPHNwYW4+e3sgJ0NhbmNlbCcgfCB0cmFuc2xhdGUgfX08L3NwYW4+XG4gIDwvYnV0dG9uPlxuICA8YnV0dG9uXG4gICAgY2xhc3M9XCJidG4gYnRuLXByaW1hcnlcIlxuICAgIHRpdGxlPVwie3sgJ0Fzc2lnbicgfCB0cmFuc2xhdGUgfX1cIlxuICAgIHR5cGU9XCJidXR0b25cIlxuICAgIFtuZ0NsYXNzXT1cInsgJ2J0bi1wZW5kaW5nJzogcGVuZGluZ1N0YXR1cyB9XCJcbiAgICAoY2xpY2spPVwiYXNzaWduRGV2aWNlcygpXCJcbiAgICBbZGlzYWJsZWRdPVwic2VsZWN0ZWQubGVuZ3RoID09PSAwIHx8ICFjYW5Bc3NpZ25EZXZpY2VcIlxuICAgIGM4eVByb2R1Y3RFeHBlcmllbmNlXG4gICAgW2FjdGlvbk5hbWVdPVwiUFJPRFVDVF9FWFBFUklFTkNFLkVWRU5UXCJcbiAgICBbYWN0aW9uRGF0YV09XCJ7XG4gICAgICBjb21wb25lbnQ6IFBST0RVQ1RfRVhQRVJJRU5DRS5BU1NJR05fREVWSUNFUy5DT01QT05FTlRTLkFTU0lHTl9ERVZJQ0VTLFxuICAgICAgYWN0aW9uOiBQUk9EVUNUX0VYUEVSSUVOQ0UuQVNTSUdOX0RFVklDRVMuQUNUSU9OUy5BU1NJR05cbiAgICB9XCJcbiAgPlxuICAgIDxzcGFuPnt7ICdBc3NpZ24nIHwgdHJhbnNsYXRlIH19PC9zcGFuPlxuICA8L2J1dHRvbj5cbjwvZGl2PlxuXG48bmctdGVtcGxhdGVcbiAgI3Nob3dEZXZpY2VzVG9nZ2xlXG4gIGxldC1jb250cm9sPVwiaGVhZGVyQWN0aW9uQ29udHJvbFwiXG4+XG4gIDxsYWJlbFxuICAgIGNsYXNzPVwiYzh5LXN3aXRjaCBhLXMtY2VudGVyXCJcbiAgICB0aXRsZT1cInt7IGNvbnRyb2wudGV4dCB8IHRyYW5zbGF0ZSB9fVwiXG4gID5cbiAgICA8aW5wdXRcbiAgICAgIHR5cGU9XCJjaGVja2JveFwiXG4gICAgICBbKG5nTW9kZWwpXT1cInNob3dDaGlsZHJlblwiXG4gICAgICAoY2xpY2spPVwiY29udHJvbC5jYWxsYmFjaygpXCJcbiAgICAvPlxuICAgIDxzcGFuPjwvc3Bhbj5cbiAgICA8c3Bhbj57eyBjb250cm9sLnRleHQgfCB0cmFuc2xhdGUgfX08L3NwYW4+XG4gIDwvbGFiZWw+XG4gIDxidXR0b25cbiAgICBjbGFzcz1cImJ0bi1oZWxwIG0tci0xNiBhLXMtY2VudGVyXCJcbiAgICBbYXR0ci5hcmlhLWxhYmVsXT1cIidIZWxwJyB8IHRyYW5zbGF0ZVwiXG4gICAgW3BvcG92ZXJdPVwiY2hpbGREZXZpY2VzUG9wXCJcbiAgICBwbGFjZW1lbnQ9XCJib3R0b21cIlxuICAgIHRyaWdnZXJzPVwiZm9jdXNcIlxuICAgIHR5cGU9XCJidXR0b25cIlxuICA+PC9idXR0b24+XG4gIDxuZy10ZW1wbGF0ZSAjY2hpbGREZXZpY2VzUG9wPlxuICAgIDxzcGFuIHRyYW5zbGF0ZT5cbiAgICAgIERpc3BsYXlzIHRoZSBidXR0b25cbiAgICAgIDxzcGFuXG4gICAgICAgIGNsYXNzPVwiYnRuIGJ0bi1kb3QgYnRuLWljb24gbm8tcG9pbnRlclwiXG4gICAgICAgIHRpdGxlPVwiQ2hpbGQgZGV2aWNlcyBpY29uXCJcbiAgICAgID5cbiAgICAgICAgPGkgY2xhc3M9XCJ0ZXh0LXByaW1hcnkgZGx0LWM4eS1pY29uLWVudGVyLWJvdHRvbVwiPjwvaT5cbiAgICAgIDwvc3Bhbj5cbiAgICAgIG5leHQgdG8gdGFyZ2V0IGRldmljZXMgd2l0aCBjaGlsZHJlbi4gQ2xpY2tpbmcgaXQgZGlzcGxheXMgYSBsaXN0IHdpdGggYWxsIGNoaWxkIGRldmljZXMgb2ZcbiAgICAgIHRoZSBzZWxlY3RlZCB0YXJnZXQgZGV2aWNlLlxuICAgIDwvc3Bhbj5cbiAgPC9uZy10ZW1wbGF0ZT5cbjwvbmctdGVtcGxhdGU+XG4iXX0=