@pvway/alpha-oas
Version:
Alpha OAuth Service by p.v.Way
301 lines • 40.3 kB
JavaScript
import { Injectable } from '@angular/core';
import { HttpHeaders } from "@angular/common/http";
import { AlphaPrincipal } from "./alpha-principal";
import { catchError, map, mergeMap, Observable, throwError } from "rxjs";
import { AlphaSessionData } from "./alpha-session-data";
import { AlphaRefreshData } from "./alpha-refresh-data";
import { AlphaAuthEnvelopFactory } from "./alpha-auth-envelop";
import { AlphaUserFactory } from "./alpha-user";
import { AlphaAuthStatusEnum } from "./alpha-oas-abstractions";
import * as i0 from "@angular/core";
export class AlphaOasService {
mHttp;
mContext = 'OAuthService';
mPrincipal;
mSignInUrl;
mRefreshUrl;
mGetMeUrl;
mOnPrincipalUpdated = () => {
};
mPostErrorLog = () => {
};
get principal() {
return this.mPrincipal;
}
constructor() {
this.mPrincipal = new AlphaPrincipal();
}
/**
* Initializes the authentication process by retrieving session data, refresh data, or setting authentication to anonymous mode.
*
* @param httpClient - need to inject the httpClient here
* @param {string} [getMeUrl] - The URL for retrieving user information.
* @param {string} [refreshUrl] - The URL for refreshing authentication.
* @param {string} [signInUrl] - The URL for signing in.
* @param {function} [postErrorLog] - A function that handles error logging.
* It accepts three parameters: context, method, and error.
* @param {function} [onPrincipalUpdated] - A function that will be triggered whenever the principal is updated.
* It accepts one parameter: principal of type IAlphaPrincipal.
*
* @return {Observable} - An Observable that emits the result of the initialization process.
*/
init(httpClient, getMeUrl, refreshUrl, signInUrl, postErrorLog, onPrincipalUpdated) {
this.mHttp = httpClient;
this.mSignInUrl = signInUrl;
this.mRefreshUrl = refreshUrl;
this.mGetMeUrl = getMeUrl;
if (postErrorLog) {
this.mPostErrorLog = postErrorLog;
}
if (onPrincipalUpdated) {
this.mOnPrincipalUpdated = onPrincipalUpdated;
}
// let's first see if there is still a session data
const sd = AlphaSessionData.retrieve();
if (sd != null) {
return this.initFromSd();
}
// then check if there is a refresh data available
const rd = AlphaRefreshData.retrieve();
if (rd != null) {
return this.initFromRd();
}
// no sd and no rd found let's start as anonymous
return this.initAsAnonymous();
}
initFromSd() {
console.log('Sd found... calling getMe');
return new Observable((subscriber) => {
this.getMe().subscribe({
next: () => subscriber.next('principal reloaded'),
error: e => subscriber.error(e)
});
});
}
initFromRd() {
return new Observable((subscriber) => {
console.log('rd active... calling refresh');
this.mPrincipal.setStatus(AlphaAuthStatusEnum.Refreshing);
this.refresh().subscribe({
next: refreshed => {
if (refreshed) {
subscriber.next('identity refreshed');
}
else {
this.mPrincipal.setStatus(AlphaAuthStatusEnum.Anonymous);
subscriber.next('refreshed failed');
}
},
error: (e) => {
subscriber.error(e);
}
});
});
}
initAsAnonymous() {
return new Observable((subscriber) => {
this.mPrincipal.setStatus(AlphaAuthStatusEnum.Anonymous);
subscriber.next('anonymous');
});
}
/**
* Inject your own signIn method */
useSignIn(signIn) {
this.internalSignIn = signIn;
}
/**
* Inject your own refresh method */
useRefresh(refresh) {
this.internalRefresh = refresh;
}
/** Inject your own authorize method */
useAuthorize(authorize) {
this.internalAuthorize = authorize;
}
internalSignIn = (username, password) => {
if (this.mHttp === undefined) {
throw new Error('service is not initialized');
}
const body = 'grant_type=password' +
'&username=' + encodeURIComponent(username) +
'&password=' + encodeURIComponent(password);
const headers = new HttpHeaders()
.set('content-type', 'application/x-www-form-urlencoded');
const url = this.mSignInUrl;
return this.mHttp
.post(url, body, { headers: headers })
.pipe(map(dso => AlphaAuthEnvelopFactory.factorFromDso(dso)), catchError(error => {
this.mPostErrorLog(this.mContext, '_signIn', JSON.stringify(error));
return throwError(() => error);
}));
};
/**
* On successful login call storeIdentity.
* Remark: there is no need to call getMe from signIn as getMe
* is actually returning the same data as signIn
* @param username
* @param password
* @param rememberMe
*/
signIn(username, password, rememberMe) {
return new Observable((subscriber) => {
this.internalSignIn(username, password, rememberMe)
.subscribe({
next: (token) => {
this.storeIdentity(token, rememberMe);
subscriber.next(true);
},
error: (e) => {
this.signOut();
if (e.status === 400 || e.status === 401) {
subscriber.next(false);
}
else {
this.mPostErrorLog(this.mContext, 'login', JSON.stringify(e));
subscriber.error(e);
}
}
});
return;
});
}
/**
* default implementation of refresh
* this implementation can be overridden by calling useRefresh
*/
internalRefresh = (refreshToken) => {
if (this.mHttp === undefined) {
throw new Error('service is not initialized');
}
const body = 'grant_type=refresh_token' +
'&refresh_token=' + encodeURIComponent(refreshToken);
const headers = new HttpHeaders()
.set('content-type', 'application/x-www-form-urlencoded');
const url = this.mRefreshUrl;
return this.mHttp.post(url, body, { headers: headers })
.pipe(map(dso => AlphaAuthEnvelopFactory.factorFromDso(dso)));
};
/**
* refreshes the accessToken from the refreshToken
* found in the local storage data
*/
refresh() {
const rd = AlphaRefreshData.retrieve();
if (rd == null) {
this.mPostErrorLog(this.mContext, 'refresh', 'rd should not be null');
return throwError(() => 'rd should not be null');
}
return new Observable((subscriber) => {
this.internalRefresh(rd.refreshToken)
.subscribe({
next: (token) => {
this.storeIdentity(token, true);
subscriber.next(true);
},
error: (e) => {
this.signOut();
if (e.status == 401) {
subscriber.next(false);
}
else {
this.mPostErrorLog(this.mContext, 'refresh', JSON.stringify(e));
subscriber.error(e);
}
}
});
});
}
/**
* called from the init() method when the session data is present
*/
getMe() {
if (!this.mHttp) {
throw new Error('service is not initialized');
}
const url = this.mGetMeUrl;
const call = this.mHttp.get(url)
.pipe(map(dso => {
const user = AlphaUserFactory.factorFromDso(dso);
this.populatePrincipal(user);
return user;
}), catchError((error) => {
this.mPostErrorLog(this.mContext, url, JSON.stringify(error));
return throwError(() => error);
}));
return this.authorize(call);
}
editUserInfo(firstName, lastName, languageCode) {
if (!this.mPrincipal.user) {
return;
}
this.mPrincipal.user.username = firstName + " " + lastName;
this.mPrincipal.user.languageCode = languageCode;
this.mOnPrincipalUpdated(this.mPrincipal);
}
signOut() {
AlphaSessionData.clear();
AlphaRefreshData.clear();
this.mPrincipal.clearUser();
this.mPrincipal.setStatus(AlphaAuthStatusEnum.Anonymous);
this.mOnPrincipalUpdated(this.mPrincipal);
}
/**
* checks that the accessToken is not expired or
* expiring (expirationTime - 1 minute).
* if still valid fires the request directly else inserts a
* refresh before firing the request
*/
internalAuthorize(httpRequest) {
const sd = AlphaSessionData.retrieve();
if (sd == null || sd.isExpiredOrExpiring) {
return this.refresh()
.pipe(mergeMap(() => httpRequest), catchError(error => {
this.mPostErrorLog(this.mContext, '_authorize', JSON.stringify(error));
return throwError(() => error);
}));
}
else {
return httpRequest;
}
}
/**
* checks the accessToken and eventually refreshes it
* before calling the request
*/
authorize(httpRequest) {
return this.internalAuthorize(httpRequest);
}
/**
* (1) stores the access token in the session storage
* (2) stores the refresh token in the local storage
* (3) populates the principal using the user info
*/
storeIdentity(authEnvelop, rememberMe) {
const ts = AlphaSessionData
.getTimestamps(authEnvelop.expiresIn);
const sd = new AlphaSessionData(true, authEnvelop.accessToken, ts.receptionTs, ts.expirationTs);
sd.store();
console.log('sd populated');
if (rememberMe) {
const rd = new AlphaRefreshData(authEnvelop.refreshToken);
rd.store();
console.log('rd populated');
}
this.populatePrincipal(authEnvelop.user);
}
populatePrincipal(user) {
this.mPrincipal.setUser(user);
console.log('principal user is set');
this.mPrincipal.setStatus(AlphaAuthStatusEnum.Authenticated);
this.mOnPrincipalUpdated(this.mPrincipal);
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.1.1", ngImport: i0, type: AlphaOasService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.1.1", ngImport: i0, type: AlphaOasService, providedIn: 'root' });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.1.1", ngImport: i0, type: AlphaOasService, decorators: [{
type: Injectable,
args: [{
providedIn: 'root'
}]
}], ctorParameters: () => [] });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWxwaGEtb2FzLnNlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9wcm9qZWN0cy9hbHBoYS1vYXMvc3JjL2xpYi9hbHBoYS1vYXMuc2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUMsVUFBVSxFQUFDLE1BQU0sZUFBZSxDQUFDO0FBQ3pDLE9BQU8sRUFBZ0MsV0FBVyxFQUFDLE1BQU0sc0JBQXNCLENBQUM7QUFDaEYsT0FBTyxFQUFDLGNBQWMsRUFBQyxNQUFNLG1CQUFtQixDQUFDO0FBQ2pELE9BQU8sRUFBQyxVQUFVLEVBQUUsR0FBRyxFQUFFLFFBQVEsRUFBRSxVQUFVLEVBQWMsVUFBVSxFQUFDLE1BQU0sTUFBTSxDQUFDO0FBQ25GLE9BQU8sRUFBQyxnQkFBZ0IsRUFBQyxNQUFNLHNCQUFzQixDQUFDO0FBQ3RELE9BQU8sRUFBQyxnQkFBZ0IsRUFBQyxNQUFNLHNCQUFzQixDQUFDO0FBQ3RELE9BQU8sRUFBQyx1QkFBdUIsRUFBQyxNQUFNLHNCQUFzQixDQUFDO0FBQzdELE9BQU8sRUFBQyxnQkFBZ0IsRUFBQyxNQUFNLGNBQWMsQ0FBQztBQUM5QyxPQUFPLEVBQ0wsbUJBQW1CLEVBRXBCLE1BQU0sMEJBQTBCLENBQUM7O0FBS2xDLE1BQU0sT0FBTyxlQUFlO0lBRWxCLEtBQUssQ0FBeUI7SUFDckIsUUFBUSxHQUFHLGNBQWMsQ0FBQztJQUMxQixVQUFVLENBQWlCO0lBQ3BDLFVBQVUsQ0FBcUI7SUFDL0IsV0FBVyxDQUFxQjtJQUNoQyxTQUFTLENBQXFCO0lBRTlCLG1CQUFtQixHQUV6QixHQUFHLEVBQUU7SUFDTCxDQUFDLENBQUM7SUFDSSxhQUFhLEdBRW5CLEdBQUcsRUFBRTtJQUNMLENBQUMsQ0FBQztJQUVKLElBQUksU0FBUztRQUNYLE9BQU8sSUFBSSxDQUFDLFVBQVUsQ0FBQztJQUN6QixDQUFDO0lBRUQ7UUFDRSxJQUFJLENBQUMsVUFBVSxHQUFHLElBQUksY0FB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LEdBQUcsSUFBSSxnQkFBZ0IsQ0FDN0IsV0FBVyxDQUFDLFlBQVksQ0FBQyxDQUFDO1lBQzVCLEVBQUUsQ0FBQyxLQUFLLEVBQUUsQ0FBQztZQUNYLE9BQU8sQ0FBQyxHQUFHLENBQUMsY0FBYyxDQUFDLENBQUM7UUFDOUIsQ0FBQztRQUVELElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDM0MsQ0FBQztJQUVPLGlCQUFpQixDQUFDLElBQWdCO1FBQ3hDLElBQUksQ0FBQyxVQUFVLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDO1FBQzlCLE9BQU8sQ0FBQyxHQUFHLENBQUMsdUJBQXVCLENBQUMsQ0FBQztRQUNyQyxJQUFJLENBQUMsVUFBVSxDQUFDLFNBQVMsQ0FBQyxtQkFBbUIsQ0FBQyxhQUFhLENBQUMsQ0FBQztRQUM3RCxJQUFJLENBQUMsbUJBQW1CLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxDQUFDO0lBQzVDLENBQUM7dUdBcFhVLGVBQWU7MkdBQWYsZUFBZSxjQUZkLE1BQU07OzJGQUVQLGVBQWU7a0JBSDNCLFVBQVU7bUJBQUM7b0JBQ1YsVUFBVSxFQUFFLE1BQU07aUJBQ25CIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtJbmplY3RhYmxlfSBmcm9tICdAYW5ndWxhci9jb3JlJztcclxuaW1wb3J0IHtIdHRwQ2xpZW50LCBIdHRwRXJyb3JSZXNwb25zZSwgSHR0cEhlYWRlcnN9IGZyb20gXCJAYW5ndWxhci9jb21tb24vaHR0cFwiO1xyXG5pbXBvcnQge0FscGhhUHJpbmNpcGFsfSBmcm9tIFwiLi9hbHBoYS1wcmluY2lwYWxcIjtcclxuaW1wb3J0IHtjYXRjaEVycm9yLCBtYXAsIG1lcmdlTWFwLCBPYnNlcnZhYmxlLCBTdWJzY3JpYmVyLCB0aHJvd0Vycm9yfSBmcm9tIFwicnhqc1wiO1xyXG5pbXBvcnQge0FscGhhU2Vzc2lvbkRhdGF9IGZyb20gXCIuL2FscGhhLXNlc3Npb24tZGF0YVwiO1xyXG5pbXBvcnQge0FscGhhUmVmcmVzaERhdGF9IGZyb20gXCIuL2FscGhhLXJlZnJlc2gtZGF0YVwiO1xyXG5pbXBvcnQge0FscGhhQXV0aEVudmVsb3BGYWN0b3J5fSBmcm9tIFwiLi9hbHBoYS1hdXRoLWVudmVsb3BcIjtcclxuaW1wb3J0IHtBbHBoYVVzZXJGYWN0b3J5fSBmcm9tIFwiLi9hbHBoYS11c2VyXCI7XHJcbmltcG9ydCB7XHJcbiAgQWxwaGFBdXRoU3RhdHVzRW51bSwgSUFscGhhQXV0aEVudmVsb3AsXHJcbiAgSUFscGhhUHJpbmNpcGFsLCBJQWxwaGFVc2VyXHJcbn0gZnJvbSBcIi4vYWxwaGEtb2FzLWFic3RyYWN0aW9uc1wiO1xyXG5cclxuQEluamVjdGFibGUoe1xyXG4gIHByb3ZpZGVkSW46ICdyb290J1xyXG59KVxyXG5leHBvcnQgY2xhc3MgQWxwaGFPYXNTZXJ2aWNlIHtcclxuXHJcbiAgcHJpdmF0ZSBtSHR0cDogSHR0cENsaWVudCB8IHVuZGVmaW5lZDtcclxuICBwcml2YXRlIHJlYWRvbmx5IG1Db250ZXh0ID0gJ09BdXRoU2VydmljZSc7XHJcbiAgcHJpdmF0ZSByZWFkb25seSBtUHJpbmNpcGFsOiBBbHBoYVByaW5jaXBhbDtcclxuICBwcml2YXRlIG1TaWduSW5Vcmw6IHN0cmluZyB8IHVuZGVmaW5lZDtcclxuICBwcml2YXRlIG1SZWZyZXNoVXJsOiBzdHJpbmcgfCB1bmRlZmluZWQ7XHJcbiAgcHJpdmF0ZSBtR2V0TWVVcmw6IHN0cmluZyB8IHVuZGVmaW5lZDtcclxuXHJcbiAgcHJpdmF0ZSBtT25QcmluY2lwYWxVcGRhdGVkOlxyXG4gICAgKHByaW5jaXBhbDogQWxwaGFQcmluY2lwYWwpID0+IGFueSA9XHJcbiAgICAoKSA9PiB7XHJcbiAgICB9O1xyXG4gIHByaXZhdGUgbVBvc3RFcnJvckxvZzpcclxuICAgIChjb250ZXh0OiBzdHJpbmcsIG1ldGhvZDogc3RyaW5nLCBlcnJvcjogc3RyaW5nKSA9PiBhbnkgPVxyXG4gICAgKCkgPT4ge1xyXG4gICAgfTtcclxuXHJcbiAgZ2V0IHByaW5jaXBhbCgpOiBJQWxwaGFQcmluY2lwYWwge1xyXG4gICAgcmV0dXJuIHRoaXMubVByaW5jaXBhbDtcclxuICB9XHJcblxyXG4gIGNvbnN0cnVjdG9yKCkge1xyXG4gICAgdGhpcy5tUHJpbmNpcGFsID0gbmV3IEFscGhhUHJpbmNpcGFsKCk7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBJbml0aWFsaXplcyB0aGUgYXV0aGVudGljYXRpb24gcHJvY2VzcyBieSByZXRyaWV2aW5nIHNlc3Npb24gZGF0YSwgcmVmcmVzaCBkYXRhLCBvciBzZXR0aW5nIGF1dGhlbnRpY2F0aW9uIHRvIGFub255bW91cyBtb2RlLlxyXG4gICAqXHJcbiAgICogQHBhcmFtIGh0dHBDbGllbnQgLSBuZWVkIHRvIGluamVjdCB0aGUgaHR0cENsaWVudCBoZXJlXHJcbiAgICogQHBhcmFtIHtzdHJpbmd9IFtnZXRNZVVybF0gLSBUaGUgVVJMIGZvciByZXRyaWV2aW5nIHVzZXIgaW5mb3JtYXRpb24uXHJcbiAgICogQHBhcmFtIHtzdHJpbmd9IFtyZWZyZXNoVXJsXSAtIFRoZSBVUkwgZm9yIHJlZnJlc2hpbmcgYXV0aGVudGljYXRpb24uXHJcbiAgICogQHBhcmFtIHtzdHJpbmd9IFtzaWduSW5VcmxdIC0gVGhlIFVSTCBmb3Igc2lnbmluZyBpbi5cclxuICAgKiBAcGFyYW0ge2Z1bmN0aW9ufSBbcG9zdEVycm9yTG9nXSAtIEEgZnVuY3Rpb24gdGhhdCBoYW5kbGVzIGVycm9yIGxvZ2dpbmcuXHJcbiAgICogICBJdCBhY2NlcHRzIHRocmVlIHBhcmFtZXRlcnM6IGNvbnRleHQsIG1ldGhvZCwgYW5kIGVycm9yLlxyXG4gICAqIEBwYXJhbSB7ZnVuY3Rpb259IFtvblByaW5jaXBhbFVwZGF0ZWRdIC0gQSBmdW5jdGlvbiB0aGF0IHdpbGwgYmUgdHJpZ2dlcmVkIHdoZW5ldmVyIHRoZSBwcmluY2lwYWwgaXMgdXBkYXRlZC5cclxuICAgKiAgIEl0IGFjY2VwdHMgb25lIHBhcmFtZXRlcjogcHJpbmNpcGFsIG9mIHR5cGUgSUFscGhhUHJpbmNpcGFsLlxyXG4gICAqXHJcbiAgICogQHJldHVybiB7T2JzZXJ2YWJsZX0gLSBBbiBPYnNlcnZhYmxlIHRoYXQgZW1pdHMgdGhlIHJlc3VsdCBvZiB0aGUgaW5pdGlhbGl6YXRpb24gcHJvY2Vzcy5cclxuICAgKi9cclxuICBpbml0KGh0dHBDbGllbnQ6IEh0dHBDbGllbnQsXHJcbiAgICAgICBnZXRNZVVybD86IHN0cmluZyxcclxuICAgICAgIHJlZnJlc2hVcmw/OiBzdHJpbmcsXHJcbiAgICAgICBzaWduSW5Vcmw/OiBzdHJpbmcsXHJcbiAgICAgICBwb3N0RXJyb3JMb2c/OiAoY29udGV4dDogc3RyaW5nLCBtZXRob2Q6IHN0cmluZywgZXJyb3I6IHN0cmluZykgPT4gYW55LFxyXG4gICAgICAgb25QcmluY2lwYWxVcGRhdGVkPzogKHByaW5jaXBhbDogSUFscGhhUHJpbmNpcGFsKSA9PiBhbnkpOiBPYnNlcnZhYmxlPHN0cmluZz4ge1xyXG4gICAgdGhpcy5tSHR0cCA9IGh0dHBDbGllbnQ7XHJcbiAgICB0aGlzLm1TaWduSW5VcmwgPSBzaWduSW5Vcmw7XHJcbiAgICB0aGlzLm1SZWZyZXNoVXJsID0gcmVmcmVzaFVybDtcclxuICAgIHRoaXMubUdldE1lVXJsID0gZ2V0TWVVcmw7XHJcbiAgICBpZiAocG9zdEVycm9yTG9nKSB7XHJcbiAgICAgIHRoaXMubVBvc3RFcnJvckxvZyA9IHBvc3RFcnJvckxvZztcclxuICAgIH1cclxuICAgIGlmIChvblByaW5jaXBhbFVwZGF0ZWQpIHtcclxuICAgICAgdGhpcy5tT25QcmluY2lwYWxVcGRhdGVkID0gb25QcmluY2lwYWxVcGRhdGVkO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIGxldCdzIGZpcnN0IHNlZSBpZiB0aGVyZSBpcyBzdGlsbCBhIHNlc3Npb24gZGF0YVxyXG4gICAgY29uc3Qgc2QgPSBBbHBoYVNlc3Npb25EYXRhLnJldHJpZXZlKCk7XHJcbiAgICBpZiAoc2QgIT0gbnVsbCkge1xyXG4gICAgICByZXR1cm4gdGhpcy5pbml0RnJvbVNkKCk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gdGhlbiBjaGVjayBpZiB0aGVyZSBpcyBhIHJlZnJlc2ggZGF0YSBhdmFpbGFibGVcclxuICAgIGNvbnN0IHJkID0gQWxwaGFSZWZyZXNoRGF0YS5yZXRyaWV2ZSgpO1xyXG4gICAgaWYgKHJkICE9IG51bGwpIHtcclxuICAgICAgcmV0dXJuIHRoaXMuaW5pdEZyb21SZCgpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIG5vIHNkIGFuZCBubyByZCBmb3VuZCBsZXQncyBzdGFydCBhcyBhbm9ueW1vdXNcclxuICAgIHJldHVybiB0aGlzLmluaXRBc0Fub255bW91cygpO1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBpbml0RnJvbVNkKCk6IE9ic2VydmFibGU8c3RyaW5nPiB7XHJcbiAgICBjb25zb2xlLmxvZygnU2QgZm91bmQuLi4gY2FsbGluZyBnZXRNZScpO1xyXG4gICAgcmV0dXJuIG5ldyBPYnNlcnZhYmxlKFxyXG4gICAgICAoc3Vic2NyaWJlcjogU3Vic2NyaWJlcjxzdHJpbmc+KSA9PiB7XHJcbiAgICAgICAgdGhpcy5nZXRNZSgpLnN1YnNjcmliZSh7XHJcbiAgICAgICAgICBuZXh0OiAoKSA9PiBzdWJzY3JpYmVyLm5leHQoJ3ByaW5jaXBhbCByZWxvYWRlZCcpLFxyXG4gICAgICAgICAgZXJyb3I6IGUgPT4gc3Vic2NyaWJlci5lcnJvcihlKVxyXG4gICAgICAgIH0pO1xyXG4gICAgICB9KTtcclxuICB9XHJcblxyXG4gIHByaXZhdGUgaW5pdEZyb21SZCgpOiBPYnNlcnZhYmxlPHN0cmluZz4ge1xyXG4gICAgcmV0dXJuIG5ldyBPYnNlcnZhYmxlKFxyXG4gICAgICAoc3Vic2NyaWJlcjogU3Vic2NyaWJlcjxzdHJpbmc+KSA9PiB7XHJcbiAgICAgICAgY29uc29sZS5sb2coJ3JkIGFjdGl2ZS4uLiBjYWxsaW5nIHJlZnJlc2gnKTtcclxuICAgICAgICB0aGlzLm1QcmluY2lwYWwuc2V0U3RhdHVzKEFscGhhQXV0aFN0YXR1c0VudW0uUmVmcmVzaGluZyk7XHJcbiAgICAgICAgdGhpcy5yZWZyZXNoKCkuc3Vic2NyaWJlKHtcclxuICAgICAgICAgIG5leHQ6IHJlZnJlc2hlZCA9PiB7XHJcbiAgICAgICAgICAgIGlmIChyZWZyZXNoZWQpIHtcclxuICAgICAgICAgICAgICBzdWJzY3JpYmVyLm5leHQoJ2lkZW50aXR5IHJlZnJlc2hlZCcpO1xyXG4gICAgICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICAgIHRoaXMubVByaW5jaXBhbC5zZXRTdGF0dXMoQWxwaGFBdXRoU3RhdHVzRW51bS5Bbm9ueW1vdXMpO1xyXG4gICAgICAgICAgICAgIHN1YnNjcmliZXIubmV4dCgncmVmcmVzaGVkIGZhaWxlZCcpO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICB9LFxyXG4gICAgICAgICAgZXJyb3I6IChlOiBhbnkpID0+IHtcclxuICAgICAgICAgICAgc3Vic2NyaWJlci5lcnJvcihlKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9KTtcclxuICAgICAgfSk7XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIGluaXRBc0Fub255bW91cygpOiBPYnNlcnZhYmxlPHN0cmluZz4ge1xyXG4gICAgcmV0dXJuIG5ldyBPYnNlcnZhYmxlKFxyXG4gICAgICAoc3Vic2NyaWJlcjogU3Vic2NyaWJlcjxzdHJpbmc+KSA9PiB7XHJcbiAgICAgICAgdGhpcy5tUHJpbmNpcGFsLnNldFN0YXR1cyhBbHBoYUF1dGhTdGF0dXNFbnVtLkFub255bW91cyk7XHJcbiAgICAgICAgc3Vic2NyaWJlci5uZXh0KCdhbm9ueW1vdXMnKTtcclxuICAgICAgfSk7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBJbmplY3QgeW91ciBvd24gc2lnbkluIG1ldGhvZCAqL1xyXG4gIHVzZVNpZ25JbihcclxuICAgIHNpZ25JbjogKFxyXG4gICAgICB1c2VyTmFtZTogc3RyaW5nLFxyXG4gICAgICBwYXNzd29yZDogc3RyaW5nLFxyXG4gICAgICByZW1lbWJlck1lOiBib29sZWFuKSA9PiBPYnNlcnZhYmxlPElBbHBoYUF1dGhFbnZlbG9wPik6IHZvaWQge1xyXG4gICAgdGhpcy5pbnRlcm5hbFNpZ25JbiA9IHNpZ25JbjtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIEluamVjdCB5b3VyIG93biByZWZyZXNoIG1ldGhvZCAqL1xyXG4gIHVzZVJlZnJlc2gocmVmcmVzaDogKFxyXG4gICAgcmVmcmVzaFRva2VuOiBzdHJpbmcpID0+IE9ic2VydmFibGU8SUFscGhhQXV0aEVudmVsb3A+KSB7XHJcbiAgICB0aGlzLmludGVybmFsUmVmcmVzaCA9IHJlZnJlc2g7XHJcbiAgfVxyXG5cclxuICAvKiogSW5qZWN0IHlvdXIgb3duIGF1dGhvcml6ZSBtZXRob2QgKi9cclxuICB1c2VBdXRob3JpemUoYXV0aG9yaXplOiAocmVxdWVzdDogT2JzZXJ2YWJsZTxhbnk+KSA9PiBPYnNlcnZhYmxlPGFueT4pOiB2b2lkIHtcclxuICAgIHRoaXMuaW50ZXJuYWxBdXRob3JpemUgPSBhdXRob3JpemU7XHJcbiAgfVxyXG5cclxuICBpbnRlcm5hbFNpZ25JbjogKFxyXG4gICAgdXNlck5hbWU6IHN0cmluZyxcclxuICAgIHBhc3N3b3JkOiBzdHJpbmcsXHJcbiAgICByZW1lbWJlck1lOiBib29sZWFuKSA9PlxyXG4gICAgT2JzZXJ2YWJsZTxJQWxwaGFBdXRoRW52ZWxvcD4gPVxyXG4gICAgKHVzZXJuYW1lOiBzdHJpbmcsIHBhc3N3b3JkOiBzdHJpbmcpID0+IHtcclxuXHJcbiAgICAgIGlmICh0aGlzLm1IdHRwID09PSB1bmRlZmluZWQpIHtcclxuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ3NlcnZpY2UgaXMgbm90IGluaXRpYWxpemVkJyk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIGNvbnN0IGJvZHkgPSAnZ3JhbnRfdHlwZT1wYXNzd29yZCcgK1xyXG4gICAgICAgICcmdXNlcm5hbWU9JyArIGVuY29kZVVSSUNvbXBvbmVudCh1c2VybmFtZSkgK1xyXG4gICAgICAgICcmcGFzc3dvcmQ9JyArIGVuY29kZVVSSUNvbXBvbmVudChwYXNzd29yZCk7XHJcblxyXG4gICAgICBjb25zdCBoZWFkZXJzID0gbmV3IEh0dHBIZWFkZXJzKClcclxuICAgICAgICAuc2V0KCdjb250ZW50LXR5cGUnLCAnYXBwbGljYXRpb24veC13d3ctZm9ybS11cmxlbmNvZGVkJyk7XHJcblxyXG4gICAgICBjb25zdCB1cmwgPSB0aGlzLm1TaWduSW5VcmwhO1xyXG4gICAgICByZXR1cm4gdGhpcy5tSHR0cCFcclxuICAgICAgICAucG9zdDxhbnk+KHVybCwgYm9keSwge2hlYWRlcnM6IGhlYWRlcnN9KVxyXG4gICAgICAgIC5waXBlKFxyXG4gICAgICAgICAgbWFwKGRzbyA9PlxyXG4gICAgICAgICAgICBBbHBoYUF1dGhFbnZlbG9wRmFjdG9yeS5mYWN0b3JGcm9tRHNvKGRzbykpLFxyXG4gICAgICAgICAgY2F0Y2hFcnJvcihlcnJvciA9PiB7XHJcbiAgICAgICAgICAgIHRoaXMubVBvc3RFcnJvckxvZyh0aGlzLm1Db250ZXh0LFxyXG4gICAgICAgICAgICAgICdfc2lnbkluJywgSlNPTi5zdHJpbmdpZnkoZXJyb3IpKTtcclxuICAgICAgICAgICAgcmV0dXJuIHRocm93RXJyb3IoKCkgPT4gZXJyb3IpO1xyXG4gICAgICAgICAgfSkpO1xyXG4gICAgfVxyXG5cclxuICAvKipcclxuICAgKiBPbiBzdWNjZXNzZnVsIGxvZ2luIGNhbGwgc3RvcmVJZGVudGl0eS5cclxuICAgKiBSZW1hcms6IHRoZXJlIGlzIG5vIG5lZWQgdG8gY2FsbCBnZXRNZSBmcm9tIHNpZ25JbiBhcyBnZXRNZVxyXG4gICAqIGlzIGFjdHVhbGx5IHJldHVybmluZyB0aGUgc2FtZSBkYXRhIGFzIHNpZ25JblxyXG4gICAqIEBwYXJhbSB1c2VybmFtZVxyXG4gICAqIEBwYXJhbSBwYXNzd29yZFxyXG4gICAqIEBwYXJhbSByZW1lbWJlck1lXHJcbiAgICovXHJcbiAgc2lnbkluKFxyXG4gICAgdXNlcm5hbWU6IHN0cmluZyxcclxuICAgIHBhc3N3b3JkOiBzdHJpbmcsXHJcbiAgICByZW1lbWJlck1lOiBib29sZWFuKTogT2JzZXJ2YWJsZTxib29sZWFuPiB7XHJcblxyXG4gICAgcmV0dXJuIG5ldyBPYnNlcnZhYmxlPGJvb2xlYW4+KFxyXG4gICAgICAoc3Vic2NyaWJlcjogU3Vic2NyaWJlcjxib29sZWFuPikgPT4ge1xyXG4gICAgICAgIHRoaXMuaW50ZXJuYWxTaWduSW4odXNlcm5hbWUsIHBhc3N3b3JkLCByZW1lbWJlck1lKVxyXG4gICAgICAgICAgLnN1YnNjcmliZSh7XHJcbiAgICAgICAgICAgIG5leHQ6ICh0b2tlbjogSUFscGhhQXV0aEVudmVsb3ApID0+IHtcclxuICAgICAgICAgICAgICB0aGlzLnN0b3JlSWRlbnRpdHkodG9rZW4sIHJlbWVtYmVyTWUpO1xyXG4gICAgICAgICAgICAgIHN1YnNjcmliZXIubmV4dCh0cnVlKTtcclxuICAgICAgICAgICAgfSxcclxuICAgICAgICAgICAgZXJyb3I6IChlOiBIdHRwRXJyb3JSZXNwb25zZSkgPT4ge1xyXG4gICAgICAgICAgICAgIHRoaXMuc2lnbk91dCgpO1xyXG4gICAgICAgICAgICAgIGlmIChlLnN0YXR1cyA9PT0gNDAwIHx8IGUuc3RhdHVzID09PSA0MDEpIHtcclxuICAgICAgICAgICAgICAgIHN1YnNjcmliZXIubmV4dChmYWxzZSk7XHJcbiAgICAgICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgICAgIHRoaXMubVBvc3RFcnJvckxvZyhcclxuICAgICAgICAgICAgICAgICAgdGhpcy5tQ29udGV4dCwgJ2xvZ2luJywgSlNPTi5zdHJpbmdpZnkoZSkpXHJcbiAgICAgICAgICAgICAgICBzdWJzY3JpYmVyLmVycm9yKGUpO1xyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfSk7XHJcbiAgICAgICAgcmV0dXJuO1xyXG4gICAgICB9KTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIGRlZmF1bHQgaW1wbGVtZW50YXRpb24gb2YgcmVmcmVzaFxyXG4gICAqIHRoaXMgaW1wbGVtZW50YXRpb24gY2FuIGJlIG92ZXJyaWRkZW4gYnkgY2FsbGluZyB1c2VSZWZyZXNoXHJcbiAgICovXHJcbiAgaW50ZXJuYWxSZWZyZXNoOiAocmVmcmVzaFRva2VuOiBzdHJpbmcpID0+IE9ic2VydmFibGU8SUFscGhhQXV0aEVudmVsb3A+ID1cclxuICAgIChyZWZyZXNoVG9rZW46IHN0cmluZykgPT4ge1xyXG5cclxuICAgICAgaWYgKHRoaXMubUh0dHAgPT09IHVuZGVmaW5lZCkge1xyXG4gICAgICAgIHRocm93IG5ldyBFcnJvcignc2VydmljZSBpcyBub3QgaW5pdGlhbGl6ZWQnKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgY29uc3QgYm9keSA9ICdncmFudF90eXBlPXJlZnJlc2hfdG9rZW4nICtcclxuICAgICAgICAnJnJlZnJlc2hfdG9rZW49JyArIGVuY29kZVVSSUNvbXBvbmVudChyZWZyZXNoVG9rZW4pO1xyXG5cclxuICAgICAgY29uc3QgaGVhZGVycyA9IG5ldyBIdHRwSGVhZGVycygpXHJcbiAgICAgICAgLnNldCgnY29udGVudC10eXBlJywgJ2FwcGxpY2F0aW9uL3gtd3d3LWZvcm0tdXJsZW5jb2RlZCcpO1xyXG5cclxuICAgICAgY29uc3QgdXJsID0gdGhpcy5tUmVmcmVzaFVybCE7XHJcbiAgICAgIHJldHVybiB0aGlzLm1IdHRwIS5wb3N0PGFueT4odXJsLCBib2R5LCB7aGVhZGVyczogaGVhZGVyc30pXHJcbiAgICAgICAgLnBpcGUoXHJcbiAgICAgICAgICBtYXAoZHNvID0+XHJcbiAgICAgICAgICAgIEFscGhhQXV0aEVudmVsb3BGYWN0b3J5LmZhY3RvckZyb21Ec28oZHNvKSkpO1xyXG4gICAgfVxyXG5cclxuICAvKipcclxuICAgKiByZWZyZXNoZXMgdGhlIGFjY2Vzc1Rva2VuIGZyb20gdGhlIHJlZnJlc2hUb2tlblxyXG4gICAqIGZvdW5kIGluIHRoZSBsb2NhbCBzdG9yYWdlIGRhdGFcclxuICAgKi9cclxuICByZWZyZXNoKCk6IE9ic2VydmFibGU8Ym9vbGVhbj4ge1xyXG5cclxuICAgIGNvbnN0IHJkID0gQWxwaGFSZWZyZXNoRGF0YS5yZXRyaWV2ZSgpO1xyXG4gICAgaWYgKHJkID09IG51bGwpIHtcclxuICAgICAgdGhpcy5tUG9zdEVycm9yTG9nKHRoaXMubUNvbnRleHQsXHJcbiAgICAgICAgJ3JlZnJlc2gnLCAncmQgc2hvdWxkIG5vdCBiZSBudWxsJyk7XHJcbiAgICAgIHJldHVybiB0aHJvd0Vycm9yKFxyXG4gICAgICAgICgpID0+ICdyZCBzaG91bGQgbm90IGJlIG51bGwnKTtcclxuICAgIH1cclxuXHJcbiAgICByZXR1cm4gbmV3IE9ic2VydmFibGU8Ym9vbGVhbj4oXHJcbiAgICAgIChzdWJzY3JpYmVyOiBTdWJzY3JpYmVyPGJvb2xlYW4+KSA9PiB7XHJcbiAgICAgICAgdGhpcy5pbnRlcm5hbFJlZnJlc2gocmQucmVmcmVzaFRva2VuKVxyXG4gICAgICAgICAgLnN1YnNjcmliZSh7XHJcbiAgICAgICAgICAgIG5leHQ6ICh0b2tlbjogSUFscGhhQXV0aEVudmVsb3ApID0+IHtcclxuICAgICAgICAgICAgICB0aGlzLnN0b3JlSWRlbnRpdHkodG9rZW4sIHRydWUpO1xyXG4gICAgICAgICAgICAgIHN1YnNjcmliZXIubmV4dCh0cnVlKTtcclxuICAgICAgICAgICAgfSxcclxuICAgICAgICAgICAgZXJyb3I6IChlOiBIdHRwRXJyb3JSZXNwb25zZSkgPT4ge1xyXG4gICAgICAgICAgICAgIHRoaXMuc2lnbk91dCgpO1xyXG4gICAgICAgICAgICAgIGlmIChlLnN0YXR1cyA9PSA0MDEpIHtcclxuICAgICAgICAgICAgICAgIHN1YnNjcmliZXIubmV4dChmYWxzZSk7XHJcbiAgICAgICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgICAgIHRoaXMubVBvc3RFcnJvckxvZyh0aGlzLm1Db250ZXh0LFxyXG4gICAgICAgICAgICAgICAgICAncmVmcmVzaCcsIEpTT04uc3RyaW5naWZ5KGUpKTtcclxuICAgICAgICAgICAgICAgIHN1YnNjcmliZXIuZXJyb3IoZSk7XHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICB9KTtcclxuICAgICAgfSk7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBjYWxsZWQgZnJvbSB0aGUgaW5pdCgpIG1ldGhvZCB3aGVuIHRoZSBzZXNzaW9uIGRhdGEgaXMgcHJlc2VudFxyXG4gICAqL1xyXG4gIGdldE1lKCk6IE9ic2VydmFibGU8SUFscGhhVXNlcj4ge1xyXG4gICAgaWYgKCF0aGlzLm1IdHRwKSB7XHJcbiAgICAgIHRocm93IG5ldyBFcnJvcignc2VydmljZSBpcyBub3QgaW5pdGlhbGl6ZWQnKTtcclxuICAgIH1cclxuICAgIGNvbnN0IHVybCA9IHRoaXMubUdldE1lVXJsITtcclxuICAgIGNvbnN0IGNhbGwgPSB0aGlzLm1IdHRwLmdldDxhbnk+KHVybClcclxuICAgICAgLnBpcGUoXHJcbiAgICAgICAgbWFwKFxyXG4gICAgICAgICAgZHNvID0+IHtcclxuICAgICAgICAgICAgY29uc3QgdXNlciA9IEFscGhhVXNlckZhY3RvcnkuZmFjdG9yRnJvbURzbyhkc28pO1xyXG4gICAgICAgICAgICB0aGlzLnBvcHVsYXRlUHJpbmNpcGFsKHVzZXIpO1xyXG4gICAgICAgICAgICByZXR1cm4gdXNlcjtcclxuICAgICAgICAgIH0pLFxyXG4gICAgICAgIGNhdGNoRXJyb3IoKGVycm9yOiBIdHRwRXJyb3JSZXNwb25zZSkgPT4ge1xyXG4gICAgICAgICAgdGhpcy5tUG9zdEVycm9yTG9nKHRoaXMubUNvbnRleHQsIHVybCxcclxuICAgICAgICAgICAgSlNPTi5zdHJpbmdpZnkoZXJyb3IpKTtcclxuICAgICAgICAgIHJldHVybiB0aHJvd0Vycm9yKCgpID0+IGVycm9yKTtcclxuICAgICAgICB9KSk7XHJcblxyXG4gICAgcmV0dXJuIHRoaXMuYXV0aG9yaXplKGNhbGwpO1xyXG4gIH1cclxuXHJcbiAgZWRpdFVzZXJJbmZvKFxyXG4gICAgZmlyc3ROYW1lOiBzdHJpbmcsXHJcbiAgICBsYXN0TmFtZTogc3RyaW5nLFxyXG4gICAgbGFuZ3VhZ2VDb2RlOiBzdHJpbmcpOiB2b2lkIHtcclxuICAgIGlmICghdGhpcy5tUHJpbmNpcGFsLnVzZXIpIHtcclxuICAgICAgcmV0dXJuO1xyXG4gICAgfVxyXG4gICAgdGhpcy5tUHJpbmNpcGFsLnVzZXIudXNlcm5hbWUgPSBmaXJzdE5hbWUgKyBcIiBcIiArIGxhc3ROYW1lO1xyXG4gICAgdGhpcy5tUHJpbmNpcGFsLnVzZXIubGFuZ3VhZ2VDb2RlID0gbGFuZ3VhZ2VDb2RlO1xyXG5cclxuICAgIHRoaXMubU9uUHJpbmNpcGFsVXBkYXRlZCh0aGlzLm1QcmluY2lwYWwpXHJcbiAgfVxyXG5cclxuICBzaWduT3V0KCk6IHZvaWQge1xyXG4gICAgQWxwaGFTZXNzaW9uRGF0YS5jbGVhcigpO1xyXG4gICAgQWxwaGFSZWZyZXNoRGF0YS5jbGVhcigpO1xyXG4gICAgdGhpcy5tUHJpbmNpcGFsLmNsZWFyVXNlcigpO1xyXG4gICAgdGhpcy5tUHJpbmNpcGFsLnNldFN0YXR1cyhBbHBoYUF1dGhTdGF0dXNFbnVtLkFub255bW91cyk7XHJcbiAgICB0aGlzLm1PblByaW5jaXBhbFVwZGF0ZWQodGhpcy5tUHJpbmNpcGFsKTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIGNoZWNrcyB0aGF0IHRoZSBhY2Nlc3NUb2tlbiBpcyBub3QgZXhwaXJlZCBvclxyXG4gICAqIGV4cGlyaW5nIChleHBpcmF0aW9uVGltZSAtIDEgbWludXRlKS5cclxuICAgKiBpZiBzdGlsbCB2YWxpZCBmaXJlcyB0aGUgcmVxdWVzdCBkaXJlY3RseSBlbHNlIGluc2VydHMgYVxyXG4gICAqIHJlZnJlc2ggYmVmb3JlIGZpcmluZyB0aGUgcmVxdWVzdFxyXG4gICAqL1xyXG4gICBpbnRlcm5hbEF1dGhvcml6ZShodHRwUmVxdWVzdDogT2JzZXJ2YWJsZTxhbnk+KTogT2JzZXJ2YWJsZTxhbnk+IHtcclxuICAgIGNvbnN0IHNkID0gQWxwaGFTZXNzaW9uRGF0YS5yZXRyaWV2ZSgpO1xyXG4gICAgaWYgKHNkID09IG51bGwgfHwgc2QuaXNFeHBpcmVkT3JFeHBpcmluZykge1xyXG4gICAgICByZXR1cm4gdGhpcy5yZWZyZXNoKClcclxuICAgICAgICAucGlwZShcclxuICAgICAgICAgIG1lcmdlTWFwKCgpID0+IGh0dHBSZXF1ZXN0KSxcclxuICAgICAgICAgIGNhdGNoRXJyb3IoZXJyb3IgPT4ge1xyXG4gICAgICAgICAgICAgIHRoaXMubVBvc3RFcnJvckxvZyh0aGlzLm1Db250ZXh0LFxyXG4gICAgICAgICAgICAgICAgJ19hdXRob3JpemUnLCBKU09OLnN0cmluZ2lmeShlcnJvcikpO1xyXG4gICAgICAgICAgICAgIHJldHVybiB0aHJvd0Vycm9yKCgpID0+IGVycm9yKVxyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICApKTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIHJldHVybiBodHRwUmVxdWVzdDtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIGNoZWNrcyB0aGUgYWNjZXNzVG9rZW4gYW5kIGV2ZW50dWFsbHkgcmVmcmVzaGVzIGl0XHJcbiAgICogYmVmb3JlIGNhbGxpbmcgdGhlIHJlcXVlc3RcclxuICAgKi9cclxuICBhdXRob3JpemUoaHR0cFJlcXVlc3Q6IE9ic2VydmFibGU8YW55Pik6IE9ic2VydmFibGU8YW55PiB7XHJcbiAgICByZXR1cm4gdGhpcy5pbnRlcm5hbEF1dGhvcml6ZShodHRwUmVxdWVzdCk7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiAoMSkgc3RvcmVzIHRoZSBhY2Nlc3MgdG9rZW4gaW4gdGhlIHNlc3Npb24gc3RvcmFnZVxyXG4gICAqICgyKSBzdG9yZXMgdGhlIHJlZnJlc2ggdG9rZW4gaW4gdGhlIGxvY2FsIHN0b3JhZ2VcclxuICAgKiAoMykgcG9wdWxhdGVzIHRoZSBwcmluY2lwYWwgdXNpbmcgdGhlIHVzZXIgaW5mb1xyXG4gICAqL1xyXG4gIHN0b3JlSWRlbnRpdHkoXHJcbiAgICBhdXRoRW52ZWxvcDogSUFscGhhQXV0aEVudmVsb3AsXHJcbiAgICByZW1lbWJlck1lOiBib29sZWFuKTogdm9pZCB7XHJcblxyXG4gICAgY29uc3QgdHMgPSBBbHBoYVNlc3Npb25EYXRhXHJcbiAgICAgIC5nZXRUaW1lc3RhbXBzKGF1dGhFbnZlbG9wLmV4cGlyZXNJbik7XHJcblxyXG4gICAgY29uc3Qgc2QgPSBuZXcgQWxwaGFTZXNzaW9uRGF0YShcclxuICAgICAgdHJ1ZSwgYXV0aEVudmVsb3AuYWNjZXNzVG9rZW4sXHJcbiAgICAgIHRzLnJlY2VwdGlvblRzLCB0cy5leHBpcmF0aW9uVHMpO1xyXG4gICAgc2Quc3RvcmUoKTtcclxuICAgIGNvbnNvbGUubG9nKCdzZCBwb3B1bGF0ZWQnKTtcclxuXHJcbiAgICBpZiAocmVtZW1iZXJNZSkge1xyXG4gICAgICBjb25zdCByZCA9IG5ldyBBbHBoYVJlZnJlc2hEYXRhKFxyXG4gICAgICAgIGF1dGhFbnZlbG9wLnJlZnJlc2hUb2tlbik7XHJcbiAgICAgIHJkLnN0b3JlKCk7XHJcbiAgICAgIGNvbnNvbGUubG9nKCdyZCBwb3B1bGF0ZWQnKTtcclxuICAgIH1cclxuXHJcbiAgICB0aGlzLnBvcHVsYXRlUHJpbmNpcGFsKGF1dGhFbnZlbG9wLnVzZXIpO1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBwb3B1bGF0ZVByaW5jaXBhbCh1c2VyOiBJQWxwaGFVc2VyKSB7XHJcbiAgICB0aGlzLm1QcmluY2lwYWwuc2V0VXNlcih1c2VyKTtcclxuICAgIGNvbnNvbGUubG9nKCdwcmluY2lwYWwgdXNlciBpcyBzZXQnKTtcclxuICAgIHRoaXMubVByaW5jaXBhbC5zZXRTdGF0dXMoQWxwaGFBdXRoU3RhdHVzRW51bS5BdXRoZW50aWNhdGVkKTtcclxuICAgIHRoaXMubU9uUHJpbmNpcGFsVXBkYXRlZCh0aGlzLm1QcmluY2lwYWwpO1xyXG4gIH1cclxuXHJcbn1cclxuIl19