UNPKG

@treeview/ngx-treeview

Version:

An Angular Boostrap treeview component

212 lines 47.1 kB
import { Component, Input, Output, EventEmitter } from '@angular/core'; import { isNil, includes } from 'lodash'; import { TreeviewItem } from '../../models/treeview-item'; import { TreeviewHelper } from '../../helpers/treeview-helper'; import * as i0 from "@angular/core"; import * as i1 from "../../models/treeview-i18n"; import * as i2 from "../../models/treeview-config"; import * as i3 from "../../helpers/treeview-event-parser"; import * as i4 from "@angular/forms"; import * as i5 from "@angular/common"; import * as i6 from "../treeview-item/treeview-item.component"; class FilterTreeviewItem extends TreeviewItem { constructor(item) { super({ text: item.text, value: item.value, disabled: item.disabled, checked: item.checked, collapsed: item.collapsed, children: item.children }); this.refItem = item; } updateRefChecked() { this.children.forEach(child => { if (child instanceof FilterTreeviewItem) { child.updateRefChecked(); } }); let refChecked = this.checked; if (refChecked) { for (const refChild of this.refItem.children) { if (!refChild.checked) { refChecked = false; break; } } } this.refItem.checked = refChecked; } } export class TreeviewComponent { constructor(i18n, defaultConfig, eventParser) { this.i18n = i18n; this.defaultConfig = defaultConfig; this.eventParser = eventParser; this.selectedChange = new EventEmitter(); this.filterChange = new EventEmitter(); this.filterText = ''; this.config = this.defaultConfig; this.allItem = new TreeviewItem({ text: 'All', value: undefined }); } get hasFilterItems() { return !isNil(this.filterItems) && this.filterItems.length > 0; } get maxHeight() { return `${this.config.maxHeight}`; } ngOnInit() { this.createHeaderTemplateContext(); this.generateSelection(); } ngOnChanges(changes) { const itemsSimpleChange = changes.items; if (!isNil(itemsSimpleChange) && !isNil(this.items)) { this.updateFilterItems(); this.updateCollapsedOfAll(); this.raiseSelectedChange(); } } onAllCollapseExpand() { this.allItem.collapsed = !this.allItem.collapsed; this.filterItems.forEach(item => item.setCollapsedRecursive(this.allItem.collapsed)); } onFilterTextChange(text) { this.filterText = text; this.filterChange.emit(text); this.updateFilterItems(); } onAllCheckedChange() { const checked = this.allItem.checked; this.filterItems.forEach(item => { item.setCheckedRecursive(checked); if (item instanceof FilterTreeviewItem) { item.updateRefChecked(); } }); this.raiseSelectedChange(); } onItemCheckedChange(item, checked) { if (item instanceof FilterTreeviewItem) { item.updateRefChecked(); } this.updateCheckedOfAll(); this.raiseSelectedChange(); } raiseSelectedChange() { this.generateSelection(); const values = this.eventParser.getSelectedChange(this); setTimeout(() => { this.selectedChange.emit(values); }); } createHeaderTemplateContext() { this.headerTemplateContext = { config: this.config, item: this.allItem, onCheckedChange: () => this.onAllCheckedChange(), onCollapseExpand: () => this.onAllCollapseExpand(), onFilterTextChange: (text) => this.onFilterTextChange(text) }; } generateSelection() { let checkedItems = []; let uncheckedItems = []; if (!isNil(this.items)) { const selection = TreeviewHelper.concatSelection(this.items, checkedItems, uncheckedItems); checkedItems = selection.checked; uncheckedItems = selection.unchecked; } this.selection = { checkedItems, uncheckedItems }; } updateFilterItems() { if (this.filterText !== '') { const filterItems = []; const filterText = this.filterText.toLowerCase(); this.items.forEach(item => { const newItem = this.filterItem(item, filterText); if (!isNil(newItem)) { filterItems.push(newItem); } }); this.filterItems = filterItems; } else { this.filterItems = this.items; } this.updateCheckedOfAll(); } filterItem(item, filterText) { const isMatch = includes(item.text.toLowerCase(), filterText); if (isMatch) { return item; } else { if (!isNil(item.children)) { const children = []; item.children.forEach(child => { const newChild = this.filterItem(child, filterText); if (!isNil(newChild)) { children.push(newChild); } }); if (children.length > 0) { const newItem = new FilterTreeviewItem(item); newItem.collapsed = false; newItem.children = children; return newItem; } } } return undefined; } updateCheckedOfAll() { let itemChecked = null; for (const filterItem of this.filterItems) { if (itemChecked === null) { itemChecked = filterItem.checked; } else if (itemChecked !== filterItem.checked) { itemChecked = undefined; break; } } if (itemChecked === null) { itemChecked = false; } this.allItem.checked = itemChecked; } updateCollapsedOfAll() { let hasItemExpanded = false; for (const filterItem of this.filterItems) { if (!filterItem.collapsed) { hasItemExpanded = true; break; } } this.allItem.collapsed = !hasItemExpanded; } } TreeviewComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: TreeviewComponent, deps: [{ token: i1.TreeviewI18n }, { token: i2.TreeviewConfig }, { token: i3.TreeviewEventParser }], target: i0.ɵɵFactoryTarget.Component }); TreeviewComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: TreeviewComponent, selector: "ngx-treeview", inputs: { headerTemplate: "headerTemplate", itemTemplate: "itemTemplate", items: "items", config: "config" }, outputs: { selectedChange: "selectedChange", filterChange: "filterChange" }, usesOnChanges: true, ngImport: i0, template: "<ng-template #defaultItemTemplate let-item=\"item\" let-onCollapseExpand=\"onCollapseExpand\"\r\n let-onCheckedChange=\"onCheckedChange\">\r\n <div class=\"d-flex align-items-center\" style=\"display: flex;\" [ngClass]=\"{'row-item': !config.compact}\">\r\n <i *ngIf=\"item.children\" (click)=\"onCollapseExpand()\" aria-hidden=\"true\" [ngSwitch]=\"item.collapsed\" class=\"me-1\">\r\n <svg *ngSwitchCase=\"true\" width=\"0.8rem\" height=\"0.8rem\" viewBox=\"0 0 16 16\" class=\"bi bi-caret-right-fill\"\r\n fill=\"currentColor\" xmlns=\"http://www.w3.org/2000/svg\">\r\n <path\r\n d=\"M12.14 8.753l-5.482 4.796c-.646.566-1.658.106-1.658-.753V3.204a1 1 0 0 1 1.659-.753l5.48 4.796a1 1 0 0 1 0 1.506z\" />\r\n </svg>\r\n <svg *ngSwitchCase=\"false\" width=\"0.8rem\" height=\"0.8rem\" viewBox=\"0 0 16 16\" class=\"bi bi-caret-down-fill\"\r\n fill=\"currentColor\" xmlns=\"http://www.w3.org/2000/svg\">\r\n <path\r\n d=\"M7.247 11.14L2.451 5.658C1.885 5.013 2.345 4 3.204 4h9.592a1 1 0 0 1 .753 1.659l-4.796 5.48a1 1 0 0 1-1.506 0z\" />\r\n </svg>\r\n </i>\r\n <div class=\"form-check mb-0\">\r\n <input type=\"checkbox\" class=\"form-check-input\" *ngIf=\"config.hasCheckBoxes\" [(ngModel)]=\"item.checked\" (ngModelChange)=\"onCheckedChange()\"\r\n [disabled]=\"item.disabled\" [indeterminate]=\"item.indeterminate\" />\r\n <label class=\"form-check-label\" (click)=\"item.checked = !item.checked; onCheckedChange()\">\r\n {{item.text}}\r\n </label>\r\n </div>\r\n </div>\r\n</ng-template>\r\n<ng-template #defaultHeaderTemplate let-config=\"config\" let-item=\"item\" let-onCollapseExpand=\"onCollapseExpand\"\r\n let-onCheckedChange=\"onCheckedChange\" let-onFilterTextChange=\"onFilterTextChange\">\r\n <div *ngIf=\"config.hasFilter\" class=\"row row-filter\">\r\n <div class=\"col-12\">\r\n <input class=\"form-control\" type=\"text\" [placeholder]=\"i18n.getFilterPlaceholder()\" [(ngModel)]=\"filterText\"\r\n (ngModelChange)=\"onFilterTextChange($event)\" />\r\n </div>\r\n </div>\r\n <div *ngIf=\"hasFilterItems\">\r\n <div *ngIf=\"(config.hasCheckBoxes && config.hasAllCheckBox) || config.hasCollapseExpand\" class=\"row row-all\">\r\n <div class=\"col-12\">\r\n <div class=\"form-check form-check-inline\" *ngIf=\"config.hasCheckBoxes && config.hasAllCheckBox\">\r\n <input type=\"checkbox\" class=\"form-check-input\" [(ngModel)]=\"item.checked\" (ngModelChange)=\"onCheckedChange()\"\r\n [indeterminate]=\"item.indeterminate\" />\r\n <label class=\"form-check-label\" (click)=\"item.checked = !item.checked; onCheckedChange()\">\r\n {{i18n.getAllCheckboxText()}}\r\n </label>\r\n </div>\r\n <label *ngIf=\"config.hasCollapseExpand\" class=\"float-end form-check-label\" (click)=\"onCollapseExpand()\">\r\n <i [title]=\"i18n.getTooltipCollapseExpandText(item.collapsed)\" aria-hidden=\"true\" [ngSwitch]=\"item.collapsed\">\r\n <svg *ngSwitchCase=\"true\" width=\"1em\" height=\"1em\" viewBox=\"0 0 16 16\" class=\"bi bi-arrows-angle-expand\"\r\n fill=\"currentColor\" xmlns=\"http://www.w3.org/2000/svg\">\r\n <path fill-rule=\"evenodd\"\r\n d=\"M1.5 10.036a.5.5 0 0 1 .5.5v3.5h3.5a.5.5 0 0 1 0 1h-4a.5.5 0 0 1-.5-.5v-4a.5.5 0 0 1 .5-.5z\" />\r\n <path fill-rule=\"evenodd\"\r\n d=\"M6.354 9.646a.5.5 0 0 1 0 .708l-4.5 4.5a.5.5 0 0 1-.708-.708l4.5-4.5a.5.5 0 0 1 .708 0zm8.5-8.5a.5.5 0 0 1 0 .708l-4.5 4.5a.5.5 0 0 1-.708-.708l4.5-4.5a.5.5 0 0 1 .708 0z\" />\r\n <path fill-rule=\"evenodd\"\r\n d=\"M10.036 1.5a.5.5 0 0 1 .5-.5h4a.5.5 0 0 1 .5.5v4a.5.5 0 1 1-1 0V2h-3.5a.5.5 0 0 1-.5-.5z\" />\r\n </svg>\r\n <svg *ngSwitchCase=\"false\" width=\"1em\" height=\"1em\" viewBox=\"0 0 16 16\" class=\"bi bi-arrows-angle-contract\"\r\n fill=\"currentColor\" xmlns=\"http://www.w3.org/2000/svg\">\r\n <path fill-rule=\"evenodd\"\r\n d=\"M9.5 2.036a.5.5 0 0 1 .5.5v3.5h3.5a.5.5 0 0 1 0 1h-4a.5.5 0 0 1-.5-.5v-4a.5.5 0 0 1 .5-.5z\" />\r\n <path fill-rule=\"evenodd\"\r\n d=\"M14.354 1.646a.5.5 0 0 1 0 .708l-4.5 4.5a.5.5 0 1 1-.708-.708l4.5-4.5a.5.5 0 0 1 .708 0zm-7.5 7.5a.5.5 0 0 1 0 .708l-4.5 4.5a.5.5 0 0 1-.708-.708l4.5-4.5a.5.5 0 0 1 .708 0z\" />\r\n <path fill-rule=\"evenodd\"\r\n d=\"M2.036 9.5a.5.5 0 0 1 .5-.5h4a.5.5 0 0 1 .5.5v4a.5.5 0 0 1-1 0V10h-3.5a.5.5 0 0 1-.5-.5z\" />\r\n </svg>\r\n </i>\r\n </label>\r\n </div>\r\n </div>\r\n <div *ngIf=\"config.hasDivider\" class=\"dropdown-divider\"></div>\r\n </div>\r\n</ng-template>\r\n<div class=\"treeview-header\">\r\n <ng-template [ngTemplateOutlet]=\"headerTemplate || defaultHeaderTemplate\"\r\n [ngTemplateOutletContext]=\"headerTemplateContext\">\r\n </ng-template>\r\n</div>\r\n<div [ngSwitch]=\"hasFilterItems\" class=\"treeview-wrapper\">\r\n <div *ngSwitchCase=\"true\" class=\"treeview-container\" [style.max-height.px]=\"maxHeight\">\r\n <ngx-treeview-item *ngFor=\"let item of filterItems\" [config]=\"config\" [item]=\"item\"\r\n [template]=\"itemTemplate || defaultItemTemplate\" (checkedChange)=\"onItemCheckedChange(item, $event)\">\r\n </ngx-treeview-item>\r\n </div>\r\n <div *ngSwitchCase=\"false\" class=\"treeview-text\">\r\n {{i18n.getFilterNoItemsFoundText()}}\r\n </div>\r\n</div>\r\n", styles: [":host .treeview-wrapper{display:block;margin-left:-.5rem}:host .treeview-header .row-filter{margin-bottom:.5rem}:host .treeview-header .row-all .bi{cursor:pointer}:host .treeview-container{overflow-y:auto;padding-right:1rem;padding-left:.5rem}:host .treeview-container .row-item{margin-bottom:.3rem;flex-wrap:nowrap}:host .treeview-container .row-item .bi{cursor:pointer;margin-right:.3rem}:host .treeview-container .treeview-row-item .col{padding-left:0}.treeview-text{padding:.3rem 0;white-space:nowrap}\n"], dependencies: [{ kind: "directive", type: i4.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: i4.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i4.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i4.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i5.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i5.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i5.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i5.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i5.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "component", type: i6.TreeviewItemComponent, selector: "ngx-treeview-item", inputs: ["config", "template", "item"], outputs: ["checkedChange"] }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: TreeviewComponent, decorators: [{ type: Component, args: [{ selector: 'ngx-treeview', template: "<ng-template #defaultItemTemplate let-item=\"item\" let-onCollapseExpand=\"onCollapseExpand\"\r\n let-onCheckedChange=\"onCheckedChange\">\r\n <div class=\"d-flex align-items-center\" style=\"display: flex;\" [ngClass]=\"{'row-item': !config.compact}\">\r\n <i *ngIf=\"item.children\" (click)=\"onCollapseExpand()\" aria-hidden=\"true\" [ngSwitch]=\"item.collapsed\" class=\"me-1\">\r\n <svg *ngSwitchCase=\"true\" width=\"0.8rem\" height=\"0.8rem\" viewBox=\"0 0 16 16\" class=\"bi bi-caret-right-fill\"\r\n fill=\"currentColor\" xmlns=\"http://www.w3.org/2000/svg\">\r\n <path\r\n d=\"M12.14 8.753l-5.482 4.796c-.646.566-1.658.106-1.658-.753V3.204a1 1 0 0 1 1.659-.753l5.48 4.796a1 1 0 0 1 0 1.506z\" />\r\n </svg>\r\n <svg *ngSwitchCase=\"false\" width=\"0.8rem\" height=\"0.8rem\" viewBox=\"0 0 16 16\" class=\"bi bi-caret-down-fill\"\r\n fill=\"currentColor\" xmlns=\"http://www.w3.org/2000/svg\">\r\n <path\r\n d=\"M7.247 11.14L2.451 5.658C1.885 5.013 2.345 4 3.204 4h9.592a1 1 0 0 1 .753 1.659l-4.796 5.48a1 1 0 0 1-1.506 0z\" />\r\n </svg>\r\n </i>\r\n <div class=\"form-check mb-0\">\r\n <input type=\"checkbox\" class=\"form-check-input\" *ngIf=\"config.hasCheckBoxes\" [(ngModel)]=\"item.checked\" (ngModelChange)=\"onCheckedChange()\"\r\n [disabled]=\"item.disabled\" [indeterminate]=\"item.indeterminate\" />\r\n <label class=\"form-check-label\" (click)=\"item.checked = !item.checked; onCheckedChange()\">\r\n {{item.text}}\r\n </label>\r\n </div>\r\n </div>\r\n</ng-template>\r\n<ng-template #defaultHeaderTemplate let-config=\"config\" let-item=\"item\" let-onCollapseExpand=\"onCollapseExpand\"\r\n let-onCheckedChange=\"onCheckedChange\" let-onFilterTextChange=\"onFilterTextChange\">\r\n <div *ngIf=\"config.hasFilter\" class=\"row row-filter\">\r\n <div class=\"col-12\">\r\n <input class=\"form-control\" type=\"text\" [placeholder]=\"i18n.getFilterPlaceholder()\" [(ngModel)]=\"filterText\"\r\n (ngModelChange)=\"onFilterTextChange($event)\" />\r\n </div>\r\n </div>\r\n <div *ngIf=\"hasFilterItems\">\r\n <div *ngIf=\"(config.hasCheckBoxes && config.hasAllCheckBox) || config.hasCollapseExpand\" class=\"row row-all\">\r\n <div class=\"col-12\">\r\n <div class=\"form-check form-check-inline\" *ngIf=\"config.hasCheckBoxes && config.hasAllCheckBox\">\r\n <input type=\"checkbox\" class=\"form-check-input\" [(ngModel)]=\"item.checked\" (ngModelChange)=\"onCheckedChange()\"\r\n [indeterminate]=\"item.indeterminate\" />\r\n <label class=\"form-check-label\" (click)=\"item.checked = !item.checked; onCheckedChange()\">\r\n {{i18n.getAllCheckboxText()}}\r\n </label>\r\n </div>\r\n <label *ngIf=\"config.hasCollapseExpand\" class=\"float-end form-check-label\" (click)=\"onCollapseExpand()\">\r\n <i [title]=\"i18n.getTooltipCollapseExpandText(item.collapsed)\" aria-hidden=\"true\" [ngSwitch]=\"item.collapsed\">\r\n <svg *ngSwitchCase=\"true\" width=\"1em\" height=\"1em\" viewBox=\"0 0 16 16\" class=\"bi bi-arrows-angle-expand\"\r\n fill=\"currentColor\" xmlns=\"http://www.w3.org/2000/svg\">\r\n <path fill-rule=\"evenodd\"\r\n d=\"M1.5 10.036a.5.5 0 0 1 .5.5v3.5h3.5a.5.5 0 0 1 0 1h-4a.5.5 0 0 1-.5-.5v-4a.5.5 0 0 1 .5-.5z\" />\r\n <path fill-rule=\"evenodd\"\r\n d=\"M6.354 9.646a.5.5 0 0 1 0 .708l-4.5 4.5a.5.5 0 0 1-.708-.708l4.5-4.5a.5.5 0 0 1 .708 0zm8.5-8.5a.5.5 0 0 1 0 .708l-4.5 4.5a.5.5 0 0 1-.708-.708l4.5-4.5a.5.5 0 0 1 .708 0z\" />\r\n <path fill-rule=\"evenodd\"\r\n d=\"M10.036 1.5a.5.5 0 0 1 .5-.5h4a.5.5 0 0 1 .5.5v4a.5.5 0 1 1-1 0V2h-3.5a.5.5 0 0 1-.5-.5z\" />\r\n </svg>\r\n <svg *ngSwitchCase=\"false\" width=\"1em\" height=\"1em\" viewBox=\"0 0 16 16\" class=\"bi bi-arrows-angle-contract\"\r\n fill=\"currentColor\" xmlns=\"http://www.w3.org/2000/svg\">\r\n <path fill-rule=\"evenodd\"\r\n d=\"M9.5 2.036a.5.5 0 0 1 .5.5v3.5h3.5a.5.5 0 0 1 0 1h-4a.5.5 0 0 1-.5-.5v-4a.5.5 0 0 1 .5-.5z\" />\r\n <path fill-rule=\"evenodd\"\r\n d=\"M14.354 1.646a.5.5 0 0 1 0 .708l-4.5 4.5a.5.5 0 1 1-.708-.708l4.5-4.5a.5.5 0 0 1 .708 0zm-7.5 7.5a.5.5 0 0 1 0 .708l-4.5 4.5a.5.5 0 0 1-.708-.708l4.5-4.5a.5.5 0 0 1 .708 0z\" />\r\n <path fill-rule=\"evenodd\"\r\n d=\"M2.036 9.5a.5.5 0 0 1 .5-.5h4a.5.5 0 0 1 .5.5v4a.5.5 0 0 1-1 0V10h-3.5a.5.5 0 0 1-.5-.5z\" />\r\n </svg>\r\n </i>\r\n </label>\r\n </div>\r\n </div>\r\n <div *ngIf=\"config.hasDivider\" class=\"dropdown-divider\"></div>\r\n </div>\r\n</ng-template>\r\n<div class=\"treeview-header\">\r\n <ng-template [ngTemplateOutlet]=\"headerTemplate || defaultHeaderTemplate\"\r\n [ngTemplateOutletContext]=\"headerTemplateContext\">\r\n </ng-template>\r\n</div>\r\n<div [ngSwitch]=\"hasFilterItems\" class=\"treeview-wrapper\">\r\n <div *ngSwitchCase=\"true\" class=\"treeview-container\" [style.max-height.px]=\"maxHeight\">\r\n <ngx-treeview-item *ngFor=\"let item of filterItems\" [config]=\"config\" [item]=\"item\"\r\n [template]=\"itemTemplate || defaultItemTemplate\" (checkedChange)=\"onItemCheckedChange(item, $event)\">\r\n </ngx-treeview-item>\r\n </div>\r\n <div *ngSwitchCase=\"false\" class=\"treeview-text\">\r\n {{i18n.getFilterNoItemsFoundText()}}\r\n </div>\r\n</div>\r\n", styles: [":host .treeview-wrapper{display:block;margin-left:-.5rem}:host .treeview-header .row-filter{margin-bottom:.5rem}:host .treeview-header .row-all .bi{cursor:pointer}:host .treeview-container{overflow-y:auto;padding-right:1rem;padding-left:.5rem}:host .treeview-container .row-item{margin-bottom:.3rem;flex-wrap:nowrap}:host .treeview-container .row-item .bi{cursor:pointer;margin-right:.3rem}:host .treeview-container .treeview-row-item .col{padding-left:0}.treeview-text{padding:.3rem 0;white-space:nowrap}\n"] }] }], ctorParameters: function () { return [{ type: i1.TreeviewI18n }, { type: i2.TreeviewConfig }, { type: i3.TreeviewEventParser }]; }, propDecorators: { headerTemplate: [{ type: Input }], itemTemplate: [{ type: Input }], items: [{ type: Input }], config: [{ type: Input }], selectedChange: [{ type: Output }], filterChange: [{ type: Output }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHJlZXZpZXcuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvbmd4LXRyZWV2aWV3L3NyYy9saWIvY29tcG9uZW50cy90cmVldmlldy90cmVldmlldy5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9uZ3gtdHJlZXZpZXcvc3JjL2xpYi9jb21wb25lbnRzL3RyZWV2aWV3L3RyZWV2aWV3LmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxTQUFTLEVBQUUsS0FBSyxFQUFFLE1BQU0sRUFBRSxZQUFZLEVBQWlELE1BQU0sZUFBZSxDQUFDO0FBQ3RILE9BQU8sRUFBRSxLQUFLLEVBQUUsUUFBUSxFQUFFLE1BQU0sUUFBUSxDQUFDO0FBRXpDLE9BQU8sRUFBRSxZQUFZLEVBQXFCLE1BQU0sNEJBQTRCLENBQUM7QUFJN0UsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLCtCQUErQixDQUFDOzs7Ozs7OztBQUcvRCxNQUFNLGtCQUFtQixTQUFRLFlBQVk7SUFFM0MsWUFBWSxJQUFrQjtRQUM1QixLQUFLLENBQUM7WUFDSixJQUFJLEVBQUUsSUFBSSxDQUFDLElBQUk7WUFDZixLQUFLLEVBQUUsSUFBSSxDQUFDLEtBQUs7WUFDakIsUUFBUSxFQUFFLElBQUksQ0FBQyxRQUFRO1lBQ3ZCLE9BQU8sRUFBRSxJQUFJLENBQUMsT0FBTztZQUNyQixTQUFTLEVBQUUsSUFBSSxDQUFDLFNBQVM7WUFDekIsUUFBUSxFQUFFLElBQUksQ0FBQyxRQUFRO1NBQ3hCLENBQUMsQ0FBQztRQUNILElBQUksQ0FBQyxPQUFPLEdBQUcsSUFBSSxDQUFDO0lBQ3RCLENBQUM7SUFFRCxnQkFBZ0I7UUFDZCxJQUFJLENBQUMsUUFBUSxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsRUFBRTtZQUM1QixJQUFJLEtBQUssWUFBWSxrQkFBa0IsRUFBRTtn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Q3hCLFdBQVcsR0FBRyxLQUFLLENBQUM7U0FDckI7UUFFRCxJQUFJLENBQUMsT0FBTyxDQUFDLE9BQU8sR0FBRyxXQUFXLENBQUM7SUFDckMsQ0FBQztJQUVPLG9CQUFvQjtRQUMxQixJQUFJLGVBQWUsR0FBRyxLQUFLLENBQUM7UUFDNUIsS0FBSyxNQUFNLFVBQVUsSUFBSSxJQUFJLENBQUMsV0FBVyxFQUFFO1lBQ3pDLElBQUksQ0FBQyxVQUFVLENBQUMsU0FBUyxFQUFFO2dCQUN6QixlQUFlLEdBQUcsSUFBSSxDQUFDO2dCQUN2QixNQUFNO2FBQ1A7U0FDRjtRQUVELElBQUksQ0FBQyxPQUFPLENBQUMsU0FBUyxHQUFHLENBQUMsZUFBZSxDQUFDO0lBQzVDLENBQUM7OzhHQXBMVSxpQkFBaUI7a0dBQWpCLGlCQUFpQixvUUNqRDlCLGk5S0FvRkE7MkZEbkNhLGlCQUFpQjtrQkFMN0IsU0FBUzsrQkFDRSxjQUFjO2tLQUtmLGNBQWM7c0JBQXRCLEtBQUs7Z0JBQ0csWUFBWTtzQkFBcEIsS0FBSztnQkFDRyxLQUFLO3NCQUFiLEtBQUs7Z0JBQ0csTUFBTTtzQkFBZCxLQUFLO2dCQUNJLGNBQWM7c0JBQXZCLE1BQU07Z0JBQ0csWUFBWTtzQkFBckIsTUFBTSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENvbXBvbmVudCwgSW5wdXQsIE91dHB1dCwgRXZlbnRFbWl0dGVyLCBTaW1wbGVDaGFuZ2VzLCBPbkNoYW5nZXMsIFRlbXBsYXRlUmVmLCBPbkluaXQgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcclxuaW1wb3J0IHsgaXNOaWwsIGluY2x1ZGVzIH0gZnJvbSAnbG9kYXNoJztcclxuaW1wb3J0IHsgVHJlZXZpZXdJMThuIH0gZnJvbSAnLi4vLi4vbW9kZWxzL3RyZWV2aWV3LWkxOG4nO1xyXG5pbXBvcnQgeyBUcmVldmlld0l0ZW0sIFRyZWV2aWV3U2VsZWN0aW9uIH0gZnJvbSAnLi4vLi4vbW9kZWxzL3RyZWV2aWV3LWl0ZW0nO1xyXG5pbXBvcnQgeyBUcmVldmlld0NvbmZpZyB9IGZyb20gJy4uLy4uL21vZGVscy90cmVldmlldy1jb25maWcnO1xyXG5pbXBvcnQgeyBUcmVldmlld0hlYWRlclRlbXBsYXRlQ29udGV4dCB9IGZyb20gJy4uLy4uL21vZGVscy90cmVldmlldy1oZWFkZXItdGVtcGxhdGUtY29udGV4dCc7XHJcbmltcG9ydCB7IFRyZWV2aWV3SXRlbVRlbXBsYXRlQ29udGV4dCB9IGZyb20gJy4uLy4uL21vZGVscy90cmVldmlldy1pdGVtLXRlbXBsYXRlLWNvbnRleHQnO1xyXG5pbXBvcnQgeyBUcmVldmlld0hlbHBlciB9IGZyb20gJy4uLy4uL2hlbHBlcnMvdHJlZXZpZXctaGVscGVyJztcclxuaW1wb3J0IHsgVHJlZXZpZXdFdmVudFBhcnNlciB9IGZyb20gJy4uLy4uL2hlbHBlcnMvdHJlZXZpZXctZXZlbnQtcGFyc2VyJztcclxuXHJcbmNsYXNzIEZpbHRlclRyZWV2aWV3SXRlbSBleHRlbmRzIFRyZWV2aWV3SXRlbSB7XHJcbiAgcHJpdmF0ZSByZWFkb25seSByZWZJdGVtOiBUcmVldmlld0l0ZW07XHJcbiAgY29uc3RydWN0b3IoaXRlbTogVHJlZXZpZXdJdGVtKSB7XHJcbiAgICBzdXBlcih7XHJcbiAgICAgIHRleHQ6IGl0ZW0udGV4dCxcclxuICAgICAgdmFsdWU6IGl0ZW0udmFsdWUsXHJcbiAgICAgIGRpc2FibGVkOiBpdGVtLmRpc2FibGVkLFxyXG4gICAgICBjaGVja2VkOiBpdGVtLmNoZWNrZWQsXHJcbiAgICAgIGNvbGxhcHNlZDogaXRlbS5jb2xsYXBzZWQsXHJcbiAgICAgIGNoaWxkcmVuOiBpdGVtLmNoaWxkcmVuXHJcbiAgICB9KTtcclxuICAgIHRoaXMucmVmSXRlbSA9IGl0ZW07XHJcbiAgfVxyXG5cclxuICB1cGRhdGVSZWZDaGVja2VkKCk6IHZvaWQge1xyXG4gICAgdGhpcy5jaGlsZHJlbi5mb3JFYWNoKGNoaWxkID0+IHtcclxuICAgICAgaWYgKGNoaWxkIGluc3RhbmNlb2YgRmlsdGVyVHJlZXZpZXdJdGVtKSB7XHJcbiAgICAgICAgY2hpbGQudXBkYXRlUmVmQ2hlY2tlZCgpO1xyXG4gICAgICB9XHJcbiAgICB9KTtcclxuXHJcbiAgICBsZXQgcmVmQ2hlY2tlZCA9IHRoaXMuY2hlY2tlZDtcclxuICAgIGlmIChyZWZDaGVja2VkKSB7XHJcbiAgICAgIGZvciAoY29uc3QgcmVmQ2hpbGQgb2YgdGhpcy5yZWZJdGVtLmNoaWxkcmVuKSB7XHJcbiAgICAgICAgaWYgKCFyZWZDaGlsZC5jaGVja2VkKSB7XHJcbiAgICAgICAgICByZWZDaGVja2VkID0gZmFsc2U7XHJcbiAgICAgICAgICBicmVhaztcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH1cclxuICAgIHRoaXMucmVmSXRlbS5jaGVja2VkID0gcmVmQ2hlY2tlZDtcclxuICB9XHJcbn1cclxuXHJcbkBDb21wb25lbnQoe1xyXG4gIHNlbGVjdG9yOiAnbmd4LXRyZWV2aWV3JyxcclxuICB0ZW1wbGF0ZVVybDogJy4vdHJlZXZpZXcuY29tcG9uZW50Lmh0bWwnLFxyXG4gIHN0eWxlVXJsczogWycuL3RyZWV2aWV3LmNvbXBvbmVudC5zY3NzJ11cclxufSlcclxuZXhwb3J0IGNsYXNzIFRyZWV2aWV3Q29tcG9uZW50IGltcGxlbWVudHMgT25DaGFuZ2VzLCBPbkluaXQge1xyXG4gIEBJbnB1dCgpIGhlYWRlclRlbXBsYXRlOiBUZW1wbGF0ZVJlZjxUcmVldmlld0hlYWRlclRlbXBsYXRlQ29udGV4dD47XHJcbiAgQElucHV0KCkgaXRlbVRlbXBsYXRlOiBUZW1wbGF0ZVJlZjxUcmVldmlld0l0ZW1UZW1wbGF0ZUNvbnRleHQ+O1xyXG4gIEBJbnB1dCgpIGl0ZW1zOiBUcmVldmlld0l0ZW1bXTtcclxuICBASW5wdXQoKSBjb25maWc6IFRyZWV2aWV3Q29uZmlnO1xyXG4gIEBPdXRwdXQoKSBzZWxlY3RlZENoYW5nZSA9IG5ldyBFdmVudEVtaXR0ZXI8YW55W10+KCk7XHJcbiAgQE91dHB1dCgpIGZpbHRlckNoYW5nZSA9IG5ldyBFdmVudEVtaXR0ZXI8c3RyaW5nPigpO1xyXG4gIGhlYWRlclRlbXBsYXRlQ29udGV4dDogVHJlZXZpZXdIZWFkZXJUZW1wbGF0ZUNvbnRleHQ7XHJcbiAgYWxsSXRlbTogVHJlZXZpZXdJdGVtO1xyXG4gIGZpbHRlclRleHQgPSAnJztcclxuICBmaWx0ZXJJdGVtczogVHJlZXZpZXdJdGVtW107XHJcbiAgc2VsZWN0aW9uOiBUcmVldmlld1NlbGVjdGlvbjtcclxuXHJcbiAgY29uc3RydWN0b3IoXHJcbiAgICBwdWJsaWMgaTE4bjogVHJlZXZpZXdJMThuLFxyXG4gICAgcHJpdmF0ZSBkZWZhdWx0Q29uZmlnOiBUcmVldmlld0NvbmZpZyxcclxuICAgIHByaXZhdGUgZXZlbnRQYXJzZXI6IFRyZWV2aWV3RXZlbnRQYXJzZXJcclxuICApIHtcclxuICAgIHRoaXMuY29uZmlnID0gdGhpcy5kZWZhdWx0Q29uZmlnO1xyXG4gICAgdGhpcy5hbGxJdGVtID0gbmV3IFRyZWV2aWV3SXRlbSh7IHRleHQ6ICdBbGwnLCB2YWx1ZTogdW5kZWZpbmVkIH0pO1xyXG4gIH1cclxuXHJcbiAgZ2V0IGhhc0ZpbHRlckl0ZW1zKCk6IGJvb2xlYW4ge1xyXG4gICAgcmV0dXJuICFpc05pbCh0aGlzLmZpbHRlckl0ZW1zKSAmJiB0aGlzLmZpbHRlckl0ZW1zLmxlbmd0aCA+IDA7XHJcbiAgfVxyXG5cclxuICBnZXQgbWF4SGVpZ2h0KCk6IHN0cmluZyB7XHJcbiAgICByZXR1cm4gYCR7dGhpcy5jb25maWcubWF4SGVpZ2h0fWA7XHJcbiAgfVxyXG5cclxuICBuZ09uSW5pdCgpOiB2b2lkIHtcclxuICAgIHRoaXMuY3JlYXRlSGVhZGVyVGVtcGxhdGVDb250ZXh0KCk7XHJcbiAgICB0aGlzLmdlbmVyYXRlU2VsZWN0aW9uKCk7XHJcbiAgfVxyXG5cclxuICBuZ09uQ2hhbmdlcyhjaGFuZ2VzOiBTaW1wbGVDaGFuZ2VzKTogdm9pZCB7XHJcbiAgICBjb25zdCBpdGVtc1NpbXBsZUNoYW5nZSA9IGNoYW5nZXMuaXRlbXM7XHJcbiAgICBpZiAoIWlzTmlsKGl0ZW1zU2ltcGxlQ2hhbmdlKSAmJiAhaXNOaWwodGhpcy5pdGVtcykpIHtcclxuICAgICAgdGhpcy51cGRhdGVGaWx0ZXJJdGVtcygpO1xyXG4gICAgICB0aGlzLnVwZGF0ZUNvbGxhcHNlZE9mQWxsKCk7XHJcbiAgICAgIHRoaXMucmFpc2VTZWxlY3RlZENoYW5nZSgpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgb25BbGxDb2xsYXBzZUV4cGFuZCgpOiB2b2lkIHtcclxuICAgIHRoaXMuYWxsSXRlbS5jb2xsYXBzZWQgPSAhdGhpcy5hbGxJdGVtLmNvbGxhcHNlZDtcclxuICAgIHRoaXMuZmlsdGVySXRlbXMuZm9yRWFjaChpdGVtID0+IGl0ZW0uc2V0Q29sbGFwc2VkUmVjdXJzaXZlKHRoaXMuYWxsSXRlbS5jb2xsYXBzZWQpKTtcclxuICB9XHJcblxyXG4gIG9uRmlsdGVyVGV4dENoYW5nZSh0ZXh0OiBzdHJpbmcpOiB2b2lkIHtcclxuICAgIHRoaXMuZmlsdGVyVGV4dCA9IHRleHQ7XHJcbiAgICB0aGlzLmZpbHRlckNoYW5nZS5lbWl0KHRleHQpO1xyXG4gICAgdGhpcy51cGRhdGVGaWx0ZXJJdGVtcygpO1xyXG4gIH1cclxuXHJcbiAgb25BbGxDaGVja2VkQ2hhbmdlKCk6IHZvaWQge1xyXG4gICAgY29uc3QgY2hlY2tlZCA9IHRoaXMuYWxsSXRlbS5jaGVja2VkO1xyXG4gICAgdGhpcy5maWx0ZXJJdGVtcy5mb3JFYWNoKGl0ZW0gPT4ge1xyXG4gICAgICBpdGVtLnNldENoZWNrZWRSZWN1cnNpdmUoY2hlY2tlZCk7XHJcbiAgICAgIGlmIChpdGVtIGluc3RhbmNlb2YgRmlsdGVyVHJlZXZpZXdJdGVtKSB7XHJcbiAgICAgICAgaXRlbS51cGRhdGVSZWZDaGVja2VkKCk7XHJcbiAgICAgIH1cclxuICAgIH0pO1xyXG5cclxuICAgIHRoaXMucmFpc2VTZWxlY3RlZENoYW5nZSgpO1xyXG4gIH1cclxuXHJcbiAgb25JdGVtQ2hlY2tlZENoYW5nZShpdGVtOiBUcmVldmlld0l0ZW0sIGNoZWNrZWQ6IGJvb2xlYW4pOiB2b2lkIHtcclxuICAgIGlmIChpdGVtIGluc3RhbmNlb2YgRmlsdGVyVHJlZXZpZXdJdGVtKSB7XHJcbiAgICAgIGl0ZW0udXBkYXRlUmVmQ2hlY2tlZCgpO1xyXG4gICAgfVxyXG5cclxuICAgIHRoaXMudXBkYXRlQ2hlY2tlZE9mQWxsKCk7XHJcbiAgICB0aGlzLnJhaXNlU2VsZWN0ZWRDaGFuZ2UoKTtcclxuICB9XHJcblxyXG4gIHJhaXNlU2VsZWN0ZWRDaGFuZ2UoKTogdm9pZCB7XHJcbiAgICB0aGlzLmdlbmVyYXRlU2VsZWN0aW9uKCk7XHJcbiAgICBjb25zdCB2YWx1ZXMgPSB0aGlzLmV2ZW50UGFyc2VyLmdldFNlbGVjdGVkQ2hhbmdlKHRoaXMpO1xyXG4gICAgc2V0VGltZW91dCgoKSA9PiB7XHJcbiAgICAgIHRoaXMuc2VsZWN0ZWRDaGFuZ2UuZW1pdCh2YWx1ZXMpO1xyXG4gICAgfSk7XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIGNyZWF0ZUhlYWRlclRlbXBsYXRlQ29udGV4dCgpOiB2b2lkIHtcclxuICAgIHRoaXMuaGVhZGVyVGVtcGxhdGVDb250ZXh0ID0ge1xyXG4gICAgICBjb25maWc6IHRoaXMuY29uZmlnLFxyXG4gICAgICBpdGVtOiB0aGlzLmFsbEl0ZW0sXHJcbiAgICAgIG9uQ2hlY2tlZENoYW5nZTogKCkgPT4gdGhpcy5vbkFsbENoZWNrZWRDaGFuZ2UoKSxcclxuICAgICAgb25Db2xsYXBzZUV4cGFuZDogKCkgPT4gdGhpcy5vbkFsbENvbGxhcHNlRXhwYW5kKCksXHJcbiAgICAgIG9uRmlsdGVyVGV4dENoYW5nZTogKHRleHQpID0+IHRoaXMub25GaWx0ZXJUZXh0Q2hhbmdlKHRleHQpXHJcbiAgICB9O1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBnZW5lcmF0ZVNlbGVjdGlvbigpOiB2b2lkIHtcclxuICAgIGxldCBjaGVja2VkSXRlbXM6IFRyZWV2aWV3SXRlbVtdID0gW107XHJcbiAgICBsZXQgdW5jaGVja2VkSXRlbXM6IFRyZWV2aWV3SXRlbVtdID0gW107XHJcbiAgICBpZiAoIWlzTmlsKHRoaXMuaXRlbXMpKSB7XHJcbiAgICAgIGNvbnN0IHNlbGVjdGlvbiA9IFRyZWV2aWV3SGVscGVyLmNvbmNhdFNlbGVjdGlvbih0aGlzLml0ZW1zLCBjaGVja2VkSXRlbXMsIHVuY2hlY2tlZEl0ZW1zKTtcclxuICAgICAgY2hlY2tlZEl0ZW1zID0gc2VsZWN0aW9uLmNoZWNrZWQ7XHJcbiAgICAgIHVuY2hlY2tlZEl0ZW1zID0gc2VsZWN0aW9uLnVuY2hlY2tlZDtcclxuICAgIH1cclxuXHJcbiAgICB0aGlzLnNlbGVjdGlvbiA9IHtcclxuICAgICAgY2hlY2tlZEl0ZW1zLFxyXG4gICAgICB1bmNoZWNrZWRJdGVtc1xyXG4gICAgfTtcclxuICB9XHJcblxyXG4gIHByaXZhdGUgdXBkYXRlRmlsdGVySXRlbXMoKTogdm9pZCB7XHJcbiAgICBpZiAodGhpcy5maWx0ZXJUZXh0ICE9PSAnJykge1xyXG4gICAgICBjb25zdCBmaWx0ZXJJdGVtczogVHJlZXZpZXdJdGVtW10gPSBbXTtcclxuICAgICAgY29uc3QgZmlsdGVyVGV4dCA9IHRoaXMuZmlsdGVyVGV4dC50b0xvd2VyQ2FzZSgpO1xyXG4gICAgICB0aGlzLml0ZW1zLmZvckVhY2goaXRlbSA9PiB7XHJcbiAgICAgICAgY29uc3QgbmV3SXRlbSA9IHRoaXMuZmlsdGVySXRlbShpdGVtLCBmaWx0ZXJUZXh0KTtcclxuICAgICAgICBpZiAoIWlzTmlsKG5ld0l0ZW0pKSB7XHJcbiAgICAgICAgICBmaWx0ZXJJdGVtcy5wdXNoKG5ld0l0ZW0pO1xyXG4gICAgICAgIH1cclxuICAgICAgfSk7XHJcbiAgICAgIHRoaXMuZmlsdGVySXRlbXMgPSBmaWx0ZXJJdGVtcztcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIHRoaXMuZmlsdGVySXRlbXMgPSB0aGlzLml0ZW1zO1xyXG4gICAgfVxyXG5cclxuICAgIHRoaXMudXBkYXRlQ2hlY2tlZE9mQWxsKCk7XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIGZpbHRlckl0ZW0oaXRlbTogVHJlZXZpZXdJdGVtLCBmaWx0ZXJUZXh0OiBzdHJpbmcpOiBUcmVldmlld0l0ZW0ge1xyXG4gICAgY29uc3QgaXNNYXRjaCA9IGluY2x1ZGVzKGl0ZW0udGV4dC50b0xvd2VyQ2FzZSgpLCBmaWx0ZXJUZXh0KTtcclxuICAgIGlmIChpc01hdGNoKSB7XHJcbiAgICAgIHJldHVybiBpdGVtO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgaWYgKCFpc05pbChpdGVtLmNoaWxkcmVuKSkge1xyXG4gICAgICAgIGNvbnN0IGNoaWxkcmVuOiBUcmVldmlld0l0ZW1bXSA9IFtdO1xyXG4gICAgICAgIGl0ZW0uY2hpbGRyZW4uZm9yRWFjaChjaGlsZCA9PiB7XHJcbiAgICAgICAgICBjb25zdCBuZXdDaGlsZCA9IHRoaXMuZmlsdGVySXRlbShjaGlsZCwgZmlsdGVyVGV4dCk7XHJcbiAgICAgICAgICBpZiAoIWlzTmlsKG5ld0NoaWxkKSkge1xyXG4gICAgICAgICAgICBjaGlsZHJlbi5wdXNoKG5ld0NoaWxkKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9KTtcclxuICAgICAgICBpZiAoY2hpbGRyZW4ubGVuZ3RoID4gMCkge1xyXG4gICAgICAgICAgY29uc3QgbmV3SXRlbSA9IG5ldyBGaWx0ZXJUcmVldmlld0l0ZW0oaXRlbSk7XHJcbiAgICAgICAgICBuZXdJdGVtLmNvbGxhcHNlZCA9IGZhbHNlO1xyXG4gICAgICAgICAgbmV3SXRlbS5jaGlsZHJlbiA9IGNoaWxkcmVuO1xyXG4gICAgICAgICAgcmV0dXJuIG5ld0l0ZW07XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgcmV0dXJuIHVuZGVmaW5lZDtcclxuICB9XHJcblxyXG4gIHByaXZhdGUgdXBkYXRlQ2hlY2tlZE9mQWxsKCk6IHZvaWQge1xyXG4gICAgbGV0IGl0ZW1DaGVja2VkOiBib29sZWFuID0gbnVsbDtcclxuICAgIGZvciAoY29uc3QgZmlsdGVySXRlbSBvZiB0aGlzLmZpbHRlckl0ZW1zKSB7XHJcbiAgICAgIGlmIChpdGVtQ2hlY2tlZCA9PT0gbnVsbCkge1xyXG4gICAgICAgIGl0ZW1DaGVja2VkID0gZmlsdGVySXRlbS5jaGVja2VkO1xyXG4gICAgICB9IGVsc2UgaWYgKGl0ZW1DaGVja2VkICE9PSBmaWx0ZXJJdGVtLmNoZWNrZWQpIHtcclxuICAgICAgICBpdGVtQ2hlY2tlZCA9IHVuZGVmaW5lZDtcclxuICAgICAgICBicmVhaztcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIGlmIChpdGVtQ2hlY2tlZCA9PT0gbnVsbCkge1xyXG4gICAgICBpdGVtQ2hlY2tlZCA9IGZhbHNlO1xyXG4gICAgfVxyXG5cclxuICAgIHRoaXMuYWxsSXRlbS5jaGVja2VkID0gaXRlbUNoZWNrZWQ7XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIHVwZGF0ZUNvbGxhcHNlZE9mQWxsKCk6IHZvaWQge1xyXG4gICAgbGV0IGhhc0l0ZW1FeHBhbmRlZCA9IGZhbHNlO1xyXG4gICAgZm9yIChjb25zdCBmaWx0ZXJJdGVtIG9mIHRoaXMuZmlsdGVySXRlbXMpIHtcclxuICAgICAgaWYgKCFmaWx0ZXJJdGVtLmNvbGxhcHNlZCkge1xyXG4gICAgICAgIGhhc0l0ZW1FeHBhbmRlZCA9IHRydWU7XHJcbiAgICAgICAgYnJlYWs7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICB0aGlzLmFsbEl0ZW0uY29sbGFwc2VkID0gIWhhc0l0ZW1FeHBhbmRlZDtcclxuICB9XHJcbn1cclxuIiwiPG5nLXRlbXBsYXRlICNkZWZhdWx0SXRlbVRlbXBsYXRlIGxldC1pdGVtPVwiaXRlbVwiIGxldC1vbkNvbGxhcHNlRXhwYW5kPVwib25Db2xsYXBzZUV4cGFuZFwiXHJcbiAgbGV0LW9uQ2hlY2tlZENoYW5nZT1cIm9uQ2hlY2tlZENoYW5nZVwiPlxyXG4gIDxkaXYgY2xhc3M9XCJkLWZsZXggYWxpZ24taXRlbXMtY2VudGVyXCIgc3R5bGU9XCJkaXNwbGF5OiBmbGV4O1wiIFtuZ0NsYXNzXT1cInsncm93LWl0ZW0nOiAhY29uZmlnLmNvbXBhY3R9XCI+XHJcbiAgICA8aSAqbmdJZj1cIml0ZW0uY2hpbGRyZW5cIiAoY2xpY2spPVwib25Db2xsYXBzZUV4cGFuZCgpXCIgYXJpYS1oaWRkZW49XCJ0cnVlXCIgW25nU3dpdGNoXT1cIml0ZW0uY29sbGFwc2VkXCIgY2xhc3M9XCJtZS0xXCI+XHJcbiAgICAgIDxzdmcgKm5nU3dpdGNoQ2FzZT1cInRydWVcIiB3aWR0aD1cIjAuOHJlbVwiIGhlaWdodD1cIjAuOHJlbVwiIHZpZXdCb3g9XCIwIDAgMTYgMTZcIiBjbGFzcz1cImJpIGJpLWNhcmV0LXJpZ2h0LWZpbGxcIlxyXG4gICAgICAgIGZpbGw9XCJjdXJyZW50Q29sb3JcIiB4bWxucz1cImh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnXCI+XHJcbiAgICAgICAgPHBhdGhcclxuICAgICAgICAgIGQ9XCJNMTIuMTQgOC43NTNsLTUuNDgyIDQuNzk2Yy0uNjQ2LjU2Ni0xLjY1OC4xMDYtMS42NTgtLjc1M1YzLjIwNGExIDEgMCAwIDEgMS42NTktLjc1M2w1LjQ4IDQuNzk2YTEgMSAwIDAgMSAwIDEuNTA2elwiIC8+XHJcbiAgICAgIDwvc3ZnPlxyXG4gICAgICA8c3ZnICpuZ1N3aXRjaENhc2U9XCJmYWxzZVwiIHdpZHRoPVwiMC44cmVtXCIgaGVpZ2h0PVwiMC44cmVtXCIgdmlld0JveD1cIjAgMCAxNiAxNlwiIGNsYXNzPVwiYmkgYmktY2FyZXQtZG93bi1maWxsXCJcclxuICAgICAgICBmaWxsPVwiY3VycmVudENvbG9yXCIgeG1sbnM9XCJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2Z1wiPlxyXG4gICAgICAgIDxwYXRoXHJcbiAgICAgICAgICBkPVwiTTcuMjQ3IDExLjE0TDIuNDUxIDUuNjU4QzEuODg1IDUuMDEzIDIuMzQ1IDQgMy4yMDQgNGg5LjU5MmExIDEgMCAwIDEgLjc1MyAxLjY1OWwtNC43OTYgNS40OGExIDEgMCAwIDEtMS41MDYgMHpcIiAvPlxyXG4gICAgICA8L3N2Zz5cclxuICAgIDwvaT5cclxuICAgIDxkaXYgY2xhc3M9XCJmb3JtLWNoZWNrIG1iLTBcIj5cclxuICAgICAgPGlucHV0IHR5cGU9XCJjaGVja2JveFwiIGNsYXNzPVwiZm9ybS1jaGVjay1pbnB1dFwiICpuZ0lmPVwiY29uZmlnLmhhc0NoZWNrQm94ZXNcIiBbKG5nTW9kZWwpXT1cIml0ZW0uY2hlY2tlZFwiIChuZ01vZGVsQ2hhbmdlKT1cIm9uQ2hlY2tlZENoYW5nZSgpXCJcclxuICAgICAgICBbZGlzYWJsZWRdPVwiaXRlbS5kaXNhYmxlZFwiIFtpbmRldGVybWluYXRlXT1cIml0ZW0uaW5kZXRlcm1pbmF0ZVwiIC8+XHJcbiAgICAgIDxsYWJlbCBjbGFzcz1cImZvcm0tY2hlY2stbGFiZWxcIiAoY2xpY2spPVwiaXRlbS5jaGVja2VkID0gIWl0ZW0uY2hlY2tlZDsgb25DaGVja2VkQ2hhbmdlKClcIj5cclxuICAgICAgICB7e2l0ZW0udGV4dH19XHJcbiAgICAgIDwvbGFiZWw+XHJcbiAgICA8L2Rpdj5cclxuICA8L2Rpdj5cclxuPC9uZy10ZW1wbGF0ZT5cclxuPG5nLXRlbXBsYXRlICNkZWZhdWx0SGVhZGVyVGVtcGxhdGUgbGV0LWNvbmZpZz1cImNvbmZpZ1wiIGxldC1pdGVtPVwiaXRlbVwiIGxldC1vbkNvbGxhcHNlRXhwYW5kPVwib25Db2xsYXBzZUV4cGFuZFwiXHJcbiAgbGV0LW9uQ2hlY2tlZENoYW5nZT1cIm9uQ2hlY2tlZENoYW5nZVwiIGxldC1vbkZpbHRlclRleHRDaGFuZ2U9XCJvbkZpbHRlclRleHRDaGFuZ2VcIj5cclxuICA8ZGl2ICpuZ0lmPVwiY29uZmlnLmhhc0ZpbHRlclwiIGNsYXNzPVwicm93IHJvdy1maWx0ZXJcIj5cclxuICAgIDxkaXYgY2xhc3M9XCJjb2wtMTJcIj5cclxuICAgICAgPGlucHV0IGNsYXNzPVwiZm9ybS1jb250cm9sXCIgdHlwZT1cInRleHRcIiBbcGxhY2Vob2xkZXJdPVwiaTE4bi5nZXRGaWx0ZXJQbGFjZWhvbGRlcigpXCIgWyhuZ01vZGVsKV09XCJmaWx0ZXJUZXh0XCJcclxuICAgICAgICAobmdNb2RlbENoYW5nZSk9XCJvbkZpbHRlclRleHRDaGFuZ2UoJGV2ZW50KVwiIC8+XHJcbiAgICA8L2Rpdj5cclxuICA8L2Rpdj5cclxuICA8ZGl2ICpuZ0lmPVwiaGFzRmlsdGVySXRlbXNcIj5cclxuICAgIDxkaXYgKm5nSWY9XCIoY29uZmlnLmhhc0NoZWNrQm94ZXMgJiYgY29uZmlnLmhhc0FsbENoZWNrQm94KSB8fCBjb25maWcuaGFzQ29sbGFwc2VFeHBhbmRcIiBjbGFzcz1cInJvdyByb3ctYWxsXCI+XHJcbiAgICAgIDxkaXYgY2xhc3M9XCJjb2wtMTJcIj5cclxuICAgICAgICA8ZGl2IGNsYXNzPVwiZm9ybS1jaGVjayBmb3JtLWNoZWNrLWlubGluZVwiICpuZ0lmPVwiY29uZmlnLmhhc0NoZWNrQm94ZXMgJiYgY29uZmlnLmhhc0FsbENoZWNrQm94XCI+XHJcbiAgICAgICAgICA8aW5wdXQgdHlwZT1cImNoZWNrYm94XCIgY2xhc3M9XCJmb3JtLWNoZWNrLWlucHV0XCIgWyhuZ01vZGVsKV09XCJpdGVtLmNoZWNrZWRcIiAobmdNb2RlbENoYW5nZSk9XCJvbkNoZWNrZWRDaGFuZ2UoKVwiXHJcbiAgICAgICAgICAgIFtpbmRldGVybWluYXRlXT1cIml0ZW0uaW5kZXRlcm1pbmF0ZVwiIC8+XHJcbiAgICAgICAgICA8bGFiZWwgY2xhc3M9XCJmb3JtLWNoZWNrLWxhYmVsXCIgKGNsaWNrKT1cIml0ZW0uY2hlY2tlZCA9ICFpdGVtLmNoZWNrZWQ7IG9uQ2hlY2tlZENoYW5nZSgpXCI+XHJcbiAgICAgICAgICAgIHt7aTE4bi5nZXRBbGxDaGVja2JveFRleHQoKX19XHJcbiAgICAgICAgICA8L2xhYmVsPlxyXG4gICAgICAgIDwvZGl2PlxyXG4gICAgICAgIDxsYWJlbCAqbmdJZj1cImNvbmZpZy5oYXNDb2xsYXBzZUV4cGFuZFwiIGNsYXNzPVwiZmxvYXQtZW5kIGZvcm0tY2hlY2stbGFiZWxcIiAoY2xpY2spPVwib25Db2xsYXBzZUV4cGFuZCgpXCI+XHJcbiAgICAgICAgICA8aSBbdGl0bGVdPVwiaTE4bi5nZXRUb29sdGlwQ29sbGFwc2VFeHBhbmRUZXh0KGl0ZW0uY29sbGFwc2VkKVwiIGFyaWEtaGlkZGVuPVwidHJ1ZVwiIFtuZ1N3aXRjaF09XCJpdGVtLmNvbGxhcHNlZFwiPlxyXG4gICAgICAgICAgICA8c3ZnICpuZ1N3aXRjaENhc2U9XCJ0cnVlXCIgd2lkdGg9XCIxZW1cIiBoZWlnaHQ9XCIxZW1cIiB2aWV3Qm94PVwiMCAwIDE2IDE2XCIgY2xhc3M9XCJiaSBiaS1hcnJvd3MtYW5nbGUtZXhwYW5kXCJcclxuICAgICAgICAgICAgICBmaWxsPVwiY3VycmVudENvbG9yXCIgeG1sbnM9XCJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2Z1wiPlxyXG4gICAgICAgICAgICAgIDxwYXRoIGZpbGwtcnVsZT1cImV2ZW5vZGRcIlxyXG4gICAgICAgICAgICAgICAgZD1cIk0xLjUgMTAuMDM2YS41LjUgMCAwIDEgLjUuNXYzLjVoMy41YS41LjUgMCAwIDEgMCAxaC00YS41LjUgMCAwIDEtLjUtLjV2LTRhLjUuNSAwIDAgMSAuNS0uNXpcIiAvPlxyXG4gICAgICAgICAgICAgIDxwYXRoIGZpbGwtcnVsZT1cImV2ZW5vZGRcIlxyXG4gICAgICAgICAgICAgICAgZD1cIk02LjM1NCA5LjY0NmEuNS41IDAgMCAxIDAgLjcwOGwtNC41IDQuNWEuNS41IDAgMCAxLS43MDgtLjcwOGw0LjUtNC41YS41LjUgMCAwIDEgLjcwOCAwem04LjUtOC41YS41LjUgMCAwIDEgMCAuNzA4bC00LjUgNC41YS41LjUgMCAwIDEtLjcwOC0uNzA4bDQuNS00LjVhLjUuNSAwIDAgMSAuNzA4IDB6XCIgLz5cclxuICAgICAgICAgICAgICA8cGF0aCBmaWxsLXJ1bGU9XCJldmVub2RkXCJcclxuICAgICAgICAgICAgICAgIGQ9XCJNMTAuMDM2IDEuNWEuNS41IDAgMCAxIC41LS41aDRhLjUuNSAwIDAgMSAuNS41djRhLjUuNSAwIDEgMS0xIDBWMmgtMy41YS41LjUgMCAwIDEtLjUtLjV6XCIgLz5cclxuICAgICAgICAgICAgPC9zdmc+XHJcbiAgICAgICAgICAgIDxzdmcgKm5nU3dpdGNoQ2FzZT1cImZhbHNlXCIgd2lkdGg9XCIxZW1cIiBoZWlnaHQ9XCIxZW1cIiB2aWV3Qm94PVwiMCAwIDE2IDE2XCIgY2xhc3M9XCJiaSBiaS1hcnJvd3MtYW5nbGUtY29udHJhY3RcIlxyXG4gICAgICAgICAgICAgIGZpbGw9XCJjdXJyZW50Q29sb3JcIiB4bWxucz1cImh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnXCI+XHJcbiAgICAgICAgICAgICAgPHBhdGggZmlsbC1ydWxlPVwiZXZlbm9kZFwiXHJcbiAgICAgICAgICAgICAgICBkPVwiTTkuNSAyLjAzNmEuNS41IDAgMCAxIC41LjV2My41aDMuNWEuNS41IDAgMCAxIDAgMWgtNGEuNS41IDAgMCAxLS41LS41di00YS41LjUgMCAwIDEgLjUtLjV6XCIgLz5cclxuICAgICAgICAgICAgICA8cGF0aCBmaWxsLXJ1bGU9XCJldmVub2RkXCJcclxuICAgICAgICAgICAgICAgIGQ9XCJNMTQuMzU0IDEuNjQ2YS41LjUgMCAwIDEgMCAuNzA4bC00LjUgNC41YS41LjUgMCAxIDEtLjcwOC0uNzA4bDQuNS00LjVhLjUuNSAwIDAgMSAuNzA4IDB6bS03LjUgNy41YS41LjUgMCAwIDEgMCAuNzA4bC00LjUgNC41YS41LjUgMCAwIDEtLjcwOC0uNzA4bDQuNS00LjVhLjUuNSAwIDAgMSAuNzA4IDB6XCIgLz5cclxuICAgICAgICAgICAgICA8cGF0aCBmaWxsLXJ1bGU9XCJldmVub2RkXCJcclxuICAgICAgICAgICAgICAgIGQ9XCJNMi4wMzYgOS41YS41LjUgMCAwIDEgLjUtLjVoNGEuNS41IDAgMCAxIC41LjV2NGEuNS41IDAgMCAxLTEgMFYxMGgtMy41YS41LjUgMCAwIDEtLjUtLjV6XCIgLz5cclxuICAgICAgICAgICAgPC9zdmc+XHJcbiAgICAgICAgICA8L2k+XHJcbiAgICAgICAgPC9sYWJlbD5cclxuICAgICAgPC9kaXY+XHJcbiAgICA8L2Rpdj5cclxuICAgIDxkaXYgKm5nSWY9XCJjb25maWcuaGFzRGl2aWRlclwiIGNsYXNzPVwiZHJvcGRvd24tZGl2aWRlclwiPjwvZGl2PlxyXG4gIDwvZGl2PlxyXG48L25nLXRlbXBsYXRlPlxyXG48ZGl2IGNsYXNzPVwidHJlZXZpZXctaGVhZGVyXCI+XHJcbiAgPG5nLXRlbXBsYXRlIFtuZ1RlbXBsYXRlT3V0bGV0XT1cImhlYWRlclRlbXBsYXRlIHx8IGRlZmF1bHRIZWFkZXJUZW1wbGF0ZVwiXHJcbiAgICBbbmdUZW1wbGF0ZU91dGxldENvbnRleHRdPVwiaGVhZGVyVGVtcGxhdGVDb250ZXh0XCI+XHJcbiAgPC9uZy10ZW1wbGF0ZT5cclxuPC9kaXY+XHJcbjxkaXYgW25nU3dpdGNoXT1cImhhc0ZpbHRlckl0ZW1zXCIgY2xhc3M9XCJ0cmVldmlldy13cmFwcGVyXCI+XHJcbiAgPGRpdiAqbmdTd2l0Y2hDYXNlPVwidHJ1ZVwiIGNsYXNzPVwidHJlZXZpZXctY29udGFpbmVyXCIgW3N0eWxlLm1heC1oZWlnaHQucHhdPVwibWF4SGVpZ2h0XCI+XHJcbiAgICA8bmd4LXRyZWV2aWV3LWl0ZW0gKm5nRm9yPVwibGV0IGl0ZW0gb2YgZmlsdGVySXRlbXNcIiBbY29uZmlnXT1cImNvbmZpZ1wiIFtpdGVtXT1cIml0ZW1cIlxyXG4gICAgICBbdGVtcGxhdGVdPVwiaXRlbVRlbXBsYXRlIHx8IGRlZmF1bHRJdGVtVGVtcGxhdGVcIiAoY2hlY2tlZENoYW5nZSk9XCJvbkl0ZW1DaGVja2VkQ2hhbmdlKGl0ZW0sICRldmVudClcIj5cclxuICAgIDwvbmd4LXRyZWV2aWV3LWl0ZW0+XHJcbiAgPC9kaXY+XHJcbiAgPGRpdiAqbmdTd2l0Y2hDYXNlPVwiZmFsc2VcIiBjbGFzcz1cInRyZWV2aWV3LXRleHRcIj5cclxuICAgIHt7aTE4bi5nZXRGaWx0ZXJOb0l0ZW1zRm91bmRUZXh0KCl9fVxyXG4gIDwvZGl2PlxyXG48L2Rpdj5cclxuIl19