@nova-ui/bits
Version:
SolarWinds Nova Framework
482 lines • 66.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 { LiveAnnouncer } from "@angular/cdk/a11y";
import { OverlayConfig } from "@angular/cdk/overlay";
import { CdkVirtualScrollViewport } from "@angular/cdk/scrolling";
import { ChangeDetectorRef, ContentChild, ContentChildren, Directive, ElementRef, EventEmitter, forwardRef, HostBinding, HostListener, Input, Output, QueryList, ViewChild, } from "@angular/core";
import includes from "lodash/includes";
import isEqual from "lodash/isEqual";
import isUndefined from "lodash/isUndefined";
import last from "lodash/last";
import pull from "lodash/pull";
import { Subject } from "rxjs";
import { delay, takeUntil, tap } from "rxjs/operators";
import { ANNOUNCER_CLOSE_MESSAGE, ANNOUNCER_OPEN_MESSAGE_SUFFIX, } from "./constants";
import { SelectV2OptionComponent } from "./option/select-v2-option.component";
import { OptionKeyControlService } from "./option-key-control.service";
import { KEYBOARD_CODE } from "../../constants/keycode.constants";
import { OVERLAY_ITEM, OVERLAY_WITH_POPUP_STYLES_CLASS, } from "../overlay/constants";
import { OverlayComponent } from "../overlay/overlay-component/overlay.component";
import { OverlayUtilitiesService } from "../overlay/overlay-utilities.service";
import * as i0 from "@angular/core";
import * as i1 from "./option-key-control.service";
import * as i2 from "@angular/cdk/a11y";
const DEFAULT_SELECT_OVERLAY_CONFIG = {
panelClass: OVERLAY_WITH_POPUP_STYLES_CLASS,
};
const V_SCROLL_HEIGHT_BUFFER = 10;
// Will be renamed in scope of the NUI-5797
export class BaseSelectV2 {
/** Sets the Overlay Config in accordance with [Material CDK]{@link https://material.angular.io/cdk/overlay/api#OverlayConfig} */
get overlayConfig() {
return this._overlayConfig;
}
set overlayConfig(value) {
this._overlayConfig = {
...DEFAULT_SELECT_OVERLAY_CONFIG,
...value,
};
}
/** Input to set aria label text */
get ariaLabel() {
return this._ariaLabel;
}
// changing the value with regular @Input doesn't trigger change detection
// so we need to do that manually in the setter
set ariaLabel(value) {
if (value !== this._ariaLabel) {
this._ariaLabel = value;
this.cdRef.markForCheck();
}
}
/** Gets options from the model */
get selectedOptions() {
return this._selectedOptions;
}
/** Sets options to the model */
set selectedOptions(options) {
this._selectedOptions = options;
const value = this.getValueFromOptions(options);
this.value = value;
this.onChange(value);
this.valueSelected.emit(value);
}
constructor(optionKeyControlService, cdRef, elRef, liveAnnouncer) {
this.optionKeyControlService = optionKeyControlService;
this.cdRef = cdRef;
this.elRef = elRef;
this.liveAnnouncer = liveAnnouncer;
/** Value used as a placeholder for the select. */
this.placeholder = "";
this._overlayConfig = DEFAULT_SELECT_OVERLAY_CONFIG;
/** Whether the Dropdown controls manually */
this.manualDropdownControl = false;
/** Sets whether an overlay must sync it's width with the width of the toggle reference */
this.syncWidth = true;
/** Whether the Select/Combobox disabled */
this.isDisabled = false;
this.allowedKeys = [
KEYBOARD_CODE.ARROW_UP,
KEYBOARD_CODE.ARROW_DOWN,
KEYBOARD_CODE.ENTER,
].map(String);
/** Name of the icon which indicates open/close state of the Dropdown */
this.caretIcon = "caret-down";
this.popupUtilities = new OverlayUtilitiesService();
this.destroy$ = new Subject();
this._selectedOptions = [];
this._ariaLabel = "";
/** Emits value which has been selected */
this.valueSelected = new EventEmitter();
/** Emits value which has been changed */
this.valueChanged = new EventEmitter();
/** Emits MouseEvent when click occurs outside Select/Combobox */
this.clickOutsideDropdown = new EventEmitter();
/** `View -> model callback called when value changes` */
this.onChange = () => { };
/** `View -> model callback called when autocomplete has been touched` */
this.onTouched = () => { };
}
ngOnChanges(changes) {
if (changes.value) {
this.handleValueChange(changes.value?.currentValue);
}
if (changes.dropdownCustomContainer && this.dropdown) {
this.defineDropdownContainer();
}
}
ngAfterContentInit() {
this.handleValueChange(this.value);
}
ngAfterViewInit() {
this.initClosingOnClicksOutside();
this.initOnTouch();
if (this.syncWidth) {
this.initPopupUtilities();
}
this.initKeyboardManager();
this.defineDropdownContainer();
this.adjustDropdownOnVScrollResize();
}
/** Handles mousedown event */
onMouseDown() {
this.mouseDown = true;
}
/** Handles mouseup event */
onMouseUp(target) {
this.mouseDown = false;
if (!this.manualDropdownControl) {
this.toggleDropdown();
}
}
/**
* Handles focusin event.
* To avoid triggering showDropdown() on MouseClick. We need to open dropdown only on TAB (SHIFT + TAB) action.
*/
onFocusIn() {
if (this.isOpenOnFocus()) {
this.showDropdown();
this.announceDropdown(true);
}
}
onWindowResize() {
this.popupUtilities.syncWidth();
}
/** Handles keydown event */
onKeyDown(event) {
if (!this.manualDropdownControl) {
this.optionKeyControlService.handleKeydown(event);
}
if (this.manualDropdownControl &&
this.dropdown.showing &&
this.isAllowedKeyOnManualDropdown(event)) {
this.optionKeyControlService.handleKeydown(event);
}
}
/** Shows dropdown */
showDropdown() {
if (this.isDisabled) {
return;
}
this.dropdown.show();
this.setActiveItemOnDropdown();
this.scrollToOption();
this.announceDropdown(true);
}
/** Hides dropdown */
hideDropdown() {
if (!this.isDisabled) {
this.dropdown.hide();
this.announceDropdown(false);
}
}
/** Toggles dropdown */
toggleDropdown() {
if (this.isDisabled) {
return;
}
this.dropdown.toggle();
this.announceDropdown(this.dropdown.showing);
this.setActiveItemOnDropdown();
this.scrollToOption();
if (this.cdkVirtualScroll) {
this.cdkVirtualScroll.checkViewportSize();
}
}
/** Selects specific option and set its value to the model */
selectOption(option) {
if (includes(this.selectedOptions, option) &&
!this.manualDropdownControl) {
this.hideDropdown();
return;
}
this.selectedOptions = this.multiselect
? this.selectedOptions.concat(option)
: [option];
this.optionKeyControlService.setActiveItem(option);
if (!this.manualDropdownControl) {
this.hideDropdown();
}
}
/** Removes selected options or passed option if multi-select mode enabled */
removeSelected(option) {
if (!this.multiselect) {
return;
}
this.selectedOptions = option ? pull(this.selectedOptions, option) : [];
}
registerOnChange(fn) {
this.onChange = fn;
}
registerOnTouched(fn) {
this.onTouched = fn;
}
/** Handles disabled state */
setDisabledState(isDisabled) {
this.isDisabled = isDisabled;
}
/** Sets value to the model */
writeValue(value) {
this.handleValueChange(value);
}
/** Returns last selected Option */
getLastSelectedOption() {
return last(this.selectedOptions);
}
/** Returns state of the Dropdown */
get isDropdownOpen() {
return this.dropdown?.showing;
}
/**
* Calls to ngOnDestroy do not automatically get propagated to base classes.
* This can lead to memory leaks.
* This is a safe guard for preventing memory leaks in derived classes.
*/
ngOnDestroy() {
if (this.dropdown?.showing) {
this.dropdown.hide();
}
this.destroy$.next();
this.destroy$.complete();
if (this.virtualScrollResizeObserver) {
this.virtualScrollResizeObserver.unobserve(this.cdkVirtualScroll.elementRef.nativeElement);
}
}
getValueFromOptions(options = this.selectedOptions) {
return this.multiselect
? options.map((o) => o.value)
: options[0]?.value || "";
}
handleValueChange(value) {
if (isUndefined(value)) {
this.value = "";
this._selectedOptions = [];
this.setActiveItemOnDropdown();
return;
}
this.value = value;
if (this.multiselect && Array.isArray(value)) {
// Using type assertion to avoid compilation error, undefined elements are filtered but compiler do not infer the type properly
this._selectedOptions = (value
.map((v) => this.options?.find((option) => isEqual(option.value, v)))
.filter((_) => _));
// removes 'undefined' elements out of the array if any
this._selectedOptions.forEach((option) => (option.outfiltered = true));
}
else {
const modelValue = value;
const selectedValue = this.options?.find((option) => isEqual(option.value, modelValue));
this._selectedOptions = selectedValue ? [selectedValue] : [];
}
// TODO: Change to the line below to emit the input value 'this.inputElement?.nativeElement?.value' in the scope of the NUI-6131
this.valueChanged.emit();
this.setActiveItemOnDropdown();
}
optionsChanged() {
return this.allPopupItems.changes.pipe(takeUntil(this.destroy$), delay(0), // because we handle options as list of COMPONENTS, so we need to wait till next check
tap(() => {
this.handleValueChange(this.value);
this.validateValueWithSelectedOptions();
this.optionKeyControlService.setFirstItemActive();
}));
}
validateValueWithSelectedOptions() {
const selectedOptionValues = this.selectedOptions.map((option) => option.value);
const valuePropToCompare = !isUndefined(this.value)
? this.multiselect
? this.value
: [this.value]
: [];
if (!isEqual(selectedOptionValues, valuePropToCompare)) {
this.value = this.multiselect
? selectedOptionValues
: selectedOptionValues[0];
this.onChange(this.value);
console.warn("Options changed, no correspondent 'value' found. Current value: ", this.value, "Previous value: ", valuePropToCompare);
}
}
scrollToOption() {
// setTimeout is necessary because scrolling to the selected item should occur only when overlay rendered
if (!isUndefined(this.value) && !this.multiselect) {
setTimeout(() => this.selectedOptions[0]?.scrollIntoView({ block: "center" }));
}
}
initKeyboardManager() {
this.optionKeyControlService.optionItems = this.allPopupItems;
this.optionKeyControlService.popup = this.dropdown;
this.optionKeyControlService.initKeyboardManager();
this.optionKeyControlService.setSkipPredicate((option) => !!(option.outfiltered || option.isDisabled));
}
setActiveItemOnDropdown() {
let selectedValue;
if (!this.multiselect) {
selectedValue = this.options?.find((option) => isEqual(option.value, this.value));
}
selectedValue && !this.multiselect
? this.optionKeyControlService.setActiveItem(this.selectedOptions[0])
: this.optionKeyControlService.setFirstItemActive();
}
initClosingOnClicksOutside() {
this.dropdown.clickOutside
.pipe(takeUntil(this.destroy$))
.subscribe((v) => {
if (!this.manualDropdownControl) {
this.hideDropdown();
}
this.clickOutsideDropdown.emit(v);
});
}
initOnTouch() {
this.dropdown.hide$.pipe(takeUntil(this.destroy$)).subscribe(() => {
this.onTouched();
this.cdRef.markForCheck(); // so caret icon will update properly
});
}
isAllowedKeyOnManualDropdown(event) {
return this.allowedKeys.includes(event.code);
}
defineDropdownContainer() {
this.dropdown.customContainer = this.dropdownCustomContainer;
}
initPopupUtilities() {
const resizeObserver = this.popupUtilities
.setPopupComponent(this.dropdown)
.getResizeObserver();
this.dropdown.show$.pipe(takeUntil(this.destroy$)).subscribe(() => {
this.popupUtilities.syncWidth();
resizeObserver.observe(this.elRef.nativeElement);
});
this.dropdown.hide$.pipe(takeUntil(this.destroy$)).subscribe(() => {
resizeObserver.unobserve(this.elRef.nativeElement);
});
}
/**
* This helps to dynamically set minHeight for overlay to avoid issues with double
* scroll. Overlay minHeight should be bigger than cdkVirtualScroll container.
*/
adjustDropdownOnVScrollResize() {
if (!this.cdkVirtualScroll) {
return;
}
const element = this.cdkVirtualScroll.elementRef.nativeElement;
const height = parseInt(element.style.height, 10);
const minHeight = Number.isNaN(height)
? 0
: height + V_SCROLL_HEIGHT_BUFFER;
this.dropdown.overlayConfig = {
...this.overlayConfig,
...{ minHeight },
};
this.virtualScrollResizeObserver = new ResizeObserver((entries) => {
for (const entry of entries) {
const content = entry.contentRect;
const minHeight = content.height
? content.height + V_SCROLL_HEIGHT_BUFFER
: 0;
this.dropdown.updateSize({ minHeight });
}
});
this.virtualScrollResizeObserver.observe(element);
}
isOpenOnFocus() {
return (!this.mouseDown &&
!this.manualDropdownControl &&
document.activeElement === this.inputElement.nativeElement);
}
announceDropdown(open) {
if (open) {
this.liveAnnouncer.announce(`${this.options.length} ${ANNOUNCER_OPEN_MESSAGE_SUFFIX}`);
return;
}
const msg = this.value
? `${this.value} selected ${ANNOUNCER_CLOSE_MESSAGE}`
: ANNOUNCER_CLOSE_MESSAGE;
this.liveAnnouncer.announce(msg);
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: BaseSelectV2, deps: [{ token: i1.OptionKeyControlService }, { token: i0.ChangeDetectorRef }, { token: i0.ElementRef }, { token: i2.LiveAnnouncer }], target: i0.ɵɵFactoryTarget.Directive }); }
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.12", type: BaseSelectV2, inputs: { placeholder: "placeholder", popupViewportMargin: "popupViewportMargin", overlayConfig: "overlayConfig", multiselect: "multiselect", manualDropdownControl: "manualDropdownControl", value: "value", dropdownCustomContainer: "dropdownCustomContainer", syncWidth: "syncWidth", isDisabled: "isDisabled", isInErrorState: "isInErrorState", ariaLabel: "ariaLabel" }, outputs: { valueSelected: "valueSelected", valueChanged: "valueChanged", clickOutsideDropdown: "clickOutsideDropdown" }, host: { listeners: { "mousedown": "onMouseDown()", "mouseup": "onMouseUp($event.target)", "focusin": "onFocusIn()", "window:resize": "onWindowResize()" }, properties: { "class.disabled": "this.isDisabled", "class.has-error": "this.isInErrorState" } }, queries: [{ propertyName: "cdkVirtualScroll", first: true, predicate: CdkVirtualScrollViewport, descendants: true }, { propertyName: "options", predicate: i0.forwardRef(() => SelectV2OptionComponent), descendants: true }, { propertyName: "allPopupItems", predicate: i0.forwardRef(() => OVERLAY_ITEM), descendants: true }], viewQueries: [{ propertyName: "inputElement", first: true, predicate: ["input"], descendants: true }, { propertyName: "dropdown", first: true, predicate: OverlayComponent, descendants: true }], usesOnChanges: true, ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: BaseSelectV2, decorators: [{
type: Directive
}], ctorParameters: () => [{ type: i1.OptionKeyControlService }, { type: i0.ChangeDetectorRef }, { type: i0.ElementRef }, { type: i2.LiveAnnouncer }], propDecorators: { placeholder: [{
type: Input
}], popupViewportMargin: [{
type: Input
}], overlayConfig: [{
type: Input
}], multiselect: [{
type: Input
}], manualDropdownControl: [{
type: Input
}], value: [{
type: Input
}], dropdownCustomContainer: [{
type: Input
}], syncWidth: [{
type: Input
}], isDisabled: [{
type: HostBinding,
args: ["class.disabled"]
}, {
type: Input
}], isInErrorState: [{
type: HostBinding,
args: ["class.has-error"]
}, {
type: Input
}], ariaLabel: [{
type: Input
}], inputElement: [{
type: ViewChild,
args: ["input", { static: false }]
}], cdkVirtualScroll: [{
type: ContentChild,
args: [CdkVirtualScrollViewport]
}], options: [{
type: ContentChildren,
args: [forwardRef(() => SelectV2OptionComponent), {
descendants: true,
}]
}], allPopupItems: [{
type: ContentChildren,
args: [forwardRef(() => OVERLAY_ITEM), { descendants: true }]
}], dropdown: [{
type: ViewChild,
args: [OverlayComponent]
}], valueSelected: [{
type: Output
}], valueChanged: [{
type: Output
}], clickOutsideDropdown: [{
type: Output
}], onMouseDown: [{
type: HostListener,
args: ["mousedown"]
}], onMouseUp: [{
type: HostListener,
args: ["mouseup", ["$event.target"]]
}], onFocusIn: [{
type: HostListener,
args: ["focusin"]
}], onWindowResize: [{
type: HostListener,
args: ["window:resize"]
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmFzZS1zZWxlY3QtdjIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvbGliL3NlbGVjdC12Mi9iYXNlLXNlbGVjdC12Mi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSx5REFBeUQ7QUFDekQsRUFBRTtBQUNGLCtFQUErRTtBQUMvRSw0RUFBNEU7QUFDNUUsOEVBQThFO0FBQzlFLCtFQUErRTtBQUMvRSw4RUFBOEU7QUFDOUUsNERBQTREO0FBQzVELEVBQUU7QUFDRiw2RUFBNkU7QUFDN0UsdURBQXVEO0FBQ3ZELEVBQUU7QUFDRiw2RUFBNkU7QUFDN0UsNEVBQTRFO0FBQzVFLCtFQUErRTtBQUMvRSwwRUFBMEU7QUFDMUUsaUZBQWlGO0FBQ2pGLDZFQUE2RTtBQUM3RSxpQkFBaUI7QUFFakIsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLG1CQUFtQixDQUFDO0FBQ2xELE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQztBQUNyRCxPQUFPLEVBQUUsd0JBQXdCLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUNsRSxPQUFPLEVBR0gsaUJBQWlCLEVBQ2pCLFlBQVksRUFDWixlQUFlLEVBQ2YsU0FBUyxFQUNULFVBQVUsRUFDVixZQUFZLEVBQ1osVUFBVSxFQUNWLFdBQVcsRUFDWCxZQUFZLEVBQ1osS0FBSyxFQUdMLE1BQU0sRUFDTixTQUFTLEVBRVQsU0FBUyxHQUNaLE1BQU0sZUFBZSxDQUFDO0FBRXZCLE9BQU8sUUFBUSxNQUFNLGlCQUFpQixDQUFDO0FBQ3ZDLE9BQU8sT0FBTyxNQUFNLGdCQUFnQixDQUFDO0FBQ3JDLE9BQU8sV0FBVyxNQUFNLG9CQUFvQixDQUFDO0FBQzdDLE9BQU8sSUFBSSxNQUFNLGFBQWEsQ0FBQztBQUMvQixPQUFPLElBQUksTUFBTSxhQUFhLENBQUM7QUFDL0IsT0FBTyxFQUFjLE9BQU8sRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUMzQyxPQUFPLEVBQUUsS0FBSyxFQUFF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LFNBQVM7c0JBQTVCLEtBQUs7Z0JBY2lDLFlBQVk7c0JBQWxELFNBQVM7dUJBQUMsT0FBTyxFQUFFLEVBQUUsTUFBTSxFQUFFLEtBQUssRUFBRTtnQkFHckMsZ0JBQWdCO3NCQURmLFlBQVk7dUJBQUMsd0JBQXdCO2dCQU8vQixPQUFPO3NCQUhiLGVBQWU7dUJBQUMsVUFBVSxDQUFDLEdBQUcsRUFBRSxDQUFDLHVCQUF1QixDQUFDLEVBQUU7d0JBQ3hELFdBQVcsRUFBRSxJQUFJO3FCQUNwQjtnQkFLTSxhQUFhO3NCQURuQixlQUFlO3VCQUFDLFVBQVUsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxZQUFZLENBQUMsRUFBRSxFQUFFLFdBQVcsRUFBRSxJQUFJLEVBQUU7Z0JBb0IvRCxRQUFRO3NCQURkLFNBQVM7dUJBQUMsZ0JBQWdCO2dCQVlWLGFBQWE7c0JBQTdCLE1BQU07Z0JBS1UsWUFBWTtzQkFBNUIsTUFBTTtnQkFHVSxvQkFBb0I7c0JBQXBDLE1BQU07Z0JBMENBLFdBQVc7c0JBRGpCLFlBQVk7dUJBQUMsV0FBVztnQkFPbEIsU0FBUztzQkFEZixZQUFZO3VCQUFDLFNBQVMsRUFBRSxDQUFDLGVBQWUsQ0FBQztnQkFhbkMsU0FBUztzQkFEZixZQUFZO3VCQUFDLFNBQVM7Z0JBU2hCLGNBQWM7c0JBRHBCLFlBQVk7dUJBQUMsZUFBZSIsInNvdXJjZXNDb250ZW50IjpbIi8vIMKpIDIwMjIgU29sYXJXaW5kcyBXb3JsZHdpZGUsIExMQy4gQWxsIHJpZ2h0cyByZXNlcnZlZC5cbi8vXG4vLyBQZXJtaXNzaW9uIGlzIGhlcmVieSBncmFudGVkLCBmcmVlIG9mIGNoYXJnZSwgdG8gYW55IHBlcnNvbiBvYnRhaW5pbmcgYSBjb3B5XG4vLyAgb2YgdGhpcyBzb2Z0d2FyZSBhbmQgYXNzb2NpYXRlZCBkb2N1bWVudGF0aW9uIGZpbGVzICh0aGUgXCJTb2Z0d2FyZVwiKSwgdG9cbi8vICBkZWFsIGluIHRoZSBTb2Z0d2FyZSB3aXRob3V0IHJlc3RyaWN0aW9uLCBpbmNsdWRpbmcgd2l0aG91dCBsaW1pdGF0aW9uIHRoZVxuLy8gIHJpZ2h0cyB0byB1c2UsIGNvcHksIG1vZGlmeSwgbWVyZ2UsIHB1Ymxpc2gsIGRpc3RyaWJ1dGUsIHN1YmxpY2Vuc2UsIGFuZC9vclxuLy8gIHNlbGwgY29waWVzIG9mIHRoZSBTb2Z0d2FyZSwgYW5kIHRvIHBlcm1pdCBwZXJzb25zIHRvIHdob20gdGhlIFNvZnR3YXJlIGlzXG4vLyAgZnVybmlzaGVkIHRvIGRvIHNvLCBzdWJqZWN0IHRvIHRoZSBmb2xsb3dpbmcgY29uZGl0aW9uczpcbi8vXG4vLyBUaGUgYWJvdmUgY29weXJpZ2h0IG5vdGljZSBhbmQgdGhpcyBwZXJtaXNzaW9uIG5vdGljZSBzaGFsbCBiZSBpbmNsdWRlZCBpblxuLy8gIGFsbCBjb3BpZXMgb3Igc3Vic3RhbnRpYWwgcG9ydGlvbnMgb2YgdGhlIFNvZnR3YXJlLlxuLy9cbi8vIFRIRSBTT0ZUV0FSRSBJUyBQUk9WSURFRCBcIkFTIElTXCIsIFdJVEhPVVQgV0FSUkFOVFkgT0YgQU5ZIEtJTkQsIEVYUFJFU1MgT1Jcbi8vICBJTVBMSUVELCBJTkNMVURJTkcgQlVUIE5PVCBMSU1JVEVEIFRPIFRIRSBXQVJSQU5USUVTIE9GIE1FUkNIQU5UQUJJTElUWSxcbi8vICBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRSBBTkQgTk9OSU5GUklOR0VNRU5ULiBJTiBOTyBFVkVOVCBTSEFMTCBUSEVcbi8vICBBVVRIT1JTIE9SIENPUFlSSUdIVCBIT0xERVJTIEJFIExJQUJMRSBGT1IgQU5ZIENMQUlNLCBEQU1BR0VTIE9SIE9USEVSXG4vLyAgTElBQklMSVRZLCBXSEVUSEVSIElOIEFOIEFDVElPTiBPRiBDT05UUkFDVCwgVE9SVCBPUiBPVEhFUldJU0UsIEFSSVNJTkcgRlJPTSxcbi8vICBPVVQgT0YgT1IgSU4gQ09OTkVDVElPTiBXSVRIIFRIRSBTT0ZUV0FSRSBPUiBUSEUgVVNFIE9SIE9USEVSIERFQUxJTkdTIElOXG4vLyAgVEhFIFNPRlRXQVJFLlxuXG5pbXBvcnQgeyBMaXZlQW5ub3VuY2VyIH0gZnJvbSBcIkBhbmd1bGFyL2Nkay9hMTF5XCI7XG5pbXBvcnQgeyBPdmVybGF5Q29uZmlnIH0gZnJvbSBcIkBhbmd1bGFyL2Nkay9vdmVybGF5XCI7XG5pbXBvcnQgeyBDZGtWaXJ0dWFsU2Nyb2xsVmlld3BvcnQgfSBmcm9tIFwiQGFuZ3VsYXIvY2RrL3Njcm9sbGluZ1wiO1xuaW1wb3J0IHtcbiAgICBBZnRlckNvbnRlbnRJbml0LFxuICAgIEFmdGVyVmlld0luaXQsXG4gICAgQ2hhbmdlRGV0ZWN0b3JSZWYsXG4gICAgQ29udGVudENoaWxkLFxuICAgIENvbnRlbnRDaGlsZHJlbixcbiAgICBEaXJlY3RpdmUsXG4gICAgRWxlbWVudFJlZixcbiAgICBFdmVudEVtaXR0ZXIsXG4gICAgZm9yd2FyZFJlZixcbiAgICBIb3N0QmluZGluZyxcbiAgICBIb3N0TGlzdGVuZXIsXG4gICAgSW5wdXQsXG4gICAgT25DaGFuZ2VzLFxuICAgIE9uRGVzdHJveSxcbiAgICBPdXRwdXQsXG4gICAgUXVlcnlMaXN0LFxuICAgIFNpbXBsZUNoYW5nZXMsXG4gICAgVmlld0NoaWxkLFxufSBmcm9tIFwiQGFuZ3VsYXIvY29yZVwiO1xuaW1wb3J0IHsgQ29udHJvbFZhbHVlQWNjZXNzb3IgfSBmcm9tIFwiQGFuZ3VsYXIvZm9ybXNcIjtcbmltcG9ydCBpbmNsdWRlcyBmcm9tIFwibG9kYXNoL2luY2x1ZGVzXCI7XG5pbXBvcnQgaXNFcXVhbCBmcm9tIFwibG9kYXNoL2lzRXF1YWxcIjtcbmltcG9ydCBpc1VuZGVmaW5lZCBmcm9tIFwibG9kYXNoL2lzVW5kZWZpbmVkXCI7XG5pbXBvcnQgbGFzdCBmcm9tIFwibG9kYXNoL2xhc3RcIjtcbmltcG9ydCBwdWxsIGZyb20gXCJsb2Rhc2gvcHVsbFwiO1xuaW1wb3J0IHsgT2JzZXJ2YWJsZSwgU3ViamVjdCB9IGZyb20gXCJyeGpzXCI7XG5pbXBvcnQgeyBkZWxheSwgdGFrZVVudGlsLCB0YXAgfSBmcm9tIFwicnhqcy9vcGVyYXRvcnNcIjtcblxuaW1wb3J0IHtcbiAgICBBTk5PVU5DRVJfQ0xPU0VfTUVTU0FHRSxcbiAgICBBTk5PVU5DRVJfT1BFTl9NRVNTQUdFX1NVRkZJWCxcbn0gZnJvbSBcIi4vY29uc3RhbnRzXCI7XG5pbXBvcnQgeyBTZWxlY3RWMk9wdGlvbkNvbXBvbmVudCB9IGZyb20gXCIuL29wdGlvbi9zZWxlY3QtdjItb3B0aW9uLmNvbXBvbmVudFwiO1xuaW1wb3J0IHsgT3B0aW9uS2V5Q29udHJvbFNlcnZpY2UgfSBmcm9tIFwiLi9vcHRpb24ta2V5LWNvbnRyb2wuc2VydmljZVwiO1xuaW1wb3J0IHsgSW5wdXRWYWx1ZVR5cGVzLCBJT3B0aW9uZWRDb21wb25lbnQgfSBmcm9tIFwiLi90eXBlc1wiO1xuaW1wb3J0IHsgS0VZQk9BUkRfQ09ERSB9IGZyb20gXCIuLi8uLi9jb25zdGFudHMva2V5Y29kZS5jb25zdGFudHNcIjtcbmltcG9ydCB7XG4gICAgT1ZFUkxBWV9JVEVNLFxuICAgIE9WRVJMQVlfV0lUSF9QT1BVUF9TVFlMRVNfQ0xBU1MsXG59IGZyb20gXCIuLi9vdmVybGF5L2NvbnN0YW50c1wiO1xuaW1wb3J0IHsgT3ZlcmxheUNvbXBvbmVudCB9IGZyb20gXCIuLi9vdmVybGF5L292ZXJsYXktY29tcG9uZW50L292ZXJsYXkuY29tcG9uZW50XCI7XG5pbXBvcnQgeyBPdmVybGF5VXRpbGl0aWVzU2VydmljZSB9IGZyb20gXCIuLi9vdmVybGF5L292ZXJsYXktdXRpbGl0aWVzLnNlcnZpY2VcIjtcbmltcG9ydCB7XG4gICAgSU9wdGlvbixcbiAgICBPcHRpb25WYWx1ZVR5cGUsXG4gICAgT3ZlcmxheUNvbnRhaW5lclR5cGUsXG59IGZyb20gXCIuLi9vdmVybGF5L3R5cGVzXCI7XG5cbmNvbnN0IERFRkFVTFRfU0VMRUNUX09WRVJMQVlfQ09ORklHOiBPdmVybGF5Q29uZmlnID0ge1xuICAgIHBhbmVsQ2xhc3M6IE9WRVJMQVlfV0lUSF9QT1BVUF9TVFlMRVNfQ0xBU1MsXG59O1xuXG5jb25zdCBWX1NDUk9MTF9IRUlHSFRfQlVGRkVSID0gMTA7XG5cbi8vIFdpbGwgYmUgcmVuYW1lZCBpbiBzY29wZSBvZiB0aGUgTlVJLTU3OTdcbkBEaXJlY3RpdmUoKVxuZXhwb3J0IGFic3RyYWN0IGNsYXNzIEJhc2VTZWxlY3RWMlxuICAgIGltcGxlbWVudHNcbiAgICAgICAgQWZ0ZXJWaWV3SW5pdCxcbiAgICAgICAgQWZ0ZXJDb250ZW50SW5pdCxcbiAgICAgICAgQ29udHJvbFZhbHVlQWNjZXNzb3IsXG4gICAgICAgIElPcHRpb25lZENvbXBvbmVudCxcbiAgICAgICAgT25EZXN0cm95LFxuICAgICAgICBPbkNoYW5nZXNcbntcbiAgICAvKiogVmFsdWUgdXNlZCBhcyBhIHBsYWNlaG9sZGVyIGZvciB0aGUgc2VsZWN0LiAqL1xuICAgIEBJbnB1dCgpIHB1YmxpYyBwbGFjZWhvbGRlcjogc3RyaW5nID0gXCJcIjtcblxuICAgIC8qKiBTZXRzIG1hcmdpbiBpbiBweCBmb3IgdGhlIERyb3Bkb3duIHJlbGF0aXZlbHkgdGhlIGNvbnRhaW5lciB3aGVyZSB0aGUgRHJvcGRvd24gYXBwZW5kZWQgdG8gKi9cbiAgICBASW5wdXQoKSBwdWJsaWMgcG9wdXBWaWV3cG9ydE1hcmdpbjogbnVtYmVyO1xuXG4gICAgLyoqIFNldHMgdGhlIE92ZXJsYXkgQ29uZmlnIGluIGFjY29yZGFuY2Ugd2l0aCBbTWF0ZXJpYWwgQ0RLXXtAbGluayBodHRwczovL21hdGVyaWFsLmFuZ3VsYXIuaW8vY2RrL292ZXJsYXkvYXBpI092ZXJsYXlDb25maWd9ICovXG4gICAgQElucHV0KClcbiAgICBwdWJsaWMgZ2V0IG92ZXJsYXlDb25maWcoKTogT3ZlcmxheUNvbmZpZyB7XG4gICAgICAgIHJldHVybiB0aGlzLl9vdmVybGF5Q29uZmlnO1xuICAgIH1cbiAgICBwdWJsaWMgc2V0IG92ZXJsYXlDb25maWcodmFsdWU6IE92ZXJsYXlDb25maWcpIHtcbiAgICAgICAgdGhpcy5fb3ZlcmxheUNvbmZpZyA9IHtcbiAgICAgICAgICAgIC4uLkRFRkFVTFRfU0VMRUNUX09WRVJMQVlfQ09ORklHLFxuICAgICAgICAgICAgLi4udmFsdWUsXG4gICAgICAgIH07XG4gICAgfVxuICAgIHByaXZhdGUgX292ZXJsYXlDb25maWc6IE92ZXJsYXlDb25maWcgPSBERUZBVUxUX1NFTEVDVF9PVkVSTEFZX0NPTkZJRztcblxuICAgIC8qKiBXaGV0aGVyIHRoZSBtdWx0aS1zZWxlY3QgbW9kZSAqL1xuICAgIEBJbnB1dCgpIHB1YmxpYyBtdWx0aXNlbGVjdDogYm9vbGVhbjtcblxuICAgIC8qKiBXaGV0aGVyIHRoZSBEcm9wZG93biBjb250cm9scyBtYW51YWxseSAqL1xuICAgIEBJbnB1dCgpIHB1YmxpYyBtYW51YWxEcm9wZG93bkNvbnRyb2w6IGJvb2xlYW4gPSBmYWxzZTtcblxuICAgIC8qKiBTZXRzIHZhbHVlIG9mIHRoZSBTZWxlY3QvQ29tYm9ib3ggKi9cbiAgICBASW5wdXQoKSBwdWJsaWMgdmFsdWU6IE9wdGlvblZhbHVlVHlwZSB8IE9wdGlvblZhbHVlVHlwZVtdIHwgbnVsbDtcblxuICAgIC8qKiBTZXRzIGN1c3RvbSBjb250YWluZXIgZm9yIENESyBPdmVybGF5LiBTZWxlY3RvciBPUiBFbGVtZW50UmVmICovXG4gICAgQElucHV0KCkgcHVibGljIGRyb3Bkb3duQ3VzdG9tQ29udGFpbmVyOiBPdmVybGF5Q29udGFpbmVyVHlwZTtcblxuICAgIC8qKiBTZXRzIHdoZXRoZXIgYW4gb3ZlcmxheSBtdXN0IHN5bmMgaXQncyB3aWR0aCB3aXRoIHRoZSB3aWR0aCBvZiB0aGUgdG9nZ2xlIHJlZmVyZW5jZSAqL1xuICAgIEBJbnB1dCgpIHB1YmxpYyBzeW5jV2lkdGg6IGJvb2xlYW4gPSB0cnVlO1xuXG4gICAgLyoqIFdoZXRoZXIgdGhlIFNlbGVjdC9Db21ib2JveCBkaXNhYmxlZCAqL1xuICAgIEBIb3N0QmluZGluZyhcImNsYXNzLmRpc2FibGVkXCIpXG4gICAgQElucHV0KClcbiAgICBwdWJsaWMgaXNEaXNhYmxlZCA9IGZhbHNlO1xuXG4gICAgLyoqIElucHV0IHRvIGFwcGx5IGVycm9yIHN0YXRlIHN0eWxlcyAqL1xuICAgIEBIb3N0QmluZGluZyhcImNsYXNzLmhhcy1lcnJvclwiKVxuICAgIEBJbnB1dCgpXG4gICAgcHVibGljIGlzSW5FcnJvclN0YXRlOiBib29sZWFuO1xuXG4gICAgcHJpdmF0ZSBhbGxvd2VkS2V5cyA9IFtcbiAgICAgICAgS0VZQk9BUkRfQ09ERS5BUlJPV19VUCxcbiAgICAgICAgS0VZQk9BUkRfQ09ERS5BUlJPV19ET1dOLFxuICAgICAgICBLRVlCT0FSRF9DT0RFLkVOVEVSLFxuICAgIF0ubWFwKFN0cmluZyk7XG5cbiAgICAvKiogSW5wdXQgdG8gc2V0IGFyaWEgbGFiZWwgdGV4dCAqL1xuICAgIEBJbnB1dCgpIHB1YmxpYyBnZXQgYXJpYUxhYmVsKCk6IHN0cmluZyB7XG4gICAgICAgIHJldHVybiB0aGlzLl9hcmlhTGFiZWw7XG4gICAgfVxuXG4gICAgLy8gY2hhbmdpbmcgdGhlIHZhbHVlIHdpdGggcmVndWxhciBASW5wdXQgZG9lc24ndCB0cmlnZ2VyIGNoYW5nZSBkZXRlY3Rpb25cbiAgICAvLyBzbyB3ZSBuZWVkIHRvIGRvIHRoYXQgbWFudWFsbHkgaW4gdGhlIHNldHRlclxuICAgIHB1YmxpYyBzZXQgYXJpYUxhYmVsKHZhbHVlOiBzdHJpbmcpIHtcbiAgICAgICAgaWYgKHZhbHVlICE9PSB0aGlzLl9hcmlhTGFiZWwpIHtcbiAgICAgICAgICAgIHRoaXMuX2FyaWFMYWJlbCA9IHZhbHVlO1xuICAgICAgICAgICAgdGhpcy5jZFJlZi5tYXJrRm9yQ2hlY2soKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8qKiBDb3JyZXNwb25kcyB0byB0aGUgVGV4dGJveCBvZiB0aGUgQ29tYm9ib3ggKi9cbiAgICBAVmlld0NoaWxkKFwiaW5wdXRcIiwgeyBzdGF0aWM6IGZhbHNlIH0pIGlucHV0RWxlbWVudDogRWxlbWVudFJlZjtcblxuICAgIEBDb250ZW50Q2hpbGQoQ2RrVmlydHVhbFNjcm9sbFZpZXdwb3J0KVxuICAgIGNka1ZpcnR1YWxTY3JvbGw6IENka1ZpcnR1YWxTY3JvbGxWaWV3cG9ydDtcblxuICAgIC8qKiBDb3JyZXNwb25kcyB0byB0aGUgT3B0aW9ucyBsaXN0ZWQgaW4gdGhlIERyb3Bkb3duICovXG4gICAgQENvbnRlbnRDaGlsZHJlbihmb3J3YXJkUmVmKCgpID0+IFNlbGVjdFYyT3B0aW9uQ29tcG9uZW50KSwge1xuICAgICAgICBkZXNjZW5kYW50czogdHJ1ZSxcbiAgICB9KVxuICAgIHB1YmxpYyBvcHRpb25zOiBRdWVyeUxpc3Q8U2VsZWN0VjJPcHRpb25Db21wb25lbnQ+O1xuXG4gICAgLyoqIENvcnJlc3BvbmRzIHRvIHRoZSBBbGwgSXRlbXMgbGlzdGVkIGluIHRoZSBEcm9wZG93biAqL1xuICAgIEBDb250ZW50Q2hpbGRyZW4oZm9yd2FyZFJlZigoKSA9PiBPVkVSTEFZX0lURU0pLCB7IGRlc2NlbmRhbnRzOiB0cnVlIH0pXG4gICAgcHVibGljIGFsbFBvcHVwSXRlbXM6IFF1ZXJ5TGlzdDxJT3B0aW9uPjtcblxuICAgIC8qKiBHZXRzIG9wdGlvbnMgZnJvbSB0aGUgbW9kZWwgKi9cbiAgICBwdWJsaWMgZ2V0IHNlbGVjdGVkT3B0aW9ucygpOiBTZWxlY3RWMk9wdGlvbkNvbXBvbmVudFtdIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX3NlbGVjdGVkT3B0aW9ucztcbiAgICB9XG4gICAgLyoqIFNldHMgb3B0aW9ucyB0byB0aGUgbW9kZWwgKi9cbiAgICBwdWJsaWMgc2V0IHNlbGVjdGVkT3B0aW9ucyhvcHRpb25zOiBTZWxlY3RWMk9wdGlvbkNvbXBvbmVudFtdKSB7XG4gICAgICAgIHRoaXMuX3NlbGVjdGVkT3B0aW9ucyA9IG9wdGlvbnM7XG4gICAgICAgIGNvbnN0IHZhbHVlID0gdGhpcy5nZXRWYWx1ZUZyb21PcHRpb25zKG9wdGlvbnMpO1xuICAgICAgICB0aGlzLnZhbHVlID0gdmFsdWU7XG4gICAgICAgIHRoaXMub25DaGFuZ2UodmFsdWUpO1xuICAgICAgICB0aGlzLnZhbHVlU2VsZWN0ZWQuZW1pdCh2YWx1ZSk7XG4gICAgfVxuXG4gICAgLyoqIE5hbWUgb2YgdGhlIGljb24gd2hpY2ggaW5kaWNhdGVzIG9wZW4vY2xvc2Ugc3RhdGUgb2YgdGhlIERyb3Bkb3duICovXG4gICAgcHVibGljIGNhcmV0SWNvbiA9IFwiY2FyZXQtZG93blwiO1xuXG4gICAgQFZpZXdDaGlsZChPdmVybGF5Q29tcG9uZW50KVxuICAgIHB1YmxpYyBkcm9wZG93bjogT3ZlcmxheUNvbXBvbmVudDtcbiAgICBwcm90ZWN0ZWQgcG9wdXBVdGlsaXRpZXM6IE92ZXJsYXlVdGlsaXRpZXNTZXJ2aWNlID1cbiAgICAgICAgbmV3IE92ZXJsYXlVdGlsaXRpZXNTZXJ2aWNlKCk7XG4gICAgcHJvdGVjdGVkIGRlc3Ryb3kkOiBTdWJqZWN0PHZvaWQ+ID0gbmV3IFN1YmplY3Q8dm9pZD4oKTtcbiAgICBwcm90ZWN0ZWQgbW91c2VEb3duOiBib29sZWFuO1xuICAgIHByaXZhdGUgX3NlbGVjdGVkT3B0aW9uczogU2VsZWN0VjJPcHRpb25Db21wb25lbnRbXSA9IFtdO1xuXG4gICAgcHJpdmF0ZSBfYXJpYUxhYmVsOiBzdHJpbmcgPSBcIlwiO1xuICAgIHByaXZhdGUgdmlydHVhbFNjcm9sbFJlc2l6ZU9ic2VydmVyOiBSZXNpemVPYnNlcnZlcjtcblxuICAgIC8qKiBFbWl0cyB2YWx1ZSB3aGljaCBoYXMgYmVlbiBzZWxlY3RlZCAqL1xuICAgIEBPdXRwdXQoKSBwdWJsaWMgdmFsdWVTZWxlY3RlZCA9IG5ldyBFdmVudEVtaXR0ZXI8XG4gICAgICAgIE9wdGlvblZhbHVlVHlwZSB8IE9wdGlvblZhbHVlVHlwZVtdIHwgbnVsbFxuICAgID4oKTtcblxuICAgIC8qKiBFbWl0cyB2YWx1ZSB3aGljaCBoYXMgYmVlbiBjaGFuZ2VkICovXG4gICAgQE91dHB1dCgpIHB1YmxpYyB2YWx1ZUNoYW5nZWQgPSBuZXcgRXZlbnRFbWl0dGVyPElucHV0VmFsdWVUeXBlcz4oKTtcblxuICAgIC8qKiBFbWl0cyBNb3VzZUV2ZW50IHdoZW4gY2xpY2sgb2NjdXJzIG91dHNpZGUgU2VsZWN0L0NvbWJvYm94ICovXG4gICAgQE91dHB1dCgpIHB1YmxpYyBjbGlja091dHNpZGVEcm9wZG93biA9IG5ldyBFdmVudEVtaXR0ZXI8TW91c2VFdmVudD4oKTtcblxuICAgIHByb3RlY3RlZCBjb25zdHJ1Y3RvcihcbiAgICAgICAgcHJvdGVjdGVkIG9wdGlvbktleUNvbnRyb2xTZXJ2aWNlOiBPcHRpb25LZXlDb250cm9sU2VydmljZTxJT3B0aW9uPixcbiAgICAgICAgcHJvdGVjdGVkIGNkUmVmOiBDaGFuZ2VEZXRlY3RvclJlZixcbiAgICAgICAgcHVibGljIGVsUmVmOiBFbGVtZW50UmVmPEhUTUxFbGVtZW50PixcbiAgICAgICAgcHVibGljIGxpdmVBbm5vdW5jZXI6IExpdmVBbm5vdW5jZXJcbiAgICApIHt9XG5cbiAgICBwdWJsaWMgbmdPbkNoYW5nZXMoY2hhbmdlczogU2ltcGxlQ2hhbmdlcyk6IHZvaWQge1xuICAgICAgICBpZiAoY2hhbmdlcy52YWx1ZSkge1xuICAgICAgICAgICAgdGhpcy5oYW5kbGVWYWx1ZUNoYW5nZShjaGFuZ2VzLnZhbHVlPy5jdXJyZW50VmFsdWUpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGNoYW5nZXMuZHJvcGRvd25DdXN0b21Db250YWluZXIgJiYgdGhpcy5kcm9wZG93bikge1xuICAgICAgICAgICAgdGhpcy5kZWZpbmVEcm9wZG93bkNvbnRhaW5lcigpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcHVibGljIG5nQWZ0ZXJDb250ZW50SW5pdCgpOiB2b2lkIHtcbiAgICAgICAgdGhpcy5oYW5kbGVWYWx1ZUNoYW5nZSh0aGlzLnZhbHVlKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgbmdBZnRlclZpZXdJbml0KCk6IHZvaWQge1xuICAgICAgICB0aGlzLmluaXRDbG9zaW5nT25DbGlja3NPdXRzaWRlKCk7XG4gICAgICAgIHRoaXMuaW5pdE9uVG91Y2goKTtcbiAgICAgICAgaWYgKHRoaXMuc3luY1dpZHRoKSB7XG4gICAgICAgICAgICB0aGlzLmluaXRQb3B1cFV0aWxpdGllcygpO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMuaW5pdEtleWJvYXJkTWFuYWdlcigpO1xuICAgICAgICB0aGlzLmRlZmluZURyb3Bkb3duQ29udGFpbmVyKCk7XG4gICAgICAgIHRoaXMuYWRqdXN0RHJvcGRvd25PblZTY3JvbGxSZXNpemUoKTtcbiAgICB9XG5cbiAgICAvKiogYFZpZXcgLT4gbW9kZWwgY2FsbGJhY2sgY2FsbGVkIHdoZW4gdmFsdWUgY2hhbmdlc2AgKi9cbiAgICBwdWJsaWMgb25DaGFuZ2U6ICh2YWx1ZTogYW55KSA9PiB2b2lkID0gKCk6IHZvaWQgPT4ge307XG5cbiAgICAvKiogYFZpZXcgLT4gbW9kZWwgY2FsbGJhY2sgY2FsbGVkIHdoZW4gYXV0b2NvbXBsZXRlIGhhcyBiZWVuIHRvdWNoZWRgICovXG4gICAgcHVibGljIG9uVG91Y2hlZCA9ICgpOiB2b2lkID0+IHt9O1xuXG4gICAgLyoqIEhhbmRsZXMgbW91c2Vkb3duIGV2ZW50ICovXG4gICAgQEhvc3