@nova-ui/bits
Version:
SolarWinds Nova Framework
251 lines • 56.1 kB
JavaScript
// © 2022 SolarWinds Worldwide, LLC. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
import { ChangeDetectorRef, Component, ContentChildren, ElementRef, HostBinding, HostListener, Input, NgZone, QueryList, ViewChild, ViewChildren, ViewEncapsulation, } from "@angular/core";
import _isEmpty from "lodash/isEmpty";
import { merge, Subject } from "rxjs";
import { debounceTime, take, takeUntil } from "rxjs/operators";
import { ToolbarItemDisplayStyle, ToolbarItemType, } from "./public-api";
import { ToolbarGroupComponent } from "./toolbar-group.component";
import { ToolbarItemComponent } from "./toolbar-item.component";
import { ToolbarKeyboardService } from "./toolbar-keyboard.service";
import { LoggerService } from "../../services/log-service";
import { MenuComponent } from "../menu";
import * as i0 from "@angular/core";
import * as i1 from "../../services/log-service";
import * as i2 from "./toolbar-keyboard.service";
import * as i3 from "@angular/common";
import * as i4 from "../../common/directives/resize-observer/resize-observer.directive";
import * as i5 from "../menu/menu-item/menu-action/menu-action.component";
import * as i6 from "../menu/menu/menu.component";
import * as i7 from "../menu/menu-item/menu-group/menu-group.component";
import * as i8 from "../divider/divider.component";
import * as i9 from "../button/button.component";
import * as i10 from "./toolbar-message.component";
/**
* NUI wrapper for toolbar control. It groups toolbar items (nui-toolbar-item),
* which can be aligned to the left or to the right side of the bar. Items are aligned to the left by default.
* Use nui-toolbar-splitter to determine the place where the right alignment starts.
* Use nui-toolbar-divider to display a vertical line between items.
* <example-url>./../examples/index.html#/toolbar</example-url>
*/
export class ToolbarComponent {
constructor(element, changeDetector, logger, ngZone, keyboardService) {
this.element = element;
this.changeDetector = changeDetector;
this.logger = logger;
this.ngZone = ngZone;
this.keyboardService = keyboardService;
this.boxShadow = true;
this.noEmptyMessage = false;
/**
* Passed to the toolbar menu
*/
this.appendToBody = false;
this.commandGroups = [];
this.menuGroups = [];
this.showMenu = true;
this.allItemsHidden = false;
this.commandsTitle = $localize `Commands`;
this.moreTitle = $localize `More`;
this.toolbarItems = [];
this.destroy$ = new Subject();
}
onKeyDown(event) {
this.keyboardService.onKeyDown(event);
}
ngAfterViewInit() {
this.splitToolbarItems();
this.childrenSubscription = merge(this.groups.changes, this.items.changes)
.pipe(debounceTime(20))
.subscribe(() => {
// timeout is needed for updating actual querylist. without it splitToolbarItems won't get new element in groups' arrays
setTimeout(() => {
this.splitToolbarItems();
}, 0);
});
this.ngZone.onStable
.asObservable()
.pipe(take(1))
.subscribe(() => {
this.moveToolbarItems();
});
this.destructiveItems = [];
this.groups.forEach((group) => {
const isDestructiveItem = group.items.filter((item) => item.displayStyle === ToolbarItemDisplayStyle.destructive);
if (isDestructiveItem.length) {
this.destructiveItems.push(isDestructiveItem);
if ((this.destructiveItems.length === 1 &&
this.destructiveIsLastItem) ||
this.destructiveItems.length > 1) {
this.logger.error("Only one tool-bar-item with type destructive may be defined, and it must be the last item in last group");
}
}
});
this.subscribeToToolbarStepsChanges();
}
ngOnDestroy() {
this.childrenSubscription.unsubscribe();
this.destroy$.next();
this.destroy$.complete();
}
onClickToolbarBtn(event, commandItem) {
event.stopPropagation();
event.target.focus();
commandItem.actionDone.emit();
}
moveToolbarItems() {
this.makeAllItemsVisible();
const containerBorder = Math.floor(this.toolbarContainer.nativeElement.getBoundingClientRect().right);
this.lastChildBorder = Math.floor(this.toolbarContainer.nativeElement.lastElementChild.getBoundingClientRect()
.right);
while (containerBorder < this.lastChildBorder &&
this.commandGroups.length > 0) {
this.commandGroups.forEach((group, index, groups) => {
if (index === groups.length - 1) {
group.items.forEach((item, index, items) => {
if (index === items.length - 1) {
item.menuHidden = true;
}
});
}
});
this.splitToolbarItems();
this.lastChildBorder = Math.floor(this.toolbarContainer.nativeElement.lastElementChild.getBoundingClientRect()
.right);
}
}
splitToolbarItems() {
this.commandGroups = [];
this.menuGroups = [];
this.groups.forEach((group) => {
const commandGroupItems = group.items.filter((item) => !item.menuHidden);
const menuGroupItems = group.items.filter((item) => !!item.menuHidden);
if (commandGroupItems.length) {
this.commandGroups.push({ items: commandGroupItems });
}
if (menuGroupItems.length) {
this.menuGroups.push({
items: menuGroupItems,
title: group.title,
});
}
});
this.showMenu = this.menuGroups.length > 0;
this.allItemsHidden = this.commandGroups.length === 0;
this.changeDetector.detectChanges();
}
makeAllItemsVisible() {
this.groups.forEach((group) => {
group.items.forEach((item) => {
if (item.type === ToolbarItemType.primary) {
item.menuHidden = false;
}
});
});
this.splitToolbarItems();
}
handleSelectionState() {
if (this.selectionEnabled) {
if (!_isEmpty(this.selectedItems)) {
const itemSelected = $localize `${this.selectedItems.current} of ${this.selectedItems.total} selected`;
const allItemSelected = $localize `All ${this.selectedItems.total} selected`;
return this.selectedItems.current === this.selectedItems.total
? allItemSelected
: itemSelected;
}
}
if (_isEmpty(this.selectedItems)) {
return "";
}
return this.selectedItems.current === this.selectedItems.total
? $localize `All ${this.selectedItems.total} selected`
: $localize `${this.selectedItems.current} of ${this.selectedItems.total} selected`;
}
get menuTitle() {
return this.allItemsHidden ? this.commandsTitle : this.moreTitle;
}
get destructiveIsLastItem() {
return (this.groups.last.items.last.displayStyle !==
ToolbarItemDisplayStyle.destructive);
}
subscribeToToolbarStepsChanges() {
this.toolbarButtons.changes
.pipe(takeUntil(this.destroy$))
.subscribe((buttons) => {
this.toolbarItems = buttons
.toArray()
.slice()
.map((b) => b["el"].nativeElement)
.filter((el) => !!el);
if (this.menu) {
// In case all buttons are hidden within the Commands menu we want this menu to receive the focus
// If at least one button is visible in the toolbar it should receive the focus first upon navigating onto the toolbar
const tabIndex = buttons.length ? "-1" : "0";
this.menu.menuToggle.nativeElement.setAttribute("tabindex", tabIndex);
this.toolbarItems.push(this.menu.menuToggle.nativeElement);
}
this.keyboardService.setToolbarItems(this.toolbarItems, this.menu);
});
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ToolbarComponent, deps: [{ token: i0.ElementRef }, { token: i0.ChangeDetectorRef }, { token: i1.LoggerService }, { token: i0.NgZone }, { token: i2.ToolbarKeyboardService }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: ToolbarComponent, selector: "nui-toolbar", inputs: { selectionEnabled: "selectionEnabled", selectedItems: "selectedItems", boxShadow: "boxShadow", noEmptyMessage: "noEmptyMessage", appendToBody: "appendToBody" }, host: { attributes: { "role": "toolbar" }, listeners: { "keydown": "onKeyDown($event)" }, properties: { "class.nui-toolbar--active": "this.selectionEnabled", "class.nui-toolbar--shadowed": "this.boxShadow" }, classAttribute: "nui-toolbar nui-strip-layout nui-flex-container" }, providers: [ToolbarKeyboardService], queries: [{ propertyName: "groups", predicate: ToolbarGroupComponent }, { propertyName: "items", predicate: ToolbarItemComponent, descendants: true }], viewQueries: [{ propertyName: "toolbarContainer", first: true, predicate: ["toolbarContainer"], descendants: true }, { propertyName: "menu", first: true, predicate: ["menuComponent"], descendants: true }, { propertyName: "toolbarButtons", predicate: ["toolbarButtons"], descendants: true }], ngImport: i0, template: "<div\n class=\"nui-toolbar-content\"\n nuiResizeObserver\n (containerResize)=\"moveToolbarItems()\"\n #toolbarContainer\n>\n <div class=\"nui-toolbar-content__dynamic\">\n <ng-template\n ngFor\n let-i=\"index\"\n let-commandGroup\n let-last=\"last\"\n [ngForOf]=\"commandGroups\"\n >\n <ng-template\n ngFor\n let-commandItem\n let-j=\"index\"\n [ngForOf]=\"commandGroup.items\"\n >\n <!-- (!i && !j) is used for set focusable state to first element first group -->\n <button\n nui-button\n type=\"button\"\n #toolbarButtons\n [tabindex]=\"!i && !j ? 0 : -1\"\n (click)=\"onClickToolbarBtn($event, commandItem)\"\n [displayStyle]=\"\n commandItem.displayStyle === 'main'\n ? 'primary'\n : commandItem.displayStyle\n \"\n [ngClass]=\"{\n 'nui-toolbar-primary-item':\n commandItem.displayStyle === 'main'\n }\"\n [icon]=\"commandItem.icon\"\n >\n <span>{{ commandItem.title }}</span>\n </button>\n </ng-template>\n <nui-divider\n *ngIf=\"!last || showMenu\"\n isVertical=\"true\"\n size=\"extra-small\"\n ></nui-divider>\n </ng-template>\n <nui-menu\n displayStyle=\"action\"\n #menuComponent\n [appendToBody]=\"appendToBody\"\n [title]=\"menuTitle\"\n *ngIf=\"showMenu\"\n >\n <ng-template ngFor let-menuGroup [ngForOf]=\"menuGroups\">\n <nui-menu-group [header]=\"menuGroup.title\">\n <ng-template ngFor let-menuItem [ngForOf]=\"menuGroup.items\">\n <nui-menu-action\n [type]=\"\n menuItem.isDestructive\n ? 'destructive'\n : 'default'\n \"\n [icon]=\"menuItem.icon\"\n (click)=\"menuItem.actionDone.emit()\"\n >{{ menuItem.title }}\n </nui-menu-action>\n </ng-template>\n </nui-menu-group>\n </ng-template>\n </nui-menu>\n <ng-container>\n <nui-toolbar-message\n *ngIf=\"allItemsHidden && !showMenu && !noEmptyMessage\"\n >\n <ng-container *ngIf=\"selectionEnabled\" i18n\n >No actions available for this selection</ng-container\n >\n <ng-container *ngIf=\"!selectionEnabled\" i18n\n >No actions available</ng-container\n >\n </nui-toolbar-message>\n <ng-content select=\"nui-toolbar-message\"></ng-content>\n </ng-container>\n </div>\n <div class=\"nui-toolbar-content__embedded\">\n <ng-container *ngIf=\"selectionEnabled\">\n <div class=\"nui-toolbar-content__select\">\n {{ handleSelectionState() }}\n </div>\n </ng-container>\n <ng-content></ng-content>\n <ng-content select=\".nui-toolbar-embedded\"></ng-content>\n </div>\n</div>\n", styles: [".nui .nui-toolbar{position:relative;transition:background-color ease .2s;padding:0 15px}.nui .nui-toolbar--shadowed{box-shadow:inset 0 -1px 0 0 var(--nui-color-line-default, #d9d9d9)}.nui .nui-toolbar--active{background-color:var(--nui-color-selected,rgba(0, 196, 210, .1))}.nui .nui-toolbar-content{width:100%;display:flex;flex-direction:row;align-items:center;justify-content:space-between;transition:visibility .25s;padding:5px 0}.nui .nui-toolbar-content__embedded{display:flex}.nui .nui-toolbar-content__embedded>div{white-space:nowrap}.nui .nui-toolbar-content__dynamic{display:flex;flex-direction:row;flex-shrink:0}.nui .nui-toolbar-content__dynamic .nui-button.btn-destructive{border-color:transparent}.nui .nui-toolbar-content__dynamic .nui-button.btn-destructive:hover,.nui .nui-toolbar-content__dynamic .nui-button.btn-destructive:active,.nui .nui-toolbar-content__dynamic .nui-button.btn-destructive:focus{border-color:transparent;background-color:var(--nui-color-bg-transparent-hover,rgba(17, 17, 17, .05))}.nui .nui-toolbar-content__dynamic nui-divider{flex-shrink:0}.nui .nui-toolbar-content__select{display:flex;align-items:center;flex-shrink:0;font-size:11px;font-weight:600;padding-left:10px}.nui .nui-toolbar-group-primary{display:flex}.nui .nui-toolbar-primary-item{margin-right:5px}.nui .nui-toolbar-embedded{margin-left:15px;display:flex;flex-wrap:nowrap}.nui .nui-toolbar-divider{display:table-cell;padding:0 5px}.nui .nui-toolbar-divider-line{width:1px;background:var(--nui-color-line-default,#d9d9d9);height:30px}.nui .nui-toolbar nui-toolbar-message{padding:5px 10px;margin-bottom:2px}\n"], dependencies: [{ kind: "directive", type: i3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i3.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i4.ResizeObserverDirective, selector: "[nuiResizeObserver]", outputs: ["containerResize"] }, { kind: "component", type: i5.MenuActionComponent, selector: "nui-menu-action", inputs: ["icon", "type"] }, { kind: "component", type: i6.MenuComponent, selector: "nui-menu", inputs: ["widthOfPopup", "contextClass", "appendToBody", "ariaLabel", "title", "size", "displayStyle", "isDisabled", "icon", "itemsSource"], outputs: ["blurred"] }, { kind: "component", type: i7.MenuGroupComponent, selector: "nui-menu-group", inputs: ["header"] }, { kind: "component", type: i8.DividerComponent, selector: "nui-divider", inputs: ["isVertical", "size"] }, { kind: "component", type: i9.ButtonComponent, selector: "[nui-button]", inputs: ["displayStyle", "icon", "iconColor", "iconRight", "isBusy", "isEmpty", "ariaLabel", "isRepeat", "size"] }, { kind: "component", type: i10.ToolbarMessageComponent, selector: "nui-toolbar-message" }], encapsulation: i0.ViewEncapsulation.None }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ToolbarComponent, decorators: [{
type: Component,
args: [{ selector: "nui-toolbar", host: {
class: "nui-toolbar nui-strip-layout nui-flex-container",
role: "toolbar",
}, encapsulation: ViewEncapsulation.None, providers: [ToolbarKeyboardService], template: "<div\n class=\"nui-toolbar-content\"\n nuiResizeObserver\n (containerResize)=\"moveToolbarItems()\"\n #toolbarContainer\n>\n <div class=\"nui-toolbar-content__dynamic\">\n <ng-template\n ngFor\n let-i=\"index\"\n let-commandGroup\n let-last=\"last\"\n [ngForOf]=\"commandGroups\"\n >\n <ng-template\n ngFor\n let-commandItem\n let-j=\"index\"\n [ngForOf]=\"commandGroup.items\"\n >\n <!-- (!i && !j) is used for set focusable state to first element first group -->\n <button\n nui-button\n type=\"button\"\n #toolbarButtons\n [tabindex]=\"!i && !j ? 0 : -1\"\n (click)=\"onClickToolbarBtn($event, commandItem)\"\n [displayStyle]=\"\n commandItem.displayStyle === 'main'\n ? 'primary'\n : commandItem.displayStyle\n \"\n [ngClass]=\"{\n 'nui-toolbar-primary-item':\n commandItem.displayStyle === 'main'\n }\"\n [icon]=\"commandItem.icon\"\n >\n <span>{{ commandItem.title }}</span>\n </button>\n </ng-template>\n <nui-divider\n *ngIf=\"!last || showMenu\"\n isVertical=\"true\"\n size=\"extra-small\"\n ></nui-divider>\n </ng-template>\n <nui-menu\n displayStyle=\"action\"\n #menuComponent\n [appendToBody]=\"appendToBody\"\n [title]=\"menuTitle\"\n *ngIf=\"showMenu\"\n >\n <ng-template ngFor let-menuGroup [ngForOf]=\"menuGroups\">\n <nui-menu-group [header]=\"menuGroup.title\">\n <ng-template ngFor let-menuItem [ngForOf]=\"menuGroup.items\">\n <nui-menu-action\n [type]=\"\n menuItem.isDestructive\n ? 'destructive'\n : 'default'\n \"\n [icon]=\"menuItem.icon\"\n (click)=\"menuItem.actionDone.emit()\"\n >{{ menuItem.title }}\n </nui-menu-action>\n </ng-template>\n </nui-menu-group>\n </ng-template>\n </nui-menu>\n <ng-container>\n <nui-toolbar-message\n *ngIf=\"allItemsHidden && !showMenu && !noEmptyMessage\"\n >\n <ng-container *ngIf=\"selectionEnabled\" i18n\n >No actions available for this selection</ng-container\n >\n <ng-container *ngIf=\"!selectionEnabled\" i18n\n >No actions available</ng-container\n >\n </nui-toolbar-message>\n <ng-content select=\"nui-toolbar-message\"></ng-content>\n </ng-container>\n </div>\n <div class=\"nui-toolbar-content__embedded\">\n <ng-container *ngIf=\"selectionEnabled\">\n <div class=\"nui-toolbar-content__select\">\n {{ handleSelectionState() }}\n </div>\n </ng-container>\n <ng-content></ng-content>\n <ng-content select=\".nui-toolbar-embedded\"></ng-content>\n </div>\n</div>\n", styles: [".nui .nui-toolbar{position:relative;transition:background-color ease .2s;padding:0 15px}.nui .nui-toolbar--shadowed{box-shadow:inset 0 -1px 0 0 var(--nui-color-line-default, #d9d9d9)}.nui .nui-toolbar--active{background-color:var(--nui-color-selected,rgba(0, 196, 210, .1))}.nui .nui-toolbar-content{width:100%;display:flex;flex-direction:row;align-items:center;justify-content:space-between;transition:visibility .25s;padding:5px 0}.nui .nui-toolbar-content__embedded{display:flex}.nui .nui-toolbar-content__embedded>div{white-space:nowrap}.nui .nui-toolbar-content__dynamic{display:flex;flex-direction:row;flex-shrink:0}.nui .nui-toolbar-content__dynamic .nui-button.btn-destructive{border-color:transparent}.nui .nui-toolbar-content__dynamic .nui-button.btn-destructive:hover,.nui .nui-toolbar-content__dynamic .nui-button.btn-destructive:active,.nui .nui-toolbar-content__dynamic .nui-button.btn-destructive:focus{border-color:transparent;background-color:var(--nui-color-bg-transparent-hover,rgba(17, 17, 17, .05))}.nui .nui-toolbar-content__dynamic nui-divider{flex-shrink:0}.nui .nui-toolbar-content__select{display:flex;align-items:center;flex-shrink:0;font-size:11px;font-weight:600;padding-left:10px}.nui .nui-toolbar-group-primary{display:flex}.nui .nui-toolbar-primary-item{margin-right:5px}.nui .nui-toolbar-embedded{margin-left:15px;display:flex;flex-wrap:nowrap}.nui .nui-toolbar-divider{display:table-cell;padding:0 5px}.nui .nui-toolbar-divider-line{width:1px;background:var(--nui-color-line-default,#d9d9d9);height:30px}.nui .nui-toolbar nui-toolbar-message{padding:5px 10px;margin-bottom:2px}\n"] }]
}], ctorParameters: () => [{ type: i0.ElementRef }, { type: i0.ChangeDetectorRef }, { type: i1.LoggerService }, { type: i0.NgZone }, { type: i2.ToolbarKeyboardService }], propDecorators: { groups: [{
type: ContentChildren,
args: [ToolbarGroupComponent]
}], items: [{
type: ContentChildren,
args: [ToolbarItemComponent, { descendants: true }]
}], selectionEnabled: [{
type: Input
}, {
type: HostBinding,
args: ["class.nui-toolbar--active"]
}], selectedItems: [{
type: Input
}], boxShadow: [{
type: Input
}, {
type: HostBinding,
args: ["class.nui-toolbar--shadowed"]
}], toolbarContainer: [{
type: ViewChild,
args: ["toolbarContainer"]
}], noEmptyMessage: [{
type: Input
}], appendToBody: [{
type: Input
}], menu: [{
type: ViewChild,
args: ["menuComponent"]
}], toolbarButtons: [{
type: ViewChildren,
args: ["toolbarButtons"]
}], onKeyDown: [{
type: HostListener,
args: ["keydown", ["$event"]]
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidG9vbGJhci5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvbGliL3Rvb2xiYXIvdG9vbGJhci5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi9zcmMvbGliL3Rvb2xiYXIvdG9vbGJhci5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSx5REFBeUQ7QUFDekQsRUFBRTtBQUNGLCtFQUErRTtBQUMvRSw0RUFBNEU7QUFDNUUsOEVBQThFO0FBQzlFLCtFQUErRTtBQUMvRSw4RUFBOEU7QUFDOUUsNERBQTREO0FBQzVELEVBQUU7QUFDRiw2RUFBNkU7QUFDN0UsdURBQXVEO0FBQ3ZELEVBQUU7QUFDRiw2RUFBNkU7QUFDN0UsNEVBQTRFO0FBQzVFLCtFQUErRTtBQUMvRSwwRUFBMEU7QUFDMUUsaUZBQWlGO0FBQ2pGLDZFQUE2RTtBQUM3RSxpQkFBaUI7QUFFakIsT0FBTyxFQUVILGlCQUFpQixFQUNqQixTQUFTLEVBQ1QsZUFBZSxFQUNmLFVBQVUsRUFDVixXQUFXLEVBQ1gsWUFBWSxFQUNaLEtBQUssRUFDTCxNQUFNLEVBRU4sU0FBUyxFQUNULFNBQVMsRUFDVCxZQUFZLEVBQ1osaUJBQWlCLEdBQ3BCLE1BQU0sZUFBZSxDQUFDO0FBQ3ZCLE9BQU8sUUFBUSxNQUFNLGdCQUFnQixDQUFDO0FBQ3RDLE9BQU8sRUFBRSxLQUFLLEVBQUUsT0FBTyxFQUFnQixNQUFNLE1BQU0sQ0FBQztBQUNwRCxPQUFPLEVBQUUsWUFBWSxFQUFFLElBQUksRUFBRSxTQUFTLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUUvRCxPQUFPLEVBR0gsdUJBQXVCLEVBQ3ZCLGVBQWUsR0FDbEIsTUFBTSxjQUFjLENBQUM7QUFDdEIsT0FBTyxFQUFFLHFCQUFxQixFQUFFLE1BQU0sMkJBQTJCLENBQUM7QUFDbEUsT0FBTyxFQUFFLG9CQUFvQixFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFDaEUsT0FBTyxFQUFF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QkFJQyxTQUFTO3NCQUZmLEtBQUs7O3NCQUNMLFdBQVc7dUJBQUMsNkJBQTZCO2dCQUluQyxnQkFBZ0I7c0JBRHRCLFNBQVM7dUJBQUMsa0JBQWtCO2dCQUl0QixjQUFjO3NCQURwQixLQUFLO2dCQU9DLFlBQVk7c0JBRGxCLEtBQUs7Z0JBRzZCLElBQUk7c0JBQXRDLFNBQVM7dUJBQUMsZUFBZTtnQkFHbkIsY0FBYztzQkFEcEIsWUFBWTt1QkFBQyxnQkFBZ0I7Z0JBeUI5QixTQUFTO3NCQURSLFlBQVk7dUJBQUMsU0FBUyxFQUFFLENBQUMsUUFBUSxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gwqkgMjAyMiBTb2xhcldpbmRzIFdvcmxkd2lkZSwgTExDLiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuLy9cbi8vIFBlcm1pc3Npb24gaXMgaGVyZWJ5IGdyYW50ZWQsIGZyZWUgb2YgY2hhcmdlLCB0byBhbnkgcGVyc29uIG9idGFpbmluZyBhIGNvcHlcbi8vICBvZiB0aGlzIHNvZnR3YXJlIGFuZCBhc3NvY2lhdGVkIGRvY3VtZW50YXRpb24gZmlsZXMgKHRoZSBcIlNvZnR3YXJlXCIpLCB0b1xuLy8gIGRlYWwgaW4gdGhlIFNvZnR3YXJlIHdpdGhvdXQgcmVzdHJpY3Rpb24sIGluY2x1ZGluZyB3aXRob3V0IGxpbWl0YXRpb24gdGhlXG4vLyAgcmlnaHRzIHRvIHVzZSwgY29weSwgbW9kaWZ5LCBtZXJnZSwgcHVibGlzaCwgZGlzdHJpYnV0ZSwgc3VibGljZW5zZSwgYW5kL29yXG4vLyAgc2VsbCBjb3BpZXMgb2YgdGhlIFNvZnR3YXJlLCBhbmQgdG8gcGVybWl0IHBlcnNvbnMgdG8gd2hvbSB0aGUgU29mdHdhcmUgaXNcbi8vICBmdXJuaXNoZWQgdG8gZG8gc28sIHN1YmplY3QgdG8gdGhlIGZvbGxvd2luZyBjb25kaXRpb25zOlxuLy9cbi8vIFRoZSBhYm92ZSBjb3B5cmlnaHQgbm90aWNlIGFuZCB0aGlzIHBlcm1pc3Npb24gbm90aWNlIHNoYWxsIGJlIGluY2x1ZGVkIGluXG4vLyAgYWxsIGNvcGllcyBvciBzdWJzdGFudGlhbCBwb3J0aW9ucyBvZiB0aGUgU29mdHdhcmUuXG4vL1xuLy8gVEhFIFNPRlRXQVJFIElTIFBST1ZJREVEIFwiQVMgSVNcIiwgV0lUSE9VVCBXQVJSQU5UWSBPRiBBTlkgS0lORCwgRVhQUkVTUyBPUlxuLy8gIElNUExJRUQsIElOQ0xVRElORyBCVVQgTk9UIExJTUlURUQgVE8gVEhFIFdBUlJBTlRJRVMgT0YgTUVSQ0hBTlRBQklMSVRZLFxuLy8gIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFIEFORCBOT05JTkZSSU5HRU1FTlQuIElOIE5PIEVWRU5UIFNIQUxMIFRIRVxuLy8gIEFVVEhPUlMgT1IgQ09QWVJJR0hUIEhPTERFUlMgQkUgTElBQkxFIEZPUiBBTlkgQ0xBSU0sIERBTUFHRVMgT1IgT1RIRVJcbi8vICBMSUFCSUxJVFksIFdIRVRIRVIgSU4gQU4gQUNUSU9OIE9GIENPTlRSQUNULCBUT1JUIE9SIE9USEVSV0lTRSwgQVJJU0lORyBGUk9NLFxuLy8gIE9VVCBPRiBPUiBJTiBDT05ORUNUSU9OIFdJVEggVEhFIFNPRlRXQVJFIE9SIFRIRSBVU0UgT1IgT1RIRVIgREVBTElOR1MgSU5cbi8vICBUSEUgU09GVFdBUkUuXG5cbmltcG9ydCB7XG4gICAgQWZ0ZXJWaWV3SW5pdCxcbiAgICBDaGFuZ2VEZXRlY3RvclJlZixcbiAgICBDb21wb25lbnQsXG4gICAgQ29udGVudENoaWxkcmVuLFxuICAgIEVsZW1lbnRSZWYsXG4gICAgSG9zdEJpbmRpbmcsXG4gICAgSG9zdExpc3RlbmVyLFxuICAgIElucHV0LFxuICAgIE5nWm9uZSxcbiAgICBPbkRlc3Ryb3ksXG4gICAgUXVlcnlMaXN0LFxuICAgIFZpZXdDaGlsZCxcbiAgICBWaWV3Q2hpbGRyZW4sXG4gICAgVmlld0VuY2Fwc3VsYXRpb24sXG59IGZyb20gXCJAYW5ndWxhci9jb3JlXCI7XG5pbXBvcnQgX2lzRW1wdHkgZnJvbSBcImxvZGFzaC9pc0VtcHR5XCI7XG5pbXBvcnQgeyBtZXJnZSwgU3ViamVjdCwgU3Vic2NyaXB0aW9uIH0gZnJvbSBcInJ4anNcIjtcbmltcG9ydCB7IGRlYm91bmNlVGltZSwgdGFrZSwgdGFrZVVudGlsIH0gZnJvbSBcInJ4anMvb3BlcmF0b3JzXCI7XG5cbmltcG9ydCB7XG4gICAgSVRvb2xiYXJHcm91cENvbnRlbnQsXG4gICAgSVRvb2xiYXJTZWxlY3Rpb25TdGF0ZSxcbiAgICBUb29sYmFySXRlbURpc3BsYXlTdHlsZSxcbiAgICBUb29sYmFySXRlbVR5cGUsXG59IGZyb20gXCIuL3B1YmxpYy1hcGlcIjtcbmltcG9ydCB7IFRvb2xiYXJHcm91cENvbXBvbmVudCB9IGZyb20gXCIuL3Rvb2xiYXItZ3JvdXAuY29tcG9uZW50XCI7XG5pbXBvcnQgeyBUb29sYmFySXRlbUNvbXBvbmVudCB9IGZyb20gXCIuL3Rvb2xiYXItaXRlbS5jb21wb25lbnRcIjtcbmltcG9ydCB7IFRvb2xiYXJLZXlib2FyZFNlcnZpY2UgfSBmcm9tIFwiLi90b29sYmFyLWtleWJvYXJkLnNlcnZpY2VcIjtcbmltcG9ydCB7IExvZ2dlclNlcnZpY2UgfSBmcm9tIFwiLi4vLi4vc2VydmljZXMvbG9nLXNlcnZpY2VcIjtcbmltcG9ydCB7IEJ1dHRvbkNvbXBvbmVudCB9IGZyb20gXCIuLi9idXR0b24vYnV0dG9uLmNvbXBvbmVudFwiO1xuaW1wb3J0IHsgTWVudUNvbXBvbmVudCB9IGZyb20gXCIuLi9tZW51XCI7XG5cbi8qKlxuICogTlVJIHdyYXBwZXIgZm9yIHRvb2xiYXIgY29udHJvbC4gSXQgZ3JvdXBzIHRvb2xiYXIgaXRlbXMgKG51aS10b29sYmFyLWl0ZW0pLFxuICogd2hpY2ggY2FuIGJlIGFsaWduZWQgdG8gdGhlIGxlZnQgb3IgdG8gdGhlIHJpZ2h0IHNpZGUgb2YgdGhlIGJhci4gSXRlbXMgYXJlIGFsaWduZWQgdG8gdGhlIGxlZnQgYnkgZGVmYXVsdC5cbiAqIFVzZSBudWktdG9vbGJhci1zcGxpdHRlciB0byBkZXRlcm1pbmUgdGhlIHBsYWNlIHdoZXJlIHRoZSByaWdodCBhbGlnbm1lbnQgc3RhcnRzLlxuICogVXNlIG51aS10b29sYmFyLWRpdmlkZXIgdG8gZGlzcGxheSBhIHZlcnRpY2FsIGxpbmUgYmV0d2VlbiBpdGVtcy5cbiAqIDxleGFtcGxlLXVybD4uLy4uL2V4YW1wbGVzL2luZGV4Lmh0bWwjL3Rvb2xiYXI8L2V4YW1wbGUtdXJsPlxuICovXG5cbkBDb21wb25lbnQoe1xuICAgIHNlbGVjdG9yOiBcIm51aS10b29sYmFyXCIsXG4gICAgdGVtcGxhdGVVcmw6IFwiLi90b29sYmFyLmNvbXBvbmVudC5odG1sXCIsXG4gICAgaG9zdDoge1xuICAgICAgICBjbGFzczogXCJudWktdG9vbGJhciBudWktc3RyaXAtbGF5b3V0IG51aS1mbGV4LWNvbnRhaW5lclwiLFxuICAgICAgICByb2xlOiBcInRvb2xiYXJcIixcbiAgICB9LFxuICAgIHN0eWxlVXJsczogW1wiLi90b29sYmFyLmNvbXBvbmVudC5sZXNzXCJdLFxuICAgIGVuY2Fwc3VsYXRpb246IFZpZXdFbmNhcHN1bGF0aW9uLk5vbmUsXG4gICAgcHJvdmlkZXJzOiBbVG9vbGJhcktleWJvYXJkU2VydmljZV0sXG59KVxuZXhwb3J0IGNsYXNzIFRvb2xiYXJDb21wb25lbnQgaW1wbGVtZW50cyBBZnRlclZpZXdJbml0LCBPbkRlc3Ryb3kge1xuICAgIEBDb250ZW50Q2hpbGRyZW4oVG9vbGJhckdyb3VwQ29tcG9uZW50KVxuICAgIHB1YmxpYyBncm91cHM6IFF1ZXJ5TGlzdDxUb29sYmFyR3JvdXBDb21wb25lbnQ+O1xuXG4gICAgQENvbnRlbnRDaGlsZHJlbihUb29sYmFySXRlbUNvbXBvbmVudCwgeyBkZXNjZW5kYW50czogdHJ1ZSB9KVxuICAgIHB1YmxpYyBpdGVtczogUXVlcnlMaXN0PFRvb2xiYXJJdGVtQ29tcG9uZW50PjtcblxuICAgIEBJbnB1dCgpXG4gICAgLyoqXG4gICAgICogc2VsZWN0aW9uRW5hYmxlZDogYm9vbGVhbiB3aGljaCBhbGxvd3MgdG8gc2hvdyBzZWxlY3RlZCBzZWN0aW9uXG4gICAgICovXG4gICAgQEhvc3RCaW5kaW5nKFwiY2xhc3MubnVpLXRvb2xiYXItLWFjdGl2ZVwiKVxuICAgIHB1YmxpYyBzZWxlY3Rpb25FbmFibGVkOiBib29sZWFuO1xuICAgIC8qKlxuICAgICAqIEluIHNlbGVjdGlvbiBtb2RlIGFsbG93cyB0byBzaG93IGN1cnJlbnQgc2VsZWN0ZWQgaXRlbSBhbmQgdG90YWwgb2Ygc2VsZWN0ZWQgaXRlbXNcbiAgICAgKi9cbiAgICBASW5wdXQoKSBwdWJsaWMgc2VsZWN0ZWRJdGVtczogSVRvb2xiYXJTZWxlY3Rpb25TdGF0ZTtcblxuICAgIEBJbnB1dCgpXG4gICAgQEhvc3RCaW5kaW5nKFwiY2xhc3MubnVpLXRvb2xiYXItLXNoYWRvd2VkXCIpXG4gICAgcHVibGljIGJveFNoYWRvdzogYm9vbGVhbiA9IHRydWU7XG5cbiAgICBAVmlld0NoaWxkKFwidG9vbGJhckNvbnRhaW5lclwiKVxuICAgIHB1YmxpYyB0b29sYmFyQ29udGFpbmVyOiBFbGVtZW50UmVmO1xuXG4gICAgQElucHV0KClcbiAgICBwdWJsaWMgbm9FbXB0eU1lc3NhZ2U6IGJvb2xlYW4gPSBmYWxzZTtcblxuICAgIC8qKlxuICAgICAqIFBhc3NlZCB0byB0aGUgdG9vbGJhciBtZW51XG4gICAgICovXG4gICAgQElucHV0KClcbiAgICBwdWJsaWMgYXBwZW5kVG9Cb2R5OiBib29sZWFuID0gZmFsc2U7XG5cbiAgICBAVmlld0NoaWxkKFwibWVudUNvbXBvbmVudFwiKSBwdWJsaWMgbWVudTogTWVudUNvbXBvbmVudDtcblxuICAgIEBWaWV3Q2hpbGRyZW4oXCJ0b29sYmFyQnV0dG9uc1wiKVxuICAgIHB1YmxpYyB0b29sYmFyQnV0dG9uczogUXVlcnlMaXN0PEJ1dHRvbkNvbXBvbmVudD47XG5cbiAgICBwdWJsaWMgY29tbWFuZEdyb3VwczogSVRvb2xiYXJHcm91cENvbnRlbnRbXSA9IFtdO1xuICAgIHB1YmxpYyBtZW51R3JvdXBzOiBJVG9vbGJhckdyb3VwQ29udGVudFtdID0gW107XG4gICAgcHVibGljIHNob3dNZW51ID0gdHJ1ZTtcbiAgICBwdWJsaWMgYWxsSXRlbXNIaWRkZW4gPSBmYWxzZTtcbiAgICBwdWJsaWMgY29tbWFuZHNUaXRsZSA9ICRsb2NhbGl6ZWBDb21tYW5kc2A7XG4gICAgcHVibGljIG1vcmVUaXRsZSA9ICRsb2NhbGl6ZWBNb3JlYDtcblxuICAgIHByaXZhdGUgbGFzdENoaWxkQm9yZGVyOiBudW1iZXI7XG4gICAgcHJpdmF0ZSB0b29sYmFySXRlbXM6IEhUTUxFbGVtZW50W10gPSBbXTtcbiAgICBwcml2YXRlIGNoaWxkcmVuU3Vic2NyaXB0aW9uOiBTdWJzY3JpcHRpb247XG4gICAgcHJpdmF0ZSBkZXN0cnVjdGl2ZUl0ZW1zOiBhbnlbXTtcbiAgICBwcml2YXRlIGRlc3Ryb3kkOiBTdWJqZWN0PHZvaWQ+ID0gbmV3IFN1YmplY3Q8dm9pZD4oKTtcblxuICAgIGNvbnN0cnVjdG9yKFxuICAgICAgICBwdWJsaWMgZWxlbWVudDogRWxlbWVudFJlZixcbiAgICAgICAgcHJpdmF0ZSBjaGFuZ2VEZXRlY3RvcjogQ2hhbmdlRGV0ZWN0b3JSZWYsXG4gICAgICAgIHByaXZhdGUgbG9nZ2VyOiBMb2dnZXJTZXJ2aWNlLFxuICAgICAgICBwcml2YXRlIG5nWm9uZTogTmdab25lLFxuICAgICAgICBwcml2YXRlIGtleWJvYXJkU2VydmljZTogVG9vbGJhcktleWJvYXJkU2VydmljZVxuICAgICkge31cblxuICAgIEBIb3N0TGlzdGVuZXIoXCJrZXlkb3duXCIsIFtcIiRldmVudFwiXSlcbiAgICBvbktleURvd24oZXZlbnQ6IEtleWJvYXJkRXZlbnQpOiB2b2lkIHtcbiAgICAgICAgdGhpcy5rZXlib2FyZFNlcnZpY2Uub25LZXlEb3duKGV2ZW50KTtcbiAgICB9XG5cbiAgICBwdWJsaWMgbmdBZnRlclZpZXdJbml0KCk6IHZvaWQge1xuICAgICAgICB0aGlzLnNwbGl0VG9vbGJhckl0ZW1zKCk7XG4gICAgICAgIHRoaXMuY2hpbGRyZW5TdWJzY3JpcHRpb24gPSBtZXJnZShcbiAgICAgICAgICAgIHRoaXMuZ3JvdXBzLmNoYW5nZXMsXG4gICAgICAgICAgICB0aGlzLml0ZW1zLmNoYW5nZXNcbiAgICAgICAgKVxuICAgICAgICAgICAgLnBpcGUoZGVib3VuY2VUaW1lKDIwKSlcbiAgICAgICAgICAgIC5zdWJzY3JpYmUoKCkgPT4ge1xuICAgICAgICAgICAgICAgIC8vIHRpbWVvdXQgaXMgbmVlZGVkIGZvciB1cGRhdGluZyBhY3R1YWwgcXVlcnlsaXN0LiB3aXRob3V0IGl0IHNwbGl0VG9vbGJhckl0ZW1zIHdvbid0IGdldCBuZXcgZWxlbWVudCBpbiBncm91cHMnIGFycmF5c1xuICAgICAgICAgICAgICAgIHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLnNwbGl0VG9vbGJhckl0ZW1zKCk7XG4gICAgICAgICAgICAgICAgfSwgMCk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgdGhpcy5uZ1pvbmUub25TdGFibGVcbiAgICAgICAgICAgIC5hc09ic2VydmFibGUoKVxuICAgICAgICAgICAgLnBpcGUodGFrZSgxKSlcbiAgICAgICAgICAgIC5zdWJzY3JpYmUoKCkgPT4ge1xuICAgICAgICAgICAgICAgIHRoaXMubW92ZVRvb2xiYXJJdGVtcygpO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIHRoaXMuZGVzdHJ1Y3RpdmVJdGVtcyA9IFtdO1xuICAgICAgICB0aGlzLmdyb3Vwcy5mb3JFYWNoKChncm91cDogVG9vbGJhckdyb3VwQ29tcG9uZW50KSA9PiB7XG4gICAgICAgICAgICBjb25zdCBpc0Rlc3RydWN0aXZlSXRlbSA9IGdyb3VwLml0ZW1zLmZpbHRlcihcbiAgICAgICAgICAgICAgICAoaXRlbTogVG9vbGJhckl0ZW1Db21wb25lbnQpID0+XG4gICAgICAgICAgICAgICAgICAgIGl0ZW0uZGlzcGxheVN0eWxlID09PSBUb29sYmFySXRlbURpc3BsYXlTdHlsZS5kZXN0cnVjdGl2ZVxuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIGlmIChpc0Rlc3RydWN0aXZlSXRlbS5sZW5ndGgpIHtcbiAgICAgICAgICAgICAgICB0aGlzLmRlc3RydWN0aXZlSXRlbXMucHVzaChpc0Rlc3RydWN0aXZlSXRlbSk7XG4gICAgICAgICAgICAgICAgaWYgKFxuICAgICAgICAgICAgICAgICAgICAodGhpcy5kZXN0cnVjdGl2ZUl0ZW1zLmxlbmd0aCA9PT0gMSAmJlxuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5kZXN0cnVjdGl2ZUlzTGFzdEl0ZW0pIHx8XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuZGVzdHJ1Y3RpdmVJdGVtcy5sZW5ndGggPiAxXG4gICAgICAgICAgICAgICAgKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMubG9nZ2VyLmVycm9yKFxuICAgICAgICAgICAgICAgICAgICAgICAgXCJPbmx5IG9uZSB0b29sLWJhci1pdGVtIHdpdGggdHlwZSBkZXN0cnVjdGl2ZSBtYXkgYmUgZGVmaW5lZCwgYW5kIGl0IG11c3QgYmUgdGhlIGxhc3QgaXRlbSBpbiBsYXN0IGdyb3VwXCJcbiAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgICAgICB0aGlzLnN1YnNjcmliZVRvVG9vbGJhclN0ZXBzQ2hhbmdlcygpO1xuICAgIH1cblxuICAgIHB1YmxpYyBuZ09uRGVzdHJveSgpOiB2b2lkIHtcbiAgICAgICAgdGhpcy5jaGlsZHJlblN1YnNjcmlwdGlvbi51bnN1YnNjcmliZSgpO1xuICAgICAgICB0aGlzLmRlc3Ryb3kkLm5leHQoKTtcbiAgICAgICAgdGhpcy5kZXN0cm95JC5jb21wbGV0ZSgpO1xuICAgIH1cblxuICAgIHB1YmxpYyBvbkNsaWNrVG9vbGJhckJ0bihcbiAgICAgICAgZXZlbnQ6IE1vdXNlRXZlbnQsXG4gICAgICAgIGNvbW1hbmRJdGVtOiBUb29sYmFySXRlbUNvbXBvbmVudFxuICAgICk6IHZvaWQge1xuICAgICAgICBldmVudC5zdG9wUHJvcGFnYXRpb24oKTtcbiAgICAgICAgKGV2ZW50LnRhcmdldCBhcyBIVE1MQnV0dG9uRWxlbWVudCkuZm9jdXMoKTtcbiAgICAgICAgY29tbWFuZEl0ZW0uYWN0aW9uRG9uZS5lbWl0KCk7XG4gICAgfVxuXG4gICAgcHVibGljIG1vdmVUb29sYmFySXRlbXMoKTogdm9pZCB7XG4gICAgICAgIHRoaXMubWFrZUFsbEl0ZW1zVmlzaWJsZSgpO1xuXG4gICAgICAgIGNvbnN0IGNvbnRhaW5lckJvcmRlciA9IE1hdGguZmxvb3IoXG4gICAgICAgICAgICB0aGlzLnRvb2xiYXJDb250YWluZXIubmF0aXZlRWxlbWVudC5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKS5yaWdodFxuICAgICAgICApO1xuICAgICAgICB0aGlzLmxhc3RDaGlsZEJvcmRlciA9IE1hdGguZmxvb3IoXG4gICAgICAgICAgICB0aGlzLnRvb2xiYXJDb250YWluZXIubmF0aXZlRWxlbWVudC5sYXN0RWxlbWVudENoaWxkLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpXG4gICAgICAgICAgICAgICAgLnJpZ2h0XG4gICAgICAgICk7XG5cbiAgICAgICAgd2hpbGUgKFxuICAgICAgICAgICAgY29udGFpbmVyQm9yZGVyIDwgdGhpcy5sYXN0Q2hpbGRCb3JkZXIgJiZcbiAgICAgICAgICAgIHRoaXMuY29tbWFuZEdyb3Vwcy5sZW5ndGggPiAwXG4gICAgICAgICkge1xuICAgICAgICAgICAgdGhpcy5jb21tYW5kR3JvdXBzLmZvckVhY2goXG4gICAgICAgICAgICAgICAgKFxuICAgICAgICAgICAgICAgICAgICBncm91cDogSVRvb2xiYXJHcm91cENvbnRlbnQsXG4gICAgICAgICAgICAgICAgICAgIGluZGV4OiBudW1iZXIsXG4gICAgICAgICAgICAgICAgICAgIGdyb3VwczogSVRvb2xiYXJHcm91cENvbnRlbnRbXVxuICAgICAgICAgICAgICAgICkgPT4ge1xuICAgICAgICAgICAgICAgICAgICBpZiAoaW5kZXggPT09IGdyb3Vwcy5sZW5ndGggLSAxKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBncm91cC5pdGVtcy5mb3JFYWNoKFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIChcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaXRlbTogVG9vbGJhckl0ZW1Db21wb25lbnQsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGluZGV4OiBudW1iZXIsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGl0ZW1zOiBUb29sYmFySXRlbUNvbXBvbmVudFtdXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgKSA9PiB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChpbmRleCA9PT0gaXRlbXMubGVuZ3RoIC0gMSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaXRlbS5tZW51SGlkZGVuID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgdGhpcy5zcGxpdFRvb2xiYXJJdGVtcygpO1xuICAgICAgICAgICAgdGhpcy5sYXN0Q2hpbGRCb3JkZXIgPSBNYXRoLmZsb29yKFxuICAgICAgICAgICAgICAgIHRoaXMudG9vbGJhckNvbnRhaW5lci5uYXRpdmVFbGVtZW50Lmxhc3RFbGVtZW50Q2hpbGQuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KClcbiAgICAgICAgICAgICAgICAgICAgLnJpZ2h0XG4gICAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcHVibGljIHNwbGl0VG9vbGJhckl0ZW1zKCk6IHZvaWQge1xuICAgICAgICB0aGlzLmNvbW1hbmRHcm91cHMgPSBbXTtcbiAgICAgICAgdGhpcy5tZW51R3JvdXBzID0gW107XG4gICAgICAgIHRoaXMuZ3JvdXBzLmZvckVhY2goKGdyb3VwOiBUb29sYmFyR3JvdXBDb21wb25lbnQpID0+IHtcbiAgICAgICAgICAgIGNvbnN0IGNvbW1hbmRHcm91cEl0ZW1zID0gZ3JvdXAuaXRlbXMuZmlsdGVyKFxuICAgICAgICAgICAgICAgIChpdGVtKSA9PiAhaXRlbS5tZW51SGlkZGVuXG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgY29uc3QgbWVudUdyb3VwSXRlbXMgPSBncm91cC5pdGVtcy5maWx0ZXIoXG4gICAgICAgICAgICAgICAgKGl0ZW0pID0+ICEhaXRlbS5tZW51SGlkZGVuXG4gICAgICAgICAgICApO1xuXG4gICAgICAgICAgICBpZiAoY29tbWFuZEdyb3VwSXRlbXMubGVuZ3RoKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5jb21tYW5kR3JvdXBzLnB1c2goeyBpdGVtczogY29tbWFuZEdyb3VwSXRlbXMgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAobWVudUdyb3VwSXRlbXMubGVuZ3RoKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5tZW51R3JvdXBzLnB1c2goe1xuICAgICAgICAgICAgICAgICAgICBpdGVtczogbWVudUdyb3VwSXRlbXMsXG4gICAgICAgICAgICAgICAgICAgIHRpdGxlOiBncm91cC50aXRsZSxcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgICAgIHRoaXMuc2hvd01lbnUgPSB0aGlzLm1lbnVHcm91cHMubGVuZ3RoID4gMDtcbiAgICAgICAgdGhpcy5hbGxJdGVtc0hpZGRlbiA9IHRoaXMuY29tbWFuZEdyb3Vwcy5sZW5ndGggPT09IDA7XG4gICAgICAgIHRoaXMuY2hhbmdlRGV0ZWN0b3IuZGV0ZWN0Q2hhbmdlcygpO1xuICAgIH1cblxuICAgIHB1YmxpYyBtYWtlQWxsSXRlbXNWaXNpYmxlKCk6IHZvaWQge1xuICAgICAgICB0aGlzLmdyb3Vwcy5mb3JFYWNoKChncm91cDogVG9vbGJhckdyb3VwQ29tcG9uZW50KSA9PiB7XG4gICAgICAgICAgICBncm91cC5pdGVtcy5mb3JFYWNoKChpdGVtOiBUb29sYmFySXRlbUNvbXBvbmVudCkgPT4ge1xuICAgICAgICAgICAgICAgIGlmIChpdGVtLnR5cGUgPT09IFRvb2xiYXJJdGVtVHlwZS5wcmltYXJ5KSB7XG4gICAgICAgICAgICAgICAgICAgIGl0ZW0ubWVudUhpZGRlbiA9IGZhbHNlO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9KTtcbiAgICAgICAgdGhpcy5zcGxpdFRvb2xiYXJJdGVtcygpO1xuICAgIH1cblxuICAgIHB1YmxpYyBoYW5kbGVTZWxlY3Rpb25TdGF0ZSgpOiBzdHJpbmcge1xuICAgICAgICBpZiAodGhpcy5zZWxlY3Rpb25FbmFibGVkKSB7XG4gICAgICAgICAgICBpZiAoIV9pc0VtcHR5KHRoaXMuc2VsZWN0ZWRJdGVtcykpIHtcbiAgICAgICAgICAgICAgICBjb25zdCBpdGVtU2VsZWN0ZWQgPSAkbG9jYWxpemVgJHt0aGlzLnNlbGVjdGVkSXRlbXMuY3VycmVudH0gb2YgJHt0aGlzLnNlbGVjdGVkSXRlbXMudG90YWx9IHNlbGVjdGVkYDtcbiAgICAgICAgICAgICAgICBjb25zdCBhbGxJdGVtU2VsZWN0ZWQgPSAkbG9jYWxpemVgQWxsICR7dGhpcy5zZWxlY3RlZEl0ZW1zLnRvdGFsfSBzZWxlY3RlZGA7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMuc2VsZWN0ZWRJdGVtcy5jdXJyZW50ID09PSB0aGlzLnNlbGVjdGVkSXRlbXMudG90YWxcbiAgICAgICAgICAgICAgICAgICAgPyBhbGxJdGVtU2VsZWN0ZWRcbiAgICAgICAgICAgICAgICAgICAgOiBpdGVtU2VsZWN0ZWQ7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgaWYgKF9pc0VtcHR5KHRoaXMuc2VsZWN0ZWRJdGVtcykpIHtcbiAgICAgICAgICAgIHJldHVybiBcIlwiO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB0aGlzLnNlbGVjdGVkSXRlbXMuY3VycmVudCA9PT0gdGhpcy5zZWxlY3RlZEl0ZW1zLnRvdGFsXG4gICAgICAgICAgICA/ICRsb2NhbGl6ZWBBbGwgJHt0aGlzLnNlbGVjdGVkSXRlbXMudG90YWx9IHNlbGVjdGVkYFxuICAgICAgICAgICAgOiAkbG9jYWxpemVgJHt0aGlzLnNlbGVjdGVkSXRlbXMuY3VycmVudH0gb2YgJHt0aGlzLnNlbGVjdGVkSXRlbXMudG90YWx9IHNlbGVjdGVkYDtcbiAgICB9XG5cbiAgICBwdWJsaWMgZ2V0IG1lbnVUaXRsZSgpOiBzdHJpbmcge1xuICAgICAgICByZXR1cm4gdGhpcy5hbGxJdGVtc0hpZGRlbiA/IHRoaXMuY29tbWFuZHNUaXRsZSA6IHRoaXMubW9yZVRpdGxlO1xuICAgIH1cblxuICAgIHB1YmxpYyBnZXQgZGVzdHJ1Y3RpdmVJc0xhc3RJdGVtKCk6IGJvb2xlYW4ge1xuICAgICAgICByZXR1cm4gKFxuICAgICAgICAgICAgdGhpcy5ncm91cHMubGFzdC5pdGVtcy5sYXN0LmRpc3BsYXlTdHlsZSAhPT1cbiAgICAgICAgICAgIFRvb2xiYXJJdGVtRGlzcGxheVN0eWxlLmRlc3RydWN0aXZlXG4gICAgICAgICk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBzdWJzY3JpYmVUb1Rvb2xiYXJTdGVwc0NoYW5nZXMoKTogdm9pZCB7XG4gICAgICAgIHRoaXMudG9vbGJhckJ1dHRvbnMuY2hhbmdlc1xuICAgICAgICAgICAgLnBpcGUodGFrZVVudGlsKHRoaXMuZGVzdHJveSQpKVxuICAgICAgICAgICAgLnN1YnNjcmliZSgoYnV0dG9uczogUXVlcnlMaXN0PEJ1dHRvbkNvbXBvbmVudD4pID0+IHtcbiAgICAgICAgICAgICAgICB0aGlzLnRvb2xiYXJJdGVtcyA9IGJ1dHRvbnNcbiAgICAgICAgICAgICAgICAgICAgLnRvQXJyYXkoKVxuICAgICAgICAgICAgICAgICAgICAuc2xpY2UoKVxuICAgICAgICAgICAgICAgICAgICAubWFwKC