@huntsman-cancer-institute/authentication 12.5.0 → 14.1.0

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.
Files changed (47) hide show
  1. package/authentication.component.d.ts +1 -1
  2. package/directlogin.component.d.ts +4 -4
  3. package/esm2020/authentication.component.mjs +131 -0
  4. package/esm2020/authentication.module.mjs +105 -0
  5. package/esm2020/authentication.provider.mjs +36 -0
  6. package/esm2020/authentication.service.mjs +393 -0
  7. package/esm2020/authorization.interceptor.mjs +79 -0
  8. package/esm2020/directlogin.component.mjs +96 -0
  9. package/esm2020/huntsman-cancer-institute-authentication.mjs +5 -0
  10. package/esm2020/index.mjs +13 -0
  11. package/esm2020/route-guard.service.mjs +52 -0
  12. package/esm2020/timeout-notification.component.mjs +148 -0
  13. package/fesm2015/huntsman-cancer-institute-authentication.mjs +1000 -0
  14. package/fesm2015/huntsman-cancer-institute-authentication.mjs.map +1 -0
  15. package/{fesm2015/huntsman-cancer-institute-authentication.js → fesm2020/huntsman-cancer-institute-authentication.mjs} +64 -189
  16. package/fesm2020/huntsman-cancer-institute-authentication.mjs.map +1 -0
  17. package/package.json +26 -18
  18. package/timeout-notification.component.d.ts +1 -1
  19. package/CHANGELOG.md +0 -4
  20. package/bundles/huntsman-cancer-institute-authentication.umd.js +0 -945
  21. package/bundles/huntsman-cancer-institute-authentication.umd.js.map +0 -1
  22. package/bundles/huntsman-cancer-institute-authentication.umd.min.js +0 -2
  23. package/bundles/huntsman-cancer-institute-authentication.umd.min.js.map +0 -1
  24. package/esm2015/authentication.component.js +0 -153
  25. package/esm2015/authentication.module.js +0 -107
  26. package/esm2015/authentication.provider.js +0 -36
  27. package/esm2015/authentication.service.js +0 -393
  28. package/esm2015/authorization.interceptor.js +0 -79
  29. package/esm2015/directlogin.component.js +0 -146
  30. package/esm2015/huntsman-cancer-institute-authentication.js +0 -5
  31. package/esm2015/index.js +0 -13
  32. package/esm2015/route-guard.service.js +0 -52
  33. package/esm2015/timeout-notification.component.js +0 -205
  34. package/esm5/authentication.component.js +0 -120
  35. package/esm5/authentication.module.js +0 -109
  36. package/esm5/authentication.provider.js +0 -47
  37. package/esm5/authentication.service.js +0 -411
  38. package/esm5/authorization.interceptor.js +0 -81
  39. package/esm5/directlogin.component.js +0 -53
  40. package/esm5/huntsman-cancer-institute-authentication.js +0 -5
  41. package/esm5/index.js +0 -13
  42. package/esm5/route-guard.service.js +0 -55
  43. package/esm5/timeout-notification.component.js +0 -125
  44. package/fesm2015/huntsman-cancer-institute-authentication.js.map +0 -1
  45. package/fesm5/huntsman-cancer-institute-authentication.js +0 -937
  46. package/fesm5/huntsman-cancer-institute-authentication.js.map +0 -1
  47. package/huntsman-cancer-institute-authentication.d.ts +0 -5
