@microsoft/windows-admin-center-sdk
Version:
Microsoft - Windows Admin Center Shell
377 lines • 64.5 kB
JavaScript
import { Injectable } from '@angular/core';
import { ActivatedRoute, NavigationEnd, NavigationStart, Router } from '@angular/router';
import { CoreEnvironment } from '@microsoft/windows-admin-center-sdk/core/data/core-environment';
import { NativeQ } from '@microsoft/windows-admin-center-sdk/core/data/native-q';
import { Net } from '@microsoft/windows-admin-center-sdk/core/data/net';
import { Logging } from '@microsoft/windows-admin-center-sdk/core/diagnostics/logging';
import { SmeWebTelemetry } from '@microsoft/windows-admin-center-sdk/core/diagnostics/sme-web-telemetry';
import { PerformanceProfile } from '@microsoft/windows-admin-center-sdk/core/performance/performance-profile';
import { PerformanceTracker } from '@microsoft/windows-admin-center-sdk/core/performance/performance-tracker';
import { RpcOverlayCloseKey } from '@microsoft/windows-admin-center-sdk/core/rpc/overlay/rpc-overlay-model';
import { RpcObservablePerformanceConfigServer } from '@microsoft/windows-admin-center-sdk/core/rpc/performance/rpc-observable-performance-config-server';
import { RpcDeactivateState, RpcOpenState, RpcOutboundCommands } from '@microsoft/windows-admin-center-sdk/core/rpc/rpc-base';
import { RpcObservableUpdateThemeServer } from '@microsoft/windows-admin-center-sdk/core/rpc/update-theme/rpc-observable-update-theme-server';
import { EMPTY, of } from 'rxjs';
import { catchError, filter, map, mergeMap, switchMap, take, tap } from 'rxjs/operators';
import { AppContextService } from './app-context.service';
import { ConnectivityEnforcer } from './connectivity-enforcer';
import { Navigation } from './navigation';
import { UserAliveService } from './user-alive.service';
import * as i0 from "@angular/core";
import * as i1 from "./app-context.service";
import * as i2 from "./user-alive.service";
import * as i3 from "@angular/router";
/**
* Once initialize this class uses the underlying RPC channel
* to communicate with the remote RPC service.
*/
export class NavigationService {
/**
* Creates a new instance of this service
*/
constructor(appContextService, userAliveService, router, activatedRoute) {
this.appContextService = appContextService;
this.userAliveService = userAliveService;
this.router = router;
this.activatedRoute = activatedRoute;
this.defaultNavigationOptions = { skipLocationChange: true };
this.enteringModule = true;
this.dialogServiceMap = {};
this.openContext = {
state: null,
requestedTime: 0,
timer: null,
deferred: null,
error: null
};
this.deactivateContext = {
state: null,
requestedTime: 0,
timer: null,
deferred: null
};
}
/**
* Initialize navigation communication from/to the shell.
*
* Registers the methods with the remote RPC defined in the manifest
* Subscribes to the router events and reports the breadcrumb items
* back to the rpc remote
*
* @param options The options to override the default behavior
*/
initialize(options) {
PerformanceTracker.navigationInitialized();
this.active = true;
this.options = options ? options : { idleRoute: ['idle'] };
this.idleUrl = `/${this.options.idleRoute[0]}`;
// navigate to idle.
this.router.navigate(this.options.idleRoute, this.defaultNavigationOptions);
this.subscription?.unsubscribe();
let startTimestamp = null;
this.subscription = this.router.events
.pipe(tap(event => {
if (event instanceof NavigationStart) {
startTimestamp = Date.now();
PerformanceTracker.navigationStarted();
}
else if (event instanceof NavigationEnd && startTimestamp) {
PerformanceProfile.logRouteNavigation('NavigationService', startTimestamp, Date.now(), event.url, this.moduleName);
startTimestamp = null;
PerformanceTracker.navigationCompleted(this.enteringModule);
}
}), filter(event => event instanceof NavigationEnd), switchMap(event => Navigation.buildSelectablePathsForRoute(this.appContextService, this.activatedRoute.snapshot)
.pipe(map(selectablePaths => ({ event, selectablePaths })))))
.subscribe((data) => {
// in the case of initial idle state, reporting url will cause rpc error. all other cases should be ok.
// RpcReport include fragment and queryParams in 'path' and 'beforeRedirectedPath'.
if (this.active && data.event.url !== this.idleUrl) {
this.appContextService.frame.report({
path: decodeURI(data.event.urlAfterRedirects),
beforeRedirectedPath: decodeURI(data.event.url),
selectablePath: data.selectablePaths
});
this.enteringModule = false;
}
});
this.appContextService.rpc.register(RpcOutboundCommands.Init, this.onInit.bind(this));
this.appContextService.rpc.register(RpcOutboundCommands.Open, this.onOpen.bind(this));
this.appContextService.rpc.register(RpcOutboundCommands.Deactivate2, this.onDeactivate2.bind(this));
this.appContextService.rpc.register(RpcOutboundCommands.Activate, this.onActivate.bind(this));
this.appContextService.rpc.register(RpcOutboundCommands.Shutdown, this.onShutdown.bind(this));
this.appContextService.rpc.register(RpcOverlayCloseKey.command, this.onOverlayClose.bind(this));
}
/**
* Shutdown the navigation communication from/to the shell.
*/
shutdown() {
this.active = false;
this.subscription?.unsubscribe();
}
/**
* Map dialog service and dialog id so that correct dialog service instance can be found
* @param dialogService dialog service to be registered
* @param dialogId associated dialog id
*/
registerDialogService(dialogService, dialogId) {
this.dialogServiceMap[dialogId] = dialogService;
}
configurePerformanceProfile(enabled) {
const startTimestamp = Date.now();
if (enabled) {
PerformanceProfile.current.enable(this.appContextService.rpc);
}
else {
PerformanceProfile.current.disable(this.appContextService.rpc);
}
PerformanceProfile.logRouteNavigation('NavigationService', startTimestamp, Date.now(), '[rpcInit]', this.moduleName);
}
onInit(data) {
// Iframe has received all initialization data from the shell.
this.appContextService.gateway.navigationReadyStatus = true;
this.active = true;
const self = MsftSme.self();
if (!MsftSme.isNullOrUndefined(self.Init.sessionExpiration) && self.Init.sessionExpiration > 0) {
this.userAliveService.start();
}
ConnectivityEnforcer.register(this.appContextService);
this.moduleName = self.Init.moduleName;
this.configurePerformanceProfile(self.Init.performanceProfile);
PerformanceProfile.logNull(this.moduleName);
if (!this.RpcObservablePerformanceConfigServer) {
this.RpcObservablePerformanceConfigServer = new RpcObservablePerformanceConfigServer(this.appContextService.rpc);
this.RpcObservablePerformanceConfigServer.register((request) => {
this.configurePerformanceProfile(request.enabled);
return of(null);
});
}
if (!this.rpcObservableUpdateThemeServer) {
this.rpcObservableUpdateThemeServer = new RpcObservableUpdateThemeServer(this.appContextService.rpc);
this.rpcObservableUpdateThemeServer.register((request) => {
CoreEnvironment.assetManager.setTheme(request.newTheme);
return of(null);
});
}
return Promise.resolve();
}
/**
* Call to dialog service to request close a dialog
* @param data data object to close a dialog from shell
*/
onOverlayClose(data) {
const dialogService = this.dialogServiceMap[data.dialogId];
let result = false;
if (dialogService) {
result = dialogService.overlayClicked(data.dialogId);
delete this.dialogServiceMap[data.dialogId];
}
return Promise.resolve({ overlayClosed: result });
}
/**
* Repeated open called until navigation is established or failed.
*
* @param data the RpcOpenData data.
*/
onOpen(data) {
const context = this.openContext;
if (context.state != null) {
const result = {
waitedTime: Date.now() - context.requestedTime,
state: this.openContext.state,
error: context.error
};
if (context.state !== RpcOpenState.InProgress) {
context.state = null;
context.requestedTime = null;
}
return Promise.resolve(result);
}
context.requestedTime = Date.now();
context.state = RpcOpenState.InProgress;
context.deferred = NativeQ.defer();
// set timeout to respond back status to shell.
context.timer = setTimeout(() => {
context.deferred.resolve({
waitedTime: Date.now() - context.requestedTime,
state: context.state
});
context.timer = null;
context.deferred = null;
}, NavigationService.initialWaitTime);
this.appContextService.servicesReady
.pipe(take(1), mergeMap(() => {
SmeWebTelemetry.init(this.appContextService).subscribe(loaded => {
Logging.logDebug('SmeWebTelemetry', loaded ? 'Loaded browser telemetry' : 'Failed to load browser telemetry');
PerformanceTracker.tryStartCalculatingTimeToInteractive();
});
const navigation = Navigation.getUrlNavigationData(this.router, data.path);
return this.router.navigate(navigation.commands, this.addDefaultNavigationOptions(navigation.options));
}), map(success => {
PerformanceProfile.logRouteNavigation('NavigationService', context.requestedTime, Date.now(), '[rpcOpen]', this.moduleName);
context.state = RpcOpenState.Opened;
// if timer isn't fired yet, just complete with success navigation.
if (context.timer) {
clearTimeout(context.timer);
context.deferred.resolve({
waitedTime: Date.now() - context.requestedTime,
state: context.state,
error: context.error
});
context.state = null;
context.requestedTime = null;
context.timer = null;
context.deferred = null;
}
}), catchError((error, caught) => {
context.state = RpcOpenState.Failed;
let message = '';
if (error && error.xhr) {
message = Net.getErrorMessage(error);
}
else if (typeof error === 'string') {
message = error;
}
else {
if (error.stack) {
message = error.stack;
}
else if (error.message) {
message = error.message;
}
}
context.error = message;
// if timer isn't fired yet, just complete with error navigation.
if (context.timer) {
clearTimeout(context.timer);
context.deferred.reject(context.error);
context.state = null;
context.requestedTime = null;
context.timer = null;
context.deferred = null;
}
return EMPTY;
}))
.subscribe();
return context.deferred.promise;
}
/**
* Repeated called until Guard is continued or cancelled.
*
* @param data the void data.
*/
onDeactivate2(data) {
const startTimestamp = Date.now();
const context = this.deactivateContext;
if (context.state != null) {
const result = {
waitedTime: Date.now() - context.requestedTime,
state: context.state
};
if (context.state !== RpcDeactivateState.InProgress) {
context.state = null;
context.requestedTime = null;
}
PerformanceProfile.logRouteNavigation('NavigationService', startTimestamp, Date.now(), '[rpcDeactivate]', this.moduleName);
return Promise.resolve(result);
}
const current = decodeURI(this.router.url);
if (current === this.idleUrl) {
// it's already inactive.
return Promise.resolve({
waitedTime: 0,
state: RpcDeactivateState.Deactivated
});
}
context.requestedTime = Date.now();
context.state = RpcDeactivateState.InProgress;
context.deferred = NativeQ.defer();
// set timeout to respond back status to shell.
context.timer = setTimeout(() => {
context.deferred.resolve({
waitedTime: Date.now() - context.requestedTime,
state: context.state
});
context.timer = null;
context.deferred = null;
// if it isn't in progress, reset the state.
if (context.state !== RpcDeactivateState.InProgress) {
context.state = null;
context.requestedTime = null;
}
}, NavigationService.initialWaitTime);
// try navigate to idle.
this.router.navigate(this.options.idleRoute, this.defaultNavigationOptions)
.then(success => {
PerformanceProfile.logRouteNavigation('NavigationService', startTimestamp, Date.now(), '[rpcDeactivate]', this.moduleName);
if (success) {
// navigate away so inactive mode.
this.active = false;
this.lastRoute = Navigation.getUrlNavigationData(this.router, current);
context.state = RpcDeactivateState.Deactivated;
}
else {
// navigate cancel so active mode.
this.active = true;
context.state = RpcDeactivateState.Cancelled;
}
// if timer isn't fired yet, just complete with success navigation.
if (context.timer) {
clearTimeout(context.timer);
context.deferred.resolve({
waitedTime: Date.now() - context.requestedTime,
state: context.state
});
context.timer = null;
context.deferred = null;
context.state = null;
context.requestedTime = null;
}
}, error => {
// navigate error so active mode.
this.active = true;
context.state = RpcDeactivateState.Cancelled;
// if timer isn't fired yet, just complete with success navigation.
if (context.timer) {
clearTimeout(context.timer);
context.deferred.resolve({
waitedTime: Date.now() - context.requestedTime,
state: context.state
});
context.timer = null;
context.deferred = null;
context.state = null;
context.requestedTime = null;
}
});
return context.deferred.promise;
}
onActivate(data) {
const startTimestamp = Date.now();
const newRoute = data.url || data.url === '' ?
Navigation.getUrlNavigationData(this.router, data.url)
: this.lastRoute || { commands: [''], options: null };
this.active = true;
this.enteringModule = true;
// Manually fire page view for every time we reactivate a module
SmeWebTelemetry.tracePageView({});
// pull latest rpc forwarder services data when reactivated.
return this.appContextService.reinitializeServices()
.pipe(mergeMap(() => this.router.navigate(newRoute.commands, this.addDefaultNavigationOptions(newRoute.options))), tap(() => PerformanceProfile.logRouteNavigation('NavigationService', startTimestamp, Date.now(), '[rpcActivate]', this.moduleName)))
.toPromise();
}
onShutdown(data) {
this.userAliveService.stop();
return this.router.navigate(this.options.idleRoute, this.defaultNavigationOptions)
.then(result => ({ canShutdown: result }));
}
addDefaultNavigationOptions(options) {
return { ...(options || {}), ...this.defaultNavigationOptions };
}
}
NavigationService.initialWaitTime = 2000;
/** @nocollapse */ NavigationService.ɵfac = function NavigationService_Factory(t) { return new (t || NavigationService)(i0.ɵɵinject(i1.AppContextService), i0.ɵɵinject(i2.UserAliveService), i0.ɵɵinject(i3.Router), i0.ɵɵinject(i3.ActivatedRoute)); };
/** @nocollapse */ NavigationService.ɵprov = /** @pureOrBreakMyCode */ i0.ɵɵdefineInjectable({ token: NavigationService, factory: NavigationService.ɵfac });
(function () { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(NavigationService, [{
type: Injectable
}], function () { return [{ type: i1.AppContextService }, { type: i2.UserAliveService }, { type: i3.Router }, { type: i3.ActivatedRoute }]; }, null); })();
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmF2aWdhdGlvbi5zZXJ2aWNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vLi4vYW5ndWxhci9zcmMvc2VydmljZS9uYXZpZ2F0aW9uLnNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUMzQyxPQUFPLEVBQUUsY0FBYyxFQUFFLGFBQWEsRUFBb0IsZUFBZSxFQUFFLE1BQU0sRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQzNHLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxnRUFBZ0UsQ0FBQztBQUNqRyxPQUFPLEVBQWtCLE9BQU8sRUFBRSxNQUFNLHdEQUF3RCxDQUFDO0FBQ2pHLE9BQU8sRUFBRSxHQUFHLEVBQUUsTUFBTSxtREFBbUQsQ0FBQztBQUN4RSxPQUFPLEVBQUUsT0FBTyxFQUFFLE1BQU0sOERBQThELENBQUM7QUFDdkYsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLHdFQUF3RSxDQUFDO0FBQ3pHLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLDBFQUEwRSxDQUFDO0FBQzlHLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLDBFQUEwRSxDQUFDO0FBQzlHLE9BQU8sRUFBRSxrQkFBa0IsRUFBZ0QsTUFBTSx3RUFBd0UsQ0FBQztBQUMxSixPQUFPLEVBQUUsb0NBQW9DLEVBQUUsTUFBTSxtR0FBbUcsQ0FBQztBQUV6SixPQUFPLEVBR0gsa0JBQWtCLEVBR2xCLFlBQVksRUFDWixtQkFBbUIsRUFHdEIsTUFBTSx1REFBdUQsQ0FBQztBQUMvRCxPQUFPLEVBQUUsOEJBQThCLEVBQUUsTUFBTSw4RkFBOEYsQ0FBQztBQUM5SSxPQUFPLEVBQUUsS0FBSyxFQUFFLEVBQUUsRUFBZ0IsTUFBTSxNQUFNLENBQUM7QUFDL0MsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLEVBQUUsR0FBRyxFQUFFLFFBQVEsRUFBRSxTQUFTLEVB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UUFDNUQsT0FBTyxJQUFJLENBQUMsaUJBQWlCLENBQUMsb0JBQW9CLEVBQUU7YUFDL0MsSUFBSSxDQUNELFFBQVEsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLFFBQVEsQ0FBQyxRQUFRLENBQUMsUUFBUSxFQUFFLElBQUksQ0FBQywyQkFBMkIsQ0FBQyxRQUFRLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxFQUMzRyxHQUFHLENBQUMsR0FBRyxFQUFFLENBQUMsa0JBQWtCLENBQUMsa0JBQWtCLENBQzNDLG1CQUFtQixFQUFFLGNBQWMsRUFBRSxJQUFJLENBQUMsR0FBRyxFQUFFLEVBQUUsZUFBZSxFQUFFLElBQUksQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUN0RjthQUNKLFNBQVMsRUFBRSxDQUFDO0lBQ3JCLENBQUM7SUFFTyxVQUFVLENBQUMsSUFBcUI7UUFDcEMsSUFBSSxDQUFDLGdCQUFnQixDQUFDLElBQUksRUFBRSxDQUFDO1FBQzdCLE9BQU8sSUFBSSxDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxTQUFTLEVBQUUsSUFBSSxDQUFDLHdCQUF3QixDQUFDO2FBQzdFLElBQUksQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDLENBQW1CLEVBQUUsV0FBVyxFQUFFLE1BQU0sRUFBRSxDQUFBLENBQUMsQ0FBQztJQUNwRSxDQUFDO0lBRU8sMkJBQTJCLENBQUMsT0FBNkI7UUFDN0QsT0FBTyxFQUFFLEdBQUcsQ0FBQyxPQUFPLElBQUksRUFBRSxDQUFDLEVBQUUsR0FBRyxJQUFJLENBQUMsd0JBQXdCLEVBQUUsQ0FBQztJQUNwRSxDQUFDOztBQXhaYyxpQ0FBZSxHQUFHLElBQUksQ0FBQztxR0FEN0IsaUJBQWlCO3NHQUFqQixpQkFBaUIsV0FBakIsaUJBQWlCO3VGQUFqQixpQkFBaUI7Y0FMN0IsVUFBVSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEluamVjdGFibGUgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcclxuaW1wb3J0IHsgQWN0aXZhdGVkUm91dGUsIE5hdmlnYXRpb25FbmQsIE5hdmlnYXRpb25FeHRyYXMsIE5hdmlnYXRpb25TdGFydCwgUm91dGVyIH0gZnJvbSAnQGFuZ3VsYXIvcm91dGVyJztcclxuaW1wb3J0IHsgQ29yZUVudmlyb25tZW50IH0gZnJvbSAnQG1pY3Jvc29mdC93aW5kb3dzLWFkbWluLWNlbnRlci1zZGsvY29yZS9kYXRhL2NvcmUtZW52aXJvbm1lbnQnO1xyXG5pbXBvcnQgeyBOYXRpdmVEZWZlcnJlZCwgTmF0aXZlUSB9IGZyb20gJ0BtaWNyb3NvZnQvd2luZG93cy1hZG1pbi1jZW50ZXItc2RrL2NvcmUvZGF0YS9uYXRpdmUtcSc7XHJcbmltcG9ydCB7IE5ldCB9IGZyb20gJ0BtaWNyb3NvZnQvd2luZG93cy1hZG1pbi1jZW50ZXItc2RrL2NvcmUvZGF0YS9uZXQnO1xyXG5pbXBvcnQgeyBMb2dnaW5nIH0gZnJvbSAnQG1pY3Jvc29mdC93aW5kb3dzLWFkbWluLWNlbnRlci1zZGsvY29yZS9kaWFnbm9zdGljcy9sb2dnaW5nJztcclxuaW1wb3J0IHsgU21lV2ViVGVsZW1ldHJ5IH0gZnJvbSAnQG1pY3Jvc29mdC93aW5kb3dzLWFkbWluLWNlbnRlci1zZGsvY29yZS9kaWFnbm9zdGljcy9zbWUtd2ViLXRlbGVtZXRyeSc7XHJcbmltcG9ydCB7IFBlcmZvcm1hbmNlUHJvZmlsZSB9IGZyb20gJ0BtaWNyb3NvZnQvd2luZG93cy1hZG1pbi1jZW50ZXItc2RrL2NvcmUvcGVyZm9ybWFuY2UvcGVyZm9ybWFuY2UtcHJvZmlsZSc7XHJcbmltcG9ydCB7IFBlcmZvcm1hbmNlVHJhY2tlciB9IGZyb20gJ0BtaWNyb3NvZnQvd2luZG93cy1hZG1pbi1jZW50ZXItc2RrL2NvcmUvcGVyZm9ybWFuY2UvcGVyZm9ybWFuY2UtdHJhY2tlcic7XHJcbmltcG9ydCB7IFJwY092ZXJsYXlDbG9zZUtleSwgUnBjRGlhbG9nT3ZlcmxheURhdGEsIFJwY0RpYWxvZ092ZXJsYXlSZXN1bHQgfSBmcm9tICdAbWljcm9zb2Z0L3dpbmRvd3MtYWRtaW4tY2VudGVyLXNkay9jb3JlL3JwYy9vdmVybGF5L3JwYy1vdmVybGF5LW1vZGVsJztcclxuaW1wb3J0IHsgUnBjT2JzZXJ2YWJsZVBlcmZvcm1hbmNlQ29uZmlnU2VydmVyIH0gZnJvbSAnQG1pY3Jvc29mdC93aW5kb3dzLWFkbWluLWNlbnRlci1zZGsvY29yZS9ycGMvcGVyZm9ybWFuY2UvcnBjLW9ic2VydmFibGUtcGVyZm9ybWFuY2UtY29uZmlnLXNlcnZlcic7XHJcbmltcG9ydCB7IFNlbGVjdGFibGVQYXRoIH0gZnJvbSAnQG1pY3Jvc29mdC93aW5kb3dzLWFkbWluLWNlbnRlci1zZGsvY29yZS9ycGMvcmVwb3J0L3JwYy1yZXBvcnQtbW9kZWwnO1xyXG5pbXBvcnQge1xyXG4gICAgUnBjQWN0aXZhdGVEYXRhLFxyXG4gICAgUnBjRGVhY3RpdmF0ZVJlc3VsdCxcclxuICAgIFJwY0RlYWN0aXZhdGVTdGF0ZSxcclxuICAgIFJwY09wZW5EYXRhLFxyXG4gICAgUnBjT3BlblJlc3VsdCxcclxuICAgIFJwY09wZW5TdGF0ZSxcclxuICAgIFJwY091dGJvdW5kQ29tbWFuZHMsXHJcbiAgICBScGNTaHV0ZG93bkRhdGEsXHJcbiAgICBScGNTaHV0ZG93blJlc3VsdFxyXG59IGZyb20gJ0BtaWNyb3NvZnQvd2luZG93cy1hZG1pbi1jZW50ZXItc2RrL2NvcmUvcnBjL3JwYy1iYXNlJztcclxuaW1wb3J0IHsgUnBjT2JzZXJ2YWJsZVVwZGF0ZVRoZW1lU2VydmVyIH0gZnJvbSAnQG1pY3Jvc29mdC93aW5kb3dzLWFkbWluLWNlbnRlci1zZGsvY29yZS9ycGMvdXBkYXRlLXRoZW1lL3JwYy1vYnNlcnZhYmxlLXVwZGF0ZS10aGVtZS1zZXJ2ZXInO1xyXG5pbXBvcnQgeyBFTVBUWSwgb2YsIFN1YnNjcmlwdGlvbiB9IGZyb20gJ3J4anMnO1xyXG5pbXBvcnQgeyBjYXRjaEVycm9yLCBmaWx0ZXIsIG1hcCwgbWVyZ2VNYXAsIHN3aXRjaE1hcCwgdGFrZSwgdGFwIH0gZnJvbSAncnhqcy9vcGVyYXRvcnMnO1xyXG5pbXBvcnQgeyBEaWFsb2dTZXJ2aWNlIH0gZnJvbSAnLi4vY29udHJvbHMvZGlhbG9nL2RpYWxvZy5zZXJ2aWNlJztcclxuaW1wb3J0IHsgQXBwQ29udGV4dFNlcnZpY2UgfSBmcm9tICcuL2FwcC1jb250ZXh0LnNlcnZpY2UnO1xyXG5pbXBvcnQgeyBDb25uZWN0aXZpdHlFbmZvcmNlciB9IGZyb20gJy4vY29ubmVjdGl2aXR5LWVuZm9yY2VyJztcclxuaW1wb3J0IHsgTmF2aWdhdGlvbiwgTmF2aWdhdGlvbkRhdGEsIE5hdmlnYXRpb25EYXRhRXh0cmFzIH0gZnJvbSAnLi9uYXZpZ2F0aW9uJztcclxuaW1wb3J0IHsgVXNlckFsaXZlU2VydmljZSB9IGZyb20gJy4vdXNlci1hbGl2ZS5zZXJ2aWNlJztcclxuLyoqXHJcbiAqIE9wdGlvbnMgdG8gb3ZlcnJpZGUgdGhlIGRlZmF1bHQgYmVoYXZpb3Igb2YgdGhlIG5hdmlnYXRpb24gc2VydmljZVxyXG4gKi9cclxuZXhwb3J0IGludGVyZmFjZSBOYXZpZ2F0b3JTZXJ2aWNlT3B0aW9ucyB7XHJcbiAgICAvKipcclxuICAgICAqIFRoZSBhbmd1bGFyIDIgZGVmYXVsdCByb3V0ZSB0byB1c2UgZHVyaW5nIGluaXRpYWxpemF0aW9uIGFuZFxyXG4gICAgICogaWYgdGhlIGFwcGxpY2F0aW9uIGdldHMgZGVhY3RpdmF0ZWQgYnV0IHN0aWxsIHJ1bm5pbmdcclxuICAgICAqIFNlZSBAYW5ndWxhci9yb3V0ZXIgLSBSb3V0ZXIubmF2aWdhdGUgbWV0aG9kIGZvciBtb3JlIGRldGFpbHNcclxuICAgICAqL1xyXG4gICAgaWRsZVJvdXRlPzogYW55W107XHJcbn1cclxuXHJcbmludGVyZmFjZSBTdGF0ZUNvbnRleHQ8VFN0YXRlLCBUUmVzdWx0PiB7XHJcbiAgICBzdGF0ZTogVFN0YXRlO1xyXG4gICAgcmVxdWVzdGVkVGltZTogbnVtYmVyO1xyXG4gICAgdGltZXI6IGFueTtcclxuICAgIGRlZmVycmVkOiBOYXRpdmVEZWZlcnJlZDxUUmVzdWx0PjtcclxuICAgIGVycm9yPzogc3RyaW5nO1xyXG59XHJcblxyXG5ASW5qZWN0YWJsZSgpXHJcbi8qKlxyXG4gKiBPbmNlIGluaXRpYWxpemUgdGhpcyBjbGFzcyB1c2VzIHRoZSB1bmRlcmx5aW5nIFJQQyBjaGFubmVsXHJcbiAqIHRvIGNvbW11bmljYXRlIHdpdGggdGhlIHJlbW90ZSBSUEMgc2VydmljZS5cclxuICovXHJcbmV4cG9ydCBjbGFzcyBOYXZpZ2F0aW9uU2VydmljZSB7XHJcbiAgICBwcml2YXRlIHN0YXRpYyBpbml0aWFsV2FpdFRpbWUgPSAyMDAwO1xyXG4gICAgcHJpdmF0ZSByZWFkb25seSBkZWZhdWx0TmF2aWdhdGlvbk9wdGlvbnM6IE5hdmlnYXRpb25FeHRyYXMgPSB7IHNraXBMb2NhdGlvbkNoYW5nZTogdHJ1ZSB9O1xyXG4gICAgcHJpdmF0ZSBsYXN0Um91dGU6IE5hdmlnYXRpb25EYXRhO1xyXG4gICAgcHJpdmF0ZSBzdWJzY3JpcHRpb246IFN1YnNjcmlwdGlvbjtcclxuICAgIHByaXZhdGUgb3B0aW9uczogTmF2aWdhdG9yU2VydmljZU9wdGlvbnM7XHJcbiAgICBwcml2YXRlIGlkbGVVcmw6IHN0cmluZztcclxuICAgIHByaXZhdGUgYWN0aXZlOiBib29sZWFuO1xyXG4gICAgcHJpdmF0ZSBlbnRlcmluZ01vZHVsZSA9IHRydWU7XHJcbiAgICBwcml2YXRlIGRpYWxvZ1NlcnZpY2VNYXA6IHsgW2luZGV4OiBzdHJpbmddOiBEaWFsb2dTZXJ2aWNlIH0gPSB7fTtcclxuICAgIHByaXZhdGUgb3BlbkNvbnRleHQ6IFN0YXRlQ29udGV4dDxScGNPcGVuU3RhdGUsIFJwY09wZW5SZXN1bHQ+ID0ge1xyXG4gICAgICAgIHN0YXRlOiBudWxsLFxyXG4gICAgICAgIHJlcXVlc3RlZFRpbWU6IDAsXHJcbiAgICAgICAgdGltZXI6IG51bGwsXHJcbiAgICAgICAgZGVmZXJyZWQ6IG51bGwsXHJcbiAgICAgICAgZXJyb3I6IG51bGxcclxuICAgIH07XHJcbiAgICBwcml2YXRlIGRlYWN0aXZhdGVDb250ZXh0OiBTdGF0ZUNvbnRleHQ8UnBjRGVhY3RpdmF0ZVN0YXRlLCBScGNEZWFjdGl2YXRlUmVzdWx0PiA9IHtcclxuICAgICAgICBzdGF0ZTogbnVsbCxcclxuICAgICAgICByZXF1ZXN0ZWRUaW1lOiAwLFxyXG4gICAgICAgIHRpbWVyOiBudWxsLFxyXG4gICAgICAgIGRlZmVycmVkOiBudWxsXHJcbiAgICB9O1xyXG4gICAgcHJpdmF0ZSBtb2R1bGVOYW1lOiBzdHJpbmc7XHJcbiAgICBwcml2YXRlIFJwY09ic2VydmFibGVQZXJmb3JtYW5jZUNvbmZpZ1NlcnZlcjogUnBjT2JzZXJ2YWJsZVBlcmZvcm1hbmNlQ29uZmlnU2VydmVyO1xyXG4gICAgcHJpdmF0ZSBycGNPYnNlcnZhYmxlVXBkYXRlVGhlbWVTZXJ2ZXI6IFJwY09ic2VydmFibGVVcGRhdGVUaGVtZVNlcnZlcjtcclxuXHJcbiAgICAvKipcclxuICAgICAqIENyZWF0ZXMgYSBuZXcgaW5zdGFuY2Ugb2YgdGhpcyBzZXJ2aWNlXHJcbiAgICAgKi9cclxuICAgIGNvbnN0cnVjdG9yKFxyXG4gICAgICAgIHByaXZhdGUgYXBwQ29udGV4dFNlcnZpY2U6IEFwcENvbnRleHRTZXJ2aWNlLFxyXG4gICAgICAgIHByaXZhdGUgdXNlckFsaXZlU2VydmljZTogVXNlckFsaXZlU2VydmljZSxcclxuICAgICAgICBwcml2YXRlIHJvdXRlcjogUm91dGVyLFxyXG4gICAgICAgIHByaXZhdGUgYWN0aXZhdGVkUm91dGU6IEFjdGl2YXRlZFJvdXRlKSB7XHJcbiAgICB9XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBJbml0aWFsaXplIG5hdmlnYXRpb24gY29tbXVuaWNhdGlvbiBmcm9tL3RvIHRoZSBzaGVsbC5cclxuICAgICAqXHJcbiAgICAgKiAgUmVnaXN0ZXJzIHRoZSBtZXRob2RzIHdpdGggdGhlIHJlbW90ZSBSUEMgZGVmaW5lZCBpbiB0aGUgbWFuaWZlc3RcclxuICAgICAqICBTdWJzY3JpYmVzIHRvIHRoZSByb3V0ZXIgZXZlbnRzIGFuZCByZXBvcnRzIHRoZSBicmVhZGNydW1iIGl0ZW1zXHJcbiAgICAgKiAgYmFjayB0byB0aGUgcnBjIHJlbW90ZVxyXG4gICAgICpcclxuICAgICAqIEBwYXJhbSBvcHRpb25zIFRoZSBvcHRpb25zIHRvIG92ZXJyaWRlIHRoZSBkZWZhdWx0IGJlaGF2aW9yXHJcbiAgICAgKi9cclxuICAgIHB1YmxpYyBpbml0aWFsaXplKG9wdGlvbnM/OiBOYXZpZ2F0b3JTZXJ2aWNlT3B0aW9ucyk6IHZvaWQge1xyXG4gICAgICAgIFBlcmZvcm1hbmNlVHJhY2tlci5uYXZpZ2F0aW9uSW5pdGlhbGl6ZWQoKTtcclxuICAgICAgICB0aGlzLmFjdGl2ZSA9IHRydWU7XHJcbiAgICAgICAgdGhpcy5vcHRpb25zID0gb3B0aW9ucyA/IG9wdGlvbnMgOiB7IGlkbGVSb3V0ZTogWydpZGxlJ10gfTtcclxuICAgICAgICB0aGlzLmlkbGVVcmwgPSBgLyR7dGhpcy5vcHRpb25zLmlkbGVSb3V0ZVswXX1gO1xyXG5cclxuICAgICAgICAvLyBuYXZpZ2F0ZSB0byBpZGxlLlxyXG4gICAgICAgIHRoaXMucm91dGVyLm5hdmlnYXRlKHRoaXMub3B0aW9ucy5pZGxlUm91dGUsIHRoaXMuZGVmYXVsdE5hdmlnYXRpb25PcHRpb25zKTtcclxuXHJcbiAgICAgICAgdGhpcy5zdWJzY3JpcHRpb24/LnVuc3Vic2NyaWJlKCk7XHJcblxyXG4gICAgICAgIGxldCBzdGFydFRpbWVzdGFtcCA9IG51bGw7XHJcbiAgICAgICAgdGhpcy5zdWJzY3JpcHRpb24gPSB0aGlzLnJvdXRlci5ldmVudHNcclxuICAgICAgICAgICAgLnBpcGUoXHJcbiAgICAgICAgICAgICAgICB0YXAoZXZlbnQgPT4ge1xyXG4gICAgICAgICAgICAgICAgICAgIGlmIChldmVudCBpbnN0YW5jZW9mIE5hdmlnYXRpb25TdGFydCkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBzdGFydFRpbWVzdGFtcCA9IERhdGUubm93KCk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIFBlcmZvcm1hbmNlVHJhY2tlci5uYXZpZ2F0aW9uU3RhcnRlZCgpO1xyXG4gICAgICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAoZXZlbnQgaW5zdGFuY2VvZiBOYXZpZ2F0aW9uRW5kICYmIHN0YXJ0VGltZXN0YW1wKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIFBlcmZvcm1hbmNlUHJvZmlsZS5sb2dSb3V0ZU5hdmlnYXRpb24oJ05hdmlnYXRpb25TZXJ2aWNlJywgc3RhcnRUaW1lc3RhbXAsIERhdGUubm93KCksIGV2ZW50LnVybCwgdGhpcy5tb2R1bGVOYW1lKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgc3RhcnRUaW1lc3RhbXAgPSBudWxsO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBQZXJmb3JtYW5jZVRyYWNrZXIubmF2aWdhdGlvbkNvbXBsZXRlZCh0aGlzLmVudGVyaW5nTW9kdWxlKTtcclxuICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICB9KSxcclxuICAgICAgICAgICAgICAgIGZpbHRlcihldmVudCA9PiBldmVudCBpbnN0YW5jZW9mIE5hdmlnYXRpb25FbmQpLFxyXG4gICAgICAgICAgICAgICAgc3dpdGNoTWFwKGV2ZW50ID0+XHJcbiAgICAgICAgICAgICAgICAgICAgTmF2aWdhdGlvbi5idWlsZFNlbGVjdGFibGVQYXRoc0ZvclJvdXRlKHRoaXMuYXBwQ29udGV4dFNlcnZpY2UsIHRoaXMuYWN0aXZhdGVkUm91dGUuc25hcHNob3QpXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLnBpcGUobWFwKHNlbGVjdGFibGVQYXRocyA9PiA8YW55PnsgZXZlbnQsIHNlbGVjdGFibGVQYXRocyB9KSkpXHJcbiAgICAgICAgICAgIClcclxuICAgICAgICAgICAgLnN1YnNjcmliZSgoZGF0YTogeyBldmVudDogTmF2aWdhdGlvbkVuZCwgc2VsZWN0YWJsZVBhdGhzOiBTZWxlY3RhYmxlUGF0aFtdfSkgPT4ge1xyXG4gICAgICAgICAgICAgICAgLy8gaW4gdGhlIGNhc2Ugb2YgaW5pdGlhbCBpZGxlIHN0YXRlLCByZXBvcnRpbmcgdXJsIHdpbGwgY2F1c2UgcnBjIGVycm9yLiBhbGwgb3RoZXIgY2FzZXMgc2hvdWxkIGJlIG9rLlxyXG4gICAgICAgICAgICAgICAgLy8gUnBjUmVwb3J0IGluY2x1ZGUgZnJhZ21lbnQgYW5kIHF1ZXJ5UGFyYW1zIGluICdwYXRoJyBhbmQgJ2JlZm9yZVJlZGlyZWN0ZWRQYXRoJy5cclxuICAgICAgICAgICAgICAgIGlmICh0aGlzLmFjdGl2ZSAmJiBkYXRhLmV2ZW50LnVybCAhPT0gdGhpcy5pZGxlVXJsKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5hcHBDb250ZXh0U2VydmljZS5mcmFtZS5yZXBvcnQoe1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBwYXRoOiBkZWNvZGVVUkkoZGF0YS5ldmVudC51cmxBZnRlclJlZGlyZWN0cyksXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGJlZm9yZVJlZGlyZWN0ZWRQYXRoOiBkZWNvZGVVUkkoZGF0YS5ldmVudC51cmwpLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICBzZWxlY3RhYmxlUGF0aDogZGF0YS5zZWxlY3RhYmxlUGF0aHNcclxuICAgICAgICAgICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgICAgICAgICB0aGlzLmVudGVyaW5nTW9kdWxlID0gZmFsc2U7XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH0pO1xyXG5cclxuICAgICAgICB0aGlzLmFwcENvbnRleHRTZXJ2aWNlLnJwYy5yZWdpc3RlcihScGNPdXRib3VuZENvbW1hbmRzLkluaXQsIHRoaXMub25Jbml0LmJpbmQodGhpcykpO1xyXG4gICAgICAgIHRoaXMuYXBwQ29udGV4dFNlcnZpY2UucnBjLnJlZ2lzdGVyKFJwY091dGJvdW5kQ29tbWFuZHMuT3BlbiwgdGhpcy5vbk9wZW4uYmluZCh0aGlzKSk7XHJcbiAgICAgICAgdGhpcy5hcHBDb250ZXh0U2VydmljZS5ycGMucmVnaXN0ZXIoUnBjT3V0Ym91bmRDb21tYW5kcy5EZWFjdGl2YXRlMiwgdGhpcy5vbkRlYWN0aXZhdGUyLmJpbmQodGhpcykpO1xyXG4gICAgICAgIHRoaXMuYXBwQ29udGV4dFNlcnZpY2UucnBjLnJlZ2lzdGVyKFJwY091dGJvdW5kQ29tbWFuZHMuQWN0aXZhdGUsIHRoaXMub25BY3RpdmF0ZS5iaW5kKHRoaXMpKTtcclxuICAgICAgICB0aGlzLmFwcENvbnRleHRTZXJ2aWNlLnJwYy5yZWdpc3RlcihScGNPdXRib3VuZENvbW1hbmRzLlNodXRkb3duLCB0aGlzLm9uU2h1dGRvd24uYmluZCh0aGlzKSk7XHJcbiAgICAgICAgdGhpcy5hcHBDb250ZXh0U2VydmljZS5ycGMucmVnaXN0ZXIoUnBjT3ZlcmxheUNsb3NlS2V5LmNvbW1hbmQsIHRoaXMub25PdmVybGF5Q2xvc2UuYmluZCh0aGlzKSk7XHJcbiAgICB9XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBTaHV0ZG93biB0aGUgbmF2aWdhdGlvbiBjb21tdW5pY2F0aW9uIGZyb20vdG8gdGhlIHNoZWxsLlxyXG4gICAgICovXHJcbiAgICBwdWJsaWMgc2h1dGRvd24oKTogdm9pZCB7XHJcbiAgICAgICAgdGhpcy5hY3RpdmUgPSBmYWxzZTtcclxuICAgICAgICB0aGlzLnN1YnNjcmlwdGlvbj8udW5zdWJzY3JpYmUoKTtcclxuICAgIH1cclxuXHJcbiAgICAvKipcclxuICAgICAqIE1hcCBkaWFsb2cgc2VydmljZSBhbmQgZGlhbG9nIGlkIHNvIHRoYXQgY29ycmVjdCBkaWFsb2cgc2VydmljZSBpbnN0YW5jZSBjYW4gYmUgZm91bmRcclxuICAgICAqIEBwYXJhbSBkaWFsb2dTZXJ2aWNlIGRpYWxvZyBzZXJ2aWNlIHRvIGJlIHJlZ2lzdGVyZWRcclxuICAgICAqIEBwYXJhbSBkaWFsb2dJZCBhc3NvY2lhdGVkIGRpYWxvZyBpZFxyXG4gICAgICovXHJcbiAgICBwdWJsaWMgcmVnaXN0ZXJEaWFsb2dTZXJ2aWNlKGRpYWxvZ1NlcnZpY2U6IERpYWxvZ1NlcnZpY2UsIGRpYWxvZ0lkOiBzdHJpbmcpOiB2b2lkIHtcclxuICAgICAgICB0aGlzLmRpYWxvZ1NlcnZpY2VNYXBbZGlhbG9nSWRdID0gZGlhbG9nU2VydmljZTtcclxuICAgIH1cclxuXHJcbiAgICBwcml2YXRlIGNvbmZpZ3VyZVBlcmZvcm1hbmNlUHJvZmlsZShlbmFibGVkOiBib29sZWFuKTogdm9pZCB7XHJcbiAgICAgICAgY29uc3Qgc3RhcnRUaW1lc3RhbXAgPSBEYXRlLm5vdygpO1xyXG4gICAgICAgIGlmIChlbmFibGVkKSB7XHJcbiAgICAgICAgICAgIFBlcmZvcm1hbmNlUHJvZmlsZS5jdXJyZW50LmVuYWJsZSh0aGlzLmFwcENvbnRleHRTZXJ2aWNlLnJwYyk7XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgUGVyZm9ybWFuY2VQcm9maWxlLmN1cnJlbnQuZGlzYWJsZSh0aGlzLmFwcENvbnRleHRTZXJ2aWNlLnJwYyk7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICBQZXJmb3JtYW5jZVByb2ZpbGUubG9nUm91dGVOYXZpZ2F0aW9uKCdOYXZpZ2F0aW9uU2VydmljZScsIHN0YXJ0VGltZXN0YW1wLCBEYXRlLm5vdygpLCAnW3JwY0luaXRdJywgdGhpcy5tb2R1bGVOYW1lKTtcclxuICAgIH1cclxuXHJcbiAgICBwcml2YXRlIG9uSW5pdChkYXRhOiBhbnkpOiBQcm9taXNlPGFueT4ge1xyXG4gICAgICAgIC8vIElmcmFtZSBoYXMgcmVjZWl2ZWQgYWxsIGluaXRpYWxpemF0aW9uIGRhdGEgZnJvbSB0aGUgc2hlbGwuXHJcbiAgICAgICAgdGhpcy5hcHBDb250ZXh0U2VydmljZS5nYXRld2F5Lm5hdmlnYXRpb25SZWFkeVN0YXR1cyA9IHRydWU7XHJcblxyXG4gICAgICAgIHRoaXMuYWN0aXZlID0gdHJ1ZTtcclxuICAgICAgICBjb25zdCBzZWxmID0gTXNmdFNtZS5zZWxmKCk7XHJcbiAgICAgICAgaWYgKCFNc2Z0U21lLmlzTnVsbE9yVW5kZWZpbmVkKHNlbGYuSW5pdC5zZXNzaW9uRXhwaXJhdGlvbikgJiYgc2VsZi5Jbml0LnNlc3Npb25FeHBpcmF0aW9uID4gMCkge1xyXG4gICAgICAgICAgICB0aGlzLnVzZXJBbGl2ZVNlcnZpY2Uuc3RhcnQoKTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIENvbm5lY3Rpdml0eUVuZm9yY2VyLnJlZ2lzdGVyKHRoaXMuYXBwQ29udGV4dFNlcnZpY2UpO1xyXG4gICAgICAgIHRoaXMubW9kdWxlTmFtZSA9IHNlbGYuSW5pdC5tb2R1bGVOYW1lO1xyXG4gICAgICAgIHRoaXMuY29uZmlndXJlUGVyZm9ybWFuY2VQcm9maWxlKHNlbGYuSW5pdC5wZXJmb3JtYW5jZVByb2ZpbGUpO1xyXG4gICAgICAgIFBlcmZvcm1hbmNlUHJvZmlsZS5sb2dOdWxsKHRoaXMubW9kdWxlTmFtZSk7XHJcbiAgICAgICAgaWYgKCF0aGlzLlJwY09ic2VydmFibGVQZXJmb3JtYW5jZUNvbmZpZ1NlcnZlcikge1xyXG4gICAgICAgICAgICB0aGlzLlJwY09ic2VydmFibGVQZXJmb3JtYW5jZUNvbmZpZ1NlcnZlciA9IG5ldyBScGNPYnNlcnZhYmxlUGVyZm9ybWFuY2VDb25maWdTZXJ2ZXIodGhpcy5hcHBDb250ZXh0U2VydmljZS5ycGMpO1xyXG4gICAgICAgICAgICB0aGlzLlJwY09ic2VydmFibGVQZXJmb3JtYW5jZUNvbmZpZ1NlcnZlci5yZWdpc3RlcigocmVxdWVzdCkgPT4ge1xyXG4gICAgICAgICAgICAgICAgdGhpcy5jb25maWd1cmVQZXJmb3JtYW5jZVByb2ZpbGUocmVxdWVzdC5lbmFibGVkKTtcclxuICAgICAgICAgICAgICAgIHJldHVybiBvZihudWxsKTtcclxuICAgICAgICAgICAgfSk7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICBpZiAoIXRoaXMucnBjT2JzZXJ2YWJsZVVwZGF0ZVRoZW1lU2VydmVyKSB7XHJcbiAgICAgICAgICAgIHRoaXMucnBjT2JzZXJ2YWJsZVVwZGF0ZVRoZW1lU2VydmVyID0gbmV3IFJwY09ic2VydmFibGVVcGRhdGVUaGVtZVNlcnZlcih0aGlzLmFwcENvbnRleHRTZXJ2aWNlLnJwYyk7XHJcbiAgICAgICAgICAgIHRoaXMucnBjT2JzZXJ2YWJsZVVwZGF0ZVRoZW1lU2VydmVyLnJlZ2lzdGVyKChyZXF1ZXN0KSA9PiB7XHJcbiAgICAgICAgICAgICAgICBDb3JlRW52aXJvbm1lbnQuYXNzZXRNYW5hZ2VyLnNldFRoZW1lKHJlcXVlc3QubmV3VGhlbWUpO1xyXG4gICAgICAgICAgICAgICAgcmV0dXJuIG9mKG51bGwpO1xyXG4gICAgICAgICAgICB9KTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIHJldHVybiBQcm9taXNlLnJlc29sdmUoKTtcclxuICAgIH1cclxuXHJcbiAgICAvKipcclxuICAgICAqIENhbGwgdG8gZGlhbG9nIHNlcnZpY2UgdG8gcmVxdWVzdCBjbG9zZSBhI