@c8y/ngx-components
Version:
Angular modules for Cumulocity IoT applications
212 lines • 40.3 kB
JavaScript
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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29uZmlndXJhdGlvbi1saXN0LmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3JlcG9zaXRvcnkvY29uZmlndXJhdGlvbi9saXN0L2NvbmZpZ3VyYXRpb24tbGlzdC5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi8uLi9yZXBvc2l0b3J5L2NvbmZpZ3VyYXRpb24vbGlzdC9jb25maWd1cmF0aW9uLWxpc3QuY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFNBQVMsRUFBRSxZQUFZLEVBQVUsU0FBUyxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQzNFLE9BQU8sRUFBa0Isc0JBQXNCLEVBQWUsTUFBTSxhQUFhLENBQUM7QUFDbEYsT0FBTyxFQUVMLFlBQVksRUFDWixpQkFBaUIsRUFFakIsZUFBZSxFQUVmLG9CQUFvQixFQUNwQixPQUFPLEVBQ1AsWUFBWSxFQUdaLE1BQU0sRUFDUCxNQUFNLHFCQUFxQixDQUFDO0FBQzdCLE9BQU8sRUFDTCxxQkFBcUIsRUFDckIsb0JBQW9CLEVBQ3BCLGNBQWMsRUFDZCw0QkFBNEIsRUFDNUIsaUJBQWlCLEVBQ2pCLGNBQWMsRUFDZCxjQUFjLEVBQ2YsTUFBTSx1Q0FBdUMsQ0FBQztBQUMvQyxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQUN2RCxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sWUFBWSxDQUFDO0FBQ3BDLE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQUNyRCxPQUFPLEVBQUUsNEJBQTRCLEVBQUUsTUFBTSxrQ0FBa0MsQ0FBQzs7Ozs7Ozs7QUFNaEYsTUFBTSxPQUFPLDBCQUEwQjtJQXlDckMsWUFDVSxLQUFtQixFQUNuQixXQUE0QixFQUM1QixpQkFBb0MsRUFDcEMsY0FBOEIsRUFDOUIsWUFBMEIsRUFDMUIsZ0JBQWtDLEVBQ2xDLHNCQUE4QztRQU45QyxVQUFLLEdBQUwsS0FBSyxDQUFjO1FBQ25CLGdCQUFXLEdBQVgsV0FBVyxDQUFpQjtRQUM1QixzQkFBaUIsR0FBakIsaUJBQWlCLENBQW1CO1FBQ3BDLG1CQUFjLEdBQWQsY0FBYyxDQUFnQjtRQUM5QixpQkFBWSxHQUFaLFlBQVksQ0FBYztRQUMxQixxQkFBZ0IsR0FBaEIsZ0JBQWdCLENBQWtCO1FBQ2xDLDJCQUFzQixHQUF0QixzQkFBc0IsQ0FBd0I7UUE5Q3hELGFBQVEsR0FBdUIsSUFBSSxZQUFZLEVBQUUsQ0FBQztRQUNsRCxlQUFVLEdBQUc7WUFDWCxRQUFRLEVBQUUsRUFBRTtZQUNaLFdBQVcsRUFBRSxDQUFDO1NBQ2YsQ0FBQztRQUNGLHFCQUFnQixHQUFHLE9BQU8sQ0FBQyx3QkFBd0IsQ0FBQyxDQUFDO1FBQ3JELGtCQUFhLEdBQUcsT0FBTyxDQUFDLCtDQUErQyxDQUFDLENBQUM7UUFDekUsc0JBQWlCLEdBQUcsT0FBTyxDQUFDLGtEQUFrRCxDQUFDLENBQUM7UUFDaEYsbUJBQWMsR0FBRyxPQUFPLENBQUMscUNBQXFDLENBQUMsQ0FBQztRQUNoRSxtQkFBYyxHQUFvQixFQUFFLENBQUM7UUFDckMsWUFBTyxHQUFhO1lBQ2xCLElBQUksNEJBQTRCLENBQUM7Z0JBQy9CLFdBQVcsRUFBRSxPQUFPLENBQUMsK0JBQStCLENBQUM7Z0JBQ3JELFdBQVcsRUFBRSxPQUFPLENBQUMsS0FBSyxDQUFDO2dCQUMzQixRQUFRLEVBQUUsSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDO2FBQy9CLENBQUM7WUFDRixJQUFJLHFCQUFxQixDQUFDO2dCQUN4QixXQUFXLEVBQUUsT0FBTyxDQUFDLHNDQUFzQyxDQUFDO2dCQUM1RCxXQUFXLEVBQUUsT0FBTyxDQUFDLG1CQUFtQixDQUFDO2FBQzFDLENBQUM7WUFDRixJQUFJLGNBQWMsRUFBRTtZQUNwQixJQUFJLG9CQUFvQixDQUFDO2dCQUN2QixJQUFJLEVBQUUsWUFBWTtnQkFDbEIsV0FBVyxFQUFFLE9BQU8sQ0FBQyxzQ0FBc0MsQ0FBQzthQUM3RCxDQUFDO1lBQ0YsSUFBSSxjQUFjLENBQUM7Z0JBQ2pCLE1BQU0sRUFBRSxPQUFPLENBQUMsb0JBQW9CLENBQUM7Z0JBQ3JDLFdBQVcsRUFBRSxPQUFPLENBQUMsOEJBQThCLENBQUM7Z0JBQ3BELE9BQU8sRUFBRSxLQUFLO2dCQUNkLElBQUksRUFBRSxtQkFBbUI7Z0JBQ3pCLGNBQWMsRUFBRSxjQUFjLENBQUMsYUFBYTthQUM3QyxDQUFDO1NBQ0gsQ0FBQztRQUVGLG9CQUFlLEdBQUcsS0FBSyxDQUFDO1FBR1Asd0JBQW1CLEdBQUcsT0FBTyxDQUFDLHdCQUF3QixDQUFDLENBQUM7UUFXdkUsSUFBSSxDQUFDLHNCQUFzQixHQUFHLElBQUksQ0FBQyxvQkFBb0IsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDckUsQ0FBQztJQUVELFFBQVE7UUFDTixJQUFJLENBQUMsY0FBYyxDQUFDLElBQUksQ0FBQztZQUN2QixJQUFJLEVBQUUsaUJBQWlCLENBQUMsSUFBSTtZQUM1QixRQUFRLEVBQUUsSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDO1NBQy9CLENBQUMsQ0FBQztRQUNILElBQUksQ0FBQyxjQUFjLENBQUMsSUFBSSxDQUFDO1lBQ3ZCLElBQUksRUFBRSxpQkFBaUIsQ0FBQyxNQUFNO1lBQzlCLFFBQVEsRUFBRSxJQUFJLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUM7U0FDakMsQ0FBQyxDQUFDO1FBQ0gsSUFBSSxDQUFDLGNBQWMsQ0FBQyxJQUFJLENBQUM7WUFDdkIsSUFBSSxFQUFFLFVBQVU7WUFDaEIsSUFBSSxFQUFFLFVBQVU7WUFDaEIsSUFBSSxFQUFFLE9BQU8sQ0FBQyxVQUFVLENBQUM7WUFDekIsTUFBTSxFQUFFLEdBQUcsQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLFlBQVksQ0FBQyxHQUFnQyxDQUFDO1lBQ2xFLFFBQVEsRUFBRSxJQUFJLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUM7U0FDbkMsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztJQUVELEtBQUssQ0FBQyxvQkFBb0IsQ0FDeEIsa0JBQXNDO1FBRXRDLE1BQU0sV0FBVyxHQUNmLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxxQkFBcUIsQ0FBQyxjQUFjLENBQUMsYUFBYSxFQUFFO1lBQ3pFLEtBQUssRUFBRSxJQUFJLENBQUMsV0FBVyxDQUFDLFdBQVcsQ0FBQyxrQkFBa0IsQ0FBQyxPQUFPLENBQUM7WUFDL0QsZ0JBQWdCLEVBQUUsSUFBSTtZQUN0QixNQUFNLEVBQUU7Z0JBQ04sUUFBUSxFQUFFLGtCQUFrQixDQUFDLFVBQVUsQ0FBQyxRQUFRO2dCQUNoRCxXQUFXLEVBQUUsa0JBQWtCLENBQUMsVUFBVSxDQUFDLFdBQVc7Z0JBQ3RELGNBQWMsRUFBRSxJQUFJO2FBQ3JCO1NBQ0YsQ0FBQyxDQUFDO1FBRUwsTUFBTSxvQkFBb0IsR0FBb0IsSUFBSSxDQUFDLGlCQUFpQjthQUNqRSxxQkFBcUIsQ0FBQyxjQUFjLENBQUMsYUFBYSxFQUFFO1lBQ25ELEtBQUssRUFBRSxJQUFJLENBQUMsV0FBVyxDQUFDLFdBQVcsQ0FBQyxrQkFBa0IsQ0FBQyxPQUFPLENBQUM7WUFDL0QsZ0JBQWdCLEVBQUUsSUFBSTtZQUN0QixNQUFNLEVBQUUsRUFBRSxRQUFRLEVBQUUsQ0FBQyxFQUFFO1NBQ3hCLENBQUM7YUFDRCxJQUFJLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQyxRQUFRLEVBQUUsTUFBTSxFQUFFLFVBQVUsQ0FBQyxDQUFDO1FBRWxELElBQUksQ0FBQyxLQUFLLEdBQUcsSUFBSSxDQUFDLGlCQUFpQjthQUNoQyxxQkFBcUIsQ0FBQyxjQUFjLENBQUMsYUFBYSxFQUFFO1lBQ25ELGdCQUFnQixFQUFFLElBQUk7WUFDdEIsTUFBTSxFQUFFLEVBQUUsUUFBUSxFQUFFLENBQUMsRUFBRTtTQUN4QixDQUFDO2FBQ0QsSUFBSSxDQUFDLFFBQVEsQ0FBQyxFQUFFO1lBQ2YsSUFBSSxDQUFDLGVBQWUsR0FBRyxJQUFJLENBQUM7WUFDNUIsT0FBTyxRQUFRLEVBQUUsTUFBTSxFQUFFLFVBQVUsQ0FBQztRQUN0QyxDQUFDLENBQUMsQ0FBQztRQUVMLE1BQU0sQ0FBQyxZQUFZLEVBQUUsSUFBSSxFQUFFLFlBQVksQ0FBQyxHQUFHLE1BQU0sT0FBTyxDQUFDLEdBQUcsQ0FBQztZQUMzRCxXQUFXO1lBQ1gsSUFBSSxDQUFDLEtBQUs7WUFDVixvQkFBb0I7U0FDckIsQ0FBQyxDQUFDO1FBRUgsTUFBTSxFQUFFLEdBQUcsRUFBRSxJQUFJLEVBQUUsTUFBTSxFQUFFLEdBQUcsWUFBWSxDQUFDO1FBRTNDLE1BQU0sb0JBQW9CLEdBQXlCO1lBQ2pELEdBQUc7WUFDSCxJQUFJO1lBQ0osTUFBTTtZQUNOLFlBQVk7WUFDWixJQUFJO1NBQ0wsQ0FBQztRQUVGLE9BQU8sb0JBQW9CLENBQUM7SUFDOUIsQ0FBQztJQUVELEtBQUssQ0FBQyxHQUFHO1FBQ1AsSUFBSSxDQUFDO1lBQ0gsTUFDRSxJQUFJLENBQUMsY0FBYyxDQUFDLElBQUksQ0FBQyw0QkFBNEIsRUFBRTtnQkFDckQsS0FBSyxFQUFFLFVBQVU7Z0JBQ2pCLGVBQWUsRUFBRSwrQkFBK0I7Z0JBQ2hELGNBQWMsRUFBRSx5QkFBeUI7Z0JBQ3pDLG1CQUFtQixFQUFFLElBQUk7Z0JBQ3pCLFFBQVEsRUFBRSxLQUFLO2FBQ2hCLENBQUMsQ0FBQyxPQUNKLENBQUMsTUFBTSxDQUFDO1lBQ1QsSUFBSSxDQUFDLFFBQVEsQ0FBQyxJQUFJLEVBQUUsQ0FBQztRQUN2QixDQUFDO1FBQUMsT0FBTyxFQUFFLEVBQUUsQ0FBQztZQUNaLGlCQUFpQjtRQUNuQixDQUFDO0lBQ0gsQ0FBQztJQUVELEtBQUssQ0FBQyxJQUFJLENBQUMsYUFBNkI7UUFDdEMsTUFBTSxVQUFVLEdBQVMsTUFBTSxJQUFJLENBQUMsaUJBQWlCLENBQUMsYUFBYSxDQUFDLGFBQWEsQ0FBQyxHQUFHLEVBQUU7WUFDckYsYUFBYSxFQUFFLEtBQUs7U0FDckIsQ0FBQyxDQUFDO1FBQ0gsSUFBSSxDQUFDO1lBQ0gsTUFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDLGNBQWMsQ0FBQyxJQUFJLENBQUMsNEJBQTRCLEVBQUU7Z0JBQ25FLEtBQUssRUFBRSxVQUFVO2dCQUNqQixlQUFlLEVBQUUsK0JBQStCO2dCQUNoRCxjQUFjLEVBQUUseUJBQXlCO2dCQUN6QyxtQkFBbUIsRUFBRSxJQUFJO2dCQUN6QixRQUFRLEVBQUUsS0FBSztnQkFFZixZQUFZLEVBQUU7b0JBQ1osT0FBTyxFQUFFLGFBQWEsQ0FBQyxJQUFJO29CQUMzQixVQUFVLEVBQUUsYUFBYSxDQUFDLFVBQVU7b0JBQ3BDLFdBQVcsRUFBRSxhQUFhLENBQUMsV0FBVztvQkFDdEMsTUFBTSxFQUFFLEVBQUUsSUFBSSxFQUFFLFVBQVUsRUFBRSxHQUFHLEVBQUUsYUFBYSxDQUFDLEdBQUcsRUFBRTtpQkFDckQ7YUFDRixDQUFDLENBQUMsT0FBdUMsQ0FBQztZQUMzQyxLQUFLLENBQUMsRUFBRSxHQUFHLGFBQWEsQ0FBQztZQUN6QixNQUFNLEtBQUssQ0FBQyxNQUFNLENBQUM7WUFDbkIsSUFBSSxDQUFDLFFBQVEsQ0FBQyxJQUFJLEVBQUUsQ0FBQztRQUN2QixDQUFDO1FBQUMsT0FBTyxFQUFFLEVBQUUsQ0FBQztZQUNaLGlCQUFpQjtRQUNuQixDQUFDO0lBQ0gsQ0FBQztJQUVELFlBQVksQ0FBQyxhQUE2QjtRQUN4QyxPQUFPLGFBQWEsQ0FBQyxHQUFHO1lBQ3RCLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLHNCQUFzQixDQUFDLFlBQVksQ0FBQyxhQUFhLENBQUMsR0FBRyxDQUFDO1lBQy9ELENBQUMsQ0FBQyxLQUFLLENBQUM7SUFDWixDQUFDO0lBRUQsS0FBSyxDQUFDLFFBQVEsQ0FBQyxhQUE2QjtRQUMxQyxNQUFNLFVBQVUsR0FBUyxNQUFNLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxhQUFhLENBQUMsYUFBYSxDQUFDLEdBQUcsRUFBRTtZQUNyRixhQUFhLEVBQUUsS0FBSztTQUNyQixDQUFDLENBQUM7UUFDSCxNQUFNLENBQUMsVUFBVSxDQUFDLENBQUM7SUFDckIsQ0FBQztJQUVELEtBQUssQ0FBQyxNQUFNLENBQUMsYUFBNkI7UUFDeEMsSUFBSSxDQUFDO1lBQ0gsTUFBTSxLQUFLLEdBQUcsT0FBTyxDQUFDLCtCQUErQixDQUFDLENBQUM7WUFDdkQsTUFBTSxnQkFBZ0IsR0FBRyxPQUFPLENBQzlCLGdFQUFnRSxDQUNqRSxDQUFDO1lBQ0YsTUFBTSxJQUFJLEdBQUcsT0FBTyxDQUFDLGlDQUFpQyxDQUFDLENBQUM7WUFDeEQsTUFBTSxPQUFPLEdBQUcsT0FBTyxDQUFDLHlCQUF5QixDQUFDLENBQUM7WUFDbkQsTUFBTSxJQUFJLEdBQUc7Z0JBQ1gsSUFBSSxDQUFDLGdCQUFnQixDQUFDLE9BQU8sQ0FBQyxnQkFBZ0IsRUFBRTtvQkFDOUMsSUFBSSxFQUFFLGFBQWEsQ0FBQyxJQUFJO2lCQUN6QixDQUFDO2dCQUNGLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDO2dCQUNuQyxJQUFJLENBQUMsZ0JBQWdCLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQzthQUN2QyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQztZQUNaLE1BQU0sTUFBTSxHQUFHO2dCQUNiLEVBQUUsRUFBRSxPQUFPLENBQUMsUUFBUSxDQUFDO2FBQ3RCLENBQUM7WUFDRixNQUFNLElBQUksQ0FBQyxZQUFZLENBQUMsT0FBTyxDQUFDLEtBQUssRUFBRSxJQUFJLEVBQUUsTUFBTSxDQUFDLE1BQU0sRUFBRSxNQUFNLENBQUMsQ0FBQztZQUNwRSxNQUFNLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxNQUFNLENBQUMsYUFBYSxDQUFDLENBQUM7WUFDbkQsSUFBSSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLG1CQUFtQixDQUFDLENBQUM7WUFDN0MsSUFBSSxDQUFDLFFBQVEsQ0FBQyxJQUFJLEVBQUUsQ0FBQztRQUN2QixDQUFDO1FBQUMsT0FBTyxFQUFFLEVBQUUsQ0FBQztZQUNaLElBQUksRUFBRSxFQUFFLENBQUM7Z0JBQ1AsSUFBSSxDQUFDLEtBQUssQ0FBQyxnQkFBZ0IsQ0FBQyxFQUFFLENBQUMsQ0FBQztZQUNsQyxDQUFDO1FBQ0gsQ0FBQztJQUNILENBQUM7SUFFRCxXQUFXLENBQUMsTUFBTSxFQUFFLE1BQWM7UUFDaEMsT0FBTyxNQUFNLENBQUMsSUFBSSxDQUFDO0lBQ3JCLENBQUM7K0dBbE5VLDBCQUEwQjttR0FBMUIsMEJBQTBCLHNHQUMxQixvQkFBb0IsZ0RDbkNqQyxvbEZBeUZBOzs0RkR2RGEsMEJBQTBCO2tCQUp0QyxTQUFTOytCQUNFLHdCQUF3QjsyUUFJa0IsTUFBTTtzQkFBekQsU0FBUzt1QkFBQyxvQkFBb0IsRUFBRSxFQUFFLE1BQU0sRUFBRSxLQUFLLEVBQUUiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDb21wb25lbnQsIEV2ZW50RW1pdHRlciwgT25Jbml0LCBWaWV3Q2hpbGQgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IElNYW5hZ2VkT2JqZWN0LCBJbnZlbnRvcnlCaW5hcnlTZXJ2aWNlLCBJUmVzdWx0TGlzdCB9IGZyb20gJ0BjOHkvY2xpZW50JztcbmltcG9ydCB7XG4gIEFjdGlvbkNvbnRyb2wsXG4gIEFsZXJ0U2VydmljZSxcbiAgQnVpbHRJbkFjdGlvblR5cGUsXG4gIENvbHVtbixcbiAgRGF0YUdyaWRTZXJ2aWNlLFxuICBEYXRhU291cmNlTW9kaWZpZXIsXG4gIEZpbHRlcklucHV0Q29tcG9uZW50LFxuICBnZXR0ZXh0LFxuICBNb2RhbFNlcnZpY2UsXG4gIFNlcnZlclNpZGVEYXRhQ2FsbGJhY2ssXG4gIFNlcnZlclNpZGVEYXRhUmVzdWx0LFxuICBTdGF0dXNcbn0gZnJvbSAnQGM4eS9uZ3gtY29tcG9uZW50cyc7XG5pbXBvcnQge1xuICBEZXNjcmlwdGlvbkdyaWRDb2x1bW4sXG4gIERldmljZVR5cGVHcmlkQ29sdW1uLFxuICBGaWxlR3JpZENvbHVtbixcbiAgUmVwb3NpdG9yeUl0ZW1OYW1lR3JpZENvbHVtbixcbiAgUmVwb3NpdG9yeVNlcnZpY2UsXG4gIFJlcG9zaXRvcnlUeXBlLFxuICBUeXBlR3JpZENvbHVtblxufSBmcm9tICdAYzh5L25neC1jb21wb25lbnRzL3JlcG9zaXRvcnkvc2hhcmVkJztcbmltcG9ydCB7IFRyYW5zbGF0ZVNlcnZpY2UgfSBmcm9tICdAbmd4LXRyYW5zbGF0ZS9jb3JlJztcbmltcG9ydCB7IHNhdmVBcyB9IGZyb20gJ2ZpbGUtc2F2ZXInO1xuaW1wb3J0IHsgQnNNb2RhbFNlcnZpY2UgfSBmcm9tICduZ3gtYm9vdHN0cmFwL21vZGFsJztcbmltcG9ydCB7IENvbmZpZ3VyYXRpb25EZXRhaWxDb21wb25lbnQgfSBmcm9tICcuL2NvbmZpZ3VyYXRpb24tZGV0YWlsLmNvbXBvbmVudCc7XG5cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ2M4eS1jb25maWd1cmF0aW9uLWxpc3QnLFxuICB0ZW1wbGF0ZVVybDogJy4vY29uZmlndXJhdGlvbi1saXN0LmNvbXBvbmVudC5odG1sJ1xufSlcbmV4cG9ydCBjbGFzcyBDb25maWd1cmF0aW9uTGlzdENvbXBvbmVudCBpbXBsZW1lbnRzIE9uSW5pdCB7XG4gIEBWaWV3Q2hpbGQoRmlsdGVySW5wdXRDb21wb25lbnQsIHsgc3RhdGljOiBmYWxzZSB9KSBmaWx0ZXI6IEZpbHRlcklucHV0Q29tcG9uZW50O1xuICByZWZyZXNoJDogRXZlbnRFbWl0dGVyPHZvaWQ+ID0gbmV3IEV2ZW50RW1pdHRlcigpO1xuICBwYWdpbmF0aW9uID0ge1xuICAgIHBhZ2VTaXplOiA1MCxcbiAgICBjdXJyZW50UGFnZTogMVxuICB9O1xuICBub1Jlc3VsdHNNZXNzYWdlID0gZ2V0dGV4dCgnTm8gcmVzdWx0cyB0byBkaXNwbGF5LicpO1xuICBub0RhdGFNZXNzYWdlID0gZ2V0dGV4dCgnVGhlcmUgYXJlIG5vIGNvbmZpZ3VyYXRpb24gc25hcHNob3RzIGRlZmluZWQuJyk7XG4gIG5vUmVzdWx0c1N1YnRpdGxlID0gZ2V0dGV4dCgnUmVmaW5lIHlvdXIgc2VhcmNoIHRlcm1zIG9yIGNoZWNrIHlvdXIgc3BlbGxpbmcuJyk7XG4gIG5vRGF0YVN1YnRpdGxlID0gZ2V0dGV4dCgnQWRkIGEgY29uZmlndXJhdGlvbiBzbmFwc2hvdCBmaXJzdC4nKTtcbiAgYWN0aW9uQ29udHJvbHM6IEFjdGlvbkNvbnRyb2xbXSA9IFtdO1xuICBjb2x1bW5zOiBDb2x1bW5bXSA9IFtcbiAgICBuZXcgUmVwb3NpdG9yeUl0ZW1OYW1lR3JpZENvbHVtbih7XG4gICAgICBmaWx0ZXJMYWJlbDogZ2V0dGV4dCgnRmlsdGVyIGNvbmZpZ3VyYXRpb25zIGJ5IG5hbWUnKSxcbiAgICAgIHBsYWNlaG9sZGVyOiBnZXR0ZXh0KCdTU0gnKSxcbiAgICAgIGNhbGxiYWNrOiB0aGlzLmVkaXQuYmluZCh0aGlzKVxuICAgIH0pLFxuICAgIG5ldyBEZXNjcmlwdGlvbkdyaWRDb2x1bW4oe1xuICAgICAgZmlsdGVyTGFiZWw6IGdldHRleHQoJ0ZpbHRlciBjb25maWd1cmF0aW9ucyBieSBkZXNjcmlwdGlvbicpLFxuICAgICAgcGxhY2Vob2xkZXI6IGdldHRleHQoJ1NTSCBjb25maWd1cmF0aW9uJylcbiAgICB9KSxcbiAgICBuZXcgRmlsZUdyaWRDb2x1bW4oKSxcbiAgICBuZXcgRGV2aWNlVHlwZUdyaWRDb2x1bW4oe1xuICAgICAgcGF0aDogJ2RldmljZVR5cGUnLFxuICAgICAgZmlsdGVyTGFiZWw6IGdldHRleHQoJ0ZpbHRlciBjb25maWd1cmF0aW9ucyBieSBkZXZpY2UgdHlwZScpXG4gICAgfSksXG4gICAgbmV3IFR5cGVHcmlkQ29sdW1uKHtcbiAgICAgIGhlYWRlcjogZ2V0dGV4dCgnQ29uZmlndXJhdGlvbiB0eXBlJyksXG4gICAgICBmaWx0ZXJMYWJlbDogZ2V0dGV4dCgnRmlsdGVyIGJ5IGNvbmZpZ3VyYXRpb24gdHlwZScpLFxuICAgICAgZXhhbXBsZTogJ3NzaCcsXG4gICAgICBwYXRoOiAnY29uZmlndXJhdGlvblR5cGUnLFxuICAgICAgcmVwb3NpdG9yeVR5cGU6IFJlcG9zaXRvcnlUeXBlLkNPTkZJR1VSQVRJT05cbiAgICB9KVxuICBdO1xuICBzaXplJDogUHJvbWlzZTxudW1iZXI+O1xuICBzaXplUmVxdWVzdERvbmUgPSBmYWxzZTtcbiAgc2VydmVyU2lkZURhdGFDYWxsYmFjazogU2VydmVyU2lkZURhdGFDYWxsYmFjaztcblxuICBwcml2YXRlIHJlYWRvbmx5IERFTEVURURfU1VDQ0VTU19NU0cgPSBnZXR0ZXh0KCdDb25maWd1cmF0aW9uIGRlbGV0ZWQuJyk7XG5cbiAgY29uc3RydWN0b3IoXG4gICAgcHJpdmF0ZSBhbGVydDogQWxlcnRTZXJ2aWNlLFxuICAgIHByaXZhdGUgZ3JpZFNlcnZpY2U6IERhdGFHcmlkU2VydmljZSxcbiAgICBwcml2YXRlIHJlcG9zaXRvcnlTZXJ2aWNlOiBSZXBvc2l0b3J5U2VydmljZSxcbiAgICBwcml2YXRlIGJzTW9kYWxTZXJ2aWNlOiBCc01vZGFsU2VydmljZSxcbiAgICBwcml2YXRlIG1vZGFsU2VydmljZTogTW9kYWxTZXJ2aWNlLFxuICAgIHByaXZhdGUgdHJhbnNsYXRlU2VydmljZTogVHJhbnNsYXRlU2VydmljZSxcbiAgICBwcml2YXRlIGludmVudG9yeUJpbmFyeVNlcnZpY2U6IEludmVudG9yeUJpbmFyeVNlcnZpY2VcbiAgKSB7XG4gICAgdGhpcy5zZXJ2ZXJTaWRlRGF0YUNhbGxiYWNrID0gdGhpcy5vbkRhdGFTb3VyY2VNb2RpZmllci5iaW5kKHRoaXMpO1xuICB9XG5cbiAgbmdPbkluaXQoKSB7XG4gICAgdGhpcy5hY3Rpb25Db250cm9scy5wdXNoKHtcbiAgICAgIHR5cGU6IEJ1aWx0SW5BY3Rpb25UeXBlLkVkaXQsXG4gICAgICBjYWxsYmFjazogdGhpcy5lZGl0LmJpbmQodGhpcylcbiAgICB9KTtcbiAgICB0aGlzLmFjdGlvbkNvbnRyb2xzLnB1c2goe1xuICAgICAgdHlwZTogQnVpbHRJbkFjdGlvblR5cGUuRGVsZXRlLFxuICAgICAgY2FsbGJhY2s6IHRoaXMuZGVsZXRlLmJpbmQodGhpcylcbiAgICB9KTtcbiAgICB0aGlzLmFjdGlvbkNvbnRyb2xzLnB1c2goe1xuICAgICAgdHlwZTogJ2Rvd25sb2FkJyxcbiAgICAgIGljb246ICdkb3dubG9hZCcsXG4gICAgICB0ZXh0OiBnZXR0ZXh0KCdEb3dubG9hZCcpLFxuICAgICAgc2hvd0lmOiByb3cgPT4gdGhpcy5pc0JpbmFyeUZpbGUocm93IGFzIHVua25vd24gYXMgSU1hbmFnZWRPYmplY3QpLFxuICAgICAgY2FsbGJhY2s6IHRoaXMuZG93bmxvYWQuYmluZCh0aGlzKVxuICAgIH0pO1xuICB9XG5cbiAgYXN5bmMgb25EYXRhU291cmNlTW9kaWZpZXIoXG4gICAgZGF0YVNvdXJjZU1vZGlmaWVyOiBEYXRhU291cmNlTW9kaWZpZXJcbiAgKTogUHJvbWlzZTxTZXJ2ZXJTaWRlRGF0YVJlc3VsdD4ge1xuICAgIGNvbnN0IGRhdGFSZXF1ZXN0OiBQcm9taXNlPElSZXN1bHRMaXN0PElNYW5hZ2VkT2JqZWN0Pj4gPVxuICAgICAgdGhpcy5yZXBvc2l0b3J5U2VydmljZS5saXN0UmVwb3NpdG9yeUVudHJpZXMoUmVwb3NpdG9yeVR5cGUuQ09ORklHVVJBVElPTiwge1xuICAgICAgICBxdWVyeTogdGhpcy5ncmlkU2VydmljZS5nZXRRdWVyeU9iaihkYXRhU291cmNlTW9kaWZpZXIuY29sdW1ucyksXG4gICAgICAgIHNraXBEZWZhdWx0T3JkZXI6IHRydWUsXG4gICAgICAgIHBhcmFtczoge1xuICAgICAgICAgIHBhZ2VTaXplOiBkYXRhU291cmNlTW9kaWZpZXIucGFnaW5hdGlvbi5wYWdlU2l6ZSxcbiAgICAgICAgICBjdXJyZW50UGFnZTogZGF0YVNvdXJjZU1vZGlmaWVyLnBhZ2luYXRpb24uY3VycmVudFBhZ2UsXG4gICAgICAgICAgd2l0aFRvdGFsUGFnZXM6IHRydWVcbiAgICAgICAgfVxuICAgICAgfSk7XG5cbiAgICBjb25zdCBmaWx0ZXJlcmRTaXplUmVxdWVzdDogUHJvbWlzZTxudW1iZXI+ID0gdGhpcy5yZXBvc2l0b3J5U2VydmljZVxuICAgICAgLmxpc3RSZXBvc2l0b3J5RW50cmllcyhSZXBvc2l0b3J5VHlwZS5DT05GSUdVUkFUSU9OLCB7XG4gICAgICAgIHF1ZXJ5OiB0aGlzLmdyaWRTZXJ2aWNlLmdldFF1ZXJ5T2JqKGRhdGFTb3VyY2VNb2RpZmllci5jb2x1bW5zKSxcbiAgICAgICAgc2tpcERlZmF1bHRPcmRlcjogdHJ1ZSxcbiAgICAgICAgcGFyYW1zOiB7IHBhZ2VTaXplOiAxIH1cbiAgICAgIH0pXG4gICAgICAudGhlbihyZXNwb25zZSA9PiByZXNwb25zZT8ucGFnaW5nPy50b3RhbFBhZ2VzKTtcblxuICAgIHRoaXMuc2l6ZSQgPSB0aGlzLnJlcG9zaXRvcnlTZXJ2aWNlXG4gICAgICAubGlzdFJlcG9zaXRvcnlFbnRyaWVzKFJlcG9zaXRvcnlUeXBlLkNPTkZJR1VSQVRJT04sIHtcbiAgICAgICAgc2tpcERlZmF1bHRPcmRlcjogdHJ1ZSxcbiAgICAgICAgcGFyYW1zOiB7IHBhZ2VTaXplOiAxIH1cbiAgICAgIH0pXG4gICAgICAudGhlbihyZXNwb25zZSA9PiB7XG4gICAgICAgIHRoaXMuc2l6ZVJlcXVlc3REb25lID0gdHJ1ZTtcbiAgICAgICAgcmV0dXJuIHJlc3BvbnNlPy5wYWdpbmc/LnRvdGFsUGFnZXM7XG4gICAgICB9KTtcblxuICAgIGNvbnN0IFtkYXRhUmVzcG9uc2UsIHNpemUsIGZpbHRlcmVkU2l6ZV0gPSBhd2FpdCBQcm9taXNlLmFsbChbXG4gICAgICBkYXRhUmVxdWVzdCxcbiAgICAgIHRoaXMuc2l6ZSQsXG4gICAgICBmaWx0ZXJlcmRTaXplUmVxdWVzdFxuICAgIF0pO1xuXG4gICAgY29uc3QgeyByZXMsIGRhdGEsIHBhZ2luZyB9ID0gZGF0YVJlc3BvbnNlO1xuXG4gICAgY29uc3Qgc2VydmVyU2lkZURhdGFSZXN1bHQ6IFNlcnZlclNpZGVEYXRhUmVzdWx0ID0ge1xuICAgICAgcmVzLFxuICAgICAgZGF0YSxcbiAgICAgIHBhZ2luZyxcbiAgICAgIGZpbHRlcmVkU2l6ZSxcbiAgICAgIHNpemVcbiAgICB9O1xuXG4gICAgcmV0dXJuIHNlcnZlclNpZGVEYXRhUmVzdWx0O1xuICB9XG5cbiAgYXN5bmMgYWRkKCkge1xuICAgIHRyeSB7XG4gICAgICBhd2FpdCAoXG4gICAgICAgIHRoaXMuYnNNb2RhbFNlcnZpY2Uuc2hvdyhDb25maWd1cmF0aW9uRGV0YWlsQ29tcG9uZW50LCB7XG4gICAgICAgICAgY2xhc3M6ICdtb2RhbC1zbScsXG4gICAgICAgICAgYXJpYURlc2NyaWJlZGJ5OiAnY29uZmlndXJhdGlvbk1vZGFsRGVzY3JpcHRpb24nLFxuICAgICAgICAgIGFyaWFMYWJlbGxlZEJ5OiAnY29uZmlndXJhdGlvbk1vZGFsVGl0bGUnLFxuICAgICAgICAgIGlnbm9yZUJhY2tkcm9wQ2xpY2s6IHRydWUsXG4gICAgICAgICAga2V5Ym9hcmQ6IGZhbHNlXG4gICAgICAgIH0pLmNvbnRlbnQgYXMgQ29uZmlndXJhdGlvbkRldGFpbENvbXBvbmVudFxuICAgICAgKS5yZXN1bHQ7XG4gICAgICB0aGlzLnJlZnJlc2gkLm5leHQoKTtcbiAgICB9IGNhdGNoIChleCkge1xuICAgICAgLy8gaW50ZW5kZWQgZW1wdHlcbiAgICB9XG4gIH1cblxuICBhc3luYyBlZGl0KGNvbmZpZ3VyYXRpb246IElNYW5hZ2VkT2JqZWN0KSB7XG4gICAgY29uc3QgZmlsZUJpbmFyeTogRmlsZSA9IGF3YWl0IHRoaXMucmVwb3NpdG9yeVNlcnZpY2UuZ2V0QmluYXJ5RmlsZShjb25maWd1cmF0aW9uLnVybCwge1xuICAgICAgYWxsb3dFeHRlcm5hbDogZmFsc2VcbiAgICB9KTtcbiAgICB0cnkge1xuICAgICAgY29uc3QgbW9kYWwgPSB0aGlzLmJzTW9kYWxTZXJ2aWNlLnNob3coQ29uZmlndXJhdGlvbkRldGFpbENvbXBvbmVudCwge1xuICAgICAgICBjbGFzczogJ21vZGFsLXNtJyxcbiAgICAgICAgYXJpYURlc2NyaWJlZGJ5OiAnY29uZmlndXJhdGlvbk1vZGFsRGVzY3JpcHRpb24nLFxuICAgICAgICBhcmlhTGFiZWxsZWRCeTogJ2NvbmZpZ3VyYXRpb25Nb2RhbFRpdGxlJyxcbiAgICAgICAgaWdub3JlQmFja2Ryb3BDbGljazogdHJ1ZSxcbiAgICAgICAga2V5Ym9hcmQ6IGZhbHNlLFxuXG4gICAgICAgIGluaXRpYWxTdGF0ZToge1xuICAgICAgICAgIHZlcnNpb246IGNvbmZpZ3VyYXRpb24ubmFtZSxcbiAgICAgICAgICBkZXZpY2VUeXBlOiBjb25maWd1cmF0aW9uLmRldmljZVR5cGUsXG4gICAgICAgICAgZGVzY3JpcHRpb246IGNvbmZpZ3VyYXRpb24uZGVzY3JpcHRpb24sXG4gICAgICAgICAgYmluYXJ5OiB7IGZpbGU6IGZpbGVCaW5hcnksIHVybDogY29uZmlndXJhdGlvbi51cmwgfVxuICAgICAgICB9XG4gICAgICB9KS5jb250ZW50IGFzIENvbmZpZ3VyYXRpb25EZXRhaWxDb21wb25lbnQ7XG4gICAgICBtb2RhbC5tbyA9IGNvbmZpZ3VyYXRpb247XG4gICAgICBhd2FpdCBtb2RhbC5yZXN1bHQ7XG4gICAgICB0aGlzLnJlZnJlc2gkLm5leHQoKTtcbiAgICB9IGNhdGNoIChleCkge1xuICAgICAgLy8gaW50ZW5kZWQgZW1wdHlcbiAgICB9XG4gIH1cblxuICBpc0JpbmFyeUZpbGUoY29uZmlndXJhdGlvbjogSU1hbmFnZWRPYmplY3QpIHtcbiAgICByZXR1cm4gY29uZmlndXJhdGlvbi51cmxcbiAgICAgID8gISF0aGlzLmludmVudG9yeUJpbmFyeVNlcnZpY2UuZ2V0SWRGcm9tVXJsKGNvbmZpZ3VyYXRpb24udXJsKVxuICAgICAgOiBmYWxzZTtcbiAgfVxuXG4gIGFzeW5jIGRvd25sb2FkKGNvbmZpZ3VyYXRpb246IElNYW5hZ2VkT2JqZWN0KSB7XG4gICAgY29uc3QgZmlsZUJpbmFyeTogRmlsZSA9IGF3YWl0IHRoaXMucmVwb3NpdG9yeVNlcnZpY2UuZ2V0QmluYXJ5RmlsZShjb25maWd1cmF0aW9uLnVybCwge1xuICAgICAgYWxsb3dFeHRlcm5hbDogZmFsc2VcbiAgICB9KTtcbiAgICBzYXZlQXMoZmlsZUJpbmFyeSk7XG4gIH1cblxuICBhc3luYyBkZWxldGUoY29uZmlndXJhdGlvbjogSU1hbmFnZWRPYmplY3QpIHtcbiAgICB0cnkge1xuICAgICAgY29uc3QgdGl0bGUgPSBnZXR0ZXh0KCdEZWxldGUgY29uZmlndXJhdGlvbiBzbmFwc2hvdCcpO1xuICAgICAgY29uc3QgY29uZmlybWF0aW9uVGV4dCA9IGdldHRleHQoXG4gICAgICAgICdZb3UgYXJlIGFib3V0IHRvIGRlbGV0ZSB0aGUgY29uZmlndXJhdGlvbiBzbmFwc2hvdCB7eyBuYW1lIH19LidcbiAgICAgICk7XG4gICAgICBjb25zdCBoaW50ID0gZ2V0dGV4dCgnVGhpcyBvcGVyYXRpb24gaXMgaXJyZXZlcnNpYmxlLicpO1xuICAgICAgY29uc3QgcHJvY2VlZCA9IGdldHRleHQoJ0RvIHlvdSB3YW50IHRvIHByb2NlZWQ/Jyk7XG4gICAgICBjb25zdCBib2R5ID0gW1xuICAgICAgICB0aGlzLnRyYW5zbGF0ZVNlcnZpY2UuaW5zdGFudChjb25maXJtYXRpb25UZXh0LCB7XG4gICAgICAgICAgbmFtZTogY29uZmlndXJhdGlvbi5uYW1lXG4gICAgICAgIH0pLFxuICAgICAgICB0aGlzLnRyYW5zbGF0ZVNlcnZpY2UuaW5zdGFudChoaW50KSxcbiAgICAgICAgdGhpcy50cmFuc2xhdGVTZXJ2aWNlLmluc3RhbnQocHJvY2VlZClcbiAgICAgIF0uam9pbignICcpO1xuICAgICAgY29uc3QgbGFiZWxzID0ge1xuICAgICAgICBvazogZ2V0dGV4dCgnRGVsZXRlJylcbiAgICAgIH07XG4gICAgICBhd2FpdCB0aGlzLm1vZGFsU2VydmljZS5jb25maXJtKHRpdGxlLCBib2R5LCBTdGF0dXMuREFOR0VSLCBsYWJlbHMpO1xuICAgICAgYXdhaXQgdGhpcy5yZXBvc2l0b3J5U2VydmljZS5kZWxldGUoY29uZmlndXJhdGlvbik7XG4gICAgICB0aGlzLmFsZXJ0LnN1Y2Nlc3ModGhpcy5ERUxFVEVEX1NVQ0NFU1NfTVNHKTtcbiAgICAgIHRoaXMucmVmcmVzaCQubmV4dCgpO1xuICAgIH0gY2F0Y2ggKGV4KSB7XG4gICAgICBpZiAoZXgpIHtcbiAgICAgICAgdGhpcy5hbGVydC5hZGRTZXJ2ZXJGYWlsdXJlKGV4KTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICB0cmFja0J5TmFtZShfaW5kZXgsIGNvbHVtbjogQ29sdW1uKTogc3RyaW5nIHtcbiAgICByZXR1cm4gY29sdW1uLm5hbWU7XG4gIH1cbn1cbiIsIjxjOHktdGl0bGU+XG4gIDxzcGFuXG4gICAgY2xhc3M9XCJtLXItNFwiXG4gICAgdHJhbnNsYXRlXG4gID5cbiAgICBDb25maWd1cmF0aW9uIHJlcG9zaXRvcnlcbiAgPC9zcGFuPlxuICA8c21hbGw+XG4gICAge3sgc2l6ZSQgfCBhc3luYyB9fVxuICAgIDxzcGFuIHRyYW5zbGF0ZT5zbmFwc2hvdHM8L3NwYW4+XG4gIDwvc21hbGw+XG48L2M4eS10aXRsZT5cblxuPGM4eS1icmVhZGNydW1iPlxuICA8Yzh5LWJyZWFkY3J1bWItaXRlbVxuICAgIGljb249XCJjOHktbWFuYWdlbWVudFwiXG4gICAgbGFiZWw9XCJ7eyAnTWFuYWdlbWVudCcgfCB0cmFuc2xhdGUgfX1cIlxuICA+PC9jOHktYnJlYWRjcnVtYi1pdGVtPlxuICA8Yzh5LWJyZWFkY3J1bWItaXRlbVxuICAgIGljb249XCJnZWFyc1wiXG4gICAgbGFiZWw9XCJ7eyAnQ29uZmlndXJhdGlvbiByZXBvc2l0b3J5JyB8IHRyYW5zbGF0ZSB9fVwiXG4gID48L2M4eS1icmVhZGNydW1iLWl0ZW0+XG48L2M4eS1icmVhZGNydW1iPlxuXG48Yzh5LWFjdGlvbi1iYXItaXRlbSBbcGxhY2VtZW50XT1cIidyaWdodCdcIj5cbiAgPGJ1dHRvblxuICAgIGNsYXNzPVwiYnRuIGJ0bi1saW5rXCJcbiAgICB0aXRsZT1cInt7ICdBZGQgY29uZmlndXJhdGlvbiBzbmFwc2hvdCcgfCB0cmFuc2xhdGUgfX1cIlxuICAgIHR5cGU9XCJidXR0b25cIlxuICAgIChjbGljayk9XCJhZGQoKVwiXG4gID5cbiAgICA8aSBjOHlJY29uPVwicGx1cy1jaXJjbGVcIj48L2k+XG4gICAge3sgJ0FkZCBjb25maWd1cmF0aW9uIHNuYXBzaG90JyB8IHRyYW5zbGF0ZSB9fVxuICA8L2J1dHRvbj5cbjwvYzh5LWFjdGlvbi1iYXItaXRlbT5cblxuPGM4eS1oZWxwXG4gIHNyYz1cIi9kb2NzL2RldmljZS1tYW5hZ2VtZW50LWFwcGxpY2F0aW9uL21hbmFnaW5nLWRldmljZS1kYXRhLyNtYW5hZ2luZy1jb25maWd1cmF0aW9uc1wiXG4+PC9jOHktaGVscD5cblxuPGRpdiBjbGFzcz1cImNvbnRlbnQtZnVsbHBhZ2UgYm9yZGVyLXRvcCBib3JkZXItYm90dG9tXCI+XG4gIDxjOHktZGF0YS1ncmlkXG4gICAgW3RpdGxlXT1cIidDb25maWd1cmF0aW9ucycgfCB0cmFuc2xhdGVcIlxuICAgIFtyZWZyZXNoXT1cInJlZnJlc2gkXCJcbiAgICBbcGFnaW5hdGlvbl09XCJwYWdpbmF0aW9uXCJcbiAgICBbY29sdW1uc109XCJjb2x1bW5zXCJcbiAgICBbYWN0aW9uQ29udHJvbHNdPVwiYWN0aW9uQ29udHJvbHNcIlxuICAgIFtpbmZpbml0ZVNjcm9sbF09XCInYXV0bydcIlxuICAgIFtzZXJ2ZXJTaWRlRGF0YUNhbGxiYWNrXT1cInNlcnZlclNpZGVEYXRhQ2FsbGJhY2tcIlxuICA+XG4gICAgPGM4eS11aS1lbXB0eS1zdGF0ZVxuICAgICAgW2ljb25dPVwic3RhdHM/LnNpemUgPiAwID8gJ3NlYXJjaCcgOiAnZ2VhcnMnXCJcbiAgICAgIFt0aXRsZV09XCJzdGF0cz8uc2l6ZSA+IDAgPyAobm9SZXN1bHRzTWVzc2FnZSB8IHRyYW5zbGF0ZSkgOiAobm9EYXRhTWVzc2FnZSB8IHRyYW5zbGF0ZSlcIlxuICAgICAgW3N1YnRpdGxlXT1cInN0YXRzPy5zaXplID4gMCA/IChub1Jlc3VsdHNTdWJ0aXRsZSB8IHRyYW5zbGF0ZSkgOiAobm9EYXRhU3VidGl0bGUgfCB0cmFuc2xhdGUpXCJcbiAgICAgICplbXB0eVN0YXRlQ29udGV4dD1cImxldCBzdGF0c1wiXG4gICAgICBbaG9yaXpvbnRhbF09XCJzdGF0cz8uc2l6ZSA+IDBcIlxuICAgID5cbiAgICAgIDxuZy1jb250YWluZXIgKm5nSWY9XCJzdGF0cz8uc2l6ZSA9PT0gMFwiPlxuICAgICAgICA8cD5cbiAgICAgICAgICA8YnV0dG9uXG4gICAgICAgICAgICBjbGFzcz1cImJ0biBidG4tcHJpbWFyeVwiXG4gICAgICAgICAgICB0aXRsZT1cInt7ICdBZGQgY29uZmlndXJhdGlvbiBzbmFwc2hvdCcgfCB0cmFuc2xhdGUgfX1cIlxuICAgICAgICAgICAgdHlwZT1cImJ1dHRvblwiXG4gICAgICAgICAgICAoY2xpY2spPVwiYWRkKClcIlxuICAgICAgICAgID5cbiAgICAgICAgICAgIHt7ICdBZGQgY29uZmlndXJhdGlvbiBzbmFwc2hvdCcgfCB0cmFuc2xhdGUgfX1cbiAgICAgICAgICA8L2J1dHRvbj5cbiAgICAgICAgPC9wPlxuICAgICAgICA8cCBjOHktZ3VpZGUtZG9jcz5cbiAgICAgICAgICA8c21hbGxcbiAgICAgICAgICAgIHRyYW5zbGF0ZVxuICAgICAgICAgICAgbmdOb25CaW5kYWJsZVxuICAgICAgICAgID5cbiAgICAgICAgICAgIEZpbmQgb3V0IG1vcmUgaW4gdGhlXG4gICAgICAgICAgICA8YVxuICAgICAgICAgICAgICBjOHktZ3VpZGUtaHJlZj1cIi9kb2NzL2RldmljZS1tYW5hZ2VtZW50LWFwcGxpY2F0aW9uL21hbmFnaW5nLWRldmljZS1kYXRhLyNtYW5hZ2luZy1jb25maWd1cmF0aW9uc1wiXG4gICAgICAgICAgICA+XG4gICAgICAgICAgICAgIHVzZXIgZG9jdW1lbnRhdGlvblxuICAgICAgICAgICAgPC9hPlxuICAgICAgICAgICAgLlxuICAgICAgICAgIDwvc21hbGw+XG4gICAgICAgIDwvcD5cbiAgICAgIDwvbmctY29udGFpbmVyPlxuICAgIDwvYzh5LXVpLWVtcHR5LXN0YXRlPlxuICAgIDxuZy1jb250YWluZXIgKm5nRm9yPVwibGV0IGNvbHVtbiBvZiBjb2x1bW5zOyB0cmFja0J5OiB0cmFja0J5TmFtZVwiPlxuICAgICAgPGM4eS1jb2x1bW4gW25hbWVdPVwiY29sdW1uLm5hbWVcIj48L2M4eS1jb2x1bW4+XG4gICAgPC9uZy1jb250YWluZXI+XG4gIDwvYzh5LWRhdGEtZ3JpZD5cbjwvZGl2PlxuIl19