UNPKG

ngx-mat-dynamic-table

Version:
420 lines 72.3 kB
import { Component, Input, Output, EventEmitter, ViewChild, Inject, LOCALE_ID, ChangeDetectionStrategy } from '@angular/core';
import { MatTableDataSource } from '@angular/material/table';
import { MatSort } from '@angular/material/sort';
import { MatPaginator } from '@angular/material/paginator';
import { SelectionModel } from '@angular/cdk/collections';
import { formatDate } from '@angular/common';
import { FormControl } from '@angular/forms';
import { XlsxExportService } from '../xlsx-table-export/service/xlsx-export.service';
import { get as _get, set as _set, cloneDeep } from 'lodash';
import { BehaviorSubject, interval, Subject } from 'rxjs';
import { debounce } from 'rxjs/operators';
import { ColumnStorageService } from '../services/column-storage.service';
export class DynamicTableComponent {
    constructor(locale, xlsxExportService, columnStorageService) {
        this.locale = locale;
        this.xlsxExportService = xlsxExportService;
        this.columnStorageService = columnStorageService;
        this.export = false; // Enable export for this table
        this.filter = false; // Enable filter for this table
        this.multiple = false; // Allow multiple select for this table
        this.optionalColumns = false; // Show or hide columns
        this.emitFilteredData = false; // Show or hide columns
        this.rowClicked = new EventEmitter();
        this.cellClicked = new EventEmitter();
        this.selectedRows = new EventEmitter();
        this.filterResult = new EventEmitter();
        this.selection = new SelectionModel(true, []);
        this.displayedColumns = [];
        this.dataSource = new MatTableDataSource();
        this.totalsRowVisible = false;
        // The hidden columns filtered out
        this.columnsToShow = new FormControl();
        this.filterKeyUp = new BehaviorSubject('');
        this.columnSearch$ = new Subject();
    }
    ngOnChanges(changes) {
        // Add headers to of data to display in table
        if (changes.columns && changes.columns.currentValue) {
            this.setColumns();
        }
        if (changes.tableData.currentValue) {
            // TODO: Test this default sort change
            // if (this.sortActive) {
            //   this.dataSource.data = this.tableData.sort((a, b) => (_get(a, this.sortActive) > _get(b, this.sortActive)) ? this.sortDirection === 'asc' ? 1 : -1 : ((_get(b, this.sortActive) > _get(a, this.sortActive)) ? this.sortDirection === 'asc' ? -1 : 1 : 0));
            // } else {
            //   this.dataSource.data = this.tableData;
            // }
            // Clear selection if new data is comming in
            this.selection.clear();
            this.dataSource.data = this.tableData;
            this.updateColumnTotals();
        }
    }
    ngAfterViewInit() {
        this.filterKeyUp.pipe(debounce(() => interval(2000))).subscribe(filterValue => {
            this.searchLoading = false;
            // apply the filter after 2 seconds
            this.dataSource.filter = filterValue;
            if (this.dataSource.paginator) {
                this.dataSource.paginator.firstPage();
            }
            // update totals
            this.updateColumnTotals();
            // If the flag is set, emit the filtered data
            if (this.emitFilteredData) {
                this.getFilteredData();
            }
        });
        this.dataSource.sort = this.sort;
        this.dataSource.paginator = this.paginator;
    }
    ngOnInit() {
        this.dataSource.sortingDataAccessor = (data, attribute) => _get(data, attribute);
        // Changed this sort function from the source to compare alpha numerics https://stackoverflow.com/a/66157044/6044269
        // https://github.com/angular/components/blob/master/src/material/table/table-data-source.ts#L165
        this.dataSource.sortData = (data, sort) => {
            const active = sort.active;
            const direction = sort.direction;
            if (!active || direction == '') {
                return data;
            }
            return data.sort((a, b) => {
                let valueA = this.dataSource.sortingDataAccessor(a, active);
                let valueB = this.dataSource.sortingDataAccessor(b, active);
                const valueAType = typeof valueA;
                const valueBType = typeof valueB;
                if (valueAType !== valueBType) {
                    if (valueAType === 'number') {
                        valueA += '';
                    }
                    if (valueBType === 'number') {
                        valueB += '';
                    }
                }
                let comparatorResult = 0;
                if (valueA != null && valueB != null) {
                    // ! This is the If that I changed https://stackoverflow.com/a/66157044/6044269
                    if (valueAType === 'string' && valueBType === 'string') {
                        comparatorResult = valueA.localeCompare(valueB, 'en', { numeric: true });
                    }
                    else if (valueA > valueB) {
                        comparatorResult = 1;
                    }
                    else if (valueA < valueB) {
                        comparatorResult = -1;
                    }
                }
                else if (valueA != null) {
                    comparatorResult = 1;
                }
                else if (valueB != null) {
                    comparatorResult = -1;
                }
                return comparatorResult * (direction == 'asc' ? 1 : -1);
            });
        };
        // Search for nested objects
        this.dataSource.filterPredicate = (data, filter) => {
            let validRow = true;
            if (!filter)
                return validRow;
            // type|searchString:column#searchType,type|searchString:column#searchType...
            const terms = filter.split(','); // Split multiple search
            terms.some(term => {
                let [type, criteria] = term.split('|'); // Split global / column search
                let dataString = '';
                let searchType; // type of search in a column
                // let criteria;
                if (type === 'global') {
                    // Search All
                    this.columns.filter(c => c.search).map(c => c.columnDef).forEach(column => {
                        const cellData = _get(data, column);
                        if (cellData)
                            dataString += cellData;
                    });
                    // String contains/equals in all columns
                    if (!dataString || dataString.toString().toLowerCase().indexOf(criteria.toLowerCase()) === -1) {
                        validRow = false;
                        return true;
                    }
                }
                else {
                    const [searchString, columnAndType] = criteria.split(':'); // Split search string and criteria
                    let column;
                    [column, searchType] = columnAndType.split('#'); // Split column and type of search
                    criteria = searchString;
                    dataString = _get(data, column); // get the data
                    if (searchType === '!=') {
                        // String contains/equals in all columns
                        if (!dataString || dataString.toString().toLowerCase().indexOf(criteria.toLowerCase()) !== -1) {
                            validRow = false;
                            return true;
                        }
                    }
                    else if (searchType === 'empty') {
                        if (dataString) {
                            validRow = false;
                            return true;
                        }
                    }
                    else {
                        // String contains/equals in all columns
                        if (!dataString || dataString.toString().toLowerCase().indexOf(criteria.toLowerCase()) === -1) {
                            validRow = false;
                            return true;
                        }
                    }
                }
            });
            return validRow;
        };
    }
    updateXLSXHeaders() {
        this.xlsxHeaders = {};
        this.columnsToShow.value.forEach(c => {
            this.xlsxHeaders[c.columnDef] = c.columnTitle;
        });
    }
    updateColumnTotals() {
        if (!this.dataSource) {
            return;
        }
        this.columns.map(col => {
            if ((col.total || col.average)) {
                this.totalsRowVisible = true;
                if (this.dataSource.filteredData.length > 0) {
                    col.totalValue = this.dataSource.filteredData.map(t => _get(t, col.columnDef)).reduce((acc, value) => acc + (value ? value : 0), 0);
                    if (isNaN(col.totalValue)) {
                        col.totalValue = 0;
                        col.averageValue = 0;
                    }
                    else {
                        col.averageValue = col.totalValue / this.dataSource.filteredData.length;
                    }
                }
                else {
                    col.totalValue = 0;
                    col.averageValue = 0;
                }
            }
            return col;
        });
    }
    applyFilter(searchTerms) {
        this.searchLoading = true;
        let filterString;
        searchTerms.forEach(term => {
            // type: Global or in a column
            // |searchString: the text/number searching for
            // :column: when type is column, this field is set
            // #searchType = != >= <= empty
            // type|searchString:column#searchType,type|searchString:column#searchType...
            const newTerm = `${term.type}|${term.search}${term.type === 'column' ? ':' + term.column + '#' + term.searchType : ''}`;
            if (filterString)
                filterString += `,${newTerm}`;
            else
                filterString = newTerm;
        });
        this.filterKeyUp.next(filterString);
    }
    applyColumnFilter(element, column, columnTitle, searchType) {
        //
        if (searchType && searchType !== 'empty' && !element.value)
            return;
        this.searchLoading = true;
        // Send data to table-search-input and add a chip
        this.columnSearch$.next({ type: 'column', column: column, columnTitle: columnTitle, inputReference: element, search: element.value, searchType: searchType });
    }
    _rowClicked(row) {
        if (!this.rowClick)
            return;
        this.rowClicked.emit(row);
    }
    onMatCellClick(row, column) {
        if (!this.cellClick)
            return;
        this.cellClicked.emit({ row: row, column: column.columnDef, data: _get(row, column.columnDef) });
    }
    /** Whether the number of selected elements matches the total number of rows. */
    isAllSelected() {
        const numSelected = this.selection.selected.length;
        const numRows = this.dataSource.data.length;
        return numSelected === numRows;
    }
    /** Selects all rows if they are not all selected; otherwise clear selection. */
    masterToggle() {
        this.isAllSelected() ?
            this.selection.clear() :
            this.dataSource.filteredData.forEach(row => this.selection.select(row));
        this.emitSelected();
    }
    toggle(event, row) {
        if (event)
            this.selection.toggle(row);
        this.emitSelected();
    }
    emitSelected() {
        this.selectedRows.emit(this.selection.selected);
    }
    setColumns() {
        this.setDefaultSorting();
        // Check for saved columns in indexedDB
        if (this.tableId) {
            this.savedColumnsLoading = true;
            // TODO: wait here for the db
            if (this.columnStorageService.isDbOpen()) {
                this.columnStorageService.read(this.tableId).subscribe(res => {
                    this.setSavedColumnSelection(res);
                });
            }
            else {
                // Wait for the DB to wake up and then query
                setTimeout(() => {
                    this.columnStorageService.read(this.tableId).subscribe(res => {
                        this.setSavedColumnSelection(res);
                    });
                }, 500);
            }
        }
        else {
            this.setStaticColumns();
        }
    }
    setStaticColumns() {
        // List of all columns to show in the view
        this.displayedColumns = [];
        // Totals row starts as false untill inspection of column definitions
        this.totalsRowVisible = false;
        // add the rest of non hidden columns to the list
        this.displayedColumns = this.columns.filter(c => !c.hidden).map(c => c.columnDef);
        // If multiple select is enabled, add select to the from of the array
        if (this.multiple)
            this.displayedColumns.unshift('select');
        // set visible columns as checked in the selector
        this.columnsToShow.setValue(this.columns.filter(c => !c.hidden));
        this.updateColumnTotals();
    }
    displayColumnsChanged(event) {
        this.displayedColumns = event.value.map(c => c.columnDef);
        if (this.multiple)
            this.displayedColumns.unshift('select');
        // save the current visible columns
        this.saveCurrentColumnSelection(this.displayedColumns);
    }
    eportToExcell() {
        this.updateXLSXHeaders();
        this.formatExportData();
        this.xlsxExportService.exportExcel(this.exportData, this.xlsxHeaders, this.fileName ? this.fileName : 'Export');
    }
    getFilteredData() {
        this.cloneData();
        this.filterResult.emit(this.exportData);
    }
    cloneData() {
        // Format dates for exporting, temp
        if (this.selection.hasValue()) {
            // Export selected data
            this.exportData = this.selection.selected.map(a => cloneDeep(a));
        }
        else {
            // Export filtered data and sorted
            this.exportData = this.dataSource.sortData(this.dataSource.filteredData, this.dataSource.sort).map(a => cloneDeep(a));
        }
    }
    formatExportData() {
        this.cloneData();
        // If the columns contain a date
        let dateColumns = this.columnsToShow.value.filter(e => e.type === 'date');
        if (dateColumns && dateColumns.length > 0) {
            this.exportData = this.exportData.map(td => {
                dateColumns.forEach(col => {
                    if (_get(td, col.columnDef))
                        _set(td, col.columnDef, formatDate(_get(td, col.columnDef), col.dateFormat ? col.dateFormat : 'dd/MM/yyyy, HH:mm', this.locale));
                });
                return td;
            });
        }
    }
    nestedFilterCheck(search, data, key) {
        if (typeof data[key] === 'object') {
            for (const k in data[key]) {
                if (data[key][k] !== null) {
                    search = this.nestedFilterCheck(search, data[key], k);
                }
            }
        }
        else {
            search += data[key];
        }
        return search;
    }
    setDefaultSorting() {
        this.columns.some(col => {
            if (col.sort) {
                this.sortActive = col.columnDef;
                this.sortDirection = col.sort;
                return true;
            }
        });
    }
    setSavedColumnSelection(saved) {
        this.savedColumnsLoading = false;
        if (!saved || saved.visibleColumns.length === 0) {
            this.setStaticColumns();
            return;
        }
        // set the column selector with the values stored in the indexeddb
        this.columnsToShow.setValue(this.columns.filter(c => saved.visibleColumns.some(item => item === c.columnDef)));
        // If multiple is enabled but was not saved in the saved array, add it
        if (this.multiple && saved.visibleColumns[0] !== 'select')
            saved.visibleColumns.unshift('select');
        this.displayedColumns = saved.visibleColumns;
    }
    saveCurrentColumnSelection(displayedColumns) {
        if (!this.tableId)
            return;
        let toSave = this.displayedColumns.slice();
        // Do not save the selection column
        if (this.multiple && toSave[0] === 'select')
            toSave.shift();
        this.columnStorageService.save({
            tableId: this.tableId,
            visibleColumns: toSave
        });
    }
}
DynamicTableComponent.decorators = [
    { type: Component, args: [{
                selector: 'ngx-mat-dynamic-table',
                template: "<div fxLayout=\"row wrap\" fxLayoutAlign=\"start center\" fxLayoutGap=\"10px\">\r\n    <!-- Search input with chips -->\r\n    <ngx-mat-table-search-input [columnSearch$]=\"columnSearch$\" (searchChange)=\"applyFilter($event)\">\r\n    </ngx-mat-table-search-input>\r\n    <mat-spinner *ngIf=\"searchLoading\" [diameter]=\"20\"></mat-spinner>\r\n    <span fxFlex.gt-xs></span>\r\n    <!-- Select enabled columns -->\r\n    <mat-spinner *ngIf=\"savedColumnsLoading\" [diameter]=\"20\"></mat-spinner>\r\n    <mat-form-field *ngIf=\"optionalColumns\" appearance=\"outline\">\r\n        <mat-label>Columns</mat-label>\r\n        <mat-select [formControl]=\"columnsToShow\" multiple (selectionChange)=\"displayColumnsChanged($event)\">\r\n            <mat-option *ngFor=\"let column of columns\" [value]=\"column\">{{column.columnTitle}}</mat-option>\r\n        </mat-select>\r\n    </mat-form-field>\r\n    <!-- Export selected or filtered data to excel -->\r\n    <button *ngIf=\"export\" mat-stroked-button color=\"primary\" (click)=\"eportToExcell()\">\r\n        <mat-icon>import_export</mat-icon> Export\r\n    </button>\r\n    <!-- Indicate number of selected items -->\r\n    <span *ngIf=\"selection.selected.length > 0\" class=\"mat-caption\">{{selection.selected.length}} values selected</span>\r\n</div>\r\n<!-- Table wrapping container -->\r\n<div class=\"table-container\">\r\n    <table mat-table #table [dataSource]=\"dataSource\" matSort [matSortActive]=\"sortActive\"\r\n        [matSortDirection]=\"sortDirection\" style=\"width: 100%;\">\r\n        <!-- Checkbox Column -->\r\n        <ng-container *ngIf=\"multiple\" matColumnDef=\"select\">\r\n            <th mat-header-cell *matHeaderCellDef>\r\n                <mat-checkbox (change)=\"$event ? masterToggle() : null\"\r\n                    [checked]=\"selection.hasValue() && isAllSelected()\"\r\n                    [indeterminate]=\"selection.hasValue() && !isAllSelected()\">\r\n                </mat-checkbox>\r\n            </th>\r\n            <td mat-cell *matCellDef=\"let row\">\r\n                <mat-checkbox (click)=\"$event.stopPropagation()\" (change)=\"toggle($event, row)\"\r\n                    [checked]=\"selection.isSelected(row)\">\r\n                </mat-checkbox>\r\n            </td>\r\n            <ng-container *ngIf=\"totalsRowVisible\">\r\n                <td mat-footer-cell *matFooterCellDef></td>\r\n            </ng-container>\r\n        </ng-container>\r\n        <!-- Table columns -->\r\n        <ng-container *ngFor=\"let column of columns\" [matColumnDef]=\"column.columnDef\" [sticky]=\"column.sticky\"\r\n            [stickyEnd]=\"column.stickyEnd\">\r\n            <!-- Table header -->\r\n            <th mat-header-cell *matHeaderCellDef>\r\n                <!-- Header and search icon -->\r\n                <div fxLayout=\"row\" fxLayoutAlign=\"start center\">\r\n                    <span mat-sort-header>\r\n                        {{ column.columnTitle }}\r\n                    </span>\r\n                    <button *ngIf=\"column.search\" class=\"search-button\" mat-icon-button [matMenuTriggerFor]=\"menu\"\r\n                        (menuOpened)=\"searchInput.focus()\">\r\n                        <mat-icon [ngClass]=\"{'search-active': searchInput.value}\">search</mat-icon>\r\n                    </button>\r\n                </div>\r\n                <!-- Search Menu -->\r\n                <mat-menu #menu=\"matMenu\">\r\n                    <div (click)=\"$event.stopPropagation()\" fxLayout=\"column\"\r\n                        style=\"padding-right: 8px; padding-left: 8px;\">\r\n                        <!-- Search input -->\r\n                        <mat-form-field>\r\n                            <input matInput #searchInput\r\n                                (keyup)=\"applyColumnFilter($event.target, column.columnDef, column.columnTitle, searchType.value);\"\r\n                                [placeholder]=\"column.columnTitle\" [disabled]=\"searchType.value === 'empty'\">\r\n                            <mat-hint>Search</mat-hint>\r\n                            <button mat-button *ngIf=\"searchInput.value\" matSuffix mat-icon-button aria-label=\"Clear\"\r\n                                (click)=\"searchInput.value=''; applyColumnFilter(searchInput, column.columnDef, column.columnTitle, searchType.value)\">\r\n                                <mat-icon>close</mat-icon>\r\n                            </button>\r\n                        </mat-form-field>\r\n                        <!-- Search options -->\r\n                        <div fxLayout=\"row\" fxLayoutAlign=\"end end\">\r\n                            <mat-button-toggle-group name=\"search type\" aria-label=\"Search Type\"\r\n                                #searchType=\"matButtonToggleGroup\" value=\"=\"\r\n                                (change)=\"applyColumnFilter(searchInput, column.columnDef, column.columnTitle, searchType.value)\">\r\n                                <mat-button-toggle value=\"=\" matTooltip=\"Equals\">=</mat-button-toggle>\r\n                                <mat-button-toggle value=\"!=\" matTooltip=\"Not Equals\">\u2260</mat-button-toggle>\r\n                                <!-- <mat-button-toggle value=\">=\">&#62;=</mat-button-toggle>\r\n                            <mat-button-toggle value=\"<=\">&#60;=</mat-button-toggle> -->\r\n                                <mat-button-toggle value=\"empty\" matTooltip=\"Empty Cell\">\" \"</mat-button-toggle>\r\n                            </mat-button-toggle-group>\r\n                        </div>\r\n                    </div>\r\n                </mat-menu>\r\n            </th>\r\n            <!-- Table Cell -->\r\n            <td mat-cell *matCellDef=\"let row\" [class]=\"row[column.cellClassKey]\"\r\n                [attr.data-label]=\"column.columnTitle\" (click)=\"onMatCellClick(row, column);\">\r\n                <ng-container [ngSwitch]=\"column.type\">\r\n                    <!-- Number type columns -->\r\n                    <span *ngSwitchCase=\"'number'\"\r\n                        [ngClass]=\"column.unit?.position === 'before' ? 'unit-before' : 'unit-after'\"\r\n                        [attr.data-unit]=\"row | lodashGet: column.unit?.key\">\r\n                        {{ row | lodashGet: column.columnDef | number }}\r\n                    </span>\r\n                    <!-- Date Type columns -->\r\n                    <span *ngSwitchCase=\"'date'\">\r\n                        {{ row | lodashGet: column.columnDef | date: column.dateFormat ? column.dateFormat :\r\n                        'dd/MM/yyyy, HH:mm' }}\r\n                    </span>\r\n                    <!-- Icon Columns -->\r\n                    <span *ngSwitchCase=\"'icon'\">\r\n                        <ng-container *ngFor=\"let icon of column.icons\">\r\n                            <mat-icon *ngIf=\"icon.value === (row | lodashGet: column.columnDef)\"\r\n                                [style.color]=\"icon.color\" [matTooltip]=\"icon.matTooltip\">{{icon.matIcon}}\r\n                            </mat-icon>\r\n                        </ng-container>\r\n                    </span>\r\n                    <!-- Text Columns -->\r\n                    <span *ngSwitchDefault>\r\n                        {{ row | lodashGet: column.columnDef }}\r\n                    </span>\r\n                </ng-container>\r\n            </td>\r\n\r\n            <ng-container *ngIf=\"totalsRowVisible\">\r\n                <td mat-footer-cell *matFooterCellDef [attr.data-label]=\"column.columnTitle\">\r\n                    <ng-container *ngIf=\"column.total\">\r\n                        {{column.totalValue | number}}\r\n                    </ng-container>\r\n                    <ng-container *ngIf=\"column.total && column.average\">\r\n                        &nbsp;|&nbsp;\r\n                    </ng-container>\r\n                    <ng-container *ngIf=\"column.average\">\r\n                        &mu;&nbsp;{{column.averageValue | number}}\r\n                    </ng-container>\r\n                </td>\r\n            </ng-container>\r\n\r\n        </ng-container>\r\n\r\n        <tr mat-header-row *matHeaderRowDef=\"displayedColumns; sticky: true;\"></tr>\r\n        <tr mat-row *matRowDef=\"let row; columns: displayedColumns;\" (click)=\"_rowClicked(row)\"\r\n            [ngClass]=\"{'row-click': rowClick}\"></tr>\r\n\r\n        <tr class=\"mat-row\" *matNoDataRow>\r\n            <td class=\"mat-cell\" [attr.colspan]=\"displayedColumns.length\">No data</td>\r\n        </tr>\r\n\r\n        <ng-container *ngIf=\"totalsRowVisible\">\r\n            <tr mat-footer-row *matFooterRowDef=\"displayedColumns; sticky: true;\"></tr>\r\n        </ng-container>\r\n\r\n    </table>\r\n</div>\r\n<mat-paginator class=\"mat-paginator-sticky\" [pageSizeOptions]=\"pageSizeOptions ? pageSizeOptions: [50, 100, 200]\">\r\n</mat-paginator>",
                changeDetection: ChangeDetectionStrategy.OnPush,
                styles: [".row-click{cursor:pointer}.search-button{height:24px!important;line-height:24px!important;width:24px!important}.search-button .mat-icon{height:18px!important;line-height:18px!important;width:18px!important}.search-button .material-icons{font-size:18px!important}.search-active{color:#00f}.unit-after:after,.unit-before:before{content:attr(data-unit)}.mat-cell{padding-left:5px;padding-right:5px}.mat-cell,.mat-header-row{text-overflow:ellipsis;white-space:nowrap}@media screen and (min-width:550px){.table-container{max-height:calc(100vh - 150px);overflow:auto}}@media screen and (max-width:550px){.mat-table .mat-row{border-bottom:5px solid #ddd;padding-bottom:5px}.mat-table .mat-header-row{display:flex;flex-wrap:wrap;height:auto;margin-bottom:4%;position:-webkit-sticky;position:sticky;top:0;z-index:2}.mat-table .mat-header-row th.mat-header-cell{align-items:center;display:flex;flex:1;justify-content:space-around;padding:1rem .5rem}.mat-table .mat-header-row th.mat-header-cell>.mat-sort-header-container{padding-left:15px}.mat-table .mat-cell{display:block;font-size:1em;font-weight:700;height:30px;margin-bottom:4%;padding-left:8px;padding-right:8px;text-align:right}.mat-table .mat-cell:before{content:attr(data-label);float:left;font-size:.85em;font-weight:400;text-transform:uppercase}.mat-table .mat-footer-cell{display:block;font-size:1em;font-weight:700;height:30px;margin-bottom:4%;padding-left:8px;padding-right:8px;text-align:right}.mat-table .mat-footer-cell:before{content:attr(data-label);float:left;font-size:.85em;font-weight:400;text-transform:uppercase}.mat-table .mat-cell:last-child{border-bottom:5px solid #ddd}}.mat-button-toggle-label-content{line-height:32px!important}"]
            },] }
];
DynamicTableComponent.ctorParameters = () => [
    { type: String, decorators: [{ type: Inject, args: [LOCALE_ID,] }] },
    { type: XlsxExportService },
    { type: ColumnStorageService }
];
DynamicTableComponent.propDecorators = {
    tableId: [{ type: Input }],
    tableData: [{ type: Input }],
    rowClick: [{ type: Input }],
    cellClick: [{ type: Input }],
    fileName: [{ type: Input }],
    columns: [{ type: Input }],
    pageSizeOptions: [{ type: Input }],
    export: [{ type: Input }],
    filter: [{ type: Input }],
    multiple: [{ type: Input }],
    optionalColumns: [{ type: Input }],
    emitFilteredData: [{ type: Input }],
    rowClicked: [{ type: Output }],
    cellClicked: [{ type: Output }],
    selectedRows: [{ type: Output }],
    filterResult: [{ type: Output }],
    sort: [{ type: ViewChild, args: [MatSort,] }],
    paginator: [{ type: ViewChild, args: [MatPaginator,] }]
};
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZHluYW1pYy10YWJsZS5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiLi4vLi4vLi4vcHJvamVjdHMvbmd4LW1hdC1keW5hbWljLXRhYmxlL3NyYy8iLCJzb3VyY2VzIjpbImxpYi9jb21wb25lbnRzL2R5bmFtaWMtdGFibGUvZHluYW1pYy10YWJsZS5jb21wb25lbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFNBQVMsRUFBVSxLQUFLLEVBQUUsTUFBTSxFQUFFLFlBQVksRUFBRSxTQUFTLEVBQUUsTUFBTSxFQUFFLFNBQVMsRUFBMkMsdUJBQXVCLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDL0ssT0FBTyxFQUFZLGtCQUFrQixFQUFFLE1BQU0seUJBQXlCLENBQUM7QUFDdkUsT0FBTyxFQUFFLE9BQU8sRUFBb0MsTUFBTSx3QkFBd0IsQ0FBQztBQUNuRixPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sNkJBQTZCLENBQUM7QUFDM0QsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLDBCQUEwQixDQUFDO0FBQzFELE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUU3QyxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFFN0MsT0FBTyxFQUFFLGlCQUFpQixFQUFFLE1BQU0sa0RBQWtELENBQUM7QUFDckYsT0FBTyxFQUFFLEdBQUcsSUFBSSxJQUFJLEVBQUUsR0FBRyxJQUFJLElBQUksRUFBRSxTQUFTLEVBQUUsTUFBTSxRQUFRLENBQUM7QUFDN0QsT0FBTyxFQUFFLGVBQWUsRUFBRSxRQUFRLEVBQUUsT0FBTyxFQUFFLE1BQU0sTUFBTSxDQUFDO0FBQzFELE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUUxQyxPQUFPLEVBQUUsb0JBQW9CLEVBQWlCLE1BQU0sb0NBQW9DLENBQUM7QUFxQ3pGLE1BQU0sT0FBTyxxQkFBcUI7SUEwRGhDLFlBQXVDLE1BQWMsRUFDM0Ms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LE9BQU87WUFDckIsY0FBYyxFQUFFLE1BQU07U0FDdkIsQ0FBQyxDQUFDO0lBQ0wsQ0FBQzs7O1lBL2FGLFNBQVMsU0FBQztnQkFDVCxRQUFRLEVBQUUsdUJBQXVCO2dCQUNqQywydVJBQTZDO2dCQUU3QyxlQUFlLEVBQUUsdUJBQXVCLENBQUMsTUFBTTs7YUFDaEQ7Ozt5Q0EyRGMsTUFBTSxTQUFDLFNBQVM7WUFwR3RCLGlCQUFpQjtZQUtqQixvQkFBb0I7OztzQkF1QzFCLEtBQUs7d0JBQ0wsS0FBSzt1QkFDTCxLQUFLO3dCQUNMLEtBQUs7dUJBQ0wsS0FBSztzQkFFTCxLQUFLOzhCQUNMLEtBQUs7cUJBRUwsS0FBSztxQkFDTCxLQUFLO3VCQUNMLEtBQUs7OEJBQ0wsS0FBSzsrQkFDTCxLQUFLO3lCQUVMLE1BQU07MEJBQ04sTUFBTTsyQkFFTixNQUFNOzJCQUNOLE1BQU07bUJBSU4sU0FBUyxTQUFDLE9BQU87d0JBRWpCLFNBQVMsU0FBQyxZQUFZIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQ29tcG9uZW50LCBPbkluaXQsIElucHV0LCBPdXRwdXQsIEV2ZW50RW1pdHRlciwgVmlld0NoaWxkLCBJbmplY3QsIExPQ0FMRV9JRCwgU2ltcGxlQ2hhbmdlcywgT25DaGFuZ2VzLCBBZnRlclZpZXdJbml0LCBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneSB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xyXG5pbXBvcnQgeyBNYXRUYWJsZSwgTWF0VGFibGVEYXRhU291cmNlIH0gZnJvbSAnQGFuZ3VsYXIvbWF0ZXJpYWwvdGFibGUnO1xyXG5pbXBvcnQgeyBNYXRTb3J0LCBNYXRTb3J0YWJsZSwgU29ydCwgU29ydERpcmVjdGlvbiB9IGZyb20gJ0Bhbmd1bGFyL21hdGVyaWFsL3NvcnQnO1xyXG5pbXBvcnQgeyBNYXRQYWdpbmF0b3IgfSBmcm9tICdAYW5ndWxhci9tYXRlcmlhbC9wYWdpbmF0b3InO1xyXG5pbXBvcnQgeyBTZWxlY3Rpb25Nb2RlbCB9IGZyb20gJ0Bhbmd1bGFyL2Nkay9jb2xsZWN0aW9ucyc7XHJcbmltcG9ydCB7IGZvcm1hdERhdGUgfSBmcm9tICdAYW5ndWxhci9jb21tb24nO1xyXG5pbXBvcnQgeyBNYXRDaGVja2JveENoYW5nZSB9IGZyb20gJ0Bhbmd1bGFyL21hdGVyaWFsL2NoZWNrYm94JztcclxuaW1wb3J0IHsgRm9ybUNvbnRyb2wgfSBmcm9tICdAYW5ndWxhci9mb3Jtcyc7XHJcbmltcG9ydCB7IE1hdFNlbGVjdENoYW5nZSB9IGZyb20gJ0Bhbmd1bGFyL21hdGVyaWFsL3NlbGVjdCc7XHJcbmltcG9ydCB7IFhsc3hFeHBvcnRTZXJ2aWNlIH0gZnJvbSAnLi4veGxzeC10YWJsZS1leHBvcnQvc2VydmljZS94bHN4LWV4cG9ydC5zZXJ2aWNlJztcclxuaW1wb3J0IHsgZ2V0IGFzIF9nZXQsIHNldCBhcyBfc2V0LCBjbG9uZURlZXAgfSBmcm9tICdsb2Rhc2gnO1xyXG5pbXBvcnQgeyBCZWhhdmlvclN1YmplY3QsIGludGVydmFsLCBTdWJqZWN0IH0gZnJvbSAncnhqcyc7XHJcbmltcG9ydCB7IGRlYm91bmNlIH0gZnJvbSAncnhqcy9vcGVyYXRvcnMnO1xyXG5pbXBvcnQgeyBTZWFyY2hUZXJtIH0gZnJvbSAnLi4vdGFibGUtc2VhcmNoLWlucHV0L3RhYmxlLXNlYXJjaC1pbnB1dC5jb21wb25lbnQnO1xyXG5pbXBvcnQgeyBDb2x1bW5TdG9yYWdlU2VydmljZSwgQ29sdW1uU3RvcmFnZSB9IGZyb20gJy4uL3NlcnZpY2VzL2NvbHVtbi1zdG9yYWdlLnNlcnZpY2UnO1xyXG5cclxuZXhwb3J0IGludGVyZmFjZSBEeW5hbWljVGFibGVDb2x1bW5EZWZpbml0aW9uIGV4dGVuZHMgRHluYW1pY1RhYmxlQ29sdW1uIHtcclxuICBjb2x1bW5EZWY6IHN0cmluZyxcclxuICBjb2x1bW5UaXRsZTogc3RyaW5nLFxyXG4gIHR5cGU/OiAnbnVtYmVyJyB8ICdkYXRlJyB8ICdpY29uJzsgLy8gbnVtYmVyLCBkYXRlLCBpY29uXHJcbiAgc2VhcmNoPzogYm9vbGVhbjsgLy8gZW5hYmxlIHNlYXJjaCBvbiB0aGlzIGNvbHVtblxyXG4gIHRvdGFsPzogYm9vbGVhbiAvLyBjYWxjdWxhdGUgdGhlIHRvdGFsIG9mIHRoaXMgY29sdW1uLCBvbmx5IG9uIHR5cGUgbnVtYmVyXHJcbiAgYXZlcmFnZT86IGJvb2xlYW4gLy8gY2FsY3VsYXRlIHRoZSBhdmVyYWdlIG9mIHRoaXMgY29sdW1uLCBvbnkgb24gdHlwZSBudW1iZXJcclxuICBzdGlja3k/OiBib29sZWFuIC8vIHN0aWNreSBjb2x1bW5cclxuICBzdGlja3lFbmQ/OiBib29sZWFuIC8vIHN0aWNreSBlbmQgY29sdW1uXHJcbiAgaWNvbnM/OiB7IHZhbHVlOiBhbnksIG1hdEljb246IHN0cmluZywgY29sb3I6IHN0cmluZywgbWF0VG9vbHRpcDogc3RyaW5nIH1bXSAvLyBJY29ucywgb25seSBvbiB0eXBlIGljb25cclxuICBzb3J0PzogJ2FzYycgfCAnZGVzYyc7IC8vIGFzYyBvZiBkZXNjLCBkZWZhdWx0IHNvcnRcclxuICBkYXRlRm9ybWF0Pzogc3RyaW5nOyAvLyBmb3IgZGF0ZXNcclxuICBoaWRkZW4/OiBib29sZWFuOyAvLyBIaWRlIHRoaXMgY29sdW1uXHJcbiAgaWdub3JlU2F2ZT86IGJvb2xlYW47IC8vIElmIHNldCwgdGhpcyBjb2x1bW4gd2lsbCBub3QgYmUgc2F2ZWQgaW4gaW5kZXhlZGRiLCBpbnRlbmRlZCBmb3IgZHluYW1pYyBkYXRlIGNvbHVtbnMgZXRjLiBcclxuICBjZWxsQ2xhc3NLZXk/OiBzdHJpbmc7IC8vIEFwcGx5IGEgY2xhc3MgdG8gYSBjZWxsXHJcbiAgdW5pdD86IHsgLy8gYWRkIHVuaXQgc3RyaW5ncyB0byBudW1iZXJzXHJcbiAgICBrZXk6IHN0cmluZyAvL2pzb24ga2V5IGZvciB0aGUgdW5pdCBzdHJpbmdcclxuICAgIHBvc2l0aW9uOiAnYmVmb3JlJyB8ICdhZnRlcic7IC8vIEJlZm9yZSBvciBhZnRlclxyXG4gIH1cclxufVxyXG5cclxuLy8gRm9yIGNhbGN1bGF0aW9uc1xyXG5pbnRlcmZhY2UgRHluYW1pY1RhYmxlQ29sdW1uIHtcclxuICB0b3RhbFZhbHVlPzogbnVtYmVyO1xyXG4gIGF2ZXJhZ2VWYWx1ZT86IG51bWJlcjtcclxufVxyXG5cclxuZXhwb3J0IGludGVyZmFjZSBEeW5hbWljVGFibGVDZWxsQ2xpY2tSZXN1bHQgeyByb3c6IGFueSwgY29sdW1uOiBzdHJpbmcsIGRhdGE6IHN0cmluZyB9XHJcblxyXG5AQ29tcG9uZW50KHtcclxuICBzZWxlY3RvcjogJ25neC1tYXQtZHluYW1pYy10YWJsZScsXHJcbiAgdGVtcGxhdGVVcmw6ICcuL2R5bmFtaWMtdGFibGUuY29tcG9uZW50Lmh0bWwnLFxyXG4gIHN0eWxlVXJsczogWycuL2R5bmFtaWMtdGFibGUuY29tcG9uZW50LnNjc3MnXSxcclxuICBjaGFuZ2VEZXRlY3Rpb246IENoYW5nZURldGVjdGlvblN0cmF0ZWd5Lk9uUHVzaFxyXG59KVxyXG5leHBvcnQgY2xhc3MgRHluYW1pY1RhYmxlQ29tcG9uZW50PFQ+IGltcGxlbWVudHMgT25Jbml0LCBPbkNoYW5nZXMsIEFmdGVyVmlld0luaXQge1xyXG5cclxuICBASW5wdXQoKSB0YWJsZUlkOiBzdHJpbmc7IC8vIHVuaXF1ZSBJRCBmb3IgdGFibGUgdG8gc2F2ZSBoaWRkZW4gY29sdW1uc1xyXG4gIEBJbnB1dCgpIHRhYmxlRGF0YTogVFtdO1xyXG4gIEBJbnB1dCgpIHJvd0NsaWNrOiBib29sZWFuO1xyXG4gIEBJbnB1dCgpIGNlbGxDbGljazogYm9vbGVhbjtcclxuICBASW5wdXQoKSBmaWxlTmFtZTogc3RyaW5nO1xyXG5cclxuICBASW5wdXQoKSBjb2x1bW5zOiBEeW5hbWljVGFibGVDb2x1bW5EZWZpbml0aW9uW107XHJcbiAgQElucHV0KCkgcGFnZVNpemVPcHRpb25zOiBudW1iZXJbXTtcclxuXHJcbiAgQElucHV0KCkgZXhwb3J0OiBib29sZWFuID0gZmFsc2U7IC8vIEVuYWJsZSBleHBvcnQgZm9yIHRoaXMgdGFibGVcclxuICBASW5wdXQoKSBmaWx0ZXI6IGJvb2xlYW4gPSBmYWxzZTsgLy8gRW5hYmxlIGZpbHRlciBmb3IgdGhpcyB0YWJsZVxyXG4gIEBJbnB1dCgpIG11bHRpcGxlOiBib29sZWFuID0gZmFsc2U7IC8vIEFsbG93IG11bHRpcGxlIHNlbGVjdCBmb3IgdGhpcyB0YWJsZVxyXG4gIEBJbnB1dCgpIG9wdGlvbmFsQ29sdW1uczogYm9vbGVhbiA9IGZhbHNlOyAvLyBTaG93IG9yIGhpZGUgY29sdW1uc1xyXG4gIEBJbnB1dCgpIGVtaXRGaWx0ZXJlZERhdGE6IGJvb2xlYW4gPSBmYWxzZTsgLy8gU2hvdyBvciBoaWRlIGNvbHVtbnNcclxuXHJcbiAgQE91dHB1dCgpIHJvd0NsaWNrZWQ6IEV2ZW50RW1pdHRlcjxUPiA9IG5ldyBFdmVudEVtaXR0ZXI8VD4oKTtcclxuICBAT3V0cHV0KCkgY2VsbENsaWNrZWQ6IEV2ZW50RW1pdHRlcjxEeW5hbWljVGFibGVDZWxsQ2xpY2tSZXN1bHQ+ID0gbmV3IEV2ZW50RW1pdHRlcjxEeW5hbWljVGFibGVDZWxsQ2xpY2tSZXN1bHQ+KCk7XHJcblxyXG4gIEBPdXRwdXQoKSBzZWxlY3RlZFJvd3M6IEV2ZW50RW1pdHRlcjxUW10+ID0gbmV3IEV2ZW50RW1pdHRlcjxUW10+KCk7XHJcbiAgQE91dHB1dCgpIGZpbHRlclJlc3VsdDogRXZlbnRFbWl0dGVyPFRbXT4gPSBuZXcgRXZlbnRFbWl0dGVyPFRbXT4oKTtcclxuXHJcbiAgLy8gQFZpZXdDaGlsZChNYXRUYWJsZSkgdGFibGU6IE1hdFRhYmxlPFQ+O1xyXG5cclxuICBAVmlld0NoaWxkKE1hdFNvcnQpIHNvcnQ6IE1hdFNvcnQ7XHJcblxyXG4gIEBWaWV3Q2hpbGQoTWF0UGFnaW5hdG9yKSBwYWdpbmF0b3I6IE1hdFBhZ2luYXRvcjtcclxuXHJcbiAgc2VsZWN0aW9uID0gbmV3IFNlbGVjdGlvbk1vZGVsPFQ+KHRydWUsIFtdKTtcclxuXHJcbiAgZGlzcGxheWVkQ29sdW1uczogc3RyaW5nW10gPSBbXTtcclxuXHJcbiAgZGF0YVNvdXJjZTogTWF0VGFibGVEYXRhU291cmNlPFQ+ID0gbmV3IE1hdFRhYmxlRGF0YVNvdXJjZSgpO1xyXG5cclxuICB0b3RhbHNSb3dWaXNpYmxlOiBib29sZWFuID0gZmFsc2U7XHJcblxyXG4gIHhsc3hIZWFkZXJzOiBhbnk7XHJcblxyXG4gIC8vIEZvcm1hdHRlZCBkYXRhIGZvciBleHBvcnRpbmcsIGV4cGVjaWFsbHkgdGhlIGRhdGVzXHJcbiAgZXhwb3J0RGF0YTogVFtdO1xyXG5cclxuICAvLyBUaGUgaGlkZGVuIGNvbHVtbnMgZmlsdGVyZWQgb3V0XHJcbiAgY29sdW1uc1RvU2hvdyA9IG5ldyBGb3JtQ29udHJvbCgpO1xyXG5cclxuICBmaWx0ZXJLZXlVcDogQmVoYXZpb3JTdWJqZWN0PHN0cmluZz4gPSBuZXcgQmVoYXZpb3JTdWJqZWN0KCcnKTtcclxuXHJcbiAgLy8gRGVmYXVsdCBzb3J0IGNvbHVtbiBkZWZpbml0aW9uXHJcbiAgc29ydEFjdGl2ZTogc3RyaW5nO1xyXG4gIC8vIERlZmF1bHQgc29ydCBkaXJlY3Rpb25cclxuICBzb3J0RGlyZWN0aW9uOiAnYXNjJyB8ICdkZXNjJztcclxuXHJcbiAgdGFibGVGaWx0ZXJzOiB7IHR5cGU6ICdjb2x1bW4nIHwgJ2dsb2JhbCcsIHJlZmVyZW5jZTogYW55LCBzZWFyY2g6IHN0cmluZyB9W107XHJcbiAgc2VhcmNoTG9hZGluZzogYm9vbGVhbjtcclxuICBjb2x1bW5TZWFyY2gkOiBTdWJqZWN0PFNlYXJjaFRlcm0+ID0gbmV3IFN1YmplY3QoKTtcclxuXHJcbiAgc2F2ZWRDb2x1bW5zTG9hZGluZzogYm9vbGVhbjtcclxuXHJcbiAgY29uc3RydWN0b3IoQEluamVjdChMT0NBTEVfSUQpIHByaXZhdGUgbG9jYWxlOiBzdHJpbmcsXHJcbiAgICBwcml2YXRlIHhsc3hFeHBvcnRTZXJ2aWNlOiBYbHN4RXhwb3J0U2VydmljZSxcclxuICAgIHByaXZhdGUgY29sdW1uU3RvcmFnZVNlcnZpY2U6IENvbHVtblN0b3JhZ2VTZXJ2aWNlKSB7IH1cclxuXHJcbiAgbmdPbkNoYW5nZXMoY2hhbmdlczogU2ltcGxlQ2hhbmdlcyk6IHZvaWQge1xyXG4gICAgLy8gQWRkIGhlYWRlcnMgdG8gb2YgZGF0YSB0byBkaXNwbGF5IGluIHRhYmxlXHJcbiAgICBpZiAoY2hhbmdlcy5jb2x1bW5zICYmIGNoYW5nZXMuY29sdW1ucy5jdXJyZW50VmFsdWUpIHtcclxuICAgICAgdGhpcy5zZXRDb2x1bW5zKCk7XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKGNoYW5nZXMudGFibGVEYXRhLmN1cnJlbnRWYWx1ZSkge1xyXG4gICAgICAvLyBUT0RPOiBUZXN0IHRoaXMgZGVmYXVsdCBzb3J0IGNoYW5nZVxyXG4gICAgICAvLyBpZiAodGhpcy5zb3J0QWN0aXZlKSB7XHJcbiAgICAgIC8vICAgdGhpcy5kYXRhU291cmNlLmRhdGEgPSB0aGlzLnRhYmxlRGF0YS5zb3J0KChhLCBiKSA9PiAoX2dldChhLCB0aGlzLnNvcnRBY3RpdmUpID4gX2dldChiLCB0aGlzLnNvcnRBY3RpdmUpKSA/IHRoaXMuc29ydERpcmVjdGlvbiA9PT0gJ2FzYycgPyAxIDogLTEgOiAoKF9nZXQoYiwgdGhpcy5zb3J0QWN0aXZlKSA+IF9nZXQoYSwgdGhpcy5zb3J0QWN0aXZlKSkgPyB0aGlzLnNvcnREaXJlY3Rpb24gPT09ICdhc2MnID8gLTEgOiAxIDogMCkpO1xyXG4gICAgICAvLyB9IGVsc2Uge1xyXG4gICAgICAvLyAgIHRoaXMuZGF0YVNvdXJjZS5kYXRhID0gdGhpcy50YWJsZURhdGE7XHJcbiAgICAgIC8vIH1cclxuICAgICAgLy8gQ2xlYXIgc2VsZWN0aW9uIGlmIG5ldyBkYXRhIGlzIGNvbW1pbmcgaW5cclxuICAgICAgdGhpcy5zZWxlY3Rpb24uY2xlYXIoKTtcclxuXHJcbiAgICAgIHRoaXMuZGF0YVNvdXJjZS5kYXRhID0gdGhpcy50YWJsZURhdGE7XHJcbiAgICAgIHRoaXMudXBkYXRlQ29sdW1uVG90YWxzKCk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBuZ0FmdGVyVmlld0luaXQoKTogdm9pZCB7XHJcbiAgICB0aGlzLmZpbHRlcktleVVwLnBpcGUoZGVib3VuY2UoKCkgPT4gaW50ZXJ2YWwoMjAwMCkpKS5zdWJzY3JpYmUoZmlsdGVyVmFsdWUgPT4ge1xyXG4gICAgICB0aGlzLnNlYXJjaExvYWRpbmcgPSBmYWxzZTtcclxuICAgICAgLy8gYXBwbHkgdGhlIGZpbHRlciBhZnRlciAyIHNlY29uZHNcclxuICAgICAgdGhpcy5kYXRhU291cmNlLmZpbHRlciA9IGZpbHRlclZhbHVlO1xyXG4gICAgICBpZiAodGhpcy5kYXRhU291cmNlLnBhZ2luYXRvcikge1xyXG4gICAgICAgIHRoaXMuZGF0YVNvdXJjZS5wYWdpbmF0b3IuZmlyc3RQYWdlKCk7XHJcbiAgICAgIH1cclxuICAgICAgLy8gdXBkYXRlIHRvdGFsc1xyXG4gICAgICB0aGlzLnVwZGF0ZUNvbHVtblRvdGFscygpO1xyXG4gICAgICAvLyBJZiB0aGUgZmxhZyBpcyBzZXQsIGVtaXQgdGhlIGZpbHRlcmVkIGRhdGFcclxuICAgICAgaWYgKHRoaXMuZW1pdEZpbHRlcmVkRGF0YSkge1xyXG4gICAgICAgIHRoaXMuZ2V0RmlsdGVyZWREYXRhKCk7XHJcbiAgICAgIH1cclxuICAgIH0pO1xyXG4gICAgdGhpcy5kYXRhU291cmNlLnNvcnQgPSB0aGlzLnNvcnQ7XHJcbiAgICB0aGlzLmRhdGFTb3VyY2UucGFnaW5hdG9yID0gdGhpcy5wYWdpbmF0b3I7XHJcblxyXG4gIH1cclxuXHJcbiAgbmdPbkluaXQoKTogdm9pZCB7XHJcbiAgICB0aGlzLmRhdGFTb3VyY2Uuc29ydGluZ0RhdGFBY2Nlc3NvciA9IChkYXRhLCBhdHRyaWJ1dGUpID0+IF9nZXQoZGF0YSwgYXR0cmlidXRlKTtcclxuICAgIC8vIENoYW5nZWQgdGhpcyBzb3J0IGZ1bmN0aW9uIGZyb20gdGhlIHNvdXJjZSB0byBjb21wYXJlIGFscGhhIG51bWVyaWNzIGh0dHBzOi8vc3RhY2tvdmVyZmxvdy5jb20vYS82NjE1NzA0NC82MDQ0MjY5XHJcbiAgICAvLyBodHRwczovL2dpdGh1Yi5jb20vYW5ndWxhci9jb21wb25lbnRzL2Jsb2IvbWFzdGVyL3NyYy9tYXRlcmlhbC90YWJsZS90YWJsZS1kYXRhLXNvdXJjZS50cyNMMTY1XHJcbiAgICB0aGlzLmRhdGFTb3VyY2Uuc29ydERhdGEgPSAoZGF0YTogVFtdLCBzb3J0OiBNYXRTb3J0KSA9PiB7XHJcbiAgICAgIGNvbnN0IGFjdGl2ZSA9IHNvcnQuYWN0aXZlO1xyXG4gICAgICBjb25zdCBkaXJlY3Rpb24gPSBzb3J0LmRpcmVjdGlvbjtcclxuICAgICAgaWYgKCFhY3RpdmUgfHwgZGlyZWN0aW9uID09ICcnKSB7IHJldHVybiBkYXRhOyB9XHJcblxyXG4gICAgICByZXR1cm4gZGF0YS5zb3J0KChhLCBiKSA9PiB7XHJcbiAgICAgICAgbGV0IHZhbHVlQSA9IHRoaXMuZGF0YVNvdXJjZS5zb3J0aW5nRGF0YUFjY2Vzc29yKGEsIGFjdGl2ZSk7XHJcbiAgICAgICAgbGV0IHZhbHVlQiA9IHRoaXMuZGF0YVNvdXJjZS5zb3J0aW5nRGF0YUFjY2Vzc29yKGIsIGFjdGl2ZSk7XHJcblxyXG4gICAgICAgIGNvbnN0IHZhbHVlQVR5cGUgPSB0eXBlb2YgdmFsdWVBO1xyXG4gICAgICAgIGNvbnN0IHZhbHVlQlR5cGUgPSB0eXBlb2YgdmFsdWVCO1xyXG5cclxuICAgICAgICBpZiAodmFsdWVBVHlwZSAhPT0gdmFsdWVCVHlwZSkge1xyXG4gICAgICAgICAgaWYgKHZhbHVlQVR5cGUgPT09ICdudW1iZXInKSB7IHZhbHVlQSArPSAnJzsgfVxyXG4gICAgICAgICAgaWYgKHZhbHVlQlR5cGUgPT09ICdudW1iZXInKSB7IHZhbHVlQiArPSAnJzsgfVxyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgbGV0IGNvbXBhcmF0b3JSZXN1bHQgPSAwO1xyXG4gICAgICAgIGlmICh2YWx1ZUEgIT0gbnVsbCAmJiB2YWx1ZUIgIT0gbnVsbCkge1xyXG4gICAgICAgICAgLy8gISBUaGlzIGlzIHRoZSBJZiB0aGF0IEkgY2hhbmdlZCBodHRwczovL3N0YWNrb3ZlcmZsb3cuY29tL2EvNjYxNTcwNDQvNjA0NDI2OVxyXG4gICAgICAgICAgaWYgKHZhbHVlQVR5cGUgPT09ICdzdHJpbmcnICYmIHZhbHVlQlR5cGUgPT09ICdzdHJpbmcnKSB7XHJcbiAgICAgICAgICAgIGNvbXBhcmF0b3JSZXN1bHQgPSAodmFsdWVBIGFzIHN0cmluZykubG9jYWxlQ29tcGFyZSh2YWx1ZUIgYXMgc3RyaW5nLCAnZW4nLCB7IG51bWVyaWM6IHRydWUgfSlcclxuICAgICAgICAgIH0gZWxzZSBpZiAodmFsdWVBID4gdmFsdWVCKSB7XHJcbiAgICAgICAgICAgIGNvbXBhcmF0b3JSZXN1bHQgPSAxO1xyXG4gICAgICAgICAgfSBlbHNlIGlmICh2YWx1ZUEgPCB2YWx1ZUIpIHtcclxuICAgICAgICAgICAgY29tcGFyYXRvclJlc3VsdCA9IC0xO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH0gZWxzZSBpZiAodmFsdWVBICE9IG51bGwpIHtcclxuICAgICAgICAgIGNvbXBhcmF0b3JSZXN1bHQgPSAxO1xyXG4gICAgICAgIH0gZWxzZSBpZiAodmFsdWVCICE9IG51bGwpIHtcclxuICAgICAgICAgIGNvbXBhcmF0b3JSZXN1bHQgPSAtMTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIHJldHVybiBjb21wYXJhdG9yUmVzdWx0ICogKGRpcmVjdGlvbiA9PSAnYXNjJyA/IDEgOiAtMSk7XHJcbiAgICAgIH0pO1xyXG4gICAgfVxyXG4gICAgLy8gU2VhcmNoIGZvciBuZXN0ZWQgb2JqZWN0c1xyXG4gICAgdGhpcy5kYXRhU291cmNlLmZpbHRlclByZWRpY2F0ZSA9IChkYXRhLCBmaWx0ZXI6IHN0cmluZykgPT4ge1xyXG4gICAgICBsZXQgdmFsaWRSb3cgPSB0cnVlO1xyXG4gICAgICBpZiAoIWZpbHRlcilcclxuICAgICAgICByZXR1cm4gdmFsaWRSb3c7XHJcbiAgICAgIC8vIHR5cGV8c2VhcmNoU3RyaW5nOmNvbHVtbiNzZWFyY2hUeXBlLHR5cGV8c2VhcmNoU3RyaW5nOmNvbHVtbiNzZWFyY2hUeXBlLi4uXHJcbiAgICAgIGNvbnN0IHRlcm1zID0gZmlsdGVyLnNwbGl0KCcsJyk7IC8vIFNwbGl0IG11bHRpcGxlIHNlYXJjaFxyXG4gICAgICB0ZXJtcy5zb21lKHRlcm0gPT4ge1xyXG4gICAgICAgIGxldCBbdHlwZSwgY3JpdGVyaWFdID0gdGVybS5zcGxpdCgnfCcpOyAvLyBTcGxpdCBnbG9iYWwgLyBjb2x1bW4gc2VhcmNoXHJcbiAgICAgICAgbGV0IGRhdGFTdHJpbmcgPSAnJztcclxuICAgICAgICBsZXQgc2VhcmNoVHlwZTsgLy8gdHlwZSBvZiBzZWFyY2ggaW4gYSBjb2x1bW5cclxuICAgICAgICAvLyBsZXQgY3JpdGVyaWE7XHJcbiAgICAgICAgaWYgKHR5cGUgPT09ICdnbG9iYWwnKSB7XHJcbiAgICAgICAgICAvLyBTZWFyY2ggQWxsXHJcbiAgICAgICAgICB0aGlzLmNvbHVtbnMuZmlsdGVyKGMgPT4gYy5zZWFyY2gpLm1hcChjID0+IGMuY29sdW1uRGVmKS5mb3JFYWNoKGNvbHVtbiA9PiB7XHJcbiAgICAgICAgICAgIGNvbnN0IGNlbGxEYXRhID0gX2dldChkYXRhLCBjb2x1bW4pXHJcbiAgICAgICAgICAgIGlmIChjZWxsRGF0YSlcclxuICAgICAgICAgICAgICBkYXRhU3RyaW5nICs9IGNlbGxEYXRhXHJcbiAgICAgICAgICB9KTtcclxuICAgICAgICAgIC8vIFN0cmluZyBjb250YWlucy9lcXVhbHMgaW4gYWxsIGNvbHVtbnNcclxuICAgICAgICAgIGlmICghZGF0YVN0cmluZyB8fCBkYXRhU3RyaW5nLnRvU3RyaW5nKCkudG9Mb3dlckNhc2UoKS5pbmRleE9mKGNyaXRlcmlhLnRvTG93ZXJDYXNlKCkpID09PSAtMSkge1xyXG4gICAgICAgICAgICB2YWxpZFJvdyA9IGZhbHNlO1xyXG4gICAgICAgICAgICByZXR1cm4gdHJ1ZTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgY29uc3QgW3NlYXJjaFN0cmluZywgY29sdW1uQW5kVHlwZV0gPSBjcml0ZXJpYS5zcGxpdCgnOicpOyAvLyBTcGxpdCBzZWFyY2ggc3RyaW5nIGFuZCBjcml0ZXJpYVxyXG4gICAgICAgICAgbGV0IGNvbHVtbjtcclxuICAgICAgICAgIFtjb2x1bW4sIHNlYXJjaFR5cGVdID0gY29sdW1uQW5kVHlwZS5zcGxpdCgnIycpOyAvLyBTcGxpdCBjb2x1bW4gYW5kIHR5cGUgb2Ygc2VhcmNoXHJcbiAgICAgICAgICBjcml0ZXJpYSA9IHNlYXJjaFN0cmluZztcclxuICAgICAgICAgIGRhdGFTdHJpbmcgPSBfZ2V0KGRhdGEsIGNvbHVtbik7IC8vIGdldCB0aGUgZGF0YVxyXG4gICAgICAgICAgaWYgKHNlYXJjaFR5cGUgPT09ICchPScpIHtcclxuICAgICAgICAgICAgLy8gU3RyaW5nIGNvbnRhaW5zL2VxdWFscyBpbiBhbGwgY29sdW1uc1xyXG4gICAgICAgICAgICBpZiAoIWRhdGFTdHJpbmcgfHwgZGF0YVN0cmluZy50b1N0cmluZygpLnRvTG93ZXJDYXNlKCkuaW5kZXhPZihjcml0ZXJpYS50b0xvd2VyQ2FzZSgpKSAhPT0gLTEpIHtcclxuICAgICAgICAgICAgICB2YWxpZFJvdyA9IGZhbHNlO1xyXG4gICAgICAgICAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICB9IGVsc2UgaWYgKHNlYXJjaFR5cGUgPT09ICdlbXB0eScpIHtcclxuICAgICAgICAgICAgaWYgKGRhdGFTdHJpbmcpIHtcclxuICAgICAgICAgICAgICB2YWxpZFJvdyA9IGZhbHNlO1xyXG4gICAgICAgICAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICAvLyBTdHJpbmcgY29udGFpbnMvZXF1YWxzIGluIGFsbCBjb2x1bW5zXHJcbiAgICAgICAgICAgIGlmICghZGF0YVN0cmluZyB8fCBkYXRhU3RyaW5nLnRvU3RyaW5nKCkudG9Mb3dlckNhc2UoKS5pbmRleE9mKGNyaXRlcmlhLnRvTG93ZXJDYXNlKCkpID09PSAtMSkge1xyXG4gICAgICAgICAgICAgIHZhbGlkUm93ID0gZmFsc2U7XHJcbiAgICAgICAgICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgIH0pO1xyXG4gICAgICByZXR1cm4gdmFsaWRSb3c7XHJcbiAgICB9O1xyXG4gIH1cclxuXHJcbiAgdXBkYXRlWExTWEhlYWRlcnMoKSB7XHJcbiAgICB0aGlzLnhsc3hIZWFkZXJzID0ge31cclxuICAgIHRoaXMuY29sdW1uc1RvU2hvdy52YWx1ZS5mb3JFYWNoKGMgPT4ge1xyXG4gICAgICB0aGlzLnhsc3hIZWFkZXJzW2MuY29sdW1uRGVmXSA9IGMuY29sdW1uVGl0bGVcclxuICAgIH0pXHJcbiAgfVxyXG5cclxuICB1cGRhdGVDb2x1bW5Ub3RhbHMoKSB7XHJcbiAgICBpZiAoIXRoaXMuZGF0YVNvdXJjZSkge1xyXG4gICAgICByZXR1cm47XHJcbiAgICB9XHJcbiAgICB0aGlzLmNvbHVtbnMubWFwKGNvbCA9PiB7XHJcbiAgICAgIGlmICgoY29sLnRvdGFsIHx8IGNvbC5hdmVyYWdlKSkge1xyXG4gICAgICAgIHRoaXMudG90YWxzUm93VmlzaWJsZSA9IHRydWU7XHJcbiAgICAgICAgaWYgKHRoaXMuZGF0YVNvdXJjZS5maWx0ZXJlZERhdGEubGVuZ3RoID4gMCkge1xyXG4gICAgICAgICAgY29sLnRvdGFsVmFsdWUgPSB0aGlzLmRhdGFTb3VyY2UuZmlsdGVyZWREYXRhLm1hcCh0ID0+IF9nZXQodCwgY29sLmNvbHVtbkRlZikpLnJlZHVjZSgoYWNjLCB2YWx1ZSkgPT4gYWNjICsgKHZhbHVlID8gdmFsdWUgOiAwKSwgMCk7XHJcbiAgICAgICAgICBpZiAoaXNOYU4oY29sLnRvdGFsVmFsdWUpKSB7XHJcbiAgICAgICAgICAgIGNvbC50b3RhbFZhbHVlID0gMDtcclxuICAgICAgICAgICAgY29sLmF2ZXJhZ2VWYWx1ZSA9IDA7XHJcbiAgICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICBjb2wuYXZlcmFnZVZhbHVlID0gY29sLnRvdGFsVmFsdWUgLyB0aGlzLmRhdGFTb3VyY2UuZmlsdGVyZWREYXRhLmxlbmd0aDtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgY29sLnRvdGFsVmFsdWUgPSAwO1xyXG4gICAgICAgICAgY29sLmF2ZXJhZ2VWYWx1ZSA9IDA7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICAgIHJldHVybiBjb2w7XHJcbiAgICB9KTtcclxuICB9XHJcblxyXG4gIGFwcGx5RmlsdGVyKHNlYXJjaFRlcm1zOiBTZWFyY2hUZXJtW10pIHtcclxuICAgIHRoaXMuc2VhcmNoTG9hZGluZyA9IHRydWU7XHJcbiAgICBsZXQgZmlsdGVyU3RyaW5nO1xyXG4gICAgc2VhcmNoVGVybXMuZm9yRWFjaCh0ZXJtID0+IHtcclxuICAgICAgLy8gdHlwZTogR2xvYmFsIG9yIGluIGEgY29sdW1uXHJcbiAgICAgIC8vIHxzZWFyY2hTdHJpbmc6IHRoZSB0ZXh0L251bWJlciBzZWFyY2hpbmcgZm9yXHJcbiAgICAgIC8vIDpjb2x1bW46IHdoZW4gdHlwZSBpcyBjb2x1bW4sIHRoaXMgZmllbGQgaXMgc2V0XHJcbiAgICAgIC8vICNzZWFyY2hUeXBlID0gIT0gPj0gPD0gZW1wdHlcclxuICAgICAgLy8gdHlwZXxzZWFyY2hTdHJpbmc6Y29sdW1uI3NlYXJjaFR5cGUsdHlwZXxzZWFyY2hTdHJpbmc6Y29sdW1uI3NlYXJjaFR5cGUuLi5cclxuICAgICAgY29uc3QgbmV3VGVybSA9IGAke3Rlcm0udHlwZX18JHt0ZXJtLnNlYXJjaH0ke3Rlcm0udHlwZSA9PT0gJ2NvbHVtbicgPyAnOicgKyB0ZXJtLmNvbHVtbiArICcjJyArIHRlcm0uc2VhcmNoVHlwZSA6ICcnfWA7XHJcbiAgICAgIGlmIChmaWx0ZXJTdHJpbmcpXHJcbiAgICAgICAgZmlsdGVyU3RyaW5nICs9IGAsJHtuZXdUZXJtfWA7XHJcbiAgICAgIGVsc2VcclxuICAgICAgICBmaWx0ZXJTdHJpbmcgPSBuZXdUZXJtO1xyXG4gICAgfSlcclxuICAgIHRoaXMuZmlsdGVyS2V5VXAubmV4dChmaWx0ZXJTdHJpbmcpO1xyXG4gIH1cclxuXHJcbiAgYXBwbHlDb2x1bW5GaWx0ZXIoZWxlbWVudDogYW55LCBjb2x1bW46IGFueSwgY29sdW1uVGl0bGU6IHN0cmluZywgc2VhcmNoVHlwZTogJz0nIHwgJyE9JyB8ICc+PScgfCAnPD0nIHwgJ2VtcHR5Jyk6IHZvaWQge1xyXG4gICAgLy9cclxuICAgIGlmIChzZWFyY2hUeXBlICYmIHNlYXJjaFR5cGUgIT09ICdlbXB0eScgJiYgIWVsZW1lbnQudmFsdWUpXHJcbiAgICAgIHJldHVybjtcclxuXHJcbiAgICB0aGlzLnNlYXJjaExvYWRpbmcgPSB0cnVlO1xyXG4gICAgLy8gU2VuZCBkYXRhIHRvIHRhYmxlLXNlYXJjaC1pbnB1dCBhbmQgYWRkIGEgY2hpcFxyXG4gICAgdGhpcy5jb2x1bW5TZWFyY2gkLm5leHQoeyB0eXBlOiAnY29sdW1uJywgY29sdW1uOiBjb2x1bW4sIGNvbHVtblRpdGxlOiBjb2x1bW5UaXRsZSwgaW5wdXRSZWZlcmVuY2U6IGVsZW1lbnQsIHNlYXJjaDogZWxlbWVudC52YWx1ZSwgc2VhcmNoVHlwZTogc2VhcmNoVHlwZSB9KTtcclxuICB9XHJcblxyXG4gIF9yb3dDbGlja2VkKHJvdzogYW55KTogdm9pZCB7XHJcbiAgICBpZiAoIXRoaXMucm93Q2xpY2spXHJcbiAgICAgIHJldHVybjtcclxuICAgIHRoaXMucm93Q2xpY2tlZC5lbWl0KHJvdyk7XHJcbiAgfVxyXG5cclxuICBvbk1hdENlbGxDbGljayhyb3c6IGFueSwgY29sdW1uOiBEeW5hbWljVGFibGVDb2x1bW5EZWZpbml0aW9uKTogdm9pZCB7XHJcbiAgICBpZiAoIXRoaXMuY2VsbENsaWNrKVxyXG4gICAgICByZXR1cm47XHJcblxyXG4gICAgdGhpcy5jZWxsQ2xpY2tlZC5lbWl0KHsgcm93OiByb3csIGNvbHVtbjogY29sdW1uLmNvbHVtbkRlZiwgZGF0YTogX2dldChyb3csIGNvbHVtbi5jb2x1bW5EZWYpIH0pO1xyXG4gIH1cclxuXHJcbiAgLyoqIFdoZXRoZXIgdGhlIG51bWJlciBvZiBzZWxlY3RlZCBlbGVtZW50cyBtYXRjaGVzIHRoZSB0b3RhbCBudW1iZXIgb2Ygcm93cy4gKi9cclxuICBpc0FsbFNlbGVjdGVkKCkge1xyXG4gICAgY29uc3QgbnVtU2VsZWN0ZWQgPSB0aGlzLnNlbGVjdGlvbi5zZWxlY3RlZC5sZW5ndGg7XHJcbiAgICBjb25zdCBudW1Sb3dzID0gdGhpcy5kYXRhU291cmNlLmRhdGEubGVuZ3RoO1xyXG4gICAgcmV0dXJuIG51bVNlbGVjdGVkID09PSBudW1Sb3dzO1xyXG4gIH1cclxuXHJcbiAgLyoqIFNlbGVjdHMgYWxsIHJvd3MgaWYgdGhleSBhcmUgbm90IGFsbCBzZWxlY3RlZDsgb3RoZXJ3aXNlIGNsZWFyIHNlbGVjdGlvbi4gKi9cclxuICBtYXN0ZXJUb2dnbGUoKSB7XHJcbiAgICB0aGlzLmlzQWxsU2VsZWN0ZWQoKSA/XHJcbiAgICAgIHRoaXMuc2VsZWN0aW9uLmNsZWFyKCkgOlxyXG4gICAgICB0aGlzLmRhdGFTb3VyY2UuZmlsdGVyZWREYXRhLmZvckVhY2gocm93ID0+IHRoaXMuc2VsZWN0aW9uLnNlbGVjdChyb3cpKTtcclxuXHJcbiAgICB0aGlzLmVtaXRTZWxlY3RlZCgpO1xyXG4gIH1cclxuXHJcbiAgdG9nZ2xlKGV2ZW50OiBNYXRDaGVja2JveENoYW5nZSwgcm93OiBUKTogdm9pZCB7XHJcbiAgICBpZiAoZXZlbnQpIHRoaXMuc2VsZWN0aW9uLnRvZ2dsZShyb3cpXHJcbiAgICB0aGlzLmVtaXRTZWxlY3RlZCgpO1xyXG4gIH1cclxuXHJcbiAgZW1pdFNlbGVjdGVkKCk6IHZvaWQge1xyXG4gICAgdGhpcy5zZWxlY3RlZFJvd3MuZW1pdCh0aGlzLnNlbGVjdGlvbi5zZWxlY3RlZCk7XHJcbiAgfVxyXG5cclxuICBzZXRDb2x1bW5zKCk6IHZvaWQge1xyXG4gICAgdGhpcy5zZXREZWZhdWx0U29ydGluZygpO1xyXG4gICAgLy8gQ2hlY2sgZm9yIHNhdmVkIGNvbHVtbnMgaW4gaW5kZXhlZERCXHJcbiAgICBpZiAodGhpcy50YWJsZUlkKSB7XHJcbiAgICAgIHRoaXMuc2F2ZWRDb2x1bW5zTG9hZGluZyA9IHRydWU7XHJcbiAgICAgIC8vIFRPRE86IHdhaXQgaGVyZSBmb3IgdGhlIGRiXHJcbiAgICAgIGlmICh0aGlzLmNvbHVtblN0b3JhZ2VTZXJ2aWNlLmlzRGJPcGVuKCkpIHtcclxuICAgICAgICB0aGlzLmNvbHVtblN0b3JhZ2VTZXJ2aWNlLnJlYWQodGhpcy50YWJsZUlkKS5zdWJzY3JpYmUocmVzID0+IHtcclxuICAgICAgICAgIHRoaXMuc2V0U2F2ZWRDb2x1bW5TZWxlY3Rpb24ocmVzKTtcclxuICAgICAgICB9KTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICAvLyBXYWl0IGZvciB0aGUgREIgdG8gd2FrZSB1cCBhbmQgdGhlbiBxdWVyeVxyXG4gICAgICAgIHNldFRpbWVvdXQoKCkgPT4ge1xyXG4gICAgICAgICAgdGhpcy5jb2x1bW5TdG9yYWdlU2VydmljZS5yZWFkKHRoaXMudGFibGVJZCkuc3Vic2NyaWJlKHJlcyA9PiB7XHJcbiAgICAgICAgICAgIHRoaXMuc2V0U2F2ZWRDb2x1bW5TZWxlY3Rpb24ocmVzKTtcclxuICAgICAgICAgIH0pO1xyXG4gICAgICAgIH0sIDUwMCk7XHJcbiAgICAgIH1cclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIHRoaXMuc2V0U3RhdGljQ29sdW1ucygpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgc2V0U3RhdGljQ29sdW1ucygpOiB2b2lkIHtcclxuICAgIC8vIExpc3Qgb2YgYWxsIGNvbHVtbnMgdG8gc2hvdyBpbiB0aGUgdmlld1xyXG4gICAgdGhpcy5kaXNwbGF5ZWRDb2x1bW5zID0gW107XHJcbiAgICAvLyBUb3RhbHMgcm93IHN0YXJ0cyBhcyBmYWxzZSB1bnRpbGwgaW5zcGVjdGlvbiBvZiBjb2x1bW4gZGVmaW5pdGlvbnNcclxuICAgIHRoaXMudG90YWxzUm93VmlzaWJsZSA9IGZhbHNlO1xyXG4gICAgLy8gYWRkIHRoZSByZXN0IG9mIG5vbiBoaWRkZW4gY29sdW1ucyB0byB0aGUgbGlzdFxyXG4gICAgdGhpcy5kaXNwbGF5ZWRDb2x1bW5zID0gdGhpcy5jb2x1bW5zLmZpbHRlcihjID0+ICFjLmhpZGRlbikubWFwKGMgPT4gYy5jb2x1bW5EZWYpO1xyXG4gICAgLy8gSWYgbXVsdGlwbGUgc2VsZWN0IGlzIGVuYWJsZWQsIGFkZCBzZWxlY3QgdG8gdGhlIGZyb20gb2YgdGhlIGFycmF5XHJcbiAgICBpZiAodGhpcy5tdWx0aXBsZSkgdGhpcy5kaXNwbGF5ZWRDb2x1bW5zLnVuc2hpZnQoJ3NlbGVjdCcpO1xyXG4gICAgLy8gc2V0IHZpc2libGUgY29sdW1ucyBhcyBjaGVja2VkIGluIHRoZSBzZWxlY3RvclxyXG4gICAgdGhpcy5jb2x1bW5zVG9TaG93LnNldFZhbHVlKHRoaXMuY29sdW1ucy5maWx0ZXIoYyA9PiAhYy5oaWRkZW4pKTtcclxuXHJcbiAgICB0aGlzLnVwZGF0ZUNvbHVtblRvdGFscygpO1xyXG4gIH1cclxuXHJcbiAgZGlzcGxheUNvbHVtbnNDaGFuZ2VkKGV2ZW50OiBNYXRTZWxlY3RDaGFuZ2UpOiB2b2lkIHtcclxuICAgIHRoaXMuZGlzcGxheWVkQ29sdW1ucyA9IGV2ZW50LnZhbHVlLm1hcChjID0+IGMuY29sdW1uRGVmKTtcclxuICAgIGlmICh0aGlzLm11bHRpcGxlKSB0aGlzLmRpc3BsYXllZENvbHVtbnMudW5zaGlmdCgnc2VsZWN0Jyk7XHJcbiAgICAvLyBzYXZlIHRoZSBjdXJyZW50IHZpc2libGUgY29sdW1uc1xyXG4gICAgdGhpcy5zYXZlQ3VycmVudENvbHVtblNlbGVjdGlvbih0aGlzLmRpc3BsYXllZENvbHVtbnMpO1xyXG4gIH1cclxuXHJcbiAgZXBvcnRUb0V4Y2VsbCgpOiB2b2lkIHtcclxuICAgIHRoaXMudXBkYXRlWExTWEhlYWRlcnMoKTtcclxuICAgIHRoaXMuZm9ybWF0RXhwb3J0RGF0YSgpO1xyXG4gICAgdGhpcy54bHN4RXhwb3J0U2VydmljZS5leHBvcnRFeGNlbCh0aGlzLmV4cG9ydERhdGEsIHRoaXMueGxzeEhlYWRlcnMsIHRoaXMuZmlsZU5hbWUgPyB0aGlzLmZpbGVOYW1lIDogJ0V4cG9ydCcpO1xyXG4gIH1cclxuXHJcbiAgZ2V0RmlsdGVyZWREYXRhKCk6IHZvaWQge1xyXG4gICAgdGhpcy5jbG9uZURhdGEoKTtcclxuICAgIHRoaXMuZmlsdGVyUmVzdWx0LmVtaXQodGhpcy5leHBvcnREYXRhKTtcclxuICB9XHJcblxyXG4gIGNsb25lRGF0YSgpOiB2b2lkIHtcclxuICAgIC8vIEZvcm1hdCBkYXRlcyBmb3IgZXhwb3J0aW5nLCB0ZW1wXHJcbiAgICBpZiAodGhpcy5zZWxlY3Rpb24uaGFzVmFsdWUoKSkge1xyXG4gICAgICAvLyBFeHBvcnQgc2VsZWN0ZWQgZGF0YVxyXG4gICAgICB0aGlzLmV4cG9ydERhdGEgPSB0aGlzLnNlbGVjdGlvbi5zZWxlY3RlZC5tYXAoYSA9PiBjbG9uZURlZXAoYSkpO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgLy8gRXhwb3J0IGZpbHRlcmVkIGRhdGEgYW5kIHNvcnRlZFxyXG4gICAgICB0aGlzLmV4cG9ydERhdGEgPSB0aGlzLmRhdGFTb3VyY2Uuc29ydERhdGEodGhpcy5kYXRhU291cmNlLmZpbHRlcmVkRGF0YSwgdGhpcy5kYXRhU291cmNlLnNvcnQpLm1hcChhID0+IGNsb25lRGVlcChhKSk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBmb3JtYXRFeHBvcnREYXRhKCk6IHZvaWQge1xyXG4gICAgdGhpcy5jbG9uZURhdGEoKTtcclxuICAgIC8vIElmIHRoZSBjb2x1bW5zIGNvbnRhaW4gYSBkYXRlXHJcbiAgICBsZXQgZGF0ZUNvbHVtbnMgPSB0aGlzLmNvbHVtbnNUb1Nob3cudmFsdWUuZmlsdGVyKGUgPT4gZS50eXBlID09PSAnZGF0ZScpXHJcbiAgICBpZiAoZGF0ZUNvbHVtbnMgJiYgZGF0ZUNvbHVtbnMubGVuZ3RoID4gMCkge1xyXG4gICAgICB0aGlzLmV4cG9ydERhdGEgPSB0aGlzLmV4cG9ydERhdGEubWFwKHRkID0+IHtcclxuICAgICAgICBkYXRlQ29sdW1ucy5mb3JFYWNoKGNvbCA9PiB7XHJcbiAgICAgICAgICBpZiAoX2dldCh0ZCwgY29sLmNvbHVtbkRlZikpXHJcbiAgICAgICAgICAgIF9zZXQodGQsIGNvbC5jb2x1bW5EZWYsIGZvcm1hdERhdGUoX2dldCh0ZCwgY29sLmNvbHVtbkRlZiksIGNvbC5kYXRlRm9ybWF0ID8gY29sLmRhdGVGb3JtYXQgOiAnZGQvTU0veXl5eSwgSEg6bW0nLCB0aGlzLmxvY2FsZSkpO1xyXG4gICAgICAgIH0pO1xyXG4gICAgICAgIHJldHVybiB0ZDtcclxuICAgICAgfSlcclxuICAgIH1cclxuICB9XHJcblxyXG4gIG5lc3RlZEZpbHRlckNoZWNrKHNlYXJjaCwgZGF0YSwga2V5KSB7XHJcbiAgICBpZiAodHlwZW9mIGRhdGFba2V5XSA9PT0gJ29iamVjdCcpIHtcclxuICAgICAgZm9yIChjb25zdCBrIGluIGRhdGFba2V5XSkge1xyXG4gICAgICAgIGlmIChkYXRhW2tleV1ba10gIT09IG51bGwpIHtcclxuICAgICAgICAgIHNlYXJjaCA9IHRoaXMubmVzdGVkRmlsdGVyQ2hlY2soc2VhcmNoLCBkYXRhW2tleV0sIGspO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfSBlbHNlIHtcclxuICAgICAgc2VhcmNoICs9IGRhdGFba2V5XTtcclxuICAgIH1cclxuICAgIHJldHVybiBzZWFyY2g7XHJcbiAgfVxyXG5cclxuICBzZXREZWZhdWx0U29ydGluZygpOiB2b2lkIHtcclxuICAgIHRoaXMuY29sdW1ucy5zb21lKGNvbCA9PiB7XHJcbiAgICAgIGlmIChjb2wuc29ydCkge1xyXG4gICAgICAgIHRoaXMuc29ydEFjdGl2ZSA9IGNvbC5jb2x1bW5EZWY7XHJcbiAgICAgICAgdGhpcy5zb3J0RGlyZWN0aW9uID0gY29sLnNvcnQ7XHJcbiAgICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICAgIH1cclxuICAgIH0pO1xyXG4gIH1cclxuXHJcbiAgc2V0U2F2ZWRDb2x1bW5TZWxlY3Rpb24oc2F2ZWQ6IENvbHVtblN0b3JhZ2UpOiB2b2lkIHtcclxuICAgIHRoaXMuc2F2ZWRDb2x1bW5zTG9hZGluZyA9IGZhbHNlO1xyXG4gICAgaWYgKCFzYXZlZCB8fCBzYXZlZC52aXNpYmxlQ29sdW1ucy5sZW5ndGggPT09IDApIHtcclxuICAgICAgdGhpcy5zZXRTdGF0aWNDb2x1bW5zKCk7XHJcbiAgICAgIHJldHVybjtcclxuICAgIH1cclxuXHJcbiAgICAvLyBzZXQgdGhlIGNvbHVtbiBzZWxlY3RvciB3aXRoIHRoZSB2YWx1ZXMgc3RvcmVkIGluIHRoZSBpbmRleGVkZGJcclxuICAgIHRoaXMuY29sdW1uc1RvU2hvdy5zZXRWYWx1ZSh0aGlzLmNvbHVtbnMuZmlsdGVyKGMgPT4gc2F2ZWQudmlzaWJsZUNvbHVtbnMuc29tZShpdGVtID0+IGl0ZW0gPT09IGMuY29sdW1uRGVmKSkpO1xyXG4gICAgLy8gSWYgbXVsdGlwbGUgaXMgZW5hYmxlZCBidXQgd2FzIG5vdCBzYXZlZCBpbiB0aGUgc2F2ZWQgYXJyYXksIGFkZCBpdFxyXG4gICAgaWYgKHRoaXMubXVsdGlwbGUgJiYgc2F2ZWQudmlzaWJsZUNvbHVtbnNbMF0gIT09ICdzZWxlY3QnKSBzYXZlZC52aXNpYmxlQ29sdW1ucy51bnNoaWZ0KCdzZWxlY3QnKTtcclxuICAgIHRoaXMuZGlzcGxheWVkQ29sdW1ucyA9IHNhdmVkLnZpc2libGVDb2x1bW5zO1xyXG4gIH1cclxuXHJcbiAgc2F2ZUN1cnJlbnRDb2x1bW5TZWxlY3Rpb24oZGlzcGxheWVkQ29sdW1uczogc3RyaW5nW10pOiB2b2lkIHtcclxuICAgIGlmICghdGhpcy50YWJsZUlkKVxyXG4gICAgICByZXR1cm47XHJcblxyXG4gICAgbGV0IHRvU2F2ZSA9IHRoaXMuZGlzcGxheWVkQ29sdW1ucy5zbGljZSgpO1xyXG4gICAgLy8gRG8gbm90IHNhdmUgdGhlIHNlbGVjdGlvbiBjb2x1bW5cclxuICAgIGlmICh0aGlzLm11bHRpcGxlICYmIHRvU2F2ZVswXSA9PT0gJ3NlbGVjdCcpIHRvU2F2ZS5zaGlmdCgpO1xyXG5cclxuICAgIHRoaXMuY29sdW1uU3RvcmFnZVNlcnZpY2Uuc2F2ZSh7XHJcbiAgICAgIHRhYmxlSWQ6IHRoaXMudGFibGVJZCxcclxuICAgICAgdmlzaWJsZUNvbHVtbnM6IHRvU2F2ZVxyXG4gICAgfSk7XHJcbiAgfVxyXG5cclxufVxyXG4iXX0=