@microsoft/windows-admin-center-sdk
Version:
Microsoft - Windows Admin Center Shell
382 lines • 65.1 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);
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