UNPKG

@visa/nova-angular

Version:

Visa Product Design System Nova Angular library

306 lines 46.4 kB
/** * Copyright (c) 2025 Visa, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * **/ import { ElementRef, EventEmitter, Injectable, Output, RendererFactory2, signal } from '@angular/core'; import { arrow, autoUpdate, computePosition, flip, offset, shift } from '@floating-ui/dom'; import { AppReadyService } from '../_utilities/services/app-stable-check.service'; import { UUIDService } from '../_utilities/services/uuid.service'; import { FloatingUIPlacements, FloatingUIVisibility } from './floating-ui.constants'; import * as i0 from "@angular/core"; import * as i1 from "../_utilities/services/uuid.service"; import * as i2 from "../_utilities/services/app-stable-check.service"; /** * This internal service is used by Combobox, Dropdown Menu, and Tooltip components. <br /> * It can be used with generic FloatingUIContainer, FloatingUIElementDirective, and FloatingUITriggerDirective to create your own custom floating-ui. <br /> * If you are using any of the components mentioned, you will typically not need to use this service directly. <br /> * Derived from [Floating UI documentation](https://floating-ui.com/). */ export class FloatingUIService { constructor(rendererFactory, uuidService, appReadyService) { this.rendererFactory = rendererFactory; this.uuidService = uuidService; this.appReadyService = appReadyService; /** @ignore */ this.offsetDefault = 2; /** @ignore */ this.comboboxMiddleware = [offset(0), flip(), shift()]; /** @ignore */ this.middlewareDefault = [offset(this.offsetDefault), flip(), shift()]; /** @ignore */ this.middleware = this.middlewareDefault; /** @ignore */ this.placement = FloatingUIPlacements.BOTTOM; /** @ignore */ this.isShown = signal(false); /** * Displays property of the floating UI element. * @default 'flex' */ this.display = 'flex'; /** * Emits true when this floating UI element is shown and false when hidden. */ this.isShownEmitter = new EventEmitter(); // for keepOnHover /** @ignore */ this.onTooltip = false; /** @ignore */ this.onTrigger = false; this.renderer = rendererFactory.createRenderer(null, null); } /** * The setUpFloatingUI method is required to initialize the floating element and its trigger. <br /> * Called by default with FloatingUIContainer or ComboboxDirective. * @param referenceEl References element that will trigger floating UI. * @param floatingEl References floating UI element. * @param eventArray Array of events for the reference/trigger element to listen for. <br> i.e. <code>[new UIEvent('focus'), FloatingUIVisibility.SHOW]</code> <br> tells the element to show the floating UI when the triggering element is focused. */ setUpfloatingUI(referenceEl, floatingEl, eventArray) { this.trigger = this.nativeElement(referenceEl); this.floatingUI = floatingEl; this.renderer.setStyle(this.floatingUI.nativeElement, 'top', '0'); this.renderer.setStyle(this.floatingUI.nativeElement, 'left', '0'); this.renderer.setStyle(this.floatingUI.nativeElement, 'display', 'none'); if (eventArray) { this.setUpTrigger(eventArray); } else { console.error('No events provided to trigger the Floating UI.'); } } /** * The nativeElement method returns the Element type of the reference element. * @param element Element to be converted to Element type. * @returns Element */ nativeElement(element) { if (element instanceof ElementRef) { return element.nativeElement; } return element; } /** * The customizeFloatingUI method allows you to provide custom placement and middleware options to the Floating UI service. * @param placement Optional. See <code>FloatingUIPlacements</code> enum. * @param middleware Optional. Visit the official Floating UI documentation for more on [middleware options](https://floating-ui.com/docs/computePosition#middleware). * @param display Optional. Sets CSS display property for the floating UI element. * @param tooltipArrow Optional. Directive reference to the arrow element. See TooltipArrowDirective. */ customizeFloatingUI(placement, middleware, display, tooltipArrow) { if (placement) { this.placement = placement; } if (middleware) { this.middleware = middleware; // save a custom offset const customOffset = this.middleware.find((m) => m['name'] === 'offset') || 2; this.offset = customOffset.options; } if (display) { this.display = display; } if (tooltipArrow) { this.arrow = tooltipArrow; // update the offset to factor in the arrow size if no custom offset was placed const floatingOffset = Math.ceil(Math.sqrt(2 * this.arrow.customSize ** 2) / 2); this.offset = this.offset ? floatingOffset + this.offset : floatingOffset + this.offsetDefault; this.middleware.push(arrow({ element: this.arrow.el.nativeElement })); const offsetIndex = this.middleware.findIndex((func) => func.name === 'offset'); // START GENAI@CHATGPT4 if (offsetIndex !== -1) { // Replace the old offset function with the new one this.middleware = [ ...this.middleware.slice(0, offsetIndex), offset(this.offset), ...this.middleware.slice(offsetIndex + 1) ]; } else { // If no old offset function is found, just add the new one this.middleware = [...this.middleware, offset(this.offset)]; } // END GENAI@CHATGPT4 } } /** * The positionFloatingUI method positions the Floating UI based on the given placement and middleware. <br /> * For more details on the internal function, refer to Floating UI's [compute position documentation](https://floating-ui.com/docs/computePosition). * @param trigger The triggering element. * @param floatingUI The element that will "float" when triggered. * @param placement Reference FloatingUIPlacements. * @param middleware Visit the official Floating UI documentation for more on [middleware options](https://floating-ui.com/docs/computePosition#middleware). */ positionFloatingUI(trigger = this.trigger, floatingUI = this.floatingUI.nativeElement, placement = this.placement) { autoUpdate(trigger, floatingUI, () => { computePosition(trigger, floatingUI, { placement: placement, middleware: this.middleware }).then(({ x, y, middlewareData, placement }) => { floatingUI.style.left = `${x}px`; floatingUI.style.top = `${y}px`; if (middlewareData.arrow) { // see: https://codesandbox.io/s/mystifying-kare-ee3hmh?file=/src/index.js if (this.arrow) { const { x, y } = middlewareData.arrow; this.renderer.setStyle(this.arrow.el.nativeElement, 'left', x != null ? `${x}px` : ''); this.renderer.setStyle(this.arrow.el.nativeElement, 'top', y != null ? `${y}px` : ''); this.renderer.setStyle(this.arrow.el.nativeElement, 'right', ''); this.renderer.setStyle(this.arrow.el.nativeElement, 'bottom', ''); const side = placement.split('-')[0]; const staticSide = { top: 'bottom', bottom: 'top', left: 'right', right: 'left' }[side]; if (staticSide) { this.renderer.setStyle(this.arrow.el.nativeElement, staticSide, -(this.arrow.el.nativeElement.offsetWidth / 2) + 'px'); } } } }); }); } /** * The showFloatingUI method displays the Floating UI element. */ showfloatingUI() { if (this.appReadyService.isBrowserAndDomAvailable()) { const triggerDisabled = this.trigger.getAttribute('disabled'); if (triggerDisabled) return; } this.positionFloatingUI(); this.isShown.set(true); this.isShownEmitter.emit(this.isShown()); this.renderer.setStyle(this.floatingUI.nativeElement, 'display', this.display); } /** * The hideFloatingUI method hides the Floating UI element. */ hidefloatingUI() { this.renderer.setStyle(this.floatingUI.nativeElement, 'display', 'none'); this.isShown.set(false); this.isShownEmitter.emit(this.isShown()); } /** * The toggleFloatingUI method toggles the visibility of the Floating UI element. */ toggleFloatingUI() { if (this.isShown()) { this.hidefloatingUI(); } else { this.showfloatingUI(); } } /** * The closeOnClickOut method closes the menu when a click occurs outside of the menu and the triggering element. * @param event Document click event. */ closeOnClickOut(event) { // listen for document click and close menu if click is outside of component if (this.isShown()) { const target = event.target; if (!this.floatingUI.nativeElement.contains(event.target) && !this.trigger.contains(target)) { this.hidefloatingUI(); } } } /** * The addCloseActions method adds default close actions to the Floating UI component. These actions include closing the menu when the escape key is pressed or when clicking outside of the floating element. */ addCloseActions() { const document = this.appReadyService.checkDocumentExists(); // close menu on escape key press or clicking outside of menu if (document) { this.renderer.listen(document, 'click', this.closeOnClickOut.bind(this)); this.renderer.listen(document, 'keydown.esc', this.hidefloatingUI.bind(this)); } } /** * The setUpTrigger method configures the triggering element by setting up the events to listen for and the actions to take when those events are triggered. * @param eventArray Array of events for the reference/trigger element to listen for.<br> i.e. <code>[new UIEvent('focus'), FloatingUIVisibility.SHOW]</code> <br> tells the element to show the floating UI when the triggering element is focused. */ setUpTrigger(eventArray) { // add default actions to close menu this.addCloseActions(); eventArray.forEach((pair) => { /** * if a custom eventArray is **not** typed as UIEventVisibilityPair[],<br /> * Typescript will type the array as ((UIEvent | "show")[] | (UIEvent | "hide")[])[] <br /> * because the passed arrays have different types, the type of the array is inferred as a union of the types of the passed arrays. <br /> * The following code ensures the correct types are assigned to the event and listener variables. */ const event = pair.find((e) => e instanceof UIEvent); const listener = pair.find((e) => e === FloatingUIVisibility.SHOW || e === FloatingUIVisibility.HIDE); if (event instanceof UIEvent) { if (event.type === 'click') { this.renderer.listen(this.trigger, event.type, this.toggleFloatingUI.bind(this)); } else if (event.type === 'mouseleave' && listener && listener === FloatingUIVisibility.HIDE) { this.keepOnHover(); } else if (listener && listener === FloatingUIVisibility.SHOW) { this.renderer.listen(this.trigger, event.type, this.showfloatingUI.bind(this)); } else if (listener && listener === FloatingUIVisibility.HIDE) { this.renderer.listen(this.trigger, event.type, this.hidefloatingUI.bind(this)); } } }); } /** * The keepOnHover method keeps the floating element visible when hovering over the trigger or the floating element. */ keepOnHover() { let offset = this.middleware.find((m) => m['name'] === 'offset'); offset = this.hideOnHoverTimeout ? this.hideOnHoverTimeout : offset['options'] ? offset['options'] * 20 : 50; this.renderer.listen(this.trigger, 'mouseleave', () => { setTimeout(() => { this.onTrigger = false; if (!this.onTooltip) { this.hidefloatingUI(); } }, offset); }); this.renderer.listen(this.trigger, 'mouseenter', () => { this.onTrigger = true; }); this.renderer.listen(this.floatingUI.nativeElement, 'mouseenter', () => { this.onTooltip = true; }); this.renderer.listen(this.floatingUI.nativeElement, 'mouseleave', () => { setTimeout(() => { this.onTooltip = false; if (!this.onTrigger) { this.hidefloatingUI(); } }, offset); }); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: FloatingUIService, deps: [{ token: i0.RendererFactory2 }, { token: i1.UUIDService }, { token: i2.AppReadyService }], target: i0.ɵɵFactoryTarget.Injectable }); } static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: FloatingUIService, providedIn: 'root' }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: FloatingUIService, decorators: [{ type: Injectable, args: [{ providedIn: 'root' }] }], ctorParameters: () => [{ type: i0.RendererFactory2 }, { type: i1.UUIDService }, { type: i2.AppReadyService }], propDecorators: { isShownEmitter: [{ type: Output }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmxvYXRpbmctdWkuc2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL2xpYnMvbm92YS1saWIvc3JjL2xpYi9mbG9hdGluZy11aS9mbG9hdGluZy11aS5zZXJ2aWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7Ozs7Ozs7SUFlSTtBQUNKLE9BQU8sRUFBRSxVQUFVLEVBQUUsWUFBWSxFQUFFLFVBQVUsRUFBRSxNQUFNLEVBQWEsZ0JBQWdCLEVBQUUsTUFBTSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQ2xILE9BQU8sRUFBRSxLQUFLLEVBQUUsVUFBVSxFQUFFLGVBQWUsRUFBeUIsSUFBSSxFQUFFLE1BQU0sRUFBRSxLQUFLLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQztBQUNsSCxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0saURBQWlELENBQUM7QUFDbEYsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLHFDQUFxQyxDQUFDO0FBRWxFLE9BQU8sRUFBRSxvQkFBb0IsRUFBRSxvQkFBb0IsRUFBeUIsTUFBTSx5QkFBeUIsQ0FBQzs7OztBQUU1Rzs7Ozs7R0FLRztBQUlILE1BQU0sT0FBTyxpQkFBaUI7SUFDNUIsWUFDVSxlQUFpQyxFQUNqQyxXQUF3QixFQUN4QixlQUFnQztRQUZoQyxvQkFBZSxHQUFmLGVBQWUsQ0FBa0I7UUFDakMsZ0JBQVcsR0FBWCxXQUFXLENBQWE7UUFDeEIsb0JBQWUsR0FBZixlQUFlLENBQWlCO1FBZ0IxQyxjQUFjO1FBQ2Qsa0JBQWEsR0FBRyxDQUFDLENBQUM7UUFDbEIsY0FBYztRQUNkLHVCQUFrQixHQUFRLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxFQUFFLElBQUksRUFBRSxFQUFFLEtBQUssRUFBRSxDQUFDLENBQUM7UUFDdkQsY0FBYztRQUNkLHNCQUFpQixHQUFRLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxhQUFhLENBQUMsRUFBRSxJQUFJLEVBQUUs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LGNBRmhCLE1BQU07OzRGQUVQLGlCQUFpQjtrQkFIN0IsVUFBVTttQkFBQztvQkFDVixVQUFVLEVBQUUsTUFBTTtpQkFDbkI7NklBaURXLGNBQWM7c0JBQXZCLE1BQU0iLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqICAgICAgICAgICAgICBDb3B5cmlnaHQgKGMpIDIwMjUgVmlzYSwgSW5jLlxuICpcbiAqIExpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSBcIkxpY2Vuc2VcIik7XG4gKiB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuXG4gKiBZb3UgbWF5IG9idGFpbiBhIGNvcHkgb2YgdGhlIExpY2Vuc2UgYXRcbiAqXG4gKiAgICAgICAgIGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMFxuICpcbiAqIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvciBhZ3JlZWQgdG8gaW4gd3JpdGluZywgc29mdHdhcmVcbiAqIGRpc3RyaWJ1dGVkIHVuZGVyIHRoZSBMaWNlbnNlIGlzIGRpc3RyaWJ1dGVkIG9uIGFuIFwiQVMgSVNcIiBCQVNJUyxcbiAqIFdJVEhPVVQgV0FSUkFOVElFUyBPUiBDT05ESVRJT05TIE9GIEFOWSBLSU5ELCBlaXRoZXIgZXhwcmVzcyBvciBpbXBsaWVkLlxuICogU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZFxuICogbGltaXRhdGlvbnMgdW5kZXIgdGhlIExpY2Vuc2UuXG4gKlxuICoqL1xuaW1wb3J0IHsgRWxlbWVudFJlZiwgRXZlbnRFbWl0dGVyLCBJbmplY3RhYmxlLCBPdXRwdXQsIFJlbmRlcmVyMiwgUmVuZGVyZXJGYWN0b3J5Miwgc2lnbmFsIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBhcnJvdywgYXV0b1VwZGF0ZSwgY29tcHV0ZVBvc2l0aW9uLCBDb21wdXRlUG9zaXRpb25SZXR1cm4sIGZsaXAsIG9mZnNldCwgc2hpZnQgfSBmcm9tICdAZmxvYXRpbmctdWkvZG9tJztcbmltcG9ydCB7IEFwcFJlYWR5U2VydmljZSB9IGZyb20gJy4uL191dGlsaXRpZXMvc2VydmljZXMvYXBwLXN0YWJsZS1jaGVjay5zZXJ2aWNlJztcbmltcG9ydCB7IFVVSURTZXJ2aWNlIH0gZnJvbSAnLi4vX3V0aWxpdGllcy9zZXJ2aWNlcy91dWlkLnNlcnZpY2UnO1xuaW1wb3J0IHsgVG9vbHRpcEFycm93RGlyZWN0aXZlIH0gZnJvbSAnLi4vYXJyb3cvYXJyb3cuZGlyZWN0aXZlJztcbmltcG9ydCB7IEZsb2F0aW5nVUlQbGFjZW1lbnRzLCBGbG9hdGluZ1VJVmlzaWJpbGl0eSwgVUlFdmVudFZpc2liaWxpdHlQYWlyIH0gZnJvbSAnLi9mbG9hdGluZy11aS5jb25zdGFudHMnO1xuXG4vKipcbiAqIFRoaXMgaW50ZXJuYWwgc2VydmljZSBpcyB1c2VkIGJ5IENvbWJvYm94LCBEcm9wZG93biBNZW51LCBhbmQgVG9vbHRpcCBjb21wb25lbnRzLiA8YnIgLz5cbiAqIEl0IGNhbiBiZSB1c2VkIHdpdGggZ2VuZXJpYyBGbG9hdGluZ1VJQ29udGFpbmVyLCBGbG9hdGluZ1VJRWxlbWVudERpcmVjdGl2ZSwgYW5kIEZsb2F0aW5nVUlUcmlnZ2VyRGlyZWN0aXZlIHRvIGNyZWF0ZSB5b3VyIG93biBjdXN0b20gZmxvYXRpbmctdWkuIDxiciAvPlxuICogSWYgeW91IGFyZSB1c2luZyBhbnkgb2YgdGhlIGNvbXBvbmVudHMgbWVudGlvbmVkLCB5b3Ugd2lsbCB0eXBpY2FsbHkgbm90IG5lZWQgdG8gdXNlIHRoaXMgc2VydmljZSBkaXJlY3RseS4gPGJyIC8+XG4gKiBEZXJpdmVkIGZyb20gW0Zsb2F0aW5nIFVJIGRvY3VtZW50YXRpb25dKGh0dHBzOi8vZmxvYXRpbmctdWkuY29tLykuXG4gKi9cbkBJbmplY3RhYmxlKHtcbiAgcHJvdmlkZWRJbjogJ3Jvb3QnXG59KVxuZXhwb3J0IGNsYXNzIEZsb2F0aW5nVUlTZXJ2aWNlIHtcbiAgY29uc3RydWN0b3IoXG4gICAgcHJpdmF0ZSByZW5kZXJlckZhY3Rvcnk6IFJlbmRlcmVyRmFjdG9yeTIsXG4gICAgcHJpdmF0ZSB1dWlkU2VydmljZTogVVVJRFNlcnZpY2UsXG4gICAgcHJpdmF0ZSBhcHBSZWFkeVNlcnZpY2U6IEFwcFJlYWR5U2VydmljZVxuICApIHtcbiAgICB0aGlzLnJlbmRlcmVyID0gcmVuZGVyZXJGYWN0b3J5LmNyZWF0ZVJlbmRlcmVyKG51bGwsIG51bGwpO1xuICB9XG4gIC8qKiBAaWdub3JlICovXG4gIHByaXZhdGUgcmVuZGVyZXI6IFJlbmRlcmVyMjtcbiAgLyoqIEBpZ25vcmUgKi9cbiAgdHJpZ2dlcjogRWxlbWVudDtcbiAgLyoqIEBpZ25vcmUgKi9cbiAgZmxvYXRpbmdVSTogRWxlbWVudFJlZjtcbiAgLyoqIEBpZ25vcmUgKi9cbiAgYXJyb3c6IFRvb2x0aXBBcnJvd0RpcmVjdGl2ZTtcbiAgLyoqIEBpZ25vcmUgKi9cbiAgZXZlbnRBcnJheTogVUlFdmVudFZpc2liaWxpdHlQYWlyO1xuICAvKiogQGlnbm9yZSAqL1xuICBvZmZzZXQ6IG51bWJlcjtcbiAgLyoqIEBpZ25vcmUgKi9cbiAgb2Zmc2V0RGVmYXVsdCA9IDI7XG4gIC8qKiBAaWdub3JlICovXG4gIGNvbWJvYm94TWlkZGxld2FyZTogYW55ID0gW29mZnNldCgwKSwgZmxpcCgpLCBzaGlmdCgpXTtcbiAgLyoqIEBpZ25vcmUgKi9cbiAgbWlkZGxld2FyZURlZmF1bHQ6IGFueSA9IFtvZmZzZXQodGhpcy5vZmZzZXREZWZhdWx0KSwgZmxpcCgpLCBzaGlmdCgpXTtcbiAgLyoqIEBpZ25vcmUgKi9cbiAgbWlkZGxld2FyZTogYW55ID0gdGhpcy5taWRkbGV3YXJlRGVmYXVsdDtcbiAgLyoqIEBpZ25vcmUgKi9cbiAgcGxhY2VtZW50OiBGbG9hdGluZ1VJUGxhY2VtZW50cyA9IEZsb2F0aW5nVUlQbGFjZW1lbnRzLkJPVFRPTTtcbiAgLyoqIEBpZ25vcmUgKi9cbiAgaXNTaG93biA9IHNpZ25hbChmYWxzZSk7XG5cbiAgLyoqXG4gICAqIERpc3BsYXlzIHByb3BlcnR5IG9mIHRoZSBmbG9hdGluZyBVSSBlbGVtZW50LlxuICAgKiBAZGVmYXVsdCAnZmxleCdcbiAgICovXG4gIGRpc3BsYXkgPSAnZmxleCc7XG5cbiAgLyoqXG4gICAqIFRpbWUgaW4gbWlsbGlzZWNvbmRzIHRvIHdhaXQgYmVmb3JlIGhpZGluZyB0aGUgZmxvYXRpbmcgVUkgZWxlbWVudCB3aGVuIHRoZSB0cmlnZ2VyIGlzIGhvdmVyZWQgb3Zlci5cbiAgICogQGRlZmF1bHQgQSBmYWN0b3Igb2YgdGhlIG9mZnNldCBtaWRkbGV3YXJlIG9wdGlvbiBpZiBwcm92aWRlZCwgb3RoZXJ3aXNlIDUwLlxuICAgKi9cbiAgaGlkZU9uSG92ZXJUaW1lb3V0OiBudW1iZXI7XG5cbiAgLyoqXG4gICAqIEVtaXRzIHRydWUgd2hlbiB0aGlzIGZsb2F0aW5nIFVJIGVsZW1lbnQgaXMgc2hvd24gYW5kIGZhbHNlIHdoZW4gaGlkZGVuLlxuICAgKi9cbiAgQE91dHB1dCgpIGlzU2hvd25FbWl0dGVyID0gbmV3IEV2ZW50RW1pdHRlcigpO1xuXG4gIC8qKlxuICAgKiBUaGXCoHNldFVwRmxvYXRpbmdVScKgbWV0aG9kIGlzIHJlcXVpcmVkIHRvIGluaXRpYWxpemUgdGhlIGZsb2F0aW5nIGVsZW1lbnQgYW5kIGl0cyB0cmlnZ2VyLiA8YnIgLz5cbiAgICogQ2FsbGVkIGJ5IGRlZmF1bHQgd2l0aCBGbG9hdGluZ1VJQ29udGFpbmVyIG9yIENvbWJvYm94RGlyZWN0aXZlLlxuICAgKiBAcGFyYW0gcmVmZXJlbmNlRWwgUmVmZXJlbmNlcyBlbGVtZW50IHRoYXQgd2lsbCB0cmlnZ2VyIGZsb2F0aW5nIFVJLlxuICAgKiBAcGFyYW0gZmxvYXRpbmdFbCBSZWZlcmVuY2VzIGZsb2F0aW5nIFVJIGVsZW1lbnQuXG4gICAqIEBwYXJhbSBldmVudEFycmF5IEFycmF5IG9mIGV2ZW50cyBmb3IgdGhlIHJlZmVyZW5jZS90cmlnZ2VyIGVsZW1lbnQgdG8gbGlzdGVuIGZvci4gPGJyPiBpLmUuIDxjb2RlPltuZXcgVUlFdmVudCgnZm9jdXMnKSwgRmxvYXRpbmdVSVZpc2liaWxpdHkuU0hPV108L2NvZGU+IDxicj4gdGVsbHMgdGhlIGVsZW1lbnQgdG8gc2hvdyB0aGUgZmxvYXRpbmcgVUkgd2hlbiB0aGUgdHJpZ2dlcmluZyBlbGVtZW50IGlzIGZvY3VzZWQuXG4gICAqL1xuICBzZXRVcGZsb2F0aW5nVUkocmVmZXJlbmNlRWw6IEVsZW1lbnRSZWYgfCBIVE1MRWxlbWVudCwgZmxvYXRpbmdFbDogRWxlbWVudFJlZiwgZXZlbnRBcnJheTogVUlFdmVudFZpc2liaWxpdHlQYWlyKSB7XG4gICAgdGhpcy50cmlnZ2VyID0gdGhpcy5uYXRpdmVFbGVtZW50KHJlZmVyZW5jZUVsKTtcbiAgICB0aGlzLmZsb2F0aW5nVUkgPSBmbG9hdGluZ0VsO1xuXG4gICAgdGhpcy5yZW5kZXJlci5zZXRTdHlsZSh0aGlzLmZsb2F0aW5nVUkubmF0aXZlRWxlbWVudCwgJ3RvcCcsICcwJyk7XG4gICAgdGhpcy5yZW5kZXJlci5zZXRTdHlsZSh0aGlzLmZsb2F0aW5nVUkubmF0aXZlRWxlbWVudCwgJ2xlZnQnLCAnMCcpO1xuICAgIHRoaXMucmVuZGVyZXIuc2V0U3R5bGUodGhpcy5mbG9hdGluZ1VJLm5hdGl2ZUVsZW1lbnQsICdkaXNwbGF5JywgJ25vbmUnKTtcblxuICAgIGlmIChldmVudEFycmF5KSB7XG4gICAgICB0aGlzLnNldFVwVHJpZ2dlcihldmVudEFycmF5KTtcbiAgICB9IGVsc2Uge1xuICAgICAgY29uc29sZS5lcnJvcignTm8gZXZlbnRzIHByb3ZpZGVkIHRvIHRyaWdnZXIgdGhlIEZsb2F0aW5nIFVJLicpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBUaGUgbmF0aXZlRWxlbWVudCBtZXRob2QgcmV0dXJucyB0aGXCoEVsZW1lbnTCoHR5cGUgb2YgdGhlIHJlZmVyZW5jZSBlbGVtZW50LlxuICAgKiBAcGFyYW0gZWxlbWVudCBFbGVtZW50IHRvIGJlIGNvbnZlcnRlZCB0byBFbGVtZW50IHR5cGUuXG4gICAqIEByZXR1cm5zIEVsZW1lbnRcbiAgICovXG4gIG5hdGl2ZUVsZW1lbnQoZWxlbWVudDogRWxlbWVudFJlZjxhbnk+IHwgSFRNTEVsZW1lbnQpOiBFbGVtZW50IHtcbiAgICBpZiAoZWxlbWVudCBpbnN0YW5jZW9mIEVsZW1lbnRSZWYpIHtcbiAgICAgIHJldHVybiBlbGVtZW50Lm5hdGl2ZUVsZW1lbnQ7XG4gICAgfVxuICAgIHJldHVybiBlbGVtZW50O1xuICB9XG5cbiAgLyoqXG4gICAqIFRoZcKgY3VzdG9taXplRmxvYXRpbmdVScKgbWV0aG9kIGFsbG93cyB5b3UgdG8gcHJvdmlkZSBjdXN0b20gcGxhY2VtZW50IGFuZCBtaWRkbGV3YXJlIG9wdGlvbnMgdG8gdGhlIEZsb2F0aW5nIFVJIHNlcnZpY2UuXG4gICAqIEBwYXJhbSBwbGFjZW1lbnQgT3B0aW9uYWwuIFNlZSA8Y29kZT5GbG9hdGluZ1VJUGxhY2VtZW50czwvY29kZT4gZW51bS5cbiAgICogQHBhcmFtIG1pZGRsZXdhcmUgT3B0aW9uYWwuIFZpc2l0IHRoZSBvZmZpY2lhbCBGbG9hdGluZyBVSSBkb2N1bWVudGF0aW9uIGZvciBtb3JlIG9uIFttaWRkbGV3YXJlIG9wdGlvbnNdKGh0dHBzOi8vZmxvYXRpbmctdWkuY29tL2RvY3MvY29tcHV0ZVBvc2l0aW9uI21pZGRsZXdhcmUpLlxuICAgKiBAcGFyYW0gZGlzcGxheSBPcHRpb25hbC4gU2V0cyBDU1MgZGlzcGxheSBwcm9wZXJ0eSBmb3IgdGhlIGZsb2F0aW5nIFVJIGVsZW1lbnQuXG4gICAqIEBwYXJhbSB0b29sdGlwQXJyb3cgT3B0aW9uYWwuIERpcmVjdGl2ZSByZWZlcmVuY2UgdG8gdGhlIGFycm93IGVsZW1lbnQuIFNlZSBUb29sdGlwQXJyb3dEaXJlY3RpdmUuXG4gICAqL1xuICBjdXN0b21pemVGbG9hdGluZ1VJKFxuICAgIHBsYWNlbWVudD86IEZsb2F0aW5nVUlQbGFjZW1lbnRzLFxuICAgIG1pZGRsZXdhcmU/OiBhbnksXG4gICAgZGlzcGxheT86IHN0cmluZyxcbiAgICB0b29sdGlwQXJyb3c/OiBUb29sdGlwQXJyb3dEaXJlY3RpdmVcbiAgKSB7XG4gICAgaWYgKHBsYWNlbWVudCkge1xuICAgICAgdGhpcy5wbGFjZW1lbnQgPSBwbGFjZW1lbnQ7XG4gICAgfVxuICAgIGlmIChtaWRkbGV3YXJlKSB7XG4gICAgICB0aGlzLm1pZGRsZXdhcmUgPSBtaWRkbGV3YXJlO1xuICAgICAgLy8gc2F2ZSBhIGN1c3RvbSBvZmZzZXRcbiAgICAgIGNvbnN0IGN1c3RvbU9mZnNldCA9ICh0aGlzLm1pZGRsZXdhcmUuZmluZCgobTogYW55KSA9PiBtWyduYW1lJ10gPT09ICdvZmZzZXQnKSBhcyBhbnkpIHx8IDI7XG4gICAgICB0aGlzLm9mZnNldCA9IGN1c3RvbU9mZnNldC5vcHRpb25zO1xuICAgIH1cbiAgICBpZiAoZGlzcGxheSkge1xuICAgICAgdGhpcy5kaXNwbGF5ID0gZGlzcGxheTtcbiAgICB9XG5cbiAgICBpZiAodG9vbHRpcEFycm93KSB7XG4gICAgICB0aGlzLmFycm93ID0gdG9vbHRpcEFycm93O1xuICAgICAgLy8gdXBkYXRlIHRoZSBvZmZzZXQgdG8gZmFjdG9yIGluIHRoZSBhcnJvdyBzaXplIGlmIG5vIGN1c3RvbSBvZmZzZXQgd2FzIHBsYWNlZFxuICAgICAgY29uc3QgZmxvYXRpbmdPZmZzZXQgPSBNYXRoLmNlaWwoTWF0aC5zcXJ0KDIgKiB0aGlzLmFycm93LmN1c3RvbVNpemUgKiogMikgLyAyKTtcbiAgICAgIHRoaXMub2Zmc2V0ID0gdGhpcy5vZmZzZXQgPyBmbG9hdGluZ09mZnNldCArIHRoaXMub2Zmc2V0IDogZmxvYXRpbmdPZmZzZXQgKyB0aGlzLm9mZnNldERlZmF1bHQ7XG4gICAgICB0aGlzLm1pZGRsZXdhcmUucHVzaChhcnJvdyh7IGVsZW1lbnQ6IHRoaXMuYXJyb3cuZWwubmF0aXZlRWxlbWVudCB9KSk7XG4gICAgICBjb25zdCBvZmZzZXRJbmRleCA9IHRoaXMubWlkZGxld2FyZS5maW5kSW5kZXgoKGZ1bmM6IGFueSkgPT4gZnVuYy5uYW1lID09PSAnb2Zmc2V0Jyk7XG5cbiAgICAgIC8vIFNUQVJUIEdFTkFJQENIQVRHUFQ0XG4gICAgICBpZiAob2Zmc2V0SW5kZXggIT09IC0xKSB7XG4gICAgICAgIC8vIFJlcGxhY2UgdGhlIG9sZCBvZmZzZXQgZnVuY3Rpb24gd2l0aCB0aGUgbmV3IG9uZVxuICAgICAgICB0aGlzLm1pZGRsZXdhcmUgPSBbXG4gICAgICAgICAgLi4udGhpcy5taWRkbGV3YXJlLnNsaWNlKDAsIG9mZnNldEluZGV4KSxcbiAgICAgICAgICBvZmZzZXQodGhpcy5vZmZzZXQpLFxuICAgICAgICAgIC4uLnRoaXMubWlkZGxld2FyZS5zbGljZShvZmZzZXRJbmRleCArIDEpXG4gICAgICAgIF07XG4gICAgICB9IGVsc2Uge1xuICAgICAgICAvLyBJZiBubyBvbGQgb2Zmc2V0IGZ1bmN0aW9uIGlzIGZvdW5kLCBqdXN0IGFkZCB0aGUgbmV3IG9uZVxuICAgICAgICB0aGlzLm1pZGRsZXdhcmUgPSBbLi4udGhpcy5taWRkbGV3YXJlLCBvZmZzZXQodGhpcy5vZmZzZXQpXTtcbiAgICAgIH1cbiAgICAgIC8vIEVORCBHRU5BSUBDSEFUR1BUNFxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBUaGXCoHBvc2l0aW9uRmxvYXRpbmdVScKgbWV0aG9kIHBvc2l0aW9ucyB0aGUgRmxvYXRpbmcgVUkgYmFzZWQgb24gdGhlIGdpdmVuIHBsYWNlbWVudCBhbmQgbWlkZGxld2FyZS4gPGJyIC8+XG4gICAqIEZvciBtb3JlIGRldGFpbHMgb24gdGhlIGludGVybmFsIGZ1bmN0aW9uLCByZWZlciB0byBGbG9hdGluZyBVSSdzIFtjb21wdXRlIHBvc2l0aW9uIGRvY3VtZW50YXRpb25dKGh0dHBzOi8vZmxvYXRpbmctdWkuY29tL2RvY3MvY29tcHV0ZVBvc2l0aW9uKS5cbiAgICogQHBhcmFtIHRyaWdnZXIgVGhlIHRyaWdnZXJpbmcgZWxlbWVudC5cbiAgICogQHBhcmFtIGZsb2F0aW5nVUkgVGhlIGVsZW1lbnQgdGhhdCB3aWxsIFwiZmxvYXRcIiB3aGVuIHRyaWdnZXJlZC5cbiAgICogQHBhcmFtIHBsYWNlbWVudCBSZWZlcmVuY2UgRmxvYXRpbmdVSVBsYWNlbWVudHMuXG4gICAqIEBwYXJhbSBtaWRkbGV3YXJlIFZpc2l0IHRoZSBvZmZpY2lhbCBGbG9hdGluZyBVSSBkb2N1bWVudGF0aW9uIGZvciBtb3JlIG9uIFttaWRkbGV3YXJlIG9wdGlvbnNdKGh0dHBzOi8vZmxvYXRpbmctdWkuY29tL2RvY3MvY29tcHV0ZVBvc2l0aW9uI21pZGRsZXdhcmUpLlxuICAgKi9cbiAgcG9zaXRpb25GbG9hdGluZ1VJKFxuICAgIHRyaWdnZXI6IEVsZW1lbnQgPSB0aGlzLnRyaWdnZXIsXG4gICAgZmxvYXRpbmdVSTogSFRNTEVsZW1lbnQgPSB0aGlzLmZsb2F0aW5nVUkubmF0aXZlRWxlbWVudCxcbiAgICBwbGFjZW1lbnQ6IEZsb2F0aW5nVUlQbGFjZW1lbnRzID0gdGhpcy5wbGFjZW1lbnRcbiAgKSB7XG4gICAgYXV0b1VwZGF0ZSh0cmlnZ2VyLCBmbG9hdGluZ1VJLCAoKSA9PiB7XG4gICAgICBjb21wdXRlUG9zaXRpb24odHJpZ2dlciwgZmxvYXRpbmdVSSwge1xuICAgICAgICBwbGFjZW1lbnQ6IHBsYWNlbWVudCxcbiAgICAgICAgbWlkZGxld2FyZTogdGhpcy5taWRkbGV3YXJlXG4gICAgICB9KS50aGVuKCh7IHgsIHksIG1pZGRsZXdhcmVEYXRhLCBwbGFjZW1lbnQgfTogQ29tcHV0ZVBvc2l0aW9uUmV0dXJuKSA9PiB7XG4gICAgICAgIGZsb2F0aW5nVUkuc3R5bGUubGVmdCA9IGAke3h9cHhgO1xuICAgICAgICBmbG9hdGluZ1VJLnN0eWxlLnRvcCA9IGAke3l9cHhgO1xuXG4gICAgICAgIGlmIChtaWRkbGV3YXJlRGF0YS5hcnJvdykge1xuICAgICAgICAgIC8vIHNlZTogaHR0cHM6Ly9jb2Rlc2FuZGJveC5pby9zL215c3RpZnlpbmcta2FyZS1lZTNobWg/ZmlsZT0vc3JjL2luZGV4LmpzXG4gICAgICAgICAgaWYgKHRoaXMuYXJyb3cpIHtcbiAgICAgICAgICAgIGNvbnN0IHsgeCwgeSB9ID0gbWlkZGxld2FyZURhdGEuYXJyb3c7XG5cbiAgICAgICAgICAgIHRoaXMucmVuZGVyZXIuc2V0U3R5bGUodGhpcy5hcnJvdy5lbC5uYXRpdmVFbGVtZW50LCAnbGVmdCcsIHggIT0gbnVsbCA/IGAke3h9cHhgIDogJycpO1xuICAgICAgICAgICAgdGhpcy5yZW5kZXJlci5zZXRTdHlsZSh0aGlzLmFycm93LmVsLm5hdGl2ZUVsZW1lbnQsICd0b3AnLCB5ICE9IG51bGwgPyBgJHt5fXB4YCA6ICcnKTtcbiAgICAgICAgICAgIHRoaXMucmVuZGVyZXIuc2V0U3R5bGUodGhpcy5hcnJvdy5lbC5uYXRpdmVFbGVtZW50LCAncmlnaHQnLCAnJyk7XG4gICAgICAgICAgICB0aGlzLnJlbmRlcmVyLnNldFN0eWxlKHRoaXMuYXJyb3cuZWwubmF0aXZlRWxlbWVudCwgJ2JvdHRvbScsICcnKTtcblxuICAgICAgICAgICAgY29uc3Qgc2lkZSA9IHBsYWNlbWVudC5zcGxpdCgnLScpWzBdO1xuICAgICAgICAgICAgY29uc3Qgc3RhdGljU2lkZSA9IHtcbiAgICAgICAgICAgICAgdG9wOiAnYm90dG9tJyxcbiAgICAgICAgICAgICAgYm90dG9tOiAndG9wJyxcbiAgICAgICAgICAgICAgbGVmdDogJ3JpZ2h0JyxcbiAgICAgICAgICAgICAgcmlnaHQ6ICdsZWZ0J1xuICAgICAgICAgICAgfVtzaWRlXTtcblxuICAgICAgICAgICAgaWYgKHN0YXRpY1NpZGUpIHtcbiAgICAgICAgICAgICAgdGhpcy5yZW5kZXJlci5zZXRTdHlsZShcbiAgICAgICAgICAgICAgICB0aGlzLmFycm93LmVsLm5hdGl2ZUVsZW1lbnQsXG4gICAgICAgICAgICAgICAgc3RhdGljU2lkZSxcbiAgICAgICAgICAgICAgICAtKHRoaXMuYXJyb3cuZWwubmF0aXZlRWxlbWVudC5vZmZzZXRXaWR0aCAvIDIpICsgJ3B4J1xuICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogVGhlwqBzaG93RmxvYXRpbmdVScKgbWV0aG9kIGRpc3BsYXlzIHRoZSBGbG9hdGluZyBVSSBlbGVtZW50LlxuICAgKi9cbiAgc2hvd2Zsb2F0aW5nVUkoKSB7XG4gICAgaWYgKHRoaXMuYXBwUmVhZHlTZXJ2aWNlLmlzQnJvd3NlckFuZERvbUF2YWlsYWJsZSgpKSB7XG4gICAgICBjb25zdCB0cmlnZ2VyRGlzYWJsZWQgPSB0aGlzLnRyaWdnZXIuZ2V0QXR0cmlidXRlKCdkaXNhYmxlZCcpO1xuICAgICAgaWYgKHRyaWdnZXJEaXNhYmxlZCkgcmV0dXJuO1xuICAgIH1cbiAgICB0aGlzLnBvc2l0aW9uRmxvYXRpbmdVSSgpO1xuICAgIHRoaXMuaXNTaG93bi5zZXQodHJ1ZSk7XG4gICAgdGhpcy5pc1Nob3duRW1pdHRlci5lbWl0KHRoaXMuaXNTaG93bigpKTtcbiAgICB0aGlzLnJlbmRlcmVyLnNldFN0eWxlKHRoaXMuZmxvYXRpbmdVSS5uYXRpdmVFbGVtZW50LCAnZGlzcGxheScsIHRoaXMuZGlzcGxheSk7XG4gIH1cblxuICAvKipcbiAgICogVGhlwqBoaWRlRmxvYXRpbmdVScKgbWV0aG9kIGhpZGVzIHRoZSBGbG9hdGluZyBVSSBlbGVtZW50LlxuICAgKi9cbiAgaGlkZWZsb2F0aW5nVUkoKSB7XG4gICAgdGhpcy5yZW5kZXJlci5zZXRTdHlsZSh0aGlzLmZsb2F0aW5nVUkubmF0aXZlRWxlbWVudCwgJ2Rpc3BsYXknLCAnbm9uZScpO1xuICAgIHRoaXMuaXNTaG93bi5zZXQoZmFsc2UpO1xuICAgIHRoaXMuaXNTaG93bkVtaXR0ZXIuZW1pdCh0aGlzLmlzU2hvd24oKSk7XG4gIH1cblxuICAvKipcbiAgICogVGhlwqB0b2dnbGVGbG9hdGluZ1VJwqBtZXRob2QgdG9nZ2xlcyB0aGUgdmlzaWJpbGl0eSBvZiB0aGUgRmxvYXRpbmcgVUkgZWxlbWVudC5cbiAgICovXG4gIHRvZ2dsZUZsb2F0aW5nVUkoKSB7XG4gICAgaWYgKHRoaXMuaXNTaG93bigpKSB7XG4gICAgICB0aGlzLmhpZGVmbG9hdGluZ1VJKCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMuc2hvd2Zsb2F0aW5nVUkoKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogVGhlwqBjbG9zZU9uQ2xpY2tPdXTCoG1ldGhvZCBjbG9zZXMgdGhlIG1lbnUgd2hlbiBhIGNsaWNrIG9jY3VycyBvdXRzaWRlIG9mIHRoZSBtZW51IGFuZCB0aGUgdHJpZ2dlcmluZyBlbGVtZW50LlxuICAgKiBAcGFyYW0gZXZlbnQgRG9jdW1lbnQgY2xpY2sgZXZlbnQuXG4gICAqL1xuICBjbG9zZU9uQ2xpY2tPdXQoZXZlbnQ6IEV2ZW50KSB7XG4gICAgLy8gbGlzdGVuIGZvciBkb2N1bWVudCBjbGljayBhbmQgY2xvc2UgbWVudSBpZiBjbGljayBpcyBvdXRzaWRlIG9mIGNvbXBvbmVudFxuICAgIGlmICh0aGlzLmlzU2hvd24oKSkge1xuICAgICAgY29uc3QgdGFyZ2V0ID0gZXZlbnQudGFyZ2V0IGFzIEhUTUxJbnB1dEVsZW1lbnQ7XG4gICAgICBpZiAoIXRoaXMuZmxvYXRpbmdVSS5uYXRpdmVFbGVtZW50LmNvbnRhaW5zKGV2ZW50LnRhcmdldCkgJiYgIXRoaXMudHJpZ2dlci5jb250YWlucyh0YXJnZXQpKSB7XG4gICAgICAgIHRoaXMuaGlkZWZsb2F0aW5nVUkoKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogVGhlwqBhZGRDbG9zZUFjdGlvbnPCoG1ldGhvZCBhZGRzIGRlZmF1bHQgY2xvc2UgYWN0aW9ucyB0byB0aGUgRmxvYXRpbmcgVUkgY29tcG9uZW50LiBUaGVzZSBhY3Rpb25zIGluY2x1ZGUgY2xvc2luZyB0aGUgbWVudSB3aGVuIHRoZSBlc2NhcGUga2V5IGlzIHByZXNzZWQgb3Igd2hlbiBjbGlja2luZyBvdXRzaWRlIG9mIHRoZSBmbG9hdGluZyBlbGVtZW50LlxuICAgKi9cbiAgYWRkQ2xvc2VBY3Rpb25zKCkge1xuICAgIGNvbnN0IGRvY3VtZW50ID0gdGhpcy5hcHBSZWFkeVNlcnZpY2UuY2hlY2tEb2N1bWVudEV4aXN0cygpO1xuICAgIC8vIGNsb3NlIG1lbnUgb24gZXNjYXBlIGtleSBwcmVzcyBvciBjbGlja2luZyBvdXRzaWRlIG9mIG1lbnVcbiAgICBpZiAoZG9jdW1lbnQpIHtcbiAgICAgIHRoaXMucmVuZGVyZXIubGlzdGVuKGRvY3VtZW50LCAnY2xpY2snLCB0aGlzLmNsb3NlT25DbGlja091dC5iaW5kKHRoaXMpKTtcbiAgICAgIHRoaXMucmVuZGVyZXIubGlzdGVuKGRvY3VtZW50LCAna2V5ZG93bi5lc2MnLCB0aGlzLmhpZGVmbG9hdGluZ1VJLmJpbmQodGhpcykpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBUaGXCoHNldFVwVHJpZ2dlcsKgbWV0aG9kIGNvbmZpZ3VyZXMgdGhlIHRyaWdnZXJpbmcgZWxlbWVudCBieSBzZXR0aW5nIHVwIHRoZSBldmVudHMgdG8gbGlzdGVuIGZvciBhbmQgdGhlIGFjdGlvbnMgdG8gdGFrZSB3aGVuIHRob3NlIGV2ZW50cyBhcmUgdHJpZ2dlcmVkLlxuICAgKiBAcGFyYW0gZXZlbnRBcnJheSBBcnJheSBvZiBldmVudHMgZm9yIHRoZSByZWZlcmVuY2UvdHJpZ2dlciBlbGVtZW50IHRvIGxpc3RlbiBmb3IuPGJyPiBpLmUuIDxjb2RlPltuZXcgVUlFdmVudCgnZm9jdXMnKSwgRmxvYXRpbmdVSVZpc2liaWxpdHkuU0hPV108L2NvZGU+IDxicj4gdGVsbHMgdGhlIGVsZW1lbnQgdG8gc2hvdyB0aGUgZmxvYXRpbmcgVUkgd2hlbiB0aGUgdHJpZ2dlcmluZyBlbGVtZW50IGlzIGZvY3VzZWQuXG4gICAqL1xuICBzZXRVcFRyaWdnZXIoZXZlbnRBcnJheTogVUlFdmVudFZpc2liaWxpdHlQYWlyKSB7XG4gICAgLy8gYWRkIGRlZmF1bHQgYWN0aW9ucyB0byBjbG9zZSBtZW51XG4gICAgdGhpcy5hZGRDbG9zZUFjdGlvbnMoKTtcbiAgICBldmVudEFycmF5LmZvckVhY2goKHBhaXIpID0+IHtcbiAgICAgIC8qKlxuICAgICAgICogaWYgYSBjdXN0b20gZXZlbnRBcnJheSBpcyAqKm5vdCoqIHR5cGVkIGFzIFVJRXZlbnRWaXNpYmlsaXR5UGFpcltdLDxiciAvPlxuICAgICAgICogVHlwZXNjcmlwdCB3aWxsIHR5cGUgdGhlIGFycmF5IGFzICgoVUlFdmVudCB8IFwic2hvd1wiKVtdIHwgKFVJRXZlbnQgfCBcImhpZGVcIilbXSlbXSA8YnIgLz5cbiAgICAgICAqIGJlY2F1c2UgdGhlIHBhc3NlZCBhcnJheXMgaGF2ZSBkaWZmZXJlbnQgdHlwZXMsIHRoZSB0eXBlIG9mIHRoZSBhcnJheSBpcyBpbmZlcnJlZCBhcyBhIHVuaW9uIG9mIHRoZSB0eXBlcyBvZiB0aGUgcGFzc2VkIGFycmF5cy4gPGJyIC8+XG4gICAgICAgKiBUaGUgZm9sbG93aW5nIGNvZGUgZW5zdXJlcyB0aGUgY29ycmVjdCB0eXBlcyBhcmUgYXNzaWduZWQgdG8gdGhlIGV2ZW50IGFuZCBsaXN0ZW5lciB2YXJpYWJsZXMuXG4gICAgICAgKi9cbiAgICAgIGNvbnN0IGV2ZW50OiBVSUV2ZW50IHwgdW5kZWZpbmVkIHwgRmxvYXRpbmdVSVZpc2liaWxpdHkgPSBwYWlyLmZpbmQoKGUpID0+IGUgaW5zdGFuY2VvZiBVSUV2ZW50KTtcbiAgICAgIGNvbnN0IGxpc3RlbmVyOiBGbG9hdGluZ1VJVmlzaWJpbGl0eSB8IHVuZGVmaW5lZCB8IFVJRXZlbnQgPSBwYWlyLmZpbmQoXG4gICAgICAgIChlKSA9PiBlID09PSBGbG9hdGluZ1VJVmlzaWJpbGl0eS5TSE9XIHx8IGUgPT09IEZsb2F0aW5nVUlWaXNpYmlsaXR5LkhJREVcbiAgICAgICk7XG4gICAgICBpZiAoZXZlbnQgaW5zdGFuY2VvZiBVSUV2ZW50KSB7XG4gICAgICAgIGlmIChldmVudC50eXBlID09PSAnY2xpY2snKSB7XG4gICAgICAgICAgdGhpcy5yZW5kZXJlci5saXN0ZW4odGhpcy50cmlnZ2VyLCBldmVudC50eXBlLCB0aGlzLnRvZ2dsZUZsb2F0aW5nVUkuYmluZCh0aGlzKSk7XG4gICAgICAgIH0gZWxzZSBpZiAoZXZlbnQudHlwZSA9PT0gJ21vdXNlbGVhdmUnICYmIGxpc3RlbmVyICYmIGxpc3RlbmVyID09PSBGbG9hdGluZ1VJVmlzaWJpbGl0eS5ISURFKSB7XG4gICAgICAgICAgdGhpcy5rZWVwT25Ib3ZlcigpO1xuICAgICAgICB9IGVsc2UgaWYgKGxpc3RlbmVyICYmIGxpc3RlbmVyID09PSBGbG9hdGluZ1VJVmlzaWJpbGl0eS5TSE9XKSB7XG4gICAgICAgICAgdGhpcy5yZW5kZXJlci5saXN0ZW4odGhpcy50cmlnZ2VyLCBldmVudC50eXBlLCB0aGlzLnNob3dmbG9hdGluZ1VJLmJpbmQodGhpcykpO1xuICAgICAgICB9IGVsc2UgaWYgKGxpc3RlbmVyICYmIGxpc3RlbmVyID09PSBGbG9hdGluZ1VJVmlzaWJpbGl0eS5ISURFKSB7XG4gICAgICAgICAgdGhpcy5yZW5kZXJlci5saXN0ZW4odGhpcy50cmlnZ2VyLCBldmVudC50eXBlLCB0aGlzLmhpZGVmbG9hdGluZ1VJLmJpbmQodGhpcykpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfSk7XG4gIH1cblxuICAvLyBmb3Iga2VlcE9uSG92ZXJcbiAgLyoqIEBpZ25vcmUgKi9cbiAgb25Ub29sdGlwID0gZmFsc2U7XG4gIC8qKiBAaWdub3JlICovXG4gIG9uVHJpZ2dlciA9IGZhbHNlO1xuXG4gIC8qKlxuICAgKiBUaGUga2VlcE9uSG92ZXIgbWV0aG9kIGtlZXBzIHRoZSBmbG9hdGluZyBlbGVtZW50IHZpc2libGUgd2hlbiBob3ZlcmluZyBvdmVyIHRoZSB0cmlnZ2VyIG9yIHRoZSBmbG9hdGluZyBlbGVtZW50LlxuICAgKi9cbiAga2VlcE9uSG92ZXIoKSB7XG4gICAgbGV0IG9mZnNldCA9IHRoaXMubWlkZGxld2FyZS5maW5kKChtOiBhbnkpID0+IG1bJ25hbWUnXSA9PT0gJ29mZnNldCcpIGFzIGFueTtcbiAgICBvZmZzZXQgPSB0aGlzLmhpZGVPbkhvdmVyVGltZW91dCA/IHRoaXMuaGlkZU9uSG92ZXJUaW1lb3V0IDogb2Zmc2V0WydvcHRpb25zJ10gPyBvZmZzZXRbJ29wdGlvbnMnXSAqIDIwIDogNTA7XG4gICAgdGhpcy5yZW5kZXJlci5saXN0ZW4odGhpcy50cmlnZ2VyLCAnbW91c2VsZWF2ZScsICgpID0+IHtcbiAgICAgIHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgICB0aGlzLm9uVHJpZ2dlciA9IGZhbHNlO1xuICAgICAgICBpZiAoIXRoaXMub25Ub29sdGlwKSB7XG4gICAgICAgICAgdGhpcy5oaWRlZmxvYXRpbmdVSSgpO1xuICAgICAgICB9XG4gICAgICB9LCBvZmZzZXQpO1xuICAgIH0pO1xuICAgIHRoaXMucmVuZGVyZXIubGlzdGVuKHRoaXMudHJpZ2dlciwgJ21vdXNlZW50ZXInLCAoKSA9PiB7XG4gICAgICB0aGlzLm9uVHJpZ2dlciA9IHRydWU7XG4gICAgfSk7XG5cbiAgICB0aGlzLnJlbmRlcmVyLmxpc3Rlbih0aGlzLmZsb2F0aW5nVUkubmF0aXZlRWxlbWVudCwgJ21vdXNlZW50ZXInLCAoKSA9PiB7XG4gICAgICB0aGlzLm9uVG9vbHRpcCA9IHRydWU7XG4gICAgfSk7XG4gICAgdGhpcy5yZW5kZXJlci5saXN0ZW4odGhpcy5mbG9hdGluZ1VJLm5hdGl2ZUVsZW1lbnQsICdtb3VzZWxlYXZlJywgKCkgPT4ge1xuICAgICAgc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICAgIHRoaXMub25Ub29sdGlwID0gZmFsc2U7XG4gICAgICAgIGlmICghdGhpcy5vblRyaWdnZXIpIHtcbiAgICAgICAgICB0aGlzLmhpZGVmbG9hdGluZ1VJKCk7XG4gICAgICAgIH1cbiAgICAgIH0sIG9mZnNldCk7XG4gICAgfSk7XG4gIH1cbn1cbiJdfQ==