@microsoft/windows-admin-center-sdk
Version:
Microsoft - Windows Admin Center Shell
421 lines • 57 kB
JavaScript
import { __decorate, __metadata } from "tslib";
import { Directive, ElementRef, EventEmitter, HostBinding, HostListener, Injector, Input, Output, TemplateRef } from '@angular/core';
import { Debounce } from '@microsoft/windows-admin-center-sdk/core/base/decorators/debounce.decorators';
import { Dom } from '@microsoft/windows-admin-center-sdk/core/dom/dom';
import { CoreBaseComponent } from '../common/base.component';
import { TooltipShowMode } from './models/tooltip-options';
import { TooltipPlacementEnum } from './models/tooltip-placement';
import { TooltipHostInstance } from './tooltip-host-instance';
import { TooltipZoneDirective } from './tooltip-zone.directive';
import * as i0 from "@angular/core";
export class ToolTipFocusEvent {
}
ToolTipFocusEvent.focusIn = 'focusin';
ToolTipFocusEvent.focusOut = 'focusout';
export class ToolTipMouseEvent {
}
ToolTipMouseEvent.mouseEnter = 'mouseenter';
ToolTipMouseEvent.mouseLeave = 'mouseleave';
/**
*
* @smeDoc {@label Tooltip @id sme-tooltip-directive}
*
* @overview
* @file {@filepath ./examples/overview.md}
*
* @example {@label Basic Usage @id basic-usage}
* @file {@filename component.html @filepath ./examples/basic-usage.component.html}
* @file {@filename component.ts @filepath ./examples/tooltip-example.component.ts}
*
* @example {@label Custom Template @id custom-template}
* @file {@filename component.html @filepath ./examples/template-reference.component.html}
* @file {@filename component.ts @filepath ./examples/tooltip-example.component.ts}
*
* @example {@label Custom Implementation @id tooltip-zone}
* @file {@filename component.html @filepath ./examples/tooltip-zone.component.html}
*/
/**
* Directive to create tooltips in the tooltip host.
*/
export class TooltipDirective extends CoreBaseComponent {
/**
* Initializes a new instance of the @see PivotComponent class.
* @param injector The angular injection service. required by @SmeInjectableBase() decorator in the base @see BaseComponent class
*/
constructor(elementRef, injector) {
super(injector);
this.elementRef = elementRef;
this.toolTipFocusEventTriggered = new EventEmitter();
this.toolTipMouseEventTriggered = new EventEmitter();
/**
* Indicates when to explicitly not show the tooltip in cases where it needs to be shown only under certain conditions.
*/
this.smeTooltipShow = true;
/**
* Indicates if receiving hover and focus events.
*/
this.smeTooltipEnableEvents = false;
/**
* Indicates if hide the tooltip when inner HTML is the same as tooltip content
* In certain cases, we always need the tooltip to show, such as the multi-tool component tool list.
*/
this.hideOnTooltipSameAsText = true;
this.smeTooltipShowOn = MsftSme.applyBitwiseOr(TooltipShowMode.Hover, TooltipShowMode.KeyboardFocus);
}
/**
* The source name to use for logging
*/
get logSourceName() {
return 'TooltipDirective';
}
/**
* Gets the id of the tooltip that will describe this element
*/
get ariaDescribedBy() {
if (!this.shown || !MsftSme.isNullOrUndefined(this.smeTooltip) || !this.hideOnTooltipSameAsText) {
return null;
}
return this.idBag && this.idBag.tooltip ? this.idBag.tooltip : null;
}
/**
* The actual placement of the tooltip
*/
get placement() {
return TooltipPlacementEnum.fromString(this.smeTooltipPlacement);
}
/**
* The tooltip host
*/
get tooltipHost() {
return TooltipHostInstance.activeHost;
}
/**
* Indicates that tooltips should show on focus/hover.
*/
get showOnfocus() {
return !!MsftSme.self().Resources.accessibilityMode;
}
/**
* Indicates if the tooltip is being shown.
*/
get shown() {
return this.tooltipHost.isShown(this.componentId);
}
/**
* Indicates that this tooltip should show only when the text is truncated
* We assume this is true if the title attribute is exactly the same as the text content of this node.
*/
get isTooltipSameAsText() {
if (MsftSme.isNullOrUndefined(this.title)) {
return false;
}
const nativehostElement = this.hostElement.nativeElement;
return !!this.title && MsftSme.localeCompareIgnoreCase(String(this.title).trim(), nativehostElement.textContent.trim()) === 0;
}
/**
* Indicates that this tooltip should be shown
*/
get shouldShow() {
if (MsftSme.isNullOrWhiteSpace(this.title)
&& MsftSme.isNullOrUndefined(this.smeTooltip) || !this.smeTooltipShow) {
return false;
}
if (MsftSme.applyBitwiseAnd(this.smeTooltipShowOn, TooltipShowMode.Click)) {
// if we are hovered or our tooltip is hovered
if (this.clicked) {
return true;
}
// if we are shown and are focused or our tooltip
if (this.shown && this.tooltipHost.isFocused) {
return true;
}
}
else if (MsftSme.applyBitwiseAnd(this.smeTooltipShowOn, (MsftSme.applyBitwiseOr(TooltipShowMode.Hover, TooltipShowMode.KeyboardFocus)))) {
if (this.hideOnTooltipSameAsText && this.isTooltipSameAsText && !this.getIsTruncated()) {
// Remove title attribute when true conditions are not met
this.setAttribute('title', '');
return false;
}
// if we are hovered or our tooltip is hovered
if (this.hovered || (this.shown && this.tooltipHost.isHovered)) {
return true;
}
// if we show on focus and are focused or our tooltip has focus
if (this.showOnfocus && (this.focused || (this.shown && this.tooltipHost.isFocused))) {
return true;
}
}
// Remove title attribute when true conditions are not met
this.setAttribute('title', '');
return false;
}
/**
* Implementation of angular OnInit interface
*/
ngOnInit() {
if (this.tooltipZone) {
this.tooltipZone.registerTooltipDirective(this);
}
// Set up observer if element can be disabled, watch for disabled changes
if (this.elementRef &&
this.elementRef.nativeElement &&
// eslint-disable-next-line eqeqeq
this.elementRef.nativeElement.disabled != null) {
// We hide the tooltip if the element it is attached to becomes disabled
this.observer = new MutationObserver(mutations => {
mutations.forEach(mutation => {
if (mutation.attributeName === 'disabled') {
// Check if need to be hidden
this.hide();
}
});
});
const config = { attributes: true, childList: true, characterData: true };
this.observer.observe(this.elementRef.nativeElement, config);
}
}
/**
* Implementation of angular OnChanges interface
* On any change we update the tooltip if it is shown
*/
ngOnChanges(changes) {
super.ngOnChanges(changes);
if (this.shown) {
this.tooltipHost.update(this.getTooltipOptions());
}
}
/**
* Implementation of angular OnDestroy interface
*/
ngOnDestroy() {
super.ngOnDestroy();
this.showHideTooltip(false, false);
if (this.tooltipZone) {
this.tooltipZone.unregisterTooltipDirective();
}
}
/**
* Creates the idBag used by this component to store unique element ids.
* id values will be assigned be the @see BaseComponent super class.
*/
createIdBag() {
return {
tooltip: ''
};
}
/**
* Host listeners for tooltip focus events
*/
onFocusEvent(event) {
// on focus in/out change focused state
const focused = event.type === ToolTipFocusEvent.focusIn || (this.focused && event.type !== ToolTipFocusEvent.focusOut);
const lostClickFocus = this.clicked && event.type === ToolTipFocusEvent.focusOut;
this.tooltipTrigger = this.clicked ? TooltipShowMode.Click : TooltipShowMode.KeyboardFocus;
this.showHideTooltip(this.hovered, focused, lostClickFocus ? false : this.clicked);
}
/**
* Host listeners for tooltip mouse events
*/
onMouseEvent(event) {
if (MsftSme.applyBitwiseAnd(this.smeTooltipShowOn, TooltipShowMode.Hover)) {
// on mouse enter/leave change hovered state
const hovered = event.type === ToolTipMouseEvent.mouseEnter || (this.hovered && event.type !== ToolTipMouseEvent.mouseLeave);
this.tooltipTrigger = TooltipShowMode.Hover;
this.showHideTooltip(hovered, this.focused, this.clicked);
}
}
/**
* Host listeners for click and enter
*/
onClick(event) {
if (MsftSme.applyBitwiseAnd(this.smeTooltipShowOn, TooltipShowMode.Click)) {
this.showHideTooltip(this.hovered, this.focused, true);
event.preventDefault();
event.stopPropagation();
}
}
/**
* Shows or hides the tooltip if either the hover or focused states are true
* @param hovered indicates the element is hovered
* @param focused indicates the element is focused
*/
showHideTooltip(hovered = this.hovered, focused = this.focused, clicked = this.clicked) {
// Only emits on status changed.
if (this.smeTooltipEnableEvents) {
if (focused !== this.focused) {
focused ?
this.toolTipFocusEventTriggered.emit(ToolTipFocusEvent.focusIn) :
this.toolTipFocusEventTriggered.emit(ToolTipFocusEvent.focusOut);
}
if (hovered !== this.hovered) {
hovered ?
this.toolTipMouseEventTriggered.emit(ToolTipMouseEvent.mouseEnter) :
this.toolTipMouseEventTriggered.emit(ToolTipMouseEvent.mouseLeave);
}
}
this.hovered = hovered;
this.focused = focused;
this.clicked = clicked;
if (this.shouldShow && !this.shown) {
this.show();
}
else if (!this.shouldShow && this.shown) {
this.hide();
}
}
/**
* Shows the tooltip.
*/
show(showOnShortCut = false, restoreFocusTo) {
if ((this.shouldShow || showOnShortCut) && !this.shown) {
// Explicitly set the tooltip to be read when using the shortcut, otherwise do not.
this.tooltipHost.show(this.getTooltipOptions(restoreFocusTo, showOnShortCut));
}
}
/**
* Hides the tooltip.
*/
hide() {
if (this.shown
&& (!this.shouldShow
|| (this.elementRef.nativeElement
&& this.elementRef.nativeElement.disabled === true))) {
// If it is showing and shouldn't be or if it is showing and disabled
this.tooltipHost.hide(this.componentId);
}
}
getTooltipOptions(restoreFocusTo, shouldRead) {
return {
targetid: this.componentId,
contentId: this.idBag.tooltip,
title: this.title,
template: this.smeTooltip,
context: this.smeTooltipContext,
element: this.hostElement,
restoreFocusTo: restoreFocusTo || document.activeElement,
placement: this.placement,
showOn: this.smeTooltipShowOn,
shouldRead: shouldRead,
onStateChanged: () => this.showHideTooltip(),
onWindowClick: () => this.showHideTooltip(this.hovered, this.focused, this.clicked),
triggeredFrom: this.tooltipTrigger
};
}
/**
* Determines if the text node content is truncated.
*/
getIsTruncated() {
const host = this.hostElement.nativeElement;
const ellipsisParent = Dom.getAncestor(host, (e) => getComputedStyle(e).textOverflow === 'ellipsis');
if (!ellipsisParent) {
return false;
}
const measureElement = document.createElement('span');
// position element off screen
measureElement.style.display = 'inline';
measureElement.style.width = 'auto';
measureElement.style.visibility = 'hidden';
measureElement.style.position = 'absolute';
measureElement.style.right = '-10000px';
measureElement.style.bottom = '-10000px';
measureElement.innerHTML = host.textContent;
// use same font as host element
const hostStyle = getComputedStyle(host);
const ellipsesParentStyle = getComputedStyle(ellipsisParent);
measureElement.style.fontFamily = hostStyle.fontFamily;
measureElement.style.fontVariant = hostStyle.fontVariant;
measureElement.style.fontSize = hostStyle.fontSize;
measureElement.style.fontStyle = hostStyle.fontStyle;
measureElement.style.fontWeight = hostStyle.fontWeight;
measureElement.style.lineHeight = hostStyle.lineHeight;
measureElement.style.letterSpacing = hostStyle.letterSpacing;
measureElement.style.padding = ellipsesParentStyle.padding;
// append the measure element to the dom and compare width with the ellipsisParent
document.body.append(measureElement);
const ellipsesParentWidth = ellipsisParent.getBoundingClientRect().width;
const measureWidth = measureElement.getBoundingClientRect().width;
const isTruncated = ellipsesParentWidth < measureWidth;
measureElement.remove();
// this logging is to verbose, but useful for debugging.
// Logging.logDebug(
// this.logSourceName,
// `Truncation Calculated: ${isTruncated}`,
// {
// ellipsesParentWidth: ellipsesParentWidth,
// measureWidth: measureWidth
// }
// );
return isTruncated;
}
}
/** @nocollapse */ TooltipDirective.ɵfac = function TooltipDirective_Factory(t) { return new (t || TooltipDirective)(i0.ɵɵdirectiveInject(i0.ElementRef), i0.ɵɵdirectiveInject(i0.Injector)); };
/** @nocollapse */ TooltipDirective.ɵdir = /** @pureOrBreakMyCode */ i0.ɵɵdefineDirective({ type: TooltipDirective, selectors: [["", "smeTooltip", ""], ["", "title", ""]], hostVars: 1, hostBindings: function TooltipDirective_HostBindings(rf, ctx) { if (rf & 1) {
i0.ɵɵlistener("focusin", function TooltipDirective_focusin_HostBindingHandler($event) { return ctx.onFocusEvent($event); })("focusout", function TooltipDirective_focusout_HostBindingHandler($event) { return ctx.onFocusEvent($event); })("mouseenter", function TooltipDirective_mouseenter_HostBindingHandler($event) { return ctx.onMouseEvent($event); })("mouseleave", function TooltipDirective_mouseleave_HostBindingHandler($event) { return ctx.onMouseEvent($event); })("click", function TooltipDirective_click_HostBindingHandler($event) { return ctx.onClick($event); })("keydown.enter", function TooltipDirective_keydown_enter_HostBindingHandler($event) { return ctx.onClick($event); })("keydown.space", function TooltipDirective_keydown_space_HostBindingHandler($event) { return ctx.onClick($event); });
} if (rf & 2) {
i0.ɵɵattribute("aria-describedBy", ctx.ariaDescribedBy);
} }, inputs: { title: "title", smeTooltip: "smeTooltip", smeTooltipContext: "smeTooltipContext", smeTooltipPlacement: "smeTooltipPlacement", smeTooltipShowOn: "smeTooltipShowOn", smeTooltipShow: "smeTooltipShow", smeTooltipEnableEvents: "smeTooltipEnableEvents", hideOnTooltipSameAsText: "hideOnTooltipSameAsText", tooltipZone: "tooltipZone" }, outputs: { toolTipFocusEventTriggered: "toolTipFocusEventTriggered", toolTipMouseEventTriggered: "toolTipMouseEventTriggered" }, features: [i0.ɵɵInheritDefinitionFeature, i0.ɵɵNgOnChangesFeature] });
__decorate([
Debounce(),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Boolean, HTMLElement]),
__metadata("design:returntype", void 0)
], TooltipDirective.prototype, "show", null);
__decorate([
Debounce(),
__metadata("design:type", Function),
__metadata("design:paramtypes", []),
__metadata("design:returntype", void 0)
], TooltipDirective.prototype, "hide", null);
(function () { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(TooltipDirective, [{
type: Directive,
args: [{
selector: '[smeTooltip],[title]'
}]
}], function () { return [{ type: i0.ElementRef }, { type: i0.Injector }]; }, { toolTipFocusEventTriggered: [{
type: Output
}], toolTipMouseEventTriggered: [{
type: Output
}], title: [{
type: Input
}], smeTooltip: [{
type: Input
}], smeTooltipContext: [{
type: Input
}], smeTooltipPlacement: [{
type: Input
}], smeTooltipShowOn: [{
type: Input
}], smeTooltipShow: [{
type: Input
}], smeTooltipEnableEvents: [{
type: Input
}], hideOnTooltipSameAsText: [{
type: Input
}], tooltipZone: [{
type: Input
}], ariaDescribedBy: [{
type: HostBinding,
args: ['attr.aria-describedBy']
}], onFocusEvent: [{
type: HostListener,
args: [ToolTipFocusEvent.focusIn, ['$event']]
}, {
type: HostListener,
args: [ToolTipFocusEvent.focusOut, ['$event']]
}], onMouseEvent: [{
type: HostListener,
args: [ToolTipMouseEvent.mouseEnter, ['$event']]
}, {
type: HostListener,
args: [ToolTipMouseEvent.mouseLeave, ['$event']]
}], onClick: [{
type: HostListener,
args: ['click', ['$event']]
}, {
type: HostListener,
args: ['keydown.enter', ['$event']]
}, {
type: HostListener,
args: ['keydown.space', ['$event']]
}], show: [], hide: [] }); })();
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidG9vbHRpcC5kaXJlY3RpdmUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi9hbmd1bGFyL3NyYy9jb250cm9scy90b29sdGlwL3Rvb2x0aXAuZGlyZWN0aXZlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQSxPQUFPLEVBQ0gsU0FBUyxFQUNULFVBQVUsRUFDVixZQUFZLEVBQ1osV0FBVyxFQUNYLFlBQVksRUFDWixRQUFRLEVBQ1IsS0FBSyxFQUlMLE1BQU0sRUFFTixXQUFXLEVBQ2QsTUFBTSxlQUFlLENBQUM7QUFDdkIsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLDhFQUE4RSxDQUFDO0FBQ3hHLE9BQU8sRUFBRSxHQUFHLEVBQUUsTUFBTSxrREFBa0QsQ0FBQztBQUN2RSxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQUU3RCxPQUFPLEVBQWtCLGVBQWUsRUFBRSxNQUFNLDBCQUEwQixDQUFDO0FBQzNFLE9BQU8sRUFBb0Isb0JBQW9CLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQztBQUNwRixPQUFPLEVBQUUsbUJBQW1CLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUM5RCxPQUFPLEVBQUUsb0JBQW9CLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQzs7QUFFaEUsTUFBTSxPQUFPLGlCQUFpQjs7QUFDbkIseUJBQU8sR0FBRyxTQUFTLENBQUM7QUFDcEIsMEJBQVEsR0FBRyxVQUFVLENBQUM7QUFHakMsTUFBTSxPQUFPLGlCQUFpQjs7QUFDbkIsNEJBQVUsR0FBRyxZQUFZLENBQUM7QUFDMUIsNEJBQVUsR0FBRyxZQUFZLENBQUM7QUFHckM7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBaUJHO0FBRUg7O0dBRUc7QUFJSCxNQUFNLE9BQU8sZ0JBQWlCLFNBQVEsaUJBQWlCO0lBNkxuRDs7O09BR0c7SUFDSCxZQUFvQixVQUFzQixFQUFFLFFBQWtCO1FBQzFELEtBQUssQ0FBQyxRQUFRLENBQUMs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aUJBQWlCLENBQUMsT0FBTyxFQUFFLENBQUMsUUFBUSxDQUFDOztrQkFDbEQsWUFBWTttQkFBQyxpQkFBaUIsQ0FBQyxRQUFRLEVBQUUsQ0FBQyxRQUFRLENBQUM7WUFjN0MsWUFBWTtrQkFGbEIsWUFBWTttQkFBQyxpQkFBaUIsQ0FBQyxVQUFVLEVBQUUsQ0FBQyxRQUFRLENBQUM7O2tCQUNyRCxZQUFZO21CQUFDLGlCQUFpQixDQUFDLFVBQVUsRUFBRSxDQUFDLFFBQVEsQ0FBQztZQWdCL0MsT0FBTztrQkFIYixZQUFZO21CQUFDLE9BQU8sRUFBRSxDQUFDLFFBQVEsQ0FBQzs7a0JBQ2hDLFlBQVk7bUJBQUMsZUFBZSxFQUFFLENBQUMsUUFBUSxDQUFDOztrQkFDeEMsWUFBWTttQkFBQyxlQUFlLEVBQUUsQ0FBQyxRQUFRLENBQUM7WUE2Q2xDLElBQUksTUFXSixJQUFJIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcclxuICAgIERpcmVjdGl2ZSxcclxuICAgIEVsZW1lbnRSZWYsXHJcbiAgICBFdmVudEVtaXR0ZXIsXHJcbiAgICBIb3N0QmluZGluZyxcclxuICAgIEhvc3RMaXN0ZW5lcixcclxuICAgIEluamVjdG9yLFxyXG4gICAgSW5wdXQsXHJcbiAgICBPbkNoYW5nZXMsXHJcbiAgICBPbkRlc3Ryb3ksXHJcbiAgICBPbkluaXQsXHJcbiAgICBPdXRwdXQsXHJcbiAgICBTaW1wbGVDaGFuZ2VzLFxyXG4gICAgVGVtcGxhdGVSZWZcclxufSBmcm9tICdAYW5ndWxhci9jb3JlJztcclxuaW1wb3J0IHsgRGVib3VuY2UgfSBmcm9tICdAbWljcm9zb2Z0L3dpbmRvd3MtYWRtaW4tY2VudGVyLXNkay9jb3JlL2Jhc2UvZGVjb3JhdG9ycy9kZWJvdW5jZS5kZWNvcmF0b3JzJztcclxuaW1wb3J0IHsgRG9tIH0gZnJvbSAnQG1pY3Jvc29mdC93aW5kb3dzLWFkbWluLWNlbnRlci1zZGsvY29yZS9kb20vZG9tJztcclxuaW1wb3J0IHsgQ29yZUJhc2VDb21wb25lbnQgfSBmcm9tICcuLi9jb21tb24vYmFzZS5jb21wb25lbnQnO1xyXG5pbXBvcnQgeyBUb29sdGlwSG9zdCB9IGZyb20gJy4vbW9kZWxzL3Rvb2x0aXAtaG9zdCc7XHJcbmltcG9ydCB7IFRvb2x0aXBPcHRpb25zLCBUb29sdGlwU2hvd01vZGUgfSBmcm9tICcuL21vZGVscy90b29sdGlwLW9wdGlvbnMnO1xyXG5pbXBvcnQgeyBUb29sdGlwUGxhY2VtZW50LCBUb29sdGlwUGxhY2VtZW50RW51bSB9IGZyb20gJy4vbW9kZWxzL3Rvb2x0aXAtcGxhY2VtZW50JztcclxuaW1wb3J0IHsgVG9vbHRpcEhvc3RJbnN0YW5jZSB9IGZyb20gJy4vdG9vbHRpcC1ob3N0LWluc3RhbmNlJztcclxuaW1wb3J0IHsgVG9vbHRpcFpvbmVEaXJlY3RpdmUgfSBmcm9tICcuL3Rvb2x0aXAtem9uZS5kaXJlY3RpdmUnO1xyXG5cclxuZXhwb3J0IGNsYXNzIFRvb2xUaXBGb2N1c0V2ZW50IHtcclxuICAgIHN0YXRpYyBmb2N1c0luID0gJ2ZvY3VzaW4nO1xyXG4gICAgc3RhdGljIGZvY3VzT3V0ID0gJ2ZvY3Vzb3V0JztcclxufVxyXG5cclxuZXhwb3J0IGNsYXNzIFRvb2xUaXBNb3VzZUV2ZW50IHtcclxuICAgIHN0YXRpYyBtb3VzZUVudGVyID0gJ21vdXNlZW50ZXInO1xyXG4gICAgc3RhdGljIG1vdXNlTGVhdmUgPSAnbW91c2VsZWF2ZSc7XHJcbn1cclxuXHJcbi8qKlxyXG4gKlxyXG4gKiBAc21lRG9jIHtAbGFiZWwgVG9vbHRpcCBAaWQgc21lLXRvb2x0aXAtZGlyZWN0aXZlfVxyXG4gKlxyXG4gKiBAb3ZlcnZpZXdcclxuICogQGZpbGUge0BmaWxlcGF0aCAuL2V4YW1wbGVzL292ZXJ2aWV3Lm1kfVxyXG4gKlxyXG4gKiBAZXhhbXBsZSB7QGxhYmVsIEJhc2ljIFVzYWdlIEBpZCBiYXNpYy11c2FnZX1cclxuICogQGZpbGUge0BmaWxlbmFtZSBjb21wb25lbnQuaHRtbCBAZmlsZXBhdGggLi9leGFtcGxlcy9iYXNpYy11c2FnZS5jb21wb25lbnQuaHRtbH1cclxuICogQGZpbGUge0BmaWxlbmFtZSBjb21wb25lbnQudHMgQGZpbGVwYXRoIC4vZXhhbXBsZXMvdG9vbHRpcC1leGFtcGxlLmNvbXBvbmVudC50c31cclxuICpcclxuICogQGV4YW1wbGUge0BsYWJlbCBDdXN0b20gVGVtcGxhdGUgQGlkIGN1c3RvbS10ZW1wbGF0ZX1cclxuICogQGZpbGUge0BmaWxlbmFtZSBjb21wb25lbnQuaHRtbCBAZmlsZXBhdGggLi9leGFtcGxlcy90ZW1wbGF0ZS1yZWZlcmVuY2UuY29tcG9uZW50Lmh0bWx9XHJcbiAqIEBmaWxlIHtAZmlsZW5hbWUgY29tcG9uZW50LnRzIEBmaWxlcGF0aCAuL2V4YW1wbGVzL3Rvb2x0aXAtZXhhbXBsZS5jb21wb25lbnQudHN9XHJcbiAqXHJcbiAqIEBleGFtcGxlIHtAbGFiZWwgQ3VzdG9tIEltcGxlbWVudGF0aW9uIEBpZCB0b29sdGlwLXpvbmV9XHJcbiAqIEBmaWxlIHtAZmlsZW5hbWUgY29tcG9uZW50Lmh0bWwgQGZpbGVwYXRoIC4vZXhhbXBsZXMvdG9vbHRpcC16b25lLmNvbXBvbmVudC5odG1sfVxyXG4gKi9cclxuXHJcbi8qKlxyXG4gKiBEaXJlY3RpdmUgdG8gY3JlYXRlIHRvb2x0aXBzIGluIHRoZSB0b29sdGlwIGhvc3QuXHJcbiAqL1xyXG5ARGlyZWN0aXZlKHtcclxuICAgIHNlbGVjdG9yOiAnW3NtZVRvb2x0aXBdLFt0aXRsZV0nXHJcbn0pXHJcbmV4cG9ydCBjbGFzcyBUb29sdGlwRGlyZWN0aXZlIGV4dGVuZHMgQ29yZUJhc2VDb21wb25lbnQgaW1wbGVtZW50cyBPbkRlc3Ryb3ksIE9uQ2hhbmdlcywgT25Jbml0IHtcclxuXHJcbiAgICAvKipcclxuICAgICAqIFRoZSBzb3VyY2UgbmFtZSB0byB1c2UgZm9yIGxvZ2dpbmdcclxuICAgICAqL1xyXG4gICAgcHJvdGVjdGVkIGdldCBsb2dTb3VyY2VOYW1lKCkge1xyXG4gICAgICAgIHJldHVybiAnVG9vbHRpcERpcmVjdGl2ZSc7XHJcbiAgICB9XHJcblxyXG4gICAgQE91dHB1dCgpIHB1YmxpYyB0b29sVGlwRm9jdXNFdmVudFRyaWdnZXJlZDogRXZlbnRFbWl0dGVyPFRvb2xUaXBGb2N1c0V2ZW50PiA9IG5ldyBFdmVudEVtaXR0ZXI8VG9vbFRpcEZvY3VzRXZlbnQ+KCk7XHJcbiAgICBAT3V0cHV0KCkgcHVibGljIHRvb2xUaXBNb3VzZUV2ZW50VHJpZ2dlcmVkOiBFdmVudEVtaXR0ZXI8VG9vbFRpcE1vdXNlRXZlbnQ+ID0gbmV3IEV2ZW50RW1pdHRlcjxUb29sVGlwTW91c2VFdmVudD4oKTtcclxuXHJcbiAgICAvKipcclxuICAgICAqIFRoZSBuYXRpdmUgdG9vbHRpcCBwcm9wZXJ0eVxyXG4gICAgICovXHJcbiAgICBASW5wdXQoKVxyXG4gICAgcHVibGljIHRpdGxlOiBzdHJpbmc7XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBBIHRlbXBsYXRlIHJlZmVyZW5jZSBmb3IgYSBjdXN0b20gdG9vbHRpcC5cclxuICAgICAqL1xyXG4gICAgQElucHV0KClcclxuICAgIHB1YmxpYyBzbWVUb29sdGlwOiBUZW1wbGF0ZVJlZjxhbnk+O1xyXG5cclxuICAgIC8qKlxyXG4gICAgICogQSBkYXRhIG9iamVjdCB0aGF0IGNhbiBiZSBhY2Nlc3NlZCBpbiBhIHRlbXBsYXRlIHJlZmVyZW5jZSBmb3IgYSBjdXN0b20gdG9vbHRpcC5cclxuICAgICAqL1xyXG4gICAgQElucHV0KClcclxuICAgIHB1YmxpYyBzbWVUb29sdGlwQ29udGV4dDogYW55O1xyXG5cclxuICAgIC8qKlxyXG4gICAgICogVGhlIGlucHV0IGZvciB0aGUgcGxhY2VtZW50IG9mIHRoZSB0b29sdGlwLiBEZWZhdWx0cyB0byAnYm90dG9tJy5cclxuICAgICAqL1xyXG4gICAgQElucHV0KClcclxuICAgIHB1YmxpYyBzbWVUb29sdGlwUGxhY2VtZW50OiBzdHJpbmc7XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBJbmRpY2F0ZXMgd2hlbiB0byBzaG93IHRoZSB0b29sdGlwLlxyXG4gICAgICovXHJcbiAgICBASW5wdXQoKVxyXG4gICAgcHVibGljIHNtZVRvb2x0aXBTaG93T246IFRvb2x0aXBTaG93TW9kZTtcclxuXHJcbiAgICAvKipcclxuICAgICAqIEluZGljYXRlcyB3aGVuIHRvIGV4cGxpY2l0bHkgbm90IHNob3cgdGhlIHRvb2x0aXAgaW4gY2FzZXMgd2hlcmUgaXQgbmVlZHMgdG8gYmUgc2hvd24gb25seSB1bmRlciBjZXJ0YWluIGNvbmRpdGlvbnMuXHJcbiAgICAgKi9cclxuICAgIEBJbnB1dCgpXHJcbiAgICBwdWJsaWMgc21lVG9vbHRpcFNob3cgPSB0cnVlO1xyXG5cclxuICAgIC8qKlxyXG4gICAgICogSW5kaWNhdGVzIGlmIHJlY2VpdmluZyBob3ZlciBhbmQgZm9jdXMgZXZlbnRzLlxyXG4gICAgICovXHJcbiAgICBASW5wdXQoKVxyXG4gICAgcHVibGljIHNtZVRvb2x0aXBFbmFibGVFdmVudHMgPSBmYWxzZTtcclxuXHJcbiAgICAvKipcclxuICAgICAqIEluZGljYXRlcyBpZiBoaWRlIHRoZSB0b29sdGlwIHdoZW4gaW5uZXIgSFRNTCBpcyB0aGUgc2FtZSBhcyB0b29sdGlwIGNvbnRlbnRcclxuICAgICAqIEluIGNlcnRhaW4gY2FzZXMsIHdlIGFsd2F5cyBuZWVkIHRoZSB0b29sdGlwIHRvIHNob3csIHN1Y2ggYXMgdGhlIG11bHRpLXRvb2wgY29tcG9uZW50IHRvb2wgbGlzdC5cclxuICAgICAqL1xyXG4gICAgIEBJbnB1dCgpXHJcbiAgICAgcHVibGljIGhpZGVPblRvb2x0aXBTYW1lQXNUZXh0ID0gdHJ1ZTtcclxuXHJcbiAgICAvKipcclxuICAgICAqIFRoZSBkZWZpbmVkIHpvbmUgZm9yIHNob3dpbmcgdG9vbHRpcCB3aXRoIGEgc2hvcnRjdXQuIFRoZSB6b25lIGlzIGEgd3JhcHBlciBmb3IgdGhlIGNvbnRlbnQgdGhhdCBpcyByZWxldmFudCB0byB0aGUgdG9vbHRpcC5cclxuICAgICAqL1xyXG4gICAgQElucHV0KClcclxuICAgIHB1YmxpYyB0b29sdGlwWm9uZTogVG9vbHRpcFpvbmVEaXJlY3RpdmU7XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBHZXRzIHRoZSBpZCBvZiB0aGUgdG9vbHRpcCB0aGF0IHdpbGwgZGVzY3JpYmUgdGhpcyBlbGVtZW50XHJcbiAgICAgKi9cclxuICAgIEBIb3N0QmluZGluZygnYXR0ci5hcmlhLWRlc2NyaWJlZEJ5JylcclxuICAgIHB1YmxpYyBnZXQgYXJpYURlc2NyaWJlZEJ5KCk6IHN0cmluZyB7XHJcbiAgICAgICAgaWYgKCF0aGlzLnNob3duIHx8ICFNc2Z0U21lLmlzTnVsbE9yVW5kZWZpbmVkKHRoaXMuc21lVG9vbHRpcCkgfHwgIXRoaXMuaGlkZU9uVG9vbHRpcFNhbWVBc1RleHQpIHtcclxuICAgICAgICAgICAgcmV0dXJuIG51bGw7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHJldHVybiB0aGlzLmlkQmFnICYmIHRoaXMuaWRCYWcudG9vbHRpcCA/IHRoaXMuaWRCYWcudG9vbHRpcCA6IG51bGw7XHJcbiAgICB9XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBUaGUgYWN0dWFsIHBsYWNlbWVudCBvZiB0aGUgdG9vbHRpcFxyXG4gICAgICovXHJcbiAgICBwcml2YXRlIGdldCBwbGFjZW1lbnQoKTogVG9vbHRpcFBsYWNlbWVudCB7XHJcbiAgICAgICAgcmV0dXJuIFRvb2x0aXBQbGFjZW1lbnRFbnVtLmZyb21TdHJpbmcodGhpcy5zbWVUb29sdGlwUGxhY2VtZW50KTtcclxuICAgIH1cclxuXHJcbiAgICAvKipcclxuICAgICAqIFRoZSB0b29sdGlwIGhvc3RcclxuICAgICAqL1xyXG4gICAgcHJpdmF0ZSBnZXQgdG9vbHRpcEhvc3QoKTogVG9vbHRpcEhvc3Qge1xyXG4gICAgICAgIHJldHVybiBUb29sdGlwSG9zdEluc3RhbmNlLmFjdGl2ZUhvc3Q7XHJcbiAgICB9XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBJbmRpY2F0ZXMgdGhhdCB0b29sdGlwcyBzaG91bGQgc2hvdyBvbiBmb2N1cy9ob3Zlci5cclxuICAgICAqL1xyXG4gICAgcHVibGljIGdldCBzaG93T25mb2N1cygpIHtcclxuICAgICAgICByZXR1cm4gISFNc2Z0U21lLnNlbGYoKS5SZXNvdXJjZXMuYWNjZXNzaWJpbGl0eU1vZGU7XHJcbiAgICB9XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBJbnRlcm5hbCBwbGFjZWhvbGRlciBmb3IgdGhlIGN1cnJlbnQgZm9jdXNlZCBzdGF0ZVxyXG4gICAgICovXHJcbiAgICBwcml2YXRlIGZvY3VzZWQ6IGJvb2xlYW47XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBJbnRlcm5hbCBwbGFjZWhvbGRlciBmb3IgdGhlIGN1cnJlbnQgY2xpY2tlZCBzdGF0ZVxyXG4gICAgICovXHJcbiAgICBwcml2YXRlIGNsaWNrZWQ6IGJvb2xlYW47XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBJbnRlcm5hbCBwbGFjZWhvbGRlciBmb3IgdGhlIGN1cnJlbnQgaG92ZXJlZCBzdGF0ZVxyXG4gICAgICovXHJcbiAgICBwcml2YXRlIGhvdmVyZWQ6IGJvb2xlYW47XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBJbnRlcm5hbCBtdXRhdGlvbiBvYnNlcnZlciB1c2VkIHRvIHdhdGNoIGZvciBkaXNhYmxlZCBhdHRyaWJ1dGUgb24gZWxlbWVudHNcclxuICAgICAqL1xyXG4gICAgcHJpdmF0ZSBvYnNlcnZlcjogTXV0YXRpb25PYnNlcnZlcjtcclxuXHJcbiAgICAvKipcclxuICAgICAqIEludGVybmFsIHBsYWNlaG9sZGVyIGZvciB0b29sdGlwIHRyaWdnZXJpbmcgY2F1c2UgKGNsaWNrLCBob3ZlciwgZm9jdXMpXHJcbiAgICAgKi9cclxuICAgIHByaXZhdGUgdG9vbHRpcFRyaWdnZXI6IFRvb2x0aXBTaG93TW9kZTtcclxuXHJcbiAgICAvKipcclxuICAgICAqIEluZGljYXRlcyBpZiB0aGUgdG9vbHRpcCBpcyBiZWluZyBzaG93bi5cclxuICAgICAqL1xyXG4gICAgcHVibGljIGdldCBzaG93bigpOiBib29sZWFuIHtcclxuICAgICAgICByZXR1cm4gdGhpcy50b29sdGlwSG9zdC5pc1Nob3duKHRoaXMuY29tcG9uZW50SWQpO1xyXG4gICAgfVxyXG5cclxuICAgIC8qKlxyXG4gICAgICogSW5kaWNhdGVzIHRoYXQgdGhpcyB0b29sdGlwIHNob3VsZCBzaG93IG9ubHkgd2hlbiB0aGUgdGV4dCBpcyB0cnVuY2F0ZWRcclxuICAgICAqIFdlIGFzc3VtZSB0aGlzIGlzIHRydWUgaWYgdGhlIHRpdGxlIGF0dHJpYnV0ZSBpcyBleGFjdGx5IHRoZSBzYW1lIGFzIHRoZSB0ZXh0IGNvbnRlbnQgb2YgdGhpcyBub2RlLlxyXG4gICAgICovXHJcbiAgICBwcml2YXRlIGdldCBpc1Rvb2x0aXBTYW1lQXNUZXh0KCk6IGJvb2xlYW4ge1xyXG4gICAgICAgIGlmIChNc2Z0U21lLmlzTnVsbE9yVW5kZWZpbmVkKHRoaXMudGl0bGUpKSB7XHJcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIGNvbnN0IG5hdGl2ZWhvc3RFbGVtZW50ID0gPEhUTUxFbGVtZW50PnRoaXMuaG9zdEVsZW1lbnQubmF0aXZlRWxlbWVudDtcclxuICAgICAgICByZXR1cm4gISF0aGlzLnRpdGxlICYmIE1zZnRTbWUubG9jYWxlQ29tcGFyZUlnbm9yZUNhc2UoXHJcbiAgICAgICAgICAgIFN0cmluZyh0aGlzLnRpdGxlKS50cmltKCksIG5hdGl2ZWhvc3RFbGVtZW50LnRleHRDb250ZW50LnRyaW0oKSkgPT09IDA7XHJcbiAgICB9XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBJbmRpY2F0ZXMgdGhhdCB0aGlzIHRvb2x0aXAgc2hvdWxkIGJlIHNob3duXHJcbiAgICAgKi9cclxuICAgIHByaXZhdGUgZ2V0IHNob3VsZFNob3coKSB7XHJcbiAgICAgICAgaWYgKE1zZnRTbWUuaXNOdWxsT3JXaGl0ZVNwYWNlKHRoaXMudGl0bGUpXHJcbiAgICAgICAgICAgICYmIE1zZnRTbWUuaXNOdWxsT3JVbmRlZmluZWQodGhpcy5zbWVUb29sdGlwKSB8fCAhdGhpcy5zbWVUb29sdGlwU2hvdykge1xyXG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICBpZiAoTXNmdFNtZS5hcHBseUJpdHdpc2VBbmQodGhpcy5zbWVUb29sdGlwU2hvd09uLCBUb29sdGlwU2hvd01vZGUuQ2xpY2spKSB7XHJcbiAgICAgICAgICAgIC8vIGlmIHdlIGFyZSBob3ZlcmVkIG9yIG91ciB0b29sdGlwIGlzIGhvdmVyZWRcclxuICAgICAgICAgICAgaWYgKHRoaXMuY2xpY2tlZCkge1xyXG4gICAgICAgICAgICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgIC8vIGlmIHdlIGFyZSBzaG93biBhbmQgYXJlIGZvY3VzZWQgb3Igb3VyIHRvb2x0aXBcclxuICAgICAgICAgICAgaWYgKHRoaXMuc2hvd24gJiYgdGhpcy50b29sdGlwSG9zdC5pc0ZvY3VzZWQpIHtcclxuICAgICAgICAgICAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgfSBlbHNlIGlmIChNc2Z0U21lLmFwcGx5Qml0d2lzZUFuZCh0aGlzLnNtZVRvb2x0aXBTaG93T24sXHJcbiAgICAgICAgICAgICAgICAgICAgKE1zZnRTbWUuYXBwbHlCaXR3aXNlT3IoVG9vbHRpcFNob3dNb2RlLkhvdmVyLCBUb29sdGlwU2hvd01vZGUuS2V5Ym9hcmRGb2N1cykpKSkge1xyXG4gICAgICAgICAgICBpZiAodGhpcy5oaWRlT25Ub29sdGlwU2FtZUFzVGV4dCAmJiB0aGlzLmlzVG9vbHRpcFNhbWVBc1RleHQgJiYgIXRoaXMuZ2V0SXNUcnVuY2F0ZWQoKSkge1xyXG5cclxuICAgICAgICAgICAgICAgIC8vIFJlbW92ZSB0aXRsZSBhdHRyaWJ1dGUgd2hlbiB0cnVlIGNvbmRpdGlvbnMgYXJlIG5vdCBtZXRcclxuICAgICAgICAgICAgICAgIHRoaXMuc2V0QXR0cmlidXRlKCd0aXRsZScsICcnKTtcclxuICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcclxuICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgLy8gaWYgd2UgYXJlIGhvdmVyZWQgb3Igb3VyIHRvb2x0aXAgaXMgaG92ZXJlZFxyXG4gICAgICAgICAgICBpZiAodGhpcy5ob3ZlcmVkIHx8ICh0aGlzLnNob3duICYmIHRoaXMudG9vbHRpcEhvc3QuaXNIb3ZlcmVkKSkge1xyXG4gICAgICAgICAgICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgIC8vIGlmIHdlIHNob3cgb24gZm9jdXMgYW5kIGFyZSBmb2N1c2VkIG9yIG91ciB0b29sdGlwIGhhcyBmb2N1c1xyXG4gICAgICAgICAgICBpZiAodGhpcy5zaG93T25mb2N1cyAmJiAodGhpcy5mb2N1c2VkIHx8ICh0aGlzLnNob3duICYmIHRoaXMudG9vbHRpcEhvc3QuaXNGb2N1c2VkKSkpIHtcclxuICAgICAgICAgICAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvLyBSZW1vdmUgdGl0bGUgYXR0cmlidXRlIHdoZW4gdHJ1ZSBjb25kaXRpb25zIGFyZSBub3QgbWV0XHJcbiAgICAgICAgdGhpcy5zZXRBdHRyaWJ1dGUoJ3RpdGxlJywgJycpO1xyXG4gICAgICAgIHJldHVybiBmYWxzZTtcclxuICAgIH1cclxuXHJcbiAgICAvKipcclxuICAgICAqIEluaXRpYWxpemVzIGEgbmV3IGluc3RhbmNlIG9mIHRoZSBAc2VlIFBpdm90Q29tcG9uZW50IGNsYXNzLlxyXG4gICAgICogQHBhcmFtIGluamVjdG9yIFRoZSBhbmd1bGFyIGluamVjdGlvbiBzZXJ2aWNlLiByZXF1aXJlZCBieSBAU21lSW5qZWN0YWJsZUJhc2UoKSBkZWNvcmF0b3IgaW4gdGhlIGJhc2UgQHNlZSBCYXNlQ29tcG9uZW50IGNsYXNzXHJcbiAgICAgKi9cclxuICAgIGNvbnN0cnVjdG9yKHByaXZhdGUgZWxlbWVudFJlZjogRWxlbWVudFJlZiwgaW5qZWN0b3I6IEluamVjdG9yKSB7XHJcbiAgICAgICAgc3VwZXIoaW5qZWN0b3IpO1xyXG4gICAgICAgIHRoaXMuc21lVG9vbHRpcFNob3dPbiA9IE1zZnRTbWUuYXBwbHlCaXR3aXNlT3IoVG9vbHRpcFNob3dNb2RlLkhvdmVyLCBUb29sdGlwU2hvd01vZGUuS2V5Ym9hcmRGb2N1cyk7XHJcbiAgICB9XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBJbXBsZW1lbnRhdGlvbiBvZiBhbmd1bGFyIE9uSW5pdCBpbnRlcmZhY2VcclxuICAgICAqL1xyXG4gICAgcHVibGljIG5nT25Jbml0KCk6IHZvaWQge1xyXG4gICAgICAgIGlmICh0aGlzLnRvb2x0aXBab25lKSB7XHJcbiAgICAgICAgICAgIHRoaXMudG9vbHRpcFpvbmUucmVnaXN0ZXJUb29sdGlwRGlyZWN0aXZlKHRoaXMpO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gU2V0IHVwIG9ic2VydmVyIGlmIGVsZW1lbnQgY2FuIGJlIGRpc2FibGVkLCB3YXRjaCBmb3IgZGlzYWJsZWQgY2hhbmdlc1xyXG4gICAgICAgIGlmICh0aGlzLmVsZW1lbnRSZWYgJiZcclxuICAgICAgICAgICAgdGhpcy5lbGVtZW50UmVmLm5hdGl2ZUVsZW1lbnQgJiZcclxuICAgICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIGVxZXFlcVxyXG4gICAgICAgICAgICB0aGlzLmVsZW1lbnRSZWYubmF0aXZlRWxlbWVudC5kaXNhYmxlZCAhPSBudWxsKSB7XHJcblxyXG4gICAgICAgICAgICAvLyBXZSBoaWRlIHRoZSB0b29sdGlwIGlmIHRoZSBlbGVtZW50IGl0IGlzIGF0dGFjaGVkIHRvIGJlY29tZXMgZGlzYWJsZWRcclxuICAgICAgICAgICAgdGhpcy5vYnNlcnZlciA9IG5ldyBNdXRhdGlvbk9ic2VydmVyKG11dGF0aW9ucyA9PiB7XHJcbiAgICAgICAgICAgICAgICBtdXRhdGlvbnMuZm9yRWFjaChtdXRhdGlvbiA9PiB7XHJcbiAgICAgICAgICAgICAgICAgICAgaWYgKG11dGF0aW9uLmF0dHJpYnV0ZU5hbWUgPT09ICdkaXNhYmxlZCcpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gQ2hlY2sgaWYgbmVlZCB0byBiZSBoaWRkZW5cclxuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5oaWRlKCk7XHJcbiAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgfSk7XHJcbiAgICAgICAgICAgIH0pO1xyXG5cclxuICAgICAgICAgICAgY29uc3QgY29uZmlnID0geyBhdHRyaWJ1dGVzOiB0cnVlLCBjaGlsZExpc3Q6IHRydWUsIGNoYXJhY3RlckRhdGE6IHRydWUgfTtcclxuICAgICAgICAgICAgdGhpcy5vYnNlcnZlci5vYnNlcnZlKHRoaXMuZWxlbWVudFJlZi5uYXRpdmVFbGVtZW50LCBjb25maWcpO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvKipcclxuICAgICAqIEltcGxlbWVudGF0aW9uIG9mIGFuZ3VsYXIgT25DaGFuZ2VzIGludGVyZmFjZVxyXG4gICAgICogT24gYW55IGNoYW5nZSB3ZSB1cGRhdGUgdGhlIHRvb2x0aXAgaWYgaXQgaXMgc2hvd25cclxuICAgICAqL1xyXG4gICAgcHVibGljIG5nT25DaGFuZ2VzKGNoYW5nZXM6IFNpbXBsZUNoYW5nZXMpOiB2b2lkIHtcclxuICAgICAgICBzdXBlci5uZ09uQ2hhbmdlcyhjaGFuZ2VzKTtcclxuXHJcbiAgICAgICAgaWYgKHRoaXMuc2hvd24pIHtcclxuICAgICAgICAgICAgdGhpcy50b29sdGlwSG9zdC51cGRhdGUodGhpcy5nZXRUb29sdGlwT3B0aW9ucygpKTtcclxuICAgICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBJbXBsZW1lbnRhdGlvbiBvZiBhbmd1bGFyIE9uRGVzdHJveSBpbnRlcmZhY2VcclxuICAgICAqL1xyXG4gICAgcHVibGljIG5nT25EZXN0cm95KCk6IHZvaWQge1xyXG4gICAgICAgIHN1cGVyLm5nT25EZXN0cm95KCk7XHJcbiAgICAgICAgdGhpcy5zaG93SGlkZVRvb2x0aXAoZmFsc2UsIGZhbHNlKTtcclxuICAgICAgICBpZiAodGhpcy50b29sdGlwWm9uZSkge1xyXG4gICAgICAgICAgICB0aGlzLnRvb2x0aXBab25lLnVucmVnaXN0ZXJUb29sdGlwRGlyZWN0aXZlKCk7XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8qKlxyXG4gICAgICogQ3JlYXRlcyB0aGUgaWRCYWcgdXNlZCBieSB0aGlzIGNvbXBvbmVudCB0byBzdG9yZSB1bmlxdWUgZWxlbWVudCBpZHMuXHJcbiAgICAgKiBpZCB2YWx1ZXMgd2lsbCBiZSBhc3NpZ25lZCBiZSB0aGUgQHNlZSBCYXNlQ29tcG9uZW50IHN1cGVyIGNsYXNzLlxyXG4gICAgICovXHJcbiAgICBwcm90ZWN0ZWQgY3JlYXRlSWRCYWcoKTogTXNmdFNtZS5TdHJpbmdNYXA8c3RyaW5nPiB7XHJcbiAgICAgICAgcmV0dXJuIHtcclxuICAgICAgICAgICAgdG9vbHRpcDogJydcclxuICAgICAgICB9O1xyXG4gICAgfVxyXG5cclxuICAgIC8qKlxyXG4gICAgICogSG9zdCBsaXN0ZW5lcnMgZm9yIHRvb2x0aXAgZm9jdXMgZXZlbnRzXHJcbiAgICAgKi9cclxuICAgIEBIb3N0TGlzdGVuZXIoVG9vbFRpcEZvY3VzRXZlbnQuZm9jdXNJbiwgWyckZXZlbnQnXSlcclxuICAgIEBIb3N0TGlzdGVuZXIoVG9vbFRpcEZvY3VzRXZlbnQuZm9jdXNPdXQsIFsnJGV2ZW50J10pXHJcbiAgICBwdWJsaWMgb25Gb2N1c0V2ZW50KGV2ZW50OiBFdmVudCk6IHZvaWQge1xyXG4gICAgICAgIC8vIG9uIGZvY3VzIGluL291dCBjaGFuZ2UgZm9jdXNlZCBzdGF0ZVxyXG4gICAgICAgIGNvbnN0IGZvY3VzZWQgPSBldmVudC50eXBlID09PSBUb29sVGlwRm9jdXNFdmVudC5mb2N1c0luIHx8ICh0aGlzLmZvY3VzZWQgJiYgZXZlbnQudHlwZSAhPT0gVG9vbFRpcEZvY3VzRXZlbnQuZm9jdXNPdXQpO1xyXG4gICAgICAgIGNvbnN0IGxvc3RDbGlja0ZvY3VzID0gdGhpcy5jbGlja2VkICYmIGV2ZW50LnR5cGUgPT09IFRvb2xUaXBGb2N1c0V2ZW50LmZvY3VzT3V0O1xyXG4gICAgICAgIHRoaXMudG9vbHRpcFRyaWdnZXIgPSB0aGlzLmNsaWNrZWQgPyBUb29sdGlwU2hvd01vZGUuQ2xpY2sgOiBUb29sdGlwU2hvd01vZGUuS2V5Ym9hcmRGb2N1cztcclxuICAgICAgICB0aGlzLnNob3dIaWRlVG9vbHRpcCh0aGlzLmhvdmVyZWQsIGZvY3VzZWQsIGxvc3RDbGlja0ZvY3VzID8gZmFsc2UgOiB0aGlzLmNsaWNrZWQpO1xyXG4gICAgfVxyXG5cclxuICAgIC8qKlxyXG4gICAgICogSG9zdCBsaXN0ZW5lcnMgZm9yIHRvb2x0aXAgbW91c2UgZXZlbnRzXHJcbiAgICAgKi9cclxuICAgIEBIb3N0TGlzdGVuZXIoVG9vbFRpcE1vdXNlRXZlbnQubW91c2VFbnRlciwgWyckZXZlbnQnXSlcclxuICAgIEBIb3N0TGlzdGVuZXIoVG9vbFRpcE1vdXNlRXZlbnQubW91c2VMZWF2ZSwgWyckZXZlbnQnXSlcclxuICAgIHB1YmxpYyBvbk1vdXNlRXZlbnQoZXZlbnQ6IEV2ZW50KTogdm9pZCB7XHJcbiAgICAgICAgaWYgKE1zZnRTbWUuYXBwbHlCaXR3aXNlQW5kKHRoaXMuc21lVG9vbHRpcFNob3dPbiwgVG9vbHRpcFNob3dNb2RlLkhvdmVyKSkge1xyXG4gICAgICAgICAgICAvLyBvbiBtb3VzZSBlbnRlci9sZWF2ZSBjaGFuZ2UgaG92ZXJlZCBzdGF0ZVxyXG4gICAgICAgICAgICBjb25zdCBob3ZlcmVkID0gZXZlbnQudHlwZSA9PT0gVG9vbFRpcE1vdXNlRXZlbnQubW91c2VFbnRlciB8fCAodGhpcy5ob3ZlcmVkICYmIGV2ZW50LnR5cGUgIT09IFRvb2xUaXBNb3VzZUV2ZW50Lm1vdXNlTGVhdmUpO1xyXG4gICAgICAgICAgICB0aGlzLnRvb2x0aXBUcmlnZ2VyID0gVG9vbHRpcFNob3dNb2RlLkhvdmVyO1xyXG4gICAgICAgICAgICB0aGlzLnNob3dIaWRlVG9vbHRpcChob3ZlcmVkLCB0aGlzLmZvY3VzZWQsIHRoaXMuY2xpY2tlZCk7XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8qKlxyXG4gICAgICogSG9zdCBsaXN0ZW5lcnMgZm9yIGNsaWNrIGFuZCBlbnRlclxyXG4gICAgICovXHJcbiAgICBASG9zdExpc3RlbmVyKCdjbGljaycsIFsnJGV2ZW50J10pXHJcbiAgICBASG9zdExpc3RlbmVyKCdrZXlkb3duLmVudGVyJywgWyckZXZlbnQnXSlcclxuICAgIEBIb3N0TGlzdGVuZXIoJ2tleWRvd24uc3BhY2UnLCBbJyRldmVudCddKVxyXG4gICAgcHVibGljIG9uQ2xpY2soZXZlbnQ6IEV2ZW50KTogdm9pZCB7XHJcbiAgICAgICAgaWYgKE1zZnRTbWUuYXBwbHlCaXR3aXNlQW5kKHRoaXMuc21lVG9vbHRpcFNob3dPbiwgVG9vbHRpcFNob3dNb2RlLkNsaWNrKSkge1xyXG4gICAgICAgICAgICB0aGlzLnNob3dIaWRlVG9vbHRpcCh0aGlzLmhvdmVyZWQsIHRoaXMuZm9jdXNlZCwgdHJ1ZSk7XHJcbiAgICAgICAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XHJcbiAgICAgICAgICAgIGV2ZW50LnN0b3BQcm9wYWdhdGlvbigpO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvKipcclxuICAgICAqIFNob3dzIG9yIGhpZGVzIHRoZSB0b29sdGlwIGlmIGVpdGhlciB0aGUgaG92ZXIgb3IgZm9jdXNlZCBzdGF0ZXMgYXJlIHRydWVcclxuICAgICAqIEBwYXJhbSBob3ZlcmVkIGluZGljYXRlcyB0aGUgZWxlbWVudCBpcyBob3ZlcmVkXHJcb