UNPKG

material-dynamic-table

Version:

Dynamic table component for angular built on top of angular material table. It offers sorting, pagination, filtering per column and the ability to specify content types and components used for displaying them.

177 lines 31.7 kB
import { Component, ViewChild, Input, Output, EventEmitter } from '@angular/core'; import { MatPaginator } from '@angular/material/paginator'; import { MatDialog, MatDialogConfig } from '@angular/material/dialog'; import { DataSource } from '@angular/cdk/table'; import { MdtMultiSort } from './multi-sort/multi-sort.directive'; import { ColumnFilter } from './column-filter.model'; import { ColumnFilterService } from './table-cell/cell-types/column-filter.service'; import * as i0 from "@angular/core"; import * as i1 from "./table-cell/cell-types/column-filter.service"; import * as i2 from "@angular/material/dialog"; import * as i3 from "@angular/common"; import * as i4 from "@angular/material/table"; import * as i5 from "@angular/material/paginator"; import * as i6 from "@angular/material/icon"; import * as i7 from "@angular/material/tooltip"; import * as i8 from "./column-resize/column-resize-directives/column-resize"; import * as i9 from "./column-resize/resizable-directives/resizable"; import * as i10 from "./table-cell/table-cell.component"; import * as i11 from "./multi-sort/multi-sort.directive"; import * as i12 from "./multi-sort/multi-sort-header"; export class DynamicTableComponent { constructor(columnFilterService, dialog) { this.columnFilterService = columnFilterService; this.dialog = dialog; this.pageSize = 20; this.pageSizeOptions = [20, 50, 100]; this.showFilters = true; this.stickyHeader = false; this.multiSort = false; this.hintDelay = 500; this.rowClick = new EventEmitter(); this.appliedFilters = {}; this.isDialogOpen = false; } ngOnInit() { if (this.dataSource == null) { throw Error('DynamicTable must be provided with data source.'); } if (this.columns == null) { throw Error('DynamicTable must be provided with column definitions.'); } if (this.paginator === undefined) { this.paginator = this.internalPaginator; } this.columns.forEach((column, index) => column.name = this.prepareColumnName(column.name, index)); this.displayedColumns = this.columns.map((column, index) => column.name); const dataSource = this.dataSource; dataSource.sort = this.sort; dataSource.paginator = this.paginator; } isUsingInternalPaginator() { return this.paginator === this.internalPaginator; } canFilter(column) { const filter = this.columnFilterService.getFilter(column.type); return filter != null; } isFiltered(column) { return this.appliedFilters[column.name]; } getFilterDescription(column) { const filter = this.appliedFilters[column.name]; if (!filter || !filter.getDescription) { return null; } return filter.getDescription(); } prepareColumnName(name, columnNumber) { return name || 'col' + columnNumber; } onFilterClick(event, column) { this.filter(column); event.stopPropagation(); } filter(column) { if (this.isDialogOpen) { return; } const filter = this.columnFilterService.getFilter(column.type); if (filter) { const dialogConfig = new MatDialogConfig(); const columnFilter = new ColumnFilter(); columnFilter.column = column; if (this.appliedFilters[column.name]) { columnFilter.filter = Object.create(this.appliedFilters[column.name]); } dialogConfig.data = columnFilter; const dialogRef = this.dialog.open(filter, dialogConfig); this.isDialogOpen = true; dialogRef.afterClosed().subscribe(result => { if (result) { this.appliedFilters[column.name] = result; } else if (result === '') { delete this.appliedFilters[column.name]; } if (result || result === '') { this.updateDataSource(); } this.isDialogOpen = false; }); } } clearFilters() { this.appliedFilters = {}; this.updateDataSource(); } updateDataSource() { const dataSource = this.dataSource; dataSource.filters = this.getFilters(); } getFilters() { const filters = this.appliedFilters; const filterArray = Object.keys(filters).map((key) => filters[key]); return filterArray; } getFilter(columnName) { const filterColumn = this.getColumnByName(columnName); if (!filterColumn) { throw Error(`Column with name '${columnName}' does not exist.`); } return this.appliedFilters[filterColumn.name]; } setFilter(columnName, filter) { const filterColumn = this.getColumnByName(columnName); if (!filterColumn) { throw Error(`Cannot set filter for a column. Column with name '${columnName}' does not exist.`); } this.appliedFilters[filterColumn.name] = filter; this.updateDataSource(); } getSort() { return this.sort.sortedBy; } setSort(sortedBy) { this.sort.sortedBy = sortedBy; } getColumnByName(columnName) { return this.columns.find(c => (c.name ? c.name.toLowerCase() : c.name) === (columnName ? columnName.toLowerCase() : columnName)); } onRowClick(row) { this.rowClick.next(row); } /** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DynamicTableComponent, deps: [{ token: i1.ColumnFilterService }, { token: i2.MatDialog }], target: i0.ɵɵFactoryTarget.Component }); } /** @nocollapse */ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: DynamicTableComponent, selector: "mdt-dynamic-table", inputs: { columns: "columns", dataSource: "dataSource", pageSize: "pageSize", pageSizeOptions: "pageSizeOptions", showFilters: "showFilters", stickyHeader: "stickyHeader", multiSort: "multiSort", hintDelay: "hintDelay", paginator: "paginator" }, outputs: { rowClick: "rowClick" }, viewQueries: [{ propertyName: "sort", first: true, predicate: MdtMultiSort, descendants: true, static: true }, { propertyName: "internalPaginator", first: true, predicate: MatPaginator, descendants: true, static: true }], ngImport: i0, template: "<table mat-table [dataSource]=\"dataSource\" columnResize\r\n mdtMultiSort mode=\"{{multiSort ? 'multi' : 'single'}}\">\r\n\r\n <ng-container *ngFor=\"let column of columns; let i = index\" matColumnDef=\"{{ column.name }}\"\r\n [sticky]=\"column.sticky === 'start'\" [stickyEnd]=\"column.sticky === 'end'\">\r\n <th mat-header-cell *matHeaderCellDef mdt-sort-header=\"{{ column.name }}\" [disabled]=\"column.sort === false\" [resizable]=\"column.resizable\">\r\n <span [matTooltip]=\"column.hint\" [matTooltipShowDelay]=\"hintDelay\">{{ column.displayName }}</span>\r\n <button type=\"button\" [attr.aria-label]=\"'Filter by ' + column.displayName\" class=\"mat-sort-header-button\" *ngIf=\"showFilters && canFilter(column)\"\r\n (click)=\"onFilterClick($event, column)\" (keydown.enter)=\"onFilterClick($event, column)\" (keydown.space)=\"onFilterClick($event, column)\"\r\n matTooltip=\"{{ getFilterDescription(column) }}\" matTooltipDisabled=\"{{ !getFilterDescription(column) }}\">\r\n <mat-icon color=\"{{ isFiltered(column) ? 'primary' : 'default' }}\">filter_list</mat-icon>\r\n </button>\r\n </th>\r\n <td mat-cell *matCellDef=\"let row\"><mdt-table-cell [row]=\"row\" [column]=\"column\"></mdt-table-cell></td>\r\n </ng-container>\r\n\r\n <tr mat-header-row *matHeaderRowDef=\"displayedColumns; sticky: [stickyHeader]\"></tr>\r\n <tr mat-row *matRowDef=\"let row; columns: displayedColumns;\" (click)=\"onRowClick(row)\"></tr>\r\n</table>\r\n<mat-paginator [hidden]=\"!isUsingInternalPaginator()\" [pageSize]=\"pageSize\"\r\n [pageSizeOptions]=\"pageSizeOptions\">\r\n</mat-paginator>", styles: ["table{width:100%}th .mat-icon.mat-default{opacity:.54}th button:focus .mat-icon.mat-default{opacity:.8}th .mat-icon.mat-default:hover{opacity:1}[hidden]{display:none}button.mat-sort-header-button{border:none;background:0 0;display:flex;align-items:center;padding:0;cursor:inherit;outline:0;font:inherit;color:currentColor;position:relative}\n"], dependencies: [{ kind: "directive", type: i3.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i4.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { kind: "directive", type: i4.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { kind: "directive", type: i4.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { kind: "directive", type: i4.MatColumnDef, selector: "[matColumnDef]", inputs: ["matColumnDef"] }, { kind: "directive", type: i4.MatCellDef, selector: "[matCellDef]" }, { kind: "directive", type: i4.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { kind: "directive", type: i4.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { kind: "directive", type: i4.MatCell, selector: "mat-cell, td[mat-cell]" }, { kind: "component", type: i4.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { kind: "component", type: i4.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }, { kind: "component", type: i5.MatPaginator, selector: "mat-paginator", inputs: ["color", "pageIndex", "length", "pageSize", "pageSizeOptions", "hidePageSize", "showFirstLastButtons", "selectConfig", "disabled"], outputs: ["page"], exportAs: ["matPaginator"] }, { kind: "component", type: i6.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: i7.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "directive", type: i8.MatColumnResize, selector: "table[mat-table][columnResize]" }, { kind: "directive", type: i9.MatResizable, selector: "mat-header-cell[resizable], th[mat-header-cell][resizable]", inputs: ["resizable"] }, { kind: "component", type: i10.TableCellComponent, selector: "mdt-table-cell", inputs: ["row", "column"] }, { kind: "directive", type: i11.MdtMultiSort, selector: "[mdtMultiSort]", inputs: ["matSortDisabled", "mdtSortActive", "mode"], outputs: ["matSortChange"], exportAs: ["mdtMultiSort"] }, { kind: "component", type: i12.MdtMultiSortHeader, selector: "[mdt-sort-header]", inputs: ["disabled", "mdt-sort-header", "start"], exportAs: ["mdtSortHeader"] }] }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DynamicTableComponent, decorators: [{ type: Component, args: [{ selector: 'mdt-dynamic-table', template: "<table mat-table [dataSource]=\"dataSource\" columnResize\r\n mdtMultiSort mode=\"{{multiSort ? 'multi' : 'single'}}\">\r\n\r\n <ng-container *ngFor=\"let column of columns; let i = index\" matColumnDef=\"{{ column.name }}\"\r\n [sticky]=\"column.sticky === 'start'\" [stickyEnd]=\"column.sticky === 'end'\">\r\n <th mat-header-cell *matHeaderCellDef mdt-sort-header=\"{{ column.name }}\" [disabled]=\"column.sort === false\" [resizable]=\"column.resizable\">\r\n <span [matTooltip]=\"column.hint\" [matTooltipShowDelay]=\"hintDelay\">{{ column.displayName }}</span>\r\n <button type=\"button\" [attr.aria-label]=\"'Filter by ' + column.displayName\" class=\"mat-sort-header-button\" *ngIf=\"showFilters && canFilter(column)\"\r\n (click)=\"onFilterClick($event, column)\" (keydown.enter)=\"onFilterClick($event, column)\" (keydown.space)=\"onFilterClick($event, column)\"\r\n matTooltip=\"{{ getFilterDescription(column) }}\" matTooltipDisabled=\"{{ !getFilterDescription(column) }}\">\r\n <mat-icon color=\"{{ isFiltered(column) ? 'primary' : 'default' }}\">filter_list</mat-icon>\r\n </button>\r\n </th>\r\n <td mat-cell *matCellDef=\"let row\"><mdt-table-cell [row]=\"row\" [column]=\"column\"></mdt-table-cell></td>\r\n </ng-container>\r\n\r\n <tr mat-header-row *matHeaderRowDef=\"displayedColumns; sticky: [stickyHeader]\"></tr>\r\n <tr mat-row *matRowDef=\"let row; columns: displayedColumns;\" (click)=\"onRowClick(row)\"></tr>\r\n</table>\r\n<mat-paginator [hidden]=\"!isUsingInternalPaginator()\" [pageSize]=\"pageSize\"\r\n [pageSizeOptions]=\"pageSizeOptions\">\r\n</mat-paginator>", styles: ["table{width:100%}th .mat-icon.mat-default{opacity:.54}th button:focus .mat-icon.mat-default{opacity:.8}th .mat-icon.mat-default:hover{opacity:1}[hidden]{display:none}button.mat-sort-header-button{border:none;background:0 0;display:flex;align-items:center;padding:0;cursor:inherit;outline:0;font:inherit;color:currentColor;position:relative}\n"] }] }], ctorParameters: () => [{ type: i1.ColumnFilterService }, { type: i2.MatDialog }], propDecorators: { columns: [{ type: Input }], dataSource: [{ type: Input }], pageSize: [{ type: Input }], pageSizeOptions: [{ type: Input }], showFilters: [{ type: Input }], stickyHeader: [{ type: Input }], multiSort: [{ type: Input }], hintDelay: [{ type: Input }], paginator: [{ type: Input }], rowClick: [{ type: Output }], sort: [{ type: ViewChild, args: [MdtMultiSort, { static: true }] }], internalPaginator: [{ type: ViewChild, args: [MatPaginator, { static: true }] }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZHluYW1pYy10YWJsZS5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9wcm9qZWN0cy9tYXRlcmlhbC1keW5hbWljLXRhYmxlL3NyYy9saWIvZHluYW1pYy10YWJsZS5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi9wcm9qZWN0cy9tYXRlcmlhbC1keW5hbWljLXRhYmxlL3NyYy9saWIvZHluYW1pYy10YWJsZS5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsU0FBUyxFQUFVLFNBQVMsRUFBRSxLQUFLLEVBQUUsTUFBTSxFQUFFLFlBQVksRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUMxRixPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sNkJBQTZCLENBQUM7QUFDM0QsT0FBTyxFQUFFLFNBQVMsRUFBRSxlQUFlLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQUN0RSxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFFaEQsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLG1DQUFtQyxDQUFDO0FBRWpFLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSx1QkFBdUIsQ0FBQztBQUNyRCxPQUFPLEVBQUUsbUJBQW1CLEVBQUUsTUFBTSwrQ0FBK0MsQ0FBQzs7Ozs7Ozs7Ozs7Ozs7QUFPcEYsTUFBTSxPQUFPLHFCQUFxQjtJQXVCaEMsWUFBNkIsbUJBQXdDLEVBQW1CLE1BQWlCO1FBQTVFLHdCQUFtQixHQUFuQixtQkFBbUIsQ0FBcUI7UUFBbUIsV0FBTSxHQUFOLE1BQU0sQ0FBVztRQW5CaEcsYUFBUSxHQUFHLEVBQUUsQ0FBQztRQUNkLG9CQUFlLEdBQUcsQ0FBQyxFQUFFLEVBQUUsRUFBRSxFQUFFLEdBQUcsQ0FBQyxDQUFDO1FBQ2hDLGdCQUFXLEdBQUcsSUFBSSxDQUFDO1FBQ25CLGlCQUFZLEdBQUcsS0FBSyxDQUFDO1FBQ3JCLGNBQVMsR0FBRyxLQUFLLENB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QUFFLElBQUksRUFBRSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENvbXBvbmVudCwgT25Jbml0LCBWaWV3Q2hpbGQsIElucHV0LCBPdXRwdXQsIEV2ZW50RW1pdHRlciB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xyXG5pbXBvcnQgeyBNYXRQYWdpbmF0b3IgfSBmcm9tICdAYW5ndWxhci9tYXRlcmlhbC9wYWdpbmF0b3InO1xyXG5pbXBvcnQgeyBNYXREaWFsb2csIE1hdERpYWxvZ0NvbmZpZyB9IGZyb20gJ0Bhbmd1bGFyL21hdGVyaWFsL2RpYWxvZyc7XHJcbmltcG9ydCB7IERhdGFTb3VyY2UgfSBmcm9tICdAYW5ndWxhci9jZGsvdGFibGUnO1xyXG5cclxuaW1wb3J0IHsgTWR0TXVsdGlTb3J0IH0gZnJvbSAnLi9tdWx0aS1zb3J0L211bHRpLXNvcnQuZGlyZWN0aXZlJztcclxuaW1wb3J0IHsgQ29sdW1uQ29uZmlnIH0gZnJvbSAnLi9jb2x1bW4tY29uZmlnLm1vZGVsJztcclxuaW1wb3J0IHsgQ29sdW1uRmlsdGVyIH0gZnJvbSAnLi9jb2x1bW4tZmlsdGVyLm1vZGVsJztcclxuaW1wb3J0IHsgQ29sdW1uRmlsdGVyU2VydmljZSB9IGZyb20gJy4vdGFibGUtY2VsbC9jZWxsLXR5cGVzL2NvbHVtbi1maWx0ZXIuc2VydmljZSc7XHJcblxyXG5AQ29tcG9uZW50KHtcclxuICBzZWxlY3RvcjogJ21kdC1keW5hbWljLXRhYmxlJyxcclxuICB0ZW1wbGF0ZVVybDogJy4vZHluYW1pYy10YWJsZS5jb21wb25lbnQuaHRtbCcsXHJcbiAgc3R5bGVVcmxzOiBbJy4vZHluYW1pYy10YWJsZS5jb21wb25lbnQuY3NzJ11cclxufSlcclxuZXhwb3J0IGNsYXNzIER5bmFtaWNUYWJsZUNvbXBvbmVudCBpbXBsZW1lbnRzIE9uSW5pdCB7XHJcblxyXG4gIEBJbnB1dCgpIGNvbHVtbnM6IENvbHVtbkNvbmZpZ1tdO1xyXG4gIEBJbnB1dCgpIGRhdGFTb3VyY2U6IERhdGFTb3VyY2U8YW55PjtcclxuICBASW5wdXQoKSBwYWdlU2l6ZSA9IDIwO1xyXG4gIEBJbnB1dCgpIHBhZ2VTaXplT3B0aW9ucyA9IFsyMCwgNTAsIDEwMF07XHJcbiAgQElucHV0KCkgc2hvd0ZpbHRlcnMgPSB0cnVlO1xyXG4gIEBJbnB1dCgpIHN0aWNreUhlYWRlciA9IGZhbHNlO1xyXG4gIEBJbnB1dCgpIG11bHRpU29ydCA9IGZhbHNlO1xyXG4gIEBJbnB1dCgpIGhpbnREZWxheSA9IDUwMDtcclxuICBASW5wdXQoKSBwYWdpbmF0b3I6IE1hdFBhZ2luYXRvcjtcclxuXHJcbiAgQE91dHB1dCgpIHJvd0NsaWNrID0gbmV3IEV2ZW50RW1pdHRlcjxhbnk+KCk7XHJcblxyXG4gIGRpc3BsYXllZENvbHVtbnM6IHN0cmluZ1tdO1xyXG5cclxuICBAVmlld0NoaWxkKE1kdE11bHRpU29ydCwgeyBzdGF0aWM6IHRydWUgfSkgc29ydDogTWR0TXVsdGlTb3J0O1xyXG4gIEBWaWV3Q2hpbGQoTWF0UGFnaW5hdG9yLCB7IHN0YXRpYzogdHJ1ZSB9KSBwcml2YXRlIGludGVybmFsUGFnaW5hdG9yOiBNYXRQYWdpbmF0b3I7XHJcblxyXG4gIHByaXZhdGUgYXBwbGllZEZpbHRlcnM6IHsgW2tleTogc3RyaW5nXTogYW55OyB9ID0ge307XHJcblxyXG4gIGlzRGlhbG9nT3BlbiA9IGZhbHNlO1xyXG5cclxuICBjb25zdHJ1Y3Rvcihwcml2YXRlIHJlYWRvbmx5IGNvbHVtbkZpbHRlclNlcnZpY2U6IENvbHVtbkZpbHRlclNlcnZpY2UsIHByaXZhdGUgcmVhZG9ubHkgZGlhbG9nOiBNYXREaWFsb2cpIHsgfVxyXG5cclxuICBuZ09uSW5pdCgpIHtcclxuICAgIGlmICh0aGlzLmRhdGFTb3VyY2UgPT0gbnVsbCkge1xyXG4gICAgICB0aHJvdyBFcnJvcignRHluYW1pY1RhYmxlIG11c3QgYmUgcHJvdmlkZWQgd2l0aCBkYXRhIHNvdXJjZS4nKTtcclxuICAgIH1cclxuICAgIGlmICh0aGlzLmNvbHVtbnMgPT0gbnVsbCkge1xyXG4gICAgICB0aHJvdyBFcnJvcignRHluYW1pY1RhYmxlIG11c3QgYmUgcHJvdmlkZWQgd2l0aCBjb2x1bW4gZGVmaW5pdGlvbnMuJyk7XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKHRoaXMucGFnaW5hdG9yID09PSB1bmRlZmluZWQpIHtcclxuICAgICAgdGhpcy5wYWdpbmF0b3IgPSB0aGlzLmludGVybmFsUGFnaW5hdG9yO1xyXG4gICAgfVxyXG5cclxuICAgIHRoaXMuY29sdW1ucy5mb3JFYWNoKChjb2x1bW4sIGluZGV4KSA9PiBjb2x1bW4ubmFtZSA9IHRoaXMucHJlcGFyZUNvbHVtbk5hbWUoY29sdW1uLm5hbWUsIGluZGV4KSk7XHJcbiAgICB0aGlzLmRpc3BsYXllZENvbHVtbnMgPSB0aGlzLmNvbHVtbnMubWFwKChjb2x1bW4sIGluZGV4KSA9PiBjb2x1bW4ubmFtZSk7XHJcblxyXG4gICAgY29uc3QgZGF0YVNvdXJjZSA9IHRoaXMuZGF0YVNvdXJjZSBhcyBhbnk7XHJcbiAgICBkYXRhU291cmNlLnNvcnQgPSB0aGlzLnNvcnQ7XHJcbiAgICBkYXRhU291cmNlLnBhZ2luYXRvciA9IHRoaXMucGFnaW5hdG9yO1xyXG4gIH1cclxuXHJcbiAgaXNVc2luZ0ludGVybmFsUGFnaW5hdG9yKCkge1xyXG4gICAgcmV0dXJuIHRoaXMucGFnaW5hdG9yID09PSB0aGlzLmludGVybmFsUGFnaW5hdG9yO1xyXG4gIH1cclxuXHJcbiAgY2FuRmlsdGVyKGNvbHVtbjogQ29sdW1uQ29uZmlnKSB7XHJcbiAgICBjb25zdCBmaWx0ZXIgPSB0aGlzLmNvbHVtbkZpbHRlclNlcnZpY2UuZ2V0RmlsdGVyKGNvbHVtbi50eXBlKTtcclxuXHJcbiAgICByZXR1cm4gZmlsdGVyICE9IG51bGw7XHJcbiAgfVxyXG5cclxuICBpc0ZpbHRlcmVkKGNvbHVtbjogQ29sdW1uQ29uZmlnKSB7XHJcbiAgICByZXR1cm4gdGhpcy5hcHBsaWVkRmlsdGVyc1tjb2x1bW4ubmFtZV07XHJcbiAgfVxyXG5cclxuICBnZXRGaWx0ZXJEZXNjcmlwdGlvbihjb2x1bW46IENvbHVtbkNvbmZpZykge1xyXG4gICAgY29uc3QgZmlsdGVyID0gdGhpcy5hcHBsaWVkRmlsdGVyc1tjb2x1bW4ubmFtZV07XHJcbiAgICBpZiAoIWZpbHRlciB8fCAhZmlsdGVyLmdldERlc2NyaXB0aW9uKSB7XHJcbiAgICAgIHJldHVybiBudWxsO1xyXG4gICAgfVxyXG5cclxuICAgIHJldHVybiBmaWx0ZXIuZ2V0RGVzY3JpcHRpb24oKTtcclxuICB9XHJcblxyXG4gIHByZXBhcmVDb2x1bW5OYW1lKG5hbWU6IHN0cmluZyB8IHVuZGVmaW5lZCwgY29sdW1uTnVtYmVyOiBudW1iZXIpIHtcclxuICAgIHJldHVybiBuYW1lIHx8ICdjb2wnICsgY29sdW1uTnVtYmVyO1xyXG4gIH1cclxuXHJcbiAgb25GaWx0ZXJDbGljayhldmVudDogRXZlbnQsIGNvbHVtbjogQ29sdW1uQ29uZmlnKTogdm9pZCB7XHJcbiAgICB0aGlzLmZpbHRlcihjb2x1bW4pO1xyXG4gICAgZXZlbnQuc3RvcFByb3BhZ2F0aW9uKCk7XHJcbiAgfVxyXG5cclxuICBmaWx0ZXIoY29sdW1uOiBDb2x1bW5Db25maWcpIHtcclxuICAgIGlmICh0aGlzLmlzRGlhbG9nT3Blbikge1xyXG4gICAgICByZXR1cm47XHJcbiAgICB9XHJcblxyXG4gICAgY29uc3QgZmlsdGVyID0gdGhpcy5jb2x1bW5GaWx0ZXJTZXJ2aWNlLmdldEZpbHRlcihjb2x1bW4udHlwZSk7XHJcblxyXG4gICAgaWYgKGZpbHRlcikge1xyXG4gICAgICBjb25zdCBkaWFsb2dDb25maWcgPSBuZXcgTWF0RGlhbG9nQ29uZmlnKCk7XHJcbiAgICAgIGNvbnN0IGNvbHVtbkZpbHRlciA9IG5ldyBDb2x1bW5GaWx0ZXIoKTtcclxuICAgICAgY29sdW1uRmlsdGVyLmNvbHVtbiA9IGNvbHVtbjtcclxuXHJcbiAgICAgIGlmICh0aGlzLmFwcGxpZWRGaWx0ZXJzW2NvbHVtbi5uYW1lXSkge1xyXG4gICAgICAgIGNvbHVtbkZpbHRlci5maWx0ZXIgPSBPYmplY3QuY3JlYXRlKHRoaXMuYXBwbGllZEZpbHRlcnNbY29sdW1uLm5hbWVdKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgZGlhbG9nQ29uZmlnLmRhdGEgPSBjb2x1bW5GaWx0ZXI7XHJcblxyXG4gICAgICBjb25zdCBkaWFsb2dSZWYgPSB0aGlzLmRpYWxvZy5vcGVuKGZpbHRlciwgZGlhbG9nQ29uZmlnKTtcclxuICAgICAgdGhpcy5pc0RpYWxvZ09wZW4gPSB0cnVlO1xyXG5cclxuICAgICAgZGlhbG9nUmVmLmFmdGVyQ2xvc2VkKCkuc3Vic2NyaWJlKHJlc3VsdCA9PiB7XHJcbiAgICAgICAgaWYgKHJlc3VsdCkge1xyXG4gICAgICAgICAgdGhpcy5hcHBsaWVkRmlsdGVyc1tjb2x1bW4ubmFtZV0gPSByZXN1bHQ7XHJcbiAgICAgICAgfSBlbHNlIGlmIChyZXN1bHQgPT09ICcnKSB7XHJcbiAgICAgICAgICBkZWxldGUgdGhpcy5hcHBsaWVkRmlsdGVyc1tjb2x1bW4ubmFtZV07XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICBpZiAocmVzdWx0IHx8IHJlc3VsdCA9PT0gJycpIHtcclxuICAgICAgICAgIHRoaXMudXBkYXRlRGF0YVNvdXJjZSgpO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgdGhpcy5pc0RpYWxvZ09wZW4gPSBmYWxzZTtcclxuICAgICAgfSk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBjbGVhckZpbHRlcnMoKSB7XHJcbiAgICB0aGlzLmFwcGxpZWRGaWx0ZXJzID0ge307XHJcbiAgICB0aGlzLnVwZGF0ZURhdGFTb3VyY2UoKTtcclxuICB9XHJcblxyXG4gIHByb3RlY3RlZCB1cGRhdGVEYXRhU291cmNlKCkge1xyXG4gICAgY29uc3QgZGF0YVNvdXJjZSA9IHRoaXMuZGF0YVNvdXJjZSBhcyBhbnk7XHJcbiAgICBkYXRhU291cmNlLmZpbHRlcnMgPSB0aGlzLmdldEZpbHRlcnMoKTtcclxuICB9XHJcblxyXG4gIGdldEZpbHRlcnMoKSB7XHJcbiAgICBjb25zdCBmaWx0ZXJzID0gdGhpcy5hcHBsaWVkRmlsdGVycztcclxuICAgIGNvbnN0IGZpbHRlckFycmF5ID0gT2JqZWN0LmtleXMoZmlsdGVycykubWFwKChrZXkpID0+IGZpbHRlcnNba2V5XSk7XHJcbiAgICByZXR1cm4gZmlsdGVyQXJyYXk7XHJcbiAgfVxyXG5cclxuICBnZXRGaWx0ZXIoY29sdW1uTmFtZTogc3RyaW5nKTogYW55IHtcclxuICAgIGNvbnN0IGZpbHRlckNvbHVtbiA9IHRoaXMuZ2V0Q29sdW1uQnlOYW1lKGNvbHVtbk5hbWUpO1xyXG5cclxuICAgIGlmICghZmlsdGVyQ29sdW1uKSB7XHJcbiAgICAgIHRocm93IEVycm9yKGBDb2x1bW4gd2l0aCBuYW1lICcke2NvbHVtbk5hbWV9JyBkb2VzIG5vdCBleGlzdC5gKTtcclxuICAgIH1cclxuXHJcbiAgICByZXR1cm4gdGhpcy5hcHBsaWVkRmlsdGVyc1tmaWx0ZXJDb2x1bW4ubmFtZV07XHJcbiAgfVxyXG5cclxuICBzZXRGaWx0ZXIoY29sdW1uTmFtZTogc3RyaW5nLCBmaWx0ZXI6IGFueSkge1xyXG4gICAgY29uc3QgZmlsdGVyQ29sdW1uID0gdGhpcy5nZXRDb2x1bW5CeU5hbWUoY29sdW1uTmFtZSk7XHJcblxyXG4gICAgaWYgKCFmaWx0ZXJDb2x1bW4pIHtcclxuICAgICAgdGhyb3cgRXJyb3IoYENhbm5vdCBzZXQgZmlsdGVyIGZvciBhIGNvbHVtbi4gQ29sdW1uIHdpdGggbmFtZSAnJHtjb2x1bW5OYW1lfScgZG9lcyBub3QgZXhpc3QuYCk7XHJcbiAgICB9XHJcblxyXG4gICAgdGhpcy5hcHBsaWVkRmlsdGVyc1tmaWx0ZXJDb2x1bW4ubmFtZV0gPSBmaWx0ZXI7XHJcbiAgICB0aGlzLnVwZGF0ZURhdGFTb3VyY2UoKTtcclxuICB9XHJcblxyXG4gIGdldFNvcnQoKSB7XHJcbiAgICByZXR1cm4gdGhpcy5zb3J0LnNvcnRlZEJ5O1xyXG4gIH1cclxuXHJcbiAgc2V0U29ydChzb3J0ZWRCeTogeyBpZDogc3RyaW5nLCBkaXJlY3Rpb246ICdhc2MnIHwgJ2Rlc2MnIH1bXSkge1xyXG4gICAgdGhpcy5zb3J0LnNvcnRlZEJ5ID0gc29ydGVkQnk7XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIGdldENvbHVtbkJ5TmFtZShjb2x1bW5OYW1lOiBzdHJpbmcpOiBDb2x1bW5Db25maWcgfCB1bmRlZmluZWQge1xyXG4gICAgcmV0dXJuIHRoaXMuY29sdW1ucy5maW5kKGMgPT5cclxuICAgICAgKGMubmFtZSA/IGMubmFtZS50b0xvd2VyQ2FzZSgpIDogYy5uYW1lKSA9PT0gKGNvbHVtbk5hbWUgPyBjb2x1bW5OYW1lLnRvTG93ZXJDYXNlKCkgOiBjb2x1bW5OYW1lKVxyXG4gICAgKTtcclxuICB9XHJcblxyXG4gIG9uUm93Q2xpY2socm93OiBhbnkpIHtcclxuICAgIHRoaXMucm93Q2xpY2submV4dChyb3cpO1xyXG4gIH1cclxufVxyXG4iLCI8dGFibGUgbWF0LXRhYmxlIFtkYXRhU291cmNlXT1cImRhdGFTb3VyY2VcIiBjb2x1bW5SZXNpemVcclxuICAgICAgIG1kdE11bHRpU29ydCBtb2RlPVwie3ttdWx0aVNvcnQgPyAnbXVsdGknIDogJ3NpbmdsZSd9fVwiPlxyXG5cclxuICA8bmctY29udGFpbmVyICpuZ0Zvcj1cImxldCBjb2x1bW4gb2YgY29sdW1uczsgbGV0IGkgPSBpbmRleFwiIG1hdENvbHVtbkRlZj1cInt7IGNvbHVtbi5uYW1lIH19XCJcclxuICAgICAgICAgICAgICAgIFtzdGlja3ldPVwiY29sdW1uLnN0aWNreSA9PT0gJ3N0YXJ0J1wiIFtzdGlja3lFbmRdPVwiY29sdW1uLnN0aWNreSA9PT0gJ2VuZCdcIj5cclxuICAgIDx0aCBtYXQtaGVhZGVyLWNlbGwgKm1hdEhlYWRlckNlbGxEZWYgbWR0LXNvcnQtaGVhZGVyPVwie3sgY29sdW1uLm5hbWUgfX1cIiBbZGlzYWJsZWRdPVwiY29sdW1uLnNvcnQgPT09IGZhbHNlXCIgW3Jlc2l6YWJsZV09XCJjb2x1bW4ucmVzaXphYmxlXCI+XHJcbiAgICAgIDxzcGFuIFttYXRUb29sdGlwXT1cImNvbHVtbi5oaW50XCIgW21hdFRvb2x0aXBTaG93RGVsYXldPVwiaGludERlbGF5XCI+e3sgY29sdW1uLmRpc3BsYXlOYW1lIH19PC9zcGFuPlxyXG4gICAgICA8YnV0dG9uIHR5cGU9XCJidXR0b25cIiBbYXR0ci5hcmlhLWxhYmVsXT1cIidGaWx0ZXIgYnkgJyArIGNvbHVtbi5kaXNwbGF5TmFtZVwiIGNsYXNzPVwibWF0LXNvcnQtaGVhZGVyLWJ1dHRvblwiICpuZ0lmPVwic2hvd0ZpbHRlcnMgJiYgY2FuRmlsdGVyKGNvbHVtbilcIlxyXG4gICAgICAgICAgICAgIChjbGljayk9XCJvbkZpbHRlckNsaWNrKCRldmVudCwgY29sdW1uKVwiIChrZXlkb3duLmVudGVyKT1cIm9uRmlsdGVyQ2xpY2soJGV2ZW50LCBjb2x1bW4pXCIgKGtleWRvd24uc3BhY2UpPVwib25GaWx0ZXJDbGljaygkZXZlbnQsIGNvbHVtbilcIlxyXG4gICAgICAgICAgICAgIG1hdFRvb2x0aXA9XCJ7eyBnZXRGaWx0ZXJEZXNjcmlwdGlvbihjb2x1bW4pIH19XCIgbWF0VG9vbHRpcERpc2FibGVkPVwie3sgIWdldEZpbHRlckRlc2NyaXB0aW9uKGNvbHVtbikgfX1cIj5cclxuICAgICAgICA8bWF0LWljb24gY29sb3I9XCJ7eyBpc0ZpbHRlcmVkKGNvbHVtbikgPyAncHJpbWFyeScgOiAnZGVmYXVsdCcgfX1cIj5maWx0ZXJfbGlzdDwvbWF0LWljb24+XHJcbiAgICAgIDwvYnV0dG9uPlxyXG4gICAgPC90aD5cclxuICAgIDx0ZCBtYXQtY2VsbCAqbWF0Q2VsbERlZj1cImxldCByb3dcIj48bWR0LXRhYmxlLWNlbGwgW3Jvd109XCJyb3dcIiBbY29sdW1uXT1cImNvbHVtblwiPjwvbWR0LXRhYmxlLWNlbGw+PC90ZD5cclxuICA8L25nLWNvbnRhaW5lcj5cclxuXHJcbiAgPHRyIG1hdC1oZWFkZXItcm93ICptYXRIZWFkZXJSb3dEZWY9XCJkaXNwbGF5ZWRDb2x1bW5zOyBzdGlja3k6IFtzdGlja3lIZWFkZXJdXCI+PC90cj5cclxuICA8dHIgbWF0LXJvdyAqbWF0Um93RGVmPVwibGV0IHJvdzsgY29sdW1uczogZGlzcGxheWVkQ29sdW1ucztcIiAoY2xpY2spPVwib25Sb3dDbGljayhyb3cpXCI+PC90cj5cclxuPC90YWJsZT5cclxuPG1hdC1wYWdpbmF0b3IgW2hpZGRlbl09XCIhaXNVc2luZ0ludGVybmFsUGFnaW5hdG9yKClcIiBbcGFnZVNpemVdPVwicGFnZVNpemVcIlxyXG4gICAgICAgICAgICAgICBbcGFnZVNpemVPcHRpb25zXT1cInBhZ2VTaXplT3B0aW9uc1wiPlxyXG48L21hdC1wYWdpbmF0b3I+Il19