@vcd/sdk 0.13.0 → 15.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -118
- package/client/client/api.result.service.d.ts +20 -0
- package/client/client/constants.d.ts +10 -0
- package/client/client/index.d.ts +7 -0
- package/client/client/logging.interceptor.d.ts +14 -0
- package/client/client/request.headers.interceptor.d.ts +20 -0
- package/client/client/response.normalization.interceptor.d.ts +39 -0
- package/client/client/vcd.api.client.d.ts +351 -0
- package/client/client/vcd.http.client.d.ts +32 -0
- package/client/client/vcd.transfer.client.d.ts +121 -0
- package/client/container-hooks/index.d.ts +58 -0
- package/client/index.d.ts +2 -0
- package/client/openapi.d.ts +76 -0
- package/client/query/filter.builder.d.ts +162 -0
- package/client/query/index.d.ts +2 -0
- package/client/query/query.builder.d.ts +30 -0
- package/common/container-hooks.d.ts +2 -2
- package/core/plugin.module.d.ts +10 -5
- package/esm2020/client/client/api.result.service.mjs +43 -0
- package/esm2020/client/client/constants.mjs +13 -0
- package/esm2020/client/client/index.mjs +8 -0
- package/esm2020/client/client/logging.interceptor.mjs +44 -0
- package/esm2020/client/client/request.headers.interceptor.mjs +91 -0
- package/esm2020/client/client/response.normalization.interceptor.mjs +59 -0
- package/esm2020/client/client/vcd.api.client.mjs +602 -0
- package/esm2020/client/client/vcd.http.client.mjs +52 -0
- package/esm2020/client/client/vcd.transfer.client.mjs +166 -0
- package/esm2020/client/container-hooks/index.mjs +57 -0
- package/esm2020/client/index.mjs +3 -0
- package/esm2020/client/openapi.mjs +16 -0
- package/esm2020/client/query/filter.builder.mjs +195 -0
- package/esm2020/client/query/index.mjs +3 -0
- package/esm2020/client/query/query.builder.mjs +79 -0
- package/esm2020/common/container-hooks.mjs +74 -0
- package/esm2020/common/index.mjs +2 -0
- package/esm2020/core/index.mjs +2 -0
- package/esm2020/core/plugin.module.mjs +18 -0
- package/esm2020/main.mjs +45 -0
- package/esm2020/public-api.mjs +8 -0
- package/esm2020/vcd-sdk.mjs +5 -0
- package/fesm2015/vcd-sdk.mjs +1513 -0
- package/fesm2015/vcd-sdk.mjs.map +1 -0
- package/fesm2020/vcd-sdk.mjs +1508 -0
- package/fesm2020/vcd-sdk.mjs.map +1 -0
- package/index.d.ts +5 -0
- package/main.d.ts +11 -5
- package/package.json +30 -39
- package/public-api.d.ts +1 -1
- package/LICENSE.txt +0 -12
- package/bundles/vcd-sdk.umd.js +0 -810
- package/bundles/vcd-sdk.umd.js.map +0 -1
- package/bundles/vcd-sdk.umd.min.js +0 -16
- package/bundles/vcd-sdk.umd.min.js.map +0 -1
- package/esm2015/common/container-hooks.js +0 -219
- package/esm2015/common/index.js +0 -6
- package/esm2015/core/index.js +0 -6
- package/esm2015/core/plugin.module.js +0 -53
- package/esm2015/i18n/index.js +0 -8
- package/esm2015/i18n/translate.pipe.js +0 -92
- package/esm2015/i18n/translate.service.js +0 -229
- package/esm2015/i18n/translation.loader.js +0 -63
- package/esm2015/main.js +0 -37
- package/esm2015/public-api.js +0 -12
- package/esm2015/vcd-sdk.js +0 -10
- package/esm5/common/container-hooks.js +0 -266
- package/esm5/common/index.js +0 -6
- package/esm5/core/index.js +0 -6
- package/esm5/core/plugin.module.js +0 -64
- package/esm5/i18n/index.js +0 -8
- package/esm5/i18n/translate.pipe.js +0 -108
- package/esm5/i18n/translate.service.js +0 -280
- package/esm5/i18n/translation.loader.js +0 -68
- package/esm5/main.js +0 -41
- package/esm5/public-api.js +0 -12
- package/esm5/vcd-sdk.js +0 -10
- package/fesm2015/vcd-sdk.js +0 -511
- package/fesm2015/vcd-sdk.js.map +0 -1
- package/fesm5/vcd-sdk.js +0 -620
- package/fesm5/vcd-sdk.js.map +0 -1
- package/i18n/index.d.ts +0 -3
- package/i18n/translate.pipe.d.ts +0 -12
- package/i18n/translate.service.d.ts +0 -21
- package/i18n/translation.loader.d.ts +0 -11
- package/schematics/collection.json +0 -10
- package/schematics/ng-add/index.d.ts +0 -3
- package/schematics/ng-add/index.js +0 -101
- package/schematics/ng-add/index.ts +0 -134
- package/schematics/ng-add/schema.d.ts +0 -8
- package/schematics/ng-add/schema.json +0 -19
- package/vcd-sdk.d.ts +0 -5
- package/vcd-sdk.metadata.json +0 -1
|
@@ -0,0 +1,602 @@
|
|
|
1
|
+
import { Injectable, Optional } from '@angular/core';
|
|
2
|
+
import { HttpHeaders } from '@angular/common/http';
|
|
3
|
+
import { BehaviorSubject, of, throwError, merge, ReplaySubject } from 'rxjs';
|
|
4
|
+
import { catchError, tap, map, concatMap, skipWhile, switchMap, withLatestFrom, share } from 'rxjs/operators';
|
|
5
|
+
import { TaskType } from '@vcd/bindings/vcloud/api/rest/schema_v1_5';
|
|
6
|
+
import { AuthTokenHolderService, API_ROOT_URL, SESSION_SCOPE, SESSION_ORG_ID } from '../container-hooks';
|
|
7
|
+
import { VcdTransferClient } from './vcd.transfer.client';
|
|
8
|
+
import { HTTP_HEADERS } from './constants';
|
|
9
|
+
import { filter } from 'rxjs/operators';
|
|
10
|
+
import * as i0 from "@angular/core";
|
|
11
|
+
import * as i1 from "./vcd.http.client";
|
|
12
|
+
import * as i2 from "../../core/plugin.module";
|
|
13
|
+
export const TRANSFER_LINK_REL = 'upload:default';
|
|
14
|
+
export const HATEOAS_HEADER = 'Link';
|
|
15
|
+
// tslint:disable:variable-name
|
|
16
|
+
/**
|
|
17
|
+
* Parse out Link headers using a very lazily implemented pull parser
|
|
18
|
+
* @param header '<url1>;name1="value1",name2="value2",<url2>;name3="value3,value4"'
|
|
19
|
+
* @returns parsed link headers
|
|
20
|
+
*/
|
|
21
|
+
export function parseHeaderHateoasLinks(header) {
|
|
22
|
+
const results = [];
|
|
23
|
+
if (!header) {
|
|
24
|
+
return results;
|
|
25
|
+
}
|
|
26
|
+
const headerFieldMappings = {
|
|
27
|
+
href: 'href',
|
|
28
|
+
model: 'type',
|
|
29
|
+
title: 'id',
|
|
30
|
+
rel: 'rel'
|
|
31
|
+
};
|
|
32
|
+
let tokenIndex = -1;
|
|
33
|
+
function peek(token) {
|
|
34
|
+
return header.indexOf(token, tokenIndex + 1);
|
|
35
|
+
}
|
|
36
|
+
function next(token) {
|
|
37
|
+
const nextIndex = peek(token);
|
|
38
|
+
if (nextIndex === -1) {
|
|
39
|
+
throw new Error(JSON.stringify({ header, token, tokenIndex }));
|
|
40
|
+
}
|
|
41
|
+
tokenIndex = nextIndex;
|
|
42
|
+
return tokenIndex;
|
|
43
|
+
}
|
|
44
|
+
while (peek('<') > -1) {
|
|
45
|
+
try {
|
|
46
|
+
const hrefStart = next('<');
|
|
47
|
+
const hrefEnd = next('>');
|
|
48
|
+
const href = header.substring(hrefStart + 1, hrefEnd);
|
|
49
|
+
const result = { href, type: null, id: null, rel: null, vCloudExtension: [] };
|
|
50
|
+
let comma = peek(',');
|
|
51
|
+
let semicolon = peek(';');
|
|
52
|
+
while ((semicolon > -1 && comma > -1 && semicolon < comma) || (semicolon > -1 && comma === -1)) {
|
|
53
|
+
const nameStart = next(';');
|
|
54
|
+
const nameEnd = next('=');
|
|
55
|
+
const name = header.substring(nameStart + 1, nameEnd).trim().toLowerCase();
|
|
56
|
+
const valueStart = next('"');
|
|
57
|
+
const valueEnd = next('"');
|
|
58
|
+
const value = header.substring(valueStart + 1, valueEnd);
|
|
59
|
+
const mappedName = headerFieldMappings[name];
|
|
60
|
+
if (mappedName) {
|
|
61
|
+
// @ts-ignore
|
|
62
|
+
result[mappedName] = decodeURIComponent(value);
|
|
63
|
+
}
|
|
64
|
+
comma = peek(',');
|
|
65
|
+
semicolon = peek(';');
|
|
66
|
+
}
|
|
67
|
+
results.push(result);
|
|
68
|
+
}
|
|
69
|
+
catch (error) { // We will try the next one...
|
|
70
|
+
console.log(error);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return results;
|
|
74
|
+
}
|
|
75
|
+
export var LinkRelType;
|
|
76
|
+
(function (LinkRelType) {
|
|
77
|
+
LinkRelType["add"] = "add";
|
|
78
|
+
LinkRelType["remove"] = "remove";
|
|
79
|
+
LinkRelType["edit"] = "edit";
|
|
80
|
+
})(LinkRelType || (LinkRelType = {}));
|
|
81
|
+
/**
|
|
82
|
+
* A basic client for interacting with the VMware Cloud Director APIs.
|
|
83
|
+
*
|
|
84
|
+
* A VMware Cloud Director plugin can get a reference to this client by using angular injection.
|
|
85
|
+
* ```
|
|
86
|
+
* constructor(private vcdApi: VcdApiClient) {}
|
|
87
|
+
* ```
|
|
88
|
+
*
|
|
89
|
+
* VcdApiClient reuses the authentication from the VCD platform so in general there is
|
|
90
|
+
* no need of an explicit authentication/login.
|
|
91
|
+
*
|
|
92
|
+
* When dealing with the session management there are two APIs:
|
|
93
|
+
* 1. Deprecated legacy API that is using the `api/session` endpoint and the corresponding models
|
|
94
|
+
* 2. Newly added API that is using the `cloudapi` endpoint and the corresponding models
|
|
95
|
+
*
|
|
96
|
+
* Note that if a plugin performs an explicit cloud api authentication call through
|
|
97
|
+
* {@link VcdApiClient#setCloudApiAuthentication} or {@link VcdApiClient#cloudApiLogin}
|
|
98
|
+
* from that moment on the VcdApiClient uses only cloud api session management.
|
|
99
|
+
* This means calls to {@link VcdApiClient#setAuthentication} or {@link VcdApiClient#login} have no effect.
|
|
100
|
+
*/
|
|
101
|
+
export class VcdApiClient {
|
|
102
|
+
set baseUrl(_baseUrl) {
|
|
103
|
+
this._baseUrl = _baseUrl;
|
|
104
|
+
}
|
|
105
|
+
get version() {
|
|
106
|
+
return this.http.requestHeadersInterceptor.version;
|
|
107
|
+
}
|
|
108
|
+
constructor(http, injector, config) {
|
|
109
|
+
this.http = http;
|
|
110
|
+
this.injector = injector;
|
|
111
|
+
this.config = config;
|
|
112
|
+
/**
|
|
113
|
+
* @deprecated Use {@link VcdApiClient#_cloudApiSession}
|
|
114
|
+
*/
|
|
115
|
+
this._session = new BehaviorSubject(null);
|
|
116
|
+
this._sessionObservable = this._session.asObservable()
|
|
117
|
+
.pipe(skipWhile(session => !session));
|
|
118
|
+
/**
|
|
119
|
+
* CloudApi Session
|
|
120
|
+
*/
|
|
121
|
+
this._cloudApiSession = new BehaviorSubject(null);
|
|
122
|
+
this._cloudApiSessionObservable = this._cloudApiSession.asObservable()
|
|
123
|
+
.pipe(skipWhile(session => !session));
|
|
124
|
+
this._cloudApiSessionLinks = new BehaviorSubject([]);
|
|
125
|
+
/**
|
|
126
|
+
* This property determines if it is an explicit cloud api login.
|
|
127
|
+
* In this case the old API (/api/session) should not be used at all.
|
|
128
|
+
*/
|
|
129
|
+
this._isCloudApiLogin = false;
|
|
130
|
+
this._baseUrl = this.injector.get(API_ROOT_URL);
|
|
131
|
+
let negotiatedVersion;
|
|
132
|
+
if (this.config?.apiVersion) {
|
|
133
|
+
negotiatedVersion = of(this.config.apiVersion).pipe(map((version) => {
|
|
134
|
+
this.setVersion(version);
|
|
135
|
+
return version;
|
|
136
|
+
}));
|
|
137
|
+
}
|
|
138
|
+
else {
|
|
139
|
+
negotiatedVersion = this.http.get(`${this._baseUrl}/api/versions`).pipe(map(versions => this.negotiateVersion(versions)), tap(version => this.setVersion(version)));
|
|
140
|
+
}
|
|
141
|
+
this._negotiateVersion = negotiatedVersion.pipe(share({ connector: () => new ReplaySubject(1) }));
|
|
142
|
+
const tokenHolder = this.injector.get(AuthTokenHolderService, { token: '' });
|
|
143
|
+
const token = tokenHolder.jwt ? `Bearer ${tokenHolder.jwt}` : tokenHolder.token;
|
|
144
|
+
this._getSession = this.setAuthentication(token)
|
|
145
|
+
.pipe(share({ connector: () => new ReplaySubject(1) }));
|
|
146
|
+
this._getCloudApiSession = this.setCloudApiAuthentication(token)
|
|
147
|
+
.pipe(share({ connector: () => new ReplaySubject(1) }));
|
|
148
|
+
// This is not an explicit cloud api login
|
|
149
|
+
this._isCloudApiLogin = false;
|
|
150
|
+
}
|
|
151
|
+
negotiateVersion(serverVersions) {
|
|
152
|
+
const supportedVersions = serverVersions.versionInfo.map(versionInfo => versionInfo.version);
|
|
153
|
+
// Default API Version used is the Latest API Version in VMware Cloud Director
|
|
154
|
+
return supportedVersions[supportedVersions.length - 1];
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* The purpose of this function is to ensure that prior to sending any call to the backend
|
|
158
|
+
* the version has been set and the current session has been retrieved.
|
|
159
|
+
* Note that this is important during the automatic authentication that is done during the
|
|
160
|
+
* constructor initialization, when the plugin is not required to perform its own explicit authentication
|
|
161
|
+
* but rather the ones from the underlying framework is used.
|
|
162
|
+
*/
|
|
163
|
+
validateRequestContext() {
|
|
164
|
+
return (this.version ? of(this.version) : this._negotiateVersion)
|
|
165
|
+
.pipe(
|
|
166
|
+
// In case of a cloud api login we are not interested in the /api/session session
|
|
167
|
+
concatMap(() => this._isCloudApiLogin ? of(null) : this._getSession), concatMap(() => this._getCloudApiSession
|
|
168
|
+
// In case of cloud api failure we do not want to prevent further execution
|
|
169
|
+
// for backward compatibility considerations since this may be a case
|
|
170
|
+
// when cloud api is not supported at all for the specified version
|
|
171
|
+
.pipe(catchError((e) => of(true)))), map(() => true));
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
*
|
|
175
|
+
* For use cases wich solely depends on cloudapi without any backward compatibility
|
|
176
|
+
* there should be no dependence on the old /api endpoint at all
|
|
177
|
+
*/
|
|
178
|
+
validateRequestContextCloudApiOnly() {
|
|
179
|
+
return (this.version ? of(this.version) : this._negotiateVersion).pipe(concatMap(() => this._getCloudApiSession));
|
|
180
|
+
}
|
|
181
|
+
setVersion(_version) {
|
|
182
|
+
this.http.requestHeadersInterceptor.version = _version;
|
|
183
|
+
return this;
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Global configuration for the service, that allows a provider user to execute API requests
|
|
187
|
+
* in the scope of a specific tenant.
|
|
188
|
+
*
|
|
189
|
+
* If you want to execute single API request in scope of specific tenant you can do it
|
|
190
|
+
* by passing "X-VMWARE-VCLOUD-TENANT-CONTEXT" header to the specific API Request.
|
|
191
|
+
*
|
|
192
|
+
* This scoping is available to query-based API calls and to bulk GET calls in the
|
|
193
|
+
* /cloudapi space.
|
|
194
|
+
*
|
|
195
|
+
* @param actAs an entityRef of the tenant (organization) to scope subsequent calls to in
|
|
196
|
+
* the VcdApiClient, or null/no parameter to remove tenant-specific scoping
|
|
197
|
+
* @returns the current VcdApiClient instance (for chaining)
|
|
198
|
+
*/
|
|
199
|
+
actAs(actAs = null) {
|
|
200
|
+
this.http.requestHeadersInterceptor.actAs = !actAs ? null : actAs.id;
|
|
201
|
+
return this;
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* @deprecated Use {@link VcdApiClient#setCloudApiAuthentication}
|
|
205
|
+
*
|
|
206
|
+
* Sets the authentication token to use for the VcdApiClient.
|
|
207
|
+
*
|
|
208
|
+
* After setting the token, the client will get the current session
|
|
209
|
+
* information associated with the authenticated token.
|
|
210
|
+
*
|
|
211
|
+
* @param authentication the authentication string (to be used in either the 'Authorization'
|
|
212
|
+
* or 'x-vcloud-authorization' header)
|
|
213
|
+
* @returns the session associated with the authentication token
|
|
214
|
+
*/
|
|
215
|
+
setAuthentication(authentication) {
|
|
216
|
+
if (this._isCloudApiLogin) {
|
|
217
|
+
return throwError('Only cloud api auth is allowed since it was already used');
|
|
218
|
+
}
|
|
219
|
+
this.http.requestHeadersInterceptor.authentication = authentication;
|
|
220
|
+
return this.http.get(`${this._baseUrl}/api/session`).pipe(tap(session => {
|
|
221
|
+
// automatically set actAs for provider in tenant scope
|
|
222
|
+
if (session.org === 'System' && this.injector.get(SESSION_SCOPE) === 'tenant') {
|
|
223
|
+
// Automatic actAs only works in versions >=9.5
|
|
224
|
+
try {
|
|
225
|
+
this.actAs({ id: this.injector.get(SESSION_ORG_ID) });
|
|
226
|
+
}
|
|
227
|
+
catch (e) {
|
|
228
|
+
console.warn('No SESSION_ORG_ID set in container. Automatic actAs is disabled.');
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}), tap(session => this._session.next(session)));
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Sets the authentication token to use for the VcdApiClient.
|
|
235
|
+
*
|
|
236
|
+
* After setting the token, the client will get the current session
|
|
237
|
+
* information associated with the authenticated token.
|
|
238
|
+
*
|
|
239
|
+
* @param authentication the authentication string (to be used in either the 'Authorization'
|
|
240
|
+
* or 'x-vcloud-authorization' header)
|
|
241
|
+
*
|
|
242
|
+
* @returns session observable associated with the authentication token
|
|
243
|
+
*/
|
|
244
|
+
setCloudApiAuthentication(authentication) {
|
|
245
|
+
this.onBeforeCloudApiAuthentication();
|
|
246
|
+
return of(true)
|
|
247
|
+
.pipe(
|
|
248
|
+
// Set the authentication as part of the observable in order to ensure the caller has subscribed to the observable
|
|
249
|
+
tap(() => this.http.requestHeadersInterceptor.authentication = authentication), switchMap(() => this.http.get(`${this._baseUrl}/cloudapi/1.0.0/sessions/current`, { observe: 'response' })))
|
|
250
|
+
.pipe(this.onCloudApiAuthentication());
|
|
251
|
+
}
|
|
252
|
+
enableLogging() {
|
|
253
|
+
this.http.loggingInterceptor.enabled = true;
|
|
254
|
+
return this;
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* @deprecated Use {@link VcdApiClient#cloudApiLogin}
|
|
258
|
+
*
|
|
259
|
+
* Creates an authenticated session for the specified credential data.
|
|
260
|
+
*
|
|
261
|
+
* @param username the name of the user to authenticate
|
|
262
|
+
* @param tenant the organization the user belongs to
|
|
263
|
+
* @param password the password for the user
|
|
264
|
+
* @returns an authenticated session for the given credentials
|
|
265
|
+
*/
|
|
266
|
+
login(username, tenant, password) {
|
|
267
|
+
if (this._isCloudApiLogin) {
|
|
268
|
+
return throwError('Only cloud api auth is allowed since it was already used');
|
|
269
|
+
}
|
|
270
|
+
const authString = btoa(`${username}@${tenant}:${password}`);
|
|
271
|
+
return this.http.post(`${this._baseUrl}/api/sessions`, null, {
|
|
272
|
+
observe: 'response',
|
|
273
|
+
headers: new HttpHeaders({ Authorization: `Basic ${authString}` })
|
|
274
|
+
})
|
|
275
|
+
.pipe(tap((response) =>
|
|
276
|
+
// tslint:disable-next-line:max-line-length
|
|
277
|
+
this.http.requestHeadersInterceptor.authentication = `${response.headers.get('x-vmware-vcloud-token-type')} ${response.headers.get('x-vmware-vcloud-access-token')}`), map(response => response.body), tap(session => this._session.next(session)));
|
|
278
|
+
}
|
|
279
|
+
/**
|
|
280
|
+
* Creates an authenticated session for the specified credential data using cloud api endpoint.
|
|
281
|
+
*
|
|
282
|
+
* @param username the name of the user to authenticate
|
|
283
|
+
* @param tenant the organization the user belongs to
|
|
284
|
+
* @param password the password for the user
|
|
285
|
+
* @returns an authenticated session for the given credentials
|
|
286
|
+
*/
|
|
287
|
+
cloudApiLogin(username, tenant, password) {
|
|
288
|
+
this.onBeforeCloudApiAuthentication();
|
|
289
|
+
const authString = btoa(`${username}@${tenant}:${password}`);
|
|
290
|
+
let url = `${this._baseUrl}/cloudapi/1.0.0/sessions`;
|
|
291
|
+
if (tenant.toLowerCase() === 'system') {
|
|
292
|
+
url += '/provider';
|
|
293
|
+
}
|
|
294
|
+
return this.http.post(url, null, {
|
|
295
|
+
observe: 'response',
|
|
296
|
+
headers: new HttpHeaders({ [HTTP_HEADERS.Authorization]: `Basic ${authString}` })
|
|
297
|
+
}).pipe(tap((response) => {
|
|
298
|
+
// tslint:disable-next-line:max-line-length
|
|
299
|
+
const token = `${response.headers.get('x-vmware-vcloud-token-type')} ${response.headers.get('x-vmware-vcloud-access-token')}`;
|
|
300
|
+
this.http.requestHeadersInterceptor.authentication = token;
|
|
301
|
+
}), this.onCloudApiAuthentication());
|
|
302
|
+
}
|
|
303
|
+
/**
|
|
304
|
+
* It is necessary to know if an explicit cloud api auth request was done.
|
|
305
|
+
* This function handles this by setting the corresponding flags, properties etc.
|
|
306
|
+
*/
|
|
307
|
+
onBeforeCloudApiAuthentication() {
|
|
308
|
+
// In case of an explicit cloud api auth request:
|
|
309
|
+
// Set the flag _isCloudApiLogin in order to know that explicit cloud api authentication is done
|
|
310
|
+
// This will help us skip code related to the old api, i.e. we should not allow explicit mix of both the api-s
|
|
311
|
+
this._isCloudApiLogin = true;
|
|
312
|
+
// In case of an explicit cloud api auth request:
|
|
313
|
+
// There is no need of _getCloudApiSession observable which is needed in the automatic login during the constructor initialization.
|
|
314
|
+
// The explicit cloud api auth request will retrieve the session.
|
|
315
|
+
this._getCloudApiSession = of(null);
|
|
316
|
+
}
|
|
317
|
+
/**
|
|
318
|
+
* Handle authentication.
|
|
319
|
+
* This includes getting HATEOAS links, setting the session, handling errors etc.
|
|
320
|
+
*/
|
|
321
|
+
onCloudApiAuthentication() {
|
|
322
|
+
return (source) => source.pipe(tap((resp) => {
|
|
323
|
+
// Get HATEOAS links
|
|
324
|
+
try {
|
|
325
|
+
this.setCloudApiSessionLinks(parseHeaderHateoasLinks(resp.headers.get(HATEOAS_HEADER)));
|
|
326
|
+
}
|
|
327
|
+
catch (e) {
|
|
328
|
+
console.log('Error when parsing session HATEOAS links:', e);
|
|
329
|
+
}
|
|
330
|
+
}), map(resp => resp.body), tap((session) => {
|
|
331
|
+
// Clear previous actAs
|
|
332
|
+
this.actAs(null);
|
|
333
|
+
// automatically set actAs for provider in tenant scope
|
|
334
|
+
if (session.org && session.org.name === 'System' && this.injector.get(SESSION_SCOPE) === 'tenant') {
|
|
335
|
+
// Automatic actAs only works in versions >=9.5
|
|
336
|
+
try {
|
|
337
|
+
this.actAs({ id: this.injector.get(SESSION_ORG_ID) });
|
|
338
|
+
}
|
|
339
|
+
catch (e) {
|
|
340
|
+
console.warn('No SESSION_ORG_ID set in container. Automatic actAs is disabled.');
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
}), tap((session) => this._cloudApiSession.next(session)), catchError((e) => {
|
|
344
|
+
this.onCloudApiAuthenticationError();
|
|
345
|
+
return throwError(e);
|
|
346
|
+
}));
|
|
347
|
+
}
|
|
348
|
+
onCloudApiAuthenticationError() {
|
|
349
|
+
// Clear the authentication so that any subsequent backend calls are not authenticated
|
|
350
|
+
this.http.requestHeadersInterceptor.authentication = '';
|
|
351
|
+
// _getCloudApiSession is in the center of any backend call, nullify it in order not to prevent those calls
|
|
352
|
+
// since it is easier to troubleshoot failing backend rather than no call
|
|
353
|
+
this._getCloudApiSession = of(null);
|
|
354
|
+
// Clear the links
|
|
355
|
+
this._cloudApiSessionLinks.next([]);
|
|
356
|
+
// Clear the session
|
|
357
|
+
this._cloudApiSession.next(null);
|
|
358
|
+
}
|
|
359
|
+
setCloudApiSessionLinks(links) {
|
|
360
|
+
this._cloudApiAccessibleLocations = null;
|
|
361
|
+
this._cloudApiSessionLinks.next(links || []);
|
|
362
|
+
}
|
|
363
|
+
get(endpoint, options) {
|
|
364
|
+
return this.validateRequestContext().pipe(concatMap(() => this.http.get(this.buildEndpointUrl(endpoint), { ...options })));
|
|
365
|
+
}
|
|
366
|
+
list(endpoint, queryBuilder, multisite, options) {
|
|
367
|
+
let url = this.buildEndpointUrl(endpoint);
|
|
368
|
+
if (queryBuilder) {
|
|
369
|
+
url = `${url}${queryBuilder.getCloudAPI()}`;
|
|
370
|
+
}
|
|
371
|
+
if (multisite) {
|
|
372
|
+
if (!options) {
|
|
373
|
+
return this.http.get(url, { headers: new HttpHeaders({ _multisite: this.parseMultisiteValue(multisite) }) });
|
|
374
|
+
}
|
|
375
|
+
else if (options?.headers) {
|
|
376
|
+
options.headers.append("_multisite", this.parseMultisiteValue(multisite));
|
|
377
|
+
return this.http.get(url, { ...options });
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
return this.validateRequestContext().pipe(concatMap(() => this.http.get(url, { ...options })));
|
|
381
|
+
}
|
|
382
|
+
createSync(endpoint, item, options) {
|
|
383
|
+
return this.validateRequestContext().pipe(concatMap(() => this.http.post(this.buildEndpointUrl(endpoint), item, { ...options })));
|
|
384
|
+
}
|
|
385
|
+
createAsync(endpoint, item, options) {
|
|
386
|
+
return this.validateRequestContext().pipe(concatMap(() => this.http.post(this.buildEndpointUrl(endpoint), item, { ...options, observe: 'response' })), concatMap(response => this.mapResponseToTask(response, 'POST')));
|
|
387
|
+
}
|
|
388
|
+
getTransferLink(endpoint, item, transferRel = TRANSFER_LINK_REL) {
|
|
389
|
+
return this.http
|
|
390
|
+
.post(this.buildEndpointUrl(endpoint), item, { observe: 'response' })
|
|
391
|
+
.pipe(map((res) => {
|
|
392
|
+
const headerLinks = res.headers.has(HATEOAS_HEADER)
|
|
393
|
+
? parseHeaderHateoasLinks(res.headers.get(HATEOAS_HEADER))
|
|
394
|
+
: [];
|
|
395
|
+
const links = res.body ? (res.body.link || []) : [];
|
|
396
|
+
const link = [...headerLinks, ...links]
|
|
397
|
+
.find((l) => l.rel === transferRel);
|
|
398
|
+
if (!link) {
|
|
399
|
+
throw new Error(`Response from ${endpoint} did not contain a transfer link`);
|
|
400
|
+
}
|
|
401
|
+
return link.href;
|
|
402
|
+
}));
|
|
403
|
+
}
|
|
404
|
+
startTransfer(endpoint, item, transferRel = TRANSFER_LINK_REL) {
|
|
405
|
+
return this.getTransferLink(endpoint, item, transferRel)
|
|
406
|
+
.pipe(map((transferUrl) => new VcdTransferClient(this.http, transferUrl)));
|
|
407
|
+
}
|
|
408
|
+
updateSync(endpoint, item, options) {
|
|
409
|
+
return this.validateRequestContext().pipe(concatMap(() => this.http.put(this.buildEndpointUrl(endpoint), item, { ...options })));
|
|
410
|
+
}
|
|
411
|
+
updateAsync(endpoint, item, options) {
|
|
412
|
+
return this.validateRequestContext().pipe(concatMap(() => this.http.put(this.buildEndpointUrl(endpoint), item, { ...options, observe: 'response' })), concatMap(response => this.mapResponseToTask(response, 'PUT')));
|
|
413
|
+
}
|
|
414
|
+
deleteSync(endpoint, options) {
|
|
415
|
+
return this.validateRequestContext().pipe(concatMap(() => this.http.delete(this.buildEndpointUrl(endpoint), { ...options })));
|
|
416
|
+
}
|
|
417
|
+
deleteAsync(endpoint, options) {
|
|
418
|
+
return this.validateRequestContext().pipe(concatMap(() => this.http.delete(this.buildEndpointUrl(endpoint), { ...options, observe: 'response' })), concatMap(response => this.mapResponseToTask(response, 'DELETE')));
|
|
419
|
+
}
|
|
420
|
+
mapResponseToTask(response, httpVerb) {
|
|
421
|
+
if (response.headers.has('Location') && response.status === 202) {
|
|
422
|
+
return this.http.get(response.headers.get('Location'));
|
|
423
|
+
}
|
|
424
|
+
else if (response.body && response.body.type.startsWith('application/vnd.vmware.vcloud.task+')) {
|
|
425
|
+
const task = Object.assign(new TaskType(), response.body);
|
|
426
|
+
return of(task);
|
|
427
|
+
}
|
|
428
|
+
return throwError(() => new Error(`An asynchronous request was made to [${httpVerb} ${response.url}], but no task was returned. The operation may still have been successful.`));
|
|
429
|
+
}
|
|
430
|
+
getEntity(entityRefOrUrn) {
|
|
431
|
+
const entityResolver = typeof entityRefOrUrn === 'string' ?
|
|
432
|
+
this.http.get(`${this._baseUrl}/api/entity/${entityRefOrUrn}`) :
|
|
433
|
+
this.http.get(`${this._baseUrl}/api/entity/urn:vcloud:${entityRefOrUrn.type}:${entityRefOrUrn.id}`);
|
|
434
|
+
return this.validateRequestContext().pipe(concatMap(() => entityResolver), concatMap(entity => this.http.get(`${entity.link[0].href}`)));
|
|
435
|
+
}
|
|
436
|
+
updateTask(task, options) {
|
|
437
|
+
return this.validateRequestContext().pipe(concatMap(() => this.http.get(task.href, { ...options })));
|
|
438
|
+
}
|
|
439
|
+
isTaskComplete(task) {
|
|
440
|
+
return ['success', 'error', 'canceled', 'aborted'].indexOf(task.status) > -1;
|
|
441
|
+
}
|
|
442
|
+
removeItem(item, options) {
|
|
443
|
+
const link = this.findLink(item, 'remove', null);
|
|
444
|
+
if (!link) {
|
|
445
|
+
return throwError(() => new Error(`No 'remove' link for specified resource.`));
|
|
446
|
+
}
|
|
447
|
+
return this.validateRequestContext().pipe(concatMap(() => this.http.delete(link.href, { ...options })));
|
|
448
|
+
}
|
|
449
|
+
query(builder, multisite, options) {
|
|
450
|
+
return this.getQueryPage(`${this._baseUrl}/api/query${builder.get()}`, multisite, options);
|
|
451
|
+
}
|
|
452
|
+
firstPage(result, multisite, options) {
|
|
453
|
+
const link = this.findLink(result, 'firstPage', result.type);
|
|
454
|
+
if (!link) {
|
|
455
|
+
return throwError(() => new Error(`No 'firstPage' link for specified query.`));
|
|
456
|
+
}
|
|
457
|
+
return this.getQueryPage(link.href, multisite, options);
|
|
458
|
+
}
|
|
459
|
+
hasFirstPage(result) {
|
|
460
|
+
return !!this.findLink(result, 'firstPage', result.type);
|
|
461
|
+
}
|
|
462
|
+
previousPage(result, multisite, options) {
|
|
463
|
+
const link = this.findLink(result, 'previousPage', result.type);
|
|
464
|
+
if (!link) {
|
|
465
|
+
return throwError(() => new Error(`No 'previousPage' link for specified query.`));
|
|
466
|
+
}
|
|
467
|
+
return this.getQueryPage(link.href, multisite, options);
|
|
468
|
+
}
|
|
469
|
+
hasPreviousPage(result) {
|
|
470
|
+
return !!this.findLink(result, 'previousPage', result.type);
|
|
471
|
+
}
|
|
472
|
+
nextPage(result, multisite, options) {
|
|
473
|
+
const link = this.findLink(result, 'nextPage', result.type);
|
|
474
|
+
if (!link) {
|
|
475
|
+
return throwError(() => new Error(`No 'nextPage' link for specified query.`));
|
|
476
|
+
}
|
|
477
|
+
return this.getQueryPage(link.href, multisite, options);
|
|
478
|
+
}
|
|
479
|
+
hasNextPage(result) {
|
|
480
|
+
return !!this.findLink(result, 'nextPage', result.type);
|
|
481
|
+
}
|
|
482
|
+
lastPage(result, multisite, options) {
|
|
483
|
+
const link = this.findLink(result, 'lastPage', result.type);
|
|
484
|
+
if (!link) {
|
|
485
|
+
return throwError(() => new Error(`No 'lastPage' link for specified query.`));
|
|
486
|
+
}
|
|
487
|
+
return this.getQueryPage(link.href, multisite, options);
|
|
488
|
+
}
|
|
489
|
+
hasLastPage(result) {
|
|
490
|
+
return !!this.findLink(result, 'lastPage', result.type);
|
|
491
|
+
}
|
|
492
|
+
getQueryPage(href, multisite, options) {
|
|
493
|
+
if (multisite) {
|
|
494
|
+
if (!options) {
|
|
495
|
+
return this.http.get(href, { headers: new HttpHeaders({ _multisite: this.parseMultisiteValue(multisite) }) });
|
|
496
|
+
}
|
|
497
|
+
else if (options?.headers) {
|
|
498
|
+
options.headers.append("_multisite", this.parseMultisiteValue(multisite));
|
|
499
|
+
return this.http.get(href, { ...options });
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
return this.validateRequestContext().pipe(concatMap(() => this.http.get(href, { ...options })));
|
|
503
|
+
}
|
|
504
|
+
/**
|
|
505
|
+
* Use to perform action availability check before calling the API
|
|
506
|
+
* @param item - the navigable item (containing link collection)
|
|
507
|
+
* @param linkRelType - the link rel type, pass either LinkRelType or string
|
|
508
|
+
* @param entityRefType - the entity reference type
|
|
509
|
+
*/
|
|
510
|
+
canPerformAction(item, linkRelType, entityRefType) {
|
|
511
|
+
return !!this.findLink(item, linkRelType, entityRefType);
|
|
512
|
+
}
|
|
513
|
+
findLink(item, rel, type) {
|
|
514
|
+
if (!item || !item.link) {
|
|
515
|
+
return undefined;
|
|
516
|
+
}
|
|
517
|
+
return item.link.find((link) => {
|
|
518
|
+
if (type) {
|
|
519
|
+
return link.rel.includes(rel) && link.type === type;
|
|
520
|
+
}
|
|
521
|
+
return link.rel.includes(rel);
|
|
522
|
+
});
|
|
523
|
+
}
|
|
524
|
+
parseMultisiteValue(multisite) {
|
|
525
|
+
return typeof multisite === 'boolean' ? (multisite ? 'global' : 'local') : multisite.map(site => site.locationId).join(',');
|
|
526
|
+
}
|
|
527
|
+
/**
|
|
528
|
+
* @deprecated Use cloudApiSession
|
|
529
|
+
*/
|
|
530
|
+
get session() {
|
|
531
|
+
return this.validateRequestContext().pipe(concatMap(() => this._sessionObservable));
|
|
532
|
+
}
|
|
533
|
+
/**
|
|
534
|
+
* Get Session observable
|
|
535
|
+
*/
|
|
536
|
+
get cloudApiSession() {
|
|
537
|
+
return this.validateRequestContextCloudApiOnly().pipe(concatMap(() => this._cloudApiSessionObservable));
|
|
538
|
+
}
|
|
539
|
+
get username() {
|
|
540
|
+
return merge(this.cloudApiSession.pipe(filter(() => this._isCloudApiLogin), map(session => session && session.user && session.user.name)), this.session.pipe(filter(() => !this._isCloudApiLogin), map(session => session && session.user)));
|
|
541
|
+
}
|
|
542
|
+
get organization() {
|
|
543
|
+
return merge(this.cloudApiSession.pipe(filter(() => this._isCloudApiLogin), map(session => session && session.org && session.org.name)), this.session.pipe(filter(() => !this._isCloudApiLogin), map(session => session && session.org)));
|
|
544
|
+
}
|
|
545
|
+
/**
|
|
546
|
+
* @deprecated Use cloudApiLocation
|
|
547
|
+
*/
|
|
548
|
+
get location() {
|
|
549
|
+
return this.session.pipe(map(session => session.authorizedLocations.location.find(location => location.locationId === session.locationId)));
|
|
550
|
+
}
|
|
551
|
+
/**
|
|
552
|
+
* Gets the location corresponding to the current session
|
|
553
|
+
*/
|
|
554
|
+
get cloudApiLocation() {
|
|
555
|
+
return this.cloudApiSession.pipe(switchMap(() => {
|
|
556
|
+
if (!this._cloudApiAccessibleLocations) {
|
|
557
|
+
// Ensure caching for getting AccessibleLocations
|
|
558
|
+
this._cloudApiAccessibleLocations = this._cloudApiSessionLinks
|
|
559
|
+
.pipe(
|
|
560
|
+
// Get the AccessibleLocations link
|
|
561
|
+
map((links) => this.findLink({ link: links }, 'down', 'AccessibleLocations')),
|
|
562
|
+
// Fetch AccessibleLocations from the backend
|
|
563
|
+
switchMap((link) => link ? this.http.get(link.href) : of(null)),
|
|
564
|
+
// Get the array with all locations (what if there are many pages)
|
|
565
|
+
map((accessibleLocations) => accessibleLocations && accessibleLocations.values))
|
|
566
|
+
.pipe(share({ connector: () => new ReplaySubject(1) }));
|
|
567
|
+
}
|
|
568
|
+
return this._cloudApiAccessibleLocations;
|
|
569
|
+
}),
|
|
570
|
+
// Need to have the session in order to get its location
|
|
571
|
+
withLatestFrom(this.cloudApiSession),
|
|
572
|
+
// Find the location that corresponds to this session
|
|
573
|
+
map(([accessibleLocations, session]) => {
|
|
574
|
+
if (!accessibleLocations || !session) {
|
|
575
|
+
return null;
|
|
576
|
+
}
|
|
577
|
+
const sessionLocation = session.location;
|
|
578
|
+
if (!sessionLocation) {
|
|
579
|
+
return null;
|
|
580
|
+
}
|
|
581
|
+
return accessibleLocations.find(location => location.locationId === sessionLocation);
|
|
582
|
+
}));
|
|
583
|
+
}
|
|
584
|
+
getLocation(session) {
|
|
585
|
+
return session.authorizedLocations.location.find(location => location.locationId === session.locationId);
|
|
586
|
+
}
|
|
587
|
+
/**
|
|
588
|
+
* Build the endpoint url. If the provided endpoint is already an absolute URL, then return it as it is without
|
|
589
|
+
* any modifications, otherwise consider it as a relative one and prepend the baseUrl as defined by the host application.
|
|
590
|
+
*/
|
|
591
|
+
buildEndpointUrl(endpoint) {
|
|
592
|
+
return endpoint.indexOf('://') > -1 ? endpoint : `${this._baseUrl}/${endpoint}`;
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
VcdApiClient.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.0", ngImport: i0, type: VcdApiClient, deps: [{ token: i1.VcdHttpClient }, { token: i0.Injector }, { token: i2.VcdSdkConfig, optional: true }], target: i0.ɵɵFactoryTarget.Injectable });
|
|
596
|
+
VcdApiClient.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.0", ngImport: i0, type: VcdApiClient });
|
|
597
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.0", ngImport: i0, type: VcdApiClient, decorators: [{
|
|
598
|
+
type: Injectable
|
|
599
|
+
}], ctorParameters: function () { return [{ type: i1.VcdHttpClient }, { type: i0.Injector }, { type: i2.VcdSdkConfig, decorators: [{
|
|
600
|
+
type: Optional
|
|
601
|
+
}] }]; } });
|
|
602
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidmNkLmFwaS5jbGllbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy92Y2Qvc2RrL3NyYy9jbGllbnQvY2xpZW50L3ZjZC5hcGkuY2xpZW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxVQUFVLEVBQVksUUFBUSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQy9ELE9BQU8sRUFBRSxXQUFXLEVBQWdCLE1BQU0sc0JBQXNCLENBQUM7QUFDakUsT0FBTyxFQUFjLGVBQWUsRUFBRSxFQUFFLEVBQUUsVUFBVSxFQUFFLEtBQUssRUFBRSxhQUFhLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFDekYsT0FBTyxFQUFFLFVBQVUsRUFBRSxHQUFHLEVBQUUsR0FBRyxFQUFFLFNBQVMsRUFBRSxTQUFTLEVBQUUsU0FBUyxFQUFFLGNBQWMsRUFBRSxLQUFLLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUM5RyxPQUFPLEVBS0gsUUFBUSxFQUNYLE1BQU0sMkNBQTJDLENBQUM7QUFJbkQsT0FBTyxFQUFFLHNCQUFzQixFQUFFLFlBQVksRUFBRSxhQUFhLEVBQUUsY0FBYyxFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFFekcsT0FBTyxFQUFFLGlCQUFpQixFQUFFLE1BQU0sdUJBQXVCLENBQUM7QUFDMUQsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUMzQyxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7Ozs7QUFHeEMsTUFBTSxDQUFDLE1BQU0saUJBQWlCLEdBQUcsZ0JBQWdCLENBQUM7QUFHbEQsTUFBTSxDQUFDLE1BQU0sY0FBYyxHQUFHLE1BQU0sQ0FBQztBQUVyQywrQkFBK0I7QUFFL0I7Ozs7R0FJRztBQUNILE1BQU0sVUFBVSx1QkFBdUIsQ0FBQyxNQUFjO0lBQ2xELE1BQU0sT0FBTyxHQUFlLEVBQUUsQ0FBQztJQUUvQixJQUFJLENBQUMsTUFBTSxF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J0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgSHR0cEhlYWRlcnMsIEh0dHBSZXNwb25zZSB9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbi9odHRwJztcbmltcG9ydCB7IE9ic2VydmFibGUsIEJlaGF2aW9yU3ViamVjdCwgb2YsIHRocm93RXJyb3IsIG1lcmdlLCBSZXBsYXlTdWJqZWN0IH0gZnJvbSAncnhqcyc7XG5pbXBvcnQgeyBjYXRjaEVycm9yLCB0YXAsIG1hcCwgY29uY2F0TWFwLCBza2lwV2hpbGUsIHN3aXRjaE1hcCwgd2l0aExhdGVzdEZyb20sIHNoYXJlIH0gZnJvbSAncnhqcy9vcGVyYXRvcnMnO1xuaW1wb3J0IHsgU2Vzc2lvblR5cGUsXG4gICAgQXV0aG9yaXplZExvY2F0aW9uVHlwZSxcbiAgICBSZXNvdXJjZVR5cGUsIExpbmtUeXBlLFxuICAgIEVudGl0eVJlZmVyZW5jZVR5cGUsXG4gICAgRW50aXR5VHlwZSxcbiAgICBUYXNrVHlwZVxufSBmcm9tICdAdmNkL2JpbmRpbmdzL3ZjbG91ZC9hcGkvcmVzdC9zY2hlbWFfdjFfNSc7XG5pbXBvcnQgeyBTdXBwb3J0ZWRWZXJzaW9uc1R5cGUgfSBmcm9tICdAdmNkL2JpbmRpbmdzL3ZjbG91ZC9hcGkvcmVzdC9zY2hlbWEvdmVyc2lvbmluZyc7XG5pbXBvcnQgeyBBY2Nlc3NpYmxlTG9jYXRpb24sIEFjY2Vzc2libGVMb2NhdGlvbnMsIFNlc3Npb24gfSBmcm9tICcuLi9vcGVuYXBpJztcbmltcG9ydCB7IFF1ZXJ5IH0gZnJvbSAnLi4vcXVlcnkvaW5kZXgnO1xuaW1wb3J0IHsgQXV0aFRva2VuSG9sZGVyU2VydmljZSwgQVBJX1JPT1RfVVJMLCBTRVNTSU9OX1NDT1BFLCBTRVNTSU9OX09SR19JRCB9IGZyb20gJy4uL2NvbnRhaW5lci1ob29rcyc7XG5pbXBvcnQgeyBWY2RIdHRwQ2xpZW50IH0gZnJvbSAnLi92Y2QuaHR0cC5jbGllbnQnO1xuaW1wb3J0IHsgVmNkVHJhbnNmZXJDbGllbnQgfSBmcm9tICcuL3ZjZC50cmFuc2Zlci5jbGllbnQnO1xuaW1wb3J0IHsgSFRUUF9IRUFERVJTIH0gZnJvbSAnLi9jb25zdGFudHMnO1xuaW1wb3J0IHsgZmlsdGVyIH0gZnJvbSAncnhqcy9vcGVyYXRvcnMnO1xuaW1wb3J0IHsgVmNkU2RrQ29uZmlnIH0gZnJvbSBcIi4uLy4uL2NvcmUvcGx1Z2luLm1vZHVsZVwiO1xuXG5leHBvcnQgY29uc3QgVFJBTlNGRVJfTElOS19SRUwgPSAndXBsb2FkOmRlZmF1bHQnO1xuZXhwb3J0IHR5cGUgTmF2aWdhYmxlID0gUmVzb3VyY2VUeXBlIHwgeyBsaW5rPzogTGlua1R5cGVbXSB9O1xuXG5leHBvcnQgY29uc3QgSEFURU9BU19IRUFERVIgPSAnTGluayc7XG5cbi8vIHRzbGludDpkaXNhYmxlOnZhcmlhYmxlLW5hbWVcblxuLyoqXG4gKiBQYXJzZSBvdXQgTGluayBoZWFkZXJzIHVzaW5nIGEgdmVyeSBsYXppbHkgaW1wbGVtZW50ZWQgcHVsbCBwYXJzZXJcbiAqIEBwYXJhbSBoZWFkZXIgJzx1cmwxPjtuYW1lMT1cInZhbHVlMVwiLG5hbWUyPVwidmFsdWUyXCIsPHVybDI+O25hbWUzPVwidmFsdWUzLHZhbHVlNFwiJ1xuICogQHJldHVybnMgcGFyc2VkIGxpbmsgaGVhZGVyc1xuICovXG5leHBvcnQgZnVuY3Rpb24gcGFyc2VIZWFkZXJIYXRlb2FzTGlua3MoaGVhZGVyOiBzdHJpbmcpOiBMaW5rVHlwZVtdIHtcbiAgICBjb25zdCByZXN1bHRzOiBMaW5rVHlwZVtdID0gW107XG5cbiAgICBpZiAoIWhlYWRlcikge1xuICAgICAgICByZXR1cm4gcmVzdWx0cztcbiAgICB9XG5cbiAgICBjb25zdCBoZWFkZXJGaWVsZE1hcHBpbmdzOiB7W2tleTogc3RyaW5nXToga2V5b2YgTGlua1R5cGV9ID0ge1xuICAgICAgICBocmVmOiAnaHJlZicsXG4gICAgICAgIG1vZGVsOiAndHlwZScsXG4gICAgICAgIHRpdGxlOiAnaWQnLFxuICAgICAgICByZWw6ICdyZWwnXG4gICAgfTtcbiAgICBsZXQgdG9rZW5JbmRleCA9IC0xO1xuXG4gICAgZnVuY3Rpb24gcGVlayh0b2tlbjogc3RyaW5nKSB7XG4gICAgICAgIHJldHVybiBoZWFkZXIuaW5kZXhPZih0b2tlbiwgdG9rZW5JbmRleCArIDEpO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIG5leHQodG9rZW46IHN0cmluZykge1xuICAgICAgICBjb25zdCBuZXh0SW5kZXggPSBwZWVrKHRva2VuKTtcbiAgICAgICAgaWYgKG5leHRJbmRleCA9PT0gLTEpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihKU09OLnN0cmluZ2lmeSh7aGVhZGVyLCB0b2tlbiwgdG9rZW5JbmRleH0pKTtcbiAgICAgICAgfVxuICAgICAgICB0b2tlbkluZGV4ID0gbmV4dEluZGV4O1xuICAgICAgICByZXR1cm4gdG9rZW5JbmRleDtcbiAgICB9XG5cbiAgICB3aGlsZSAocGVlaygnPCcpID4gLTEpIHtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGNvbnN0IGhyZWZTdGFydCA9IG5leHQoJzwnKTtcbiAgICAgICAgICAgIGNvbnN0IGhyZWZFbmQgPSBuZXh0KCc+Jyk7XG4gICAgICAgICAgICBjb25zdCBocmVmID0gaGVhZGVyLnN1YnN0cmluZyhocmVmU3RhcnQgKyAxLCBocmVmRW5kKTtcbiAgICAgICAgICAgIGNvbnN0IHJlc3VsdDogTGlua1R5cGUgPSB7aHJlZiwgdHlwZTogbnVsbCwgaWQ6IG51bGwsIHJlbDogbnVsbCwgdkNsb3VkRXh0ZW5zaW9uOiBbXX07XG4gICAgICAgICAgICBsZXQgY29tbWEgPSBwZWVrKCcsJyk7XG4gICAgICAgICAgICBsZXQgc2VtaWNvbG9uID0gcGVlaygnOycpO1xuICAgICAgICAgICAgd2hpbGUgKChzZW1pY29sb24gPiAtMSAmJiBjb21tYSA+IC0xICYmIHNlbWljb2xvbiA8IGNvbW1hKSB8fCAoc2VtaWNvbG9uID4gLTEgJiYgY29tbWEgPT09IC0xKSkge1xuICAgICAgICAgICAgICAgIGNvbnN0IG5hbWVTdGFydCA9IG5leHQoJzsnKTtcbiAgICAgICAgICAgICAgICBjb25zdCBuYW1lRW5kID0gbmV4dCgnPScpO1xuICAgICAgICAgICAgICAgIGNvbnN0IG5hbWUgPSBoZWFkZXIuc3Vic3RyaW5nKG5hbWVTdGFydCArIDEsIG5hbWVFbmQpLnRyaW0oKS50b0xvd2VyQ2FzZSgpO1xuICAgICAgICAgICAgICAgIGNvbnN0IHZhbHVlU3RhcnQgPSBuZXh0KCdcIicpO1xuICAgICAgICAgICAgICAgIGNvbnN0IHZhbHVlRW5kID0gbmV4dCgnXCInKTtcbiAgICAgICAgICAgICAgICBjb25zdCB2YWx1ZSA9IGhlYWRlci5zdWJzdHJpbmcodmFsdWVTdGFydCArIDEsIHZhbHVlRW5kKTtcbiAgICAgICAgICAgICAgICBjb25zdCBtYXBwZWROYW1lID0gaGVhZGVyRmllbGRNYXBwaW5nc1tuYW1lXTtcbiAgICAgICAgICAgICAgICBpZiAobWFwcGVkTmFtZSkge1xuICAgICAgICAgICAgICAgICAgICAvLyBAdHMtaWdub3JlXG4gICAgICAgICAgICAgICAgICAgIHJlc3VsdFttYXBwZWROYW1lXSA9IGRlY29kZVVSSUNvbXBvbmVudCh2YWx1ZSkgYXMgYW55O1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBjb21tYSA9IHBlZWsoJywnKTtcbiAgICAgICAgICAgICAgICBzZW1pY29sb24gPSBwZWVrKCc7Jyk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXN1bHRzLnB1c2gocmVzdWx0KTtcbiAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHsgIC8vIFdlIHdpbGwgdHJ5IHRoZSBuZXh0IG9uZS4uLlxuICAgICAgICAgICAgY29uc29sZS5sb2coZXJyb3IpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIHJlc3VsdHM7XG59XG5cbmV4cG9ydCBlbnVtIExpbmtSZWxUeXBlIHtcbiAgICBhZGQgPSAnYWRkJyxcbiAgICByZW1vdmUgPSAncmVtb3ZlJyxcbiAgICBlZGl0ID0gJ2VkaXQnLFxufVxuXG4vKipcbiAqIEEgYmFzaWMgY2xpZW50IGZvciBpbnRlcmFjdGluZyB3aXRoIHRoZSBWTXdhcmUgQ2xvdWQgRGlyZWN0b3IgQVBJcy5cbiAqXG4gKiBBIFZNd2FyZSBDbG91ZCBEaXJlY3RvciBwbHVnaW4gY2FuIGdldCBhIHJlZmVyZW5jZSB0byB0aGlzIGNsaWVudCBieSB1c2luZyBhbmd1bGFyIGluamVjdGlvbi5cbiAqIGBgYFxuICogICAgIGNvbnN0cnVjdG9yKHByaXZhdGUgdmNkQXBpOiBWY2RBcGlDbGllbnQpIHt9XG4gKiBgYGBcbiAqXG4gKiBWY2RBcGlDbGllbnQgcmV1c2VzIHRoZSBhdXRoZW50aWNhdGlvbiBmcm9tIHRoZSBWQ0QgcGxhdGZvcm0gc28gaW4gZ2VuZXJhbCB0aGVyZSBpc1xuICogbm8gbmVlZCBvZiBhbiBleHBsaWNpdCBhdXRoZW50aWNhdGlvbi9sb2dpbi5cbiAqXG4gKiBXaGVuIGRlYWxpbmcgd2l0aCB0aGUgc2Vzc2lvbiBtYW5hZ2VtZW50IHRoZXJlIGFyZSB0d28gQVBJczpcbiAqIDEuIERlcHJlY2F0ZWQgbGVnYWN5IEFQSSB0aGF0IGlzIHVzaW5nIHRoZSBgYXBpL3Nlc3Npb25gIGVuZHBvaW50IGFuZCB0aGUgY29ycmVzcG9uZGluZyBtb2RlbHNcbiAqIDIuIE5ld2x5IGFkZGVkIEFQSSB0aGF0IGlzIHVzaW5nIHRoZSBgY2xvdWRhcGlgIGVuZHBvaW50IGFuZCB0aGUgY29ycmVzcG9uZGluZyBtb2RlbHNcbiAqXG4gKiBOb3RlIHRoYXQgaWYgYSBwbHVnaW4gcGVyZm9ybXMgYW4gZXhwbGljaXQgY2xvdWQgYXBpIGF1dGhlbnRpY2F0aW9uIGNhbGwgdGhyb3VnaFxuICoge0BsaW5rIFZjZEFwaUNsaWVudCNzZXRDbG91ZEFwaUF1dGhlbnRpY2F0aW9ufSBvciB7QGxpbmsgVmNkQXBpQ2xpZW50I2Nsb3VkQXBpTG9naW59XG4gKiBmcm9tIHRoYXQgbW9tZW50IG9uIHRoZSBWY2RBcGlDbGllbnQgdXNlcyBvbmx5IGNsb3VkIGFwaSBzZXNzaW9uIG1hbmFnZW1lbnQuXG4gKiBUaGlzIG1lYW5zIGNhbGxzIHRvIHtAbGluayBWY2RBcGlDbGllbnQjc2V0QXV0aGVudGljYXRpb259IG9yIHtAbGluayBWY2RBcGlDbGllbnQjbG9naW59IGhhdmUgbm8gZWZmZWN0LlxuICovXG5ASW5qZWN0YWJsZSgpXG5leHBvcnQgY2xhc3MgVmNkQXBpQ2xpZW50IHtcbiAgICBzZXQgYmFzZVVybChfYmFzZVVybDogc3RyaW5nKSB7XG4gICAgICAgIHRoaXMuX2Jhc2VVcmwgPSBfYmFzZVVybDtcbiAgICB9XG5cbiAgICBnZXQgdmVyc2lvbigpOiBzdHJpbmcge1xuICAgICAgICByZXR1cm4gdGhpcy5odHRwLnJlcXVlc3RIZWFkZXJzSW50ZXJjZXB0b3IudmVyc2lvbjtcbiAgICB9XG5cbiAgICBwcml2YXRlIF9uZWdvdGlhdGVWZXJzaW9uOiBPYnNlcnZhYmxlPHN0cmluZz47XG4gICAgcHJpdmF0ZSBfYmFzZVVybDogc3RyaW5nO1xuXG4gICAgLyoqXG4gICAgICogQGRlcHJlY2F0ZWQgVXNlIHtAbGluayBWY2RBcGlDbGllbnQjX2Nsb3VkQXBpU2Vzc2lvbn1cbiAgICAgKi9cbiAgICBwcml2YXRlIF9zZXNzaW9uOiBCZWhhdmlvclN1YmplY3Q8U2Vzc2lvblR5cGU+ID0gbmV3IEJlaGF2aW9yU3ViamVjdDxTZXNzaW9uVHlwZT4obnVsbCk7XG4gICAgcHJpdmF0ZSBfc2Vzc2lvbk9ic2VydmFibGU6IE9ic2VydmFibGU8U2Vzc2lvblR5cGU+ID0gdGhpcy5fc2Vzc2lvbi5hc09ic2VydmFibGUoKVxuICAgICAgICAucGlwZShcbiAgICAgICAgICAgIHNraXBXaGlsZShzZXNzaW9uID0+ICFzZXNzaW9uKVxuICAgICAgICApO1xuICAgIHByaXZhdGUgX2dldFNlc3Npb246IE9ic2VydmFibGU8U2Vzc2lvblR5cGU+O1xuXG4gICAgLyoqXG4gICAgICogQ2xvdWRBcGkgU2Vzc2lvblxuICAgICAqL1xuICAgIHByaXZhdGUgX2Nsb3VkQXBpU2Vzc2lvbjogQmVoYXZpb3JTdWJqZWN0PFNlc3Npb24+ID0gbmV3IEJlaGF2aW9yU3ViamVjdDxTZXNzaW9uPihudWxsKTtcbiAgICBwcml2YXRlIF9jbG91ZEFwaVNlc3Npb25PYnNlcnZhYmxlOiBPYnNlcnZhYmxlPFNlc3Npb24+ID0gdGhpcy5fY2xvdWRBcGlTZXNzaW9uLmFzT2JzZXJ2YWJsZSgpXG4gICAgICAgIC5waXBlKFxuICAgICAgICAgICAgc2tpcFdoaWxlKHNlc3Npb24gPT4gIXNlc3Npb24pXG4gICAgICAgICk7XG4gICAgLyoqXG4gICAgICogVGhpcyBvYnNlcnZhYmxlIGhhcyBhIHNwZWNpYWwgcHVycG9zZSB3aGVuIGRvaW5nIGF1dG9tYXRpYyBsb2dpbiBkdXJpbmcgdGhlIGNvbnN0cnVjdG9yIGluaXRpYWxpemF0aW9uLlxuICAgICAqIEl0IGFsbG93cyBiYWNrZW5kIGNhbGwgb25seSBhZnRlciBhbiBBUEkgdmVyc2lvbiBpcyBzZXQuXG4gICAgICogSXQgYWxzbyBlbnN1cmVzIHRoYXQgYSBiYWNrZW5kIGNhbGwgdG8gZ2V0IHRoZSBjdXJyZW50IHNlc3Npb24gaXMgZG9uZSBvbmNlIHByaW9yIHRvIGFueSBvdGhlciBjYWxscy5cbiAgICAgKlxuICAgICAqIEluIGNhc2Ugb2YgYW4gZXhwbGljaXQgY2xvdWQgYXBpIGF1dGggcmVxdWVzdCB0aGVyZSBpcyBubyBuZWVkIG9mIHRoaXMgb2JzZXJ2YWJsZVxuICAgICAqIHNpbmNlIHRoaXMgYXV0aCByZXF1ZXN0IHdpbGwgcmV0cmlldmUgdGhlIHNlc3Npb24gaXRzZWxmXG4gICAgICovXG4gICAgcHJpdmF0ZSBfZ2V0Q2xvdWRBcGlTZXNzaW9uOiBPYnNlcnZhYmxlPFNlc3Npb24+O1xuXG4gICAgcHJpdmF0ZSBfY2xvdWRBcGlTZXNzaW9uTGlua3M6IEJlaGF2aW9yU3ViamVjdDxMaW5rVHlwZVtdPiA9IG5ldyBCZWhhdmlvclN1YmplY3Q8TGlua1R5cGVbXT4oW10pO1xuXG4gICAgLyoqXG4gICAgICogQ2FjaGVkLCBsYXp5IGxvYWRlZCBvYnNlcnZhYmxlIG9mIHRoZSBBY2Nlc3NpYmxlTG9jYXRpb24gYXJyYXlcbiAgICAgKi9cbiAgICBwcml2YXRlIF9jbG91ZEFwaUFjY2Vzc2libGVMb2NhdGlvbnM6IE9ic2VydmFibGU8QWNjZXNzaWJsZUxvY2F0aW9uW10+O1xuXG4gICAgLyoqXG4gICAgICogVGhpcyBwcm9wZXJ0eSBkZXRlcm1pbmVzIGlmIGl0IGlzIGFuIGV4cGxpY2l0IGNsb3VkIGFwaSBsb2dpbi5cbiAgICAgKiBJbiB0aGlzIGNhc2UgdGhlIG9sZCBBUEkgKC9hcGkvc2Vzc2lvbikgc2hvdWxkIG5vdCBiZSB1c2VkIGF0IGFsbC5cbiAgICAgKi9cbiAgICBwcml2YXRlIF9pc0Nsb3VkQXBpTG9naW4gPSBmYWxzZTtcblxuICAgIGNvbnN0cnVjdG9yKFxuICAgICAgICAgICAgcHJpdmF0ZSBodHRwOiBWY2RIdHRwQ2xpZW50LFxuICAgICAgICAgICAgcHJpdmF0ZSBpbmplY3RvcjogSW5qZWN0b3IsXG4gICAgICAgICAgICBAT3B0aW9uYWwoKSBwcml2YXRlIGNvbmZpZz86IFZjZFNka0NvbmZpZyxcbiAgICApIHtcbiAgICAgICAgdGhpcy5fYmFzZVVybCA9IHRoaXMuaW5qZWN0b3IuZ2V0KEFQSV9ST09UX1VSTCk7XG4gICAgICAgIFxuICAgICAgICBsZXQgbmVnb3RpYXRlZFZlcnNpb246IE9ic2VydmFibGU8c3RyaW5nPjtcbiAgICAgICAgaWYgKHRoaXMuY29uZmlnPy5hcGlWZXJzaW9uKSB7XG4gICAgICAgICAgICBuZWdvdGlhdGVkVmVyc2lvbiA9IG9mKHRoaXMuY29uZmlnLmFwaVZlcnNpb24pLnBpcGUoXG4gICAgICAgICAgICAgICAgbWFwKCh2ZXJzaW9uKSA9PiB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuc2V0VmVyc2lvbih2ZXJzaW9uKTtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHZlcnNpb247XG4gICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBuZWdvdGlhdGVkVmVyc2lvbiA9IHRoaXMuaHR0cC5nZXQ8U3VwcG9ydGVkVmVyc2lvbnNUeXBlPihgJHt0aGlzLl9iYXNlVXJsfS9hcGkvdmVyc2lvbnNgKS5waXBlKFxuICAgICAgICAgICAgICAgIG1hcCh2ZXJzaW9ucyA9PiB0aGlzLm5lZ290aWF0ZVZlcnNpb24odmVyc2lvbnMpKSxcbiAgICAgICAgICAgICAgICB0YXAodmVyc2lvbiA9PiB0aGlzLnNldFZlcnNpb24odmVyc2lvbikpXG4gICAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMuX25lZ290aWF0ZVZlcnNpb24gPSBuZWdvdGlhdGVkVmVyc2lvbi5waXBlKFxuICAgICAgICAgICAgc2hhcmUoeyBjb25uZWN0b3I6ICgpID0+IG5ldyBSZXBsYXlTdWJqZWN0KDEpIH0pXG4gICAgICAgICk7XG5cbiAgICAgICAgY29uc3QgdG9rZW5Ib2xkZXI6IEF1dGhUb2tlbkhvbGRlclNlcnZpY2UgPSB0aGlzLmluamVjdG9yLmdldChBdXRoVG9rZW5Ib2xkZXJTZXJ2aWNlLCB7IHRva2VuOiAnJyB9KTtcbiAgICAgICAgY29uc3QgdG9rZW4gPSB0b2tlbkhvbGRlci5qd3QgPyBgQmVhcmVyICR7dG9rZW5Ib2xkZXIuand0fWAgOiB0b2tlbkhvbGRlci50b2tlbjtcbiAgICAgICAgdGhpcy5fZ2V0U2Vzc2lvbiA9IHRoaXMuc2V0QXV0aGVudGljYXRpb24odG9rZW4pXG4gICAgICAgICAgICAucGlwZShcbiAgICAgICAgICAgICAgICBzaGFyZSh7IGNvbm5lY3RvcjogKCkgPT4gbmV3IFJlcGxheVN1YmplY3QoMSkgfSlcbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgdGhpcy5fZ2V0Q2xvdWRBcGlTZXNzaW9uID0gdGhpcy5zZXRDbG91ZEFwaUF1dGhlbnRpY2F0aW9uKHRva2VuKVxuICAgICAgICAgICAgLnBpcGUoXG4gICAgICAgICAgICAgICAgc2hhcmUoeyBjb25uZWN0b3I6ICgpID0+IG5ldyBSZXBsYXlTdWJqZWN0KDEpIH0pXG4gICAgICAgICAgICApO1xuICAgICAgICAvLyBUaGlzIGlzIG5vdCBhbiBleHBsaWNpdCBjbG91ZCBhcGkgbG9naW5cbiAgICAgICAgdGhpcy5faXNDbG91ZEFwaUxvZ2luID0gZmFsc2U7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBuZWdvdGlhdGVWZXJzaW9uKHNlcnZlclZlcnNpb25zOiBTdXBwb3J0ZWRWZXJzaW9uc1R5cGUpOiBzdHJpbmcge1xuICAgICAgICBjb25zdCBzdXBwb3J0ZWRWZXJzaW9uczogc3RyaW5nW10gPSBzZXJ2ZXJWZXJzaW9ucy52ZXJzaW9uSW5mby5tYXAodmVyc2lvbkluZm8gPT4gdmVyc2lvbkluZm8udmVyc2lvbik7XG5cbiAgICAgICAgLy8gRGVmYXVsdCBBUEkgVmVyc2lvbiB1c2VkIGlzIHRoZSBMYXRlc3QgQVBJIFZlcnNpb24gaW4gVk13YXJlIENsb3VkIERpcmVjdG9yXG4gICAgICAgIHJldHVybiBzdXBwb3J0ZWRWZXJzaW9uc1tzdXBwb3J0ZWRWZXJzaW9ucy5sZW5ndGggLSAxXTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBUaGUgcHVycG9zZSBvZiB0aGlzIGZ1bmN0aW9uIGlzIHRvIGVuc3VyZSB0aGF0IHByaW9yIHRvIHNlbmRpbmcgYW55IGNhbGwgdG8gdGhlIGJhY2tlbmRcbiAgICAgKiB0aGUgdmVyc2lvbiBoYXMgYmVlbiBzZXQgYW5kIHRoZSBjdXJyZW50IHNlc3Npb24gaGFzIGJlZW4gcmV0cmlldmVkLlxuICAgICAqIE5vdGUgdGhhdCB0aGlzIGlzIGltcG9ydGFudCBkdXJpbmcgdGhlIGF1dG9tYXRpYyBhdXRoZW50aWNhdGlvbiB0aGF0IGlzIGRvbmUgZHVyaW5nIHRoZVxuICAgICAqIGNvbnN0cnVjdG9yIGluaXRpYWxpemF0aW9uLCB3aGVuIHRoZSBwbHVnaW4gaXMgbm90IHJlcXVpcmVkIHRvIHBlcmZvcm0gaXRzIG93biBleHBsaWNpdCBhdXRoZW50aWNhdGlvblxuICAgICAqIGJ1dCByYXRoZXIgdGhlIG9uZXMgZnJvbSB0aGUgdW5kZXJseWluZyBmcmFtZXdvcmsgaXMgdXNlZC5cbiAgICAgKi9cbiAgICBwcml2YXRlIHZhbGlkYXRlUmVxdWVzdENvbnRleHQoKTogT2JzZXJ2YWJsZTx0cnVlPiB7XG4gICAgICAgIHJldHVybiAodGhpcy52ZXJzaW9uID8gb2YodGhpcy52ZXJzaW9uKSA6IHRoaXMuX25lZ290aWF0ZVZlcnNpb24pXG4gICAgICAgICAgICAucGlwZShcbiAgICAgICAgICAgICAgICAvLyBJbiBjYXNlIG9mIGEgY2xvdWQgYXBpIGxvZ2luIHdlIGFyZSBub3QgaW50ZXJlc3RlZCBpbiB0aGUgL2FwaS9zZXNzaW9uIHNlc3Npb25cbiAgICAgICAgICAgICAgICBjb25jYXRNYXAoKCkgPT4gdGhpcy5faXNDbG91ZEFwaUxvZ2luID8gb2YobnVsbCkgOiB0aGlzLl9nZXRTZXNzaW9uKSxcbiAgICAgICAgICAgICAgICBjb25jYXRNYXAoKCkgPT4gdGhpcy5fZ2V0Q2xvdWRBcGlTZXNzaW9uXG4gICAgICAgICAgICAgICAgICAgIC8vIEluIGNhc2Ugb2YgY2xvdWQgYXBpIGZhaWx1cmUgd2UgZG8gbm90IHdhbnQgdG8gcHJldmVudCBmdXJ0aGVyIGV4ZWN1dGlvblxuICAgICAgICAgICAgICAgICAgICAvLyBmb3IgYmFja3dhcmQgY29tcGF0aWJpbGl0eSBjb25zaWRlcmF0aW9ucyBzaW5jZSB0aGlzIG1heSBiZSBhIGNhc2VcbiAgICAgICAgICAgICAgICAgICAgLy8gd2hlbiBjbG91ZCBhcGkgaXMgbm90IHN1cHBvcnRlZCBhdCBhbGwgZm9yIHRoZSBzcGVjaWZpZWQgdmVyc2lvblxuICAgICAgICAgICAgICAgICAgICAucGlwZShjYXRjaEVycm9yKChlKSA9PiBvZih0cnVlKSkpXG4gICAgICAgICAgICAgICAgKSxcbiAgICAgICAgICAgICAgICBtYXAoKCkgPT4gdHJ1ZSlcbiAgICAgICAgICAgICk7XG4gICAgICAgIH1cblxuICAgIC8qKlxuICAgICAqXG4gICAgICogRm9yIHVzZSBjYXNlcyB3aWNoIHNvbGVseSBkZXBlbmRzIG9uIGNsb3VkYXBpIHdpdGhvdXQgYW55IGJhY2t3YXJkIGNvbXBhdGliaWxpdHlcbiAgICAgKiB0aGVyZSBzaG91bGQgYmUgbm8gZGVwZW5kZW5jZSBvbiB0aGUgb2xkIC9hcGkgZW5kcG9pbnQgYXQgYWxsXG4gICAgICovXG4gICAgcHJpdmF0ZSB2YWxpZGF0ZVJlcXVlc3RDb250ZXh0Q2xvdWRBcGlPbmx5KCk6IE9ic2VydmFibGU8U2Vzc2lvbj4ge1xuICAgICAgICByZXR1cm4gKHRoaXMudmVyc2lvbiA/IG9mKHRoaXMudmVyc2lvbikgOiB0aGlzLl9uZWdvdGlhdGVWZXJzaW9uKS5waXBlKFxuICAgICAgICAgICAgY29uY2F0TWFwKCgpID0+IHRoaXMuX2dldENsb3VkQXBpU2Vzc2lvbilcbiAgICAgICAgKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgc2V0VmVyc2lvbihfdmVyc2lvbjogc3RyaW5nKTogVmNkQXBpQ2xpZW50IHtcbiAgICAgICAgdGhpcy5odHRwLnJlcXVlc3RIZWFkZXJzSW50ZXJjZXB0b3IudmVyc2lvbiA9IF92ZXJzaW9uO1xuICAgICAgICByZXR1cm4gdGhpcztcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBHbG9iYWwgY29uZmlndXJhdGlvbiBmb3IgdGhlIHNlcnZpY2UsIHRoYXQgYWxsb3dzIGEgcHJvdmlkZXIgdXNlciB0byBleGVjdXRlIEFQSSByZXF1ZXN0c1xuICAgICAqIGluIHRoZSBzY29wZSBvZiBhIHNwZWNpZmljIHRlbmFudC5cbiAgICAgKiBcbiAgICAgKiBJZiB5b3Ugd2FudCB0byBleGVjdXRlIHNpbmdsZSBBUEkgcmVxdWVzdCBpbiBzY29wZSBvZiBzcGVjaWZpYyB0ZW5hbnQgeW91IGNhbiBkbyBpdFxuICAgICAqIGJ5IHBhc3NpbmcgXCJYLVZNV0FSRS1WQ0xPVUQtVEVOQU5ULUNPTlRFWFRcIiBoZWFkZXIgdG8gdGhlIHNwZWNpZmljIEFQSSBSZXF1ZXN0LlxuICAgICAqXG4gICAgICogVGhpcyBzY29waW5nIGlzIGF2YWlsYWJsZSB0byBxdWVyeS1iYXNlZCBBUEkgY2FsbHMgYW5kIHRvIGJ1bGsgR0VUIGNhbGxzIGluIHRoZVxuICAgICAqIC9jbG91ZGFwaSBzcGFjZS5cbiAgICAgKlxuICAgICAqIEBwYXJhbSBhY3RBcyBhbiBlbnRpdHlSZWYgb2YgdGhlIHRlbmFudCAob3JnYW5pemF0aW9uKSB0byBzY29wZSBzdWJzZXF1ZW50IGNhbGxzIHRvIGluXG4gICAgICogIHRoZSBWY2RBcGlDbGllbnQsIG9yIG51bGwvbm8gcGFyYW1ldGVyIHRvIHJlbW92ZSB0ZW5hbnQtc3BlY2lmaWMgc2NvcGluZ1xuICAgICAqIEByZXR1cm5zIHRoZSBjdXJyZW50IFZjZEFwaUNsaWVudCBpbnN0YW5jZSAoZm9yIGNoYWluaW5nKVxuICAgICAqL1xuICAgIHB1YmxpYyBhY3RBcyhhY3RBczogRW50aXR5UmVmZXJlbmNlVHlwZSA9IG51bGwpOiBWY2RBcGlDbGllbnQge1xuICAgICAgICB0aGlzLmh0dHAucmVxdWVzdEhlYWRlcnNJbnRlcmNlcHRvci5hY3RBcyA9ICFhY3RBcyA/IG51bGwgOiBhY3RBcy5pZDtcbiAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQGRlcHJlY2F0ZWQgVXNlIHtAbGluayBWY2RBcGlDbGllbnQjc2V0Q2xvdWRBcGlBdXRoZW50aWNhdGlvbn1cbiAgICAgKlxuICAgICAqIFNldHMgdGhlIGF1dGhlbnRpY2F0aW9uIHRva2VuIHRvIHVzZSBmb3IgdGhlIFZjZEFwaUNsaWVudC5cbiAgICAgKlxuICAgICAqIEFmdGVyIHNldHRpbmcgdGhlIHRva2VuLCB0aGUgY2xpZW50IHdpbGwgZ2V0IHRoZSBjdXJyZW50IHNlc3Npb25cbiAgICAgKiBpbmZvcm1hdGlvbiBhc3NvY2lhdGVkIHdpdGggdGhlIGF1dGhlbnRpY2F0ZWQgdG9rZW4uXG4gICAgICpcbiAgICAgKiBAcGFyYW0gYXV0aGVudGljYXRpb24gdGhlIGF1dGhlbnRpY2F0aW9uIHN0cmluZyAodG8gYmUgdXNlZCBpbiBlaXRoZXIgdGhlICdBdXRob3JpemF0aW9uJ1xuICAgICAqICBvciAneC12Y2xvdWQtYXV0aG9yaXphdGlvbicgaGVhZGVyKVxuICAgICAqIEByZXR1cm5zIHRoZSBzZXNzaW9uIGFzc29jaWF0ZWQgd2l0aCB0aGUgYXV0aGVudGljYXRpb24gdG9rZW5cbiAgICAgKi9cbiAgICBwdWJsaWMgc2V0QXV0aGVudGljYXRpb24oYXV0aGVudGljYXRpb246IHN0cmluZyk6IE9ic2VydmFibGU8U2Vzc2lvblR5cGU+IHtcbiAgICAgICAgaWYgKHRoaXMuX2lzQ2xvdWRBcGlMb2dpbikge1xuICAgICAgICAgICAgcmV0dXJuIHRocm93RXJyb3IoJ09ubHkgY2xvdWQgYXBpIGF1dGggaXMgYWxsb3dlZCBzaW5jZSBpdCB3YXMgYWxyZWFkeSB1c2VkJyk7XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLmh0dHAucmVxdWVzdEhlYWRlcnNJbnRlcmNlcHRvci5hdXRoZW50aWNhdGlvbiA9IGF1dGhlbnRpY2F0aW9uO1xuICAgICAgICByZXR1cm4gdGhpcy5odHRwLmdldDxTZXNzaW9uVHlwZT4oYCR7dGhpcy5fYmFzZVVybH0vYXBpL3Nlc3Npb25gKS5waXBlKFxuICAgICAgICAgICAgICAgIHRhcChzZXNzaW9uID0+IHtcbiAgICAgICAgICAgICAgICAgICAgLy8gYXV0b21hdGljYWxseSBzZXQgYWN0QXMgZm9yIHByb3ZpZGVyIGluIHRlbmFudCBzY29wZVxuICAgICAgICAgICAgICAgICAgICBpZiAoc2Vzc2lvbi5vcmcgPT09ICdTeXN0ZW0nICYmIHRoaXMuaW5qZWN0b3IuZ2V0KFNFU1NJT05fU0NPUEUpID09PSAndGVuYW50Jykge1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gQXV0b21hdGljIGFjdEFzIG9ubHkgd29ya3MgaW4gdmVyc2lvbnMgPj05LjVcbiAgICAgICAgICAgICAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5hY3RBcyh7aWQ6IHRoaXMuaW5qZWN0b3IuZ2V0KFNFU1NJT05fT1JHX0lEKX0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnNvbGUud2FybignTm8gU0VTU0lPTl9PUkdfSUQgc2V0IGluIGNvbnRhaW5lci4gQXV0b21hdGljIGFjdEFzIGlzIGRpc2FibGVkLicpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSksXG4gICAgICAgICAgICAgICAgdGFwKHNlc3Npb24gPT4gdGhpcy5fc2Vzc2lvbi5uZXh0KHNlc3Npb24pKVxuICAgICAgICAgICAgKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBTZXRzIHRoZSBhdXRoZW50aWNhdGlvbiB0b2tlbiB0byB1c2UgZm9yIHRoZSBWY2RBcGlDbGllbnQuXG4gICAgICpcbiAgICAgKiBBZnRlciBzZXR0aW5nIHRoZSB0b2tlbiwgdGhlIGNsaWVudCB3aWxsIGdldCB0aGUgY3VycmVudCBzZXNzaW9uXG4gICAgICogaW5mb3JtYXRpb24gYXNzb2NpYXRlZCB3aXRoIHRoZSBhdXRoZW50aWNhdGVkIHRva2VuLlxuICAgICAqXG4gICAgICogQHBhcmFtIGF1dGhlbnRpY2F0aW9uIHRoZSBhdXRoZW50aWNhdGlvbiBzdHJpbmcgKHRvIGJlIHVzZWQgaW4gZWl0aGVyIHRoZSAnQXV0aG9yaXphdGlvbidcbiAgICAgKiAgb3IgJ3gtdmNsb3VkLWF1dGhvcml6YXRpb24nIGhlYWRlcilcbiAgICAgKlxuICAgICAqIEByZXR1cm5zIHNlc3Npb24gb2JzZXJ2YWJsZSBhc3NvY2lhdGVkIHdpdGggdGhlIGF1dGhlbnRpY2F0aW9uIHRva2VuXG4gICAgICovXG4gICAgcHVibGljIHNldENsb3VkQXBpQXV0aGVudGljYXRpb24oYXV0aGVudGljYXRpb246IHN0cmluZyk6IE9ic2VydmFibGU8U2Vzc2lvbj4ge1xuICAgICAgICB0aGlzLm9uQmVmb3JlQ2xvdWRBcGlBdXRoZW50aWNhdGlvbigpO1xuXG4gICAgICAgIHJldHVybiBvZih0cnVlKVxuICAgICAgICAgICAgLnBpcGUoXG4gICAgICAgICAgICAgICAgLy8gU2V0IHRoZSBhdXRoZW50aWNhdGlvbiBhcyBwYXJ0IG9mIHRoZSBvYnNlcnZhYmxlIGluIG9yZGVyIHRvIGVuc3VyZSB0aGUgY2FsbGVyIGhhcyBzdWJzY3JpYmVkIHRvIHRoZSBvYnNlcnZhYmxlXG4gICAgICAgICAgICAgICAgdGFwKCgpID0+IHRoaXMuaHR0cC5yZXF1ZXN0SGVhZGVyc0ludGVyY2VwdG9yLmF1dGhlbnRpY2F0aW9uID0gYXV0aGVudGljYXRpb24pLFxuICAgICAgICAgICAgICAgIHN3aXRjaE1hcCgoKSA9PiB0aGlzLmh0dHAuZ2V0PFNlc3Npb24+KGAke3RoaXMuX2Jhc2VVcmx9L2Nsb3VkYXBpLzEuMC4wL3Nlc3Npb25zL2N1cnJlbnRgLCB7IG9ic2VydmU6ICdyZXNwb25zZScgfSkpLFxuICAgICAgICAgICAgKVxuICAgICAgICAgICAgLnBpcGUoXG4gICAgICAgICAgICAgICAgdGhpcy5vbkNsb3VkQXBpQXV0aGVudGljYXRpb24oKVxuICAgICAgICAgICAgKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgZW5hYmxlTG9nZ2luZygpOiBWY2RBcGlDbGllbnQge1xuICAgICAgICB0aGlzLmh0dHAubG9nZ2luZ0ludGVyY2VwdG9yLmVuYWJsZWQgPSB0cnVlO1xuXG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEBkZXByZWNhdGVkIFVzZSB7QGxpbmsgVmNkQXBpQ2xpZW50I2Nsb3VkQXBpTG9naW59XG4gICAgICpcbiAgICAgKiBDcmVhdGVzIGFuIGF1dGhlbnRpY2F0ZWQgc2Vzc2lvbiBmb3IgdGhlIHNwZWNpZmllZCBjcmVkZW50aWFsIGRhdGEuXG4gICAgICpcbiAgICAgKiBAcGFyYW0gdXNlcm5hbWUgdGhlIG5hbWUgb2YgdGhlIHVzZXIgdG8gYXV0aGVudGljYXRlXG4gICAgICogQHBhcmFtIHRlbmFudCB0aGUgb3JnYW5pemF0aW9uIHRoZSB1c2VyIGJlbG9uZ3MgdG9cbiAgICAgKiBAcGFyYW0gcGFzc3dvcmQgdGhlIHBhc3N3b3JkIGZvciB0aGUgdXNlclxuICAgICAqIEByZXR1cm5zIGFuIGF1dGhlbnRpY2F0ZWQgc2Vzc2lvbiBmb3IgdGhlIGdpdmVuIGNyZWRlbnRpYWxzXG4gICAgICovXG4gICAgcHVibGljIGxvZ2luKHVzZXJuYW1lOiBzdHJpbmcsIHRlbmFudDogc3RyaW5nLCBwYXNzd29yZDogc3RyaW5nKTogT2JzZXJ2YWJsZTxTZXNzaW9uVHlwZT4ge1xuICAgICAgICBpZiAodGhpcy5faXNDbG91ZEFwaUxvZ2luKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhyb3dFcnJvcignT25seSBjbG91ZCBhcGkgYXV0aCBpcyBhbGxvd2VkIHNpbmNlIGl0IHdhcyBhbHJlYWR5IHVzZWQnKTtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCBhdXRoU3RyaW5nOiBzdHJpbmcgPSBidG9hKGAke3VzZXJuYW1lfUAke3RlbmFudH06JHtwYXNzd29yZH1gKTtcblxuICAgICAgICByZXR1cm4gdGhpcy5odHRwLnBvc3Q8U2Vzc2lvblR5cGU+KFxuICAgICAgICAgICAgYCR7dGhpcy5fYmFzZVVybH0vYXBpL3Nlc3Npb25zYCxcbiAgICAgICAgICAgIG51bGwsXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgb2JzZXJ2ZTogJ3Jlc3BvbnNlJyxcbiAgICAgICAgICAgICAgICBoZWFkZXJzOiBuZXcgSHR0cEhlYWRlcnMoeyBBdXRob3JpemF0aW9uOiBgQmFzaWMgJHthdXRoU3RyaW5nfWB9KVxuICAgICAgICAgICAgfVxuICAgICAgICApXG4gICAgICAgIC5waXBlKFxuICAgICAgICAgICAgdGFwKChyZXNwb25zZTogSHR0cFJlc3BvbnNlPGFueT4pID0+XG4gICAgICAgICAgICAgICAgLy8gdHNsaW50OmRpc2FibGUtbmV4dC1saW5lOm1heC1saW5lLWxlbmd0aFxuICAgICAgICAgICAgICAgIHRoaXMuaHR0cC5yZXF1ZXN0SGVhZGVyc0ludGVyY2VwdG9yLmF1dGhlbnRpY2F0aW9uID0gYCR7cmVzcG9uc2UuaGVhZGVycy5nZXQoJ3gtdm13YXJlLXZjbG91ZC10b2tlbi10eXBlJyl9ICR7cmVzcG9uc2UuaGVhZGVycy5nZXQoJ3gtdm13YXJlLXZjbG91ZC1hY2Nlc3MtdG9rZW4nKX1gXG4gICAgICAgICAgICApLFxuICAgICAgICAgICAgbWFwKHJlc3BvbnNlID0+IHJlc3BvbnNlLmJvZHkpLFxuICAgICAgICAgICAgdGFwKHNlc3Npb24gPT4gdGhpcy5fc2Vzc2lvbi5uZXh0KHNlc3Npb24pKVxuICAgICAgICApO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIENyZWF0ZXMgYW4gYXV0aGVudGljYXRlZCBzZXNzaW9uIGZvciB0aGUgc3BlY2lmaWVkIGNyZWRlbnRpYWwgZGF0YSB1c2luZyBjbG91ZCBhcGkgZW5kcG9pbnQuXG4gICAgICpcbiAgICAgKiBAcGFyYW0gdXNlcm5hbWUgdGhlIG5hbWUgb2YgdGhlIHVzZXIgdG8gYXV0aGVudGljYXRlXG4gICAgICogQHBhcmFtIHRlbmFudCB0aGUgb3JnYW5pemF0aW9uIHRoZSB1c2VyIGJlbG9uZ3MgdG9cbiAgICAgKiBAcGFyYW0gcGFzc3dvcmQgdGhlIHBhc3N3b3JkIGZvciB0aGUgdXNlclxuICAgICAqIEByZXR1cm5zIGFuIGF1dGhlbnRpY2F0ZWQgc2Vzc2lvbiBmb3IgdGhlIGdpdmVuIGNyZWRlbnRpYWxzXG4gICAgICovXG4gICAgcHVibGljIGNsb3VkQXBpTG9naW4odXNlcm5hbWU6IHN0cmluZywgdGVuYW50OiBzdHJpbmcsIHBhc3N3b3JkOiBzdHJpbmcpOiBPYnNlcnZhYmxlPFNlc3Npb24+IHtcbiAgICAgICAgdGhpcy5vbkJlZm9yZUNsb3VkQXBpQXV0aGVudGljYXRpb24oKTtcblxuICAgICAgICBjb25zdCBhdXRoU3RyaW5nOiBzdHJpbmcgPSBidG9hKGAke3VzZXJuYW1lfUAke3RlbmFudH06JHtwYXNzd29yZH1gKTtcbiAgICAgICAgbGV0IHVybCA9IGAke3RoaXMuX2Jhc2VVcmx9L2Nsb3VkYXBpLzEuMC4wL3Nlc3Npb25zYDtcbiAgICAgICAgaWYgKHRlbmFudC50b0xvd2VyQ2FzZSgpID09PSAnc3lzdGVtJykge1xuICAgICAgICAgICAgdXJsICs9ICcvcHJvdmlkZXInO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB0aGlzLmh0dHAucG9zdDxTZXNzaW9uPihcbiAgICAgICAgICAgIHVybCxcbiAgICAgICAgICAgIG51bGwsXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgb2JzZXJ2ZTogJ3Jlc3BvbnNlJyxcbiAgICAgICAgICAgICAgICBoZWFkZXJzOiBuZXcgSHR0cEhlYWRlcnMoeyBbSFRUUF9IRUFERVJTLkF1dGhvcml6YXRpb25dOiBgQmFzaWMgJHthdXRoU3RyaW5nfWAgfSlcbiAgICAgICAgICAgIH1cbiAgICAgICAgKS5waXBlKFxuICAgICAgICAgICAgdGFwKChyZXNwb25zZTogSHR0cFJlc3BvbnNlPFNlc3Npb24+KSA9PiB7XG4gICAgICAgICAgICAgICAgLy8gdHNsaW50OmRpc2FibGUtbmV4dC1saW5lOm1heC1saW5lLWxlbmd0aFxuICAgICAgICAgICAgICAgIGNvbnN0IHRva2VuID0gYCR7cmVzcG9uc2UuaGVhZGVycy5nZXQoJ3gtdm13YXJlLXZjbG91ZC10b2tlbi10eXBlJyl9ICR7cmVzcG9uc2UuaGVhZGVycy5nZXQoJ3gtdm13YXJlLXZjbG91ZC1hY2Nlc3MtdG9rZW4nKX1gO1xuICAgICAgICAgICAgICAgIHRoaXMuaHR0cC5yZXF1ZXN0SGVhZGVyc0ludGVyY2VwdG9yLmF1dGhlbnRpY2F0aW9uID0gdG9rZW47XG4gICAgICAgICAgICB9KSxcbiAgICAgICAgICAgIHRoaXMub25DbG91ZEFwaUF1dGhlbnRpY2F0aW9uKClcbiAgICAgICAgKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBJdCBpcyBuZWNlc3NhcnkgdG8ga25vdyBpZiBhbiBleHBsaWNpdCBjbG91ZCBhcGkgYXV0aCByZXF1ZXN0IHdhcyBkb25lLlxuICAgICAqIFRoaXMgZnVuY3Rpb24gaGFuZGxlcyB0aGlzIGJ5IHNldHRpbmcgdGhlIGNvcnJlc3BvbmRpbmcgZmxhZ3MsIHByb3BlcnRpZXMgZXRjLlxuICAgICAqL1xuICAgIHByaXZhdGUgb25CZWZvcmVDbG91ZEFwaUF1dGhlbnRpY2F0aW9uKCkge1xuICAgICAgICAvLyBJbiBjYXNlIG9mIGFuIGV4cGxpY2l0IGNsb3VkIGFwaSBhdXRoIHJlcXVlc3Q6XG4gICAgICAgIC8vIFNldCB0aGUgZmxhZyBfaXNDbG91ZEFwaUxvZ2luIGluIG9yZGVyIHRvIGtub3cgdGhhdCBleHBsaWNpdCBjbG91ZCBhcGkgYXV0aGVudGljYXRpb24gaXMgZG9uZVxuICAgICAgICAvLyBUaGlzIHdpbGwgaGVscCB1cyBza2lwIGNvZGUgcmVsYXRlZCB0byB0aGUgb2xkIGFwaSwgaS5lLiB3ZSBzaG91bGQgbm90IGFsbG93IGV4cGxpY2l0IG1peCBvZiBib3RoIHRoZSBhcGktc1xuICAgICAgICB0aGlzLl9pc0Nsb3VkQXBpTG9naW4gPSB0cnVlO1xuICAgICAgICAvLyBJbiBjYXNlIG9mIGFuIGV4cGxpY2l0IGNsb3VkIGFwaSBhdXRoIHJlcXVlc3Q6XG4gICAgICAgIC8vIFRoZXJlIGlzIG5vIG5lZWQgb2YgX2dldENsb3VkQXBpU2Vzc2lvbiBvYnNlcnZhYmxlIHdoaWNoIGlzIG5lZWRlZCBpbiB0aGUgYXV0b21hdGljIGxvZ2luIGR1cmluZyB0aGUgY29uc3RydWN0b3IgaW5pdGlhbGl6YXRpb24uXG4gICAgICAgIC8vIFRoZSBleHBsaWNpdCBjbG91ZCBhcGkgYXV0aCByZXF1ZXN0IHdpbGwgcmV0cmlldmUgdGhlIHNlc3Npb24uXG4gICAgICAgIHRoaXMuX2dldENsb3VkQXBpU2Vzc2lvbiA9IG9mKG51bGwpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEhhbmRsZSBhdXRoZW50aWNhdGlvbi5cbiAgICAgKiBUaGlzIGluY2x1ZGVzIGdldHRpbmcgSEFURU9BUyBsaW5rcywgc2V0dGluZyB0aGUgc2Vzc2lvbiwgaGFuZGxpbmcgZXJyb3JzIGV0Yy5cbiAgICAgKi9cbiAgICBwcml2YXRlIG9uQ2xvdWRBcGlBdXRoZW50aWNhdGlvbigpOiAoc291cmNlOiBPYnNlcnZhYmxlPEh0dHBSZXNwb25zZTxTZXNzaW9uPj4pID0+IE9ic2VydmFibGU8U2Vzc2lvbj4ge1xuICAgICAgICByZXR1cm4gKHNvdXJjZSkgPT4gc291cmNlLnBpcGUoXG4gICAgICAgICAgICB0YXAoKHJlc3A6IEh0dHBSZXNwb25zZTxTZXNzaW9uPikgPT4ge1xuICAgICAgICAgICAgICAgIC8vIEdldCBIQVRFT0FTIGxpbmtzXG4gICAgICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5zZXRDbG91ZEFwaVNlc3Npb25MaW5rcyhwYXJzZUhlYWRlckhhdGVvYXNMaW5rcyhyZXNwLmhlYWRlcnMuZ2V0KEhBVEVPQVNfSEVBREVSKSkpO1xuICAgICAgICAgICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc29sZS5sb2coJ0Vycm9yIHdoZW4gcGFyc2luZyBzZXNzaW9uIEhBVEVPQVMgbGlua3M6JywgZSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSksXG4gICAgICAgICAgICBtYXAocmVzcCA9PiByZXNwLmJvZHkpLFxuICAgICAgICAgICAgdGFwKChzZXNzaW9uOiBTZXNzaW9uKSA9PiB7XG4gICAgICAgICAgICAgICAgLy8gQ2xlYXIgcHJldmlvdXMgYWN0QXNcbiAgICAgICAgICAgICAgICB0aGlzLmFjdEFzKG51bGwpO1xuICAgICAgICAgICAgICAgIC8vIGF1dG9tYXRpY2FsbHkgc2V0IGFjdEFzIGZvciBwcm92aWRlciBpbiB0ZW5hbnQgc2NvcGVcbiAgICAgICAgICAgICAgICBpZiAoc2Vzc2lvbi5vcmcgJiYgc2Vzc2lvbi5vcmcubmFtZSA9PT0gJ1N5c3RlbScgJiYgdGhpcy5pbmplY3Rvci5nZXQoU0VTU0lPTl9TQ09QRSkgPT09ICd0ZW5hbnQnKSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIEF1dG9tYXRpYyBhY3RBcyBvbmx5IHdvcmtzIGluIHZlcnNpb25zID49OS41XG4gICAgICAgICAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmFjdEFzKHsgaWQ6IHRoaXMuaW5qZWN0b3IuZ2V0KFNFU1NJT05fT1JHX0lEKSB9KTtcbiAgICAgICAgICAgICAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgY29uc29sZS53YXJuKCdObyBTRVNTSU9OX09SR19JRCBzZXQgaW4gY29udGFpbmVyLiBBdXRvbWF0aWMgYWN0QXMgaXMgZGlzYWJsZWQuJyk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KSxcbiAgICAgICAgICAgIHRhcCgoc2Vzc2lvbjogU2Vzc2lvbikgPT4gdGhpcy5fY2xvdWRBcGlTZXNzaW9uLm5leHQoc2Vzc2lvbikpLFxuICAgICAgICAgICAgY2F0Y2hFcnJvcigoZSkgPT4ge1xuICAgICAgICAgICAgICAgIHRoaXMub25DbG91ZEFwaUF1dGhlbnRpY2F0aW9uRXJyb3IoKTtcbiAgICAgICAgICAgICAgICByZXR1cm4gdGhyb3dFcnJvcihlKTtcbiAgICAgICAgICAgIH0pXG4gICAgICAgICk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBvbkNsb3VkQXBpQXV0aGVudGljYXRpb25FcnJvcigpIHtcbiAgICAgICAgLy8gQ2xlYXIgdGhlIGF1dGhlbnRpY2F0aW9uIHNvIHRoYXQgYW55IHN1YnNlcXVlbnQgYmFja2VuZCBjYWxscyBhcmUgbm90IGF1dGhlbnRpY2F0ZWRcbiAgICAgICAgdGhpcy5odHRwLnJlcXVlc3RIZWFkZXJzSW50ZXJjZXB0b3IuYXV0aGVudGljYXRpb24gPSAnJztcbiAgICAgICAgLy8gX2dldENsb3VkQXBpU2Vzc2lvbiBpcyBpbiB0aGUgY2VudGVyIG9mIGFueSBiYWNrZW5kIGNhbGwsIG51bGxpZnkgaXQgaW4gb3JkZXIgbm90IHRvIHByZXZlbnQgdGhvc2UgY2FsbHNcbiAgICAgICAgLy8gc2luY2UgaXQgaXMgZWFzaWVyIHRvIHRyb3VibGVzaG9vdCBmYWlsaW5nIGJhY2tlbmQgcmF0aGVyIHRoYW4gbm8gY2FsbFxuICAgICAgICB0aGlzLl9nZXRDbG91ZEFwaVNlc3Npb24gPSBvZihudWxsKTtcbiAgICAgICAgLy8gQ2xlYXIgdGhlIGxpbmtzXG4gICAgICAgIHRoaXMuX2Nsb3VkQXBpU2Vzc2lvbkxpbmtzLm5leHQoW10pO1xuICAgICAgICAvLyBDbGVhciB0aGUgc2Vzc2lvblxuICAgICAgICB0aGlzLl9jbG91ZEFwaVNlc3Npb24ubmV4dChudWxsKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIHNldENsb3VkQXBpU2Vzc2lvbkxpbmtzKGxpbmtzOiBMaW5rVHlwZVtdKSB7XG4gICAgICAgIHRoaXMuX2Nsb3VkQXBpQWNjZXNzaWJsZUxvY2F0aW9ucyA9IG51bGw7XG4gICAgICAgIHRoaXMuX2Nsb3VkQXBpU2Vzc2lvbkxpbmtzLm5leHQobGlua3MgfHwgW10pO1xuICAgIH1cblxuICAgIHB1YmxpYyBnZXQ8VD4oZW5kcG9pbnQ6IHN0cmluZywgIG9wdGlvbnM/OiB7IGhlYWRlcnM/OiBIdHRwSGVhZGVycyB9KTogT2JzZXJ2YWJsZTxUPiB7XG4gICAgICAgIHJldHVybiB0aGlzLnZhbGlkYXRlUmVxdWVzdENvbnRleHQoKS5waXBlKFxuICAgICAgICAgICAgY29uY2F0TWFwKCgpID0+IHRoaXMuaHR0cC5nZXQ8VD4odGhpcy5idWlsZEVuZHBvaW50VXJsKGVuZHBvaW50KSwgey4uLm9wdGlvbnN9KSlcbiAgICAgICAgKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgbGlzdDxUPihlbmRwb2ludDogc3RyaW5nLCBxdWVyeUJ1aWxkZXI/OiBRdWVyeS5CdWlsZGVyLCBtdWx0aXNpdGU/OiBib29sZWFuIHwgQXV0aG9yaXplZExvY2F0aW9uVHlwZVtdLCBvcHRpb25zPzogeyBoZWFkZXJzPzogSHR0cEhlYWRlcnMgfSkge1xuICAgICAgICBsZXQgdXJsID0gdGhpcy5idWlsZEVuZHBvaW50VXJsKGVuZHBvaW50KTtcblxuICAgICAgICBpZiAocXVlcnlCdWlsZGVyKSB7XG4gICAgICAgICAgICB1cmwgPSBgJHt1cmx9JHtxdWVyeUJ1aWxkZXIuZ2V0Q2xvdWRBUEkoKX1gO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKG11bHRpc2l0ZSkge1xuICAgICAgICAgICAgaWYgKCFvcHRpb25zKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMuaHR0cC5nZXQ8VD4odXJsLCB7IGhlYWRlcnM6IG5ldyBIdHRwSGVhZGVycyh7IF9tdWx0aXNpdGU6IHRoaXMucGFyc2VNdWx0aXNpdGVWYWx1ZShtdWx0aXNpdGUpIH0pIH0pO1xuICAgICAgICAgICAgfSBlbHNlIGlmIChvcHRpb25zPy5oZWFkZXJzKSB7XG4gICAgICAgICAgICAgICAgb3B0aW9ucy5oZWFkZXJzLmFwcGVuZChcIl9tdWx0aXNpdGVcIiwgdGhpcy5wYXJzZU11bHRpc2l0ZVZhbHVlKG11bHRpc2l0ZSkpO1xuICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLmh0dHAuZ2V0PFQ+KHVybCwgeyAuLi5vcHRpb25zIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHRoaXMudmFsaWRhdGVSZXF1ZXN0Q29udGV4dCgpLnBpcGUoXG4gICAgICAgICAgICBjb25jYXRNYXAoKCkgPT4gdGhpcy5odHRwLmdldDxUPih1cmwsIHsgLi4ub3B0aW9ucyB9KSlcbiAgICAgICAgKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgY3JlYXRlU3luYzxUPihlbmRwb2ludDogc3RyaW5nLCBpdGVtOiBULCBvcHRpb25zPzogeyBoZWFkZXJzPzogSHR0cEhlYWRlcnMgfSk6IE9ic2VydmFibGU8VD4ge1xuICAgICAgICByZXR1cm4gdGhpcy52YWxpZGF0ZVJlcXVlc3RDb250ZXh0KCkucGlwZShcbiAgICAgICAgICAgIGNvbmNhdE1hcCgoKSA9PiB0aGlzLmh0dHAucG9zdDxUPihcbiAgICAgICAgICAgICAgICB0aGlzLmJ1aWxkRW5kcG9pbnRVcmwoZW5kcG9pbnQpLFxuICAgICAgICAgICAgICAgIGl0ZW0sXG4gICAgICAgICAgICAgICAgey4uLm9wdGlvbnN9XG4gICAgICAgICAgICApKVxuICAgICAgICApO1xuICAgIH1cblxuICAgIHB1YmxpYyBjcmVhdGVBc3luYzxUPihlbmRwb2ludDogc3RyaW5nLCBpdGVtOiBULCBvcHRpb25zPzogeyBoZWFkZXJzPzogSHR0cEhlYWRlcnMgfSk6IE9ic2VydmFibGU8VGFza1R5cGU+IHtcbiAgICAgICAgcmV0dXJuIHRoaXMudmFsaWRhdGVSZXF1ZXN0Q29udGV4dCgpLnBpcGUoXG4gICAgICAgICAgICBjb25jYXRNYXAoKCkgPT4gdGhpcy5odHRwLnBvc3QoXG4gICAgICAgICAgICAgICAgdGhpcy5idWlsZEVuZHBvaW50VXJsKGVuZHBvaW50KSxcbiAgICAgICAgICAgICAgICBpdGVtLFxuICAgICAgICAgICAgICAgIHsgLi4ub3B0aW9ucywgb2JzZXJ2ZTogJ3Jlc3BvbnNlJyB9XG4gICAgICAgICAgICApKSxcbiAgICAgICAgICAgIGNvbmNhdE1hcChyZXNwb25zZSA9PiB0aGlzLm1hcFJlc3BvbnNlVG9UYXNrKHJlc3BvbnNlLCAnUE9TVCcpKVxuICAgICAgICApO1xuICAgIH1cblxuICAgIHB1YmxpYyBnZXRUcmFuc2Zlckxpbms8VD4oZW5kcG9pbnQ6IHN0cmluZywgaXRlbTogVCwgdHJhbnNmZXJSZWw6IHN0cmluZyA9IFRSQU5TRkVSX0xJTktfUkVMKTogT2JzZXJ2YWJsZTxzdHJpbmc+IHtcbiAgICAgICAgcmV0dXJuIHRoaXMuaHR0cFxuICAgICAgICAgICAgLnBvc3QodGhpcy5idWlsZEVuZHBvaW50VXJsKGVuZHBvaW50KSwgaXRlbSwgeyBvYnNlcnZlOiAncmVzcG9uc2UnIH0pXG4gICAgICAgICAgICAucGlwZShcbiAgICAgICAgICAgICAgICBtYXAoKHJlczogSHR0cFJlc3BvbnNlPFQgJiBOYXZpZ2FibGU+KSA9PiB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IGhlYWRlckxpbmtzOiBMaW5rVHlwZVtdID0gcmVzLmhlYWRlcnMuaGFzKEhBVEVPQVNfSEVBREVSKVxuICAgICAgICAgICAgICAgICAgICAgICAgPyBwYXJzZUhlYWRlckhhdGVvYXNMaW5rcyhyZXMuaGVhZGVycy5nZXQoSEFURU9BU19IRUFERVIpKVxuICAgICAgICAgICAgICAgICAgICAgICAgOiBbXTtcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgbGlua3M6IExpbmtUeXBlW10gPSByZXMuYm9keSA/IChyZXMuYm9keS5saW5rIHx8IFtdKSA6IFtdO1xuICAgICAgICAgICAgICAgICAgICBjb25zdCBsaW5rID0gWy4uLmhlYWRlckxpbmtzLCAuLi5saW5rc11cbiAgICAgICAgICAgICAgICAgICAgICAgIC5maW5kKChsKSA9PiBsLnJlbCA9PT0gdHJhbnNmZXJSZWwpO1xuICAgICAgICAgICAgICAgICAgICBpZiAoIWxpbmspIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgUmVzcG9uc2UgZnJvbSAke2VuZHBvaW50fSBkaWQgbm90IGNvbnRhaW4gYSB0cmFuc2ZlciBsaW5rYCk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGxpbmsuaHJlZjtcbiAgICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgc3RhcnRUcmFuc2ZlcjxUPihlbmRwb2ludDogc3RyaW5nLCBpdGVtOiBULCB0cmFuc2ZlclJlbDogc3RyaW5nID0gVFJBTlNGRVJfTElOS19SRUwpOiBPYnNlcnZhYmxlPFZjZFRyYW5zZmVyQ2xpZW50PiB7XG4gICAgICAgIHJldHVybiB0aGlzLmdldFRyYW5zZmVyTGluayhlbmRwb2ludCwgaXRlbSwgdHJhbnNmZXJSZWwpXG4gICAgICAgICAgICAucGlwZShcbiAgICAgICAgICAgICAgICBtYXAoKHRyYW5zZmVyVXJsKSA9PiBuZXcgVmNkVHJhbnNmZXJDbGllbnQodGhpcy5odHRwLCB0cmFuc2ZlclVybCkpXG4gICAgICAgICAgICApO1xuICAgIH1cblxuICAgIHB1YmxpYyB1cGRhdGVTeW5jPFQ+KGVuZHBvaW50OiBzdHJpbmcsIGl0ZW06IFQsIG9wdGlvbnM/OiB7IGhlYWRlcnM/OiBIdHRwSGVhZGVycyB9KTogT2JzZXJ2YWJsZTxUPiB7XG4gICAgICAgIHJldHVybiB0aGlzLnZhbGlkYXRlUmVxdWVzdENvbnRleHQoKS5waXBlKFxuICAgICAgICAgICAgY29uY2F0TWFwKCgpID0+IHRoaXMuaHR0cC5wdXQ8VD4oXG4gICAgICAgICAgICAgICAgdGhpcy5idWlsZEVuZHBvaW50VXJsKGVuZHBvaW50KSxcbiAgICAgICAgICAgICAgICBpdGVtLFxuICAgICAgICAgICAgICAgIHsgLi4ub3B0aW9ucyB9XG4gICAgICAgICAgICApKVxuICAgICAgICApO1xuICAgIH1cblxuICAgIHB1YmxpYyB1cGRhdGVBc3luYzxUPihlbmRwb2ludDogc3RyaW5nLCBpdGVtOiBULCBvcHRpb25zPzogeyBoZWFkZXJzPzogSHR0cEhlYWRlcnMgfSk6IE9ic2VydmFibGU8VGFza1R5cGU+IHtcblxuICAgICAgICByZXR1cm4gdGhpcy52YWxpZGF0ZVJlcXVlc3RDb250ZXh0KCkucGlwZShcbiAgICAgICAgICAgIGNvbmNhdE1hcCgoKSA9PiB0aGlzLmh0dHAucHV0KFxuICAgICAgICAgICAgICAgIHRoaXMuYnVpbGRFbmRwb2ludFVybChlbmRwb2ludCksXG4gICAgICAgICAgICAgICAgaXRlbSxcbiAgICAgICAgICAgICAgICB7IC4uLm9wdGlvbnMsIG9ic2VydmU6ICdyZXNwb25zZScgfVxuICAgICAgICAgICAgKSksXG4gICAgICAgICAgICBjb25jYXRNYXAocmVzcG9uc2UgPT4gdGhpcy5tYXBSZXNwb25zZVRvVGFzayhyZXNwb25zZSwgJ1BVVCcpKVxuICAgICAgICApO1xuICAgIH1cblxuICAgIHB1YmxpYyBkZWxldGVTeW5jKGVuZHBvaW50OiBzdHJpbmcsIG9wdGlvbnM/OiB7IGhlYWRlcnM/OiBIdHRwSGVhZGVycyB9KTogT2JzZXJ2YWJsZTx2b2lkPiB7XG4gICAgICAgIHJldHVybiB0aGlzLnZhbGlkYXRlUmVxdWVzdENvbnRleHQoKS5waXBlKFxuICAgICAgICAgICAgY29uY2F0TWFwKCgpID0+IHRoaXMuaHR0cC5kZWxldGU8dm9pZD4odGhpcy5idWlsZEVuZHBvaW50VXJsKGVuZHBvaW50KSwgeyAuLi5vcHRpb25zIH0pKVxuICAgICAgICApO1xuICAgIH1cblxuICAgIHB1YmxpYyBkZWxldGVBc3luYyhlbmRwb2ludDogc3RyaW5nLCBvcHRpb25zPzogeyBoZWFkZXJzPzogSHR0cEhlYWRlcnMgfSk6IE9ic2VydmFibGU8VGFza1R5cGU+IHtcbiAgICAgICAgcmV0dXJuIHRoaXMudmFsaWRhdGVSZXF1ZXN0Q29udGV4dCgpLnBpcGUoXG4gICAgICAgICAgICBjb25jYXRNYXAoKCkgPT4gdGhpcy5odHRwLmRlbGV0ZSh0aGlzLmJ1aWxkRW5kcG9pbnRVcmwoZW5kcG9pbnQpLCB7IC4uLm9wdGlvbnMsIG9ic2VydmU6ICdyZXNwb25zZScgfSkpLFxuICAgICAgICAgICAgY29uY2F0TWFwKHJlc3BvbnNlID0+IHRoaXMubWFwUmVzcG9uc2VUb1Rhc2socmVzcG9uc2UsICdERUxFVEUnKSlcbiAgICAgICAgKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIG1hcFJlc3BvbnNlVG9UYXNrKHJlc3BvbnNlOiBIdHRwUmVzcG9uc2U8YW55PiwgaHR0cFZlcmI6IHN0cmluZyk6IE9ic2VydmFibGU8VGFza1R5cGU+IHtcbiAgICAgICAgaWYgKHJlc3BvbnNlLmhlYWRlcnMuaGFzKCdMb2NhdGlvbicpICYmIHJlc3BvbnNlLnN0YXR1cyA9PT0gMjAyKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5odHRwLmdldDxUYXNrVHlwZT4ocmVzcG9uc2UuaGVhZGVycy5nZXQoJ0xvY2F0aW9uJykpO1xuICAgICAgICB9IGVsc2UgaWYgKHJlc3BvbnNlLmJvZHkgJiYgcmVzcG9uc2UuYm9keS50eXBlLnN0YXJ0c1dpdGgoJ2FwcGxpY2F0aW9uL3ZuZC52bXdhcmUudmNsb3VkLnRhc2srJykpIHtcbiAgICAgICAgICAgIGNvbnN0IHRhc2s6IFRhc2tUeXBlID0gT2JqZWN0LmFzc2lnbihuZXcgVGFza1R5cGUoKSwgcmVzcG9uc2UuYm9keSk7XG4gICAgICAgICAgICByZXR1cm4gb2YodGFzayk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gdGhyb3dFcnJvcigoKSA9PiBuZXcgRXJyb3IoYEFuIGFzeW5jaHJvbm91cyByZXF1ZXN0IHdhcyBtYWRlIHRvIFske2h0dHBWZXJifSAke3Jlc3BvbnNlLnVybH1dLCBidXQgbm8gdGFzayB3YXMgcmV0dXJuZWQuICBUaGUgb3BlcmF0aW9uIG1heSBzdGlsbCBoYXZlIGJlZW4gc3VjY2Vzc2Z1bC5gKSk7XG4gICAgfVxuXG4gICAgcHVibGljIGdldEVudGl0eTxUIGV4dGVuZHMgRW50aXR5UmVmZXJlbmNlVHlwZT4oZW50aXR5UmVmOiBFbnRpdHlSZWZlcmVuY2VUeXBlKTogT2JzZXJ2YWJsZTxUPjtcbiAgICAvLyB0c2xpbnQ6ZGlzYWJsZS1uZXh0LWxpbmU6dW5pZmllZC1zaWduYXR1cmVzXG4gICAgcHVibGljIGdldEVudGl0eTxUIGV4dGVuZHMgRW50aXR5UmVmZXJlbmNlVHlwZT4odXJuOiBzdHJpbmcpOiBPYnNlcnZhYmxlPFQ+O1xuICAgIHB1YmxpYyBnZXRFbnRpdHk8VCBleHRlbmRzIEVudGl0eVJlZmVyZW5jZVR5cGU+KGVudGl0eVJlZk9yVXJuOiBFbnRpdHlSZWZlcmVuY2VUeXBlIHwgc3RyaW5nKTogT2JzZXJ2YWJsZTxUPiB7XG4gICAgICAgIGNvbnN0IGVudGl0eVJlc29sdmVyOiBPYnNlcnZhYmxlPEVudGl0eVR5cGU+ID0gdHlwZW9mIGVudGl0eVJlZk9yVXJuID09PSAnc3RyaW5nJyA/XG4gICAgICAgICAgICB0aGlzLmh0dHAuZ2V0PEVudGl0eVR5cGU+KGAke3RoaXMuX2Jhc2VVcmx9L2FwaS9lbnRpdHkvJHtlbnRpdHlSZWZPclVybn1gKSA6XG4gICAgICAgICAgICB0aGlzLmh0dHAuZ2V0PEVudGl0eVR5cGU+KGAke3RoaXMuX2Jhc2VVcmx9L2FwaS9lbnRpdHkvdXJuOnZjbG91ZDoke2VudGl0eVJlZk9yVXJuLnR5cGV9OiR7ZW50aXR5UmVmT3JVcm4uaWR9YCk7XG5cbiAgICAgICAgcmV0dXJuIHRoaXMudmFsaWRhdGVSZXF1ZXN0Q29udGV4dCgpLnBpcGUoXG4gICAgICAgICAgICBjb25jYXRNYXAoKCkgPT4gZW50aXR5UmVzb2x2ZXIpLFxuICAgICAgICAgICAgY29uY2F0TWFwKGVudGl0eSA9PiB0aGlzLmh0dHAuZ2V0PFQ+KGAke2VudGl0eS5saW5rWzBdLmhyZWZ9YCkpXG4gICAgICAgICk7XG4gICAgfVxuXG4gICAgcHVibGljIHVwZGF0ZVRhc2sodGFzazogVGFza1R5cGUsIG9wdGlvbnM/OiB7IGhlYWRlcnM/OiBIdHRwSGVhZGVycyB9KTogT2JzZXJ2YWJsZTxUYXNrVHlwZT4ge1xuICAgICAgICByZXR1cm4gdGhpcy52YWxpZGF0ZVJlcXVlc3RDb250ZXh0KCkucGlwZShcbiAgICAgICAgICAgIGNvbmNhdE1hcCgoKSA9PiB0aGlzLmh0dHAuZ2V0PFRhc2tUeXBlPih0YXNrLmhyZWYsIHsgLi4ub3B0aW9ucyB9KSlcbiAgICAgICAgKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgaXNUYXNrQ29tcGxldGUodGFzazogVGFza1R5cGUpOiBib29sZWFuIHtcbiAgICAgICAgcmV0dXJuIFsnc3VjY2VzcycsICdlcnJvcicsICdjYW5jZWxlZCcsICdhYm9ydGVkJ10uaW5kZXhPZih0YXNrLnN0YXR1cykgPiAtMTtcbiAgICB9XG5cbiAgICBwdWJsaWMgcmVtb3ZlSXRlbShpdGVtOiBOYXZpZ2FibGUsIG9wdGlvbnM/OiB7IGhlYWRlcnM/OiBIdHRwSGVhZGVycyB9KTogT2JzZXJ2YWJsZTxUYXNrVHlwZT4ge1xuICAgICAgICBjb25zdCBsaW5rOiBMaW5rVHlwZSA9IHRoaXMuZmluZExpbmsoaXRlbSwgJ3JlbW92ZScsIG51bGwpO1xuICAgICAgICBpZiAoIWxpbmspIHtcbiAgICAgICAgICAgIHJldHVybiB0aHJvd0Vycm9yKCgpID0+IG5ldyBFcnJvcihgTm8gJ3JlbW92ZScgbGluayBmb3Igc3BlY2lmaWVkIHJlc291cmNlLmApKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiB0aGlzLnZhbGlkYXRlUmVxdWVzdENvbnRleHQoKS5waXBlKFxuICAgICAgICAgICAgY29uY2F0TWFwKCgpID0+IHRoaXMuaHR0cC5kZWxldGU8VGFza1R5cGU+KGxpbmsuaHJlZiwgeyAuLi5vcHRpb25zIH0pKVxuICAgICAgICApO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFF1ZXJpZXMgdGhlIFZNd2FyZSBDbG91ZCBEaXJlY3RvciBBUEkgYmFzZWQgb24gdGhlIHNwZWNpZmllZCBRdWVyeS5CdWlsZGVyIGluc3RhbmNlLlxuICAgICAqXG4gICAgICogQHBhcmFtIGJ1aWxkZXIgQW4gZGVmaW5pdGlvbiBvZiB0aGUgcXVlcnkgdG8gY29uc3RydWN0ICh0eXBlLCBmaWx0ZXIsIHBhZ2Ugc2l6ZSwgZXRjLilcbiAgICAgKiBAcGFyYW0gbXVsdGlzaXRlIGEgZmxhZyBpbmRpY2F0aW5nIHdoZXRoZXIgb3Igbm90IHRvIGZhbiB0aGUgcXVlcnkgb3V0IHRvIGFsbCBhdmFpbGFibGUgc2l0ZXNcbiAgICAgKiBAcmV0dXJucyBhIHF1ZXJ5IHJlc3VsdCBmb3IgdGhlIHNwZWNpZmllZCBxdWVyeVxuICAgICAqL1xuICAgIHB1YmxpYyBxdWVyeTxUPihidWlsZGVyOiBRdWVyeS5CdWlsZGVyLCBtdWx0aXNpdGU/OiBib29sZWFuLCBvcHRpb25zPzogeyBoZWFkZXJzPzogSHR0cEhlYWRlcnMgfSk6IE9ic2VydmFibGU8VD47XG4gICAgLyoqXG4gICAgICogUXVlcmllcyB0aGUgVk13YXJlIENsb3VkIERpcmVjdG9yIEFQSSBiYXNlZCBvbiB0aGUgc3BlY2lmaWVkIFF1ZXJ5LkJ1aWxkZXIgaW5zdGFuY2UuXG4gICAgICpcbiAgICAgKiBAcGFyYW0gYnVpbGRlciBBbiBkZWZpbml0aW9uIG9mIHRoZSBxdWVyeSB0byBjb25zdHJ1Y3QgKHR5cGUsIGZpbHRlciwgcGFnZSBzaXplLCBldGMuKVxuICAgICAqIEBwYXJhbSBtdWx0aXNpdGUgdGhlIHNldCBvZiBzaXRlIGxvY2F0aW9ucyB0byBpbmNsdWRlIGluIHRoZSBxdWVyeSBmYW5vdXRcbiAgICAgKiBAcmV0dXJucyBhIHF1ZXJ5IHJlc3VsdCBmb3IgdGhlIHNwZWNpZmllZCBxdWVyeVxuICAgICAqL1xuICAgIC8vIHRzbGludDpkaXNhYmxlLW5leHQtbGluZTp1bmlmaWVkLXNpZ25hdHVyZXNcbiAgICBwdWJsaWMgcXVlcnk8VD4oYnVpbGRlcjogUXVlcnkuQnVpbGRlciwgbXVsdGlzaXRlPzogQXV0aG9yaXplZExvY2F0aW9uVHlwZVtdLCBvcHRpb25zPzogeyBoZWFkZXJzPzogSHR0cEhlYWRlcnMgfSk6IE9ic2VydmFibGU8VD47XG4gICAgcHVibGljIHF1ZXJ5PFQ+KGJ1aWxkZXI6IFF1ZXJ5LkJ1aWxkZXIsIG11bHRpc2l0ZT86IGFueSwgb3B0aW9ucz86IHsgaGVhZGVycz86IEh0dHBIZWFkZXJzIH0pOiBPYnNlcnZhYmxlPFQ+IHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZ2V0UXVlcnlQYWdlKGAke3RoaXMuX2Jhc2VVcmx9L2FwaS9xdWVyeSR7YnVpbGRlci5nZXQoKX1gLCBtdWx0aXNpdGUsIG9wdGlvbnMpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFF1ZXJpZXMgdGhlIFZNd2FyZSBDbG91ZCBEaXJlY3RvciBBUEkgZm9yIHRoZSBmaXJzdCBwYWdlIG9mIHRoZSBwcm92aWRlZCByZXN1bHQgc2V0LlxuICAgICAqXG4gICAgICogQHBhcmFtIHJlc3VsdCB0aGUgcmVzdWx0IHNldCB0byByZXRyaWV2ZSB0aGUgZmlyc3QgcGFnZSBvZiByZWNvcmRzIGZvclxuICAgICAqIEBwYXJhbSBtdWx0aXNpdGUgYSBmbGFnIGluZGljYXRpbmcgd2hldGhlciBvciBub3QgdG8gZmFuIHRoZSBxdWVyeSBvdXQgdG8gYWxsIGF2YWlsYWJsZSBzaXRlc1xuICAgICAqIEByZXR1cm5zIHRoZSByZWNvcmRzIGZvciB0aGUgZmlyc3QgcGFnZSBvZiB0aGUgcXVlcnlcbiAgICAgKi9cbiAgICBwdWJsaWMgZmlyc3RQYWdlPFQ+KHJlc3VsdDogVCwgbXVsdGlzaXRlPzogYm9vbGVhbiwgb3B0aW9ucz86IHsgaGVhZGVycz86IEh0dHBIZWFkZXJzIH0pOiBPYnNlcnZhYmxlPFQ+O1xuICAgIC8qKlxuICAgICAqIFF1ZXJpZXMgdGhlIFZNd2FyZSBDbG91ZCBEaXJlY3RvciBBUEkgZm9yIHRoZSBmaXJzdCBwYWdlIG9mIHRoZSBwcm92aWRlZCByZXN1bHQgc2V0LlxuICAgICAqXG4gICAgICogQHBhcmFtIHJlc3VsdCB0aGUgcmVzdWx0IHNldCB0byByZXRyaWV2ZSB0aGUgZmlyc3QgcGFnZSBvZiByZWNvcmRzIGZvclxuICAgICAqIEBwYXJhbSBtdWx0aXNpdGUgdGhlIHNldCBvZiBzaXRlIGxvY2F0aW9ucyB0byBpbmNsdWRlIGluIHRoZSBxdWVyeSBmYW5vdXRcbiAgICAgKiBAcmV0dXJucyB0aGUgcmVjb3JkcyBmb3IgdGhlIGZpcnN0IHBhZ2Ugb2YgdGhlIHF1ZXJ5XG4gICAgICovXG4gICAgLy8gdHNsaW50OmRpc2FibGUtbmV4dC1saW5lOnVuaWZpZWQtc2lnbmF0dXJlc1xuICAgIHB1YmxpYyBmaXJzdFBhZ2U8VD4ocmVzdWx0OiBULCBtdWx0aXNpdGU/OiBBdXRob3JpemVkTG9jYXRpb25UeXBlW10sIG9wdGlvbnM/OiB7IGhlYWRlcnM/OiBIdHRwSGVhZGVycyB9KTogT2JzZXJ2YWJsZTxUPjtcbiAgICBwdWJsaWMgZmlyc3RQYWdlPFQ+KHJlc3VsdDogVCwgbXVsdGlzaXRlPzogYW55LCBvcHRpb25zPzogeyBoZWFkZXJzPzogSHR0cEhlYWRlcnMgfSk6IE9ic2VydmFibGU8VD4ge1xuICAgICAgICBjb25zdCBsaW5rOiBMaW5rVHlwZSA9IHRoaXMuZmluZExpbmsocmVzdWx0LCAnZmlyc3RQYWdlJywgKHJlc3VsdCBhcyBSZXNvdXJjZVR5cGUpLnR5cGUpO1xuICAgICAgICBpZiAoIWxpbmspIHtcbiAgICAgICAgICAgIHJldHVybiB0aHJvd0Vycm9yKCgpID0+IG5ldyBFcnJvcihgTm8gJ2ZpcnN0UGFnZScgbGluayBmb3Igc3BlY2lmaWVkIHF1ZXJ5LmApKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiB0aGlzLmdldFF1ZXJ5UGFnZShsaW5rLmhyZWYsIG11bHRpc2l0ZSwgb3B0aW9ucyk7XG4gICAgfVxuXG4gICAgcHVibGljIGhhc0ZpcnN0UGFnZTxUPihyZXN1bHQ6IFQpOiBib29sZWFuIHtcbiAgICAgICAgcmV0dXJuICEhdGhpcy5maW5kTGluayhyZXN1bHQsICdmaXJzdFBhZ2UnLCAocmVzdWx0IGFzIFJlc291cmNlVHlwZSkudHlwZSk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUXVlcmllcyB0aGUgVk13YXJlIENsb3VkIERpcmVjdG9yIEFQSSBmb3IgdGhlIHByZXZpb3VzIHBhZ2Ugb2YgdGhlIHByb3ZpZGVkIHJlc3VsdCBzZXQuXG4gICAgICpcbiAgICAgKiBAcGFyYW0gcmVzdWx0IHRoZSByZXN1bHQgc2V0IHRvIHJldHJpZXZlIHRoZSBwcmV2aW91cyBwYWdlIG9mIHJlY29yZHMgZm9yXG4gICAgICogQHBhcmFtIG11bHRpc2l0ZSBhIGZsYWcgaW5kaWNhdGluZyB3aGV0aGVyIG9yIG5vdCB0byBmYW4gdGhlIHF1ZXJ5IG91dCB0byBhbGwgYXZhaWxhYmxlIHNpdGVzXG4gICAgICogQHJldHVybnMgdGhlIHJlY29yZHMgZm9yIHRoZSBwcmV2aW91cyBwYWdlIG9mIHRoZSBxdWVyeVxuICAgICAqL1xuICAgIHB1YmxpYyBwcmV2aW91c1BhZ2U8VD4ocmVzdWx0OiBULCBtdWx0aXNpdGU/OiBib29sZWFuLCBvcHRpb25zPzogeyBoZWFkZXJzPzogSHR0cEhlYWRlcnMgfSk6IE9ic2VydmFibGU8VD47XG4gICAgLyoqXG4gICAgICogUXVlcmllcyB0aGUgVk13YXJlIENsb3VkIERpcmVjdG9yIEFQSSBmb3IgdGhlIHByZXZpb3VzIHBhZ2Ugb2YgdGhlIHByb3ZpZGVkIHJlc3VsdCBzZXQuXG4gICAgICpcbiAgICAgKiBAcGFyYW0gcmVzdWx0IHRoZSByZXN1bHQgc2V0IHRvIHJldHJpZXZlIHRoZSBwcmV2aW91cyBwYWdlIG9mIHJlY29yZHMgZm9yXG4gICAgICogQHBhcmFtIG11bHRpc2l0ZSB0aGUgc2V0IG9mIHNpdGUgbG9jYXRpb25zIHRvIGluY2x1ZGUgaW4gdGhlIHF1ZXJ5IGZhbm91dFxuICAgICAqIEByZXR1cm5zIHRoZSByZWNvcmRzIGZvciB0aGUgcHJldmlvdXMgcGFnZSBvZiB0aGUgcXVlcnlcbiAgICAgKi9cbiAgICAvLyB0c2xpbnQ6ZGlzYWJsZS1uZXh0LWxpbmU6dW5pZmllZC1zaWduYXR1cmVzXG4gICAgcHVibGljIHByZXZpb3VzUGFnZTxUPihyZXN1bHQ6IFQsIG11bHRpc2l0ZT86IEF1dGhvcml6ZWRMb2NhdGlvblR5cGVbXSwgb3B0aW9ucz86IHsgaGVhZGVycz86IEh0dHBIZWFkZXJzIH0pOiBPYnNlcnZhYmxlPFQ+O1xuICAgIHB1YmxpYyBwcmV2aW91c1BhZ2U8VD4ocmVzdWx0OiBULCBtdWx0aXNpdGU/OiBhbnksIG9wdGlvbnM/OiB7IGhlYWRlcnM/OiBIdHRwSGVhZGVycyB9KTogT2JzZXJ2YWJsZTxUPiB7XG4gICAgICAgIGNvbnN0IGxpbms6IExpbmtUeXBlID0gdGhpcy5maW5kTGluayhyZXN1bHQsICdwcmV2aW91c1BhZ2UnLCAocmVzdWx0IGFzIFJlc291cmNlVHlwZSkudHlwZSk7XG4gICAgICAgIGlmICghbGluaykge1xuICAgICAgICAgICAgcmV0dXJuIHRocm93RXJyb3IoKCkgPT4gbmV3IEVycm9yKGBObyAncHJldmlvdXNQYWdlJyBsaW5rIGZvciBzcGVjaWZpZWQgcXVlcnkuYCkpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHRoaXMuZ2V0UXVlcnlQYWdlKGxpbmsuaHJlZiwgbXVsdGlzaXRlLCBvcHRpb25zKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgaGFzUHJldmlvdXNQYWdlPFQ+KHJlc3VsdDogVCk6IGJvb2xlYW4ge1xuICAgICAgICByZXR1cm4gISF0aGlzLmZpbmRMaW5rKHJlc3VsdCwgJ3ByZXZpb3VzUGFnZScsIChyZXN1bHQgYXMgUmVzb3VyY2VUeXBlKS50eXBlKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBRdWVyaWVzIHRoZSBWTXdhcmUgQ2xvdWQgRGlyZWN0b3IgQVBJIGZvciB0aGUgbmV4dCBwYWdlIG9mIHRoZSBwcm92aWRlZCByZXN1bHQgc2V0LlxuICAgICAqXG4gICAgICogQHBhcmFtIHJlc3VsdCB0aGUgcmVzdWx0IHNldCB0byByZXRyaWV2ZSB0aGUgbmV4dCBwYWdlIG9mIHJlY29yZHMgZm9yXG4gICAgICogQHBhcmFtIG11bHRpc2l0ZSBhIGZsYWcgaW5kaWNhdGluZyB3aGV0aGVyIG9yIG5vdCB0byBmYW4gdGhlIHF1ZXJ5IG91dCB0byBhbGwgYXZhaWxhYmxlIHNpdGVzXG4gICAgICogQHJldHVybnMgdGhlIHJlY29yZHMgZm9yIHRoZSBuZXh0IHBhZ2Ugb2YgdGhlIHF1ZXJ5XG4gICAgICovXG4gICAgcHVibGljIG5leHRQYWdlPFQ+KHJlc3VsdDogVCwgbXVsdGlzaXRlPzogYm9vbGVhbiwgb3B0aW9ucz86IHsgaGVhZGVycz86IEh0dHBIZWFkZXJzIH0pOiBPYnNlcnZhYmxlPFQ+O1xuICAgIC8qKlxuICAgICAqIFF1ZXJpZXMgdGhlIFZNd2FyZSBDbG91ZCBEaXJlY3RvciBBUEkgZm9yIHRoZSBuZXh0IHBhZ2Ugb2YgdGhlIHByb3ZpZGVkIHJlc3VsdCBzZXQuXG4gICAgICpcbiAgICAgKiBAcGFyYW0gcmVzdWx0IHRoZSByZXN1bHQgc2V0IHRvIHJldHJpZXZlIHRoZSBuZXh0IHBhZ2Ugb2YgcmVjb3JkcyBmb3JcbiAgICAgKiBAcGFyYW0gbXVsdGlzaXRlIHRoZSBzZXQgb2Ygc2l0ZSBsb2NhdGlvbnMgdG8gaW5jbHVkZSBpbiB0aGUgcXVlcnkgZmFub3V0XG4gICAgICogQHJldHVybnMgdGhlIHJlY29yZHMgZm9yIHRoZSBuZXh0IHBhZ2Ugb2YgdGhlIHF1ZXJ5XG4gICAgICovXG4gICAgLy8gdHNsaW50OmRpc2FibGUtbmV4dC1saW5lOnVuaWZpZWQtc2lnbmF0dXJlc1xuICAgIHB1YmxpYyBuZXh0UGFnZTxUPihyZXN1bHQ6IFQsIG11bHRpc2l0ZT86IEF1dGhvcml6ZWRMb2NhdGlvblR5cGVbXSwgb3B0aW9ucz86IHsgaGVhZGVycz86IEh0dHBIZWFkZXJzIH0pOiBPYnNlcnZhYmxlPFQ+O1xuICAgIHB1YmxpYyBuZXh0UGFnZTxUPihyZXN1bHQ6IFQsIG11bHRpc2l0ZT86IGFueSwgb3B0aW9ucz86IHsgaGVhZGVycz86IEh0dHBIZWFkZXJzIH0pOiBPYnNlcnZhYmxlPFQ+IHtcbiAgICAgICAgY29uc3QgbGluazogTGlua1R5cGUgPSB0aGlzLmZpbmRMaW5rKHJlc3VsdCwgJ25leHRQYWdlJywgKHJlc3VsdCBhcyBSZXNvdXJjZVR5cGUpLnR5cGUpO1xuICAgICAgICBpZiAoIWxpbmspIHtcbiAgICAgICAgICAgIHJldHVybiB0aHJvd0Vycm9yKCgpID0+IG5ldyBFcnJvcihgTm8gJ25leHRQYWdlJyBsaW5rIGZvciBzcGVjaWZpZWQgcXVlcnkuYCkpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHRoaXMuZ2V0UXVlcnlQYWdlPFQ+KGxpbmsuaHJlZiwgbXVsdGlzaXRlLCBvcHRpb25zKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgaGFzTmV4dFBhZ2U8VD4ocmVzdWx0OiBUKTogYm9vbGVhbiB7XG4gICAgICAgIHJldHVybiAhIXRoaXMuZmluZExpbmsocmVzdWx0LCAnbmV4dFBhZ2UnLCAocmVzdWx0IGFzIFJlc291cmNlVHlwZSkudHlwZSk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUXVlcmllcyB0aGUgVk13YXJlIENsb3VkIERpcmVjdG9yIEFQSSBmb3IgdGhlIGxhc3QgcGFnZSBvZiB0aGUgcHJvdmlkZWQgcmVzdWx0IHNldC5cbiAgICAgKlxuICAgICAqIEBwYXJhbSByZXN1bHQgdGhlIHJlc3VsdCBzZXQgdG8gcmV0cmlldmUgdGhlIGxhc3QgcGFnZSBvZiByZWNvcmRzIGZvclxuICAgICAqIEBwYXJhbSBtdWx0aXNpdGUgYSBmbGFnIGluZGljYXRpbmcgd2hldGhlciBvciBub3QgdG8gZmFuIHRoZSBxdWVyeSBvdXQgdG8gYWxsIGF2YWlsYWJsZSBzaXRlc1xuICAgICAqIEByZXR1cm5zIHRoZSByZWNvcmRzIGZvciB0aGUgbGFzdCBwYWdlIG9mIHRoZSBxdWVyeVxuICAgICAqL1xuICAgIHB1YmxpYyBsYXN0UGFnZTxUPihyZXN1bHQ6IFQsIG11bHRpc2l0ZT86IGJvb2xlYW4sIG9wdGlvbnM/OiB7IGhlYWRlcnM/OiBIdHRwSGVhZGVycyB9KTogT2JzZXJ2YWJsZTxUPjtcbiAgICAvKipcbiAgICAgKiBRdWVyaWVzIHRoZSBWTXdhcmUgQ2xvdWQgRGlyZWN0b3IgQVBJIGZvciB0aGUgbGFzdCBwYWdlIG9mIHRoZSBwcm92aWRlZCByZXN1bHQgc2V0LlxuICAgICAqXG4gICAgICogQHBhcmFtIHJlc3VsdCB0aGUgcmVzdWx0IHNldCB0byByZXRyaWV2ZSB0aGUgbGFzdCBwYWdlIG9mIHJlY29yZHMgZm9yXG4gICAgICogQHBhcmFtIG11bHRpc2l0ZSB0aGUgc2V0IG9mIHNpdGUgbG9jYXRpb25zIHRvIGluY2x1ZGUgaW4gdGhlIHF1ZXJ5IGZhbm91dFxuICAgICAqIEByZXR1cm5zIHRoZSByZWNvcmRzIGZvciB0aGUgbGFzdCBwYWdlIG9mIHRoZSBxdWVyeVxuICAgICAqL1xuICAgIC8vIHRzbGludDpkaXNhYmxlLW5leHQtbGluZTp1bmlmaWVkLXNpZ25hdHVyZXNcbiAgICBwdWJsaWMgbGFzdFBhZ2U8VD4ocmVzdWx0OiBULCBtdWx0aXNpdGU/OiBBdXRob3JpemVkTG9jYXRpb25UeXBlW10sIG9wdGlvbnM/OiB7IGhlYWRlcnM/OiBIdHRwSGVhZGVycyB9KTogT2JzZXJ2YWJsZTxUPjtcbiAgICBwdWJsaWMgbGFzdFBhZ2U8VD4ocmVzdWx0OiBULCBtdWx0aXNpdGU/OiBhbnksIG9wdGlvbnM/OiB7IGhlYWRlcnM/OiBIdHRwSGVhZGVycyB9KTogT2JzZXJ2YWJsZTxUPiB7XG4gICAgICAgIGNvbnN0IGxpbms6IExpbmtUeXBlID0gdGhpcy5maW5kTGluayhyZXN1bHQsICdsYXN0UGFnZScsIChyZXN1bHQgYXMgUmVzb3VyY2VUeXBlKS50eXBlKTtcbiAgICAgICAgaWYgKCFsaW5rKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhyb3dFcnJvcigoKSA9PiBuZXcgRXJyb3IoYE5vICdsYXN0UGFnZScgbGluayBmb3Igc3BlY2lmaWVkIHF1ZXJ5LmApKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiB0aGlzLmdldFF1ZXJ5UGFnZShsaW5rLmhyZWYsIG11bHRpc2l0ZSwgb3B0aW9ucyk7XG4gICAgfVxuXG4gICAgcHVibGljIGhhc0xhc3RQYWdlPFQ+KHJlc3VsdDogVCk6IGJvb2xlYW4ge1xuICAgICAgICByZXR1cm4gISF0aGlzLmZpbmRMaW5rKHJlc3VsdCwgJ2xhc3RQYWdlJywgKHJlc3VsdCBhcyBSZXNvdXJjZVR5cGUpLnR5cGUpO1xuICAgIH1cblxuICAgIHByaXZhdGUgZ2V0UXVlcnlQYWdlPFQ+KGhyZWY6IHN0cmluZywgbXVsdGlzaXRlPzogYW55LCBvcHRpb25zPzogeyBoZWFkZXJzPzogSHR0cEhlYWRlcnMgfSk6IE9ic2VydmFibGU8VD4ge1xuICAgICAgICBpZiAobXVsdGlzaXRlKSB7XG4gICAgICAgICAgICBpZiAoIW9wdGlvbnMpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5odHRwLmdldDxUPihocmVmLCB7IGhlYWRlcnM6IG5ldyBIdHRwSGVhZGVycyh7IF9tdWx0aXNpdGU6IHRoaXMucGFyc2VNdWx0aXNpdGVWYWx1ZShtdWx0aXNpdGUpIH0pIH0pXG4gICAgICAgICAgICB9IGVsc2UgaWYgKG9wdGlvbnM/LmhlYWRlcnMpIHtcbiAgICAgICAgICAgICAgICBvcHRpb25zLmhlYWRlcnMuYXBwZW5kKFwiX211bHRpc2l0ZVwiLCB0aGlzLnBhcnNlTXVsdGlzaXRlVmFsdWUobXVsdGlzaXRlKSk7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMuaHR0cC5nZXQ8VD4oaHJlZiwgeyAuLi5vcHRpb25zIH0pXG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gdGhpcy52YWxpZGF0ZVJlcXVlc3RDb250ZXh0KCkucGlwZShcbiAgICAgICAgICAgIGNvbmNhdE1hcCgoKSA9PiB0aGlzLmh0dHAuZ2V0PFQ+KGhyZWYsIHsgLi4ub3B0aW9ucyB9KSlcbiAgICAgICAgKTtcbiAgICB9XG5cbiAgLyoqXG4gICAqIFVzZSB0byBwZXJmb3JtIGFjdGlvbiBhdmFpbGFiaWxpdHkgY2hlY2sgYmVmb3JlIGNhbGxpbmcgdGhlIEFQSVxuICAgKiBAcGFyYW0gaXRlbSAtIHRoZSBuYXZpZ2FibGUgaXRlbSAoY29udGFpbmluZyBsaW5rIGNvbGxlY3Rpb24pXG4gICAqIEBwYXJhbSBsaW5rUmVsVHlwZSAtIHRoZSBsaW5rIHJlbCB0eXBlLCBwYXNzIGVpdGhlciBMaW5rUmVsVHlwZSBvciBzdHJpbmdcbiAgICogQHBhcmFtIGVudGl0eVJlZlR5cGUgLSB0aGUgZW50aXR5IHJlZmVyZW5jZSB0eXBlXG4gICAqL1xuICAgIHB1YmxpYyBjYW5QZXJmb3JtQWN0aW9uKGl0ZW06IE5hdmlnYWJsZSwgbGlua1JlbFR5cGU6IExpbmtSZWxUeXBlIHwgc3RyaW5nLCBlbnRpdHlSZWZUeXBlPzogc3RyaW5nKTogYm9vbGVhbiB7XG4gICAgICAgIHJldHVybiAhIXRoaXMuZmluZExpbmsoaXRlbSwgbGlua1JlbFR5cGUsIGVudGl0eVJlZlR5cGUpO1xuICAgIH1cblxuICAgIHByaXZhdGUgZmluZExpbmsoaXRlbTogTmF2aWdhYmxlLCByZWw6IHN0cmluZywgdHlwZTogc3RyaW5nKTogTGlua1R5cGUge1xuICAgICAgICBpZiAoIWl0ZW0gfHwgIWl0ZW0ubGluaykge1xuICAgICAgICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBpdGVtLmxpbmsuZmluZCgobGluaykgPT4ge1xuICAgICAgICAgICAgaWYgKHR5cGUpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gbGluay5yZWwuaW5jbHVkZXMocmVsKSAmJiBsaW5rLnR5cGUgPT09IHR5cGU7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHJldHVybiBsaW5rLnJlbC5pbmNsdWRlcyhyZWwpO1xuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICBwcml2YXRlIHBhcnNlTXVsdGlzaXRlVmFsdWUobXVsdGlzaXRlOiBib29sZWFuIHwgQXV0aG9yaXplZExvY2F0aW9uVHlwZVtdKTogc3RyaW5nIHtcbiAgICAgICAgcmV0dXJuIHR5cGVvZiBtdWx0aXNpdGUgPT09ICdib29sZWFuJyA/IChtdWx0aXNpdGUgPyAnZ2xvYmFsJyA6ICdsb2NhbCcpIDogbXVsdGlzaXRlLm1hcChzaXRlID0+IHNpdGUubG9jYXRpb25JZCkuam9pbignLCcpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEBkZXByZWNhdGVkIFVzZSBjbG91ZEFwaVNlc3Npb25cbiAgICAgKi9cbiAgICBwdWJsaWMgZ2V0IHNlc3Npb24oKTogT2JzZXJ2YWJsZTxTZXNzaW9uVHlwZT4ge1xuICAgICAgICByZXR1cm4gdGhpcy52YWxpZGF0ZVJlcXVlc3RDb250ZXh0KCkucGlwZShcbiAgICAgICAgICAgIGNvbmNhdE1hcCgoKSA9PiB0aGlzLl9zZXNzaW9uT2JzZXJ2YWJsZSlcbiAgICAgICAgKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBHZXQgU2Vzc2lvbiBvYnNlcnZhYmxlXG4gICAgICovXG4gICAgcHVibGljIGdldCBjbG91ZEFwaVNlc3Npb24oKTogT2JzZXJ2YWJsZTxTZXNzaW9uPiB7XG4gICAgICAgIHJldHVybiB0aGlzLnZhbGlkYXRlUmVxdWVzdENvbnRleHRDbG91ZEFwaU9ubHkoKS5waXBlKFxuICAgICAgICAgICAgY29uY2F0TWFwKCgpID0+IHRoaXMuX2Nsb3VkQXBpU2Vzc2lvbk9ic2VydmFibGUpXG4gICAgICAgICk7XG4gICAgfVxuXG4gICAgcHVibGljIGdldCB1c2VybmFtZSgpOiBPYnNlcnZhYmxlPHN0cmluZz4ge1xuICAgICAgICByZXR1cm4gbWVyZ2UoXG4gICAgICAgICAgICAgICAgdGhpcy5jbG91ZEFwaVNlc3Npb24ucGlwZShcbiAgICAgICAgICAgICAgICAgICAgZmlsdGVyKCgpID0+IHRoaXMuX2lzQ2xvdWRBcGlMb2dpbiksXG4gICAgICAgICAgICAgICAgICAgIG1hcChzZXNzaW9uID0+IHNlc3Npb24gJiYgc2Vzc2lvbi51c2VyICYmIHNlc3Npb24udXNlci5uYW1lKVxuICAgICAgICAgICAgICAgICksXG4gICAgICAgICAgICAgICAgdGhpcy5zZXNzaW9uLnBpcGUoXG4gICAgICAgICAgICAgICAgICAgIGZpbHRlcigoKSA9PiAhdGhpcy5faXNDbG91ZEFwaUxvZ2luKSxcbiAgICAgICAgICAgICAgICAgICAgbWFwKHNlc3Npb24gPT4gc2Vzc2lvbiAmJiBzZXNzaW9uLnVzZXIpXG4gICAgICAgICAgICAgICAgKVxuICAgICAgICAgICAgKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgZ2V0IG9yZ2FuaXphdGlvbigpOiBPYnNlcnZhYmxlPHN0cmluZz4ge1xuICAgICAgICByZXR1cm4gbWVyZ2UoXG4gICAgICAgICAgICB0aGlzLmNsb3VkQXBpU2Vzc2lvbi5waXBlKFxuICAgICAgICAgICAgICAgIGZpbHRlcigoKSA9PiB0aGlzLl9pc0Nsb3VkQXBpTG9naW4pLFxuICAgICAgICAgICAgICAgIG1hcChzZXNzaW9uID0+IHNlc3Npb24gJiYgc2Vzc2lvbi5vcmcgJiYgc2Vzc2lvbi5vcmcubmFtZSlcbiAgICAgICAgICAgICksXG4gICAgICAgICAgICB0aGlzLnNlc3Npb24ucGlwZShcbiAgICAgICAgICAgICAgICBmaWx0ZXIoKCkgPT4gIXRoaXMuX2lzQ2xvdWRBcGlMb2dpbiksXG4gICAgICAgICAgICAgICAgbWFwKHNlc3Npb24gPT4gc2Vzc2lvbiAmJiBzZXNzaW9uLm9yZylcbiAgICAgICAgICAgIClcbiAgICAgICAgKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBAZGVwcmVjYXRlZCBVc2UgY2xvdWRBcGlMb2NhdGlvblxuICAgICAqL1xuICAgIHB1YmxpYyBnZXQgbG9jYXRpb24oKTogT2JzZXJ2YWJsZTxBdXRob3JpemVkTG9jYXRpb25UeXBlPiB7XG4gICAgICAgIHJldHVybiB0aGlzLnNlc3Npb24ucGlwZShcbiAgICAgICAgICAgIG1hcChzZXNzaW9uID0+IHNlc3Npb24uYXV0aG9yaXplZExvY2F0aW9ucy5sb2NhdGlvbi5maW5kKGxvY2F0aW9uID0+IGxvY2F0aW9uLmxvY2F0aW9uSWQgPT09IHNlc3Npb24ubG9jYXRpb25JZCkpXG4gICAgICAgICk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogR2V0cyB0aGUgbG9jYXRpb24gY29ycmVzcG9uZGluZyB0byB0aGUgY3VycmVudCBzZXNzaW9uXG4gICAgICovXG4gICAgcHVibGljIGdldCBjbG91ZEFwaUxvY2F0aW9uKCk6IE9ic2VydmFibGU8QWNjZXNzaWJsZUxvY2F0aW9uPiB7XG4gICAgICAgIHJldHVybiB0aGlzLmNsb3VkQXBpU2Vzc2lvbi5waXBlKFxuICAgICAgICAgICAgc3dpdGNoTWFwKCgpID0+IHtcbiAgICAgICAgICAgICAgICBpZiAoIXRoaXMuX2Nsb3VkQXBpQWNjZXNzaWJsZUxvY2F0aW9ucykge1xuICAgICAgICAgICAgICAgICAgICAvLyBFbnN1cmUgY2FjaGluZyBmb3IgZ2V0dGluZyBBY2Nlc3NpYmxlTG9jYXRpb25zXG4gICAgICAgICAgICAgICAgICAgIHRoaXMuX2Nsb3VkQXBpQWNjZXNzaWJsZUxvY2F0aW9ucyA9IHRoaXMuX2Nsb3VkQXBpU2Vzc2lvbkxpbmtzXG4gICAgICAgICAgICAgICAgICAgICAgICAucGlwZShcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBHZXQgdGhlIEFjY2Vzc2libGVMb2NhdGlvbnMgbGlua1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcCgobGlua3MpID0+IHRoaXMuZmluZExpbmsoeyBsaW5rOiBsaW5rcyB9LCAnZG93bicsICdBY2Nlc3NpYmxlTG9jYXRpb25zJykpLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIEZldGNoIEFjY2Vzc2libGVMb2NhdGlvbnMgZnJvbSB0aGUgYmFja2VuZFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN3aXRjaE1hcCgobGluazogTGlua1R5cGUpID0+IGxpbmsgPyB0aGlzLmh0dHAuZ2V0PEFjY2Vzc2libGVMb2NhdGlvbnM+KGxpbmsuaHJlZikgOiBvZihudWxsKSksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gR2V0IHRoZSBhcnJheSB3aXRoIGFsbCBsb2NhdGlvbnMgKHdoYXQgaWYgdGhlcmUgYXJlIG1hbnkgcGFnZXMpXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFwKChhY2Nlc3NpYmxlTG9jYXRpb25zOiBBY2Nlc3NpYmxlTG9jYXRpb25zKSA9PiBhY2Nlc3NpYmxlTG9jYXRpb25zICYmIGFjY2Vzc2libGVMb2NhdGlvbnMudmFsdWVzKVxuICAgICAgICAgICAgICAgICAgICAgICAgKVxuICAgICAgICAgICAgICAgICAgICAgICAgLnBpcGUoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgc2hhcmUoeyBjb25uZWN0b3I6ICgpID0+IG5ldyBSZXBsYXlTdWJqZWN0KDEpIH0pXG4gICAgICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5fY2xvdWRBcGlBY2Nlc3NpYmxlTG9jYXRpb25zO1xuICAgICAgICAgICAgfSksXG5cbiAgICAgICAgICAgIC8vIE5lZWQgdG8gaGF2ZSB0aGUgc2Vzc2lvbiBpbiBvcmRlciB0byBnZXQgaXRzIGxvY2F0aW9uXG4gICAgICAgICAgICB3aXRoTGF0ZXN0RnJvbSh0aGlzLmNsb3VkQXBpU2Vzc2lvbiksXG4gICAgICAgICAgICAvLyBGaW5kIHRoZSBsb2NhdGlvbiB0aGF0IGNvcnJlc3BvbmRzIHRvIHRoaXMgc2Vzc2lvblxuICAgICAgICAgICAgbWFwKChbYWNjZXNzaWJsZUxvY2F0aW9ucywgc2Vzc2lvbl0pID0+IHtcbiAgICAgICAgICAgICAgICBpZiAoIWFjY2Vzc2libGVMb2NhdGlvbnMgfHwgIXNlc3Npb24pIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGNvbnN0IHNlc3Npb25Mb2NhdGlvbiA9IHNlc3Npb24ubG9jYXRpb247XG4gICAgICAgICAgICAgICAgaWYgKCFzZXNzaW9uTG9jYXRpb24pIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHJldHVybiBhY2Nlc3NpYmxlTG9jYXRpb25zLmZpbmQobG9jYXRpb24gPT4gbG9jYXRpb24ubG9jYXRpb25JZCA9PT0gc2Vzc2lvbkxvY2F0aW9uKTtcbiAgICAgICAgICAgIH0pLFxuICAgICAgICApO1xuICAgIH1cblxuICAgIHB1YmxpYyBnZXRMb2NhdGlvbihzZXNzaW9uOiBTZXNzaW9uVHlwZSk6IEF1dGhvcml6ZWRMb2NhdGlvblR5cGUge1xuICAgICAgICByZXR1cm4gc2Vzc2lvbi5hdXRob3JpemVkTG9jYXRpb25zLmxvY2F0aW9uLmZpbmQobG9jYXRpb24gPT4gbG9jYXRpb24ubG9jYXRpb25JZCA9PT0gc2Vzc2lvbi5sb2NhdGlvbklkKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBCdWlsZCB0aGUgZW5kcG9pbnQgdXJsLiBJZiB0aGUgcHJvdmlkZWQgZW5kcG9pbnQgaXMgYWxyZWFkeSBhbiBhYnNvbHV0ZSBVUkwsIHRoZW4gcmV0dXJuIGl0IGFzIGl0IGlzIHdpdGhvdXRcbiAgICAgKiBhbnkgbW9kaWZpY2F0aW9ucywgb3RoZXJ3aXNlIGNvbnNpZGVyIGl0IGFzIGEgcmVsYXRpdmUgb25lIGFuZCBwcmVwZW5kIHRoZSBiYXNlVXJsIGFzIGRlZmluZWQgYnkgdGhlIGhvc3QgYXBwbGljYXRpb24uXG4gICAgICovXG4gICAgcHJpdmF0ZSBidWlsZEVuZHBvaW50VXJsKGVuZHBvaW50OiBzdHJpbmcpOiBzdHJpbmcge1xuICAgICAgICByZXR1cm4gZW5kcG9pbnQuaW5kZXhPZignOi8vJykgPiAtMSA/IGVuZHBvaW50IDogYCR7dGhpcy5fYmFzZVVybH0vJHtlbmRwb2ludH1gO1xuICAgIH1cblxufVxuIl19
|