@huntsman-cancer-institute/authentication 16.0.1 → 17.0.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.
@@ -1,393 +1,393 @@
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 let AUTHENTICATION_SERVER_URL = new InjectionToken("authentication_server_rest_api");
26
- export let AUTHENTICATION_LOGOUT_PATH = new InjectionToken("authentication_logout_path");
27
- export let AUTHENTICATION_DIRECT_ENDPOINT = new InjectionToken("authentication_direct_endpoint");
28
- export let AUTHENTICATION_TOKEN_ENDPOINT = new InjectionToken("authentication_token_endpoint");
29
- export let AUTHENTICATION_ROUTE = new InjectionToken("authentication_route");
30
- export let AUTHENTICATION_MAX_INACTIVITY_MINUTES = new InjectionToken("authentication_max_inactivity");
31
- export let AUTHENTICATION_USER_COUNTDOWN_SECONDS = new InjectionToken("authentication_user_countdown_seconds");
32
- export let AUTHENTICATION_IDP_INACTIVITY_MINUTES = new InjectionToken("authentication_idp_inactivity_minutes");
33
- /**
34
- * @since 1.0.0
35
- */
36
- export class AuthenticationService {
37
- /**
38
- * The generic error message used when a server error is thrown without a status.
39
- *
40
- * @type {string}
41
- */
42
- static { this.GENERIC_ERR_MSG = "Server error"; }
43
- static { this.CONTENT_TYPE = "Content-Type"; }
44
- static { this.SEC_GOV_CLASS_HEADER = "SecurityGovernorClass"; }
45
- static { this.SEC_GOV_ID_HEADER = "SecurityGovernorId"; }
46
- static { this.DEIDENT_HEADER = "DeidentifiedContext"; }
47
- static { this.LIMITED_HEADER = "LimitedContext"; }
48
- constructor(_http, _router, _localStorageService, _jwtHelper, authenticationProvider, _authenticationRoute, _logoutPath, _tokenEndpoint, _serverUrl, _directEndpoint, _maxInactivity, _userCountdownSeconds, _idpInactivityMinutes, locationStrategy) {
49
- this._http = _http;
50
- this._router = _router;
51
- this._localStorageService = _localStorageService;
52
- this._jwtHelper = _jwtHelper;
53
- this.authenticationProvider = authenticationProvider;
54
- this._authenticationRoute = _authenticationRoute;
55
- this._logoutPath = _logoutPath;
56
- this._tokenEndpoint = _tokenEndpoint;
57
- this._serverUrl = _serverUrl;
58
- this._directEndpoint = _directEndpoint;
59
- this._maxInactivity = _maxInactivity;
60
- this._userCountdownSeconds = _userCountdownSeconds;
61
- this._idpInactivityMinutes = _idpInactivityMinutes;
62
- this.locationStrategy = locationStrategy;
63
- this.userCountdownSeconds = 60;
64
- this.idpInactivityMinutes = 5;
65
- this.contentType = "application/json";
66
- this.limitedContext = false;
67
- this.deidentifiedContext = false;
68
- this.maxViewPermission = new BehaviorSubject("viewident");
69
- this._isAuthenticatedSubject = new BehaviorSubject(false);
70
- this._userIsAboutToTimeOut = new BehaviorSubject(false);
71
- this._maxInactivityMinutes = 120;
72
- this.contextRoot = "";
73
- if (isDevMode()) {
74
- console.debug("window.location.href: " + window.location.href);
75
- }
76
- if (window.location) {
77
- let parts = window.location.href.split("/");
78
- this.baseUrl = parts[0] + "//" + parts[2];
79
- if (parts.length > 3) {
80
- this.contextRoot = parts[3];
81
- }
82
- }
83
- if (this._localStorageService.getItem("maxViewPermission")) {
84
- this.maxViewPermission.next(this._localStorageService.getItem("maxViewPermission"));
85
- }
86
- if (_maxInactivity) {
87
- this._maxInactivityMinutes = _maxInactivity;
88
- }
89
- if (_userCountdownSeconds) {
90
- this.userCountdownSeconds = _userCountdownSeconds;
91
- }
92
- if (_idpInactivityMinutes) {
93
- this.idpInactivityMinutes = _idpInactivityMinutes;
94
- }
95
- this.hasValidConfig();
96
- //There could be a non-expired token in local storage.
97
- let token = this.authenticationProvider.authToken;
98
- this.storeToken(token);
99
- }
100
- getBaseUrl() {
101
- return (this.baseUrl) ? this.baseUrl : "";
102
- }
103
- getContextRoot() {
104
- return this.contextRoot;
105
- }
106
- getHeaders(req) {
107
- let headers = req.headers;
108
- //Don't set content type if already set
109
- if (!req.headers.get(AuthenticationService.CONTENT_TYPE)) {
110
- headers = headers.set(AuthenticationService.CONTENT_TYPE, this.contentType.toString());
111
- }
112
- if (headers.get(AuthenticationService.SEC_GOV_CLASS_HEADER) === "") {
113
- headers = headers.delete(AuthenticationService.SEC_GOV_CLASS_HEADER);
114
- }
115
- else if (this.securityGovernorClass && !headers.get(AuthenticationService.SEC_GOV_CLASS_HEADER)) {
116
- headers = headers.set(AuthenticationService.SEC_GOV_CLASS_HEADER, this.securityGovernorClass);
117
- }
118
- if (headers.get(AuthenticationService.SEC_GOV_ID_HEADER) === "") {
119
- headers = headers.delete(AuthenticationService.SEC_GOV_ID_HEADER);
120
- }
121
- else if (this.securityGovernorId && !headers.get(AuthenticationService.SEC_GOV_ID_HEADER)) {
122
- headers = headers.set(AuthenticationService.SEC_GOV_ID_HEADER, this.securityGovernorId.toString());
123
- }
124
- headers = headers.set(AuthenticationService.DEIDENT_HEADER, this.deidentifiedContext.toString());
125
- headers = headers.set(AuthenticationService.LIMITED_HEADER, this.limitedContext.toString());
126
- return headers;
127
- }
128
- get authenticationTokenKey() {
129
- return this.authenticationProvider.authenticationTokenKey;
130
- }
131
- get authToken() {
132
- return this.authenticationProvider.authToken;
133
- }
134
- updateUserActivity() {
135
- if (this._isAuthenticatedSubject.value) {
136
- this._lastUserInteraction = new Date();
137
- this._userIsAboutToTimeOut.next(false);
138
- }
139
- }
140
- /**
141
- * A mutator for identifying the clients original request location. Setting this value will influence the end location
142
- * navigated to by {@link #navigateToPath}.
143
- *
144
- * @param redirectUrl location of the users request before authentication
145
- */
146
- set redirectUrl(redirectUrl) {
147
- this._redirectUrl = redirectUrl;
148
- }
149
- get redirectUrl() {
150
- return this._redirectUrl;
151
- }
152
- requestAccessToken(redirectOnSuccess) {
153
- this._http.get(this.tokenLocation(), { withCredentials: true })
154
- .subscribe((response) => {
155
- this.storeToken(response.auth_token);
156
- if (redirectOnSuccess) {
157
- this.proceedIfAuthenticated();
158
- }
159
- }, (error) => {
160
- //Token refresh failed.
161
- this.logout(true);
162
- });
163
- }
164
- /**
165
- * Verifies whether or not a current user session exists.
166
- *
167
- * @returns {Observable<boolean>} evaluates to true if the user is authenticated, false otherwise.
168
- */
169
- isAuthenticated() {
170
- return this._isAuthenticatedSubject.asObservable();
171
- }
172
- isAboutToTimeOut() {
173
- return this._userIsAboutToTimeOut.asObservable();
174
- }
175
- getTimeoutStart() {
176
- if (this._lastUserInteraction) {
177
- return this._lastUserInteraction.valueOf() + (((this._maxInactivityMinutes * 60) - this.userCountdownSeconds) * 1000);
178
- }
179
- }
180
- tokenLocation() {
181
- if (this._serverUrl) {
182
- return this._serverUrl + this._tokenEndpoint;
183
- }
184
- else {
185
- return this._tokenEndpoint;
186
- }
187
- }
188
- directLoginLocation() {
189
- if (this._serverUrl) {
190
- return this._serverUrl + this._directEndpoint;
191
- }
192
- else {
193
- return this._directEndpoint;
194
- }
195
- }
196
- logoutLocation() {
197
- if (this._serverUrl) {
198
- return this._serverUrl + this._logoutPath;
199
- }
200
- else {
201
- return this._logoutPath;
202
- }
203
- }
204
- /**
205
- * A function to authenticated the user with the provided credentials. Failure results in an error that describes the
206
- * server response (status and status message) and should be actionable by the client application.
207
- *
208
- * @param username of the authenticating user to verify
209
- * @param password of the authenticating user to verify
210
- * @returns {Observable<R>} describing the result of the login action, true or an error
211
- */
212
- login(_username, _password) {
213
- return this._http.post(this.directLoginLocation(), { username: _username, password: _password }, { observe: "response" }).pipe(map((resp) => {
214
- if (resp.status === 201) {
215
- return true;
216
- }
217
- else {
218
- throw new Error("Authentication failed. " + resp.status + ": " + resp.statusText);
219
- }
220
- }), catchError(this.handleError));
221
- }
222
- clearLogin() {
223
- //Front-end logout
224
- try {
225
- this._localStorageService.removeItem(this.authenticationProvider.authenticationTokenKey);
226
- this.unsubscribeFromTokenRefresh();
227
- this._isAuthenticatedSubject.next(false);
228
- this._userIsAboutToTimeOut.next(false);
229
- }
230
- catch (Error) {
231
- }
232
- //Back-end logout
233
- let headers = new HttpHeaders().set(AuthenticationService.CONTENT_TYPE, "text/plain");
234
- return this._http.get(this.logoutLocation(), { headers: headers });
235
- }
236
- /**
237
- * A function to signal the termination of the current session. Invoking this function will clean up any relevant state
238
- * related to the last active session.
239
- */
240
- logout(keepCurrentRoute = false) {
241
- //Prevent logout if already on authentication route. Doing otherwise screws up SAML
242
- if (!this._router.routerState || this._router.routerState.snapshot.url !== this._authenticationRoute) {
243
- this._redirectUrl = (keepCurrentRoute && this._router.routerState && this._router.routerState.snapshot) ? this._router.routerState.snapshot.url : "";
244
- if (this._redirectUrl.startsWith("/")) {
245
- this._redirectUrl = this._redirectUrl.substring(1);
246
- }
247
- this.clearLogin().subscribe((response) => {
248
- window.location.replace(this._redirectUrl);
249
- }, (error) => {
250
- window.location.replace(this._redirectUrl);
251
- });
252
- }
253
- }
254
- storeToken(token) {
255
- let valid = this.validateToken(token);
256
- // unsubscribe from refesh before we decide wether to resubscribe
257
- this.unsubscribeFromTokenRefresh();
258
- if (valid) {
259
- this._localStorageService.setItem(this.authenticationProvider.authenticationTokenKey, token);
260
- this.subscribeToTokenRefresh(token);
261
- //Change the BehaviorSubject if the user was not previously authenticated.
262
- //Since other code may be subscribing to this observable, we don't want to cause new events to fire if just refreshing the JWT.
263
- if (!this._isAuthenticatedSubject.value) {
264
- this._isAuthenticatedSubject.next(true);
265
- }
266
- }
267
- else {
268
- this._localStorageService.removeItem(this.authenticationProvider.authenticationTokenKey);
269
- this._isAuthenticatedSubject.next(false);
270
- }
271
- }
272
- proceedIfAuthenticated() {
273
- if (isDevMode()) {
274
- console.debug("AuthenticationService.proceedIfAuthenticated: " + this._redirectUrl);
275
- }
276
- if (this._isAuthenticatedSubject.value) {
277
- //Login counts as user activity, too
278
- this.updateUserActivity();
279
- if (this._redirectUrl && this._redirectUrl && this._redirectUrl !== "") {
280
- this._router.navigateByUrl(this._redirectUrl);
281
- }
282
- else {
283
- this._router.navigate([""]);
284
- }
285
- return true;
286
- }
287
- else {
288
- return false;
289
- }
290
- }
291
- validateToken(token) {
292
- return (token && !this._jwtHelper.isTokenExpired(token));
293
- }
294
- subscribeToTokenRefresh(token) {
295
- let exp = this._jwtHelper.getTokenExpirationDate(token);
296
- // Use a timer to periodically check timeouts
297
- this._refreshSubscription = interval(1000)
298
- .subscribe(() => {
299
- // If a tab is inactive we can't know if our timer is accurate
300
- // so when the interval hits check against timestamps
301
- if (this._isAuthenticatedSubject.value && Date.now() > this.getTimeoutStart()) {
302
- //Don't update the subject more than once! Doing so initializes more than one countdown timer!
303
- if (this._userIsAboutToTimeOut.getValue() !== true) {
304
- this._userIsAboutToTimeOut.next(true);
305
- }
306
- }
307
- // check for refresh token
308
- let msToExpiry = (exp.valueOf() - new Date().valueOf());
309
- // Refresh 60 seconds before expiry
310
- if (msToExpiry <= 60000) {
311
- this.refreshTokenIfUserIsActive();
312
- }
313
- });
314
- }
315
- unsubscribeFromTokenRefresh() {
316
- if (this._refreshSubscription && !this._refreshSubscription.closed) {
317
- this._refreshSubscription.unsubscribe();
318
- }
319
- }
320
- getMaxViewPermission() {
321
- return this.maxViewPermission.getValue();
322
- }
323
- getMaxViewPermissionSubject() {
324
- return this.maxViewPermission;
325
- }
326
- setMaxViewPermission(maxViewPermission) {
327
- this._localStorageService.setItem("maxViewPermission", maxViewPermission);
328
- this.maxViewPermission.next(maxViewPermission);
329
- }
330
- refreshTokenIfUserIsActive() {
331
- //Only refresh if the user has been active
332
- if (this._lastUserInteraction && ((new Date().valueOf() - this._lastUserInteraction.valueOf()) <= (this._maxInactivityMinutes * 60 * 1000))) {
333
- this.requestAccessToken(false);
334
- }
335
- }
336
- hasValidConfig() {
337
- if (this._tokenEndpoint == null && (this._serverUrl === null || this._logoutPath === null)) {
338
- throw new Error("BUG ALERT! Invalid AuthenticationService configuration. No valid configuration for authentication endpoint(s).");
339
- }
340
- if (this._localStorageService === null || this.authenticationProvider.authenticationTokenKey === null) {
341
- throw new Error("BUG ALERT! Invalid AuthenticationService configuration. No valid configuration for local storage");
342
- }
343
- }
344
- handleError(error) {
345
- let errMsg = (error.message) ? error.message : AuthenticationService.GENERIC_ERR_MSG;
346
- return throwError(errMsg);
347
- }
348
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", 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 }); }
349
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: AuthenticationService }); }
350
- }
351
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: AuthenticationService, decorators: [{
352
- type: Injectable
353
- }], ctorParameters: function () { return [{ type: i1.HttpClient }, { type: i2.Router }, { type: i3.CoolLocalStorage }, { type: i4.JwtHelperService }, { type: i5.AuthenticationProvider }, { type: undefined, decorators: [{
354
- type: Inject,
355
- args: [AUTHENTICATION_ROUTE]
356
- }] }, { type: undefined, decorators: [{
357
- type: Inject,
358
- args: [AUTHENTICATION_LOGOUT_PATH]
359
- }] }, { type: undefined, decorators: [{
360
- type: Inject,
361
- args: [AUTHENTICATION_TOKEN_ENDPOINT]
362
- }] }, { type: undefined, decorators: [{
363
- type: Optional
364
- }, {
365
- type: Inject,
366
- args: [AUTHENTICATION_SERVER_URL]
367
- }] }, { type: undefined, decorators: [{
368
- type: Optional
369
- }, {
370
- type: Inject,
371
- args: [AUTHENTICATION_DIRECT_ENDPOINT]
372
- }] }, { type: undefined, decorators: [{
373
- type: Optional
374
- }, {
375
- type: Inject,
376
- args: [AUTHENTICATION_MAX_INACTIVITY_MINUTES]
377
- }] }, { type: undefined, decorators: [{
378
- type: Optional
379
- }, {
380
- type: Inject,
381
- args: [AUTHENTICATION_USER_COUNTDOWN_SECONDS]
382
- }] }, { type: undefined, decorators: [{
383
- type: Optional
384
- }, {
385
- type: Inject,
386
- args: [AUTHENTICATION_IDP_INACTIVITY_MINUTES]
387
- }] }, { type: i6.LocationStrategy, decorators: [{
388
- type: Optional
389
- }, {
390
- type: Inject,
391
- args: [LocationStrategy]
392
- }] }]; } });
393
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXV0aGVudGljYXRpb24uc2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3Byb2plY3RzL2F1dGhlbnRpY2F0aW9uL3NyYy9hdXRoZW50aWNhdGlvbi5zZXJ2aWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOztHQUVHO0FBQ0gsT0FBTyxFQUFDLFVBQVUsRUFBRSxjQUFjLEVBQUUsTUFBTSxFQUFFLFFBQVEsRUFBRSxTQUFTLEVBQUMsTUFBTSxlQUFlLENBQUM7QUFDdEYsT0FBTyxFQUFDLGdCQUFnQixFQUFDLE1BQU0saUJBQWlCLENBQUM7QUFDakQsT0FBTyxFQUFDLE1BQU0sRUFBQyxNQUFNLGlCQUFpQixDQUFDO0FBQ3ZDLE9BQU8sRUFBQyxVQUFVLEVBQUUsV0FBVyxFQUE0QixNQUFNLHNCQUFzQixDQUFDO0FBRXhGLE9BQU8sRUFBQyxRQUFRLEVBQWMsZUFBZSxFQUFnQixVQUFVLEVBQUssTUFBTSxNQUFNLENBQUM7QUFDekYsT0FBTyxFQUFDLFVBQVUsRUFBUyxHQUFHLEVBQUMsTUFBTSxnQkFBZ0IsQ0FBQztBQUN0RCxPQUFPLEVBQUMsZ0JBQWdCLEVBQUMsTUFBTSxvQkFBb0IsQ0FBQztBQUVwRCxPQUFPLEVBQUMsc0JBQXNCLEVBQUMsTUFBTSwyQkFBMkIsQ0FBQztBQUNqRSxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSx1QkFBdUIsQ0FBQzs7Ozs7Ozs7QUFFekQ7Ozs7R0FJRztBQUNILE1BQU0sQ0FBQyxJQUFJLHlCQUF5QixHQUFHLElBQUksY0FBYyxDQUFTLGdDQUFnQyxDQUFDLENBQUM7QUFDcEcsTUFBTSxDQUFDLElBQUksMEJBQTBCLEdBQUcsSUFBSSxjQUFjLENBQVMsNEJBQTRCLENBQUMsQ0FBQztBQUNqRyxNQUFNLENBQUMsSUFBSSw4QkFBOEIsR0FBRyxJQUFJLGNBQWMsQ0FBUyxnQ0FBZ0MsQ0FBQyxDQUFDO0FBQ3pHLE1BQU0sQ0FBQyxJQUFJLDZCQUE2QixHQUFHLElBQUks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QUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMscUJBQXFCLENBQUMsZUFBZSxDQUFDO1FBQ3JGLE9BQU8sVUFBVSxDQUFDLE1BQU0sQ0FBQyxDQUFDO0lBQzVCLENBQUM7K0dBNVhVLHFCQUFxQix3S0F3Q1osb0JBQW9CLGFBQ3BCLDBCQUEwQixhQUMxQiw2QkFBNkIsYUFDakIseUJBQXlCLDZCQUN6Qiw4QkFBOEIsNkJBQzlCLHFDQUFxQyw2QkFDckMscUNBQXFDLDZCQUNyQyxxQ0FBcUMsNkJBQ3JDLGdCQUFnQjttSEFoRHJDLHFCQUFxQjs7NEZBQXJCLHFCQUFxQjtrQkFEakMsVUFBVTs7MEJBeUNJLE1BQU07MkJBQUMsb0JBQW9COzswQkFDM0IsTUFBTTsyQkFBQywwQkFBMEI7OzBCQUNqQyxNQUFNOzJCQUFDLDZCQUE2Qjs7MEJBQ3BDLFFBQVE7OzBCQUFJLE1BQU07MkJBQUMseUJBQXlCOzswQkFDNUMsUUFBUTs7MEJBQUksTUFBTTsyQkFBQyw4QkFBOEI7OzBCQUNqRCxRQUFROzswQkFBSSxNQUFNOzJCQUFDLHFDQUFxQzs7MEJBQ3hELFFBQVE7OzBCQUFJLE1BQU07MkJBQUMscUNBQXFDOzswQkFDeEQsUUFBUTs7MEJBQUksTUFBTTsyQkFBQyxxQ0FBcUM7OzBCQUN4RCxRQUFROzswQkFBSSxNQUFNOzJCQUFDLGdCQUFnQiIsInNvdXJjZXNDb250ZW50IjpbIi8qXHJcbiAqIENvcHlyaWdodCAoYykgMjAxNiBIdW50c21hbiBDYW5jZXIgSW5zdGl0dXRlIGF0IHRoZSBVbml2ZXJzaXR5IG9mIFV0YWgsIENvbmZpZGVudGlhbCBhbmQgUHJvcHJpZXRhcnlcclxuICovXHJcbmltcG9ydCB7SW5qZWN0YWJsZSwgSW5qZWN0aW9uVG9rZW4sIEluamVjdCwgT3B0aW9uYWwsIGlzRGV2TW9kZX0gZnJvbSBcIkBhbmd1bGFyL2NvcmVcIjtcclxuaW1wb3J0IHtMb2NhdGlvblN0cmF0ZWd5fSBmcm9tIFwiQGFuZ3VsYXIvY29tbW9uXCI7XHJcbmltcG9ydCB7Um91dGVyfSBmcm9tIFwiQGFuZ3VsYXIvcm91dGVyXCI7XHJcbmltcG9ydCB7SHR0cENsaWVudCwgSHR0cEhlYWRlcnMsIEh0dHBSZXF1ZXN0LCBIdHRwUmVzcG9uc2V9IGZyb20gXCJAYW5ndWxhci9jb21tb24vaHR0cFwiO1xyXG5cclxuaW1wb3J0IHtpbnRlcnZhbCwgT2JzZXJ2YWJsZSwgQmVoYXZpb3JTdWJqZWN0LCBTdWJzY3JpcHRpb24sIHRocm93RXJyb3IsIG9mfSBmcm9tIFwicnhqc1wiO1xyXG5pbXBvcnQge2NhdGNoRXJyb3IsIGZpcnN0LCBtYXB9IGZyb20gXCJyeGpzL29wZXJhdG9yc1wiO1xyXG5pbXBvcnQge0p3dEhlbHBlclNlcnZpY2V9IGZyb20gXCJAYXV0aDAvYW5ndWxhci1qd3RcIjtcclxuXHJcbmltcG9ydCB7QXV0aGVudGljYXRpb25Qcm92aWRlcn0gZnJvbSBcIi4vYXV0aGVudGljYXRpb24ucHJvdmlkZXJcIjtcclxuaW1wb3J0IHsgQ29vbExvY2FsU3RvcmFnZSB9IGZyb20gXCJAYW5ndWxhci1jb29sL3N0b3JhZ2VcIjtcclxuXHJcbi8qKlxyXG4gKiBUaGUgdG9rZW4gdXNlZCBmb3IgaW5qZWN0aW9uIG9mIHRoZSBzZXJ2ZXIgc2lkZSBlbmRwb2ludCBmb3IgdGhlIGN1cnJlbnRseSBhdXRoZW50aWNhdGVkIHN1YmplY3QuXHJcbiAqXHJcbiAqIEB0eXBlIHtJbmplY3Rpb25Ub2tlbn1cclxuICovXHJcbmV4cG9ydCBsZXQgQVVUSEVOVElDQVRJT05fU0VSVkVSX1VSTCA9IG5ldyBJbmplY3Rpb25Ub2tlbjxzdHJpbmc+KFwiYXV0aGVudGljYXRpb25fc2VydmVyX3Jlc3RfYXBpXCIpO1xyXG5leHBvcnQgbGV0IEFVVEhFTlRJQ0FUSU9OX0xPR09VVF9QQVRIID0gbmV3IEluamVjdGlvblRva2VuPHN0cmluZz4oXCJhdXRoZW50aWNhdGlvbl9sb2dvdXRfcGF0aFwiKTtcclxuZXhwb3J0IGxldCBBVVRIRU5USUNBVElPTl9ESVJFQ1RfRU5EUE9JTlQgPSBuZXcgSW5qZWN0aW9uVG9rZW48c3RyaW5nPihcImF1dGhlbnRpY2F0aW9uX2RpcmVjdF9lbmRwb2ludFwiKTtcclxuZXhwb3J0IGxldCBBVVRIRU5USUNBVElPTl9UT0tFTl9FTkRQT0lOVCA9IG5ldyBJbmplY3Rpb25Ub2tlbjxzdHJpbmc+KFwiYXV0aGVudGljYXRpb25fdG9rZW5fZW5kcG9pbnRcIik7XHJcbmV4cG9ydCBsZXQgQVVUSEVOVElDQVRJT05fUk9VVEUgPSBuZXcgSW5qZWN0aW9uVG9rZW48c3RyaW5nPihcImF1dGhlbnRpY2F0aW9uX3JvdXRlXCIpO1xyXG5leHBvcnQgbGV0IEFVVEhFTlRJQ0FUSU9OX01BWF9JTkFDVElWSVRZX01JTlVURVMgPSBuZXcgSW5qZWN0aW9uVG9rZW48bnVtYmVyPihcImF1dGhlbnRpY2F0aW9uX21heF9pbmFjdGl2aXR5XCIpO1xyXG5leHBvcnQgbGV0IEFVVEhFTlRJQ0FUSU9OX1VTRVJfQ09VTlRET1dOX1NFQ09ORFMgPSBuZXcgSW5qZWN0aW9uVG9rZW48bnVtYmVyPihcImF1dGhlbnRpY2F0aW9uX3VzZXJfY291bnRkb3duX3NlY29uZHNcIik7XHJcbmV4cG9ydCBsZXQgQVVUSEVOVElDQVRJT05fSURQX0lOQUNUSVZJVFlfTUlOVVRFUyA9IG5ldyBJbmplY3Rpb25Ub2tlbjxudW1iZXI+KFwiYXV0aGVudGljYXRpb25faWRwX2luYWN0aXZpdHlfbWludXRlc1wiKTtcclxuXHJcbi8qKlxyXG4gKiBAc2luY2UgMS4wLjBcclxuICovXHJcbkBJbmplY3RhYmxlKClcclxuZXhwb3J0IGNsYXNzIEF1dGhlbnRpY2F0aW9uU2VydmljZSB7XHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBnZW5lcmljIGVycm9yIG1lc3NhZ2UgdXNlZCB3aGVuIGEgc2VydmVyIGVycm9yIGlzIHRocm93biB3aXRob3V0IGEgc3RhdHVzLlxyXG4gICAqXHJcbiAgICogQHR5cGUge3N0cmluZ31cclxuICAgKi9cclxuICBwdWJsaWMgc3RhdGljIEdFTkVSSUNfRVJSX01TRzogc3RyaW5nID0gXCJTZXJ2ZXIgZXJyb3JcIjtcclxuXHJcbiAgcHJpdmF0ZSBzdGF0aWMgQ09OVEVOVF9UWVBFOiBzdHJpbmcgPSBcIkNvbnRlbnQtVHlwZVwiO1xyXG4gIHByaXZhdGUgc3RhdGljIFNFQ19HT1ZfQ0xBU1NfSEVBREVSOiBzdHJpbmcgPSBcIlNlY3VyaXR5R292ZXJub3JDbGFzc1wiO1xyXG4gIHByaXZhdGUgc3RhdGljIFNFQ19HT1ZfSURfSEVBREVSOiBzdHJpbmcgPSBcIlNlY3VyaXR5R292ZXJub3JJZFwiO1xyXG4gIHByaXZhdGUgc3RhdGljIERFSURFTlRfSEVBREVSOiBzdHJpbmcgPSBcIkRlaWRlbnRpZmllZENvbnRleHRcIjtcclxuICBwcml2YXRlIHN0YXRpYyBMSU1JVEVEX0hFQURFUjogc3RyaW5nID0gXCJMaW1pdGVkQ29udGV4dFwiO1xyXG5cclxuICBwdWJsaWMgdXNlckNvdW50ZG93blNlY29uZHM6IG51bWJlciA9IDYwO1xyXG4gIHB1YmxpYyBpZHBJbmFjdGl2aXR5TWludXRlczogbnVtYmVyID0gNTtcclxuXHJcbiAgcHVibGljIGNvbnRlbnRUeXBlOiBzdHJpbmcgPSBcImFwcGxpY2F0aW9uL2pzb25cIjtcclxuICBwdWJsaWMgc2VjdXJpdHlHb3Zlcm5vckNsYXNzOiBzdHJpbmc7XHJcbiAgcHVibGljIHNlY3VyaXR5R292ZXJub3JJZDogbnVtYmVyO1xyXG4gIHB1YmxpYyBsaW1pdGVkQ29udGV4dDogYm9vbGVhbiA9IGZhbHNlO1xyXG4gIHB1YmxpYyBkZWlkZW50aWZpZWRDb250ZXh0OiBib29sZWFuID0gZmFsc2U7XHJcblxyXG4gIHByaXZhdGUgbWF4Vmlld1Blcm1pc3Npb246IEJlaGF2aW9yU3ViamVjdDxcInZpZXdcIiB8IFwidmlld2lkZW50XCIgfCBcInZpZXdsaW1pdGVkXCI+ID0gbmV3IEJlaGF2aW9yU3ViamVjdDxcInZpZXdcIiB8IFwidmlld2lkZW50XCIgfCBcInZpZXdsaW1pdGVkXCI+KFwidmlld2lkZW50XCIpO1xyXG4gIHByaXZhdGUgX2lzQXV0aGVudGljYXRlZFN1YmplY3Q6IEJlaGF2aW9yU3ViamVjdDxib29sZWFuPiA9IG5ldyBCZWhhdmlvclN1YmplY3Q8Ym9vbGVhbj4oZmFsc2UpO1xyXG4gIHByaXZhdGUgX3VzZXJJc0Fib3V0VG9UaW1lT3V0OiBCZWhhdmlvclN1YmplY3Q8Ym9vbGVhbj4gPSBuZXcgQmVoYXZpb3JTdWJqZWN0PGJvb2xlYW4+KGZhbHNlKTtcclxuICBwcml2YXRlIF9yZWRpcmVjdFVybDogc3RyaW5nO1xyXG4gIHByaXZhdGUgX3JlZnJlc2hTdWJzY3JpcHRpb246IFN1YnNjcmlwdGlvbjtcclxuICBwcml2YXRlIF9sYXN0VXNlckludGVyYWN0aW9uOiBEYXRlO1xyXG4gIHByaXZhdGUgX21heEluYWN0aXZpdHlNaW51dGVzOiBudW1iZXIgPSAxMjA7XHJcblxyXG4gIHByaXZhdGUgYmFzZVVybDogc3RyaW5nO1xyXG4gIHByaXZhdGUgY29udGV4dFJvb3Q6IHN0cmluZyA9IFwiXCI7XHJcblxyXG4gIGNvbnN0cnVjdG9yKHByaXZhdGUgX2h0dHA6IEh0dHBDbGllbnQsXHJcbiAgICAgICAgICAgICAgcHJpdmF0ZSBfcm91dGVyOiBSb3V0ZXIsXHJcbiAgICAgICAgICAgICAgcHJpdmF0ZSBfbG9jYWxTdG9yYWdlU2VydmljZTogQ29vbExvY2FsU3RvcmFnZSxcclxuICAgICAgICAgICAgICBwcml2YXRlIF9qd3RIZWxwZXI6IEp3dEhlbHBlclNlcnZpY2UsXHJcbiAgICAgICAgICAgICAgcHJpdmF0ZSBhdXRoZW50aWNhdGlvblByb3ZpZGVyOiBBdXRoZW50aWNhdGlvblByb3ZpZGVyLFxyXG4gICAgICAgICAgICAgIEBJbmplY3QoQVVUSEVOVElDQVRJT05fUk9VVEUpIHByaXZhdGUgX2F1dGhlbnRpY2F0aW9uUm91dGU6IHN0cmluZyxcclxuICAgICAgICAgICAgICBASW5qZWN0KEFVVEhFTlRJQ0FUSU9OX0xPR09VVF9QQVRIKSBwcml2YXRlIF9sb2dvdXRQYXRoOiBzdHJpbmcsXHJcbiAgICAgICAgICAgICAgQEluamVjdChBVVRIRU5USUNBVElPTl9UT0tFTl9FTkRQT0lOVCkgcHJpdmF0ZSBfdG9rZW5FbmRwb2ludDogc3RyaW5nLFxyXG4gICAgICAgICAgICAgIEBPcHRpb25hbCgpIEBJbmplY3QoQVVUSEVOVElDQVRJT05fU0VSVkVSX1VSTCkgcHJpdmF0ZSBfc2VydmVyVXJsOiBzdHJpbmcsXHJcbiAgICAgICAgICAgICAgQE9wdGlvbmFsKCkgQEluamVjdChBVVRIRU5USUNBVElPTl9ESVJFQ1RfRU5EUE9JTlQpIHByaXZhdGUgX2RpcmVjdEVuZHBvaW50OiBzdHJpbmcsXHJcbiAgICAgICAgICAgICAgQE9wdGlvbmFsKCkgQEluamVjdChBVVRIRU5USUNBVElPTl9NQVhfSU5BQ1RJVklUWV9NSU5VVEVTKSBwcml2YXRlIF9tYXhJbmFjdGl2aXR5OiBudW1iZXIsXHJcbiAgICAgICAgICAgICAgQE9wdGlvbmFsKCkgQEluamVjdChBVVRIRU5USUNBVElPTl9VU0VSX0NPVU5URE9XTl9TRUNPTkRTKSBwcml2YXRlIF91c2VyQ291bnRkb3duU2Vjb25kczogbnVtYmVyLFxyXG4gICAgICAgICAgICAgIEBPcHRpb25hbCgpIEBJbmplY3QoQVVUSEVOVElDQVRJT05fSURQX0lOQUNUSVZJVFlfTUlOVVRFUykgcHJpdmF0ZSBfaWRwSW5hY3Rpdml0eU1pbnV0ZXM6IG51bWJlcixcclxuICAgICAgICAgICAgICBAT3B0aW9uYWwoKSBASW5qZWN0KExvY2F0aW9uU3RyYXRlZ3kpIHByaXZhdGUgbG9jYXRpb25TdHJhdGVneTogTG9jYXRpb25TdHJhdGVneSkge1xyXG4gICAgaWYgKGlzRGV2TW9kZSgpKSB7XHJcbiAgICAgIGNvbnNvbGUuZGVidWcoXCJ3aW5kb3cubG9jYXRpb24uaHJlZjogXCIgKyB3aW5kb3cubG9jYXRpb24uaHJlZik7XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKHdpbmRvdy5sb2NhdGlvbikge1xyXG4gICAgICBsZXQgcGFydHM6IHN0cmluZ1tdID0gd2luZG93LmxvY2F0aW9uLmhyZWYuc3BsaXQoXCIvXCIpO1xyXG4gICAgICB0aGlzLmJhc2VVcmwgPSBwYXJ0c1swXSArIFwiLy9cIiArIHBhcnRzWzJdO1xyXG4gICAgICBpZiAocGFydHMubGVuZ3RoID4gMykge1xyXG4gICAgICAgIHRoaXMuY29udGV4dFJvb3QgPSBwYXJ0c1szXTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIGlmICh0aGlzLl9sb2NhbFN0b3JhZ2VTZXJ2aWNlLmdldEl0ZW0oXCJtYXhWaWV3UGVybWlzc2lvblwiKSkge1xyXG4gICAgICB0aGlzLm1heFZpZXdQZXJtaXNzaW9uLm5leHQoPFwidmlld1wiIHwgXCJ2aWV3aWRlbnRcIiB8IFwidmlld2xpbWl0ZWRcIj50aGlzLl9sb2NhbFN0b3JhZ2VTZXJ2aWNlLmdldEl0ZW0oXCJtYXhWaWV3UGVybWlzc2lvblwiKSk7XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKF9tYXhJbmFjdGl2aXR5KSB7XHJcbiAgICAgIHRoaXMuX21heEluYWN0aXZpdHlNaW51dGVzID0gX21heEluYWN0aXZpdHk7XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKF91c2VyQ291bnRkb3duU2Vjb25kcykge1xyXG4gICAgICB0aGlzLnVzZXJDb3VudGRvd25TZWNvbmRzID0gX3VzZXJDb3VudGRvd25TZWNvbmRzO1xyXG4gICAgfVxyXG5cclxuICAgIGlmIChfaWRwSW5hY3Rpdml0eU1pbnV0ZXMpIHtcclxuICAgICAgdGhpcy5pZHBJbmFjdGl2aXR5TWludXRlcyA9IF9pZHBJbmFjdGl2aXR5TWludXRlcztcclxuICAgIH1cclxuXHJcbiAgICB0aGlzLmhhc1ZhbGlkQ29uZmlnKCk7XHJcblxyXG4gICAgLy9UaGVyZSBjb3VsZCBiZSBhIG5vbi1leHBpcmVkIHRva2VuIGluIGxvY2FsIHN0b3JhZ2UuXHJcbiAgICBsZXQgdG9rZW46IHN0cmluZyA9IHRoaXMuYXV0aGVudGljYXRpb25Qcm92aWRlci5hdXRoVG9rZW47XHJcbiAgICB0aGlzLnN0b3JlVG9rZW4odG9rZW4pO1xyXG4gIH1cclxuXHJcbiAgZ2V0QmFzZVVybCgpOiBzdHJpbmcge1xyXG4gICAgcmV0dXJuICh0aGlzLmJhc2VVcmwpID8gdGhpcy5iYXNlVXJsIDogXCJcIjtcclxuICB9XHJcblxyXG4gIGdldENvbnRleHRSb290KCk6IHN0cmluZyB7XHJcbiAgICByZXR1cm4gdGhpcy5jb250ZXh0Um9vdDtcclxuICB9XHJcblxyXG4gIGdldEhlYWRlcnMocmVxOiBIdHRwUmVxdWVzdDxhbnk+KTogSHR0cEhlYWRlcnMge1xyXG4gICAgbGV0IGhlYWRlcnM6IEh0dHBIZWFkZXJzID0gcmVxLmhlYWRlcnM7XHJcblxyXG4gICAgLy9Eb24ndCBzZXQgY29udGVudCB0eXBlIGlmIGFscmVhZHkgc2V0XHJcbiAgICBpZiAoIXJlcS5oZWFkZXJzLmdldChBdXRoZW50aWNhdGlvblNlcnZpY2UuQ09OVEVOVF9UWVBFKSkge1xyXG4gICAgICBoZWFkZXJzID0gaGVhZGVycy5zZXQoQXV0aGVudGljYXRpb25TZXJ2aWNlLkNPTlRFTlRfVFlQRSwgdGhpcy5jb250ZW50VHlwZS50b1N0cmluZygpKTtcclxuICAgIH1cclxuXHJcbiAgICBpZiAoaGVhZGVycy5nZXQoQXV0aGVudGljYXRpb25TZXJ2aWNlLlNFQ19HT1ZfQ0xBU1NfSEVBREVSKSA9PT0gXCJcIikge1xyXG4gICAgICBoZWFkZXJzID0gaGVhZGVycy5kZWxldGUoQXV0aGVudGljYXRpb25TZXJ2aWNlLlNFQ19HT1ZfQ0xBU1NfSEVBREVSKTtcclxuICAgIH0gZWxzZSBpZiAodGhpcy5zZWN1cml0eUdvdmVybm9yQ2xhc3MgJiYgIWhlYWRlcnMuZ2V0KEF1dGhlbnRpY2F0aW9uU2VydmljZS5TRUNfR09WX0NMQVNTX0hFQURFUikpIHtcclxuICAgICAgaGVhZGVycyA9IGhlYWRlcnMuc2V0KEF1dGhlbnRpY2F0aW9uU2VydmljZS5TRUNfR09WX0NMQVNTX0hFQURFUiwgdGhpcy5zZWN1cml0eUdvdmVybm9yQ2xhc3MpO1xyXG4gICAgfVxyXG5cclxuICAgIGlmIChoZWFkZXJzLmdldChBdXRoZW50aWNhdGlvblNlcnZpY2UuU0VDX0dPVl9JRF9IRUFERVIpID09PSBcIlwiKSB7XHJcbiAgICAgIGhlYWRlcnMgPSBoZWFkZXJzLmRlbGV0ZShBdXRoZW50aWNhdGlvblNlcnZpY2UuU0VDX0dPVl9JRF9IRUFERVIpO1xyXG4gICAgfSBlbHNlIGlmICh0aGlzLnNlY3VyaXR5R292ZXJub3JJZCAmJiAhaGVhZGVycy5nZXQoQXV0aGVudGljYXRpb25TZXJ2aWNlLlNFQ19HT1ZfSURfSEVBREVSKSkge1xyXG4gICAgICBoZWFkZXJzID0gaGVhZGVycy5zZXQoQXV0aGVudGljYXRpb25TZXJ2aWNlLlNFQ19HT1ZfSURfSEVBREVSLCB0aGlzLnNlY3VyaXR5R292ZXJub3JJZC50b1N0cmluZygpKTtcclxuICAgIH1cclxuXHJcbiAgICBoZWFkZXJzID0gaGVhZGVycy5zZXQoQXV0aGVudGljYXRpb25TZXJ2aWNlLkRFSURFTlRfSEVBREVSLCB0aGlzLmRlaWRlbnRpZmllZENvbnRleHQudG9TdHJpbmcoKSk7XHJcbiAgICBoZWFkZXJzID0gaGVhZGVycy5zZXQoQXV0aGVudGljYXRpb25TZXJ2aWNlLkxJTUlURURfSEVBREVSLCB0aGlzLmxpbWl0ZWRDb250ZXh0LnRvU3RyaW5nKCkpO1xyXG5cclxuICAgIHJldHVybiBoZWFkZXJzO1xyXG4gIH1cclxuXHJcbiAgZ2V0IGF1dGhlbnRpY2F0aW9uVG9rZW5LZXkoKTogc3RyaW5nIHtcclxuICAgIHJldHVybiB0aGlzLmF1dGhlbnRpY2F0aW9uUHJvdmlkZXIuYXV0aGVudGljYXRpb25Ub2tlbktleTtcclxuICB9XHJcblxyXG4gIGdldCBhdXRoVG9rZW4oKTogc3RyaW5nIHtcclxuICAgIHJldHVybiB0aGlzLmF1dGhlbnRpY2F0aW9uUHJvdmlkZXIuYXV0aFRva2VuO1xyXG4gIH1cclxuXHJcbiAgcHVibGljIHVwZGF0ZVVzZXJBY3Rpdml0eSgpOiB2b2lkIHtcclxuICAgIGlmICh0aGlzLl9pc0F1dGhlbnRpY2F0ZWRTdWJqZWN0LnZhbHVlKSB7XHJcbiAgICAgIHRoaXMuX2xhc3RVc2VySW50ZXJhY3Rpb24gPSBuZXcgRGF0ZSgpO1xyXG4gICAgICB0aGlzLl91c2VySXNBYm91dFRvVGltZU91dC5uZXh0KGZhbHNlKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIEEgbXV0YXRvciBmb3IgaWRlbnRpZnlpbmcgdGhlIGNsaWVudHMgb3JpZ2luYWwgcmVxdWVzdCBsb2NhdGlvbi4gU2V0dGluZyB0aGlzIHZhbHVlIHdpbGwgaW5mbHVlbmNlIHRoZSBlbmQgbG9jYXRpb25cclxuICAgKiBuYXZpZ2F0ZWQgdG8gYnkge0BsaW5rICNuYXZpZ2F0ZVRvUGF0aH0uXHJcbiAgICpcclxuICAgKiBAcGFyYW0gcmVkaXJlY3RVcmwgbG9jYXRpb24gb2YgdGhlIHVzZXJzIHJlcXVlc3QgYmVmb3JlIGF1dGhlbnRpY2F0aW9uXHJcbiAgICovXHJcbiAgc2V0IHJlZGlyZWN0VXJsKHJlZGlyZWN0VXJsOiBzdHJpbmcpIHtcclxuICAgIHRoaXMuX3JlZGlyZWN0VXJsID0gcmVkaXJlY3RVcmw7XHJcbiAgfVxyXG5cclxuICBnZXQgcmVkaXJlY3RVcmwoKSB7XHJcbiAgICByZXR1cm4gdGhpcy5fcmVkaXJlY3RVcmw7XHJcbiAgfVxyXG5cclxuICByZXF1ZXN0QWNjZXNzVG9rZW4ocmVkaXJlY3RPblN1Y2Nlc3M6IGJvb2xlYW4pOiB2b2lkIHtcclxuXHJcbiAgICB0aGlzLl9odHRwLmdldCh0aGlzLnRva2VuTG9jYXRpb24oKSwge3dpdGhDcmVkZW50aWFsczogdHJ1ZX0pXHJcbiAgICAgIC5zdWJzY3JpYmUoXHJcbiAgICAgICAgKHJlc3BvbnNlOiBhbnkpID0+IHtcclxuICAgICAgICAgIHRoaXMuc3RvcmVUb2tlbihyZXNwb25zZS5hdXRoX3Rva2VuKTtcclxuICAgICAgICAgIGlmIChyZWRpcmVjdE9uU3VjY2Vzcykge1xyXG4gICAgICAgICAgICB0aGlzLnByb2NlZWRJZkF1dGhlbnRpY2F0ZWQoKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9LFxyXG4gICAgICAgIChlcnJvcikgPT4ge1xyXG4gICAgICAgICAgLy9Ub2tlbiByZWZyZXNoIGZhaWxlZC5cclxuICAgICAgICAgIHRoaXMubG9nb3V0KHRydWUpO1xyXG4gICAgICAgIH1cclxuICAgICAgKTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIFZlcmlmaWVzIHdoZXRoZXIgb3Igbm90IGEgY3VycmVudCB1c2VyIHNlc3Npb24gZXhpc3RzLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge09ic2VydmFibGU8Ym9vbGVhbj59IGV2YWx1YXRlcyB0byB0cnVlIGlmIHRoZSB1c2VyIGlzIGF1dGhlbnRpY2F0ZWQsIGZhbHNlIG90aGVyd2lzZS5cclxuICAgKi9cclxuICBpc0F1dGhlbnRpY2F0ZWQoKTogT2JzZXJ2YWJsZTxib29sZWFuPiB7XHJcbiAgICByZXR1cm4gdGhpcy5faXNBdXRoZW50aWNhdGVkU3ViamVjdC5hc09ic2VydmFibGUoKTtcclxuICB9XHJcblxyXG4gIGlzQWJvdXRUb1RpbWVPdXQoKTogT2JzZXJ2YWJsZTxib29sZWFuPiB7XHJcbiAgICByZXR1cm4gdGhpcy5fdXNlcklzQWJvdXRUb1RpbWVPdXQuYXNPYnNlcnZhYmxlKCk7XHJcbiAgfVxyXG5cclxuICBnZXRUaW1lb3V0U3RhcnQoKTogbnVtYmVyIHtcclxuICAgIGlmICh0aGlzLl9sYXN0VXNlckludGVyYWN0aW9uKSB7XHJcbiAgICAgIHJldHVybiB0aGlzLl9sYXN0VXNlckludGVyYWN0aW9uLnZhbHVlT2YoKSArICgoKHRoaXMuX21heEluYWN0aXZpdHlNaW51dGVzICogNjApIC0gdGhpcy51c2VyQ291bnRkb3duU2Vjb25kcykgKiAxMDAwKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIHRva2VuTG9jYXRpb24oKTogc3RyaW5nIHtcclxuICAgIGlmICh0aGlzLl9zZXJ2ZXJVcmwpIHtcclxuICAgICAgcmV0dXJuIHRoaXMuX3NlcnZlclVybCArIHRoaXMuX3Rva2VuRW5kcG9pbnQ7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICByZXR1cm4gdGhpcy5fdG9rZW5FbmRwb2ludDtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIGRpcmVjdExvZ2luTG9jYXRpb24oKTogc3RyaW5nIHtcclxuICAgIGlmICh0aGlzLl9zZXJ2ZXJVcmwpIHtcclxuICAgICAgcmV0dXJuIHRoaXMuX3NlcnZlclVybCArIHRoaXMuX2RpcmVjdEVuZHBvaW50O1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgcmV0dXJuIHRoaXMuX2RpcmVjdEVuZHBvaW50O1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgbG9nb3V0TG9jYXRpb24oKTogc3RyaW5nIHtcclxuICAgIGlmICh0aGlzLl9zZXJ2ZXJVcmwpIHtcclxuICAgICAgcmV0dXJuIHRoaXMuX3NlcnZlclVybCArIHRoaXMuX2xvZ291dFBhdGg7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICByZXR1cm4gdGhpcy5fbG9nb3V0UGF0aDtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIEEgZnVuY3Rpb24gdG8gYXV0aGVudGljYXRlZCB0aGUgdXNlciB3aXRoIHRoZSBwcm92aWRlZCBjcmVkZW50aWFscy4gRmFpbHVyZSByZXN1bHRzIGluIGFuIGVycm9yIHRoYXQgZGVzY3JpYmVzIHRoZVxyXG4gICAqIHNlcnZlciByZXNwb25zZSAoc3RhdHVzIGFuZCBzdGF0dXMgbWVzc2FnZSkgYW5kIHNob3VsZCBiZSBhY3Rpb25hYmxlIGJ5IHRoZSBjbGllbnQgYXBwbGljYXRpb24uXHJcbiAgICpcclxuICAgKiBAcGFyYW0gdXNlcm5hbWUgb2YgdGhlIGF1dGhlbnRpY2F0aW5nIHVzZXIgdG8gdmVyaWZ5XHJcbiAgICogQHBhcmFtIHBhc3N3b3JkIG9mIHRoZSBhdXRoZW50aWNhdGluZyB1c2VyIHRvIHZlcmlmeVxyXG4gICAqIEByZXR1cm5zIHtPYnNlcnZhYmxlPFI+fSBkZXNjcmliaW5nIHRoZSByZXN1bHQgb2YgdGhlIGxvZ2luIGFjdGlvbiwgdHJ1ZSBvciBhbiBlcnJvclxyXG4gICAqL1xyXG4gIGxvZ2luKF91c2VybmFtZTogc3RyaW5nLCBfcGFzc3dvcmQ6IHN0cmluZyk6IE9ic2VydmFibGU8Ym9vbGVhbj4ge1xyXG4gICAgcmV0dXJuIHRoaXMuX2h0dHAucG9zdChcclxuICAgICAgdGhpcy5kaXJlY3RMb2dpbkxvY2F0aW9uKCksXHJcbiAgICAgIHt1c2VybmFtZTogX3VzZXJuYW1lLCBwYXNzd29yZDogX3Bhc3N3b3JkfSxcclxuICAgICAge29ic2VydmU6IFwicmVzcG9uc2VcIn1cclxuICAgICkucGlwZShtYXAoKHJlc3A6IEh0dHBSZXNwb25zZTxhbnk+KSA9PiB7XHJcbiAgICAgIGlmIChyZXNwLnN0YXR1cyA9PT0gMjAxKSB7XHJcbiAgICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiQXV0aGVudGljYXRpb24gZmFpbGVkLiBcIiArIHJlc3Auc3RhdHVzICsgXCI6IFwiICsgcmVzcC5zdGF0dXNUZXh0KTtcclxuICAgICAgfVxyXG4gICAgfSksXHJcbiAgICAgIGNhdGNoRXJyb3IodGhpcy5oYW5kbGVFcnJvcikpO1xyXG4gIH1cclxuXHJcblxyXG4gIGNsZWFyTG9naW4oKTogT2JzZXJ2YWJsZTxSZXNwb25zZT4ge1xyXG4gICAgLy9Gcm9udC1lbmQgbG9nb3V0XHJcbiAgICB0cnkge1xyXG4gICAgICB0aGlzLl9sb2NhbFN0b3JhZ2VTZXJ2aWNlLnJlbW92ZUl0ZW0odGhpcy5hdXRoZW50aWNhdGlvblByb3ZpZGVyLmF1dGhlbnRpY2F0aW9uVG9rZW5LZXkpO1xyXG4gICAgICB0aGlzLnVuc3Vic2NyaWJlRnJvbVRva2VuUmVmcmVzaCgpO1xyXG4gICAgICB0aGlzLl9pc0F1dGhlbnRpY2F0ZWRTdWJqZWN0Lm5leHQoZmFsc2UpO1xyXG4gICAgICB0aGlzLl91c2VySXNBYm91dFRvVGltZU91dC5uZXh0KGZhbHNlKTtcclxuICAgIH0gY2F0Y2ggKEVycm9yKSB7XHJcbiAgICB9XHJcblxyXG4gICAgLy9CYWNrLWVuZCBsb2dvdXRcclxuICAgIGxldCBoZWFkZXJzID0gbmV3IEh0dHBIZWFkZXJzKCkuc2V0KEF1dGhlbnRpY2F0aW9uU2VydmljZS5DT05URU5UX1RZUEUsIFwidGV4dC9wbGFpblwiKTtcclxuICAgIHJldHVybiA8T2JzZXJ2YWJsZTxSZXNwb25zZT4+dGhpcy5faHR0cC5nZXQodGhpcy5sb2dvdXRMb2NhdGlvbigpLCB7aGVhZGVyczogaGVhZGVyc30pO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogQSBmdW5jdGlvbiB0byBzaWduYWwgdGhlIHRlcm1pbmF0aW9uIG9mIHRoZSBjdXJyZW50IHNlc3Npb24uIEludm9raW5nIHRoaXMgZnVuY3Rpb24gd2lsbCBjbGVhbiB1cCBhbnkgcmVsZXZhbnQgc3RhdGVcclxuICAgKiByZWxhdGVkIHRvIHRoZSBsYXN0IGFjdGl2ZSBzZXNzaW9uLlxyXG4gICAqL1xyXG4gIGxvZ291dChrZWVwQ3VycmVudFJvdXRlOiBib29sZWFuID0gZmFsc2UpOiB2b2lkIHtcclxuICAgIC8vUHJldmVudCBsb2dvdXQgaWYgYWxyZWFkeSBvbiBhdXRoZW50aWNhdGlvbiByb3V0ZS4gRG9pbmcgb3RoZXJ3aXNlIHNjcmV3cyB1cCBTQU1MXHJcbiAgICBpZiAoISB0aGlzLl9yb3V0ZXIucm91dGVyU3RhdGUgfHwgdGhpcy5fcm91dGVyLnJvdXRlclN0YXRlLnNuYXBzaG90LnVybCAhPT0gdGhpcy5fYXV0aGVudGljYXRpb25Sb3V0ZSkge1xyXG4gICAgICB0aGlzLl9yZWRpcmVjdFVybCA9IChrZWVwQ3VycmVudFJvdXRlICYmIHRoaXMuX3JvdXRlci5yb3V0ZXJTdGF0ZSAmJiB0aGlzLl9yb3V0ZXIucm91dGVyU3RhdGUuc25hcHNob3QpID8gdGhpcy5fcm91dGVyLnJvdXRlclN0YXRlLnNuYXBzaG90LnVybCA6IFwiXCI7XHJcblxyXG4gICAgICBpZiAodGhpcy5fcmVkaXJlY3RVcmwuc3RhcnRzV2l0aChcIi9cIikpIHtcclxuICAgICAgICB0aGlzLl9yZWRpcmVjdFVybCA9IHRoaXMuX3JlZGlyZWN0VXJsLnN1YnN0cmluZygxKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgdGhpcy5jbGVhckxvZ2luKCkuc3Vic2NyaWJlKFxyXG4gICAgICAgIChyZXNwb25zZSkgPT4ge1xyXG4gICAgICAgICAgd2luZG93LmxvY2F0aW9uLnJlcGxhY2UodGhpcy5fcmVkaXJlY3RVcmwpO1xyXG4gICAgICAgICAgfSxcclxuICAgICAgICAoZXJyb3IpID0+IHtcclxuICAgICAgICAgIHdpbmRvdy5sb2NhdGlvbi5yZXBsYWNlKHRoaXMuX3JlZGlyZWN0VXJsKTtcclxuICAgICAgICB9XHJcbiAgICAgICk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBzdG9yZVRva2VuKHRva2VuOiBzdHJpbmcpOiB2b2lkIHtcclxuICAgIGxldCB2YWxpZCA9IHRoaXMudmFsaWRhdGVUb2tlbih0b2tlbik7XHJcblxyXG4gICAgLy8gdW5zdWJzY3JpYmUgZnJvbSByZWZlc2ggYmVmb3JlIHdlIGRlY2lkZSB3ZXRoZXIgdG8gcmVzdWJzY3JpYmVcclxuICAgIHRoaXMudW5zdWJzY3JpYmVGcm9tVG9rZW5SZWZyZXNoKCk7XHJcblxyXG4gICAgaWYgKHZhbGlkKSB7XHJcbiAgICAgIHRoaXMuX2xvY2FsU3RvcmFnZVNlcnZpY2Uuc2V0SXRlbSh0aGlzLmF1dGhlbnRpY2F0aW9uUHJvdmlkZXIuYXV0aGVudGljYXRpb25Ub2tlbktleSwgdG9rZW4pO1xyXG4gICAgICB0aGlzLnN1YnNjcmliZVRvVG9rZW5SZWZyZXNoKHRva2VuKTtcclxuXHJcbiAgICAgIC8vQ2hhbmdlIHRoZSBCZWhhdmlvclN1YmplY3QgaWYgdGhlIHVzZXIgd2FzIG5vdCBwcmV2aW91c2x5IGF1dGhlbnRpY2F0ZWQuXHJcbiAgICAgIC8vU2luY2Ugb3RoZXIgY29kZSBtYXkgYmUgc3Vic2NyaWJpbmcgdG8gdGhpcyBvYnNlcnZhYmxlLCB3ZSBkb24ndCB3YW50IHRvIGNhdXNlIG5ldyBldmVudHMgdG8gZmlyZSBpZiBqdXN0IHJlZnJlc2hpbmcgdGhlIEpXVC5cclxuICAgICAgaWYgKCEgdGhpcy5faXNBdXRoZW50aWNhdGVkU3ViamVjdC52YWx1ZSkge1xyXG4gICAgICAgIHRoaXMuX2lzQXV0aGVudGljYXRlZFN1YmplY3QubmV4dCh0cnVlKTtcclxuICAgICAgfVxyXG4gICAgfSBlbHNlIHtcclxuICAgICAgdGhpcy5fbG9jYWxTdG9yYWdlU2VydmljZS5yZW1vdmVJdGVtKHRoaXMuYXV0aGVudGljYXRpb25Qcm92aWRlci5hdXRoZW50aWNhdGlvblRva2VuS2V5KTtcclxuICAgICAgdGhpcy5faXNBdXRoZW50aWNhdGVkU3ViamVjdC5uZXh0KGZhbHNlKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIHByb2NlZWRJZkF1dGhlbnRpY2F0ZWQoKTogYm9vbGVhbiB7XHJcbiAgICBpZiAoaXNEZXZNb2RlKCkpIHtcclxuICAgICAgY29uc29sZS5kZWJ1ZyhcIkF1dGhlbnRpY2F0aW9uU2VydmljZS5wcm9jZWVkSWZBdXRoZW50aWNhdGVkOiBcIiArIHRoaXMuX3JlZGlyZWN0VXJsKTtcclxuICAgIH1cclxuXHJcbiAgICBpZiAodGhpcy5faXNBdXRoZW50aWNhdGVkU3ViamVjdC52YWx1ZSkge1xyXG4gICAgICAvL0xvZ2luIGNvdW50cyBhcyB1c2VyIGFjdGl2aXR5LCB0b29cclxuICAgICAgdGhpcy51cGRhdGVVc2VyQWN0aXZpdHkoKTtcclxuXHJcbiAgICAgIGlmICh0aGlzLl9yZWRpcmVjdFVybCAmJiB0aGlzLl9yZWRpcmVjdFVybCAmJiB0aGlzLl9yZWRpcmVjdFVybCAhPT0gXCJcIikge1xyXG4gICAgICAgIHRoaXMuX3JvdXRlci5uYXZpZ2F0ZUJ5VXJsKHRoaXMuX3JlZGlyZWN0VXJsKTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICB0aGlzLl9yb3V0ZXIubmF2aWdhdGUoW1wiXCJdKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICB2YWxpZGF0ZVRva2VuKHRva2VuOiBzdHJpbmcpOiBib29sZWFuIHtcclxuICAgIHJldHVybiAodG9rZW4gJiYgIXRoaXMuX2p3dEhlbHBlci5pc1Rva2VuRXhwaXJlZCh0b2tlbikpO1xyXG4gIH1cclxuXHJcbiAgc3Vic2NyaWJlVG9Ub2tlblJlZnJlc2godG9rZW46IGFueSk6IHZvaWQge1xyXG4gICAgbGV0IGV4cCA9IHRoaXMuX2p3dEhlbHBlci5nZXRUb2tlbkV4cGlyYXRpb25EYXRlKHRva2VuKTtcclxuXHJcbiAgICAvLyBVc2UgYSB0aW1lciB0byBwZXJpb2RpY2FsbHkgY2hlY2sgdGltZW91dHNcclxuICAgIHRoaXMuX3JlZnJlc2hTdWJzY3JpcHRpb24gPSBpbnRlcnZhbCgxMDAwKVxyXG4gICAgICAuc3Vic2NyaWJlKCgpID0+IHtcclxuXHJcbiAgICAgICAgLy8gSWYgYSB0YWIgaXMgaW5hY3RpdmUgd2UgY2FuJ3Qga25vdyBpZiBvdXIgdGltZXIgaXMgYWNjdXJhdGVcclxuICAgICAgICAvLyBzbyB3aGVuIHRoZSBpbnRlcnZhbCBoaXRzIGNoZWNrIGFnYWluc3QgdGltZXN0YW1wc1xyXG4gICAgICAgIGlmICh0aGlzLl9pc0F1dGhlbnRpY2F0ZWRTdWJqZWN0LnZhbHVlICYmIERhdGUubm93KCkgPiB0aGlzLmdldFRpbWVvdXRTdGFydCgpKSB7XHJcbiAgICAgICAgICAvL0Rvbid0IHVwZGF0ZSB0aGUgc3ViamVjdCBtb3JlIHRoYW4gb25jZSEgRG9pbmcgc28gaW5pdGlhbGl6ZXMgbW9yZSB0aGFuIG9uZSBjb3VudGRvd24gdGltZXIhXHJcbiAgICAgICAgICBpZiAodGhpcy5fdXNlcklzQWJvdXRUb1RpbWVPdXQuZ2V0VmFsdWUoKSAhPT0gdHJ1ZSkge1xyXG4gICAgICAgICAgICB0aGlzLl91c2VySXNBYm91dFRvVGltZU91dC5uZXh0KHRydWUpO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gY2hlY2sgZm9yIHJlZnJlc2ggdG9rZW5cclxuICAgICAgICBsZXQgbXNUb0V4cGlyeSA9IChleHAudmFsdWVPZigpIC0gbmV3IERhdGUoKS52YWx1ZU9mKCkpO1xyXG5cclxuICAgICAgICAvLyBSZWZyZXNoIDYwIHNlY29uZHMgYmVmb3JlIGV4cGlyeVxyXG4gICAgICAgIGlmIChtc1RvRXhwaXJ5IDw9IDYwMDAwKSB7XHJcbiAgICAgICAgICB0aGlzLnJlZnJlc2hUb2tlbklmVXNlcklzQWN0aXZlKCk7XHJcbiAgICAgICAgfVxyXG4gICAgICB9KTtcclxuICB9XHJcblxyXG4gIHVuc3Vic2NyaWJlRnJvbVRva2VuUmVmcmVzaCgpOiB2b2lkIHtcclxuICAgIGlmICh0aGlzLl9yZWZyZXNoU3Vic2NyaXB0aW9uICYmICEgdGhpcy5fcmVmcmVzaFN1YnNjcmlwdGlvbi5jbG9zZWQpIHtcclxuICAgICAgdGhpcy5fcmVmcmVzaFN1YnNjcmlwdGlvbi51bnN1YnNjcmliZSgpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgZ2V0TWF4Vmlld1Blcm1pc3Npb24oKTogXCJ2aWV3XCIgfCBcInZpZXdpZGVudFwiIHwgXCJ2aWV3bGltaXRlZFwiIHtcclxuICAgIHJldHVybiB0aGlzLm1heFZpZXdQZXJtaXNzaW9uLmdldFZhbHVlKCk7XHJcbiAgfVxyXG5cclxuICBnZXRNYXhWaWV3UGVybWlzc2lvblN1YmplY3QoKTogQmVoYXZpb3JTdWJqZWN0PFwidmlld1wiIHwgXCJ2aWV3aWRlbnRcIiB8IFwidmlld2xpbWl0ZWRcIj4ge1xyXG4gICAgcmV0dXJuIHRoaXMubWF4Vmlld1Blcm1pc3Npb247XHJcbiAgfVxyXG5cclxuICBzZXRNYXhWaWV3UGVybWlzc2lvbihtYXhWaWV3UGVybWlzc2lvbjogXCJ2aWV3XCIgfCBcInZpZXdpZGVudFwiIHwgXCJ2aWV3bGltaXRlZFwiKTogdm9pZCB7XHJcbiAgICB0aGlzLl9sb2NhbFN0b3JhZ2VTZXJ2aWNlLnNldEl0ZW0oXCJtYXhWaWV3UGVybWlzc2lvblwiLCBtYXhWaWV3UGVybWlzc2lvbik7XHJcbiAgICB0aGlzLm1heFZpZXdQZXJtaXNzaW9uLm5leHQobWF4Vmlld1Blcm1pc3Npb24pO1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSByZWZyZXNoVG9rZW5JZlVzZXJJc0FjdGl2ZSgpOiB2b2lkIHtcclxuICAgIC8vT25seSByZWZyZXNoIGlmIHRoZSB1c2VyIGhhcyBiZWVuIGFjdGl2ZVxyXG4gICAgaWYgKHRoaXMuX2xhc3RVc2VySW50ZXJhY3Rpb24gJiYgKChuZXcgRGF0ZSgpLnZhbHVlT2YoKSAtIHRoaXMuX2xhc3RVc2VySW50ZXJhY3Rpb24udmFsdWVPZigpKSA8PSAodGhpcy5fbWF4SW5hY3Rpdml0eU1pbnV0ZXMgKiA2MCAqIDEwMDApKSkge1xyXG4gICAgICB0aGlzLnJlcXVlc3RBY2Nlc3NUb2tlbihmYWxzZSk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIGhhc1ZhbGlkQ29uZmlnKCk6IHZvaWQge1xyXG4gICAgaWYgKHRoaXMuX3Rva2VuRW5kcG9pbnQgPT0gbnVsbCAmJiAodGhpcy5fc2VydmVyVXJsID09PSBudWxsIHx8IHRoaXMuX2xvZ291dFBhdGggPT09IG51bGwpKSB7XHJcbiAgICAgIHRocm93IG5ldyBFcnJvcihcIkJVRyBBTEVSVCEgSW52YWxpZCBBdXRoZW50aWNhdGlvblNlcnZpY2UgY29uZmlndXJhdGlvbi4gTm8gdmFsaWQgY29uZmlndXJhdGlvbiBmb3IgYXV0aGVudGljYXRpb24gZW5kcG9pbnQocykuXCIpO1xyXG4gICAgfVxyXG4gICAgaWYgKHRoaXMuX2xvY2FsU3RvcmFnZVNlcnZpY2UgPT09IG51bGwgfHwgdGhpcy5hdXRoZW50aWNhdGlvblByb3ZpZGVyLmF1dGhlbnRpY2F0aW9uVG9rZW5LZXkgPT09IG51bGwpIHtcclxuICAgICAgdGhyb3cgbmV3IEVycm9yKFwiQlVHIEFMRVJUISBJbnZhbGlkIEF1dGhlbnRpY2F0aW9uU2VydmljZSBjb25maWd1cmF0aW9uLiBObyB2YWxpZCBjb25maWd1cmF0aW9uIGZvciBsb2NhbCBzdG9yYWdlXCIpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBoYW5kbGVFcnJvcihlcnJvcjogYW55KSA6IE9ic2VydmFibGU8bmV2ZXI+IHtcclxuICAgIGxldCBlcnJNc2cgPSAoZXJyb3IubWVzc2FnZSkgPyBlcnJvci5tZXNzYWdlIDogQXV0aGVudGljYXRpb25TZXJ2aWNlLkdFTkVSSUNfRVJSX01TRztcclxuICAgIHJldHVybiB0aHJvd0Vycm9yKGVyck1zZyk7XHJcbiAgfVxyXG59XHJcbiJdfQ==
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 let AUTHENTICATION_SERVER_URL = new InjectionToken("authentication_server_rest_api");
26
+ export let AUTHENTICATION_LOGOUT_PATH = new InjectionToken("authentication_logout_path");
27
+ export let AUTHENTICATION_DIRECT_ENDPOINT = new InjectionToken("authentication_direct_endpoint");
28
+ export let AUTHENTICATION_TOKEN_ENDPOINT = new InjectionToken("authentication_token_endpoint");
29
+ export let AUTHENTICATION_ROUTE = new InjectionToken("authentication_route");
30
+ export let AUTHENTICATION_MAX_INACTIVITY_MINUTES = new InjectionToken("authentication_max_inactivity");
31
+ export let AUTHENTICATION_USER_COUNTDOWN_SECONDS = new InjectionToken("authentication_user_countdown_seconds");
32
+ export let AUTHENTICATION_IDP_INACTIVITY_MINUTES = new InjectionToken("authentication_idp_inactivity_minutes");
33
+ /**
34
+ * @since 1.0.0
35
+ */
36
+ export class AuthenticationService {
37
+ /**
38
+ * The generic error message used when a server error is thrown without a status.
39
+ *
40
+ * @type {string}
41
+ */
42
+ static { this.GENERIC_ERR_MSG = "Server error"; }
43
+ static { this.CONTENT_TYPE = "Content-Type"; }
44
+ static { this.SEC_GOV_CLASS_HEADER = "SecurityGovernorClass"; }
45
+ static { this.SEC_GOV_ID_HEADER = "SecurityGovernorId"; }
46
+ static { this.DEIDENT_HEADER = "DeidentifiedContext"; }
47
+ static { this.LIMITED_HEADER = "LimitedContext"; }
48
+ constructor(_http, _router, _localStorageService, _jwtHelper, authenticationProvider, _authenticationRoute, _logoutPath, _tokenEndpoint, _serverUrl, _directEndpoint, _maxInactivity, _userCountdownSeconds, _idpInactivityMinutes, locationStrategy) {
49
+ this._http = _http;
50
+ this._router = _router;
51
+ this._localStorageService = _localStorageService;
52
+ this._jwtHelper = _jwtHelper;
53
+ this.authenticationProvider = authenticationProvider;
54
+ this._authenticationRoute = _authenticationRoute;
55
+ this._logoutPath = _logoutPath;
56
+ this._tokenEndpoint = _tokenEndpoint;
57
+ this._serverUrl = _serverUrl;
58
+ this._directEndpoint = _directEndpoint;
59
+ this._maxInactivity = _maxInactivity;
60
+ this._userCountdownSeconds = _userCountdownSeconds;
61
+ this._idpInactivityMinutes = _idpInactivityMinutes;
62
+ this.locationStrategy = locationStrategy;
63
+ this.userCountdownSeconds = 60;
64
+ this.idpInactivityMinutes = 5;
65
+ this.contentType = "application/json";
66
+ this.limitedContext = false;
67
+ this.deidentifiedContext = false;
68
+ this.maxViewPermission = new BehaviorSubject("viewident");
69
+ this._isAuthenticatedSubject = new BehaviorSubject(false);
70
+ this._userIsAboutToTimeOut = new BehaviorSubject(false);
71
+ this._maxInactivityMinutes = 120;
72
+ this.contextRoot = "";
73
+ if (isDevMode()) {
74
+ console.debug("window.location.href: " + window.location.href);
75
+ }
76
+ if (window.location) {
77
+ let parts = window.location.href.split("/");
78
+ this.baseUrl = parts[0] + "//" + parts[2];
79
+ if (parts.length > 3) {
80
+ this.contextRoot = parts[3];
81
+ }
82
+ }
83
+ if (this._localStorageService.getItem("maxViewPermission")) {
84
+ this.maxViewPermission.next(this._localStorageService.getItem("maxViewPermission"));
85
+ }
86
+ if (_maxInactivity) {
87
+ this._maxInactivityMinutes = _maxInactivity;
88
+ }
89
+ if (_userCountdownSeconds) {
90
+ this.userCountdownSeconds = _userCountdownSeconds;
91
+ }
92
+ if (_idpInactivityMinutes) {
93
+ this.idpInactivityMinutes = _idpInactivityMinutes;
94
+ }
95
+ this.hasValidConfig();
96
+ //There could be a non-expired token in local storage.
97
+ let token = this.authenticationProvider.authToken;
98
+ this.storeToken(token);
99
+ }
100
+ getBaseUrl() {
101
+ return (this.baseUrl) ? this.baseUrl : "";
102
+ }
103
+ getContextRoot() {
104
+ return this.contextRoot;
105
+ }
106
+ getHeaders(req) {
107
+ let headers = req.headers;
108
+ //Don't set content type if already set
109
+ if (!req.headers.get(AuthenticationService.CONTENT_TYPE)) {
110
+ headers = headers.set(AuthenticationService.CONTENT_TYPE, this.contentType.toString());
111
+ }
112
+ if (headers.get(AuthenticationService.SEC_GOV_CLASS_HEADER) === "") {
113
+ headers = headers.delete(AuthenticationService.SEC_GOV_CLASS_HEADER);
114
+ }
115
+ else if (this.securityGovernorClass && !headers.get(AuthenticationService.SEC_GOV_CLASS_HEADER)) {
116
+ headers = headers.set(AuthenticationService.SEC_GOV_CLASS_HEADER, this.securityGovernorClass);
117
+ }
118
+ if (headers.get(AuthenticationService.SEC_GOV_ID_HEADER) === "") {
119
+ headers = headers.delete(AuthenticationService.SEC_GOV_ID_HEADER);
120
+ }
121
+ else if (this.securityGovernorId && !headers.get(AuthenticationService.SEC_GOV_ID_HEADER)) {
122
+ headers = headers.set(AuthenticationService.SEC_GOV_ID_HEADER, this.securityGovernorId.toString());
123
+ }
124
+ headers = headers.set(AuthenticationService.DEIDENT_HEADER, this.deidentifiedContext.toString());
125
+ headers = headers.set(AuthenticationService.LIMITED_HEADER, this.limitedContext.toString());
126
+ return headers;
127
+ }
128
+ get authenticationTokenKey() {
129
+ return this.authenticationProvider.authenticationTokenKey;
130
+ }
131
+ get authToken() {
132
+ return this.authenticationProvider.authToken;
133
+ }
134
+ updateUserActivity() {
135
+ if (this._isAuthenticatedSubject.value) {
136
+ this._lastUserInteraction = new Date();
137
+ this._userIsAboutToTimeOut.next(false);
138
+ }
139
+ }
140
+ /**
141
+ * A mutator for identifying the clients original request location. Setting this value will influence the end location
142
+ * navigated to by {@link #navigateToPath}.
143
+ *
144
+ * @param redirectUrl location of the users request before authentication
145
+ */
146
+ set redirectUrl(redirectUrl) {
147
+ this._redirectUrl = redirectUrl;
148
+ }
149
+ get redirectUrl() {
150
+ return this._redirectUrl;
151
+ }
152
+ requestAccessToken(redirectOnSuccess) {
153
+ this._http.get(this.tokenLocation(), { withCredentials: true })
154
+ .subscribe((response) => {
155
+ this.storeToken(response.auth_token);
156
+ if (redirectOnSuccess) {
157
+ this.proceedIfAuthenticated();
158
+ }
159
+ }, (error) => {
160
+ //Token refresh failed.
161
+ this.logout(true);
162
+ });
163
+ }
164
+ /**
165
+ * Verifies whether or not a current user session exists.
166
+ *
167
+ * @returns {Observable<boolean>} evaluates to true if the user is authenticated, false otherwise.
168
+ */
169
+ isAuthenticated() {
170
+ return this._isAuthenticatedSubject.asObservable();
171
+ }
172
+ isAboutToTimeOut() {
173
+ return this._userIsAboutToTimeOut.asObservable();
174
+ }
175
+ getTimeoutStart() {
176
+ if (this._lastUserInteraction) {
177
+ return this._lastUserInteraction.valueOf() + (((this._maxInactivityMinutes * 60) - this.userCountdownSeconds) * 1000);
178
+ }
179
+ }
180
+ tokenLocation() {
181
+ if (this._serverUrl) {
182
+ return this._serverUrl + this._tokenEndpoint;
183
+ }
184
+ else {
185
+ return this._tokenEndpoint;
186
+ }
187
+ }
188
+ directLoginLocation() {
189
+ if (this._serverUrl) {
190
+ return this._serverUrl + this._directEndpoint;
191
+ }
192
+ else {
193
+ return this._directEndpoint;
194
+ }
195
+ }
196
+ logoutLocation() {
197
+ if (this._serverUrl) {
198
+ return this._serverUrl + this._logoutPath;
199
+ }
200
+ else {
201
+ return this._logoutPath;
202
+ }
203
+ }
204
+ /**
205
+ * A function to authenticated the user with the provided credentials. Failure results in an error that describes the
206
+ * server response (status and status message) and should be actionable by the client application.
207
+ *
208
+ * @param username of the authenticating user to verify
209
+ * @param password of the authenticating user to verify
210
+ * @returns {Observable<R>} describing the result of the login action, true or an error
211
+ */
212
+ login(_username, _password) {
213
+ return this._http.post(this.directLoginLocation(), { username: _username, password: _password }, { observe: "response" }).pipe(map((resp) => {
214
+ if (resp.status === 201) {
215
+ return true;
216
+ }
217
+ else {
218
+ throw new Error("Authentication failed. " + resp.status + ": " + resp.statusText);
219
+ }
220
+ }), catchError(this.handleError));
221
+ }
222
+ clearLogin() {
223
+ //Front-end logout
224
+ try {
225
+ this._localStorageService.removeItem(this.authenticationProvider.authenticationTokenKey);
226
+ this.unsubscribeFromTokenRefresh();
227
+ this._isAuthenticatedSubject.next(false);
228
+ this._userIsAboutToTimeOut.next(false);
229
+ }
230
+ catch (Error) {
231
+ }
232
+ //Back-end logout
233
+ let headers = new HttpHeaders().set(AuthenticationService.CONTENT_TYPE, "text/plain");
234
+ return this._http.get(this.logoutLocation(), { headers: headers });
235
+ }
236
+ /**
237
+ * A function to signal the termination of the current session. Invoking this function will clean up any relevant state
238
+ * related to the last active session.
239
+ */
240
+ logout(keepCurrentRoute = false) {
241
+ //Prevent logout if already on authentication route. Doing otherwise screws up SAML
242
+ if (!this._router.routerState || this._router.routerState.snapshot.url !== this._authenticationRoute) {
243
+ this._redirectUrl = (keepCurrentRoute && this._router.routerState && this._router.routerState.snapshot) ? this._router.routerState.snapshot.url : "";
244
+ if (this._redirectUrl.startsWith("/")) {
245
+ this._redirectUrl = this._redirectUrl.substring(1);
246
+ }
247
+ this.clearLogin().subscribe((response) => {
248
+ window.location.replace(this._redirectUrl);
249
+ }, (error) => {
250
+ window.location.replace(this._redirectUrl);
251
+ });
252
+ }
253
+ }
254
+ storeToken(token) {
255
+ let valid = this.validateToken(token);
256
+ // unsubscribe from refesh before we decide wether to resubscribe
257
+ this.unsubscribeFromTokenRefresh();
258
+ if (valid) {
259
+ this._localStorageService.setItem(this.authenticationProvider.authenticationTokenKey, token);
260
+ this.subscribeToTokenRefresh(token);
261
+ //Change the BehaviorSubject if the user was not previously authenticated.
262
+ //Since other code may be subscribing to this observable, we don't want to cause new events to fire if just refreshing the JWT.
263
+ if (!this._isAuthenticatedSubject.value) {
264
+ this._isAuthenticatedSubject.next(true);
265
+ }
266
+ }
267
+ else {
268
+ this._localStorageService.removeItem(this.authenticationProvider.authenticationTokenKey);
269
+ this._isAuthenticatedSubject.next(false);
270
+ }
271
+ }
272
+ proceedIfAuthenticated() {
273
+ if (isDevMode()) {
274
+ console.debug("AuthenticationService.proceedIfAuthenticated: " + this._redirectUrl);
275
+ }
276
+ if (this._isAuthenticatedSubject.value) {
277
+ //Login counts as user activity, too
278
+ this.updateUserActivity();
279
+ if (this._redirectUrl && this._redirectUrl && this._redirectUrl !== "") {
280
+ this._router.navigateByUrl(this._redirectUrl);
281
+ }
282
+ else {
283
+ this._router.navigate([""]);
284
+ }
285
+ return true;
286
+ }
287
+ else {
288
+ return false;
289
+ }
290
+ }
291
+ validateToken(token) {
292
+ return (token && !this._jwtHelper.isTokenExpired(token));
293
+ }
294
+ subscribeToTokenRefresh(token) {
295
+ let exp = this._jwtHelper.getTokenExpirationDate(token);
296
+ // Use a timer to periodically check timeouts
297
+ this._refreshSubscription = interval(1000)
298
+ .subscribe(() => {
299
+ // If a tab is inactive we can't know if our timer is accurate
300
+ // so when the interval hits check against timestamps
301
+ if (this._isAuthenticatedSubject.value && Date.now() > this.getTimeoutStart()) {
302
+ //Don't update the subject more than once! Doing so initializes more than one countdown timer!
303
+ if (this._userIsAboutToTimeOut.getValue() !== true) {
304
+ this._userIsAboutToTimeOut.next(true);
305
+ }
306
+ }
307
+ // check for refresh token
308
+ let msToExpiry = (exp.valueOf() - new Date().valueOf());
309
+ // Refresh 60 seconds before expiry
310
+ if (msToExpiry <= 60000) {
311
+ this.refreshTokenIfUserIsActive();
312
+ }
313
+ });
314
+ }
315
+ unsubscribeFromTokenRefresh() {
316
+ if (this._refreshSubscription && !this._refreshSubscription.closed) {
317
+ this._refreshSubscription.unsubscribe();
318
+ }
319
+ }
320
+ getMaxViewPermission() {
321
+ return this.maxViewPermission.getValue();
322
+ }
323
+ getMaxViewPermissionSubject() {
324
+ return this.maxViewPermission;
325
+ }
326
+ setMaxViewPermission(maxViewPermission) {
327
+ this._localStorageService.setItem("maxViewPermission", maxViewPermission);
328
+ this.maxViewPermission.next(maxViewPermission);
329
+ }
330
+ refreshTokenIfUserIsActive() {
331
+ //Only refresh if the user has been active
332
+ if (this._lastUserInteraction && ((new Date().valueOf() - this._lastUserInteraction.valueOf()) <= (this._maxInactivityMinutes * 60 * 1000))) {
333
+ this.requestAccessToken(false);
334
+ }
335
+ }
336
+ hasValidConfig() {
337
+ if (this._tokenEndpoint == null && (this._serverUrl === null || this._logoutPath === null)) {
338
+ throw new Error("BUG ALERT! Invalid AuthenticationService configuration. No valid configuration for authentication endpoint(s).");
339
+ }
340
+ if (this._localStorageService === null || this.authenticationProvider.authenticationTokenKey === null) {
341
+ throw new Error("BUG ALERT! Invalid AuthenticationService configuration. No valid configuration for local storage");
342
+ }
343
+ }
344
+ handleError(error) {
345
+ let errMsg = (error.message) ? error.message : AuthenticationService.GENERIC_ERR_MSG;
346
+ return throwError(errMsg);
347
+ }
348
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.1.2", 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 }); }
349
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: AuthenticationService }); }
350
+ }
351
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: AuthenticationService, decorators: [{
352
+ type: Injectable
353
+ }], ctorParameters: () => [{ type: i1.HttpClient }, { type: i2.Router }, { type: i3.CoolLocalStorage }, { type: i4.JwtHelperService }, { type: i5.AuthenticationProvider }, { type: undefined, decorators: [{
354
+ type: Inject,
355
+ args: [AUTHENTICATION_ROUTE]
356
+ }] }, { type: undefined, decorators: [{
357
+ type: Inject,
358
+ args: [AUTHENTICATION_LOGOUT_PATH]
359
+ }] }, { type: undefined, decorators: [{
360
+ type: Inject,
361
+ args: [AUTHENTICATION_TOKEN_ENDPOINT]
362
+ }] }, { type: undefined, decorators: [{
363
+ type: Optional
364
+ }, {
365
+ type: Inject,
366
+ args: [AUTHENTICATION_SERVER_URL]
367
+ }] }, { type: undefined, decorators: [{
368
+ type: Optional
369
+ }, {
370
+ type: Inject,
371
+ args: [AUTHENTICATION_DIRECT_ENDPOINT]
372
+ }] }, { type: undefined, decorators: [{
373
+ type: Optional
374
+ }, {
375
+ type: Inject,
376
+ args: [AUTHENTICATION_MAX_INACTIVITY_MINUTES]
377
+ }] }, { type: undefined, decorators: [{
378
+ type: Optional
379
+ }, {
380
+ type: Inject,
381
+ args: [AUTHENTICATION_USER_COUNTDOWN_SECONDS]
382
+ }] }, { type: undefined, decorators: [{
383
+ type: Optional
384
+ }, {
385
+ type: Inject,
386
+ args: [AUTHENTICATION_IDP_INACTIVITY_MINUTES]
387
+ }] }, { type: i6.LocationStrategy, decorators: [{
388
+ type: Optional
389
+ }, {
390
+ type: Inject,
391
+ args: [LocationStrategy]
392
+ }] }] });
393
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXV0aGVudGljYXRpb24uc2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3Byb2plY3RzL2F1dGhlbnRpY2F0aW9uL3NyYy9hdXRoZW50aWNhdGlvbi5zZXJ2aWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOztHQUVHO0FBQ0gsT0FBTyxFQUFDLFVBQVUsRUFBRSxjQUFjLEVBQUUsTUFBTSxFQUFFLFFBQVEsRUFBRSxTQUFTLEVBQUMsTUFBTSxlQUFlLENBQUM7QUFDdEYsT0FBTyxFQUFDLGdCQUFnQixFQUFDLE1BQU0saUJBQWlCLENBQUM7QUFDakQsT0FBTyxFQUFDLE1BQU0sRUFBQyxNQUFNLGlCQUFpQixDQUFDO0FBQ3ZDLE9BQU8sRUFBQyxVQUFVLEVBQUUsV0FBVyxFQUE0QixNQUFNLHNCQUFzQixDQUFDO0FBRXhGLE9BQU8sRUFBQyxRQUFRLEVBQWMsZUFBZSxFQUFnQixVQUFVLEVBQUssTUFBTSxNQUFNLENBQUM7QUFDekYsT0FBTyxFQUFDLFVBQVUsRUFBUyxHQUFHLEVBQUMsTUFBTSxnQkFBZ0IsQ0FBQztBQUN0RCxPQUFPLEVBQUMsZ0JBQWdCLEVBQUMsTUFBTSxvQkFBb0IsQ0FBQztBQUVwRCxPQUFPLEVBQUMsc0JBQXNCLEVBQUMsTUFBTSwyQkFBMkIsQ0FBQztBQUNqRSxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSx1QkFBdUIsQ0FBQzs7Ozs7Ozs7QUFFekQ7Ozs7R0FJRztBQUNILE1BQU0sQ0FBQyxJQUFJLHlCQUF5QixHQUFHLElBQUksY0FBYyxDQUFTLGdDQUFnQyxDQUFDLENBQUM7QUFDcEcsTUFBTSxDQUFDLElBQUksMEJBQTBCLEdBQUcsSUFBSSxjQUFjLENBQVMsNEJBQTRCLENBQUMsQ0FBQztBQUNqRyxNQUFNLENBQUMsSUFBSSw4QkFBOEIsR0FBRyxJQUFJLGNBQWMsQ0FBUyxnQ0FBZ0MsQ0FBQyxDQUFDO0FBQ3pHLE1BQU0sQ0FBQyxJQUFJLDZCQUE2QixHQUFHLElBQUks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QUFROzswQkFBSSxNQUFNOzJCQUFDLHFDQUFxQzs7MEJBQ3hELFFBQVE7OzBCQUFJLE1BQU07MkJBQUMscUNBQXFDOzswQkFDeEQsUUFBUTs7MEJBQUksTUFBTTsyQkFBQyxxQ0FBcUM7OzBCQUN4RCxRQUFROzswQkFBSSxNQUFNOzJCQUFDLGdCQUFnQiIsInNvdXJjZXNDb250ZW50IjpbIi8qXHJcbiAqIENvcHlyaWdodCAoYykgMjAxNiBIdW50c21hbiBDYW5jZXIgSW5zdGl0dXRlIGF0IHRoZSBVbml2ZXJzaXR5IG9mIFV0YWgsIENvbmZpZGVudGlhbCBhbmQgUHJvcHJpZXRhcnlcclxuICovXHJcbmltcG9ydCB7SW5qZWN0YWJsZSwgSW5qZWN0aW9uVG9rZW4sIEluamVjdCwgT3B0aW9uYWwsIGlzRGV2TW9kZX0gZnJvbSBcIkBhbmd1bGFyL2NvcmVcIjtcclxuaW1wb3J0IHtMb2NhdGlvblN0cmF0ZWd5fSBmcm9tIFwiQGFuZ3VsYXIvY29tbW9uXCI7XHJcbmltcG9ydCB7Um91dGVyfSBmcm9tIFwiQGFuZ3VsYXIvcm91dGVyXCI7XHJcbmltcG9ydCB7SHR0cENsaWVudCwgSHR0cEhlYWRlcnMsIEh0dHBSZXF1ZXN0LCBIdHRwUmVzcG9uc2V9IGZyb20gXCJAYW5ndWxhci9jb21tb24vaHR0cFwiO1xyXG5cclxuaW1wb3J0IHtpbnRlcnZhbCwgT2JzZXJ2YWJsZSwgQmVoYXZpb3JTdWJqZWN0LCBTdWJzY3JpcHRpb24sIHRocm93RXJyb3IsIG9mfSBmcm9tIFwicnhqc1wiO1xyXG5pbXBvcnQge2NhdGNoRXJyb3IsIGZpcnN0LCBtYXB9IGZyb20gXCJyeGpzL29wZXJhdG9yc1wiO1xyXG5pbXBvcnQge0p3dEhlbHBlclNlcnZpY2V9IGZyb20gXCJAYXV0aDAvYW5ndWxhci1qd3RcIjtcclxuXHJcbmltcG9ydCB7QXV0aGVudGljYXRpb25Qcm92aWRlcn0gZnJvbSBcIi4vYXV0aGVudGljYXRpb24ucHJvdmlkZXJcIjtcclxuaW1wb3J0IHsgQ29vbExvY2FsU3RvcmFnZSB9IGZyb20gXCJAYW5ndWxhci1jb29sL3N0b3JhZ2VcIjtcclxuXHJcbi8qKlxyXG4gKiBUaGUgdG9rZW4gdXNlZCBmb3IgaW5qZWN0aW9uIG9mIHRoZSBzZXJ2ZXIgc2lkZSBlbmRwb2ludCBmb3IgdGhlIGN1cnJlbnRseSBhdXRoZW50aWNhdGVkIHN1YmplY3QuXHJcbiAqXHJcbiAqIEB0eXBlIHtJbmplY3Rpb25Ub2tlbn1cclxuICovXHJcbmV4cG9ydCBsZXQgQVVUSEVOVElDQVRJT05fU0VSVkVSX1VSTCA9IG5ldyBJbmplY3Rpb25Ub2tlbjxzdHJpbmc+KFwiYXV0aGVudGljYXRpb25fc2VydmVyX3Jlc3RfYXBpXCIpO1xyXG5leHBvcnQgbGV0IEFVVEhFTlRJQ0FUSU9OX0xPR09VVF9QQVRIID0gbmV3IEluamVjdGlvblRva2VuPHN0cmluZz4oXCJhdXRoZW50aWNhdGlvbl9sb2dvdXRfcGF0aFwiKTtcclxuZXhwb3J0IGxldCBBVVRIRU5USUNBVElPTl9ESVJFQ1RfRU5EUE9JTlQgPSBuZXcgSW5qZWN0aW9uVG9rZW48c3RyaW5nPihcImF1dGhlbnRpY2F0aW9uX2RpcmVjdF9lbmRwb2ludFwiKTtcclxuZXhwb3J0IGxldCBBVVRIRU5USUNBVElPTl9UT0tFTl9FTkRQT0lOVCA9IG5ldyBJbmplY3Rpb25Ub2tlbjxzdHJpbmc+KFwiYXV0aGVudGljYXRpb25fdG9rZW5fZW5kcG9pbnRcIik7XHJcbmV4cG9ydCBsZXQgQVVUSEVOVElDQVRJT05fUk9VVEUgPSBuZXcgSW5qZWN0aW9uVG9rZW48c3RyaW5nPihcImF1dGhlbnRpY2F0aW9uX3JvdXRlXCIpO1xyXG5leHBvcnQgbGV0IEFVVEhFTlRJQ0FUSU9OX01BWF9JTkFDVElWSVRZX01JTlVURVMgPSBuZXcgSW5qZWN0aW9uVG9rZW48bnVtYmVyPihcImF1dGhlbnRpY2F0aW9uX21heF9pbmFjdGl2aXR5XCIpO1xyXG5leHBvcnQgbGV0IEFVVEhFTlRJQ0FUSU9OX1VTRVJfQ09VTlRET1dOX1NFQ09ORFMgPSBuZXcgSW5qZWN0aW9uVG9rZW48bnVtYmVyPihcImF1dGhlbnRpY2F0aW9uX3VzZXJfY291bnRkb3duX3NlY29uZHNcIik7XHJcbmV4cG9ydCBsZXQgQVVUSEVOVElDQVRJT05fSURQX0lOQUNUSVZJVFlfTUlOVVRFUyA9IG5ldyBJbmplY3Rpb25Ub2tlbjxudW1iZXI+KFwiYXV0aGVudGljYXRpb25faWRwX2luYWN0aXZpdHlfbWludXRlc1wiKTtcclxuXHJcbi8qKlxyXG4gKiBAc2luY2UgMS4wLjBcclxuICovXHJcbkBJbmplY3RhYmxlKClcclxuZXhwb3J0IGNsYXNzIEF1dGhlbnRpY2F0aW9uU2VydmljZSB7XHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBnZW5lcmljIGVycm9yIG1lc3NhZ2UgdXNlZCB3aGVuIGEgc2VydmVyIGVycm9yIGlzIHRocm93biB3aXRob3V0IGEgc3RhdHVzLlxyXG4gICAqXHJcbiAgICogQHR5cGUge3N0cmluZ31cclxuICAgKi9cclxuICBwdWJsaWMgc3RhdGljIEdFTkVSSUNfRVJSX01TRzogc3RyaW5nID0gXCJTZXJ2ZXIgZXJyb3JcIjtcclxuXHJcbiAgcHJpdmF0ZSBzdGF0aWMgQ09OVEVOVF9UWVBFOiBzdHJpbmcgPSBcIkNvbnRlbnQtVHlwZVwiO1xyXG4gIHByaXZhdGUgc3RhdGljIFNFQ19HT1ZfQ0xBU1NfSEVBREVSOiBzdHJpbmcgPSBcIlNlY3VyaXR5R292ZXJub3JDbGFzc1wiO1xyXG4gIHByaXZhdGUgc3RhdGljIFNFQ19HT1ZfSURfSEVBREVSOiBzdHJpbmcgPSBcIlNlY3VyaXR5R292ZXJub3JJZFwiO1xyXG4gIHByaXZhdGUgc3RhdGljIERFSURFTlRfSEVBREVSOiBzdHJpbmcgPSBcIkRlaWRlbnRpZmllZENvbnRleHRcIjtcclxuICBwcml2YXRlIHN0YXRpYyBMSU1JVEVEX0hFQURFUjogc3RyaW5nID0gXCJMaW1pdGVkQ29udGV4dFwiO1xyXG5cclxuICBwdWJsaWMgdXNlckNvdW50ZG93blNlY29uZHM6IG51bWJlciA9IDYwO1xyXG4gIHB1YmxpYyBpZHBJbmFjdGl2aXR5TWludXRlczogbnVtYmVyID0gNTtcclxuXHJcbiAgcHVibGljIGNvbnRlbnRUeXBlOiBzdHJpbmcgPSBcImFwcGxpY2F0aW9uL2pzb25cIjtcclxuICBwdWJsaWMgc2VjdXJpdHlHb3Zlcm5vckNsYXNzOiBzdHJpbmc7XHJcbiAgcHVibGljIHNlY3VyaXR5R292ZXJub3JJZDogbnVtYmVyO1xyXG4gIHB1YmxpYyBsaW1pdGVkQ29udGV4dDogYm9vbGVhbiA9IGZhbHNlO1xyXG4gIHB1YmxpYyBkZWlkZW50aWZpZWRDb250ZXh0OiBib29sZWFuID0gZmFsc2U7XHJcblxyXG4gIHByaXZhdGUgbWF4Vmlld1Blcm1pc3Npb246IEJlaGF2aW9yU3ViamVjdDxcInZpZXdcIiB8IFwidmlld2lkZW50XCIgfCBcInZpZXdsaW1pdGVkXCI+ID0gbmV3IEJlaGF2aW9yU3ViamVjdDxcInZpZXdcIiB8IFwidmlld2lkZW50XCIgfCBcInZpZXdsaW1pdGVkXCI+KFwidmlld2lkZW50XCIpO1xyXG4gIHByaXZhdGUgX2lzQXV0aGVudGljYXRlZFN1YmplY3Q6IEJlaGF2aW9yU3ViamVjdDxib29sZWFuPiA9IG5ldyBCZWhhdmlvclN1YmplY3Q8Ym9vbGVhbj4oZmFsc2UpO1xyXG4gIHByaXZhdGUgX3VzZXJJc0Fib3V0VG9UaW1lT3V0OiBCZWhhdmlvclN1YmplY3Q8Ym9vbGVhbj4gPSBuZXcgQmVoYXZpb3JTdWJqZWN0PGJvb2xlYW4+KGZhbHNlKTtcclxuICBwcml2YXRlIF9yZWRpcmVjdFVybDogc3RyaW5nO1xyXG4gIHByaXZhdGUgX3JlZnJlc2hTdWJzY3JpcHRpb246IFN1YnNjcmlwdGlvbjtcclxuICBwcml2YXRlIF9sYXN0VXNlckludGVyYWN0aW9uOiBEYXRlO1xyXG4gIHByaXZhdGUgX21heEluYWN0aXZpdHlNaW51dGVzOiBudW1iZXIgPSAxMjA7XHJcblxyXG4gIHByaXZhdGUgYmFzZVVybDogc3RyaW5nO1xyXG4gIHByaXZhdGUgY29udGV4dFJvb3Q6IHN0cmluZyA9IFwiXCI7XHJcblxyXG4gIGNvbnN0cnVjdG9yKHByaXZhdGUgX2h0dHA6IEh0dHBDbGllbnQsXHJcbiAgICAgICAgICAgICAgcHJpdmF0ZSBfcm91dGVyOiBSb3V0ZXIsXHJcbiAgICAgICAgICAgICAgcHJpdmF0ZSBfbG9jYWxTdG9yYWdlU2VydmljZTogQ29vbExvY2FsU3RvcmFnZSxcclxuICAgICAgICAgICAgICBwcml2YXRlIF9qd3RIZWxwZXI6IEp3dEhlbHBlclNlcnZpY2UsXHJcbiAgICAgICAgICAgICAgcHJpdmF0ZSBhdXRoZW50aWNhdGlvblByb3ZpZGVyOiBBdXRoZW50aWNhdGlvblByb3ZpZGVyLFxyXG4gICAgICAgICAgICAgIEBJbmplY3QoQVVUSEVOVElDQVRJT05fUk9VVEUpIHByaXZhdGUgX2F1dGhlbnRpY2F0aW9uUm91dGU6IHN0cmluZyxcclxuICAgICAgICAgICAgICBASW5qZWN0KEFVVEhFTlRJQ0FUSU9OX0xPR09VVF9QQVRIKSBwcml2YXRlIF9sb2dvdXRQYXRoOiBzdHJpbmcsXHJcbiAgICAgICAgICAgICAgQEluamVjdChBVVRIRU5USUNBVElPTl9UT0tFTl9FTkRQT0lOVCkgcHJpdmF0ZSBfdG9rZW5FbmRwb2ludDogc3RyaW5nLFxyXG4gICAgICAgICAgICAgIEBPcHRpb25hbCgpIEBJbmplY3QoQVVUSEVOVElDQVRJT05fU0VSVkVSX1VSTCkgcHJpdmF0ZSBfc2VydmVyVXJsOiBzdHJpbmcsXHJcbiAgICAgICAgICAgICAgQE9wdGlvbmFsKCkgQEluamVjdChBVVRIRU5USUNBVElPTl9ESVJFQ1RfRU5EUE9JTlQpIHByaXZhdGUgX2RpcmVjdEVuZHBvaW50OiBzdHJpbmcsXHJcbiAgICAgICAgICAgICAgQE9wdGlvbmFsKCkgQEluamVjdChBVVRIRU5USUNBVElPTl9NQVhfSU5BQ1RJVklUWV9NSU5VVEVTKSBwcml2YXRlIF9tYXhJbmFjdGl2aXR5OiBudW1iZXIsXHJcbiAgICAgICAgICAgICAgQE9wdGlvbmFsKCkgQEluamVjdChBVVRIRU5USUNBVElPTl9VU0VSX0NPVU5URE9XTl9TRUNPTkRTKSBwcml2YXRlIF91c2VyQ291bnRkb3duU2Vjb25kczogbnVtYmVyLFxyXG4gICAgICAgICAgICAgIEBPcHRpb25hbCgpIEBJbmplY3QoQVVUSEVOVElDQVRJT05fSURQX0lOQUNUSVZJVFlfTUlOVVRFUykgcHJpdmF0ZSBfaWRwSW5hY3Rpdml0eU1pbnV0ZXM6IG51bWJlcixcclxuICAgICAgICAgICAgICBAT3B0aW9uYWwoKSBASW5qZWN0KExvY2F0aW9uU3RyYXRlZ3kpIHByaXZhdGUgbG9jYXRpb25TdHJhdGVneTogTG9jYXRpb25TdHJhdGVneSkge1xyXG4gICAgaWYgKGlzRGV2TW9kZSgpKSB7XHJcbiAgICAgIGNvbnNvbGUuZGVidWcoXCJ3aW5kb3cubG9jYXRpb24uaHJlZjogXCIgKyB3aW5kb3cubG9jYXRpb24uaHJlZik7XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKHdpbmRvdy5sb2NhdGlvbikge1xyXG4gICAgICBsZXQgcGFydHM6IHN0cmluZ1tdID0gd2luZG93LmxvY2F0aW9uLmhyZWYuc3BsaXQoXCIvXCIpO1xyXG4gICAgICB0aGlzLmJhc2VVcmwgPSBwYXJ0c1swXSArIFwiLy9cIiArIHBhcnRzWzJdO1xyXG4gICAgICBpZiAocGFydHMubGVuZ3RoID4gMykge1xyXG4gICAgICAgIHRoaXMuY29udGV4dFJvb3QgPSBwYXJ0c1szXTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIGlmICh0aGlzLl9sb2NhbFN0b3JhZ2VTZXJ2aWNlLmdldEl0ZW0oXCJtYXhWaWV3UGVybWlzc2lvblwiKSkge1xyXG4gICAgICB0aGlzLm1heFZpZXdQZXJtaXNzaW9uLm5leHQoPFwidmlld1wiIHwgXCJ2aWV3aWRlbnRcIiB8IFwidmlld2xpbWl0ZWRcIj50aGlzLl9sb2NhbFN0b3JhZ2VTZXJ2aWNlLmdldEl0ZW0oXCJtYXhWaWV3UGVybWlzc2lvblwiKSk7XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKF9tYXhJbmFjdGl2aXR5KSB7XHJcbiAgICAgIHRoaXMuX21heEluYWN0aXZpdHlNaW51dGVzID0gX21heEluYWN0aXZpdHk7XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKF91c2VyQ291bnRkb3duU2Vjb25kcykge1xyXG4gICAgICB0aGlzLnVzZXJDb3VudGRvd25TZWNvbmRzID0gX3VzZXJDb3VudGRvd25TZWNvbmRzO1xyXG4gICAgfVxyXG5cclxuICAgIGlmIChfaWRwSW5hY3Rpdml0eU1pbnV0ZXMpIHtcclxuICAgICAgdGhpcy5pZHBJbmFjdGl2aXR5TWludXRlcyA9IF9pZHBJbmFjdGl2aXR5TWludXRlcztcclxuICAgIH1cclxuXHJcbiAgICB0aGlzLmhhc1ZhbGlkQ29uZmlnKCk7XHJcblxyXG4gICAgLy9UaGVyZSBjb3VsZCBiZSBhIG5vbi1leHBpcmVkIHRva2VuIGluIGxvY2FsIHN0b3JhZ2UuXHJcbiAgICBsZXQgdG9rZW46IHN0cmluZyA9IHRoaXMuYXV0aGVudGljYXRpb25Qcm92aWRlci5hdXRoVG9rZW47XHJcbiAgICB0aGlzLnN0b3JlVG9rZW4odG9rZW4pO1xyXG4gIH1cclxuXHJcbiAgZ2V0QmFzZVVybCgpOiBzdHJpbmcge1xyXG4gICAgcmV0dXJuICh0aGlzLmJhc2VVcmwpID8gdGhpcy5iYXNlVXJsIDogXCJcIjtcclxuICB9XHJcblxyXG4gIGdldENvbnRleHRSb290KCk6IHN0cmluZyB7XHJcbiAgICByZXR1cm4gdGhpcy5jb250ZXh0Um9vdDtcclxuICB9XHJcblxyXG4gIGdldEhlYWRlcnMocmVxOiBIdHRwUmVxdWVzdDxhbnk+KTogSHR0cEhlYWRlcnMge1xyXG4gICAgbGV0IGhlYWRlcnM6IEh0dHBIZWFkZXJzID0gcmVxLmhlYWRlcnM7XHJcblxyXG4gICAgLy9Eb24ndCBzZXQgY29udGVudCB0eXBlIGlmIGFscmVhZHkgc2V0XHJcbiAgICBpZiAoIXJlcS5oZWFkZXJzLmdldChBdXRoZW50aWNhdGlvblNlcnZpY2UuQ09OVEVOVF9UWVBFKSkge1xyXG4gICAgICBoZWFkZXJzID0gaGVhZGVycy5zZXQoQXV0aGVudGljYXRpb25TZXJ2aWNlLkNPTlRFTlRfVFlQRSwgdGhpcy5jb250ZW50VHlwZS50b1N0cmluZygpKTtcclxuICAgIH1cclxuXHJcbiAgICBpZiAoaGVhZGVycy5nZXQoQXV0aGVudGljYXRpb25TZXJ2aWNlLlNFQ19HT1ZfQ0xBU1NfSEVBREVSKSA9PT0gXCJcIikge1xyXG4gICAgICBoZWFkZXJzID0gaGVhZGVycy5kZWxldGUoQXV0aGVudGljYXRpb25TZXJ2aWNlLlNFQ19HT1ZfQ0xBU1NfSEVBREVSKTtcclxuICAgIH0gZWxzZSBpZiAodGhpcy5zZWN1cml0eUdvdmVybm9yQ2xhc3MgJiYgIWhlYWRlcnMuZ2V0KEF1dGhlbnRpY2F0aW9uU2VydmljZS5TRUNfR09WX0NMQVNTX0hFQURFUikpIHtcclxuICAgICAgaGVhZGVycyA9IGhlYWRlcnMuc2V0KEF1dGhlbnRpY2F0aW9uU2VydmljZS5TRUNfR09WX0NMQVNTX0hFQURFUiwgdGhpcy5zZWN1cml0eUdvdmVybm9yQ2xhc3MpO1xyXG4gICAgfVxyXG5cclxuICAgIGlmIChoZWFkZXJzLmdldChBdXRoZW50aWNhdGlvblNlcnZpY2UuU0VDX0dPVl9JRF9IRUFERVIpID09PSBcIlwiKSB7XHJcbiAgICAgIGhlYWRlcnMgPSBoZWFkZXJzLmRlbGV0ZShBdXRoZW50aWNhdGlvblNlcnZpY2UuU0VDX0dPVl9JRF9IRUFERVIpO1xyXG4gICAgfSBlbHNlIGlmICh0aGlzLnNlY3VyaXR5R292ZXJub3JJZCAmJiAhaGVhZGVycy5nZXQoQXV0aGVudGljYXRpb25TZXJ2aWNlLlNFQ19HT1ZfSURfSEVBREVSKSkge1xyXG4gICAgICBoZWFkZXJzID0gaGVhZGVycy5zZXQoQXV0aGVudGljYXRpb25TZXJ2aWNlLlNFQ19HT1ZfSURfSEVBREVSLCB0aGlzLnNlY3VyaXR5R292ZXJub3JJZC50b1N0cmluZygpKTtcclxuICAgIH1cclxuXHJcbiAgICBoZWFkZXJzID0gaGVhZGVycy5zZXQoQXV0aGVudGljYXRpb25TZXJ2aWNlLkRFSURFTlRfSEVBREVSLCB0aGlzLmRlaWRlbnRpZmllZENvbnRleHQudG9TdHJpbmcoKSk7XHJcbiAgICBoZWFkZXJzID0gaGVhZGVycy5zZXQoQXV0aGVudGljYXRpb25TZXJ2aWNlLkxJTUlURURfSEVBREVSLCB0aGlzLmxpbWl0ZWRDb250ZXh0LnRvU3RyaW5nKCkpO1xyXG5cclxuICAgIHJldHVybiBoZWFkZXJzO1xyXG4gIH1cclxuXHJcbiAgZ2V0IGF1dGhlbnRpY2F0aW9uVG9rZW5LZXkoKTogc3RyaW5nIHtcclxuICAgIHJldHVybiB0aGlzLmF1dGhlbnRpY2F0aW9uUHJvdmlkZXIuYXV0aGVudGljYXRpb25Ub2tlbktleTtcclxuICB9XHJcblxyXG4gIGdldCBhdXRoVG9rZW4oKTogc3RyaW5nIHtcclxuICAgIHJldHVybiB0aGlzLmF1dGhlbnRpY2F0aW9uUHJvdmlkZXIuYXV0aFRva2VuO1xyXG4gIH1cclxuXHJcbiAgcHVibGljIHVwZGF0ZVVzZXJBY3Rpdml0eSgpOiB2b2lkIHtcclxuICAgIGlmICh0aGlzLl9pc0F1dGhlbnRpY2F0ZWRTdWJqZWN0LnZhbHVlKSB7XHJcbiAgICAgIHRoaXMuX2xhc3RVc2VySW50ZXJhY3Rpb24gPSBuZXcgRGF0ZSgpO1xyXG4gICAgICB0aGlzLl91c2VySXNBYm91dFRvVGltZU91dC5uZXh0KGZhbHNlKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIEEgbXV0YXRvciBmb3IgaWRlbnRpZnlpbmcgdGhlIGNsaWVudHMgb3JpZ2luYWwgcmVxdWVzdCBsb2NhdGlvbi4gU2V0dGluZyB0aGlzIHZhbHVlIHdpbGwgaW5mbHVlbmNlIHRoZSBlbmQgbG9jYXRpb25cclxuICAgKiBuYXZpZ2F0ZWQgdG8gYnkge0BsaW5rICNuYXZpZ2F0ZVRvUGF0aH0uXHJcbiAgICpcclxuICAgKiBAcGFyYW0gcmVkaXJlY3RVcmwgbG9jYXRpb24gb2YgdGhlIHVzZXJzIHJlcXVlc3QgYmVmb3JlIGF1dGhlbnRpY2F0aW9uXHJcbiAgICovXHJcbiAgc2V0IHJlZGlyZWN0VXJsKHJlZGlyZWN0VXJsOiBzdHJpbmcpIHtcclxuICAgIHRoaXMuX3JlZGlyZWN0VXJsID0gcmVkaXJlY3RVcmw7XHJcbiAgfVxyXG5cclxuICBnZXQgcmVkaXJlY3RVcmwoKSB7XHJcbiAgICByZXR1cm4gdGhpcy5fcmVkaXJlY3RVcmw7XHJcbiAgfVxyXG5cclxuICByZXF1ZXN0QWNjZXNzVG9rZW4ocmVkaXJlY3RPblN1Y2Nlc3M6IGJvb2xlYW4pOiB2b2lkIHtcclxuXHJcbiAgICB0aGlzLl9odHRwLmdldCh0aGlzLnRva2VuTG9jYXRpb24oKSwge3dpdGhDcmVkZW50aWFsczogdHJ1ZX0pXHJcbiAgICAgIC5zdWJzY3JpYmUoXHJcbiAgICAgICAgKHJlc3BvbnNlOiBhbnkpID0+IHtcclxuICAgICAgICAgIHRoaXMuc3RvcmVUb2tlbihyZXNwb25zZS5hdXRoX3Rva2VuKTtcclxuICAgICAgICAgIGlmIChyZWRpcmVjdE9uU3VjY2Vzcykge1xyXG4gICAgICAgICAgICB0aGlzLnByb2NlZWRJZkF1dGhlbnRpY2F0ZWQoKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9LFxyXG4gICAgICAgIChlcnJvcikgPT4ge1xyXG4gICAgICAgICAgLy9Ub2tlbiByZWZyZXNoIGZhaWxlZC5cclxuICAgICAgICAgIHRoaXMubG9nb3V0KHRydWUpO1xyXG4gICAgICAgIH1cclxuICAgICAgKTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIFZlcmlmaWVzIHdoZXRoZXIgb3Igbm90IGEgY3VycmVudCB1c2VyIHNlc3Npb24gZXhpc3RzLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge09ic2VydmFibGU8Ym9vbGVhbj59IGV2YWx1YXRlcyB0byB0cnVlIGlmIHRoZSB1c2VyIGlzIGF1dGhlbnRpY2F0ZWQsIGZhbHNlIG90aGVyd2lzZS5cclxuICAgKi9cclxuICBpc0F1dGhlbnRpY2F0ZWQoKTogT2JzZXJ2YWJsZTxib29sZWFuPiB7XHJcbiAgICByZXR1cm4gdGhpcy5faXNBdXRoZW50aWNhdGVkU3ViamVjdC5hc09ic2VydmFibGUoKTtcclxuICB9XHJcblxyXG4gIGlzQWJvdXRUb1RpbWVPdXQoKTogT2JzZXJ2YWJsZTxib29sZWFuPiB7XHJcbiAgICByZXR1cm4gdGhpcy5fdXNlcklzQWJvdXRUb1RpbWVPdXQuYXNPYnNlcnZhYmxlKCk7XHJcbiAgfVxyXG5cclxuICBnZXRUaW1lb3V0U3RhcnQoKTogbnVtYmVyIHtcclxuICAgIGlmICh0aGlzLl9sYXN0VXNlckludGVyYWN0aW9uKSB7XHJcbiAgICAgIHJldHVybiB0aGlzLl9sYXN0VXNlckludGVyYWN0aW9uLnZhbHVlT2YoKSArICgoKHRoaXMuX21heEluYWN0aXZpdHlNaW51dGVzICogNjApIC0gdGhpcy51c2VyQ291bnRkb3duU2Vjb25kcykgKiAxMDAwKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIHRva2VuTG9jYXRpb24oKTogc3RyaW5nIHtcclxuICAgIGlmICh0aGlzLl9zZXJ2ZXJVcmwpIHtcclxuICAgICAgcmV0dXJuIHRoaXMuX3NlcnZlclVybCArIHRoaXMuX3Rva2VuRW5kcG9pbnQ7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICByZXR1cm4gdGhpcy5fdG9rZW5FbmRwb2ludDtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIGRpcmVjdExvZ2luTG9jYXRpb24oKTogc3RyaW5nIHtcclxuICAgIGlmICh0aGlzLl9zZXJ2ZXJVcmwpIHtcclxuICAgICAgcmV0dXJuIHRoaXMuX3NlcnZlclVybCArIHRoaXMuX2RpcmVjdEVuZHBvaW50O1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgcmV0dXJuIHRoaXMuX2RpcmVjdEVuZHBvaW50O1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgbG9nb3V0TG9jYXRpb24oKTogc3RyaW5nIHtcclxuICAgIGlmICh0aGlzLl9zZXJ2ZXJVcmwpIHtcclxuICAgICAgcmV0dXJuIHRoaXMuX3NlcnZlclVybCArIHRoaXMuX2xvZ291dFBhdGg7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICByZXR1cm4gdGhpcy5fbG9nb3V0UGF0aDtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIEEgZnVuY3Rpb24gdG8gYXV0aGVudGljYXRlZCB0aGUgdXNlciB3aXRoIHRoZSBwcm92aWRlZCBjcmVkZW50aWFscy4gRmFpbHVyZSByZXN1bHRzIGluIGFuIGVycm9yIHRoYXQgZGVzY3JpYmVzIHRoZVxyXG4gICAqIHNlcnZlciByZXNwb25zZSAoc3RhdHVzIGFuZCBzdGF0dXMgbWVzc2FnZSkgYW5kIHNob3VsZCBiZSBhY3Rpb25hYmxlIGJ5IHRoZSBjbGllbnQgYXBwbGljYXRpb24uXHJcbiAgICpcclxuICAgKiBAcGFyYW0gdXNlcm5hbWUgb2YgdGhlIGF1dGhlbnRpY2F0aW5nIHVzZXIgdG8gdmVyaWZ5XHJcbiAgICogQHBhcmFtIHBhc3N3b3JkIG9mIHRoZSBhdXRoZW50aWNhdGluZyB1c2VyIHRvIHZlcmlmeVxyXG4gICAqIEByZXR1cm5zIHtPYnNlcnZhYmxlPFI+fSBkZXNjcmliaW5nIHRoZSByZXN1bHQgb2YgdGhlIGxvZ2luIGFjdGlvbiwgdHJ1ZSBvciBhbiBlcnJvclxyXG4gICAqL1xyXG4gIGxvZ2luKF91c2VybmFtZTogc3RyaW5nLCBfcGFzc3dvcmQ6IHN0cmluZyk6IE9ic2VydmFibGU8Ym9vbGVhbj4ge1xyXG4gICAgcmV0dXJuIHRoaXMuX2h0dHAucG9zdChcclxuICAgICAgdGhpcy5kaXJlY3RMb2dpbkxvY2F0aW9uKCksXHJcbiAgICAgIHt1c2VybmFtZTogX3VzZXJuYW1lLCBwYXNzd29yZDogX3Bhc3N3b3JkfSxcclxuICAgICAge29ic2VydmU6IFwicmVzcG9uc2VcIn1cclxuICAgICkucGlwZShtYXAoKHJlc3A6IEh0dHBSZXNwb25zZTxhbnk+KSA9PiB7XHJcbiAgICAgIGlmIChyZXNwLnN0YXR1cyA9PT0gMjAxKSB7XHJcbiAgICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiQXV0aGVudGljYXRpb24gZmFpbGVkLiBcIiArIHJlc3Auc3RhdHVzICsgXCI6IFwiICsgcmVzcC5zdGF0dXNUZXh0KTtcclxuICAgICAgfVxyXG4gICAgfSksXHJcbiAgICAgIGNhdGNoRXJyb3IodGhpcy5oYW5kbGVFcnJvcikpO1xyXG4gIH1cclxuXHJcblxyXG4gIGNsZWFyTG9naW4oKTogT2JzZXJ2YWJsZTxSZXNwb25zZT4ge1xyXG4gICAgLy9Gcm9udC1lbmQgbG9nb3V0XHJcbiAgICB0cnkge1xyXG4gICAgICB0aGlzLl9sb2NhbFN0b3JhZ2VTZXJ2aWNlLnJlbW92ZUl0ZW0odGhpcy5hdXRoZW50aWNhdGlvblByb3ZpZGVyLmF1dGhlbnRpY2F0aW9uVG9rZW5LZXkpO1xyXG4gICAgICB0aGlzLnVuc3Vic2NyaWJlRnJvbVRva2VuUmVmcmVzaCgpO1xyXG4gICAgICB0aGlzLl9pc0F1dGhlbnRpY2F0ZWRTdWJqZWN0Lm5leHQoZmFsc2UpO1xyXG4gICAgICB0aGlzLl91c2VySXNBYm91dFRvVGltZU91dC5uZXh0KGZhbHNlKTtcclxuICAgIH0gY2F0Y2ggKEVycm9yKSB7XHJcbiAgICB9XHJcblxyXG4gICAgLy9CYWNrLWVuZCBsb2dvdXRcclxuICAgIGxldCBoZWFkZXJzID0gbmV3IEh0dHBIZWFkZXJzKCkuc2V0KEF1dGhlbnRpY2F0aW9uU2VydmljZS5DT05URU5UX1RZUEUsIFwidGV4dC9wbGFpblwiKTtcclxuICAgIHJldHVybiA8T2JzZXJ2YWJsZTxSZXNwb25zZT4+dGhpcy5faHR0cC5nZXQodGhpcy5sb2dvdXRMb2NhdGlvbigpLCB7aGVhZGVyczogaGVhZGVyc30pO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogQSBmdW5jdGlvbiB0byBzaWduYWwgdGhlIHRlcm1pbmF0aW9uIG9mIHRoZSBjdXJyZW50IHNlc3Npb24uIEludm9raW5nIHRoaXMgZnVuY3Rpb24gd2lsbCBjbGVhbiB1cCBhbnkgcmVsZXZhbnQgc3RhdGVcclxuICAgKiByZWxhdGVkIHRvIHRoZSBsYXN0IGFjdGl2ZSBzZXNzaW9uLlxyXG4gICAqL1xyXG4gIGxvZ291dChrZWVwQ3VycmVudFJvdXRlOiBib29sZWFuID0gZmFsc2UpOiB2b2lkIHtcclxuICAgIC8vUHJldmVudCBsb2dvdXQgaWYgYWxyZWFkeSBvbiBhdXRoZW50aWNhdGlvbiByb3V0ZS4gRG9pbmcgb3RoZXJ3aXNlIHNjcmV3cyB1cCBTQU1MXHJcbiAgICBpZiAoISB0aGlzLl9yb3V0ZXIucm91dGVyU3RhdGUgfHwgdGhpcy5fcm91dGVyLnJvdXRlclN0YXRlLnNuYXBzaG90LnVybCAhPT0gdGhpcy5fYXV0aGVudGljYXRpb25Sb3V0ZSkge1xyXG4gICAgICB0aGlzLl9yZWRpcmVjdFVybCA9IChrZWVwQ3VycmVudFJvdXRlICYmIHRoaXMuX3JvdXRlci5yb3V0ZXJTdGF0ZSAmJiB0aGlzLl9yb3V0ZXIucm91dGVyU3RhdGUuc25hcHNob3QpID8gdGhpcy5fcm91dGVyLnJvdXRlclN0YXRlLnNuYXBzaG90LnVybCA6IFwiXCI7XHJcblxyXG4gICAgICBpZiAodGhpcy5fcmVkaXJlY3RVcmwuc3RhcnRzV2l0aChcIi9cIikpIHtcclxuICAgICAgICB0aGlzLl9yZWRpcmVjdFVybCA9IHRoaXMuX3JlZGlyZWN0VXJsLnN1YnN0cmluZygxKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgdGhpcy5jbGVhckxvZ2luKCkuc3Vic2NyaWJlKFxyXG4gICAgICAgIChyZXNwb25zZSkgPT4ge1xyXG4gICAgICAgICAgd2luZG93LmxvY2F0aW9uLnJlcGxhY2UodGhpcy5fcmVkaXJlY3RVcmwpO1xyXG4gICAgICAgICAgfSxcclxuICAgICAgICAoZXJyb3IpID0+IHtcclxuICAgICAgICAgIHdpbmRvdy5sb2NhdGlvbi5yZXBsYWNlKHRoaXMuX3JlZGlyZWN0VXJsKTtcclxuICAgICAgICB9XHJcbiAgICAgICk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBzdG9yZVRva2VuKHRva2VuOiBzdHJpbmcpOiB2b2lkIHtcclxuICAgIGxldCB2YWxpZCA9IHRoaXMudmFsaWRhdGVUb2tlbih0b2tlbik7XHJcblxyXG4gICAgLy8gdW5zdWJzY3JpYmUgZnJvbSByZWZlc2ggYmVmb3JlIHdlIGRlY2lkZSB3ZXRoZXIgdG8gcmVzdWJzY3JpYmVcclxuICAgIHRoaXMudW5zdWJzY3JpYmVGcm9tVG9rZW5SZWZyZXNoKCk7XHJcblxyXG4gICAgaWYgKHZhbGlkKSB7XHJcbiAgICAgIHRoaXMuX2xvY2FsU3RvcmFnZVNlcnZpY2Uuc2V0SXRlbSh0aGlzLmF1dGhlbnRpY2F0aW9uUHJvdmlkZXIuYXV0aGVudGljYXRpb25Ub2tlbktleSwgdG9rZW4pO1xyXG4gICAgICB0aGlzLnN1YnNjcmliZVRvVG9rZW5SZWZyZXNoKHRva2VuKTtcclxuXHJcbiAgICAgIC8vQ2hhbmdlIHRoZSBCZWhhdmlvclN1YmplY3QgaWYgdGhlIHVzZXIgd2FzIG5vdCBwcmV2aW91c2x5IGF1dGhlbnRpY2F0ZWQuXHJcbiAgICAgIC8vU2luY2Ugb3RoZXIgY29kZSBtYXkgYmUgc3Vic2NyaWJpbmcgdG8gdGhpcyBvYnNlcnZhYmxlLCB3ZSBkb24ndCB3YW50IHRvIGNhdXNlIG5ldyBldmVudHMgdG8gZmlyZSBpZiBqdXN0IHJlZnJlc2hpbmcgdGhlIEpXVC5cclxuICAgICAgaWYgKCEgdGhpcy5faXNBdXRoZW50aWNhdGVkU3ViamVjdC52YWx1ZSkge1xyXG4gICAgICAgIHRoaXMuX2lzQXV0aGVudGljYXRlZFN1YmplY3QubmV4dCh0cnVlKTtcclxuICAgICAgfVxyXG4gICAgfSBlbHNlIHtcclxuICAgICAgdGhpcy5fbG9jYWxTdG9yYWdlU2VydmljZS5yZW1vdmVJdGVtKHRoaXMuYXV0aGVudGljYXRpb25Qcm92aWRlci5hdXRoZW50aWNhdGlvblRva2VuS2V5KTtcclxuICAgICAgdGhpcy5faXNBdXRoZW50aWNhdGVkU3ViamVjdC5uZXh0KGZhbHNlKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIHByb2NlZWRJZkF1dGhlbnRpY2F0ZWQoKTogYm9vbGVhbiB7XHJcbiAgICBpZiAoaXNEZXZNb2RlKCkpIHtcclxuICAgICAgY29uc29sZS5kZWJ1ZyhcIkF1dGhlbnRpY2F0aW9uU2VydmljZS5wcm9jZWVkSWZBdXRoZW50aWNhdGVkOiBcIiArIHRoaXMuX3JlZGlyZWN0VXJsKTtcclxuICAgIH1cclxuXHJcbiAgICBpZiAodGhpcy5faXNBdXRoZW50aWNhdGVkU3ViamVjdC52YWx1ZSkge1xyXG4gICAgICAvL0xvZ2luIGNvdW50cyBhcyB1c2VyIGFjdGl2aXR5LCB0b29cclxuICAgICAgdGhpcy51cGRhdGVVc2VyQWN0aXZpdHkoKTtcclxuXHJcbiAgICAgIGlmICh0aGlzLl9yZWRpcmVjdFVybCAmJiB0aGlzLl9yZWRpcmVjdFVybCAmJiB0aGlzLl9yZWRpcmVjdFVybCAhPT0gXCJcIikge1xyXG4gICAgICAgIHRoaXMuX3JvdXRlci5uYXZpZ2F0ZUJ5VXJsKHRoaXMuX3JlZGlyZWN0VXJsKTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICB0aGlzLl9yb3V0ZXIubmF2aWdhdGUoW1wiXCJdKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICB2YWxpZGF0ZVRva2VuKHRva2VuOiBzdHJpbmcpOiBib29sZWFuIHtcclxuICAgIHJldHVybiAodG9rZW4gJiYgIXRoaXMuX2p3dEhlbHBlci5pc1Rva2VuRXhwaXJlZCh0b2tlbikpO1xyXG4gIH1cclxuXHJcbiAgc3Vic2NyaWJlVG9Ub2tlblJlZnJlc2godG9rZW46IGFueSk6IHZvaWQge1xyXG4gICAgbGV0IGV4cCA9IHRoaXMuX2p3dEhlbHBlci5nZXRUb2tlbkV4cGlyYXRpb25EYXRlKHRva2VuKTtcclxuXHJcbiAgICAvLyBVc2UgYSB0aW1lciB0byBwZXJpb2RpY2FsbHkgY2hlY2sgdGltZW91dHNcclxuICAgIHRoaXMuX3JlZnJlc2hTdWJzY3JpcHRpb24gPSBpbnRlcnZhbCgxMDAwKVxyXG4gICAgICAuc3Vic2NyaWJlKCgpID0+IHtcclxuXHJcbiAgICAgICAgLy8gSWYgYSB0YWIgaXMgaW5hY3RpdmUgd2UgY2FuJ3Qga25vdyBpZiBvdXIgdGltZXIgaXMgYWNjdXJhdGVcclxuICAgICAgICAvLyBzbyB3aGVuIHRoZSBpbnRlcnZhbCBoaXRzIGNoZWNrIGFnYWluc3QgdGltZXN0YW1wc1xyXG4gICAgICAgIGlmICh0aGlzLl9pc0F1dGhlbnRpY2F0ZWRTdWJqZWN0LnZhbHVlICYmIERhdGUubm93KCkgPiB0aGlzLmdldFRpbWVvdXRTdGFydCgpKSB7XHJcbiAgICAgICAgICAvL0Rvbid0IHVwZGF0ZSB0aGUgc3ViamVjdCBtb3JlIHRoYW4gb25jZSEgRG9pbmcgc28gaW5pdGlhbGl6ZXMgbW9yZSB0aGFuIG9uZSBjb3VudGRvd24gdGltZXIhXHJcbiAgICAgICAgICBpZiAodGhpcy5fdXNlcklzQWJvdXRUb1RpbWVPdXQuZ2V0VmFsdWUoKSAhPT0gdHJ1ZSkge1xyXG4gICAgICAgICAgICB0aGlzLl91c2VySXNBYm91dFRvVGltZU91dC5uZXh0KHRydWUpO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gY2hlY2sgZm9yIHJlZnJlc2ggdG9rZW5cclxuICAgICAgICBsZXQgbXNUb0V4cGlyeSA9IChleHAudmFsdWVPZigpIC0gbmV3IERhdGUoKS52YWx1ZU9mKCkpO1xyXG5cclxuICAgICAgICAvLyBSZWZyZXNoIDYwIHNlY29uZHMgYmVmb3JlIGV4cGlyeVxyXG4gICAgICAgIGlmIChtc1RvRXhwaXJ5IDw9IDYwMDAwKSB7XHJcbiAgICAgICAgICB0aGlzLnJlZnJlc2hUb2tlbklmVXNlcklzQWN0aXZlKCk7XHJcbiAgICAgICAgfVxyXG4gICAgICB9KTtcclxuICB9XHJcblxyXG4gIHVuc3Vic2NyaWJlRnJvbVRva2VuUmVmcmVzaCgpOiB2b2lkIHtcclxuICAgIGlmICh0aGlzLl9yZWZyZXNoU3Vic2NyaXB0aW9uICYmICEgdGhpcy5fcmVmcmVzaFN1YnNjcmlwdGlvbi5jbG9zZWQpIHtcclxuICAgICAgdGhpcy5fcmVmcmVzaFN1YnNjcmlwdGlvbi51bnN1YnNjcmliZSgpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgZ2V0TWF4Vmlld1Blcm1pc3Npb24oKTogXCJ2aWV3XCIgfCBcInZpZXdpZGVudFwiIHwgXCJ2aWV3bGltaXRlZFwiIHtcclxuICAgIHJldHVybiB0aGlzLm1heFZpZXdQZXJtaXNzaW9uLmdldFZhbHVlKCk7XHJcbiAgfVxyXG5cclxuICBnZXRNYXhWaWV3UGVybWlzc2lvblN1YmplY3QoKTogQmVoYXZpb3JTdWJqZWN0PFwidmlld1wiIHwgXCJ2aWV3aWRlbnRcIiB8IFwidmlld2xpbWl0ZWRcIj4ge1xyXG4gICAgcmV0dXJuIHRoaXMubWF4Vmlld1Blcm1pc3Npb247XHJcbiAgfVxyXG5cclxuICBzZXRNYXhWaWV3UGVybWlzc2lvbihtYXhWaWV3UGVybWlzc2lvbjogXCJ2aWV3XCIgfCBcInZpZXdpZGVudFwiIHwgXCJ2aWV3bGltaXRlZFwiKTogdm9pZCB7XHJcbiAgICB0aGlzLl9sb2NhbFN0b3JhZ2VTZXJ2aWNlLnNldEl0ZW0oXCJtYXhWaWV3UGVybWlzc2lvblwiLCBtYXhWaWV3UGVybWlzc2lvbik7XHJcbiAgICB0aGlzLm1heFZpZXdQZXJtaXNzaW9uLm5leHQobWF4Vmlld1Blcm1pc3Npb24pO1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSByZWZyZXNoVG9rZW5JZlVzZXJJc0FjdGl2ZSgpOiB2b2lkIHtcclxuICAgIC8vT25seSByZWZyZXNoIGlmIHRoZSB1c2VyIGhhcyBiZWVuIGFjdGl2ZVxyXG4gICAgaWYgKHRoaXMuX2xhc3RVc2VySW50ZXJhY3Rpb24gJiYgKChuZXcgRGF0ZSgpLnZhbHVlT2YoKSAtIHRoaXMuX2xhc3RVc2VySW50ZXJhY3Rpb24udmFsdWVPZigpKSA8PSAodGhpcy5fbWF4SW5hY3Rpdml0eU1pbnV0ZXMgKiA2MCAqIDEwMDApKSkge1xyXG4gICAgICB0aGlzLnJlcXVlc3RBY2Nlc3NUb2tlbihmYWxzZSk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIGhhc1ZhbGlkQ29uZmlnKCk6IHZvaWQge1xyXG4gICAgaWYgKHRoaXMuX3Rva2VuRW5kcG9pbnQgPT0gbnVsbCAmJiAodGhpcy5fc2VydmVyVXJsID09PSBudWxsIHx8IHRoaXMuX2xvZ291dFBhdGggPT09IG51bGwpKSB7XHJcbiAgICAgIHRocm93IG5ldyBFcnJvcihcIkJVRyBBTEVSVCEgSW52YWxpZCBBdXRoZW50aWNhdGlvblNlcnZpY2UgY29uZmlndXJhdGlvbi4gTm8gdmFsaWQgY29uZmlndXJhdGlvbiBmb3IgYXV0aGVudGljYXRpb24gZW5kcG9pbnQocykuXCIpO1xyXG4gICAgfVxyXG4gICAgaWYgKHRoaXMuX2xvY2FsU3RvcmFnZVNlcnZpY2UgPT09IG51bGwgfHwgdGhpcy5hdXRoZW50aWNhdGlvblByb3ZpZGVyLmF1dGhlbnRpY2F0aW9uVG9rZW5LZXkgPT09IG51bGwpIHtcclxuICAgICAgdGhyb3cgbmV3IEVycm9yKFwiQlVHIEFMRVJUISBJbnZhbGlkIEF1dGhlbnRpY2F0aW9uU2VydmljZSBjb25maWd1cmF0aW9uLiBObyB2YWxpZCBjb25maWd1cmF0aW9uIGZvciBsb2NhbCBzdG9yYWdlXCIpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBoYW5kbGVFcnJvcihlcnJvcjogYW55KSA6IE9ic2VydmFibGU8bmV2ZXI+IHtcclxuICAgIGxldCBlcnJNc2cgPSAoZXJyb3IubWVzc2FnZSkgPyBlcnJvci5tZXNzYWdlIDogQXV0aGVudGljYXRpb25TZXJ2aWNlLkdFTkVSSUNfRVJSX01TRztcclxuICAgIHJldHVybiB0aHJvd0Vycm9yKGVyck1zZyk7XHJcbiAgfVxyXG59XHJcbiJdfQ==