UNPKG

@c8y/ngx-components

Version:

Angular modules for Cumulocity IoT applications

196 lines 37.4 kB
import { Component, EventEmitter, forwardRef } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; import { AlertService, BuiltInActionType, DataGridService, gettext, ModalService, PRODUCT_EXPERIENCE_EVENT_SOURCE, Status } from '@c8y/ngx-components'; import { DeviceTypeGridColumn, RepositoryItemNameGridColumn, RepositoryService, RepositoryType } from '@c8y/ngx-components/repository/shared'; import { TranslateService } from '@ngx-translate/core'; import { cloneDeep } from 'lodash-es'; import { BsModalService } from 'ngx-bootstrap/modal'; import { from } from 'rxjs'; import { map } from 'rxjs/operators'; import { AddDeviceProfileComponent } from './add-device-profile.component'; import { PRODUCT_EXPERIENCE_DEVICE_PROFILE } from './device-profile.model'; import { DeviceProfileService } from './device-profile.service'; import * as i0 from "@angular/core"; import * as i1 from "@c8y/ngx-components/repository/shared"; import * as i2 from "@c8y/ngx-components"; import * as i3 from "ngx-bootstrap/modal"; import * as i4 from "@ngx-translate/core"; import * as i5 from "@angular/router"; import * as i6 from "./device-profile.service"; import * as i7 from "@angular/common"; export class DeviceProfileListComponent { constructor(repositoryService, gridService, modalService, bsModalService, translateService, alertService, router, activatedRoute, deviceProfileService) { this.repositoryService = repositoryService; this.gridService = gridService; this.modalService = modalService; this.bsModalService = bsModalService; this.translateService = translateService; this.alertService = alertService; this.router = router; this.activatedRoute = activatedRoute; this.deviceProfileService = deviceProfileService; this.sizeRequestDone = false; this.refresh$ = new EventEmitter(); this.isDataPresent$ = from(this.repositoryService.listRepositoryEntries(RepositoryType.PROFILE, { skipLegacy: true })).pipe(map(({ data }) => data.length > 0)); this.columns = [ new RepositoryItemNameGridColumn({ filterLabel: gettext('Filter device profile by name'), placeholder: gettext('ubuntu core') }), new DeviceTypeGridColumn({ filterLabel: gettext('Filter device profile by device type') }) ]; this.actionControls = []; this.pagination = { pageSize: 50, currentPage: 1 }; this.productExperienceEvent = { eventName: PRODUCT_EXPERIENCE_DEVICE_PROFILE.EVENTS.REPOSITORY, data: { component: PRODUCT_EXPERIENCE_DEVICE_PROFILE.COMPONENTS.DEVICE_PROFILE_LIST } }; this.noResultsMessage = gettext('No results to display.'); this.noDataMessage = gettext('No device profiles to display.'); this.noResultsSubtitle = gettext('Refine your search terms or check your spelling.'); this.noDataSubtitle = gettext('Add a new device profile by clicking below.'); this.serverSideDataCallback = this.onDataSourceModifier.bind(this); } ngOnInit() { this.actionControls.push({ type: BuiltInActionType.Edit, callback: this.editDeviceProfile.bind(this) }); this.actionControls.push({ type: 'duplicate', icon: 'copy', text: gettext('Duplicate'), callback: this.duplicateDeviceProfile.bind(this) }); this.actionControls.push({ type: BuiltInActionType.Delete, callback: this.deleteDeviceProfile.bind(this) }); } async onDataSourceModifier(dataSourceModifier) { const dataRequest = this.repositoryService.listRepositoryEntries(RepositoryType.PROFILE, { query: this.gridService.getQueryObj(dataSourceModifier.columns), skipDefaultOrder: true, params: { pageSize: dataSourceModifier.pagination.pageSize, currentPage: dataSourceModifier.pagination.currentPage } }); const filtererdSizeRequest = this.repositoryService .listRepositoryEntries(RepositoryType.PROFILE, { skipDefaultOrder: true, query: this.gridService.getQueryObj(dataSourceModifier.columns), params: { pageSize: 1 } }) .then(response => response?.paging?.totalPages); this.sizeRequest = this.repositoryService .listRepositoryEntries(RepositoryType.PROFILE, { skipDefaultOrder: true, params: { pageSize: 1 } }) .then(response => { this.sizeRequestDone = true; return response?.paging?.totalPages; }); const [dataResponse, size, filteredSize] = await Promise.all([ dataRequest, this.sizeRequest, filtererdSizeRequest ]); const { res, data, paging } = dataResponse; const serverSideDataResult = { res, data, paging, filteredSize, size }; return serverSideDataResult; } editDeviceProfile(deviceProfile) { this.router.navigate([deviceProfile.id], { relativeTo: this.activatedRoute }); } async createDeviceProfile() { const modal = this.bsModalService.show(AddDeviceProfileComponent, { class: 'modal-sm', ariaDescribedby: 'addDeviceProfileModalDescription', ariaLabelledBy: 'addDeviceProfileModalTitle', ignoreBackdropClick: true, keyboard: false, initialState: { productExperienceEvent: { ...this.productExperienceEvent, data: { ...this.productExperienceEvent.data, component: PRODUCT_EXPERIENCE_DEVICE_PROFILE.COMPONENTS.ADD_DEVICE_PROFILE } } } }).content; try { const profileId = await modal.result; modal.close(); this.router.navigateByUrl(`/device-profiles/${profileId}`); } catch (ex) { // do nothing } } async duplicateDeviceProfile(deviceProfile) { const copy = cloneDeep(deviceProfile); copy.id = null; copy.name = 'Duplicate of ' + deviceProfile.name; const mo = (await this.deviceProfileService.createDeviceProfile(copy)).data; this.router.navigateByUrl(`/device-profiles/${mo.id}`); } async deleteDeviceProfile(deviceProfile) { const deviceProfileName = deviceProfile.name; const title = gettext('Delete device profile'); const confirmationText = this.translateService.instant(gettext('You are about to delete a device profile "{{ deviceProfileName }}".'), { deviceProfileName }); const finalQuestion = this.translateService.instant(gettext('Do you want to proceed?')); try { await this.modalService.confirm(title, `${confirmationText} ${finalQuestion}`, Status.DANGER, { ok: gettext('Delete') }, {}, this.productExperienceEvent); await this.delete(deviceProfile.id); this.refresh$.next(); } catch (ex) { // do nothing } } trackByName(_index, column) { return column.name; } async delete(profileId) { try { await this.repositoryService.delete(profileId); this.alertService.success(gettext('Device profile deleted.')); } catch (ex) { this.alertService.addServerFailure(ex); } } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DeviceProfileListComponent, deps: [{ token: i1.RepositoryService }, { token: i2.DataGridService }, { token: i2.ModalService }, { token: i3.BsModalService }, { token: i4.TranslateService }, { token: i2.AlertService }, { token: i5.Router }, { token: i5.ActivatedRoute }, { token: i6.DeviceProfileService }], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: DeviceProfileListComponent, selector: "c8y-device-profile-list", providers: [ { provide: PRODUCT_EXPERIENCE_EVENT_SOURCE, useExisting: forwardRef(() => DeviceProfileListComponent) } ], ngImport: i0, template: "<c8y-title>{{ 'Device profiles' | translate }}</c8y-title>\n\n<c8y-breadcrumb>\n <c8y-breadcrumb-item\n icon=\"c8y-management\"\n label=\"{{ 'Management' | translate }}\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item\n icon=\"c8y-device-profile\"\n label=\"{{ 'Device profiles' | translate }}\"\n ></c8y-breadcrumb-item>\n</c8y-breadcrumb>\n\n<c8y-action-bar-item [placement]=\"'right'\">\n <button\n class=\"btn btn-link\"\n title=\"{{ 'Add device profile' | translate }}\"\n data-cy=\"device-profile-list--Add-device-profile\"\n (click)=\"createDeviceProfile()\"\n >\n <i c8yIcon=\"plus-circle\"></i>\n {{ 'Add device profile' | translate }}\n </button>\n</c8y-action-bar-item>\n\n<c8y-help\n src=\"/docs/device-management-application/managing-device-data/#managing-device-profiles\"\n></c8y-help>\n\n<div class=\"content-fullpage border-top border-bottom\">\n <c8y-data-grid\n [title]=\"'Device profiles' | translate\"\n [refresh]=\"refresh$\"\n [pagination]=\"pagination\"\n [columns]=\"columns\"\n [actionControls]=\"actionControls\"\n [infiniteScroll]=\"'auto'\"\n [serverSideDataCallback]=\"serverSideDataCallback\"\n >\n <c8y-ui-empty-state\n [icon]=\"stats?.size > 0 ? 'search' : 'c8y-tools'\"\n [title]=\"stats?.size > 0 ? (noResultsMessage | translate) : (noDataMessage | translate)\"\n [subtitle]=\"stats?.size > 0 ? (noResultsSubtitle | translate) : (noDataSubtitle | translate)\"\n *emptyStateContext=\"let stats\"\n [horizontal]=\"stats?.size > 0\"\n >\n <p *ngIf=\"stats?.size === 0\">\n <button\n class=\"btn btn-primary\"\n title=\"{{ 'Add device profile' | translate }}\"\n type=\"button\"\n (click)=\"createDeviceProfile()\"\n >\n {{ 'Add device profile' | translate }}\n </button>\n </p>\n </c8y-ui-empty-state>\n <ng-container *ngFor=\"let column of columns; trackBy: trackByName\">\n <c8y-column [name]=\"column.name\"></c8y-column>\n </ng-container>\n </c8y-data-grid>\n</div>\n", dependencies: [{ kind: "component", type: i2.ActionBarItemComponent, selector: "c8y-action-bar-item", inputs: ["placement", "priority", "itemClass", "injector", "groupId", "inGroupPriority"] }, { 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.EmptyStateContextDirective, selector: "[emptyStateContext]" }, { kind: "directive", type: i2.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: i7.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i7.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2.ColumnDirective, selector: "c8y-column", inputs: ["name"] }, { kind: "component", type: i2.DataGridComponent, selector: "c8y-data-grid", inputs: ["title", "loadMoreItemsLabel", "loadingItemsLabel", "showSearch", "refresh", "columns", "rows", "pagination", "infiniteScroll", "serverSideDataCallback", "selectable", "singleSelection", "selectionPrimaryKey", "displayOptions", "actionControls", "bulkActionControls", "headerActionControls", "searchText", "configureColumnsEnabled", "showCounterWarning", "activeClassName", "expandableRows"], outputs: ["rowMouseOver", "rowMouseLeave", "rowClick", "onConfigChange", "onBeforeFilter", "onBeforeSearch", "onFilter", "itemsSelect", "onReload", "onAddCustomColumn", "onRemoveCustomColumn", "onColumnFilterReset", "onSort", "onPageSizeChange", "onColumnReordered", "onColumnVisibilityChange"] }, { kind: "component", type: i2.TitleComponent, selector: "c8y-title", inputs: ["pageTitleUpdate"] }, { kind: "component", type: i2.HelpComponent, selector: "c8y-help", inputs: ["src", "isCollapsed", "priority", "icon"] }, { kind: "pipe", type: i2.C8yTranslatePipe, name: "translate" }] }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DeviceProfileListComponent, decorators: [{ type: Component, args: [{ selector: 'c8y-device-profile-list', providers: [ { provide: PRODUCT_EXPERIENCE_EVENT_SOURCE, useExisting: forwardRef(() => DeviceProfileListComponent) } ], template: "<c8y-title>{{ 'Device profiles' | translate }}</c8y-title>\n\n<c8y-breadcrumb>\n <c8y-breadcrumb-item\n icon=\"c8y-management\"\n label=\"{{ 'Management' | translate }}\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item\n icon=\"c8y-device-profile\"\n label=\"{{ 'Device profiles' | translate }}\"\n ></c8y-breadcrumb-item>\n</c8y-breadcrumb>\n\n<c8y-action-bar-item [placement]=\"'right'\">\n <button\n class=\"btn btn-link\"\n title=\"{{ 'Add device profile' | translate }}\"\n data-cy=\"device-profile-list--Add-device-profile\"\n (click)=\"createDeviceProfile()\"\n >\n <i c8yIcon=\"plus-circle\"></i>\n {{ 'Add device profile' | translate }}\n </button>\n</c8y-action-bar-item>\n\n<c8y-help\n src=\"/docs/device-management-application/managing-device-data/#managing-device-profiles\"\n></c8y-help>\n\n<div class=\"content-fullpage border-top border-bottom\">\n <c8y-data-grid\n [title]=\"'Device profiles' | translate\"\n [refresh]=\"refresh$\"\n [pagination]=\"pagination\"\n [columns]=\"columns\"\n [actionControls]=\"actionControls\"\n [infiniteScroll]=\"'auto'\"\n [serverSideDataCallback]=\"serverSideDataCallback\"\n >\n <c8y-ui-empty-state\n [icon]=\"stats?.size > 0 ? 'search' : 'c8y-tools'\"\n [title]=\"stats?.size > 0 ? (noResultsMessage | translate) : (noDataMessage | translate)\"\n [subtitle]=\"stats?.size > 0 ? (noResultsSubtitle | translate) : (noDataSubtitle | translate)\"\n *emptyStateContext=\"let stats\"\n [horizontal]=\"stats?.size > 0\"\n >\n <p *ngIf=\"stats?.size === 0\">\n <button\n class=\"btn btn-primary\"\n title=\"{{ 'Add device profile' | translate }}\"\n type=\"button\"\n (click)=\"createDeviceProfile()\"\n >\n {{ 'Add device profile' | translate }}\n </button>\n </p>\n </c8y-ui-empty-state>\n <ng-container *ngFor=\"let column of columns; trackBy: trackByName\">\n <c8y-column [name]=\"column.name\"></c8y-column>\n </ng-container>\n </c8y-data-grid>\n</div>\n" }] }], ctorParameters: () => [{ type: i1.RepositoryService }, { type: i2.DataGridService }, { type: i2.ModalService }, { type: i3.BsModalService }, { type: i4.TranslateService }, { type: i2.AlertService }, { type: i5.Router }, { type: i5.ActivatedRoute }, { type: i6.DeviceProfileService }] }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGV2aWNlLXByb2ZpbGUtbGlzdC5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9kZXZpY2UtcHJvZmlsZS9kZXZpY2UtcHJvZmlsZS1saXN0LmNvbXBvbmVudC50cyIsIi4uLy4uLy4uL2RldmljZS1wcm9maWxlL2RldmljZS1wcm9maWxlLWxpc3QuY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFNBQVMsRUFBRSxZQUFZLEVBQUUsVUFBVSxFQUFVLE1BQU0sZUFBZSxDQUFDO0FBQzVFLE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFFekQsT0FBTyxFQUVMLFlBQVksRUFDWixpQkFBaUIsRUFFakIsZUFBZSxFQUVmLE9BQU8sRUFDUCxZQUFZLEVBQ1osK0JBQStCLEVBSS9CLE1BQU0sRUFDUCxNQUFNLHFCQUFxQixDQUFDO0FBQzdCLE9BQU8sRUFDTCxvQkFBb0IsRUFDcEIsNEJBQTRCLEVBQzVCLGlCQUFpQixFQUNqQixjQUFjLEVBQ2YsTUFBTSx1Q0FBdUMsQ0FBQztBQUMvQyxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQUN2RCxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sV0FBVyxDQUFDO0FBQ3RDLE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQUNyRCxPQUFPLEVBQUUsSUFBSSxFQUFjLE1BQU0sTUFBTSxDQUFDO0FBQ3hDLE9BQU8sRUFBRSxHQUFHLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUNyQyxPQUFPLEVBQUUseUJBQXlCLEVBQUUsTUFBTSxnQ0FBZ0MsQ0FBQztBQUMzRSxPQUFPLEVBQUUsaUNBQWlDLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUMzRSxPQUFPLEVBQUUsb0JBQW9CLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQzs7Ozs7Ozs7O0FBWWhFLE1BQU0sT0FB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QkFBeUIsYUFFeEI7d0JBQ1Q7NEJBQ0UsT0FBTyxFQUFFLCtCQUErQjs0QkFDeEMsV0FBVyxFQUFFLFVBQVUsQ0FBQyxHQUFHLEVBQUUsMkJBQTJCLENBQUM7eUJBQzFEO3FCQUNGIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQ29tcG9uZW50LCBFdmVudEVtaXR0ZXIsIGZvcndhcmRSZWYsIE9uSW5pdCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgQWN0aXZhdGVkUm91dGUsIFJvdXRlciB9IGZyb20gJ0Bhbmd1bGFyL3JvdXRlcic7XG5pbXBvcnQgeyBJTWFuYWdlZE9iamVjdCwgSVJlc3VsdExpc3QgfSBmcm9tICdAYzh5L2NsaWVudCc7XG5pbXBvcnQge1xuICBBY3Rpb25Db250cm9sLFxuICBBbGVydFNlcnZpY2UsXG4gIEJ1aWx0SW5BY3Rpb25UeXBlLFxuICBDb2x1bW4sXG4gIERhdGFHcmlkU2VydmljZSxcbiAgRGF0YVNvdXJjZU1vZGlmaWVyLFxuICBnZXR0ZXh0LFxuICBNb2RhbFNlcnZpY2UsXG4gIFBST0RVQ1RfRVhQRVJJRU5DRV9FVkVOVF9TT1VSQ0UsXG4gIFByb2R1Y3RFeHBlcmllbmNlRXZlbnQsXG4gIFNlcnZlclNpZGVEYXRhQ2FsbGJhY2ssXG4gIFNlcnZlclNpZGVEYXRhUmVzdWx0LFxuICBTdGF0dXNcbn0gZnJvbSAnQGM4eS9uZ3gtY29tcG9uZW50cyc7XG5pbXBvcnQge1xuICBEZXZpY2VUeXBlR3JpZENvbHVtbixcbiAgUmVwb3NpdG9yeUl0ZW1OYW1lR3JpZENvbHVtbixcbiAgUmVwb3NpdG9yeVNlcnZpY2UsXG4gIFJlcG9zaXRvcnlUeXBlXG59IGZyb20gJ0BjOHkvbmd4LWNvbXBvbmVudHMvcmVwb3NpdG9yeS9zaGFyZWQnO1xuaW1wb3J0IHsgVHJhbnNsYXRlU2VydmljZSB9IGZyb20gJ0BuZ3gtdHJhbnNsYXRlL2NvcmUnO1xuaW1wb3J0IHsgY2xvbmVEZWVwIH0gZnJvbSAnbG9kYXNoLWVzJztcbmltcG9ydCB7IEJzTW9kYWxTZXJ2aWNlIH0gZnJvbSAnbmd4LWJvb3RzdHJhcC9tb2RhbCc7XG5pbXBvcnQgeyBmcm9tLCBPYnNlcnZhYmxlIH0gZnJvbSAncnhqcyc7XG5pbXBvcnQgeyBtYXAgfSBmcm9tICdyeGpzL29wZXJhdG9ycyc7XG5pbXBvcnQgeyBBZGREZXZpY2VQcm9maWxlQ29tcG9uZW50IH0gZnJvbSAnLi9hZGQtZGV2aWNlLXByb2ZpbGUuY29tcG9uZW50JztcbmltcG9ydCB7IFBST0RVQ1RfRVhQRVJJRU5DRV9ERVZJQ0VfUFJPRklMRSB9IGZyb20gJy4vZGV2aWNlLXByb2ZpbGUubW9kZWwnO1xuaW1wb3J0IHsgRGV2aWNlUHJvZmlsZVNlcnZpY2UgfSBmcm9tICcuL2RldmljZS1wcm9maWxlLnNlcnZpY2UnO1xuXG5AQ29tcG9uZW50KHtcbiAgc2VsZWN0b3I6ICdjOHktZGV2aWNlLXByb2ZpbGUtbGlzdCcsXG4gIHRlbXBsYXRlVXJsOiAnLi9kZXZpY2UtcHJvZmlsZS1saXN0LmNvbXBvbmVudC5odG1sJyxcbiAgcHJvdmlkZXJzOiBbXG4gICAge1xuICAgICAgcHJvdmlkZTogUFJPRFVDVF9FWFBFUklFTkNFX0VWRU5UX1NPVVJDRSxcbiAgICAgIHVzZUV4aXN0aW5nOiBmb3J3YXJkUmVmKCgpID0+IERldmljZVByb2ZpbGVMaXN0Q29tcG9uZW50KVxuICAgIH1cbiAgXVxufSlcbmV4cG9ydCBjbGFzcyBEZXZpY2VQcm9maWxlTGlzdENvbXBvbmVudCBpbXBsZW1lbnRzIE9uSW5pdCB7XG4gIHNpemVSZXF1ZXN0OiBQcm9taXNlPG51bWJlcj47XG4gIHNpemVSZXF1ZXN0RG9uZSA9IGZhbHNlO1xuICByZWZyZXNoJDogRXZlbnRFbWl0dGVyPHZvaWQ+ID0gbmV3IEV2ZW50RW1pdHRlcigpO1xuICBpc0RhdGFQcmVzZW50JDogT2JzZXJ2YWJsZTxib29sZWFuPiA9IGZyb20oXG4gICAgdGhpcy5yZXBvc2l0b3J5U2VydmljZS5saXN0UmVwb3NpdG9yeUVudHJpZXMoUmVwb3NpdG9yeVR5cGUuUFJPRklMRSwgeyBza2lwTGVnYWN5OiB0cnVlIH0pXG4gICkucGlwZShtYXAoKHsgZGF0YSB9KSA9PiBkYXRhLmxlbmd0aCA+IDApKTtcblxuICBjb2x1bW5zOiBDb2x1bW5bXSA9IFtcbiAgICBuZXcgUmVwb3NpdG9yeUl0ZW1OYW1lR3JpZENvbHVtbih7XG4gICAgICBmaWx0ZXJMYWJlbDogZ2V0dGV4dCgnRmlsdGVyIGRldmljZSBwcm9maWxlIGJ5IG5hbWUnKSxcbiAgICAgIHBsYWNlaG9sZGVyOiBnZXR0ZXh0KCd1YnVudHUgY29yZScpXG4gICAgfSksXG4gICAgbmV3IERldmljZVR5cGVHcmlkQ29sdW1uKHsgZmlsdGVyTGFiZWw6IGdldHRleHQoJ0ZpbHRlciBkZXZpY2UgcHJvZmlsZSBieSBkZXZpY2UgdHlwZScpIH0pXG4gIF07XG4gIGFjdGlvbkNvbnRyb2xzOiBBY3Rpb25Db250cm9sW10gPSBbXTtcbiAgc2VydmVyU2lkZURhdGFDYWxsYmFjazogU2VydmVyU2lkZURhdGFDYWxsYmFjaztcbiAgcGFnaW5hdGlvbiA9IHtcbiAgICBwYWdlU2l6ZTogNTAsXG4gICAgY3VycmVudFBhZ2U6IDFcbiAgfTtcbiAgcHJvZHVjdEV4cGVyaWVuY2VFdmVudDogUHJvZHVjdEV4cGVyaWVuY2VFdmVudCA9IHtcbiAgICBldmVudE5hbWU6IFBST0RVQ1RfRVhQRVJJRU5DRV9ERVZJQ0VfUFJPRklMRS5FVkVOVFMuUkVQT1NJVE9SWSxcbiAgICBkYXRhOiB7XG4gICAgICBjb21wb25lbnQ6IFBST0RVQ1RfRVhQRVJJRU5DRV9ERVZJQ0VfUFJPRklMRS5DT01QT05FTlRTLkRFVklDRV9QUk9GSUxFX0xJU1RcbiAgICB9XG4gIH07XG5cbiAgbm9SZXN1bHRzTWVzc2FnZSA9IGdldHRleHQoJ05vIHJlc3VsdHMgdG8gZGlzcGxheS4nKTtcbiAgbm9EYXRhTWVzc2FnZSA9IGdldHRleHQoJ05vIGRldmljZSBwcm9maWxlcyB0byBkaXNwbGF5LicpO1xuICBub1Jlc3VsdHNTdWJ0aXRsZSA9IGdldHRleHQoJ1JlZmluZSB5b3VyIHNlYXJjaCB0ZXJtcyBvciBjaGVjayB5b3VyIHNwZWxsaW5nLicpO1xuICBub0RhdGFTdWJ0aXRsZSA9IGdldHRleHQoJ0FkZCBhIG5ldyBkZXZpY2UgcHJvZmlsZSBieSBjbGlja2luZyBiZWxvdy4nKTtcblxuICBjb25zdHJ1Y3RvcihcbiAgICBwcml2YXRlIHJlcG9zaXRvcnlTZXJ2aWNlOiBSZXBvc2l0b3J5U2VydmljZSxcbiAgICBwcml2YXRlIGdyaWRTZXJ2aWNlOiBEYXRhR3JpZFNlcnZpY2UsXG4gICAgcHJpdmF0ZSBtb2RhbFNlcnZpY2U6IE1vZGFsU2VydmljZSxcbiAgICBwcml2YXRlIGJzTW9kYWxTZXJ2aWNlOiBCc01vZGFsU2VydmljZSxcbiAgICBwcml2YXRlIHRyYW5zbGF0ZVNlcnZpY2U6IFRyYW5zbGF0ZVNlcnZpY2UsXG4gICAgcHJpdmF0ZSBhbGVydFNlcnZpY2U6IEFsZXJ0U2VydmljZSxcbiAgICBwcml2YXRlIHJvdXRlcjogUm91dGVyLFxuICAgIHByaXZhdGUgYWN0aXZhdGVkUm91dGU6IEFjdGl2YXRlZFJvdXRlLFxuICAgIHByaXZhdGUgZGV2aWNlUHJvZmlsZVNlcnZpY2U6IERldmljZVByb2ZpbGVTZXJ2aWNlXG4gICkge1xuICAgIHRoaXMuc2VydmVyU2lkZURhdGFDYWxsYmFjayA9IHRoaXMub25EYXRhU291cmNlTW9kaWZpZXIuYmluZCh0aGlzKTtcbiAgfVxuXG4gIG5nT25Jbml0KCk6IHZvaWQge1xuICAgIHRoaXMuYWN0aW9uQ29udHJvbHMucHVzaCh7XG4gICAgICB0eXBlOiBCdWlsdEluQWN0aW9uVHlwZS5FZGl0LFxuICAgICAgY2FsbGJhY2s6IHRoaXMuZWRpdERldmljZVByb2ZpbGUuYmluZCh0aGlzKVxuICAgIH0pO1xuICAgIHRoaXMuYWN0aW9uQ29udHJvbHMucHVzaCh7XG4gICAgICB0eXBlOiAnZHVwbGljYXRlJyxcbiAgICAgIGljb246ICdjb3B5JyxcbiAgICAgIHRleHQ6IGdldHRleHQoJ0R1cGxpY2F0ZScpLFxuICAgICAgY2FsbGJhY2s6IHRoaXMuZHVwbGljYXRlRGV2aWNlUHJvZmlsZS5iaW5kKHRoaXMpXG4gICAgfSk7XG4gICAgdGhpcy5hY3Rpb25Db250cm9scy5wdXNoKHtcbiAgICAgIHR5cGU6IEJ1aWx0SW5BY3Rpb25UeXBlLkRlbGV0ZSxcbiAgICAgIGNhbGxiYWNrOiB0aGlzLmRlbGV0ZURldmljZVByb2ZpbGUuYmluZCh0aGlzKVxuICAgIH0pO1xuICB9XG5cbiAgYXN5bmMgb25EYXRhU291cmNlTW9kaWZpZXIoXG4gICAgZGF0YVNvdXJjZU1vZGlmaWVyOiBEYXRhU291cmNlTW9kaWZpZXJcbiAgKTogUHJvbWlzZTxTZXJ2ZXJTaWRlRGF0YVJlc3VsdD4ge1xuICAgIGNvbnN0IGRhdGFSZXF1ZXN0OiBQcm9taXNlPElSZXN1bHRMaXN0PElNYW5hZ2VkT2JqZWN0Pj4gPVxuICAgICAgdGhpcy5yZXBvc2l0b3J5U2VydmljZS5saXN0UmVwb3NpdG9yeUVudHJpZXMoUmVwb3NpdG9yeVR5cGUuUFJPRklMRSwge1xuICAgICAgICBxdWVyeTogdGhpcy5ncmlkU2VydmljZS5nZXRRdWVyeU9iaihkYXRhU291cmNlTW9kaWZpZXIuY29sdW1ucyksXG4gICAgICAgIHNraXBEZWZhdWx0T3JkZXI6IHRydWUsXG4gICAgICAgIHBhcmFtczoge1xuICAgICAgICAgIHBhZ2VTaXplOiBkYXRhU291cmNlTW9kaWZpZXIucGFnaW5hdGlvbi5wYWdlU2l6ZSxcbiAgICAgICAgICBjdXJyZW50UGFnZTogZGF0YVNvdXJjZU1vZGlmaWVyLnBhZ2luYXRpb24uY3VycmVudFBhZ2VcbiAgICAgICAgfVxuICAgICAgfSk7XG5cbiAgICBjb25zdCBmaWx0ZXJlcmRTaXplUmVxdWVzdDogUHJvbWlzZTxudW1iZXI+ID0gdGhpcy5yZXBvc2l0b3J5U2VydmljZVxuICAgICAgLmxpc3RSZXBvc2l0b3J5RW50cmllcyhSZXBvc2l0b3J5VHlwZS5QUk9GSUxFLCB7XG4gICAgICAgIHNraXBEZWZhdWx0T3JkZXI6IHRydWUsXG4gICAgICAgIHF1ZXJ5OiB0aGlzLmdyaWRTZXJ2aWNlLmdldFF1ZXJ5T2JqKGRhdGFTb3VyY2VNb2RpZmllci5jb2x1bW5zKSxcbiAgICAgICAgcGFyYW1zOiB7IHBhZ2VTaXplOiAxIH1cbiAgICAgIH0pXG4gICAgICAudGhlbihyZXNwb25zZSA9PiByZXNwb25zZT8ucGFnaW5nPy50b3RhbFBhZ2VzKTtcblxuICAgIHRoaXMuc2l6ZVJlcXVlc3QgPSB0aGlzLnJlcG9zaXRvcnlTZXJ2aWNlXG4gICAgICAubGlzdFJlcG9zaXRvcnlFbnRyaWVzKFJlcG9zaXRvcnlUeXBlLlBST0ZJTEUsIHtcbiAgICAgICAgc2tpcERlZmF1bHRPcmRlcjogdHJ1ZSxcbiAgICAgICAgcGFyYW1zOiB7IHBhZ2VTaXplOiAxIH1cbiAgICAgIH0pXG4gICAgICAudGhlbihyZXNwb25zZSA9PiB7XG4gICAgICAgIHRoaXMuc2l6ZVJlcXVlc3REb25lID0gdHJ1ZTtcbiAgICAgICAgcmV0dXJuIHJlc3BvbnNlPy5wYWdpbmc/LnRvdGFsUGFnZXM7XG4gICAgICB9KTtcblxuICAgIGNvbnN0IFtkYXRhUmVzcG9uc2UsIHNpemUsIGZpbHRlcmVkU2l6ZV0gPSBhd2FpdCBQcm9taXNlLmFsbChbXG4gICAgICBkYXRhUmVxdWVzdCxcbiAgICAgIHRoaXMuc2l6ZVJlcXVlc3QsXG4gICAgICBmaWx0ZXJlcmRTaXplUmVxdWVzdFxuICAgIF0pO1xuXG4gICAgY29uc3QgeyByZXMsIGRhdGEsIHBhZ2luZyB9ID0gZGF0YVJlc3BvbnNlO1xuXG4gICAgY29uc3Qgc2VydmVyU2lkZURhdGFSZXN1bHQ6IFNlcnZlclNpZGVEYXRhUmVzdWx0ID0ge1xuICAgICAgcmVzLFxuICAgICAgZGF0YSxcbiAgICAgIHBhZ2luZyxcbiAgICAgIGZpbHRlcmVkU2l6ZSxcbiAgICAgIHNpemVcbiAgICB9O1xuXG4gICAgcmV0dXJuIHNlcnZlclNpZGVEYXRhUmVzdWx0O1xuICB9XG5cbiAgZWRpdERldmljZVByb2ZpbGUoZGV2aWNlUHJvZmlsZTogUGFydGlhbDxJTWFuYWdlZE9iamVjdD4pIHtcbiAgICB0aGlzLnJvdXRlci5uYXZpZ2F0ZShbZGV2aWNlUHJvZmlsZS5pZF0sIHsgcmVsYXRpdmVUbzogdGhpcy5hY3RpdmF0ZWRSb3V0ZSB9KTtcbiAgfVxuXG4gIGFzeW5jIGNyZWF0ZURldmljZVByb2ZpbGUoKSB7XG4gICAgY29uc3QgbW9kYWwgPSB0aGlzLmJzTW9kYWxTZXJ2aWNlLnNob3coQWRkRGV2aWNlUHJvZmlsZUNvbXBvbmVudCwge1xuICAgICAgY2xhc3M6ICdtb2RhbC1zbScsXG4gICAgICBhcmlhRGVzY3JpYmVkYnk6ICdhZGREZXZpY2VQcm9maWxlTW9kYWxEZXNjcmlwdGlvbicsXG4gICAgICBhcmlhTGFiZWxsZWRCeTogJ2FkZERldmljZVByb2ZpbGVNb2RhbFRpdGxlJyxcbiAgICAgIGlnbm9yZUJhY2tkcm9wQ2xpY2s6IHRydWUsXG4gICAgICBrZXlib2FyZDogZmFsc2UsXG4gICAgICBpbml0aWFsU3RhdGU6IHtcbiAgICAgICAgcHJvZHVjdEV4cGVyaWVuY2VFdmVudDoge1xuICAgICAgICAgIC4uLnRoaXMucHJvZHVjdEV4cGVyaWVuY2VFdmVudCxcbiAgICAgICAgICBkYXRhOiB7XG4gICAgICAgICAgICAuLi50aGlzLnByb2R1Y3RFeHBlcmllbmNlRXZlbnQuZGF0YSxcbiAgICAgICAgICAgIGNvbXBvbmVudDogUFJPRFVDVF9FWFBFUklFTkNFX0RFVklDRV9QUk9GSUxFLkNPTVBPTkVOVFMuQUREX0RFVklDRV9QUk9GSUxFXG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG4gICAgfSkuY29udGVudCBhcyBBZGREZXZpY2VQcm9maWxlQ29tcG9uZW50O1xuICAgIHRyeSB7XG4gICAgICBjb25zdCBwcm9maWxlSWQgPSBhd2FpdCBtb2RhbC5yZXN1bHQ7XG4gICAgICBtb2RhbC5jbG9zZSgpO1xuICAgICAgdGhpcy5yb3V0ZXIubmF2aWdhdGVCeVVybChgL2RldmljZS1wcm9maWxlcy8ke3Byb2ZpbGVJZH1gKTtcbiAgICB9IGNhdGNoIChleCkge1xuICAgICAgLy8gZG8gbm90aGluZ1xuICAgIH1cbiAgfVxuXG4gIGFzeW5jIGR1cGxpY2F0ZURldmljZVByb2ZpbGUoZGV2aWNlUHJvZmlsZSkge1xuICAgIGNvbnN0IGNvcHkgPSBjbG9uZURlZXAoZGV2aWNlUHJvZmlsZSk7XG4gICAgY29weS5pZCA9IG51bGw7XG4gICAgY29weS5uYW1lID0gJ0R1cGxpY2F0ZSBvZiAnICsgZGV2aWNlUHJvZmlsZS5uYW1lO1xuICAgIGNvbnN0IG1vID0gKGF3YWl0IHRoaXMuZGV2aWNlUHJvZmlsZVNlcnZpY2UuY3JlYXRlRGV2aWNlUHJvZmlsZShjb3B5KSkuZGF0YTtcbiAgICB0aGlzLnJvdXRlci5uYXZpZ2F0ZUJ5VXJsKGAvZGV2aWNlLXByb2ZpbGVzLyR7bW8uaWR9YCk7XG4gIH1cblxuICBhc3luYyBkZWxldGVEZXZpY2VQcm9maWxlKGRldmljZVByb2ZpbGUpIHtcbiAgICBjb25zdCBkZXZpY2VQcm9maWxlTmFtZSA9IGRldmljZVByb2ZpbGUubmFtZTtcbiAgICBjb25zdCB0aXRsZSA9IGdldHRleHQoJ0RlbGV0ZSBkZXZpY2UgcHJvZmlsZScpO1xuICAgIGNvbnN0IGNvbmZpcm1hdGlvblRleHQgPSB0aGlzLnRyYW5zbGF0ZVNlcnZpY2UuaW5zdGFudChcbiAgICAgIGdldHRleHQoJ1lvdSBhcmUgYWJvdXQgdG8gZGVsZXRlIGEgZGV2aWNlIHByb2ZpbGUgXCJ7eyBkZXZpY2VQcm9maWxlTmFtZSB9fVwiLicpLFxuICAgICAgeyBkZXZpY2VQcm9maWxlTmFtZSB9XG4gICAgKTtcbiAgICBjb25zdCBmaW5hbFF1ZXN0aW9uID0gdGhpcy50cmFuc2xhdGVTZXJ2aWNlLmluc3RhbnQoZ2V0dGV4dCgnRG8geW91IHdhbnQgdG8gcHJvY2VlZD8nKSk7XG4gICAgdHJ5IHtcbiAgICAgIGF3YWl0IHRoaXMubW9kYWxTZXJ2aWNlLmNvbmZpcm0oXG4gICAgICAgIHRpdGxlLFxuICAgICAgICBgJHtjb25maXJtYXRpb25UZXh0fSAke2ZpbmFsUXVlc3Rpb259YCxcbiAgICAgICAgU3RhdHVzLkRBTkdFUixcbiAgICAgICAge1xuICAgICAgICAgIG9rOiBnZXR0ZXh0KCdEZWxldGUnKVxuICAgICAgICB9LFxuICAgICAgICB7fSxcbiAgICAgICAgdGhpcy5wcm9kdWN0RXhwZXJpZW5jZUV2ZW50XG4gICAgICApO1xuICAgICAgYXdhaXQgdGhpcy5kZWxldGUoZGV2aWNlUHJvZmlsZS5pZCk7XG4gICAgICB0aGlzLnJlZnJlc2gkLm5leHQoKTtcbiAgICB9IGNhdGNoIChleCkge1xuICAgICAgLy8gZG8gbm90aGluZ1xuICAgIH1cbiAgfVxuXG4gIHRyYWNrQnlOYW1lKF9pbmRleCwgY29sdW1uOiBDb2x1bW4pOiBzdHJpbmcge1xuICAgIHJldHVybiBjb2x1bW4ubmFtZTtcbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgZGVsZXRlKHByb2ZpbGVJZCkge1xuICAgIHRyeSB7XG4gICAgICBhd2FpdCB0aGlzLnJlcG9zaXRvcnlTZXJ2aWNlLmRlbGV0ZShwcm9maWxlSWQpO1xuICAgICAgdGhpcy5hbGVydFNlcnZpY2Uuc3VjY2VzcyhnZXR0ZXh0KCdEZXZpY2UgcHJvZmlsZSBkZWxldGVkLicpKTtcbiAgICB9IGNhdGNoIChleCkge1xuICAgICAgdGhpcy5hbGVydFNlcnZpY2UuYWRkU2VydmVyRmFpbHVyZShleCk7XG4gICAgfVxuICB9XG59XG4iLCI8Yzh5LXRpdGxlPnt7ICdEZXZpY2UgcHJvZmlsZXMnIHwgdHJhbnNsYXRlIH19PC9jOHktdGl0bGU+XG5cbjxjOHktYnJlYWRjcnVtYj5cbiAgPGM4eS1icmVhZGNydW1iLWl0ZW1cbiAgICBpY29uPVwiYzh5LW1hbmFnZW1lbnRcIlxuICAgIGxhYmVsPVwie3sgJ01hbmFnZW1lbnQnIHwgdHJhbnNsYXRlIH19XCJcbiAgPjwvYzh5LWJyZWFkY3J1bWItaXRlbT5cbiAgPGM4eS1icmVhZGNydW1iLWl0ZW1cbiAgICBpY29uPVwiYzh5LWRldmljZS1wcm9maWxlXCJcbiAgICBsYWJlbD1cInt7ICdEZXZpY2UgcHJvZmlsZXMnIHwgdHJhbnNsYXRlIH19XCJcbiAgPjwvYzh5LWJyZWFkY3J1bWItaXRlbT5cbjwvYzh5LWJyZWFkY3J1bWI+XG5cbjxjOHktYWN0aW9uLWJhci1pdGVtIFtwbGFjZW1lbnRdPVwiJ3JpZ2h0J1wiPlxuICA8YnV0dG9uXG4gICAgY2xhc3M9XCJidG4gYnRuLWxpbmtcIlxuICAgIHRpdGxlPVwie3sgJ0FkZCBkZXZpY2UgcHJvZmlsZScgfCB0cmFuc2xhdGUgfX1cIlxuICAgIGRhdGEtY3k9XCJkZXZpY2UtcHJvZmlsZS1saXN0LS1BZGQtZGV2aWNlLXByb2ZpbGVcIlxuICAgIChjbGljayk9XCJjcmVhdGVEZXZpY2VQcm9maWxlKClcIlxuICA+XG4gICAgPGkgYzh5SWNvbj1cInBsdXMtY2lyY2xlXCI+PC9pPlxuICAgIHt7ICdBZGQgZGV2aWNlIHByb2ZpbGUnIHwgdHJhbnNsYXRlIH19XG4gIDwvYnV0dG9uPlxuPC9jOHktYWN0aW9uLWJhci1pdGVtPlxuXG48Yzh5LWhlbHBcbiAgc3JjPVwiL2RvY3MvZGV2aWNlLW1hbmFnZW1lbnQtYXBwbGljYXRpb24vbWFuYWdpbmctZGV2aWNlLWRhdGEvI21hbmFnaW5nLWRldmljZS1wcm9maWxlc1wiXG4+PC9jOHktaGVscD5cblxuPGRpdiBjbGFzcz1cImNvbnRlbnQtZnVsbHBhZ2UgYm9yZGVyLXRvcCBib3JkZXItYm90dG9tXCI+XG4gIDxjOHktZGF0YS1ncmlkXG4gICAgW3RpdGxlXT1cIidEZXZpY2UgcHJvZmlsZXMnIHwgdHJhbnNsYXRlXCJcbiAgICBbcmVmcmVzaF09XCJyZWZyZXNoJFwiXG4gICAgW3BhZ2luYXRpb25dPVwicGFnaW5hdGlvblwiXG4gICAgW2NvbHVtbnNdPVwiY29sdW1uc1wiXG4gICAgW2FjdGlvbkNvbnRyb2xzXT1cImFjdGlvbkNvbnRyb2xzXCJcbiAgICBbaW5maW5pdGVTY3JvbGxdPVwiJ2F1dG8nXCJcbiAgICBbc2VydmVyU2lkZURhdGFDYWxsYmFja109XCJzZXJ2ZXJTaWRlRGF0YUNhbGxiYWNrXCJcbiAgPlxuICAgIDxjOHktdWktZW1wdHktc3RhdGVcbiAgICAgIFtpY29uXT1cInN0YXRzPy5zaXplID4gMCA/ICdzZWFyY2gnIDogJ2M4eS10b29scydcIlxuICAgICAgW3RpdGxlXT1cInN0YXRzPy5zaXplID4gMCA/IChub1Jlc3VsdHNNZXNzYWdlIHwgdHJhbnNsYXRlKSA6IChub0RhdGFNZXNzYWdlIHwgdHJhbnNsYXRlKVwiXG4gICAgICBbc3VidGl0bGVdPVwic3RhdHM/LnNpemUgPiAwID8gKG5vUmVzdWx0c1N1YnRpdGxlIHwgdHJhbnNsYXRlKSA6IChub0RhdGFTdWJ0aXRsZSB8IHRyYW5zbGF0ZSlcIlxuICAgICAgKmVtcHR5U3RhdGVDb250ZXh0PVwibGV0IHN0YXRzXCJcbiAgICAgIFtob3Jpem9udGFsXT1cInN0YXRzPy5zaXplID4gMFwiXG4gICAgPlxuICAgICAgPHAgKm5nSWY9XCJzdGF0cz8uc2l6ZSA9PT0gMFwiPlxuICAgICAgICA8YnV0dG9uXG4gICAgICAgICAgY2xhc3M9XCJidG4gYnRuLXByaW1hcnlcIlxuICAgICAgICAgIHRpdGxlPVwie3sgJ0FkZCBkZXZpY2UgcHJvZmlsZScgfCB0cmFuc2xhdGUgfX1cIlxuICAgICAgICAgIHR5cGU9XCJidXR0b25cIlxuICAgICAgICAgIChjbGljayk9XCJjcmVhdGVEZXZpY2VQcm9maWxlKClcIlxuICAgICAgICA+XG4gICAgICAgICAge3sgJ0FkZCBkZXZpY2UgcHJvZmlsZScgfCB0cmFuc2xhdGUgfX1cbiAgICAgICAgPC9idXR0b24+XG4gICAgICA8L3A+XG4gICAgPC9jOHktdWktZW1wdHktc3RhdGU+XG4gICAgPG5nLWNvbnRhaW5lciAqbmdGb3I9XCJsZXQgY29sdW1uIG9mIGNvbHVtbnM7IHRyYWNrQnk6IHRyYWNrQnlOYW1lXCI+XG4gICAgICA8Yzh5LWNvbHVtbiBbbmFtZV09XCJjb2x1bW4ubmFtZVwiPjwvYzh5LWNvbHVtbj5cbiAgICA8L25nLWNvbnRhaW5lcj5cbiAgPC9jOHktZGF0YS1ncmlkPlxuPC9kaXY+XG4iXX0=