UNPKG

ngx-gem-spaas

Version:

This library contains services, components, images and styles to provide a unified look and way-of-working throughout GEM SPaaS.

164 lines 34.2 kB
import { Component, EventEmitter, Input, Output } from '@angular/core'; import { FormControl, FormGroup } from "@angular/forms"; import { TableColumnFilterModel } from "../_models/table-column.model"; import { UtilsService } from "ngx-gem-spaas"; import * as i0 from "@angular/core"; import * as i1 from "@angular/common"; import * as i2 from "@angular/material/form-field"; import * as i3 from "@angular/material/input"; import * as i4 from "@angular/material/select"; import * as i5 from "@angular/material/core"; import * as i6 from "@angular/forms"; export class TableFilterComponent { static cleanValue(val) { // trim, escape backslashes and lowercase the value return (val + '').trim().replace(/\\/g, '\\\\').toLowerCase(); } constructor() { this.tableData = []; this.columns = []; this.withFreeSearch = true; this.filterChanged = new EventEmitter(); // also emit separately that the "clear all" button has been clicked (for parent components with additional filtering) this.filterCleared = new EventEmitter(); this.filterString = ''; this.filterForm = new FormGroup({}); this.filterColumns = []; this.FREESEARCH_CTRL = 'freeSearch'; this.ALL_VALUE = ''; this.filterForm.addControl(this.FREESEARCH_CTRL, new FormControl('')); } ngOnChanges(changes) { if (changes.hasOwnProperty('columns')) { this.setFilterFormAndColumns(); } if (changes.hasOwnProperty('tableData') && this.tableData?.length) { this.setDropdownLists(); } } setFilterFormAndColumns() { this.filterColumns = []; let hasValidDefault = false; for (const col of this.columns) { if (col.withFilterSelect) { let newValidDefault = false; const filterCol = new TableColumnFilterModel(); filterCol.update(col); this.filterColumns.push(filterCol); if (col.withFilterSelect === 'single') { newValidDefault = !!col.withFilterDefault && typeof col.withFilterDefault === 'string'; const filterDefault = newValidDefault ? col.withFilterDefault : ''; this.filterForm.addControl(col.dataField, new FormControl(filterDefault)); } else { newValidDefault = !!col.withFilterDefault && Array.isArray(col.withFilterDefault) && col.withFilterDefault.length > 0; const filterDefault = newValidDefault ? col.withFilterDefault : [this.ALL_VALUE]; this.filterForm.addControl(col.dataField, new FormControl(filterDefault)); } hasValidDefault = hasValidDefault || newValidDefault; } } if (hasValidDefault) { this.updateFilter(); } } setDropdownLists() { if (!this.filterColumns.length) { // should not happen since the columns should always be initialised before the data, but do the check anyway this.setFilterFormAndColumns(); } for (const col of this.filterColumns) { const allColValues = this.tableData.map((t) => t[col.dataField] === null ? '' : '' + t[col.dataField]); col.filterDropdownValues = UtilsService.distinct(allColValues); } } onSelectAll(column) { if (column.withFilterSelect === 'multiple') { this.filterForm.controls[column.dataField].patchValue([this.ALL_VALUE]); } this.updateFilter(); } onSelectOne(column) { if (column.withFilterSelect === 'multiple') { const val = this.filterForm.controls[column.dataField].value; if (!val.length) { // user has deselected the only selected value => set to "all" value this.filterForm.controls[column.dataField].patchValue([this.ALL_VALUE]); } else { // user has selected an option, deselect "all" value this.filterForm.controls[column.dataField].patchValue(val.filter((v) => v !== this.ALL_VALUE)); } } this.updateFilter(); } updateFilter() { let freeValueFilter = ''; let dropdownFilter = ''; // first free search const freeValue = TableFilterComponent.cleanValue(this.filterForm.controls[this.FREESEARCH_CTRL].value); if (freeValue) { // here we add ALL columns, not just the ones with filter === true for (const col of this.columns) { freeValueFilter += '("" + e["' + col.dataField + '"]).toLowerCase().includes("' + freeValue + '") || '; } freeValueFilter = '(' + freeValueFilter.substring(0, freeValueFilter.length - 4) + ') '; } // then dropdown fields for (const col of this.filterColumns) { if (col.withFilterSelect == 'single') { const colFilterValue = TableFilterComponent.cleanValue(this.filterForm.controls[col.dataField].value); if (colFilterValue) { dropdownFilter += '("" + e["' + col.dataField + '"]).toLowerCase() === "' + colFilterValue + '" && '; } } else { const colFilterValues = this.filterForm.controls[col.dataField].value; let multiGroup = ''; for (const val of colFilterValues) { if (val) { multiGroup += '("" + e["' + col.dataField + '"]).toLowerCase() === "' + TableFilterComponent.cleanValue(val) + '" || '; } } if (multiGroup) { dropdownFilter += '(' + multiGroup.substring(0, multiGroup.length - 4) + ') && '; } } } if (dropdownFilter) { dropdownFilter = '(' + dropdownFilter.substring(0, dropdownFilter.length - 4) + ') '; } const concatFilter = freeValueFilter && dropdownFilter ? freeValueFilter + ' && ' + dropdownFilter : freeValueFilter || dropdownFilter; this.emitFilter(concatFilter); } onReset() { this.filterForm.controls[this.FREESEARCH_CTRL].patchValue(''); for (const col of this.filterColumns) { const ctrl = this.filterForm.controls[col.dataField]; ctrl.patchValue(col.withFilterSelect === 'single' ? '' : [this.ALL_VALUE]); } this.emitFilter(''); this.filterCleared.emit(); } emitFilter(filter) { this.filterString = filter; this.filterChanged.emit(filter); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: TableFilterComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.12", type: TableFilterComponent, selector: "spaas-table-filter", inputs: { tableData: "tableData", columns: "columns", withFreeSearch: "withFreeSearch" }, outputs: { filterChanged: "filterChanged", filterCleared: "filterCleared" }, usesOnChanges: true, ngImport: i0, template: "<div [formGroup]=\"filterForm\"\r\n [ngClass]=\"{\r\n 'column': withFreeSearch,\r\n 'row-reverse': !withFreeSearch,\r\n }\"\r\n class=\"filter pad-small flex column-gap-10\">\r\n\r\n <div class=\"flex wrap column-gap-10 align-center\">\r\n\r\n @if (withFreeSearch) {\r\n <mat-form-field class=\"grow-h free-search\"\r\n floatLabel=\"always\">\r\n <mat-label>search any field...</mat-label>\r\n <input matInput\r\n type=\"search\"\r\n (search)=\"updateFilter()\"\r\n formControlName=\"freeSearch\">\r\n </mat-form-field>\r\n }\r\n\r\n <div class=\"flex column-gap-10 pad-small-top\">\r\n @if (withFreeSearch) {\r\n <button class=\"primary\"\r\n (click)=\"updateFilter()\">\r\n search\r\n </button>\r\n }\r\n @if (filterColumns?.length) {\r\n <button class=\"error\"\r\n (click)=\"onReset()\">\r\n clear all\r\n </button>\r\n }\r\n </div>\r\n\r\n </div>\r\n\r\n <div class=\"flex wrap column-gap-10 align-center\"\r\n [class.grow-h]=\"!withFreeSearch\">\r\n\r\n @for (column of filterColumns; track column) {\r\n <mat-form-field class=\"grow-h\"\r\n floatLabel=\"always\">\r\n <mat-label>{{ column.columnLabel || column.dataField }}</mat-label>\r\n <mat-select [formControlName]=\"column.dataField\"\r\n [multiple]=\"column.withFilterSelect === 'multiple'\">\r\n <mat-option (click)=\"onSelectAll(column)\" [value]=\"ALL_VALUE\">all</mat-option>\r\n @for (val of column.filterDropdownValues; track val) {\r\n <mat-option (click)=\"onSelectOne(column)\"\r\n [value]=\"val\">\r\n {{ val }}\r\n </mat-option>\r\n }\r\n </mat-select>\r\n </mat-form-field>\r\n }\r\n\r\n </div>\r\n\r\n</div>\r\n", styles: [".filter .mat-mdc-form-field{min-width:140px}.filter .mat-mdc-form-field.free-search{max-width:300px}\n"], dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: i2.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i2.MatLabel, selector: "mat-label" }, { kind: "directive", type: i3.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }, { kind: "component", type: i4.MatSelect, selector: "mat-select", inputs: ["aria-describedby", "panelClass", "disabled", "disableRipple", "tabIndex", "hideSingleSelectionIndicator", "placeholder", "required", "multiple", "disableOptionCentering", "compareWith", "value", "aria-label", "aria-labelledby", "errorStateMatcher", "typeaheadDebounceInterval", "sortComparator", "id", "panelWidth"], outputs: ["openedChange", "opened", "closed", "selectionChange", "valueChange"], exportAs: ["matSelect"] }, { kind: "component", type: i5.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "directive", type: i6.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i6.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i6.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i6.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i6.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }] }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: TableFilterComponent, decorators: [{ type: Component, args: [{ selector: 'spaas-table-filter', template: "<div [formGroup]=\"filterForm\"\r\n [ngClass]=\"{\r\n 'column': withFreeSearch,\r\n 'row-reverse': !withFreeSearch,\r\n }\"\r\n class=\"filter pad-small flex column-gap-10\">\r\n\r\n <div class=\"flex wrap column-gap-10 align-center\">\r\n\r\n @if (withFreeSearch) {\r\n <mat-form-field class=\"grow-h free-search\"\r\n floatLabel=\"always\">\r\n <mat-label>search any field...</mat-label>\r\n <input matInput\r\n type=\"search\"\r\n (search)=\"updateFilter()\"\r\n formControlName=\"freeSearch\">\r\n </mat-form-field>\r\n }\r\n\r\n <div class=\"flex column-gap-10 pad-small-top\">\r\n @if (withFreeSearch) {\r\n <button class=\"primary\"\r\n (click)=\"updateFilter()\">\r\n search\r\n </button>\r\n }\r\n @if (filterColumns?.length) {\r\n <button class=\"error\"\r\n (click)=\"onReset()\">\r\n clear all\r\n </button>\r\n }\r\n </div>\r\n\r\n </div>\r\n\r\n <div class=\"flex wrap column-gap-10 align-center\"\r\n [class.grow-h]=\"!withFreeSearch\">\r\n\r\n @for (column of filterColumns; track column) {\r\n <mat-form-field class=\"grow-h\"\r\n floatLabel=\"always\">\r\n <mat-label>{{ column.columnLabel || column.dataField }}</mat-label>\r\n <mat-select [formControlName]=\"column.dataField\"\r\n [multiple]=\"column.withFilterSelect === 'multiple'\">\r\n <mat-option (click)=\"onSelectAll(column)\" [value]=\"ALL_VALUE\">all</mat-option>\r\n @for (val of column.filterDropdownValues; track val) {\r\n <mat-option (click)=\"onSelectOne(column)\"\r\n [value]=\"val\">\r\n {{ val }}\r\n </mat-option>\r\n }\r\n </mat-select>\r\n </mat-form-field>\r\n }\r\n\r\n </div>\r\n\r\n</div>\r\n", styles: [".filter .mat-mdc-form-field{min-width:140px}.filter .mat-mdc-form-field.free-search{max-width:300px}\n"] }] }], ctorParameters: () => [], propDecorators: { tableData: [{ type: Input }], columns: [{ type: Input }], withFreeSearch: [{ type: Input }], filterChanged: [{ type: Output }], filterCleared: [{ type: Output }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGFibGUtZmlsdGVyLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL25neC1nZW0tc3BhYXMvdGFibGUvc3JjL3RhYmxlLWZpbHRlci90YWJsZS1maWx0ZXIuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvbmd4LWdlbS1zcGFhcy90YWJsZS9zcmMvdGFibGUtZmlsdGVyL3RhYmxlLWZpbHRlci5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUMsU0FBUyxFQUFFLFlBQVksRUFBRSxLQUFLLEVBQWEsTUFBTSxFQUFnQixNQUFNLGVBQWUsQ0FBQztBQUMvRixPQUFPLEVBQUMsV0FBVyxFQUFFLFNBQVMsRUFBQyxNQUFNLGdCQUFnQixDQUFDO0FBQ3RELE9BQU8sRUFBQyxzQkFBc0IsRUFBbUIsTUFBTSwrQkFBK0IsQ0FBQztBQUN2RixPQUFPLEVBQUMsWUFBWSxFQUFDLE1BQU0sZUFBZSxDQUFDOzs7Ozs7OztBQU8zQyxNQUFNLE9BQU8sb0JBQW9CO0lBaUJ2QixNQUFNLENBQUMsVUFBVSxDQUFDLEdBQVE7UUFDaEMsbURBQW1EO1FBQ25ELE9BQU8sQ0FBQyxHQUFHLEdBQUcsRUFBRSxDQUFDLENBQUMsSUFBSSxFQUFFLENBQUMsT0FBTyxDQUFDLEtBQUssRUFBRSxNQUFNLENBQUMsQ0FBQyxXQUFXLEVBQUUsQ0FBQztJQUNoRSxDQUFDO0lBRUQ7UUFwQlMsY0FBUyxHQUFVLEVBQUUsQ0FBQztRQUN0QixZQUFPLEdBQXVCLEVBQUUsQ0FBQztRQUNqQyxtQkFBYyxHQUFZLElBQUksQ0FBQztRQUU5QixrQkFBYSxHQUFHLElBQUksWUFBWSxFQUFVLENBQUM7UUFDckQsc0hBQXNIO1FBQzVHLGtCQUFhLEdBQUcsSUFBSSxZQUFZLEVBQVEsQ0FBQztRQUVuRCxpQkFBWSxHQUFHLEVBQUUsQ0FBQztRQUNsQixlQUFVLEdBQUcsSUFB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Q0wsSUFBSSxDQUFDLFVBQVUsQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLGVBQWUsQ0FBQyxDQUFDLFVBQVUsQ0FBQyxFQUFFLENBQUMsQ0FBQztRQUM5RCxLQUFLLE1BQU0sR0FBRyxJQUFJLElBQUksQ0FBQyxhQUFhLEVBQUUsQ0FBQztZQUNyQyxNQUFNLElBQUksR0FBRyxJQUFJLENBQUMsVUFBVSxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsU0FBUyxDQUFDLENBQUM7WUFDckQsSUFBSSxDQUFDLFVBQVUsQ0FBQyxHQUFHLENBQUMsZ0JBQWdCLEtBQUssUUFBUSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUM7UUFDN0UsQ0FBQztRQUNELElBQUksQ0FBQyxVQUFVLENBQUMsRUFBRSxDQUFDLENBQUE7UUFDbkIsSUFBSSxDQUFDLGFBQWEsQ0FBQyxJQUFJLEVBQUUsQ0FBQztJQUM1QixDQUFDO0lBRU8sVUFBVSxDQUFDLE1BQWM7UUFDL0IsSUFBSSxDQUFDLFlBQVksR0FBRyxNQUFNLENBQUM7UUFDM0IsSUFBSSxDQUFDLGFBQWEsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUM7SUFDbEMsQ0FBQzsrR0FqSlUsb0JBQW9CO21HQUFwQixvQkFBb0Isc1BDVmpDLHk3REE0REE7OzRGRGxEYSxvQkFBb0I7a0JBTGhDLFNBQVM7K0JBQ0Usb0JBQW9CO3dEQU1yQixTQUFTO3NCQUFqQixLQUFLO2dCQUNHLE9BQU87c0JBQWYsS0FBSztnQkFDRyxjQUFjO3NCQUF0QixLQUFLO2dCQUVJLGFBQWE7c0JBQXRCLE1BQU07Z0JBRUcsYUFBYTtzQkFBdEIsTUFBTSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7Q29tcG9uZW50LCBFdmVudEVtaXR0ZXIsIElucHV0LCBPbkNoYW5nZXMsIE91dHB1dCwgU2ltcGxlQ2hhbmdlc30gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XHJcbmltcG9ydCB7Rm9ybUNvbnRyb2wsIEZvcm1Hcm91cH0gZnJvbSBcIkBhbmd1bGFyL2Zvcm1zXCI7XHJcbmltcG9ydCB7VGFibGVDb2x1bW5GaWx0ZXJNb2RlbCwgVGFibGVDb2x1bW5Nb2RlbH0gZnJvbSBcIi4uL19tb2RlbHMvdGFibGUtY29sdW1uLm1vZGVsXCI7XHJcbmltcG9ydCB7VXRpbHNTZXJ2aWNlfSBmcm9tIFwibmd4LWdlbS1zcGFhc1wiO1xyXG5cclxuQENvbXBvbmVudCh7XHJcbiAgc2VsZWN0b3I6ICdzcGFhcy10YWJsZS1maWx0ZXInLFxyXG4gIHN0eWxlVXJsczogWycuL3RhYmxlLWZpbHRlci5jb21wb25lbnQuc2NzcyddLFxyXG4gIHRlbXBsYXRlVXJsOiAnLi90YWJsZS1maWx0ZXIuY29tcG9uZW50Lmh0bWwnLFxyXG59KVxyXG5leHBvcnQgY2xhc3MgVGFibGVGaWx0ZXJDb21wb25lbnQgaW1wbGVtZW50cyBPbkNoYW5nZXMge1xyXG5cclxuICBASW5wdXQoKSB0YWJsZURhdGE6IGFueVtdID0gW107XHJcbiAgQElucHV0KCkgY29sdW1uczogVGFibGVDb2x1bW5Nb2RlbFtdID0gW107XHJcbiAgQElucHV0KCkgd2l0aEZyZWVTZWFyY2g6IGJvb2xlYW4gPSB0cnVlO1xyXG5cclxuICBAT3V0cHV0KCkgZmlsdGVyQ2hhbmdlZCA9IG5ldyBFdmVudEVtaXR0ZXI8c3RyaW5nPigpO1xyXG4gIC8vIGFsc28gZW1pdCBzZXBhcmF0ZWx5IHRoYXQgdGhlIFwiY2xlYXIgYWxsXCIgYnV0dG9uIGhhcyBiZWVuIGNsaWNrZWQgKGZvciBwYXJlbnQgY29tcG9uZW50cyB3aXRoIGFkZGl0aW9uYWwgZmlsdGVyaW5nKVxyXG4gIEBPdXRwdXQoKSBmaWx0ZXJDbGVhcmVkID0gbmV3IEV2ZW50RW1pdHRlcjx2b2lkPigpO1xyXG5cclxuICBmaWx0ZXJTdHJpbmcgPSAnJztcclxuICBmaWx0ZXJGb3JtID0gbmV3IEZvcm1Hcm91cDxhbnk+KHt9KTtcclxuICBmaWx0ZXJDb2x1bW5zOiBUYWJsZUNvbHVtbkZpbHRlck1vZGVsW10gPSBbXTtcclxuXHJcbiAgcmVhZG9ubHkgRlJFRVNFQVJDSF9DVFJMID0gJ2ZyZWVTZWFyY2gnO1xyXG4gIHJlYWRvbmx5IEFMTF9WQUxVRSA9ICcnO1xyXG5cclxuICBwcml2YXRlIHN0YXRpYyBjbGVhblZhbHVlKHZhbDogYW55KTogc3RyaW5nIHtcclxuICAgIC8vIHRyaW0sIGVzY2FwZSBiYWNrc2xhc2hlcyBhbmQgbG93ZXJjYXNlIHRoZSB2YWx1ZVxyXG4gICAgcmV0dXJuICh2YWwgKyAnJykudHJpbSgpLnJlcGxhY2UoL1xcXFwvZywgJ1xcXFxcXFxcJykudG9Mb3dlckNhc2UoKTtcclxuICB9XHJcblxyXG4gIGNvbnN0cnVjdG9yKCkge1xyXG4gICAgdGhpcy5maWx0ZXJGb3JtLmFkZENvbnRyb2wodGhpcy5GUkVFU0VBUkNIX0NUUkwsIG5ldyBGb3JtQ29udHJvbDxzdHJpbmc+KCcnKSk7XHJcbiAgfVxyXG5cclxuICBuZ09uQ2hhbmdlcyhjaGFuZ2VzOiBTaW1wbGVDaGFuZ2VzKTogdm9pZCB7XHJcbiAgICBpZiAoY2hhbmdlcy5oYXNPd25Qcm9wZXJ0eSgnY29sdW1ucycpKSB7XHJcbiAgICAgIHRoaXMuc2V0RmlsdGVyRm9ybUFuZENvbHVtbnMoKTtcclxuICAgIH1cclxuICAgIGlmIChjaGFuZ2VzLmhhc093blByb3BlcnR5KCd0YWJsZURhdGEnKSAmJiB0aGlzLnRhYmxlRGF0YT8ubGVuZ3RoKSB7XHJcbiAgICAgIHRoaXMuc2V0RHJvcGRvd25MaXN0cygpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBzZXRGaWx0ZXJGb3JtQW5kQ29sdW1ucygpOiB2b2lkIHtcclxuICAgIHRoaXMuZmlsdGVyQ29sdW1ucyA9IFtdO1xyXG4gICAgbGV0IGhhc1ZhbGlkRGVmYXVsdCA9IGZhbHNlO1xyXG4gICAgZm9yIChjb25zdCBjb2wgb2YgdGhpcy5jb2x1bW5zKSB7XHJcbiAgICAgIGlmIChjb2wud2l0aEZpbHRlclNlbGVjdCkge1xyXG4gICAgICAgIGxldCBuZXdWYWxpZERlZmF1bHQgPSBmYWxzZTtcclxuICAgICAgICBjb25zdCBmaWx0ZXJDb2wgPSBuZXcgVGFibGVDb2x1bW5GaWx0ZXJNb2RlbCgpO1xyXG4gICAgICAgIGZpbHRlckNvbC51cGRhdGUoY29sKTtcclxuICAgICAgICB0aGlzLmZpbHRlckNvbHVtbnMucHVzaChmaWx0ZXJDb2wpO1xyXG4gICAgICAgIGlmIChjb2wud2l0aEZpbHRlclNlbGVjdCA9PT0gJ3NpbmdsZScpIHtcclxuICAgICAgICAgIG5ld1ZhbGlkRGVmYXVsdCA9ICEhY29sLndpdGhGaWx0ZXJEZWZhdWx0ICYmIHR5cGVvZiBjb2wud2l0aEZpbHRlckRlZmF1bHQgPT09ICdzdHJpbmcnO1xyXG4gICAgICAgICAgY29uc3QgZmlsdGVyRGVmYXVsdCA9IG5ld1ZhbGlkRGVmYXVsdCA/IGNvbC53aXRoRmlsdGVyRGVmYXVsdCBhcyBzdHJpbmcgOiAnJztcclxuICAgICAgICAgIHRoaXMuZmlsdGVyRm9ybS5hZGRDb250cm9sKGNvbC5kYXRhRmllbGQsIG5ldyBGb3JtQ29udHJvbDxzdHJpbmc+KGZpbHRlckRlZmF1bHQpKTtcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgbmV3VmFsaWREZWZhdWx0ID0gISFjb2wud2l0aEZpbHRlckRlZmF1bHQgJiYgQXJyYXkuaXNBcnJheShjb2wud2l0aEZpbHRlckRlZmF1bHQpICYmIGNvbC53aXRoRmlsdGVyRGVmYXVsdC5sZW5ndGggPiAwO1xyXG4gICAgICAgICAgY29uc3QgZmlsdGVyRGVmYXVsdCA9IG5ld1ZhbGlkRGVmYXVsdCA/IGNvbC53aXRoRmlsdGVyRGVmYXVsdCBhcyBzdHJpbmdbXSA6IFt0aGlzLkFMTF9WQUxVRV07XHJcbiAgICAgICAgICB0aGlzLmZpbHRlckZvcm0uYWRkQ29udHJvbChjb2wuZGF0YUZpZWxkLCBuZXcgRm9ybUNvbnRyb2w8c3RyaW5nW10+KGZpbHRlckRlZmF1bHQpKTtcclxuICAgICAgICB9XHJcbiAgICAgICAgaGFzVmFsaWREZWZhdWx0ID0gaGFzVmFsaWREZWZhdWx0IHx8IG5ld1ZhbGlkRGVmYXVsdDtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gICAgaWYgKGhhc1ZhbGlkRGVmYXVsdCkge1xyXG4gICAgICB0aGlzLnVwZGF0ZUZpbHRlcigpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBzZXREcm9wZG93bkxpc3RzKCk6IHZvaWQge1xyXG4gICAgaWYgKCF0aGlzLmZpbHRlckNvbHVtbnMubGVuZ3RoKSB7XHJcbiAgICAgIC8vIHNob3VsZCBub3QgaGFwcGVuIHNpbmNlIHRoZSBjb2x1bW5zIHNob3VsZCBhbHdheXMgYmUgaW5pdGlhbGlzZWQgYmVmb3JlIHRoZSBkYXRhLCBidXQgZG8gdGhlIGNoZWNrIGFueXdheVxyXG4gICAgICB0aGlzLnNldEZpbHRlckZvcm1BbmRDb2x1bW5zKCk7XHJcbiAgICB9XHJcbiAgICBmb3IgKGNvbnN0IGNvbCBvZiB0aGlzLmZpbHRlckNvbHVtbnMpIHtcclxuICAgICAgY29uc3QgYWxsQ29sVmFsdWVzID0gdGhpcy50YWJsZURhdGEubWFwKCh0KSA9PiB0W2NvbC5kYXRhRmllbGRdID09PSBudWxsID8gJycgOiAnJyArIHRbY29sLmRhdGFGaWVsZF0pO1xyXG4gICAgICBjb2wuZmlsdGVyRHJvcGRvd25WYWx1ZXMgPSBVdGlsc1NlcnZpY2UuZGlzdGluY3QoYWxsQ29sVmFsdWVzKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIG9uU2VsZWN0QWxsKGNvbHVtbjogVGFibGVDb2x1bW5GaWx0ZXJNb2RlbCk6IHZvaWQge1xyXG4gICAgaWYgKGNvbHVtbi53aXRoRmlsdGVyU2VsZWN0ID09PSAnbXVsdGlwbGUnKSB7XHJcbiAgICAgIHRoaXMuZmlsdGVyRm9ybS5jb250cm9sc1tjb2x1bW4uZGF0YUZpZWxkXS5wYXRjaFZhbHVlKFt0aGlzLkFMTF9WQUxVRV0pO1xyXG4gICAgfVxyXG4gICAgdGhpcy51cGRhdGVGaWx0ZXIoKTtcclxuICB9XHJcblxyXG4gIG9uU2VsZWN0T25lKGNvbHVtbjogVGFibGVDb2x1bW5GaWx0ZXJNb2RlbCk6IHZvaWQge1xyXG4gICAgaWYgKGNvbHVtbi53aXRoRmlsdGVyU2VsZWN0ID09PSAnbXVsdGlwbGUnKSB7XHJcbiAgICAgIGNvbnN0IHZhbCA9IHRoaXMuZmlsdGVyRm9ybS5jb250cm9sc1tjb2x1bW4uZGF0YUZpZWxkXS52YWx1ZTtcclxuICAgICAgaWYgKCF2YWwubGVuZ3RoKSB7XHJcbiAgICAgICAgLy8gdXNlciBoYXMgZGVzZWxlY3RlZCB0aGUgb25seSBzZWxlY3RlZCB2YWx1ZSA9PiBzZXQgdG8gXCJhbGxcIiB2YWx1ZVxyXG4gICAgICAgIHRoaXMuZmlsdGVyRm9ybS5jb250cm9sc1tjb2x1bW4uZGF0YUZpZWxkXS5wYXRjaFZhbHVlKFt0aGlzLkFMTF9WQUxVRV0pO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIC8vIHVzZXIgaGFzIHNlbGVjdGVkIGFuIG9wdGlvbiwgZGVzZWxlY3QgXCJhbGxcIiB2YWx1ZVxyXG4gICAgICAgIHRoaXMuZmlsdGVyRm9ybS5jb250cm9sc1tjb2x1bW4uZGF0YUZpZWxkXS5wYXRjaFZhbHVlKHZhbC5maWx0ZXIoKHY6IHN0cmluZykgPT4gdiAhPT0gdGhpcy5BTExfVkFMVUUpKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gICAgdGhpcy51cGRhdGVGaWx0ZXIoKTtcclxuICB9XHJcblxyXG4gIHVwZGF0ZUZpbHRlcigpOiB2b2lkIHtcclxuICAgIGxldCBmcmVlVmFsdWVGaWx0ZXIgPSAnJztcclxuICAgIGxldCBkcm9wZG93bkZpbHRlciA9ICcnO1xyXG4gICAgLy8gZmlyc3QgZnJlZSBzZWFyY2hcclxuICAgIGNvbnN0IGZyZWVWYWx1ZSA9IFRhYmxlRmlsdGVyQ29tcG9uZW50LmNsZWFuVmFsdWUodGhpcy5maWx0ZXJGb3JtLmNvbnRyb2xzW3RoaXMuRlJFRVNFQVJDSF9DVFJMXS52YWx1ZSk7XHJcbiAgICBpZiAoZnJlZVZhbHVlKSB7XHJcbiAgICAgIC8vIGhlcmUgd2UgYWRkIEFMTCBjb2x1bW5zLCBub3QganVzdCB0aGUgb25lcyB3aXRoIGZpbHRlciA9PT0gdHJ1ZVxyXG4gICAgICBmb3IgKGNvbnN0IGNvbCBvZiB0aGlzLmNvbHVtbnMpIHtcclxuICAgICAgICBmcmVlVmFsdWVGaWx0ZXIgKz0gJyhcIlwiICsgZVtcIicgKyBjb2wuZGF0YUZpZWxkICsgJ1wiXSkudG9Mb3dlckNhc2UoKS5pbmNsdWRlcyhcIicgKyBmcmVlVmFsdWUgKyAnXCIpIHx8ICc7XHJcbiAgICAgIH1cclxuICAgICAgZnJlZVZhbHVlRmlsdGVyID0gJygnICsgZnJlZVZhbHVlRmlsdGVyLnN1YnN0cmluZygwLCBmcmVlVmFsdWVGaWx0ZXIubGVuZ3RoIC0gNCkgKyAnKSAnO1xyXG4gICAgfVxyXG4gICAgLy8gdGhlbiBkcm9wZG93biBmaWVsZHNcclxuICAgIGZvciAoY29uc3QgY29sIG9mIHRoaXMuZmlsdGVyQ29sdW1ucykge1xyXG4gICAgICBpZiAoY29sLndpdGhGaWx0ZXJTZWxlY3QgPT0gJ3NpbmdsZScpIHtcclxuICAgICAgICBjb25zdCBjb2xGaWx0ZXJWYWx1ZSA9IFRhYmxlRmlsdGVyQ29tcG9uZW50LmNsZWFuVmFsdWUodGhpcy5maWx0ZXJGb3JtLmNvbnRyb2xzW2NvbC5kYXRhRmllbGRdLnZhbHVlKTtcclxuICAgICAgICBpZiAoY29sRmlsdGVyVmFsdWUpIHtcclxuICAgICAgICAgIGRyb3Bkb3duRmlsdGVyICs9ICcoXCJcIiArIGVbXCInICsgY29sLmRhdGFGaWVsZCArICdcIl0pLnRvTG93ZXJDYXNlKCkgPT09IFwiJyArIGNvbEZpbHRlclZhbHVlICsgJ1wiICYmICc7XHJcbiAgICAgICAgfVxyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIGNvbnN0IGNvbEZpbHRlclZhbHVlcyA9IHRoaXMuZmlsdGVyRm9ybS5jb250cm9sc1tjb2wuZGF0YUZpZWxkXS52YWx1ZTtcclxuICAgICAgICBsZXQgbXVsdGlHcm91cCA9ICcnO1xyXG4gICAgICAgIGZvciAoY29uc3QgdmFsIG9mIGNvbEZpbHRlclZhbHVlcykge1xyXG4gICAgICAgICAgaWYgKHZhbCkge1xyXG4gICAgICAgICAgICBtdWx0aUdyb3VwICs9ICcoXCJcIiArIGVbXCInICsgY29sLmRhdGFGaWVsZCArICdcIl0pLnRvTG93ZXJDYXNlKCkgPT09IFwiJyArIFRhYmxlRmlsdGVyQ29tcG9uZW50LmNsZWFuVmFsdWUodmFsKSArICdcIiB8fCAnO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgICBpZiAobXVsdGlHcm91cCkge1xyXG4gICAgICAgICAgZHJvcGRvd25GaWx0ZXIgKz0gJygnICsgbXVsdGlHcm91cC5zdWJzdHJpbmcoMCwgbXVsdGlHcm91cC5sZW5ndGggLSA0KSArICcpICYmICc7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgICBpZiAoZHJvcGRvd25GaWx0ZXIpIHtcclxuICAgICAgZHJvcGRvd25GaWx0ZXIgPSAnKCcgKyBkcm9wZG93bkZpbHRlci5zdWJzdHJpbmcoMCwgZHJvcGRvd25GaWx0ZXIubGVuZ3RoIC0gNCkgKyAnKSAnO1xyXG4gICAgfVxyXG4gICAgY29uc3QgY29uY2F0RmlsdGVyID0gZnJlZVZhbHVlRmlsdGVyICYmIGRyb3Bkb3duRmlsdGVyID8gZnJlZVZhbHVlRmlsdGVyICsgJyAmJiAnICsgZHJvcGRvd25GaWx0ZXIgOiBmcmVlVmFsdWVGaWx0ZXIgfHwgZHJvcGRvd25GaWx0ZXI7XHJcbiAgICB0aGlzLmVtaXRGaWx0ZXIoY29uY2F0RmlsdGVyKTtcclxuICB9XHJcblxyXG4gIG9uUmVzZXQoKTogdm9pZCB7XHJcbiAgICB0aGlzLmZpbHRlckZvcm0uY29udHJvbHNbdGhpcy5GUkVFU0VBUkNIX0NUUkxdLnBhdGNoVmFsdWUoJycpO1xyXG4gICAgZm9yIChjb25zdCBjb2wgb2YgdGhpcy5maWx0ZXJDb2x1bW5zKSB7XHJcbiAgICAgIGNvbnN0IGN0cmwgPSB0aGlzLmZpbHRlckZvcm0uY29udHJvbHNbY29sLmRhdGFGaWVsZF07XHJcbiAgICAgIGN0cmwucGF0Y2hWYWx1ZShjb2wud2l0aEZpbHRlclNlbGVjdCA9PT0gJ3NpbmdsZScgPyAnJyA6IFt0aGlzLkFMTF9WQUxVRV0pO1xyXG4gICAgfVxyXG4gICAgdGhpcy5lbWl0RmlsdGVyKCcnKVxyXG4gICAgdGhpcy5maWx0ZXJDbGVhcmVkLmVtaXQoKTtcclxuICB9XHJcblxyXG4gIHByaXZhdGUgZW1pdEZpbHRlcihmaWx0ZXI6IHN0cmluZyk6IHZvaWQge1xyXG4gICAgdGhpcy5maWx0ZXJTdHJpbmcgPSBmaWx0ZXI7XHJcbiAgICB0aGlzLmZpbHRlckNoYW5nZWQuZW1pdChmaWx0ZXIpO1xyXG4gIH1cclxuXHJcbn1cclxuIiwiPGRpdiBbZm9ybUdyb3VwXT1cImZpbHRlckZvcm1cIlxyXG4gICAgIFtuZ0NsYXNzXT1cIntcclxuICAgICAnY29sdW1uJzogd2l0aEZyZWVTZWFyY2gsXHJcbiAgICAgJ3Jvdy1yZXZlcnNlJzogIXdpdGhGcmVlU2VhcmNoLFxyXG4gICAgIH1cIlxyXG4gICAgIGNsYXNzPVwiZmlsdGVyIHBhZC1zbWFsbCBmbGV4IGNvbHVtbi1nYXAtMTBcIj5cclxuXHJcbiAgPGRpdiBjbGFzcz1cImZsZXggd3JhcCBjb2x1bW4tZ2FwLTEwIGFsaWduLWNlbnRlclwiPlxyXG5cclxuICAgIEBpZiAod2l0aEZyZWVTZWFyY2gpIHtcclxuICAgICAgPG1hdC1mb3JtLWZpZWxkIGNsYXNzPVwiZ3Jvdy1oIGZyZWUtc2VhcmNoXCJcclxuICAgICAgICAgICAgICAgICAgICAgIGZsb2F0TGFiZWw9XCJhbHdheXNcIj5cclxuICAgICAgICA8bWF0LWxhYmVsPnNlYXJjaCBhbnkgZmllbGQuLi48L21hdC1sYWJlbD5cclxuICAgICAgICA8aW5wdXQgbWF0SW5wdXRcclxuICAgICAgICAgICAgICAgdHlwZT1cInNlYXJjaFwiXHJcbiAgICAgICAgICAgICAgIChzZWFyY2gpPVwidXBkYXRlRmlsdGVyKClcIlxyXG4gICAgICAgICAgICAgICBmb3JtQ29udHJvbE5hbWU9XCJmcmVlU2VhcmNoXCI+XHJcbiAgICAgIDwvbWF0LWZvcm0tZmllbGQ+XHJcbiAgICB9XHJcblxyXG4gICAgPGRpdiBjbGFzcz1cImZsZXggY29sdW1uLWdhcC0xMCBwYWQtc21hbGwtdG9wXCI+XHJcbiAgICAgIEBpZiAod2l0aEZyZWVTZWFyY2gpIHtcclxuICAgICAgICA8YnV0dG9uIGNsYXNzPVwicHJpbWFyeVwiXHJcbiAgICAgICAgICAgICAgICAoY2xpY2spPVwidXBkYXRlRmlsdGVyKClcIj5cclxuICAgICAgICAgIHNlYXJjaFxyXG4gICAgICAgIDwvYnV0dG9uPlxyXG4gICAgICB9XHJcbiAgICAgIEBpZiAoZmlsdGVyQ29sdW1ucz8ubGVuZ3RoKSB7XHJcbiAgICAgICAgPGJ1dHRvbiBjbGFzcz1cImVycm9yXCJcclxuICAgICAgICAgICAgICAgIChjbGljayk9XCJvblJlc2V0KClcIj5cclxuICAgICAgICAgIGNsZWFyIGFsbFxyXG4gICAgICAgIDwvYnV0dG9uPlxyXG4gICAgICB9XHJcbiAgICA8L2Rpdj5cclxuXHJcbiAgPC9kaXY+XHJcblxyXG4gIDxkaXYgY2xhc3M9XCJmbGV4IHdyYXAgY29sdW1uLWdhcC0xMCBhbGlnbi1jZW50ZXJcIlxyXG4gICAgICAgW2NsYXNzLmdyb3ctaF09XCIhd2l0aEZyZWVTZWFyY2hcIj5cclxuXHJcbiAgICBAZm9yIChjb2x1bW4gb2YgZmlsdGVyQ29sdW1uczsgdHJhY2sgY29sdW1uKSB7XHJcbiAgICAgIDxtYXQtZm9ybS1maWVsZCBjbGFzcz1cImdyb3ctaFwiXHJcbiAgICAgICAgICAgICAgICAgICAgICBmbG9hdExhYmVsPVwiYWx3YXlzXCI+XHJcbiAgICAgICAgPG1hdC1sYWJlbD57eyBjb2x1bW4uY29sdW1uTGFiZWwgfHwgY29sdW1uLmRhdGFGaWVsZCB9fTwvbWF0LWxhYmVsPlxyXG4gICAgICAgIDxtYXQtc2VsZWN0IFtmb3JtQ29udHJvbE5hbWVdPVwiY29sdW1uLmRhdGFGaWVsZFwiXHJcbiAgICAgICAgICAgICAgICAgICAgW211bHRpcGxlXT1cImNvbHVtbi53aXRoRmlsdGVyU2VsZWN0ID09PSAnbXVsdGlwbGUnXCI+XHJcbiAgICAgICAgICA8bWF0LW9wdGlvbiAoY2xpY2spPVwib25TZWxlY3RBbGwoY29sdW1uKVwiIFt2YWx1ZV09XCJBTExfVkFMVUVcIj5hbGw8L21hdC1vcHRpb24+XHJcbiAgICAgICAgICBAZm9yICh2YWwgb2YgY29sdW1uLmZpbHRlckRyb3Bkb3duVmFsdWVzOyB0cmFjayB2YWwpIHtcclxuICAgICAgICAgICAgPG1hdC1vcHRpb24gKGNsaWNrKT1cIm9uU2VsZWN0T25lKGNvbHVtbilcIlxyXG4gICAgICAgICAgICAgICAgICAgICAgICBbdmFsdWVdPVwidmFsXCI+XHJcbiAgICAgICAgICAgICAge3sgdmFsIH19XHJcbiAgICAgICAgICAgIDwvbWF0LW9wdGlvbj5cclxuICAgICAgICAgIH1cclxuICAgICAgICA8L21hdC1zZWxlY3Q+XHJcbiAgICAgIDwvbWF0LWZvcm0tZmllbGQ+XHJcbiAgICB9XHJcblxyXG4gIDwvZGl2PlxyXG5cclxuPC9kaXY+XHJcbiJdfQ==