UNPKG

ngm-tree-grid

Version:

A tree grid that supports editable fields like Inputs and Checkboxes.

129 lines 23.1 kB
import { Component, ContentChildren, EventEmitter, Input, Output, ViewChildren } from '@angular/core'; import { CellHostDirective } from '../../directive'; import * as i0 from "@angular/core"; import * as i1 from "@angular/common"; import * as i2 from "ngm-live-search"; import * as i3 from "../tree-grid-item/tree-grid-item.component"; import * as i4 from "../../directive/cell-host.directive"; export class TreeGridComponent { /** When user clicks on arrow to expand a row, this emitter emits an event */ expand = new EventEmitter(); /** When user clicks on arrow to collapse a row, this emitter emits an event */ collapse = new EventEmitter(); dataSource; config = { hasSearch: true, columns: [], searchPlaceHolder: 'Search', searchFn: (obj, txt) => { return Object.values(obj) .filter((x) => (typeof x === 'string' || typeof x === 'number')) .map(x => String(x)) .some((y) => y.includes(txt)); } }; cellContents; headerContents; headerPanes; filterText = ''; filteredData = []; showGrid = true; constructor() { } ngAfterContentInit() { setTimeout(() => { if (this.headerContents) { this.headerPanes.forEach((x, i) => { x.viewContainerRef.clear(); x.viewContainerRef.createEmbeddedView(this.headerContents.get(i % this.headerContents.length)); }); } }, 10); } onExpand(e) { this.expand.emit(e); } onCollapse(e) { this.collapse.emit(e); } refreshGrid() { this.showGrid = false; setTimeout(() => { this.showGrid = true; }, 0); } onSearch(text) { if (typeof text === 'string' && text != '') { this.filterText = text; } else { this.filterText = ''; } if (!this.config.searchFn) { throw new Error('You should Provide searchFn'); } this.refreshGrid(); this.filterTree(); } /////////////////////////////////////////////////////////////////////////// /////////////////////********************************///////////////////// ///////////********** Start Filtering **********/////////// /** * There are two important things to consider in a tree search.. * If a node contains that search, It should be in final result. * If a node doesn't contain the searched text, but its children do, It should also be in final result. * Otherwise it should be filtered out of the result. */ filterTree() { if (this.dataSource.data && this.filterText) { this.filteredData = [...this.dataSource.data] .filter((item) => this.hasIncludedSearchTextInChildren(item, this.filterText)) .map((item) => this.filtering(item, this.filterText)); } else { this.filteredData = [...this.dataSource.data]; } } filtering(node, text) { return { ...node, isOpen: true, show: true, nodes: this.dataSource.getChildrenFn(node) ?.filter((item) => this.hasIncludedSearchTextInChildren(item, text)) .map((item) => this.filtering(item, text)), }; } hasIncludedSearchTextInChildren(node, searchText) { if (this.config.searchFn(node, searchText)) { return true; } if (this.dataSource.getChildrenFn(node)) { return this.dataSource.getChildrenFn(node).some((child) => this.hasIncludedSearchTextInChildren(child, searchText)); } return false; } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: TreeGridComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: TreeGridComponent, selector: "ngm-tree-grid", inputs: { dataSource: "dataSource", config: "config" }, outputs: { expand: "expand", collapse: "collapse" }, queries: [{ propertyName: "cellContents", predicate: ["treeGridCell"] }, { propertyName: "headerContents", predicate: ["treeGridHeader"] }], viewQueries: [{ propertyName: "headerPanes", predicate: CellHostDirective, descendants: true }], ngImport: i0, template: "<div class=\"ngm-tree-grid\">\r\n <header>\r\n <div class=\"tree-grid-search\" *ngIf=\"config.hasSearch\">\r\n <ngm-live-search\r\n [searchLabel]=\"config.searchPlaceHolder ?? 'Search'\"\r\n (search)=\"onSearch($event)\"\r\n >\r\n </ngm-live-search>\r\n </div>\r\n </header>\r\n <main>\r\n <div class=\"tree-grid-titles\">\r\n <ng-container *ngIf=\"headerContents\">\r\n <div *ngFor=\"let head of headerContents; index as i\"\r\n [ngStyle]=\"{\r\n width: config.columns[i].width\r\n ? config.columns[i].width + '%'\r\n : 100 / config.columns.length + '%'\r\n }\">\r\n <ng-template ngmCellHost></ng-template>\r\n </div>\r\n </ng-container>\r\n <ng-container *ngIf=\"!headerContents\">\r\n <div\r\n *ngFor=\"let head of config.columns; let first = first\"\r\n [ngStyle]=\"{\r\n width: head.width\r\n ? head.width + '%'\r\n : 100 / config.columns.length + '%'\r\n }\"\r\n >\r\n {{ head.header }}\r\n </div>\r\n </ng-container>\r\n </div>\r\n <ngm-tree-grid-item\r\n *ngIf=\"showGrid\"\r\n [data]=\"filterText === '' ? dataSource.data : filteredData\"\r\n [config]=\"config\"\r\n (expand)=\"onExpand($event)\"\r\n (collapse)=\"onCollapse($event)\"\r\n [getChildrenFn]=\"dataSource.getChildrenFn\"\r\n [cellInputs]=\"cellContents\"\r\n >\r\n </ngm-tree-grid-item>\r\n </main>\r\n <footer></footer>\r\n</div>\r\n", styles: [".ngm-tree-grid{border:1px solid rgba(0,0,0,.1215686275)}.tree-grid-titles{width:100%;display:flex;flex-direction:row;justify-content:flex-start;align-items:center}.tree-grid-titles div{padding:2px;border:1px solid rgba(0,0,0,.1215686275);min-width:100px;height:40px}.tree-grid-titles>div:first-child{padding:2px 1px;width:30%}.tree-grid-search{max-width:200px}\n"], dependencies: [{ kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "component", type: i2.NgmLiveSearchComponent, selector: "ngm-live-search", inputs: ["config", "searchLabel"], outputs: ["search", "searchClosed"] }, { kind: "component", type: i3.TreeGridItemComponent, selector: "ngm-tree-grid-item", inputs: ["level", "data", "config", "getChildrenFn", "cellInputs"], outputs: ["expand", "collapse"] }, { kind: "directive", type: i4.CellHostDirective, selector: "[ngmCellHost]" }] }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: TreeGridComponent, decorators: [{ type: Component, args: [{ selector: 'ngm-tree-grid', template: "<div class=\"ngm-tree-grid\">\r\n <header>\r\n <div class=\"tree-grid-search\" *ngIf=\"config.hasSearch\">\r\n <ngm-live-search\r\n [searchLabel]=\"config.searchPlaceHolder ?? 'Search'\"\r\n (search)=\"onSearch($event)\"\r\n >\r\n </ngm-live-search>\r\n </div>\r\n </header>\r\n <main>\r\n <div class=\"tree-grid-titles\">\r\n <ng-container *ngIf=\"headerContents\">\r\n <div *ngFor=\"let head of headerContents; index as i\"\r\n [ngStyle]=\"{\r\n width: config.columns[i].width\r\n ? config.columns[i].width + '%'\r\n : 100 / config.columns.length + '%'\r\n }\">\r\n <ng-template ngmCellHost></ng-template>\r\n </div>\r\n </ng-container>\r\n <ng-container *ngIf=\"!headerContents\">\r\n <div\r\n *ngFor=\"let head of config.columns; let first = first\"\r\n [ngStyle]=\"{\r\n width: head.width\r\n ? head.width + '%'\r\n : 100 / config.columns.length + '%'\r\n }\"\r\n >\r\n {{ head.header }}\r\n </div>\r\n </ng-container>\r\n </div>\r\n <ngm-tree-grid-item\r\n *ngIf=\"showGrid\"\r\n [data]=\"filterText === '' ? dataSource.data : filteredData\"\r\n [config]=\"config\"\r\n (expand)=\"onExpand($event)\"\r\n (collapse)=\"onCollapse($event)\"\r\n [getChildrenFn]=\"dataSource.getChildrenFn\"\r\n [cellInputs]=\"cellContents\"\r\n >\r\n </ngm-tree-grid-item>\r\n </main>\r\n <footer></footer>\r\n</div>\r\n", styles: [".ngm-tree-grid{border:1px solid rgba(0,0,0,.1215686275)}.tree-grid-titles{width:100%;display:flex;flex-direction:row;justify-content:flex-start;align-items:center}.tree-grid-titles div{padding:2px;border:1px solid rgba(0,0,0,.1215686275);min-width:100px;height:40px}.tree-grid-titles>div:first-child{padding:2px 1px;width:30%}.tree-grid-search{max-width:200px}\n"] }] }], ctorParameters: function () { return []; }, propDecorators: { expand: [{ type: Output }], collapse: [{ type: Output }], dataSource: [{ type: Input }], config: [{ type: Input }], cellContents: [{ type: ContentChildren, args: ['treeGridCell'] }], headerContents: [{ type: ContentChildren, args: ['treeGridHeader'] }], headerPanes: [{ type: ViewChildren, args: [CellHostDirective] }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHJlZS1ncmlkLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL25nbS10cmVlLWdyaWQvc3JjL2xpYi9jb21wb25lbnRzL3RyZWUtZ3JpZC90cmVlLWdyaWQuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvbmdtLXRyZWUtZ3JpZC9zcmMvbGliL2NvbXBvbmVudHMvdHJlZS1ncmlkL3RyZWUtZ3JpZC5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsU0FBUyxFQUFFLGVBQWUsRUFBRSxZQUFZLEVBQUUsS0FBSyxFQUFFLE1BQU0sRUFBMEIsWUFBWSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQzlILE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxNQUFNLGlCQUFpQixDQUFDOzs7Ozs7QUFVcEQsTUFBTSxPQUFPLGlCQUFpQjtJQUM1Qiw2RUFBNkU7SUFFN0UsTUFBTSxHQUFHLElBQUksWUFBWSxFQUFpQixDQUFDO0lBRTNDLCtFQUErRTtJQUUvRSxRQUFRLEdBQUcsSUFBSSxZQUFZLEVBQWlCLENBQUM7SUFHN0MsVUFBVSxDQUFxQjtJQUcvQixNQUFNLEdBQXVCO1FBQzNCLFNBQVMsRUFBRSxJQUFJO1FBQ2YsT0FBTyxFQUFFLEVBQUU7UUFDWCxpQkFBaUIsRUFBRSxRQUFRO1FBQzNCLFFBQVEsRUFBRSxDQUFDLEdBQVEsRUFBRSxHQUFXLEVBQUUsRUFBRTtZQUNsQyxPQUFPLE1BQU0sQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDO2lCQUN0QixNQUFNLENBQUMsQ0FBQyxDQUFNLEVBQUUsRUFBRSxDQUFDLENBQUMsT0FBTyxDQUFDLEtBQUssUUFBUSxJQUFJLE9BQU8sQ0FBQyxLQUFLLFFBQVEsQ0FBQyxDQUFDO2lCQUNwRSxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUM7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QUFlO3VCQUFDLGdCQUFnQjtnQkFDQSxXQUFXO3NCQUEzQyxZQUFZO3VCQUFDLGlCQUFpQiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENvbXBvbmVudCwgQ29udGVudENoaWxkcmVuLCBFdmVudEVtaXR0ZXIsIElucHV0LCBPdXRwdXQsIFF1ZXJ5TGlzdCwgVGVtcGxhdGVSZWYsIFZpZXdDaGlsZHJlbiB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xyXG5pbXBvcnQgeyBDZWxsSG9zdERpcmVjdGl2ZSB9IGZyb20gJy4uLy4uL2RpcmVjdGl2ZSc7XHJcbmltcG9ydCB7IElOZ21FeHBhbnNpb24gfSBmcm9tICcuLi8uLi9tb2RlbCc7XHJcbmltcG9ydCB7IElOZ21EYXRhU291cmNlIH0gZnJvbSAnLi8uLi8uLi9tb2RlbC9kYXRhc291cmNlLW1vZGVsJztcclxuaW1wb3J0IHsgSU5nbVRyZWVHcmlkQ29uZmlnIH0gZnJvbSAnLi8uLi8uLi9tb2RlbC90cmVlLWdyaWQtY29uZmlnJztcclxuXHJcbkBDb21wb25lbnQoe1xyXG4gIHNlbGVjdG9yOiAnbmdtLXRyZWUtZ3JpZCcsXHJcbiAgdGVtcGxhdGVVcmw6ICcuL3RyZWUtZ3JpZC5jb21wb25lbnQuaHRtbCcsXHJcbiAgc3R5bGVVcmxzOiBbJy4vdHJlZS1ncmlkLmNvbXBvbmVudC5zY3NzJ11cclxufSlcclxuZXhwb3J0IGNsYXNzIFRyZWVHcmlkQ29tcG9uZW50PFQ+IHtcclxuICAvKiogV2hlbiB1c2VyIGNsaWNrcyBvbiBhcnJvdyB0byBleHBhbmQgYSByb3csIHRoaXMgZW1pdHRlciBlbWl0cyBhbiBldmVudCAqL1xyXG4gIEBPdXRwdXQoKVxyXG4gIGV4cGFuZCA9IG5ldyBFdmVudEVtaXR0ZXI8SU5nbUV4cGFuc2lvbj4oKTtcclxuXHJcbiAgLyoqIFdoZW4gdXNlciBjbGlja3Mgb24gYXJyb3cgdG8gY29sbGFwc2UgYSByb3csIHRoaXMgZW1pdHRlciBlbWl0cyBhbiBldmVudCAqL1xyXG4gIEBPdXRwdXQoKVxyXG4gIGNvbGxhcHNlID0gbmV3IEV2ZW50RW1pdHRlcjxJTmdtRXhwYW5zaW9uPigpO1xyXG5cclxuICBASW5wdXQoKVxyXG4gIGRhdGFTb3VyY2UhOiBJTmdtRGF0YVNvdXJjZTxUPjtcclxuXHJcbiAgQElucHV0KClcclxuICBjb25maWc6IElOZ21UcmVlR3JpZENvbmZpZyA9IHtcclxuICAgIGhhc1NlYXJjaDogdHJ1ZSxcclxuICAgIGNvbHVtbnM6IFtdLFxyXG4gICAgc2VhcmNoUGxhY2VIb2xkZXI6ICdTZWFyY2gnLFxyXG4gICAgc2VhcmNoRm46IChvYmo6IGFueSwgdHh0OiBzdHJpbmcpID0+IHtcclxuICAgICAgcmV0dXJuIE9iamVjdC52YWx1ZXMob2JqKVxyXG4gICAgICAgIC5maWx0ZXIoKHg6IGFueSkgPT4gKHR5cGVvZiB4ID09PSAnc3RyaW5nJyB8fCB0eXBlb2YgeCA9PT0gJ251bWJlcicpKVxyXG4gICAgICAgIC5tYXAoeCA9PiBTdHJpbmcoeCkpXHJcbiAgICAgICAgLnNvbWUoKHk6IHN0cmluZykgPT4geS5pbmNsdWRlcyh0eHQpKVxyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgQENvbnRlbnRDaGlsZHJlbigndHJlZUdyaWRDZWxsJykgY2VsbENvbnRlbnRzITogUXVlcnlMaXN0PFRlbXBsYXRlUmVmPGFueT4+O1xyXG4gIEBDb250ZW50Q2hpbGRyZW4oJ3RyZWVHcmlkSGVhZGVyJykgaGVhZGVyQ29udGVudHM/OiBRdWVyeUxpc3Q8VGVtcGxhdGVSZWY8YW55Pj47XHJcbiAgQFZpZXdDaGlsZHJlbihDZWxsSG9zdERpcmVjdGl2ZSkgaGVhZGVyUGFuZXMhOiBRdWVyeUxpc3Q8Q2VsbEhvc3REaXJlY3RpdmU+O1xyXG5cclxuICBmaWx0ZXJUZXh0ID0gJyc7XHJcbiAgZmlsdGVyZWREYXRhOiBUW10gPSBbXTtcclxuXHJcbiAgc2hvd0dyaWQgPSB0cnVlO1xyXG5cclxuICBjb25zdHJ1Y3RvcigpIHsgfVxyXG5cclxuICBuZ0FmdGVyQ29udGVudEluaXQoKTogdm9pZCB7XHJcbiAgICBzZXRUaW1lb3V0KCgpID0+IHtcclxuICAgICAgaWYodGhpcy5oZWFkZXJDb250ZW50cykge1xyXG4gICAgICAgIHRoaXMuaGVhZGVyUGFuZXMuZm9yRWFjaCgoeCwgaSkgPT4ge1xyXG4gICAgICAgICAgeC52aWV3Q29udGFpbmVyUmVmLmNsZWFyKCk7XHJcbiAgICAgICAgICB4LnZpZXdDb250YWluZXJSZWYuY3JlYXRlRW1iZWRkZWRWaWV3KHRoaXMuaGVhZGVyQ29udGVudHMhLmdldChpICUgdGhpcy5oZWFkZXJDb250ZW50cyEubGVuZ3RoKSEpXHJcbiAgICAgICAgfSk7XHJcbiAgICAgIH1cclxuICAgIH0sIDEwKTtcclxuICB9XHJcblxyXG4gIG9uRXhwYW5kKGU6IElOZ21FeHBhbnNpb24pIHtcclxuICAgIHRoaXMuZXhwYW5kLmVtaXQoZSlcclxuICB9XHJcblxyXG4gIG9uQ29sbGFwc2UoZTogSU5nbUV4cGFuc2lvbikge1xyXG4gICAgdGhpcy5jb2xsYXBzZS5lbWl0KGUpXHJcbiAgfVxyXG5cclxuICByZWZyZXNoR3JpZCgpIHtcclxuICAgIHRoaXMuc2hvd0dyaWQgPSBmYWxzZTtcclxuICAgIHNldFRpbWVvdXQoKCkgPT4ge1xyXG4gICAgICB0aGlzLnNob3dHcmlkID0gdHJ1ZVxyXG4gICAgfSwgMCk7XHJcbiAgfVxyXG5cclxuICBvblNlYXJjaCh0ZXh0OiBzdHJpbmcpIHtcclxuICAgIGlmICh0eXBlb2YgdGV4dCA9PT0gJ3N0cmluZycgJiYgdGV4dCAhPSAnJykge1xyXG4gICAgICB0aGlzLmZpbHRlclRleHQgPSB0ZXh0XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICB0aGlzLmZpbHRlclRleHQgPSAnJ1xyXG4gICAgfVxyXG4gICAgaWYgKCF0aGlzLmNvbmZpZy5zZWFyY2hGbikge1xyXG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ1lvdSBzaG91bGQgUHJvdmlkZSBzZWFyY2hGbicpXHJcbiAgICB9XHJcbiAgICB0aGlzLnJlZnJlc2hHcmlkKCk7XHJcbiAgICB0aGlzLmZpbHRlclRyZWUoKTtcclxuICB9XHJcblxyXG4gIC8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vL1xyXG4gIC8vLy8vLy8vLy8vLy8vLy8vLy8vLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqLy8vLy8vLy8vLy8vLy8vLy8vLy8vXHJcbiAgLy8vLy8vLy8vLy8qKioqKioqKioqICAgICBTdGFydCBGaWx0ZXJpbmcgICAgICAgKioqKioqKioqKi8vLy8vLy8vLy8vXHJcbiAgLyoqXHJcbiAgICogVGhlcmUgYXJlIHR3byBpbXBvcnRhbnQgdGhpbmdzIHRvIGNvbnNpZGVyIGluIGEgdHJlZSBzZWFyY2guLlxyXG4gICAqIElmIGEgbm9kZSBjb250YWlucyB0aGF0IHNlYXJjaCwgSXQgc2hvdWxkIGJlIGluIGZpbmFsIHJlc3VsdC5cclxuICAgKiBJZiBhIG5vZGUgZG9lc24ndCBjb250YWluIHRoZSBzZWFyY2hlZCB0ZXh0LCBidXQgaXRzIGNoaWxkcmVuIGRvLCBJdCBzaG91bGQgYWxzbyBiZSBpbiBmaW5hbCByZXN1bHQuXHJcbiAgICogT3RoZXJ3aXNlIGl0IHNob3VsZCBiZSBmaWx0ZXJlZCBvdXQgb2YgdGhlIHJlc3VsdC5cclxuICAgKi9cclxuICBmaWx0ZXJUcmVlKCkge1xyXG4gICAgaWYgKHRoaXMuZGF0YVNvdXJjZS5kYXRhICYmIHRoaXMuZmlsdGVyVGV4dCkge1xyXG4gICAgICB0aGlzLmZpbHRlcmVkRGF0YSA9IFsuLi50aGlzLmRhdGFTb3VyY2UuZGF0YV1cclxuICAgICAgICAuZmlsdGVyKChpdGVtKSA9PlxyXG4gICAgICAgICAgdGhpcy5oYXNJbmNsdWRlZFNlYXJjaFRleHRJbkNoaWxkcmVuKGl0ZW0sIHRoaXMuZmlsdGVyVGV4dClcclxuICAgICAgICApXHJcbiAgICAgICAgLm1hcCgoaXRlbSkgPT4gdGhpcy5maWx0ZXJpbmcoaXRlbSwgdGhpcy5maWx0ZXJUZXh0KSk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICB0aGlzLmZpbHRlcmVkRGF0YSA9IFsuLi50aGlzLmRhdGFTb3VyY2UuZGF0YV07XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBmaWx0ZXJpbmcobm9kZTogVCwgdGV4dDogc3RyaW5nKTogVCB7XHJcbiAgICByZXR1cm4ge1xyXG4gICAgICAuLi5ub2RlLFxyXG4gICAgICBpc09wZW46IHRydWUsXHJcbiAgICAgIHNob3c6IHRydWUsXHJcbiAgICAgIG5vZGVzOiB0aGlzLmRhdGFTb3VyY2UuZ2V0Q2hpbGRyZW5Gbihub2RlKVxyXG4gICAgICAgID8uZmlsdGVyKChpdGVtKSA9PiB0aGlzLmhhc0luY2x1ZGVkU2VhcmNoVGV4dEluQ2hpbGRyZW4oaXRlbSwgdGV4dCkpXHJcbiAgICAgICAgLm1hcCgoaXRlbSkgPT4gdGhpcy5maWx0ZXJpbmcoaXRlbSwgdGV4dCkpLFxyXG4gICAgfTtcclxuICB9XHJcblxyXG4gIGhhc0luY2x1ZGVkU2VhcmNoVGV4dEluQ2hpbGRyZW4obm9kZTogYW55LCBzZWFyY2hUZXh0OiBzdHJpbmcpOiBib29sZWFuIHtcclxuICAgIGlmICh0aGlzLmNvbmZpZy5zZWFyY2hGbiEobm9kZSwgc2VhcmNoVGV4dCkpIHtcclxuICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICB9XHJcbiAgICBpZiAodGhpcy5kYXRhU291cmNlLmdldENoaWxkcmVuRm4obm9kZSkpIHtcclxuICAgICAgcmV0dXJuIHRoaXMuZGF0YVNvdXJjZS5nZXRDaGlsZHJlbkZuKG5vZGUpLnNvbWUoKGNoaWxkOiBhbnkpID0+XHJcbiAgICAgICAgdGhpcy5oYXNJbmNsdWRlZFNlYXJjaFRleHRJbkNoaWxkcmVuKGNoaWxkLCBzZWFyY2hUZXh0KVxyXG4gICAgICApO1xyXG4gICAgfVxyXG4gICAgcmV0dXJuIGZhbHNlO1xyXG4gIH1cclxuXHJcbiAgLy8vLy8vLy8vLy8vLyoqKioqKioqKiogICAgIEVuZCBGaWx0ZXJpbmcgICAgICAqKioqKioqKioqLy8vLy8vLy8vLy8vXHJcbiAgLy8vLy8vLy8vLy8vLy8vLy8vLy8vKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovLy8vLy8vLy8vLy8vLy8vLy8vLy9cclxuICAvLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vL1xyXG5cclxuXHJcblxyXG59XHJcbiIsIjxkaXYgY2xhc3M9XCJuZ20tdHJlZS1ncmlkXCI+XHJcbiAgPGhlYWRlcj5cclxuICAgIDxkaXYgY2xhc3M9XCJ0cmVlLWdyaWQtc2VhcmNoXCIgKm5nSWY9XCJjb25maWcuaGFzU2VhcmNoXCI+XHJcbiAgICAgIDxuZ20tbGl2ZS1zZWFyY2hcclxuICAgICAgICBbc2VhcmNoTGFiZWxdPVwiY29uZmlnLnNlYXJjaFBsYWNlSG9sZGVyID8/ICdTZWFyY2gnXCJcclxuICAgICAgICAoc2VhcmNoKT1cIm9uU2VhcmNoKCRldmVudClcIlxyXG4gICAgICA+XHJcbiAgICAgIDwvbmdtLWxpdmUtc2VhcmNoPlxyXG4gICAgPC9kaXY+XHJcbiAgPC9oZWFkZXI+XHJcbiAgPG1haW4+XHJcbiAgICA8ZGl2IGNsYXNzPVwidHJlZS1ncmlkLXRpdGxlc1wiPlxyXG4gICAgICA8bmctY29udGFpbmVyICpuZ0lmPVwiaGVhZGVyQ29udGVudHNcIj5cclxuICAgICAgICA8ZGl2ICpuZ0Zvcj1cImxldCBoZWFkIG9mIGhlYWRlckNvbnRlbnRzOyBpbmRleCBhcyBpXCJcclxuICAgICAgICBbbmdTdHlsZV09XCJ7XHJcbiAgICAgICAgICB3aWR0aDogY29uZmlnLmNvbHVtbnNbaV0ud2lkdGhcclxuICAgICAgICAgICAgPyBjb25maWcuY29sdW1uc1tpXS53aWR0aCArICclJ1xyXG4gICAgICAgICAgICA6IDEwMCAvIGNvbmZpZy5jb2x1bW5zLmxlbmd0aCArICclJ1xyXG4gICAgICAgIH1cIj5cclxuICAgICAgICAgIDxuZy10ZW1wbGF0ZSBuZ21DZWxsSG9zdD48L25nLXRlbXBsYXRlPlxyXG4gICAgICAgIDwvZGl2PlxyXG4gICAgICA8L25nLWNvbnRhaW5lcj5cclxuICAgICAgPG5nLWNvbnRhaW5lciAqbmdJZj1cIiFoZWFkZXJDb250ZW50c1wiPlxyXG4gICAgICAgIDxkaXZcclxuICAgICAgICAqbmdGb3I9XCJsZXQgaGVhZCBvZiBjb25maWcuY29sdW1uczsgbGV0IGZpcnN0ID0gZmlyc3RcIlxyXG4gICAgICAgIFtuZ1N0eWxlXT1cIntcclxuICAgICAgICAgIHdpZHRoOiBoZWFkLndpZHRoXHJcbiAgICAgICAgICAgID8gaGVhZC53aWR0aCArICclJ1xyXG4gICAgICAgICAgICA6IDEwMCAvIGNvbmZpZy5jb2x1bW5zLmxlbmd0aCArICclJ1xyXG4gICAgICAgIH1cIlxyXG4gICAgICA+XHJcbiAgICAgICAge3sgaGVhZC5oZWFkZXIgfX1cclxuICAgICAgPC9kaXY+XHJcbiAgICAgIDwvbmctY29udGFpbmVyPlxyXG4gICAgPC9kaXY+XHJcbiAgICA8bmdtLXRyZWUtZ3JpZC1pdGVtXHJcbiAgICAgICpuZ0lmPVwic2hvd0dyaWRcIlxyXG4gICAgICBbZGF0YV09XCJmaWx0ZXJUZXh0ID09PSAnJyA/IGRhdGFTb3VyY2UuZGF0YSA6IGZpbHRlcmVkRGF0YVwiXHJcbiAgICAgIFtjb25maWddPVwiY29uZmlnXCJcclxuICAgICAgKGV4cGFuZCk9XCJvbkV4cGFuZCgkZXZlbnQpXCJcclxuICAgICAgKGNvbGxhcHNlKT1cIm9uQ29sbGFwc2UoJGV2ZW50KVwiXHJcbiAgICAgIFtnZXRDaGlsZHJlbkZuXT1cImRhdGFTb3VyY2UuZ2V0Q2hpbGRyZW5GblwiXHJcbiAgICAgIFtjZWxsSW5wdXRzXT1cImNlbGxDb250ZW50c1wiXHJcbiAgICA+XHJcbiAgICA8L25nbS10cmVlLWdyaWQtaXRlbT5cclxuICA8L21haW4+XHJcbiAgPGZvb3Rlcj48L2Zvb3Rlcj5cclxuPC9kaXY+XHJcbiJdfQ==