UNPKG

@microsoft/windows-admin-center-sdk

Version:

Microsoft - Windows Admin Center Shell

382 lines 65.1 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); if (this.subscription) { 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; if (this.subscription) { this.subscription.unsubscribe(); this.subscription = null; } } /** * 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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmF2aWdhdGlvbi5zZXJ2aWNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vLi4vYW5ndWxhci9zcmMvc2VydmljZS9uYXZpZ2F0aW9uLnNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUMzQyxPQUFPLEVBQUUsY0FBYyxFQUFFLGFBQWEsRUFBb0IsZUFBZSxFQUFFLE1BQU0sRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQzNHLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxnRUFBZ0UsQ0FBQztBQUNqRyxPQUFPLEVBQWtCLE9BQU8sRUFBRSxNQUFNLHdEQUF3RCxDQUFDO0FBQ2pHLE9BQU8sRUFBRSxHQUFHLEVBQUUsTUFBTSxtREFBbUQsQ0FBQztBQUN4RSxPQUFPLEVBQUUsT0FBTyxFQUFFLE1BQU0sOERBQThELENBQUM7QUFDdkYsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLHdFQUF3RSxDQUFDO0FBQ3pHLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLDBFQUEwRSxDQUFDO0FBQzlHLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLDBFQUEwRSxDQUFDO0FBRTlHLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLHdFQUF3RSxDQUFDO0FBQzVHLE9BQU8sRUFBRSxvQ0FBb0MsRUFBRSxNQUFNLG1HQUFtRyxDQUFDO0FBRXpKLE9BQU8sRUFHSCxrQkFBa0IsRUFHbEIsWUFBWSxFQUNaLG1CQUFtQixFQUd0QixNQUFNLHVEQUF1RCxDQUFDO0FBQy9ELE9BQU8sRUFBRSw4QkFBOEIsRUFBRSxNQUFNLDhGQUE4RixDQUFDO0FBQzlJLE9BQU8sRUFBRSxLQUFLLEVBQUUsRUFBRSxFQUFnQixNQUFNLE1BQU0sQ0FBQztBQUMvQyxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sRUFBRSxHQUFHLEVBQUUsUUFBUSxFQUFFLFNBQVMsRUFB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QkFBaUI7dUZBQWpCLGlCQUFpQjtjQUw3QixVQUFVIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgSW5qZWN0YWJsZSB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xyXG5pbXBvcnQgeyBBY3RpdmF0ZWRSb3V0ZSwgTmF2aWdhdGlvbkVuZCwgTmF2aWdhdGlvbkV4dHJhcywgTmF2aWdhdGlvblN0YXJ0LCBSb3V0ZXIgfSBmcm9tICdAYW5ndWxhci9yb3V0ZXInO1xyXG5pbXBvcnQgeyBDb3JlRW52aXJvbm1lbnQgfSBmcm9tICdAbWljcm9zb2Z0L3dpbmRvd3MtYWRtaW4tY2VudGVyLXNkay9jb3JlL2RhdGEvY29yZS1lbnZpcm9ubWVudCc7XHJcbmltcG9ydCB7IE5hdGl2ZURlZmVycmVkLCBOYXRpdmVRIH0gZnJvbSAnQG1pY3Jvc29mdC93aW5kb3dzLWFkbWluLWNlbnRlci1zZGsvY29yZS9kYXRhL25hdGl2ZS1xJztcclxuaW1wb3J0IHsgTmV0IH0gZnJvbSAnQG1pY3Jvc29mdC93aW5kb3dzLWFkbWluLWNlbnRlci1zZGsvY29yZS9kYXRhL25ldCc7XHJcbmltcG9ydCB7IExvZ2dpbmcgfSBmcm9tICdAbWljcm9zb2Z0L3dpbmRvd3MtYWRtaW4tY2VudGVyLXNkay9jb3JlL2RpYWdub3N0aWNzL2xvZ2dpbmcnO1xyXG5pbXBvcnQgeyBTbWVXZWJUZWxlbWV0cnkgfSBmcm9tICdAbWljcm9zb2Z0L3dpbmRvd3MtYWRtaW4tY2VudGVyLXNkay9jb3JlL2RpYWdub3N0aWNzL3NtZS13ZWItdGVsZW1ldHJ5JztcclxuaW1wb3J0IHsgUGVyZm9ybWFuY2VQcm9maWxlIH0gZnJvbSAnQG1pY3Jvc29mdC93aW5kb3dzLWFkbWluLWNlbnRlci1zZGsvY29yZS9wZXJmb3JtYW5jZS9wZXJmb3JtYW5jZS1wcm9maWxlJztcclxuaW1wb3J0IHsgUGVyZm9ybWFuY2VUcmFja2VyIH0gZnJvbSAnQG1pY3Jvc29mdC93aW5kb3dzLWFkbWluLWNlbnRlci1zZGsvY29yZS9wZXJmb3JtYW5jZS9wZXJmb3JtYW5jZS10cmFja2VyJztcclxuaW1wb3J0IHsgUnBjRGlhbG9nT3ZlcmxheURhdGEsIFJwY0RpYWxvZ092ZXJsYXlSZXN1bHQgfSBmcm9tICdAbWljcm9zb2Z0L3dpbmRvd3MtYWRtaW4tY2VudGVyLXNkay9jb3JlL3JwYy9vdmVybGF5L3JwYy1vdmVybGF5LW1vZGVsJztcclxuaW1wb3J0IHsgUnBjT3ZlcmxheUNsb3NlS2V5IH0gZnJvbSAnQG1pY3Jvc29mdC93aW5kb3dzLWFkbWluLWNlbnRlci1zZGsvY29yZS9ycGMvb3ZlcmxheS9ycGMtb3ZlcmxheS1tb2RlbCc7XHJcbmltcG9ydCB7IFJwY09ic2VydmFibGVQZXJmb3JtYW5jZUNvbmZpZ1NlcnZlciB9IGZyb20gJ0BtaWNyb3NvZnQvd2luZG93cy1hZG1pbi1jZW50ZXItc2RrL2NvcmUvcnBjL3BlcmZvcm1hbmNlL3JwYy1vYnNlcnZhYmxlLXBlcmZvcm1hbmNlLWNvbmZpZy1zZXJ2ZXInO1xyXG5pbXBvcnQgeyBTZWxlY3RhYmxlUGF0aCB9IGZyb20gJ0BtaWNyb3NvZnQvd2luZG93cy1hZG1pbi1jZW50ZXItc2RrL2NvcmUvcnBjL3JlcG9ydC9ycGMtcmVwb3J0LW1vZGVsJztcclxuaW1wb3J0IHtcclxuICAgIFJwY0FjdGl2YXRlRGF0YSxcclxuICAgIFJwY0RlYWN0aXZhdGVSZXN1bHQsXHJcbiAgICBScGNEZWFjdGl2YXRlU3RhdGUsXHJcbiAgICBScGNPcGVuRGF0YSxcclxuICAgIFJwY09wZW5SZXN1bHQsXHJcbiAgICBScGNPcGVuU3RhdGUsXHJcbiAgICBScGNPdXRib3VuZENvbW1hbmRzLFxyXG4gICAgUnBjU2h1dGRvd25EYXRhLFxyXG4gICAgUnBjU2h1dGRvd25SZXN1bHRcclxufSBmcm9tICdAbWljcm9zb2Z0L3dpbmRvd3MtYWRtaW4tY2VudGVyLXNkay9jb3JlL3JwYy9ycGMtYmFzZSc7XHJcbmltcG9ydCB7IFJwY09ic2VydmFibGVVcGRhdGVUaGVtZVNlcnZlciB9IGZyb20gJ0BtaWNyb3NvZnQvd2luZG93cy1hZG1pbi1jZW50ZXItc2RrL2NvcmUvcnBjL3VwZGF0ZS10aGVtZS9ycGMtb2JzZXJ2YWJsZS11cGRhdGUtdGhlbWUtc2VydmVyJztcclxuaW1wb3J0IHsgRU1QVFksIG9mLCBTdWJzY3JpcHRpb24gfSBmcm9tICdyeGpzJztcclxuaW1wb3J0IHsgY2F0Y2hFcnJvciwgZmlsdGVyLCBtYXAsIG1lcmdlTWFwLCBzd2l0Y2hNYXAsIHRha2UsIHRhcCB9IGZyb20gJ3J4anMvb3BlcmF0b3JzJztcclxuaW1wb3J0IHsgRGlhbG9nU2VydmljZSB9IGZyb20gJy4uL2NvbnRyb2xzL2RpYWxvZy9kaWFsb2cuc2VydmljZSc7XHJcbmltcG9ydCB7IEFwcENvbnRleHRTZXJ2aWNlIH0gZnJvbSAnLi9hcHAtY29udGV4dC5zZXJ2aWNlJztcclxuaW1wb3J0IHsgQ29ubmVjdGl2aXR5RW5mb3JjZXIgfSBmcm9tICcuL2Nvbm5lY3Rpdml0eS1lbmZvcmNlcic7XHJcbmltcG9ydCB7IE5hdmlnYXRpb24sIE5hdmlnYXRpb25EYXRhLCBOYXZpZ2F0aW9uRGF0YUV4dHJhcyB9IGZyb20gJy4vbmF2aWdhdGlvbic7XHJcbmltcG9ydCB7IFVzZXJBbGl2ZVNlcnZpY2UgfSBmcm9tICcuL3VzZXItYWxpdmUuc2VydmljZSc7XHJcbi8qKlxyXG4gKiBPcHRpb25zIHRvIG92ZXJyaWRlIHRoZSBkZWZhdWx0IGJlaGF2aW9yIG9mIHRoZSBuYXZpZ2F0aW9uIHNlcnZpY2VcclxuICovXHJcbmV4cG9ydCBpbnRlcmZhY2UgTmF2aWdhdG9yU2VydmljZU9wdGlvbnMge1xyXG4gICAgLyoqXHJcbiAgICAgKiBUaGUgYW5ndWxhciAyIGRlZmF1bHQgcm91dGUgdG8gdXNlIGR1cmluZyBpbml0aWFsaXphdGlvbiBhbmRcclxuICAgICAqIGlmIHRoZSBhcHBsaWNhdGlvbiBnZXRzIGRlYWN0aXZhdGVkIGJ1dCBzdGlsbCBydW5uaW5nXHJcbiAgICAgKiBTZWUgQGFuZ3VsYXIvcm91dGVyIC0gUm91dGVyLm5hdmlnYXRlIG1ldGhvZCBmb3IgbW9yZSBkZXRhaWxzXHJcbiAgICAgKi9cclxuICAgIGlkbGVSb3V0ZT86IGFueVtdO1xyXG59XHJcblxyXG5pbnRlcmZhY2UgU3RhdGVDb250ZXh0PFRTdGF0ZSwgVFJlc3VsdD4ge1xyXG4gICAgc3RhdGU6IFRTdGF0ZTtcclxuICAgIHJlcXVlc3RlZFRpbWU6IG51bWJlcjtcclxuICAgIHRpbWVyOiBhbnk7XHJcbiAgICBkZWZlcnJlZDogTmF0aXZlRGVmZXJyZWQ8VFJlc3VsdD47XHJcbiAgICBlcnJvcj86IHN0cmluZztcclxufVxyXG5cclxuQEluamVjdGFibGUoKVxyXG4vKipcclxuICogT25jZSBpbml0aWFsaXplIHRoaXMgY2xhc3MgdXNlcyB0aGUgdW5kZXJseWluZyBSUEMgY2hhbm5lbFxyXG4gKiB0byBjb21tdW5pY2F0ZSB3aXRoIHRoZSByZW1vdGUgUlBDIHNlcnZpY2UuXHJcbiAqL1xyXG5leHBvcnQgY2xhc3MgTmF2aWdhdGlvblNlcnZpY2Uge1xyXG4gICAgcHJpdmF0ZSBzdGF0aWMgaW5pdGlhbFdhaXRUaW1lID0gMjAwMDtcclxuICAgIHByaXZhdGUgcmVhZG9ubHkgZGVmYXVsdE5hdmlnYXRpb25PcHRpb25zOiBOYXZpZ2F0aW9uRXh0cmFzID0geyBza2lwTG9jYXRpb25DaGFuZ2U6IHRydWUgfTtcclxuICAgIHByaXZhdGUgbGFzdFJvdXRlOiBOYXZpZ2F0aW9uRGF0YTtcclxuICAgIHByaXZhdGUgc3Vic2NyaXB0aW9uOiBTdWJzY3JpcHRpb247XHJcbiAgICBwcml2YXRlIG9wdGlvbnM6IE5hdmlnYXRvclNlcnZpY2VPcHRpb25zO1xyXG4gICAgcHJpdmF0ZSBpZGxlVXJsOiBzdHJpbmc7XHJcbiAgICBwcml2YXRlIGFjdGl2ZTogYm9vbGVhbjtcclxuICAgIHByaXZhdGUgZW50ZXJpbmdNb2R1bGUgPSB0cnVlO1xyXG4gICAgcHJpdmF0ZSBkaWFsb2dTZXJ2aWNlTWFwOiB7IFtpbmRleDogc3RyaW5nXTogRGlhbG9nU2VydmljZSB9ID0ge307XHJcbiAgICBwcml2YXRlIG9wZW5Db250ZXh0OiBTdGF0ZUNvbnRleHQ8UnBjT3BlblN0YXRlLCBScGNPcGVuUmVzdWx0PiA9IHtcclxuICAgICAgICBzdGF0ZTogbnVsbCxcclxuICAgICAgICByZXF1ZXN0ZWRUaW1lOiAwLFxyXG4gICAgICAgIHRpbWVyOiBudWxsLFxyXG4gICAgICAgIGRlZmVycmVkOiBudWxsLFxyXG4gICAgICAgIGVycm9yOiBudWxsXHJcbiAgICB9O1xyXG4gICAgcHJpdmF0ZSBkZWFjdGl2YXRlQ29udGV4dDogU3RhdGVDb250ZXh0PFJwY0RlYWN0aXZhdGVTdGF0ZSwgUnBjRGVhY3RpdmF0ZVJlc3VsdD4gPSB7XHJcbiAgICAgICAgc3RhdGU6IG51bGwsXHJcbiAgICAgICAgcmVxdWVzdGVkVGltZTogMCxcclxuICAgICAgICB0aW1lcjogbnVsbCxcclxuICAgICAgICBkZWZlcnJlZDogbnVsbFxyXG4gICAgfTtcclxuICAgIHByaXZhdGUgbW9kdWxlTmFtZTogc3RyaW5nO1xyXG4gICAgcHJpdmF0ZSBScGNPYnNlcnZhYmxlUGVyZm9ybWFuY2VDb25maWdTZXJ2ZXI6IFJwY09ic2VydmFibGVQZXJmb3JtYW5jZUNvbmZpZ1NlcnZlcjtcclxuICAgIHByaXZhdGUgcnBjT2JzZXJ2YWJsZVVwZGF0ZVRoZW1lU2VydmVyOiBScGNPYnNlcnZhYmxlVXBkYXRlVGhlbWVTZXJ2ZXI7XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBDcmVhdGVzIGEgbmV3IGluc3RhbmNlIG9mIHRoaXMgc2VydmljZVxyXG4gICAgICovXHJcbiAgICBjb25zdHJ1Y3RvcihcclxuICAgICAgICBwcml2YXRlIGFwcENvbnRleHRTZXJ2aWNlOiBBcHBDb250ZXh0U2VydmljZSxcclxuICAgICAgICBwcml2YXRlIHVzZXJBbGl2ZVNlcnZpY2U6IFVzZXJBbGl2ZVNlcnZpY2UsXHJcbiAgICAgICAgcHJpdmF0ZSByb3V0ZXI6IFJvdXRlcixcclxuICAgICAgICBwcml2YXRlIGFjdGl2YXRlZFJvdXRlOiBBY3RpdmF0ZWRSb3V0ZSkge1xyXG4gICAgfVxyXG5cclxuICAgIC8qKlxyXG4gICAgICogSW5pdGlhbGl6ZSBuYXZpZ2F0aW9uIGNvbW11bmljYXRpb24gZnJvbS90byB0aGUgc2hlbGwuXHJcbiAgICAgKlxyXG4gICAgICogIFJlZ2lzdGVycyB0aGUgbWV0aG9kcyB3aXRoIHRoZSByZW1vdGUgUlBDIGRlZmluZWQgaW4gdGhlIG1hbmlmZXN0XHJcbiAgICAgKiAgU3Vic2NyaWJlcyB0byB0aGUgcm91dGVyIGV2ZW50cyBhbmQgcmVwb3J0cyB0aGUgYnJlYWRjcnVtYiBpdGVtc1xyXG4gICAgICogIGJhY2sgdG8gdGhlIHJwYyByZW1vdGVcclxuICAgICAqXHJcbiAgICAgKiBAcGFyYW0gb3B0aW9ucyBUaGUgb3B0aW9ucyB0byBvdmVycmlkZSB0aGUgZGVmYXVsdCBiZWhhdmlvclxyXG4gICAgICovXHJcbiAgICBwdWJsaWMgaW5pdGlhbGl6ZShvcHRpb25zPzogTmF2aWdhdG9yU2VydmljZU9wdGlvbnMpOiB2b2lkIHtcclxuICAgICAgICBQZXJmb3JtYW5jZVRyYWNrZXIubmF2aWdhdGlvbkluaXRpYWxpemVkKCk7XHJcbiAgICAgICAgdGhpcy5hY3RpdmUgPSB0cnVlO1xyXG4gICAgICAgIHRoaXMub3B0aW9ucyA9IG9wdGlvbnMgPyBvcHRpb25zIDogeyBpZGxlUm91dGU6IFsnaWRsZSddIH07XHJcbiAgICAgICAgdGhpcy5pZGxlVXJsID0gYC8ke3RoaXMub3B0aW9ucy5pZGxlUm91dGVbMF19YDtcclxuXHJcbiAgICAgICAgLy8gbmF2aWdhdGUgdG8gaWRsZS5cclxuICAgICAgICB0aGlzLnJvdXRlci5uYXZpZ2F0ZSh0aGlzLm9wdGlvbnMuaWRsZVJvdXRlLCB0aGlzLmRlZmF1bHROYXZpZ2F0aW9uT3B0aW9ucyk7XHJcblxyXG4gICAgICAgIGlmICh0aGlzLnN1YnNjcmlwdGlvbikge1xyXG4gICAgICAgICAgICB0aGlzLnN1YnNjcmlwdGlvbi51bnN1YnNjcmliZSgpO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgbGV0IHN0YXJ0VGltZXN0YW1wID0gbnVsbDtcclxuICAgICAgICB0aGlzLnN1YnNjcmlwdGlvbiA9IHRoaXMucm91dGVyLmV2ZW50c1xyXG4gICAgICAgICAgICAucGlwZShcclxuICAgICAgICAgICAgICAgIHRhcChldmVudCA9PiB7XHJcbiAgICAgICAgICAgICAgICAgICAgaWYgKGV2ZW50IGluc3RhbmNlb2YgTmF2aWdhdGlvblN0YXJ0KSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIHN0YXJ0VGltZXN0YW1wID0gRGF0ZS5ub3coKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgUGVyZm9ybWFuY2VUcmFja2VyLm5hdmlnYXRpb25TdGFydGVkKCk7XHJcbiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIGlmIChldmVudCBpbnN0YW5jZW9mIE5hdmlnYXRpb25FbmQgJiYgc3RhcnRUaW1lc3RhbXApIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgUGVyZm9ybWFuY2VQcm9maWxlLmxvZ1JvdXRlTmF2aWdhdGlvbignTmF2aWdhdGlvblNlcnZpY2UnLCBzdGFydFRpbWVzdGFtcCwgRGF0ZS5ub3coKSwgZXZlbnQudXJsLCB0aGlzLm1vZHVsZU5hbWUpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBzdGFydFRpbWVzdGFtcCA9IG51bGw7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIFBlcmZvcm1hbmNlVHJhY2tlci5uYXZpZ2F0aW9uQ29tcGxldGVkKHRoaXMuZW50ZXJpbmdNb2R1bGUpO1xyXG4gICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgIH0pLFxyXG4gICAgICAgICAgICAgICAgZmlsdGVyKGV2ZW50ID0+IGV2ZW50IGluc3RhbmNlb2YgTmF2aWdhdGlvbkVuZCksXHJcbiAgICAgICAgICAgICAgICBzd2l0Y2hNYXAoZXZlbnQgPT5cclxuICAgICAgICAgICAgICAgICAgICBOYXZpZ2F0aW9uLmJ1aWxkU2VsZWN0YWJsZVBhdGhzRm9yUm91dGUodGhpcy5hcHBDb250ZXh0U2VydmljZSwgdGhpcy5hY3RpdmF0ZWRSb3V0ZS5zbmFwc2hvdClcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAucGlwZShtYXAoc2VsZWN0YWJsZVBhdGhzID0+IDxhbnk+eyBldmVudCwgc2VsZWN0YWJsZVBhdGhzIH0pKSlcclxuICAgICAgICAgICAgKVxyXG4gICAgICAgICAgICAuc3Vic2NyaWJlKChkYXRhOiB7IGV2ZW50OiBOYXZpZ2F0aW9uRW5kLCBzZWxlY3RhYmxlUGF0aHM6IFNlbGVjdGFibGVQYXRoW119KSA9PiB7XHJcbiAgICAgICAgICAgICAgICAvLyBpbiB0aGUgY2FzZSBvZiBpbml0aWFsIGlkbGUgc3RhdGUsIHJlcG9ydGluZyB1cmwgd2lsbCBjYXVzZSBycGMgZXJyb3IuIGFsbCBvdGhlciBjYXNlcyBzaG91bGQgYmUgb2suXHJcbiAgICAgICAgICAgICAgICAvLyBScGNSZXBvcnQgaW5jbHVkZSBmcmFnbWVudCBhbmQgcXVlcnlQYXJhbXMgaW4gJ3BhdGgnIGFuZCAnYmVmb3JlUmVkaXJlY3RlZFBhdGgnLlxyXG4gICAgICAgICAgICAgICAgaWYgKHRoaXMuYWN0aXZlICYmIGRhdGEuZXZlbnQudXJsICE9PSB0aGlzLmlkbGVVcmwpIHtcclxuICAgICAgICAgICAgICAgICAgICB0aGlzLmFwcENvbnRleHRTZXJ2aWNlLmZyYW1lLnJlcG9ydCh7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIHBhdGg6IGRlY29kZVVSSShkYXRhLmV2ZW50LnVybEFmdGVyUmVkaXJlY3RzKSxcclxuICAgICAgICAgICAgICAgICAgICAgICAgYmVmb3JlUmVkaXJlY3RlZFBhdGg6IGRlY29kZVVSSShkYXRhLmV2ZW50LnVybCksXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIHNlbGVjdGFibGVQYXRoOiBkYXRhLnNlbGVjdGFibGVQYXRoc1xyXG4gICAgICAgICAgICAgICAgICAgIH0pO1xyXG4gICAgICAgICAgICAgICAgICAgIHRoaXMuZW50ZXJpbmdNb2R1bGUgPSBmYWxzZTtcclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfSk7XHJcblxyXG4gICAgICAgIHRoaXMuYXBwQ29udGV4dFNlcnZpY2UucnBjLnJlZ2lzdGVyKFJwY091dGJvdW5kQ29tbWFuZHMuSW5pdCwgdGhpcy5vbkluaXQuYmluZCh0aGlzKSk7XHJcbiAgICAgICAgdGhpcy5hcHBDb250ZXh0U2VydmljZS5ycGMucmVnaXN0ZXIoUnBjT3V0Ym91bmRDb21tYW5kcy5PcGVuLCB0aGlzLm9uT3Blbi5iaW5kKHRoaXMpKTtcclxuICAgICAgICB0aGlzLmFwcENvbnRleHRTZXJ2aWNlLnJwYy5yZWdpc3RlcihScGNPdXRib3VuZENvbW1hbmRzLkRlYWN0aXZhdGUyLCB0aGlzLm9uRGVhY3RpdmF0ZTIuYmluZCh0aGlzKSk7XHJcbiAgICAgICAgdGhpcy5hcHBDb250ZXh0U2VydmljZS5ycGMucmVnaXN0ZXIoUnBjT3V0Ym91bmRDb21tYW5kcy5BY3RpdmF0ZSwgdGhpcy5vbkFjdGl2YXRlLmJpbmQodGhpcykpO1xyXG4gICAgICAgIHRoaXMuYXBwQ29udGV4dFNlcnZpY2UucnBjLnJlZ2lzdGVyKFJwY091dGJvdW5kQ29tbWFuZHMuU2h1dGRvd24sIHRoaXMub25TaHV0ZG93bi5iaW5kKHRoaXMpKTtcclxuICAgICAgICB0aGlzLmFwcENvbnRleHRTZXJ2aWNlLnJwYy5yZWdpc3RlcihScGNPdmVybGF5Q2xvc2VLZXkuY29tbWFuZCwgdGhpcy5vbk92ZXJsYXlDbG9zZS5iaW5kKHRoaXMpKTtcclxuICAgIH1cclxuXHJcbiAgICAvKipcclxuICAgICAqIFNodXRkb3duIHRoZSBuYXZpZ2F0aW9uIGNvbW11bmljYXRpb24gZnJvbS90byB0aGUgc2hlbGwuXHJcbiAgICAgKi9cclxuICAgIHB1YmxpYyBzaHV0ZG93bigpOiB2b2lkIHtcclxuICAgICAgICB0aGlzLmFjdGl2ZSA9IGZhbHNlO1xyXG4gICAgICAgIGlmICh0aGlzLnN1YnNjcmlwdGlvbikge1xyXG4gICAgICAgICAgICB0aGlzLnN1YnNjcmlwdGlvbi51bnN1YnNjcmliZSgpO1xyXG4gICAgICAgICAgICB0aGlzLnN1YnNjcmlwdGlvbiA9IG51bGw7XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8qKlxyXG4gICAgICogTWFwIGRpYWxvZyBzZXJ2aWNlIGFuZCBkaWFsb2cgaWQgc28gdGhhdCBjb3JyZWN0IGRpYWxvZyBzZXJ2aWNlIGluc3RhbmNlIGNhbiBiZSBmb3VuZFxyXG4gICAgICogQHBhcmFtIGRpYWxvZ1NlcnZpY2UgZGlhbG9nIHNlcnZpY2UgdG8gYmUgcmVnaXN0ZXJlZFxyXG4gICAgICogQHBhcmFtIGRpYWxvZ0lkIGFzc29jaWF0ZWQgZGlhbG9nIGlkXHJcbiAgICAgKi9cclxuICAgIHB1YmxpYyByZWdpc3RlckRpYWxvZ1NlcnZpY2UoZGlhbG9nU2VydmljZTogRGlhbG9nU2VydmljZSwgZGlhbG9nSWQ6IHN0cmluZyk6IHZvaWQge1xyXG4gICAgICAgIHRoaXMuZGlhbG9nU2VydmljZU1hcFtkaWFsb2dJZF0gPSBkaWFsb2dTZXJ2aWNlO1xyXG4gICAgfVxyXG5cclxuICAgIHByaXZhdGUgY29uZmlndXJlUGVyZm9ybWFuY2VQcm9maWxlKGVuYWJsZWQ6IGJvb2xlYW4pOiB2b2lkIHtcclxuICAgICAgICBjb25zdCBzdGFydFRpbWVzdGFtcCA9IERhdGUubm93KCk7XHJcbiAgICAgICAgaWYgKGVuYWJsZWQpIHtcclxuICAgICAgICAgICAgUGVyZm9ybWFuY2VQcm9maWxlLmN1cnJlbnQuZW5hYmxlKHRoaXMuYXBwQ29udGV4dFNlcnZpY2UucnBjKTtcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICBQZXJmb3JtYW5jZVByb2ZpbGUuY3VycmVudC5kaXNhYmxlKHRoaXMuYXBwQ29udGV4dFNlcnZpY2UucnBjKTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIFBlcmZvcm1hbmNlUHJvZmlsZS5sb2dSb3V0ZU5hdmlnYXRpb24oJ05hdmlnYXRpb25TZXJ2aWNlJywgc3RhcnRUaW1lc3RhbXAsIERhdGUubm93KCksICdbcnBjSW5pdF0nLCB0aGlzLm1vZHVsZU5hbWUpO1xyXG4gICAgfVxyXG5cclxuICAgIHByaXZhdGUgb25Jbml0KGRhdGE6IGFueSk6IFByb21pc2U8YW55PiB7XHJcbiAgICAgICAgLy8gSWZyYW1lIGhhcyByZWNlaXZlZCBhbGwgaW5pdGlhbGl6YXRpb24gZGF0YSBmcm9tIHRoZSBzaGVsbC5cclxuICAgICAgICB0aGlzLmFwcENvbnRleHRTZXJ2aWNlLmdhdGV3YXkubmF2aWdhdGlvblJlYWR5U3RhdHVzID0gdHJ1ZTtcclxuXHJcbiAgICAgICAgdGhpcy5hY3RpdmUgPSB0cnVlO1xyXG4gICAgICAgIGNvbnN0IHNlbGYgPSBNc2Z0U21lLnNlbGYoKTtcclxuICAgICAgICBpZiAoIU1zZnRTbWUuaXNOdWxsT3JVbmRlZmluZWQoc2VsZi5Jbml0LnNlc3Npb25FeHBpcmF0aW9uKSAmJiBzZWxmLkluaXQuc2Vzc2lvbkV4cGlyYXRpb24gPiAwKSB7XHJcbiAgICAgICAgICAgIHRoaXMudXNlckFsaXZlU2VydmljZS5zdGFydCgpO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgQ29ubmVjdGl2aXR5RW5mb3JjZXIucmVnaXN0ZXIodGhpcy5hcHBDb250ZXh0U2VydmljZSk7XHJcbiAgICAgICAgdGhpcy5tb2R1bGVOYW1lID0gc2VsZi5Jbml0Lm1vZHVsZU5hbWU7XHJcbiAgICAgICAgdGhpcy5jb25maWd1cmVQZXJmb3JtYW5jZVByb2ZpbGUoc2VsZi5Jbml0LnBlcmZvcm1hbmNlUHJvZmlsZSk7XHJcbiAgICAgICAgUGVyZm9ybWFuY2VQcm9maWxlLmxvZ051bGwodGhpcy5tb2R1bGVOYW1lKTtcclxuICAgICAgICBpZiAoIXRoaXMuUnBjT2JzZXJ2YWJsZVBlcmZvcm1hbmNlQ29uZmlnU2VydmVyKSB7XHJcbiAgICAgICAgICAgIHRoaXMuUnBjT2JzZXJ2YWJsZVBlcmZvcm1hbmNlQ29uZmlnU2VydmVyID0gbmV3IFJwY09ic2VydmFibGVQZXJmb3JtYW5jZUNvbmZpZ1NlcnZlcih0aGlzLmFwcENvbnRleHRTZXJ2aWNlLnJwYyk7XHJcbiAgICAgICAgICAgIHRoaXMuUnBjT2JzZXJ2YWJsZVBlcmZvcm1hbmNlQ29uZmlnU2VydmVyLnJlZ2lzdGVyKChyZXF1ZXN0KSA9PiB7XHJcbiAgICAgICAgICAgICAgICB0aGlzLmNvbmZpZ3VyZVBlcmZvcm1hbmNlUHJvZmlsZShyZXF1ZXN0LmVuYWJsZWQpO1xyXG4gICAgICAgICAgICAgICAgcmV0dXJuIG9mKG51bGwpO1xyXG4gICAgICAgICAgICB9KTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIGlmICghdGhpcy5ycGNPYnNlcnZhYmxlVXBkYXRlVGhlbWVTZXJ2ZXIpIHtcclxuICAgIC