UNPKG

@microsoft/windows-admin-center-sdk

Version:

Microsoft - Windows Admin Center Shell

377 lines 64.5 kB
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