UNPKG

@nova-ui/bits

Version:

SolarWinds Nova Framework

482 lines 66.1 kB
// © 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