UNPKG

ngx-treeview-v2

Version:
224 lines 46.2 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 { refItem; 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 { i18n; defaultConfig; eventParser; headerTemplate; itemTemplate; items; config; selectedChange = new EventEmitter(); filterChange = new EventEmitter(); headerTemplateContext; allItem; filterText = ''; filterItems; selection; constructor(i18n, defaultConfig, eventParser) { this.i18n = i18n; this.defaultConfig = defaultConfig; this.eventParser = eventParser; 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; } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: TreeviewComponent, deps: [{ token: i1.TreeviewI18n }, { token: i2.TreeviewConfig }, { token: i3.TreeviewEventParser }], target: i0.ɵɵFactoryTarget.Component }); static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", 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=\"form-inline row-item\">\r\n <i *ngIf=\"item.children\" (click)=\"onCollapseExpand()\" aria-hidden=\"true\" [ngSwitch]=\"item.collapsed\">\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\">\r\n <input type=\"checkbox\" class=\"form-check-input\" [(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.hasAllCheckBox || config.hasCollapseExpand\" class=\"row row-all\">\r\n <div class=\"col-12\">\r\n <div class=\"form-check form-check-inline\" *ngIf=\"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-right 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\">\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-header .row-filter{margin-bottom:.5rem}:host .treeview-header .row-all .bi{cursor:pointer}:host .treeview-container .row-item{margin-bottom:.3rem;flex-wrap:nowrap}:host .treeview-container .row-item .bi{cursor:pointer;margin-right:.3rem}.treeview-container{overflow-y:auto;padding-right:.3rem}.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.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: "16.2.12", 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=\"form-inline row-item\">\r\n <i *ngIf=\"item.children\" (click)=\"onCollapseExpand()\" aria-hidden=\"true\" [ngSwitch]=\"item.collapsed\">\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\">\r\n <input type=\"checkbox\" class=\"form-check-input\" [(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.hasAllCheckBox || config.hasCollapseExpand\" class=\"row row-all\">\r\n <div class=\"col-12\">\r\n <div class=\"form-check form-check-inline\" *ngIf=\"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-right 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\">\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-header .row-filter{margin-bottom:.5rem}:host .treeview-header .row-all .bi{cursor:pointer}:host .treeview-container .row-item{margin-bottom:.3rem;flex-wrap:nowrap}:host .treeview-container .row-item .bi{cursor:pointer;margin-right:.3rem}.treeview-container{overflow-y:auto;padding-right:.3rem}.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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHJlZXZpZXcuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvbmd4LXRyZWV2aWV3LXYyL3NyYy9saWIvY29tcG9uZW50cy90cmVldmlldy90cmVldmlldy5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9uZ3gtdHJlZXZpZXctdjIvc3JjL2xpYi9jb21wb25lbnRzL3RyZWV2aWV3L3RyZWV2aWV3LmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxTQUFTLEVBQUUsS0FBSyxFQUFFLE1BQU0sRUFBRSxZQUFZLEVBQWlELE1BQU0sZUFBZSxDQUFDO0FBQ3RILE9BQU8sRUFBRSxLQUFLLEVBQUUsUUFBUSxFQUFFLE1BQU0sUUFBUSxDQUFDO0FBRXpDLE9BQU8sRUFBRSxZQUFZLEVBQXFCLE1BQU0sNEJBQTRCLENBQUM7QUFJN0UsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLCtCQUErQixDQUFDOzs7Ozs7OztBQUcvRCxNQUFNLGtCQUFtQixTQUFRLFlBQVk7SUFDMUIsT0FBTyxDQUFlO0lBQ3ZDLFlBQVksSUFBa0I7UUFDNUIsS0FBSyxDQUFDO1lBQ0osSUFBSSxFQUFFLElBQUksQ0FBQyxJQUFJO1lBQ2YsS0FBSyxFQUFFLElBQUksQ0FBQyxLQUFLO1lBQ2pCLFFBQVEsRUFBRSxJQUFJLENBQUMsUUFBUTtZQUN2QixPQUFPLEVBQUUsSUFBSSxDQUFDLE9BQU87WUFDckIsU0FBUyxFQUFFLElBQUksQ0FBQyxTQUFTO1lBQ3pCLFFBQVEsRUFBRSxJQUFJLENBQUMsUUFBUTtTQUN4QixDQUFDLENBQUM7UUFDSCxJQUFJLENBQUMsT0FBTyxHQUFHLElBQUksQ0FBQztJQUN0QixDQUFDO0lBRUQsZ0JBQWdCO1FBQ2QsSUFBSSxDQUFDLFFBQVEsQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLEVBQUU7WUFDNUIsSUFBSSxL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QUksRUFBRTtnQkFDeEIsV0FBVyxHQUFHLFVBQVUsQ0FBQyxPQUFPLENBQUM7YUFDbEM7aUJBQU0sSUFBSSxXQUFXLEtBQUssVUFBVSxDQUFDLE9BQU8sRUFBRTtnQkFDN0MsV0FBVyxHQUFHLFNBQVMsQ0FBQztnQkFDeEIsTUFBTTthQUNQO1NBQ0Y7UUFFRCxJQUFJLFdBQVcsS0FBSyxJQUFJLEVBQUU7WUFDeEIsV0FBVyxHQUFHLEtBQUssQ0FBQztTQUNyQjtRQUVELElBQUksQ0FBQyxPQUFPLENBQUMsT0FBTyxHQUFHLFdBQVcsQ0FBQztJQUNyQyxDQUFDO0lBRU8sb0JBQW9CO1FBQzFCLElBQUksZUFBZSxHQUFHLEtBQUssQ0FBQztRQUM1QixLQUFLLE1BQU0sVUFBVSxJQUFJLElBQUksQ0FBQyxXQUFXLEVBQUU7WUFDekMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxTQUFTLEVBQUU7Z0JBQ3pCLGVBQWUsR0FBRyxJQUFJLENBQUM7Z0JBQ3ZCLE1BQU07YUFDUDtTQUNGO1FBRUQsSUFBSSxDQUFDLE9BQU8sQ0FBQyxTQUFTLEdBQUcsQ0FBQyxlQUFlLENBQUM7SUFDNUMsQ0FBQzt3R0FwTFUsaUJBQWlCOzRGQUFqQixpQkFBaUIsb1FDakQ5Qix5d0tBb0ZBOzs0RkRuQ2EsaUJBQWlCO2tCQUw3QixTQUFTOytCQUNFLGNBQWM7a0tBS2YsY0FBYztzQkFBdEIsS0FBSztnQkFDRyxZQUFZO3NCQUFwQixLQUFLO2dCQUNHLEtBQUs7c0JBQWIsS0FBSztnQkFDRyxNQUFNO3NCQUFkLEtBQUs7Z0JBQ0ksY0FBYztzQkFBdkIsTUFBTTtnQkFDRyxZQUFZO3NCQUFyQixNQUFNIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQ29tcG9uZW50LCBJbnB1dCwgT3V0cHV0LCBFdmVudEVtaXR0ZXIsIFNpbXBsZUNoYW5nZXMsIE9uQ2hhbmdlcywgVGVtcGxhdGVSZWYsIE9uSW5pdCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xyXG5pbXBvcnQgeyBpc05pbCwgaW5jbHVkZXMgfSBmcm9tICdsb2Rhc2gnO1xyXG5pbXBvcnQgeyBUcmVldmlld0kxOG4gfSBmcm9tICcuLi8uLi9tb2RlbHMvdHJlZXZpZXctaTE4bic7XHJcbmltcG9ydCB7IFRyZWV2aWV3SXRlbSwgVHJlZXZpZXdTZWxlY3Rpb24gfSBmcm9tICcuLi8uLi9tb2RlbHMvdHJlZXZpZXctaXRlbSc7XHJcbmltcG9ydCB7IFRyZWV2aWV3Q29uZmlnIH0gZnJvbSAnLi4vLi4vbW9kZWxzL3RyZWV2aWV3LWNvbmZpZyc7XHJcbmltcG9ydCB7IFRyZWV2aWV3SGVhZGVyVGVtcGxhdGVDb250ZXh0IH0gZnJvbSAnLi4vLi4vbW9kZWxzL3RyZWV2aWV3LWhlYWRlci10ZW1wbGF0ZS1jb250ZXh0JztcclxuaW1wb3J0IHsgVHJlZXZpZXdJdGVtVGVtcGxhdGVDb250ZXh0IH0gZnJvbSAnLi4vLi4vbW9kZWxzL3RyZWV2aWV3LWl0ZW0tdGVtcGxhdGUtY29udGV4dCc7XHJcbmltcG9ydCB7IFRyZWV2aWV3SGVscGVyIH0gZnJvbSAnLi4vLi4vaGVscGVycy90cmVldmlldy1oZWxwZXInO1xyXG5pbXBvcnQgeyBUcmVldmlld0V2ZW50UGFyc2VyIH0gZnJvbSAnLi4vLi4vaGVscGVycy90cmVldmlldy1ldmVudC1wYXJzZXInO1xyXG5cclxuY2xhc3MgRmlsdGVyVHJlZXZpZXdJdGVtIGV4dGVuZHMgVHJlZXZpZXdJdGVtIHtcclxuICBwcml2YXRlIHJlYWRvbmx5IHJlZkl0ZW06IFRyZWV2aWV3SXRlbTtcclxuICBjb25zdHJ1Y3RvcihpdGVtOiBUcmVldmlld0l0ZW0pIHtcclxuICAgIHN1cGVyKHtcclxuICAgICAgdGV4dDogaXRlbS50ZXh0LFxyXG4gICAgICB2YWx1ZTogaXRlbS52YWx1ZSxcclxuICAgICAgZGlzYWJsZWQ6IGl0ZW0uZGlzYWJsZWQsXHJcbiAgICAgIGNoZWNrZWQ6IGl0ZW0uY2hlY2tlZCxcclxuICAgICAgY29sbGFwc2VkOiBpdGVtLmNvbGxhcHNlZCxcclxuICAgICAgY2hpbGRyZW46IGl0ZW0uY2hpbGRyZW5cclxuICAgIH0pO1xyXG4gICAgdGhpcy5yZWZJdGVtID0gaXRlbTtcclxuICB9XHJcblxyXG4gIHVwZGF0ZVJlZkNoZWNrZWQoKTogdm9pZCB7XHJcbiAgICB0aGlzLmNoaWxkcmVuLmZvckVhY2goY2hpbGQgPT4ge1xyXG4gICAgICBpZiAoY2hpbGQgaW5zdGFuY2VvZiBGaWx0ZXJUcmVldmlld0l0ZW0pIHtcclxuICAgICAgICBjaGlsZC51cGRhdGVSZWZDaGVja2VkKCk7XHJcbiAgICAgIH1cclxuICAgIH0pO1xyXG5cclxuICAgIGxldCByZWZDaGVja2VkID0gdGhpcy5jaGVja2VkO1xyXG4gICAgaWYgKHJlZkNoZWNrZWQpIHtcclxuICAgICAgZm9yIChjb25zdCByZWZDaGlsZCBvZiB0aGlzLnJlZkl0ZW0uY2hpbGRyZW4pIHtcclxuICAgICAgICBpZiAoIXJlZkNoaWxkLmNoZWNrZWQpIHtcclxuICAgICAgICAgIHJlZkNoZWNrZWQgPSBmYWxzZTtcclxuICAgICAgICAgIGJyZWFrO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfVxyXG4gICAgdGhpcy5yZWZJdGVtLmNoZWNrZWQgPSByZWZDaGVja2VkO1xyXG4gIH1cclxufVxyXG5cclxuQENvbXBvbmVudCh7XHJcbiAgc2VsZWN0b3I6ICduZ3gtdHJlZXZpZXcnLFxyXG4gIHRlbXBsYXRlVXJsOiAnLi90cmVldmlldy5jb21wb25lbnQuaHRtbCcsXHJcbiAgc3R5bGVVcmxzOiBbJy4vdHJlZXZpZXcuY29tcG9uZW50LnNjc3MnXVxyXG59KVxyXG5leHBvcnQgY2xhc3MgVHJlZXZpZXdDb21wb25lbnQgaW1wbGVtZW50cyBPbkNoYW5nZXMsIE9uSW5pdCB7XHJcbiAgQElucHV0KCkgaGVhZGVyVGVtcGxhdGU6IFRlbXBsYXRlUmVmPFRyZWV2aWV3SGVhZGVyVGVtcGxhdGVDb250ZXh0PjtcclxuICBASW5wdXQoKSBpdGVtVGVtcGxhdGU6IFRlbXBsYXRlUmVmPFRyZWV2aWV3SXRlbVRlbXBsYXRlQ29udGV4dD47XHJcbiAgQElucHV0KCkgaXRlbXM6IFRyZWV2aWV3SXRlbVtdO1xyXG4gIEBJbnB1dCgpIGNvbmZpZzogVHJlZXZpZXdDb25maWc7XHJcbiAgQE91dHB1dCgpIHNlbGVjdGVkQ2hhbmdlID0gbmV3IEV2ZW50RW1pdHRlcjxhbnlbXT4oKTtcclxuICBAT3V0cHV0KCkgZmlsdGVyQ2hhbmdlID0gbmV3IEV2ZW50RW1pdHRlcjxzdHJpbmc+KCk7XHJcbiAgaGVhZGVyVGVtcGxhdGVDb250ZXh0OiBUcmVldmlld0hlYWRlclRlbXBsYXRlQ29udGV4dDtcclxuICBhbGxJdGVtOiBUcmVldmlld0l0ZW07XHJcbiAgZmlsdGVyVGV4dCA9ICcnO1xyXG4gIGZpbHRlckl0ZW1zOiBUcmVldmlld0l0ZW1bXTtcclxuICBzZWxlY3Rpb246IFRyZWV2aWV3U2VsZWN0aW9uO1xyXG5cclxuICBjb25zdHJ1Y3RvcihcclxuICAgIHB1YmxpYyBpMThuOiBUcmVldmlld0kxOG4sXHJcbiAgICBwcml2YXRlIGRlZmF1bHRDb25maWc6IFRyZWV2aWV3Q29uZmlnLFxyXG4gICAgcHJpdmF0ZSBldmVudFBhcnNlcjogVHJlZXZpZXdFdmVudFBhcnNlclxyXG4gICkge1xyXG4gICAgdGhpcy5jb25maWcgPSB0aGlzLmRlZmF1bHRDb25maWc7XHJcbiAgICB0aGlzLmFsbEl0ZW0gPSBuZXcgVHJlZXZpZXdJdGVtKHsgdGV4dDogJ0FsbCcsIHZhbHVlOiB1bmRlZmluZWQgfSk7XHJcbiAgfVxyXG5cclxuICBnZXQgaGFzRmlsdGVySXRlbXMoKTogYm9vbGVhbiB7XHJcbiAgICByZXR1cm4gIWlzTmlsKHRoaXMuZmlsdGVySXRlbXMpICYmIHRoaXMuZmlsdGVySXRlbXMubGVuZ3RoID4gMDtcclxuICB9XHJcblxyXG4gIGdldCBtYXhIZWlnaHQoKTogc3RyaW5nIHtcclxuICAgIHJldHVybiBgJHt0aGlzLmNvbmZpZy5tYXhIZWlnaHR9YDtcclxuICB9XHJcblxyXG4gIG5nT25Jbml0KCk6IHZvaWQge1xyXG4gICAgdGhpcy5jcmVhdGVIZWFkZXJUZW1wbGF0ZUNvbnRleHQoKTtcclxuICAgIHRoaXMuZ2VuZXJhdGVTZWxlY3Rpb24oKTtcclxuICB9XHJcblxyXG4gIG5nT25DaGFuZ2VzKGNoYW5nZXM6IFNpbXBsZUNoYW5nZXMpOiB2b2lkIHtcclxuICAgIGNvbnN0IGl0ZW1zU2ltcGxlQ2hhbmdlID0gY2hhbmdlcy5pdGVtcztcclxuICAgIGlmICghaXNOaWwoaXRlbXNTaW1wbGVDaGFuZ2UpICYmICFpc05pbCh0aGlzLml0ZW1zKSkge1xyXG4gICAgICB0aGlzLnVwZGF0ZUZpbHRlckl0ZW1zKCk7XHJcbiAgICAgIHRoaXMudXBkYXRlQ29sbGFwc2VkT2ZBbGwoKTtcclxuICAgICAgdGhpcy5yYWlzZVNlbGVjdGVkQ2hhbmdlKCk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBvbkFsbENvbGxhcHNlRXhwYW5kKCk6IHZvaWQge1xyXG4gICAgdGhpcy5hbGxJdGVtLmNvbGxhcHNlZCA9ICF0aGlzLmFsbEl0ZW0uY29sbGFwc2VkO1xyXG4gICAgdGhpcy5maWx0ZXJJdGVtcy5mb3JFYWNoKGl0ZW0gPT4gaXRlbS5zZXRDb2xsYXBzZWRSZWN1cnNpdmUodGhpcy5hbGxJdGVtLmNvbGxhcHNlZCkpO1xyXG4gIH1cclxuXHJcbiAgb25GaWx0ZXJUZXh0Q2hhbmdlKHRleHQ6IHN0cmluZyk6IHZvaWQge1xyXG4gICAgdGhpcy5maWx0ZXJUZXh0ID0gdGV4dDtcclxuICAgIHRoaXMuZmlsdGVyQ2hhbmdlLmVtaXQodGV4dCk7XHJcbiAgICB0aGlzLnVwZGF0ZUZpbHRlckl0ZW1zKCk7XHJcbiAgfVxyXG5cclxuICBvbkFsbENoZWNrZWRDaGFuZ2UoKTogdm9pZCB7XHJcbiAgICBjb25zdCBjaGVja2VkID0gdGhpcy5hbGxJdGVtLmNoZWNrZWQ7XHJcbiAgICB0aGlzLmZpbHRlckl0ZW1zLmZvckVhY2goaXRlbSA9PiB7XHJcbiAgICAgIGl0ZW0uc2V0Q2hlY2tlZFJlY3Vyc2l2ZShjaGVja2VkKTtcclxuICAgICAgaWYgKGl0ZW0gaW5zdGFuY2VvZiBGaWx0ZXJUcmVldmlld0l0ZW0pIHtcclxuICAgICAgICBpdGVtLnVwZGF0ZVJlZkNoZWNrZWQoKTtcclxuICAgICAgfVxyXG4gICAgfSk7XHJcblxyXG4gICAgdGhpcy5yYWlzZVNlbGVjdGVkQ2hhbmdlKCk7XHJcbiAgfVxyXG5cclxuICBvbkl0ZW1DaGVja2VkQ2hhbmdlKGl0ZW06IFRyZWV2aWV3SXRlbSwgY2hlY2tlZDogYm9vbGVhbik6IHZvaWQge1xyXG4gICAgaWYgKGl0ZW0gaW5zdGFuY2VvZiBGaWx0ZXJUcmVldmlld0l0ZW0pIHtcclxuICAgICAgaXRlbS51cGRhdGVSZWZDaGVja2VkKCk7XHJcbiAgICB9XHJcblxyXG4gICAgdGhpcy51cGRhdGVDaGVja2VkT2ZBbGwoKTtcclxuICAgIHRoaXMucmFpc2VTZWxlY3RlZENoYW5nZSgpO1xyXG4gIH1cclxuXHJcbiAgcmFpc2VTZWxlY3RlZENoYW5nZSgpOiB2b2lkIHtcclxuICAgIHRoaXMuZ2VuZXJhdGVTZWxlY3Rpb24oKTtcclxuICAgIGNvbnN0IHZhbHVlcyA9IHRoaXMuZXZlbnRQYXJzZXIuZ2V0U2VsZWN0ZWRDaGFuZ2UodGhpcyk7XHJcbiAgICBzZXRUaW1lb3V0KCgpID0+IHtcclxuICAgICAgdGhpcy5zZWxlY3RlZENoYW5nZS5lbWl0KHZhbHVlcyk7XHJcbiAgICB9KTtcclxuICB9XHJcblxyXG4gIHByaXZhdGUgY3JlYXRlSGVhZGVyVGVtcGxhdGVDb250ZXh0KCk6IHZvaWQge1xyXG4gICAgdGhpcy5oZWFkZXJUZW1wbGF0ZUNvbnRleHQgPSB7XHJcbiAgICAgIGNvbmZpZzogdGhpcy5jb25maWcsXHJcbiAgICAgIGl0ZW06IHRoaXMuYWxsSXRlbSxcclxuICAgICAgb25DaGVja2VkQ2hhbmdlOiAoKSA9PiB0aGlzLm9uQWxsQ2hlY2tlZENoYW5nZSgpLFxyXG4gICAgICBvbkNvbGxhcHNlRXhwYW5kOiAoKSA9PiB0aGlzLm9uQWxsQ29sbGFwc2VFeHBhbmQoKSxcclxuICAgICAgb25GaWx0ZXJUZXh0Q2hhbmdlOiAodGV4dCkgPT4gdGhpcy5vbkZpbHRlclRleHRDaGFuZ2UodGV4dClcclxuICAgIH07XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIGdlbmVyYXRlU2VsZWN0aW9uKCk6IHZvaWQge1xyXG4gICAgbGV0IGNoZWNrZWRJdGVtczogVHJlZXZpZXdJdGVtW10gPSBbXTtcclxuICAgIGxldCB1bmNoZWNrZWRJdGVtczogVHJlZXZpZXdJdGVtW10gPSBbXTtcclxuICAgIGlmICghaXNOaWwodGhpcy5pdGVtcykpIHtcclxuICAgICAgY29uc3Qgc2VsZWN0aW9uID0gVHJlZXZpZXdIZWxwZXIuY29uY2F0U2VsZWN0aW9uKHRoaXMuaXRlbXMsIGNoZWNrZWRJdGVtcywgdW5jaGVja2VkSXRlbXMpO1xyXG4gICAgICBjaGVja2VkSXRlbXMgPSBzZWxlY3Rpb24uY2hlY2tlZDtcclxuICAgICAgdW5jaGVja2VkSXRlbXMgPSBzZWxlY3Rpb24udW5jaGVja2VkO1xyXG4gICAgfVxyXG5cclxuICAgIHRoaXMuc2VsZWN0aW9uID0ge1xyXG4gICAgICBjaGVja2VkSXRlbXMsXHJcbiAgICAgIHVuY2hlY2tlZEl0ZW1zXHJcbiAgICB9O1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSB1cGRhdGVGaWx0ZXJJdGVtcygpOiB2b2lkIHtcclxuICAgIGlmICh0aGlzLmZpbHRlclRleHQgIT09ICcnKSB7XHJcbiAgICAgIGNvbnN0IGZpbHRlckl0ZW1zOiBUcmVldmlld0l0ZW1bXSA9IFtdO1xyXG4gICAgICBjb25zdCBmaWx0ZXJUZXh0ID0gdGhpcy5maWx0ZXJUZXh0LnRvTG93ZXJDYXNlKCk7XHJcbiAgICAgIHRoaXMuaXRlbXMuZm9yRWFjaChpdGVtID0+IHtcclxuICAgICAgICBjb25zdCBuZXdJdGVtID0gdGhpcy5maWx0ZXJJdGVtKGl0ZW0sIGZpbHRlclRleHQpO1xyXG4gICAgICAgIGlmICghaXNOaWwobmV3SXRlbSkpIHtcclxuICAgICAgICAgIGZpbHRlckl0ZW1zLnB1c2gobmV3SXRlbSk7XHJcbiAgICAgICAgfVxyXG4gICAgICB9KTtcclxuICAgICAgdGhpcy5maWx0ZXJJdGVtcyA9IGZpbHRlckl0ZW1zO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgdGhpcy5maWx0ZXJJdGVtcyA9IHRoaXMuaXRlbXM7XHJcbiAgICB9XHJcblxyXG4gICAgdGhpcy51cGRhdGVDaGVja2VkT2ZBbGwoKTtcclxuICB9XHJcblxyXG4gIHByaXZhdGUgZmlsdGVySXRlbShpdGVtOiBUcmVldmlld0l0ZW0sIGZpbHRlclRleHQ6IHN0cmluZyk6IFRyZWV2aWV3SXRlbSB7XHJcbiAgICBjb25zdCBpc01hdGNoID0gaW5jbHVkZXMoaXRlbS50ZXh0LnRvTG93ZXJDYXNlKCksIGZpbHRlclRleHQpO1xyXG4gICAgaWYgKGlzTWF0Y2gpIHtcclxuICAgICAgcmV0dXJuIGl0ZW07XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICBpZiAoIWlzTmlsKGl0ZW0uY2hpbGRyZW4pKSB7XHJcbiAgICAgICAgY29uc3QgY2hpbGRyZW46IFRyZWV2aWV3SXRlbVtdID0gW107XHJcbiAgICAgICAgaXRlbS5jaGlsZHJlbi5mb3JFYWNoKGNoaWxkID0+IHtcclxuICAgICAgICAgIGNvbnN0IG5ld0NoaWxkID0gdGhpcy5maWx0ZXJJdGVtKGNoaWxkLCBmaWx0ZXJUZXh0KTtcclxuICAgICAgICAgIGlmICghaXNOaWwobmV3Q2hpbGQpKSB7XHJcbiAgICAgICAgICAgIGNoaWxkcmVuLnB1c2gobmV3Q2hpbGQpO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH0pO1xyXG4gICAgICAgIGlmIChjaGlsZHJlbi5sZW5ndGggPiAwKSB7XHJcbiAgICAgICAgICBjb25zdCBuZXdJdGVtID0gbmV3IEZpbHRlclRyZWV2aWV3SXRlbShpdGVtKTtcclxuICAgICAgICAgIG5ld0l0ZW0uY29sbGFwc2VkID0gZmFsc2U7XHJcbiAgICAgICAgICBuZXdJdGVtLmNoaWxkcmVuID0gY2hpbGRyZW47XHJcbiAgICAgICAgICByZXR1cm4gbmV3SXRlbTtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICByZXR1cm4gdW5kZWZpbmVkO1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSB1cGRhdGVDaGVja2VkT2ZBbGwoKTogdm9pZCB7XHJcbiAgICBsZXQgaXRlbUNoZWNrZWQ6IGJvb2xlYW4gPSBudWxsO1xyXG4gICAgZm9yIChjb25zdCBmaWx0ZXJJdGVtIG9mIHRoaXMuZmlsdGVySXRlbXMpIHtcclxuICAgICAgaWYgKGl0ZW1DaGVja2VkID09PSBudWxsKSB7XHJcbiAgICAgICAgaXRlbUNoZWNrZWQgPSBmaWx0ZXJJdGVtLmNoZWNrZWQ7XHJcbiAgICAgIH0gZWxzZSBpZiAoaXRlbUNoZWNrZWQgIT09IGZpbHRlckl0ZW0uY2hlY2tlZCkge1xyXG4gICAgICAgIGl0ZW1DaGVja2VkID0gdW5kZWZpbmVkO1xyXG4gICAgICAgIGJyZWFrO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKGl0ZW1DaGVja2VkID09PSBudWxsKSB7XHJcbiAgICAgIGl0ZW1DaGVja2VkID0gZmFsc2U7XHJcbiAgICB9XHJcblxyXG4gICAgdGhpcy5hbGxJdGVtLmNoZWNrZWQgPSBpdGVtQ2hlY2tlZDtcclxuICB9XHJcblxyXG4gIHByaXZhdGUgdXBkYXRlQ29sbGFwc2VkT2ZBbGwoKTogdm9pZCB7XHJcbiAgICBsZXQgaGFzSXRlbUV4cGFuZGVkID0gZmFsc2U7XHJcbiAgICBmb3IgKGNvbnN0IGZpbHRlckl0ZW0gb2YgdGhpcy5maWx0ZXJJdGVtcykge1xyXG4gICAgICBpZiAoIWZpbHRlckl0ZW0uY29sbGFwc2VkKSB7XHJcbiAgICAgICAgaGFzSXRlbUV4cGFuZGVkID0gdHJ1ZTtcclxuICAgICAgICBicmVhaztcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIHRoaXMuYWxsSXRlbS5jb2xsYXBzZWQgPSAhaGFzSXRlbUV4cGFuZGVkO1xyXG4gIH1cclxufVxyXG4iLCI8bmctdGVtcGxhdGUgI2RlZmF1bHRJdGVtVGVtcGxhdGUgbGV0LWl0ZW09XCJpdGVtXCIgbGV0LW9uQ29sbGFwc2VFeHBhbmQ9XCJvbkNvbGxhcHNlRXhwYW5kXCJcclxuICBsZXQtb25DaGVja2VkQ2hhbmdlPVwib25DaGVja2VkQ2hhbmdlXCI+XHJcbiAgPGRpdiBjbGFzcz1cImZvcm0taW5saW5lIHJvdy1pdGVtXCI+XHJcbiAgICA8aSAqbmdJZj1cIml0ZW0uY2hpbGRyZW5cIiAoY2xpY2spPVwib25Db2xsYXBzZUV4cGFuZCgpXCIgYXJpYS1oaWRkZW49XCJ0cnVlXCIgW25nU3dpdGNoXT1cIml0ZW0uY29sbGFwc2VkXCI+XHJcbiAgICAgIDxzdmcgKm5nU3dpdGNoQ2FzZT1cInRydWVcIiB3aWR0aD1cIjAuOHJlbVwiIGhlaWdodD1cIjAuOHJlbVwiIHZpZXdCb3g9XCIwIDAgMTYgMTZcIiBjbGFzcz1cImJpIGJpLWNhcmV0LXJpZ2h0LWZpbGxcIlxyXG4gICAgICAgIGZpbGw9XCJjdXJyZW50Q29sb3JcIiB4bWxucz1cImh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnXCI+XHJcbiAgICAgICAgPHBhdGhcclxuICAgICAgICAgIGQ9XCJNMTIuMTQgOC43NTNsLTUuNDgyIDQuNzk2Yy0uNjQ2LjU2Ni0xLjY1OC4xMDYtMS42NTgtLjc1M1YzLjIwNGExIDEgMCAwIDEgMS42NTktLjc1M2w1LjQ4IDQuNzk2YTEgMSAwIDAgMSAwIDEuNTA2elwiIC8+XHJcbiAgICAgIDwvc3ZnPlxyXG4gICAgICA8c3ZnICpuZ1N3aXRjaENhc2U9XCJmYWxzZVwiIHdpZHRoPVwiMC44cmVtXCIgaGVpZ2h0PVwiMC44cmVtXCIgdmlld0JveD1cIjAgMCAxNiAxNlwiIGNsYXNzPVwiYmkgYmktY2FyZXQtZG93bi1maWxsXCJcclxuICAgICAgICBmaWxsPVwiY3VycmVudENvbG9yXCIgeG1sbnM9XCJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2Z1wiPlxyXG4gICAgICAgIDxwYXRoXHJcbiAgICAgICAgICBkPVwiTTcuMjQ3IDExLjE0TDIuNDUxIDUuNjU4QzEuODg1IDUuMDEzIDIuMzQ1IDQgMy4yMDQgNGg5LjU5MmExIDEgMCAwIDEgLjc1MyAxLjY1OWwtNC43OTYgNS40OGExIDEgMCAwIDEtMS41MDYgMHpcIiAvPlxyXG4gICAgICA8L3N2Zz5cclxuICAgIDwvaT5cclxuICAgIDxkaXYgY2xhc3M9XCJmb3JtLWNoZWNrXCI+XHJcbiAgICAgIDxpbnB1dCB0eXBlPVwiY2hlY2tib3hcIiBjbGFzcz1cImZvcm0tY2hlY2staW5wdXRcIiBbKG5nTW9kZWwpXT1cIml0ZW0uY2hlY2tlZFwiIChuZ01vZGVsQ2hhbmdlKT1cIm9uQ2hlY2tlZENoYW5nZSgpXCJcclxuICAgICAgICBbZGlzYWJsZWRdPVwiaXRlbS5kaXNhYmxlZFwiIFtpbmRldGVybWluYXRlXT1cIml0ZW0uaW5kZXRlcm1pbmF0ZVwiIC8+XHJcbiAgICAgIDxsYWJlbCBjbGFzcz1cImZvcm0tY2hlY2stbGFiZWxcIiAoY2xpY2spPVwiaXRlbS5jaGVja2VkID0gIWl0ZW0uY2hlY2tlZDsgb25DaGVja2VkQ2hhbmdlKClcIj5cclxuICAgICAgICB7e2l0ZW0udGV4dH19XHJcbiAgICAgIDwvbGFiZWw+XHJcbiAgICA8L2Rpdj5cclxuICA8L2Rpdj5cclxuPC9uZy10ZW1wbGF0ZT5cclxuPG5nLXRlbXBsYXRlICNkZWZhdWx0SGVhZGVyVGVtcGxhdGUgbGV0LWNvbmZpZz1cImNvbmZpZ1wiIGxldC1pdGVtPVwiaXRlbVwiIGxldC1vbkNvbGxhcHNlRXhwYW5kPVwib25Db2xsYXBzZUV4cGFuZFwiXHJcbiAgbGV0LW9uQ2hlY2tlZENoYW5nZT1cIm9uQ2hlY2tlZENoYW5nZVwiIGxldC1vbkZpbHRlclRleHRDaGFuZ2U9XCJvbkZpbHRlclRleHRDaGFuZ2VcIj5cclxuICA8ZGl2ICpuZ0lmPVwiY29uZmlnLmhhc0ZpbHRlclwiIGNsYXNzPVwicm93IHJvdy1maWx0ZXJcIj5cclxuICAgIDxkaXYgY2xhc3M9XCJjb2wtMTJcIj5cclxuICAgICAgPGlucHV0IGNsYXNzPVwiZm9ybS1jb250cm9sXCIgdHlwZT1cInRleHRcIiBbcGxhY2Vob2xkZXJdPVwiaTE4bi5nZXRGaWx0ZXJQbGFjZWhvbGRlcigpXCIgWyhuZ01vZGVsKV09XCJmaWx0ZXJUZXh0XCJcclxuICAgICAgICAobmdNb2RlbENoYW5nZSk9XCJvbkZpbHRlclRleHRDaGFuZ2UoJGV2ZW50KVwiIC8+XHJcbiAgICA8L2Rpdj5cclxuICA8L2Rpdj5cclxuICA8ZGl2ICpuZ0lmPVwiaGFzRmlsdGVySXRlbXNcIj5cclxuICAgIDxkaXYgKm5nSWY9XCJjb25maWcuaGFzQWxsQ2hlY2tCb3ggfHwgY29uZmlnLmhhc0NvbGxhcHNlRXhwYW5kXCIgY2xhc3M9XCJyb3cgcm93LWFsbFwiPlxyXG4gICAgICA8ZGl2IGNsYXNzPVwiY29sLTEyXCI+XHJcbiAgICAgICAgPGRpdiBjbGFzcz1cImZvcm0tY2hlY2sgZm9ybS1jaGVjay1pbmxpbmVcIiAqbmdJZj1cImNvbmZpZy5oYXNBbGxDaGVja0JveFwiPlxyXG4gICAgICAgICAgPGlucHV0IHR5cGU9XCJjaGVja2JveFwiIGNsYXNzPVwiZm9ybS1jaGVjay1pbnB1dFwiIFsobmdNb2RlbCldPVwiaXRlbS5jaGVja2VkXCIgKG5nTW9kZWxDaGFuZ2UpPVwib25DaGVja2VkQ2hhbmdlKClcIlxyXG4gICAgICAgICAgICBbaW5kZXRlcm1pbmF0ZV09XCJpdGVtLmluZGV0ZXJtaW5hdGVcIiAvPlxyXG4gICAgICAgICAgPGxhYmVsIGNsYXNzPVwiZm9ybS1jaGVjay1sYWJlbFwiIChjbGljayk9XCJpdGVtLmNoZWNrZWQgPSAhaXRlbS5jaGVja2VkOyBvbkNoZWNrZWRDaGFuZ2UoKVwiPlxyXG4gICAgICAgICAgICB7e2kxOG4uZ2V0QWxsQ2hlY2tib3hUZXh0KCl9fVxyXG4gICAgICAgICAgPC9sYWJlbD5cclxuICAgICAgICA8L2Rpdj5cclxuICAgICAgICA8bGFiZWwgKm5nSWY9XCJjb25maWcuaGFzQ29sbGFwc2VFeHBhbmRcIiBjbGFzcz1cImZsb2F0LXJpZ2h0IGZvcm0tY2hlY2stbGFiZWxcIiAoY2xpY2spPVwib25Db2xsYXBzZUV4cGFuZCgpXCI+XHJcbiAgICAgICAgICA8aSBbdGl0bGVdPVwiaTE4bi5nZXRUb29sdGlwQ29sbGFwc2VFeHBhbmRUZXh0KGl0ZW0uY29sbGFwc2VkKVwiIGFyaWEtaGlkZGVuPVwidHJ1ZVwiIFtuZ1N3aXRjaF09XCJpdGVtLmNvbGxhcHNlZFwiPlxyXG4gICAgICAgICAgICA8c3ZnICpuZ1N3aXRjaENhc2U9XCJ0cnVlXCIgd2lkdGg9XCIxZW1cIiBoZWlnaHQ9XCIxZW1cIiB2aWV3Qm94PVwiMCAwIDE2IDE2XCIgY2xhc3M9XCJiaSBiaS1hcnJvd3MtYW5nbGUtZXhwYW5kXCJcclxuICAgICAgICAgICAgICBmaWxsPVwiY3VycmVudENvbG9yXCIgeG1sbnM9XCJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2Z1wiPlxyXG4gICAgICAgICAgICAgIDxwYXRoIGZpbGwtcnVsZT1cImV2ZW5vZGRcIlxyXG4gICAgICAgICAgICAgICAgZD1cIk0xLjUgMTAuMDM2YS41LjUgMCAwIDEgLjUuNXYzLjVoMy41YS41LjUgMCAwIDEgMCAxaC00YS41LjUgMCAwIDEtLjUtLjV2LTRhLjUuNSAwIDAgMSAuNS0uNXpcIiAvPlxyXG4gICAgICAgICAgICAgIDxwYXRoIGZpbGwtcnVsZT1cImV2ZW5vZGRcIlxyXG4gICAgICAgICAgICAgICAgZD1cIk02LjM1NCA5LjY0NmEuNS41IDAgMCAxIDAgLjcwOGwtNC41IDQuNWEuNS41IDAgMCAxLS43MDgtLjcwOGw0LjUtNC41YS41LjUgMCAwIDEgLjcwOCAwem04LjUtOC41YS41LjUgMCAwIDEgMCAuNzA4bC00LjUgNC41YS41LjUgMCAwIDEtLjcwOC0uNzA4bDQuNS00LjVhLjUuNSAwIDAgMSAuNzA4IDB6XCIgLz5cclxuICAgICAgICAgICAgICA8cGF0aCBmaWxsLXJ1bGU9XCJldmVub2RkXCJcclxuICAgICAgICAgICAgICAgIGQ9XCJNMTAuMDM2IDEuNWEuNS41IDAgMCAxIC41LS41aDRhLjUuNSAwIDAgMSAuNS41djRhLjUuNSAwIDEgMS0xIDBWMmgtMy41YS41LjUgMCAwIDEtLjUtLjV6XCIgLz5cclxuICAgICAgICAgICAgPC9zdmc+XHJcbiAgICAgICAgICAgIDxzdmcgKm5nU3dpdGNoQ2FzZT1cImZhbHNlXCIgd2lkdGg9XCIxZW1cIiBoZWlnaHQ9XCIxZW1cIiB2aWV3Qm94PVwiMCAwIDE2IDE2XCIgY2xhc3M9XCJiaSBiaS1hcnJvd3MtYW5nbGUtY29udHJhY3RcIlxyXG4gICAgICAgICAgICAgIGZpbGw9XCJjdXJyZW50Q29sb3JcIiB4bWxucz1cImh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnXCI+XHJcbiAgICAgICAgICAgICAgPHBhdGggZmlsbC1ydWxlPVwiZXZlbm9kZFwiXHJcbiAgICAgICAgICAgICAgICBkPVwiTTkuNSAyLjAzNmEuNS41IDAgMCAxIC41LjV2My41aDMuNWEuNS41IDAgMCAxIDAgMWgtNGEuNS41IDAgMCAxLS41LS41di00YS41LjUgMCAwIDEgLjUtLjV6XCIgLz5cclxuICAgICAgICAgICAgICA8cGF0aCBmaWxsLXJ1bGU9XCJldmVub2RkXCJcclxuICAgICAgICAgICAgICAgIGQ9XCJNMTQuMzU0IDEuNjQ2YS41LjUgMCAwIDEgMCAuNzA4bC00LjUgNC41YS41LjUgMCAxIDEtLjcwOC0uNzA4bDQuNS00LjVhLjUuNSAwIDAgMSAuNzA4IDB6bS03LjUgNy41YS41LjUgMCAwIDEgMCAuNzA4bC00LjUgNC41YS41LjUgMCAwIDEtLjcwOC0uNzA4bDQuNS00LjVhLjUuNSAwIDAgMSAuNzA4IDB6XCIgLz5cclxuICAgICAgICAgICAgICA8cGF0aCBmaWxsLXJ1bGU9XCJldmVub2RkXCJcclxuICAgICAgICAgICAgICAgIGQ9XCJNMi4wMzYgOS41YS41LjUgMCAwIDEgLjUtLjVoNGEuNS41IDAgMCAxIC41LjV2NGEuNS41IDAgMCAxLTEgMFYxMGgtMy41YS41LjUgMCAwIDEtLjUtLjV6XCIgLz5cclxuICAgICAgICAgICAgPC9zdmc+XHJcbiAgICAgICAgICA8L2k+XHJcbiAgICAgICAgPC9sYWJlbD5cclxuICAgICAgPC9kaXY+XHJcbiAgICA8L2Rpdj5cclxuICAgIDxkaXYgKm5nSWY9XCJjb25maWcuaGFzRGl2aWRlclwiIGNsYXNzPVwiZHJvcGRvd24tZGl2aWRlclwiPjwvZGl2PlxyXG4gIDwvZGl2PlxyXG48L25nLXRlbXBsYXRlPlxyXG48ZGl2IGNsYXNzPVwidHJlZXZpZXctaGVhZGVyXCI+XHJcbiAgPG5nLXRlbXBsYXRlIFtuZ1RlbXBsYXRlT3V0bGV0XT1cImhlYWRlclRlbXBsYXRlIHx8IGRlZmF1bHRIZWFkZXJUZW1wbGF0ZVwiXHJcbiAgICBbbmdUZW1wbGF0ZU91dGxldENvbnRleHRdPVwiaGVhZGVyVGVtcGxhdGVDb250ZXh0XCI+XHJcbiAgPC9uZy10ZW1wbGF0ZT5cclxuPC9kaXY+XHJcbjxkaXYgW25nU3dpdGNoXT1cImhhc0ZpbHRlckl0ZW1zXCI+XHJcbiAgPGRpdiAqbmdTd2l0Y2hDYXNlPVwidHJ1ZVwiIGNsYXNzPVwidHJlZXZpZXctY29udGFpbmVyXCIgW3N0eWxlLm1heC1oZWlnaHQucHhdPVwibWF4SGVpZ2h0XCI+XHJcbiAgICA8bmd4LXRyZWV2aWV3LWl0ZW0gKm5nRm9yPVwibGV0IGl0ZW0gb2YgZmlsdGVySXRlbXNcIiBbY29uZmlnXT1cImNvbmZpZ1wiIFtpdGVtXT1cIml0ZW1cIlxyXG4gICAgICBbdGVtcGxhdGVdPVwiaXRlbVRlbXBsYXRlIHx8IGRlZmF1bHRJdGVtVGVtcGxhdGVcIiAoY2hlY2tlZENoYW5nZSk9XCJvbkl0ZW1DaGVja2VkQ2hhbmdlKGl0ZW0sICRldmVudClcIj5cclxuICAgIDwvbmd4LXRyZWV2aWV3LWl0ZW0+XHJcbiAgPC9kaXY+XHJcbiAgPGRpdiAqbmdTd2l0Y2hDYXNlPVwiZmFsc2VcIiBjbGFzcz1cInRyZWV2aWV3LXRleHRcIj5cclxuICAgIHt7aTE4bi5nZXRGaWx0ZXJOb0l0ZW1zRm91bmRUZXh0KCl9fVxyXG4gIDwvZGl2PlxyXG48L2Rpdj5cclxuIl19