UNPKG

angular-auth-oidc-client

Version:
185 lines 33.2 kB
import { DOCUMENT } from '@angular/common'; import { Injectable, NgZone, inject } from '@angular/core'; import { BehaviorSubject, Observable, of } from 'rxjs'; import { take } from 'rxjs/operators'; import { LoggerService } from '../logging/logger.service'; import { EventTypes } from '../public-events/event-types'; import { PublicEventsService } from '../public-events/public-events.service'; import { StoragePersistenceService } from '../storage/storage-persistence.service'; import { IFrameService } from './existing-iframe.service'; import * as i0 from "@angular/core"; const IFRAME_FOR_CHECK_SESSION_IDENTIFIER = 'myiFrameForCheckSession'; // http://openid.net/specs/openid-connect-session-1_0-ID4.html export class CheckSessionService { constructor() { this.loggerService = inject(LoggerService); this.storagePersistenceService = inject(StoragePersistenceService); this.iFrameService = inject(IFrameService); this.eventService = inject(PublicEventsService); this.zone = inject(NgZone); this.document = inject(DOCUMENT); this.checkSessionReceived = false; this.scheduledHeartBeatRunning = null; this.lastIFrameRefresh = 0; this.outstandingMessages = 0; this.heartBeatInterval = 3000; this.iframeRefreshInterval = 60000; this.checkSessionChangedInternal$ = new BehaviorSubject(false); } get checkSessionChanged$() { return this.checkSessionChangedInternal$.asObservable(); } ngOnDestroy() { this.stop(); const windowAsDefaultView = this.document.defaultView; if (windowAsDefaultView && this.iframeMessageEventListener) { windowAsDefaultView.removeEventListener('message', this.iframeMessageEventListener, false); } } isCheckSessionConfigured(configuration) { const { startCheckSession } = configuration; return Boolean(startCheckSession); } start(configuration) { if (!!this.scheduledHeartBeatRunning) { return; } const { clientId } = configuration; this.pollServerSession(clientId, configuration); } stop() { if (!this.scheduledHeartBeatRunning) { return; } this.clearScheduledHeartBeat(); this.checkSessionReceived = false; } serverStateChanged(configuration) { const { startCheckSession } = configuration; return Boolean(startCheckSession) && this.checkSessionReceived; } getExistingIframe() { return this.iFrameService.getExistingIFrame(IFRAME_FOR_CHECK_SESSION_IDENTIFIER); } init(configuration) { if (this.lastIFrameRefresh + this.iframeRefreshInterval > Date.now()) { return of(undefined); } const authWellKnownEndPoints = this.storagePersistenceService.read('authWellKnownEndPoints', configuration); if (!authWellKnownEndPoints) { this.loggerService.logWarning(configuration, 'CheckSession - init check session: authWellKnownEndpoints is undefined. Returning.'); return of(); } const existingIframe = this.getOrCreateIframe(configuration); // https://www.w3.org/TR/2000/REC-DOM-Level-2-Events-20001113/events.html#Events-EventTarget-addEventListener // If multiple identical EventListeners are registered on the same EventTarget with the same parameters the duplicate instances are discarded. They do not cause the EventListener to be called twice and since they are discarded they do not need to be removed with the removeEventListener method. // this is done even if iframe exists for HMR to work, since iframe exists on service init this.bindMessageEventToIframe(configuration); const checkSessionIframe = authWellKnownEndPoints.checkSessionIframe; const contentWindow = existingIframe.contentWindow; if (!checkSessionIframe) { this.loggerService.logWarning(configuration, 'CheckSession - init check session: checkSessionIframe is not configured to run'); } if (!contentWindow) { this.loggerService.logWarning(configuration, 'CheckSession - init check session: IFrame contentWindow does not exist'); } else { contentWindow.location.replace(checkSessionIframe); } return new Observable((observer) => { existingIframe.onload = () => { this.lastIFrameRefresh = Date.now(); observer.next(); observer.complete(); }; }); } pollServerSession(clientId, configuration) { this.outstandingMessages = 0; const pollServerSessionRecur = () => { this.init(configuration) .pipe(take(1)) .subscribe(() => { const existingIframe = this.getExistingIframe(); if (existingIframe && clientId) { this.loggerService.logDebug(configuration, `CheckSession - clientId : '${clientId}' - existingIframe: '${existingIframe}'`); const sessionState = this.storagePersistenceService.read('session_state', configuration); const authWellKnownEndPoints = this.storagePersistenceService.read('authWellKnownEndPoints', configuration); const contentWindow = existingIframe.contentWindow; if (sessionState && authWellKnownEndPoints?.checkSessionIframe && contentWindow) { const iframeOrigin = new URL(authWellKnownEndPoints.checkSessionIframe)?.origin; this.outstandingMessages++; contentWindow.postMessage(clientId + ' ' + sessionState, iframeOrigin); } else { this.loggerService.logDebug(configuration, `CheckSession - session_state is '${sessionState}' - AuthWellKnownEndPoints is '${JSON.stringify(authWellKnownEndPoints, null, 2)}'`); this.checkSessionChangedInternal$.next(true); } } else { this.loggerService.logWarning(configuration, `CheckSession - OidcSecurityCheckSession pollServerSession checkSession IFrame does not exist: clientId : '${clientId}' - existingIframe: '${existingIframe}'`); } // after sending three messages with no response, fail. if (this.outstandingMessages > 3) { this.loggerService.logError(configuration, `CheckSession - OidcSecurityCheckSession not receiving check session response messages. Outstanding messages: '${this.outstandingMessages}'. Server unreachable?`); } this.zone.runOutsideAngular(() => { this.scheduledHeartBeatRunning = this.document?.defaultView?.setTimeout(() => this.zone.run(pollServerSessionRecur), this.heartBeatInterval) ?? null; }); }); }; pollServerSessionRecur(); } clearScheduledHeartBeat() { if (this.scheduledHeartBeatRunning !== null) { clearTimeout(this.scheduledHeartBeatRunning); this.scheduledHeartBeatRunning = null; } } messageHandler(configuration, e) { const existingIFrame = this.getExistingIframe(); const authWellKnownEndPoints = this.storagePersistenceService.read('authWellKnownEndPoints', configuration); const startsWith = !!authWellKnownEndPoints?.checkSessionIframe?.startsWith(e.origin); this.outstandingMessages = 0; if (existingIFrame && startsWith && e.source === existingIFrame.contentWindow) { if (e.data === 'error') { this.loggerService.logWarning(configuration, 'CheckSession - error from check session messageHandler'); } else if (e.data === 'changed') { this.loggerService.logDebug(configuration, `CheckSession - ${e} from check session messageHandler`); this.checkSessionReceived = true; this.eventService.fireEvent(EventTypes.CheckSessionReceived, e.data); this.checkSessionChangedInternal$.next(true); } else { this.eventService.fireEvent(EventTypes.CheckSessionReceived, e.data); this.loggerService.logDebug(configuration, `CheckSession - ${e.data} from check session messageHandler`); } } } bindMessageEventToIframe(configuration) { this.iframeMessageEventListener = this.messageHandler.bind(this, configuration); const defaultView = this.document.defaultView; if (defaultView) { defaultView.addEventListener('message', this.iframeMessageEventListener, false); } } getOrCreateIframe(configuration) { return (this.getExistingIframe() || this.iFrameService.addIFrameToWindowBody(IFRAME_FOR_CHECK_SESSION_IDENTIFIER, configuration)); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: CheckSessionService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); } static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: CheckSessionService, providedIn: 'root' }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: CheckSessionService, decorators: [{ type: Injectable, args: [{ providedIn: 'root' }] }] }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2hlY2stc2Vzc2lvbi5zZXJ2aWNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvYW5ndWxhci1hdXRoLW9pZGMtY2xpZW50L3NyYy9saWIvaWZyYW1lL2NoZWNrLXNlc3Npb24uc2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDM0MsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLEVBQWEsTUFBTSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQ3RFLE9BQU8sRUFBRSxlQUFlLEVBQUUsVUFBVSxFQUFFLEVBQUUsRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUN2RCxPQUFPLEVBQUUsSUFBSSxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFFdEMsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLDJCQUEyQixDQUFDO0FBQzFELE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSw4QkFBOEIsQ0FBQztBQUMxRCxPQUFPLEVBQUUsbUJBQW1CLEVBQUUsTUFBTSx3Q0FBd0MsQ0FBQztBQUM3RSxPQUFPLEVBQUUseUJBQXlCLEVBQUUsTUFBTSx3Q0FBd0MsQ0FBQztBQUNuRixPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0sMkJBQTJCLENBQUM7O0FBRTFELE1BQU0sbUNBQW1DLEdBQUcseUJBQXlCLENBQUM7QUFFdEUsOERBQThEO0FBRzlELE1BQU0sT0FBTyxtQkFBbUI7SUFEaEM7UUFFbUIsa0JBQWEsR0FBRyxNQUFNLENBQUMsYUFBYSxDQUFDLENBQUM7UUFFdEMsOEJBQXlCLEdBQUcsTUFBTSxDQUNqRCx5QkFBeUIsQ0FDMUIsQ0FBQztRQUVlLGtCQUFhLEdBQUcsTUFBTSxDQUFDLGFBQWEsQ0FBQyxDQUFDO1FBRXRDLGlCQUFZLEdBQUcsTUFBTSxDQUFDLG1CQUFtQixDQUFDLENBQUM7UUFFM0MsU0FBSSxHQUFHLE1BQU0sQ0FBQyxNQUFNLENBQUMsQ0FBQztRQUV0QixhQUFRLEdBQUcsTUFBTSxDQUFDLFFBQVEsQ0FBQyxDQUFDO1FBRXJDLHlCQUFvQixHQUFHLEtBQUssQ0FBQztRQUU3Qiw4QkFBeUIsR0FBa0IsSUFBSSxDQUFDO1FBRWhELHNCQUFpQixHQUFHLENBQUMsQ0FBQztRQUV0Qix3QkFBbUIsR0FBRyxDQUFDLENBQUM7UUFFZixzQkFBaUIsR0FBRyxJQUFJLENBQUM7UUFFekIsMEJBQXFCLEdBQUcsS0FBSyxDQUFDO1FBRTlCLGlDQUE0QixHQUFHLElBQUksZUFBZSxDQUNqRSxLQUFLLENBQ04sQ0FBQztLQStRSDtJQXhRQyxJQUFJLG9CQUFvQjtRQUN0QixPQUFPLElBQUksQ0FBQyw0QkFBNEIsQ0FBQyxZQUFZLEVBQUUsQ0FBQztJQUMxRCxDQUFDO0lBRUQsV0FBVztRQUNULElBQUksQ0FBQyxJQUFJLEVBQUUsQ0FBQztRQUNaLE1BQU0sbUJBQW1CLEdBQUcsSUFBSSxDQUFDLFFBQVEsQ0FBQyxXQUFXLENBQUM7UUFFdEQsSUFBSSxtQkFBbUIsSUFBSSxJQUFJLENBQUMsMEJBQTBCLEVBQUUsQ0FBQztZQUMzRCxtQkFBbUIsQ0FBQyxtQkFBbUIsQ0FDckMsU0FBUyxFQUNULElBQUksQ0FBQywwQkFBMEIsRUFDL0IsS0FBSyxDQUNOLENBQUM7UUFDSixDQUFDO0lBQ0gsQ0FBQztJQUVELHdCQUF3QixDQUFDLGFBQWtDO1FBQ3pELE1BQU0sRUFBRSxpQkFBaUIsRUFBRSxHQUFHLGFBQWEsQ0FBQztRQUU1QyxPQUFPLE9BQU8sQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDO0lBQ3BDLENBQUM7SUFFRCxLQUFLLENBQUMsYUFBa0M7UUFDdEMsSUFBSSxDQUFDLENBQUMsSUFBSSxDQUFDLHlCQUF5QixFQUFFLENBQUM7WUFDckMsT0FBTztRQUNULENBQUM7UUFFRCxNQUFNLEVBQUUsUUFBUSxFQUFFLEdBQUcsYUFBYSxDQUFDO1FBRW5DLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxRQUFRLEVBQUUsYUFBYSxDQUFDLENBQUM7SUFDbEQsQ0FBQztJQUVELElBQUk7UUFDRixJQUFJLENBQUMsSUFBSSxDQUFDLHlCQUF5QixFQUFFLENBQUM7WUFDcEMsT0FBTztRQUNULENBQUM7UUFFRCxJQUFJLENBQUMsdUJBQXVCLEVBQUUsQ0FBQztRQUMvQixJQUFJLENBQUMsb0JBQW9CLEdBQUcsS0FBSyxDQUFDO0lBQ3BDLENBQUM7SUFFRCxrQkFBa0IsQ0FBQyxhQUFrQztRQUNuRCxNQUFNLEVBQUUsaUJBQWlCLEVBQUUsR0FBRyxhQUFhLENBQUM7UUFFNUMsT0FBTyxPQUFPLENBQUMsaUJBQWlCLENBQUMsSUFBSSxJQUFJLENBQUMsb0JBQW9CLENBQUM7SUFDakUsQ0FBQztJQUVELGlCQUFpQjtRQUNmLE9BQU8sSUFBSSxDQUFDLGFBQWEsQ0FBQyxpQkFBaUIsQ0FDekMsbUNBQW1DLENBQ3BDLENBQUM7SUFDSixDQUFDO0lBRU8sSUFBSSxDQUFDLGFBQWtDO1FBQzdDLElBQUksSUFBSSxDQUFDLGlCQUFpQixHQUFHLElBQUksQ0FBQyxxQkFBcUIsR0FBRyxJQUFJLENBQUMsR0FBRyxFQUFFLEVBQUUsQ0FBQztZQUNyRSxPQUFPLEVBQUUsQ0FBQyxTQUFTLENBQUMsQ0FBQztRQUN2QixDQUFDO1FBRUQsTUFBTSxzQkFBc0IsR0FBRyxJQUFJLENBQUMseUJBQXlCLENBQUMsSUFBSSxDQUNoRSx3QkFBd0IsRUFDeEIsYUFBYSxDQUNkLENBQUM7UUFFRixJQUFJLENBQUMsc0JBQXNCLEVBQUUsQ0FBQztZQUM1QixJQUFJLENBQUMsYUFBYSxDQUFDLFVBQVUsQ0FDM0IsYUFBYSxFQUNiLG9GQUFvRixDQUNyRixDQUFDO1lBRUYsT0FBTyxFQUFFLEVBQUUsQ0FBQztRQUNkLENBQUM7UUFFRCxNQUFNLGNBQWMsR0FBRyxJQUFJLENBQUMsaUJBQWlCLENBQUMsYUFBYSxDQUFDLENBQUM7UUFFN0QsNkdBQTZHO1FBQzdHLHNTQUFzUztRQUN0UywwRkFBMEY7UUFDMUYsSUFBSSxDQUFDLHdCQUF3QixDQUFDLGFBQWEsQ0FBQyxDQUFDO1FBQzdDLE1BQU0sa0JBQWtCLEdBQUcsc0JBQXNCLENBQUMsa0JBQWtCLENBQUM7UUFDckUsTUFBTSxhQUFhLEdBQUcsY0FBYyxDQUFDLGFBQWEsQ0FBQztRQUVuRCxJQUFJLENBQUMsa0JBQWtCLEVBQUUsQ0FBQztZQUN4QixJQUFJLENBQUMsYUFBYSxDQUFDLFVBQVUsQ0FDM0IsYUFBYSxFQUNiLGdGQUFnRixDQUNqRixDQUFDO1FBQ0osQ0FBQztRQUVELElBQUksQ0FBQyxhQUFhLEVBQUUsQ0FBQztZQUNuQixJQUFJLENBQUMsYUFBYSxDQUFDLFVBQVUsQ0FDM0IsYUFBYSxFQUNiLHdFQUF3RSxDQUN6RSxDQUFDO1FBQ0osQ0FBQzthQUFNLENBQUM7WUFDTixhQUFhLENBQUMsUUFBUSxDQUFDLE9BQU8sQ0FBQyxrQkFBa0IsQ0FBQyxDQUFDO1FBQ3JELENBQUM7UUFFRCxPQUFPLElBQUksVUFBVSxDQUFDLENBQUMsUUFBUSxFQUFFLEVBQUU7WUFDakMsY0FBYyxDQUFDLE1BQU0sR0FBRyxHQUFTLEVBQUU7Z0JBQ2pDLElBQUksQ0FBQyxpQkFBaUIsR0FBRyxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUM7Z0JBQ3BDLFFBQVEsQ0FBQyxJQUFJLEVBQUUsQ0FBQztnQkFDaEIsUUFBUSxDQUFDLFFBQVEsRUFBRSxDQUFDO1lBQ3RCLENBQUMsQ0FBQztRQUNKLENBQUMsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztJQUVPLGlCQUFpQixDQUN2QixRQUE0QixFQUM1QixhQUFrQztRQUVsQyxJQUFJLENBQUMsbUJBQW1CLEdBQUcsQ0FBQyxDQUFDO1FBRTdCLE1BQU0sc0JBQXNCLEdBQUcsR0FBUyxFQUFFO1lBQ3hDLElBQUksQ0FBQyxJQUFJLENBQUMsYUFBYSxDQUFDO2lCQUNyQixJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDO2lCQUNiLFNBQVMsQ0FBQyxHQUFHLEVBQUU7Z0JBQ2QsTUFBTSxjQUFjLEdBQUcsSUFBSSxDQUFDLGlCQUFpQixFQUFFLENBQUM7Z0JBRWhELElBQUksY0FBYyxJQUFJLFFBQVEsRUFBRSxDQUFDO29CQUMvQixJQUFJLENBQUMsYUFBYSxDQUFDLFFBQVEsQ0FDekIsYUFBYSxFQUNiLDhCQUE4QixRQUFRLHdCQUF3QixjQUFjLEdBQUcsQ0FDaEYsQ0FBQztvQkFDRixNQUFNLFlBQVksR0FBRyxJQUFJLENBQUMseUJBQXlCLENBQUMsSUFBSSxDQUN0RCxlQUFlLEVBQ2YsYUFBYSxDQUNkLENBQUM7b0JBQ0YsTUFBTSxzQkFBc0IsR0FBRyxJQUFJLENBQUMseUJBQXlCLENBQUMsSUFBSSxDQUNoRSx3QkFBd0IsRUFDeEIsYUFBYSxDQUNkLENBQUM7b0JBQ0YsTUFBTSxhQUFhLEdBQUcsY0FBYyxDQUFDLGFBQWEsQ0FBQztvQkFFbkQsSUFDRSxZQUFZO3dCQUNaLHNCQUFzQixFQUFFLGtCQUFrQjt3QkFDMUMsYUFBYSxFQUNiLENBQUM7d0JBQ0QsTUFBTSxZQUFZLEdBQUcsSUFBSSxHQUFHLENBQzFCLHNCQUFzQixDQUFDLGtCQUFrQixDQUMxQyxFQUFFLE1BQU0sQ0FBQzt3QkFFVixJQUFJLENBQUMsbUJBQW1CLEVBQUUsQ0FBQzt3QkFDM0IsYUFBYSxDQUFDLFdBQVcsQ0FDdkIsUUFBUSxHQUFHLEdBQUcsR0FBRyxZQUFZLEVBQzdCLFlBQVksQ0FDYixDQUFDO29CQUNKLENBQUM7eUJBQU0sQ0FBQzt3QkFDTixJQUFJLENBQUMsYUFBYSxDQUFDLFFBQVEsQ0FDekIsYUFBYSxFQUNiLG9DQUFvQyxZQUFZLGtDQUFrQyxJQUFJLENBQUMsU0FBUyxDQUM5RixzQkFBc0IsRUFDdEIsSUFBSSxFQUNKLENBQUMsQ0FDRixHQUFHLENBQ0wsQ0FBQzt3QkFDRixJQUFJLENBQUMsNEJBQTRCLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO29CQUMvQyxDQUFDO2dCQUNILENBQUM7cUJBQU0sQ0FBQztvQkFDTixJQUFJLENBQUMsYUFBYSxDQUFDLFVBQVUsQ0FDM0IsYUFBYSxFQUNiOzZCQUNlLFFBQVEsd0JBQXdCLGNBQWMsR0FBRyxDQUNqRSxDQUFDO2dCQUNKLENBQUM7Z0JBRUQsdURBQXVEO2dCQUN2RCxJQUFJLElBQUksQ0FBQyxtQkFBbUIsR0FBRyxDQUFDLEVBQUUsQ0FBQztvQkFDakMsSUFBSSxDQUFDLGFBQWEsQ0FBQyxRQUFRLENBQ3pCLGFBQWEsRUFDYjtxREFDdUMsSUFBSSxDQUFDLG1CQUFtQix3QkFBd0IsQ0FDeEYsQ0FBQztnQkFDSixDQUFDO2dCQUVELElBQUksQ0FBQyxJQUFJLENBQUMsaUJBQWlCLENBQUMsR0FBRyxFQUFFO29CQUMvQixJQUFJLENBQUMseUJBQXlCO3dCQUM1QixJQUFJLENBQUMsUUFBUSxFQUFFLFdBQVcsRUFBRSxVQUFVLENBQ3BDLEdBQUcsRUFBRSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLHNCQUFzQixDQUFDLEVBQzNDLElBQUksQ0FBQyxpQkFBaUIsQ0FDdkIsSUFBSSxJQUFJLENBQUM7Z0JBQ2QsQ0FBQyxDQUFDLENBQUM7WUFDTCxDQUFDLENBQUMsQ0FBQztRQUNQLENBQUMsQ0FBQztRQUVGLHNCQUFzQixFQUFFLENBQUM7SUFDM0IsQ0FBQztJQUVPLHVCQUF1QjtRQUM3QixJQUFJLElBQUksQ0FBQyx5QkFBeUIsS0FBSyxJQUFJLEVBQUUsQ0FBQztZQUM1QyxZQUFZLENBQUMsSUFBSSxDQUFDLHlCQUF5QixDQUFDLENBQUM7WUFDN0MsSUFBSSxDQUFDLHlCQUF5QixHQUFHLElBQUksQ0FBQztRQUN4QyxDQUFDO0lBQ0gsQ0FBQztJQUVPLGNBQWMsQ0FBQyxhQUFrQyxFQUFFLENBQU07UUFDL0QsTUFBTSxjQUFjLEdBQUcsSUFBSSxDQUFDLGlCQUFpQixFQUFFLENBQUM7UUFDaEQsTUFBTSxzQkFBc0IsR0FBRyxJQUFJLENBQUMseUJBQXlCLENBQUMsSUFBSSxDQUNoRSx3QkFBd0IsRUFDeEIsYUFBYSxDQUNkLENBQUM7UUFDRixNQUFNLFVBQVUsR0FBRyxDQUFDLENBQUMsc0JBQXNCLEVBQUUsa0JBQWtCLEVBQUUsVUFBVSxDQUN6RSxDQUFDLENBQUMsTUFBTSxDQUNULENBQUM7UUFFRixJQUFJLENBQUMsbUJBQW1CLEdBQUcsQ0FBQyxDQUFDO1FBRTdCLElBQ0UsY0FBYztZQUNkLFVBQVU7WUFDVixDQUFDLENBQUMsTUFBTSxLQUFLLGNBQWMsQ0FBQyxhQUFhLEVBQ3pDLENBQUM7WUFDRCxJQUFJLENBQUMsQ0FBQyxJQUFJLEtBQUssT0FBTyxFQUFFLENBQUM7Z0JBQ3ZCLElBQUksQ0FBQyxhQUFhLENBQUMsVUFBVSxDQUMzQixhQUFhLEVBQ2Isd0RBQXdELENBQ3pELENBQUM7WUFDSixDQUFDO2lCQUFNLElBQUksQ0FBQyxDQUFDLElBQUksS0FBSyxTQUFTLEVBQUUsQ0FBQztnQkFDaEMsSUFBSSxDQUFDLGFBQWEsQ0FBQyxRQUFRLENBQ3pCLGFBQWEsRUFDYixrQkFBa0IsQ0FBQyxvQ0FBb0MsQ0FDeEQsQ0FBQztnQkFDRixJQUFJLENBQUMsb0JBQW9CLEdBQUcsSUFBSSxDQUFDO2dCQUNqQyxJQUFJLENBQUMsWUFBWSxDQUFDLFNBQVMsQ0FBQyxVQUFVLENBQUMsb0JBQW9CLEVBQUUsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDO2dCQUNyRSxJQUFJLENBQUMsNEJBQTRCLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO1lBQy9DLENBQUM7aUJBQU0sQ0FBQztnQkFDTixJQUFJLENBQUMsWUFBWSxDQUFDLFNBQVMsQ0FBQyxVQUFVLENBQUMsb0JBQW9CLEVBQUUsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDO2dCQUNyRSxJQUFJLENBQUMsYUFBYSxDQUFDLFFBQVEsQ0FDekIsYUFBYSxFQUNiLGtCQUFrQixDQUFDLENBQUMsSUFBSSxvQ0FBb0MsQ0FDN0QsQ0FBQztZQUNKLENBQUM7UUFDSCxDQUFDO0lBQ0gsQ0FBQztJQUVPLHdCQUF3QixDQUFDLGFBQWtDO1FBQ2pFLElBQUksQ0FBQywwQkFBMEIsR0FBRyxJQUFJLENBQUMsY0FBYyxDQUFDLElBQUksQ0FDeEQsSUFBSSxFQUNKLGFBQWEsQ0FDZCxDQUFDO1FBRUYsTUFBTSxXQUFXLEdBQUcsSUFBSSxDQUFDLFFBQVEsQ0FBQyxXQUFXLENBQUM7UUFFOUMsSUFBSSxXQUFXLEVBQUUsQ0FBQztZQUNoQixXQUFXLENBQUMsZ0JBQWdCLENBQzFCLFNBQVMsRUFDVCxJQUFJLENBQUMsMEJBQTBCLEVBQy9CLEtBQUssQ0FDTixDQUFDO1FBQ0osQ0FBQztJQUNILENBQUM7SUFFTyxpQkFBaUIsQ0FDdkIsYUFBa0M7UUFFbEMsT0FBTyxDQUNMLElBQUksQ0FBQyxpQkFBaUIsRUFBRTtZQUN4QixJQUFJLENBQUMsYUFBYSxDQUFDLHFCQUFxQixDQUN0QyxtQ0FBbUMsRUFDbkMsYUFBYSxDQUNkLENBQ0YsQ0FBQztJQUNKLENBQUM7OEdBM1NVLG1CQUFtQjtrSEFBbkIsbUJBQW1CLGNBRE4sTUFBTTs7MkZBQ25CLG1CQUFtQjtrQkFEL0IsVUFBVTttQkFBQyxFQUFFLFVBQVUsRUFBRSxNQUFNLEVBQUUiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBET0NVTUVOVCB9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbic7XHJcbmltcG9ydCB7IEluamVjdGFibGUsIE5nWm9uZSwgT25EZXN0cm95LCBpbmplY3QgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcclxuaW1wb3J0IHsgQmVoYXZpb3JTdWJqZWN0LCBPYnNlcnZhYmxlLCBvZiB9IGZyb20gJ3J4anMnO1xyXG5pbXBvcnQgeyB0YWtlIH0gZnJvbSAncnhqcy9vcGVyYXRvcnMnO1xyXG5pbXBvcnQgeyBPcGVuSWRDb25maWd1cmF0aW9uIH0gZnJvbSAnLi4vY29uZmlnL29wZW5pZC1jb25maWd1cmF0aW9uJztcclxuaW1wb3J0IHsgTG9nZ2VyU2VydmljZSB9IGZyb20gJy4uL2xvZ2dpbmcvbG9nZ2VyLnNlcnZpY2UnO1xyXG5pbXBvcnQgeyBFdmVudFR5cGVzIH0gZnJvbSAnLi4vcHVibGljLWV2ZW50cy9ldmVudC10eXBlcyc7XHJcbmltcG9ydCB7IFB1YmxpY0V2ZW50c1NlcnZpY2UgfSBmcm9tICcuLi9wdWJsaWMtZXZlbnRzL3B1YmxpYy1ldmVudHMuc2VydmljZSc7XHJcbmltcG9ydCB7IFN0b3JhZ2VQZXJzaXN0ZW5jZVNlcnZpY2UgfSBmcm9tICcuLi9zdG9yYWdlL3N0b3JhZ2UtcGVyc2lzdGVuY2Uuc2VydmljZSc7XHJcbmltcG9ydCB7IElGcmFtZVNlcnZpY2UgfSBmcm9tICcuL2V4aXN0aW5nLWlmcmFtZS5zZXJ2aWNlJztcclxuXHJcbmNvbnN0IElGUkFNRV9GT1JfQ0hFQ0tfU0VTU0lPTl9JREVOVElGSUVSID0gJ215aUZyYW1lRm9yQ2hlY2tTZXNzaW9uJztcclxuXHJcbi8vIGh0dHA6Ly9vcGVuaWQubmV0L3NwZWNzL29wZW5pZC1jb25uZWN0LXNlc3Npb24tMV8wLUlENC5odG1sXHJcblxyXG5ASW5qZWN0YWJsZSh7IHByb3ZpZGVkSW46ICdyb290JyB9KVxyXG5leHBvcnQgY2xhc3MgQ2hlY2tTZXNzaW9uU2VydmljZSBpbXBsZW1lbnRzIE9uRGVzdHJveSB7XHJcbiAgcHJpdmF0ZSByZWFkb25seSBsb2dnZXJTZXJ2aWNlID0gaW5qZWN0KExvZ2dlclNlcnZpY2UpO1xyXG5cclxuICBwcml2YXRlIHJlYWRvbmx5IHN0b3JhZ2VQZXJzaXN0ZW5jZVNlcnZpY2UgPSBpbmplY3QoXHJcbiAgICBTdG9yYWdlUGVyc2lzdGVuY2VTZXJ2aWNlXHJcbiAgKTtcclxuXHJcbiAgcHJpdmF0ZSByZWFkb25seSBpRnJhbWVTZXJ2aWNlID0gaW5qZWN0KElGcmFtZVNlcnZpY2UpO1xyXG5cclxuICBwcml2YXRlIHJlYWRvbmx5IGV2ZW50U2VydmljZSA9IGluamVjdChQdWJsaWNFdmVudHNTZXJ2aWNlKTtcclxuXHJcbiAgcHJpdmF0ZSByZWFkb25seSB6b25lID0gaW5qZWN0KE5nWm9uZSk7XHJcblxyXG4gIHByaXZhdGUgcmVhZG9ubHkgZG9jdW1lbnQgPSBpbmplY3QoRE9DVU1FTlQpO1xyXG5cclxuICBwcml2YXRlIGNoZWNrU2Vzc2lvblJlY2VpdmVkID0gZmFsc2U7XHJcblxyXG4gIHByaXZhdGUgc2NoZWR1bGVkSGVhcnRCZWF0UnVubmluZzogbnVtYmVyIHwgbnVsbCA9IG51bGw7XHJcblxyXG4gIHByaXZhdGUgbGFzdElGcmFtZVJlZnJlc2ggPSAwO1xyXG5cclxuICBwcml2YXRlIG91dHN0YW5kaW5nTWVzc2FnZXMgPSAwO1xyXG5cclxuICBwcml2YXRlIHJlYWRvbmx5IGhlYXJ0QmVhdEludGVydmFsID0gMzAwMDtcclxuXHJcbiAgcHJpdmF0ZSByZWFkb25seSBpZnJhbWVSZWZyZXNoSW50ZXJ2YWwgPSA2MDAwMDtcclxuXHJcbiAgcHJpdmF0ZSByZWFkb25seSBjaGVja1Nlc3Npb25DaGFuZ2VkSW50ZXJuYWwkID0gbmV3IEJlaGF2aW9yU3ViamVjdDxib29sZWFuPihcclxuICAgIGZhbHNlXHJcbiAgKTtcclxuXHJcbiAgcHJpdmF0ZSBpZnJhbWVNZXNzYWdlRXZlbnRMaXN0ZW5lcj86IChcclxuICAgIHRoaXM6IFdpbmRvdyxcclxuICAgIGV2OiBNZXNzYWdlRXZlbnQ8YW55PlxyXG4gICkgPT4gYW55O1xyXG5cclxuICBnZXQgY2hlY2tTZXNzaW9uQ2hhbmdlZCQoKTogT2JzZXJ2YWJsZTxib29sZWFuPiB7XHJcbiAgICByZXR1cm4gdGhpcy5jaGVja1Nlc3Npb25DaGFuZ2VkSW50ZXJuYWwkLmFzT2JzZXJ2YWJsZSgpO1xyXG4gIH1cclxuXHJcbiAgbmdPbkRlc3Ryb3koKTogdm9pZCB7XHJcbiAgICB0aGlzLnN0b3AoKTtcclxuICAgIGNvbnN0IHdpbmRvd0FzRGVmYXVsdFZpZXcgPSB0aGlzLmRvY3VtZW50LmRlZmF1bHRWaWV3O1xyXG5cclxuICAgIGlmICh3aW5kb3dBc0RlZmF1bHRWaWV3ICYmIHRoaXMuaWZyYW1lTWVzc2FnZUV2ZW50TGlzdGVuZXIpIHtcclxuICAgICAgd2luZG93QXNEZWZhdWx0Vmlldy5yZW1vdmVFdmVudExpc3RlbmVyKFxyXG4gICAgICAgICdtZXNzYWdlJyxcclxuICAgICAgICB0aGlzLmlmcmFtZU1lc3NhZ2VFdmVudExpc3RlbmVyLFxyXG4gICAgICAgIGZhbHNlXHJcbiAgICAgICk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBpc0NoZWNrU2Vzc2lvbkNvbmZpZ3VyZWQoY29uZmlndXJhdGlvbjogT3BlbklkQ29uZmlndXJhdGlvbik6IGJvb2xlYW4ge1xyXG4gICAgY29uc3QgeyBzdGFydENoZWNrU2Vzc2lvbiB9ID0gY29uZmlndXJhdGlvbjtcclxuXHJcbiAgICByZXR1cm4gQm9vbGVhbihzdGFydENoZWNrU2Vzc2lvbik7XHJcbiAgfVxyXG5cclxuICBzdGFydChjb25maWd1cmF0aW9uOiBPcGVuSWRDb25maWd1cmF0aW9uKTogdm9pZCB7XHJcbiAgICBpZiAoISF0aGlzLnNjaGVkdWxlZEhlYXJ0QmVhdFJ1bm5pbmcpIHtcclxuICAgICAgcmV0dXJuO1xyXG4gICAgfVxyXG5cclxuICAgIGNvbnN0IHsgY2xpZW50SWQgfSA9IGNvbmZpZ3VyYXRpb247XHJcblxyXG4gICAgdGhpcy5wb2xsU2VydmVyU2Vzc2lvbihjbGllbnRJZCwgY29uZmlndXJhdGlvbik7XHJcbiAgfVxyXG5cclxuICBzdG9wKCk6IHZvaWQge1xyXG4gICAgaWYgKCF0aGlzLnNjaGVkdWxlZEhlYXJ0QmVhdFJ1bm5pbmcpIHtcclxuICAgICAgcmV0dXJuO1xyXG4gICAgfVxyXG5cclxuICAgIHRoaXMuY2xlYXJTY2hlZHVsZWRIZWFydEJlYXQoKTtcclxuICAgIHRoaXMuY2hlY2tTZXNzaW9uUmVjZWl2ZWQgPSBmYWxzZTtcclxuICB9XHJcblxyXG4gIHNlcnZlclN0YXRlQ2hhbmdlZChjb25maWd1cmF0aW9uOiBPcGVuSWRDb25maWd1cmF0aW9uKTogYm9vbGVhbiB7XHJcbiAgICBjb25zdCB7IHN0YXJ0Q2hlY2tTZXNzaW9uIH0gPSBjb25maWd1cmF0aW9uO1xyXG5cclxuICAgIHJldHVybiBCb29sZWFuKHN0YXJ0Q2hlY2tTZXNzaW9uKSAmJiB0aGlzLmNoZWNrU2Vzc2lvblJlY2VpdmVkO1xyXG4gIH1cclxuXHJcbiAgZ2V0RXhpc3RpbmdJZnJhbWUoKTogSFRNTElGcmFtZUVsZW1lbnQgfCBudWxsIHtcclxuICAgIHJldHVybiB0aGlzLmlGcmFtZVNlcnZpY2UuZ2V0RXhpc3RpbmdJRnJhbWUoXHJcbiAgICAgIElGUkFNRV9GT1JfQ0hFQ0tfU0VTU0lPTl9JREVOVElGSUVSXHJcbiAgICApO1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBpbml0KGNvbmZpZ3VyYXRpb246IE9wZW5JZENvbmZpZ3VyYXRpb24pOiBPYnNlcnZhYmxlPGFueT4ge1xyXG4gICAgaWYgKHRoaXMubGFzdElGcmFtZVJlZnJlc2ggKyB0aGlzLmlmcmFtZVJlZnJlc2hJbnRlcnZhbCA+IERhdGUubm93KCkpIHtcclxuICAgICAgcmV0dXJuIG9mKHVuZGVmaW5lZCk7XHJcbiAgICB9XHJcblxyXG4gICAgY29uc3QgYXV0aFdlbGxLbm93bkVuZFBvaW50cyA9IHRoaXMuc3RvcmFnZVBlcnNpc3RlbmNlU2VydmljZS5yZWFkKFxyXG4gICAgICAnYXV0aFdlbGxLbm93bkVuZFBvaW50cycsXHJcbiAgICAgIGNvbmZpZ3VyYXRpb25cclxuICAgICk7XHJcblxyXG4gICAgaWYgKCFhdXRoV2VsbEtub3duRW5kUG9pbnRzKSB7XHJcbiAgICAgIHRoaXMubG9nZ2VyU2VydmljZS5sb2dXYXJuaW5nKFxyXG4gICAgICAgIGNvbmZpZ3VyYXRpb24sXHJcbiAgICAgICAgJ0NoZWNrU2Vzc2lvbiAtIGluaXQgY2hlY2sgc2Vzc2lvbjogYXV0aFdlbGxLbm93bkVuZHBvaW50cyBpcyB1bmRlZmluZWQuIFJldHVybmluZy4nXHJcbiAgICAgICk7XHJcblxyXG4gICAgICByZXR1cm4gb2YoKTtcclxuICAgIH1cclxuXHJcbiAgICBjb25zdCBleGlzdGluZ0lmcmFtZSA9IHRoaXMuZ2V0T3JDcmVhdGVJZnJhbWUoY29uZmlndXJhdGlvbik7XHJcblxyXG4gICAgLy8gaHR0cHM6Ly93d3cudzMub3JnL1RSLzIwMDAvUkVDLURPTS1MZXZlbC0yLUV2ZW50cy0yMDAwMTExMy9ldmVudHMuaHRtbCNFdmVudHMtRXZlbnRUYXJnZXQtYWRkRXZlbnRMaXN0ZW5lclxyXG4gICAgLy8gSWYgbXVsdGlwbGUgaWRlbnRpY2FsIEV2ZW50TGlzdGVuZXJzIGFyZSByZWdpc3RlcmVkIG9uIHRoZSBzYW1lIEV2ZW50VGFyZ2V0IHdpdGggdGhlIHNhbWUgcGFyYW1ldGVycyB0aGUgZHVwbGljYXRlIGluc3RhbmNlcyBhcmUgZGlzY2FyZGVkLiBUaGV5IGRvIG5vdCBjYXVzZSB0aGUgRXZlbnRMaXN0ZW5lciB0byBiZSBjYWxsZWQgdHdpY2UgYW5kIHNpbmNlIHRoZXkgYXJlIGRpc2NhcmRlZCB0aGV5IGRvIG5vdCBuZWVkIHRvIGJlIHJlbW92ZWQgd2l0aCB0aGUgcmVtb3ZlRXZlbnRMaXN0ZW5lciBtZXRob2QuXHJcbiAgICAvLyB0aGlzIGlzIGRvbmUgZXZlbiBpZiBpZnJhbWUgZXhpc3RzIGZvciBITVIgdG8gd29yaywgc2luY2UgaWZyYW1lIGV4aXN0cyBvbiBzZXJ2aWNlIGluaXRcclxuICAgIHRoaXMuYmluZE1lc3NhZ2VFdmVudFRvSWZyYW1lKGNvbmZpZ3VyYXRpb24pO1xyXG4gICAgY29uc3QgY2hlY2tTZXNzaW9uSWZyYW1lID0gYXV0aFdlbGxLbm93bkVuZFBvaW50cy5jaGVja1Nlc3Npb25JZnJhbWU7XHJcbiAgICBjb25zdCBjb250ZW50V2luZG93ID0gZXhpc3RpbmdJZnJhbWUuY29udGVudFdpbmRvdztcclxuXHJcbiAgICBpZiAoIWNoZWNrU2Vzc2lvbklmcmFtZSkge1xyXG4gICAgICB0aGlzLmxvZ2dlclNlcnZpY2UubG9nV2FybmluZyhcclxuICAgICAgICBjb25maWd1cmF0aW9uLFxyXG4gICAgICAgICdDaGVja1Nlc3Npb24gLSBpbml0IGNoZWNrIHNlc3Npb246IGNoZWNrU2Vzc2lvbklmcmFtZSBpcyBub3QgY29uZmlndXJlZCB0byBydW4nXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKCFjb250ZW50V2luZG93KSB7XHJcbiAgICAgIHRoaXMubG9nZ2VyU2VydmljZS5sb2dXYXJuaW5nKFxyXG4gICAgICAgIGNvbmZpZ3VyYXRpb24sXHJcbiAgICAgICAgJ0NoZWNrU2Vzc2lvbiAtIGluaXQgY2hlY2sgc2Vzc2lvbjogSUZyYW1lIGNvbnRlbnRXaW5kb3cgZG9lcyBub3QgZXhpc3QnXHJcbiAgICAgICk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICBjb250ZW50V2luZG93LmxvY2F0aW9uLnJlcGxhY2UoY2hlY2tTZXNzaW9uSWZyYW1lKTtcclxuICAgIH1cclxuXHJcbiAgICByZXR1cm4gbmV3IE9ic2VydmFibGUoKG9ic2VydmVyKSA9PiB7XHJcbiAgICAgIGV4aXN0aW5nSWZyYW1lLm9ubG9hZCA9ICgpOiB2b2lkID0+IHtcclxuICAgICAgICB0aGlzLmxhc3RJRnJhbWVSZWZyZXNoID0gRGF0ZS5ub3coKTtcclxuICAgICAgICBvYnNlcnZlci5uZXh0KCk7XHJcbiAgICAgICAgb2JzZXJ2ZXIuY29tcGxldGUoKTtcclxuICAgICAgfTtcclxuICAgIH0pO1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBwb2xsU2VydmVyU2Vzc2lvbihcclxuICAgIGNsaWVudElkOiBzdHJpbmcgfCB1bmRlZmluZWQsXHJcbiAgICBjb25maWd1cmF0aW9uOiBPcGVuSWRDb25maWd1cmF0aW9uXHJcbiAgKTogdm9pZCB7XHJcbiAgICB0aGlzLm91dHN0YW5kaW5nTWVzc2FnZXMgPSAwO1xyXG5cclxuICAgIGNvbnN0IHBvbGxTZXJ2ZXJTZXNzaW9uUmVjdXIgPSAoKTogdm9pZCA9PiB7XHJcbiAgICAgIHRoaXMuaW5pdChjb25maWd1cmF0aW9uKVxyXG4gICAgICAgIC5waXBlKHRha2UoMSkpXHJcbiAgICAgICAgLnN1YnNjcmliZSgoKSA9PiB7XHJcbiAgICAgICAgICBjb25zdCBleGlzdGluZ0lmcmFtZSA9IHRoaXMuZ2V0RXhpc3RpbmdJZnJhbWUoKTtcclxuXHJcbiAgICAgICAgICBpZiAoZXhpc3RpbmdJZnJhbWUgJiYgY2xpZW50SWQpIHtcclxuICAgICAgICAgICAgdGhpcy5sb2dnZXJTZXJ2aWNlLmxvZ0RlYnVnKFxyXG4gICAgICAgICAgICAgIGNvbmZpZ3VyYXRpb24sXHJcbiAgICAgICAgICAgICAgYENoZWNrU2Vzc2lvbiAtIGNsaWVudElkIDogJyR7Y2xpZW50SWR9JyAtIGV4aXN0aW5nSWZyYW1lOiAnJHtleGlzdGluZ0lmcmFtZX0nYFxyXG4gICAgICAgICAgICApO1xyXG4gICAgICAgICAgICBjb25zdCBzZXNzaW9uU3RhdGUgPSB0aGlzLnN0b3JhZ2VQZXJzaXN0ZW5jZVNlcnZpY2UucmVhZChcclxuICAgICAgICAgICAgICAnc2Vzc2lvbl9zdGF0ZScsXHJcbiAgICAgICAgICAgICAgY29uZmlndXJhdGlvblxyXG4gICAgICAgICAgICApO1xyXG4gICAgICAgICAgICBjb25zdCBhdXRoV2VsbEtub3duRW5kUG9pbnRzID0gdGhpcy5zdG9yYWdlUGVyc2lzdGVuY2VTZXJ2aWNlLnJlYWQoXHJcbiAgICAgICAgICAgICAgJ2F1dGhXZWxsS25vd25FbmRQb2ludHMnLFxyXG4gICAgICAgICAgICAgIGNvbmZpZ3VyYXRpb25cclxuICAgICAgICAgICAgKTtcclxuICAgICAgICAgICAgY29uc3QgY29udGVudFdpbmRvdyA9IGV4aXN0aW5nSWZyYW1lLmNvbnRlbnRXaW5kb3c7XHJcblxyXG4gICAgICAgICAgICBpZiAoXHJcbiAgICAgICAgICAgICAgc2Vzc2lvblN0YXRlICYmXHJcbiAgICAgICAgICAgICAgYXV0aFdlbGxLbm93bkVuZFBvaW50cz8uY2hlY2tTZXNzaW9uSWZyYW1lICYmXHJcbiAgICAgICAgICAgICAgY29udGVudFdpbmRvd1xyXG4gICAgICAgICAgICApIHtcclxuICAgICAgICAgICAgICBjb25zdCBpZnJhbWVPcmlnaW4gPSBuZXcgVVJMKFxyXG4gICAgICAgICAgICAgICAgYXV0aFdlbGxLbm93bkVuZFBvaW50cy5jaGVja1Nlc3Npb25JZnJhbWVcclxuICAgICAgICAgICAgICApPy5vcmlnaW47XHJcblxyXG4gICAgICAgICAgICAgIHRoaXMub3V0c3RhbmRpbmdNZXNzYWdlcysrO1xyXG4gICAgICAgICAgICAgIGNvbnRlbnRXaW5kb3cucG9zdE1lc3NhZ2UoXHJcbiAgICAgICAgICAgICAgICBjbGllbnRJZCArICcgJyArIHNlc3Npb25TdGF0ZSxcclxuICAgICAgICAgICAgICAgIGlmcmFtZU9yaWdpblxyXG4gICAgICAgICAgICAgICk7XHJcbiAgICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgICAgdGhpcy5sb2dnZXJTZXJ2aWNlLmxvZ0RlYnVnKFxyXG4gICAgICAgICAgICAgICAgY29uZmlndXJhdGlvbixcclxuICAgICAgICAgICAgICAgIGBDaGVja1Nlc3Npb24gLSBzZXNzaW9uX3N0YXRlIGlzICcke3Nlc3Npb25TdGF0ZX0nIC0gQXV0aFdlbGxLbm93bkVuZFBvaW50cyBpcyAnJHtKU09OLnN0cmluZ2lmeShcclxuICAgICAgICAgICAgICAgICAgYXV0aFdlbGxLbm93bkVuZFBvaW50cyxcclxuICAgICAgICAgICAgICAgICAgbnVsbCxcclxuICAgICAgICAgICAgICAgICAgMlxyXG4gICAgICAgICAgICAgICAgKX0nYFxyXG4gICAgICAgICAgICAgICk7XHJcbiAgICAgICAgICAgICAgdGhpcy5jaGVja1Nlc3Npb25DaGFuZ2VkSW50ZXJuYWwkLm5leHQodHJ1ZSk7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgIHRoaXMubG9nZ2VyU2VydmljZS5sb2dXYXJuaW5nKFxyXG4gICAgICAgICAgICAgIGNvbmZpZ3VyYXRpb24sXHJcbiAgICAgICAgICAgICAgYENoZWNrU2Vzc2lvbiAtIE9pZGNTZWN1cml0eUNoZWNrU2Vzc2lvbiBwb2xsU2VydmVyU2Vzc2lvbiBjaGVja1Nlc3Npb24gSUZyYW1lIGRvZXMgbm90IGV4aXN0OlxyXG4gICAgICAgICAgICAgICBjbGllbnRJZCA6ICcke2NsaWVudElkfScgLSBleGlzdGluZ0lmcmFtZTogJyR7ZXhpc3RpbmdJZnJhbWV9J2BcclxuICAgICAgICAgICAgKTtcclxuICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAvLyBhZnRlciBzZW5kaW5nIHRocmVlIG1lc3NhZ2VzIHdpdGggbm8gcmVzcG9uc2UsIGZhaWwuXHJcbiAgICAgICAgICBpZiAodGhpcy5vdXRzdGFuZGluZ01lc3NhZ2VzID4gMykge1xyXG4gICAgICAgICAgICB0aGlzLmxvZ2dlclNlcnZpY2UubG9nRXJyb3IoXHJcbiAgICAgICAgICAgICAgY29uZmlndXJhdGlvbixcclxuICAgICAgICAgICAgICBgQ2hlY2tTZXNzaW9uIC0gT2lkY1NlY3VyaXR5Q2hlY2tTZXNzaW9uIG5vdCByZWNlaXZpbmcgY2hlY2sgc2Vzc2lvbiByZXNwb25zZSBtZXNzYWdlcy5cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIE91dHN0YW5kaW5nIG1lc3NhZ2VzOiAnJHt0aGlzLm91dHN0YW5kaW5nTWVzc2FnZXN9Jy4gU2VydmVyIHVucmVhY2hhYmxlP2BcclxuICAgICAgICAgICAgKTtcclxuICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICB0aGlzLnpvbmUucnVuT3V0c2lkZUFuZ3VsYXIoKCkgPT4ge1xyXG4gICAgICAgICAgICB0aGlzLnNjaGVkdWxlZEhlYXJ0QmVhdFJ1bm5pbmcgPVxyXG4gICAgICAgICAgICAgIHRoaXMuZG9jdW1lbnQ/LmRlZmF1bHRWaWV3Py5zZXRUaW1lb3V0KFxyXG4gICAgICAgICAgICAgICAgKCkgPT4gdGhpcy56b25lLnJ1bihwb2xsU2VydmVyU2Vzc2lvblJlY3VyKSxcclxuICAgICAgICAgICAgICAgIHRoaXMuaGVhcnRCZWF0SW50ZXJ2YWxcclxuICAgICAgICAgICAgICApID8/IG51bGw7XHJcbiAgICAgICAgICB9KTtcclxuICAgICAgICB9KTtcclxuICAgIH07XHJcblxyXG4gICAgcG9sbFNlcnZlclNlc3Npb25SZWN1cigpO1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBjbGVhclNjaGVkdWxlZEhlYXJ0QmVhdCgpOiB2b2lkIHtcclxuICAgIGlmICh0aGlzLnNjaGVkdWxlZEhlYXJ0QmVhdFJ1bm5pbmcgIT09IG51bGwpIHtcclxuICAgICAgY2xlYXJUaW1lb3V0KHRoaXMuc2NoZWR1bGVkSGVhcnRCZWF0UnVubmluZyk7XHJcbiAgICAgIHRoaXMuc2NoZWR1bGVkSGVhcnRCZWF0UnVubmluZyA9IG51bGw7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIG1lc3NhZ2VIYW5kbGVyKGNvbmZpZ3VyYXRpb246IE9wZW5JZENvbmZpZ3VyYXRpb24sIGU6IGFueSk6IHZvaWQge1xyXG4gICAgY29uc3QgZXhpc3RpbmdJRnJhbWUgPSB0aGlzLmdldEV4aXN0aW5nSWZyYW1lKCk7XHJcbiAgICBjb25zdCBhdXRoV2VsbEtub3duRW5kUG9pbnRzID0gdGhpcy5zdG9yYWdlUGVyc2lzdGVuY2VTZXJ2aWNlLnJlYWQoXHJcbiAgICAgICdhdXRoV2VsbEtub3duRW5kUG9pbnRzJyxcclxuICAgICAgY29uZmlndXJhdGlvblxyXG4gICAgKTtcclxuICAgIGNvbnN0IHN0YXJ0c1dpdGggPSAhIWF1dGhXZWxsS25vd25FbmRQb2ludHM/LmNoZWNrU2Vzc2lvbklmcmFtZT8uc3RhcnRzV2l0aChcclxuICAgICAgZS5vcmlnaW5cclxuICAgICk7XHJcblxyXG4gICAgdGhpcy5vdXRzdGFuZGluZ01lc3NhZ2VzID0gMDtcclxuXHJcbiAgICBpZiAoXHJcbiAgICAgIGV4aXN0aW5nSUZyYW1lICYmXHJcbiAgICAgIHN0YXJ0c1dpdGggJiZcclxuICAgICAgZS5zb3VyY2UgPT09IGV4aXN0aW5nSUZyYW1lLmNvbnRlbnRXaW5kb3dcclxuICAgICkge1xyXG4gICAgICBpZiAoZS5kYXRhID09PSAnZXJyb3InKSB7XHJcbiAgICAgICAgdGhpcy5sb2dnZXJTZXJ2aWNlLmxvZ1dhcm5pbmcoXHJcbiAgICAgICAgICBjb25maWd1cmF0aW9uLFxyXG4gICAgICAgICAgJ0NoZWNrU2Vzc2lvbiAtIGVycm9yIGZyb20gY2hlY2sgc2Vzc2lvbiBtZXNzYWdlSGFuZGxlcidcclxuICAgICAgICApO1xyXG4gICAgICB9IGVsc2UgaWYgKGUuZGF0YSA9PT0gJ2NoYW5nZWQnKSB7XHJcbiAgICAgICAgdGhpcy5sb2dnZXJTZXJ2aWNlLmxvZ0RlYnVnKFxyXG4gICAgICAgICAgY29uZmlndXJhdGlvbixcclxuICAgICAgICAgIGBDaGVja1Nlc3Npb24gLSAke2V9IGZyb20gY2hlY2sgc2Vzc2lvbiBtZXNzYWdlSGFuZGxlcmBcclxuICAgICAgICApO1xyXG4gICAgICAgIHRoaXMuY2hlY2tTZXNzaW9uUmVjZWl2ZWQgPSB0cnVlO1xyXG4gICAgICAgIHRoaXMuZXZlbnRTZXJ2aWNlLmZpcmVFdmVudChFdmVudFR5cGVzLkNoZWNrU2Vzc2lvblJlY2VpdmVkLCBlLmRhdGEpO1xyXG4gICAgICAgIHRoaXMuY2hlY2tTZXNzaW9uQ2hhbmdlZEludGVybmFsJC5uZXh0KHRydWUpO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIHRoaXMuZXZlbnRTZXJ2aWNlLmZpcmVFdmVudChFdmVudFR5cGVzLkNoZWNrU2Vzc2lvblJlY2VpdmVkLCBlLmRhdGEpO1xyXG4gICAgICAgIHRoaXMubG9nZ2VyU2VydmljZS5sb2dEZWJ1ZyhcclxuICAgICAgICAgIGNvbmZpZ3VyYXRpb24sXHJcbiAgICAgICAgICBgQ2hlY2tTZXNzaW9uIC0gJHtlLmRhdGF9IGZyb20gY2hlY2sgc2Vzc2lvbiBtZXNzYWdlSGFuZGxlcmBcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIGJpbmRNZXNzYWdlRXZlbnRUb0lmcmFtZShjb25maWd1cmF0aW9uOiBPcGVuSWRDb25maWd1cmF0aW9uKTogdm9pZCB7XHJcbiAgICB0aGlzLmlmcmFtZU1lc3NhZ2VFdmVudExpc3RlbmVyID0gdGhpcy5tZXNzYWdlSGFuZGxlci5iaW5kKFxyXG4gICAgICB0aGlzLFxyXG4gICAgICBjb25maWd1cmF0aW9uXHJcbiAgICApO1xyXG5cclxuICAgIGNvbnN0IGRlZmF1bHRWaWV3ID0gdGhpcy5kb2N1bWVudC5kZWZhdWx0VmlldztcclxuXHJcbiAgICBpZiAoZGVmYXVsdFZpZXcpIHtcclxuICAgICAgZGVmYXVsdFZpZXcuYWRkRXZlbnRMaXN0ZW5lcihcclxuICAgICAgICAnbWVzc2FnZScsXHJcbiAgICAgICAgdGhpcy5pZnJhbWVNZXNzYWdlRXZlbnRMaXN0ZW5lcixcclxuICAgICAgICBmYWxzZVxyXG4gICAgICApO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBnZXRPckNyZWF0ZUlmcmFtZShcclxuICAgIGNvbmZpZ3VyYXRpb246IE9wZW5JZENvbmZpZ3VyYXRpb25cclxuICApOiBIVE1MSUZyYW1lRWxlbWVudCB7XHJcbiAgICByZXR1cm4gKFxyXG4gICAgICB0aGlzLmdldEV4aXN0aW5nSWZyYW1lKCkgfHxcclxuICAgICAgdGhpcy5pRnJhbWVTZXJ2aWNlLmFkZElGcmFtZVRvV2luZG93Qm9keShcclxuICAgICAgICBJRlJBTUVfRk9SX0NIRUNLX1NFU1NJT05fSURFTlRJRklFUixcclxuICAgICAgICBjb25maWd1cmF0aW9uXHJcbiAgICAgIClcclxuICAgICk7XHJcbiAgfVxyXG59XHJcbiJdfQ==