@c8y/ngx-components
Version:
Angular modules for Cumulocity IoT applications
161 lines • 38.9 kB
JavaScript
import { Component, EventEmitter, ViewChild } from '@angular/core';
import { InventoryBinaryService } from '@c8y/client';
import { AlertService, BuiltInActionType, DataGridComponent, FilesService, gettext, ModalService, Status } from '@c8y/ngx-components';
import { TranslateService } from '@ngx-translate/core';
import { BsModalService } from 'ngx-bootstrap/modal';
import { Subject } from 'rxjs';
import { take, takeUntil } from 'rxjs/operators';
import { FilesRepositoryUploadComponent } from './files-repository-upload.component';
import { FilesRepositoryService } from './files-repository.service';
import * as i0 from "@angular/core";
import * as i1 from "./files-repository.service";
import * as i2 from "@c8y/client";
import * as i3 from "@c8y/ngx-components";
import * as i4 from "ngx-bootstrap/modal";
import * as i5 from "@ngx-translate/core";
import * as i6 from "@angular/common";
import * as i7 from "@c8y/ngx-components/file-preview";
export class FilesRepositoryComponent {
constructor(filesRepositoryService, inventoryBinaryService, modalService, alertService, bsModalService, fileService, translateService) {
this.filesRepositoryService = filesRepositoryService;
this.inventoryBinaryService = inventoryBinaryService;
this.modalService = modalService;
this.alertService = alertService;
this.bsModalService = bsModalService;
this.fileService = fileService;
this.translateService = translateService;
this.destroy$ = new Subject();
this.title = gettext('Files repository');
this.managementTitle = gettext('Management');
this.loadMoreItemsLabel = gettext('Load more files');
this.loadingItemsLabel = gettext('Loading files…');
this.isLoading = true;
this.displayOptions = {
bordered: false,
striped: true,
filter: true,
gridHeader: true,
hover: true
};
this.columns = this.filesRepositoryService.getColumns();
this.pagination = this.filesRepositoryService.getPagination();
this.infiniteScroll = 'auto';
this.selectable = true;
this.actionControls = [
{
text: gettext('Delete'),
icon: 'trash',
type: BuiltInActionType.Delete,
showIf: selectedItem => !this.filesRepositoryService.hasApplicationStorageFragment(selectedItem),
callback: selectedItem => this.onDeleteItem(selectedItem)
},
{
text: gettext('Download'),
icon: 'download',
type: BuiltInActionType.Export,
callback: selectedItem => this.onDownloadItem(selectedItem)
}
];
this.bulkActionControls = [
{
type: BuiltInActionType.Delete,
callback: selectedItemIds => this.onDeleteItems(selectedItemIds)
}
];
this.refresh = new EventEmitter();
this.noResultsMessage = gettext('No results to display.');
this.noDataMessage = gettext('No files to display.');
this.noResultsSubtitle = gettext('Refine your search terms or check your spelling.');
this.noDataSubtitle = gettext('Add a new file by clicking below.');
// we're setting up `serverSideDataCallback` to execute a method from this component with bound `this`
this.serverSideDataCallback = this.onDataSourceModifier.bind(this);
}
async onDataSourceModifier(dataSourceModifier) {
const { res, data, paging } = await this.filesRepositoryService.getData(dataSourceModifier.columns, dataSourceModifier.pagination, dataSourceModifier.searchText);
const filteredSize = paging.totalElements;
const size = await this.filesRepositoryService.getTotal();
const serverSideDataResult = { res, data, paging, filteredSize, size };
this.isLoading = false;
this.returnedDataSize = serverSideDataResult.size;
return serverSideDataResult;
}
async onDeleteItem(selectedItem) {
return this.deleteItemsWithConfirmation([selectedItem.id], {
title: gettext('Delete file'),
body: this.translateService.instant(gettext('You are about to delete file "{{ name }}". Do you want to proceed?'), selectedItem),
successText: gettext('File deleted.')
});
}
async onDeleteItems(selectedItemsIds) {
const dataGridDataSourceData = await this.dataGrid.dataSource.data$.pipe(take(1)).toPromise();
const deletableItemsIds = this.filesRepositoryService.getDeletableItemsIds(selectedItemsIds, dataGridDataSourceData);
let body;
if (deletableItemsIds.length < selectedItemsIds.length) {
body = gettext(`
You are about to delete the selected files.
Note: the selected files of type "c8y_applications_storage_*" won't be deleted though
- such files can be deleted only from the "Activity log" of the associated application.
Do you want to proceed?
`);
}
else {
body = gettext('You are about to delete the selected files. Do you want to proceed?');
}
return this.deleteItemsWithConfirmation(deletableItemsIds, {
title: gettext('Delete files'),
body,
successText: gettext('Files deleted.')
});
}
async onDownloadItem(selectedItem) {
return this.fileService.download(selectedItem);
}
openFileUploadComponent() {
const modalOptions = {
class: 'modal-sm',
ariaDescribedby: 'modal-body',
ariaLabelledBy: 'modal-title',
ignoreBackdropClick: true
};
const modalRef = this.bsModalService.show(FilesRepositoryUploadComponent, modalOptions);
modalRef.content.onClose.pipe(takeUntil(this.destroy$)).subscribe(({ uploaded }) => {
if (uploaded) {
this.refresh.emit();
}
modalRef.hide();
});
}
async deleteItemsWithConfirmation(selectedItemsIds, options) {
try {
await this.confirmItemsDeletion(options);
this.isLoading = true;
const promises = selectedItemsIds.map(selectedItemId => this.inventoryBinaryService.delete(selectedItemId));
await Promise.all(promises);
this.alertService.success(options.successText);
this.refresh.next();
}
catch (ex) {
if (ex) {
this.alertService.addServerFailure(ex);
}
}
finally {
this.isLoading = false;
}
}
async confirmItemsDeletion({ title, body }) {
const status = Status.DANGER;
const labels = { ok: gettext('Delete'), cancel: gettext('Cancel') };
await this.modalService.confirm(title, body, status, labels);
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: FilesRepositoryComponent, deps: [{ token: i1.FilesRepositoryService }, { token: i2.InventoryBinaryService }, { token: i3.ModalService }, { token: i3.AlertService }, { token: i4.BsModalService }, { token: i3.FilesService }, { token: i5.TranslateService }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: FilesRepositoryComponent, selector: "c8y-files-repository", viewQueries: [{ propertyName: "dataGrid", first: true, predicate: DataGridComponent, descendants: true, static: true }], ngImport: i0, template: "<c8y-title>\n {{ title | translate }}\n</c8y-title>\n\n<c8y-breadcrumb>\n <c8y-breadcrumb-item\n icon=\"c8y-management\"\n [label]=\"managementTitle | translate\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item [label]=\"title | translate\"></c8y-breadcrumb-item>\n</c8y-breadcrumb>\n\n<c8y-action-bar-item [placement]=\"'right'\">\n <button\n class=\"btn btn-link\"\n title=\"{{ 'Upload files' | translate }}\"\n *c8yIfAllowed=\"['ROLE_INVENTORY_ADMIN', 'ROLE_INVENTORY_CREATE']; allowAny: true\"\n (click)=\"openFileUploadComponent()\"\n data-cy=\"c8y-files-repository--open-file-upload-component\"\n >\n <i c8yIcon=\"upload\"></i>\n {{ 'Upload files' | translate }}\n </button>\n</c8y-action-bar-item>\n\n<c8y-help src=\"/docs/standard-tenant/managing-data/#file-repository\"></c8y-help>\n\n<div class=\"content-fullpage border-top border-bottom\">\n <c8y-data-grid\n [title]=\"title\"\n [loadMoreItemsLabel]=\"loadMoreItemsLabel\"\n [loadingItemsLabel]=\"loadingItemsLabel\"\n [displayOptions]=\"displayOptions\"\n [columns]=\"columns\"\n [pagination]=\"pagination\"\n [infiniteScroll]=\"infiniteScroll\"\n [serverSideDataCallback]=\"serverSideDataCallback\"\n [actionControls]=\"actionControls\"\n [selectable]=\"selectable\"\n [showSearch]=\"true\"\n [refresh]=\"refresh\"\n [bulkActionControls]=\"bulkActionControls\"\n >\n <c8y-ui-empty-state\n [icon]=\"stats?.size > 0 ? 'search' : 'c8y-archive'\"\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=\"{{ 'Upload file' | translate }}\"\n type=\"button\"\n (click)=\"openFileUploadComponent()\"\n >\n <i c8yIcon=\"plus-circle\"></i>\n {{ 'Upload file' | translate }}\n </button>\n </p>\n </c8y-ui-empty-state>\n\n <c8y-column name=\"name\">\n <ng-container *c8yCellRendererDef=\"let context\">\n <span title=\"{{ context.value }}\">\n <div class=\"d-flex j-c-between a-i-center\">\n {{ context.value }}\n <c8y-file-preview\n class=\"m-l-auto\"\n [mo]=\"context.item\"\n >\n <button\n class=\"btn btn-emphasis btn-icon\"\n [title]=\"'Preview file' | translate\"\n type=\"button\"\n customButton\n >\n <i c8yIcon=\"search\"></i>\n </button>\n </c8y-file-preview>\n </div>\n </span>\n </ng-container>\n </c8y-column>\n\n <c8y-column name=\"length\">\n <ng-container *c8yCellRendererDef=\"let context\">\n <span title=\"{{ context.value }} B\">\n {{ context.value | bytes }}\n </span>\n </ng-container>\n </c8y-column>\n\n <c8y-column name=\"lastUpdated\">\n <ng-container *c8yCellRendererDef=\"let context\">\n <span title=\"{{ context.value | c8yDate }}\">\n {{ context.value | c8yDate }}\n </span>\n </ng-container>\n </c8y-column>\n </c8y-data-grid>\n</div>\n", dependencies: [{ kind: "component", type: i3.ActionBarItemComponent, selector: "c8y-action-bar-item", inputs: ["placement", "priority", "itemClass", "injector", "groupId", "inGroupPriority"] }, { kind: "component", type: i3.BreadcrumbComponent, selector: "c8y-breadcrumb" }, { kind: "component", type: i3.BreadcrumbItemComponent, selector: "c8y-breadcrumb-item", inputs: ["icon", "translate", "label", "path", "injector"] }, { kind: "component", type: i3.EmptyStateComponent, selector: "c8y-ui-empty-state", inputs: ["icon", "title", "subtitle", "horizontal"] }, { kind: "directive", type: i3.EmptyStateContextDirective, selector: "[emptyStateContext]" }, { kind: "directive", type: i3.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: i6.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i3.IfAllowedDirective, selector: "[c8yIfAllowed]", inputs: ["c8yIfAllowed", "c8yIfAllowedAllowAny"] }, { kind: "directive", type: i3.CellRendererDefDirective, selector: "[c8yCellRendererDef]" }, { kind: "directive", type: i3.ColumnDirective, selector: "c8y-column", inputs: ["name"] }, { kind: "component", type: i3.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: i3.TitleComponent, selector: "c8y-title", inputs: ["pageTitleUpdate"] }, { kind: "component", type: i3.HelpComponent, selector: "c8y-help", inputs: ["src", "isCollapsed", "priority", "icon"] }, { kind: "component", type: i7.FilePreviewComponent, selector: "c8y-file-preview", inputs: ["mo"] }, { kind: "pipe", type: i3.C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: i3.DatePipe, name: "c8yDate" }, { kind: "pipe", type: i3.BytesPipe, name: "bytes" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: FilesRepositoryComponent, decorators: [{
type: Component,
args: [{ selector: 'c8y-files-repository', template: "<c8y-title>\n {{ title | translate }}\n</c8y-title>\n\n<c8y-breadcrumb>\n <c8y-breadcrumb-item\n icon=\"c8y-management\"\n [label]=\"managementTitle | translate\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item [label]=\"title | translate\"></c8y-breadcrumb-item>\n</c8y-breadcrumb>\n\n<c8y-action-bar-item [placement]=\"'right'\">\n <button\n class=\"btn btn-link\"\n title=\"{{ 'Upload files' | translate }}\"\n *c8yIfAllowed=\"['ROLE_INVENTORY_ADMIN', 'ROLE_INVENTORY_CREATE']; allowAny: true\"\n (click)=\"openFileUploadComponent()\"\n data-cy=\"c8y-files-repository--open-file-upload-component\"\n >\n <i c8yIcon=\"upload\"></i>\n {{ 'Upload files' | translate }}\n </button>\n</c8y-action-bar-item>\n\n<c8y-help src=\"/docs/standard-tenant/managing-data/#file-repository\"></c8y-help>\n\n<div class=\"content-fullpage border-top border-bottom\">\n <c8y-data-grid\n [title]=\"title\"\n [loadMoreItemsLabel]=\"loadMoreItemsLabel\"\n [loadingItemsLabel]=\"loadingItemsLabel\"\n [displayOptions]=\"displayOptions\"\n [columns]=\"columns\"\n [pagination]=\"pagination\"\n [infiniteScroll]=\"infiniteScroll\"\n [serverSideDataCallback]=\"serverSideDataCallback\"\n [actionControls]=\"actionControls\"\n [selectable]=\"selectable\"\n [showSearch]=\"true\"\n [refresh]=\"refresh\"\n [bulkActionControls]=\"bulkActionControls\"\n >\n <c8y-ui-empty-state\n [icon]=\"stats?.size > 0 ? 'search' : 'c8y-archive'\"\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=\"{{ 'Upload file' | translate }}\"\n type=\"button\"\n (click)=\"openFileUploadComponent()\"\n >\n <i c8yIcon=\"plus-circle\"></i>\n {{ 'Upload file' | translate }}\n </button>\n </p>\n </c8y-ui-empty-state>\n\n <c8y-column name=\"name\">\n <ng-container *c8yCellRendererDef=\"let context\">\n <span title=\"{{ context.value }}\">\n <div class=\"d-flex j-c-between a-i-center\">\n {{ context.value }}\n <c8y-file-preview\n class=\"m-l-auto\"\n [mo]=\"context.item\"\n >\n <button\n class=\"btn btn-emphasis btn-icon\"\n [title]=\"'Preview file' | translate\"\n type=\"button\"\n customButton\n >\n <i c8yIcon=\"search\"></i>\n </button>\n </c8y-file-preview>\n </div>\n </span>\n </ng-container>\n </c8y-column>\n\n <c8y-column name=\"length\">\n <ng-container *c8yCellRendererDef=\"let context\">\n <span title=\"{{ context.value }} B\">\n {{ context.value | bytes }}\n </span>\n </ng-container>\n </c8y-column>\n\n <c8y-column name=\"lastUpdated\">\n <ng-container *c8yCellRendererDef=\"let context\">\n <span title=\"{{ context.value | c8yDate }}\">\n {{ context.value | c8yDate }}\n </span>\n </ng-container>\n </c8y-column>\n </c8y-data-grid>\n</div>\n" }]
}], ctorParameters: () => [{ type: i1.FilesRepositoryService }, { type: i2.InventoryBinaryService }, { type: i3.ModalService }, { type: i3.AlertService }, { type: i4.BsModalService }, { type: i3.FilesService }, { type: i5.TranslateService }], propDecorators: { dataGrid: [{
type: ViewChild,
args: [DataGridComponent, { static: true }]
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmlsZXMtcmVwb3NpdG9yeS5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9maWxlcy1yZXBvc2l0b3J5L2ZpbGVzLXJlcG9zaXRvcnkuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vZmlsZXMtcmVwb3NpdG9yeS9maWxlcy1yZXBvc2l0b3J5LmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxTQUFTLEVBQUUsWUFBWSxFQUFFLFNBQVMsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUNuRSxPQUFPLEVBQXdCLHNCQUFzQixFQUFFLE1BQU0sYUFBYSxDQUFDO0FBQzNFLE9BQU8sRUFFTCxZQUFZLEVBQ1osaUJBQWlCLEVBR2pCLGlCQUFpQixFQUdqQixZQUFZLEVBQ1osT0FBTyxFQUVQLFlBQVksRUFLWixNQUFNLEVBQ1AsTUFBTSxxQkFBcUIsQ0FBQztBQUM3QixPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQUN2RCxPQUFPLEVBQUUsY0FBYyxFQUFnQixNQUFNLHFCQUFxQixDQUFDO0FBQ25FLE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFDL0IsT0FBTyxFQUFFLElBQUksRUFBRSxTQUFTLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUNqRCxPQUFPLEVBQUUsOEJBQThCLEVBQUUsTUFBTSxxQ0FBcUMsQ0FBQztBQUNyRixPQUFPLEVBQUUsc0JBQXNCLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQzs7Ozs7Ozs7O0FBTXBFLE1BQU0sT0FBTyx3QkFBd0I7SUFzRG5DLFlBQ1Usc0JBQThDLEVBQzlDLHNCQUE4QyxFQUM5QyxZQUEwQixFQUMxQixZQUEwQixFQUMxQixjQUE4QixFQUM5QixXQUF5QixFQUN6QixnQkFBa0M7UUFObEMsMkJBQXNCLEdBQXRCLHNCQUFzQixDQUF3QjtRQUM5QywyQkFBc0IsR0FBdEIsc0JBQXNCLENBQXdCO1FBQzlD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a0JBSnBDLFNBQVM7K0JBQ0Usc0JBQXNCOzZRQUlnQixRQUFRO3NCQUF2RCxTQUFTO3VCQUFDLGlCQUFpQixFQUFFLEVBQUUsTUFBTSxFQUFFLElBQUksRUFBRSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENvbXBvbmVudCwgRXZlbnRFbWl0dGVyLCBWaWV3Q2hpbGQgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IElNYW5hZ2VkT2JqZWN0QmluYXJ5LCBJbnZlbnRvcnlCaW5hcnlTZXJ2aWNlIH0gZnJvbSAnQGM4eS9jbGllbnQnO1xuaW1wb3J0IHtcbiAgQWN0aW9uQ29udHJvbCxcbiAgQWxlcnRTZXJ2aWNlLFxuICBCdWlsdEluQWN0aW9uVHlwZSxcbiAgQnVsa0FjdGlvbkNvbnRyb2wsXG4gIENvbHVtbixcbiAgRGF0YUdyaWRDb21wb25lbnQsXG4gIERhdGFTb3VyY2VNb2RpZmllcixcbiAgRGlzcGxheU9wdGlvbnMsXG4gIEZpbGVzU2VydmljZSxcbiAgZ2V0dGV4dCxcbiAgTG9hZE1vcmVNb2RlLFxuICBNb2RhbFNlcnZpY2UsXG4gIFBhZ2luYXRpb24sXG4gIFJvdyxcbiAgU2VydmVyU2lkZURhdGFDYWxsYmFjayxcbiAgU2VydmVyU2lkZURhdGFSZXN1bHQsXG4gIFN0YXR1c1xufSBmcm9tICdAYzh5L25neC1jb21wb25lbnRzJztcbmltcG9ydCB7IFRyYW5zbGF0ZVNlcnZpY2UgfSBmcm9tICdAbmd4LXRyYW5zbGF0ZS9jb3JlJztcbmltcG9ydCB7IEJzTW9kYWxTZXJ2aWNlLCBNb2RhbE9wdGlvbnMgfSBmcm9tICduZ3gtYm9vdHN0cmFwL21vZGFsJztcbmltcG9ydCB7IFN1YmplY3QgfSBmcm9tICdyeGpzJztcbmltcG9ydCB7IHRha2UsIHRha2VVbnRpbCB9IGZyb20gJ3J4anMvb3BlcmF0b3JzJztcbmltcG9ydCB7IEZpbGVzUmVwb3NpdG9yeVVwbG9hZENvbXBvbmVudCB9IGZyb20gJy4vZmlsZXMtcmVwb3NpdG9yeS11cGxvYWQuY29tcG9uZW50JztcbmltcG9ydCB7IEZpbGVzUmVwb3NpdG9yeVNlcnZpY2UgfSBmcm9tICcuL2ZpbGVzLXJlcG9zaXRvcnkuc2VydmljZSc7XG5cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ2M4eS1maWxlcy1yZXBvc2l0b3J5JyxcbiAgdGVtcGxhdGVVcmw6ICcuL2ZpbGVzLXJlcG9zaXRvcnkuY29tcG9uZW50Lmh0bWwnXG59KVxuZXhwb3J0IGNsYXNzIEZpbGVzUmVwb3NpdG9yeUNvbXBvbmVudCB7XG4gIEBWaWV3Q2hpbGQoRGF0YUdyaWRDb21wb25lbnQsIHsgc3RhdGljOiB0cnVlIH0pIGRhdGFHcmlkOiBEYXRhR3JpZENvbXBvbmVudDtcbiAgZGVzdHJveSQ6IFN1YmplY3Q8Ym9vbGVhbj4gPSBuZXcgU3ViamVjdDxib29sZWFuPigpO1xuICB0aXRsZTogc3RyaW5nID0gZ2V0dGV4dCgnRmlsZXMgcmVwb3NpdG9yeScpO1xuICBtYW5hZ2VtZW50VGl0bGU6IHN0cmluZyA9IGdldHRleHQoJ01hbmFnZW1lbnQnKTtcbiAgbG9hZE1vcmVJdGVtc0xhYmVsOiBzdHJpbmcgPSBnZXR0ZXh0KCdMb2FkIG1vcmUgZmlsZXMnKTtcbiAgbG9hZGluZ0l0ZW1zTGFiZWw6IHN0cmluZyA9IGdldHRleHQoJ0xvYWRpbmcgZmlsZXPigKYnKTtcblxuICBpc0xvYWRpbmcgPSB0cnVlO1xuXG4gIGRpc3BsYXlPcHRpb25zOiBEaXNwbGF5T3B0aW9ucyA9IHtcbiAgICBib3JkZXJlZDogZmFsc2UsXG4gICAgc3RyaXBlZDogdHJ1ZSxcbiAgICBmaWx0ZXI6IHRydWUsXG4gICAgZ3JpZEhlYWRlcjogdHJ1ZSxcbiAgICBob3ZlcjogdHJ1ZVxuICB9O1xuXG4gIGNvbHVtbnM6IENvbHVtbltdID0gdGhpcy5maWxlc1JlcG9zaXRvcnlTZXJ2aWNlLmdldENvbHVtbnMoKTtcbiAgcGFnaW5hdGlvbjogUGFnaW5hdGlvbiA9IHRoaXMuZmlsZXNSZXBvc2l0b3J5U2VydmljZS5nZXRQYWdpbmF0aW9uKCk7XG4gIGluZmluaXRlU2Nyb2xsOiBMb2FkTW9yZU1vZGUgPSAnYXV0byc7XG4gIHNlcnZlclNpZGVEYXRhQ2FsbGJhY2s6IFNlcnZlclNpZGVEYXRhQ2FsbGJhY2s7XG4gIHJldHVybmVkRGF0YVNpemU6IG51bWJlcjtcbiAgc2VsZWN0YWJsZSA9IHRydWU7XG4gIGFjdGlvbkNvbnRyb2xzOiBBY3Rpb25Db250cm9sW10gPSBbXG4gICAge1xuICAgICAgdGV4dDogZ2V0dGV4dCgnRGVsZXRlJyksXG4gICAgICBpY29uOiAndHJhc2gnLFxuICAgICAgdHlwZTogQnVpbHRJbkFjdGlvblR5cGUuRGVsZXRlLFxuICAgICAgc2hvd0lmOiBzZWxlY3RlZEl0ZW0gPT5cbiAgICAgICAgIXRoaXMuZmlsZXNSZXBvc2l0b3J5U2VydmljZS5oYXNBcHBsaWNhdGlvblN0b3JhZ2VGcmFnbWVudChzZWxlY3RlZEl0ZW0pLFxuICAgICAgY2FsbGJhY2s6IHNlbGVjdGVkSXRlbSA9PiB0aGlzLm9uRGVsZXRlSXRlbShzZWxlY3RlZEl0ZW0pXG4gICAgfSxcbiAgICB7XG4gICAgICB0ZXh0OiBnZXR0ZXh0KCdEb3dubG9hZCcpLFxuICAgICAgaWNvbjogJ2Rvd25sb2FkJyxcbiAgICAgIHR5cGU6IEJ1aWx0SW5BY3Rpb25UeXBlLkV4cG9ydCxcbiAgICAgIGNhbGxiYWNrOiBzZWxlY3RlZEl0ZW0gPT4gdGhpcy5vbkRvd25sb2FkSXRlbShzZWxlY3RlZEl0ZW0gYXMgSU1hbmFnZWRPYmplY3RCaW5hcnkpXG4gICAgfVxuICBdO1xuICBidWxrQWN0aW9uQ29udHJvbHM6IEJ1bGtBY3Rpb25Db250cm9sW10gPSBbXG4gICAge1xuICAgICAgdHlwZTogQnVpbHRJbkFjdGlvblR5cGUuRGVsZXRlLFxuICAgICAgY2FsbGJhY2s6IHNlbGVjdGVkSXRlbUlkcyA9PiB0aGlzLm9uRGVsZXRlSXRlbXMoc2VsZWN0ZWRJdGVtSWRzKVxuICAgIH1cbiAgXTtcblxuICByZWZyZXNoOiBFdmVudEVtaXR0ZXI8dm9pZD4gPSBuZXcgRXZlbnRFbWl0dGVyPHZvaWQ+KCk7XG5cbiAgbm9SZXN1bHRzTWVzc2FnZSA9IGdldHRleHQoJ05vIHJlc3VsdHMgdG8gZGlzcGxheS4nKTtcbiAgbm9EYXRhTWVzc2FnZSA9IGdldHRleHQoJ05vIGZpbGVzIHRvIGRpc3BsYXkuJyk7XG4gIG5vUmVzdWx0c1N1YnRpdGxlID0gZ2V0dGV4dCgnUmVmaW5lIHlvdXIgc2VhcmNoIHRlcm1zIG9yIGNoZWNrIHlvdXIgc3BlbGxpbmcuJyk7XG4gIG5vRGF0YVN1YnRpdGxlID0gZ2V0dGV4dCgnQWRkIGEgbmV3IGZpbGUgYnkgY2xpY2tpbmcgYmVsb3cuJyk7XG5cbiAgY29uc3RydWN0b3IoXG4gICAgcHJpdmF0ZSBmaWxlc1JlcG9zaXRvcnlTZXJ2aWNlOiBGaWxlc1JlcG9zaXRvcnlTZXJ2aWNlLFxuICAgIHByaXZhdGUgaW52ZW50b3J5QmluYXJ5U2VydmljZTogSW52ZW50b3J5QmluYXJ5U2VydmljZSxcbiAgICBwcml2YXRlIG1vZGFsU2VydmljZTogTW9kYWxTZXJ2aWNlLFxuICAgIHByaXZhdGUgYWxlcnRTZXJ2aWNlOiBBbGVydFNlcnZpY2UsXG4gICAgcHJpdmF0ZSBic01vZGFsU2VydmljZTogQnNNb2RhbFNlcnZpY2UsXG4gICAgcHJpdmF0ZSBmaWxlU2VydmljZTogRmlsZXNTZXJ2aWNlLFxuICAgIHByaXZhdGUgdHJhbnNsYXRlU2VydmljZTogVHJhbnNsYXRlU2VydmljZVxuICApIHtcbiAgICAvLyB3ZSdyZSBzZXR0aW5nIHVwIGBzZXJ2ZXJTaWRlRGF0YUNhbGxiYWNrYCB0byBleGVjdXRlIGEgbWV0aG9kIGZyb20gdGhpcyBjb21wb25lbnQgd2l0aCBib3VuZCBgdGhpc2BcbiAgICB0aGlzLnNlcnZlclNpZGVEYXRhQ2FsbGJhY2sgPSB0aGlzLm9uRGF0YVNvdXJjZU1vZGlmaWVyLmJpbmQodGhpcyk7XG4gIH1cblxuICBhc3luYyBvbkRhdGFTb3VyY2VNb2RpZmllcihcbiAgICBkYXRhU291cmNlTW9kaWZpZXI6IERhdGFTb3VyY2VNb2RpZmllclxuICApOiBQcm9taXNlPFNlcnZlclNpZGVEYXRhUmVzdWx0PiB7XG4gICAgY29uc3QgeyByZXMsIGRhdGEsIHBhZ2luZyB9ID0gYXdhaXQgdGhpcy5maWxlc1JlcG9zaXRvcnlTZXJ2aWNlLmdldERhdGEoXG4gICAgICBkYXRhU291cmNlTW9kaWZpZXIuY29sdW1ucyxcbiAgICAgIGRhdGFTb3VyY2VNb2RpZmllci5wYWdpbmF0aW9uLFxuICAgICAgZGF0YVNvdXJjZU1vZGlmaWVyLnNlYXJjaFRleHRcbiAgICApO1xuICAgIGNvbnN0IGZpbHRlcmVkU2l6ZTogbnVtYmVyID0gcGFnaW5nLnRvdGFsRWxlbWVudHM7XG4gICAgY29uc3Qgc2l6ZTogbnVtYmVyID0gYXdhaXQgdGhpcy5maWxlc1JlcG9zaXRvcnlTZXJ2aWNlLmdldFRvdGFsKCk7XG5cbiAgICBjb25zdCBzZXJ2ZXJTaWRlRGF0YVJlc3VsdDogU2VydmVyU2lkZURhdGFSZXN1bHQgPSB7IHJlcywgZGF0YSwgcGFnaW5nLCBmaWx0ZXJlZFNpemUsIHNpemUgfTtcbiAgICB0aGlzLmlzTG9hZGluZyA9IGZhbHNlO1xuICAgIHRoaXMucmV0dXJuZWREYXRhU2l6ZSA9IHNlcnZlclNpZGVEYXRhUmVzdWx0LnNpemU7XG5cbiAgICByZXR1cm4gc2VydmVyU2lkZURhdGFSZXN1bHQ7XG4gIH1cblxuICBhc3luYyBvbkRlbGV0ZUl0ZW0oc2VsZWN0ZWRJdGVtOiBSb3cpIHtcbiAgICByZXR1cm4gdGhpcy5kZWxldGVJdGVtc1dpdGhDb25maXJtYXRpb24oW3NlbGVjdGVkSXRlbS5pZF0sIHtcbiAgICAgIHRpdGxlOiBnZXR0ZXh0KCdEZWxldGUgZmlsZScpLFxuICAgICAgYm9keTogdGhpcy50cmFuc2xhdGVTZXJ2aWNlLmluc3RhbnQoXG4gICAgICAgIGdldHRleHQoJ1lvdSBhcmUgYWJvdXQgdG8gZGVsZXRlIGZpbGUgXCJ7eyBuYW1lIH19XCIuIERvIHlvdSB3YW50IHRvIHByb2NlZWQ/JyksXG4gICAgICAgIHNlbGVjdGVkSXRlbVxuICAgICAgKSxcbiAgICAgIHN1Y2Nlc3NUZXh0OiBnZXR0ZXh0KCdGaWxlIGRlbGV0ZWQuJylcbiAgICB9KTtcbiAgfVxuXG4gIGFzeW5jIG9uRGVsZXRlSXRlbXMoc2VsZWN0ZWRJdGVtc0lkczogc3RyaW5nW10pIHtcbiAgICBjb25zdCBkYXRhR3JpZERhdGFTb3VyY2VEYXRhID0gYXdhaXQgdGhpcy5kYXRhR3JpZC5kYXRhU291cmNlLmRhdGEkLnBpcGUodGFrZSgxKSkudG9Qcm9taXNlKCk7XG4gICAgY29uc3QgZGVsZXRhYmxlSXRlbXNJZHMgPSB0aGlzLmZpbGVzUmVwb3NpdG9yeVNlcnZpY2UuZ2V0RGVsZXRhYmxlSXRlbXNJZHMoXG4gICAgICBzZWxlY3RlZEl0ZW1zSWRzLFxuICAgICAgZGF0YUdyaWREYXRhU291cmNlRGF0YVxuICAgICk7XG4gICAgbGV0IGJvZHk6IHN0cmluZztcbiAgICBpZiAoZGVsZXRhYmxlSXRlbXNJZHMubGVuZ3RoIDwgc2VsZWN0ZWRJdGVtc0lkcy5sZW5ndGgpIHtcbiAgICAgIGJvZHkgPSBnZXR0ZXh0KGBcbiAgICAgICAgWW91IGFyZSBhYm91dCB0byBkZWxldGUgdGhlIHNlbGVjdGVkIGZpbGVzLlxuICAgICAgICBOb3RlOiB0aGUgc2VsZWN0ZWQgZmlsZXMgb2YgdHlwZSBcImM4eV9hcHBsaWNhdGlvbnNfc3RvcmFnZV8qXCIgd29uJ3QgYmUgZGVsZXRlZCB0aG91Z2hcbiAgICAgICAgLSBzdWNoIGZpbGVzIGNhbiBiZSBkZWxldGVkIG9ubHkgZnJvbSB0aGUgXCJBY3Rpdml0eSBsb2dcIiBvZiB0aGUgYXNzb2NpYXRlZCBhcHBsaWNhdGlvbi5cbiAgICAgICAgRG8geW91IHdhbnQgdG8gcHJvY2VlZD9cbiAgICAgIGApO1xuICAgIH0gZWxzZSB7XG4gICAgICBib2R5ID0gZ2V0dGV4dCgnWW91IGFyZSBhYm91dCB0byBkZWxldGUgdGhlIHNlbGVjdGVkIGZpbGVzLiBEbyB5b3Ugd2FudCB0byBwcm9jZWVkPycpO1xuICAgIH1cblxuICAgIHJldHVybiB0aGlzLmRlbGV0ZUl0ZW1zV2l0aENvbmZpcm1hdGlvbihkZWxldGFibGVJdGVtc0lkcywge1xuICAgICAgdGl0bGU6IGdldHRleHQoJ0RlbGV0ZSBmaWxlcycpLFxuICAgICAgYm9keSxcbiAgICAgIHN1Y2Nlc3NUZXh0OiBnZXR0ZXh0KCdGaWxlcyBkZWxldGVkLicpXG4gICAgfSk7XG4gIH1cblxuICBhc3luYyBvbkRvd25sb2FkSXRlbShzZWxlY3RlZEl0ZW06IElNYW5hZ2VkT2JqZWN0QmluYXJ5KSB7XG4gICAgcmV0dXJuIHRoaXMuZmlsZVNlcnZpY2UuZG93bmxvYWQoc2VsZWN0ZWRJdGVtKTtcbiAgfVxuXG4gIG9wZW5GaWxlVXBsb2FkQ29tcG9uZW50KCkge1xuICAgIGNvbnN0IG1vZGFsT3B0aW9uczogTW9kYWxPcHRpb25zPEZpbGVzUmVwb3NpdG9yeVVwbG9hZENvbXBvbmVudD4gPSB7XG4gICAgICBjbGFzczogJ21vZGFsLXNtJyxcbiAgICAgIGFyaWFEZXNjcmliZWRieTogJ21vZGFsLWJvZHknLFxuICAgICAgYXJpYUxhYmVsbGVkQnk6ICdtb2RhbC10aXRsZScsXG4gICAgICBpZ25vcmVCYWNrZHJvcENsaWNrOiB0cnVlXG4gICAgfTtcbiAgICBjb25zdCBtb2RhbFJlZiA9IHRoaXMuYnNNb2RhbFNlcnZpY2Uuc2hvdyhGaWxlc1JlcG9zaXRvcnlVcGxvYWRDb21wb25lbnQsIG1vZGFsT3B0aW9ucyk7XG4gICAgbW9kYWxSZWYuY29udGVudC5vbkNsb3NlLnBpcGUodGFrZVVudGlsKHRoaXMuZGVzdHJveSQpKS5zdWJzY3JpYmUoKHsgdXBsb2FkZWQgfSkgPT4ge1xuICAgICAgaWYgKHVwbG9hZGVkKSB7XG4gICAgICAgIHRoaXMucmVmcmVzaC5lbWl0KCk7XG4gICAgICB9XG4gICAgICBtb2RhbFJlZi5oaWRlKCk7XG4gICAgfSk7XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIGRlbGV0ZUl0ZW1zV2l0aENvbmZpcm1hdGlvbihcbiAgICBzZWxlY3RlZEl0ZW1zSWRzOiBzdHJpbmdbXSxcbiAgICBvcHRpb25zOiB7IHRpdGxlOiBzdHJpbmc7IGJvZHk6IHN0cmluZzsgc3VjY2Vzc1RleHQ6IHN0cmluZyB9XG4gICkge1xuICAgIHRyeSB7XG4gICAgICBhd2FpdCB0aGlzLmNvbmZpcm1JdGVtc0RlbGV0aW9uKG9wdGlvbnMpO1xuICAgICAgdGhpcy5pc0xvYWRpbmcgPSB0cnVlO1xuICAgICAgY29uc3QgcHJvbWlzZXMgPSBzZWxlY3RlZEl0ZW1zSWRzLm1hcChzZWxlY3RlZEl0ZW1JZCA9PlxuICAgICAgICB0aGlzLmludmVudG9yeUJpbmFyeVNlcnZpY2UuZGVsZXRlKHNlbGVjdGVkSXRlbUlkKVxuICAgICAgKTtcbiAgICAgIGF3YWl0IFByb21pc2UuYWxsKHByb21pc2VzKTtcbiAgICAgIHRoaXMuYWxlcnRTZXJ2aWNlLnN1Y2Nlc3Mob3B0aW9ucy5zdWNjZXNzVGV4dCk7XG4gICAgICB0aGlzLnJlZnJlc2gubmV4dCgpO1xuICAgIH0gY2F0Y2ggKGV4KSB7XG4gICAgICBpZiAoZXgpIHtcbiAgICAgICAgdGhpcy5hbGVydFNlcnZpY2UuYWRkU2VydmVyRmFpbHVyZShleCk7XG4gICAgICB9XG4gICAgfSBmaW5hbGx5IHtcbiAgICAgIHRoaXMuaXNMb2FkaW5nID0gZmFsc2U7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBjb25maXJtSXRlbXNEZWxldGlvbih7IHRpdGxlLCBib2R5IH06IHsgdGl0bGU6IHN0cmluZzsgYm9keTogc3RyaW5nIH0pIHtcbiAgICBjb25zdCBzdGF0dXMgPSBTdGF0dXMuREFOR0VSO1xuICAgIGNvbnN0IGxhYmVscyA9IHsgb2s6IGdldHRleHQoJ0RlbGV0ZScpLCBjYW5jZWw6IGdldHRleHQoJ0NhbmNlbCcpIH07XG4gICAgYXdhaXQgdGhpcy5tb2RhbFNlcnZpY2UuY29uZmlybSh0aXRsZSwgYm9keSwgc3RhdHVzLCBsYWJlbHMpO1xuICB9XG59XG4iLCI8Yzh5LXRpdGxlPlxuICB7eyB0aXRsZSB8IHRyYW5zbGF0ZSB9fVxuPC9jOHktdGl0bGU+XG5cbjxjOHktYnJlYWRjcnVtYj5cbiAgPGM4eS1icmVhZGNydW1iLWl0ZW1cbiAgICBpY29uPVwiYzh5LW1hbmFnZW1lbnRcIlxuICAgIFtsYWJlbF09XCJtYW5hZ2VtZW50VGl0bGUgfCB0cmFuc2xhdGVcIlxuICA+PC9jOHktYnJlYWRjcnVtYi1pdGVtPlxuICA8Yzh5LWJyZWFkY3J1bWItaXRlbSBbbGFiZWxdPVwidGl0bGUgfCB0cmFuc2xhdGVcIj48L2M4eS1icmVhZGNydW1iLWl0ZW0+XG48L2M4eS1icmVhZGNydW1iPlxuXG48Yzh5LWFjdGlvbi1iYXItaXRlbSBbcGxhY2VtZW50XT1cIidyaWdodCdcIj5cbiAgPGJ1dHRvblxuICAgIGNsYXNzPVwiYnRuIGJ0bi1saW5rXCJcbiAgICB0aXRsZT1cInt7ICdVcGxvYWQgZmlsZXMnIHwgdHJhbnNsYXRlIH19XCJcbiAgICAqYzh5SWZBbGxvd2VkPVwiWydST0xFX0lOVkVOVE9SWV9BRE1JTicsICdST0xFX0lOVkVOVE9SWV9DUkVBVEUnXTsgYWxsb3dBbnk6IHRydWVcIlxuICAgIChjbGljayk9XCJvcGVuRmlsZVVwbG9hZENvbXBvbmVudCgpXCJcbiAgICBkYXRhLWN5PVwiYzh5LWZpbGVzLXJlcG9zaXRvcnktLW9wZW4tZmlsZS11cGxvYWQtY29tcG9uZW50XCJcbiAgPlxuICAgIDxpIGM4eUljb249XCJ1cGxvYWRcIj48L2k+XG4gICAge3sgJ1VwbG9hZCBmaWxlcycgfCB0cmFuc2xhdGUgfX1cbiAgPC9idXR0b24+XG48L2M4eS1hY3Rpb24tYmFyLWl0ZW0+XG5cbjxjOHktaGVscCBzcmM9XCIvZG9jcy9zdGFuZGFyZC10ZW5hbnQvbWFuYWdpbmctZGF0YS8jZmlsZS1yZXBvc2l0b3J5XCI+PC9jOHktaGVscD5cblxuPGRpdiBjbGFzcz1cImNvbnRlbnQtZnVsbHBhZ2UgYm9yZGVyLXRvcCBib3JkZXItYm90dG9tXCI+XG4gIDxjOHktZGF0YS1ncmlkXG4gICAgW3RpdGxlXT1cInRpdGxlXCJcbiAgICBbbG9hZE1vcmVJdGVtc0xhYmVsXT1cImxvYWRNb3JlSXRlbXNMYWJlbFwiXG4gICAgW2xvYWRpbmdJdGVtc0xhYmVsXT1cImxvYWRpbmdJdGVtc0xhYmVsXCJcbiAgICBbZGlzcGxheU9wdGlvbnNdPVwiZGlzcGxheU9wdGlvbnNcIlxuICAgIFtjb2x1bW5zXT1cImNvbHVtbnNcIlxuICAgIFtwYWdpbmF0aW9uXT1cInBhZ2luYXRpb25cIlxuICAgIFtpbmZpbml0ZVNjcm9sbF09XCJpbmZpbml0ZVNjcm9sbFwiXG4gICAgW3NlcnZlclNpZGVEYXRhQ2FsbGJhY2tdPVwic2VydmVyU2lkZURhdGFDYWxsYmFja1wiXG4gICAgW2FjdGlvbkNvbnRyb2xzXT1cImFjdGlvbkNvbnRyb2xzXCJcbiAgICBbc2VsZWN0YWJsZV09XCJzZWxlY3RhYmxlXCJcbiAgICBbc2hvd1NlYXJjaF09XCJ0cnVlXCJcbiAgICBbcmVmcmVzaF09XCJyZWZyZXNoXCJcbiAgICBbYnVsa0FjdGlvbkNvbnRyb2xzXT1cImJ1bGtBY3Rpb25Db250cm9sc1wiXG4gID5cbiAgICA8Yzh5LXVpLWVtcHR5LXN0YXRlXG4gICAgICBbaWNvbl09XCJzdGF0cz8uc2l6ZSA+IDAgPyAnc2VhcmNoJyA6ICdjOHktYXJjaGl2ZSdcIlxuICAgICAgW3RpdGxlXT1cInN0YXRzPy5zaXplID4gMCA/IChub1Jlc3VsdHNNZXNzYWdlIHwgdHJhbnNsYXRlKSA6IChub0RhdGFNZXNzYWdlIHwgdHJhbnNsYXRlKVwiXG4gICAgICBbc3VidGl0bGVdPVwic3RhdHM/LnNpemUgPiAwID8gKG5vUmVzdWx0c1N1YnRpdGxlIHwgdHJhbnNsYXRlKSA6IChub0RhdGFTdWJ0aXRsZSB8IHRyYW5zbGF0ZSlcIlxuICAgICAgKmVtcHR5U3RhdGVDb250ZXh0PVwibGV0IHN0YXRzXCJcbiAgICAgIFtob3Jpem9udGFsXT1cInN0YXRzPy5zaXplID4gMFwiXG4gICAgPlxuICAgICAgPHAgKm5nSWY9XCJzdGF0cz8uc2l6ZSA9PT0gMFwiPlxuICAgICAgICA8YnV0dG9uXG4gICAgICAgICAgY2xhc3M9XCJidG4gYnRuLXByaW1hcnlcIlxuICAgICAgICAgIHRpdGxlPVwie3sgJ1VwbG9hZCBmaWxlJyB8IHRyYW5zbGF0ZSB9fVwiXG4gICAgICAgICAgdHlwZT1cImJ1dHRvblwiXG4gICAgICAgICAgKGNsaWNrKT1cIm9wZW5GaWxlVXBsb2FkQ29tcG9uZW50KClcIlxuICAgICAgICA+XG4gICAgICAgICAgPGkgYzh5SWNvbj1cInBsdXMtY2lyY2xlXCI+PC9pPlxuICAgICAgICAgIHt7ICdVcGxvYWQgZmlsZScgfCB0cmFuc2xhdGUgfX1cbiAgICAgICAgPC9idXR0b24+XG4gICAgICA8L3A+XG4gICAgPC9jOHktdWktZW1wdHktc3RhdGU+XG5cbiAgICA8Yzh5LWNvbHVtbiBuYW1lPVwibmFtZVwiPlxuICAgICAgPG5nLWNvbnRhaW5lciAqYzh5Q2VsbFJlbmRlcmVyRGVmPVwibGV0IGNvbnRleHRcIj5cbiAgICAgICAgPHNwYW4gdGl0bGU9XCJ7eyBjb250ZXh0LnZhbHVlIH19XCI+XG4gICAgICAgICAgPGRpdiBjbGFzcz1cImQtZmxleCBqLWMtYmV0d2VlbiBhLWktY2VudGVyXCI+XG4gICAgICAgICAgICB7eyBjb250ZXh0LnZhbHVlIH19XG4gICAgICAgICAgICA8Yzh5LWZpbGUtcHJldmlld1xuICAgICAgICAgICAgICBjbGFzcz1cIm0tbC1hdXRvXCJcbiAgICAgICAgICAgICAgW21vXT1cImNvbnRleHQuaXRlbVwiXG4gICAgICAgICAgICA+XG4gICAgICAgICAgICAgIDxidXR0b25cbiAgICAgICAgICAgICAgICBjbGFzcz1cImJ0biBidG4tZW1waGFzaXMgYnRuLWljb25cIlxuICAgICAgICAgICAgICAgIFt0aXRsZV09XCInUHJldmlldyBmaWxlJyB8IHRyYW5zbGF0ZVwiXG4gICAgICAgICAgICAgICAgdHlwZT1cImJ1dHRvblwiXG4gICAgICAgICAgICAgICAgY3VzdG9tQnV0dG9uXG4gICAgICAgICAgICAgID5cbiAgICAgICAgICAgICAgICA8aSBjOHlJY29uPVwic2VhcmNoXCI+PC9pPlxuICAgICAgICAgICAgICA8L2J1dHRvbj5cbiAgICAgICAgICAgIDwvYzh5LWZpbGUtcHJldmlldz5cbiAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgPC9zcGFuPlxuICAgICAgPC9uZy1jb250YWluZXI+XG4gICAgPC9jOHktY29sdW1uPlxuXG4gICAgPGM4eS1jb2x1bW4gbmFtZT1cImxlbmd0aFwiPlxuICAgICAgPG5nLWNvbnRhaW5lciAqYzh5Q2VsbFJlbmRlcmVyRGVmPVwibGV0IGNvbnRleHRcIj5cbiAgICAgICAgPHNwYW4gdGl0bGU9XCJ7eyBjb250ZXh0LnZhbHVlIH19IEJcIj5cbiAgICAgICAgICB7eyBjb250ZXh0LnZhbHVlIHwgYnl0ZXMgfX1cbiAgICAgICAgPC9zcGFuPlxuICAgICAgPC9uZy1jb250YWluZXI+XG4gICAgPC9jOHktY29sdW1uPlxuXG4gICAgPGM4eS1jb2x1bW4gbmFtZT1cImxhc3RVcGRhdGVkXCI+XG4gICAgICA8bmctY29udGFpbmVyICpjOHlDZWxsUmVuZGVyZXJEZWY9XCJsZXQgY29udGV4dFwiPlxuICAgICAgICA8c3BhbiB0aXRsZT1cInt7IGNvbnRleHQudmFsdWUgfCBjOHlEYXRlIH19XCI+XG4gICAgICAgICAge3sgY29udGV4dC52YWx1ZSB8IGM4eURhdGUgfX1cbiAgICAgICAgPC9zcGFuPlxuICAgICAgPC9uZy1jb250YWluZXI+XG4gICAgPC9jOHktY29sdW1uPlxuICA8L2M4eS1kYXRhLWdyaWQ+XG48L2Rpdj5cbiJdfQ==