ngx-oauth 1.0.2 → 2.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,398 @@
1
+ import { Inject, Injectable } from '@angular/core';
2
+ import { HttpHeaders, HttpParams } from '@angular/common/http';
3
+ import { catchError, concatMap, delay, filter, map, shareReplay, switchMap, tap } from 'rxjs/operators';
4
+ import { EMPTY, from, noop, of, ReplaySubject } from 'rxjs';
5
+ import { LOCATION, OAUTH_CONFIG, OAuthStatus, OAuthType } from '../models';
6
+ import * as i0 from "@angular/core";
7
+ import * as i1 from "@angular/common/http";
8
+ import * as i2 from "@angular/common";
9
+ const arrToString = (buf) => buf.reduce((s, b) => s + String.fromCharCode(b), '');
10
+ const base64url = (str) => btoa(str)
11
+ .replace(/\+/g, '-')
12
+ .replace(/\//g, '_')
13
+ .replace(/=/g, '');
14
+ const randomString = (length = 48) => {
15
+ const buff = arrToString(crypto.getRandomValues(new Uint8Array(length * 2)));
16
+ return base64url(buff).substring(0, length);
17
+ };
18
+ const pkce = async (value) => {
19
+ const buff = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(value));
20
+ return base64url(arrToString(new Uint8Array(buff)));
21
+ };
22
+ const REQUEST_HEADER = new HttpHeaders({ 'Content-Type': 'application/x-www-form-urlencoded' });
23
+ const parseOauthUri = (hash) => {
24
+ const regex = /([^&=]+)=([^&]*)/g;
25
+ const params = {};
26
+ let m;
27
+ // tslint:disable-next-line:no-conditional-assignment
28
+ while ((m = regex.exec(hash)) !== null) {
29
+ params[decodeURIComponent(m[1])] = decodeURIComponent(m[2]);
30
+ }
31
+ if (Object.keys(params).length) {
32
+ return params;
33
+ }
34
+ return null;
35
+ };
36
+ const jwt = (token) => JSON.parse(atob(token.split('.')[1]));
37
+ export class OAuthService {
38
+ constructor(http, zone, authConfig, location, locationService) {
39
+ this.http = http;
40
+ this.zone = zone;
41
+ this.authConfig = authConfig;
42
+ this.location = location;
43
+ this.locationService = locationService;
44
+ this._token = null;
45
+ this._status = OAuthStatus.NOT_AUTHORIZED;
46
+ this.state$ = new ReplaySubject(1);
47
+ this.status$ = new ReplaySubject(1);
48
+ this.userInfo$ = this.status$.pipe(filter(s => s === OAuthStatus.AUTHORIZED), map(() => {
49
+ const { config } = this.authConfig;
50
+ return config.userPath;
51
+ }), filter(p => !!p), switchMap(path => this.http.get(path)), shareReplay());
52
+ setTimeout(() => this.init()); // decouple for http interceptor
53
+ }
54
+ /**
55
+ * Get the oauth config for initialize. If OpenId with issuerPath is configured then configure from server openid configuration.
56
+ * @protected
57
+ */
58
+ get config$() {
59
+ let { config } = this.authConfig;
60
+ if (config && config.clientId) {
61
+ const { issuerPath, scope } = config;
62
+ if (issuerPath) {
63
+ return this.http.get(`${issuerPath}/.well-known/openid-configuration`).pipe(tap(v => this.set(this.type, {
64
+ ...v.authorization_endpoint && { authorizePath: v.authorization_endpoint } || {},
65
+ ...v.token_endpoint && { tokenPath: v.token_endpoint } || {},
66
+ ...v.revocation_endpoint && { revokePath: v.revocation_endpoint } || {},
67
+ ...v.code_challenge_methods_supported && { pkce: v.code_challenge_methods_supported.indexOf('S256') > -1 } || {},
68
+ ...v.userinfo_endpoint && { userPath: v.userinfo_endpoint } || {},
69
+ ...v.introspection_endpoint && { introspectionPath: v.introspection_endpoint } || {},
70
+ ...scope && {} || { scope: 'openid' }
71
+ })), map(() => this.authConfig.config));
72
+ }
73
+ return of(config);
74
+ }
75
+ console.warn('clientId is missing in oauth config');
76
+ return EMPTY;
77
+ }
78
+ /**
79
+ * Init. Will check the url implicit or authorization flow or existing saved token.
80
+ * @protected
81
+ */
82
+ init() {
83
+ const { hash, search, origin, pathname } = this.location;
84
+ const isImplicitRedirect = hash && /(access_token=)|(error=)/.test(hash);
85
+ const isAuthCodeRedirect = search && /(code=)|(error=)/.test(search);
86
+ const { storageKey } = this.authConfig;
87
+ const savedToken = storageKey && this.authConfig.storage && this.authConfig.storage[storageKey] &&
88
+ JSON.parse(this.authConfig.storage[storageKey]);
89
+ this.config$.subscribe(config => {
90
+ if (isImplicitRedirect) {
91
+ const parameters = parseOauthUri(hash.substr(1));
92
+ this.token = parameters;
93
+ this.status = this.checkResponse(savedToken, parameters) && OAuthStatus.AUTHORIZED || OAuthStatus.DENIED;
94
+ }
95
+ else if (isAuthCodeRedirect) {
96
+ const parameters = parseOauthUri(search.substr(1));
97
+ if (!this.checkResponse(savedToken, parameters)) {
98
+ this.token = parameters;
99
+ this.status = OAuthStatus.DENIED;
100
+ }
101
+ else {
102
+ const newParametersString = this.getCleanedUnSearchParameters();
103
+ const { clientId, clientSecret, tokenPath, scope } = config;
104
+ const codeVerifier = savedToken && savedToken.codeVerifier;
105
+ this.http.post(tokenPath, new HttpParams({
106
+ fromObject: {
107
+ code: parameters?.code,
108
+ client_id: clientId,
109
+ ...clientSecret && { client_secret: clientSecret } || {},
110
+ redirect_uri: `${origin}${pathname}${newParametersString}`,
111
+ grant_type: 'authorization_code',
112
+ ...scope && { scope } || {},
113
+ ...codeVerifier && { code_verifier: codeVerifier } || {}
114
+ }
115
+ }), { headers: REQUEST_HEADER }).pipe(catchError((err) => {
116
+ this.token = err;
117
+ this.status = OAuthStatus.DENIED;
118
+ this.locationService.replaceState(`${pathname}${newParametersString}`);
119
+ return EMPTY;
120
+ })).subscribe(token => {
121
+ this.token = token;
122
+ this.status = OAuthStatus.AUTHORIZED;
123
+ this.locationService.replaceState(`${pathname}${newParametersString}`);
124
+ });
125
+ }
126
+ }
127
+ else if (savedToken) {
128
+ this._token = savedToken;
129
+ const { access_token, refresh_token, error } = savedToken;
130
+ if (access_token) {
131
+ if (refresh_token) { // force refresh since might be a manual page refresh
132
+ this.refreshToken();
133
+ }
134
+ else {
135
+ this.status = OAuthStatus.AUTHORIZED;
136
+ }
137
+ }
138
+ else {
139
+ this.status = error && OAuthStatus.DENIED || OAuthStatus.NOT_AUTHORIZED;
140
+ }
141
+ }
142
+ else {
143
+ this.status = OAuthStatus.NOT_AUTHORIZED;
144
+ }
145
+ });
146
+ }
147
+ async login(parameters) {
148
+ if (this.isResourceType(parameters)) {
149
+ this.resourceLogin(parameters);
150
+ }
151
+ else if (this.isAuthorizationCodeType(parameters)) {
152
+ await this.authorizationCodeLogin(parameters);
153
+ }
154
+ else if (this.isImplicitType(parameters)) {
155
+ await this.implicitLogin(parameters);
156
+ }
157
+ else if (this.isClientCredentialType()) {
158
+ this.clientCredentialLogin();
159
+ }
160
+ }
161
+ logout() {
162
+ this.revoke();
163
+ this.token = null;
164
+ this.status = OAuthStatus.NOT_AUTHORIZED;
165
+ }
166
+ revoke() {
167
+ const { revokePath, clientId, clientSecret } = this.authConfig.config;
168
+ if (revokePath) {
169
+ const { access_token, refresh_token } = this.token;
170
+ const toRevoke = [];
171
+ if (access_token) {
172
+ toRevoke.push({
173
+ ...clientId && { client_id: clientId } || {},
174
+ ...clientSecret && { client_secret: clientSecret } || {},
175
+ token: access_token,
176
+ token_type_hint: 'access_token'
177
+ });
178
+ }
179
+ if (refresh_token) {
180
+ toRevoke.push({
181
+ ...clientId && { client_id: clientId } || {},
182
+ ...clientSecret && { client_secret: clientSecret } || {},
183
+ token: refresh_token,
184
+ token_type_hint: 'refresh_token'
185
+ });
186
+ }
187
+ from(toRevoke).pipe(concatMap(o => of(o).pipe(delay(300))), // space request to avoid cancellation
188
+ switchMap(o => this.http.post(revokePath, new HttpParams({ fromObject: o })))).subscribe(noop);
189
+ }
190
+ }
191
+ get status() {
192
+ return this._status;
193
+ }
194
+ set status(status) {
195
+ this._status = status;
196
+ this.status$.next(status);
197
+ }
198
+ set(type, config) {
199
+ this.authConfig.type = type;
200
+ if (config) {
201
+ this.authConfig.config = {
202
+ ...this.authConfig.config,
203
+ ...config
204
+ };
205
+ }
206
+ }
207
+ get type() {
208
+ return this.authConfig.type;
209
+ }
210
+ get ignorePaths() {
211
+ return this.authConfig.ignorePaths || [];
212
+ }
213
+ resourceLogin(parameters) {
214
+ const { clientId, clientSecret, tokenPath, scope } = this.authConfig.config;
215
+ const { username, password } = parameters;
216
+ this.http.post(tokenPath, new HttpParams({
217
+ fromObject: {
218
+ client_id: clientId,
219
+ ...clientSecret && { client_secret: clientSecret } || {},
220
+ grant_type: OAuthType.RESOURCE,
221
+ ...scope && { scope } || {},
222
+ username,
223
+ password
224
+ }
225
+ }), { headers: REQUEST_HEADER }).pipe(catchError(err => {
226
+ this.token = err;
227
+ this.status = OAuthStatus.DENIED;
228
+ return EMPTY;
229
+ })).subscribe(params => {
230
+ this.token = params;
231
+ this.status = OAuthStatus.AUTHORIZED;
232
+ });
233
+ }
234
+ async authorizationCodeLogin(parameters) {
235
+ const authUrl = await this.toAuthorizationUrl(parameters, OAuthType.AUTHORIZATION_CODE);
236
+ this.location.replace(authUrl);
237
+ }
238
+ async implicitLogin(parameters) {
239
+ const authUrl = await this.toAuthorizationUrl(parameters, OAuthType.IMPLICIT);
240
+ this.location.replace(authUrl);
241
+ }
242
+ clientCredentialLogin() {
243
+ const { clientId, clientSecret, tokenPath, scope } = this.authConfig.config;
244
+ this.http.post(tokenPath, new HttpParams({
245
+ fromObject: {
246
+ client_id: clientId,
247
+ client_secret: clientSecret,
248
+ grant_type: OAuthType.CLIENT_CREDENTIAL,
249
+ ...scope ? { scope } : {},
250
+ }
251
+ }), { headers: REQUEST_HEADER }).pipe(catchError(() => {
252
+ this.token = null;
253
+ this.status = OAuthStatus.DENIED;
254
+ return EMPTY;
255
+ })).subscribe(params => {
256
+ this.token = params;
257
+ this.status = OAuthStatus.AUTHORIZED;
258
+ });
259
+ }
260
+ isClientCredentialType() {
261
+ return this.authConfig.type === OAuthType.CLIENT_CREDENTIAL;
262
+ }
263
+ isResourceType(parameters) {
264
+ return this.authConfig.type === OAuthType.RESOURCE && !!parameters?.password;
265
+ }
266
+ isImplicitType(parameters) {
267
+ return this.authConfig.type === OAuthType.IMPLICIT && !!parameters?.redirectUri;
268
+ }
269
+ isAuthorizationCodeType(parameters) {
270
+ return this.authConfig.type === OAuthType.AUTHORIZATION_CODE && !!parameters?.redirectUri;
271
+ }
272
+ async toAuthorizationUrl(parameters, responseType) {
273
+ const { config } = this.authConfig;
274
+ let authorizationUrl = `${config.authorizePath}`;
275
+ authorizationUrl += config.authorizePath.includes('?') && '&' || '?';
276
+ authorizationUrl += `client_id=${config.clientId}`;
277
+ authorizationUrl += `&redirect_uri=${encodeURIComponent(parameters.redirectUri)}`;
278
+ authorizationUrl += `&response_type=${responseType}`;
279
+ authorizationUrl += `&scope=${encodeURIComponent(config.scope || '')}`;
280
+ authorizationUrl += `&state=${encodeURIComponent(parameters.state || '')}`;
281
+ return `${authorizationUrl}${this.generateNonce(config)}${await this.generateCodeChallenge(config)}`;
282
+ }
283
+ async generateCodeChallenge(config) {
284
+ if (config.pkce) {
285
+ const codeVerifier = randomString();
286
+ this.token = { ...this.token, codeVerifier };
287
+ return `&code_challenge=${await pkce(codeVerifier)}&code_challenge_method=S256`;
288
+ }
289
+ return '';
290
+ }
291
+ generateNonce(config) {
292
+ if (config && config.scope && config.scope.indexOf('openid') > -1) {
293
+ const nonce = randomString(10);
294
+ this.token = { ...this.token, nonce };
295
+ return `&nonce=${nonce}`;
296
+ }
297
+ return '';
298
+ }
299
+ checkResponse(token, parameters) {
300
+ this.emitState(parameters);
301
+ this.cleanLocationHash();
302
+ if (!parameters || parameters.error) {
303
+ return false;
304
+ }
305
+ if (token && token.nonce && parameters.access_token) {
306
+ const jwtToken = jwt(parameters.access_token);
307
+ return token.nonce === jwtToken.nonce;
308
+ }
309
+ return parameters.access_token || parameters.code;
310
+ }
311
+ set token(token) {
312
+ this._token = token;
313
+ const { storageKey } = this.authConfig;
314
+ if (token) {
315
+ // @ts-ignore
316
+ this.authConfig.storage[storageKey] = JSON.stringify(this.token);
317
+ clearTimeout(this.timer);
318
+ if (this.token && this.token.expires_in) {
319
+ this.zone.runOutsideAngular(() => {
320
+ this.timer = setTimeout(() => {
321
+ this.zone.run(() => {
322
+ this.refreshToken();
323
+ });
324
+ }, Number(this.token?.expires_in) * 1000);
325
+ });
326
+ }
327
+ }
328
+ else {
329
+ // @ts-ignore
330
+ delete this.authConfig.storage[storageKey];
331
+ }
332
+ }
333
+ get token() {
334
+ return this._token;
335
+ }
336
+ refreshToken() {
337
+ const { tokenPath, clientId, clientSecret, scope } = this.authConfig.config;
338
+ const { refresh_token } = this.token;
339
+ if (tokenPath && refresh_token) {
340
+ this.http.post(tokenPath, new HttpParams({
341
+ fromObject: {
342
+ client_id: clientId,
343
+ ...clientSecret && { client_secret: clientSecret } || {},
344
+ grant_type: 'refresh_token',
345
+ refresh_token,
346
+ ...scope && { scope } || {},
347
+ }
348
+ }), { headers: REQUEST_HEADER }).pipe(catchError(() => {
349
+ this.logout();
350
+ return EMPTY;
351
+ })).subscribe(params => {
352
+ this.token = {
353
+ ...this.token,
354
+ ...params
355
+ };
356
+ this.status = OAuthStatus.AUTHORIZED;
357
+ });
358
+ }
359
+ }
360
+ getCleanedUnSearchParameters() {
361
+ const { search } = this.location;
362
+ let searchString = search.substr(1);
363
+ const hashKeys = ['code', 'state', 'error', 'error_description', 'session_state'];
364
+ hashKeys.forEach((hashKey) => {
365
+ const re = new RegExp('&' + hashKey + '(=[^&]*)?|^' + hashKey + '(=[^&]*)?&?');
366
+ searchString = searchString.replace(re, '');
367
+ });
368
+ return searchString.length && `?${searchString}` || '';
369
+ }
370
+ cleanLocationHash() {
371
+ const { hash } = this.location;
372
+ let curHash = hash.substr(1);
373
+ const hashKeys = ['access_token', 'token_type', 'expires_in', 'scope', 'state', 'error', 'error_description', 'session_state', 'nonce'];
374
+ hashKeys.forEach((hashKey) => {
375
+ const re = new RegExp('&' + hashKey + '(=[^&]*)?|^' + hashKey + '(=[^&]*)?&?');
376
+ curHash = curHash.replace(re, '');
377
+ });
378
+ this.location.hash = curHash;
379
+ }
380
+ emitState(parameters) {
381
+ const { state } = parameters;
382
+ if (state) {
383
+ this.state$.next(state);
384
+ }
385
+ }
386
+ }
387
+ OAuthService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.0.2", ngImport: i0, type: OAuthService, deps: [{ token: i1.HttpClient }, { token: i0.NgZone }, { token: OAUTH_CONFIG }, { token: LOCATION }, { token: i2.Location }], target: i0.ɵɵFactoryTarget.Injectable });
388
+ OAuthService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "13.0.2", ngImport: i0, type: OAuthService });
389
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.0.2", ngImport: i0, type: OAuthService, decorators: [{
390
+ type: Injectable
391
+ }], ctorParameters: function () { return [{ type: i1.HttpClient }, { type: i0.NgZone }, { type: undefined, decorators: [{
392
+ type: Inject,
393
+ args: [OAUTH_CONFIG]
394
+ }] }, { type: Location, decorators: [{
395
+ type: Inject,
396
+ args: [LOCATION]
397
+ }] }, { type: i2.Location }]; } });
398
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib2F1dGguc2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL25neC1vYXV0aC9zcmMvbGliL3NlcnZpY2VzL29hdXRoLnNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFDLE1BQU0sRUFBRSxVQUFVLEVBQVMsTUFBTSxlQUFlLENBQUM7QUFDekQsT0FBTyxFQUFhLFdBQVcsRUFBRSxVQUFVLEVBQUMsTUFBTSxzQkFBc0IsQ0FBQztBQUN6RSxPQUFPLEVBQUMsVUFBVSxFQUFFLFNBQVMsRUFBRSxLQUFLLEVBQUUsTUFBTSxFQUFFLEdBQUcsRUFBRSxXQUFXLEVBQUUsU0FBUyxFQUFFLEdBQUcsRUFBQyxNQUFNLGdCQUFnQixDQUFDO0FBQ3RHLE9BQU8sRUFBQyxLQUFLLEVBQUUsSUFBSSxFQUFFLElBQUksRUFBYyxFQUFFLEVBQUUsYUFBYSxFQUFDLE1BQU0sTUFBTSxDQUFDO0FBQ3RFLE9BQU8sRUFHTCxRQUFRLEVBQ1IsWUFBWSxFQUdaLFdBQVcsRUFFWCxTQUFTLEVBR1YsTUFBTSxXQUFXLENBQUM7Ozs7QUFHbkIsTUFBTSxXQUFXLEdBQUcsQ0FBQyxHQUFlLEVBQUUsRUFBRSxDQUFDLEdBQUcsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLEdBQUcsTUFBTSxDQUFDLFlBQVksQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQztBQUU5RixNQUFNLFNBQVMsR0FBRyxDQUFDLEdBQVcsRUFBRSxFQUFFLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQztLQUN6QyxPQUFPLENBQUMsS0FBSyxFQUFFLEdBQUcsQ0FBQztLQUNuQixPQUFPLENBQUMsS0FBSyxFQUFFLEdBQUcsQ0FBQztLQUNuQixPQUFPLENBQUMsSUFBSSxFQUFFLEVBQUUsQ0FBQyxDQUFDO0FBRXJCLE1BQU0sWUFBWSxHQUFHLENBQUMsU0FB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SSxNQUFNOzJCQUFDLFlBQVk7OEJBQ2dCLFFBQVE7MEJBQTNDLE1BQU07MkJBQUMsUUFBUSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7SW5qZWN0LCBJbmplY3RhYmxlLCBOZ1pvbmV9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHtIdHRwQ2xpZW50LCBIdHRwSGVhZGVycywgSHR0cFBhcmFtc30gZnJvbSAnQGFuZ3VsYXIvY29tbW9uL2h0dHAnO1xuaW1wb3J0IHtjYXRjaEVycm9yLCBjb25jYXRNYXAsIGRlbGF5LCBmaWx0ZXIsIG1hcCwgc2hhcmVSZXBsYXksIHN3aXRjaE1hcCwgdGFwfSBmcm9tICdyeGpzL29wZXJhdG9ycyc7XG5pbXBvcnQge0VNUFRZLCBmcm9tLCBub29wLCBPYnNlcnZhYmxlLCBvZiwgUmVwbGF5U3ViamVjdH0gZnJvbSAncnhqcyc7XG5pbXBvcnQge1xuICBBdXRob3JpemF0aW9uQ29kZVBhcmFtZXRlcnMsXG4gIEltcGxpY2l0UGFyYW1ldGVycyxcbiAgTE9DQVRJT04sXG4gIE9BVVRIX0NPTkZJRyxcbiAgT0F1dGhDb25maWcsXG4gIE9BdXRoUGFyYW1ldGVycyxcbiAgT0F1dGhTdGF0dXMsXG4gIE9BdXRoVG9rZW4sXG4gIE9BdXRoVHlwZSxcbiAgT0F1dGhUeXBlQ29uZmlnLCBPcGVuSWRDb25maWcsIE9wZW5JZENvbmZpZ3VyYXRpb24sXG4gIFJlc291cmNlUGFyYW1ldGVycywgVXNlckluZm9cbn0gZnJvbSAnLi4vbW9kZWxzJztcbmltcG9ydCB7TG9jYXRpb24gYXMgTG9jYXRpb24yfSBmcm9tICdAYW5ndWxhci9jb21tb24nO1xuXG5jb25zdCBhcnJUb1N0cmluZyA9IChidWY6IFVpbnQ4QXJyYXkpID0+IGJ1Zi5yZWR1Y2UoKHMsIGIpID0+IHMgKyBTdHJpbmcuZnJvbUNoYXJDb2RlKGIpLCAnJyk7XG5cbmNvbnN0IGJhc2U2NHVybCA9IChzdHI6IHN0cmluZykgPT4gYnRvYShzdHIpXG4gIC5yZXBsYWNlKC9cXCsvZywgJy0nKVxuICAucmVwbGFjZSgvXFwvL2csICdfJylcbiAgLnJlcGxhY2UoLz0vZywgJycpO1xuXG5jb25zdCByYW5kb21TdHJpbmcgPSAobGVuZ3RoOiBudW1iZXIgPSA0OCkgPT4ge1xuICBjb25zdCBidWZmID0gYXJyVG9TdHJpbmcoY3J5cHRvLmdldFJhbmRvbVZhbHVlcyhuZXcgVWludDhBcnJheShsZW5ndGggKiAyKSkpO1xuICByZXR1cm4gYmFzZTY0dXJsKGJ1ZmYpLnN1YnN0cmluZygwLCBsZW5ndGgpO1xufTtcblxuY29uc3QgcGtjZSA9IGFzeW5jICh2YWx1ZTogc3RyaW5nKSA9PiB7XG4gIGNvbnN0IGJ1ZmYgPSBhd2FpdCBjcnlwdG8uc3VidGxlLmRpZ2VzdCgnU0hBLTI1NicsIG5ldyBUZXh0RW5jb2RlcigpLmVuY29kZSh2YWx1ZSkpO1xuICByZXR1cm4gYmFzZTY0dXJsKGFyclRvU3RyaW5nKG5ldyBVaW50OEFycmF5KGJ1ZmYpKSk7XG59O1xuXG5jb25zdCBSRVFVRVNUX0hFQURFUiA9IG5ldyBIdHRwSGVhZGVycyh7J0NvbnRlbnQtVHlwZSc6ICdhcHBsaWNhdGlvbi94LXd3dy1mb3JtLXVybGVuY29kZWQnfSk7XG5cbmNvbnN0IHBhcnNlT2F1dGhVcmkgPSAoaGFzaDogc3RyaW5nKTogUmVjb3JkPHN0cmluZywgc3RyaW5nPiB8IG51bGwgPT4ge1xuICBjb25zdCByZWdleCA9IC8oW14mPV0rKT0oW14mXSopL2c7XG4gIGNvbnN0IHBhcmFtczogUmVjb3JkPHN0cmluZywgc3RyaW5nPiA9IHt9O1xuICBsZXQgbTtcbiAgLy8gdHNsaW50OmRpc2FibGUtbmV4dC1saW5lOm5vLWNvbmRpdGlvbmFsLWFzc2lnbm1lbnRcbiAgd2hpbGUgKChtID0gcmVnZXguZXhlYyhoYXNoKSkgIT09IG51bGwpIHtcbiAgICBwYXJhbXNbZGVjb2RlVVJJQ29tcG9uZW50KG1bMV0pXSA9IGRlY29kZVVSSUNvbXBvbmVudChtWzJdKTtcbiAgfVxuICBpZiAoT2JqZWN0LmtleXMocGFyYW1zKS5sZW5ndGgpIHtcbiAgICByZXR1cm4gcGFyYW1zO1xuICB9XG4gIHJldHVybiBudWxsO1xufTtcblxuY29uc3Qgand0ID0gKHRva2VuOiBzdHJpbmcpID0+IEpTT04ucGFyc2UoYXRvYih0b2tlbi5zcGxpdCgnLicpWzFdKSk7XG5cbkBJbmplY3RhYmxlKClcbmV4cG9ydCBjbGFzcyBPQXV0aFNlcnZpY2Uge1xuXG4gIHByaXZhdGUgX3Rva2VuOiBPQXV0aFRva2VuIHwgbnVsbCA9IG51bGw7XG4gIHByaXZhdGUgX3N0YXR1cyA9IE9BdXRoU3RhdHVzLk5PVF9BVVRIT1JJWkVEO1xuICBwcml2YXRlIHRpbWVyOiBhbnk7XG4gIHN0YXRlJDogUmVwbGF5U3ViamVjdDxzdHJpbmc+ID0gbmV3IFJlcGxheVN1YmplY3QoMSk7XG4gIHN0YXR1cyQ6IFJlcGxheVN1YmplY3Q8T0F1dGhTdGF0dXM+ID0gbmV3IFJlcGxheVN1YmplY3QoMSk7XG4gIHVzZXJJbmZvJDogT2JzZXJ2YWJsZTxVc2VySW5mbz4gPSB0aGlzLnN0YXR1cyQucGlwZShcbiAgICBmaWx0ZXIocyA9PiBzID09PSBPQXV0aFN0YXR1cy5BVVRIT1JJWkVEKSxcbiAgICBtYXAoKCkgPT4ge1xuICAgICAgY29uc3Qge2NvbmZpZ30gPSB0aGlzLmF1dGhDb25maWcgYXMgYW55O1xuICAgICAgcmV0dXJuIGNvbmZpZy51c2VyUGF0aDtcbiAgICB9KSxcbiAgICBmaWx0ZXIocCA9PiAhIXApLFxuICAgIHN3aXRjaE1hcChwYXRoID0+IHRoaXMuaHR0cC5nZXQ8VXNlckluZm8+KHBhdGgpKSxcbiAgICBzaGFyZVJlcGxheSgpXG4gICk7XG5cbiAgY29uc3RydWN0b3IocHJpdmF0ZSBodHRwOiBIdHRwQ2xpZW50LFxuICAgICAgICAgICAgICBwcml2YXRlIHpvbmU6IE5nWm9uZSxcbiAgICAgICAgICAgICAgQEluamVjdChPQVVUSF9DT05GSUcpIHByaXZhdGUgYXV0aENvbmZpZzogT0F1dGhDb25maWcsXG4gICAgICAgICAgICAgIEBJbmplY3QoTE9DQVRJT04pIHByaXZhdGUgbG9jYXRpb246IExvY2F0aW9uLFxuICAgICAgICAgICAgICBwcml2YXRlIGxvY2F0aW9uU2VydmljZTogTG9jYXRpb24yKSB7XG4gICAgc2V0VGltZW91dCgoKSA9PiB0aGlzLmluaXQoKSk7IC8vIGRlY291cGxlIGZvciBodHRwIGludGVyY2VwdG9yXG4gIH1cblxuICAvKipcbiAgICogR2V0IHRoZSBvYXV0aCBjb25maWcgZm9yIGluaXRpYWxpemUuIElmIE9wZW5JZCB3aXRoIGlzc3VlclBhdGggaXMgY29uZmlndXJlZCB0aGVuIGNvbmZpZ3VyZSBmcm9tIHNlcnZlciBvcGVuaWQgY29uZmlndXJhdGlvbi5cbiAgICogQHByb3RlY3RlZFxuICAgKi9cbiAgcHJvdGVjdGVkIGdldCBjb25maWckKCkge1xuICAgIGxldCB7Y29uZmlnfSA9IHRoaXMuYXV0aENvbmZpZztcbiAgICBpZiAoY29uZmlnICYmIGNvbmZpZy5jbGllbnRJZCkge1xuICAgICAgY29uc3Qge2lzc3VlclBhdGgsIHNjb3BlfSA9IGNvbmZpZyBhcyBPcGVuSWRDb25maWc7XG4gICAgICBpZiAoaXNzdWVyUGF0aCkge1xuICAgICAgICByZXR1cm4gdGhpcy5odHRwLmdldDxPcGVuSWRDb25maWd1cmF0aW9uPihgJHtpc3N1ZXJQYXRofS8ud2VsbC1rbm93bi9vcGVuaWQtY29uZmlndXJhdGlvbmApLnBpcGUoXG4gICAgICAgICAgdGFwKHYgPT4gdGhpcy5zZXQodGhpcy50eXBlLCB7XG4gICAgICAgICAgICAuLi52LmF1dGhvcml6YXRpb25fZW5kcG9pbnQgJiYge2F1dGhvcml6ZVBhdGg6IHYuYXV0aG9yaXphdGlvbl9lbmRwb2ludH0gfHwge30sXG4gICAgICAgICAgICAuLi52LnRva2VuX2VuZHBvaW50ICYmIHt0b2tlblBhdGg6IHYudG9rZW5fZW5kcG9pbnR9IHx8IHt9LFxuICAgICAgICAgICAgLi4udi5yZXZvY2F0aW9uX2VuZHBvaW50ICYmIHtyZXZva2VQYXRoOiB2LnJldm9jYXRpb25fZW5kcG9pbnR9IHx8IHt9LFxuICAgICAgICAgICAgLi4udi5jb2RlX2NoYWxsZW5nZV9tZXRob2RzX3N1cHBvcnRlZCAmJiB7cGtjZTogdi5jb2RlX2NoYWxsZW5nZV9tZXRob2RzX3N1cHBvcnRlZC5pbmRleE9mKCdTMjU2JykgPiAtMX0gfHwge30sXG4gICAgICAgICAgICAuLi52LnVzZXJpbmZvX2VuZHBvaW50ICYmIHt1c2VyUGF0aDogdi51c2VyaW5mb19lbmRwb2ludH0gfHwge30sXG4gICAgICAgICAgICAuLi52LmludHJvc3BlY3Rpb25fZW5kcG9pbnQgJiYge2ludHJvc3BlY3Rpb25QYXRoOiB2LmludHJvc3BlY3Rpb25fZW5kcG9pbnR9IHx8IHt9LFxuICAgICAgICAgICAgLi4uc2NvcGUgJiYge30gfHwge3Njb3BlOiAnb3BlbmlkJ31cbiAgICAgICAgICB9IGFzIGFueSkpLFxuICAgICAgICAgIG1hcCgoKSA9PiB0aGlzLmF1dGhDb25maWcuY29uZmlnKVxuICAgICAgICApO1xuICAgICAgfVxuICAgICAgcmV0dXJuIG9mKGNvbmZpZyk7XG4gICAgfVxuICAgIGNvbnNvbGUud2FybignY2xpZW50SWQgaXMgbWlzc2luZyBpbiBvYXV0aCBjb25maWcnKTtcbiAgICByZXR1cm4gRU1QVFk7XG4gIH1cblxuICAvKipcbiAgICogSW5pdC4gV2lsbCBjaGVjayB0aGUgdXJsIGltcGxpY2l0IG9yIGF1dGhvcml6YXRpb24gZmxvdyBvciBleGlzdGluZyBzYXZlZCB0b2tlbi5cbiAgICogQHByb3RlY3RlZFxuICAgKi9cbiAgcHJvdGVjdGVkIGluaXQoKTogdm9pZCB7XG4gICAgY29uc3Qge2hhc2gsIHNlYXJjaCwgb3JpZ2luLCBwYXRobmFtZX0gPSB0aGlzLmxvY2F0aW9uO1xuICAgIGNvbnN0IGlzSW1wbGljaXRSZWRpcmVjdCA9IGhhc2ggJiYgLyhhY2Nlc3NfdG9rZW49KXwoZXJyb3I9KS8udGVzdChoYXNoKTtcbiAgICBjb25zdCBpc0F1dGhDb2RlUmVkaXJlY3QgPSBzZWFyY2ggJiYgLyhjb2RlPSl8KGVycm9yPSkvLnRlc3Qoc2VhcmNoKTtcbiAgICBjb25zdCB7c3RvcmFnZUtleX0gPSB0aGlzLmF1dGhDb25maWc7XG4gICAgY29uc3Qgc2F2ZWRUb2tlbiA9IHN0b3JhZ2VLZXkgJiYgdGhpcy5hdXRoQ29uZmlnLnN0b3JhZ2UgJiYgdGhpcy5hdXRoQ29uZmlnLnN0b3JhZ2Vbc3RvcmFnZUtleV0gJiZcbiAgICAgIEpTT04ucGFyc2UodGhpcy5hdXRoQ29uZmlnLnN0b3JhZ2Vbc3RvcmFnZUtleV0pO1xuICAgIHRoaXMuY29uZmlnJC5zdWJzY3JpYmUoY29uZmlnID0+IHtcbiAgICAgIGlmIChpc0ltcGxpY2l0UmVkaXJlY3QpIHtcbiAgICAgICAgY29uc3QgcGFyYW1ldGVycyA9IHBhcnNlT2F1dGhVcmkoaGFzaC5zdWJzdHIoMSkpO1xuICAgICAgICB0aGlzLnRva2VuID0gcGFyYW1ldGVycztcbiAgICAgICAgdGhpcy5zdGF0dXMgPSB0aGlzLmNoZWNrUmVzcG9uc2Uoc2F2ZWRUb2tlbiwgcGFyYW1ldGVycykgJiYgT0F1dGhTdGF0dXMuQVVUSE9SSVpFRCB8fCBPQXV0aFN0YXR1cy5ERU5JRUQ7XG4gICAgICB9IGVsc2UgaWYgKGlzQXV0aENvZGVSZWRpcmVjdCkge1xuICAgICAgICBjb25zdCBwYXJhbWV0ZXJzID0gcGFyc2VPYXV0aFVyaShzZWFyY2guc3Vic3RyKDEpKTtcbiAgICAgICAgaWYgKCF0aGlzLmNoZWNrUmVzcG9uc2Uoc2F2ZWRUb2tlbiwgcGFyYW1ldGVycykpIHtcbiAgICAgICAgICB0aGlzLnRva2VuID0gcGFyYW1ldGVycztcbiAgICAgICAgICB0aGlzLnN0YXR1cyA9IE9BdXRoU3RhdHVzLkRFTklFRDtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBjb25zdCBuZXdQYXJhbWV0ZXJzU3RyaW5nID0gdGhpcy5nZXRDbGVhbmVkVW5TZWFyY2hQYXJhbWV0ZXJzKCk7XG4gICAgICAgICAgY29uc3Qge2NsaWVudElkLCBjbGllbnRTZWNyZXQsIHRva2VuUGF0aCwgc2NvcGV9ID0gY29uZmlnIGFzIGFueTtcbiAgICAgICAgICBjb25zdCBjb2RlVmVyaWZpZXIgPSBzYXZlZFRva2VuICYmIHNhdmVkVG9rZW4uY29kZVZlcmlmaWVyO1xuICAgICAgICAgIHRoaXMuaHR0cC5wb3N0KHRva2VuUGF0aCwgbmV3IEh0dHBQYXJhbXMoe1xuICAgICAgICAgICAgZnJvbU9iamVjdDoge1xuICAgICAgICAgICAgICBjb2RlOiBwYXJhbWV0ZXJzPy5jb2RlLFxuICAgICAgICAgICAgICBjbGllbnRfaWQ6IGNsaWVudElkLFxuICAgICAgICAgICAgICAuLi5jbGllbnRTZWNyZXQgJiYge2NsaWVudF9zZWNyZXQ6IGNsaWVudFNlY3JldH0gfHwge30sXG4gICAgICAgICAgICAgIHJlZGlyZWN0X3VyaTogYCR7b3JpZ2lufSR7cGF0aG5hbWV9JHtuZXdQYXJhbWV0ZXJzU3RyaW5nfWAsXG4gICAgICAgICAgICAgIGdyYW50X3R5cGU6ICdhdXRob3JpemF0aW9uX2NvZGUnLFxuICAgICAgICAgICAgICAuLi5zY29wZSAmJiB7c2NvcGV9IHx8IHt9LFxuICAgICAgICAgICAgICAuLi5jb2RlVmVyaWZpZXIgJiYge2NvZGVfdmVyaWZpZXI6IGNvZGVWZXJpZmllcn0gfHwge31cbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9KSwge2hlYWRlcnM6IFJFUVVFU1RfSEVBREVSfSkucGlwZShcbiAgICAgICAgICAgIGNhdGNoRXJyb3IoKGVycikgPT4ge1xuICAgICAgICAgICAgICB0aGlzLnRva2VuID0gZXJyO1xuICAgICAgICAgICAgICB0aGlzLnN0YXR1cyA9IE9BdXRoU3RhdHVzLkRFTklFRDtcbiAgICAgICAgICAgICAgdGhpcy5sb2NhdGlvblNlcnZpY2UucmVwbGFjZVN0YXRlKGAke3BhdGhuYW1lfSR7bmV3UGFyYW1ldGVyc1N0cmluZ31gKTtcbiAgICAgICAgICAgICAgcmV0dXJuIEVNUFRZO1xuICAgICAgICAgICAgfSlcbiAgICAgICAgICApLnN1YnNjcmliZSh0b2tlbiA9PiB7XG4gICAgICAgICAgICB0aGlzLnRva2VuID0gdG9rZW47XG4gICAgICAgICAgICB0aGlzLnN0YXR1cyA9IE9BdXRoU3RhdHVzLkFVVEhPUklaRUQ7XG4gICAgICAgICAgICB0aGlzLmxvY2F0aW9uU2VydmljZS5yZXBsYWNlU3RhdGUoYCR7cGF0aG5hbWV9JHtuZXdQYXJhbWV0ZXJzU3RyaW5nfWApO1xuICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICB9IGVsc2UgaWYgKHNhdmVkVG9rZW4pIHtcbiAgICAgICAgdGhpcy5fdG9rZW4gPSBzYXZlZFRva2VuO1xuICAgICAgICBjb25zdCB7YWNjZXNzX3Rva2VuLCByZWZyZXNoX3Rva2VuLCBlcnJvcn0gPSBzYXZlZFRva2VuO1xuICAgICAgICBpZiAoYWNjZXNzX3Rva2VuKSB7XG4gICAgICAgICAgaWYgKHJlZnJlc2hfdG9rZW4pIHsgLy8gZm9yY2UgcmVmcmVzaCBzaW5jZSBtaWdodCBiZSBhIG1hbnVhbCBwYWdlIHJlZnJlc2hcbiAgICAgICAgICAgIHRoaXMucmVmcmVzaFRva2VuKCk7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMuc3RhdHVzID0gT0F1dGhTdGF0dXMuQVVUSE9SSVpFRDtcbiAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgdGhpcy5zdGF0dXMgPSBlcnJvciAmJiBPQXV0aFN0YXR1cy5ERU5JRUQgfHwgT0F1dGhTdGF0dXMuTk9UX0FVVEhPUklaRUQ7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRoaXMuc3RhdHVzID0gT0F1dGhTdGF0dXMuTk9UX0FVVEhPUklaRUQ7XG4gICAgICB9XG4gICAgfSk7XG4gIH1cblxuICBhc3luYyBsb2dpbihwYXJhbWV0ZXJzPzogT0F1dGhQYXJhbWV0ZXJzKSB7XG4gICAgaWYgKHRoaXMuaXNSZXNvdXJjZVR5cGUocGFyYW1ldGVycyBhcyBSZXNvdXJjZVBhcmFtZXRlcnMpKSB7XG4gICAgICB0aGlzLnJlc291cmNlTG9naW4ocGFyYW1ldGVycyBhcyBSZXNvdXJjZVBhcmFtZXRlcnMpO1xuICAgIH0gZWxzZSBpZiAodGhpcy5pc0F1dGhvcml6YXRpb25Db2RlVHlwZShwYXJhbWV0ZXJzIGFzIEF1dGhvcml6YXRpb25Db2RlUGFyYW1ldGVycykpIHtcbiAgICAgIGF3YWl0IHRoaXMuYXV0aG9yaXphdGlvbkNvZGVMb2dpbihwYXJhbWV0ZXJzIGFzIEF1dGhvcml6YXRpb25Db2RlUGFyYW1ldGVycyk7XG4gICAgfSBlbHNlIGlmICh0aGlzLmlzSW1wbGljaXRUeXBlKHBhcmFtZXRlcnMgYXMgSW1wbGljaXRQYXJhbWV0ZXJzKSkge1xuICAgICAgYXdhaXQgdGhpcy5pbXBsaWNpdExvZ2luKHBhcmFtZXRlcnMgYXMgSW1wbGljaXRQYXJhbWV0ZXJzKTtcbiAgICB9IGVsc2UgaWYgKHRoaXMuaXNDbGllbnRDcmVkZW50aWFsVHlwZSgpKSB7XG4gICAgICB0aGlzLmNsaWVudENyZWRlbnRpYWxMb2dpbigpO1xuICAgIH1cbiAgfVxuXG4gIGxvZ291dCgpIHtcbiAgICB0aGlzLnJldm9rZSgpO1xuICAgIHRoaXMudG9rZW4gPSBudWxsO1xuICAgIHRoaXMuc3RhdHVzID0gT0F1dGhTdGF0dXMuTk9UX0FVVEhPUklaRUQ7XG4gIH1cblxuICByZXZva2UoKSB7XG4gICAgY29uc3Qge3Jldm9rZVBhdGgsIGNsaWVudElkLCBjbGllbnRTZWNyZXR9ID0gdGhpcy5hdXRoQ29uZmlnLmNvbmZpZyBhcyBhbnk7XG4gICAgaWYgKHJldm9rZVBhdGgpIHtcbiAgICAgIGNvbnN0IHthY2Nlc3NfdG9rZW4sIHJlZnJlc2hfdG9rZW59ID0gdGhpcy50b2tlbiBhcyBPQXV0aFRva2VuO1xuICAgICAgY29uc3QgdG9SZXZva2UgPSBbXTtcbiAgICAgIGlmIChhY2Nlc3NfdG9rZW4pIHtcbiAgICAgICAgdG9SZXZva2UucHVzaCh7XG4gICAgICAgICAgLi4uY2xpZW50SWQgJiYge2NsaWVudF9pZDogY2xpZW50SWR9IHx8IHt9LFxuICAgICAgICAgIC4uLmNsaWVudFNlY3JldCAmJiB7Y2xpZW50X3NlY3JldDogY2xpZW50U2VjcmV0fSB8fCB7fSxcbiAgICAgICAgICB0b2tlbjogYWNjZXNzX3Rva2VuLFxuICAgICAgICAgIHRva2VuX3R5cGVfaGludDogJ2FjY2Vzc190b2tlbidcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgICBpZiAocmVmcmVzaF90b2tlbikge1xuICAgICAgICB0b1Jldm9rZS5wdXNoKHtcbiAgICAgICAgICAuLi5jbGllbnRJZCAmJiB7Y2xpZW50X2lkOiBjbGllbnRJZH0gfHwge30sXG4gICAgICAgICAgLi4uY2xpZW50U2VjcmV0ICYmIHtjbGllbnRfc2VjcmV0OiBjbGllbnRTZWNyZXR9IHx8IHt9LFxuICAgICAgICAgIHRva2VuOiByZWZyZXNoX3Rva2VuLFxuICAgICAgICAgIHRva2VuX3R5cGVfaGludDogJ3JlZnJlc2hfdG9rZW4nXG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgICAgZnJvbSh0b1Jldm9rZSkucGlwZShcbiAgICAgICAgY29uY2F0TWFwKG8gPT4gb2YobykucGlwZShkZWxheSgzMDApKSksIC8vIHNwYWNlIHJlcXVlc3QgdG8gYXZvaWQgY2FuY2VsbGF0aW9uXG4gICAgICAgIHN3aXRjaE1hcChvID0+IHRoaXMuaHR0cC5wb3N0KHJldm9rZVBhdGgsIG5ldyBIdHRwUGFyYW1zKHtmcm9tT2JqZWN0OiBvfSkpKSxcbiAgICAgICkuc3Vic2NyaWJlKG5vb3ApO1xuICAgIH1cbiAgfVxuXG4gIGdldCBzdGF0dXMoKTogT0F1dGhTdGF0dXMge1xuICAgIHJldHVybiB0aGlzLl9zdGF0dXM7XG4gIH1cblxuICBzZXQgc3RhdHVzKHN0YXR1cykge1xuICAgIHRoaXMuX3N0YXR1cyA9IHN0YXR1cztcbiAgICB0aGlzLnN0YXR1cyQubmV4dChzdGF0dXMpO1xuICB9XG5cbiAgc2V0KHR5cGU6IE9BdXRoVHlwZSwgY29uZmlnPzogT0F1dGhUeXBlQ29uZmlnKTogdm9pZCB7XG4gICAgdGhpcy5hdXRoQ29uZmlnLnR5cGUgPSB0eXBlO1xuICAgIGlmIChjb25maWcpIHtcbiAgICAgIHRoaXMuYXV0aENvbmZpZy5jb25maWcgPSB7XG4gICAgICAgIC4uLnRoaXMuYXV0aENvbmZpZy5jb25maWcsXG4gICAgICAgIC4uLmNvbmZpZ1xuICAgICAgfTtcbiAgICB9XG4gIH1cblxuICBnZXQgdHlwZSgpOiBPQXV0aFR5cGUge1xuICAgIHJldHVybiB0aGlzLmF1dGhDb25maWcudHlwZTtcbiAgfVxuXG4gIGdldCBpZ25vcmVQYXRocygpOiBSZWdFeHBbXSB7XG4gICAgcmV0dXJuIHRoaXMuYXV0aENvbmZpZy5pZ25vcmVQYXRocyB8fCBbXTtcbiAgfVxuXG4gIHByaXZhdGUgcmVzb3VyY2VMb2dpbihwYXJhbWV0ZXJzOiBSZXNvdXJjZVBhcmFtZXRlcnMpIHtcbiAgICBjb25zdCB7Y2xpZW50SWQsIGNsaWVudFNlY3JldCwgdG9rZW5QYXRoLCBzY29wZX0gPSB0aGlzLmF1dGhDb25maWcuY29uZmlnIGFzIGFueTtcbiAgICBjb25zdCB7dXNlcm5hbWUsIHBhc3N3b3JkfSA9IHBhcmFtZXRlcnM7XG4gICAgdGhpcy5odHRwLnBvc3QodG9rZW5QYXRoLCBuZXcgSHR0cFBhcmFtcyh7XG4gICAgICBmcm9tT2JqZWN0OiB7XG4gICAgICAgIGNsaWVudF9pZDogY2xpZW50SWQsXG4gICAgICAgIC4uLmNsaWVudFNlY3JldCAmJiB7Y2xpZW50X3NlY3JldDogY2xpZW50U2VjcmV0fSB8fCB7fSxcbiAgICAgICAgZ3JhbnRfdHlwZTogT0F1dGhUeXBlLlJFU09VUkNFLFxuICAgICAgICAuLi5zY29wZSAmJiB7c2NvcGV9IHx8IHt9LFxuICAgICAgICB1c2VybmFtZSxcbiAgICAgICAgcGFzc3dvcmRcbiAgICAgIH1cbiAgICB9KSwge2hlYWRlcnM6IFJFUVVFU1RfSEVBREVSfSkucGlwZShcbiAgICAgIGNhdGNoRXJyb3IoZXJyID0+IHtcbiAgICAgICAgdGhpcy50b2tlbiA9IGVycjtcbiAgICAgICAgdGhpcy5zdGF0dXMgPSBPQXV0aFN0YXR1cy5ERU5JRUQ7XG4gICAgICAgIHJldHVybiBFTVBUWTtcbiAgICAgIH0pXG4gICAgKS5zdWJzY3JpYmUocGFyYW1zID0+IHtcbiAgICAgIHRoaXMudG9rZW4gPSBwYXJhbXM7XG4gICAgICB0aGlzLnN0YXR1cyA9IE9BdXRoU3RhdHVzLkFVVEhPUklaRUQ7XG4gICAgfSk7XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIGF1dGhvcml6YXRpb25Db2RlTG9naW4ocGFyYW1ldGVyczogQXV0aG9yaXphdGlvbkNvZGVQYXJhbWV0ZXJzKSB7XG4gICAgY29uc3QgYXV0aFVybCA9IGF3YWl0IHRoaXMudG9BdXRob3JpemF0aW9uVXJsKHBhcmFtZXRlcnMsIE9BdXRoVHlwZS5BVVRIT1JJWkFUSU9OX0NPREUpO1xuICAgIHRoaXMubG9jYXRpb24ucmVwbGFjZShhdXRoVXJsKTtcbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgaW1wbGljaXRMb2dpbihwYXJhbWV0ZXJzOiBJbXBsaWNpdFBhcmFtZXRlcnMpIHtcbiAgICBjb25zdCBhdXRoVXJsID0gYXdhaXQgdGhpcy50b0F1dGhvcml6YXRpb25VcmwocGFyYW1ldGVycywgT0F1dGhUeXBlLklNUExJQ0lUKTtcbiAgICB0aGlzLmxvY2F0aW9uLnJlcGxhY2UoYXV0aFVybCk7XG4gIH1cblxuICBwcml2YXRlIGNsaWVudENyZWRlbnRpYWxMb2dpbigpIHtcbiAgICBjb25zdCB7Y2xpZW50SWQsIGNsaWVudFNlY3JldCwgdG9rZW5QYXRoLCBzY29wZX0gPSB0aGlzLmF1dGhDb25maWcuY29uZmlnIGFzIGFueTtcbiAgICB0aGlzLmh0dHAucG9zdCh0b2tlblBhdGgsIG5ldyBIdHRwUGFyYW1zKHtcbiAgICAgIGZyb21PYmplY3Q6IHtcbiAgICAgICAgY2xpZW50X2lkOiBjbGllbnRJZCxcbiAgICAgICAgY2xpZW50X3NlY3JldDogY2xpZW50U2VjcmV0LFxuICAgICAgICBncmFudF90eXBlOiBPQXV0aFR5cGUuQ0xJRU5UX0NSRURFTlRJQUwsXG4gICAgICAgIC4uLnNjb3BlID8ge3Njb3BlfSA6IHt9LFxuICAgICAgfVxuICAgIH0pLCB7aGVhZGVyczogUkVRVUVTVF9IRUFERVJ9KS5waXBlKFxuICAgICAgY2F0Y2hFcnJvcigoKSA9PiB7XG4gICAgICAgIHRoaXMudG9rZW4gPSBudWxsO1xuICAgICAgICB0aGlzLnN0YXR1cyA9IE9BdXRoU3RhdHVzLkRFTklFRDtcbiAgICAgICAgcmV0dXJuIEVNUFRZO1xuICAgICAgfSlcbiAgICApLnN1YnNjcmliZShwYXJhbXMgPT4ge1xuICAgICAgdGhpcy50b2tlbiA9IHBhcmFtcztcbiAgICAgIHRoaXMuc3RhdHVzID0gT0F1dGhTdGF0dXMuQVVUSE9SSVpFRDtcbiAgICB9KTtcbiAgfVxuXG4gIHByaXZhdGUgaXNDbGllbnRDcmVkZW50aWFsVHlwZSgpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy5hdXRoQ29uZmlnLnR5cGUgPT09IE9BdXRoVHlwZS5DTElFTlRfQ1JFREVOVElBTDtcbiAgfVxuXG4gIHByaXZhdGUgaXNSZXNvdXJjZVR5cGUocGFyYW1ldGVycz86IFJlc291cmNlUGFyYW1ldGVycyk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLmF1dGhDb25maWcudHlwZSA9PT0gT0F1dGhUeXBlLlJFU09VUkNFICYmICEhcGFyYW1ldGVycz8ucGFzc3dvcmQ7XG4gIH1cblxuICBwcml2YXRlIGlzSW1wbGljaXRUeXBlKHBhcmFtZXRlcnM/OiBJbXBsaWNpdFBhcmFtZXRlcnMpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy5hdXRoQ29uZmlnLnR5cGUgPT09IE9BdXRoVHlwZS5JTVBMSUNJVCAmJiAhIXBhcmFtZXRlcnM/LnJlZGlyZWN0VXJpO1xuICB9XG5cbiAgcHJpdmF0ZSBpc0F1dGhvcml6YXRpb25Db2RlVHlwZShwYXJhbWV0ZXJzPzogQXV0aG9yaXphdGlvbkNvZGVQYXJhbWV0ZXJzKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMuYXV0aENvbmZpZy50eXBlID09PSBPQXV0aFR5cGUuQVVUSE9SSVpBVElPTl9DT0RFICYmICEhcGFyYW1ldGVycz8ucmVkaXJlY3RVcmk7XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIHRvQXV0aG9yaXphdGlvblVybChwYXJhbWV0ZXJzOiBBdXRob3JpemF0aW9uQ29kZVBhcmFtZXRlcnMgfCBJbXBsaWNpdFBhcmFtZXRlcnMsIHJlc3BvbnNlVHlwZTogT0F1dGhUeXBlKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICBjb25zdCB7Y29uZmlnfSA9IHRoaXMuYXV0aENvbmZpZyBhcyBhbnk7XG4gICAgbGV0IGF1dGhvcml6YXRpb25VcmwgPSBgJHtjb25maWcuYXV0aG9yaXplUGF0aH1gO1xuICAgIGF1dGhvcml6YXRpb25VcmwgKz0gY29uZmlnLmF1dGhvcml6ZVBhdGguaW5jbHVkZXMoJz8nKSAmJiAnJicgfHwgJz8nO1xuICAgIGF1dGhvcml6YXRpb25VcmwgKz0gYGNsaWVudF9pZD0ke2NvbmZpZy5jbGllbnRJZH1gO1xuICAgIGF1dGhvcml6YXRpb25VcmwgKz0gYCZyZWRpcmVjdF91cmk9JHtlbmNvZGVVUklDb21wb25lbnQocGFyYW1ldGVycy5yZWRpcmVjdFVyaSl9YDtcbiAgICBhdXRob3JpemF0aW9uVXJsICs9IGAmcmVzcG9uc2VfdHlwZT0ke3Jlc3BvbnNlVHlwZX1gO1xuICAgIGF1dGhvcml6YXRpb25VcmwgKz0gYCZzY29wZT0ke2VuY29kZVVSSUNvbXBvbmVudChjb25maWcuc2NvcGUgfHwgJycpfWA7XG4gICAgYXV0aG9yaXphdGlvblVybCArPSBgJnN0YXRlPSR7ZW5jb2RlVVJJQ29tcG9uZW50KHBhcmFtZXRlcnMuc3RhdGUgfHwgJycpfWA7XG4gICAgcmV0dXJuIGAke2F1dGhvcml6YXRpb25Vcmx9JHt0aGlzLmdlbmVyYXRlTm9uY2UoY29uZmlnKX0ke2F3YWl0IHRoaXMuZ2VuZXJhdGVDb2RlQ2hhbGxlbmdlKGNvbmZpZyl9YDtcbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgZ2VuZXJhdGVDb2RlQ2hhbGxlbmdlKGNvbmZpZzogYW55KSB7XG4gICAgaWYgKGNvbmZpZy5wa2NlKSB7XG4gICAgICBjb25zdCBjb2RlVmVyaWZpZXIgPSByYW5kb21TdHJpbmcoKTtcbiAgICAgIHRoaXMudG9rZW4gPSB7Li4udGhpcy50b2tlbiwgY29kZVZlcmlmaWVyfTtcbiAgICAgIHJldHVybiBgJmNvZGVfY2hhbGxlbmdlPSR7YXdhaXQgcGtjZShjb2RlVmVyaWZpZXIpfSZjb2RlX2NoYWxsZW5nZV9tZXRob2Q9UzI1NmA7XG4gICAgfVxuICAgIHJldHVybiAnJztcbiAgfVxuXG4gIHByaXZhdGUgZ2VuZXJhdGVOb25jZShjb25maWc6IGFueSkge1xuICAgIGlmIChjb25maWcgJiYgY29uZmlnLnNjb3BlICYmIGNvbmZpZy5zY29wZS5pbmRleE9mKCdvcGVuaWQnKSA+IC0xKSB7XG4gICAgICBjb25zdCBub25jZSA9IHJhbmRvbVN0cmluZygxMCk7XG4gICAgICB0aGlzLnRva2VuID0gey4uLnRoaXMudG9rZW4sIG5vbmNlfTtcbiAgICAgIHJldHVybiBgJm5vbmNlPSR7bm9uY2V9YDtcbiAgICB9XG4gICAgcmV0dXJuICcnO1xuICB9XG5cbiAgcHJpdmF0ZSBjaGVja1Jlc3BvbnNlKHRva2VuOiBhbnksIHBhcmFtZXRlcnM6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4gfCBudWxsKSB7XG4gICAgdGhpcy5lbWl0U3RhdGUocGFyYW1ldGVycyk7XG4gICAgdGhpcy5jbGVhbkxvY2F0aW9uSGFzaCgpO1xuICAgIGlmICghcGFyYW1ldGVycyB8fCBwYXJhbWV0ZXJzLmVycm9yKSB7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICAgIGlmICh0b2tlbiAmJiB0b2tlbi5ub25jZSAmJiBwYXJhbWV0ZXJzLmFjY2Vzc190b2tlbikge1xuICAgICAgY29uc3Qgand0VG9rZW4gPSBqd3QocGFyYW1ldGVycy5hY2Nlc3NfdG9rZW4pO1xuICAgICAgcmV0dXJuIHRva2VuLm5vbmNlID09PSBqd3RUb2tlbi5ub25jZTtcbiAgICB9XG4gICAgcmV0dXJuIHBhcmFtZXRlcnMuYWNjZXNzX3Rva2VuIHx8IHBhcmFtZXRlcnMuY29kZTtcbiAgfVxuXG4gIHNldCB0b2tlbih0b2tlbjogT0F1dGhUb2tlbiB8IG51bGwpIHtcbiAgICB0aGlzLl90b2tlbiA9IHRva2VuO1xuICAgIGNvbnN0IHtzdG9yYWdlS2V5fSA9IHRoaXMuYXV0aENvbmZpZztcbiAgICBpZiAodG9rZW4pIHtcbiAgICAgIC8vIEB0cy1pZ25vcmVcbiAgICAgIHRoaXMuYXV0aENvbmZpZy5zdG9yYWdlW3N0b3JhZ2VLZXldID0gSlNPTi5zdHJpbmdpZnkodGhpcy50b2tlbik7XG4gICAgICBjbGVhclRpbWVvdXQodGhpcy50aW1lcik7XG4gICAgICBpZiAodGhpcy50b2tlbiAmJiB0aGlzLnRva2VuLmV4cGlyZXNfaW4pIHtcbiAgICAgICAgdGhpcy56b25lLnJ1bk91dHNpZGVBbmd1bGFyKCgpID0+IHtcbiAgICAgICAgICB0aGlzLnRpbWVyID0gc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICAgICAgICB0aGlzLnpvbmUucnVuKCgpID0+IHtcbiAgICAgICAgICAgICAgdGhpcy5yZWZyZXNoVG9rZW4oKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH0sIE51bWJlcih0aGlzLnRva2VuPy5leHBpcmVzX2luKSAqIDEwMDApO1xuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgLy8gQHRzLWlnbm9yZVxuICAgICAgZGVsZXRlIHRoaXMuYXV0aENvbmZpZy5zdG9yYWdlW3N0b3JhZ2VLZXldO1xuICAgIH1cbiAgfVxuXG4gIGdldCB0b2tlbigpIHtcbiAgICByZXR1cm4gdGhpcy5fdG9rZW47XG4gIH1cblxuICBwcml2YXRlIHJlZnJlc2hUb2tlbigpIHtcbiAgICBjb25zdCB7dG9rZW5QYXRoLCBjbGllbnRJZCwgY2xpZW50U2VjcmV0LCBzY29wZX0gPSB0aGlzLmF1dGhDb25maWcuY29uZmlnIGFzIGFueTtcbiAgICBjb25zdCB7cmVmcmVzaF90b2tlbn0gPSB0aGlzLnRva2VuIGFzIE9BdXRoVG9rZW47XG4gICAgaWYgKHRva2VuUGF0aCAmJiByZWZyZXNoX3Rva2VuKSB7XG4gICAgICB0aGlzLmh0dHAucG9zdCh0b2tlblBhdGgsIG5ldyBIdHRwUGFyYW1zKHtcbiAgICAgICAgZnJvbU9iamVjdDoge1xuICAgICAgICAgIGNsaWVudF9pZDogY2xpZW50SWQsXG4gICAgICAgICAgLi4uY2xpZW50U2VjcmV0ICYmIHtjbGllbnRfc2VjcmV0OiBjbGllbnRTZWNyZXR9IHx8IHt9LFxuICAgICAgICAgIGdyYW50X3R5cGU6ICdyZWZyZXNoX3Rva2VuJyxcbiAgICAgICAgICByZWZyZXNoX3Rva2VuLFxuICAgICAgICAgIC4uLnNjb3BlICYmIHtzY29wZX0gfHwge30sXG4gICAgICAgIH1cbiAgICAgIH0pLCB7aGVhZGVyczogUkVRVUVTVF9IRUFERVJ9KS5waXBlKFxuICAgICAgICBjYXRjaEVycm9yKCgpID0+IHtcbiAgICAgICAgICB0aGlzLmxvZ291dCgpO1xuICAgICAgICAgIHJldHVybiBFTVBUWTtcbiAgICAgICAgfSlcbiAgICAgICkuc3Vic2NyaWJlKHBhcmFtcyA9PiB7XG4gICAgICAgIHRoaXMudG9rZW4gPSB7XG4gICAgICAgICAgLi4udGhpcy50b2tlbixcbiAgICAgICAgICAuLi5wYXJhbXNcbiAgICAgICAgfTtcbiAgICAgICAgdGhpcy5zdGF0dXMgPSBPQXV0aFN0YXR1cy5BVVRIT1JJWkVEO1xuICAgICAgfSk7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBnZXRDbGVhbmVkVW5TZWFyY2hQYXJhbWV0ZXJzKCk6IHN0cmluZyB7XG4gICAgY29uc3Qge3NlYXJjaH0gPSB0aGlzLmxvY2F0aW9uO1xuICAgIGxldCBzZWFyY2hTdHJpbmcgPSBzZWFyY2guc3Vic3RyKDEpO1xuICAgIGNvbnN0IGhhc2hLZXlzID0gWydjb2RlJywgJ3N0YXRlJywgJ2Vycm9yJywgJ2Vycm9yX2Rlc2NyaXB0aW9uJywgJ3Nlc3Npb25fc3RhdGUnXTtcbiAgICBoYXNoS2V5cy5mb3JFYWNoKChoYXNoS2V5KSA9PiB7XG4gICAgICBjb25zdCByZSA9IG5ldyBSZWdFeHAoJyYnICsgaGFzaEtleSArICcoPVteJl0qKT98XicgKyBoYXNoS2V5ICsgJyg9W14mXSopPyY/Jyk7XG4gICAgICBzZWFyY2hTdHJpbmcgPSBzZWFyY2hTdHJpbmcucmVwbGFjZShyZSwgJycpO1xuICAgIH0pO1xuICAgIHJldHVybiBzZWFyY2hTdHJpbmcubGVuZ3RoICYmIGA/JHtzZWFyY2hTdHJpbmd9YCB8fCAnJztcbiAgfVxuXG4gIHByaXZhdGUgY2xlYW5Mb2NhdGlvbkhhc2goKSB7XG4gICAgY29uc3Qge2hhc2h9ID0gdGhpcy5sb2NhdGlvbjtcbiAgICBsZXQgY3VySGFzaCA9IGhhc2guc3Vic3RyKDEpO1xuICAgIGNvbnN0IGhhc2hLZXlzID0gWydhY2Nlc3NfdG9rZW4nLCAndG9rZW5fdHlwZScsICdleHBpcmVzX2luJywgJ3Njb3BlJywgJ3N0YXRlJywgJ2Vycm9yJywgJ2Vycm9yX2Rlc2NyaXB0aW9uJywgJ3Nlc3Npb25fc3RhdGUnLCAnbm9uY2UnXTtcbiAgICBoYXNoS2V5cy5mb3JFYWNoKChoYXNoS2V5KSA9PiB7XG4gICAgICBjb25zdCByZSA9IG5ldyBSZWdFeHAoJyYnICsgaGFzaEtleSArICcoPVteJl0qKT98XicgKyBoYXNoS2V5ICsgJyg9W14mXSopPyY/Jyk7XG4gICAgICBjdXJIYXNoID0gY3VySGFzaC5yZXBsYWNlKHJlLCAnJyk7XG4gICAgfSk7XG4gICAgdGhpcy5sb2NhdGlvbi5oYXNoID0gY3VySGFzaDtcbiAgfVxuXG4gIHByaXZhdGUgZW1pdFN0YXRlKHBhcmFtZXRlcnM6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4gfCBudWxsKSB7XG4gICAgY29uc3Qge3N0YXRlfSA9IHBhcmFtZXRlcnMgYXMgYW55O1xuICAgIGlmIChzdGF0ZSkge1xuICAgICAgdGhpcy5zdGF0ZSQubmV4dChzdGF0ZSk7XG4gICAgfVxuICB9XG59XG4iXX0=
File without changes