@@ -1,411 +0,0 @@
1
- /*
2
- * Copyright (c) 2016 Huntsman Cancer Institute at the University of Utah, Confidential and Proprietary
3
- */
4
- import { Injectable, InjectionToken, Inject, Optional, isDevMode } from "@angular/core";
5
- import { LocationStrategy } from "@angular/common";
6
- import { Router } from "@angular/router";
7
- import { HttpClient, HttpHeaders } from "@angular/common/http";
8
- import { interval, BehaviorSubject, throwError } from "rxjs";
9
- import { catchError, map } from "rxjs/operators";
10
- import { JwtHelperService } from "@auth0/angular-jwt";
11
- import { AuthenticationProvider } from "./authentication.provider";
12
- import { CoolLocalStorage } from "@angular-cool/storage";
13
- import * as i0 from "@angular/core";
14
- import * as i1 from "@angular/common/http";
15
- import * as i2 from "@angular/router";
16
- import * as i3 from "@angular-cool/storage";
17
- import * as i4 from "@auth0/angular-jwt";
18
- import * as i5 from "./authentication.provider";
19
- import * as i6 from "@angular/common";
20
- /**
21
- * The token used for injection of the server side endpoint for the currently authenticated subject.
22
- *
23
- * @type {InjectionToken}
24
- */
25
- export var AUTHENTICATION_SERVER_URL = new InjectionToken("authentication_server_rest_api");
26
- export var AUTHENTICATION_LOGOUT_PATH = new InjectionToken("authentication_logout_path");
27
- export var AUTHENTICATION_DIRECT_ENDPOINT = new InjectionToken("authentication_direct_endpoint");
28
- export var AUTHENTICATION_TOKEN_ENDPOINT = new InjectionToken("authentication_token_endpoint");
29
- export var AUTHENTICATION_ROUTE = new InjectionToken("authentication_route");
30
- export var AUTHENTICATION_MAX_INACTIVITY_MINUTES = new InjectionToken("authentication_max_inactivity");
31
- export var AUTHENTICATION_USER_COUNTDOWN_SECONDS = new InjectionToken("authentication_user_countdown_seconds");
32
- export var AUTHENTICATION_IDP_INACTIVITY_MINUTES = new InjectionToken("authentication_idp_inactivity_minutes");
33
- /**
34
- * @since 1.0.0
35
- */
36
- var AuthenticationService = /** @class */ (function () {
37
- function AuthenticationService(_http, _router, _localStorageService, _jwtHelper, authenticationProvider, _authenticationRoute, _logoutPath, _tokenEndpoint, _serverUrl, _directEndpoint, _maxInactivity, _userCountdownSeconds, _idpInactivityMinutes, locationStrategy) {
38
- this._http = _http;
39
- this._router = _router;
40
- this._localStorageService = _localStorageService;
41
- this._jwtHelper = _jwtHelper;
42
- this.authenticationProvider = authenticationProvider;
43
- this._authenticationRoute = _authenticationRoute;
44
- this._logoutPath = _logoutPath;
45
- this._tokenEndpoint = _tokenEndpoint;
46
- this._serverUrl = _serverUrl;
47
- this._directEndpoint = _directEndpoint;
48
- this._maxInactivity = _maxInactivity;
49
- this._userCountdownSeconds = _userCountdownSeconds;
50
- this._idpInactivityMinutes = _idpInactivityMinutes;
51
- this.locationStrategy = locationStrategy;
52
- this.userCountdownSeconds = 60;
53
- this.idpInactivityMinutes = 5;
54
- this.contentType = "application/json";
55
- this.limitedContext = false;
56
- this.deidentifiedContext = false;
57
- this.maxViewPermission = new BehaviorSubject("viewident");
58
- this._isAuthenticatedSubject = new BehaviorSubject(false);
59
- this._userIsAboutToTimeOut = new BehaviorSubject(false);
60
- this._maxInactivityMinutes = 120;
61
- this.contextRoot = "";
62
- if (isDevMode()) {
63
- console.debug("window.location.href: " + window.location.href);
64
- }
65
- if (window.location) {
66
- var parts = window.location.href.split("/");
67
- this.baseUrl = parts[0] + "//" + parts[2];
68
- if (parts.length > 3) {
69
- this.contextRoot = parts[3];
70
- }
71
- }
72
- if (this._localStorageService.getItem("maxViewPermission")) {
73
- this.maxViewPermission.next(this._localStorageService.getItem("maxViewPermission"));
74
- }
75
- if (_maxInactivity) {
76
- this._maxInactivityMinutes = _maxInactivity;
77
- }
78
- if (_userCountdownSeconds) {
79
- this.userCountdownSeconds = _userCountdownSeconds;
80
- }
81
- if (_idpInactivityMinutes) {
82
- this.idpInactivityMinutes = _idpInactivityMinutes;
83
- }
84
- this.hasValidConfig();
85
- //There could be a non-expired token in local storage.
86
- var token = this.authenticationProvider.authToken;
87
- this.storeToken(token);
88
- }
89
- AuthenticationService.prototype.getBaseUrl = function () {
90
- return (this.baseUrl) ? this.baseUrl : "";
91
- };
92
- AuthenticationService.prototype.getContextRoot = function () {
93
- return this.contextRoot;
94
- };
95
- AuthenticationService.prototype.getHeaders = function (req) {
96
- var headers = req.headers;
97
- //Don't set content type if already set
98
- if (!req.headers.get(AuthenticationService.CONTENT_TYPE)) {
99
- headers = headers.set(AuthenticationService.CONTENT_TYPE, this.contentType.toString());
100
- }
101
- if (headers.get(AuthenticationService.SEC_GOV_CLASS_HEADER) === "") {
102
- headers = headers.delete(AuthenticationService.SEC_GOV_CLASS_HEADER);
103
- }
104
- else if (this.securityGovernorClass && !headers.get(AuthenticationService.SEC_GOV_CLASS_HEADER)) {
105
- headers = headers.set(AuthenticationService.SEC_GOV_CLASS_HEADER, this.securityGovernorClass);
106
- }
107
- if (headers.get(AuthenticationService.SEC_GOV_ID_HEADER) === "") {
108
- headers = headers.delete(AuthenticationService.SEC_GOV_ID_HEADER);
109
- }
110
- else if (this.securityGovernorId && !headers.get(AuthenticationService.SEC_GOV_ID_HEADER)) {
111
- headers = headers.set(AuthenticationService.SEC_GOV_ID_HEADER, this.securityGovernorId.toString());
112
- }
113
- headers = headers.set(AuthenticationService.DEIDENT_HEADER, this.deidentifiedContext.toString());
114
- headers = headers.set(AuthenticationService.LIMITED_HEADER, this.limitedContext.toString());
115
- return headers;
116
- };
117
- Object.defineProperty(AuthenticationService.prototype, "authenticationTokenKey", {
118
- get: function () {
119
- return this.authenticationProvider.authenticationTokenKey;
120
- },
121
- enumerable: false,
122
- configurable: true
123
- });
124
- Object.defineProperty(AuthenticationService.prototype, "authToken", {
125
- get: function () {
126
- return this.authenticationProvider.authToken;
127
- },
128
- enumerable: false,
129
- configurable: true
130
- });
131
- AuthenticationService.prototype.updateUserActivity = function () {
132
- if (this._isAuthenticatedSubject.value) {
133
- this._lastUserInteraction = new Date();
134
- this._userIsAboutToTimeOut.next(false);
135
- }
136
- };
137
- Object.defineProperty(AuthenticationService.prototype, "redirectUrl", {
138
- get: function () {
139
- return this._redirectUrl;
140
- },
141
- /**
142
- * A mutator for identifying the clients original request location. Setting this value will influence the end location
143
- * navigated to by {@link #navigateToPath}.
144
- *
145
- * @param redirectUrl location of the users request before authentication
146
- */
147
- set: function (redirectUrl) {
148
- this._redirectUrl = redirectUrl;
149
- },
150
- enumerable: false,
151
- configurable: true
152
- });
153
- AuthenticationService.prototype.requestAccessToken = function (redirectOnSuccess) {
154
- var _this = this;
155
- this._http.get(this.tokenLocation(), { withCredentials: true })
156
- .subscribe(function (response) {
157
- _this.storeToken(response.auth_token);
158
- if (redirectOnSuccess) {
159
- _this.proceedIfAuthenticated();
160
- }
161
- }, function (error) {
162
- //Token refresh failed.
163
- _this.logout(true);
164
- });
165
- };
166
- /**
167
- * Verifies whether or not a current user session exists.
168
- *
169
- * @returns {Observable<boolean>} evaluates to true if the user is authenticated, false otherwise.
170
- */
171
- AuthenticationService.prototype.isAuthenticated = function () {
172
- return this._isAuthenticatedSubject.asObservable();
173
- };
174
- AuthenticationService.prototype.isAboutToTimeOut = function () {
175
- return this._userIsAboutToTimeOut.asObservable();
176
- };
177
- AuthenticationService.prototype.getTimeoutStart = function () {
178
- if (this._lastUserInteraction) {
179
- return this._lastUserInteraction.valueOf() + (((this._maxInactivityMinutes * 60) - this.userCountdownSeconds) * 1000);
180
- }
181
- };
182
- AuthenticationService.prototype.tokenLocation = function () {
183
- if (this._serverUrl) {
184
- return this._serverUrl + this._tokenEndpoint;
185
- }
186
- else {
187
- return this._tokenEndpoint;
188
- }
189
- };
190
- AuthenticationService.prototype.directLoginLocation = function () {
191
- if (this._serverUrl) {
192
- return this._serverUrl + this._directEndpoint;
193
- }
194
- else {
195
- return this._directEndpoint;
196
- }
197
- };
198
- AuthenticationService.prototype.logoutLocation = function () {
199
- if (this._serverUrl) {
200
- return this._serverUrl + this._logoutPath;
201
- }
202
- else {
203
- return this._logoutPath;
204
- }
205
- };
206
- /**
207
- * A function to authenticated the user with the provided credentials. Failure results in an error that describes the
208
- * server response (status and status message) and should be actionable by the client application.
209
- *
210
- * @param username of the authenticating user to verify
211
- * @param password of the authenticating user to verify
212
- * @returns {Observable<R>} describing the result of the login action, true or an error
213
- */
214
- AuthenticationService.prototype.login = function (_username, _password) {
215
- return this._http.post(this.directLoginLocation(), { username: _username, password: _password }, { observe: "response" }).pipe(map(function (resp) {
216
- if (resp.status === 201) {
217
- return true;
218
- }
219
- else {
220
- throw new Error("Authentication failed. " + resp.status + ": " + resp.statusText);
221
- }
222
- }), catchError(this.handleError));
223
- };
224
- AuthenticationService.prototype.clearLogin = function () {
225
- //Front-end logout
226
- try {
227
- this._localStorageService.removeItem(this.authenticationProvider.authenticationTokenKey);
228
- this.unsubscribeFromTokenRefresh();
229
- this._isAuthenticatedSubject.next(false);
230
- this._userIsAboutToTimeOut.next(false);
231
- }
232
- catch (Error) {
233
- }
234
- //Back-end logout
235
- var headers = new HttpHeaders().set(AuthenticationService.CONTENT_TYPE, "text/plain");
236
- return this._http.get(this.logoutLocation(), { headers: headers });
237
- };
238
- /**
239
- * A function to signal the termination of the current session. Invoking this function will clean up any relevant state
240
- * related to the last active session.
241
- */
242
- AuthenticationService.prototype.logout = function (keepCurrentRoute) {
243
- var _this = this;
244
- if (keepCurrentRoute === void 0) { keepCurrentRoute = false; }
245
- //Prevent logout if already on authentication route. Doing otherwise screws up SAML
246
- if (!this._router.routerState || this._router.routerState.snapshot.url !== this._authenticationRoute) {
247
- this._redirectUrl = (keepCurrentRoute && this._router.routerState && this._router.routerState.snapshot) ? this._router.routerState.snapshot.url : "";
248
- if (this._redirectUrl.startsWith("/")) {
249
- this._redirectUrl = this._redirectUrl.substring(1);
250
- }
251
- this.clearLogin().subscribe(function (response) {
252
- window.location.replace(_this._redirectUrl);
253
- }, function (error) {
254
- window.location.replace(_this._redirectUrl);
255
- });
256
- }
257
- };
258
- AuthenticationService.prototype.storeToken = function (token) {
259
- var valid = this.validateToken(token);
260
- // unsubscribe from refesh before we decide wether to resubscribe
261
- this.unsubscribeFromTokenRefresh();
262
- if (valid) {
263
- this._localStorageService.setItem(this.authenticationProvider.authenticationTokenKey, token);
264
- this.subscribeToTokenRefresh(token);
265
- //Change the BehaviorSubject if the user was not previously authenticated.
266
- //Since other code may be subscribing to this observable, we don't want to cause new events to fire if just refreshing the JWT.
267
- if (!this._isAuthenticatedSubject.value) {
268
- this._isAuthenticatedSubject.next(true);
269
- }
270
- }
271
- else {
272
- this._localStorageService.removeItem(this.authenticationProvider.authenticationTokenKey);
273
- this._isAuthenticatedSubject.next(false);
274
- }
275
- };
276
- AuthenticationService.prototype.proceedIfAuthenticated = function () {
277
- if (isDevMode()) {
278
- console.debug("AuthenticationService.proceedIfAuthenticated: " + this._redirectUrl);
279
- }
280
- if (this._isAuthenticatedSubject.value) {
281
- //Login counts as user activity, too
282
- this.updateUserActivity();
283
- if (this._redirectUrl && this._redirectUrl && this._redirectUrl !== "") {
284
- this._router.navigateByUrl(this._redirectUrl);
285
- }
286
- else {
287
- this._router.navigate([""]);
288
- }
289
- return true;
290
- }
291
- else {
292
- return false;
293
- }
294
- };
295
- AuthenticationService.prototype.validateToken = function (token) {
296
- return (token && !this._jwtHelper.isTokenExpired(token));
297
- };
298
- AuthenticationService.prototype.subscribeToTokenRefresh = function (token) {
299
- var _this = this;
300
- var exp = this._jwtHelper.getTokenExpirationDate(token);
301
- // Use a timer to periodically check timeouts
302
- this._refreshSubscription = interval(1000)
303
- .subscribe(function () {
304
- // If a tab is inactive we can't know if our timer is accurate
305
- // so when the interval hits check against timestamps
306
- if (_this._isAuthenticatedSubject.value && Date.now() > _this.getTimeoutStart()) {
307
- //Don't update the subject more than once! Doing so initializes more than one countdown timer!
308
- if (_this._userIsAboutToTimeOut.getValue() !== true) {
309
- _this._userIsAboutToTimeOut.next(true);
310
- }
311
- }
312
- // check for refresh token
313
- var msToExpiry = (exp.valueOf() - new Date().valueOf());
314
- // Refresh 60 seconds before expiry
315
- if (msToExpiry <= 60000) {
316
- _this.refreshTokenIfUserIsActive();
317
- }
318
- });
319
- };
320
- AuthenticationService.prototype.unsubscribeFromTokenRefresh = function () {
321
- if (this._refreshSubscription && !this._refreshSubscription.closed) {
322
- this._refreshSubscription.unsubscribe();
323
- }
324
- };
325
- AuthenticationService.prototype.getMaxViewPermission = function () {
326
- return this.maxViewPermission.getValue();
327
- };
328
- AuthenticationService.prototype.getMaxViewPermissionSubject = function () {
329
- return this.maxViewPermission;
330
- };
331
- AuthenticationService.prototype.setMaxViewPermission = function (maxViewPermission) {
332
- this._localStorageService.setItem("maxViewPermission", maxViewPermission);
333
- this.maxViewPermission.next(maxViewPermission);
334
- };
335
- AuthenticationService.prototype.refreshTokenIfUserIsActive = function () {
336
- //Only refresh if the user has been active
337
- if (this._lastUserInteraction && ((new Date().valueOf() - this._lastUserInteraction.valueOf()) <= (this._maxInactivityMinutes * 60 * 1000))) {
338
- this.requestAccessToken(false);
339
- }
340
- };
341
- AuthenticationService.prototype.hasValidConfig = function () {
342
- if (this._tokenEndpoint == null && (this._serverUrl === null || this._logoutPath === null)) {
343
- throw new Error("BUG ALERT! Invalid AuthenticationService configuration. No valid configuration for authentication endpoint(s).");
344
- }
345
- if (this._localStorageService === null || this.authenticationProvider.authenticationTokenKey === null) {
346
- throw new Error("BUG ALERT! Invalid AuthenticationService configuration. No valid configuration for local storage");
347
- }
348
- };
349
- AuthenticationService.prototype.handleError = function (error) {
350
- var errMsg = (error.message) ? error.message : AuthenticationService.GENERIC_ERR_MSG;
351
- return throwError(errMsg);
352
- };
353
- /**
354
- * The generic error message used when a server error is thrown without a status.
355
- *
356
- * @type {string}
357
- */
358
- AuthenticationService.GENERIC_ERR_MSG = "Server error";
359
- AuthenticationService.CONTENT_TYPE = "Content-Type";
360
- AuthenticationService.SEC_GOV_CLASS_HEADER = "SecurityGovernorClass";
361
- AuthenticationService.SEC_GOV_ID_HEADER = "SecurityGovernorId";
362
- AuthenticationService.DEIDENT_HEADER = "DeidentifiedContext";
363
- AuthenticationService.LIMITED_HEADER = "LimitedContext";
364
- AuthenticationService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.17", ngImport: i0, type: AuthenticationService, deps: [{ token: i1.HttpClient }, { token: i2.Router }, { token: i3.CoolLocalStorage }, { token: i4.JwtHelperService }, { token: i5.AuthenticationProvider }, { token: AUTHENTICATION_ROUTE }, { token: AUTHENTICATION_LOGOUT_PATH }, { token: AUTHENTICATION_TOKEN_ENDPOINT }, { token: AUTHENTICATION_SERVER_URL, optional: true }, { token: AUTHENTICATION_DIRECT_ENDPOINT, optional: true }, { token: AUTHENTICATION_MAX_INACTIVITY_MINUTES, optional: true }, { token: AUTHENTICATION_USER_COUNTDOWN_SECONDS, optional: true }, { token: AUTHENTICATION_IDP_INACTIVITY_MINUTES, optional: true }, { token: LocationStrategy, optional: true }], target: i0.ɵɵFactoryTarget.Injectable });
365
- AuthenticationService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "12.2.17", ngImport: i0, type: AuthenticationService });
366
- return AuthenticationService;
367
- }());
368
- export { AuthenticationService };
369
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.17", ngImport: i0, type: AuthenticationService, decorators: [{
370
- type: Injectable
371
- }], ctorParameters: function () { return [{ type: i1.HttpClient }, { type: i2.Router }, { type: i3.CoolLocalStorage }, { type: i4.JwtHelperService }, { type: i5.AuthenticationProvider }, { type: undefined, decorators: [{
372
- type: Inject,
373
- args: [AUTHENTICATION_ROUTE]
374
- }] }, { type: undefined, decorators: [{
375
- type: Inject,
376
- args: [AUTHENTICATION_LOGOUT_PATH]
377
- }] }, { type: undefined, decorators: [{
378
- type: Inject,
379
- args: [AUTHENTICATION_TOKEN_ENDPOINT]
380
- }] }, { type: undefined, decorators: [{
381
- type: Optional
382
- }, {
383
- type: Inject,
384
- args: [AUTHENTICATION_SERVER_URL]
385
- }] }, { type: undefined, decorators: [{
386
- type: Optional
387
- }, {
388
- type: Inject,
389
- args: [AUTHENTICATION_DIRECT_ENDPOINT]
390
- }] }, { type: undefined, decorators: [{
391
- type: Optional
392
- }, {
393
- type: Inject,
394
- args: [AUTHENTICATION_MAX_INACTIVITY_MINUTES]
395
- }] }, { type: undefined, decorators: [{
396
- type: Optional
397
- }, {
398
- type: Inject,
399
- args: [AUTHENTICATION_USER_COUNTDOWN_SECONDS]
400
- }] }, { type: undefined, decorators: [{
401
- type: Optional
402
- }, {
403
- type: Inject,
404
- args: [AUTHENTICATION_IDP_INACTIVITY_MINUTES]
405
- }] }, { type: i6.LocationStrategy, decorators: [{
406
- type: Optional
407
- }, {
408
- type: Inject,
409
- args: [LocationStrategy]
410
- }] }]; } });
411
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXV0aGVudGljYXRpb24uc2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiJuZzovL0BodW50c21hbi1jYW5jZXItaW5zdGl0dXRlL2F1dGhlbnRpY2F0aW9uLyIsInNvdXJjZXMiOlsiYXV0aGVudGljYXRpb24uc2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7R0FFRztBQUNILE9BQU8sRUFBQyxVQUFVLEVBQUUsY0FBYyxFQUFFLE1BQU0sRUFBRSxRQUFRLEVBQUUsU0FBUyxFQUFDLE1BQU0sZUFBZSxDQUFDO0FBQ3RGLE9BQU8sRUFBQyxnQkFBZ0IsRUFBQyxNQUFNLGlCQUFpQixDQUFDO0FBQ2pELE9BQU8sRUFBQyxNQUFNLEVBQUMsTUFBTSxpQkFBaUIsQ0FBQztBQUN2QyxPQUFPLEVBQUMsVUFBVSxFQUFFLFdBQVcsRUFBNEIsTUFBTSxzQkFBc0IsQ0FBQztBQUV4RixPQUFPLEVBQUMsUUFBUSxFQUFjLGVBQWUsRUFBZ0IsVUFBVSxFQUFLLE1BQU0sTUFBTSxDQUFDO0FBQ3pGLE9BQU8sRUFBQyxVQUFVLEVBQVMsR0FBRyxFQUFDLE1BQU0sZ0JBQWdCLENBQUM7QUFDdEQsT0FBTyxFQUFDLGdCQUFnQixFQUFDLE1BQU0sb0JBQW9CLENBQUM7QUFFcEQsT0FBTyxFQUFDLHNCQUFzQixFQUFDLE1BQU0sMkJBQTJCLENBQUM7QUFDakUsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sdUJBQXVCLENBQUM7Ozs7Ozs7O0FBRXpEOzs7O0dBSUc7QUFDSCxNQUFNLENBQUMsSUFBSSx5QkFBeUIsR0FBRyxJQUFJLGNBQWMsQ0FBUyxnQ0FBZ0MsQ0FBQyxDQUFDO0FBQ3BHLE1BQU0sQ0FBQyxJQUFJLDBCQUEwQixHQUFHLElBQUksY0FBYyxDQUFTLDRCQUE0QixDQUFDLENBQUM7QUFDakcsTUFBTSxDQUFDLElBQUksOEJBQThCLEdBQUcsSUFBSSxjQUFjLENBQVMsZ0NBQWdDLENBQUMsQ0FBQztBQUN6RyxNQUFNLENBQUMsSUFBSSw2QkFBNkIs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QyxDQUFDLHFCQUFxQixDQUFDLGVBQWUsQ0FBQztRQUNyRixPQUFPLFVBQVUsQ0FBQyxNQUFNLENBQUMsQ0FBQztJQUM1QixDQUFDO0lBMVhEOzs7O09BSUc7SUFDVyxxQ0FBZSxHQUFXLGNBQWMsQ0FBQztJQUV4QyxrQ0FBWSxHQUFXLGNBQWMsQ0FBQztJQUN0QywwQ0FBb0IsR0FBVyx1QkFBdUIsQ0FBQztJQUN2RCx1Q0FBaUIsR0FBVyxvQkFBb0IsQ0FBQztJQUNqRCxvQ0FBYyxHQUFXLHFCQUFxQixDQUFDO0lBQy9DLG9DQUFjLEdBQVcsZ0JBQWdCLENBQUM7dUhBYjlDLHFCQUFxQix3S0F3Q1osb0JBQW9CLGFBQ3BCLDBCQUEwQixhQUMxQiw2QkFBNkIsYUFDakIseUJBQXlCLDZCQUN6Qiw4QkFBOEIsNkJBQzlCLHFDQUFxQyw2QkFDckMscUNBQXFDLDZCQUNyQyxxQ0FBcUMsNkJBQ3JDLGdCQUFnQjsySEFoRHJDLHFCQUFxQjtnQ0FqQ2xDO0NBOFpDLEFBOVhELElBOFhDO1NBN1hZLHFCQUFxQjs0RkFBckIscUJBQXFCO2tCQURqQyxVQUFVOzswQkF5Q0ksTUFBTTsyQkFBQyxvQkFBb0I7OzBCQUMzQixNQUFNOzJCQUFDLDBCQUEwQjs7MEJBQ2pDLE1BQU07MkJBQUMsNkJBQTZCOzswQkFDcEMsUUFBUTs7MEJBQUksTUFBTTsyQkFBQyx5QkFBeUI7OzBCQUM1QyxRQUFROzswQkFBSSxNQUFNOzJCQUFDLDhCQUE4Qjs7MEJBQ2pELFFBQVE7OzBCQUFJLE1BQU07MkJBQUMscUNBQXFDOzswQkFDeEQsUUFBUTs7MEJBQUksTUFBTTsyQkFBQyxxQ0FBcUM7OzBCQUN4RCxRQUFROzswQkFBSSxNQUFNOzJCQUFDLHFDQUFxQzs7MEJBQ3hELFFBQVE7OzBCQUFJLE1BQU07MkJBQUMsZ0JBQWdCIiwic291cmNlc0NvbnRlbnQiOlsiLypcclxuICogQ29weXJpZ2h0IChjKSAyMDE2IEh1bnRzbWFuIENhbmNlciBJbnN0aXR1dGUgYXQgdGhlIFVuaXZlcnNpdHkgb2YgVXRhaCwgQ29uZmlkZW50aWFsIGFuZCBQcm9wcmlldGFyeVxyXG4gKi9cclxuaW1wb3J0IHtJbmplY3RhYmxlLCBJbmplY3Rpb25Ub2tlbiwgSW5qZWN0LCBPcHRpb25hbCwgaXNEZXZNb2RlfSBmcm9tIFwiQGFuZ3VsYXIvY29yZVwiO1xyXG5pbXBvcnQge0xvY2F0aW9uU3RyYXRlZ3l9IGZyb20gXCJAYW5ndWxhci9jb21tb25cIjtcclxuaW1wb3J0IHtSb3V0ZXJ9IGZyb20gXCJAYW5ndWxhci9yb3V0ZXJcIjtcclxuaW1wb3J0IHtIdHRwQ2xpZW50LCBIdHRwSGVhZGVycywgSHR0cFJlcXVlc3QsIEh0dHBSZXNwb25zZX0gZnJvbSBcIkBhbmd1bGFyL2NvbW1vbi9odHRwXCI7XHJcblxyXG5pbXBvcnQge2ludGVydmFsLCBPYnNlcnZhYmxlLCBCZWhhdmlvclN1YmplY3QsIFN1YnNjcmlwdGlvbiwgdGhyb3dFcnJvciwgb2Z9IGZyb20gXCJyeGpzXCI7XHJcbmltcG9ydCB7Y2F0Y2hFcnJvciwgZmlyc3QsIG1hcH0gZnJvbSBcInJ4anMvb3BlcmF0b3JzXCI7XHJcbmltcG9ydCB7Snd0SGVscGVyU2VydmljZX0gZnJvbSBcIkBhdXRoMC9hbmd1bGFyLWp3dFwiO1xyXG5cclxuaW1wb3J0IHtBdXRoZW50aWNhdGlvblByb3ZpZGVyfSBmcm9tIFwiLi9hdXRoZW50aWNhdGlvbi5wcm92aWRlclwiO1xyXG5pbXBvcnQgeyBDb29sTG9jYWxTdG9yYWdlIH0gZnJvbSBcIkBhbmd1bGFyLWNvb2wvc3RvcmFnZVwiO1xyXG5cclxuLyoqXHJcbiAqIFRoZSB0b2tlbiB1c2VkIGZvciBpbmplY3Rpb24gb2YgdGhlIHNlcnZlciBzaWRlIGVuZHBvaW50IGZvciB0aGUgY3VycmVudGx5IGF1dGhlbnRpY2F0ZWQgc3ViamVjdC5cclxuICpcclxuICogQHR5cGUge0luamVjdGlvblRva2VufVxyXG4gKi9cclxuZXhwb3J0IGxldCBBVVRIRU5USUNBVElPTl9TRVJWRVJfVVJMID0gbmV3IEluamVjdGlvblRva2VuPHN0cmluZz4oXCJhdXRoZW50aWNhdGlvbl9zZXJ2ZXJfcmVzdF9hcGlcIik7XHJcbmV4cG9ydCBsZXQgQVVUSEVOVElDQVRJT05fTE9HT1VUX1BBVEggPSBuZXcgSW5qZWN0aW9uVG9rZW48c3RyaW5nPihcImF1dGhlbnRpY2F0aW9uX2xvZ291dF9wYXRoXCIpO1xyXG5leHBvcnQgbGV0IEFVVEhFTlRJQ0FUSU9OX0RJUkVDVF9FTkRQT0lOVCA9IG5ldyBJbmplY3Rpb25Ub2tlbjxzdHJpbmc+KFwiYXV0aGVudGljYXRpb25fZGlyZWN0X2VuZHBvaW50XCIpO1xyXG5leHBvcnQgbGV0IEFVVEhFTlRJQ0FUSU9OX1RPS0VOX0VORFBPSU5UID0gbmV3IEluamVjdGlvblRva2VuPHN0cmluZz4oXCJhdXRoZW50aWNhdGlvbl90b2tlbl9lbmRwb2ludFwiKTtcclxuZXhwb3J0IGxldCBBVVRIRU5USUNBVElPTl9ST1VURSA9IG5ldyBJbmplY3Rpb25Ub2tlbjxzdHJpbmc+KFwiYXV0aGVudGljYXRpb25fcm91dGVcIik7XHJcbmV4cG9ydCBsZXQgQVVUSEVOVElDQVRJT05fTUFYX0lOQUNUSVZJVFlfTUlOVVRFUyA9IG5ldyBJbmplY3Rpb25Ub2tlbjxudW1iZXI+KFwiYXV0aGVudGljYXRpb25fbWF4X2luYWN0aXZpdHlcIik7XHJcbmV4cG9ydCBsZXQgQVVUSEVOVElDQVRJT05fVVNFUl9DT1VOVERPV05fU0VDT05EUyA9IG5ldyBJbmplY3Rpb25Ub2tlbjxudW1iZXI+KFwiYXV0aGVudGljYXRpb25fdXNlcl9jb3VudGRvd25fc2Vjb25kc1wiKTtcclxuZXhwb3J0IGxldCBBVVRIRU5USUNBVElPTl9JRFBfSU5BQ1RJVklUWV9NSU5VVEVTID0gbmV3IEluamVjdGlvblRva2VuPG51bWJlcj4oXCJhdXRoZW50aWNhdGlvbl9pZHBfaW5hY3Rpdml0eV9taW51dGVzXCIpO1xyXG5cclxuLyoqXHJcbiAqIEBzaW5jZSAxLjAuMFxyXG4gKi9cclxuQEluamVjdGFibGUoKVxyXG5leHBvcnQgY2xhc3MgQXV0aGVudGljYXRpb25TZXJ2aWNlIHtcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGdlbmVyaWMgZXJyb3IgbWVzc2FnZSB1c2VkIHdoZW4gYSBzZXJ2ZXIgZXJyb3IgaXMgdGhyb3duIHdpdGhvdXQgYSBzdGF0dXMuXHJcbiAgICpcclxuICAgKiBAdHlwZSB7c3RyaW5nfVxyXG4gICAqL1xyXG4gIHB1YmxpYyBzdGF0aWMgR0VORVJJQ19FUlJfTVNHOiBzdHJpbmcgPSBcIlNlcnZlciBlcnJvclwiO1xyXG5cclxuICBwcml2YXRlIHN0YXRpYyBDT05URU5UX1RZUEU6IHN0cmluZyA9IFwiQ29udGVudC1UeXBlXCI7XHJcbiAgcHJpdmF0ZSBzdGF0aWMgU0VDX0dPVl9DTEFTU19IRUFERVI6IHN0cmluZyA9IFwiU2VjdXJpdHlHb3Zlcm5vckNsYXNzXCI7XHJcbiAgcHJpdmF0ZSBzdGF0aWMgU0VDX0dPVl9JRF9IRUFERVI6IHN0cmluZyA9IFwiU2VjdXJpdHlHb3Zlcm5vcklkXCI7XHJcbiAgcHJpdmF0ZSBzdGF0aWMgREVJREVOVF9IRUFERVI6IHN0cmluZyA9IFwiRGVpZGVudGlmaWVkQ29udGV4dFwiO1xyXG4gIHByaXZhdGUgc3RhdGljIExJTUlURURfSEVBREVSOiBzdHJpbmcgPSBcIkxpbWl0ZWRDb250ZXh0XCI7XHJcblxyXG4gIHB1YmxpYyB1c2VyQ291bnRkb3duU2Vjb25kczogbnVtYmVyID0gNjA7XHJcbiAgcHVibGljIGlkcEluYWN0aXZpdHlNaW51dGVzOiBudW1iZXIgPSA1O1xyXG5cclxuICBwdWJsaWMgY29udGVudFR5cGU6IHN0cmluZyA9IFwiYXBwbGljYXRpb24vanNvblwiO1xyXG4gIHB1YmxpYyBzZWN1cml0eUdvdmVybm9yQ2xhc3M6IHN0cmluZztcclxuICBwdWJsaWMgc2VjdXJpdHlHb3Zlcm5vcklkOiBudW1iZXI7XHJcbiAgcHVibGljIGxpbWl0ZWRDb250ZXh0OiBib29sZWFuID0gZmFsc2U7XHJcbiAgcHVibGljIGRlaWRlbnRpZmllZENvbnRleHQ6IGJvb2xlYW4gPSBmYWxzZTtcclxuXHJcbiAgcHJpdmF0ZSBtYXhWaWV3UGVybWlzc2lvbjogQmVoYXZpb3JTdWJqZWN0PFwidmlld1wiIHwgXCJ2aWV3aWRlbnRcIiB8IFwidmlld2xpbWl0ZWRcIj4gPSBuZXcgQmVoYXZpb3JTdWJqZWN0PFwidmlld1wiIHwgXCJ2aWV3aWRlbnRcIiB8IFwidmlld2xpbWl0ZWRcIj4oXCJ2aWV3aWRlbnRcIik7XHJcbiAgcHJpdmF0ZSBfaXNBdXRoZW50aWNhdGVkU3ViamVjdDogQmVoYXZpb3JTdWJqZWN0PGJvb2xlYW4+ID0gbmV3IEJlaGF2aW9yU3ViamVjdDxib29sZWFuPihmYWxzZSk7XHJcbiAgcHJpdmF0ZSBfdXNlcklzQWJvdXRUb1RpbWVPdXQ6IEJlaGF2aW9yU3ViamVjdDxib29sZWFuPiA9IG5ldyBCZWhhdmlvclN1YmplY3Q8Ym9vbGVhbj4oZmFsc2UpO1xyXG4gIHByaXZhdGUgX3JlZGlyZWN0VXJsOiBzdHJpbmc7XHJcbiAgcHJpdmF0ZSBfcmVmcmVzaFN1YnNjcmlwdGlvbjogU3Vic2NyaXB0aW9uO1xyXG4gIHByaXZhdGUgX2xhc3RVc2VySW50ZXJhY3Rpb246IERhdGU7XHJcbiAgcHJpdmF0ZSBfbWF4SW5hY3Rpdml0eU1pbnV0ZXM6IG51bWJlciA9IDEyMDtcclxuXHJcbiAgcHJpdmF0ZSBiYXNlVXJsOiBzdHJpbmc7XHJcbiAgcHJpdmF0ZSBjb250ZXh0Um9vdDogc3RyaW5nID0gXCJcIjtcclxuXHJcbiAgY29uc3RydWN0b3IocHJpdmF0ZSBfaHR0cDogSHR0cENsaWVudCxcclxuICAgICAgICAgICAgICBwcml2YXRlIF9yb3V0ZXI6IFJvdXRlcixcclxuICAgICAgICAgICAgICBwcml2YXRlIF9sb2NhbFN0b3JhZ2VTZXJ2aWNlOiBDb29sTG9jYWxTdG9yYWdlLFxyXG4gICAgICAgICAgICAgIHByaXZhdGUgX2p3dEhlbHBlcjogSnd0SGVscGVyU2VydmljZSxcclxuICAgICAgICAgICAgICBwcml2YXRlIGF1dGhlbnRpY2F0aW9uUHJvdmlkZXI6IEF1dGhlbnRpY2F0aW9uUHJvdmlkZXIsXHJcbiAgICAgICAgICAgICAgQEluamVjdChBVVRIRU5USUNBVElPTl9ST1VURSkgcHJpdmF0ZSBfYXV0aGVudGljYXRpb25Sb3V0ZTogc3RyaW5nLFxyXG4gICAgICAgICAgICAgIEBJbmplY3QoQVVUSEVOVElDQVRJT05fTE9HT1VUX1BBVEgpIHByaXZhdGUgX2xvZ291dFBhdGg6IHN0cmluZyxcclxuICAgICAgICAgICAgICBASW5qZWN0KEFVVEhFTlRJQ0FUSU9OX1RPS0VOX0VORFBPSU5UKSBwcml2YXRlIF90b2tlbkVuZHBvaW50OiBzdHJpbmcsXHJcbiAgICAgICAgICAgICAgQE9wdGlvbmFsKCkgQEluamVjdChBVVRIRU5USUNBVElPTl9TRVJWRVJfVVJMKSBwcml2YXRlIF9zZXJ2ZXJVcmw6IHN0cmluZyxcclxuICAgICAgICAgICAgICBAT3B0aW9uYWwoKSBASW5qZWN0KEFVVEhFTlRJQ0FUSU9OX0RJUkVDVF9FTkRQT0lOVCkgcHJpdmF0ZSBfZGlyZWN0RW5kcG9pbnQ6IHN0cmluZyxcclxuICAgICAgICAgICAgICBAT3B0aW9uYWwoKSBASW5qZWN0KEFVVEhFTlRJQ0FUSU9OX01BWF9JTkFDVElWSVRZX01JTlVURVMpIHByaXZhdGUgX21heEluYWN0aXZpdHk6IG51bWJlcixcclxuICAgICAgICAgICAgICBAT3B0aW9uYWwoKSBASW5qZWN0KEFVVEhFTlRJQ0FUSU9OX1VTRVJfQ09VTlRET1dOX1NFQ09ORFMpIHByaXZhdGUgX3VzZXJDb3VudGRvd25TZWNvbmRzOiBudW1iZXIsXHJcbiAgICAgICAgICAgICAgQE9wdGlvbmFsKCkgQEluamVjdChBVVRIRU5USUNBVElPTl9JRFBfSU5BQ1RJVklUWV9NSU5VVEVTKSBwcml2YXRlIF9pZHBJbmFjdGl2aXR5TWludXRlczogbnVtYmVyLFxyXG4gICAgICAgICAgICAgIEBPcHRpb25hbCgpIEBJbmplY3QoTG9jYXRpb25TdHJhdGVneSkgcHJpdmF0ZSBsb2NhdGlvblN0cmF0ZWd5OiBMb2NhdGlvblN0cmF0ZWd5KSB7XHJcbiAgICBpZiAoaXNEZXZNb2RlKCkpIHtcclxuICAgICAgY29uc29sZS5kZWJ1ZyhcIndpbmRvdy5sb2NhdGlvbi5ocmVmOiBcIiArIHdpbmRvdy5sb2NhdGlvbi5ocmVmKTtcclxuICAgIH1cclxuXHJcbiAgICBpZiAod2luZG93LmxvY2F0aW9uKSB7XHJcbiAgICAgIGxldCBwYXJ0czogc3RyaW5nW10gPSB3aW5kb3cubG9jYXRpb24uaHJlZi5zcGxpdChcIi9cIik7XHJcbiAgICAgIHRoaXMuYmFzZVVybCA9IHBhcnRzWzBdICsgXCIvL1wiICsgcGFydHNbMl07XHJcbiAgICAgIGlmIChwYXJ0cy5sZW5ndGggPiAzKSB7XHJcbiAgICAgICAgdGhpcy5jb250ZXh0Um9vdCA9IHBhcnRzWzNdO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKHRoaXMuX2xvY2FsU3RvcmFnZVNlcnZpY2UuZ2V0SXRlbShcIm1heFZpZXdQZXJtaXNzaW9uXCIpKSB7XHJcbiAgICAgIHRoaXMubWF4Vmlld1Blcm1pc3Npb24ubmV4dCg8XCJ2aWV3XCIgfCBcInZpZXdpZGVudFwiIHwgXCJ2aWV3bGltaXRlZFwiPnRoaXMuX2xvY2FsU3RvcmFnZVNlcnZpY2UuZ2V0SXRlbShcIm1heFZpZXdQZXJtaXNzaW9uXCIpKTtcclxuICAgIH1cclxuXHJcbiAgICBpZiAoX21heEluYWN0aXZpdHkpIHtcclxuICAgICAgdGhpcy5fbWF4SW5hY3Rpdml0eU1pbnV0ZXMgPSBfbWF4SW5hY3Rpdml0eTtcclxuICAgIH1cclxuXHJcbiAgICBpZiAoX3VzZXJDb3VudGRvd25TZWNvbmRzKSB7XHJcbiAgICAgIHRoaXMudXNlckNvdW50ZG93blNlY29uZHMgPSBfdXNlckNvdW50ZG93blNlY29uZHM7XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKF9pZHBJbmFjdGl2aXR5TWludXRlcykge1xyXG4gICAgICB0aGlzLmlkcEluYWN0aXZpdHlNaW51dGVzID0gX2lkcEluYWN0aXZpdHlNaW51dGVzO1xyXG4gICAgfVxyXG5cclxuICAgIHRoaXMuaGFzVmFsaWRDb25maWcoKTtcclxuXHJcbiAgICAvL1RoZXJlIGNvdWxkIGJlIGEgbm9uLWV4cGlyZWQgdG9rZW4gaW4gbG9jYWwgc3RvcmFnZS5cclxuICAgIGxldCB0b2tlbjogc3RyaW5nID0gdGhpcy5hdXRoZW50aWNhdGlvblByb3ZpZGVyLmF1dGhUb2tlbjtcclxuICAgIHRoaXMuc3RvcmVUb2tlbih0b2tlbik7XHJcbiAgfVxyXG5cclxuICBnZXRCYXNlVXJsKCk6IHN0cmluZyB7XHJcbiAgICByZXR1cm4gKHRoaXMuYmFzZVVybCkgPyB0aGlzLmJhc2VVcmwgOiBcIlwiO1xyXG4gIH1cclxuXHJcbiAgZ2V0Q29udGV4dFJvb3QoKTogc3RyaW5nIHtcclxuICAgIHJldHVybiB0aGlzLmNvbnRleHRSb290O1xyXG4gIH1cclxuXHJcbiAgZ2V0SGVhZGVycyhyZXE6IEh0dHBSZXF1ZXN0PGFueT4pOiBIdHRwSGVhZGVycyB7XHJcbiAgICBsZXQgaGVhZGVyczogSHR0cEhlYWRlcnMgPSByZXEuaGVhZGVycztcclxuXHJcbiAgICAvL0Rvbid0IHNldCBjb250ZW50IHR5cGUgaWYgYWxyZWFkeSBzZXRcclxuICAgIGlmICghcmVxLmhlYWRlcnMuZ2V0KEF1dGhlbnRpY2F0aW9uU2VydmljZS5DT05URU5UX1RZUEUpKSB7XHJcbiAgICAgIGhlYWRlcnMgPSBoZWFkZXJzLnNldChBdXRoZW50aWNhdGlvblNlcnZpY2UuQ09OVEVOVF9UWVBFLCB0aGlzLmNvbnRlbnRUeXBlLnRvU3RyaW5nKCkpO1xyXG4gICAgfVxyXG5cclxuICAgIGlmIChoZWFkZXJzLmdldChBdXRoZW50aWNhdGlvblNlcnZpY2UuU0VDX0dPVl9DTEFTU19IRUFERVIpID09PSBcIlwiKSB7XHJcbiAgICAgIGhlYWRlcnMgPSBoZWFkZXJzLmRlbGV0ZShBdXRoZW50aWNhdGlvblNlcnZpY2UuU0VDX0dPVl9DTEFTU19IRUFERVIpO1xyXG4gICAgfSBlbHNlIGlmICh0aGlzLnNlY3VyaXR5R292ZXJub3JDbGFzcyAmJiAhaGVhZGVycy5nZXQoQXV0aGVudGljYXRpb25TZXJ2aWNlLlNFQ19HT1ZfQ0xBU1NfSEVBREVSKSkge1xyXG4gICAgICBoZWFkZXJzID0gaGVhZGVycy5zZXQoQXV0aGVudGljYXRpb25TZXJ2aWNlLlNFQ19HT1ZfQ0xBU1NfSEVBREVSLCB0aGlzLnNlY3VyaXR5R292ZXJub3JDbGFzcyk7XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKGhlYWRlcnMuZ2V0KEF1dGhlbnRpY2F0aW9uU2VydmljZS5TRUNfR09WX0lEX0hFQURFUikgPT09IFwiXCIpIHtcclxuICAgICAgaGVhZGVycyA9IGhlYWRlcnMuZGVsZXRlKEF1dGhlbnRpY2F0aW9uU2VydmljZS5TRUNfR09WX0lEX0hFQURFUik7XHJcbiAgICB9IGVsc2UgaWYgKHRoaXMuc2VjdXJpdHlHb3Zlcm5vcklkICYmICFoZWFkZXJzLmdldChBdXRoZW50aWNhdGlvblNlcnZpY2UuU0VDX0dPVl9JRF9IRUFERVIpKSB7XHJcbiAgICAgIGhlYWRlcnMgPSBoZWFkZXJzLnNldChBdXRoZW50aWNhdGlvblNlcnZpY2UuU0VDX0dPVl9JRF9IRUFERVIsIHRoaXMuc2VjdXJpdHlHb3Zlcm5vcklkLnRvU3RyaW5nKCkpO1xyXG4gICAgfVxyXG5cclxuICAgIGhlYWRlcnMgPSBoZWFkZXJzLnNldChBdXRoZW50aWNhdGlvblNlcnZpY2UuREVJREVOVF9IRUFERVIsIHRoaXMuZGVpZGVudGlmaWVkQ29udGV4dC50b1N0cmluZygpKTtcclxuICAgIGhlYWRlcnMgPSBoZWFkZXJzLnNldChBdXRoZW50aWNhdGlvblNlcnZpY2UuTElNSVRFRF9IRUFERVIsIHRoaXMubGltaXRlZENvbnRleHQudG9TdHJpbmcoKSk7XHJcblxyXG4gICAgcmV0dXJuIGhlYWRlcnM7XHJcbiAgfVxyXG5cclxuICBnZXQgYXV0aGVudGljYXRpb25Ub2tlbktleSgpOiBzdHJpbmcge1xyXG4gICAgcmV0dXJuIHRoaXMuYXV0aGVudGljYXRpb25Qcm92aWRlci5hdXRoZW50aWNhdGlvblRva2VuS2V5O1xyXG4gIH1cclxuXHJcbiAgZ2V0IGF1dGhUb2tlbigpOiBzdHJpbmcge1xyXG4gICAgcmV0dXJuIHRoaXMuYXV0aGVudGljYXRpb25Qcm92aWRlci5hdXRoVG9rZW47XHJcbiAgfVxyXG5cclxuICBwdWJsaWMgdXBkYXRlVXNlckFjdGl2aXR5KCk6IHZvaWQge1xyXG4gICAgaWYgKHRoaXMuX2lzQXV0aGVudGljYXRlZFN1YmplY3QudmFsdWUpIHtcclxuICAgICAgdGhpcy5fbGFzdFVzZXJJbnRlcmFjdGlvbiA9IG5ldyBEYXRlKCk7XHJcbiAgICAgIHRoaXMuX3VzZXJJc0Fib3V0VG9UaW1lT3V0Lm5leHQoZmFsc2UpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogQSBtdXRhdG9yIGZvciBpZGVudGlmeWluZyB0aGUgY2xpZW50cyBvcmlnaW5hbCByZXF1ZXN0IGxvY2F0aW9uLiBTZXR0aW5nIHRoaXMgdmFsdWUgd2lsbCBpbmZsdWVuY2UgdGhlIGVuZCBsb2NhdGlvblxyXG4gICAqIG5hdmlnYXRlZCB0byBieSB7QGxpbmsgI25hdmlnYXRlVG9QYXRofS5cclxuICAgKlxyXG4gICAqIEBwYXJhbSByZWRpcmVjdFVybCBsb2NhdGlvbiBvZiB0aGUgdXNlcnMgcmVxdWVzdCBiZWZvcmUgYXV0aGVudGljYXRpb25cclxuICAgKi9cclxuICBzZXQgcmVkaXJlY3RVcmwocmVkaXJlY3RVcmw6IHN0cmluZykge1xyXG4gICAgdGhpcy5fcmVkaXJlY3RVcmwgPSByZWRpcmVjdFVybDtcclxuICB9XHJcblxyXG4gIGdldCByZWRpcmVjdFVybCgpIHtcclxuICAgIHJldHVybiB0aGlzLl9yZWRpcmVjdFVybDtcclxuICB9XHJcblxyXG4gIHJlcXVlc3RBY2Nlc3NUb2tlbihyZWRpcmVjdE9uU3VjY2VzczogYm9vbGVhbik6IHZvaWQge1xyXG5cclxuICAgIHRoaXMuX2h0dHAuZ2V0KHRoaXMudG9rZW5Mb2NhdGlvbigpLCB7d2l0aENyZWRlbnRpYWxzOiB0cnVlfSlcclxuICAgICAgLnN1YnNjcmliZShcclxuICAgICAgICAocmVzcG9uc2U6IGFueSkgPT4ge1xyXG4gICAgICAgICAgdGhpcy5zdG9yZVRva2VuKHJlc3BvbnNlLmF1dGhfdG9rZW4pO1xyXG4gICAgICAgICAgaWYgKHJlZGlyZWN0T25TdWNjZXNzKSB7XHJcbiAgICAgICAgICAgIHRoaXMucHJvY2VlZElmQXV0aGVudGljYXRlZCgpO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH0sXHJcbiAgICAgICAgKGVycm9yKSA9PiB7XHJcbiAgICAgICAgICAvL1Rva2VuIHJlZnJlc2ggZmFpbGVkLlxyXG4gICAgICAgICAgdGhpcy5sb2dvdXQodHJ1ZSk7XHJcbiAgICAgICAgfVxyXG4gICAgICApO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogVmVyaWZpZXMgd2hldGhlciBvciBub3QgYSBjdXJyZW50IHVzZXIgc2Vzc2lvbiBleGlzdHMuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7T2JzZXJ2YWJsZTxib29sZWFuPn0gZXZhbHVhdGVzIHRvIHRydWUgaWYgdGhlIHVzZXIgaXMgYXV0aGVudGljYXRlZCwgZmFsc2Ugb3RoZXJ3aXNlLlxyXG4gICAqL1xyXG4gIGlzQXV0aGVudGljYXRlZCgpOiBPYnNlcnZhYmxlPGJvb2xlYW4+IHtcclxuICAgIHJldHVybiB0aGlzLl9pc0F1dGhlbnRpY2F0ZWRTdWJqZWN0LmFzT2JzZXJ2YWJsZSgpO1xyXG4gIH1cclxuXHJcbiAgaXNBYm91dFRvVGltZU91dCgpOiBPYnNlcnZhYmxlPGJvb2xlYW4+IHtcclxuICAgIHJldHVybiB0aGlzLl91c2VySXNBYm91dFRvVGltZU91dC5hc09ic2VydmFibGUoKTtcclxuICB9XHJcblxyXG4gIGdldFRpbWVvdXRTdGFydCgpOiBudW1iZXIge1xyXG4gICAgaWYgKHRoaXMuX2xhc3RVc2VySW50ZXJhY3Rpb24pIHtcclxuICAgICAgcmV0dXJuIHRoaXMuX2xhc3RVc2VySW50ZXJhY3Rpb24udmFsdWVPZigpICsgKCgodGhpcy5fbWF4SW5hY3Rpdml0eU1pbnV0ZXMgKiA2MCkgLSB0aGlzLnVzZXJDb3VudGRvd25TZWNvbmRzKSAqIDEwMDApO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgdG9rZW5Mb2NhdGlvbigpOiBzdHJpbmcge1xyXG4gICAgaWYgKHRoaXMuX3NlcnZlclVybCkge1xyXG4gICAgICByZXR1cm4gdGhpcy5fc2VydmVyVXJsICsgdGhpcy5fdG9rZW5FbmRwb2ludDtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIHJldHVybiB0aGlzLl90b2tlbkVuZHBvaW50O1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgZGlyZWN0TG9naW5Mb2NhdGlvbigpOiBzdHJpbmcge1xyXG4gICAgaWYgKHRoaXMuX3NlcnZlclVybCkge1xyXG4gICAgICByZXR1cm4gdGhpcy5fc2VydmVyVXJsICsgdGhpcy5fZGlyZWN0RW5kcG9pbnQ7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICByZXR1cm4gdGhpcy5fZGlyZWN0RW5kcG9pbnQ7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBsb2dvdXRMb2NhdGlvbigpOiBzdHJpbmcge1xyXG4gICAgaWYgKHRoaXMuX3NlcnZlclVybCkge1xyXG4gICAgICByZXR1cm4gdGhpcy5fc2VydmVyVXJsICsgdGhpcy5fbG9nb3V0UGF0aDtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIHJldHVybiB0aGlzLl9sb2dvdXRQYXRoO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogQSBmdW5jdGlvbiB0byBhdXRoZW50aWNhdGVkIHRoZSB1c2VyIHdpdGggdGhlIHByb3ZpZGVkIGNyZWRlbnRpYWxzLiBGYWlsdXJlIHJlc3VsdHMgaW4gYW4gZXJyb3IgdGhhdCBkZXNjcmliZXMgdGhlXHJcbiAgICogc2VydmVyIHJlc3BvbnNlIChzdGF0dXMgYW5kIHN0YXR1cyBtZXNzYWdlKSBhbmQgc2hvdWxkIGJlIGFjdGlvbmFibGUgYnkgdGhlIGNsaWVudCBhcHBsaWNhdGlvbi5cclxuICAgKlxyXG4gICAqIEBwYXJhbSB1c2VybmFtZSBvZiB0aGUgYXV0aGVudGljYXRpbmcgdXNlciB0byB2ZXJpZnlcclxuICAgKiBAcGFyYW0gcGFzc3dvcmQgb2YgdGhlIGF1dGhlbnRpY2F0aW5nIHVzZXIgdG8gdmVyaWZ5XHJcbiAgICogQHJldHVybnMge09ic2VydmFibGU8Uj59IGRlc2NyaWJpbmcgdGhlIHJlc3VsdCBvZiB0aGUgbG9naW4gYWN0aW9uLCB0cnVlIG9yIGFuIGVycm9yXHJcbiAgICovXHJcbiAgbG9naW4oX3VzZXJuYW1lOiBzdHJpbmcsIF9wYXNzd29yZDogc3RyaW5nKTogT2JzZXJ2YWJsZTxib29sZWFuPiB7XHJcbiAgICByZXR1cm4gdGhpcy5faHR0cC5wb3N0KFxyXG4gICAgICB0aGlzLmRpcmVjdExvZ2luTG9jYXRpb24oKSxcclxuICAgICAge3VzZXJuYW1lOiBfdXNlcm5hbWUsIHBhc3N3b3JkOiBfcGFzc3dvcmR9LFxyXG4gICAgICB7b2JzZXJ2ZTogXCJyZXNwb25zZVwifVxyXG4gICAgKS5waXBlKG1hcCgocmVzcDogSHR0cFJlc3BvbnNlPGFueT4pID0+IHtcclxuICAgICAgaWYgKHJlc3Auc3RhdHVzID09PSAyMDEpIHtcclxuICAgICAgICByZXR1cm4gdHJ1ZTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJBdXRoZW50aWNhdGlvbiBmYWlsZWQuIFwiICsgcmVzcC5zdGF0dXMgKyBcIjogXCIgKyByZXNwLnN0YXR1c1RleHQpO1xyXG4gICAgICB9XHJcbiAgICB9KSxcclxuICAgICAgY2F0Y2hFcnJvcih0aGlzLmhhbmRsZUVycm9yKSk7XHJcbiAgfVxyXG5cclxuXHJcbiAgY2xlYXJMb2dpbigpOiBPYnNlcnZhYmxlPFJlc3BvbnNlPiB7XHJcbiAgICAvL0Zyb250LWVuZCBsb2dvdXRcclxuICAgIHRyeSB7XHJcbiAgICAgIHRoaXMuX2xvY2FsU3RvcmFnZVNlcnZpY2UucmVtb3ZlSXRlbSh0aGlzLmF1dGhlbnRpY2F0aW9uUHJvdmlkZXIuYXV0aGVudGljYXRpb25Ub2tlbktleSk7XHJcbiAgICAgIHRoaXMudW5zdWJzY3JpYmVGcm9tVG9rZW5SZWZyZXNoKCk7XHJcbiAgICAgIHRoaXMuX2lzQXV0aGVudGljYXRlZFN1YmplY3QubmV4dChmYWxzZSk7XHJcbiAgICAgIHRoaXMuX3VzZXJJc0Fib3V0VG9UaW1lT3V0Lm5leHQoZmFsc2UpO1xyXG4gICAgfSBjYXRjaCAoRXJyb3IpIHtcclxuICAgIH1cclxuXHJcbiAgICAvL0JhY2stZW5kIGxvZ291dFxyXG4gICAgbGV0IGhlYWRlcnMgPSBuZXcgSHR0cEhlYWRlcnMoKS5zZXQoQXV0aGVudGljYXRpb25TZXJ2aWNlLkNPTlRFTlRfVFlQRSwgXCJ0ZXh0L3BsYWluXCIpO1xyXG4gICAgcmV0dXJuIDxPYnNlcnZhYmxlPFJlc3BvbnNlPj50aGlzLl9odHRwLmdldCh0aGlzLmxvZ291dExvY2F0aW9uKCksIHtoZWFkZXJzOiBoZWFkZXJzfSk7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBBIGZ1bmN0aW9uIHRvIHNpZ25hbCB0aGUgdGVybWluYXRpb24gb2YgdGhlIGN1cnJlbnQgc2Vzc2lvbi4gSW52b2tpbmcgdGhpcyBmdW5jdGlvbiB3aWxsIGNsZWFuIHVwIGFueSByZWxldmFudCBzdGF0ZVxyXG4gICAqIHJlbGF0ZWQgdG8gdGhlIGxhc3QgYWN0aXZlIHNlc3Npb24uXHJcbiAgICovXHJcbiAgbG9nb3V0KGtlZXBDdXJyZW50Um91dGU6IGJvb2xlYW4gPSBmYWxzZSk6IHZvaWQge1xyXG4gICAgLy9QcmV2ZW50IGxvZ291dCBpZiBhbHJlYWR5IG9uIGF1dGhlbnRpY2F0aW9uIHJvdXRlLiBEb2luZyBvdGhlcndpc2Ugc2NyZXdzIHVwIFNBTUxcclxuICAgIGlmICghIHRoaXMuX3JvdXRlci5yb3V0ZXJTdGF0ZSB8fCB0aGlzLl9yb3V0ZXIucm91dGVyU3RhdGUuc25hcHNob3QudXJsICE9PSB0aGlzLl9hdXRoZW50aWNhdGlvblJvdXRlKSB7XHJcbiAgICAgIHRoaXMuX3JlZGlyZWN0VXJsID0gKGtlZXBDdXJyZW50Um91dGUgJiYgdGhpcy5fcm91dGVyLnJvdXRlclN0YXRlICYmIHRoaXMuX3JvdXRlci5yb3V0ZXJTdGF0ZS5zbmFwc2hvdCkgPyB0aGlzLl9yb3V0ZXIucm91dGVyU3RhdGUuc25hcHNob3QudXJsIDogXCJcIjtcclxuXHJcbiAgICAgIGlmICh0aGlzLl9yZWRpcmVjdFVybC5zdGFydHNXaXRoKFwiL1wiKSkge1xyXG4gICAgICAgIHRoaXMuX3JlZGlyZWN0VXJsID0gdGhpcy5fcmVkaXJlY3RVcmwuc3Vic3RyaW5nKDEpO1xyXG4gICAgICB9XHJcblxyXG4gICAgICB0aGlzLmNsZWFyTG9naW4oKS5zdWJzY3JpYmUoXHJcbiAgICAgICAgKHJlc3BvbnNlKSA9PiB7XHJcbiAgICAgICAgICB3aW5kb3cubG9jYXRpb24ucmVwbGFjZSh0aGlzLl9yZWRpcmVjdFVybCk7XHJcbiAgICAgICAgICB9LFxyXG4gICAgICAgIChlcnJvcikgPT4ge1xyXG4gICAgICAgICAgd2luZG93LmxvY2F0aW9uLnJlcGxhY2UodGhpcy5fcmVkaXJlY3RVcmwpO1xyXG4gICAgICAgIH1cclxuICAgICAgKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIHN0b3JlVG9rZW4odG9rZW46IHN0cmluZyk6IHZvaWQge1xyXG4gICAgbGV0IHZhbGlkID0gdGhpcy52YWxpZGF0ZVRva2VuKHRva2VuKTtcclxuXHJcbiAgICAvLyB1bnN1YnNjcmliZSBmcm9tIHJlZmVzaCBiZWZvcmUgd2UgZGVjaWRlIHdldGhlciB0byByZXN1YnNjcmliZVxyXG4gICAgdGhpcy51bnN1YnNjcmliZUZyb21Ub2tlblJlZnJlc2goKTtcclxuXHJcbiAgICBpZiAodmFsaWQpIHtcclxuICAgICAgdGhpcy5fbG9jYWxTdG9yYWdlU2VydmljZS5zZXRJdGVtKHRoaXMuYXV0aGVudGljYXRpb25Qcm92aWRlci5hdXRoZW50aWNhdGlvblRva2VuS2V5LCB0b2tlbik7XHJcbiAgICAgIHRoaXMuc3Vic2NyaWJlVG9Ub2tlblJlZnJlc2godG9rZW4pO1xyXG5cclxuICAgICAgLy9DaGFuZ2UgdGhlIEJlaGF2aW9yU3ViamVjdCBpZiB0aGUgdXNlciB3YXMgbm90IHByZXZpb3VzbHkgYXV0aGVudGljYXRlZC5cclxuICAgICAgLy9TaW5jZSBvdGhlciBjb2RlIG1heSBiZSBzdWJzY3JpYmluZyB0byB0aGlzIG9ic2VydmFibGUsIHdlIGRvbid0IHdhbnQgdG8gY2F1c2UgbmV3IGV2ZW50cyB0byBmaXJlIGlmIGp1c3QgcmVmcmVzaGluZyB0aGUgSldULlxyXG4gICAgICBpZiAoISB0aGlzLl9pc0F1dGhlbnRpY2F0ZWRTdWJqZWN0LnZhbHVlKSB7XHJcbiAgICAgICAgdGhpcy5faXNBdXRoZW50aWNhdGVkU3ViamVjdC5uZXh0KHRydWUpO1xyXG4gICAgICB9XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICB0aGlzLl9sb2NhbFN0b3JhZ2VTZXJ2aWNlLnJlbW92ZUl0ZW0odGhpcy5hdXRoZW50aWNhdGlvblByb3ZpZGVyLmF1dGhlbnRpY2F0aW9uVG9rZW5LZXkpO1xyXG4gICAgICB0aGlzLl9pc0F1dGhlbnRpY2F0ZWRTdWJqZWN0Lm5leHQoZmFsc2UpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgcHJvY2VlZElmQXV0aGVudGljYXRlZCgpOiBib29sZWFuIHtcclxuICAgIGlmIChpc0Rldk1vZGUoKSkge1xyXG4gICAgICBjb25zb2xlLmRlYnVnKFwiQXV0aGVudGljYXRpb25TZXJ2aWNlLnByb2NlZWRJZkF1dGhlbnRpY2F0ZWQ6IFwiICsgdGhpcy5fcmVkaXJlY3RVcmwpO1xyXG4gICAgfVxyXG5cclxuICAgIGlmICh0aGlzLl9pc0F1dGhlbnRpY2F0ZWRTdWJqZWN0LnZhbHVlKSB7XHJcbiAgICAgIC8vTG9naW4gY291bnRzIGFzIHVzZXIgYWN0aXZpdHksIHRvb1xyXG4gICAgICB0aGlzLnVwZGF0ZVVzZXJBY3Rpdml0eSgpO1xyXG5cclxuICAgICAgaWYgKHRoaXMuX3JlZGlyZWN0VXJsICYmIHRoaXMuX3JlZGlyZWN0VXJsICYmIHRoaXMuX3JlZGlyZWN0VXJsICE9PSBcIlwiKSB7XHJcbiAgICAgICAgdGhpcy5fcm91dGVyLm5hdmlnYXRlQnlVcmwodGhpcy5fcmVkaXJlY3RVcmwpO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIHRoaXMuX3JvdXRlci5uYXZpZ2F0ZShbXCJcIl0pO1xyXG4gICAgICB9XHJcblxyXG4gICAgICByZXR1cm4gdHJ1ZTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIHJldHVybiBmYWxzZTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIHZhbGlkYXRlVG9rZW4odG9rZW46IHN0cmluZyk6IGJvb2xlYW4ge1xyXG4gICAgcmV0dXJuICh0b2tlbiAmJiAhdGhpcy5fand0SGVscGVyLmlzVG9rZW5FeHBpcmVkKHRva2VuKSk7XHJcbiAgfVxyXG5cclxuICBzdWJzY3JpYmVUb1Rva2VuUmVmcmVzaCh0b2tlbjogYW55KTogdm9pZCB7XHJcbiAgICBsZXQgZXhwID0gdGhpcy5fand0SGVscGVyLmdldFRva2VuRXhwaXJhdGlvbkRhdGUodG9rZW4pO1xyXG5cclxuICAgIC8vIFVzZSBhIHRpbWVyIHRvIHBlcmlvZGljYWxseSBjaGVjayB0aW1lb3V0c1xyXG4gICAgdGhpcy5fcmVmcmVzaFN1YnNjcmlwdGlvbiA9IGludGVydmFsKDEwMDApXHJcbiAgICAgIC5zdWJzY3JpYmUoKCkgPT4ge1xyXG5cclxuICAgICAgICAvLyBJZiBhIHRhYiBpcyBpbmFjdGl2ZSB3ZSBjYW4ndCBrbm93IGlmIG91ciB0aW1lciBpcyBhY2N1cmF0ZVxyXG4gICAgICAgIC8vIHNvIHdoZW4gdGhlIGludGVydmFsIGhpdHMgY2hlY2sgYWdhaW5zdCB0aW1lc3RhbXBzXHJcbiAgICAgICAgaWYgKHRoaXMuX2lzQXV0aGVudGljYXRlZFN1YmplY3QudmFsdWUgJiYgRGF0ZS5ub3coKSA+IHRoaXMuZ2V0VGltZW91dFN0YXJ0KCkpIHtcclxuICAgICAgICAgIC8vRG9uJ3QgdXBkYXRlIHRoZSBzdWJqZWN0IG1vcmUgdGhhbiBvbmNlISBEb2luZyBzbyBpbml0aWFsaXplcyBtb3JlIHRoYW4gb25lIGNvdW50ZG93biB0aW1lciFcclxuICAgICAgICAgIGlmICh0aGlzLl91c2VySXNBYm91dFRvVGltZU91dC5nZXRWYWx1ZSgpICE9PSB0cnVlKSB7XHJcbiAgICAgICAgICAgIHRoaXMuX3VzZXJJc0Fib3V0VG9UaW1lT3V0Lm5leHQodHJ1ZSk7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvLyBjaGVjayBmb3IgcmVmcmVzaCB0b2tlblxyXG4gICAgICAgIGxldCBtc1RvRXhwaXJ5ID0gKGV4cC52YWx1ZU9mKCkgLSBuZXcgRGF0ZSgpLnZhbHVlT2YoKSk7XHJcblxyXG4gICAgICAgIC8vIFJlZnJlc2ggNjAgc2Vjb25kcyBiZWZvcmUgZXhwaXJ5XHJcbiAgICAgICAgaWYgKG1zVG9FeHBpcnkgPD0gNjAwMDApIHtcclxuICAgICAgICAgIHRoaXMucmVmcmVzaFRva2VuSWZVc2VySXNBY3RpdmUoKTtcclxuICAgICAgICB9XHJcbiAgICAgIH0pO1xyXG4gIH1cclxuXHJcbiAgdW5zdWJzY3JpYmVGcm9tVG9rZW5SZWZyZXNoKCk6IHZvaWQge1xyXG4gICAgaWYgKHRoaXMuX3JlZnJlc2hTdWJzY3JpcHRpb24gJiYgISB0aGlzLl9yZWZyZXNoU3Vic2NyaXB0aW9uLmNsb3NlZCkge1xyXG4gICAgICB0aGlzLl9yZWZyZXNoU3Vic2NyaXB0aW9uLnVuc3Vic2NyaWJlKCk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBnZXRNYXhWaWV3UGVybWlzc2lvbigpOiBcInZpZXdcIiB8IFwidmlld2lkZW50XCIgfCBcInZpZXdsaW1pdGVkXCIge1xyXG4gICAgcmV0dXJuIHRoaXMubWF4Vmlld1Blcm1pc3Npb24uZ2V0VmFsdWUoKTtcclxuICB9XHJcblxyXG4gIGdldE1heFZpZXdQZXJtaXNzaW9uU3ViamVjdCgpOiBCZWhhdmlvclN1YmplY3Q8XCJ2aWV3XCIgfCBcInZpZXdpZGVudFwiIHwgXCJ2aWV3bGltaXRlZFwiPiB7XHJcbiAgICByZXR1cm4gdGhpcy5tYXhWaWV3UGVybWlzc2lvbjtcclxuICB9XHJcblxyXG4gIHNldE1heFZpZXdQZXJtaXNzaW9uKG1heFZpZXdQZXJtaXNzaW9uOiBcInZpZXdcIiB8IFwidmlld2lkZW50XCIgfCBcInZpZXdsaW1pdGVkXCIpOiB2b2lkIHtcclxuICAgIHRoaXMuX2xvY2FsU3RvcmFnZVNlcnZpY2Uuc2V0SXRlbShcIm1heFZpZXdQZXJtaXNzaW9uXCIsIG1heFZpZXdQZXJtaXNzaW9uKTtcclxuICAgIHRoaXMubWF4Vmlld1Blcm1pc3Npb24ubmV4dChtYXhWaWV3UGVybWlzc2lvbik7XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIHJlZnJlc2hUb2tlbklmVXNlcklzQWN0aXZlKCk6IHZvaWQge1xyXG4gICAgLy9Pbmx5IHJlZnJlc2ggaWYgdGhlIHVzZXIgaGFzIGJlZW4gYWN0aXZlXHJcbiAgICBpZiAodGhpcy5fbGFzdFVzZXJJbnRlcmFjdGlvbiAmJiAoKG5ldyBEYXRlKCkudmFsdWVPZigpIC0gdGhpcy5fbGFzdFVzZXJJbnRlcmFjdGlvbi52YWx1ZU9mKCkpIDw9ICh0aGlzLl9tYXhJbmFjdGl2aXR5TWludXRlcyAqIDYwICogMTAwMCkpKSB7XHJcbiAgICAgIHRoaXMucmVxdWVzdEFjY2Vzc1Rva2VuKGZhbHNlKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIHByaXZhdGUgaGFzVmFsaWRDb25maWcoKTogdm9pZCB7XHJcbiAgICBpZiAodGhpcy5fdG9rZW5FbmRwb2ludCA9PSBudWxsICYmICh0aGlzLl9zZXJ2ZXJVcmwgPT09IG51bGwgfHwgdGhpcy5fbG9nb3V0UGF0aCA9PT0gbnVsbCkpIHtcclxuICAgICAgdGhyb3cgbmV3IEVycm9yKFwiQlVHIEFMRVJUISBJbnZhbGlkIEF1dGhlbnRpY2F0aW9uU2VydmljZSBjb25maWd1cmF0aW9uLiBObyB2YWxpZCBjb25maWd1cmF0aW9uIGZvciBhdXRoZW50aWNhdGlvbiBlbmRwb2ludChzKS5cIik7XHJcbiAgICB9XHJcbiAgICBpZiAodGhpcy5fbG9jYWxTdG9yYWdlU2VydmljZSA9PT0gbnVsbCB8fCB0aGlzLmF1dGhlbnRpY2F0aW9uUHJvdmlkZXIuYXV0aGVudGljYXRpb25Ub2tlbktleSA9PT0gbnVsbCkge1xyXG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXCJCVUcgQUxFUlQhIEludmFsaWQgQXV0aGVudGljYXRpb25TZXJ2aWNlIGNvbmZpZ3VyYXRpb24uIE5vIHZhbGlkIGNvbmZpZ3VyYXRpb24gZm9yIGxvY2FsIHN0b3JhZ2VcIik7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIGhhbmRsZUVycm9yKGVycm9yOiBhbnkpIDogT2JzZXJ2YWJsZTxuZXZlcj4ge1xyXG4gICAgbGV0IGVyck1zZyA9IChlcnJvci5tZXNzYWdlKSA/IGVycm9yLm1lc3NhZ2UgOiBBdXRoZW50aWNhdGlvblNlcnZpY2UuR0VORVJJQ19FUlJfTVNHO1xyXG4gICAgcmV0dXJuIHRocm93RXJyb3IoZXJyTXNnKTtcclxuICB9XHJcbn1cclxuIl19
@@ -1,81 +0,0 @@
1
- import { Injectable, Injector, isDevMode } from "@angular/core";
2
- import { throwError } from "rxjs";
3
- import { catchError } from "rxjs/operators";
4
- import { AuthenticationService } from "./authentication.service";
5
- import * as i0 from "@angular/core";
6
- var AuthorizationInterceptor = /** @class */ (function () {
7
- function AuthorizationInterceptor(injector) {
8
- this.injector = injector;
9
- }
10
- AuthorizationInterceptor.prototype.intercept = function (req, next) {
11
- if (isDevMode()) {
12
- console.debug("AuthorizationInterceptor.intercept");
13
- }
14
- var authService = this.injector.get(AuthenticationService);
15
- //Don't want to include background token refreshes in considering the user 'active'
16
- if (req.url !== authService.tokenLocation()) {
17
- //Update user activity. Done here instead of the previous method using a subscription to a subject in AuthenticationProvider
18
- authService.updateUserActivity();
19
- }
20
- var headers = authService.getHeaders(req);
21
- var url = req.url;
22
- if (url.startsWith("/")) {
23
- url = authService.getBaseUrl() + url;
24
- }
25
- else if (!url.startsWith("http")) {
26
- if (authService.getContextRoot().length > 0) {
27
- url = authService.getBaseUrl() + "/" + authService.getContextRoot() + "/" + url;
28
- }
29
- else {
30
- url = authService.getBaseUrl() + "/" + url;
31
- }
32
- }
33
- var params = req.params;
34
- if (url.indexOf("/crud/") > 0) {
35
- params = params.set("maxViewPermission", authService.getMaxViewPermission());
36
- }
37
- var reqClone = req.clone({
38
- url: url,
39
- withCredentials: true,
40
- headers: headers,
41
- params: params
42
- });
43
- return next.handle(reqClone)
44
- .pipe(catchError(function (error) {
45
- if (isDevMode()) {
46
- console.error("AuthorizationInterceptor.error");
47
- console.error(error);
48
- }
49
- /**
50
- * If the token is not authenticated which angular does not know about, then a REST request to the backend will
51
- * return a 401. To duplicate this, open Core in two tabs. In one tab, logout, in the other, perform a request
52
- * that hits a protected resource.
53
- */
54
- if (error.status === 401) {
55
- authService.isAuthenticated().subscribe(function (authenticated) {
56
- if (authenticated) {
57
- // If authenticated, then logout which will redirect.
58
- authService.logout(true);
59
- return throwError(error.message);
60
- }
61
- else {
62
- // Otherwise, for example, when the user first opens Core, 401s are expected.
63
- return throwError(error);
64
- }
65
- });
66
- }
67
- if (error.status === 403) {
68
- // TODO: Trigger notification for unauthorized.
69
- }
70
- return throwError(error);
71
- }));
72
- };
73
- AuthorizationInterceptor.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.17", ngImport: i0, type: AuthorizationInterceptor, deps: [{ token: i0.Injector }], target: i0.ɵɵFactoryTarget.Injectable });
74
- AuthorizationInterceptor.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "12.2.17", ngImport: i0, type: AuthorizationInterceptor });
75
- return AuthorizationInterceptor;
76
- }());
77
- export { AuthorizationInterceptor };
78
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.17", ngImport: i0, type: AuthorizationInterceptor, decorators: [{
79
- type: Injectable
80
- }], ctorParameters: function () { return [{ type: i0.Injector }]; } });
81
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXV0aG9yaXphdGlvbi5pbnRlcmNlcHRvci5qcyIsInNvdXJjZVJvb3QiOiJuZzovL0BodW50c21hbi1jYW5jZXItaW5zdGl0dXRlL2F1dGhlbnRpY2F0aW9uLyIsInNvdXJjZXMiOlsiYXV0aG9yaXphdGlvbi5pbnRlcmNlcHRvci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUMsVUFBVSxFQUFFLFFBQVEsRUFBRSxTQUFTLEVBQUMsTUFBTSxlQUFlLENBQUM7QUFHOUQsT0FBTyxFQUFhLFVBQVUsRUFBQyxNQUFNLE1BQU0sQ0FBQztBQUM1QyxPQUFPLEVBQUMsVUFBVSxFQUFDLE1BQU0sZ0JBQWdCLENBQUM7QUFFMUMsT0FBTyxFQUFDLHFCQUFxQixFQUFDLE1BQU0sMEJBQTBCLENBQUM7O0FBRS9EO0lBR0Usa0NBQW9CLFFBQWtCO1FBQWxCLGFBQVEsR0FBUixRQUFRLENBQVU7SUFBRyxDQUFDO0lBRTFDLDRDQUFTLEdBQVQsVUFBVSxHQUFxQixFQUFFLElBQWlCO1FBQ2hELElBQUksU0FBUyxFQUFFLEVBQUU7WUFDZixPQUFPLENBQUMsS0FBSyxDQUFDLG9DQUFvQyxDQUFDLENBQUM7U0FDckQ7UUFFRCxJQUFJLFdBQVcsR0FBMEIsSUFBSSxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMscUJBQXFCLENBQUMsQ0FBQztRQUVsRixtRkFBbUY7UUFDbkYsSUFBSSxHQUFHLENBQUMsR0FBRyxLQUFLLFdBQVcsQ0FBQyxhQUFhLEVBQUUsRUFBRTtZQUMzQyw0SEFBNEg7WUFDNUgsV0FBVyxDQUFDLGtCQUFrQixFQUFFLENBQUM7U0FDbEM7UUFFRCxJQUFJLE9BQU8sR0FBZ0IsV0FBVyxDQUFDLFVBQVUsQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUN2RCxJQUFJLEdBQUcsR0FBVyxHQUFHLENBQUMsR0FBRyxDQUFDO1FBQzFCLElBQUksR0FBRyxDQUFDLFVBQVUsQ0FBQyxHQUFHLENBQUMsRUFBRTtZQUN2QixHQUFHLEdBQUcsV0FBVyxDQUFDLFVBQVUsRUFBRSxHQUFHLEdBQUcsQ0FBQztTQUN0QzthQUFNLElBQUksQ0FBQyxHQUFHLENBQUMsVUFBVSxDQUFDLE1BQU0sQ0FBQyxFQUFFO1lBQ2xDLElBQUksV0FBVyxDQUFDLGNBQWMsRUFBRSxDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUU7Z0JBQzNDLEdBQUcsR0FBRyxXQUFXLENBQUMsVUFBVSxFQUFFLEdBQUcsR0FBRyxHQUFHLFdBQVcsQ0FBQyxjQUFjLEVBQUUsR0FBRyxHQUFHLEdBQUcsR0FBRyxDQUFDO2FBQ2pGO2lCQUFNO2dCQUNMLEdBQUcsR0FBRyxXQUFXLENBQUMsVUFBVSxFQUFFLEdBQUcsR0FBRyxHQUFHLEdBQUcsQ0FBQzthQUM1QztTQUNGO1FBRUQsSUFBSSxNQUFNLEdBQWUsR0FBRyxDQUFDLE1BQU0sQ0FBQztRQUNwQyxJQUFJLEdBQUcsQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxFQUFFO1lBQzdCLE1BQU0sR0FBRyxNQUFNLENBQUMsR0FBRyxDQUFDLG1CQUFtQixFQUFFLFdBQVcsQ0FBQyxvQkFBb0IsRUFBRSxDQUFDLENBQUM7U0FDOUU7UUFFRCxJQUFJLFFBQVEsR0FBRyxHQUFHLENBQUMsS0FBSyxDQUFDO1lBQ3ZCLEdBQUcsRUFBRSxHQUFHO1lBQ1IsZUFBZSxFQUFFLElBQUk7WUFDckIsT0FBTyxFQUFFLE9BQU87WUFDaEIsTUFBTSxFQUFFLE1BQU07U0FDZixDQUFDLENBQUM7UUFFSCxPQUFPLElBQUksQ0FBQyxNQUFNLENBQUMsUUFBUSxDQUFDO2FBQ3pCLElBQUksQ0FBQyxVQUFVLENBQUMsVUFBQyxLQUFLO1lBQ3JCLElBQUksU0FBUyxFQUFFLEVBQUU7Z0JBQ2YsT0FBTyxDQUFDLEtBQUssQ0FBQyxnQ0FBZ0MsQ0FBQyxDQUFDO2dCQUNoRCxPQUFPLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FBQyxDQUFDO2FBQ3RCO1lBRUQ7Ozs7ZUFJRztZQUNILElBQUksS0FBSyxDQUFDLE1BQU0sS0FBSyxHQUFHLEVBQUU7Z0JBQ3hCLFdBQVcsQ0FBQyxlQUFlLEVBQUUsQ0FBQyxTQUFTLENBQUMsVUFBQyxhQUFhO29CQUNwRCxJQUFJLGFBQWEsRUFBRTt3QkFDakIscURBQXFEO3dCQUNyRCxXQUFXLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxDQUFDO3dCQUN6QixPQUFPLFVBQVUsQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUM7cUJBQ2xDO3lCQUFNO3dCQUNMLDZFQUE2RTt3QkFDN0UsT0FBTyxVQUFVLENBQUMsS0FBSyxDQUFDLENBQUM7cUJBQzFCO2dCQUNILENBQUMsQ0FBQyxDQUFDO2FBQ0o7WUFDRCxJQUFJLEtBQUssQ0FBQyxNQUFNLEtBQUssR0FBRyxFQUFFO2dCQUN4QiwrQ0FBK0M7YUFDaEQ7WUFDRCxPQUFPLFVBQVUsQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUMzQixDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ1IsQ0FBQzswSEF0RVUsd0JBQXdCOzhIQUF4Qix3QkFBd0I7bUNBVHJDO0NBZ0ZDLEFBeEVELElBd0VDO1NBdkVZLHdCQUF3Qjs0RkFBeEIsd0JBQXdCO2tCQURwQyxVQUFVIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtJbmplY3RhYmxlLCBJbmplY3RvciwgaXNEZXZNb2RlfSBmcm9tIFwiQGFuZ3VsYXIvY29yZVwiO1xyXG5pbXBvcnQge0h0dHBSZXF1ZXN0LCBIdHRwSGFuZGxlciwgSHR0cEV2ZW50LCBIdHRwSW50ZXJjZXB0b3IsIEh0dHBIZWFkZXJzLCBIdHRwUGFyYW1zfSBmcm9tIFwiQGFuZ3VsYXIvY29tbW9uL2h0dHBcIjtcclxuXHJcbmltcG9ydCB7T2JzZXJ2YWJsZSwgdGhyb3dFcnJvcn0gZnJvbSBcInJ4anNcIjtcclxuaW1wb3J0IHtjYXRjaEVycm9yfSBmcm9tIFwicnhqcy9vcGVyYXRvcnNcIjtcclxuXHJcbmltcG9ydCB7QXV0aGVudGljYXRpb25TZXJ2aWNlfSBmcm9tIFwiLi9hdXRoZW50aWNhdGlvbi5zZXJ2aWNlXCI7XHJcblxyXG5ASW5qZWN0YWJsZSgpXHJcbmV4cG9ydCBjbGFzcyBBdXRob3JpemF0aW9uSW50ZXJjZXB0b3IgaW1wbGVtZW50cyBIdHRwSW50ZXJjZXB0b3Ige1xyXG5cclxuICBjb25zdHJ1Y3Rvcihwcml2YXRlIGluamVjdG9yOiBJbmplY3Rvcikge31cclxuXHJcbiAgaW50ZXJjZXB0KHJlcTogSHR0cFJlcXVlc3Q8YW55PiwgbmV4dDogSHR0cEhhbmRsZXIpOiBPYnNlcnZhYmxlPEh0dHBFdmVudDxhbnk+PiB7XHJcbiAgICBpZiAoaXNEZXZNb2RlKCkpIHtcclxuICAgICAgY29uc29sZS5kZWJ1ZyhcIkF1dGhvcml6YXRpb25JbnRlcmNlcHRvci5pbnRlcmNlcHRcIik7XHJcbiAgICB9XHJcbiAgICBcclxuICAgIGxldCBhdXRoU2VydmljZTogQXV0aGVudGljYXRpb25TZXJ2aWNlID0gdGhpcy5pbmplY3Rvci5nZXQoQXV0aGVudGljYXRpb25TZXJ2aWNlKTtcclxuICAgIFxyXG4gICAgLy9Eb24ndCB3YW50IHRvIGluY2x1ZGUgYmFja2dyb3VuZCB0b2tlbiByZWZyZXNoZXMgaW4gY29uc2lkZXJpbmcgdGhlIHVzZXIgJ2FjdGl2ZSdcclxuICAgIGlmIChyZXEudXJsICE9PSBhdXRoU2VydmljZS50b2tlbkxvY2F0aW9uKCkpIHtcclxuICAgICAgLy9VcGRhdGUgdXNlciBhY3Rpdml0eS4gRG9uZSBoZXJlIGluc3RlYWQgb2YgdGhlIHByZXZpb3VzIG1ldGhvZCB1c2luZyBhIHN1YnNjcmlwdGlvbiB0byBhIHN1YmplY3QgaW4gQXV0aGVudGljYXRpb25Qcm92aWRlclxyXG4gICAgICBhdXRoU2VydmljZS51cGRhdGVVc2VyQWN0aXZpdHkoKTtcclxuICAgIH1cclxuICAgIFxyXG4gICAgbGV0IGhlYWRlcnM6IEh0dHBIZWFkZXJzID0gYXV0aFNlcnZpY2UuZ2V0SGVhZGVycyhyZXEpO1xyXG4gICAgbGV0IHVybDogc3RyaW5nID0gcmVxLnVybDtcclxuICAgIGlmICh1cmwuc3RhcnRzV2l0aChcIi9cIikpIHtcclxuICAgICAgdXJsID0gYXV0aFNlcnZpY2UuZ2V0QmFzZVVybCgpICsgdXJsO1xyXG4gICAgfSBlbHNlIGlmICghdXJsLnN0YXJ0c1dpdGgoXCJodHRwXCIpKSB7XHJcbiAgICAgIGlmIChhdXRoU2VydmljZS5nZXRDb250ZXh0Um9vdCgpLmxlbmd0aCA+IDApIHtcclxuICAgICAgICB1cmwgPSBhdXRoU2VydmljZS5nZXRCYXNlVXJsKCkgKyBcIi9cIiArIGF1dGhTZXJ2aWNlLmdldENvbnRleHRSb290KCkgKyBcIi9cIiArIHVybDtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICB1cmwgPSBhdXRoU2VydmljZS5nZXRCYXNlVXJsKCkgKyBcIi9cIiArIHVybDtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIGxldCBwYXJhbXM6IEh0dHBQYXJhbXMgPSByZXEucGFyYW1zO1xyXG4gICAgaWYgKHVybC5pbmRleE9mKFwiL2NydWQvXCIpID4gMCkge1xyXG4gICAgICBwYXJhbXMgPSBwYXJhbXMuc2V0KFwibWF4Vmlld1Blcm1pc3Npb25cIiwgYXV0aFNlcnZpY2UuZ2V0TWF4Vmlld1Blcm1pc3Npb24oKSk7XHJcbiAgICB9XHJcblxyXG4gICAgbGV0IHJlcUNsb25lID0gcmVxLmNsb25lKHtcclxuICAgICAgdXJsOiB1cmwsXHJcbiAgICAgIHdpdGhDcmVkZW50aWFsczogdHJ1ZSxcclxuICAgICAgaGVhZGVyczogaGVhZGVycyxcclxuICAgICAgcGFyYW1zOiBwYXJhbXNcclxuICAgIH0pO1xyXG5cclxuICAgIHJldHVybiBuZXh0LmhhbmRsZShyZXFDbG9uZSlcclxuICAgICAgLnBpcGUoY2F0Y2hFcnJvcigoZXJyb3IpID0+IHtcclxuICAgICAgICBpZiAoaXNEZXZNb2RlKCkpIHtcclxuICAgICAgICAgIGNvbnNvbGUuZXJyb3IoXCJBdXRob3JpemF0aW9uSW50ZXJjZXB0b3IuZXJyb3JcIik7XHJcbiAgICAgICAgICBjb25zb2xlLmVycm9yKGVycm9yKTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8qKlxyXG4gICAgICAgICAqIElmIHRoZSB0b2tlbiBpcyBub3QgYXV0aGVudGljYXRlZCB3aGljaCBhbmd1bGFyIGRvZXMgbm90IGtub3cgYWJvdXQsIHRoZW4gYSBSRVNUIHJlcXVlc3QgdG8gdGhlIGJhY2tlbmQgd2lsbFxyXG4gICAgICAgICAqIHJldHVybiBhIDQwMS4gIFRvIGR1cGxpY2F0ZSB0aGlzLCBvcGVuIENvcmUgaW4gdHdvIHRhYnMuICBJbiBvbmUgdGFiLCBsb2dvdXQsIGluIHRoZSBvdGhlciwgcGVyZm9ybSBhIHJlcXVlc3RcclxuICAgICAgICAgKiB0aGF0IGhpdHMgYSBwcm90ZWN0ZWQgcmVzb3VyY2UuXHJcbiAgICAgICAgICovXHJcbiAgICAgICAgaWYgKGVycm9yLnN0YXR1cyA9PT0gNDAxKSB7XHJcbiAgICAgICAgICBhdXRoU2VydmljZS5pc0F1dGhlbnRpY2F0ZWQoKS5zdWJzY3JpYmUoKGF1dGhlbnRpY2F0ZWQpID0+IHtcclxuICAgICAgICAgICAgaWYgKGF1dGhlbnRpY2F0ZWQpIHtcclxuICAgICAgICAgICAgICAvLyBJZiBhdXRoZW50aWNhdGVkLCB0aGVuIGxvZ291dCB3aGljaCB3aWxsIHJlZGlyZWN0LlxyXG4gICAgICAgICAgICAgIGF1dGhTZXJ2aWNlLmxvZ291dCh0cnVlKTtcclxuICAgICAgICAgICAgICByZXR1cm4gdGhyb3dFcnJvcihlcnJvci5tZXNzYWdlKTtcclxuICAgICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgICAvLyBPdGhlcndpc2UsIGZvciBleGFtcGxlLCB3aGVuIHRoZSB1c2VyIGZpcnN0IG9wZW5zIENvcmUsIDQwMXMgYXJlIGV4cGVjdGVkLlxyXG4gICAgICAgICAgICAgIHJldHVybiB0aHJvd0Vycm9yKGVycm9yKTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfSk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGlmIChlcnJvci5zdGF0dXMgPT09IDQwMykge1xyXG4gICAgICAgICAgLy8gVE9ETzogVHJpZ2dlciBub3RpZmljYXRpb24gZm9yIHVuYXV0aG9yaXplZC5cclxuICAgICAgICB9XHJcbiAgICAgICAgcmV0dXJuIHRocm93RXJyb3IoZXJyb3IpO1xyXG4gICAgICB9KSk7XHJcbiAgfVxyXG59XHJcbiJdfQ==