UNPKG

@ux-aspects/ux-aspects

Version:

Open source user interface framework for building modern, responsive, mobile big data applications

375 lines 56.1 kB
import { Overlay, ScrollDispatcher } from '@angular/cdk/overlay'; import { ComponentPortal } from '@angular/cdk/portal'; import { ChangeDetectorRef, Directive, ElementRef, EventEmitter, Input, Output, Renderer2, ViewContainerRef, inject } from '@angular/core'; import { Subject, fromEvent } from 'rxjs'; import { filter, takeUntil } from 'rxjs/operators'; import { OverlayPlacementService } from '../../services/overlay-placement/index'; import { TooltipComponent } from './tooltip.component'; import { TooltipService } from './tooltip.service'; import * as i0 from "@angular/core"; export class TooltipDirective { constructor() { this._elementRef = inject(ElementRef); this._viewContainerRef = inject(ViewContainerRef); this._overlay = inject(Overlay); this._scrollDispatcher = inject(ScrollDispatcher); this._changeDetectorRef = inject(ChangeDetectorRef); this._renderer = inject(Renderer2); this._tooltipService = inject(TooltipService); this._overlayFallback = inject(OverlayPlacementService); /** All the user to add a custom class to the tooltip */ this.customClass = ''; /** All the user to add a role to the tooltip - default is tooltip */ this.role = 'tooltip'; /** Provide the TemplateRef a context object */ this.context = {}; /** Delay the showing of the tooltip by a number of miliseconds */ this.delay = 0; /** Programmatically show and hide the tooltip */ this.isOpen = false; /** Customize how the tooltip should be positioned relative to the element */ this.placement = 'top'; /** Customize the position of the callout */ this.alignment = 'center'; /** Specify which events should show the tooltip */ this.showTriggers = ['mouseenter', 'focus']; /** Specify which events should hide the tooltip */ this.hideTriggers = ['mouseleave', 'blur']; /** Emits an event when the tooltip is shown */ this.shown = new EventEmitter(); /** Emits a event when the tooltip is hidden */ this.hidden = new EventEmitter(); /** Allow two way binding to track the visibility of the tooltip */ this.isOpenChange = new EventEmitter(); /** Keep track of the tooltip visibility */ this.isVisible = false; /** The name of the css class to use for the tooltip direction */ this.positionClass = this.placement; /** Define the overlay class */ this._overlayClass = 'ux-tooltip-pane'; /** This will emit when the directive is destroyed allowing us to unsubscribe all subscriptions automatically */ this._onDestroy = new Subject(); /** Store the timeout interval for cancelation */ this._showTimeoutId = null; /** Internally store the type of this component - usual for distinctions when extending this class */ this._type = 'tooltip'; } /** Set up the triggers and bind to the show/hide events to keep visibility in sync */ ngOnInit() { // set up show and hide event triggers fromEvent(this._elementRef.nativeElement, 'click').pipe(takeUntil(this._onDestroy)).subscribe(this.onClick.bind(this)); fromEvent(this._elementRef.nativeElement, 'mouseenter').pipe(takeUntil(this._onDestroy)).subscribe(this.onMouseEnter.bind(this)); fromEvent(this._elementRef.nativeElement, 'mouseleave').pipe(takeUntil(this._onDestroy)).subscribe(this.onMouseLeave.bind(this)); fromEvent(this._elementRef.nativeElement, 'focus').pipe(takeUntil(this._onDestroy)).subscribe(this.onFocus.bind(this)); fromEvent(this._elementRef.nativeElement, 'blur').pipe(takeUntil(this._onDestroy)).subscribe(this.onBlur.bind(this)); // when any other tooltips open hide this one this._tooltipService.shown$.pipe(filter(() => this._type === 'tooltip'), filter(tooltip => tooltip !== this._instance), takeUntil(this._onDestroy)).subscribe(this.hide.bind(this)); // if the tooltip should be initially visible then open it if (this.isOpen) { this.show(); } } /** * We need to send input changes to the tooltip component * We can't use setters as they may trigger before tooltip initialised and can't resend once initialised **/ ngOnChanges(changes) { // we can ignore the first change as it's handled in ngOnInit if (changes.isOpen && !changes.isOpen.firstChange && changes.isOpen.currentValue !== this.isVisible) { changes.isOpen.currentValue ? this.show() : this.hide(); } // destroy the overlay ref so a new correctly positioned instance will be created next time if (changes.placement) { this.destroyOverlay(); } if (this._instance && changes.placement) { this._instance.setPlacement(changes.placement.currentValue); } if (this._instance && changes.alignment) { this._instance.setAlignment(changes.alignment.currentValue); } if (this._instance && changes.content) { this._instance.setContent(changes.content.currentValue); } if (this._instance && changes.customClass) { this._instance.setClass(changes.customClass.currentValue); } if (this._instance && changes.context) { this._instance.setContext(changes.context.currentValue); } if (this._instance && changes.role) { this._instance.setContext(changes.role.currentValue); } } /** Ensure we clean up after ourselves */ ngOnDestroy() { // ensure we close the tooltip when the host is destroyed if (this._overlayRef) { this._overlayRef.dispose(); this._instance = null; } // clear any pending timeouts this.cancelTooltip(); // emit this event to automatically unsubscribe from all subscriptions this._onDestroy.next(); this._onDestroy.complete(); } /** Make the tooltip open */ show() { // if the tooltip is disabled then do nothing if (this.disabled || this.isVisible || this._showTimeoutId || !this.content) { return; } // delay the show by the delay amount this._showTimeoutId = window.setTimeout(() => { // create the tooltip and get the overlay ref const overlayRef = this.createOverlay(); // create the portal to create the tooltip component this._portal = this.createPortal(); this._instance = this.createInstance(overlayRef); // watch for any changes to the content this._instance.reposition$.pipe(takeUntil(this._onDestroy)).subscribe(this.reposition.bind(this)); // store the visible state this.isVisible = true; // ensure the overlay has the correct initial position this.reposition(); // emit the show events this.shown.emit(); this.isOpenChange.next(true); // clear the interval id this._showTimeoutId = null; // emit the show event to close any other tooltips this._tooltipService.shown$.next(this._instance); // ensure change detection is run this._changeDetectorRef.detectChanges(); }, this.delay); } /** If a tooltip exists and is visible, hide it */ hide() { // if we are waiting to show a tooltip then cancel the pending timeout if (this._showTimeoutId) { window.clearTimeout(this._showTimeoutId); this._showTimeoutId = null; return; } // if the tooltip is hidden then do nothing if (!this.isVisible) { return; } if (this._overlayRef && this._overlayRef.hasAttached()) { this._overlayRef.detach(); } this.setAriaDescribedBy(null); this._instance = null; // store the visible state this.isVisible = false; // emit the hide events this.hidden.emit(); this.isOpenChange.next(false); // ensure change detection is run this._changeDetectorRef.detectChanges(); } /** Toggle the visibility of the tooltip */ toggle() { this.isVisible ? this.hide() : this.show(); } /** Recalculate the position of the popover */ reposition() { if (this.isVisible && this._overlayRef) { this._overlayRef.updatePosition(); } } /** Create an instance from the overlay ref - allows overriding and additional logic here */ createInstance(overlayRef) { const instance = overlayRef.attach(this._portal).instance; // supply the tooltip with the correct properties instance.setContent(this.content); instance.setPlacement(this.placement); instance.setAlignment(this.alignment); instance.setClass(this.customClass); instance.setContext(this.context); instance.setRole(this.role); // Update the aria-describedby attribute this.setAriaDescribedBy(instance.id); return instance; } /** Create the component portal - allows overriding to allow other portals eg. popovers */ createPortal() { return this._portal || new ComponentPortal(TooltipComponent, this._viewContainerRef); } /** Create the overlay and set up the scroll handling behavior */ createOverlay() { // if the tooltip has already been created then just return the existing instance if (this._overlayRef) { return this._overlayRef; } const strategy = this._overlay.position() .flexibleConnectedTo(this._elementRef) .withFlexibleDimensions(false) .withPush(false); this._overlayRef = this._overlay.create({ positionStrategy: strategy, panelClass: this._overlayClass, scrollStrategy: this._overlay.scrollStrategies.reposition({ scrollThrottle: 0 }), hasBackdrop: false }); this._overlayFallback.updatePosition(this._overlayRef, this.placement, this.alignment, this.fallbackPlacement); strategy.positionChanges.subscribe(positionChange => { const currentPosition = positionChange.connectionPair; this.getPositionClass(currentPosition); }); return this._overlayRef; } /** Recreate the overlay ref using the updated origin and overlay positions */ destroyOverlay() { // destroy the existing overlay if (this._overlayRef && this._overlayRef.hasAttached()) { this._overlayRef.detach(); } if (this._overlayRef) { this._overlayRef.dispose(); this._overlayRef = null; } this.isVisible = false; } getPositionClass(currentPosition) { let positionClass = this.placement; if (currentPosition.originX === 'center') { positionClass = currentPosition.originY === 'top' ? 'top' : 'bottom'; } else if (currentPosition.originY === 'center') { positionClass = currentPosition.originX === 'start' ? 'left' : 'right'; } this._instance.positionClass = positionClass; this._changeDetectorRef.detectChanges(); } /** * Simple utility method - because IE doesn't support array.includes * And it isn't included in the core-js/es6 polyfills which are the * only ones required by Angular and guaranteed to be there **/ includes(array, value) { return Array.isArray(array) && !!array.find(item => item === value); } /** Handle the click event - show or hide accordingly */ onClick() { // if its not visible and click is a show trigger open it if (!this.isVisible && this.includes(this.showTriggers, 'click') && this._showTimeoutId === null) { return this.show(); } // if its visible and click is a hide trigger close it if (this.isVisible && this.includes(this.hideTriggers, 'click') && this._showTimeoutId === null) { return this.hide(); } // if its not visible and click is a hide trigger close it and there is a pending tooltip if (!this.isVisible && this.includes(this.hideTriggers, 'click') && this._showTimeoutId !== null) { return this.cancelTooltip(); } } /** Handle the mouse enter event - show or hide accordingly */ onMouseEnter() { // this is an show only trigger - if already open or it isn't a trigger do nothing if (this.isVisible || !this.includes(this.showTriggers, 'mouseenter')) { return; } // otherwise open the tooltip this.show(); } /** Handle the mouse leave event - show or hide accordingly */ onMouseLeave() { // If the tooltip is pending then cancel showing it if (!this.isVisible && this.includes(this.hideTriggers, 'mouseleave') && this._showTimeoutId !== null) { return this.cancelTooltip(); } // if the tooltip is not visible or mouseleave isn't a hide trigger then do nothing if (!this.isVisible || !this.includes(this.hideTriggers, 'mouseleave')) { return; } // otherwise close the tooltip this.hide(); } /** Handle the focus event - show or hide accordingly */ onFocus() { // this is an show only trigger - if already open or it isn't a trigger do nothing if (this.isVisible || !this.includes(this.showTriggers, 'focus')) { return; } // otherwise open the tooltip this.show(); } /** Handle the blur event - show or hide accordingly */ onBlur() { // If the tooltip is pending then cancel showing it if (!this.isVisible && this.includes(this.hideTriggers, 'blur') && this._showTimeoutId !== null) { return this.cancelTooltip(); } // this is an hide only trigger - if not open or it isn't a trigger do nothing if (!this.isVisible || !this.includes(this.hideTriggers, 'blur')) { return; } // otherwise close the tooltip this.hide(); } /** Programmatically update the aria-describedby property */ setAriaDescribedBy(id) { if (id === null) { this._renderer.removeAttribute(this._elementRef.nativeElement, 'aria-describedby'); } else { this._renderer.setAttribute(this._elementRef.nativeElement, 'aria-describedby', id); } } /** Cancel any pending tooltip (waiting on delay ellapsing) */ cancelTooltip() { if (this._showTimeoutId !== null) { window.clearTimeout(this._showTimeoutId); this._showTimeoutId = null; } } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.12", ngImport: i0, type: TooltipDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); } static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.2.12", type: TooltipDirective, selector: "[uxTooltip]", inputs: { content: ["uxTooltip", "content"], disabled: ["tooltipDisabled", "disabled"], customClass: ["tooltipClass", "customClass"], role: ["tooltipRole", "role"], context: ["tooltipContext", "context"], delay: ["tooltipDelay", "delay"], isOpen: "isOpen", placement: "placement", fallbackPlacement: "fallbackPlacement", alignment: "alignment", showTriggers: "showTriggers", hideTriggers: "hideTriggers" }, outputs: { shown: "shown", hidden: "hidden", isOpenChange: "isOpenChange" }, exportAs: ["ux-tooltip"], usesOnChanges: true, ngImport: i0 }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.12", ngImport: i0, type: TooltipDirective, decorators: [{ type: Directive, args: [{ selector: '[uxTooltip]', exportAs: 'ux-tooltip' }] }], propDecorators: { content: [{ type: Input, args: ['uxTooltip'] }], disabled: [{ type: Input, args: ['tooltipDisabled'] }], customClass: [{ type: Input, args: ['tooltipClass'] }], role: [{ type: Input, args: ['tooltipRole'] }], context: [{ type: Input, args: ['tooltipContext'] }], delay: [{ type: Input, args: ['tooltipDelay'] }], isOpen: [{ type: Input }], placement: [{ type: Input }], fallbackPlacement: [{ type: Input }], alignment: [{ type: Input }], showTriggers: [{ type: Input }], hideTriggers: [{ type: Input }], shown: [{ type: Output }], hidden: [{ type: Output }], isOpenChange: [{ type: Output }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidG9vbHRpcC5kaXJlY3RpdmUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9zcmMvY29tcG9uZW50cy90b29sdGlwL3Rvb2x0aXAuZGlyZWN0aXZlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBMEIsT0FBTyxFQUFjLGdCQUFnQixFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFDckcsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBQ3RELE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxTQUFTLEVBQUUsVUFBVSxFQUFFLFlBQVksRUFBRSxLQUFLLEVBQWdDLE1BQU0sRUFBRSxTQUFTLEVBQThCLGdCQUFnQixFQUFFLE1BQU0sRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUNyTSxPQUFPLEVBQUUsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUMxQyxPQUFPLEVBQUUsTUFBTSxFQUFFLFNBQVMsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBRW5ELE9BQU8sRUFBRSx1QkFBdUIsRUFBRSxNQUFNLHdDQUF3QyxDQUFDO0FBQ2pGLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBQ3ZELE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSxtQkFBbUIsQ0FBQzs7QUFNbkQsTUFBTSxPQUFPLGdCQUFnQjtJQUo3QjtRQUt1QixnQkFBVyxHQUFHLE1BQU0sQ0FBQyxVQUFVLENBQUMsQ0FBQztRQUVqQyxzQkFBaUIsR0FBRyxNQUFNLENBQUMsZ0JBQWdCLENBQUMsQ0FBQztRQUU3QyxhQUFRLEdBQUcsTUFBTSxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBRTNCLHNCQUFpQixHQUFHLE1BQU0sQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDO1FBRS9DLHVCQUFrQixHQUFHLE1BQU0sQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDO1FBRS9DLGNBQVMsR0FBRyxNQUFNLENBQUMsU0FBUyxDQUFDLENBQUM7UUFFOUIsb0JBQWUsR0FBRyxNQUFNLENBQUMsY0FBYyxDQUFDLENBQUM7UUFFekMscUJBQWdCLEdBQUcsTUFBTSxDQUFDLHVCQUF1QixDQUFDLENBQUM7UUFTcEUsd0RBQXdEO1FBQ2pDLGdCQUFXLEdBQVcsRUFBRSxDQUFDO1FBRWhELHFFQUFxRTtRQUMvQyxTQUFJLEdBQVcsU0FBUyxDQUFDO1FBRS9DLCtDQUErQztRQUV0QixZQUFPLEdBQVEsRUFBRSxDQUFDO1FBRTNDLGtFQUFrRTtRQUMzQyxVQUFLLEdBQVcsQ0FBQyxDQUFDO1FBRXpDLGlEQUFpRDtRQUN4QyxXQUFNLEdBQVksS0FBSyxDQUFDO1FBRWpDLDZFQUE2RTtRQUNwRSxjQUFTLEdBQW9CLEtBQUssQ0FBQztRQUs1Qyw0Q0FBNEM7UUFDbkMsY0FBUyxHQUFvQixRQUFRLENBQUM7UUFFL0MsbURBQW1EO1FBQzFDLGlCQUFZLEdBQXFCLENBQUMsWUFBWSxFQUFFLE9BQU8sQ0FBQyxDQUFDO1FBRWxFLG1EQUFtRDtRQUMxQyxpQkFBWSxHQUFxQixDQUFDLFlBQVksRUFBRSxNQUFNLENBQUMsQ0FBQztRQUVqRSwrQ0FBK0M7UUFDckMsVUFBSyxHQUFHLElBQUksWUFBWSxFQUFRLENBQUM7UUFFM0MsK0NBQStDO1FBQ3JDLFdBQU0sR0FBRyxJQUFJLFlBQVksRUFBUSxDQUFDO1FBRTVDLG1FQUFtRTtRQUN6RCxpQkFBWSxHQUFHLElBQUksWUFBWSxFQUFXLENBQUM7UUFFckQsMkNBQTJDO1FBQzNDLGNBQVMsR0FBWSxLQUFLLENBQUM7UUFFM0IsaUVBQWlFO1FBQ2pFLGtCQUFhLEdBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQztRQUUvQiwrQkFBK0I7UUFDckIsa0JBQWEsR0FBVyxpQkFBaUIsQ0FBQztRQVdwRCxnSEFBZ0g7UUFDdEcsZUFBVSxHQUFHLElBQUksT0FBTyxFQUFRLENBQUM7UUFFM0MsaURBQWlEO1FBQ3pDLG1CQUFjLEdBQVcsSUFBSSxDQUFDO1FBRXRDLHFHQUFxRztRQUMzRixVQUFLLEdBQVcsU0FBUyxDQUFDO0tBd1d2QztJQXRXRyxzRkFBc0Y7SUFDdEYsUUFBUTtRQUVKLHNDQUFzQztRQUN0QyxTQUFTLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxhQUFhLEVBQUUsT0FBTyxDQUFDLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQztRQUN2SCxTQUFTLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxhQUFhLEVBQUUsWUFBWSxDQUFDLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLFlBQVksQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQztRQUNqSSxTQUFTLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxhQUFhLEVBQUUsWUFBWSxDQUFDLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLFlBQVksQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQztRQUNqSSxTQUFTLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxhQUFhLEVBQUUsT0FBTyxDQUFDLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQztRQUN2SCxTQUFTLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxhQUFhLEVBQUUsTUFBTSxDQUFDLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQztRQUVy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Z0JBR0csTUFBTTtzQkFBZixNQUFNO2dCQUdHLFlBQVk7c0JBQXJCLE1BQU0iLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDb25uZWN0aW9uUG9zaXRpb25QYWlyLCBPdmVybGF5LCBPdmVybGF5UmVmLCBTY3JvbGxEaXNwYXRjaGVyIH0gZnJvbSAnQGFuZ3VsYXIvY2RrL292ZXJsYXknO1xuaW1wb3J0IHsgQ29tcG9uZW50UG9ydGFsIH0gZnJvbSAnQGFuZ3VsYXIvY2RrL3BvcnRhbCc7XG5pbXBvcnQgeyBDaGFuZ2VEZXRlY3RvclJlZiwgRGlyZWN0aXZlLCBFbGVtZW50UmVmLCBFdmVudEVtaXR0ZXIsIElucHV0LCBPbkNoYW5nZXMsIE9uRGVzdHJveSwgT25Jbml0LCBPdXRwdXQsIFJlbmRlcmVyMiwgU2ltcGxlQ2hhbmdlcywgVGVtcGxhdGVSZWYsIFZpZXdDb250YWluZXJSZWYsIGluamVjdCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgU3ViamVjdCwgZnJvbUV2ZW50IH0gZnJvbSAncnhqcyc7XG5pbXBvcnQgeyBmaWx0ZXIsIHRha2VVbnRpbCB9IGZyb20gJ3J4anMvb3BlcmF0b3JzJztcbmltcG9ydCB7IEFuY2hvckFsaWdubWVudCwgQW5jaG9yUGxhY2VtZW50IH0gZnJvbSAnLi4vLi4vY29tbW9uL292ZXJsYXkvaW5kZXgnO1xuaW1wb3J0IHsgT3ZlcmxheVBsYWNlbWVudFNlcnZpY2UgfSBmcm9tICcuLi8uLi9zZXJ2aWNlcy9vdmVybGF5LXBsYWNlbWVudC9pbmRleCc7XG5pbXBvcnQgeyBUb29sdGlwQ29tcG9uZW50IH0gZnJvbSAnLi90b29sdGlwLmNvbXBvbmVudCc7XG5pbXBvcnQgeyBUb29sdGlwU2VydmljZSB9IGZyb20gJy4vdG9vbHRpcC5zZXJ2aWNlJztcblxuQERpcmVjdGl2ZSh7XG4gICAgc2VsZWN0b3I6ICdbdXhUb29sdGlwXScsXG4gICAgZXhwb3J0QXM6ICd1eC10b29sdGlwJ1xufSlcbmV4cG9ydCBjbGFzcyBUb29sdGlwRGlyZWN0aXZlIGltcGxlbWVudHMgT25Jbml0LCBPbkNoYW5nZXMsIE9uRGVzdHJveSB7XG4gICAgcHJvdGVjdGVkIHJlYWRvbmx5IF9lbGVtZW50UmVmID0gaW5qZWN0KEVsZW1lbnRSZWYpO1xuXG4gICAgcHJvdGVjdGVkIHJlYWRvbmx5IF92aWV3Q29udGFpbmVyUmVmID0gaW5qZWN0KFZpZXdDb250YWluZXJSZWYpO1xuXG4gICAgcHJvdGVjdGVkIHJlYWRvbmx5IF9vdmVybGF5ID0gaW5qZWN0KE92ZXJsYXkpO1xuXG4gICAgcHJvdGVjdGVkIHJlYWRvbmx5IF9zY3JvbGxEaXNwYXRjaGVyID0gaW5qZWN0KFNjcm9sbERpc3BhdGNoZXIpO1xuXG4gICAgcHJpdmF0ZSByZWFkb25seSBfY2hhbmdlRGV0ZWN0b3JSZWYgPSBpbmplY3QoQ2hhbmdlRGV0ZWN0b3JSZWYpO1xuXG4gICAgcHJpdmF0ZSByZWFkb25seSBfcmVuZGVyZXIgPSBpbmplY3QoUmVuZGVyZXIyKTtcblxuICAgIHByaXZhdGUgcmVhZG9ubHkgX3Rvb2x0aXBTZXJ2aWNlID0gaW5qZWN0KFRvb2x0aXBTZXJ2aWNlKTtcblxuICAgIHByaXZhdGUgcmVhZG9ubHkgX292ZXJsYXlGYWxsYmFjayA9IGluamVjdChPdmVybGF5UGxhY2VtZW50U2VydmljZSk7XG5cbiAgICAvKiogQ29udGFpbnMgdGhlIGNvbnRlbnQgb2YgdGhlIHRvb2x0aXAgb3IgYSBUZW1wbGF0ZVJlZiBmb3IgbW9yZSBkZXRhaWxlZCBjb250ZW50ICovXG4gICAgIFxuICAgIEBJbnB1dCgndXhUb29sdGlwJykgY29udGVudDogc3RyaW5nIHwgVGVtcGxhdGVSZWY8YW55PjtcblxuICAgIC8qKiBBbGxvdyB0aGUgdG9vbHRpcCB0byBiZSBjb25kaXRpb25hbGx5IGRpc2FibGVkICovXG4gICAgQElucHV0KCd0b29sdGlwRGlzYWJsZWQnKSBkaXNhYmxlZDogYm9vbGVhbjtcblxuICAgIC8qKiBBbGwgdGhlIHVzZXIgdG8gYWRkIGEgY3VzdG9tIGNsYXNzIHRvIHRoZSB0b29sdGlwICovXG4gICAgQElucHV0KCd0b29sdGlwQ2xhc3MnKSBjdXN0b21DbGFzczogc3RyaW5nID0gJyc7XG5cbiAgICAvKiogQWxsIHRoZSB1c2VyIHRvIGFkZCBhIHJvbGUgdG8gdGhlIHRvb2x0aXAgLSBkZWZhdWx0IGlzIHRvb2x0aXAgKi9cbiAgICBASW5wdXQoJ3Rvb2x0aXBSb2xlJykgcm9sZTogc3RyaW5nID0gJ3Rvb2x0aXAnO1xuXG4gICAgLyoqIFByb3ZpZGUgdGhlIFRlbXBsYXRlUmVmIGEgY29udGV4dCBvYmplY3QgKi9cbiAgICAgXG4gICAgQElucHV0KCd0b29sdGlwQ29udGV4dCcpIGNvbnRleHQ6IGFueSA9IHt9O1xuXG4gICAgLyoqIERlbGF5IHRoZSBzaG93aW5nIG9mIHRoZSB0b29sdGlwIGJ5IGEgbnVtYmVyIG9mIG1pbGlzZWNvbmRzICovXG4gICAgQElucHV0KCd0b29sdGlwRGVsYXknKSBkZWxheTogbnVtYmVyID0gMDtcblxuICAgIC8qKiBQcm9ncmFtbWF0aWNhbGx5IHNob3cgYW5kIGhpZGUgdGhlIHRvb2x0aXAgKi9cbiAgICBASW5wdXQoKSBpc09wZW46IGJvb2xlYW4gPSBmYWxzZTtcblxuICAgIC8qKiBDdXN0b21pemUgaG93IHRoZSB0b29sdGlwIHNob3VsZCBiZSBwb3NpdGlvbmVkIHJlbGF0aXZlIHRvIHRoZSBlbGVtZW50ICovXG4gICAgQElucHV0KCkgcGxhY2VtZW50OiBBbmNob3JQbGFjZW1lbnQgPSAndG9wJztcblxuICAgIC8qKiBTcGVjaWZ5IHRoZSBmYWxsYmFjayBwbGFjZW1lbnQgaWYgdGhlIHNwZWNpZmllZCBwbGFjZW1lbnQgY2Fubm90IGJlIHVzZWQgKi9cbiAgICBASW5wdXQoKSBmYWxsYmFja1BsYWNlbWVudDogQW5jaG9yUGxhY2VtZW50O1xuXG4gICAgLyoqIEN1c3RvbWl6ZSB0aGUgcG9zaXRpb24gb2YgdGhlIGNhbGxvdXQgKi9cbiAgICBASW5wdXQoKSBhbGlnbm1lbnQ6IEFuY2hvckFsaWdubWVudCA9ICdjZW50ZXInO1xuXG4gICAgLyoqIFNwZWNpZnkgd2hpY2ggZXZlbnRzIHNob3VsZCBzaG93IHRoZSB0b29sdGlwICovXG4gICAgQElucHV0KCkgc2hvd1RyaWdnZXJzOiBPdmVybGF5VHJpZ2dlcltdID0gWydtb3VzZWVudGVyJywgJ2ZvY3VzJ107XG5cbiAgICAvKiogU3BlY2lmeSB3aGljaCBldmVudHMgc2hvdWxkIGhpZGUgdGhlIHRvb2x0aXAgKi9cbiAgICBASW5wdXQoKSBoaWRlVHJpZ2dlcnM6IE92ZXJsYXlUcmlnZ2VyW10gPSBbJ21vdXNlbGVhdmUnLCAnYmx1ciddO1xuXG4gICAgLyoqIEVtaXRzIGFuIGV2ZW50IHdoZW4gdGhlIHRvb2x0aXAgaXMgc2hvd24gKi9cbiAgICBAT3V0cHV0KCkgc2hvd24gPSBuZXcgRXZlbnRFbWl0dGVyPHZvaWQ+KCk7XG5cbiAgICAvKiogRW1pdHMgYSBldmVudCB3aGVuIHRoZSB0b29sdGlwIGlzIGhpZGRlbiAqL1xuICAgIEBPdXRwdXQoKSBoaWRkZW4gPSBuZXcgRXZlbnRFbWl0dGVyPHZvaWQ+KCk7XG5cbiAgICAvKiogQWxsb3cgdHdvIHdheSBiaW5kaW5nIHRvIHRyYWNrIHRoZSB2aXNpYmlsaXR5IG9mIHRoZSB0b29sdGlwICovXG4gICAgQE91dHB1dCgpIGlzT3BlbkNoYW5nZSA9IG5ldyBFdmVudEVtaXR0ZXI8Ym9vbGVhbj4oKTtcblxuICAgIC8qKiBLZWVwIHRyYWNrIG9mIHRoZSB0b29sdGlwIHZpc2liaWxpdHkgKi9cbiAgICBpc1Zpc2libGU6IGJvb2xlYW4gPSBmYWxzZTtcblxuICAgIC8qKiBUaGUgbmFtZSBvZiB0aGUgY3NzIGNsYXNzIHRvIHVzZSBmb3IgdGhlIHRvb2x0aXAgZGlyZWN0aW9uICovXG4gICAgcG9zaXRpb25DbGFzcyA9IHRoaXMucGxhY2VtZW50O1xuXG4gICAgLyoqIERlZmluZSB0aGUgb3ZlcmxheSBjbGFzcyAqL1xuICAgIHByb3RlY3RlZCBfb3ZlcmxheUNsYXNzOiBzdHJpbmcgPSAndXgtdG9vbHRpcC1wYW5lJztcblxuICAgIC8qKiBBIHJlZmVyZW5jZSB0byB0aGUgQ0RLIHBvcnRhbCBjb250YWluaW5nIHRoZSBvdmVybGF5ICovXG4gICAgcHJvdGVjdGVkIF9wb3J0YWw6IENvbXBvbmVudFBvcnRhbDxUb29sdGlwQ29tcG9uZW50PjtcblxuICAgIC8qKiBBIHJlZmVyZW5jZSB0byB0aGUgb3ZlcmxheSB0aGUgdG9vbHRpcCB3aWxsIGJlIGluc2VydGVkIGludG8gKi9cbiAgICBwcm90ZWN0ZWQgX292ZXJsYXlSZWY6IE92ZXJsYXlSZWY7XG5cbiAgICAvKiogQSByZWZlcmVuY2UgdG8gdGhlIGluc3RhbmNlIG9mIHRoZSB0b29sdGlwIGNvbXBvbmVudCB3aGVuIGNyZWF0ZWQgKi9cbiAgICBwcm90ZWN0ZWQgX2luc3RhbmNlOiBUb29sdGlwQ29tcG9uZW50O1xuXG4gICAgLyoqIFRoaXMgd2lsbCBlbWl0IHdoZW4gdGhlIGRpcmVjdGl2ZSBpcyBkZXN0cm95ZWQgYWxsb3dpbmcgdXMgdG8gdW5zdWJzY3JpYmUgYWxsIHN1YnNjcmlwdGlvbnMgYXV0b21hdGljYWxseSAqL1xuICAgIHByb3RlY3RlZCBfb25EZXN0cm95ID0gbmV3IFN1YmplY3Q8dm9pZD4oKTtcblxuICAgIC8qKiBTdG9yZSB0aGUgdGltZW91dCBpbnRlcnZhbCBmb3IgY2FuY2VsYXRpb24gKi9cbiAgICBwcml2YXRlIF9zaG93VGltZW91dElkOiBudW1iZXIgPSBudWxsO1xuXG4gICAgLyoqIEludGVybmFsbHkgc3RvcmUgdGhlIHR5cGUgb2YgdGhpcyBjb21wb25lbnQgLSB1c3VhbCBmb3IgZGlzdGluY3Rpb25zIHdoZW4gZXh0ZW5kaW5nIHRoaXMgY2xhc3MgKi9cbiAgICBwcm90ZWN0ZWQgX3R5cGU6IHN0cmluZyA9ICd0b29sdGlwJztcblxuICAgIC8qKiBTZXQgdXAgdGhlIHRyaWdnZXJzIGFuZCBiaW5kIHRvIHRoZSBzaG93L2hpZGUgZXZlbnRzIHRvIGtlZXAgdmlzaWJpbGl0eSBpbiBzeW5jICovXG4gICAgbmdPbkluaXQoKTogdm9pZCB7XG5cbiAgICAgICAgLy8gc2V0IHVwIHNob3cgYW5kIGhpZGUgZXZlbnQgdHJpZ2dlcnNcbiAgICAgICAgZnJvbUV2ZW50KHRoaXMuX2VsZW1lbnRSZWYubmF0aXZlRWxlbWVudCwgJ2NsaWNrJykucGlwZSh0YWtlVW50aWwodGhpcy5fb25EZXN0cm95KSkuc3Vic2NyaWJlKHRoaXMub25DbGljay5iaW5kKHRoaXMpKTtcbiAgICAgICAgZnJvbUV2ZW50KHRoaXMuX2VsZW1lbnRSZWYubmF0aXZlRWxlbWVudCwgJ21vdXNlZW50ZXInKS5waXBlKHRha2VVbnRpbCh0aGlzLl9vbkRlc3Ryb3kpKS5zdWJzY3JpYmUodGhpcy5vbk1vdXNlRW50ZXIuYmluZCh0aGlzKSk7XG4gICAgICAgIGZyb21FdmVudCh0aGlzLl9lbGVtZW50UmVmLm5hdGl2ZUVsZW1lbnQsICdtb3VzZWxlYXZlJykucGlwZSh0YWtlVW50aWwodGhpcy5fb25EZXN0cm95KSkuc3Vic2NyaWJlKHRoaXMub25Nb3VzZUxlYXZlLmJpbmQodGhpcykpO1xuICAgICAgICBmcm9tRXZlbnQodGhpcy5fZWxlbWVudFJlZi5uYXRpdmVFbGVtZW50LCAnZm9jdXMnKS5waXBlKHRha2VVbnRpbCh0aGlzLl9vbkRlc3Ryb3kpKS5zdWJzY3JpYmUodGhpcy5vbkZvY3VzLmJpbmQodGhpcykpO1xuICAgICAgICBmcm9tRXZlbnQodGhpcy5fZWxlbWVudFJlZi5uYXRpdmVFbGVtZW50LCAnYmx1cicpLnBpcGUodGFrZVVudGlsKHRoaXMuX29uRGVzdHJveSkpLnN1YnNjcmliZSh0aGlzLm9uQmx1ci5iaW5kKHRoaXMpKTtcblxuICAgICAgICAvLyB3aGVuIGFueSBvdGhlciB0b29sdGlwcyBvcGVuIGhpZGUgdGhpcyBvbmVcbiAgICAgICAgdGhpcy5fdG9vbHRpcFNlcnZpY2Uuc2hvd24kLnBpcGUoXG4gICAgICAgICAgICBmaWx0ZXIoKCkgPT4gdGhpcy5fdHlwZSA9PT0gJ3Rvb2x0aXAnKSxcbiAgICAgICAgICAgIGZpbHRlcih0b29sdGlwID0+IHRvb2x0aXAgIT09IHRoaXMuX2luc3RhbmNlKSxcbiAgICAgICAgICAgIHRha2VVbnRpbCh0aGlzLl9vbkRlc3Ryb3kpXG4gICAgICAgICkuc3Vic2NyaWJlKHRoaXMuaGlkZS5iaW5kKHRoaXMpKTtcblxuICAgICAgICAvLyBpZiB0aGUgdG9vbHRpcCBzaG91bGQgYmUgaW5pdGlhbGx5IHZpc2libGUgdGhlbiBvcGVuIGl0XG4gICAgICAgIGlmICh0aGlzLmlzT3Blbikge1xuICAgICAgICAgICAgdGhpcy5zaG93KCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBXZSBuZWVkIHRvIHNlbmQgaW5wdXQgY2hhbmdlcyB0byB0aGUgdG9vbHRpcCBjb21wb25lbnRcbiAgICAgKiBXZSBjYW4ndCB1c2Ugc2V0dGVycyBhcyB0aGV5IG1heSB0cmlnZ2VyIGJlZm9yZSB0b29sdGlwIGluaXRpYWxpc2VkIGFuZCBjYW4ndCByZXNlbmQgb25jZSBpbml0aWFsaXNlZFxuICAgICAqKi9cbiAgICBuZ09uQ2hhbmdlcyhjaGFuZ2VzOiBTaW1wbGVDaGFuZ2VzKTogdm9pZCB7XG5cbiAgICAgICAgLy8gd2UgY2FuIGlnbm9yZSB0aGUgZmlyc3QgY2hhbmdlIGFzIGl0J3MgaGFuZGxlZCBpbiBuZ09uSW5pdFxuICAgICAgICBpZiAoY2hhbmdlcy5pc09wZW4gJiYgIWNoYW5nZXMuaXNPcGVuLmZpcnN0Q2hhbmdlICYmIGNoYW5nZXMuaXNPcGVuLmN1cnJlbnRWYWx1ZSAhPT0gdGhpcy5pc1Zpc2libGUpIHtcbiAgICAgICAgICAgIGNoYW5nZXMuaXNPcGVuLmN1cnJlbnRWYWx1ZSA/IHRoaXMuc2hvdygpIDogdGhpcy5oaWRlKCk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBkZXN0cm95IHRoZSBvdmVybGF5IHJlZiBzbyBhIG5ldyBjb3JyZWN0bHkgcG9zaXRpb25lZCBpbnN0YW5jZSB3aWxsIGJlIGNyZWF0ZWQgbmV4dCB0aW1lXG4gICAgICAgIGlmIChjaGFuZ2VzLnBsYWNlbWVudCkge1xuICAgICAgICAgICAgdGhpcy5kZXN0cm95T3ZlcmxheSgpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHRoaXMuX2luc3RhbmNlICYmIGNoYW5nZXMucGxhY2VtZW50KSB7XG4gICAgICAgICAgICB0aGlzLl9pbnN0YW5jZS5zZXRQbGFjZW1lbnQoY2hhbmdlcy5wbGFjZW1lbnQuY3VycmVudFZhbHVlKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICh0aGlzLl9pbnN0YW5jZSAmJiBjaGFuZ2VzLmFsaWdubWVudCkge1xuICAgICAgICAgICAgdGhpcy5faW5zdGFuY2Uuc2V0QWxpZ25tZW50KGNoYW5nZXMuYWxpZ25tZW50LmN1cnJlbnRWYWx1ZSk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAodGhpcy5faW5zdGFuY2UgJiYgY2hhbmdlcy5jb250ZW50KSB7XG4gICAgICAgICAgICB0aGlzLl9pbnN0YW5jZS5zZXRDb250ZW50KGNoYW5nZXMuY29udGVudC5jdXJyZW50VmFsdWUpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHRoaXMuX2luc3RhbmNlICYmIGNoYW5nZXMuY3VzdG9tQ2xhc3MpIHtcbiAgICAgICAgICAgIHRoaXMuX2luc3RhbmNlLnNldENsYXNzKGNoYW5nZXMuY3VzdG9tQ2xhc3MuY3VycmVudFZhbHVlKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICh0aGlzLl9pbnN0YW5jZSAmJiBjaGFuZ2VzLmNvbnRleHQpIHtcbiAgICAgICAgICAgIHRoaXMuX2luc3RhbmNlLnNldENvbnRleHQoY2hhbmdlcy5jb250ZXh0LmN1cnJlbnRWYWx1ZSk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAodGhpcy5faW5zdGFuY2UgJiYgY2hhbmdlcy5yb2xlKSB7XG4gICAgICAgICAgICB0aGlzLl9pbnN0YW5jZS5zZXRDb250ZXh0KGNoYW5nZXMucm9sZS5jdXJyZW50VmFsdWUpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqIEVuc3VyZSB3ZSBjbGVhbiB1cCBhZnRlciBvdXJzZWx2ZXMgKi9cbiAgICBuZ09uRGVzdHJveSgpOiB2b2lkIHtcblxuICAgICAgICAvLyBlbnN1cmUgd2UgY2xvc2UgdGhlIHRvb2x0aXAgd2hlbiB0aGUgaG9zdCBpcyBkZXN0cm95ZWRcbiAgICAgICAgaWYgKHRoaXMuX292ZXJsYXlSZWYpIHtcbiAgICAgICAgICAgIHRoaXMuX292ZXJsYXlSZWYuZGlzcG9zZSgpO1xuICAgICAgICAgICAgdGhpcy5faW5zdGFuY2UgPSBudWxsO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gY2xlYXIgYW55IHBlbmRpbmcgdGltZW91dHNcbiAgICAgICAgdGhpcy5jYW5jZWxUb29sdGlwKCk7XG5cbiAgICAgICAgLy8gZW1pdCB0aGlzIGV2ZW50IHRvIGF1dG9tYXRpY2FsbHkgdW5zdWJzY3JpYmUgZnJvbSBhbGwgc3Vic2NyaXB0aW9uc1xuICAgICAgICB0aGlzLl9vbkRlc3Ryb3kubmV4dCgpO1xuICAgICAgICB0aGlzLl9vbkRlc3Ryb3kuY29tcGxldGUoKTtcbiAgICB9XG5cbiAgICAvKiogTWFrZSB0aGUgdG9vbHRpcCBvcGVuICovXG4gICAgc2hvdygpOiB2b2lkIHtcblxuICAgICAgICAvLyBpZiB0aGUgdG9vbHRpcCBpcyBkaXNhYmxlZCB0aGVuIGRvIG5vdGhpbmdcbiAgICAgICAgaWYgKHRoaXMuZGlzYWJsZWQgfHwgdGhpcy5pc1Zpc2libGUgfHwgdGhpcy5fc2hvd1RpbWVvdXRJZCB8fCAhdGhpcy5jb250ZW50KSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICAvLyBkZWxheSB0aGUgc2hvdyBieSB0aGUgZGVsYXkgYW1vdW50XG4gICAgICAgIHRoaXMuX3Nob3dUaW1lb3V0SWQgPSB3aW5kb3cuc2V0VGltZW91dCgoKSA9PiB7XG5cbiAgICAgICAgICAgIC8vIGNyZWF0ZSB0aGUgdG9vbHRpcCBhbmQgZ2V0IHRoZSBvdmVybGF5IHJlZlxuICAgICAgICAgICAgY29uc3Qgb3ZlcmxheVJlZiA9IHRoaXMuY3JlYXRlT3ZlcmxheSgpO1xuXG4gICAgICAgICAgICAvLyBjcmVhdGUgdGhlIHBvcnRhbCB0byBjcmVhdGUgdGhlIHRvb2x0aXAgY29tcG9uZW50XG4gICAgICAgICAgICB0aGlzLl9wb3J0YWwgPSB0aGlzLmNyZWF0ZVBvcnRhbCgpO1xuICAgICAgICAgICAgdGhpcy5faW5zdGFuY2UgPSB0aGlzLmNyZWF0ZUluc3RhbmNlKG92ZXJsYXlSZWYpO1xuXG4gICAgICAgICAgICAvLyB3YXRjaCBmb3IgYW55IGNoYW5nZXMgdG8gdGhlIGNvbnRlbnRcbiAgICAgICAgICAgIHRoaXMuX2luc3RhbmNlLnJlcG9zaXRpb24kLnBpcGUodGFrZVVudGlsKHRoaXMuX29uRGVzdHJveSkpLnN1YnNjcmliZSh0aGlzLnJlcG9zaXRpb24uYmluZCh0aGlzKSk7XG5cbiAgICAgICAgICAgIC8vIHN0b3JlIHRoZSB2aXNpYmxlIHN0YXRlXG4gICAgICAgICAgICB0aGlzLmlzVmlzaWJsZSA9IHRydWU7XG5cbiAgICAgICAgICAgIC8vIGVuc3VyZSB0aGUgb3ZlcmxheSBoYXMgdGhlIGNvcnJlY3QgaW5pdGlhbCBwb3NpdGlvblxuICAgICAgICAgICAgdGhpcy5yZXBvc2l0aW9uKCk7XG5cbiAgICAgICAgICAgIC8vIGVtaXQgdGhlIHNob3cgZXZlbnRzXG4gICAgICAgICAgICB0aGlzLnNob3duLmVtaXQoKTtcbiAgICAgICAgICAgIHRoaXMuaXNPcGVuQ2hhbmdlLm5leHQodHJ1ZSk7XG5cbiAgICAgICAgICAgIC8vIGNsZWFyIHRoZSBpbnRlcnZhbCBpZFxuICAgICAgICAgICAgdGhpcy5fc2hvd1RpbWVvdXRJZCA9IG51bGw7XG5cbiAgICAgICAgICAgIC8vIGVtaXQgdGhlIHNob3cgZXZlbnQgdG8gY2xvc2UgYW55IG90aGVyIHRvb2x0aXBzXG4gICAgICAgICAgICB0aGlzLl90b29sdGlwU2VydmljZS5zaG93biQubmV4dCh0aGlzLl9pbnN0YW5jZSk7XG5cbiAgICAgICAgICAgIC8vIGVuc3VyZSBjaGFuZ2UgZGV0ZWN0aW9uIGlzIHJ1blxuICAgICAgICAgICAgdGhpcy5fY2hhbmdlRGV0ZWN0b3JSZWYuZGV0ZWN0Q2hhbmdlcygpO1xuICAgICAgICB9LCB0aGlzLmRlbGF5KTtcblxuICAgIH1cblxuICAgIC8qKiBJZiBhIHRvb2x0aXAgZXhpc3RzIGFuZCBpcyB2aXNpYmxlLCBoaWRlIGl0ICovXG4gICAgaGlkZSgpOiB2b2lkIHtcblxuICAgICAgICAvLyBpZiB3ZSBhcmUgd2FpdGluZyB0byBzaG93IGEgdG9vbHRpcCB0aGVuIGNhbmNlbCB0aGUgcGVuZGluZyB0aW1lb3V0XG4gICAgICAgIGlmICh0aGlzLl9zaG93VGltZW91dElkKSB7XG4gICAgICAgICAgICB3aW5kb3cuY2xlYXJUaW1lb3V0KHRoaXMuX3Nob3dUaW1lb3V0SWQpO1xuICAgICAgICAgICAgdGhpcy5fc2hvd1RpbWVvdXRJZCA9IG51bGw7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgXG4gICAgICAgIC8vIGlmIHRoZSB0b29sdGlwIGlzIGhpZGRlbiB0aGVuIGRvIG5vdGhpbmdcbiAgICAgICAgaWYgKCF0aGlzLmlzVmlzaWJsZSkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHRoaXMuX292ZXJsYXlSZWYgJiYgdGhpcy5fb3ZlcmxheVJlZi5oYXNBdHRhY2hlZCgpKSB7XG4gICAgICAgICAgICB0aGlzLl9vdmVybGF5UmVmLmRldGFjaCgpO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5zZXRBcmlhRGVzY3JpYmVkQnkobnVsbCk7XG4gICAgICAgIHRoaXMuX2luc3RhbmNlID0gbnVsbDtcblxuICAgICAgICAvLyBzdG9yZSB0aGUgdmlzaWJsZSBzdGF0ZVxuICAgICAgICB0aGlzLmlzVmlzaWJsZSA9IGZhbHNlO1xuXG4gICAgICAgIC8vIGVtaXQgdGhlIGhpZGUgZXZlbnRzXG4gICAgICAgIHRoaXMuaGlkZGVuLmVtaXQoKTtcbiAgICAgICAgdGhpcy5pc09wZW5DaGFuZ2UubmV4dChmYWxzZSk7XG5cbiAgICAgICAgLy8gZW5zdXJlIGNoYW5nZSBkZXRlY3Rpb24gaXMgcnVuXG4gICAgICAgIHRoaXMuX2NoYW5nZURldGVjdG9yUmVmLmRldGVjdENoYW5nZXMoKTtcbiAgICB9XG5cbiAgICAvKiogVG9nZ2xlIHRoZSB2aXNpYmlsaXR5IG9mIHRoZSB0b29sdGlwICovXG4gICAgdG9nZ2xlKCk6IHZvaWQge1xuICAgICAgICB0aGlzLmlzVmlzaWJsZSA/IHRoaXMuaGlkZSgpIDogdGhpcy5zaG93KCk7XG4gICAgfVxuXG4gICAgLyoqIFJlY2FsY3VsYXRlIHRoZSBwb3NpdGlvbiBvZiB0aGUgcG9wb3ZlciAqL1xuICAgIHJlcG9zaXRpb24oKTogdm9pZCB7XG4gICAgICAgIGlmICh0aGlzLmlzVmlzaWJsZSAmJiB0aGlzLl9vdmVybGF5UmVmKSB7XG4gICAgICAgICAgICB0aGlzLl9vdmVybGF5UmVmLnVwZGF0ZVBvc2l0aW9uKCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKiogQ3JlYXRlIGFuIGluc3RhbmNlIGZyb20gdGhlIG92ZXJsYXkgcmVmIC0gYWxsb3dzIG92ZXJyaWRpbmcgYW5kIGFkZGl0aW9uYWwgbG9naWMgaGVyZSAqL1xuICAgIHByb3RlY3RlZCBjcmVhdGVJbnN0YW5jZShvdmVybGF5UmVmOiBPdmVybGF5UmVmKTogVG9vbHRpcENvbXBvbmVudCB7XG4gICAgICAgIGNvbnN0IGluc3RhbmNlID0gb3ZlcmxheVJlZi5hdHRhY2godGhpcy5fcG9ydGFsKS5pbnN0YW5jZSBhcyBUb29sdGlwQ29tcG9uZW50O1xuXG4gICAgICAgIC8vIHN1cHBseSB0aGUgdG9vbHRpcCB3aXRoIHRoZSBjb3JyZWN0IHByb3BlcnRpZXNcbiAgICAgICAgaW5zdGFuY2Uuc2V0Q29udGVudCh0aGlzLmNvbnRlbnQpO1xuICAgICAgICBpbnN0YW5jZS5zZXRQbGFjZW1lbnQodGhpcy5wbGFjZW1lbnQpO1xuICAgICAgICBpbnN0YW5jZS5zZXRBbGlnbm1lbnQodGhpcy5hbGlnbm1lbnQpO1xuICAgICAgICBpbnN0YW5jZS5zZXRDbGFzcyh0aGlzLmN1c3RvbUNsYXNzKTtcbiAgICAgICAgaW5zdGFuY2Uuc2V0Q29udGV4dCh0aGlzLmNvbnRleHQpO1xuICAgICAgICBpbnN0YW5jZS5zZXRSb2xlKHRoaXMucm9sZSk7XG5cbiAgICAgICAgLy8gVXBkYXRlIHRoZSBhcmlhLWRlc2NyaWJlZGJ5IGF0dHJpYnV0ZVxuICAgICAgICB0aGlzLnNldEFyaWFEZXNjcmliZWRCeShpbnN0YW5jZS5pZCk7XG5cbiAgICAgICAgcmV0dXJuIGluc3RhbmNlO1xuICAgIH1cblxuICAgIC8qKiBDcmVhdGUgdGhlIGNvbXBvbmVudCBwb3J0YWwgLSBhbGxvd3Mgb3ZlcnJpZGluZyB0byBhbGxvdyBvdGhlciBwb3J0YWxzIGVnLiBwb3BvdmVycyAqL1xuICAgICBcbiAgICBwcm90ZWN0ZWQgY3JlYXRlUG9ydGFsKCk6IENvbXBvbmVudFBvcnRhbDxhbnk+IHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX3BvcnRhbCB8fCBuZXcgQ29tcG9uZW50UG9ydGFsKFRvb2x0aXBDb21wb25lbnQsIHRoaXMuX3ZpZXdDb250YWluZXJSZWYpO1xuICAgIH1cblxuICAgIC8qKiBDcmVhdGUgdGhlIG92ZXJsYXkgYW5kIHNldCB1cCB0aGUgc2Nyb2xsIGhhbmRsaW5nIGJlaGF2aW9yICovXG4gICAgcHJpdmF0ZSBjcmVhdGVPdmVybGF5KCk6IE92ZXJsYXlSZWYge1xuXG4gICAgICAgIC8vIGlmIHRoZSB0b29sdGlwIGhhcyBhbHJlYWR5IGJlZW4gY3JlYXRlZCB0aGVuIGp1c3QgcmV0dXJuIHRoZSBleGlzdGluZyBpbnN0YW5jZVxuICAgICAgICBpZiAodGhpcy5fb3ZlcmxheVJlZikge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuX292ZXJsYXlSZWY7XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBzdHJhdGVneSA9IHRoaXMuX292ZXJsYXkucG9zaXRpb24oKVxuICAgICAgICAgICAgLmZsZXhpYmxlQ29ubmVjdGVkVG8odGhpcy5fZWxlbWVudFJlZilcbiAgICAgICAgICAgIC53aXRoRmxleGlibGVEaW1lbnNpb25zKGZhbHNlKVxuICAgICAgICAgICAgLndpdGhQdXNoKGZhbHNlKTtcblxuXG4gICAgICAgIHRoaXMuX292ZXJsYXlSZWYgPSB0aGlzLl9vdmVybGF5LmNyZWF0ZSh7XG4gICAgICAgICAgICBwb3NpdGlvblN0cmF0ZWd5OiBzdHJhdGVneSxcbiAgICAgICAgICAgIHBhbmVsQ2xhc3M6IHRoaXMuX292ZXJsYXlDbGFzcyxcbiAgICAgICAgICAgIHNjcm9sbFN0cmF0ZWd5OiB0aGlzLl9vdmVybGF5LnNjcm9sbFN0cmF0ZWdpZXMucmVwb3NpdGlvbih7IHNjcm9sbFRocm90dGxlOiAwIH0pLFxuICAgICAgICAgICAgaGFzQmFja2Ryb3A6IGZhbHNlXG4gICAgICAgIH0pO1xuXG4gICAgICAgIHRoaXMuX292ZXJsYXlGYWxsYmFjay51cGRhdGVQb3NpdGlvbih0aGlzLl9vdmVybGF5UmVmLCB0aGlzLnBsYWNlbWVudCwgdGhpcy5hbGlnbm1lbnQsIHRoaXMuZmFsbGJhY2tQbGFjZW1lbnQpO1xuXG4gICAgICAgIHN0cmF0ZWd5LnBvc2l0aW9uQ2hhbmdlcy5zdWJzY3JpYmUocG9zaXRpb25DaGFuZ2UgPT4ge1xuICAgICAgICAgICAgY29uc3QgY3VycmVudFBvc2l0aW9uID0gcG9zaXRpb25DaGFuZ2UuY29ubmVjdGlvblBhaXI7XG4gICAgICAgICAgICB0aGlzLmdldFBvc2l0aW9uQ2xhc3MoY3VycmVudFBvc2l0aW9uKTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgcmV0dXJuIHRoaXMuX292ZXJsYXlSZWY7XG4gICAgfVxuXG4gICAgLyoqIFJlY3JlYXRlIHRoZSBvdmVybGF5IHJlZiB1c2luZyB0aGUgdXBkYXRlZCBvcmlnaW4gYW5kIG92ZXJsYXkgcG9zaXRpb25zICovXG4gICAgcHJpdmF0ZSBkZXN0cm95T3ZlcmxheSgpOiB2b2lkIHtcblxuICAgICAgICAvLyBkZXN0cm95IHRoZSBleGlzdGluZyBvdmVybGF5XG4gICAgICAgIGlmICh0aGlzLl9vdmVybGF5UmVmICYmIHRoaXMuX292ZXJsYXlSZWYuaGFzQXR0YWNoZWQoKSkge1xuICAgICAgICAgICAgdGhpcy5fb3ZlcmxheVJlZi5kZXRhY2goKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICh0aGlzLl9vdmVybGF5UmVmKSB7XG4gICAgICAgICAgICB0aGlzLl9vdmVy