ngm-tree-grid
Version:
A tree grid that supports editable fields like Inputs and Checkboxes.
129 lines • 23.1 kB
JavaScript
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==