UNPKG

@clr/angular

Version:

Angular components for Clarity

359 lines 62.2 kB
/* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ import { isPlatformBrowser } from '@angular/common'; import { Component, ContentChild, EventEmitter, HostListener, Inject, Input, Optional, Output, PLATFORM_ID, Self, ViewChild, } from '@angular/core'; import { IF_ACTIVE_ID_PROVIDER } from '../../utils/conditional/if-active.service'; import { Keys } from '../../utils/enums/keys.enum'; import { FOCUS_SERVICE_PROVIDER } from '../../utils/focus/focus.service'; import { ClrLoadingState } from '../../utils/loading/loading'; import { LoadingListener } from '../../utils/loading/loading-listener'; import { ClrAlignment } from '../../utils/popover/enums/alignment.enum'; import { ClrAxis } from '../../utils/popover/enums/axis.enum'; import { ClrSide } from '../../utils/popover/enums/side.enum'; import { ClrPopoverHostDirective } from '../../utils/popover/popover-host.directive'; import { CONTROL_STATE } from '../common/if-control-state/if-control-state.service'; import { WrappedFormControl } from '../common/wrapped-control'; import { ClrComboboxContainer } from './combobox-container'; import { MultiSelectComboboxModel } from './model/multi-select-combobox.model'; import { SingleSelectComboboxModel } from './model/single-select-combobox.model'; import { ClrOptionSelected } from './option-selected.directive'; import { ClrOptions } from './options'; import { COMBOBOX_FOCUS_HANDLER_PROVIDER } from './providers/combobox-focus-handler.service'; import { OptionSelectionService } from './providers/option-selection.service'; import * as i0 from "@angular/core"; import * as i1 from "@angular/forms"; import * as i2 from "./providers/option-selection.service"; import * as i3 from "../../utils/i18n/common-strings.service"; import * as i4 from "../../utils/popover/providers/popover-toggle.service"; import * as i5 from "../../utils/popover/providers/popover-position.service"; import * as i6 from "../common/if-control-state/if-control-state.service"; import * as i7 from "./providers/combobox-container.service"; import * as i8 from "./providers/combobox-focus-handler.service"; import * as i9 from "../../utils/popover/popover-host.directive"; import * as i10 from "@angular/common"; import * as i11 from "../../icon/icon"; import * as i12 from "../../utils/focus/key-focus/roving-tabindex"; import * as i13 from "../../utils/focus/key-focus/key-focus-item"; import * as i14 from "../../utils/popover/popover-anchor"; import * as i15 from "../../utils/popover/popover-open-close-button"; import * as i16 from "../../utils/popover/popover-content"; export class ClrCombobox extends WrappedFormControl { constructor(vcr, injector, control, renderer, el, optionSelectionService, commonStrings, toggleService, positionService, controlStateService, containerService, platformId, focusHandler, cdr) { super(vcr, ClrComboboxContainer, injector, control, renderer, el); this.control = control; this.renderer = renderer; this.el = el; this.optionSelectionService = optionSelectionService; this.commonStrings = commonStrings; this.toggleService = toggleService; this.positionService = positionService; this.controlStateService = controlStateService; this.containerService = containerService; this.platformId = platformId; this.focusHandler = focusHandler; this.cdr = cdr; this.placeholder = ''; this.clrInputChange = new EventEmitter(false); this.clrOpenChange = this.toggleService.openChange; /** * This output should be used to set up a live region using aria-live and populate it with updates that reflect each combobox change. */ this.clrSelectionChange = this.optionSelectionService.selectionChanged; this.invalid = false; this.focused = false; this.smartPosition = { axis: ClrAxis.VERTICAL, side: ClrSide.AFTER, anchor: ClrAlignment.START, content: ClrAlignment.START, }; this.index = 1; this._searchText = ''; if (control) { control.valueAccessor = this; } // default to SingleSelectComboboxModel, in case the optional input [ClrMulti] isn't used this.optionSelectionService.selectionModel = new SingleSelectComboboxModel(); this.updateControlValue(); } get multiSelect() { return this.optionSelectionService.multiselectable; } set multiSelect(value) { if (value) { this.optionSelectionService.selectionModel = new MultiSelectComboboxModel(); } else { // in theory, setting this again should not cause errors even though we already set it in constructor, // since the initial call to writeValue (caused by [ngModel] input) should happen after this this.optionSelectionService.selectionModel = new SingleSelectComboboxModel(); } this.updateControlValue(); } // Override the id of WrappedFormControl, as we want to move it to the embedded input. // Otherwise the label/component connection does not work and screen readers do not read the label. get id() { return this.controlIdService.id + '-combobox'; } set id(id) { super.id = id; } get searchText() { return this._searchText; } set searchText(text) { // if input text has changed since last time, fire a change event so application can react to it if (text !== this._searchText) { if (this.toggleService.open) { this.optionSelectionService.showAllOptions = false; } this._searchText = text; this.clrInputChange.emit(this.searchText); } // We need to trigger this even if unchanged, so the option-items directive will update its list // based on the "showAllOptions" variable which may have changed in the openChange subscription below. // The option-items directive does not listen to openChange, but it listens to currentInput changes. this.optionSelectionService.currentInput = this.searchText; } get openState() { return this.toggleService.open; } get multiSelectModel() { if (!this.multiSelect) { throw Error('multiSelectModel is not available in single selection context'); } return this.optionSelectionService.selectionModel.model; } get ariaControls() { return this.options?.optionsId; } get ariaOwns() { return this.options?.optionsId; } get ariaDescribedBySelection() { return 'selection-' + this.id; } get displayField() { return this.optionSelectionService.displayField; } get disabled() { return this.control && this.control.disabled; } ngAfterContentInit() { this.initializeSubscriptions(); // Initialize with preselected value if (!this.optionSelectionService.selectionModel.isEmpty()) { this.updateInputValue(this.optionSelectionService.selectionModel); } } ngAfterViewInit() { this.focusHandler.componentCdRef = this.cdr; this.focusHandler.textInput = this.textbox.nativeElement; this.focusHandler.trigger = this.trigger.nativeElement; // The text input is the actual element we are wrapping // This assignment is needed by the wrapper, so it can set // the aria properties on the input element, not on the component. this.el = this.textbox; } onKeyUp(event) { // if BACKSPACE in multiselect mode, delete the last pill if text is empty if (event.key === Keys.Backspace && this.multiSelect && this._searchText.length === 0) { const multiModel = this.optionSelectionService.selectionModel.model; if (multiModel && multiModel.length > 0) { const lastItem = multiModel[multiModel.length - 1]; this.control.control.markAsTouched(); this.optionSelectionService.unselect(lastItem); } } } inputId() { return this.controlIdService.id; } loadingStateChange(state) { this.optionSelectionService.loading = state === ClrLoadingState.LOADING; this.positionService.realign(); if (state !== ClrLoadingState.LOADING && isPlatformBrowser(this.platformId)) { this.focusFirstActive(); } } unselect(item) { if (!this.disabled) { this.optionSelectionService.unselect(item); } } onBlur() { this.onTouchedCallback(); if (this.control.control.updateOn === 'blur') { this.control.control.updateValueAndValidity(); } this.focused = false; } onFocus() { this.focused = true; // fix for "expression changed" error when focus is returned to a combobox after a modal is closed // https://github.com/vmware-clarity/ng-clarity/issues/663 this.cdr.detectChanges(); } getSelectionAriaLabel() { if (this.containerService && this.containerService.labelText) { return `${this.containerService.labelText} ${this.commonStrings.keys.comboboxSelection}`; } return this.commonStrings.keys.comboboxSelection; } focusFirstActive() { setTimeout(() => { this.focusHandler.focusFirstActive(); }); } writeValue(value) { this.optionSelectionService.selectionModel.model = value; this.updateInputValue(this.optionSelectionService.selectionModel); } registerOnTouched(onTouched) { this.onTouchedCallback = onTouched; } registerOnChange(onChange) { this.onChangeCallback = onChange; } getActiveDescendant() { const model = this.focusHandler.pseudoFocus.model; return model ? model.id : null; } setDisabledState() { // do nothing } focusInput() { this.focusHandler.focusInput(); } initializeSubscriptions() { this.subscriptions.push(this.optionSelectionService.selectionChanged.subscribe((newSelection) => { this.updateInputValue(newSelection); if (this.multiSelect) { this.positionService.realign(); } if (!this.multiSelect && newSelection && !newSelection.isEmpty()) { this.toggleService.open = false; } this.updateControlValue(); })); this.subscriptions.push(this.toggleService.openChange.subscribe(open => { if (open) { this.focusFirstActive(); } else { this.optionSelectionService.showAllOptions = true; } if (this.multiSelect) { this.searchText = ''; } else { this.searchText = this.getDisplayNames(this.optionSelectionService.selectionModel.model)[0] || ''; } })); this.subscriptions.push(this.toggleService.popoverAligned.subscribe(popoverNode => { // When used outside a combobox container if (!this.containerService) { return; } const popover = popoverNode; // Update position if popover hides the label if (popover.getBoundingClientRect().top < this.el.nativeElement.getBoundingClientRect().top) { this.renderer.setStyle(popoverNode, 'top', `${popover.offsetTop + this.containerService.labelOffset}px`); } })); if (this.controlStateService) { this.subscriptions.push(this.controlStateService.statusChanges.subscribe(invalid => { this.invalid = invalid === CONTROL_STATE.INVALID; })); } } updateInputValue(model) { if (!this.multiSelect) { this.searchText = model.model ? this.getDisplayNames(model.model)[0] : ''; if (this.searchText) { this.optionSelectionService.currentInput = this.searchText; } } } updateControlValue() { if (this.onChangeCallback) { this.onChangeCallback(this.optionSelectionService.selectionModel.model); } } getDisplayNames(model) { if (this.displayField) { if (!Array.isArray(model)) { model = [model]; } return model.map(item => (item ? item[this.displayField] : null)); } return [this.optionSelectionService.selectionModel.model]; } } ClrCombobox.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrCombobox, deps: [{ token: i0.ViewContainerRef }, { token: i0.Injector }, { token: i1.NgControl, optional: true, self: true }, { token: i0.Renderer2 }, { token: i0.ElementRef }, { token: i2.OptionSelectionService }, { token: i3.ClrCommonStringsService }, { token: i4.ClrPopoverToggleService }, { token: i5.ClrPopoverPositionService }, { token: i6.IfControlStateService, optional: true }, { token: i7.ComboboxContainerService, optional: true }, { token: PLATFORM_ID }, { token: i8.ComboboxFocusHandler }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); ClrCombobox.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrCombobox, selector: "clr-combobox", inputs: { placeholder: "placeholder", multiSelect: ["clrMulti", "multiSelect"] }, outputs: { clrInputChange: "clrInputChange", clrOpenChange: "clrOpenChange", clrSelectionChange: "clrSelectionChange" }, host: { listeners: { "keydown": "onKeyUp($event)" }, properties: { "class.aria-required": "true", "class.clr-combobox": "true", "class.clr-combobox-disabled": "control?.disabled" } }, providers: [ OptionSelectionService, { provide: LoadingListener, useExisting: ClrCombobox }, IF_ACTIVE_ID_PROVIDER, FOCUS_SERVICE_PROVIDER, COMBOBOX_FOCUS_HANDLER_PROVIDER, ], queries: [{ propertyName: "optionSelected", first: true, predicate: ClrOptionSelected, descendants: true }, { propertyName: "options", first: true, predicate: ClrOptions, descendants: true }], viewQueries: [{ propertyName: "textbox", first: true, predicate: ["textboxInput"], descendants: true }, { propertyName: "trigger", first: true, predicate: ["trigger"], descendants: true }], usesInheritance: true, hostDirectives: [{ directive: i9.ClrPopoverHostDirective }], ngImport: i0, template: "<!--\n* Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved.\n* This software is released under MIT license.\n* The full license information can be found in LICENSE in the root directory of this project.\n-->\n\n<!-- The (click) handler is needed to auto-focus on input field which can not currently occupy the whole\n width of the component, after being wrapped to a new line -->\n<div\n class=\"clr-combobox-wrapper\"\n clrPopoverAnchor\n (click)=\"focusInput()\"\n [class.multi]=\"multiSelect\"\n [class.invalid]=\"invalid\"\n [class.disabled]=\"control?.disabled? true: null\"\n>\n <span\n *ngIf=\"multiSelect && optionSelectionService.selectionModel.model\"\n role=\"grid\"\n clrRovingTabindex\n [clrRovingTabindexDisabled]=\"control?.disabled\"\n clrDirection=\"both\"\n [attr.aria-label]=\"getSelectionAriaLabel()\"\n [attr.aria-disabled]=\"control?.disabled? true: null\"\n >\n <span *ngFor=\"let item of multiSelectModel; let i = index\" class=\"label label-combobox-pill\" role=\"row\">\n <span role=\"gridcell\">\n <span class=\"clr-combobox-pill-content\" clrKeyFocusItem>\n <ng-container\n *ngIf=\"optionSelected\"\n [ngTemplateOutlet]=\"optionSelected.template\"\n [ngTemplateOutletContext]=\"{$implicit: optionSelectionService.selectionModel.model[i]}\"\n ></ng-container>\n </span>\n </span>\n <span role=\"gridcell\">\n <button\n clrKeyFocusItem\n type=\"button\"\n class=\"clr-combobox-remove-btn\"\n [disabled]=\"control?.disabled? true: null\"\n [attr.aria-label]=\"commonStrings.keys.comboboxDelete + ' ' + optionSelectionService.selectionModel.toString(displayField, i)\"\n (click)=\"unselect(item)\"\n >\n <cds-icon shape=\"window-close\" size=\"12\"></cds-icon>\n </button>\n </span>\n </span>\n </span>\n\n <span class=\"clr-combobox-input-wrapper\">\n <input\n #textboxInput\n type=\"text\"\n role=\"combobox\"\n [id]=\"inputId()\"\n class=\"clr-input clr-combobox-input\"\n [(ngModel)]=\"searchText\"\n (blur)=\"onBlur()\"\n (focus)=\"onFocus()\"\n [attr.aria-expanded]=\"openState\"\n [attr.aria-owns]=\"ariaOwns\"\n aria-haspopup=\"listbox\"\n aria-autocomplete=\"list\"\n autocomplete=\"off\"\n [attr.aria-invalid]=\"control?.invalid? true: null\"\n [disabled]=\"control?.disabled? true: null\"\n [attr.aria-activedescendant]=\"getActiveDescendant()\"\n [attr.placeholder]=\"placeholder\"\n />\n </span>\n\n <!-- No click handler, as it uses the handler on the .clr-combobox-wrapper -->\n <button\n clrPopoverOpenCloseButton\n #trigger\n type=\"button\"\n class=\"clr-combobox-trigger\"\n tabindex=\"-1\"\n [disabled]=\"control?.disabled || null\"\n [attr.aria-label]=\"commonStrings.keys.comboboxOpen\"\n >\n <cds-icon shape=\"angle\" direction=\"down\"></cds-icon>\n </button>\n\n <div class=\"clr-focus-indicator\" [class.clr-focus]=\"focused\"></div>\n</div>\n\n<!-- Both close handlers are handled manually due to issues in Edge browser.\n Additionally 'outsideClickToClose' has complex handling that's necessary\n to be manual due to the component architecture -->\n<div role=\"dialog\" *clrPopoverContent=\"openState at smartPosition; outsideClickToClose: false; scrollToClose: false\">\n <ng-content></ng-content>\n</div>\n", dependencies: [{ kind: "directive", type: i10.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i10.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i1.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: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i11.CdsIconCustomTag, selector: "cds-icon" }, { kind: "component", type: i12.ClrRovingTabindex, selector: "[clrRovingTabindex]", inputs: ["clrRovingTabindex", "clrRovingTabindexDisabled"] }, { kind: "directive", type: i13.ClrKeyFocusItem, selector: "[clrKeyFocusItem]" }, { kind: "directive", type: i14.ClrPopoverAnchor, selector: "[clrPopoverAnchor]" }, { kind: "directive", type: i15.ClrPopoverOpenCloseButton, selector: "[clrPopoverOpenCloseButton]", outputs: ["clrPopoverOpenCloseChange"] }, { kind: "directive", type: i16.ClrPopoverContent, selector: "[clrPopoverContent]", inputs: ["clrPopoverContent", "clrPopoverContentAt", "clrPopoverContentOutsideClickToClose", "clrPopoverContentScrollToClose"] }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrCombobox, decorators: [{ type: Component, args: [{ selector: 'clr-combobox', providers: [ OptionSelectionService, { provide: LoadingListener, useExisting: ClrCombobox }, IF_ACTIVE_ID_PROVIDER, FOCUS_SERVICE_PROVIDER, COMBOBOX_FOCUS_HANDLER_PROVIDER, ], hostDirectives: [ClrPopoverHostDirective], host: { '[class.aria-required]': 'true', '[class.clr-combobox]': 'true', '[class.clr-combobox-disabled]': 'control?.disabled', }, template: "<!--\n* Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved.\n* This software is released under MIT license.\n* The full license information can be found in LICENSE in the root directory of this project.\n-->\n\n<!-- The (click) handler is needed to auto-focus on input field which can not currently occupy the whole\n width of the component, after being wrapped to a new line -->\n<div\n class=\"clr-combobox-wrapper\"\n clrPopoverAnchor\n (click)=\"focusInput()\"\n [class.multi]=\"multiSelect\"\n [class.invalid]=\"invalid\"\n [class.disabled]=\"control?.disabled? true: null\"\n>\n <span\n *ngIf=\"multiSelect && optionSelectionService.selectionModel.model\"\n role=\"grid\"\n clrRovingTabindex\n [clrRovingTabindexDisabled]=\"control?.disabled\"\n clrDirection=\"both\"\n [attr.aria-label]=\"getSelectionAriaLabel()\"\n [attr.aria-disabled]=\"control?.disabled? true: null\"\n >\n <span *ngFor=\"let item of multiSelectModel; let i = index\" class=\"label label-combobox-pill\" role=\"row\">\n <span role=\"gridcell\">\n <span class=\"clr-combobox-pill-content\" clrKeyFocusItem>\n <ng-container\n *ngIf=\"optionSelected\"\n [ngTemplateOutlet]=\"optionSelected.template\"\n [ngTemplateOutletContext]=\"{$implicit: optionSelectionService.selectionModel.model[i]}\"\n ></ng-container>\n </span>\n </span>\n <span role=\"gridcell\">\n <button\n clrKeyFocusItem\n type=\"button\"\n class=\"clr-combobox-remove-btn\"\n [disabled]=\"control?.disabled? true: null\"\n [attr.aria-label]=\"commonStrings.keys.comboboxDelete + ' ' + optionSelectionService.selectionModel.toString(displayField, i)\"\n (click)=\"unselect(item)\"\n >\n <cds-icon shape=\"window-close\" size=\"12\"></cds-icon>\n </button>\n </span>\n </span>\n </span>\n\n <span class=\"clr-combobox-input-wrapper\">\n <input\n #textboxInput\n type=\"text\"\n role=\"combobox\"\n [id]=\"inputId()\"\n class=\"clr-input clr-combobox-input\"\n [(ngModel)]=\"searchText\"\n (blur)=\"onBlur()\"\n (focus)=\"onFocus()\"\n [attr.aria-expanded]=\"openState\"\n [attr.aria-owns]=\"ariaOwns\"\n aria-haspopup=\"listbox\"\n aria-autocomplete=\"list\"\n autocomplete=\"off\"\n [attr.aria-invalid]=\"control?.invalid? true: null\"\n [disabled]=\"control?.disabled? true: null\"\n [attr.aria-activedescendant]=\"getActiveDescendant()\"\n [attr.placeholder]=\"placeholder\"\n />\n </span>\n\n <!-- No click handler, as it uses the handler on the .clr-combobox-wrapper -->\n <button\n clrPopoverOpenCloseButton\n #trigger\n type=\"button\"\n class=\"clr-combobox-trigger\"\n tabindex=\"-1\"\n [disabled]=\"control?.disabled || null\"\n [attr.aria-label]=\"commonStrings.keys.comboboxOpen\"\n >\n <cds-icon shape=\"angle\" direction=\"down\"></cds-icon>\n </button>\n\n <div class=\"clr-focus-indicator\" [class.clr-focus]=\"focused\"></div>\n</div>\n\n<!-- Both close handlers are handled manually due to issues in Edge browser.\n Additionally 'outsideClickToClose' has complex handling that's necessary\n to be manual due to the component architecture -->\n<div role=\"dialog\" *clrPopoverContent=\"openState at smartPosition; outsideClickToClose: false; scrollToClose: false\">\n <ng-content></ng-content>\n</div>\n" }] }], ctorParameters: function () { return [{ type: i0.ViewContainerRef }, { type: i0.Injector }, { type: i1.NgControl, decorators: [{ type: Self }, { type: Optional }] }, { type: i0.Renderer2 }, { type: i0.ElementRef }, { type: i2.OptionSelectionService }, { type: i3.ClrCommonStringsService }, { type: i4.ClrPopoverToggleService }, { type: i5.ClrPopoverPositionService }, { type: i6.IfControlStateService, decorators: [{ type: Optional }] }, { type: i7.ComboboxContainerService, decorators: [{ type: Optional }] }, { type: undefined, decorators: [{ type: Inject, args: [PLATFORM_ID] }] }, { type: i8.ComboboxFocusHandler }, { type: i0.ChangeDetectorRef }]; }, propDecorators: { placeholder: [{ type: Input, args: ['placeholder'] }], clrInputChange: [{ type: Output, args: ['clrInputChange'] }], clrOpenChange: [{ type: Output, args: ['clrOpenChange'] }], clrSelectionChange: [{ type: Output, args: ['clrSelectionChange'] }], textbox: [{ type: ViewChild, args: ['textboxInput'] }], trigger: [{ type: ViewChild, args: ['trigger'] }], optionSelected: [{ type: ContentChild, args: [ClrOptionSelected] }], options: [{ type: ContentChild, args: [ClrOptions] }], multiSelect: [{ type: Input, args: ['clrMulti'] }], onKeyUp: [{ type: HostListener, args: ['keydown', ['$event']] }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29tYm9ib3guanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9hbmd1bGFyL3NyYy9mb3Jtcy9jb21ib2JveC9jb21ib2JveC50cyIsIi4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL2FuZ3VsYXIvc3JjL2Zvcm1zL2NvbWJvYm94L2NvbWJvYm94Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7R0FJRztBQUVILE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQ3BELE9BQU8sRUFHTCxTQUFTLEVBQ1QsWUFBWSxFQUVaLFlBQVksRUFDWixZQUFZLEVBQ1osTUFBTSxFQUVOLEtBQUssRUFDTCxRQUFRLEVBQ1IsTUFBTSxFQUNOLFdBQVcsRUFFWCxJQUFJLEVBQ0osU0FBUyxHQUVWLE1BQU0sZUFBZSxDQUFDO0FBR3ZCLE9BQU8sRUFBRSxxQkFBcUIsRUFBRSxNQUFNLDJDQUEyQyxDQUFDO0FBQ2xGLE9BQU8sRUFBRSxJQUFJLEVBQUUsTUFBTSw2QkFBNkIsQ0FBQztBQUNuRCxPQUFPLEVBQUUsc0JBQXNCLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQztBQUV6RSxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sNkJBQTZCLENBQUM7QUFDOUQsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLHNDQUFzQyxDQUFDO0FBQ3ZFLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSwwQ0FBMEMsQ0FBQztBQUN4RSxPQUFPLEVBQUUsT0FBTyxFQUFFLE1BQU0scUNBQXFDLENBQUM7QUFDOUQsT0FBTyxFQUFFLE9BQU8sRUFBRSxNQUFNLHFDQUFxQyxDQUFDO0FBRTlELE9BQU8sRUFBRSx1QkFBdUIsRUFBRSxNQUFNLDRDQUE0QyxDQUFDO0FBR3JGLE9BQU8sRUFBRSxhQUFhLEVBQXlCLE1BQU0scURBQXFELENBQUM7QUFDM0csT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sMkJBQTJCLENBQUM7QUFD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KGMpIDIwMTYtMjAyMyBWTXdhcmUsIEluYy4gQWxsIFJpZ2h0cyBSZXNlcnZlZC5cbiAqIFRoaXMgc29mdHdhcmUgaXMgcmVsZWFzZWQgdW5kZXIgTUlUIGxpY2Vuc2UuXG4gKiBUaGUgZnVsbCBsaWNlbnNlIGluZm9ybWF0aW9uIGNhbiBiZSBmb3VuZCBpbiBMSUNFTlNFIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHByb2plY3QuXG4gKi9cblxuaW1wb3J0IHsgaXNQbGF0Zm9ybUJyb3dzZXIgfSBmcm9tICdAYW5ndWxhci9jb21tb24nO1xuaW1wb3J0IHtcbiAgQWZ0ZXJDb250ZW50SW5pdCxcbiAgQ2hhbmdlRGV0ZWN0b3JSZWYsXG4gIENvbXBvbmVudCxcbiAgQ29udGVudENoaWxkLFxuICBFbGVtZW50UmVmLFxuICBFdmVudEVtaXR0ZXIsXG4gIEhvc3RMaXN0ZW5lcixcbiAgSW5qZWN0LFxuICBJbmplY3RvcixcbiAgSW5wdXQsXG4gIE9wdGlvbmFsLFxuICBPdXRwdXQsXG4gIFBMQVRGT1JNX0lELFxuICBSZW5kZXJlcjIsXG4gIFNlbGYsXG4gIFZpZXdDaGlsZCxcbiAgVmlld0NvbnRhaW5lclJlZixcbn0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBDb250cm9sVmFsdWVBY2Nlc3NvciwgTmdDb250cm9sIH0gZnJvbSAnQGFuZ3VsYXIvZm9ybXMnO1xuXG5pbXBvcnQgeyBJRl9BQ1RJVkVfSURfUFJPVklERVIgfSBmcm9tICcuLi8uLi91dGlscy9jb25kaXRpb25hbC9pZi1hY3RpdmUuc2VydmljZSc7XG5pbXBvcnQgeyBLZXlzIH0gZnJvbSAnLi4vLi4vdXRpbHMvZW51bXMva2V5cy5lbnVtJztcbmltcG9ydCB7IEZPQ1VTX1NFUlZJQ0VfUFJPVklERVIgfSBmcm9tICcuLi8uLi91dGlscy9mb2N1cy9mb2N1cy5zZXJ2aWNlJztcbmltcG9ydCB7IENsckNvbW1vblN0cmluZ3NTZXJ2aWNlIH0gZnJvbSAnLi4vLi4vdXRpbHMvaTE4bi9jb21tb24tc3RyaW5ncy5zZXJ2aWNlJztcbmltcG9ydCB7IENsckxvYWRpbmdTdGF0ZSB9IGZyb20gJy4uLy4uL3V0aWxzL2xvYWRpbmcvbG9hZGluZyc7XG5pbXBvcnQgeyBMb2FkaW5nTGlzdGVuZXIgfSBmcm9tICcuLi8uLi91dGlscy9sb2FkaW5nL2xvYWRpbmctbGlzdGVuZXInO1xuaW1wb3J0IHsgQ2xyQWxpZ25tZW50IH0gZnJvbSAnLi4vLi4vdXRpbHMvcG9wb3Zlci9lbnVtcy9hbGlnbm1lbnQuZW51bSc7XG5pbXBvcnQgeyBDbHJBeGlzIH0gZnJvbSAnLi4vLi4vdXRpbHMvcG9wb3Zlci9lbnVtcy9heGlzLmVudW0nO1xuaW1wb3J0IHsgQ2xyU2lkZSB9IGZyb20gJy4uLy4uL3V0aWxzL3BvcG92ZXIvZW51bXMvc2lkZS5lbnVtJztcbmltcG9ydCB7IENsclBvcG92ZXJQb3NpdGlvbiB9IGZyb20gJy4uLy4uL3V0aWxzL3BvcG92ZXIvaW50ZXJmYWNlcy9wb3BvdmVyLXBvc2l0aW9uLmludGVyZmFjZSc7XG5pbXBvcnQgeyBDbHJQb3BvdmVySG9zdERpcmVjdGl2ZSB9IGZyb20gJy4uLy4uL3V0aWxzL3BvcG92ZXIvcG9wb3Zlci1ob3N0LmRpcmVjdGl2ZSc7XG5pbXBvcnQgeyBDbHJQb3BvdmVyUG9zaXRpb25TZXJ2aWNlIH0gZnJvbSAnLi4vLi4vdXRpbHMvcG9wb3Zlci9wcm92aWRlcnMvcG9wb3Zlci1wb3NpdGlvbi5zZXJ2aWNlJztcbmltcG9ydCB7IENsclBvcG92ZXJUb2dnbGVTZXJ2aWNlIH0gZnJvbSAnLi4vLi4vdXRpbHMvcG9wb3Zlci9wcm92aWRlcnMvcG9wb3Zlci10b2dnbGUuc2VydmljZSc7XG5pbXBvcnQgeyBDT05UUk9MX1NUQVRFLCBJZkNvbnRyb2xTdGF0ZVNlcnZpY2UgfSBmcm9tICcuLi9jb21tb24vaWYtY29udHJvbC1zdGF0ZS9pZi1jb250cm9sLXN0YXRlLnNlcnZpY2UnO1xuaW1wb3J0IHsgV3JhcHBlZEZvcm1Db250cm9sIH0gZnJvbSAnLi4vY29tbW9uL3dyYXBwZWQtY29udHJvbCc7XG5pbXBvcnQgeyBDbHJDb21ib2JveENvbnRhaW5lciB9IGZyb20gJy4vY29tYm9ib3gtY29udGFpbmVyJztcbmltcG9ydCB7IENvbWJvYm94TW9kZWwgfSBmcm9tICcuL21vZGVsL2NvbWJvYm94Lm1vZGVsJztcbmltcG9ydCB7IE11bHRpU2VsZWN0Q29tYm9ib3hNb2RlbCB9IGZyb20gJy4vbW9kZWwvbXVsdGktc2VsZWN0LWNvbWJvYm94Lm1vZGVsJztcbmltcG9ydCB7IFNpbmdsZVNlbGVjdENvbWJvYm94TW9kZWwgfSBmcm9tICcuL21vZGVsL3NpbmdsZS1zZWxlY3QtY29tYm9ib3gubW9kZWwnO1xuaW1wb3J0IHsgQ2xyT3B0aW9uU2VsZWN0ZWQgfSBmcm9tICcuL29wdGlvbi1zZWxlY3RlZC5kaXJlY3RpdmUnO1xuaW1wb3J0IHsgQ2xyT3B0aW9ucyB9IGZyb20gJy4vb3B0aW9ucyc7XG5pbXBvcnQgeyBDb21ib2JveENvbnRhaW5lclNlcnZpY2UgfSBmcm9tICcuL3Byb3ZpZGVycy9jb21ib2JveC1jb250YWluZXIuc2VydmljZSc7XG5pbXBvcnQgeyBDT01CT0JPWF9GT0NVU19IQU5ETEVSX1BST1ZJREVSLCBDb21ib2JveEZvY3VzSGFuZGxlciB9IGZyb20gJy4vcHJvdmlkZXJzL2NvbWJvYm94LWZvY3VzLWhhbmRsZXIuc2VydmljZSc7XG5pbXBvcnQgeyBPcHRpb25TZWxlY3Rpb25TZXJ2aWNlIH0gZnJvbSAnLi9wcm92aWRlcnMvb3B0aW9uLXNlbGVjdGlvbi5zZXJ2aWNlJztcblxuQENvbXBvbmVudCh7XG4gIHNlbGVjdG9yOiAnY2xyLWNvbWJvYm94JyxcbiAgdGVtcGxhdGVVcmw6ICcuL2NvbWJvYm94Lmh0bWwnLFxuICBwcm92aWRlcnM6IFtcbiAgICBPcHRpb25TZWxlY3Rpb25TZXJ2aWNlLFxuICAgIHsgcHJvdmlkZTogTG9hZGluZ0xpc3RlbmVyLCB1c2VFeGlzdGluZzogQ2xyQ29tYm9ib3ggfSxcbiAgICBJRl9BQ1RJVkVfSURfUFJPVklERVIsXG4gICAgRk9DVVNfU0VSVklDRV9QUk9WSURFUixcbiAgICBDT01CT0JPWF9GT0NVU19IQU5ETEVSX1BST1ZJREVSLFxuICBdLFxuICBob3N0RGlyZWN0aXZlczogW0NsclBvcG92ZXJIb3N0RGlyZWN0aXZlXSxcbiAgaG9zdDoge1xuICAgICdbY2xhc3MuYXJpYS1yZXF1aXJlZF0nOiAndHJ1ZScsXG4gICAgJ1tjbGFzcy5jbHItY29tYm9ib3hdJzogJ3RydWUnLFxuICAgICdbY2xhc3MuY2xyLWNvbWJvYm94LWRpc2FibGVkXSc6ICdjb250cm9sPy5kaXNhYmxlZCcsXG4gIH0sXG59KVxuZXhwb3J0IGNsYXNzIENsckNvbWJvYm94PFQ+XG4gIGV4dGVuZHMgV3JhcHBlZEZvcm1Db250cm9sPENsckNvbWJvYm94Q29udGFpbmVyPlxuICBpbXBsZW1lbnRzIENvbnRyb2xWYWx1ZUFjY2Vzc29yLCBMb2FkaW5nTGlzdGVuZXIsIEFmdGVyQ29udGVudEluaXRcbntcbiAgQElucHV0KCdwbGFjZWhvbGRlcicpIHBsYWNlaG9sZGVyID0gJyc7XG5cbiAgQE91dHB1dCgnY2xySW5wdXRDaGFuZ2UnKSBjbHJJbnB1dENoYW5nZSA9IG5ldyBFdmVudEVtaXR0ZXI8c3RyaW5nPihmYWxzZSk7XG4gIEBPdXRwdXQoJ2Nsck9wZW5DaGFuZ2UnKSBjbHJPcGVuQ2hhbmdlID0gdGhpcy50b2dnbGVTZXJ2aWNlLm9wZW5DaGFuZ2U7XG5cbiAgLyoqXG4gICAqIFRoaXMgb3V0cHV0IHNob3VsZCBiZSB1c2VkIHRvIHNldCB1cCBhIGxpdmUgcmVnaW9uIHVzaW5nIGFyaWEtbGl2ZSBhbmQgcG9wdWxhdGUgaXQgd2l0aCB1cGRhdGVzIHRoYXQgcmVmbGVjdCBlYWNoIGNvbWJvYm94IGNoYW5nZS5cbiAgICovXG4gIEBPdXRwdXQoJ2NsclNlbGVjdGlvbkNoYW5nZScpIGNsclNlbGVjdGlvbkNoYW5nZSA9IHRoaXMub3B0aW9uU2VsZWN0aW9uU2VydmljZS5zZWxlY3Rpb25DaGFuZ2VkO1xuXG4gIEBWaWV3Q2hpbGQoJ3RleHRib3hJbnB1dCcpIHRleHRib3g6IEVsZW1lbnRSZWY7XG4gIEBWaWV3Q2hpbGQoJ3RyaWdnZXInKSB0cmlnZ2VyOiBFbGVtZW50UmVmO1xuICBAQ29udGVudENoaWxkKENsck9wdGlvblNlbGVjdGVkKSBvcHRpb25TZWxlY3RlZDogQ2xyT3B0aW9uU2VsZWN0ZWQ8VD47XG5cbiAgaW52YWxpZCA9IGZhbHNlO1xuICBmb2N1c2VkID0gZmFsc2U7XG4gIGZvY3VzZWRQaWxsOiBhbnk7XG5cbiAgc21hcnRQb3NpdGlvbjogQ2xyUG9wb3ZlclBvc2l0aW9uID0ge1xuICAgIGF4aXM6IENsckF4aXMuVkVSVElDQUwsXG4gICAgc2lkZTogQ2xyU2lkZS5BRlRFUixcbiAgICBhbmNob3I6IENsckFsaWdubWVudC5TVEFSVCxcbiAgICBjb250ZW50OiBDbHJBbGlnbm1lbnQuU1RBUlQsXG4gIH07XG5cbiAgcHJvdGVjdGVkIG92ZXJyaWRlIGluZGV4ID0gMTtcblxuICBAQ29udGVudENoaWxkKENsck9wdGlvbnMpIHByaXZhdGUgb3B0aW9uczogQ2xyT3B0aW9uczxUPjtcblxuICBwcml2YXRlIF9zZWFyY2hUZXh0ID0gJyc7XG4gIHByaXZhdGUgb25Ub3VjaGVkQ2FsbGJhY2s6ICgpID0+IGFueTtcbiAgcHJpdmF0ZSBvbkNoYW5nZUNhbGxiYWNrOiAobW9kZWw6IFQgfCBUW10pID0+IGFueTtcblxuICBjb25zdHJ1Y3RvcihcbiAgICB2Y3I6IFZpZXdDb250YWluZXJSZWYsXG4gICAgaW5qZWN0b3I6IEluamVjdG9yLFxuICAgIEBTZWxmKClcbiAgICBAT3B0aW9uYWwoKVxuICAgIHB1YmxpYyBjb250cm9sOiBOZ0NvbnRyb2wsXG4gICAgcHJvdGVjdGVkIG92ZXJyaWRlIHJlbmRlcmVyOiBSZW5kZXJlcjIsXG4gICAgcHJvdGVjdGVkIG92ZXJyaWRlIGVsOiBFbGVtZW50UmVmLFxuICAgIHB1YmxpYyBvcHRpb25TZWxlY3Rpb25TZXJ2aWNlOiBPcHRpb25TZWxlY3Rpb25TZXJ2aWNlPFQ+LFxuICAgIHB1YmxpYyBjb21tb25TdHJpbmdzOiBDbHJDb21tb25TdHJpbmdzU2VydmljZSxcbiAgICBwcml2YXRlIHRvZ2dsZVNlcnZpY2U6IENsclBvcG92ZXJUb2dnbGVTZXJ2aWNlLFxuICAgIHByaXZhdGUgcG9zaXRpb25TZXJ2aWNlOiBDbHJQb3BvdmVyUG9zaXRpb25TZXJ2aWNlLFxuICAgIEBPcHRpb25hbCgpIHByaXZhdGUgY29udHJvbFN0YXRlU2VydmljZTogSWZDb250cm9sU3RhdGVTZXJ2aWNlLFxuICAgIEBPcHRpb25hbCgpIHByaXZhdGUgY29udGFpbmVyU2VydmljZTogQ29tYm9ib3hDb250YWluZXJTZXJ2aWNlLFxuICAgIEBJbmplY3QoUExBVEZPUk1fSUQpIHByaXZhdGUgcGxhdGZvcm1JZDogYW55LFxuICAgIHByaXZhdGUgZm9jdXNIYW5kbGVyOiBDb21ib2JveEZvY3VzSGFuZGxlcjxUPixcbiAgICBwcml2YXRlIGNkcjogQ2hhbmdlRGV0ZWN0b3JSZWZcbiAgKSB7XG4gICAgc3VwZXIodmNyLCBDbHJDb21ib2JveENvbnRhaW5lciwgaW5qZWN0b3IsIGNvbnRyb2wsIHJlbmRlcmVyLCBlbCk7XG4gICAgaWYgKGNvbnRyb2wpIHtcbiAgICAgIGNvbnRyb2wudmFsdWVBY2Nlc3NvciA9IHRoaXM7XG4gICAgfVxuICAgIC8vIGRlZmF1bHQgdG8gU2luZ2xlU2VsZWN0Q29tYm9ib3hNb2RlbCwgaW4gY2FzZSB0aGUgb3B0aW9uYWwgaW5wdXQgW0Nsck11bHRpXSBpc24ndCB1c2VkXG4gICAgdGhpcy5vcHRpb25TZWxlY3Rpb25TZXJ2aWNlLnNlbGVjdGlvbk1vZGVsID0gbmV3IFNpbmdsZVNlbGVjdENvbWJvYm94TW9kZWw8VD4oKTtcbiAgICB0aGlzLnVwZGF0ZUNvbnRyb2xWYWx1ZSgpO1xuICB9XG5cbiAgQElucHV0KCdjbHJNdWx0aScpXG4gIGdldCBtdWx0aVNlbGVjdCgpIHtcbiAgICByZXR1cm4gdGhpcy5vcHRpb25TZWxlY3Rpb25TZXJ2aWNlLm11bHRpc2VsZWN0YWJsZTtcbiAgfVxuICBzZXQgbXVsdGlTZWxlY3QodmFsdWU6IGJvb2xlYW4gfCBzdHJpbmcpIHtcbiAgICBpZiAodmFsdWUpIHtcbiAgICAgIHRoaXMub3B0aW9uU2VsZWN0aW9uU2VydmljZS5zZWxlY3Rpb25Nb2RlbCA9IG5ldyBNdWx0aVNlbGVjdENvbWJvYm94TW9kZWw8VD4oKTtcbiAgICB9IGVsc2Uge1xuICAgICAgLy8gaW4gdGhlb3J5LCBzZXR0aW5nIHRoaXMgYWdhaW4gc2hvdWxkIG5vdCBjYXVzZSBlcnJvcnMgZXZlbiB0aG91Z2ggd2UgYWxyZWFkeSBzZXQgaXQgaW4gY29uc3RydWN0b3IsXG4gICAgICAvLyBzaW5jZSB0aGUgaW5pdGlhbCBjYWxsIHRvIHdyaXRlVmFsdWUgKGNhdXNlZCBieSBbbmdNb2RlbF0gaW5wdXQpIHNob3VsZCBoYXBwZW4gYWZ0ZXIgdGhpc1xuICAgICAgdGhpcy5vcHRpb25TZWxlY3Rpb25TZXJ2aWNlLnNlbGVjdGlvbk1vZGVsID0gbmV3IFNpbmdsZVNlbGVjdENvbWJvYm94TW9kZWw8VD4oKTtcbiAgICB9XG4gICAgdGhpcy51cGRhdGVDb250cm9sVmFsdWUoKTtcbiAgfVxuXG4gIC8vIE92ZXJyaWRlIHRoZSBpZCBvZiBXcmFwcGVkRm9ybUNvbnRyb2wsIGFzIHdlIHdhbnQgdG8gbW92ZSBpdCB0byB0aGUgZW1iZWRkZWQgaW5wdXQuXG4gIC8vIE90aGVyd2lzZSB0aGUgbGFiZWwvY29tcG9uZW50IGNvbm5lY3Rpb24gZG9lcyBub3Qgd29yayBhbmQgc2NyZWVuIHJlYWRlcnMgZG8gbm90IHJlYWQgdGhlIGxhYmVsLlxuICBvdmVycmlkZSBnZXQgaWQoKSB7XG4gICAgcmV0dXJuIHRoaXMuY29udHJvbElkU2VydmljZS5pZCArICctY29tYm9ib3gnO1xuICB9XG4gIG92ZXJyaWRlIHNldCBpZChpZDogc3RyaW5nKSB7XG4gICAgc3VwZXIuaWQgPSBpZDtcbiAgfVxuXG4gIGdldCBzZWFyY2hUZXh0KCk6IHN0cmluZyB7XG4gICAgcmV0dXJuIHRoaXMuX3NlYXJjaFRleHQ7XG4gIH1cbiAgc2V0IHNlYXJjaFRleHQodGV4dDogc3RyaW5nKSB7XG4gICAgLy8gaWYgaW5wdXQgdGV4dCBoYXMgY2hhbmdlZCBzaW5jZSBsYXN0IHRpbWUsIGZpcmUgYSBjaGFuZ2UgZXZlbnQgc28gYXBwbGljYXRpb24gY2FuIHJlYWN0IHRvIGl0XG4gICAgaWYgKHRleHQgIT09IHRoaXMuX3NlYXJjaFRleHQpIHtcbiAgICAgIGlmICh0aGlzLnRvZ2dsZVNlcnZpY2Uub3Blbikge1xuICAgICAgICB0aGlzLm9wdGlvblNlbGVjdGlvblNlcnZpY2Uuc2hvd0FsbE9wdGlvbnMgPSBmYWxzZTtcbiAgICAgIH1cbiAgICAgIHRoaXMuX3NlYXJjaFRleHQgPSB0ZXh0O1xuICAgICAgdGhpcy5jbHJJbnB1dENoYW5nZS5lbWl0KHRoaXMuc2VhcmNoVGV4dCk7XG4gICAgfVxuICAgIC8vIFdlIG5lZWQgdG8gdHJpZ2dlciB0aGlzIGV2ZW4gaWYgdW5jaGFuZ2VkLCBzbyB0aGUgb3B0aW9uLWl0ZW1zIGRpcmVjdGl2ZSB3aWxsIHVwZGF0ZSBpdHMgbGlzdFxuICAgIC8vIGJhc2VkIG9uIHRoZSBcInNob3dBbGxPcHRpb25zXCIgdmFyaWFibGUgd2hpY2ggbWF5IGhhdmUgY2hhbmdlZCBpbiB0aGUgb3BlbkNoYW5nZSBzdWJzY3JpcHRpb24gYmVsb3cuXG4gICAgLy8gVGhlIG9wdGlvbi1pdGVtcyBkaXJlY3RpdmUgZG9lcyBub3QgbGlzdGVuIHRvIG9wZW5DaGFuZ2UsIGJ1dCBpdCBsaXN0ZW5zIHRvIGN1cnJlbnRJbnB1dCBjaGFuZ2VzLlxuICAgIHRoaXMub3B0aW9uU2VsZWN0aW9uU2VydmljZS5jdXJyZW50SW5wdXQgPSB0aGlzLnNlYXJjaFRleHQ7XG4gIH1cblxuICBnZXQgb3BlblN0YXRlKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLnRvZ2dsZVNlcnZpY2Uub3BlbjtcbiAgfVxuXG4gIGdldCBtdWx0aVNlbGVjdE1vZGVsKCk6IFRbXSB7XG4gICAgaWYgKCF0aGlzLm11bHRpU2VsZWN0KSB7XG4gICAgICB0aHJvdyBFcnJvcignbXVsdGlTZWxlY3RNb2RlbCBpcyBub3QgYXZhaWxhYmxlIGluIHNpbmdsZSBzZWxlY3Rpb24gY29udGV4dCcpO1xuICAgIH1cbiAgICByZXR1cm4gKHRoaXMub3B0aW9uU2VsZWN0aW9uU2VydmljZS5zZWxlY3Rpb25Nb2RlbCBhcyBNdWx0aVNlbGVjdENvbWJvYm94TW9kZWw8VD4pLm1vZGVsO1xuICB9XG5cbiAgZ2V0IGFyaWFDb250cm9scygpOiBzdHJpbmcge1xuICAgIHJldHVybiB0aGlzLm9wdGlvbnM/Lm9wdGlvbnNJZDtcbiAgfVxuXG4gIGdldCBhcmlhT3ducygpOiBzdHJpbmcge1xuICAgIHJldHVybiB0aGlzLm9wdGlvbnM/Lm9wdGlvbnNJZDtcbiAgfVxuXG4gIGdldCBhcmlhRGVzY3JpYmVkQnlTZWxlY3Rpb24oKTogc3RyaW5nIHtcbiAgICByZXR1cm4gJ3NlbGVjdGlvbi0nICsgdGhpcy5pZDtcbiAgfVxuXG4gIGdldCBkaXNwbGF5RmllbGQoKTogc3RyaW5nIHtcbiAgICByZXR1cm4gdGhpcy5vcHRpb25TZWxlY3Rpb25TZXJ2aWNlLmRpc3BsYXlGaWVsZDtcbiAgfVxuXG4gIHByaXZhdGUgZ2V0IGRpc2FibGVkKCkge1xuICAgIHJldHVybiB0aGlzLmNvbnRyb2wgJiYgdGhpcy5jb250cm9sLmRpc2FibGVkO1xuICB9XG5cbiAgbmdBZnRlckNvbnRlbnRJbml0KCkge1xuICAgIHRoaXMuaW5pdGlhbGl6ZVN1YnNjcmlwdGlvbnMoKTtcblxuICAgIC8vIEluaXRpYWxpemUgd2l0aCBwcmVzZWxlY3RlZCB2YWx1