@azure/msal-angular 2.5.4 → 2.5.6

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 (40) hide show
  1. package/IMsalService.d.ts +15 -15
  2. package/LICENSE +20 -20
  3. package/README.md +151 -151
  4. package/azure-msal-angular.d.ts +4 -4
  5. package/azure-msal-angular.metadata.json +1 -1
  6. package/bundles/azure-msal-angular.umd.js +1025 -1025
  7. package/bundles/azure-msal-angular.umd.js.map +1 -1
  8. package/bundles/azure-msal-angular.umd.min.js +1 -1
  9. package/bundles/azure-msal-angular.umd.min.js.map +1 -1
  10. package/constants.d.ts +5 -5
  11. package/esm2015/IMsalService.js +6 -6
  12. package/esm2015/azure-msal-angular.js +4 -4
  13. package/esm2015/constants.js +10 -10
  14. package/esm2015/msal.broadcast.config.js +6 -6
  15. package/esm2015/msal.broadcast.service.js +46 -46
  16. package/esm2015/msal.guard.config.js +6 -6
  17. package/esm2015/msal.guard.js +189 -189
  18. package/esm2015/msal.interceptor.config.js +6 -6
  19. package/esm2015/msal.interceptor.js +230 -230
  20. package/esm2015/msal.module.js +46 -46
  21. package/esm2015/msal.navigation.client.js +53 -53
  22. package/esm2015/msal.redirect.component.js +33 -33
  23. package/esm2015/msal.service.js +77 -77
  24. package/esm2015/packageMetadata.js +4 -4
  25. package/esm2015/public-api.js +18 -18
  26. package/fesm2015/azure-msal-angular.js +626 -626
  27. package/fesm2015/azure-msal-angular.js.map +1 -1
  28. package/msal.broadcast.config.d.ts +3 -3
  29. package/msal.broadcast.service.d.ts +14 -14
  30. package/msal.guard.config.d.ts +9 -9
  31. package/msal.guard.d.ts +40 -40
  32. package/msal.interceptor.config.d.ts +17 -17
  33. package/msal.interceptor.d.ts +59 -59
  34. package/msal.module.d.ts +7 -7
  35. package/msal.navigation.client.d.ts +16 -16
  36. package/msal.redirect.component.d.ts +12 -12
  37. package/msal.service.d.ts +28 -28
  38. package/package.json +2 -2
  39. package/packageMetadata.d.ts +2 -2
  40. package/public-api.d.ts +17 -17
