ems-web-app-cognito
Version:
This angular.io module includes a component, service and supporting classes that wrap the Amazon Cognito Identity SDK to enable simple username/password authentication.
319 lines • 54.7 kB
JavaScript
import { Injectable } from '@angular/core';
import { HttpHeaders } from '@angular/common/http';
import { BehaviorSubject, of } from 'rxjs';
import { map } from "rxjs/operators";
import 'cross-fetch/polyfill';
import { CognitoUser, CognitoUserPool, CognitoUserSession, CognitoIdToken, CognitoAccessToken, CognitoRefreshToken, AuthenticationDetails } from 'amazon-cognito-identity-js';
import { CognitoResponseType, CognitoRequestType } from "./cognito.types";
import { EphemeralStorage } from "./cognito.classes";
import { params } from "./cognito.utils";
import { jwtDecode } from "jwt-decode";
import * as i0 from "@angular/core";
import * as i1 from "@angular/common/http";
export class CognitoService {
constructor(http) {
this.http = http;
this.sessionSource = new BehaviorSubject(null);
this.session$ = this.sessionSource.asObservable();
this.userSource = new BehaviorSubject(null);
this.user$ = this.userSource.asObservable();
this.formSource = new BehaviorSubject(null);
this.form$ = this.formSource.asObservable();
this.user = null;
this.storage = new EphemeralStorage();
this.useLocalStorage = true;
}
initialize(UserPoolId, ClientId, useLocalStorage = true, idToken, accessToken, refreshToken) {
//for federated users
const access = params("access_token") ?? accessToken ?? localStorage.getItem("ems_access_token") ?? null;
const id = params("id_token") ?? idToken ?? localStorage.getItem("ems_id_token") ?? null;
const sessionId = params("sessionId") ?? null;
const otp = params("otp") ?? null;
this.useLocalStorage = useLocalStorage;
if (useLocalStorage && access && id) {
localStorage.setItem("ems_access_token", access);
localStorage.setItem("ems_id_token", id);
window.location.hash = "";
}
this.accessToken = access;
this.idToken = id;
//for srp users
if (useLocalStorage) {
this.pool = new CognitoUserPool({ UserPoolId, ClientId });
this.user = this.pool.getCurrentUser();
this.userSource.next(this.user);
this.user?.getSession((e, session) => this.sessionSource.next(session));
}
else {
this.setCognitoUserFromToken(UserPoolId, ClientId, idToken, accessToken, refreshToken);
}
}
setCognitoUserFromToken(UserPoolId, ClientId, idToken, accessToken, refreshToken) {
this.pool = new CognitoUserPool({ UserPoolId, ClientId, Storage: this.storage });
if (idToken) {
const decoded = jwtDecode(idToken);
this.user = new CognitoUser({
Username: decoded['cognito:username'],
Pool: this.pool,
Storage: this.storage
});
const idTokenObj = new CognitoIdToken({ IdToken: idToken });
const accessTokenObj = new CognitoAccessToken({ AccessToken: accessToken });
const refreshTokenObj = new CognitoRefreshToken({ RefreshToken: refreshToken });
const session = new CognitoUserSession({ IdToken: idTokenObj, AccessToken: accessTokenObj, RefreshToken: refreshTokenObj });
// Set the session to the Cognito user
this.user.setSignInUserSession(session);
}
else {
this.user = this.pool.getCurrentUser();
}
this.userSource.next(this.user);
this.user?.getSession((e, session) => this.sessionSource.next(session));
return this.user;
}
;
magicLinkAuthenticate(Username, ChallengeResponse, SessionId) {
const request = ChallengeResponse ? CognitoRequestType.MagicLink : CognitoRequestType.Authentication;
const details = new AuthenticationDetails({ Username });
const data = { Username, Pool: this.pool };
if (!this.useLocalStorage)
data.Storage = this.storage;
const user = this.user = this.user ?? new CognitoUser(data);
this.user.setAuthenticationFlowType('CUSTOM_AUTH');
//@ts-ignore
if (SessionId)
this.user.Session = SessionId;
return new Promise(async (resolve, reject) => {
const handler = {
onSuccess: (session) => {
this.sessionSource.next(session);
this.userSource.next(this.user);
resolve({ type: CognitoResponseType.Authenticated, session, user, request });
},
onFailure: (error) => reject({ type: CognitoResponseType.NotAuthorized, error, user, request, session: null }),
customChallenge: (challengeParameters) => {
resolve({ type: CognitoResponseType.MagicLink, user, request, challengeParameters });
}
};
if (ChallengeResponse)
user.sendCustomChallengeAnswer(ChallengeResponse, handler);
else
user.initiateAuth(details, handler);
});
}
passkeyAuthenticate(Username, ChallengeResponse) {
const request = ChallengeResponse ? CognitoRequestType.Passkey : CognitoRequestType.Authentication;
const details = new AuthenticationDetails({ Username });
const data = { Username, Pool: this.pool };
if (!this.useLocalStorage)
data.Storage = this.storage;
const user = this.user = this.user ?? new CognitoUser(data);
this.user.setAuthenticationFlowType('CUSTOM_AUTH');
return new Promise(async (resolve, reject) => {
const handler = {
onSuccess: (session) => {
this.sessionSource.next(session);
this.userSource.next(this.user);
resolve({ type: CognitoResponseType.Authenticated, session, user, request });
},
onFailure: (error) => reject({ type: CognitoResponseType.NotAuthorized, error, user, request, session: null }),
customChallenge: (challengeParameters) => resolve({ type: CognitoResponseType.Passkey, user, request, challengeParameters })
};
if (ChallengeResponse)
user.sendCustomChallengeAnswer(ChallengeResponse, handler);
else
user.initiateAuth(details, handler);
});
}
otpAuthenticate(Username, ChallengeResponse) {
const request = ChallengeResponse ? CognitoRequestType.OtpChallenge : CognitoRequestType.Authentication;
const details = new AuthenticationDetails({ Username });
const data = { Username, Pool: this.pool };
if (!this.useLocalStorage)
data.Storage = this.storage;
const user = this.user = this.user ?? new CognitoUser(data);
this.user.setAuthenticationFlowType('CUSTOM_AUTH');
return new Promise(async (resolve, reject) => {
const handler = {
onSuccess: (session) => {
this.sessionSource.next(session);
this.userSource.next(this.user);
resolve({ type: CognitoResponseType.Authenticated, session, user, request });
},
onFailure: (error) => reject({ type: CognitoResponseType.NotAuthorized, error, user, request, session: null }),
customChallenge: (challengeParameters) => resolve({ type: CognitoResponseType.OtpChallenge, user, request, challengeParameters })
};
if (ChallengeResponse)
user.sendCustomChallengeAnswer(ChallengeResponse, handler);
else
user.initiateAuth(details, handler);
});
}
getUserInfo(url) {
const request = `${url}/oauth2/userInfo`;
const headers = this.headers();
return this.http.get(request, { headers, withCredentials: true }).pipe(map((result) => {
return {
email: result.email,
username: result.username,
sub: result.sub,
firstName: result.given_name,
lastName: result.family_name,
accessToken: this.accessToken,
idToken: this.idToken
};
})).toPromise();
//, catchError(this.handleErrorQuietly)
}
setUserSession(session) {
this.sessionSource.next(session);
}
showForm(form) {
this.formSource.next(form);
}
logout() {
return new Promise((resolve, reject) => {
if (this.user) {
this.userSource.next(null);
this.sessionSource.next(null);
localStorage.removeItem("ems_id_token");
localStorage.removeItem("ems_access_token");
this.user.globalSignOut({
onSuccess: resolve,
onFailure: () => {
//if user is disabled, must manually clear local storage (apparently)
for (let prop in localStorage) {
if (prop.match(/cognito/i))
localStorage.removeItem(prop);
}
resolve(null);
}
});
}
else {
resolve(null);
}
});
}
authenticate(Username, Password) {
const details = new AuthenticationDetails({ Username, Password });
const data = { Username, Pool: this.pool };
if (!this.useLocalStorage)
data.Storage = this.storage;
const user = new CognitoUser(data);
return new Promise((resolve, reject) => {
if (!this.user)
this.authenticateUser(user, details, resolve, reject);
else
this.getUserSession(resolve, reject);
});
}
createFederatedSession(IdToken, AccessToken) {
const session = new CognitoUserSession({
IdToken: new CognitoIdToken({ IdToken }),
AccessToken: new CognitoAccessToken({ AccessToken }),
});
const Username = session.getIdToken().payload["cognito:username"];
const data = { Username, Pool: this.pool };
if (!this.useLocalStorage)
data.Storage = this.storage;
this.user = new CognitoUser(data);
this.userSource.next(this.user);
this.sessionSource.next(session);
}
completePasswordUpdate(password, user, attributes) {
const request = CognitoRequestType.NewUserPasswordReset;
return new Promise((resolve, reject) => {
user.completeNewPasswordChallenge(password, attributes, {
onSuccess: (session) => {
this.user = user;
this.userSource.next(user);
this.sessionSource.next(session);
resolve({ type: CognitoResponseType.Authenticated, session, user, request: CognitoRequestType.Authentication });
},
onFailure: (error) => reject({ type: CognitoResponseType.NotAuthorized, error, user, request, session: null })
});
});
}
requestVerificationCode(Username) {
const data = { Username, Pool: this.pool };
if (!this.useLocalStorage)
data.Storage = this.storage;
const user = new CognitoUser(data);
return this.forgotPassword(user);
}
resetPassword(user, oldPassword, newPassword) {
const request = CognitoRequestType.PasswordReset;
return new Promise((resolve, reject) => {
user.changePassword(oldPassword, newPassword, (error, result) => {
if (error)
reject({ type: CognitoResponseType.LimitExceededException, user, request, error, session: null });
else
resolve({ type: CognitoResponseType.Success, user, request, session: null });
});
});
}
forgotPassword(user) {
const request = CognitoRequestType.ForgotPassword;
return new Promise((resolve, reject) => {
user.forgotPassword({
onSuccess: (response) => resolve({ type: CognitoResponseType.Success, user, request, session: null }),
onFailure: (error) => reject({ type: CognitoResponseType.LimitExceededException, error, user, request, session: null })
});
});
}
confirmPassword(user, code, password) {
const request = CognitoRequestType.ConfirmPassword;
return new Promise((resolve, reject) => {
user.confirmPassword(code, password, {
onSuccess: (response) => { resolve({ type: CognitoResponseType.Success, user, request, session: null }); },
onFailure: (error) => reject({ type: CognitoResponseType.InvalidCode, error, user, request, session: null })
});
});
}
authenticateUser(user, details, resolve, reject) {
const request = CognitoRequestType.Authentication;
user.authenticateUser(details, {
onSuccess: (session) => {
this.sessionSource.next(session);
this.userSource.next(user);
this.user = user;
resolve({ type: CognitoResponseType.Authenticated, session, user, request });
},
onFailure: (error) => reject({ type: CognitoResponseType.NotAuthorized, error, user, request, session: null }),
newPasswordRequired: (userAttributes, requiredAttributes) => {
resolve({ type: CognitoResponseType.PasswordReset, userAttributes, requiredAttributes, user, request, session: null });
}
});
}
getUserSession(resolve, reject) {
const request = CognitoRequestType.Authentication;
this.user.getSession((error, session) => {
if (error)
reject({ type: CognitoResponseType.Authenticated, session, user: this.user, request, error });
else {
this.sessionSource.next(session);
resolve({ type: CognitoResponseType.Authenticated, session, user: this.user, request });
}
});
}
handleErrorQuietly(error) {
return of(error);
}
headers(custom = {}) {
const headers = {
"Content-Type": "application/json",
"Authorization": this.accessToken ? `Bearer ${this.accessToken}` : ""
};
return new HttpHeaders(headers);
}
}
CognitoService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.7", ngImport: i0, type: CognitoService, deps: [{ token: i1.HttpClient }], target: i0.ɵɵFactoryTarget.Injectable });
CognitoService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "13.2.7", ngImport: i0, type: CognitoService, providedIn: 'root' });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.7", ngImport: i0, type: CognitoService, decorators: [{
type: Injectable,
args: [{
providedIn: 'root'
}]
}], ctorParameters: function () { return [{ type: i1.HttpClient }]; } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29nbml0by5zZXJ2aWNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2xpYi9jb2duaXRvLnNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUMzQyxPQUFPLEVBQWMsV0FBVyxFQUE0RCxNQUFNLHNCQUFzQixDQUFDO0FBQ3pILE9BQU8sRUFBdUIsZUFBZSxFQUFjLEVBQUUsRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUM1RSxPQUFPLEVBQWMsR0FBRyxFQUFhLE1BQU0sZ0JBQWdCLENBQUM7QUFDNUQsT0FBTyxzQkFBc0IsQ0FBQztBQUM5QixPQUFPLEVBQUUsV0FBVyxFQUFFLGVBQWUsRUFBRSxrQkFBa0IsRUFBRSxjQUFjLEVBQUUsa0JBQWtCLEVBQUUsbUJBQW1CLEVBQUUscUJBQXFCLEVBQUUsTUFBTyw0QkFBNEIsQ0FBQztBQUUvSyxPQUFPLEVBQUUsbUJBQW1CLEVBQUUsa0JBQWtCLEVBQW1CLE1BQU0saUJBQWlCLENBQUM7QUFDM0YsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sbUJBQW1CLENBQUM7QUFDckQsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQ3pDLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxZQUFZLENBQUM7OztBQUt2QyxNQUFNLE9BQU8sY0FBYztJQW9CekIsWUFBb0IsSUFBZ0I7UUFBaEIsU0FBSSxHQUFKLElBQUksQ0FBWTtRQWxCNUIsa0JBQWEsR0FBK0MsSUFBSSxlQUFlLENBQTRCLElBQUksQ0FBQyxDQUFDO1FBQ2xILGFBQVEsR0FBMEMsSUFBSSxDQUFDLGFBQWEsQ0FBQyxZQUFZLEVBQUUsQ0FBQztRQUVuRixlQUFVLEdBQXdDLElBQUksZUFBZSxDQUFxQixJQUFJLENBQUMsQ0FBQztRQUNqRyxVQUFLLEdBQW1DLElBQUksQ0FBQyxVQUFVLENBQUMsWUFBWSxFQUFFLENBQUM7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LENBQUMsQ0FBQTtJQUNKLENBQUM7SUFFTyxrQkFBa0IsQ0FBQyxLQUF3QjtRQUNqRCxPQUFPLEVBQUUsQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUNuQixDQUFDO0lBRU8sT0FBTyxDQUFDLFNBQWMsRUFBRTtRQUM5QixNQUFNLE9BQU8sR0FBRztZQUNWLGNBQWMsRUFBRSxrQkFBa0I7WUFDbEMsZUFBZSxFQUFFLElBQUksQ0FBQyxXQUFXLENBQUMsQ0FBQyxDQUFDLFVBQVUsSUFBSSxDQUFDLFdBQVcsRUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFFO1NBQ3ZFLENBQUM7UUFDTCxPQUFPLElBQUksV0FBVyxDQUFDLE9BQU8sQ0FBQyxDQUFDO0lBQ2xDLENBQUM7OzJHQXhVVSxjQUFjOytHQUFkLGNBQWMsY0FGYixNQUFNOzJGQUVQLGNBQWM7a0JBSDFCLFVBQVU7bUJBQUM7b0JBQ1YsVUFBVSxFQUFFLE1BQU07aUJBQ25CIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgSW5qZWN0YWJsZSB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgSHR0cENsaWVudCwgSHR0cEhlYWRlcnMsIEh0dHBSZXNwb25zZSwgSHR0cFJlcXVlc3QsIEh0dHBFcnJvclJlc3BvbnNlLCBIdHRwUGFyYW1zIH0gZnJvbSAnQGFuZ3VsYXIvY29tbW9uL2h0dHAnO1xuaW1wb3J0IHsgT2JzZXJ2YWJsZSwgU3ViamVjdCwgQmVoYXZpb3JTdWJqZWN0LCB0aHJvd0Vycm9yLCBvZiB9IGZyb20gJ3J4anMnO1xuaW1wb3J0IHsgY2F0Y2hFcnJvciwgbWFwLCB0YXAsIHRha2UgfSBmcm9tIFwicnhqcy9vcGVyYXRvcnNcIjtcbmltcG9ydCAnY3Jvc3MtZmV0Y2gvcG9seWZpbGwnO1xuaW1wb3J0IHsgQ29nbml0b1VzZXIsIENvZ25pdG9Vc2VyUG9vbCwgQ29nbml0b1VzZXJTZXNzaW9uLCBDb2duaXRvSWRUb2tlbiwgQ29nbml0b0FjY2Vzc1Rva2VuLCBDb2duaXRvUmVmcmVzaFRva2VuLCBBdXRoZW50aWNhdGlvbkRldGFpbHMgfSAgZnJvbSAnYW1hem9uLWNvZ25pdG8taWRlbnRpdHktanMnO1xuaW1wb3J0IHsgSUNvZ25pdG9SZXNwb25zZSwgSUNvZ25pdG9Vc2VyRGF0YSB9IGZyb20gXCIuL2NvZ25pdG8uaW50ZXJmYWNlc1wiO1xuaW1wb3J0IHsgQ29nbml0b1Jlc3BvbnNlVHlwZSwgQ29nbml0b1JlcXVlc3RUeXBlLCBDb2duaXRvRm9ybVR5cGUgfSBmcm9tIFwiLi9jb2duaXRvLnR5cGVzXCI7XG5pbXBvcnQgeyBFcGhlbWVyYWxTdG9yYWdlIH0gZnJvbSBcIi4vY29nbml0by5jbGFzc2VzXCI7XG5pbXBvcnQgeyBwYXJhbXMgfSBmcm9tIFwiLi9jb2duaXRvLnV0aWxzXCI7XG5pbXBvcnQgeyBqd3REZWNvZGUgfSBmcm9tIFwiand0LWRlY29kZVwiO1xuXG5ASW5qZWN0YWJsZSh7XG4gIHByb3ZpZGVkSW46ICdyb290J1xufSlcbmV4cG9ydCBjbGFzcyBDb2duaXRvU2VydmljZSB7XG5cbiAgcHJpdmF0ZSBzZXNzaW9uU291cmNlOiBCZWhhdmlvclN1YmplY3Q8Q29nbml0b1VzZXJTZXNzaW9uIHwgbnVsbD4gPSBuZXcgQmVoYXZpb3JTdWJqZWN0PENvZ25pdG9Vc2VyU2Vzc2lvbiB8IG51bGw+KG51bGwpO1xuICBwdWJsaWMgc2Vzc2lvbiQ6IE9ic2VydmFibGU8Q29nbml0b1VzZXJTZXNzaW9uIHwgbnVsbD4gPSB0aGlzLnNlc3Npb25Tb3VyY2UuYXNPYnNlcnZhYmxlKCk7XG5cbiAgcHJpdmF0ZSB1c2VyU291cmNlOiBCZWhhdmlvclN1YmplY3Q8Q29nbml0b1VzZXIgfCBudWxsPiA9IG5ldyBCZWhhdmlvclN1YmplY3Q8Q29nbml0b1VzZXIgfCBudWxsPihudWxsKTtcbiAgcHVibGljIHVzZXIkOiBPYnNlcnZhYmxlPENvZ25pdG9Vc2VyIHwgbnVsbD4gPSB0aGlzLnVzZXJTb3VyY2UuYXNPYnNlcnZhYmxlKCk7XG5cbiAgcHJpdmF0ZSBmb3JtU291cmNlOiBCZWhhdmlvclN1YmplY3Q8Q29nbml0b0Zvcm1UeXBlIHwgbnVsbD4gPSBuZXcgQmVoYXZpb3JTdWJqZWN0PENvZ25pdG9Gb3JtVHlwZSB8IG51bGw+KG51bGwpO1xuICBwdWJsaWMgZm9ybSQ6IE9ic2VydmFibGU8Q29nbml0b0Zvcm1UeXBlIHwgbnVsbD4gPSB0aGlzLmZvcm1Tb3VyY2UuYXNPYnNlcnZhYmxlKCk7XG5cblxuICBwcml2YXRlIHVzZXI6IENvZ25pdG9Vc2VyIHwgbnVsbCA9IG51bGw7XG4gIHByaXZhdGUgcG9vbCE6IENvZ25pdG9Vc2VyUG9vbDtcblxuICBwcml2YXRlIGFjY2Vzc1Rva2VuPzogc3RyaW5nO1xuICBwcml2YXRlIGlkVG9rZW4/OiBzdHJpbmc7XG4gIHByaXZhdGUgc3RvcmFnZTogRXBoZW1lcmFsU3RvcmFnZSA9IG5ldyBFcGhlbWVyYWxTdG9yYWdlKCk7XG4gIHByaXZhdGUgdXNlTG9jYWxTdG9yYWdlOiBib29sZWFuID0gdHJ1ZTtcblxuICBjb25zdHJ1Y3Rvcihwcml2YXRlIGh0dHA6IEh0dHBDbGllbnQpIHtcblxuICB9XG5cbiAgcHVibGljIGluaXRpYWxpemUoVXNlclBvb2xJZDogc3RyaW5nLCBDbGllbnRJZDogc3RyaW5nLCB1c2VMb2NhbFN0b3JhZ2U6IGJvb2xlYW4gPSB0cnVlLCBpZFRva2VuPzogc3RyaW5nLCBhY2Nlc3NUb2tlbj86IHN0cmluZywgcmVmcmVzaFRva2VuPzogc3RyaW5nICkge1xuXG4gICAgLy9mb3IgZmVkZXJhdGVkIHVzZXJzXG4gICAgY29uc3QgYWNjZXNzID0gcGFyYW1zKFwiYWNjZXNzX3Rva2VuXCIpID8/IGFjY2Vzc1Rva2VuID8/IGxvY2FsU3RvcmFnZS5nZXRJdGVtKFwiZW1zX2FjY2Vzc190b2tlblwiKSA/PyBudWxsO1xuICAgIGNvbnN0IGlkID0gcGFyYW1zKFwiaWRfdG9rZW5cIikgPz8gaWRUb2tlbiA/PyBsb2NhbFN0b3JhZ2UuZ2V0SXRlbShcImVtc19pZF90b2tlblwiKSA/PyBudWxsO1xuICAgIGNvbnN0IHNlc3Npb25JZCA9IHBhcmFtcyhcInNlc3Npb25JZFwiKSA/PyBudWxsO1xuICAgIGNvbnN0IG90cCA9IHBhcmFtcyhcIm90cFwiKSA/PyBudWxsO1xuXG4gICAgdGhpcy51c2VMb2NhbFN0b3JhZ2UgPSB1c2VMb2NhbFN0b3JhZ2U7XG5cbiAgICBpZih1c2VMb2NhbFN0b3JhZ2UgJiYgYWNjZXNzICYmIGlkKSB7XG4gICAgICBsb2NhbFN0b3JhZ2Uuc2V0SXRlbShcImVtc19hY2Nlc3NfdG9rZW5cIiwgYWNjZXNzKTtcbiAgICAgIGxvY2FsU3RvcmFnZS5zZXRJdGVtKFwiZW1zX2lkX3Rva2VuXCIsIGlkKTtcbiAgICAgIHdpbmRvdy5sb2NhdGlvbi5oYXNoID0gXCJcIjtcbiAgICB9IFxuXG4gICAgdGhpcy5hY2Nlc3NUb2tlbiA9IGFjY2VzcztcbiAgICB0aGlzLmlkVG9rZW4gPSBpZDtcblxuICAgIC8vZm9yIHNycCB1c2Vyc1xuICAgIGlmKHVzZUxvY2FsU3RvcmFnZSkge1xuICAgICAgdGhpcy5wb29sID0gbmV3IENvZ25pdG9Vc2VyUG9vbCh7IFVzZXJQb29sSWQsIENsaWVudElkIH0pO1xuICAgICAgdGhpcy51c2VyID0gdGhpcy5wb29sLmdldEN1cnJlbnRVc2VyKCk7XG4gICAgICB0aGlzLnVzZXJTb3VyY2UubmV4dCh0aGlzLnVzZXIpO1xuICAgICAgdGhpcy51c2VyPy5nZXRTZXNzaW9uKChlOiBFcnJvciwgc2Vzc2lvbjogbnVsbCkgPT4gdGhpcy5zZXNzaW9uU291cmNlLm5leHQoc2Vzc2lvbikpO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLnNldENvZ25pdG9Vc2VyRnJvbVRva2VuKFVzZXJQb29sSWQsIENsaWVudElkLCBpZFRva2VuLCBhY2Nlc3NUb2tlbiwgcmVmcmVzaFRva2VuKTtcbiAgICB9XG4gICAgXG4gIH1cblxuICBwdWJsaWMgc2V0Q29nbml0b1VzZXJGcm9tVG9rZW4gKFVzZXJQb29sSWQ6IHN0cmluZywgQ2xpZW50SWQ6IHN0cmluZywgaWRUb2tlbj86IHN0cmluZywgYWNjZXNzVG9rZW4/OiBzdHJpbmcsIHJlZnJlc2hUb2tlbj86IHN0cmluZykge1xuICAgICAgdGhpcy5wb29sID0gbmV3IENvZ25pdG9Vc2VyUG9vbCh7IFVzZXJQb29sSWQsIENsaWVudElkLCBTdG9yYWdlOiB0aGlzLnN0b3JhZ2UgfSk7XG4gICAgICBcbiAgICAgIGlmKGlkVG9rZW4pIHtcbiAgICAgICAgY29uc3QgZGVjb2RlZDogYW55ID0gand0RGVjb2RlKGlkVG9rZW4pO1xuICAgICAgICB0aGlzLnVzZXIgPSBuZXcgQ29nbml0b1VzZXIoe1xuICAgICAgICAgICAgVXNlcm5hbWU6IGRlY29kZWRbJ2NvZ25pdG86dXNlcm5hbWUnXSxcbiAgICAgICAgICAgIFBvb2w6IHRoaXMucG9vbCwgXG4gICAgICAgICAgICBTdG9yYWdlOiB0aGlzLnN0b3JhZ2VcbiAgICAgICAgfSk7XG5cbiAgICAgICAgY29uc3QgaWRUb2tlbk9iaiA9IG5ldyBDb2duaXRvSWRUb2tlbih7IElkVG9rZW46IGlkVG9rZW4gfSk7XG4gICAgICAgIGNvbnN0IGFjY2Vzc1Rva2VuT2JqID0gbmV3IENvZ25pdG9BY2Nlc3NUb2tlbih7IEFjY2Vzc1Rva2VuOiBhY2Nlc3NUb2tlbiEgfSk7XG4gICAgICAgIGNvbnN0IHJlZnJlc2hUb2tlbk9iaiA9IG5ldyBDb2duaXRvUmVmcmVzaFRva2VuKHsgUmVmcmVzaFRva2VuOiByZWZyZXNoVG9rZW4hIH0pO1xuICAgICAgICBjb25zdCBzZXNzaW9uID0gbmV3IENvZ25pdG9Vc2VyU2Vzc2lvbih7IElkVG9rZW46IGlkVG9rZW5PYmosIEFjY2Vzc1Rva2VuOiBhY2Nlc3NUb2tlbk9iaiwgUmVmcmVzaFRva2VuOiByZWZyZXNoVG9rZW5PYmogfSk7XG5cbiAgICAgICAgLy8gU2V0IHRoZSBzZXNzaW9uIHRvIHRoZSBDb2duaXRvIHVzZXJcbiAgICAgICAgdGhpcy51c2VyLnNldFNpZ25JblVzZXJTZXNzaW9uKHNlc3Npb24pO1xuICAgICAgICBcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRoaXMudXNlciA9IHRoaXMucG9vbC5nZXRDdXJyZW50VXNlcigpO1xuICAgICAgfVxuICAgICAgXG4gICAgICB0aGlzLnVzZXJTb3VyY2UubmV4dCh0aGlzLnVzZXIpO1xuICAgICAgdGhpcy51c2VyPy5nZXRTZXNzaW9uKChlOiBFcnJvciwgc2Vzc2lvbjogbnVsbCkgPT4gdGhpcy5zZXNzaW9uU291cmNlLm5leHQoc2Vzc2lvbikpO1xuICAgICAgcmV0dXJuIHRoaXMudXNlcjtcbiAgfTtcblxuICBwdWJsaWMgbWFnaWNMaW5rQXV0aGVudGljYXRlKFVzZXJuYW1lOiBzdHJpbmcsIENoYWxsZW5nZVJlc3BvbnNlPzogc3RyaW5nLCBTZXNzaW9uSWQ/OiBzdHJpbmcpIHtcbiAgICBjb25zdCByZXF1ZXN0ID0gQ2hhbGxlbmdlUmVzcG9uc2UgPyBDb2duaXRvUmVxdWVzdFR5cGUuTWFnaWNMaW5rIDogQ29nbml0b1JlcXVlc3RUeXBlLkF1dGhlbnRpY2F0aW9uO1xuICAgIGNvbnN0IGRldGFpbHMgPSBuZXcgQXV0aGVudGljYXRpb25EZXRhaWxzKHsgVXNlcm5hbWUgfSk7XG4gICAgY29uc3QgZGF0YTogYW55ID0geyBVc2VybmFtZSwgUG9vbDogdGhpcy5wb29sIH07XG4gICAgaWYoIXRoaXMudXNlTG9jYWxTdG9yYWdlKSBkYXRhLlN0b3JhZ2UgPSB0aGlzLnN0b3JhZ2U7XG4gICAgY29uc3QgdXNlciA9IHRoaXMudXNlciA9IHRoaXMudXNlciA/PyBuZXcgQ29nbml0b1VzZXIoZGF0YSk7XG4gICAgdGhpcy51c2VyLnNldEF1dGhlbnRpY2F0aW9uRmxvd1R5cGUoJ0NVU1RPTV9BVVRIJyk7XG5cbiAgICAvL0B0cy1pZ25vcmVcbiAgICBpZihTZXNzaW9uSWQpIHRoaXMudXNlci5TZXNzaW9uID0gU2Vzc2lvbklkO1xuXG4gICAgcmV0dXJuIG5ldyBQcm9taXNlKGFzeW5jKCByZXNvbHZlOiAocmVzdWx0OiBhbnkpID0+dm9pZCwgcmVqZWN0OiAocmVzdWx0OiBhbnkpID0+IHZvaWQpID0+IHtcbiAgICAgIGNvbnN0IGhhbmRsZXIgPSB7XG4gICAgICAgIG9uU3VjY2VzczogKHNlc3Npb246IENvZ25pdG9Vc2VyU2Vzc2lvbikgPT4ge1xuICAgICAgICAgIHRoaXMuc2Vzc2lvblNvdXJjZS5uZXh0KHNlc3Npb24pO1xuICAgICAgICAgIHRoaXMudXNlclNvdXJjZS5uZXh0KHRoaXMudXNlcik7XG4gICAgICAgICAgcmVzb2x2ZSh7IHR5cGU6IENvZ25pdG9SZXNwb25zZVR5cGUuQXV0aGVudGljYXRlZCwgc2Vzc2lvbiwgdXNlciwgcmVxdWVzdCB9KVxuICAgICAgICB9LFxuICAgICAgICBvbkZhaWx1cmU6IChlcnJvcjogYW55KT0+IHJlamVjdCh7IHR5cGU6IENvZ25pdG9SZXNwb25zZVR5cGUuTm90QXV0aG9yaXplZCwgZXJyb3IsIHVzZXIsIHJlcXVlc3QsIHNlc3Npb246IG51bGwgfSksXG4gICAgICAgIGN1c3RvbUNoYWxsZW5nZTogKGNoYWxsZW5nZVBhcmFtZXRlcnM6IGFueSkgPT4ge1xuICAgICAgICAgIHJlc29sdmUoeyB0eXBlOiBDb2duaXRvUmVzcG9uc2VUeXBlLk1hZ2ljTGluaywgdXNlciwgcmVxdWVzdCwgY2hhbGxlbmdlUGFyYW1ldGVycyB9KTtcbiAgICAgICAgfVxuICAgICAgfTtcbiAgICAgIFxuICAgICAgaWYoQ2hhbGxlbmdlUmVzcG9uc2UpIHVzZXIuc2VuZEN1c3RvbUNoYWxsZW5nZUFuc3dlcihDaGFsbGVuZ2VSZXNwb25zZSwgaGFuZGxlcik7XG4gICAgICBlbHNlIHVzZXIuaW5pdGlhdGVBdXRoKGRldGFpbHMsIGhhbmRsZXIpO1xuICAgIH0pO1xuICB9XG5cbiAgcHVibGljIHBhc3NrZXlBdXRoZW50aWNhdGUoVXNlcm5hbWU6IHN0cmluZywgQ2hhbGxlbmdlUmVzcG9uc2U/OiBzdHJpbmcpIHtcbiAgICBjb25zdCByZXF1ZXN0ID0gQ2hhbGxlbmdlUmVzcG9uc2UgPyBDb2duaXRvUmVxdWVzdFR5cGUuUGFzc2tleSA6IENvZ25pdG9SZXF1ZXN0VHlwZS5BdXRoZW50aWNhdGlvbjtcbiAgICBjb25zdCBkZXRhaWxzID0gbmV3IEF1dGhlbnRpY2F0aW9uRGV0YWlscyh7IFVzZXJuYW1lIH0pO1xuICAgIGNvbnN0IGRhdGE6YW55ID0geyBVc2VybmFtZSwgUG9vbDogdGhpcy5wb29sIH07XG4gICAgaWYoIXRoaXMudXNlTG9jYWxTdG9yYWdlKSBkYXRhLlN0b3JhZ2UgPSB0aGlzLnN0b3JhZ2U7XG4gICAgY29uc3QgdXNlciA9IHRoaXMudXNlciA9IHRoaXMudXNlciA/PyBuZXcgQ29nbml0b1VzZXIoZGF0YSk7XG4gICAgdGhpcy51c2VyLnNldEF1dGhlbnRpY2F0aW9uRmxvd1R5cGUoJ0NVU1RPTV9BVVRIJyk7XG5cbiAgICByZXR1cm4gbmV3IFByb21pc2UoYXN5bmMoIHJlc29sdmU6IChyZXN1bHQ6IGFueSkgPT52b2lkLCByZWplY3Q6IChyZXN1bHQ6IGFueSkgPT4gdm9pZCkgPT4ge1xuICAgICAgY29uc3QgaGFuZGxlciA9IHtcbiAgICAgICAgb25TdWNjZXNzOiAoc2Vzc2lvbjogQ29nbml0b1VzZXJTZXNzaW9uKSA9PiB7XG4gICAgICAgICAgdGhpcy5zZXNzaW9uU291cmNlLm5leHQoc2Vzc2lvbik7XG4gICAgICAgICAgdGhpcy51c2VyU291cmNlLm5leHQodGhpcy51c2VyKTtcbiAgICAgICAgICByZXNvbHZlKHsgdHlwZTogQ29nbml0b1Jlc3BvbnNlVHlwZS5BdXRoZW50aWNhdGVkLCBzZXNzaW9uLCB1c2VyLCByZXF1ZXN0IH0pXG4gICAgICAgIH0sXG4gICAgICAgIG9uRmFpbHVyZTogKGVycm9yOiBhbnkpPT4gcmVqZWN0KHsgdHlwZTogQ29nbml0b1Jlc3BvbnNlVHlwZS5Ob3RBdXRob3JpemVkLCBlcnJvciwgdXNlciwgcmVxdWVzdCwgc2Vzc2lvbjogbnVsbCB9KSxcbiAgICAgICAgY3VzdG9tQ2hhbGxlbmdlOiAoY2hhbGxlbmdlUGFyYW1ldGVyczogYW55KSA9PiByZXNvbHZlKHsgdHlwZTogQ29nbml0b1Jlc3BvbnNlVHlwZS5QYXNza2V5LCB1c2VyLCByZXF1ZXN0LCBjaGFsbGVuZ2VQYXJhbWV0ZXJzIH0pXG4gICAgICB9O1xuICAgICAgXG4gICAgICBpZihDaGFsbGVuZ2VSZXNwb25zZSkgdXNlci5zZW5kQ3VzdG9tQ2hhbGxlbmdlQW5zd2VyKENoYWxsZW5nZVJlc3BvbnNlLCBoYW5kbGVyKTtcbiAgICAgIGVsc2UgdXNlci5pbml0aWF0ZUF1dGgoZGV0YWlscywgaGFuZGxlcik7XG4gICAgfSk7XG4gIH1cblxuICBwdWJsaWMgb3RwQXV0aGVudGljYXRlKFVzZXJuYW1lOiBzdHJpbmcsIENoYWxsZW5nZVJlc3BvbnNlPzogc3RyaW5nKSB7XG4gICAgY29uc3QgcmVxdWVzdCA9IENoYWxsZW5nZVJlc3BvbnNlID8gQ29nbml0b1JlcXVlc3RUeXBlLk90cENoYWxsZW5nZSA6IENvZ25pdG9SZXF1ZXN0VHlwZS5BdXRoZW50aWNhdGlvbjtcbiAgICBjb25zdCBkZXRhaWxzID0gbmV3IEF1dGhlbnRpY2F0aW9uRGV0YWlscyh7IFVzZXJuYW1lIH0pO1xuICAgIGNvbnN0IGRhdGE6YW55ID0geyBVc2VybmFtZSwgUG9vbDogdGhpcy5wb29sIH07XG4gICAgaWYoIXRoaXMudXNlTG9jYWxTdG9yYWdlKSBkYXRhLlN0b3JhZ2UgPSB0aGlzLnN0b3JhZ2U7XG4gICAgY29uc3QgdXNlciA9IHRoaXMudXNlciA9IHRoaXMudXNlciA/PyBuZXcgQ29nbml0b1VzZXIoZGF0YSk7XG4gICAgdGhpcy51c2VyLnNldEF1dGhlbnRpY2F0aW9uRmxvd1R5cGUoJ0NVU1RPTV9BVVRIJyk7XG5cbiAgICByZXR1cm4gbmV3IFByb21pc2UoYXN5bmMoIHJlc29sdmU6IChyZXN1bHQ6IGFueSkgPT52b2lkLCByZWplY3Q6IChyZXN1bHQ6IGFueSkgPT4gdm9pZCkgPT4ge1xuICAgICAgY29uc3QgaGFuZGxlciA9IHtcbiAgICAgICAgb25TdWNjZXNzOiAoc2Vzc2lvbjogQ29nbml0b1VzZXJTZXNzaW9uKSA9PiB7XG4gICAgICAgICAgdGhpcy5zZXNzaW9uU291cmNlLm5leHQoc2Vzc2lvbik7XG4gICAgICAgICAgdGhpcy51c2VyU291cmNlLm5leHQodGhpcy51c2VyKTtcbiAgICAgICAgICByZXNvbHZlKHsgdHlwZTogQ29nbml0b1Jlc3BvbnNlVHlwZS5BdXRoZW50aWNhdGVkLCBzZXNzaW9uLCB1c2VyLCByZXF1ZXN0IH0pXG4gICAgICAgIH0sXG4gICAgICAgIG9uRmFpbHVyZTogKGVycm9yOiBhbnkpPT4gcmVqZWN0KHsgdHlwZTogQ29nbml0b1Jlc3BvbnNlVHlwZS5Ob3RBdXRob3JpemVkLCBlcnJvciwgdXNlciwgcmVxdWVzdCwgc2Vzc2lvbjogbnVsbCB9KSxcbiAgICAgICAgY3VzdG9tQ2hhbGxlbmdlOiAoY2hhbGxlbmdlUGFyYW1ldGVyczogYW55KSA9PiByZXNvbHZlKHsgdHlwZTogQ29nbml0b1Jlc3BvbnNlVHlwZS5PdHBDaGFsbGVuZ2UsIHVzZXIsIHJlcXVlc3QsIGNoYWxsZW5nZVBhcmFtZXRlcnMgfSlcbiAgICAgIH07XG4gICAgICBcbiAgICAgIGlmKENoYWxsZW5nZVJlc3BvbnNlKSB1c2VyLnNlbmRDdXN0b21DaGFsbGVuZ2VBbnN3ZXIoQ2hhbGxlbmdlUmVzcG9uc2UsIGhhbmRsZXIpO1xuICAgICAgZWxzZSB1c2VyLmluaXRpYXRlQXV0aChkZXRhaWxzLCBoYW5kbGVyKTtcbiAgICB9KTtcbiAgfVxuXG4gIHB1YmxpYyBnZXRVc2VySW5mbyh1cmw6IHN0cmluZyk6IFByb21pc2U8SUNvZ25pdG9Vc2VyRGF0YSB8IEh0dHBFcnJvclJlc3BvbnNlIHwgdW5kZWZpbmVkPiB7XG4gICAgY29uc3QgcmVxdWVzdCA9IGAke3VybH0vb2F1dGgyL3VzZXJJbmZvYFxuICAgIGNvbnN0IGhlYWRlcnMgPSB0aGlzLmhlYWRlcnMoKTtcblxuICAgIHJldHVybiB0aGlzLmh0dHAuZ2V0KHJlcXVlc3QsIHsgaGVhZGVycywgd2l0aENyZWRlbnRpYWxzOiB0cnVlIH0gKS5waXBlKFxuICAgICAgICBtYXAoKHJlc3VsdDogYW55KSA9PiBcbiAgICAgICAgICB7IHJldHVybiB7XG4gICAgICAgICAgICBlbWFpbDogcmVzdWx0LmVtYWlsLFxuICAgICAgICAgICAgdXNlcm5hbWU6IHJlc3VsdC51c2VybmFtZSxcbiAgICAgICAgICAgIHN1YjogcmVzdWx0LnN1YixcbiAgICAgICAgICAgIGZpcnN0TmFtZTogcmVzdWx0LmdpdmVuX25hbWUsXG4gICAgICAgICAgICBsYXN0TmFtZTogcmVzdWx0LmZhbWlseV9uYW1lLFxuICAgICAgICAgICAgYWNjZXNzVG9rZW46IHRoaXMuYWNjZXNzVG9rZW4hLFxuICAgICAgICAgICAgaWRUb2tlbjogdGhpcy5pZFRva2VuIVxuICAgICAgICAgIH19XG4gICAgICAgIClcbiAgICAgKS50b1Byb21pc2UoKTtcblxuICAgIC8vLCBjYXRjaEVycm9yKHRoaXMuaGFuZGxlRXJyb3JRdWlldGx5KVxuICB9XG5cbiAgcHVibGljIHNldFVzZXJTZXNzaW9uKHNlc3Npb246IENvZ25pdG9Vc2VyU2Vzc2lvbikge1xuICAgIHRoaXMuc2Vzc2lvblNvdXJjZS5uZXh0KHNlc3Npb24pO1xuICB9XG5cbiAgcHVibGljIHNob3dGb3JtKGZvcm06IENvZ25pdG9Gb3JtVHlwZSB8IG51bGwpIHtcbiAgICB0aGlzLmZvcm1Tb3VyY2UubmV4dChmb3JtKTtcbiAgfVxuXG4gIHB1YmxpYyBsb2dvdXQoKSB7XG4gICAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlOiAocmVzdWx0OiBhbnkpID0+IHZvaWQsIHJlamVjdDogKHJlc3VsdDogYW55KSA9PiB2b2lkKSA9PiB7XG4gICAgICBpZih0aGlzLnVzZXIpIHtcbiAgICAgICAgdGhpcy51c2VyU291cmNlLm5leHQobnVsbCk7XG4gICAgICAgIHRoaXMuc2Vzc2lvblNvdXJjZS5uZXh0KG51bGwpO1xuICAgICAgICBsb2NhbFN0b3JhZ2UucmVtb3ZlSXRlbShcImVtc19pZF90b2tlblwiKTtcbiAgICAgICAgbG9jYWxTdG9yYWdlLnJlbW92ZUl0ZW0oXCJlbXNfYWNjZXNzX3Rva2VuXCIpO1xuICAgICAgICB0aGlzLnVzZXIuZ2xvYmFsU2lnbk91dCh7XG4gICAgICAgICAgb25TdWNjZXNzOiByZXNvbHZlLFxuICAgICAgICAgIG9uRmFpbHVyZTogKCkgPT4ge1xuICAgICAgICAgICAgLy9pZiB1c2VyIGlzIGRpc2FibGVkLCBtdXN0IG1hbnVhbGx5IGNsZWFyIGxvY2FsIHN0b3JhZ2UgKGFwcGFyZW50bHkpXG4gICAgICAgICAgICBmb3IobGV0IHByb3AgaW4gbG9jYWxTdG9yYWdlKSB7XG4gICAgICAgICAgICAgIGlmKHByb3AubWF0Y2goL2NvZ25pdG8vaSkpIGxvY2FsU3RvcmFnZS5yZW1vdmVJdGVtKHByb3ApO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmVzb2x2ZShudWxsKTtcbiAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgcmVzb2x2ZShudWxsKTtcbiAgICAgIH1cbiAgICB9KTtcbiAgICBcbiAgfVxuXG4gIHB1YmxpYyBhdXRoZW50aWNhdGUoVXNlcm5hbWU6IHN0cmluZywgUGFzc3dvcmQ6IHN0cmluZyk6IFByb21pc2U8SUNvZ25pdG9SZXNwb25zZT4ge1xuICAgIGNvbnN0IGRldGFpbHMgPSBuZXcgQXV0aGVudGljYXRpb25EZXRhaWxzKHsgVXNlcm5hbWUsIFBhc3N3b3JkfSk7XG4gICAgY29uc3QgZGF0YTphbnkgPSB7IFVzZXJuYW1lLCBQb29sOiB0aGlzLnBvb2wgfTtcbiAgICBpZighdGhpcy51c2VMb2NhbFN0b3JhZ2UpIGRhdGEuU3RvcmFnZSA9IHRoaXMuc3RvcmFnZTtcbiAgICBjb25zdCB1c2VyID0gbmV3IENvZ25pdG9Vc2VyKGRhdGEpO1xuICAgIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZTogKHJlc3VsdDogYW55KSA9PiB2b2lkLCByZWplY3Q6IChyZXN1bHQ6IGFueSkgPT4gdm9pZCkgPT4ge1xuICAgICAgICBpZighdGhpcy51c2VyKSB0aGlzLmF1dGhlbnRpY2F0ZVVzZXIodXNlciwgZGV0YWlscywgcmVzb2x2ZSwgcmVqZWN0KTtcbiAgICAgICAgZWxzZSB0aGlzLmdldFVzZXJTZXNzaW9uKHJlc29sdmUsIHJlamVjdClcbiAgICB9KTtcbiAgfVxuXG4gIHB1YmxpYyBjcmVhdGVGZWRlcmF0ZWRTZXNzaW9uKElkVG9rZW46IHN0cmluZywgQWNjZXNzVG9rZW46IHN0cmluZykge1xuXG4gICAgY29uc3Qgc2Vzc2lvbiA9IG5ldyBDb2duaXRvVXNlclNlc3Npb24oe1xuICAgICAgICAgIElkVG9rZW46IG5ldyBDb2duaXRvSWRUb2tlbih7IElkVG9rZW4gfSksXG4gICAgICAgICAgQWNjZXNzVG9rZW46IG5ldyBDb2duaXRvQWNjZXNzVG9rZW4oeyBBY2Nlc3NUb2tlbiB9KSxcbiAgICB9KTtcblxuICAgIGNvbnN0IFVzZXJuYW1lID0gc2Vzc2lvbi5nZXRJZFRva2VuKCkucGF5bG9hZFtcImNvZ25pdG86dXNlcm5hbWVcIl07XG4gICAgY29uc3QgZGF0YTphbnkgPSB7IFVzZXJuYW1lLCBQb29sOiB0aGlzLnBvb2wgfTtcbiAgICBpZighdGhpcy51c2VMb2NhbFN0b3JhZ2UpIGRhdGEuU3RvcmFnZSA9IHRoaXMuc3RvcmFnZTtcbiAgICB0aGlzLnVzZXIgPSBuZXcgQ29nbml0b1VzZXIoZGF0YSk7XG4gICAgdGhpcy51c2VyU291cmNlLm5leHQodGhpcy51c2VyKTtcbiAgICB0aGlzLnNlc3Npb25Tb3VyY2UubmV4dChzZXNzaW9uKTtcbiAgfVxuXG4gIHB1YmxpYyBjb21wbGV0ZVBhc3N3b3JkVXBkYXRlKHBhc3N3b3JkOiBzdHJpbmcsIHVzZXI6IENvZ25pdG9Vc2VyLCBhdHRyaWJ1dGVzOiBhbnkpOiBQcm9taXNlPElDb2duaXRvUmVzcG9uc2U+IHtcbiAgICBjb25zdCByZXF1ZXN0ID0gQ29nbml0b1JlcXVlc3RUeXBlLk5ld1VzZXJQYXNzd29yZFJlc2V0O1xuICAgIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZTogKHJlc3VsdDogSUNvZ25pdG9SZXNwb25zZSkgPT4gdm9pZCwgcmVqZWN0OiAocmVzdWx0OiBJQ29nbml0b1Jlc3BvbnNlKSA9PiB2b2lkKSA9PiB7XG4gICAgICB1c2VyLmNvbXBsZXRlTmV3UGFzc3dvcmRDaGFsbGVuZ2UocGFzc3dvcmQsIGF0dHJpYnV0ZXMsIHtcbiAgICAgICAgb25TdWNjZXNzOiAoc2Vzc2lvbjogQ29nbml0b1VzZXJTZXNzaW9uKSA9PiB7XG4gICAgICAgICAgdGhpcy51c2VyID0gdXNlcjtcbiAgICAgICAgICB0aGlzLnVzZXJTb3VyY2UubmV4dCh1c2VyKTtcbiAgICAgICAgICB0aGlzLnNlc3Npb25Tb3VyY2UubmV4dChzZXNzaW9uKTtcbiAgICAgICAgICByZXNvbHZlKHsgdHlwZTogQ29nbml0b1Jlc3BvbnNlVHlwZS5BdXRoZW50aWNhdGVkLCBzZXNzaW9uLCB1c2VyLCByZXF1ZXN0OiBDb2duaXRvUmVxdWVzdFR5cGUuQXV0aGVudGljYXRpb24gfSk7XG4gICAgICAgIH0sXG4gICAgICAgIG9uRmFpbHVyZTogKGVycm9yOiBhbnkpID0+IHJlamVjdCh7IHR5cGU6IENvZ25pdG9SZXNwb25zZVR5cGUuTm90QXV0aG9yaXplZCwgZXJyb3IsIHVzZXIsIHJlcXVlc3QsIHNlc3Npb246IG51bGwgfSlcbiAgICAgIH0pXG4gICAgfSk7XG4gIH1cblxuICBwdWJsaWMgcmVxdWVzdFZlcmlmaWNhdGlvbkNvZGUoVXNlcm5hbWU6IHN0cmluZyk6IFByb21pc2U8SUNvZ25pdG9SZXNwb25zZT4ge1xuICAgIGNvbnN0IGRhdGE6IGFueSA9IHsgVXNlcm5hbWUsIFBvb2w6IHRoaXMucG9vbCB9O1xuICAgIGlmKCF0aGlzLnVzZUxvY2FsU3RvcmFnZSkgZGF0YS5TdG9yYWdlID0gdGhpcy5zdG9yYWdlO1xuICAgIGNvbnN0IHVzZXIgPSBuZXcgQ29nbml0b1VzZXIoZGF0YSk7XG4gICAgcmV0dXJuIHRoaXMuZm9yZ290UGFzc3dvcmQodXNlcik7XG4gIH1cblxuICBwdWJsaWMgcmVzZXRQYXNzd29yZCh1c2VyOiBDb2duaXRvVXNlciwgb2xkUGFzc3dvcmQ6IHN0cmluZywgbmV3UGFzc3dvcmQ6IHN0cmluZyk6IFByb21pc2U8SUNvZ25pdG9SZXNwb25zZT4ge1xuICAgIGNvbnN0IHJlcXVlc3QgPSBDb2duaXRvUmVxdWVzdFR5cGUuUGFzc3dvcmRSZXNldDtcbiAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmU6IChyZXN1bHQ6IElDb2duaXRvUmVzcG9uc2UpID0+IHZvaWQsIHJlamVjdDogKHJlc3VsdDogSUNvZ25pdG9SZXNwb25zZSkgPT4gdm9pZCkgPT4ge1xuICAgICAgIHVzZXIuY2hhbmdlUGFzc3dvcmQob2xkUGFzc3dvcmQsIG5ld1Bhc3N3b3JkLCAoZXJyb3IsIHJlc3VsdCkgPT4ge1xuICAgICAgICAgaWYoZXJyb3IpIHJlamVjdCh7IHR5cGU6IENvZ25pdG9SZXNwb25zZVR5cGUuTGltaXRFeGNlZWRlZEV4Y2VwdGlvbiwgdXNlciwgcmVxdWVzdCwgZXJyb3IsIHNlc3Npb246IG51bGx9KTtcbiAgICAgICAgIGVsc2UgcmVzb2x2ZSh7IHR5cGU6IENvZ25pdG9SZXNwb25zZVR5cGUuU3VjY2VzcywgdXNlciwgcmVxdWVzdCwgc2Vzc2lvbjogbnVsbCB9KTtcbiAgICAgICB9KVxuICAgIH0pO1xuICB9XG5cbiAgcHVibGljIGZvcmdvdFBhc3N3b3JkKHVzZXI6IENvZ25pdG9Vc2VyKTogUHJvbWlzZTxJQ29nbml0b1Jlc3BvbnNlPiB7XG4gICAgY29uc3QgcmVxdWVzdCA9IENvZ25pdG9SZXF1ZXN0VHlwZS5Gb3Jnb3RQYXNzd29yZDtcbiAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmU6IChyZXN1bHQ6IElDb2duaXRvUmVzcG9uc2UpID0+IHZvaWQsIHJlamVjdDogKHJlc3VsdDogSUNvZ25pdG9SZXNwb25zZSkgPT4gdm9pZCkgPT4ge1xuICAgICAgIHVzZXIuZm9yZ290UGFzc3dvcmQoe1xuICAgICAgICAgb25TdWNjZXNzOiAocmVzcG9uc2U6IGFueSkgPT4gcmVzb2x2ZSh7IHR5cGU6IENvZ25pdG9SZXNwb25zZVR5cGUuU3VjY2VzcywgdXNlciwgcmVxdWVzdCwgc2Vzc2lvbjogbnVsbCB9KSxcbiAgICAgICAgIG9uRmFpbHVyZTogKGVycm9yOiBhbnkpID0+IHJlamVjdCh7IHR5cGU6IENvZ25pdG9SZXNwb25zZVR5cGUuTGltaXRFeGNlZWRlZEV4Y2VwdGlvbiwgZXJyb3IsIHVzZXIsIHJlcXVlc3QsIHNlc3Npb246IG51bGwgfSlcbiAgICAgICB9KVxuICAgIH0pO1xuICB9XG5cbiAgcHVibGljIGNvbmZpcm1QYXNzd29yZCh1c2VyOiBDb2duaXRvVXNlciwgY29kZTogc3RyaW5nLCBwYXNzd29yZDogc3RyaW5nKTogUHJvbWlzZTxJQ29nbml0b1Jlc3BvbnNlPiB7XG4gICAgY29uc3QgcmVxdWVzdCA9IENvZ25pdG9SZXF1ZXN0VHlwZS5Db25maXJtUGFzc3dvcmQ7XG4gICAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlOiAocmVzdWx0OiBJQ29nbml0b1Jlc3BvbnNlKSA9PiB2b2lkLCByZWplY3Q6IChyZXN1bHQ6IElDb2duaXRvUmVzcG9uc2UpID0+IHZvaWQpID0+IHtcbiAgICAgICB1c2VyLmNvbmZpcm1QYXNzd29yZChjb2RlLCBwYXNzd29yZCwge1xuICAgICAgICAgb25TdWNjZXNzOiAocmVzcG9uc2U6IGFueSkgPT4geyByZXNvbHZlKHsgdHlwZTogQ29nbml0b1Jlc3BvbnNlVHlwZS5TdWNjZXNzLCB1c2VyLCByZXF1ZXN0LCBzZXNzaW9uOiBudWxsIH0pIH0sXG4gICAgICAgICBvbkZhaWx1cmU6IChlcnJvcjogYW55KSA9PiByZWplY3QoeyB0eXBlOiBDb2duaXRvUmVzcG9uc2VUeXBlLkludmFsaWRDb2RlLCBlcnJvciwgdXNlciwgcmVxdWVzdCwgc2Vzc2lvbjogbnVsbCB9KVxuICAgICAgIH0pXG4gICAgfSk7XG4gIH1cblxuICBwcml2YXRlIGF1dGhlbnRpY2F0ZVVzZXIodXNlcjogQ29nbml0b1VzZXIsIGRldGFpbHM6IEF1dGhlbnRpY2F0aW9uRGV0YWlscywgcmVzb2x2ZTogKHJlc3VsdDogSUNvZ25pdG9SZXNwb25zZSkgPT4gdm9pZCwgcmVqZWN0OiAocmVzdWx0OiBJQ29nbml0b1Jlc3BvbnNlKSA9PiB2b2lkICkge1xuICAgIGNvbnN0IHJlcXVlc3QgPSBDb2duaXRvUmVxdWVzdFR5cGUuQXV0aGVudGljYXRpb247XG4gICAgdXNlci5hdXRoZW50aWNhdGVVc2VyKGRldGFpbHMsIHtcbiAgICAgICAgb25TdWNjZXNzOiAoc2Vzc2lvbjogQ29nbml0b1VzZXJTZXNzaW9uKSA9PiB7XG4gICAgICAgICAgdGhpcy5zZXNzaW9uU291cmNlLm5leHQoc2Vzc2lvbik7XG4gICAgICAgICAgdGhpcy51c2VyU291cmNlLm5leHQodXNlcik7XG4gICAgICAgICAgdGhpcy51c2VyID0gdXNlcjtcbiAgICAgICAgICByZXNvbHZlKHsgdHlwZTogQ29nbml0b1Jlc3BvbnNlVHlwZS5BdXRoZW50aWNhdGVkLCBzZXNzaW9uLCB1c2VyLCByZXF1ZXN0IH0pO1xuICAgICAgICB9LFxuICAgICAgICBvbkZhaWx1cmU6IChlcnJvcjogYW55KSA9PiByZWplY3QoeyB0eXBlOiBDb2duaXRvUmVzcG9uc2VUeXBlLk5vdEF1dGhvcml6ZWQsIGVycm9yLCB1c2VyLCByZXF1ZXN0LCBzZXNzaW9uOiBudWxsIH0pLFxuICAgICAgICBuZXdQYXNzd29yZFJlcXVpcmVkOiAodXNlckF0dHJpYnV0ZXMsIHJlcXVpcmVkQXR0cmlidXRlcykgPT4ge1xuICAgICAgICAgIHJlc29sdmUoe3R5cGU6IENvZ25pdG9SZXNwb25zZVR5cGUuUGFzc3dvcmRSZXNldCwgdXNlckF0dHJpYnV0ZXMsIHJlcXVpcmVkQXR0cmlidXRlcywgdXNlciwgcmVxdWVzdCwgc2Vzc2lvbjogbnVsbCB9KVxuICAgICAgICB9XG4gICAgfSk7XG4gIH1cblxuICBwcml2YXRlIGdldFVzZXJTZXNzaW9uKHJlc29sdmU6IChyZXN1bHQ6IElDb2duaXRvUmVzcG9uc2UpID0+IHZvaWQsIHJlamVjdDogKHJlc3VsdDogSUNvZ25pdG9SZXNwb25zZSkgPT4gdm9pZCkge1xuICAgIGNvbnN0IHJlcXVlc3QgPSBDb2duaXRvUmVxdWVzdFR5cGUuQXV0aGVudGljYXRpb247XG4gICAgdGhpcy51c2VyIS5nZXRTZXNzaW9uKChlcnJvcjogRXJyb3IsIHNlc3Npb246IG51bGwpID0+IHtcbiAgICAgIGlmKGVycm9yKSByZWplY3QoeyB0eXBlOiBDb2duaXRvUmVzcG9uc2VUeXBlLkF1dGhlbnRpY2F0ZWQsIHNlc3Npb24sIHVzZXI6IHRoaXMudXNlciEsIHJlcXVlc3QsIGVycm9yIH0pO1xuICAgICAgZWxzZSB7XG4gICAgICAgIHRoaXMuc2Vzc2lvblNvdXJjZS5uZXh0KHNlc3Npb24pO1xuICAgICAgICByZXNvbHZlKHsgdHlwZTogQ29nbml0b1Jlc3BvbnNlVHlwZS5BdXRoZW50aWNhdGVkLCBzZXNzaW9uLCB1c2VyOiB0aGlzLnVzZXIhLCByZXF1ZXN0IH0pO1xuICAgICAgfVxuICAgIH0pXG4gIH1cblxuICBwcml2YXRlIGhhbmRsZUVycm9yUXVpZXRseShlcnJvcjogSHR0cEVycm9yUmVzcG9uc2UpIHtcbiAgICByZXR1cm4gb2YoZXJyb3IpO1xuICB9XG5cbiAgcHJpdmF0ZSBoZWFkZXJzKGN1c3RvbTogYW55ID0ge30pIHtcbiAgICBjb25zdCBoZWFkZXJzID0geyBcbiAgICAgICAgICBcIkNvbnRlbnQtVHlwZVwiOiBcImFwcGxpY2F0aW9uL2pzb25cIixcbiAgICAgICAgICBcIkF1dGhvcml6YXRpb25cIjogdGhpcy5hY2Nlc3NUb2tlbiA/IGBCZWFyZXIgJHt0aGlzLmFjY2Vzc1Rva2VufWAgOiBcIlwiXG4gICAgICAgfTtcbiAgICByZXR1cm4gbmV3IEh0dHBIZWFkZXJzKGhlYWRlcnMpO1xuICB9XG59XG4iXX0=