UNPKG

@spartacus/core

Version:

Spartacus - the core framework

248 lines 36.9 kB
import { Injectable } from '@angular/core'; import { combineLatest, defer, EMPTY, queueScheduler, Subject, Subscription, using, } from 'rxjs'; import { filter, map, observeOn, pairwise, shareReplay, skipWhile, switchMap, take, tap, withLatestFrom, } from 'rxjs/operators'; import { GlobalMessageType } from '../../../global-message/models/global-message.model'; import * as i0 from "@angular/core"; import * as i1 from "../facade/auth.service"; import * as i2 from "./auth-storage.service"; import * as i3 from "./oauth-lib-wrapper.service"; import * as i4 from "../../../routing/facade/routing.service"; import * as i5 from "../../../occ/services/occ-endpoints.service"; import * as i6 from "../../../global-message/facade/global-message.service"; import * as i7 from "./auth-redirect.service"; /** * Extendable service for `AuthInterceptor`. */ export class AuthHttpHeaderService { constructor(authService, authStorageService, oAuthLibWrapperService, routingService, occEndpoints, globalMessageService, authRedirectService) { this.authService = authService; this.authStorageService = authStorageService; this.oAuthLibWrapperService = oAuthLibWrapperService; this.routingService = routingService; this.occEndpoints = occEndpoints; this.globalMessageService = globalMessageService; this.authRedirectService = authRedirectService; /** * Indicates whether the access token is being refreshed * * @deprecated will be removed in the next major. Use `AuthService.refreshInProgress$` instead. */ // TODO:#13421 - legacy, remove this flag this.refreshInProgress = false; /** * Starts the refresh of the access token */ this.refreshTokenTrigger$ = new Subject(); /** * Internal token streams which reads the latest from the storage. * Emits the token or `undefined` */ this.token$ = this.authStorageService .getToken() .pipe(map((token) => ((token === null || token === void 0 ? void 0 : token.access_token) ? token : undefined))); /** * Compares the previous and the new token in order to stop the refresh or logout processes */ this.stopProgress$ = this.token$.pipe( // Keeps the previous and the new token pairwise(), tap(([oldToken, newToken]) => { // if we got the new token we know that either the refresh or logout finished if ((oldToken === null || oldToken === void 0 ? void 0 : oldToken.access_token) !== (newToken === null || newToken === void 0 ? void 0 : newToken.access_token)) { this.authService.setLogoutProgress(false); this.authService.setRefreshProgress(false); } })); /** * Refreshes the token only if currently there's no refresh nor logout in progress. * If the refresh token is not present, it triggers the logout process */ this.refreshToken$ = this.refreshTokenTrigger$.pipe(withLatestFrom(this.authService.refreshInProgress$, this.authService.logoutInProgress$), filter(([, refreshInProgress, logoutInProgress]) => !refreshInProgress && !logoutInProgress), tap(([token]) => { if (token === null || token === void 0 ? void 0 : token.refresh_token) { this.oAuthLibWrapperService.refreshToken(); this.authService.setRefreshProgress(true); } else { this.handleExpiredRefreshToken(); } })); /** * Kicks of the process by listening to the new token and refresh token processes. * This token should be used when retrying the failed http request. */ this.tokenToRetryRequest$ = using(() => this.refreshToken$.subscribe(), () => this.getStableToken()).pipe(shareReplay({ refCount: true, bufferSize: 1 })); this.subscriptions = new Subscription(); // We need to have stopProgress$ stream active for the whole time, // so when the logout finishes we finish it's process. // It could happen when retryToken$ is not active. this.subscriptions.add(this.stopProgress$.subscribe()); } /** * Checks if request should be handled by this service (if it's OCC call). */ shouldCatchError(request) { return this.isOccUrl(request.url); } shouldAddAuthorizationHeader(request) { const hasAuthorizationHeader = !!this.getAuthorizationHeader(request); const isOccUrl = this.isOccUrl(request.url); return !hasAuthorizationHeader && isOccUrl; } /** * Adds `Authorization` header for OCC calls. */ alterRequest(request, token) { const hasAuthorizationHeader = !!this.getAuthorizationHeader(request); const isOccUrl = this.isOccUrl(request.url); if (!hasAuthorizationHeader && isOccUrl) { return request.clone({ setHeaders: Object.assign({}, this.createAuthorizationHeader(token)), }); } return request; } isOccUrl(url) { return url.includes(this.occEndpoints.getBaseUrl()); } getAuthorizationHeader(request) { const rawValue = request.headers.get('Authorization'); return rawValue; } createAuthorizationHeader(token) { if (token === null || token === void 0 ? void 0 : token.access_token) { return { Authorization: `${token.token_type || 'Bearer'} ${token.access_token}`, }; } let currentToken; this.authStorageService .getToken() .subscribe((token) => (currentToken = token)) .unsubscribe(); if (currentToken === null || currentToken === void 0 ? void 0 : currentToken.access_token) { return { Authorization: `${currentToken.token_type || 'Bearer'} ${currentToken.access_token}`, }; } return {}; } /** * Refreshes access_token and then retries the call with the new token. */ handleExpiredAccessToken(request, next, // TODO:#13421 make required initialToken) { // TODO:#13421 remove this if-statement, and just return the stream. if (initialToken) { return this.getValidToken(initialToken).pipe(switchMap((token) => // we break the stream with EMPTY when we don't have the token. This prevents sending the requests with `Authorization: bearer undefined` header token ? next.handle(this.createNewRequestWithNewToken(request, token)) : EMPTY)); } // TODO:#13421 legacy - remove in 5.0 return this.handleExpiredToken().pipe(switchMap((token) => { return token ? next.handle(this.createNewRequestWithNewToken(request, token)) : EMPTY; })); } /** * Logout user, redirected to login page and informs about expired session. */ handleExpiredRefreshToken() { // There might be 2 cases: // 1. when user is already on some page (router is stable) and performs an UI action // that triggers http call (i.e. button click to save data in backend) // 2. when user is navigating to some page and a route guard triggers the http call // (i.e. guard loading cms page data) // // In the second case, we want to remember the anticipated url before we navigate to // the login page, so we can redirect back to that URL after user authenticates. this.authRedirectService.saveCurrentNavigationUrl(); // Logout user // TODO(#9638): Use logout route when it will support passing redirect url this.authService.coreLogout().finally(() => { this.routingService.go({ cxRoute: 'login' }); this.globalMessageService.add({ key: 'httpHandlers.sessionExpired', }, GlobalMessageType.MSG_TYPE_ERROR); }); } // TODO:#13421 - remove this method /** * Attempts to refresh token if possible. * If it is not possible calls `handleExpiredRefreshToken`. * * @return observable which omits new access_token. (Warn: might never emit!). * * @deprecated will be removed in the next major. Use `getValidToken()` instead */ handleExpiredToken() { const stream = this.authStorageService.getToken(); let oldToken; return stream.pipe(tap((token) => { if (token.access_token && token.refresh_token && !oldToken && !this.refreshInProgress) { this.refreshInProgress = true; this.oAuthLibWrapperService.refreshToken(); } else if (!token.refresh_token) { this.handleExpiredRefreshToken(); } oldToken = oldToken || token; }), filter((token) => oldToken.access_token !== token.access_token), tap(() => { this.refreshInProgress = false; }), map((token) => ((token === null || token === void 0 ? void 0 : token.access_token) ? token : undefined)), take(1)); } /** * Emits the token or `undefined` only when the refresh or the logout processes are finished. */ getStableToken() { return combineLatest([ this.token$, this.authService.refreshInProgress$, this.authService.logoutInProgress$, ]).pipe(observeOn(queueScheduler), filter(([_, refreshInProgress, logoutInProgress]) => !refreshInProgress && !logoutInProgress), switchMap(() => this.token$)); } /** * Returns a valid access token. * It will attempt to refresh it if the current one expired; emits after the new one is retrieved. */ getValidToken(requestToken) { return defer(() => { // flag to only refresh token only on first emission let refreshTriggered = false; return this.tokenToRetryRequest$.pipe(tap((token) => { // we want to refresh the access token only when it is old. // this is a guard for the case when there are multiple parallel http calls if ((token === null || token === void 0 ? void 0 : token.access_token) === (requestToken === null || requestToken === void 0 ? void 0 : requestToken.access_token) && !refreshTriggered) { this.refreshTokenTrigger$.next(token); } refreshTriggered = true; }), skipWhile((token) => (token === null || token === void 0 ? void 0 : token.access_token) === requestToken.access_token), take(1)); }); } createNewRequestWithNewToken(request, token) { request = request.clone({ setHeaders: { Authorization: `${token.token_type || 'Bearer'} ${token.access_token}`, }, }); return request; } ngOnDestroy() { this.subscriptions.unsubscribe(); } } AuthHttpHeaderService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.0.5", ngImport: i0, type: AuthHttpHeaderService, deps: [{ token: i1.AuthService }, { token: i2.AuthStorageService }, { token: i3.OAuthLibWrapperService }, { token: i4.RoutingService }, { token: i5.OccEndpointsService }, { token: i6.GlobalMessageService }, { token: i7.AuthRedirectService }], target: i0.ɵɵFactoryTarget.Injectable }); AuthHttpHeaderService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "12.0.5", ngImport: i0, type: AuthHttpHeaderService, providedIn: 'root' }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.0.5", ngImport: i0, type: AuthHttpHeaderService, decorators: [{ type: Injectable, args: [{ providedIn: 'root', }] }], ctorParameters: function () { return [{ type: i1.AuthService }, { type: i2.AuthStorageService }, { type: i3.OAuthLibWrapperService }, { type: i4.RoutingService }, { type: i5.OccEndpointsService }, { type: i6.GlobalMessageService }, { type: i7.AuthRedirectService }]; } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXV0aC1odHRwLWhlYWRlci5zZXJ2aWNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvY29yZS9zcmMvYXV0aC91c2VyLWF1dGgvc2VydmljZXMvYXV0aC1odHRwLWhlYWRlci5zZXJ2aWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUNBLE9BQU8sRUFBRSxVQUFVLEVBQWEsTUFBTSxlQUFlLENBQUM7QUFDdEQsT0FBTyxFQUNMLGFBQWEsRUFDYixLQUFLLEVBQ0wsS0FBSyxFQUVMLGNBQWMsRUFDZCxPQUFPLEVBQ1AsWUFBWSxFQUNaLEtBQUssR0FDTixNQUFNLE1BQU0sQ0FBQztBQUNkLE9BQU8sRUFDTCxNQUFNLEVBQ04sR0FBRyxFQUNILFNBQVMsRUFDVCxRQUFRLEVBQ1IsV0FBVyxFQUNYLFNBQVMsRUFDVCxTQUFTLEVBQ1QsSUFBSSxFQUNKLEdBQUcsRUFDSCxjQUFjLEdBQ2YsTUFBTSxnQkFBZ0IsQ0FBQztBQUV4QixPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSxxREFBcUQsQ0FBQzs7Ozs7Ozs7O0FBU3hGOztHQUVHO0FBSUgsTUFBTSxPQUFPLHFCQUFxQjtJQXVFaEMsWUFDWSxXQUF3QixFQUN4QixrQkFBc0MsRUFDdEMsc0JBQThDLEVBQzlDLGNBQThCLEVBQzlCLFlBQWlDLEVBQ2pDLG9CQUEwQyxFQUMxQyxtQkFBd0M7UUFOeEMsZ0JBQVcsR0FBWCxXQUFXLENBQWE7UUFDeEIsdUJBQWtCLEdBQWxCLGtCQUFrQixDQUFvQjtRQUN0QywyQkFBc0IsR0FBdEIsc0JBQXNCLENBQXdCO1FBQzlDLG1CQUFjLEdBQWQsY0FBYyxDQUFnQjtRQUM5QixpQkFBWSxHQUFaLFlBQVksQ0FBcUI7UUFDakMseUJBQW9CLEdBQXBCLG9CQUFvQixDQUFzQjtRQUMxQyx3QkFBbUIsR0FBbkIsbUJBQW1CLENBQXFCO1FBN0VwRDs7OztXQUlHO1FBQ0gseUNBQXlDO1FBQy9CLHNCQUFpQixH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QUMzRCwyRUFBMkU7Z0JBQzNFLElBQ0UsQ0FBQSxLQUFLLGFBQUwsS0FBSyx1QkFBTCxLQUFLLENBQUUsWUFBWSxPQUFLLFlBQVksYUFBWixZQUFZLHVCQUFaLFlBQVksQ0FBRSxZQUFZLENBQUE7b0JBQ2xELENBQUMsZ0JBQWdCLEVBQ2pCO29CQUNBLElBQUksQ0FBQyxvQkFBb0IsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUM7aUJBQ3ZDO2dCQUNELGdCQUFnQixHQUFHLElBQUksQ0FBQztZQUMxQixDQUFDLENBQUMsRUFDRixTQUFTLENBQUMsQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDLENBQUEsS0FBSyxhQUFMLEtBQUssdUJBQUwsS0FBSyxDQUFFLFlBQVksTUFBSyxZQUFZLENBQUMsWUFBWSxDQUFDLEVBQ3ZFLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FDUixDQUFDO1FBQ0osQ0FBQyxDQUFDLENBQUM7SUFDTCxDQUFDO0lBRVMsNEJBQTRCLENBQ3BDLE9BQXlCLEVBQ3pCLEtBQWdCO1FBRWhCLE9BQU8sR0FBRyxPQUFPLENBQUMsS0FBSyxDQUFDO1lBQ3RCLFVBQVUsRUFBRTtnQkFDVixhQUFhLEVBQUUsR0FBRyxLQUFLLENBQUMsVUFBVSxJQUFJLFFBQVEsSUFBSSxLQUFLLENBQUMsWUFBWSxFQUFFO2FBQ3ZFO1NBQ0YsQ0FBQyxDQUFDO1FBQ0gsT0FBTyxPQUFPLENBQUM7SUFDakIsQ0FBQztJQUVELFdBQVc7UUFDVCxJQUFJLENBQUMsYUFBYSxDQUFDLFdBQVcsRUFBRSxDQUFDO0lBQ25DLENBQUM7O2tIQWxUVSxxQkFBcUI7c0hBQXJCLHFCQUFxQixjQUZwQixNQUFNOzJGQUVQLHFCQUFxQjtrQkFIakMsVUFBVTttQkFBQztvQkFDVixVQUFVLEVBQUUsTUFBTTtpQkFDbkIiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBIdHRwRXZlbnQsIEh0dHBIYW5kbGVyLCBIdHRwUmVxdWVzdCB9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbi9odHRwJztcbmltcG9ydCB7IEluamVjdGFibGUsIE9uRGVzdHJveSB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHtcbiAgY29tYmluZUxhdGVzdCxcbiAgZGVmZXIsXG4gIEVNUFRZLFxuICBPYnNlcnZhYmxlLFxuICBxdWV1ZVNjaGVkdWxlcixcbiAgU3ViamVjdCxcbiAgU3Vic2NyaXB0aW9uLFxuICB1c2luZyxcbn0gZnJvbSAncnhqcyc7XG5pbXBvcnQge1xuICBmaWx0ZXIsXG4gIG1hcCxcbiAgb2JzZXJ2ZU9uLFxuICBwYWlyd2lzZSxcbiAgc2hhcmVSZXBsYXksXG4gIHNraXBXaGlsZSxcbiAgc3dpdGNoTWFwLFxuICB0YWtlLFxuICB0YXAsXG4gIHdpdGhMYXRlc3RGcm9tLFxufSBmcm9tICdyeGpzL29wZXJhdG9ycyc7XG5pbXBvcnQgeyBHbG9iYWxNZXNzYWdlU2VydmljZSB9IGZyb20gJy4uLy4uLy4uL2dsb2JhbC1tZXNzYWdlL2ZhY2FkZS9nbG9iYWwtbWVzc2FnZS5zZXJ2aWNlJztcbmltcG9ydCB7IEdsb2JhbE1lc3NhZ2VUeXBlIH0gZnJvbSAnLi4vLi4vLi4vZ2xvYmFsLW1lc3NhZ2UvbW9kZWxzL2dsb2JhbC1tZXNzYWdlLm1vZGVsJztcbmltcG9ydCB7IE9jY0VuZHBvaW50c1NlcnZpY2UgfSBmcm9tICcuLi8uLi8uLi9vY2Mvc2VydmljZXMvb2NjLWVuZHBvaW50cy5zZXJ2aWNlJztcbmltcG9ydCB7IFJvdXRpbmdTZXJ2aWNlIH0gZnJvbSAnLi4vLi4vLi4vcm91dGluZy9mYWNhZGUvcm91dGluZy5zZXJ2aWNlJztcbmltcG9ydCB7IEF1dGhTZXJ2aWNlIH0gZnJvbSAnLi4vZmFjYWRlL2F1dGguc2VydmljZSc7XG5pbXBvcnQgeyBBdXRoVG9rZW4gfSBmcm9tICcuLi9tb2RlbHMvYXV0aC10b2tlbi5tb2RlbCc7XG5pbXBvcnQgeyBBdXRoUmVkaXJlY3RTZXJ2aWNlIH0gZnJvbSAnLi9hdXRoLXJlZGlyZWN0LnNlcnZpY2UnO1xuaW1wb3J0IHsgQXV0aFN0b3JhZ2VTZXJ2aWNlIH0gZnJvbSAnLi9hdXRoLXN0b3JhZ2Uuc2VydmljZSc7XG5pbXBvcnQgeyBPQXV0aExpYldyYXBwZXJTZXJ2aWNlIH0gZnJvbSAnLi9vYXV0aC1saWItd3JhcHBlci5zZXJ2aWNlJztcblxuLyoqXG4gKiBFeHRlbmRhYmxlIHNlcnZpY2UgZm9yIGBBdXRoSW50ZXJjZXB0b3JgLlxuICovXG5ASW5qZWN0YWJsZSh7XG4gIHByb3ZpZGVkSW46ICdyb290Jyxcbn0pXG5leHBvcnQgY2xhc3MgQXV0aEh0dHBIZWFkZXJTZXJ2aWNlIGltcGxlbWVudHMgT25EZXN0cm95IHtcbiAgLyoqXG4gICAqIEluZGljYXRlcyB3aGV0aGVyIHRoZSBhY2Nlc3MgdG9rZW4gaXMgYmVpbmcgcmVmcmVzaGVkXG4gICAqXG4gICAqIEBkZXByZWNhdGVkIHdpbGwgYmUgcmVtb3ZlZCBpbiB0aGUgbmV4dCBtYWpvci4gVXNlIGBBdXRoU2VydmljZS5yZWZyZXNoSW5Qcm9ncmVzcyRgIGluc3RlYWQuXG4gICAqL1xuICAvLyBUT0RPOiMxMzQyMSAtIGxlZ2FjeSwgcmVtb3ZlIHRoaXMgZmxhZ1xuICBwcm90ZWN0ZWQgcmVmcmVzaEluUHJvZ3Jlc3MgPSBmYWxzZTtcblxuICAvKipcbiAgICogU3RhcnRzIHRoZSByZWZyZXNoIG9mIHRoZSBhY2Nlc3MgdG9rZW5cbiAgICovXG4gIHByb3RlY3RlZCByZWZyZXNoVG9rZW5UcmlnZ2VyJCA9IG5ldyBTdWJqZWN0PEF1dGhUb2tlbj4oKTtcblxuICAvKipcbiAgICogSW50ZXJuYWwgdG9rZW4gc3RyZWFtcyB3aGljaCByZWFkcyB0aGUgbGF0ZXN0IGZyb20gdGhlIHN0b3JhZ2UuXG4gICAqIEVtaXRzIHRoZSB0b2tlbiBvciBgdW5kZWZpbmVkYFxuICAgKi9cbiAgcHJvdGVjdGVkIHRva2VuJDogT2JzZXJ2YWJsZTxBdXRoVG9rZW4gfCB1bmRlZmluZWQ+ID0gdGhpcy5hdXRoU3RvcmFnZVNlcnZpY2VcbiAgICAuZ2V0VG9rZW4oKVxuICAgIC5waXBlKG1hcCgodG9rZW4pID0+ICh0b2tlbj8uYWNjZXNzX3Rva2VuID8gdG9rZW4gOiB1bmRlZmluZWQpKSk7XG5cbiAgLyoqXG4gICAqIENvbXBhcmVzIHRoZSBwcmV2aW91cyBhbmQgdGhlIG5ldyB0b2tlbiBpbiBvcmRlciB0byBzdG9wIHRoZSByZWZyZXNoIG9yIGxvZ291dCBwcm9jZXNzZXNcbiAgICovXG4gIHByb3RlY3RlZCBzdG9wUHJvZ3Jlc3MkID0gdGhpcy50b2tlbiQucGlwZShcbiAgICAvLyBLZWVwcyB0aGUgcHJldmlvdXMgYW5kIHRoZSBuZXcgdG9rZW5cbiAgICBwYWlyd2lzZSgpLFxuICAgIHRhcCgoW29sZFRva2VuLCBuZXdUb2tlbl0pID0+IHtcbiAgICAgIC8vIGlmIHdlIGdvdCB0aGUgbmV3IHRva2VuIHdlIGtub3cgdGhhdCBlaXRoZXIgdGhlIHJlZnJlc2ggb3IgbG9nb3V0IGZpbmlzaGVkXG4gICAgICBpZiAob2xkVG9rZW4/LmFjY2Vzc190b2tlbiAhPT0gbmV3VG9rZW4/LmFjY2Vzc190b2tlbikge1xuICAgICAgICB0aGlzLmF1dGhTZXJ2aWNlLnNldExvZ291dFByb2dyZXNzKGZhbHNlKTtcbiAgICAgICAgdGhpcy5hdXRoU2VydmljZS5zZXRSZWZyZXNoUHJvZ3Jlc3MoZmFsc2UpO1xuICAgICAgfVxuICAgIH0pXG4gICk7XG5cbiAgLyoqXG4gICAqIFJlZnJlc2hlcyB0aGUgdG9rZW4gb25seSBpZiBjdXJyZW50bHkgdGhlcmUncyBubyByZWZyZXNoIG5vciBsb2dvdXQgaW4gcHJvZ3Jlc3MuXG4gICAqIElmIHRoZSByZWZyZXNoIHRva2VuIGlzIG5vdCBwcmVzZW50LCBpdCB0cmlnZ2VycyB0aGUgbG9nb3V0IHByb2Nlc3NcbiAgICovXG4gIHByb3RlY3RlZCByZWZyZXNoVG9rZW4kID0gdGhpcy5yZWZyZXNoVG9rZW5UcmlnZ2VyJC5waXBlKFxuICAgIHdpdGhMYXRlc3RGcm9tKFxuICAgICAgdGhpcy5hdXRoU2VydmljZS5yZWZyZXNoSW5Qcm9ncmVzcyQsXG4gICAgICB0aGlzLmF1dGhTZXJ2aWNlLmxvZ291dEluUHJvZ3Jlc3MkXG4gICAgKSxcbiAgICBmaWx0ZXIoXG4gICAgICAoWywgcmVmcmVzaEluUHJvZ3Jlc3MsIGxvZ291dEluUHJvZ3Jlc3NdKSA9PlxuICAgICAgICAhcmVmcmVzaEluUHJvZ3Jlc3MgJiYgIWxvZ291dEluUHJvZ3Jlc3NcbiAgICApLFxuICAgIHRhcCgoW3Rva2VuXSkgPT4ge1xuICAgICAgaWYgKHRva2VuPy5yZWZyZXNoX3Rva2VuKSB7XG4gICAgICAgIHRoaXMub0F1dGhMaWJXcmFwcGVyU2VydmljZS5yZWZyZXNoVG9rZW4oKTtcbiAgICAgICAgdGhpcy5hdXRoU2VydmljZS5zZXRSZWZyZXNoUHJvZ3Jlc3ModHJ1ZSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0aGlzLmhhbmRsZUV4cGlyZWRSZWZyZXNoVG9rZW4oKTtcbiAgICAgIH1cbiAgICB9KVxuICApO1xuXG4gIC8qKlxuICAgKiBLaWNrcyBvZiB0aGUgcHJvY2VzcyBieSBsaXN0ZW5pbmcgdG8gdGhlIG5ldyB0b2tlbiBhbmQgcmVmcmVzaCB0b2tlbiBwcm9jZXNzZXMuXG4gICAqIFRoaXMgdG9rZW4gc2hvdWxkIGJlIHVzZWQgd2hlbiByZXRyeWluZyB0aGUgZmFpbGVkIGh0dHAgcmVxdWVzdC5cbiAgICovXG4gIHByb3RlY3RlZCB0b2tlblRvUmV0cnlSZXF1ZXN0JCA9IHVzaW5nKFxuICAgICgpID0+IHRoaXMucmVmcmVzaFRva2VuJC5zdWJzY3JpYmUoKSxcbiAgICAoKSA9PiB0aGlzLmdldFN0YWJsZVRva2VuKClcbiAgKS5waXBlKHNoYXJlUmVwbGF5KHsgcmVmQ291bnQ6IHRydWUsIGJ1ZmZlclNpemU6IDEgfSkpO1xuXG4gIHByb3RlY3RlZCBzdWJzY3JpcHRpb25zID0gbmV3IFN1YnNjcmlwdGlvbigpO1xuXG4gIGNvbnN0cnVjdG9yKFxuICAgIHByb3RlY3RlZCBhdXRoU2VydmljZTogQXV0aFNlcnZpY2UsXG4gICAgcHJvdGVjdGVkIGF1dGhTdG9yYWdlU2VydmljZTogQXV0aFN0b3JhZ2VTZXJ2aWNlLFxuICAgIHByb3RlY3RlZCBvQXV0aExpYldyYXBwZXJTZXJ2aWNlOiBPQXV0aExpYldyYXBwZXJTZXJ2aWNlLFxuICAgIHByb3RlY3RlZCByb3V0aW5nU2VydmljZTogUm91dGluZ1NlcnZpY2UsXG4gICAgcHJvdGVjdGVkIG9jY0VuZHBvaW50czogT2NjRW5kcG9pbnRzU2VydmljZSxcbiAgICBwcm90ZWN0ZWQgZ2xvYmFsTWVzc2FnZVNlcnZpY2U6IEdsb2JhbE1lc3NhZ2VTZXJ2aWNlLFxuICAgIHByb3RlY3RlZCBhdXRoUmVkaXJlY3RTZXJ2aWNlOiBBdXRoUmVkaXJlY3RTZXJ2aWNlXG4gICkge1xuICAgIC8vIFdlIG5lZWQgdG8gaGF2ZSBzdG9wUHJvZ3Jlc3MkIHN0cmVhbSBhY3RpdmUgZm9yIHRoZSB3aG9sZSB0aW1lLFxuICAgIC8vIHNvIHdoZW4gdGhlIGxvZ291dCBmaW5pc2hlcyB3ZSBmaW5pc2ggaXQncyBwcm9jZXNzLlxuICAgIC8vIEl0IGNvdWxkIGhhcHBlbiB3aGVuIHJldHJ5VG9rZW4kIGlzIG5vdCBhY3RpdmUuXG4gICAgdGhpcy5zdWJzY3JpcHRpb25zLmFkZCh0aGlzLnN0b3BQcm9ncmVzcyQuc3Vic2NyaWJlKCkpO1xuICB9XG5cbiAgLyoqXG4gICAqIENoZWNrcyBpZiByZXF1ZXN0IHNob3VsZCBiZSBoYW5kbGVkIGJ5IHRoaXMgc2VydmljZSAoaWYgaXQncyBPQ0MgY2FsbCkuXG4gICAqL1xuICBwdWJsaWMgc2hvdWxkQ2F0Y2hFcnJvcihyZXF1ZXN0OiBIdHRwUmVxdWVzdDxhbnk+KTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMuaXNPY2NVcmwocmVxdWVzdC51cmwpO1xuICB9XG5cbiAgcHVibGljIHNob3VsZEFkZEF1dGhvcml6YXRpb25IZWFkZXIocmVxdWVzdDogSHR0cFJlcXVlc3Q8YW55Pik6IGJvb2xlYW4ge1xuICAgIGNvbnN0IGhhc0F1dGhvcml6YXRpb25IZWFkZXIgPSAhIXRoaXMuZ2V0QXV0aG9yaXphdGlvbkhlYWRlcihyZXF1ZXN0KTtcbiAgICBjb25zdCBpc09jY1VybCA9IHRoaXMuaXNPY2NVcmwocmVxdWVzdC51cmwpO1xuICAgIHJldHVybiAhaGFzQXV0aG9yaXphdGlvbkhlYWRlciAmJiBpc09jY1VybDtcbiAgfVxuXG4gIC8qKlxuICAgKiBBZGRzIGBBdXRob3JpemF0aW9uYCBoZWFkZXIgZm9yIE9DQyBjYWxscy5cbiAgICovXG4gIHB1YmxpYyBhbHRlclJlcXVlc3QoXG4gICAgcmVxdWVzdDogSHR0cFJlcXVlc3Q8YW55PixcbiAgICB0b2tlbj86IEF1dGhUb2tlblxuICApOiBIdHRwUmVxdWVzdDxhbnk+IHtcbiAgICBjb25zdCBoYXNBdXRob3JpemF0aW9uSGVhZGVyID0gISF0aGlzLmdldEF1dGhvcml6YXRpb25IZWFkZXIocmVxdWVzdCk7XG4gICAgY29uc3QgaXNPY2NVcmwgPSB0aGlzLmlzT2NjVXJsKHJlcXVlc3QudXJsKTtcbiAgICBpZiAoIWhhc0F1dGhvcml6YXRpb25IZWFkZXIgJiYgaXNPY2NVcmwpIHtcbiAgICAgIHJldHVybiByZXF1ZXN0LmNsb25lKHtcbiAgICAgICAgc2V0SGVhZGVyczoge1xuICAgICAgICAgIC4uLnRoaXMuY3JlYXRlQXV0aG9yaXphdGlvbkhlYWRlcih0b2tlbiksXG4gICAgICAgIH0sXG4gICAgICB9KTtcbiAgICB9XG4gICAgcmV0dXJuIHJlcXVlc3Q7XG4gIH1cblxuICBwcm90ZWN0ZWQgaXNPY2NVcmwodXJsOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdXJsLmluY2x1ZGVzKHRoaXMub2NjRW5kcG9pbnRzLmdldEJhc2VVcmwoKSk7XG4gIH1cblxuICBwcm90ZWN0ZWQgZ2V0QXV0aG9yaXphdGlvbkhlYWRlcihyZXF1ZXN0OiBIdHRwUmVxdWVzdDxhbnk+KTogc3RyaW5nIHwgbnVsbCB7XG4gICAgY29uc3QgcmF3VmFsdWUgPSByZXF1ZXN0LmhlYWRlcnMuZ2V0KCdBdXRob3JpemF0aW9uJyk7XG4gICAgcmV0dXJuIHJhd1ZhbHVlO1xuICB9XG5cbiAgcHJvdGVjdGVkIGNyZWF0ZUF1dGhvcml6YXRpb25IZWFkZXIoXG4gICAgdG9rZW4/OiBBdXRoVG9rZW5cbiAgKTogeyBBdXRob3JpemF0aW9uOiBzdHJpbmcgfSB8IHt9IHtcbiAgICBpZiAodG9rZW4/LmFjY2Vzc190b2tlbikge1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgQXV0aG9yaXphdGlvbjogYCR7dG9rZW4udG9rZW5fdHlwZSB8fCAnQmVhcmVyJ30gJHt0b2tlbi5hY2Nlc3NfdG9rZW59YCxcbiAgICAgIH07XG4gICAgfVxuICAgIGxldCBjdXJyZW50VG9rZW46IEF1dGhUb2tlbiB8IHVuZGVmaW5lZDtcbiAgICB0aGlzLmF1dGhTdG9yYWdlU2VydmljZVxuICAgICAgLmdldFRva2VuKClcbiAgICAgIC5zdWJzY3JpYmUoKHRva2VuKSA9PiAoY3VycmVudFRva2VuID0gdG9rZW4pKVxuICAgICAgLnVuc3Vic2NyaWJlKCk7XG5cbiAgICBpZiAoY3VycmVudFRva2VuPy5hY2Nlc3NfdG9rZW4pIHtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIEF1dGhvcml6YXRpb246IGAke2N1cnJlbnRUb2tlbi50b2tlbl90eXBlIHx8ICdCZWFyZXInfSAke1xuICAgICAgICAgIGN1cnJlbnRUb2tlbi5hY2Nlc3NfdG9rZW5cbiAgICAgICAgfWAsXG4gICAgICB9O1xuICAgIH1cbiAgICByZXR1cm4ge307XG4gIH1cblxuICAvKipcbiAgICogUmVmcmVzaGVzIGFjY2Vzc190b2tlbiBhbmQgdGhlbiByZXRyaWVzIHRoZSBjYWxsIHdpdGggdGhlIG5ldyB0b2tlbi5cbiAgICovXG4gIHB1YmxpYyBoYW5kbGVFeHBpcmVkQWNjZXNzVG9rZW4oXG4gICAgcmVxdWVzdDogSHR0cFJlcXVlc3Q8YW55PixcbiAgICBuZXh0OiBIdHRwSGFuZGxlcixcbiAgICAvLyBUT0RPOiMxMzQyMSBtYWtlIHJlcXVpcmVkXG4gICAgaW5pdGlhbFRva2VuPzogQXV0aFRva2VuXG4gICk6IE9ic2VydmFibGU8SHR0cEV2ZW50PEF1dGhUb2tlbj4+IHtcbiAgICAvLyBUT0RPOiMxMzQyMSByZW1vdmUgdGhpcyBpZi1zdGF0ZW1lbnQsIGFuZCBqdXN0IHJldHVybiB0aGUgc3RyZWFtLlxuICAgIGlmIChpbml0aWFsVG9rZW4pIHtcbiAgICAgIHJldHVybiB0aGlzLmdldFZhbGlkVG9rZW4oaW5pdGlhbFRva2VuKS5waXBlKFxuICAgICAgICBzd2l0Y2hNYXAoKHRva2VuKSA9PlxuICAgICAgICAgIC8vIHdlIGJyZWFrIHRoZSBzdHJlYW0gd2l0aCBFTVBUWSB3aGVuIHdlIGRvbid0IGhhdmUgdGhlIHRva2VuLiBUaGlzIHByZXZlbnRzIHNlbmRpbmcgdGhlIHJlcXVlc3RzIHdpdGggYEF1dGhvcml6YXRpb246IGJlYXJlciB1bmRlZmluZWRgIGhlYWRlclxuICAgICAgICAgIHRva2VuXG4gICAgICAgICAgICA/IG5leHQuaGFuZGxlKHRoaXMuY3JlYXRlTmV3UmVxdWVzdFdpdGhOZXdUb2tlbihyZXF1ZXN0LCB0b2tlbikpXG4gICAgICAgICAgICA6IEVNUFRZXG4gICAgICAgIClcbiAgICAgICk7XG4gICAgfVxuXG4gICAgLy8gVE9ETzojMTM0MjEgbGVnYWN5IC0gcmVtb3ZlIGluIDUuMFxuICAgIHJldHVybiB0aGlzLmhhbmRsZUV4cGlyZWRUb2tlbigpLnBpcGUoXG4gICAgICBzd2l0Y2hNYXAoKHRva2VuKSA9PiB7XG4gICAgICAgIHJldHVybiB0b2tlblxuICAgICAgICAgID8gbmV4dC5oYW5kbGUodGhpcy5jcmVhdGVOZXdSZXF1ZXN0V2l0aE5ld1Rva2VuKHJlcXVlc3QsIHRva2VuKSlcbiAgICAgICAgICA6IEVNUFRZO1xuICAgICAgfSlcbiAgICApO1xuICB9XG5cbiAgLyoqXG4gICAqIExvZ291dCB1c2VyLCByZWRpcmVjdGVkIHRvIGxvZ2luIHBhZ2UgYW5kIGluZm9ybXMgYWJvdXQgZXhwaXJlZCBzZXNzaW9uLlxuICAgKi9cbiAgcHVibGljIGhhbmRsZUV4cGlyZWRSZWZyZXNoVG9rZW4oKTogdm9pZCB7XG4gICAgLy8gVGhlcmUgbWlnaHQgYmUgMiBjYXNlczpcbiAgICAvLyAxLiB3aGVuIHVzZXIgaXMgYWxyZWFkeSBvbiBzb21lIHBhZ2UgKHJvdXRlciBpcyBzdGFibGUpIGFuZCBwZXJmb3JtcyBhbiBVSSBhY3Rpb25cbiAgICAvLyB0aGF0IHRyaWdnZXJzIGh0dHAgY2FsbCAoaS5lLiBidXR0b24gY2xpY2sgdG8gc2F2ZSBkYXRhIGluIGJhY2tlbmQpXG4gICAgLy8gMi4gd2hlbiB1c2VyIGlzIG5hdmlnYXRpbmcgdG8gc29tZSBwYWdlIGFuZCBhIHJvdXRlIGd1YXJkIHRyaWdnZXJzIHRoZSBodHRwIGNhbGxcbiAgICAvLyAoaS5lLiBndWFyZCBsb2FkaW5nIGNtcyBwYWdlIGRhdGEpXG4gICAgLy9cbiAgICAvLyBJbiB0aGUgc2Vjb25kIGNhc2UsIHdlIHdhbnQgdG8gcmVtZW1iZXIgdGhlIGFudGljaXBhdGVkIHVybCBiZWZvcmUgd2UgbmF2aWdhdGUgdG9cbiAgICAvLyB0aGUgbG9naW4gcGFnZSwgc28gd2UgY2FuIHJlZGlyZWN0IGJhY2sgdG8gdGhhdCBVUkwgYWZ0ZXIgdXNlciBhdXRoZW50aWNhdGVzLlxuICAgIHRoaXMuYXV0aFJlZGlyZWN0U2VydmljZS5zYXZlQ3VycmVudE5hdmlnYXRpb25VcmwoKTtcblxuICAgIC8vIExvZ291dCB1c2VyXG4gICAgLy8gVE9ETygjOTYzOCk6IFVzZSBsb2dvdXQgcm91dGUgd2hlbiBpdCB3aWxsIHN1cHBvcnQgcGFzc2luZyByZWRpcmVjdCB1cmxcbiAgICB0aGlzLmF1dGhTZXJ2aWNlLmNvcmVMb2dvdXQoKS5maW5hbGx5KCgpID0+IHtcbiAgICAgIHRoaXMucm91dGluZ1NlcnZpY2UuZ28oeyBjeFJvdXRlOiAnbG9naW4nIH0pO1xuXG4gICAgICB0aGlzLmdsb2JhbE1lc3NhZ2VTZXJ2aWNlLmFkZChcbiAgICAgICAge1xuICAgICAgICAgIGtleTogJ2h0dHBIYW5kbGVycy5zZXNzaW9uRXhwaXJlZCcsXG4gICAgICAgIH0sXG4gICAgICAgIEdsb2JhbE1lc3NhZ2VUeXBlLk1TR19UWVBFX0VSUk9SXG4gICAgICApO1xuICAgIH0pO1xuICB9XG5cbiAgLy8gVE9ETzojMTM0MjEgLSByZW1vdmUgdGhpcyBtZXRob2RcbiAgLyoqXG4gICAqIEF0dGVtcHRzIHRvIHJlZnJlc2ggdG9rZW4gaWYgcG9zc2libGUuXG4gICAqIElmIGl0IGlzIG5vdCBwb3NzaWJsZSBjYWxscyBgaGFuZGxlRXhwaXJlZFJlZnJlc2hUb2tlbmAuXG4gICAqXG4gICAqIEByZXR1cm4gb2JzZXJ2YWJsZSB3aGljaCBvbWl0cyBuZXcgYWNjZXNzX3Rva2VuLiAoV2FybjogbWlnaHQgbmV2ZXIgZW1pdCEpLlxuICAgKlxuICAgKiBAZGVwcmVjYXRlZCB3aWxsIGJlIHJlbW92ZWQgaW4gdGhlIG5leHQgbWFqb3IuIFVzZSBgZ2V0VmFsaWRUb2tlbigpYCBpbnN0ZWFkXG4gICAqL1xuICBwcm90ZWN0ZWQgaGFuZGxlRXhwaXJlZFRva2VuKCk6IE9ic2VydmFibGU8QXV0aFRva2VuIHwgdW5kZWZpbmVkPiB7XG4gICAgY29uc3Qgc3RyZWFtID0gdGhpcy5hdXRoU3RvcmFnZVNlcnZpY2UuZ2V0VG9rZW4oKTtcbiAgICBsZXQgb2xkVG9rZW46IEF1dGhUb2tlbjtcbiAgICByZXR1cm4gc3RyZWFtLnBpcGUoXG4gICAgICB0YXAoKHRva2VuKSA9PiB7XG4gICAgICAgIGlmIChcbiAgICAgICAgICB0b2tlbi5hY2Nlc3NfdG9rZW4gJiZcbiAgICAgICAgICB0b2tlbi5yZWZyZXNoX3Rva2VuICYmXG4gICAgICAgICAgIW9sZFRva2VuICYmXG4gICAgICAgICAgIXRoaXMucmVmcmVzaEluUHJvZ3Jlc3NcbiAgICAgICAgKSB7XG4gICAgICAgICAgdGhpcy5yZWZyZXNoSW5Qcm9ncmVzcyA9IHRydWU7XG4gICAgICAgICAgdGhpcy5vQXV0aExpYldyYXBwZXJTZXJ2aWNlLnJlZnJlc2hUb2tlbigpO1xuICAgICAgICB9IGVsc2UgaWYgKCF0b2tlbi5yZWZyZXNoX3Rva2VuKSB7XG4gICAgICAgICAgdGhpcy5oYW5kbGVFeHBpcmVkUmVmcmVzaFRva2VuKCk7XG4gICAgICAgIH1cbiAgICAgICAgb2xkVG9rZW4gPSBvbGRUb2tlbiB8fCB0b2tlbjtcbiAgICAgIH0pLFxuICAgICAgZmlsdGVyKCh0b2tlbikgPT4gb2xkVG9rZW4uYWNjZXNzX3Rva2VuICE9PSB0b2tlbi5hY2Nlc3NfdG9rZW4pLFxuICAgICAgdGFwKCgpID0+IHtcbiAgICAgICAgdGhpcy5yZWZyZXNoSW5Qcm9ncmVzcyA9IGZhbHNlO1xuICAgICAgfSksXG4gICAgICBtYXAoKHRva2VuKSA9PiAodG9rZW4/LmFjY2Vzc190b2tlbiA/IHRva2VuIDogdW5kZWZpbmVkKSksXG4gICAgICB0YWtlKDEpXG4gICAgKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBFbWl0cyB0aGUgdG9rZW4gb3IgYHVuZGVmaW5lZGAgb25seSB3aGVuIHRoZSByZWZyZXNoIG9yIHRoZSBsb2dvdXQgcHJvY2Vzc2VzIGFyZSBmaW5pc2hlZC5cbiAgICovXG4gIGdldFN0YWJsZVRva2VuKCk6IE9ic2VydmFibGU8QXV0aFRva2VuIHwgdW5kZWZpbmVkPiB7XG4gICAgcmV0dXJuIGNvbWJpbmVMYXRlc3QoW1xuICAgICAgdGhpcy50b2tlbiQsXG4gICAgICB0aGlzLmF1dGhTZXJ2aWNlLnJlZnJlc2hJblByb2dyZXNzJCxcbiAgICAgIHRoaXMuYXV0aFNlcnZpY2UubG9nb3V0SW5Qcm9ncmVzcyQsXG4gICAgXSkucGlwZShcbiAgICAgIG9ic2VydmVPbihxdWV1ZVNjaGVkdWxlciksXG4gICAgICBmaWx0ZXIoXG4gICAgICAgIChbXywgcmVmcmVzaEluUHJvZ3Jlc3MsIGxvZ291dEluUHJvZ3Jlc3NdKSA9PlxuICAgICAgICAgICFyZWZyZXNoSW5Qcm9ncmVzcyAmJiAhbG9nb3V0SW5Qcm9ncmVzc1xuICAgICAgKSxcbiAgICAgIHN3aXRjaE1hcCgoKSA9PiB0aGlzLnRva2VuJClcbiAgICApO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgYSB2YWxpZCBhY2Nlc3MgdG9rZW4uXG4gICAqIEl0IHdpbGwgYXR0ZW1wdCB0byByZWZyZXNoIGl0IGlmIHRoZSBjdXJyZW50IG9uZSBleHBpcmVkOyBlbWl0cyBhZnRlciB0aGUgbmV3IG9uZSBpcyByZXRyaWV2ZWQuXG4gICAqL1xuICBwcm90ZWN0ZWQgZ2V0VmFsaWRUb2tlbihcbiAgICByZXF1ZXN0VG9rZW46IEF1dGhUb2tlblxuICApOiBPYnNlcnZhYmxlPEF1dGhUb2tlbiB8IHVuZGVmaW5lZD4ge1xuICAgIHJldHVybiBkZWZlcigoKSA9PiB7XG4gICAgICAvLyBmbGFnIHRvIG9ubHkgcmVmcmVzaCB0b2tlbiBvbmx5IG9uIGZpcnN0IGVtaXNzaW9uXG4gICAgICBsZXQgcmVmcmVzaFRyaWdnZXJlZCA9IGZhbHNlO1xuICAgICAgcmV0dXJuIHRoaXMudG9rZW5Ub1JldHJ5UmVxdWVzdCQucGlwZShcbiAgICAgICAgdGFwKCh0b2tlbikgPT4ge1xuICAgICAgICAgIC8vIHdlIHdhbnQgdG8gcmVmcmVzaCB0aGUgYWNjZXNzIHRva2VuIG9ubHkgd2hlbiBpdCBpcyBvbGQuXG4gICAgICAgICAgLy8gdGhpcyBpcyBhIGd1YXJkIGZvciB0aGUgY2FzZSB3aGVuIHRoZXJlIGFyZSBtdWx0aXBsZSBwYXJhbGxlbCBodHRwIGNhbGxzXG4gICAgICAgICAgaWYgKFxuICAgICAgICAgICAgdG9rZW4/LmFjY2Vzc190b2tlbiA9PT0gcmVxdWVzdFRva2VuPy5hY2Nlc3NfdG9rZW4gJiZcbiAgICAgICAgICAgICFyZWZyZXNoVHJpZ2dlcmVkXG4gICAgICAgICAgKSB7XG4gICAgICAgICAgICB0aGlzLnJlZnJlc2hUb2tlblRyaWdnZXIkLm5leHQodG9rZW4pO1xuICAgICAgICAgIH1cbiAgICAgICAgICByZWZyZXNoVHJpZ2dlcmVkID0gdHJ1ZTtcbiAgICAgICAgfSksXG4gICAgICAgIHNraXBXaGlsZSgodG9rZW4pID0+IHRva2VuPy5hY2Nlc3NfdG9rZW4gPT09IHJlcXVlc3RUb2tlbi5hY2Nlc3NfdG9rZW4pLFxuICAgICAgICB0YWtlKDEpXG4gICAgICApO1xuICAgIH0pO1xuICB9XG5cbiAgcHJvdGVjdGVkIGNyZWF0ZU5ld1JlcXVlc3RXaXRoTmV3VG9rZW4oXG4gICAgcmVxdWVzdDogSHR0cFJlcXVlc3Q8YW55PixcbiAgICB0b2tlbjogQXV0aFRva2VuXG4gICk6IEh0dHBSZXF1ZXN0PGFueT4ge1xuICAgIHJlcXVlc3QgPSByZXF1ZXN0LmNsb25lKHtcbiAgICAgIHNldEhlYWRlcnM6IHtcbiAgICAgICAgQXV0aG9yaXphdGlvbjogYCR7dG9rZW4udG9rZW5fdHlwZSB8fCAnQmVhcmVyJ30gJHt0b2tlbi5hY2Nlc3NfdG9rZW59YCxcbiAgICAgIH0sXG4gICAgfSk7XG4gICAgcmV0dXJuIHJlcXVlc3Q7XG4gIH1cblxuICBuZ09uRGVzdHJveSgpOiB2b2lkIHtcbiAgICB0aGlzLnN1YnNjcmlwdGlvbnMudW5zdWJzY3JpYmUoKTtcbiAgfVxufVxuIl19