@@ -1,230 +1,230 @@
1
- /*
2
- * Copyright (c) Microsoft Corporation. All rights reserved.
3
- * Licensed under the MIT License.
4
- */
5
- import { Location, DOCUMENT } from "@angular/common";
6
- import { EMPTY, of } from "rxjs";
7
- import { switchMap, catchError, take, filter } from "rxjs/operators";
8
- import { MsalService } from "./msal.service";
9
- import { BrowserConfigurationAuthError, InteractionStatus, InteractionType, StringUtils, UrlString } from "@azure/msal-browser";
10
- import { Injectable, Inject } from "@angular/core";
11
- import { MSAL_INTERCEPTOR_CONFIG } from "./constants";
12
- import { MsalBroadcastService } from "./msal.broadcast.service";
13
- export class MsalInterceptor {
14
- constructor(msalInterceptorConfig, authService, location, msalBroadcastService,
15
- // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/explicit-module-boundary-types
16
- document) {
17
- this.msalInterceptorConfig = msalInterceptorConfig;
18
- this.authService = authService;
19
- this.location = location;
20
- this.msalBroadcastService = msalBroadcastService;
21
- this._document = document;
22
- }
23
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
24
- intercept(req, next) {
25
- if (this.msalInterceptorConfig.interactionType !== InteractionType.Popup && this.msalInterceptorConfig.interactionType !== InteractionType.Redirect) {
26
- throw new BrowserConfigurationAuthError("invalid_interaction_type", "Invalid interaction type provided to MSAL Interceptor. InteractionType.Popup, InteractionType.Redirect must be provided in the msalInterceptorConfiguration");
27
- }
28
- this.authService.getLogger().verbose("MSAL Interceptor activated");
29
- const scopes = this.getScopesForEndpoint(req.url, req.method);
30
- // If no scopes for endpoint, does not acquire token
31
- if (!scopes || scopes.length === 0) {
32
- this.authService.getLogger().verbose("Interceptor - no scopes for endpoint");
33
- return next.handle(req);
34
- }
35
- // Sets account as active account or first account
36
- let account;
37
- if (!!this.authService.instance.getActiveAccount()) {
38
- this.authService.getLogger().verbose("Interceptor - active account selected");
39
- account = this.authService.instance.getActiveAccount();
40
- }
41
- else {
42
- this.authService.getLogger().verbose("Interceptor - no active account, fallback to first account");
43
- account = this.authService.instance.getAllAccounts()[0];
44
- }
45
- const authRequest = typeof this.msalInterceptorConfig.authRequest === "function"
46
- ? this.msalInterceptorConfig.authRequest(this.authService, req, { account: account })
47
- : Object.assign(Object.assign({}, this.msalInterceptorConfig.authRequest), { account });
48
- this.authService.getLogger().info(`Interceptor - ${scopes.length} scopes found for endpoint`);
49
- this.authService.getLogger().infoPii(`Interceptor - [${scopes}] scopes found for ${req.url}`);
50
- return this.acquireToken(authRequest, scopes, account)
51
- .pipe(switchMap((result) => {
52
- this.authService.getLogger().verbose("Interceptor - setting authorization headers");
53
- const headers = req.headers
54
- .set("Authorization", `Bearer ${result.accessToken}`);
55
- const requestClone = req.clone({ headers });
56
- return next.handle(requestClone);
57
- }));
58
- }
59
- /**
60
- * Try to acquire token silently. Invoke interaction if acquireTokenSilent rejected with error or resolved with null access token
61
- * @param authRequest Request
62
- * @param scopes Array of scopes for the request
63
- * @param account Account
64
- * @returns Authentication result
65
- */
66
- acquireToken(authRequest, scopes, account) {
67
- // Note: For MSA accounts, include openid scope when calling acquireTokenSilent to return idToken
68
- return this.authService.acquireTokenSilent(Object.assign(Object.assign({}, authRequest), { scopes, account }))
69
- .pipe(catchError(() => {
70
- this.authService.getLogger().error("Interceptor - acquireTokenSilent rejected with error. Invoking interaction to resolve.");
71
- return this.msalBroadcastService.inProgress$
72
- .pipe(take(1), switchMap((status) => {
73
- if (status === InteractionStatus.None) {
74
- return this.acquireTokenInteractively(authRequest, scopes);
75
- }
76
- return this.msalBroadcastService.inProgress$
77
- .pipe(filter((status) => status === InteractionStatus.None), take(1), switchMap(() => this.acquireToken(authRequest, scopes, account)));
78
- }));
79
- }), switchMap((result) => {
80
- if (!result.accessToken) {
81
- this.authService.getLogger().error("Interceptor - acquireTokenSilent resolved with null access token. Known issue with B2C tenants, invoking interaction to resolve.");
82
- return this.msalBroadcastService.inProgress$
83
- .pipe(filter((status) => status === InteractionStatus.None), take(1), switchMap(() => this.acquireTokenInteractively(authRequest, scopes)));
84
- }
85
- return of(result);
86
- }));
87
- }
88
- /**
89
- * Invoke interaction for the given set of scopes
90
- * @param authRequest Request
91
- * @param scopes Array of scopes for the request
92
- * @returns Result from the interactive request
93
- */
94
- acquireTokenInteractively(authRequest, scopes) {
95
- if (this.msalInterceptorConfig.interactionType === InteractionType.Popup) {
96
- this.authService.getLogger().verbose("Interceptor - error acquiring token silently, acquiring by popup");
97
- return this.authService.acquireTokenPopup(Object.assign(Object.assign({}, authRequest), { scopes }));
98
- }
99
- this.authService.getLogger().verbose("Interceptor - error acquiring token silently, acquiring by redirect");
100
- const redirectStartPage = window.location.href;
101
- this.authService.acquireTokenRedirect(Object.assign(Object.assign({}, authRequest), { scopes, redirectStartPage }));
102
- return EMPTY;
103
- }
104
- /**
105
- * Looks up the scopes for the given endpoint from the protectedResourceMap
106
- * @param endpoint Url of the request
107
- * @param httpMethod Http method of the request
108
- * @returns Array of scopes, or null if not found
109
- *
110
- */
111
- getScopesForEndpoint(endpoint, httpMethod) {
112
- this.authService.getLogger().verbose("Interceptor - getting scopes for endpoint");
113
- // Ensures endpoints and protected resources compared are normalized
114
- const normalizedEndpoint = this.location.normalize(endpoint);
115
- const protectedResourcesArray = Array.from(this.msalInterceptorConfig.protectedResourceMap.keys());
116
- const matchingProtectedResources = this.matchResourcesToEndpoint(protectedResourcesArray, normalizedEndpoint);
117
- // Check absolute urls of resources first before checking relative to prevent incorrect matching where multiple resources have similar relative urls
118
- if (matchingProtectedResources.absoluteResources.length > 0) {
119
- return this.matchScopesToEndpoint(this.msalInterceptorConfig.protectedResourceMap, matchingProtectedResources.absoluteResources, httpMethod);
120
- }
121
- else if (matchingProtectedResources.relativeResources.length > 0) {
122
- return this.matchScopesToEndpoint(this.msalInterceptorConfig.protectedResourceMap, matchingProtectedResources.relativeResources, httpMethod);
123
- }
124
- return null;
125
- }
126
- /**
127
- * Finds resource endpoints that match request endpoint
128
- * @param protectedResourcesEndpoints
129
- * @param endpoint
130
- * @returns
131
- */
132
- matchResourcesToEndpoint(protectedResourcesEndpoints, endpoint) {
133
- const matchingResources = { absoluteResources: [], relativeResources: [] };
134
- protectedResourcesEndpoints.forEach(key => {
135
- // Normalizes and adds resource to matchingResources.absoluteResources if key matches endpoint. StringUtils.matchPattern accounts for wildcards
136
- const normalizedKey = this.location.normalize(key);
137
- if (StringUtils.matchPattern(normalizedKey, endpoint)) {
138
- matchingResources.absoluteResources.push(key);
139
- }
140
- // Get url components for relative urls
141
- const absoluteKey = this.getAbsoluteUrl(key);
142
- const keyComponents = new UrlString(absoluteKey).getUrlComponents();
143
- const absoluteEndpoint = this.getAbsoluteUrl(endpoint);
144
- const endpointComponents = new UrlString(absoluteEndpoint).getUrlComponents();
145
- // Normalized key should include query strings if applicable
146
- const relativeNormalizedKey = keyComponents.QueryString ? `${keyComponents.AbsolutePath}?${keyComponents.QueryString}` : this.location.normalize(keyComponents.AbsolutePath);
147
- // Add resource to matchingResources.relativeResources if same origin, relativeKey matches endpoint, and is not empty
148
- if (keyComponents.HostNameAndPort === endpointComponents.HostNameAndPort && StringUtils.matchPattern(relativeNormalizedKey, absoluteEndpoint) && relativeNormalizedKey !== "" && relativeNormalizedKey !== "/*") {
149
- matchingResources.relativeResources.push(key);
150
- }
151
- });
152
- return matchingResources;
153
- }
154
- /**
155
- * Transforms relative urls to absolute urls
156
- * @param url
157
- * @returns
158
- */
159
- getAbsoluteUrl(url) {
160
- const link = this._document.createElement("a");
161
- link.href = url;
162
- return link.href;
163
- }
164
- /**
165
- * Finds scopes from first matching endpoint with HTTP method that matches request
166
- * @param protectedResourceMap Protected resource map
167
- * @param endpointArray Array of resources that match request endpoint
168
- * @param httpMethod Http method of the request
169
- * @returns
170
- */
171
- matchScopesToEndpoint(protectedResourceMap, endpointArray, httpMethod) {
172
- const allMatchedScopes = [];
173
- // Check each matched endpoint for matching HttpMethod and scopes
174
- endpointArray.forEach(matchedEndpoint => {
175
- const scopesForEndpoint = [];
176
- const methodAndScopesArray = protectedResourceMap.get(matchedEndpoint);
177
- // Return if resource is unprotected
178
- if (methodAndScopesArray === null) {
179
- allMatchedScopes.push(null);
180
- return;
181
- }
182
- methodAndScopesArray.forEach(entry => {
183
- // Entry is either array of scopes or ProtectedResourceScopes object
184
- if (typeof entry === "string") {
185
- scopesForEndpoint.push(entry);
186
- }
187
- else {
188
- // Ensure methods being compared are normalized
189
- const normalizedRequestMethod = httpMethod.toLowerCase();
190
- const normalizedResourceMethod = entry.httpMethod.toLowerCase();
191
- // Method in protectedResourceMap matches request http method
192
- if (normalizedResourceMethod === normalizedRequestMethod) {
193
- // Validate if scopes comes null to unprotect the resource in a certain http method
194
- if (entry.scopes === null) {
195
- allMatchedScopes.push(null);
196
- }
197
- else {
198
- entry.scopes.forEach((scope) => {
199
- scopesForEndpoint.push(scope);
200
- });
201
- }
202
- }
203
- }
204
- });
205
- // Only add to all scopes if scopes for endpoint and method is found
206
- if (scopesForEndpoint.length > 0) {
207
- allMatchedScopes.push(scopesForEndpoint);
208
- }
209
- });
210
- if (allMatchedScopes.length > 0) {
211
- if (allMatchedScopes.length > 1) {
212
- this.authService.getLogger().warning("Interceptor - More than 1 matching scopes for endpoint found.");
213
- }
214
- // Returns scopes for first matching endpoint
215
- return allMatchedScopes[0];
216
- }
217
- return null;
218
- }
219
- }
220
- MsalInterceptor.decorators = [
221
- { type: Injectable }
222
- ];
223
- MsalInterceptor.ctorParameters = () => [
224
- { type: undefined, decorators: [{ type: Inject, args: [MSAL_INTERCEPTOR_CONFIG,] }] },
225
- { type: MsalService },
226
- { type: Location },
227
- { type: MsalBroadcastService },
228
- { type: undefined, decorators: [{ type: Inject, args: [DOCUMENT,] }] }
229
- ];
230
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibXNhbC5pbnRlcmNlcHRvci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9tc2FsLmludGVyY2VwdG9yLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7R0FHRztBQVFILE9BQU8sRUFBRSxRQUFRLEVBQUUsUUFBUSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDckQsT0FBTyxFQUFjLEtBQUssRUFBRSxFQUFFLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFDN0MsT0FBTyxFQUFFLFNBQVMsRUFBRSxVQUFVLEVBQUUsSUFBSSxFQUFFLE1BQU0sRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQ3JFLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUM3QyxPQUFPLEVBQXFDLDZCQUE2QixFQUFFLGlCQUFpQixFQUFFLGVBQWUsRUFBRSxXQUFXLEVBQUUsU0FBUyxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDbkssT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDbkQsT0FBTyxFQUFFLHVCQUF1QixFQUFFLE1BQU0sYUFBYSxDQUFDO0FBRXRELE9BQU8sRUFBRSxvQkFBb0IsRUFBRSxNQUFNLDBCQUEwQixDQUFDO0FBR2hFLE1BQU0sT0FBTyxlQUFlO0lBR3hCLFlBQzZDLHFCQUFtRCxFQUNwRixXQUF3QixFQUN4QixRQUFrQixFQUNsQixvQkFBMEM7SUFDbEQsaUhBQWlIO0lBQy9GLFFBQWM7UUFMUywwQkFBcUIsR0FBckIscUJBQXFCLENBQThCO1FBQ3BGLGdCQUFXLEdBQVgsV0FBVyxDQUFhO1FBQ3hCLGFBQVEsR0FBUixRQUFRLENBQVU7UUFDbEIseUJBQW9CLEdBQXBCLG9CQUFvQixDQUFzQjtRQUlsRCxJQUFJLENBQUMsU0FBUyxHQUFHLFFBQW9CLENBQUM7SUFDMUMsQ0FBQztJQUVELDhEQUE4RDtJQUM5RCxTQUFTLENBQUMsR0FBcUIsRUFBRSxJQUFpQjtRQUM5QyxJ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LGlCQUFpQixDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQzs0QkFDbEMsQ0FBQyxDQUFDLENBQUM7eUJBQ047cUJBQ0o7aUJBQ0o7WUFDTCxDQUFDLENBQUMsQ0FBQztZQUVILG9FQUFvRTtZQUNwRSxJQUFJLGlCQUFpQixDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUU7Z0JBQzlCLGdCQUFnQixDQUFDLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDO2FBQzVDO1FBQ0wsQ0FBQyxDQUFDLENBQUM7UUFFSCxJQUFJLGdCQUFnQixDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUU7WUFDN0IsSUFBSSxnQkFBZ0IsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFO2dCQUM3QixJQUFJLENBQUMsV0FBVyxDQUFDLFNBQVMsRUFBRSxDQUFDLE9BQU8sQ0FBQywrREFBK0QsQ0FBQyxDQUFDO2FBQ3pHO1lBQ0QsNkNBQTZDO1lBQzdDLE9BQU8sZ0JBQWdCLENBQUMsQ0FBQyxDQUFDLENBQUM7U0FDOUI7UUFFRCxPQUFPLElBQUksQ0FBQztJQUNoQixDQUFDOzs7WUE1UEosVUFBVTs7OzRDQUtGLE1BQU0sU0FBQyx1QkFBdUI7WUFaOUIsV0FBVztZQUhYLFFBQVE7WUFRUixvQkFBb0I7NENBWXBCLE1BQU0sU0FBQyxRQUFRIiwic291cmNlc0NvbnRlbnQiOlsiLypcbiAqIENvcHlyaWdodCAoYykgTWljcm9zb2Z0IENvcnBvcmF0aW9uLiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICogTGljZW5zZWQgdW5kZXIgdGhlIE1JVCBMaWNlbnNlLlxuICovXG5cbmltcG9ydCB7XG4gICAgSHR0cFJlcXVlc3QsXG4gICAgSHR0cEhhbmRsZXIsXG4gICAgSHR0cEV2ZW50LFxuICAgIEh0dHBJbnRlcmNlcHRvclxufSBmcm9tIFwiQGFuZ3VsYXIvY29tbW9uL2h0dHBcIjtcbmltcG9ydCB7IExvY2F0aW9uLCBET0NVTUVOVCB9IGZyb20gXCJAYW5ndWxhci9jb21tb25cIjtcbmltcG9ydCB7IE9ic2VydmFibGUsIEVNUFRZLCBvZiB9IGZyb20gXCJyeGpzXCI7XG5pbXBvcnQgeyBzd2l0Y2hNYXAsIGNhdGNoRXJyb3IsIHRha2UsIGZpbHRlciB9IGZyb20gXCJyeGpzL29wZXJhdG9yc1wiO1xuaW1wb3J0IHsgTXNhbFNlcnZpY2UgfSBmcm9tIFwiLi9tc2FsLnNlcnZpY2VcIjtcbmltcG9ydCB7IEFjY291bnRJbmZvLCBBdXRoZW50aWNhdGlvblJlc3VsdCwgQnJvd3NlckNvbmZpZ3VyYXRpb25BdXRoRXJyb3IsIEludGVyYWN0aW9uU3RhdHVzLCBJbnRlcmFjdGlvblR5cGUsIFN0cmluZ1V0aWxzLCBVcmxTdHJpbmcgfSBmcm9tIFwiQGF6dXJlL21zYWwtYnJvd3NlclwiO1xuaW1wb3J0IHsgSW5qZWN0YWJsZSwgSW5qZWN0IH0gZnJvbSBcIkBhbmd1bGFyL2NvcmVcIjtcbmltcG9ydCB7IE1TQUxfSU5URVJDRVBUT1JfQ09ORklHIH0gZnJvbSBcIi4vY29uc3RhbnRzXCI7XG5pbXBvcnQgeyBNc2FsSW50ZXJjZXB0b3JBdXRoUmVxdWVzdCwgTXNhbEludGVyY2VwdG9yQ29uZmlndXJhdGlvbiwgUHJvdGVjdGVkUmVzb3VyY2VTY29wZXMsIE1hdGNoaW5nUmVzb3VyY2VzIH0gZnJvbSBcIi4vbXNhbC5pbnRlcmNlcHRvci5jb25maWdcIjtcbmltcG9ydCB7IE1zYWxCcm9hZGNhc3RTZXJ2aWNlIH0gZnJvbSBcIi4vbXNhbC5icm9hZGNhc3Quc2VydmljZVwiO1xuXG5ASW5qZWN0YWJsZSgpXG5leHBvcnQgY2xhc3MgTXNhbEludGVyY2VwdG9yIGltcGxlbWVudHMgSHR0cEludGVyY2VwdG9yIHtcbiAgICBwcml2YXRlIF9kb2N1bWVudD86IERvY3VtZW50O1xuXG4gICAgY29uc3RydWN0b3IoXG4gICAgICAgIEBJbmplY3QoTVNBTF9JTlRFUkNFUFRPUl9DT05GSUcpIHByaXZhdGUgbXNhbEludGVyY2VwdG9yQ29uZmlnOiBNc2FsSW50ZXJjZXB0b3JDb25maWd1cmF0aW9uLFxuICAgICAgICBwcml2YXRlIGF1dGhTZXJ2aWNlOiBNc2FsU2VydmljZSxcbiAgICAgICAgcHJpdmF0ZSBsb2NhdGlvbjogTG9jYXRpb24sXG4gICAgICAgIHByaXZhdGUgbXNhbEJyb2FkY2FzdFNlcnZpY2U6IE1zYWxCcm9hZGNhc3RTZXJ2aWNlLFxuICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLWV4cGxpY2l0LWFueSwgQHR5cGVzY3JpcHQtZXNsaW50L2V4cGxpY2l0LW1vZHVsZS1ib3VuZGFyeS10eXBlc1xuICAgICAgICBASW5qZWN0KERPQ1VNRU5UKSBkb2N1bWVudD86IGFueVxuICAgICkge1xuICAgICAgICB0aGlzLl9kb2N1bWVudCA9IGRvY3VtZW50IGFzIERvY3VtZW50O1xuICAgIH1cblxuICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tZXhwbGljaXQtYW55XG4gICAgaW50ZXJjZXB0KHJlcTogSHR0cFJlcXVlc3Q8YW55PiwgbmV4dDogSHR0cEhhbmRsZXIpOiBPYnNlcnZhYmxlPEh0dHBFdmVudDxhbnk+PiB7XG4gICAgICAgIGlmICh0aGlzLm1zYWxJbnRlcmNlcHRvckNvbmZpZy5pbnRlcmFjdGlvblR5cGUgIT09IEludGVyYWN0aW9uVHlwZS5Qb3B1cCAmJiB0aGlzLm1zYWxJbnRlcmNlcHRvckNvbmZpZy5pbnRlcmFjdGlvblR5cGUgIT09IEludGVyYWN0aW9uVHlwZS5SZWRpcmVjdCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEJyb3dzZXJDb25maWd1cmF0aW9uQXV0aEVycm9yKFwiaW52YWxpZF9pbnRlcmFjdGlvbl90eXBlXCIsIFwiSW52YWxpZCBpbnRlcmFjdGlvbiB0eXBlIHByb3ZpZGVkIHRvIE1TQUwgSW50ZXJjZXB0b3IuIEludGVyYWN0aW9uVHlwZS5Qb3B1cCwgSW50ZXJhY3Rpb25UeXBlLlJlZGlyZWN0IG11c3QgYmUgcHJvdmlkZWQgaW4gdGhlIG1zYWxJbnRlcmNlcHRvckNvbmZpZ3VyYXRpb25cIik7XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLmF1dGhTZXJ2aWNlLmdldExvZ2dlcigpLnZlcmJvc2UoXCJNU0FMIEludGVyY2VwdG9yIGFjdGl2YXRlZFwiKTtcbiAgICAgICAgY29uc3Qgc2NvcGVzID0gdGhpcy5nZXRTY29wZXNGb3JFbmRwb2ludChyZXEudXJsLCByZXEubWV0aG9kKTtcblxuICAgICAgICAvLyBJZiBubyBzY29wZXMgZm9yIGVuZHBvaW50LCBkb2VzIG5vdCBhY3F1aXJlIHRva2VuXG4gICAgICAgIGlmICghc2NvcGVzIHx8IHNjb3Blcy5sZW5ndGggPT09IDApIHtcbiAgICAgICAgICAgIHRoaXMuYXV0aFNlcnZpY2UuZ2V0TG9nZ2VyKCkudmVyYm9zZShcIkludGVyY2VwdG9yIC0gbm8gc2NvcGVzIGZvciBlbmRwb2ludFwiKTtcbiAgICAgICAgICAgIHJldHVybiBuZXh0LmhhbmRsZShyZXEpO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gU2V0cyBhY2NvdW50IGFzIGFjdGl2ZSBhY2NvdW50IG9yIGZpcnN0IGFjY291bnRcbiAgICAgICAgbGV0IGFjY291bnQ6IEFjY291bnRJbmZvO1xuICAgICAgICBpZiAoISF0aGlzLmF1dGhTZXJ2aWNlLmluc3RhbmNlLmdldEFjdGl2ZUFjY291bnQoKSkge1xuICAgICAgICAgICAgdGhpcy5hdXRoU2VydmljZS5nZXRMb2dnZXIoKS52ZXJib3NlKFwiSW50ZXJjZXB0b3IgLSBhY3RpdmUgYWNjb3VudCBzZWxlY3RlZFwiKTtcbiAgICAgICAgICAgIGFjY291bnQgPSB0aGlzLmF1dGhTZXJ2aWNlLmluc3RhbmNlLmdldEFjdGl2ZUFjY291bnQoKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMuYXV0aFNlcnZpY2UuZ2V0TG9nZ2VyKCkudmVyYm9zZShcIkludGVyY2VwdG9yIC0gbm8gYWN0aXZlIGFjY291bnQsIGZhbGxiYWNrIHRvIGZpcnN0IGFjY291bnRcIik7XG4gICAgICAgICAgICBhY2NvdW50ID0gdGhpcy5hdXRoU2VydmljZS5pbnN0YW5jZS5nZXRBbGxBY2NvdW50cygpWzBdO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgYXV0aFJlcXVlc3QgPSB0eXBlb2YgdGhpcy5tc2FsSW50ZXJjZXB0b3JDb25maWcuYXV0aFJlcXVlc3QgPT09IFwiZnVuY3Rpb25cIlxuICAgICAgICAgICAgPyB0aGlzLm1zYWxJbnRlcmNlcHRvckNvbmZpZy5hdXRoUmVxdWVzdCh0aGlzLmF1dGhTZXJ2aWNlLCByZXEsIHsgYWNjb3VudDogYWNjb3VudCB9KVxuICAgICAgICAgICAgOiB7IC4uLnRoaXMubXNhbEludGVyY2VwdG9yQ29uZmlnLmF1dGhSZXF1ZXN0LCBhY2NvdW50IH07XG5cbiAgICAgICAgdGhpcy5hdXRoU2VydmljZS5nZXRMb2dnZXIoKS5pbmZvKGBJbnRlcmNlcHRvciAtICR7c2NvcGVzLmxlbmd0aH0gc2NvcGVzIGZvdW5kIGZvciBlbmRwb2ludGApO1xuICAgICAgICB0aGlzLmF1dGhTZXJ2aWNlLmdldExvZ2dlcigpLmluZm9QaWkoYEludGVyY2VwdG9yIC0gWyR7c2NvcGVzfV0gc2NvcGVzIGZvdW5kIGZvciAke3JlcS51cmx9YCk7XG5cbiAgICAgICAgcmV0dXJuIHRoaXMuYWNxdWlyZVRva2VuKGF1dGhSZXF1ZXN0LCBzY29wZXMsIGFjY291bnQpXG4gICAgICAgICAgICAucGlwZShcbiAgICAgICAgICAgICAgICBzd2l0Y2hNYXAoKHJlc3VsdDogQXV0aGVudGljYXRpb25SZXN1bHQpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5hdXRoU2VydmljZS5nZXRMb2dnZXIoKS52ZXJib3NlKFwiSW50ZXJjZXB0b3IgLSBzZXR0aW5nIGF1dGhvcml6YXRpb24gaGVhZGVyc1wiKTtcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgaGVhZGVycyA9IHJlcS5oZWFkZXJzXG4gICAgICAgICAgICAgICAgICAgICAgICAuc2V0KFwiQXV0aG9yaXphdGlvblwiLCBgQmVhcmVyICR7cmVzdWx0LmFjY2Vzc1Rva2VufWApO1xuXG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IHJlcXVlc3RDbG9uZSA9IHJlcS5jbG9uZSh7aGVhZGVyc30pO1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gbmV4dC5oYW5kbGUocmVxdWVzdENsb25lKTtcbiAgICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBUcnkgdG8gYWNxdWlyZSB0b2tlbiBzaWxlbnRseS4gSW52b2tlIGludGVyYWN0aW9uIGlmIGFjcXVpcmVUb2tlblNpbGVudCByZWplY3RlZCB3aXRoIGVycm9yIG9yIHJlc29sdmVkIHdpdGggbnVsbCBhY2Nlc3MgdG9rZW5cbiAgICAgKiBAcGFyYW0gYXV0aFJlcXVlc3QgUmVxdWVzdFxuICAgICAqIEBwYXJhbSBzY29wZXMgQXJyYXkgb2Ygc2NvcGVzIGZvciB0aGUgcmVxdWVzdFxuICAgICAqIEBwYXJhbSBhY2NvdW50IEFjY291bnRcbiAgICAgKiBAcmV0dXJucyBBdXRoZW50aWNhdGlvbiByZXN1bHRcbiAgICAgKi9cbiAgICBwcml2YXRlIGFjcXVpcmVUb2tlbihhdXRoUmVxdWVzdDogTXNhbEludGVyY2VwdG9yQXV0aFJlcXVlc3QsIHNjb3Blczogc3RyaW5nW10sIGFjY291bnQ6IEFjY291bnRJbmZvKTogT2JzZXJ2YWJsZTxBdXRoZW50aWNhdGlvblJlc3VsdD4ge1xuICAgICAgICAvLyBOb3RlOiBGb3IgTVNBIGFjY291bnRzLCBpbmNsdWRlIG9wZW5pZCBzY29wZSB3aGVuIGNhbGxpbmcgYWNxdWlyZVRva2VuU2lsZW50IHRvIHJldHVybiBpZFRva2VuXG4gICAgICAgIHJldHVybiB0aGlzLmF1dGhTZXJ2aWNlLmFjcXVpcmVUb2tlblNpbGVudCh7Li4uYXV0aFJlcXVlc3QsIHNjb3BlcywgYWNjb3VudCB9KVxuICAgICAgICAgICAgLnBpcGUoXG4gICAgICAgICAgICAgICAgY2F0Y2hFcnJvcigoKSA9PiB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuYXV0aFNlcnZpY2UuZ2V0TG9nZ2VyKCkuZXJyb3IoXCJJbnRlcmNlcHRvciAtIGFjcXVpcmVUb2tlblNpbGVudCByZWplY3RlZCB3aXRoIGVycm9yLiBJbnZva2luZyBpbnRlcmFjdGlvbiB0byByZXNvbHZlLlwiKTtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMubXNhbEJyb2FkY2FzdFNlcnZpY2UuaW5Qcm9ncmVzcyRcbiAgICAgICAgICAgICAgICAgICAgICAgIC5waXBlKFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRha2UoMSksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgc3dpdGNoTWFwKChzdGF0dXM6IEludGVyYWN0aW9uU3RhdHVzKSA9PiB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChzdGF0dXMgPT09IEludGVyYWN0aW9uU3RhdHVzLk5vbmUpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLmFjcXVpcmVUb2tlbkludGVyYWN0aXZlbHkoYXV0aFJlcXVlc3QsIHNjb3Blcyk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5tc2FsQnJvYWRjYXN0U2VydmljZS5pblByb2dyZXNzJFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLnBpcGUoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsdGVyKChzdGF0dXM6IEludGVyYWN0aW9uU3RhdHVzKSA9PiBzdGF0dXMgPT09IEludGVyYWN0aW9uU3RhdHVzLk5vbmUpLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRha2UoMSksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3dpdGNoTWFwKCgpID0+IHRoaXMuYWNxdWlyZVRva2VuKGF1dGhSZXF1ZXN0LCBzY29wZXMsIGFjY291bnQpKVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICB9KSxcbiAgICAgICAgICAgICAgICBzd2l0Y2hNYXAoKHJlc3VsdDogQXV0aGVudGljYXRpb25SZXN1bHQpICA9PiB7XG4gICAgICAgICAgICAgICAgICAgIGlmICghcmVzdWx0LmFjY2Vzc1Rva2VuKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmF1dGhTZXJ2aWNlLmdldExvZ2dlcigpLmVycm9yKFwiSW50ZXJjZXB0b3IgLSBhY3F1aXJlVG9rZW5TaWxlbnQgcmVzb2x2ZWQgd2l0aCBudWxsIGFjY2VzcyB0b2tlbi4gS25vd24gaXNzdWUgd2l0aCBCMkMgdGVuYW50cywgaW52b2tpbmcgaW50ZXJhY3Rpb24gdG8gcmVzb2x2ZS5cIik7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5tc2FsQnJvYWRjYXN0U2VydmljZS5pblByb2dyZXNzJFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC5waXBlKFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWx0ZXIoKHN0YXR1czogSW50ZXJhY3Rpb25TdGF0dXMpID0+IHN0YXR1cyA9PT0gSW50ZXJhY3Rpb25TdGF0dXMuTm9uZSksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRha2UoMSksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN3aXRjaE1hcCgoKSA9PiB0aGlzLmFjcXVpcmVUb2tlbkludGVyYWN0aXZlbHkoYXV0aFJlcXVlc3QsIHNjb3BlcykpXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICByZXR1cm4gb2YocmVzdWx0KTtcbiAgICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBJbnZva2UgaW50ZXJhY3Rpb24gZm9yIHRoZSBnaXZlbiBzZXQgb2Ygc2NvcGVzXG4gICAgICogQHBhcmFtIGF1dGhSZXF1ZXN0IFJlcXVlc3RcbiAgICAgKiBAcGFyYW0gc2NvcGVzIEFycmF5IG9mIHNjb3BlcyBmb3IgdGhlIHJlcXVlc3RcbiAgICAgKiBAcmV0dXJucyBSZXN1bHQgZnJvbSB0aGUgaW50ZXJhY3RpdmUgcmVxdWVzdFxuICAgICAqL1xuICAgIHByaXZhdGUgYWNxdWlyZVRva2VuSW50ZXJhY3RpdmVseShhdXRoUmVxdWVzdDogTXNhbEludGVyY2VwdG9yQXV0aFJlcXVlc3QsIHNjb3Blczogc3RyaW5nW10pOiBPYnNlcnZhYmxlPEF1dGhlbnRpY2F0aW9uUmVzdWx0PiB7XG4gICAgICAgIGlmICh0aGlzLm1zYWxJbnRlcmNlcHRvckNvbmZpZy5pbnRlcmFjdGlvblR5cGUgPT09IEludGVyYWN0aW9uVHlwZS5Qb3B1cCkge1xuICAgICAgICAgICAgdGhpcy5hdXRoU2VydmljZS5nZXRMb2dnZXIoKS52ZXJib3NlKFwiSW50ZXJjZXB0b3IgLSBlcnJvciBhY3F1aXJpbmcgdG9rZW4gc2lsZW50bHksIGFjcXVpcmluZyBieSBwb3B1cFwiKTtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLmF1dGhTZXJ2aWNlLmFjcXVpcmVUb2tlblBvcHVwKHsgLi4uYXV0aFJlcXVlc3QsIHNjb3BlcyB9KTtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLmF1dGhTZXJ2aWNlLmdldExvZ2dlcigpLnZlcmJvc2UoXCJJbnRlcmNlcHRvciAtIGVycm9yIGFjcXVpcmluZyB0b2tlbiBzaWxlbnRseSwgYWNxdWlyaW5nIGJ5IHJlZGlyZWN0XCIpO1xuICAgICAgICBjb25zdCByZWRpcmVjdFN0YXJ0UGFnZSA9IHdpbmRvdy5sb2NhdGlvbi5ocmVmO1xuICAgICAgICB0aGlzLmF1dGhTZXJ2aWNlLmFjcXVpcmVUb2tlblJlZGlyZWN0KHsuLi5hdXRoUmVxdWVzdCwgc2NvcGVzLCByZWRpcmVjdFN0YXJ0UGFnZSB9KTtcbiAgICAgICAgcmV0dXJuIEVNUFRZO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIExvb2tzIHVwIHRoZSBzY29wZXMgZm9yIHRoZSBnaXZlbiBlbmRwb2ludCBmcm9tIHRoZSBwcm90ZWN0ZWRSZXNvdXJjZU1hcFxuICAgICAqIEBwYXJhbSBlbmRwb2ludCBVcmwgb2YgdGhlIHJlcXVlc3RcbiAgICAgKiBAcGFyYW0gaHR0cE1ldGhvZCBIdHRwIG1ldGhvZCBvZiB0aGUgcmVxdWVzdFxuICAgICAqIEByZXR1cm5zIEFycmF5IG9mIHNjb3Blcywgb3IgbnVsbCBpZiBub3QgZm91bmRcbiAgICAgKlxuICAgICAqL1xuICAgIHByaXZhdGUgZ2V0U2NvcGVzRm9yRW5kcG9pbnQoZW5kcG9pbnQ6IHN0cmluZywgaHR0cE1ldGhvZDogc3RyaW5nKTogQXJyYXk8c3RyaW5nPnxudWxsIHtcbiAgICAgICAgdGhpcy5hdXRoU2VydmljZS5nZXRMb2dnZXIoKS52ZXJib3NlKFwiSW50ZXJjZXB0b3IgLSBnZXR0aW5nIHNjb3BlcyBmb3IgZW5kcG9pbnRcIik7XG5cbiAgICAgICAgLy8gRW5zdXJlcyBlbmRwb2ludHMgYW5kIHByb3RlY3RlZCByZXNvdXJjZXMgY29tcGFyZWQgYXJlIG5vcm1hbGl6ZWRcbiAgICAgICAgY29uc3Qgbm9ybWFsaXplZEVuZHBvaW50ID0gdGhpcy5sb2NhdGlvbi5ub3JtYWxpemUoZW5kcG9pbnQpO1xuXG4gICAgICAgIGNvbnN0IHByb3RlY3RlZFJlc291cmNlc0FycmF5ID0gQXJyYXkuZnJvbSh0aGlzLm1zYWxJbnRlcmNlcHRvckNvbmZpZy5wcm90ZWN0ZWRSZXNvdXJjZU1hcC5rZXlzKCkpO1xuXG4gICAgICAgIGNvbnN0IG1hdGNoaW5nUHJvdGVjdGVkUmVzb3VyY2VzID0gdGhpcy5tYXRjaFJlc291cmNlc1RvRW5kcG9pbnQocHJvdGVjdGVkUmVzb3VyY2VzQXJyYXksIG5vcm1hbGl6ZWRFbmRwb2ludCk7XG5cbiAgICAgICAgLy8gQ2hlY2sgYWJzb2x1dGUgdXJscyBvZiByZXNvdXJjZXMgZmlyc3QgYmVmb3JlIGNoZWNraW5nIHJlbGF0aXZlIHRvIHByZXZlbnQgaW5jb3JyZWN0IG1hdGNoaW5nIHdoZXJlIG11bHRpcGxlIHJlc291cmNlcyBoYXZlIHNpbWlsYXIgcmVsYXRpdmUgdXJsc1xuICAgICAgICBpZiAobWF0Y2hpbmdQcm90ZWN0ZWRSZXNvdXJjZXMuYWJzb2x1dGVSZXNvdXJjZXMubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMubWF0Y2hTY29wZXNUb0VuZHBvaW50KHRoaXMubXNhbEludGVyY2VwdG9yQ29uZmlnLnByb3RlY3RlZFJlc291cmNlTWFwLCBtYXRjaGluZ1Byb3RlY3RlZFJlc291cmNlcy5hYnNvbHV0ZVJlc291cmNlcywgaHR0cE1ldGhvZCk7XG4gICAgICAgIH0gZWxzZSBpZiAobWF0Y2hpbmdQcm90ZWN0ZWRSZXNvdXJjZXMucmVsYXRpdmVSZXNvdXJjZXMubGVuZ3RoID4gMCl7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5tYXRjaFNjb3Blc1RvRW5kcG9pbnQodGhpcy5tc2FsSW50ZXJjZXB0b3JDb25maWcucHJvdGVjdGVkUmVzb3VyY2VNYXAsIG1hdGNoaW5nUHJvdGVjdGVkUmVzb3VyY2VzLnJlbGF0aXZlUmVzb3VyY2VzLCBodHRwTWV0aG9kKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBudWxsO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEZpbmRzIHJlc291cmNlIGVuZHBvaW50cyB0aGF0IG1hdGNoIHJlcXVlc3QgZW5kcG9pbnRcbiAgICAgKiBAcGFyYW0gcHJvdGVjdGVkUmVzb3VyY2VzRW5kcG9pbnRzXG4gICAgICogQHBhcmFtIGVuZHBvaW50XG4gICAgICogQHJldHVybnNcbiAgICAgKi9cbiAgICBwcml2YXRlIG1hdGNoUmVzb3VyY2VzVG9FbmRwb2ludChwcm90ZWN0ZWRSZXNvdXJjZXNFbmRwb2ludHM6IHN0cmluZ1tdLCBlbmRwb2ludDogc3RyaW5nKTogTWF0Y2hpbmdSZXNvdXJjZXMge1xuICAgICAgICBjb25zdCBtYXRjaGluZ1Jlc291cmNlczogTWF0Y2hpbmdSZXNvdXJjZXMgPSB7YWJzb2x1dGVSZXNvdXJjZXM6IFtdLCByZWxhdGl2ZVJlc291cmNlczogW119O1xuXG4gICAgICAgIHByb3RlY3RlZFJlc291cmNlc0VuZHBvaW50cy5mb3JFYWNoKGtleSA9PiB7XG4gICAgICAgICAgICAvLyBOb3JtYWxpemVzIGFuZCBhZGRzIHJlc291cmNlIHRvIG1hdGNoaW5nUmVzb3VyY2VzLmFic29sdXRlUmVzb3VyY2VzIGlmIGtleSBtYXRjaGVzIGVuZHBvaW50LiBTdHJpbmdVdGlscy5tYXRjaFBhdHRlcm4gYWNjb3VudHMgZm9yIHdpbGRjYXJkc1xuICAgICAgICAgICAgY29uc3Qgbm9ybWFsaXplZEtleSA9IHRoaXMubG9jYXRpb24ubm9ybWFsaXplKGtleSk7XG4gICAgICAgICAgICBpZiAoU3RyaW5nVXRpbHMubWF0Y2hQYXR0ZXJuKG5vcm1hbGl6ZWRLZXksIGVuZHBvaW50KSl7XG4gICAgICAgICAgICAgICAgbWF0Y2hpbmdSZXNvdXJjZXMuYWJzb2x1dGVSZXNvdXJjZXMucHVzaChrZXkpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvLyBHZXQgdXJsIGNvbXBvbmVudHMgZm9yIHJlbGF0aXZlIHVybHNcbiAgICAgICAgICAgIGNvbnN0IGFic29sdXRlS2V5ID0gdGhpcy5nZXRBYnNvbHV0ZVVybChrZXkpO1xuICAgICAgICAgICAgY29uc3Qga2V5Q29tcG9uZW50cyA9IG5ldyBVcmxTdHJpbmcoYWJzb2x1dGVLZXkpLmdldFVybENvbXBvbmVudHMoKTtcbiAgICAgICAgICAgIGNvbnN0IGFic29sdXRlRW5kcG9pbnQgPSB0aGlzLmdldEFic29sdXRlVXJsKGVuZHBvaW50KTtcbiAgICAgICAgICAgIGNvbnN0IGVuZHBvaW50Q29tcG9uZW50cyA9IG5ldyBVcmxTdHJpbmcoYWJzb2x1dGVFbmRwb2ludCkuZ2V0VXJsQ29tcG9uZW50cygpO1xuXG4gICAgICAgICAgICAvLyBOb3JtYWxpemVkIGtleSBzaG91bGQgaW5jbHVkZSBxdWVyeSBzdHJpbmdzIGlmIGFwcGxpY2FibGVcbiAgICAgICAgICAgIGNvbnN0IHJlbGF0aXZlTm9ybWFsaXplZEtleSA9IGtleUNvbXBvbmVudHMuUXVlcnlTdHJpbmcgPyBgJHtrZXlDb21wb25lbnRzLkFic29sdXRlUGF0aH0/JHtrZXlDb21wb25lbnRzLlF1ZXJ5U3RyaW5nfWAgOiB0aGlzLmxvY2F0aW9uLm5vcm1hbGl6ZShrZXlDb21wb25lbnRzLkFic29sdXRlUGF0aCk7XG5cbiAgICAgICAgICAgIC8vIEFkZCByZXNvdXJjZSB0byBtYXRjaGluZ1Jlc291cmNlcy5yZWxhdGl2ZVJlc291cmNlcyBpZiBzYW1lIG9yaWdpbiwgcmVsYXRpdmVLZXkgbWF0Y2hlcyBlbmRwb2ludCwgYW5kIGlzIG5vdCBlbXB0eVxuICAgICAgICAgICAgaWYgKGtleUNvbXBvbmVudHMuSG9zdE5hbWVBbmRQb3J0ID09PSBlbmRwb2ludENvbXBvbmVudHMuSG9zdE5hbWVBbmRQb3J0ICYmIFN0cmluZ1V0aWxzLm1hdGNoUGF0dGVybihyZWxhdGl2ZU5vcm1hbGl6ZWRLZXksIGFic29sdXRlRW5kcG9pbnQpICYmIHJlbGF0aXZlTm9ybWFsaXplZEtleSAhPT0gXCJcIiAmJiByZWxhdGl2ZU5vcm1hbGl6ZWRLZXkgIT09IFwiLypcIil7XG4gICAgICAgICAgICAgICAgbWF0Y2hpbmdSZXNvdXJjZXMucmVsYXRpdmVSZXNvdXJjZXMucHVzaChrZXkpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcblxuICAgICAgICByZXR1cm4gbWF0Y2hpbmdSZXNvdXJjZXM7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogVHJhbnNmb3JtcyByZWxhdGl2ZSB1cmxzIHRvIGFic29sdXRlIHVybHNcbiAgICAgKiBAcGFyYW0gdXJsXG4gICAgICogQHJldHVybnNcbiAgICAgKi9cbiAgICBwcml2YXRlIGdldEFic29sdXRlVXJsKHVybDogc3RyaW5nKTogc3RyaW5nIHtcbiAgICAgICAgY29uc3QgbGluayA9IHRoaXMuX2RvY3VtZW50LmNyZWF0ZUVsZW1lbnQoXCJhXCIpO1xuICAgICAgICBsaW5rLmhyZWYgPSB1cmw7XG4gICAgICAgIHJldHVybiBsaW5rLmhyZWY7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogRmluZHMgc2NvcGVzIGZyb20gZmlyc3QgbWF0Y2hpbmcgZW5kcG9pbnQgd2l0aCBIVFRQIG1ldGhvZCB0aGF0IG1hdGNoZXMgcmVxdWVzdFxuICAgICAqIEBwYXJhbSBwcm90ZWN0ZWRSZXNvdXJjZU1hcCBQcm90ZWN0ZWQgcmVzb3VyY2UgbWFwXG4gICAgICogQHBhcmFtIGVuZHBvaW50QXJyYXkgQXJyYXkgb2YgcmVzb3VyY2VzIHRoYXQgbWF0Y2ggcmVxdWVzdCBlbmRwb2ludFxuICAgICAqIEBwYXJhbSBodHRwTWV0aG9kIEh0dHAgbWV0aG9kIG9mIHRoZSByZXF1ZXN0XG4gICAgICogQHJldHVybnNcbiAgICAgKi9cbiAgICBwcml2YXRlIG1hdGNoU2NvcGVzVG9FbmRwb2ludChwcm90ZWN0ZWRSZXNvdXJjZU1hcDogTWFwPHN0cmluZywgQXJyYXk8c3RyaW5nfFByb3RlY3RlZFJlc291cmNlU2NvcGVzPiB8IG51bGw+LCBlbmRwb2ludEFycmF5OiBzdHJpbmdbXSwgaHR0cE1ldGhvZDogc3RyaW5nKTogQXJyYXk8c3RyaW5nPnxudWxsIHtcbiAgICAgICAgY29uc3QgYWxsTWF0Y2hlZFNjb3BlcyA9IFtdO1xuXG4gICAgICAgIC8vIENoZWNrIGVhY2ggbWF0Y2hlZCBlbmRwb2ludCBmb3IgbWF0Y2hpbmcgSHR0cE1ldGhvZCBhbmQgc2NvcGVzXG4gICAgICAgIGVuZHBvaW50QXJyYXkuZm9yRWFjaChtYXRjaGVkRW5kcG9pbnQgPT4ge1xuICAgICAgICAgICAgY29uc3Qgc2NvcGVzRm9yRW5kcG9pbnQgPSBbXTtcbiAgICAgICAgICAgIGNvbnN0IG1ldGhvZEFuZFNjb3Blc0FycmF5ID0gcHJvdGVjdGVkUmVzb3VyY2VNYXAuZ2V0KG1hdGNoZWRFbmRwb2ludCk7XG5cbiAgICAgICAgICAgIC8vIFJldHVybiBpZiByZXNvdXJjZSBpcyB1bnByb3RlY3RlZFxuICAgICAgICAgICAgaWYgKG1ldGhvZEFuZFNjb3Blc0FycmF5ID09PSBudWxsKSB7XG4gICAgICAgICAgICAgICAgYWxsTWF0Y2hlZFNjb3Blcy5wdXNoKG51bGwpO1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgbWV0aG9kQW5kU2NvcGVzQXJyYXkuZm9yRWFjaChlbnRyeSA9PiB7XG4gICAgICAgICAgICAgICAgLy8gRW50cnkgaXMgZWl0aGVyIGFycmF5IG9mIHNjb3BlcyBvciBQcm90ZWN0ZWRSZXNvdXJjZVNjb3BlcyBvYmplY3RcbiAgICAgICAgICAgICAgICBpZiAodHlwZW9mIGVudHJ5ID09PSBcInN0cmluZ1wiKSB7XG4gICAgICAgICAgICAgICAgICAgIHNjb3Blc0ZvckVuZHBvaW50LnB1c2goZW50cnkpO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIEVuc3VyZSBtZXRob2RzIGJlaW5nIGNvbXBhcmVkIGFyZSBub3JtYWxpemVkXG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IG5vcm1hbGl6ZWRSZXF1ZXN0TWV0aG9kID0gaHR0cE1ldGhvZC50b0xvd2VyQ2FzZSgpO1xuICAgICAgICAgICAgICAgICAgICBjb25zdCBub3JtYWxpemVkUmVzb3VyY2VNZXRob2QgPSBlbnRyeS5odHRwTWV0aG9kLnRvTG93ZXJDYXNlKCk7XG4gICAgICAgICAgICAgICAgICAgIC8vIE1ldGhvZCBpbiBwcm90ZWN0ZWRSZXNvdXJjZU1hcCBtYXRjaGVzIHJlcXVlc3QgaHR0cCBtZXRob2RcbiAgICAgICAgICAgICAgICAgICAgaWYgKG5vcm1hbGl6ZWRSZXNvdXJjZU1ldGhvZCA9PT0gbm9ybWFsaXplZFJlcXVlc3RNZXRob2QpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIFZhbGlkYXRlIGlmIHNjb3BlcyBjb21lcyBudWxsIHRvIHVucHJvdGVjdCB0aGUgcmVzb3VyY2UgaW4gYSBjZXJ0YWluIGh0dHAgbWV0aG9kXG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoZW50cnkuc2NvcGVzID09PSBudWxsKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgYWxsTWF0Y2hlZFNjb3Blcy5wdXNoKG51bGwpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbnRyeS5zY29wZXMuZm9yRWFjaCgoc2NvcGUpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2NvcGVzRm9yRW5kcG9pbnQucHVzaChzY29wZSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgLy8gT25seSBhZGQgdG8gYWxsIHNjb3BlcyBpZiBzY29wZXMgZm9yIGVuZHBvaW50IGFuZCBtZXRob2QgaXMgZm91bmRcbiAgICAgICAgICAgIGlmIChzY29wZXNGb3JFbmRwb2ludC5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICAgICAgYWxsTWF0Y2hlZFNjb3Blcy5wdXNoKHNjb3Blc0ZvckVuZHBvaW50KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG5cbiAgICAgICAgaWYgKGFsbE1hdGNoZWRTY29wZXMubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgaWYgKGFsbE1hdGNoZWRTY29wZXMubGVuZ3RoID4gMSkge1xuICAgICAgICAgICAgICAgIHRoaXMuYXV0aFNlcnZpY2UuZ2V0TG9nZ2VyKCkud2FybmluZyhcIkludGVyY2VwdG9yIC0gTW9yZSB0aGFuIDEgbWF0Y2hpbmcgc2NvcGVzIGZvciBlbmRwb2ludCBmb3VuZC5cIik7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICAvLyBSZXR1cm5zIHNjb3BlcyBmb3IgZmlyc3QgbWF0Y2hpbmcgZW5kcG9pbnRcbiAgICAgICAgICAgIHJldHVybiBhbGxNYXRjaGVkU2NvcGVzWzBdO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuXG59XG4iXX0=
1
+ /*
2
+ * Copyright (c) Microsoft Corporation. All rights reserved.
3
+ * Licensed under the MIT License.
4
+ */
5
+ import { Location, DOCUMENT } from "@angular/common";
6
+ import { EMPTY, of } from "rxjs";
7
+ import { switchMap, catchError, take, filter } from "rxjs/operators";
8
+ import { MsalService } from "./msal.service";
9
+ import { BrowserConfigurationAuthError, InteractionStatus, InteractionType, StringUtils, UrlString } from "@azure/msal-browser";
10
+ import { Injectable, Inject } from "@angular/core";
11
+ import { MSAL_INTERCEPTOR_CONFIG } from "./constants";
12
+ import { MsalBroadcastService } from "./msal.broadcast.service";
13
+ export class MsalInterceptor {
14
+ constructor(msalInterceptorConfig, authService, location, msalBroadcastService,
15
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/explicit-module-boundary-types
16
+ document) {
17
+ this.msalInterceptorConfig = msalInterceptorConfig;
18
+ this.authService = authService;
19
+ this.location = location;
20
+ this.msalBroadcastService = msalBroadcastService;
21
+ this._document = document;
22
+ }
23
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
24
+ intercept(req, next) {
25
+ if (this.msalInterceptorConfig.interactionType !== InteractionType.Popup && this.msalInterceptorConfig.interactionType !== InteractionType.Redirect) {
26
+ throw new BrowserConfigurationAuthError("invalid_interaction_type", "Invalid interaction type provided to MSAL Interceptor. InteractionType.Popup, InteractionType.Redirect must be provided in the msalInterceptorConfiguration");
27
+ }
28
+ this.authService.getLogger().verbose("MSAL Interceptor activated");
29
+ const scopes = this.getScopesForEndpoint(req.url, req.method);
30
+ // If no scopes for endpoint, does not acquire token
31
+ if (!scopes || scopes.length === 0) {
32
+ this.authService.getLogger().verbose("Interceptor - no scopes for endpoint");
33
+ return next.handle(req);
34
+ }
35
+ // Sets account as active account or first account
36
+ let account;
37
+ if (!!this.authService.instance.getActiveAccount()) {
38
+ this.authService.getLogger().verbose("Interceptor - active account selected");
39
+ account = this.authService.instance.getActiveAccount();
40
+ }
41
+ else {
42
+ this.authService.getLogger().verbose("Interceptor - no active account, fallback to first account");
43
+ account = this.authService.instance.getAllAccounts()[0];
44
+ }
45
+ const authRequest = typeof this.msalInterceptorConfig.authRequest === "function"
46
+ ? this.msalInterceptorConfig.authRequest(this.authService, req, { account: account })
47
+ : Object.assign(Object.assign({}, this.msalInterceptorConfig.authRequest), { account });
48
+ this.authService.getLogger().info(`Interceptor - ${scopes.length} scopes found for endpoint`);
49
+ this.authService.getLogger().infoPii(`Interceptor - [${scopes}] scopes found for ${req.url}`);
50
+ return this.acquireToken(authRequest, scopes, account)
51
+ .pipe(switchMap((result) => {
52
+ this.authService.getLogger().verbose("Interceptor - setting authorization headers");
53
+ const headers = req.headers
54
+ .set("Authorization", `Bearer ${result.accessToken}`);
55
+ const requestClone = req.clone({ headers });
56
+ return next.handle(requestClone);
57
+ }));
58
+ }
59
+ /**
60
+ * Try to acquire token silently. Invoke interaction if acquireTokenSilent rejected with error or resolved with null access token
61
+ * @param authRequest Request
62
+ * @param scopes Array of scopes for the request
63
+ * @param account Account
64
+ * @returns Authentication result
65
+ */
66
+ acquireToken(authRequest, scopes, account) {
67
+ // Note: For MSA accounts, include openid scope when calling acquireTokenSilent to return idToken
68
+ return this.authService.acquireTokenSilent(Object.assign(Object.assign({}, authRequest), { scopes, account }))
69
+ .pipe(catchError(() => {
70
+ this.authService.getLogger().error("Interceptor - acquireTokenSilent rejected with error. Invoking interaction to resolve.");
71
+ return this.msalBroadcastService.inProgress$
72
+ .pipe(take(1), switchMap((status) => {
73
+ if (status === InteractionStatus.None) {
74
+ return this.acquireTokenInteractively(authRequest, scopes);
75
+ }
76
+ return this.msalBroadcastService.inProgress$
77
+ .pipe(filter((status) => status === InteractionStatus.None), take(1), switchMap(() => this.acquireToken(authRequest, scopes, account)));
78
+ }));
79
+ }), switchMap((result) => {
80
+ if (!result.accessToken) {
81
+ this.authService.getLogger().error("Interceptor - acquireTokenSilent resolved with null access token. Known issue with B2C tenants, invoking interaction to resolve.");
82
+ return this.msalBroadcastService.inProgress$
83
+ .pipe(filter((status) => status === InteractionStatus.None), take(1), switchMap(() => this.acquireTokenInteractively(authRequest, scopes)));
84
+ }
85
+ return of(result);
86
+ }));
87
+ }
88
+ /**
89
+ * Invoke interaction for the given set of scopes
90
+ * @param authRequest Request
91
+ * @param scopes Array of scopes for the request
92
+ * @returns Result from the interactive request
93
+ */
94
+ acquireTokenInteractively(authRequest, scopes) {
95
+ if (this.msalInterceptorConfig.interactionType === InteractionType.Popup) {
96
+ this.authService.getLogger().verbose("Interceptor - error acquiring token silently, acquiring by popup");
97
+ return this.authService.acquireTokenPopup(Object.assign(Object.assign({}, authRequest), { scopes }));
98
+ }
99
+ this.authService.getLogger().verbose("Interceptor - error acquiring token silently, acquiring by redirect");
100
+ const redirectStartPage = window.location.href;
101
+ this.authService.acquireTokenRedirect(Object.assign(Object.assign({}, authRequest), { scopes, redirectStartPage }));
102
+ return EMPTY;
103
+ }
104
+ /**
105
+ * Looks up the scopes for the given endpoint from the protectedResourceMap
106
+ * @param endpoint Url of the request
107
+ * @param httpMethod Http method of the request
108
+ * @returns Array of scopes, or null if not found
109
+ *
110
+ */
111
+ getScopesForEndpoint(endpoint, httpMethod) {
112
+ this.authService.getLogger().verbose("Interceptor - getting scopes for endpoint");
113
+ // Ensures endpoints and protected resources compared are normalized
114
+ const normalizedEndpoint = this.location.normalize(endpoint);
115
+ const protectedResourcesArray = Array.from(this.msalInterceptorConfig.protectedResourceMap.keys());
116
+ const matchingProtectedResources = this.matchResourcesToEndpoint(protectedResourcesArray, normalizedEndpoint);
117
+ // Check absolute urls of resources first before checking relative to prevent incorrect matching where multiple resources have similar relative urls
118
+ if (matchingProtectedResources.absoluteResources.length > 0) {
119
+ return this.matchScopesToEndpoint(this.msalInterceptorConfig.protectedResourceMap, matchingProtectedResources.absoluteResources, httpMethod);
120
+ }
121
+ else if (matchingProtectedResources.relativeResources.length > 0) {
122
+ return this.matchScopesToEndpoint(this.msalInterceptorConfig.protectedResourceMap, matchingProtectedResources.relativeResources, httpMethod);
123
+ }
124
+ return null;
125
+ }
126
+ /**
127
+ * Finds resource endpoints that match request endpoint
128
+ * @param protectedResourcesEndpoints
129
+ * @param endpoint
130
+ * @returns
131
+ */
132
+ matchResourcesToEndpoint(protectedResourcesEndpoints, endpoint) {
133
+ const matchingResources = { absoluteResources: [], relativeResources: [] };
134
+ protectedResourcesEndpoints.forEach(key => {
135
+ // Normalizes and adds resource to matchingResources.absoluteResources if key matches endpoint. StringUtils.matchPattern accounts for wildcards
136
+ const normalizedKey = this.location.normalize(key);
137
+ if (StringUtils.matchPattern(normalizedKey, endpoint)) {
138
+ matchingResources.absoluteResources.push(key);
139
+ }
140
+ // Get url components for relative urls
141
+ const absoluteKey = this.getAbsoluteUrl(key);
142
+ const keyComponents = new UrlString(absoluteKey).getUrlComponents();
143
+ const absoluteEndpoint = this.getAbsoluteUrl(endpoint);
144
+ const endpointComponents = new UrlString(absoluteEndpoint).getUrlComponents();
145
+ // Normalized key should include query strings if applicable
146
+ const relativeNormalizedKey = keyComponents.QueryString ? `${keyComponents.AbsolutePath}?${keyComponents.QueryString}` : this.location.normalize(keyComponents.AbsolutePath);
147
+ // Add resource to matchingResources.relativeResources if same origin, relativeKey matches endpoint, and is not empty
148
+ if (keyComponents.HostNameAndPort === endpointComponents.HostNameAndPort && StringUtils.matchPattern(relativeNormalizedKey, absoluteEndpoint) && relativeNormalizedKey !== "" && relativeNormalizedKey !== "/*") {
149
+ matchingResources.relativeResources.push(key);
150
+ }
151
+ });
152
+ return matchingResources;
153
+ }
154
+ /**
155
+ * Transforms relative urls to absolute urls
156
+ * @param url
157
+ * @returns
158
+ */
159
+ getAbsoluteUrl(url) {
160
+ const link = this._document.createElement("a");
161
+ link.href = url;
162
+ return link.href;
163
+ }
164
+ /**
165
+ * Finds scopes from first matching endpoint with HTTP method that matches request
166
+ * @param protectedResourceMap Protected resource map
167
+ * @param endpointArray Array of resources that match request endpoint
168
+ * @param httpMethod Http method of the request
169
+ * @returns
170
+ */
171
+ matchScopesToEndpoint(protectedResourceMap, endpointArray, httpMethod) {
172
+ const allMatchedScopes = [];
173
+ // Check each matched endpoint for matching HttpMethod and scopes
174
+ endpointArray.forEach(matchedEndpoint => {
175
+ const scopesForEndpoint = [];
176
+ const methodAndScopesArray = protectedResourceMap.get(matchedEndpoint);
177
+ // Return if resource is unprotected
178
+ if (methodAndScopesArray === null) {
179
+ allMatchedScopes.push(null);
180
+ return;
181
+ }
182
+ methodAndScopesArray.forEach(entry => {
183
+ // Entry is either array of scopes or ProtectedResourceScopes object
184
+ if (typeof entry === "string") {
185
+ scopesForEndpoint.push(entry);
186
+ }
187
+ else {
188
+ // Ensure methods being compared are normalized
189
+ const normalizedRequestMethod = httpMethod.toLowerCase();
190
+ const normalizedResourceMethod = entry.httpMethod.toLowerCase();
191
+ // Method in protectedResourceMap matches request http method
192
+ if (normalizedResourceMethod === normalizedRequestMethod) {
193
+ // Validate if scopes comes null to unprotect the resource in a certain http method
194
+ if (entry.scopes === null) {
195
+ allMatchedScopes.push(null);
196
+ }
197
+ else {
198
+ entry.scopes.forEach((scope) => {
199
+ scopesForEndpoint.push(scope);
200
+ });
201
+ }
202
+ }
203
+ }
204
+ });
205
+ // Only add to all scopes if scopes for endpoint and method is found
206
+ if (scopesForEndpoint.length > 0) {
207
+ allMatchedScopes.push(scopesForEndpoint);
208
+ }
209
+ });
210
+ if (allMatchedScopes.length > 0) {
211
+ if (allMatchedScopes.length > 1) {
212
+ this.authService.getLogger().warning("Interceptor - More than 1 matching scopes for endpoint found.");
213
+ }
214
+ // Returns scopes for first matching endpoint
215
+ return allMatchedScopes[0];
216
+ }
217
+ return null;
218
+ }
219
+ }
220
+ MsalInterceptor.decorators = [
221
+ { type: Injectable }
222
+ ];
223
+ MsalInterceptor.ctorParameters = () => [
224
+ { type: undefined, decorators: [{ type: Inject, args: [MSAL_INTERCEPTOR_CONFIG,] }] },
225
+ { type: MsalService },
226
+ { type: Location },
227
+ { type: MsalBroadcastService },
228
+ { type: undefined, decorators: [{ type: Inject, args: [DOCUMENT,] }] }
229
+ ];
230
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibXNhbC5pbnRlcmNlcHRvci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9tc2FsLmludGVyY2VwdG9yLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7R0FHRztBQVFILE9BQU8sRUFBRSxRQUFRLEVBQUUsUUFBUSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDckQsT0FBTyxFQUFjLEtBQUssRUFBRSxFQUFFLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFDN0MsT0FBTyxFQUFFLFNBQVMsRUFBRSxVQUFVLEVBQUUsSUFBSSxFQUFFLE1BQU0sRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQ3JFLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUM3QyxPQUFPLEVBQXFDLDZCQUE2QixFQUFFLGlCQUFpQixFQUFFLGVBQWUsRUFBRSxXQUFXLEVBQUUsU0FBUyxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDbkssT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDbkQsT0FBTyxFQUFFLHVCQUF1QixFQUFFLE1BQU0sYUFBYSxDQUFDO0FBRXRELE9BQU8sRUFBRSxvQkFBb0IsRUFBRSxNQUFNLDBCQUEwQixDQUFDO0FBR2hFLE1BQU0sT0FBTyxlQUFlO0lBR3hCLFlBQzZDLHFCQUFtRCxFQUNwRixXQUF3QixFQUN4QixRQUFrQixFQUNsQixvQkFBMEM7SUFDbEQsaUhBQWlIO0lBQy9GLFFBQWM7UUFMUywwQkFBcUIsR0FBckIscUJBQXFCLENBQThCO1FBQ3BGLGdCQUFXLEdBQVgsV0FBVyxDQUFhO1FBQ3hCLGFBQVEsR0FBUixRQUFRLENBQVU7UUFDbEIseUJBQW9CLEdBQXBCLG9CQUFvQixDQUFzQjtRQUlsRCxJQUFJLENBQUMsU0FBUyxHQUFHLFFBQW9CLENBQUM7SUFDMUMsQ0FBQztJQUVELDhEQUE4RDtJQUM5RCxTQUFTLENBQUMsR0FBcUIsRUFBRSxJQUFpQjtRQUM5QyxJ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LGlCQUFpQixDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQzs0QkFDbEMsQ0FBQyxDQUFDLENBQUM7eUJBQ047cUJBQ0o7aUJBQ0o7WUFDTCxDQUFDLENBQUMsQ0FBQztZQUVILG9FQUFvRTtZQUNwRSxJQUFJLGlCQUFpQixDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUU7Z0JBQzlCLGdCQUFnQixDQUFDLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDO2FBQzVDO1FBQ0wsQ0FBQyxDQUFDLENBQUM7UUFFSCxJQUFJLGdCQUFnQixDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUU7WUFDN0IsSUFBSSxnQkFBZ0IsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFO2dCQUM3QixJQUFJLENBQUMsV0FBVyxDQUFDLFNBQVMsRUFBRSxDQUFDLE9BQU8sQ0FBQywrREFBK0QsQ0FBQyxDQUFDO2FBQ3pHO1lBQ0QsNkNBQTZDO1lBQzdDLE9BQU8sZ0JBQWdCLENBQUMsQ0FBQyxDQUFDLENBQUM7U0FDOUI7UUFFRCxPQUFPLElBQUksQ0FBQztJQUNoQixDQUFDOzs7WUE1UEosVUFBVTs7OzRDQUtGLE1BQU0sU0FBQyx1QkFBdUI7WUFaOUIsV0FBVztZQUhYLFFBQVE7WUFRUixvQkFBb0I7NENBWXBCLE1BQU0sU0FBQyxRQUFRIiwic291cmNlc0NvbnRlbnQiOlsiLypcclxuICogQ29weXJpZ2h0IChjKSBNaWNyb3NvZnQgQ29ycG9yYXRpb24uIEFsbCByaWdodHMgcmVzZXJ2ZWQuXHJcbiAqIExpY2Vuc2VkIHVuZGVyIHRoZSBNSVQgTGljZW5zZS5cclxuICovXHJcblxyXG5pbXBvcnQge1xyXG4gICAgSHR0cFJlcXVlc3QsXHJcbiAgICBIdHRwSGFuZGxlcixcclxuICAgIEh0dHBFdmVudCxcclxuICAgIEh0dHBJbnRlcmNlcHRvclxyXG59IGZyb20gXCJAYW5ndWxhci9jb21tb24vaHR0cFwiO1xyXG5pbXBvcnQgeyBMb2NhdGlvbiwgRE9DVU1FTlQgfSBmcm9tIFwiQGFuZ3VsYXIvY29tbW9uXCI7XHJcbmltcG9ydCB7IE9ic2VydmFibGUsIEVNUFRZLCBvZiB9IGZyb20gXCJyeGpzXCI7XHJcbmltcG9ydCB7IHN3aXRjaE1hcCwgY2F0Y2hFcnJvciwgdGFrZSwgZmlsdGVyIH0gZnJvbSBcInJ4anMvb3BlcmF0b3JzXCI7XHJcbmltcG9ydCB7IE1zYWxTZXJ2aWNlIH0gZnJvbSBcIi4vbXNhbC5zZXJ2aWNlXCI7XHJcbmltcG9ydCB7IEFjY291bnRJbmZvLCBBdXRoZW50aWNhdGlvblJlc3VsdCwgQnJvd3NlckNvbmZpZ3VyYXRpb25BdXRoRXJyb3IsIEludGVyYWN0aW9uU3RhdHVzLCBJbnRlcmFjdGlvblR5cGUsIFN0cmluZ1V0aWxzLCBVcmxTdHJpbmcgfSBmcm9tIFwiQGF6dXJlL21zYWwtYnJvd3NlclwiO1xyXG5pbXBvcnQgeyBJbmplY3RhYmxlLCBJbmplY3QgfSBmcm9tIFwiQGFuZ3VsYXIvY29yZVwiO1xyXG5pbXBvcnQgeyBNU0FMX0lOVEVSQ0VQVE9SX0NPTkZJRyB9IGZyb20gXCIuL2NvbnN0YW50c1wiO1xyXG5pbXBvcnQgeyBNc2FsSW50ZXJjZXB0b3JBdXRoUmVxdWVzdCwgTXNhbEludGVyY2VwdG9yQ29uZmlndXJhdGlvbiwgUHJvdGVjdGVkUmVzb3VyY2VTY29wZXMsIE1hdGNoaW5nUmVzb3VyY2VzIH0gZnJvbSBcIi4vbXNhbC5pbnRlcmNlcHRvci5jb25maWdcIjtcclxuaW1wb3J0IHsgTXNhbEJyb2FkY2FzdFNlcnZpY2UgfSBmcm9tIFwiLi9tc2FsLmJyb2FkY2FzdC5zZXJ2aWNlXCI7XHJcblxyXG5ASW5qZWN0YWJsZSgpXHJcbmV4cG9ydCBjbGFzcyBNc2FsSW50ZXJjZXB0b3IgaW1wbGVtZW50cyBIdHRwSW50ZXJjZXB0b3Ige1xyXG4gICAgcHJpdmF0ZSBfZG9jdW1lbnQ/OiBEb2N1bWVudDtcclxuXHJcbiAgICBjb25zdHJ1Y3RvcihcclxuICAgICAgICBASW5qZWN0KE1TQUxfSU5URVJDRVBUT1JfQ09ORklHKSBwcml2YXRlIG1zYWxJbnRlcmNlcHRvckNvbmZpZzogTXNhbEludGVyY2VwdG9yQ29uZmlndXJhdGlvbixcclxuICAgICAgICBwcml2YXRlIGF1dGhTZXJ2aWNlOiBNc2FsU2VydmljZSxcclxuICAgICAgICBwcml2YXRlIGxvY2F0aW9uOiBMb2NhdGlvbixcclxuICAgICAgICBwcml2YXRlIG1zYWxCcm9hZGNhc3RTZXJ2aWNlOiBNc2FsQnJvYWRjYXN0U2VydmljZSxcclxuICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLWV4cGxpY2l0LWFueSwgQHR5cGVzY3JpcHQtZXNsaW50L2V4cGxpY2l0LW1vZHVsZS1ib3VuZGFyeS10eXBlc1xyXG4gICAgICAgIEBJbmplY3QoRE9DVU1FTlQpIGRvY3VtZW50PzogYW55XHJcbiAgICApIHtcclxuICAgICAgICB0aGlzLl9kb2N1bWVudCA9IGRvY3VtZW50IGFzIERvY3VtZW50O1xyXG4gICAgfVxyXG5cclxuICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tZXhwbGljaXQtYW55XHJcbiAgICBpbnRlcmNlcHQocmVxOiBIdHRwUmVxdWVzdDxhbnk+LCBuZXh0OiBIdHRwSGFuZGxlcik6IE9ic2VydmFibGU8SHR0cEV2ZW50PGFueT4+IHtcclxuICAgICAgICBpZiAodGhpcy5tc2FsSW50ZXJjZXB0b3JDb25maWcuaW50ZXJhY3Rpb25UeXBlICE9PSBJbnRlcmFjdGlvblR5cGUuUG9wdXAgJiYgdGhpcy5tc2FsSW50ZXJjZXB0b3JDb25maWcuaW50ZXJhY3Rpb25UeXBlICE9PSBJbnRlcmFjdGlvblR5cGUuUmVkaXJlY3QpIHtcclxuICAgICAgICAgICAgdGhyb3cgbmV3IEJyb3dzZXJDb25maWd1cmF0aW9uQXV0aEVycm9yKFwiaW52YWxpZF9pbnRlcmFjdGlvbl90eXBlXCIsIFwiSW52YWxpZCBpbnRlcmFjdGlvbiB0eXBlIHByb3ZpZGVkIHRvIE1TQUwgSW50ZXJjZXB0b3IuIEludGVyYWN0aW9uVHlwZS5Qb3B1cCwgSW50ZXJhY3Rpb25UeXBlLlJlZGlyZWN0IG11c3QgYmUgcHJvdmlkZWQgaW4gdGhlIG1zYWxJbnRlcmNlcHRvckNvbmZpZ3VyYXRpb25cIik7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICB0aGlzLmF1dGhTZXJ2aWNlLmdldExvZ2dlcigpLnZlcmJvc2UoXCJNU0FMIEludGVyY2VwdG9yIGFjdGl2YXRlZFwiKTtcclxuICAgICAgICBjb25zdCBzY29wZXMgPSB0aGlzLmdldFNjb3Blc0ZvckVuZHBvaW50KHJlcS51cmwsIHJlcS5tZXRob2QpO1xyXG5cclxuICAgICAgICAvLyBJZiBubyBzY29wZXMgZm9yIGVuZHBvaW50LCBkb2VzIG5vdCBhY3F1aXJlIHRva2VuXHJcbiAgICAgICAgaWYgKCFzY29wZXMgfHwgc2NvcGVzLmxlbmd0aCA9PT0gMCkge1xyXG4gICAgICAgICAgICB0aGlzLmF1dGhTZXJ2aWNlLmdldExvZ2dlcigpLnZlcmJvc2UoXCJJbnRlcmNlcHRvciAtIG5vIHNjb3BlcyBmb3IgZW5kcG9pbnRcIik7XHJcbiAgICAgICAgICAgIHJldHVybiBuZXh0LmhhbmRsZShyZXEpO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gU2V0cyBhY2NvdW50IGFzIGFjdGl2ZSBhY2NvdW50IG9yIGZpcnN0IGFjY291bnRcclxuICAgICAgICBsZXQgYWNjb3VudDogQWNjb3VudEluZm87XHJcbiAgICAgICAgaWYgKCEhdGhpcy5hdXRoU2VydmljZS5pbnN0YW5jZS5nZXRBY3RpdmVBY2NvdW50KCkpIHtcclxuICAgICAgICAgICAgdGhpcy5hdXRoU2VydmljZS5nZXRMb2dnZXIoKS52ZXJib3NlKFwiSW50ZXJjZXB0b3IgLSBhY3RpdmUgYWNjb3VudCBzZWxlY3RlZFwiKTtcclxuICAgICAgICAgICAgYWNjb3VudCA9IHRoaXMuYXV0aFNlcnZpY2UuaW5zdGFuY2UuZ2V0QWN0aXZlQWNjb3VudCgpO1xyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgIHRoaXMuYXV0aFNlcnZpY2UuZ2V0TG9nZ2VyKCkudmVyYm9zZShcIkludGVyY2VwdG9yIC0gbm8gYWN0aXZlIGFjY291bnQsIGZhbGxiYWNrIHRvIGZpcnN0IGFjY291bnRcIik7XHJcbiAgICAgICAgICAgIGFjY291bnQgPSB0aGlzLmF1dGhTZXJ2aWNlLmluc3RhbmNlLmdldEFsbEFjY291bnRzKClbMF07XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICBjb25zdCBhdXRoUmVxdWVzdCA9IHR5cGVvZiB0aGlzLm1zYWxJbnRlcmNlcHRvckNvbmZpZy5hdXRoUmVxdWVzdCA9PT0gXCJmdW5jdGlvblwiXHJcbiAgICAgICAgICAgID8gdGhpcy5tc2FsSW50ZXJjZXB0b3JDb25maWcuYXV0aFJlcXVlc3QodGhpcy5hdXRoU2VydmljZSwgcmVxLCB7IGFjY291bnQ6IGFjY291bnQgfSlcclxuICAgICAgICAgICAgOiB7IC4uLnRoaXMubXNhbEludGVyY2VwdG9yQ29uZmlnLmF1dGhSZXF1ZXN0LCBhY2NvdW50IH07XHJcblxyXG4gICAgICAgIHRoaXMuYXV0aFNlcnZpY2UuZ2V0TG9nZ2VyKCkuaW5mbyhgSW50ZXJjZXB0b3IgLSAke3Njb3Blcy5sZW5ndGh9IHNjb3BlcyBmb3VuZCBmb3IgZW5kcG9pbnRgKTtcclxuICAgICAgICB0aGlzLmF1dGhTZXJ2aWNlLmdldExvZ2dlcigpLmluZm9QaWkoYEludGVyY2VwdG9yIC0gWyR7c2NvcGVzfV0gc2NvcGVzIGZvdW5kIGZvciAke3JlcS51cmx9YCk7XHJcblxyXG4gICAgICAgIHJldHVybiB0aGlzLmFjcXVpcmVUb2tlbihhdXRoUmVxdWVzdCwgc2NvcGVzLCBhY2NvdW50KVxyXG4gICAgICAgICAgICAucGlwZShcclxuICAgICAgICAgICAgICAgIHN3aXRjaE1hcCgocmVzdWx0OiBBdXRoZW50aWNhdGlvblJlc3VsdCkgPT4ge1xyXG4gICAgICAgICAgICAgICAgICAgIHRoaXMuYXV0aFNlcnZpY2UuZ2V0TG9nZ2VyKCkudmVyYm9zZShcIkludGVyY2VwdG9yIC0gc2V0dGluZyBhdXRob3JpemF0aW9uIGhlYWRlcnNcIik7XHJcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgaGVhZGVycyA9IHJlcS5oZWFkZXJzXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIC5zZXQoXCJBdXRob3JpemF0aW9uXCIsIGBCZWFyZXIgJHtyZXN1bHQuYWNjZXNzVG9rZW59YCk7XHJcblxyXG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IHJlcXVlc3RDbG9uZSA9IHJlcS5jbG9uZSh7aGVhZGVyc30pO1xyXG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBuZXh0LmhhbmRsZShyZXF1ZXN0Q2xvbmUpO1xyXG4gICAgICAgICAgICAgICAgfSlcclxuICAgICAgICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvKipcclxuICAgICAqIFRyeSB0byBhY3F1aXJlIHRva2VuIHNpbGVudGx5LiBJbnZva2UgaW50ZXJhY3Rpb24gaWYgYWNxdWlyZVRva2VuU2lsZW50IHJlamVjdGVkIHdpdGggZXJyb3Igb3IgcmVzb2x2ZWQgd2l0aCBudWxsIGFjY2VzcyB0b2tlblxyXG4gICAgICogQHBhcmFtIGF1dGhSZXF1ZXN0IFJlcXVlc3RcclxuICAgICAqIEBwYXJhbSBzY29wZXMgQXJyYXkgb2Ygc2NvcGVzIGZvciB0aGUgcmVxdWVzdFxyXG4gICAgICogQHBhcmFtIGFjY291bnQgQWNjb3VudFxyXG4gICAgICogQHJldHVybnMgQXV0aGVudGljYXRpb24gcmVzdWx0XHJcbiAgICAgKi9cclxuICAgIHByaXZhdGUgYWNxdWlyZVRva2VuKGF1dGhSZXF1ZXN0OiBNc2FsSW50ZXJjZXB0b3JBdXRoUmVxdWVzdCwgc2NvcGVzOiBzdHJpbmdbXSwgYWNjb3VudDogQWNjb3VudEluZm8pOiBPYnNlcnZhYmxlPEF1dGhlbnRpY2F0aW9uUmVzdWx0PiB7XHJcbiAgICAgICAgLy8gTm90ZTogRm9yIE1TQSBhY2NvdW50cywgaW5jbHVkZSBvcGVuaWQgc2NvcGUgd2hlbiBjYWxsaW5nIGFjcXVpcmVUb2tlblNpbGVudCB0byByZXR1cm4gaWRUb2tlblxyXG4gICAgICAgIHJldHVybiB0aGlzLmF1dGhTZXJ2aWNlLmFjcXVpcmVUb2tlblNpbGVudCh7Li4uYXV0aFJlcXVlc3QsIHNjb3BlcywgYWNjb3VudCB9KVxyXG4gICAgICAgICAgICAucGlwZShcclxuICAgICAgICAgICAgICAgIGNhdGNoRXJyb3IoKCkgPT4ge1xyXG4gICAgICAgICAgICAgICAgICAgIHRoaXMuYXV0aFNlcnZpY2UuZ2V0TG9nZ2VyKCkuZXJyb3IoXCJJbnRlcmNlcHRvciAtIGFjcXVpcmVUb2tlblNpbGVudCByZWplY3RlZCB3aXRoIGVycm9yLiBJbnZva2luZyBpbnRlcmFjdGlvbiB0byByZXNvbHZlLlwiKTtcclxuICAgICAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5tc2FsQnJvYWRjYXN0U2VydmljZS5pblByb2dyZXNzJFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAucGlwZShcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRha2UoMSksXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzd2l0Y2hNYXAoKHN0YXR1czogSW50ZXJhY3Rpb25TdGF0dXMpID0+IHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoc3RhdHVzID09PSBJbnRlcmFjdGlvblN0YXR1cy5Ob25lKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLmFjcXVpcmVUb2tlbkludGVyYWN0aXZlbHkoYXV0aFJlcXVlc3QsIHNjb3Blcyk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5tc2FsQnJvYWRjYXN0U2VydmljZS5pblByb2dyZXNzJFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAucGlwZShcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbHRlcigoc3RhdHVzOiBJbnRlcmFjdGlvblN0YXR1cykgPT4gc3RhdHVzID09PSBJbnRlcmFjdGlvblN0YXR1cy5Ob25lKSxcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRha2UoMSksXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzd2l0Y2hNYXAoKCkgPT4gdGhpcy5hY3F1aXJlVG9rZW4oYXV0aFJlcXVlc3QsIHNjb3BlcywgYWNjb3VudCkpXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KVxyXG4gICAgICAgICAgICAgICAgICAgICAgICApO1xyXG4gICAgICAgICAgICAgICAgfSksXHJcbiAgICAgICAgICAgICAgICBzd2l0Y2hNYXAoKHJlc3VsdDogQXV0aGVudGljYXRpb25SZXN1bHQpICA9PiB7XHJcbiAgICAgICAgICAgICAgICAgICAgaWYgKCFyZXN1bHQuYWNjZXNzVG9rZW4pIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5hdXRoU2VydmljZS5nZXRMb2dnZXIoKS5lcnJvcihcIkludGVyY2VwdG9yIC0gYWNxdWlyZVRva2VuU2lsZW50IHJlc29sdmVkIHdpdGggbnVsbCBhY2Nlc3MgdG9rZW4uIEtub3duIGlzc3VlIHdpdGggQjJDIHRlbmFudHMsIGludm9raW5nIGludGVyYWN0aW9uIHRvIHJlc29sdmUuXCIpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5tc2FsQnJvYWRjYXN0U2VydmljZS5pblByb2dyZXNzJFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLnBpcGUoXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsdGVyKChzdGF0dXM6IEludGVyYWN0aW9uU3RhdHVzKSA9PiBzdGF0dXMgPT09IEludGVyYWN0aW9uU3RhdHVzLk5vbmUpLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRha2UoMSksXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3dpdGNoTWFwKCgpID0+IHRoaXMuYWNxdWlyZVRva2VuSW50ZXJhY3RpdmVseShhdXRoUmVxdWVzdCwgc2NvcGVzKSlcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICk7XHJcbiAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBvZihyZXN1bHQpO1xyXG4gICAgICAgICAgICAgICAgfSlcclxuICAgICAgICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvKipcclxuICAgICAqIEludm9rZSBpbnRlcmFjdGlvbiBmb3IgdGhlIGdpdmVuIHNldCBvZiBzY29wZXNcclxuICAgICAqIEBwYXJhbSBhdXRoUmVxdWVzdCBSZXF1ZXN0XHJcbiAgICAgKiBAcGFyYW0gc2NvcGVzIEFycmF5IG9mIHNjb3BlcyBmb3IgdGhlIHJlcXVlc3RcclxuICAgICAqIEByZXR1cm5zIFJlc3VsdCBmcm9tIHRoZSBpbnRlcmFjdGl2ZSByZXF1ZXN0XHJcbiAgICAgKi9cclxuICAgIHByaXZhdGUgYWNxdWlyZVRva2VuSW50ZXJhY3RpdmVseShhdXRoUmVxdWVzdDogTXNhbEludGVyY2VwdG9yQXV0aFJlcXVlc3QsIHNjb3Blczogc3RyaW5nW10pOiBPYnNlcnZhYmxlPEF1dGhlbnRpY2F0aW9uUmVzdWx0PiB7XHJcbiAgICAgICAgaWYgKHRoaXMubXNhbEludGVyY2VwdG9yQ29uZmlnLmludGVyYWN0aW9uVHlwZSA9PT0gSW50ZXJhY3Rpb25UeXBlLlBvcHVwKSB7XHJcbiAgICAgICAgICAgIHRoaXMuYXV0aFNlcnZpY2UuZ2V0TG9nZ2VyKCkudmVyYm9zZShcIkludGVyY2VwdG9yIC0gZXJyb3IgYWNxdWlyaW5nIHRva2VuIHNpbGVudGx5LCBhY3F1aXJpbmcgYnkgcG9wdXBcIik7XHJcbiAgICAgICAgICAgIHJldHVybiB0aGlzLmF1dGhTZXJ2aWNlLmFjcXVpcmVUb2tlblBvcHVwKHsgLi4uYXV0aFJlcXVlc3QsIHNjb3BlcyB9KTtcclxuICAgICAgICB9XHJcbiAgICAgICAgdGhpcy5hdXRoU2VydmljZS5nZXRMb2dnZXIoKS52ZXJib3NlKFwiSW50ZXJjZXB0b3IgLSBlcnJvciBhY3F1aXJpbmcgdG9rZW4gc2lsZW50bHksIGFjcXVpcmluZyBieSByZWRpcmVjdFwiKTtcclxuICAgICAgICBjb25zdCByZWRpcmVjdFN0YXJ0UGFnZSA9IHdpbmRvdy5sb2NhdGlvbi5ocmVmO1xyXG4gICAgICAgIHRoaXMuYXV0aFNlcnZpY2UuYWNxdWlyZVRva2VuUmVkaXJlY3Qoey4uLmF1dGhSZXF1ZXN0LCBzY29wZXMsIHJlZGlyZWN0U3RhcnRQYWdlIH0pO1xyXG4gICAgICAgIHJldHVybiBFTVBUWTtcclxuICAgIH1cclxuXHJcbiAgICAvKipcclxuICAgICAqIExvb2tzIHVwIHRoZSBzY29wZXMgZm9yIHRoZSBnaXZlbiBlbmRwb2ludCBmcm9tIHRoZSBwcm90ZWN0ZWRSZXNvdXJjZU1hcFxyXG4gICAgICogQHBhcmFtIGVuZHBvaW50IFVybCBvZiB0aGUgcmVxdWVzdFxyXG4gICAgICogQHBhcmFtIGh0dHBNZXRob2QgSHR0cCBtZXRob2Qgb2YgdGhlIHJlcXVlc3RcclxuICAgICAqIEByZXR1cm5zIEFycmF5IG9mIHNjb3Blcywgb3IgbnVsbCBpZiBub3QgZm91bmRcclxuICAgICAqXHJcbiAgICAgKi9cclxuICAgIHByaXZhdGUgZ2V0U2NvcGVzRm9yRW5kcG9pbnQoZW5kcG9pbnQ6IHN0cmluZywgaHR0cE1ldGhvZDogc3RyaW5nKTogQXJyYXk8c3RyaW5nPnxudWxsIHtcclxuICAgICAgICB0aGlzLmF1dGhTZXJ2aWNlLmdldExvZ2dlcigpLnZlcmJvc2UoXCJJbnRlcmNlcHRvciAtIGdldHRpbmcgc2NvcGVzIGZvciBlbmRwb2ludFwiKTtcclxuXHJcbiAgICAgICAgLy8gRW5zdXJlcyBlbmRwb2ludHMgYW5kIHByb3RlY3RlZCByZXNvdXJjZXMgY29tcGFyZWQgYXJlIG5vcm1hbGl6ZWRcclxuICAgICAgICBjb25zdCBub3JtYWxpemVkRW5kcG9pbnQgPSB0aGlzLmxvY2F0aW9uLm5vcm1hbGl6ZShlbmRwb2ludCk7XHJcblxyXG4gICAgICAgIGNvbnN0IHByb3RlY3RlZFJlc291cmNlc0FycmF5ID0gQXJyYXkuZnJvbSh0aGlzLm1zYWxJbnRlcmNlcHRvckNvbmZpZy5wcm90ZWN0ZWRSZXNvdXJjZU1hcC5rZXlzKCkpO1xyXG5cclxuICAgICAgICBjb25zdCBtYXRjaGluZ1Byb3RlY3RlZFJlc291cmNlcyA9IHRoaXMubWF0Y2hSZXNvdXJjZXNUb0VuZHBvaW50KHByb3RlY3RlZFJlc291cmNlc0FycmF5LCBub3JtYWxpemVkRW5kcG9pbnQpO1xyXG5cclxuICAgICAgICAvLyBDaGVjayBhYnNvbHV0ZSB1cmxzIG9mIHJlc291cmNlcyBmaXJzdCBiZWZvcmUgY2hlY2tpbmcgcmVsYXRpdmUgdG8gcHJldmVudCBpbmNvcnJlY3QgbWF0Y2hpbmcgd2hlcmUgbXVsdGlwbGUgcmVzb3VyY2VzIGhhdmUgc2ltaWxhciByZWxhdGl2ZSB1cmxzXHJcbiAgICAgICAgaWYgKG1hdGNoaW5nUHJvdGVjdGVkUmVzb3VyY2VzLmFic29sdXRlUmVzb3VyY2VzLmxlbmd0aCA+IDApIHtcclxuICAgICAgICAgICAgcmV0dXJuIHRoaXMubWF0Y2hTY29wZXNUb0VuZHBvaW50KHRoaXMubXNhbEludGVyY2VwdG9yQ29uZmlnLnByb3RlY3RlZFJlc291cmNlTWFwLCBtYXRjaGluZ1Byb3RlY3RlZFJlc291cmNlcy5hYnNvbHV0ZVJlc291cmNlcywgaHR0cE1ldGhvZCk7XHJcbiAgICAgICAgfSBlbHNlIGlmIChtYXRjaGluZ1Byb3RlY3RlZFJlc291cmNlcy5yZWxhdGl2ZVJlc291cmNlcy5sZW5ndGggPiAwKXtcclxuICAgICAgICAgICAgcmV0dXJuIHRoaXMubWF0Y2hTY29wZXNUb0VuZHBvaW50KHRoaXMubXNhbEludGVyY2VwdG9yQ29uZmlnLnByb3RlY3RlZFJlc291cmNlTWFwLCBtYXRjaGluZ1Byb3RlY3RlZFJlc291cmNlcy5yZWxhdGl2ZVJlc291cmNlcywgaHR0cE1ldGhvZCk7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICByZXR1cm4gbnVsbDtcclxuICAgIH1cclxuXHJcbiAgICAvKipcclxuICAgICAqIEZpbmRzIHJlc291cmNlIGVuZHBvaW50cyB0aGF0IG1hdGNoIHJlcXVlc3QgZW5kcG9pbnRcclxuICAgICAqIEBwYXJhbSBwcm90ZWN0ZWRSZXNvdXJjZXNFbmRwb2ludHNcclxuICAgICAqIEBwYXJhbSBlbmRwb2ludFxyXG4gICAgICogQHJldHVybnNcclxuICAgICAqL1xyXG4gICAgcHJpdmF0ZSBtYXRjaFJlc291cmNlc1RvRW5kcG9pbnQocHJvdGVjdGVkUmVzb3VyY2VzRW5kcG9pbnRzOiBzdHJpbmdbXSwgZW5kcG9pbnQ6IHN0cmluZyk6IE1hdGNoaW5nUmVzb3VyY2VzIHtcclxuICAgICAgICBjb25zdCBtYXRjaGluZ1Jlc291cmNlczogTWF0Y2hpbmdSZXNvdXJjZXMgPSB7YWJzb2x1dGVSZXNvdXJjZXM6IFtdLCByZWxhdGl2ZVJlc291cmNlczogW119O1xyXG5cclxuICAgICAgICBwcm90ZWN0ZWRSZXNvdXJjZXNFbmRwb2ludHMuZm9yRWFjaChrZXkgPT4ge1xyXG4gICAgICAgICAgICAvLyBOb3JtYWxpemVzIGFuZCBhZGRzIHJlc291cmNlIHRvIG1hdGNoaW5nUmVzb3VyY2VzLmFic29sdXRlUmVzb3VyY2VzIGlmIGtleSBtYXRjaGVzIGVuZHBvaW50LiBTdHJpbmdVdGlscy5tYXRjaFBhdHRlcm4gYWNjb3VudHMgZm9yIHdpbGRjYXJkc1xyXG4gICAgICAgICAgICBjb25zdCBub3JtYWxpemVkS2V5ID0gdGhpcy5sb2NhdGlvbi5ub3JtYWxpemUoa2V5KTtcclxuICAgICAgICAgICAgaWYgKFN0cmluZ1V0aWxzLm1hdGNoUGF0dGVybihub3JtYWxpemVkS2V5LCBlbmRwb2ludCkpe1xyXG4gICAgICAgICAgICAgICAgbWF0Y2hpbmdSZXNvdXJjZXMuYWJzb2x1dGVSZXNvdXJjZXMucHVzaChrZXkpO1xyXG4gICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAvLyBHZXQgdXJsIGNvbXBvbmVudHMgZm9yIHJlbGF0aXZlIHVybHNcclxuICAgICAgICAgICAgY29uc3QgYWJzb2x1dGVLZXkgPSB0aGlzLmdldEFic29sdXRlVXJsKGtleSk7XHJcbiAgICAgICAgICAgIGNvbnN0IGtleUNvbXBvbmVudHMgPSBuZXcgVXJsU3RyaW5nKGFic29sdXRlS2V5KS5nZXRVcmxDb21wb25lbnRzKCk7XHJcbiAgICAgICAgICAgIGNvbnN0IGFic29sdXRlRW5kcG9pbnQgPSB0aGlzLmdldEFic29sdXRlVXJsKGVuZHBvaW50KTtcclxuICAgICAgICAgICAgY29uc3QgZW5kcG9pbnRDb21wb25lbnRzID0gbmV3IFVybFN0cmluZyhhYnNvbHV0ZUVuZHBvaW50KS5nZXRVcmxDb21wb25lbnRzKCk7XHJcblxyXG4gICAgICAgICAgICAvLyBOb3JtYWxpemVkIGtleSBzaG91bGQgaW5jbHVkZSBxdWVyeSBzdHJpbmdzIGlmIGFwcGxpY2FibGVcclxuICAgICAgICAgICAgY29uc3QgcmVsYXRpdmVOb3JtYWxpemVkS2V5ID0ga2V5Q29tcG9uZW50cy5RdWVyeVN0cmluZyA/IGAke2tleUNvbXBvbmVudHMuQWJzb2x1dGVQYXRofT8ke2tleUNvbXBvbmVudHMuUXVlcnlTdHJpbmd9YCA6IHRoaXMubG9jYXRpb24ubm9ybWFsaXplKGtleUNvbXBvbmVudHMuQWJzb2x1dGVQYXRoKTtcclxuXHJcbiAgICAgICAgICAgIC8vIEFkZCByZXNvdXJjZSB0byBtYXRjaGluZ1Jlc291cmNlcy5yZWxhdGl2ZVJlc291cmNlcyBpZiBzYW1lIG9yaWdpbiwgcmVsYXRpdmVLZXkgbWF0Y2hlcyBlbmRwb2ludCwgYW5kIGlzIG5vdCBlbXB0eVxyXG4gICAgICAgICAgICBpZiAoa2V5Q29tcG9uZW50cy5Ib3N0TmFtZUFuZFBvcnQgPT09IGVuZHBvaW50Q29tcG9uZW50cy5Ib3N0TmFtZUFuZFBvcnQgJiYgU3RyaW5nVXRpbHMubWF0Y2hQYXR0ZXJuKHJlbGF0aXZlTm9ybWFsaXplZEtleSwgYWJzb2x1dGVFbmRwb2ludCkgJiYgcmVsYXRpdmVOb3JtYWxpemVkS2V5ICE9PSBcIlwiICYmIHJlbGF0aXZlTm9ybWFsaXplZEtleSAhPT0gXCIvKlwiKXtcclxuICAgICAgICAgICAgICAgIG1hdGNoaW5nUmVzb3VyY2VzLnJlbGF0aXZlUmVzb3VyY2VzLnB1c2goa2V5KTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH0pO1xyXG5cclxuICAgICAgICByZXR1cm4gbWF0Y2hpbmdSZXNvdXJjZXM7XHJcbiAgICB9XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBUcmFuc2Zvcm1zIHJlbGF0aXZlIHVybHMgdG8gYWJzb2x1dGUgdXJsc1xyXG4gICAgICogQHBhcmFtIHVybFxyXG4gICAgICogQHJldHVybnNcclxuICAgICAqL1xyXG4gICAgcHJpdmF0ZSBnZXRBYnNvbHV0ZVVybCh1cmw6IHN0cmluZyk6IHN0cmluZyB7XHJcbiAgICAgICAgY29uc3QgbGluayA9IHRoaXMuX2RvY3VtZW50LmNyZWF0ZUVsZW1lbnQoXCJhXCIpO1xyXG4gICAgICAgIGxpbmsuaHJlZiA9IHVybDtcclxuICAgICAgICByZXR1cm4gbGluay5ocmVmO1xyXG4gICAgfVxyXG5cclxuICAgIC8qKlxyXG4gICAgICogRmluZHMgc2NvcGVzIGZyb20gZmlyc3QgbWF0Y2hpbmcgZW5kcG9pbnQgd2l0aCBIVFRQIG1ldGhvZCB0aGF0IG1hdGNoZXMgcmVxdWVzdFxyXG4gICAgICogQHBhcmFtIHByb3RlY3RlZFJlc291cmNlTWFwIFByb3RlY3RlZCByZXNvdXJjZSBtYXBcclxuICAgICAqIEBwYXJhbSBlbmRwb2ludEFycmF5IEFycmF5IG9mIHJlc291cmNlcyB0aGF0IG1hdGNoIHJlcXVlc3QgZW5kcG9pbnRcclxuICAgICAqIEBwYXJhbSBodHRwTWV0aG9kIEh0dHAgbWV0aG9kIG9mIHRoZSByZXF1ZXN0XHJcbiAgICAgKiBAcmV0dXJuc1xyXG4gICAgICovXHJcbiAgICBwcml2YXRlIG1hdGNoU2NvcGVzVG9FbmRwb2ludChwcm90ZWN0ZWRSZXNvdXJjZU1hcDogTWFwPHN0cmluZywgQXJyYXk8c3RyaW5nfFByb3RlY3RlZFJlc291cmNlU2NvcGVzPiB8IG51bGw+LCBlbmRwb2ludEFycmF5OiBzdHJpbmdbXSwgaHR0cE1ldGhvZDogc3RyaW5nKTogQXJyYXk8c3RyaW5nPnxudWxsIHtcclxuICAgICAgICBjb25zdCBhbGxNYXRjaGVkU2NvcGVzID0gW107XHJcblxyXG4gICAgICAgIC8vIENoZWNrIGVhY2ggbWF0Y2hlZCBlbmRwb2ludCBmb3IgbWF0Y2hpbmcgSHR0cE1ldGhvZCBhbmQgc2NvcGVzXHJcbiAgICAgICAgZW5kcG9pbnRBcnJheS5mb3JFYWNoKG1hdGNoZWRFbmRwb2ludCA9PiB7XHJcbiAgICAgICAgICAgIGNvbnN0IHNjb3Blc0ZvckVuZHBvaW50ID0gW107XHJcbiAgICAgICAgICAgIGNvbnN0IG1ldGhvZEFuZFNjb3Blc0FycmF5ID0gcHJvdGVjdGVkUmVzb3VyY2VNYXAuZ2V0KG1hdGNoZWRFbmRwb2ludCk7XHJcblxyXG4gICAgICAgICAgICAvLyBSZXR1cm4gaWYgcmVzb3VyY2UgaXMgdW5wcm90ZWN0ZWRcclxuICAgICAgICAgICAgaWYgKG1ldGhvZEFuZFNjb3Blc0FycmF5ID09PSBudWxsKSB7XHJcbiAgICAgICAgICAgICAgICBhbGxNYXRjaGVkU2NvcGVzLnB1c2gobnVsbCk7XHJcbiAgICAgICAgICAgICAgICByZXR1cm47XHJcbiAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgIG1ldGhvZEFuZFNjb3Blc0FycmF5LmZvckVhY2goZW50cnkgPT4ge1xyXG4gICAgICAgICAgICAgICAgLy8gRW50cnkgaXMgZWl0aGVyIGFycmF5IG9mIHNjb3BlcyBvciBQcm90ZWN0ZWRSZXNvdXJjZVNjb3BlcyBvYmplY3RcclxuICAgICAgICAgICAgICAgIGlmICh0eXBlb2YgZW50cnkgPT09IFwic3RyaW5nXCIpIHtcclxuICAgICAgICAgICAgICAgICAgICBzY29wZXNGb3JFbmRwb2ludC5wdXNoKGVudHJ5KTtcclxuICAgICAgICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgICAgICAgICAgLy8gRW5zdXJlIG1ldGhvZHMgYmVpbmcgY29tcGFyZWQgYXJlIG5vcm1hbGl6ZWRcclxuICAgICAgICAgICAgICAgICAgICBjb25zdCBub3JtYWxpemVkUmVxdWVzdE1ldGhvZCA9IGh0dHBNZXRob2QudG9Mb3dlckNhc2UoKTtcclxuICAgICAgICAgICAgICAgICAgICBjb25zdCBub3JtYWxpemVkUmVzb3VyY2VNZXRob2QgPSBlbnRyeS5odHRwTWV0aG9kLnRvTG93ZXJDYXNlKCk7XHJcbiAgICAgICAgICAgICAgICAgICAgLy8gTWV0aG9kIGluIHByb3RlY3RlZFJlc291cmNlTWFwIG1hdGNoZXMgcmVxdWVzdCBodHRwIG1ldGhvZFxyXG4gICAgICAgICAgICAgICAgICAgIGlmIChub3JtYWxpemVkUmVzb3VyY2VNZXRob2QgPT09IG5vcm1hbGl6ZWRSZXF1ZXN0TWV0aG9kKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIFZhbGlkYXRlIGlmIHNjb3BlcyBjb21lcyBudWxsIHRvIHVucHJvdGVjdCB0aGUgcmVzb3VyY2UgaW4gYSBjZXJ0YWluIGh0dHAgbWV0aG9kXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChlbnRyeS5zY29wZXMgPT09IG51bGwpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFsbE1hdGNoZWRTY29wZXMucHVzaChudWxsKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVudHJ5LnNjb3Blcy5mb3JFYWNoKChzY29wZSkgPT4ge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNjb3Blc0ZvckVuZHBvaW50LnB1c2goc2NvcGUpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfSk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH0pO1xyXG5cclxuICAgICAgICAgICAgLy8gT25seSBhZGQgdG8gYWxsIHNjb3BlcyBpZiBzY29wZXMgZm9yIGVuZHBvaW50IGFuZCBtZXRob2QgaXMgZm91bmRcclxuICAgICAgICAgICAgaWYgKHNjb3Blc0ZvckVuZHBvaW50Lmxlbmd0aCA+IDApIHtcclxuICAgICAgICAgICAgICAgIGFsbE1hdGNoZWRTY29wZXMucHVzaChzY29wZXNGb3JFbmRwb2ludCk7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICB9KTtcclxuXHJcbiAgICAgICAgaWYgKGFsbE1hdGNoZWRTY29wZXMubGVuZ3RoID4gMCkge1xyXG4gICAgICAgICAgICBpZiAoYWxsTWF0Y2hlZFNjb3Blcy5sZW5ndGggPiAxKSB7XHJcbiAgICAgICAgICAgICAgICB0aGlzLmF1dGhTZXJ2aWNlLmdldExvZ2dlcigpLndhcm5pbmcoXCJJbnRlcmNlcHRvciAtIE1vcmUgdGhhbiAxIG1hdGNoaW5nIHNjb3BlcyBmb3IgZW5kcG9pbnQgZm91bmQuXCIpO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIC8vIFJldHVybnMgc2NvcGVzIGZvciBmaXJzdCBtYXRjaGluZyBlbmRwb2ludFxyXG4gICAgICAgICAgICByZXR1cm4gYWxsTWF0Y2hlZFNjb3Blc1swXTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIHJldHVybiBudWxsO1xyXG4gICAgfVxyXG5cclxufVxyXG4iXX0=