UNPKG

@c8y/ngx-components

Version:

Angular modules for Cumulocity IoT applications

212 lines 40.3 kB
import { Component, EventEmitter, ViewChild } from '@angular/core'; import { InventoryBinaryService } from '@c8y/client'; import { AlertService, BuiltInActionType, DataGridService, FilterInputComponent, gettext, ModalService, Status } from '@c8y/ngx-components'; import { DescriptionGridColumn, DeviceTypeGridColumn, FileGridColumn, RepositoryItemNameGridColumn, RepositoryService, RepositoryType, TypeGridColumn } from '@c8y/ngx-components/repository/shared'; import { TranslateService } from '@ngx-translate/core'; import { saveAs } from 'file-saver'; import { BsModalService } from 'ngx-bootstrap/modal'; import { ConfigurationDetailComponent } from './configuration-detail.component'; import * as i0 from "@angular/core"; import * as i1 from "@c8y/ngx-components"; import * as i2 from "@c8y/ngx-components/repository/shared"; import * as i3 from "ngx-bootstrap/modal"; import * as i4 from "@ngx-translate/core"; import * as i5 from "@c8y/client"; import * as i6 from "@angular/common"; export class ConfigurationListComponent { constructor(alert, gridService, repositoryService, bsModalService, modalService, translateService, inventoryBinaryService) { this.alert = alert; this.gridService = gridService; this.repositoryService = repositoryService; this.bsModalService = bsModalService; this.modalService = modalService; this.translateService = translateService; this.inventoryBinaryService = inventoryBinaryService; this.refresh$ = new EventEmitter(); this.pagination = { pageSize: 50, currentPage: 1 }; this.noResultsMessage = gettext('No results to display.'); this.noDataMessage = gettext('There are no configuration snapshots defined.'); this.noResultsSubtitle = gettext('Refine your search terms or check your spelling.'); this.noDataSubtitle = gettext('Add a configuration snapshot first.'); this.actionControls = []; this.columns = [ new RepositoryItemNameGridColumn({ filterLabel: gettext('Filter configurations by name'), placeholder: gettext('SSH'), callback: this.edit.bind(this) }), new DescriptionGridColumn({ filterLabel: gettext('Filter configurations by description'), placeholder: gettext('SSH configuration') }), new FileGridColumn(), new DeviceTypeGridColumn({ path: 'deviceType', filterLabel: gettext('Filter configurations by device type') }), new TypeGridColumn({ header: gettext('Configuration type'), filterLabel: gettext('Filter by configuration type'), example: 'ssh', path: 'configurationType', repositoryType: RepositoryType.CONFIGURATION }) ]; this.sizeRequestDone = false; this.DELETED_SUCCESS_MSG = gettext('Configuration deleted.'); this.serverSideDataCallback = this.onDataSourceModifier.bind(this); } ngOnInit() { this.actionControls.push({ type: BuiltInActionType.Edit, callback: this.edit.bind(this) }); this.actionControls.push({ type: BuiltInActionType.Delete, callback: this.delete.bind(this) }); this.actionControls.push({ type: 'download', icon: 'download', text: gettext('Download'), showIf: row => this.isBinaryFile(row), callback: this.download.bind(this) }); } async onDataSourceModifier(dataSourceModifier) { const dataRequest = this.repositoryService.listRepositoryEntries(RepositoryType.CONFIGURATION, { query: this.gridService.getQueryObj(dataSourceModifier.columns), skipDefaultOrder: true, params: { pageSize: dataSourceModifier.pagination.pageSize, currentPage: dataSourceModifier.pagination.currentPage, withTotalPages: true } }); const filtererdSizeRequest = this.repositoryService .listRepositoryEntries(RepositoryType.CONFIGURATION, { query: this.gridService.getQueryObj(dataSourceModifier.columns), skipDefaultOrder: true, params: { pageSize: 1 } }) .then(response => response?.paging?.totalPages); this.size$ = this.repositoryService .listRepositoryEntries(RepositoryType.CONFIGURATION, { skipDefaultOrder: true, params: { pageSize: 1 } }) .then(response => { this.sizeRequestDone = true; return response?.paging?.totalPages; }); const [dataResponse, size, filteredSize] = await Promise.all([ dataRequest, this.size$, filtererdSizeRequest ]); const { res, data, paging } = dataResponse; const serverSideDataResult = { res, data, paging, filteredSize, size }; return serverSideDataResult; } async add() { try { await this.bsModalService.show(ConfigurationDetailComponent, { class: 'modal-sm', ariaDescribedby: 'configurationModalDescription', ariaLabelledBy: 'configurationModalTitle', ignoreBackdropClick: true, keyboard: false }).content.result; this.refresh$.next(); } catch (ex) { // intended empty } } async edit(configuration) { const fileBinary = await this.repositoryService.getBinaryFile(configuration.url, { allowExternal: false }); try { const modal = this.bsModalService.show(ConfigurationDetailComponent, { class: 'modal-sm', ariaDescribedby: 'configurationModalDescription', ariaLabelledBy: 'configurationModalTitle', ignoreBackdropClick: true, keyboard: false, initialState: { version: configuration.name, deviceType: configuration.deviceType, description: configuration.description, binary: { file: fileBinary, url: configuration.url } } }).content; modal.mo = configuration; await modal.result; this.refresh$.next(); } catch (ex) { // intended empty } } isBinaryFile(configuration) { return configuration.url ? !!this.inventoryBinaryService.getIdFromUrl(configuration.url) : false; } async download(configuration) { const fileBinary = await this.repositoryService.getBinaryFile(configuration.url, { allowExternal: false }); saveAs(fileBinary); } async delete(configuration) { try { const title = gettext('Delete configuration snapshot'); const confirmationText = gettext('You are about to delete the configuration snapshot {{ name }}.'); const hint = gettext('This operation is irreversible.'); const proceed = gettext('Do you want to proceed?'); const body = [ this.translateService.instant(confirmationText, { name: configuration.name }), this.translateService.instant(hint), this.translateService.instant(proceed) ].join(' '); const labels = { ok: gettext('Delete') }; await this.modalService.confirm(title, body, Status.DANGER, labels); await this.repositoryService.delete(configuration); this.alert.success(this.DELETED_SUCCESS_MSG); this.refresh$.next(); } catch (ex) { if (ex) { this.alert.addServerFailure(ex); } } } trackByName(_index, column) { return column.name; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ConfigurationListComponent, deps: [{ token: i1.AlertService }, { token: i1.DataGridService }, { token: i2.RepositoryService }, { token: i3.BsModalService }, { token: i1.ModalService }, { token: i4.TranslateService }, { token: i5.InventoryBinaryService }], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: ConfigurationListComponent, selector: "c8y-configuration-list", viewQueries: [{ propertyName: "filter", first: true, predicate: FilterInputComponent, descendants: true }], ngImport: i0, template: "<c8y-title>\n <span\n class=\"m-r-4\"\n translate\n >\n Configuration repository\n </span>\n <small>\n {{ size$ | async }}\n <span translate>snapshots</span>\n </small>\n</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=\"gears\"\n label=\"{{ 'Configuration repository' | 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 configuration snapshot' | translate }}\"\n type=\"button\"\n (click)=\"add()\"\n >\n <i c8yIcon=\"plus-circle\"></i>\n {{ 'Add configuration snapshot' | translate }}\n </button>\n</c8y-action-bar-item>\n\n<c8y-help\n src=\"/docs/device-management-application/managing-device-data/#managing-configurations\"\n></c8y-help>\n\n<div class=\"content-fullpage border-top border-bottom\">\n <c8y-data-grid\n [title]=\"'Configurations' | 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' : 'gears'\"\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 <ng-container *ngIf=\"stats?.size === 0\">\n <p>\n <button\n class=\"btn btn-primary\"\n title=\"{{ 'Add configuration snapshot' | translate }}\"\n type=\"button\"\n (click)=\"add()\"\n >\n {{ 'Add configuration snapshot' | translate }}\n </button>\n </p>\n <p c8y-guide-docs>\n <small\n translate\n ngNonBindable\n >\n Find out more in the\n <a\n c8y-guide-href=\"/docs/device-management-application/managing-device-data/#managing-configurations\"\n >\n user documentation\n </a>\n .\n </small>\n </p>\n </ng-container>\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: "directive", type: i6.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i6.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i1.ActionBarItemComponent, selector: "c8y-action-bar-item", inputs: ["placement", "priority", "itemClass", "injector", "groupId", "inGroupPriority"] }, { kind: "component", type: i1.BreadcrumbComponent, selector: "c8y-breadcrumb" }, { kind: "component", type: i1.BreadcrumbItemComponent, selector: "c8y-breadcrumb-item", inputs: ["icon", "translate", "label", "path", "injector"] }, { kind: "component", type: i1.EmptyStateComponent, selector: "c8y-ui-empty-state", inputs: ["icon", "title", "subtitle", "horizontal"] }, { kind: "directive", type: i1.EmptyStateContextDirective, selector: "[emptyStateContext]" }, { kind: "directive", type: i1.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: i1.C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: i1.ColumnDirective, selector: "c8y-column", inputs: ["name"] }, { kind: "component", type: i1.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: i1.TitleComponent, selector: "c8y-title", inputs: ["pageTitleUpdate"] }, { kind: "directive", type: i1.GuideHrefDirective, selector: "[c8y-guide-href]", inputs: ["c8y-guide-href"] }, { kind: "component", type: i1.GuideDocsComponent, selector: "[c8y-guide-docs]" }, { kind: "component", type: i1.HelpComponent, selector: "c8y-help", inputs: ["src", "isCollapsed", "priority", "icon"] }, { kind: "pipe", type: i6.AsyncPipe, name: "async" }, { kind: "pipe", type: i1.C8yTranslatePipe, name: "translate" }] }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ConfigurationListComponent, decorators: [{ type: Component, args: [{ selector: 'c8y-configuration-list', template: "<c8y-title>\n <span\n class=\"m-r-4\"\n translate\n >\n Configuration repository\n </span>\n <small>\n {{ size$ | async }}\n <span translate>snapshots</span>\n </small>\n</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=\"gears\"\n label=\"{{ 'Configuration repository' | 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 configuration snapshot' | translate }}\"\n type=\"button\"\n (click)=\"add()\"\n >\n <i c8yIcon=\"plus-circle\"></i>\n {{ 'Add configuration snapshot' | translate }}\n </button>\n</c8y-action-bar-item>\n\n<c8y-help\n src=\"/docs/device-management-application/managing-device-data/#managing-configurations\"\n></c8y-help>\n\n<div class=\"content-fullpage border-top border-bottom\">\n <c8y-data-grid\n [title]=\"'Configurations' | 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' : 'gears'\"\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 <ng-container *ngIf=\"stats?.size === 0\">\n <p>\n <button\n class=\"btn btn-primary\"\n title=\"{{ 'Add configuration snapshot' | translate }}\"\n type=\"button\"\n (click)=\"add()\"\n >\n {{ 'Add configuration snapshot' | translate }}\n </button>\n </p>\n <p c8y-guide-docs>\n <small\n translate\n ngNonBindable\n >\n Find out more in the\n <a\n c8y-guide-href=\"/docs/device-management-application/managing-device-data/#managing-configurations\"\n >\n user documentation\n </a>\n .\n </small>\n </p>\n </ng-container>\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.AlertService }, { type: i1.DataGridService }, { type: i2.RepositoryService }, { type: i3.BsModalService }, { type: i1.ModalService }, { type: i4.TranslateService }, { type: i5.InventoryBinaryService }], propDecorators: { filter: [{ type: ViewChild, args: [FilterInputComponent, { static: false }] }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29uZmlndXJhdGlvbi1saXN0LmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3JlcG9zaXRvcnkvY29uZmlndXJhdGlvbi9saXN0L2NvbmZpZ3VyYXRpb24tbGlzdC5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi8uLi9yZXBvc2l0b3J5L2NvbmZpZ3VyYXRpb24vbGlzdC9jb25maWd1cmF0aW9uLWxpc3QuY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFNBQVMsRUFBRSxZQUFZLEVBQVUsU0FBUyxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQzNFLE9BQU8sRUFBa0Isc0JBQXNCLEVBQWUsTUFBTSxhQUFhLENBQUM7QUFDbEYsT0FBTyxFQUVMLFlBQVksRUFDWixpQkFBaUIsRUFFakIsZUFBZSxFQUVmLG9CQUFvQixFQUNwQixPQUFPLEVBQ1AsWUFBWSxFQUdaLE1BQU0sRUFDUCxNQUFNLHFCQUFxQixDQUFDO0FBQzdCLE9BQU8sRUFDTCxxQkFBcUIsRUFDckIsb0JBQW9CLEVBQ3BCLGNBQWMsRUFDZCw0QkFBNEIsRUFDNUIsaUJBQWlCLEVBQ2pCLGNBQWMsRUFDZCxjQUFjLEVBQ2YsTUFBTSx1Q0FBdUMsQ0FBQztBQUMvQyxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQUN2RCxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sWUFBWSxDQUFDO0FBQ3BDLE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQUNyRCxPQUFPLEVBQUUsNEJBQTRCLEVBQUUsTUFBTSxrQ0FBa0MsQ0FBQzs7Ozs7Ozs7QUFNaEYsTUFBTSxPQUFPLDBCQUEwQjtJQXlDckMsWUFDVSxLQUFtQixFQUNuQixXQUE0QixFQUM1QixpQkFBb0MsRUFDcEMsY0FBOEIsRUFDOUIsWUFBMEIsRUFDMUIsZ0JBQWtDLEVBQ2xDLHNCQUE4QztRQU45QyxVQUFL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Q0FBQztZQUNsQyxDQUFDO1FBQ0gsQ0FBQztJQUNILENBQUM7SUFFRCxXQUFXLENBQUMsTUFBTSxFQUFFLE1BQWM7UUFDaEMsT0FBTyxNQUFNLENBQUMsSUFBSSxDQUFDO0lBQ3JCLENBQUM7K0dBbE5VLDBCQUEwQjttR0FBMUIsMEJBQTBCLHNHQUMxQixvQkFBb0IsZ0RDbkNqQyxvbEZBeUZBOzs0RkR2RGEsMEJBQTBCO2tCQUp0QyxTQUFTOytCQUNFLHdCQUF3QjsyUUFJa0IsTUFBTTtzQkFBekQsU0FBUzt1QkFBQyxvQkFBb0IsRUFBRSxFQUFFLE1BQU0sRUFBRSxLQUFLLEVBQUUiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDb21wb25lbnQsIEV2ZW50RW1pdHRlciwgT25Jbml0LCBWaWV3Q2hpbGQgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IElNYW5hZ2VkT2JqZWN0LCBJbnZlbnRvcnlCaW5hcnlTZXJ2aWNlLCBJUmVzdWx0TGlzdCB9IGZyb20gJ0BjOHkvY2xpZW50JztcbmltcG9ydCB7XG4gIEFjdGlvbkNvbnRyb2wsXG4gIEFsZXJ0U2VydmljZSxcbiAgQnVpbHRJbkFjdGlvblR5cGUsXG4gIENvbHVtbixcbiAgRGF0YUdyaWRTZXJ2aWNlLFxuICBEYXRhU291cmNlTW9kaWZpZXIsXG4gIEZpbHRlcklucHV0Q29tcG9uZW50LFxuICBnZXR0ZXh0LFxuICBNb2RhbFNlcnZpY2UsXG4gIFNlcnZlclNpZGVEYXRhQ2FsbGJhY2ssXG4gIFNlcnZlclNpZGVEYXRhUmVzdWx0LFxuICBTdGF0dXNcbn0gZnJvbSAnQGM4eS9uZ3gtY29tcG9uZW50cyc7XG5pbXBvcnQge1xuICBEZXNjcmlwdGlvbkdyaWRDb2x1bW4sXG4gIERldmljZVR5cGVHcmlkQ29sdW1uLFxuICBGaWxlR3JpZENvbHVtbixcbiAgUmVwb3NpdG9yeUl0ZW1OYW1lR3JpZENvbHVtbixcbiAgUmVwb3NpdG9yeVNlcnZpY2UsXG4gIFJlcG9zaXRvcnlUeXBlLFxuICBUeXBlR3JpZENvbHVtblxufSBmcm9tICdAYzh5L25neC1jb21wb25lbnRzL3JlcG9zaXRvcnkvc2hhcmVkJztcbmltcG9ydCB7IFRyYW5zbGF0ZVNlcnZpY2UgfSBmcm9tICdAbmd4LXRyYW5zbGF0ZS9jb3JlJztcbmltcG9ydCB7IHNhdmVBcyB9IGZyb20gJ2ZpbGUtc2F2ZXInO1xuaW1wb3J0IHsgQnNNb2RhbFNlcnZpY2UgfSBmcm9tICduZ3gtYm9vdHN0cmFwL21vZGFsJztcbmltcG9ydCB7IENvbmZpZ3VyYXRpb25EZXRhaWxDb21wb25lbnQgfSBmcm9tICcuL2NvbmZpZ3VyYXRpb24tZGV0YWlsLmNvbXBvbmVudCc7XG5cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ2M4eS1jb25maWd1cmF0aW9uLWxpc3QnLFxuICB0ZW1wbGF0ZVVybDogJy4vY29uZmlndXJhdGlvbi1saXN0LmNvbXBvbmVudC5odG1sJ1xufSlcbmV4cG9ydCBjbGFzcyBDb25maWd1cmF0aW9uTGlzdENvbXBvbmVudCBpbXBsZW1lbnRzIE9uSW5pdCB7XG4gIEBWaWV3Q2hpbGQoRmlsdGVySW5wdXRDb21wb25lbnQsIHsgc3RhdGljOiBmYWxzZSB9KSBmaWx0ZXI6IEZpbHRlcklucHV0Q29tcG9uZW50O1xuICByZWZyZXNoJDogRXZlbnRFbWl0dGVyPHZvaWQ+ID0gbmV3IEV2ZW50RW1pdHRlcigpO1xuICBwYWdpbmF0aW9uID0ge1xuICAgIHBhZ2VTaXplOiA1MCxcbiAgICBjdXJyZW50UGFnZTogMVxuICB9O1xuICBub1Jlc3VsdHNNZXNzYWdlID0gZ2V0dGV4dCgnTm8gcmVzdWx0cyB0byBkaXNwbGF5LicpO1xuICBub0RhdGFNZXNzYWdlID0gZ2V0dGV4dCgnVGhlcmUgYXJlIG5vIGNvbmZpZ3VyYXRpb24gc25hcHNob3RzIGRlZmluZWQuJyk7XG4gIG5vUmVzdWx0c1N1YnRpdGxlID0gZ2V0dGV4dCgnUmVmaW5lIHlvdXIgc2VhcmNoIHRlcm1zIG9yIGNoZWNrIHlvdXIgc3BlbGxpbmcuJyk7XG4gIG5vRGF0YVN1YnRpdGxlID0gZ2V0dGV4dCgnQWRkIGEgY29uZmlndXJhdGlvbiBzbmFwc2hvdCBmaXJzdC4nKTtcbiAgYWN0aW9uQ29udHJvbHM6IEFjdGlvbkNvbnRyb2xbXSA9IFtdO1xuICBjb2x1bW5zOiBDb2x1bW5bXSA9IFtcbiAgICBuZXcgUmVwb3NpdG9yeUl0ZW1OYW1lR3JpZENvbHVtbih7XG4gICAgICBmaWx0ZXJMYWJlbDogZ2V0dGV4dCgnRmlsdGVyIGNvbmZpZ3VyYXRpb25zIGJ5IG5hbWUnKSxcbiAgICAgIHBsYWNlaG9sZGVyOiBnZXR0ZXh0KCdTU0gnKSxcbiAgICAgIGNhbGxiYWNrOiB0aGlzLmVkaXQuYmluZCh0aGlzKVxuICAgIH0pLFxuICAgIG5ldyBEZXNjcmlwdGlvbkdyaWRDb2x1bW4oe1xuICAgICAgZmlsdGVyTGFiZWw6IGdldHRleHQoJ0ZpbHRlciBjb25maWd1cmF0aW9ucyBieSBkZXNjcmlwdGlvbicpLFxuICAgICAgcGxhY2Vob2xkZXI6IGdldHRleHQoJ1NTSCBjb25maWd1cmF0aW9uJylcbiAgICB9KSxcbiAgICBuZXcgRmlsZUdyaWRDb2x1bW4oKSxcbiAgICBuZXcgRGV2aWNlVHlwZUdyaWRDb2x1bW4oe1xuICAgICAgcGF0aDogJ2RldmljZVR5cGUnLFxuICAgICAgZmlsdGVyTGFiZWw6IGdldHRleHQoJ0ZpbHRlciBjb25maWd1cmF0aW9ucyBieSBkZXZpY2UgdHlwZScpXG4gICAgfSksXG4gICAgbmV3IFR5cGVHcmlkQ29sdW1uKHtcbiAgICAgIGhlYWRlcjogZ2V0dGV4dCgnQ29uZmlndXJhdGlvbiB0eXBlJyksXG4gICAgICBmaWx0ZXJMYWJlbDogZ2V0dGV4dCgnRmlsdGVyIGJ5IGNvbmZpZ3VyYXRpb24gdHlwZScpLFxuICAgICAgZXhhbXBsZTogJ3NzaCcsXG4gICAgICBwYXRoOiAnY29uZmlndXJhdGlvblR5cGUnLFxuICAgICAgcmVwb3NpdG9yeVR5cGU6IFJlcG9zaXRvcnlUeXBlLkNPTkZJR1VSQVRJT05cbiAgICB9KVxuICBdO1xuICBzaXplJDogUHJvbWlzZTxudW1iZXI+O1xuICBzaXplUmVxdWVzdERvbmUgPSBmYWxzZTtcbiAgc2VydmVyU2lkZURhdGFDYWxsYmFjazogU2VydmVyU2lkZURhdGFDYWxsYmFjaztcblxuICBwcml2YXRlIHJlYWRvbmx5IERFTEVURURfU1VDQ0VTU19NU0cgPSBnZXR0ZXh0KCdDb25maWd1cmF0aW9uIGRlbGV0ZWQuJyk7XG5cbiAgY29uc3RydWN0b3IoXG4gICAgcHJpdmF0ZSBhbGVydDogQWxlcnRTZXJ2aWNlLFxuICAgIHByaXZhdGUgZ3JpZFNlcnZpY2U6IERhdGFHcmlkU2VydmljZSxcbiAgICBwcml2YXRlIHJlcG9zaXRvcnlTZXJ2aWNlOiBSZXBvc2l0b3J5U2VydmljZSxcbiAgICBwcml2YXRlIGJzTW9kYWxTZXJ2aWNlOiBCc01vZGFsU2VydmljZSxcbiAgICBwcml2YXRlIG1vZGFsU2VydmljZTogTW9kYWxTZXJ2aWNlLFxuICAgIHByaXZhdGUgdHJhbnNsYXRlU2VydmljZTogVHJhbnNsYXRlU2VydmljZSxcbiAgICBwcml2YXRlIGludmVudG9yeUJpbmFyeVNlcnZpY2U6IEludmVudG9yeUJpbmFyeVNlcnZpY2VcbiAgKSB7XG4gICAgdGhpcy5zZXJ2ZXJTaWRlRGF0YUNhbGxiYWNrID0gdGhpcy5vbkRhdGFTb3VyY2VNb2RpZmllci5iaW5kKHRoaXMpO1xuICB9XG5cbiAgbmdPbkluaXQoKSB7XG4gICAgdGhpcy5hY3Rpb25Db250cm9scy5wdXNoKHtcbiAgICAgIHR5cGU6IEJ1aWx0SW5BY3Rpb25UeXBlLkVkaXQsXG4gICAgICBjYWxsYmFjazogdGhpcy5lZGl0LmJpbmQodGhpcylcbiAgICB9KTtcbiAgICB0aGlzLmFjdGlvbkNvbnRyb2xzLnB1c2goe1xuICAgICAgdHlwZTogQnVpbHRJbkFjdGlvblR5cGUuRGVsZXRlLFxuICAgICAgY2FsbGJhY2s6IHRoaXMuZGVsZXRlLmJpbmQodGhpcylcbiAgICB9KTtcbiAgICB0aGlzLmFjdGlvbkNvbnRyb2xzLnB1c2goe1xuICAgICAgdHlwZTogJ2Rvd25sb2FkJyxcbiAgICAgIGljb246ICdkb3dubG9hZCcsXG4gICAgICB0ZXh0OiBnZXR0ZXh0KCdEb3dubG9hZCcpLFxuICAgICAgc2hvd0lmOiByb3cgPT4gdGhpcy5pc0JpbmFyeUZpbGUocm93IGFzIHVua25vd24gYXMgSU1hbmFnZWRPYmplY3QpLFxuICAgICAgY2FsbGJhY2s6IHRoaXMuZG93bmxvYWQuYmluZCh0aGlzKVxuICAgIH0pO1xuICB9XG5cbiAgYXN5bmMgb25EYXRhU291cmNlTW9kaWZpZXIoXG4gICAgZGF0YVNvdXJjZU1vZGlmaWVyOiBEYXRhU291cmNlTW9kaWZpZXJcbiAgKTogUHJvbWlzZTxTZXJ2ZXJTaWRlRGF0YVJlc3VsdD4ge1xuICAgIGNvbnN0IGRhdGFSZXF1ZXN0OiBQcm9taXNlPElSZXN1bHRMaXN0PElNYW5hZ2VkT2JqZWN0Pj4gPVxuICAgICAgdGhpcy5yZXBvc2l0b3J5U2VydmljZS5saXN0UmVwb3NpdG9yeUVudHJpZXMoUmVwb3NpdG9yeVR5cGUuQ09ORklHVVJBVElPTiwge1xuICAgICAgICBxdWVyeTogdGhpcy5ncmlkU2VydmljZS5nZXRRdWVyeU9iaihkYXRhU291cmNlTW9kaWZpZXIuY29sdW1ucyksXG4gICAgICAgIHNraXBEZWZhdWx0T3JkZXI6IHRydWUsXG4gICAgICAgIHBhcmFtczoge1xuICAgICAgICAgIHBhZ2VTaXplOiBkYXRhU291cmNlTW9kaWZpZXIucGFnaW5hdGlvbi5wYWdlU2l6ZSxcbiAgICAgICAgICBjdXJyZW50UGFnZTogZGF0YVNvdXJjZU1vZGlmaWVyLnBhZ2luYXRpb24uY3VycmVudFBhZ2UsXG4gICAgICAgICAgd2l0aFRvdGFsUGFnZXM6IHRydWVcbiAgICAgICAgfVxuICAgICAgfSk7XG5cbiAgICBjb25zdCBmaWx0ZXJlcmRTaXplUmVxdWVzdDogUHJvbWlzZTxudW1iZXI+ID0gdGhpcy5yZXBvc2l0b3J5U2VydmljZVxuICAgICAgLmxpc3RSZXBvc2l0b3J5RW50cmllcyhSZXBvc2l0b3J5VHlwZS5DT05GSUdVUkFUSU9OLCB7XG4gICAgICAgIHF1ZXJ5OiB0aGlzLmdyaWRTZXJ2aWNlLmdldFF1ZXJ5T2JqKGRhdGFTb3VyY2VNb2RpZmllci5jb2x1bW5zKSxcbiAgICAgICAgc2tpcERlZmF1bHRPcmRlcjogdHJ1ZSxcbiAgICAgICAgcGFyYW1zOiB7IHBhZ2VTaXplOiAxIH1cbiAgICAgIH0pXG4gICAgICAudGhlbihyZXNwb25zZSA9PiByZXNwb25zZT8ucGFnaW5nPy50b3RhbFBhZ2VzKTtcblxuICAgIHRoaXMuc2l6ZSQgPSB0aGlzLnJlcG9zaXRvcnlTZXJ2aWNlXG4gICAgICAubGlzdFJlcG9zaXRvcnlFbnRyaWVzKFJlcG9zaXRvcnlUeXBlLkNPTkZJR1VSQVRJT04sIHtcbiAgICAgICAgc2tpcERlZmF1bHRPcmRlcjogdHJ1ZSxcbiAgICAgICAgcGFyYW1zOiB7IHBhZ2VTaXplOiAxIH1cbiAgICAgIH0pXG4gICAgICAudGhlbihyZXNwb25zZSA9PiB7XG4gICAgICAgIHRoaXMuc2l6ZVJlcXVlc3REb25lID0gdHJ1ZTtcbiAgICAgICAgcmV0dXJuIHJlc3BvbnNlPy5wYWdpbmc/LnRvdGFsUGFnZXM7XG4gICAgICB9KTtcblxuICAgIGNvbnN0IFtkYXRhUmVzcG9uc2UsIHNpemUsIGZpbHRlcmVkU2l6ZV0gPSBhd2FpdCBQcm9taXNlLmFsbChbXG4gICAgICBkYXRhUmVxdWVzdCxcbiAgICAgIHRoaXMuc2l6ZSQsXG4gICAgICBmaWx0ZXJlcmRTaXplUmVxdWVzdFxuICAgIF0pO1xuXG4gICAgY29uc3QgeyByZXMsIGRhdGEsIHBhZ2luZyB9ID0gZGF0YVJlc3BvbnNlO1xuXG4gICAgY29uc3Qgc2VydmVyU2lkZURhdGFSZXN1bHQ6IFNlcnZlclNpZGVEYXRhUmVzdWx0ID0ge1xuICAgICAgcmVzLFxuICAgICAgZGF0YSxcbiAgICAgIHBhZ2luZyxcbiAgICAgIGZpbHRlcmVkU2l6ZSxcbiAgICAgIHNpemVcbiAgICB9O1xuXG4gICAgcmV0dXJuIHNlcnZlclNpZGVEYXRhUmVzdWx0O1xuICB9XG5cbiAgYXN5bmMgYWRkKCkge1xuICAgIHRyeSB7XG4gICAgICBhd2FpdCAoXG4gICAgICAgIHRoaXMuYnNNb2RhbFNlcnZpY2Uuc2hvdyhDb25maWd1cmF0aW9uRGV0YWlsQ29tcG9uZW50LCB7XG4gICAgICAgICAgY2xhc3M6ICdtb2RhbC1zbScsXG4gICAgICAgICAgYXJpYURlc2NyaWJlZGJ5OiAnY29uZmlndXJhdGlvbk1vZGFsRGVzY3JpcHRpb24nLFxuICAgICAgICAgIGFyaWFMYWJlbGxlZEJ5OiAnY29uZmlndXJhdGlvbk1vZGFsVGl0bGUnLFxuICAgICAgICAgIGlnbm9yZUJhY2tkcm9wQ2xpY2s6IHRydWUsXG4gICAgICAgICAga2V5Ym9hcmQ6IGZhbHNlXG4gICAgICAgIH0pLmNvbnRlbnQgYXMgQ29uZmlndXJhdGlvbkRldGFpbENvbXBvbmVudFxuICAgICAgKS5yZXN1bHQ7XG4gICAgICB0aGlzLnJlZnJlc2gkLm5leHQoKTtcbiAgICB9IGNhdGNoIChleCkge1xuICAgICAgLy8gaW50ZW5kZWQgZW1wdHlcbiAgICB9XG4gIH1cblxuICBhc3luYyBlZGl0KGNvbmZpZ3VyYXRpb246IElNYW5hZ2VkT2JqZWN0KSB7XG4gICAgY29uc3QgZmlsZUJpbmFyeTogRmlsZSA9IGF3YWl0IHRoaXMucmVwb3NpdG9yeVNlcnZpY2UuZ2V0QmluYXJ5RmlsZShjb25maWd1cmF0aW9uLnVybCwge1xuICAgICAgYWxsb3dFeHRlcm5hbDogZmFsc2VcbiAgICB9KTtcbiAgICB0cnkge1xuICAgICAgY29uc3QgbW9kYWwgPSB0aGlzLmJzTW9kYWxTZXJ2aWNlLnNob3coQ29uZmlndXJhdGlvbkRldGFpbENvbXBvbmVudCwge1xuICAgICAgICBjbGFzczogJ21vZGFsLXNtJyxcbiAgICAgICAgYXJpYURlc2NyaWJlZGJ5OiAnY29uZmlndXJhdGlvbk1vZGFsRGVzY3JpcHRpb24nLFxuICAgICAgICBhcmlhTGFiZWxsZWRCeTogJ2NvbmZpZ3VyYXRpb25Nb2RhbFRpdGxlJyxcbiAgICAgICAgaWdub3JlQmFja2Ryb3BDbGljazogdHJ1ZSxcbiAgICAgICAga2V5Ym9hcmQ6IGZhbHNlLFxuXG4gICAgICAgIGluaXRpYWxTdGF0ZToge1xuICAgICAgICAgIHZlcnNpb246IGNvbmZpZ3VyYXRpb24ubmFtZSxcbiAgICAgICAgICBkZXZpY2VUeXBlOiBjb25maWd1cmF0aW9uLmRldmljZVR5cGUsXG4gICAgICAgICAgZGVzY3JpcHRpb246IGNvbmZpZ3VyYXRpb24uZGVzY3JpcHRpb24sXG4gICAgICAgICAgYmluYXJ5OiB7IGZpbGU6IGZpbGVCaW5hcnksIHVybDogY29uZmlndXJhdGlvbi51cmwgfVxuICAgICAgICB9XG4gICAgICB9KS5jb250ZW50IGFzIENvbmZpZ3VyYXRpb25EZXRhaWxDb21wb25lbnQ7XG4gICAgICBtb2RhbC5tbyA9IGNvbmZpZ3VyYXRpb247XG4gICAgICBhd2FpdCBtb2RhbC5yZXN1bHQ7XG4gICAgICB0aGlzLnJlZnJlc2gkLm5leHQoKTtcbiAgICB9IGNhdGNoIChleCkge1xuICAgICAgLy8gaW50ZW5kZWQgZW1wdHlcbiAgICB9XG4gIH1cblxuICBpc0JpbmFyeUZpbGUoY29uZmlndXJhdGlvbjogSU1hbmFnZWRPYmplY3QpIHtcbiAgICByZXR1cm4gY29uZmlndXJhdGlvbi51cmxcbiAgICAgID8gISF0aGlzLmludmVudG9yeUJpbmFyeVNlcnZpY2UuZ2V0SWRGcm9tVXJsKGNvbmZpZ3VyYXRpb24udXJsKVxuICAgICAgOiBmYWxzZTtcbiAgfVxuXG4gIGFzeW5jIGRvd25sb2FkKGNvbmZpZ3VyYXRpb246IElNYW5hZ2VkT2JqZWN0KSB7XG4gICAgY29uc3QgZmlsZUJpbmFyeTogRmlsZSA9IGF3YWl0IHRoaXMucmVwb3NpdG9yeVNlcnZpY2UuZ2V0QmluYXJ5RmlsZShjb25maWd1cmF0aW9uLnVybCwge1xuICAgICAgYWxsb3dFeHRlcm5hbDogZmFsc2VcbiAgICB9KTtcbiAgICBzYXZlQXMoZmlsZUJpbmFyeSk7XG4gIH1cblxuICBhc3luYyBkZWxldGUoY29uZmlndXJhdGlvbjogSU1hbmFnZWRPYmplY3QpIHtcbiAgICB0cnkge1xuICAgICAgY29uc3QgdGl0bGUgPSBnZXR0ZXh0KCdEZWxldGUgY29uZmlndXJhdGlvbiBzbmFwc2hvdCcpO1xuICAgICAgY29uc3QgY29uZmlybWF0aW9uVGV4dCA9IGdldHRleHQoXG4gICAgICAgICdZb3UgYXJlIGFib3V0IHRvIGRlbGV0ZSB0aGUgY29uZmlndXJhdGlvbiBzbmFwc2hvdCB7eyBuYW1lIH19LidcbiAgICAgICk7XG4gICAgICBjb25zdCBoaW50ID0gZ2V0dGV4dCgnVGhpcyBvcGVyYXRpb24gaXMgaXJyZXZlcnNpYmxlLicpO1xuICAgICAgY29uc3QgcHJvY2VlZCA9IGdldHRleHQoJ0RvIHlvdSB3YW50IHRvIHByb2NlZWQ/Jyk7XG4gICAgICBjb25zdCBib2R5ID0gW1xuICAgICAgICB0aGlzLnRyYW5zbGF0ZVNlcnZpY2UuaW5zdGFudChjb25maXJtYXRpb25UZXh0LCB7XG4gICAgICAgICAgbmFtZTogY29uZmlndXJhdGlvbi5uYW1lXG4gICAgICAgIH0pLFxuICAgICAgICB0aGlzLnRyYW5zbGF0ZVNlcnZpY2UuaW5zdGFudChoaW50KSxcbiAgICAgICAgdGhpcy50cmFuc2xhdGVTZXJ2aWNlLmluc3RhbnQocHJvY2VlZClcbiAgICAgIF0uam9pbignICcpO1xuICAgICAgY29uc3QgbGFiZWxzID0ge1xuICAgICAgICBvazogZ2V0dGV4dCgnRGVsZXRlJylcbiAgICAgIH07XG4gICAgICBhd2FpdCB0aGlzLm1vZGFsU2VydmljZS5jb25maXJtKHRpdGxlLCBib2R5LCBTdGF0dXMuREFOR0VSLCBsYWJlbHMpO1xuICAgICAgYXdhaXQgdGhpcy5yZXBvc2l0b3J5U2VydmljZS5kZWxldGUoY29uZmlndXJhdGlvbik7XG4gICAgICB0aGlzLmFsZXJ0LnN1Y2Nlc3ModGhpcy5ERUxFVEVEX1NVQ0NFU1NfTVNHKTtcbiAgICAgIHRoaXMucmVmcmVzaCQubmV4dCgpO1xuICAgIH0gY2F0Y2ggKGV4KSB7XG4gICAgICBpZiAoZXgpIHtcbiAgICAgICAgdGhpcy5hbGVydC5hZGRTZXJ2ZXJGYWlsdXJlKGV4KTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICB0cmFja0J5TmFtZShfaW5kZXgsIGNvbHVtbjogQ29sdW1uKTogc3RyaW5nIHtcbiAgICByZXR1cm4gY29sdW1uLm5hbWU7XG4gIH1cbn1cbiIsIjxjOHktdGl0bGU+XG4gIDxzcGFuXG4gICAgY2xhc3M9XCJtLXItNFwiXG4gICAgdHJhbnNsYXRlXG4gID5cbiAgICBDb25maWd1cmF0aW9uIHJlcG9zaXRvcnlcbiAgPC9zcGFuPlxuICA8c21hbGw+XG4gICAge3sgc2l6ZSQgfCBhc3luYyB9fVxuICAgIDxzcGFuIHRyYW5zbGF0ZT5zbmFwc2hvdHM8L3NwYW4+XG4gIDwvc21hbGw+XG48L2M4eS10aXRsZT5cblxuPGM4eS1icmVhZGNydW1iPlxuICA8Yzh5LWJyZWFkY3J1bWItaXRlbVxuICAgIGljb249XCJjOHktbWFuYWdlbWVudFwiXG4gICAgbGFiZWw9XCJ7eyAnTWFuYWdlbWVudCcgfCB0cmFuc2xhdGUgfX1cIlxuICA+PC9jOHktYnJlYWRjcnVtYi1pdGVtPlxuICA8Yzh5LWJyZWFkY3J1bWItaXRlbVxuICAgIGljb249XCJnZWFyc1wiXG4gICAgbGFiZWw9XCJ7eyAnQ29uZmlndXJhdGlvbiByZXBvc2l0b3J5JyB8IHRyYW5zbGF0ZSB9fVwiXG4gID48L2M4eS1icmVhZGNydW1iLWl0ZW0+XG48L2M4eS1icmVhZGNydW1iPlxuXG48Yzh5LWFjdGlvbi1iYXItaXRlbSBbcGxhY2VtZW50XT1cIidyaWdodCdcIj5cbiAgPGJ1dHRvblxuICAgIGNsYXNzPVwiYnRuIGJ0bi1saW5rXCJcbiAgICB0aXRsZT1cInt7ICdBZGQgY29uZmlndXJhdGlvbiBzbmFwc2hvdCcgfCB0cmFuc2xhdGUgfX1cIlxuICAgIHR5cGU9XCJidXR0b25cIlxuICAgIChjbGljayk9XCJhZGQoKVwiXG4gID5cbiAgICA8aSBjOHlJY29uPVwicGx1cy1jaXJjbGVcIj48L2k+XG4gICAge3sgJ0FkZCBjb25maWd1cmF0aW9uIHNuYXBzaG90JyB8IHRyYW5zbGF0ZSB9fVxuICA8L2J1dHRvbj5cbjwvYzh5LWFjdGlvbi1iYXItaXRlbT5cblxuPGM4eS1oZWxwXG4gIHNyYz1cIi9kb2NzL2RldmljZS1tYW5hZ2VtZW50LWFwcGxpY2F0aW9uL21hbmFnaW5nLWRldmljZS1kYXRhLyNtYW5hZ2luZy1jb25maWd1cmF0aW9uc1wiXG4+PC9jOHktaGVscD5cblxuPGRpdiBjbGFzcz1cImNvbnRlbnQtZnVsbHBhZ2UgYm9yZGVyLXRvcCBib3JkZXItYm90dG9tXCI+XG4gIDxjOHktZGF0YS1ncmlkXG4gICAgW3RpdGxlXT1cIidDb25maWd1cmF0aW9ucycgfCB0cmFuc2xhdGVcIlxuICAgIFtyZWZyZXNoXT1cInJlZnJlc2gkXCJcbiAgICBbcGFnaW5hdGlvbl09XCJwYWdpbmF0aW9uXCJcbiAgICBbY29sdW1uc109XCJjb2x1bW5zXCJcbiAgICBbYWN0aW9uQ29udHJvbHNdPVwiYWN0aW9uQ29udHJvbHNcIlxuICAgIFtpbmZpbml0ZVNjcm9sbF09XCInYXV0bydcIlxuICAgIFtzZXJ2ZXJTaWRlRGF0YUNhbGxiYWNrXT1cInNlcnZlclNpZGVEYXRhQ2FsbGJhY2tcIlxuICA+XG4gICAgPGM4eS11aS1lbXB0eS1zdGF0ZVxuICAgICAgW2ljb25dPVwic3RhdHM/LnNpemUgPiAwID8gJ3NlYXJjaCcgOiAnZ2VhcnMnXCJcbiAgICAgIFt0aXRsZV09XCJzdGF0cz8uc2l6ZSA+IDAgPyAobm9SZXN1bHRzTWVzc2FnZSB8IHRyYW5zbGF0ZSkgOiAobm9EYXRhTWVzc2FnZSB8IHRyYW5zbGF0ZSlcIlxuICAgICAgW3N1YnRpdGxlXT1cInN0YXRzPy5zaXplID4gMCA/IChub1Jlc3VsdHNTdWJ0aXRsZSB8IHRyYW5zbGF0ZSkgOiAobm9EYXRhU3VidGl0bGUgfCB0cmFuc2xhdGUpXCJcbiAgICAgICplbXB0eVN0YXRlQ29udGV4dD1cImxldCBzdGF0c1wiXG4gICAgICBbaG9yaXpvbnRhbF09XCJzdGF0cz8uc2l6ZSA+IDBcIlxuICAgID5cbiAgICAgIDxuZy1jb250YWluZXIgKm5nSWY9XCJzdGF0cz8uc2l6ZSA9PT0gMFwiPlxuICAgICAgICA8cD5cbiAgICAgICAgICA8YnV0dG9uXG4gICAgICAgICAgICBjbGFzcz1cImJ0biBidG4tcHJpbWFyeVwiXG4gICAgICAgICAgICB0aXRsZT1cInt7ICdBZGQgY29uZmlndXJhdGlvbiBzbmFwc2hvdCcgfCB0cmFuc2xhdGUgfX1cIlxuICAgICAgICAgICAgdHlwZT1cImJ1dHRvblwiXG4gICAgICAgICAgICAoY2xpY2spPVwiYWRkKClcIlxuICAgICAgICAgID5cbiAgICAgICAgICAgIHt7ICdBZGQgY29uZmlndXJhdGlvbiBzbmFwc2hvdCcgfCB0cmFuc2xhdGUgfX1cbiAgICAgICAgICA8L2J1dHRvbj5cbiAgICAgICAgPC9wPlxuICAgICAgICA8cCBjOHktZ3VpZGUtZG9jcz5cbiAgICAgICAgICA8c21hbGxcbiAgICAgICAgICAgIHRyYW5zbGF0ZVxuICAgICAgICAgICAgbmdOb25CaW5kYWJsZVxuICAgICAgICAgID5cbiAgICAgICAgICAgIEZpbmQgb3V0IG1vcmUgaW4gdGhlXG4gICAgICAgICAgICA8YVxuICAgICAgICAgICAgICBjOHktZ3VpZGUtaHJlZj1cIi9kb2NzL2RldmljZS1tYW5hZ2VtZW50LWFwcGxpY2F0aW9uL21hbmFnaW5nLWRldmljZS1kYXRhLyNtYW5hZ2luZy1jb25maWd1cmF0aW9uc1wiXG4gICAgICAgICAgICA+XG4gICAgICAgICAgICAgIHVzZXIgZG9jdW1lbnRhdGlvblxuICAgICAgICAgICAgPC9hPlxuICAgICAgICAgICAgLlxuICAgICAgICAgIDwvc21hbGw+XG4gICAgICAgIDwvcD5cbiAgICAgIDwvbmctY29udGFpbmVyPlxuICAgIDwvYzh5LXVpLWVtcHR5LXN0YXRlPlxuICAgIDxuZy1jb250YWluZXIgKm5nRm9yPVwibGV0IGNvbHVtbiBvZiBjb2x1bW5zOyB0cmFja0J5OiB0cmFja0J5TmFtZVwiPlxuICAgICAgPGM4eS1jb2x1bW4gW25hbWVdPVwiY29sdW1uLm5hbWVcIj48L2M4eS1jb2x1bW4+XG4gICAgPC9uZy1jb250YWluZXI+XG4gIDwvYzh5LWRhdGEtZ3JpZD5cbjwvZGl2PlxuIl19