@notiz/ngx-tablo
Version:
JSON powered material table for Angular
423 lines (415 loc) • 39.8 kB
JavaScript
import { CommonModule } from '@angular/common';
import { Component, computed, effect, input, model, output, viewChild, } from '@angular/core';
import { MatPaginator, MatPaginatorModule, } from '@angular/material/paginator';
import { MatSort, MatSortModule, } from '@angular/material/sort';
import { MatTableDataSource, MatTableModule } from '@angular/material/table';
import { Observable, Subject, takeUntil } from 'rxjs';
import { CellValuePipe } from './cell-value.pipe';
import { HasCellValuePipe } from './has-cell-value.pipe';
import { NestedColumnNamePipe } from './nested-column-name.pipe';
import * as i0 from "@angular/core";
import * as i1 from "@angular/common";
import * as i2 from "@angular/material/table";
import * as i3 from "@angular/material/paginator";
import * as i4 from "@angular/material/sort";
export class Tablo {
constructor() {
this.tableClasses = input('');
/**
* Add custom dataSource.
*
* Default: MatTableDataSource
*/
this.dataSource = input(new MatTableDataSource());
this.data = model();
this.columns = input([]);
this.displayedColumns = computed(() => this.columns().map((column) => column.columnName));
this.mode = input('client');
/**
* Sorting
*/
this.sortActive = model('');
this.sortDirection = model('');
/**
* Custom sorting function for `MatTableDataSource`.
*
* Use this if data properties don't match column names or for complex data objects.
*
* Default expects column `xyz` to represent `data['xyz']`.
*
*/
this.sortingDataAccessor = input();
/**
* Filter value for `MatTableDataSource`.
*/
this.filter = input();
/**
* Custom filter function for `MatTableDataSource`.
*/
this.filterPredicate = input();
/**
* Paging
*/
this.showPaging = model(false);
this.pagingDisabled = model(false);
this.hidePageSize = model(false);
this.showFirstLastButtons = model(true);
this.pageSize = model(0);
this.pageIndex = model(0);
this.length = model(0);
this.pageSizeOptions = model([10, 20, 50, 100]);
this.pageAriaLabel = model('Select page');
/**
* default to false
*/
this.resetPageOnSort = model(false);
/**
* Outputs
*/
this.rowClick = output();
this.pageChange = output();
this.sortChange = output();
this.paginator = viewChild(MatPaginator);
this.sort = viewChild.required(MatSort);
this.destroy$ = new Subject();
effect(() => {
this.fillData();
}, { allowSignalWrites: true });
effect(() => {
const filter = this.filter();
if (this.dataSource() instanceof MatTableDataSource) {
this.getMatTableDataSource().filter = filter || '';
}
}, { allowSignalWrites: true });
}
ngOnInit() {
this.columns().forEach((column) => {
if (column.lifecycle?.onInit) {
column.lifecycle.onInit(column);
}
});
if (this.dataSource() instanceof MatTableDataSource) {
if (this.filterPredicate()) {
this.getMatTableDataSource().filterPredicate = this.filterPredicate();
}
if (this.sortingDataAccessor()) {
this.getMatTableDataSource().sortingDataAccessor =
this.sortingDataAccessor();
}
}
}
ngAfterViewInit() {
this.columns().forEach((column) => {
if (column.lifecycle?.afterViewInit) {
column.lifecycle.afterViewInit(column);
}
});
this.sort().sortChange.subscribe((sort) => {
this.sortChange.emit(sort);
if (this.resetPageOnSort()) {
this.firstPage();
}
});
if (this.paginator()) {
this.paginator().page.subscribe((page) => this.pageChange.emit(page));
}
if (this.mode() === 'client' &&
this.dataSource() instanceof MatTableDataSource) {
this.getMatTableDataSource().paginator = this.paginator();
this.getMatTableDataSource().sort = this.sort();
}
}
ngOnDestroy() {
this.destroy$.next();
this.destroy$.complete();
}
firstPage() {
if (this.paginator()) {
this.paginator().firstPage();
}
}
lastPage() {
if (this.paginator()) {
this.paginator().lastPage();
}
}
clearFilter() {
if (this.dataSource() instanceof MatTableDataSource) {
this.getMatTableDataSource().filter = '';
}
}
fillData() {
if (this.data() && this.dataSource() instanceof MatTableDataSource) {
if (this.data() instanceof Observable) {
this.data()
.pipe(takeUntil(this.destroy$))
.subscribe((data) => (this.getMatTableDataSource().data = data));
}
else {
this.getMatTableDataSource().data = this.data();
}
}
}
getMatTableDataSource() {
return this.dataSource();
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.8", ngImport: i0, type: Tablo, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.8", type: Tablo, isStandalone: true, selector: "ngx-tablo", inputs: { tableClasses: { classPropertyName: "tableClasses", publicName: "tableClasses", isSignal: true, isRequired: false, transformFunction: null }, dataSource: { classPropertyName: "dataSource", publicName: "dataSource", isSignal: true, isRequired: false, transformFunction: null }, data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: false, transformFunction: null }, mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null }, sortActive: { classPropertyName: "sortActive", publicName: "sortActive", isSignal: true, isRequired: false, transformFunction: null }, sortDirection: { classPropertyName: "sortDirection", publicName: "sortDirection", isSignal: true, isRequired: false, transformFunction: null }, sortingDataAccessor: { classPropertyName: "sortingDataAccessor", publicName: "sortingDataAccessor", isSignal: true, isRequired: false, transformFunction: null }, filter: { classPropertyName: "filter", publicName: "filter", isSignal: true, isRequired: false, transformFunction: null }, filterPredicate: { classPropertyName: "filterPredicate", publicName: "filterPredicate", isSignal: true, isRequired: false, transformFunction: null }, showPaging: { classPropertyName: "showPaging", publicName: "showPaging", isSignal: true, isRequired: false, transformFunction: null }, pagingDisabled: { classPropertyName: "pagingDisabled", publicName: "pagingDisabled", isSignal: true, isRequired: false, transformFunction: null }, hidePageSize: { classPropertyName: "hidePageSize", publicName: "hidePageSize", isSignal: true, isRequired: false, transformFunction: null }, showFirstLastButtons: { classPropertyName: "showFirstLastButtons", publicName: "showFirstLastButtons", isSignal: true, isRequired: false, transformFunction: null }, pageSize: { classPropertyName: "pageSize", publicName: "pageSize", isSignal: true, isRequired: false, transformFunction: null }, pageIndex: { classPropertyName: "pageIndex", publicName: "pageIndex", isSignal: true, isRequired: false, transformFunction: null }, length: { classPropertyName: "length", publicName: "length", isSignal: true, isRequired: false, transformFunction: null }, pageSizeOptions: { classPropertyName: "pageSizeOptions", publicName: "pageSizeOptions", isSignal: true, isRequired: false, transformFunction: null }, pageAriaLabel: { classPropertyName: "pageAriaLabel", publicName: "pageAriaLabel", isSignal: true, isRequired: false, transformFunction: null }, resetPageOnSort: { classPropertyName: "resetPageOnSort", publicName: "resetPageOnSort", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { data: "dataChange", sortActive: "sortActiveChange", sortDirection: "sortDirectionChange", showPaging: "showPagingChange", pagingDisabled: "pagingDisabledChange", hidePageSize: "hidePageSizeChange", showFirstLastButtons: "showFirstLastButtonsChange", pageSize: "pageSizeChange", pageIndex: "pageIndexChange", length: "lengthChange", pageSizeOptions: "pageSizeOptionsChange", pageAriaLabel: "pageAriaLabelChange", resetPageOnSort: "resetPageOnSortChange", rowClick: "rowClick", pageChange: "pageChange", sortChange: "sortChange" }, viewQueries: [{ propertyName: "paginator", first: true, predicate: MatPaginator, descendants: true, isSignal: true }, { propertyName: "sort", first: true, predicate: MatSort, descendants: true, isSignal: true }], ngImport: i0, template: `
<table
[class]="tableClasses()"
mat-table
[dataSource]="dataSource()"
matSort
[matSortActive]="sortActive()"
[matSortDirection]="sortDirection()"
>
(column of columns(); track column; let i = $index) {
<ng-container [matColumnDef]="column.columnName">
<th
mat-header-cell
[mat-sort-header]="column.sortHeader || column.columnName"
[disabled]="!column.sort"
*matHeaderCellDef
>
(column.headerTemplate; as content) {
<ng-container
[ngTemplateOutlet]="headerContentTemplate"
[ngTemplateOutletContext]="{
content: content,
column: column
}"
></ng-container>
} {
(
(column.headerHTMLContent &&
column.headerHTMLContent(column)) ||
column.header;
as content
) {
<div
[class]="column.headerClassName"
[innerHTML]="content"
></div>
}
}
</th>
<td mat-cell *matCellDef="let row">
(row | hasCellValue: column; as content) {
<ng-container
[ngTemplateOutlet]="cellContentTemplate"
[ngTemplateOutletContext]="{
content: row | cellValue: column,
row: row,
className: column.className,
format: column.format
}"
>
</ng-container>
}
</td>
</ng-container>
}
<tr mat-header-row *matHeaderRowDef="displayedColumns()"></tr>
<tr
mat-row
*matRowDef="let row; columns: displayedColumns()"
(click)="rowClick.emit(row)"
></tr>
</table>
(showPaging()) {
<mat-paginator
[disabled]="pagingDisabled()"
[hidePageSize]="hidePageSize()"
[pageSizeOptions]="pageSizeOptions()"
[pageSize]="pageSize()"
[pageIndex]="pageIndex()"
[length]="length()"
[showFirstLastButtons]="showFirstLastButtons()"
[attr.aria-label]="pageAriaLabel()"
>
</mat-paginator>
}
<ng-template
#headerContentTemplate
let-content="content"
let-column="column"
>
<ng-container
[ngTemplateOutlet]="content"
[ngTemplateOutletContext]="{ column: column }"
></ng-container>
</ng-template>
<ng-template
#cellContentTemplate
let-content="content"
let-row="row"
let-className="className"
let-format="format"
>
(!content.createEmbeddedView) {
(format) {
<div [class]="className">
<!-- NOTE: each specified format will be displayed currently -->
(format.date) {
{{ content | date: format.date }}
}
(format.decimal) {
{{ content | number: format.decimal }}
}
(format.percent) {
{{ content | percent: format.percent }}
}
(format.currency) {
{{ content | currency: format.currency }}
}
(format.titleCase) {
{{ content | titlecase }}
}
</div>
} {
<div [class]="className" [innerHTML]="content"></div>
}
} {
<ng-container
[ngTemplateOutlet]="content"
[ngTemplateOutletContext]="{ row: row }"
></ng-container>
}
</ng-template>
`, isInline: true, styles: ["table{width:100%}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "pipe", type: i1.DecimalPipe, name: "number" }, { kind: "pipe", type: i1.PercentPipe, name: "percent" }, { kind: "pipe", type: i1.TitleCasePipe, name: "titlecase" }, { kind: "pipe", type: i1.CurrencyPipe, name: "currency" }, { kind: "pipe", type: i1.DatePipe, name: "date" }, { kind: "ngmodule", type: MatTableModule }, { kind: "component", type: i2.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { kind: "directive", type: i2.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { kind: "directive", type: i2.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { kind: "directive", type: i2.MatColumnDef, selector: "[matColumnDef]", inputs: ["matColumnDef"] }, { kind: "directive", type: i2.MatCellDef, selector: "[matCellDef]" }, { kind: "directive", type: i2.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { kind: "directive", type: i2.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { kind: "directive", type: i2.MatCell, selector: "mat-cell, td[mat-cell]" }, { kind: "component", type: i2.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { kind: "component", type: i2.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }, { kind: "ngmodule", type: MatPaginatorModule }, { kind: "component", type: i3.MatPaginator, selector: "mat-paginator", inputs: ["color", "pageIndex", "length", "pageSize", "pageSizeOptions", "hidePageSize", "showFirstLastButtons", "selectConfig", "disabled"], outputs: ["page"], exportAs: ["matPaginator"] }, { kind: "ngmodule", type: MatSortModule }, { kind: "directive", type: i4.MatSort, selector: "[matSort]", inputs: ["matSortActive", "matSortStart", "matSortDirection", "matSortDisableClear", "matSortDisabled"], outputs: ["matSortChange"], exportAs: ["matSort"] }, { kind: "component", type: i4.MatSortHeader, selector: "[mat-sort-header]", inputs: ["mat-sort-header", "arrowPosition", "start", "disabled", "sortActionDescription", "disableClear"], exportAs: ["matSortHeader"] }, { kind: "pipe", type: HasCellValuePipe, name: "hasCellValue" }, { kind: "pipe", type: CellValuePipe, name: "cellValue" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.8", ngImport: i0, type: Tablo, decorators: [{
type: Component,
args: [{ selector: 'ngx-tablo', standalone: true, imports: [
CommonModule,
MatTableModule,
MatPaginatorModule,
MatSortModule,
NestedColumnNamePipe,
HasCellValuePipe,
CellValuePipe,
], template: `
<table
[class]="tableClasses()"
mat-table
[dataSource]="dataSource()"
matSort
[matSortActive]="sortActive()"
[matSortDirection]="sortDirection()"
>
(column of columns(); track column; let i = $index) {
<ng-container [matColumnDef]="column.columnName">
<th
mat-header-cell
[mat-sort-header]="column.sortHeader || column.columnName"
[disabled]="!column.sort"
*matHeaderCellDef
>
(column.headerTemplate; as content) {
<ng-container
[ngTemplateOutlet]="headerContentTemplate"
[ngTemplateOutletContext]="{
content: content,
column: column
}"
></ng-container>
} {
(
(column.headerHTMLContent &&
column.headerHTMLContent(column)) ||
column.header;
as content
) {
<div
[class]="column.headerClassName"
[innerHTML]="content"
></div>
}
}
</th>
<td mat-cell *matCellDef="let row">
(row | hasCellValue: column; as content) {
<ng-container
[ngTemplateOutlet]="cellContentTemplate"
[ngTemplateOutletContext]="{
content: row | cellValue: column,
row: row,
className: column.className,
format: column.format
}"
>
</ng-container>
}
</td>
</ng-container>
}
<tr mat-header-row *matHeaderRowDef="displayedColumns()"></tr>
<tr
mat-row
*matRowDef="let row; columns: displayedColumns()"
(click)="rowClick.emit(row)"
></tr>
</table>
(showPaging()) {
<mat-paginator
[disabled]="pagingDisabled()"
[hidePageSize]="hidePageSize()"
[pageSizeOptions]="pageSizeOptions()"
[pageSize]="pageSize()"
[pageIndex]="pageIndex()"
[length]="length()"
[showFirstLastButtons]="showFirstLastButtons()"
[attr.aria-label]="pageAriaLabel()"
>
</mat-paginator>
}
<ng-template
#headerContentTemplate
let-content="content"
let-column="column"
>
<ng-container
[ngTemplateOutlet]="content"
[ngTemplateOutletContext]="{ column: column }"
></ng-container>
</ng-template>
<ng-template
#cellContentTemplate
let-content="content"
let-row="row"
let-className="className"
let-format="format"
>
(!content.createEmbeddedView) {
(format) {
<div [class]="className">
<!-- NOTE: each specified format will be displayed currently -->
(format.date) {
{{ content | date: format.date }}
}
(format.decimal) {
{{ content | number: format.decimal }}
}
(format.percent) {
{{ content | percent: format.percent }}
}
(format.currency) {
{{ content | currency: format.currency }}
}
(format.titleCase) {
{{ content | titlecase }}
}
</div>
} {
<div [class]="className" [innerHTML]="content"></div>
}
} {
<ng-container
[ngTemplateOutlet]="content"
[ngTemplateOutletContext]="{ row: row }"
></ng-container>
}
</ng-template>
`, styles: ["table{width:100%}\n"] }]
}], ctorParameters: () => [] });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmd4LXRhYmxvLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3Byb2plY3RzL25neC10YWJsby9zcmMvbGliL25neC10YWJsby5jb21wb25lbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQ0EsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQy9DLE9BQU8sRUFFTCxTQUFTLEVBR1QsUUFBUSxFQUNSLE1BQU0sRUFDTixLQUFLLEVBQ0wsS0FBSyxFQUNMLE1BQU0sRUFDTixTQUFTLEdBQ1YsTUFBTSxlQUFlLENBQUM7QUFDdkIsT0FBTyxFQUNMLFlBQVksRUFDWixrQkFBa0IsR0FFbkIsTUFBTSw2QkFBNkIsQ0FBQztBQUNyQyxPQUFPLEVBQ0wsT0FBTyxFQUNQLGFBQWEsR0FHZCxNQUFNLHdCQUF3QixDQUFDO0FBQ2hDLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxjQUFjLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUM3RSxPQUFPLEVBQUUsVUFBVSxFQUFFLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFDdEQsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLG1CQUFtQixDQUFDO0FBQ2xELE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLHVCQUF1QixDQUFDO0FBQ3pELE9BQU8sRUFBRSxvQkFBb0IsRUFBRSxNQUFNLDJCQUEyQixDQUFDOzs7Ozs7QUFzSmpFLE1BQU0sT0FBTyxLQUFLO0lBMkVoQjtRQTFFQSxpQkFBWSxHQUFHLEtBQUssQ0FBUyxFQUFFLENBQUMsQ0FBQztRQUVqQzs7OztXQUlHO1FBQ0gsZUFBVSxHQUFHLEtBQUssQ0FBZ0IsSUFBSSxrQkFBa0IsRUFBRSxDQUFDLENBQUM7UUFFNUQsU0FBSSxHQUFHLEtBQUssRUFBcUMsQ0FBQztRQUVsRCxZQUFPLEdBQUcsS0FBSyxDQUFrQixFQUFFLENBQUMsQ0FBQztRQUUzQixxQkFBZ0IsR0FBRyxRQUFR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QUksR0FBRyxJQUFJLENBQUMsQ0FBQyxDQUFDO1lBQ3JFLENBQUM7aUJBQU0sQ0FBQztnQkFDTixJQUFJLENBQUMscUJBQXFCLEVBQUUsQ0FBQyxJQUFJLEdBQUcsSUFBSSxDQUFDLElBQUksRUFBUyxDQUFDO1lBQ3pELENBQUM7UUFDSCxDQUFDO0lBQ0gsQ0FBQztJQUVPLHFCQUFxQjtRQUMzQixPQUFPLElBQUksQ0FBQyxVQUFVLEVBQTJCLENBQUM7SUFDcEQsQ0FBQzs4R0FsTFUsS0FBSztrR0FBTCxLQUFLLHUyR0FzRTRCLFlBQVksdUZBQ3RCLE9BQU8sZ0VBOU0vQjs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBOEhULDRGQXRJQyxZQUFZLGllQUNaLGNBQWMsc2dDQUNkLGtCQUFrQixtU0FDbEIsYUFBYSw2Y0FFYixnQkFBZ0IsZ0RBQ2hCLGFBQWE7OzJGQXlJSixLQUFLO2tCQW5KakIsU0FBUzsrQkFDRSxXQUFXLGNBQ1QsSUFBSSxXQUNQO3dCQUNQLFlBQVk7d0JBQ1osY0FBYzt3QkFDZCxrQkFBa0I7d0JBQ2xCLGFBQWE7d0JBQ2Isb0JBQW9CO3dCQUNwQixnQkFBZ0I7d0JBQ2hCLGFBQWE7cUJBQ2QsWUFDUzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBOEhUIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgRGF0YVNvdXJjZSB9IGZyb20gJ0Bhbmd1bGFyL2Nkay9jb2xsZWN0aW9ucyc7XG5pbXBvcnQgeyBDb21tb25Nb2R1bGUgfSBmcm9tICdAYW5ndWxhci9jb21tb24nO1xuaW1wb3J0IHtcbiAgQWZ0ZXJWaWV3SW5pdCxcbiAgQ29tcG9uZW50LFxuICBPbkRlc3Ryb3ksXG4gIE9uSW5pdCxcbiAgY29tcHV0ZWQsXG4gIGVmZmVjdCxcbiAgaW5wdXQsXG4gIG1vZGVsLFxuICBvdXRwdXQsXG4gIHZpZXdDaGlsZCxcbn0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQge1xuICBNYXRQYWdpbmF0b3IsXG4gIE1hdFBhZ2luYXRvck1vZHVsZSxcbiAgUGFnZUV2ZW50LFxufSBmcm9tICdAYW5ndWxhci9tYXRlcmlhbC9wYWdpbmF0b3InO1xuaW1wb3J0IHtcbiAgTWF0U29ydCxcbiAgTWF0U29ydE1vZHVsZSxcbiAgU29ydCxcbiAgU29ydERpcmVjdGlvbixcbn0gZnJvbSAnQGFuZ3VsYXIvbWF0ZXJpYWwvc29ydCc7XG5pbXBvcnQgeyBNYXRUYWJsZURhdGFTb3VyY2UsIE1hdFRhYmxlTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvbWF0ZXJpYWwvdGFibGUnO1xuaW1wb3J0IHsgT2JzZXJ2YWJsZSwgU3ViamVjdCwgdGFrZVVudGlsIH0gZnJvbSAncnhqcyc7XG5pbXBvcnQgeyBDZWxsVmFsdWVQaXBlIH0gZnJvbSAnLi9jZWxsLXZhbHVlLnBpcGUnO1xuaW1wb3J0IHsgSGFzQ2VsbFZhbHVlUGlwZSB9IGZyb20gJy4vaGFzLWNlbGwtdmFsdWUucGlwZSc7XG5pbXBvcnQgeyBOZXN0ZWRDb2x1bW5OYW1lUGlwZSB9IGZyb20gJy4vbmVzdGVkLWNvbHVtbi1uYW1lLnBpcGUnO1xuaW1wb3J0IHsgVGFibG9Db2x1bW5zIH0gZnJvbSAnLi90YWJsby1jb2x1bW4nO1xuXG5AQ29tcG9uZW50KHtcbiAgc2VsZWN0b3I6ICduZ3gtdGFibG8nLFxuICBzdGFuZGFsb25lOiB0cnVlLFxuICBpbXBvcnRzOiBbXG4gICAgQ29tbW9uTW9kdWxlLFxuICAgIE1hdFRhYmxlTW9kdWxlLFxuICAgIE1hdFBhZ2luYXRvck1vZHVsZSxcbiAgICBNYXRTb3J0TW9kdWxlLFxuICAgIE5lc3RlZENvbHVtbk5hbWVQaXBlLFxuICAgIEhhc0NlbGxWYWx1ZVBpcGUsXG4gICAgQ2VsbFZhbHVlUGlwZSxcbiAgXSxcbiAgdGVtcGxhdGU6IGBcbiAgICA8dGFibGVcbiAgICAgIFtjbGFzc109XCJ0YWJsZUNsYXNzZXMoKVwiXG4gICAgICBtYXQtdGFibGVcbiAgICAgIFtkYXRhU291cmNlXT1cImRhdGFTb3VyY2UoKVwiXG4gICAgICBtYXRTb3J0XG4gICAgICBbbWF0U29ydEFjdGl2ZV09XCJzb3J0QWN0aXZlKClcIlxuICAgICAgW21hdFNvcnREaXJlY3Rpb25dPVwic29ydERpcmVjdGlvbigpXCJcbiAgICA+XG4gICAgICBAZm9yIChjb2x1bW4gb2YgY29sdW1ucygpOyB0cmFjayBjb2x1bW47IGxldCBpID0gJGluZGV4KSB7XG4gICAgICAgIDxuZy1jb250YWluZXIgW21hdENvbHVtbkRlZl09XCJjb2x1bW4uY29sdW1uTmFtZVwiPlxuICAgICAgICAgIDx0aFxuICAgICAgICAgICAgbWF0LWhlYWRlci1jZWxsXG4gICAgICAgICAgICBbbWF0LXNvcnQtaGVhZGVyXT1cImNvbHVtbi5zb3J0SGVhZGVyIHx8IGNvbHVtbi5jb2x1bW5OYW1lXCJcbiAgICAgICAgICAgIFtkaXNhYmxlZF09XCIhY29sdW1uLnNvcnRcIlxuICAgICAgICAgICAgKm1hdEhlYWRlckNlbGxEZWZcbiAgICAgICAgICA+XG4gICAgICAgICAgICBAaWYgKGNvbHVtbi5oZWFkZXJUZW1wbGF0ZTsgYXMgY29udGVudCkge1xuICAgICAgICAgICAgICA8bmctY29udGFpbmVyXG4gICAgICAgICAgICAgICAgW25nVGVtcGxhdGVPdXRsZXRdPVwiaGVhZGVyQ29udGVudFRlbXBsYXRlXCJcbiAgICAgICAgICAgICAgICBbbmdUZW1wbGF0ZU91dGxldENvbnRleHRdPVwie1xuICAgICAgICAgICAgICAgICAgY29udGVudDogY29udGVudCxcbiAgICAgICAgICAgICAgICAgIGNvbHVtbjogY29sdW1uXG4gICAgICAgICAgICAgICAgfVwiXG4gICAgICAgICAgICAgID48L25nLWNvbnRhaW5lcj5cbiAgICAgICAgICAgIH0gQGVsc2Uge1xuICAgICAgICAgICAgICBAaWYgKFxuICAgICAgICAgICAgICAgIChjb2x1bW4uaGVhZGVySFRNTENvbnRlbnQgJiZcbiAgICAgICAgICAgICAgICAgIGNvbHVtbi5oZWFkZXJIVE1MQ29udGVudChjb2x1bW4pKSB8fFxuICAgICAgICAgICAgICAgICAgY29sdW1uLmhlYWRlcjtcbiAgICAgICAgICAgICAgICBhcyBjb250ZW50XG4gICAgICAgICAgICAgICkge1xuICAgICAgICAgICAgICAgIDxkaXZcbiAgICAgICAgICAgICAgICAgIFtjbGFzc109XCJjb2x1bW4uaGVhZGVyQ2xhc3NOYW1lXCJcbiAgICAgICAgICAgICAgICAgIFtpbm5lckhUTUxdPVwiY29udGVudFwiXG4gICAgICAgICAgICAgICAgPjwvZGl2PlxuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgPC90aD5cbiAgICAgICAgICA8dGQgbWF0LWNlbGwgKm1hdENlbGxEZWY9XCJsZXQgcm93XCI+XG4gICAgICAgICAgICBAaWYgKHJvdyB8IGhhc0NlbGxWYWx1ZTogY29sdW1uOyBhcyBjb250ZW50KSB7XG4gICAgICAgICAgICAgIDxuZy1jb250YWluZXJcbiAgICAgICAgICAgICAgICBbbmdUZW1wbGF0ZU91dGxldF09XCJjZWxsQ29udGVudFRlbXBsYXRlXCJcbiAgICAgICAgICAgICAgICBbbmdUZW1wbGF0ZU91dGxldENvbnRleHRdPVwie1xuICAgICAgICAgICAgICAgICAgY29udGVudDogcm93IHwgY2VsbFZhbHVlOiBjb2x1bW4sXG4gICAgICAgICAgICAgICAgICByb3c6IHJvdyxcbiAgICAgICAgICAgICAgICAgIGNsYXNzTmFtZTogY29sdW1uLmNsYXNzTmFtZSxcbiAgICAgICAgICAgICAgICAgIGZvcm1hdDogY29sdW1uLmZvcm1hdFxuICAgICAgICAgICAgICAgIH1cIlxuICAgICAgICAgICAgICA+XG4gICAgICAgICAgICAgIDwvbmctY29udGFpbmVyPlxuICAgICAgICAgICAgfVxuICAgICAgICAgIDwvdGQ+XG4gICAgICAgIDwvbmctY29udGFpbmVyPlxuICAgICAgfVxuXG4gICAgICA8dHIgbWF0LWhlYWRlci1yb3cgKm1hdEhlYWRlclJvd0RlZj1cImRpc3BsYXllZENvbHVtbnMoKVwiPjwvdHI+XG4gICAgICA8dHJcbiAgICAgICAgbWF0LXJvd1xuICAgICAgICAqbWF0Um93RGVmPVwibGV0IHJvdzsgY29sdW1uczogZGlzcGxheWVkQ29sdW1ucygpXCJcbiAgICAgICAgKGNsaWNrKT1cInJvd0NsaWNrLmVtaXQocm93KVwiXG4gICAgICA+PC90cj5cbiAgICA8L3RhYmxlPlxuXG4gICAgQGlmIChzaG93UGFnaW5nKCkpIHtcbiAgICAgIDxtYXQtcGFnaW5hdG9yXG4gICAgICAgIFtkaXNhYmxlZF09XCJwYWdpbmdEaXNhYmxlZCgpXCJcbiAgICAgICAgW2hpZGVQYWdlU2l6ZV09XCJoaWRlUGFnZVNpemUoKVwiXG4gICAgICAgIFtwYWdlU2l6ZU9wdGlvbnNdPVwicGFnZVNpemVPcHRpb25zKClcIlxuICAgICAgICBbcGFnZVNpemVdPVwicGFnZVNpemUoKVwiXG4gICAgICAgIFtwYWdlSW5kZXhdPVwicGFnZUluZGV4KClcIlxuICAgICAgICBbbGVuZ3RoXT1cImxlbmd0aCgpXCJcbiAgICAgICAgW3Nob3dGaXJzdExhc3RCdXR0b25zXT1cInNob3dGaXJzdExhc3RCdXR0b25zKClcIlxuICAgICAgICBbYXR0ci5hcmlhLWxhYmVsXT1cInBhZ2VBcmlhTGFiZWwoKVwiXG4gICAgICA+XG4gICAgICA8L21hdC1wYWdpbmF0b3I+XG4gICAgfVxuXG4gICAgPG5nLXRlbXBsYXRlXG4gICAgICAjaGVhZGVyQ29udGVudFRlbXBsYXRlXG4gICAgICBsZXQtY29udGVudD1cImNvbnRlbnRcIlxuICAgICAgbGV0LWNvbHVtbj1cImNvbHVtblwiXG4gICAgPlxuICAgICAgPG5nLWNvbnRhaW5lclxuICAgICAgICBbbmdUZW1wbGF0ZU91dGxldF09XCJjb250ZW50XCJcbiAgICAgICAgW25nVGVtcGxhdGVPdXRsZXRDb250ZXh0XT1cInsgY29sdW1uOiBjb2x1bW4gfVwiXG4gICAgICA+PC9uZy1jb250YWluZXI+XG4gICAgPC9uZy10ZW1wbGF0ZT5cblxuICAgIDxuZy10ZW1wbGF0ZVxuICAgICAgI2NlbGxDb250ZW50VGVtcGxhdGVcbiAgICAgIGxldC1jb250ZW50PVwiY29udGVudFwiXG4gICAgICBsZXQtcm93PVwicm93XCJcbiAgICAgIGxldC1jbGFzc05hbWU9XCJjbGFzc05hbWVcIlxuICAgICAgbGV0LWZvcm1hdD1cImZvcm1hdFwiXG4gICAgPlxuICAgICAgQGlmICghY29udGVudC5jcmVhdGVFbWJlZGRlZFZpZXcpIHtcbiAgICAgICAgQGlmIChmb3JtYXQpIHtcbiAgICAgICAgICA8ZGl2IFtjbGFzc109XCJjbGFzc05hbWVcIj5cbiAgICAgICAgICAgIDwhLS0gTk9URTogZWFjaCBzcGVjaWZpZWQgZm9ybWF0IHdpbGwgYmUgZGlzcGxheWVkIGN1cnJlbnRseSAtLT5cbiAgICAgICAgICAgIEBpZiAoZm9ybWF0LmRhdGUpIHtcbiAgICAgICAgICAgICAge3sgY29udGVudCB8IGRhdGU6IGZvcm1hdC5kYXRlIH19XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBAaWYgKGZvcm1hdC5kZWNpbWFsKSB7XG4gICAgICAgICAgICAgIHt7IGNvbnRlbnQgfCBudW1iZXI6IGZvcm1hdC5kZWNpbWFsIH19XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBAaWYgKGZvcm1hdC5wZXJjZW50KSB7XG4gICAgICAgICAgICAgIHt7IGNvbnRlbnQgfCBwZXJjZW50OiBmb3JtYXQucGVyY2VudCB9fVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgQGlmIChmb3JtYXQuY3VycmVuY3kpIHtcbiAgICAgICAgICAgICAge3sgY29udGVudCB8IGN1cnJlbmN5OiBmb3JtYXQuY3VycmVuY3kgfX1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIEBpZiAoZm9ybWF0LnRpdGxlQ2FzZSkge1xuICAgICAgICAgICAgICB7eyBjb250ZW50IHwgdGl0bGVjYXNlIH19XG4gICAgICAgICAgICB9XG4gICAgICAgICAgPC9kaXY+XG4gICAgICAgIH0gQGVsc2Uge1xuICAgICAgICAgIDxkaXYgW2NsYXNzXT1cImNsYXNzTmFtZVwiIFtpbm5lckhUTUxdPVwiY29udGVudFwiPjwvZGl2PlxuICAgICAgICB9XG4gICAgICB9IEBlbHNlIHtcbiAgICAgICAgPG5nLWNvbnRhaW5lclxuICAgICAgICAgIFtuZ1RlbXBsYXRlT3V0bGV0XT1cImNvbnRlbnRcIlxuICAgICAgICAgIFtuZ1RlbXBsYXRlT3V0bGV0Q29udGV4dF09XCJ7IHJvdzogcm93IH1cIlxuICAgICAgICA+PC9uZy1jb250YWluZXI+XG4gICAgICB9XG4gICAgPC9uZy10ZW1wbGF0ZT5cbiAgYCxcbiAgc3R5bGVzOiBbXG4gICAgYFxuICAgICAgdGFibGUge1xuICAgICAgICB3aWR0aDogMTAwJTtcbiAgICAgIH1cbiAgICBgLFxuICBdLFxufSlcbmV4cG9ydCBjbGFzcyBUYWJsbzxUPiBpbXBsZW1lbnRzIE9uSW5pdCwgQWZ0ZXJWaWV3SW5pdCwgT25EZXN0cm95IHtcbiAgdGFibGVDbGFzc2VzID0gaW5wdXQ8c3RyaW5nPignJyk7XG5cbiAgLyoqXG4gICAqIEFkZCBjdXN0b20gZGF0YVNvdXJjZS5cbiAgICpcbiAgICogRGVmYXVsdDogTWF0VGFibGVEYXRhU291cmNlXG4gICAqL1xuICBkYXRhU291cmNlID0gaW5wdXQ8RGF0YVNvdXJjZTxUPj4obmV3IE1hdFRhYmxlRGF0YVNvdXJjZSgpKTtcblxuICBkYXRhID0gbW9kZWw8VFtdIHwgT2JzZXJ2YWJsZTxUW10+IHwgdW5kZWZpbmVkPigpO1xuXG4gIGNvbHVtbnMgPSBpbnB1dDxUYWJsb0NvbHVtbnM8VD4+KFtdKTtcblxuICBwcm90ZWN0ZWQgZGlzcGxheWVkQ29sdW1ucyA9IGNvbXB1dGVkKCgpID0+XG4gICAgdGhpcy5jb2x1bW5zKCkubWFwKChjb2x1bW4pID0+IGNvbHVtbi5jb2x1bW5OYW1lKSxcbiAgKTtcblxuICBtb2RlID0gaW5wdXQ8J2NsaWVudCcgfCAnc2VydmVyJz4oJ2NsaWVudCcpO1xuXG4gIC8qKlxuICAgKiBTb3J0aW5nXG4gICAqL1xuICBzb3J0QWN0aXZlID0gbW9kZWwoJycpO1xuICBzb3J0RGlyZWN0aW9uID0gbW9kZWw8U29ydERpcmVjdGlvbj4oJycpO1xuICAvKipcbiAgICogQ3VzdG9tIHNvcnRpbmcgZnVuY3Rpb24gZm9yIGBNYXRUYWJsZURhdGFTb3VyY2VgLlxuICAgKlxuICAgKiBVc2UgdGhpcyBpZiBkYXRhIHByb3BlcnRpZXMgZG9uJ3QgbWF0Y2ggY29sdW1uIG5hbWVzIG9yIGZvciBjb21wbGV4IGRhdGEgb2JqZWN0cy5cbiAgICpcbiAgICogRGVmYXVsdCBleHBlY3RzIGNvbHVtbiBgeHl6YCB0byByZXByZXNlbnQgYGRhdGFbJ3h5eiddYC5cbiAgICpcbiAgICovXG4gIHNvcnRpbmdEYXRhQWNjZXNzb3IgPVxuICAgIGlucHV0PChkYXRhOiBULCBzb3J0SGVhZGVySWQ6IHN0cmluZykgPT4gc3RyaW5nIHwgbnVtYmVyPigpO1xuXG4gIC8qKlxuICAgKiBGaWx0ZXIgdmFsdWUgZm9yIGBNYXRUYWJsZURhdGFTb3VyY2VgLlxuICAgKi9cbiAgZmlsdGVyID0gaW5wdXQ8c3RyaW5nPigpO1xuXG4gIC8qKlxuICAgKiBDdXN0b20gZmlsdGVyIGZ1bmN0aW9uIGZvciBgTWF0VGFibGVEYXRhU291cmNlYC5cbiAgICovXG4gIGZpbHRlclByZWRpY2F0ZSA9IGlucHV0PChkYXRhOiBULCBmaWx0ZXI6IHN0cmluZykgPT4gYm9vbGVhbj4oKTtcblxuICAvKipcbiAgICogUGFnaW5nXG4gICAqL1xuICBzaG93UGFnaW5nID0gbW9kZWwoZmFsc2UpO1xuICBwYWdpbmdEaXNhYmxlZCA9IG1vZGVsKGZhbHNlKTtcbiAgaGlkZVBhZ2VTaXplID0gbW9kZWwoZmFsc2UpO1xuICBzaG93Rmlyc3RMYXN0QnV0dG9ucyA9IG1vZGVsKHRydWUpO1xuICBwYWdlU2l6ZSA9IG1vZGVsKDApO1xuICBwYWdlSW5kZXggPSBtb2RlbCgwKTtcbiAgbGVuZ3RoID0gbW9kZWw8bnVtYmVyPigwKTtcbiAgcGFnZVNpemVPcHRpb25zID0gbW9kZWwoWzEwLCAyMCwgNTAsIDEwMF0pO1xuICBwYWdlQXJpYUxhYmVsID0gbW9kZWwoJ1NlbGVjdCBwYWdlJyk7XG4gIC8qKlxuICAgKiBkZWZhdWx0IHRvIGZhbHNlXG4gICAqL1xuICByZXNldFBhZ2VPblNvcnQgPSBtb2RlbDxib29sZWFuPihmYWxzZSk7XG5cbiAgLyoqXG4gICAqIE91dHB1dHNcbiAgICovXG4gIHJvd0NsaWNrID0gb3V0cHV0PFQ+KCk7XG4gIHBhZ2VDaGFuZ2UgPSBvdXRwdXQ8UGFnZUV2ZW50PigpO1xuICBzb3J0Q2hhbmdlID0gb3V0cHV0PFNvcnQ+KCk7XG5cbiAgcHJpdmF0ZSBwYWdpbmF0b3IgPSB2aWV3Q2hpbGQ8TWF0UGFnaW5hdG9yPihNYXRQYWdpbmF0b3IpO1xuICBwcml2YXRlIHNvcnQgPSB2aWV3Q2hpbGQucmVxdWlyZWQoTWF0U29ydCk7XG5cbiAgcHJpdmF0ZSBkZXN0cm95JCA9IG5ldyBTdWJqZWN0PHZvaWQ+KCk7XG5cbiAgY29uc3RydWN0b3IoKSB7XG4gICAgZWZmZWN0KFxuICAgICAgKCkgPT4ge1xuICAgICAgICB0aGlzLmZpbGxEYXRhKCk7XG4gICAgICB9LFxuICAgICAgeyBhbGxvd1NpZ25hbFdyaXRlczogdHJ1ZSB9LFxuICAgICk7XG5cbiAgICBlZmZlY3QoXG4gICAgICAoKSA9PiB7XG4gICAgICAgIGNvbnN0IGZpbHRlciA9IHRoaXMuZmlsdGVyKCk7XG5cbiAgICAgICAgaWYgKHRoaXMuZGF0YVNvdXJjZSgpIGluc3RhbmNlb2YgTWF0VGFibGVEYXRhU291cmNlKSB7XG4gICAgICAgICAgdGhpcy5nZXRNYXRUYWJsZURhdGFTb3VyY2UoKS5maWx0ZXIgPSBmaWx0ZXIgfHwgJyc7XG4gICAgICAgIH1cbiAgICAgIH0sXG4gICAgICB7IGFsbG93U2lnbmFsV3JpdGVzOiB0cnVlIH0sXG4gICAgKTtcbiAgfVxuXG4gIG5nT25Jbml0KCk6IHZvaWQge1xuICAgIHRoaXMuY29sdW1ucygpLmZvckVhY2goKGNvbHVtbikgPT4ge1xuICAgICAgaWYgKGNvbHVtbi5saWZlY3ljbGU/Lm9uSW5pdCkge1xuICAgICAgICBjb2x1bW4ubGlmZWN5Y2xlLm9uSW5pdChjb2x1bW4pO1xuICAgICAgfVxuICAgIH0pO1xuXG4gICAgaWYgKHRoaXMuZGF0YVNvdXJjZSgpIGluc3RhbmNlb2YgTWF0VGFibGVEYXRhU291cmNlKSB7XG4gICAgICBpZiAodGhpcy5maWx0ZXJQcmVkaWNhdGUoKSkge1xuICAgICAgICB0aGlzLmdldE1hdFRhYmxlRGF0YVNvdXJjZSgpLmZpbHRlclByZWRpY2F0ZSA9IHRoaXMuZmlsdGVyUHJlZGljYXRlKCkhO1xuICAgICAgfVxuXG4gICAgICBpZiAodGhpcy5zb3J0aW5nRGF0YUFjY2Vzc29yKCkpIHtcbiAgICAgICAgdGhpcy5nZXRNYXRUYWJsZURhdGFTb3VyY2UoKS5zb3J0aW5nRGF0YUFjY2Vzc29yID1cbiAgICAgICAgICB0aGlzLnNvcnRpbmdEYXRhQWNjZXNzb3IoKSE7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgbmdBZnRlclZpZXdJbml0KCkge1xuICAgIHRoaXMuY29sdW1ucygpLmZvckVhY2goKGNvbHVtbikgPT4ge1xuICAgICAgaWYgKGNvbHVtbi5saWZlY3ljbGU/LmFmdGVyVmlld0luaXQpIHtcbiAgICAgICAgY29sdW1uLmxpZmVjeWNsZS5hZnRlclZpZXdJbml0KGNvbHVtbik7XG4gICAgICB9XG4gICAgfSk7XG5cbiAgICB0aGlzLnNvcnQoKS5zb3J0Q2hhbmdlLnN1YnNjcmliZSgoc29ydCkgPT4ge1xuICAgICAgdGhpcy5zb3J0Q2hhbmdlLmVtaXQoc29ydCk7XG4gICAgICBpZiAodGhpcy5yZXNldFBhZ2VPblNvcnQoKSkge1xuICAgICAgICB0aGlzLmZpcnN0UGFnZSgpO1xuICAgICAgfVxuICAgIH0pO1xuXG4gICAgaWYgKHRoaXMucGFnaW5hdG9yKCkpIHtcbiAgICAgIHRoaXMucGFnaW5hdG9yKCkhLnBhZ2Uuc3Vic2NyaWJlKChwYWdlKSA9PiB0aGlzLnBhZ2VDaGFuZ2UuZW1pdChwYWdlKSk7XG4gICAgfVxuXG4gICAgaWYgKFxuICAgICAgdGhpcy5tb2RlKCkgPT09ICdjbGllbnQnICYmXG4gICAgICB0aGlzLmRhdGFTb3VyY2UoKSBpbnN0YW5jZW9mIE1hdFRhYmxlRGF0YVNvdXJjZVxuICAgICkge1xuICAgICAgdGhpcy5nZXRNYXRUYWJsZURhdGFTb3VyY2UoKS5wYWdpbmF0b3IgPSB0aGlzLnBhZ2luYXRvcigpITtcbiAgICAgIHRoaXMuZ2V0TWF0VGFibGVEYXRhU291cmNlKCkuc29ydCA9IHRoaXMuc29ydCgpO1xuICAgIH1cbiAgfVxuXG4gIG5nT25EZXN0cm95KCk6IHZvaWQge1xuICAgIHRoaXMuZGVzdHJveSQubmV4dCgpO1xuICAgIHRoaXMuZGVzdHJveSQuY29tcGxldGUoKTtcbiAgfVxuXG4gIGZpcnN0UGFnZSgpIHtcbiAgICBpZiAodGhpcy5wYWdpbmF0b3IoKSkge1xuICAgICAgdGhpcy5wYWdpbmF0b3IoKSEuZmlyc3RQYWdlKCk7XG4gICAgfVxuICB9XG5cbiAgbGFzdFBhZ2UoKSB7XG4gICAgaWYgKHRoaXMucGFnaW5hdG9yKCkpIHtcbiAgICAgIHRoaXMucGFnaW5hdG9yKCkhLmxhc3RQYWdlKCk7XG4gICAgfVxuICB9XG5cbiAgY2xlYXJGaWx0ZXIoKSB7XG4gICAgaWYgKHRoaXMuZGF0YVNvdXJjZSgpIGluc3RhbmNlb2YgTWF0VGFibGVEYXRhU291cmNlKSB7XG4gICAgICB0aGlzLmdldE1hdFRhYmxlRGF0YVNvdXJjZSgpLmZpbHRlciA9ICcnO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgZmlsbERhdGEoKSB7XG4gICAgaWYgKHRoaXMuZGF0YSgpICYmIHRoaXMuZGF0YVNvdXJjZSgpIGluc3RhbmNlb2YgTWF0VGFibGVEYXRhU291cmNlKSB7XG4gICAgICBpZiAodGhpcy5kYXRhKCkgaW5zdGFuY2VvZiBPYnNlcnZhYmxlKSB7XG4gICAgICAgICh0aGlzLmRhdGEoKSBhcyBPYnNlcnZhYmxlPFRbXT4pXG4gICAgICAgICAgLnBpcGUodGFrZVVudGlsKHRoaXMuZGVzdHJveSQpKVxuICAgICAgICAgIC5zdWJzY3JpYmUoKGRhdGEpID0+ICh0aGlzLmdldE1hdFRhYmxlRGF0YVNvdXJjZSgpLmRhdGEgPSBkYXRhKSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0aGlzLmdldE1hdFRhYmxlRGF0YVNvdXJjZSgpLmRhdGEgPSB0aGlzLmRhdGEoKSBhcyBUW107XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBnZXRNYXRUYWJsZURhdGFTb3VyY2UoKTogTWF0VGFibGVEYXRhU291cmNlPFQ+IHtcbiAgICByZXR1cm4gdGhpcy5kYXRhU291cmNlKCkgYXMgTWF0VGFibGVEYXRhU291cmNlPFQ+O1xuICB9XG59XG4iXX0=