@ux-aspects/ux-aspects
Version:
Open source user interface framework for building modern, responsive, mobile big data applications
375 lines • 56.1 kB
JavaScript
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