@gnwebsoft/ui 4.0.8 → 4.0.10
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/dist/{chunk-4YBENPMZ.cjs → chunk-7ZWRNOYQ.cjs} +3 -2
- package/dist/chunk-GH57WZ2A.js +2527 -0
- package/dist/core/api/ApiClient.d.ts +2 -2
- package/dist/core/api/ApiClient.d.ts.map +1 -1
- package/dist/core/api/Models/FilterModel.d.ts +1 -1
- package/dist/core/api/Models/FilterModel.d.ts.map +1 -1
- package/dist/core/api/Models/index.d.ts +1 -1
- package/dist/core/api/Models/index.d.ts.map +1 -1
- package/dist/core/api/Utils/UrlBuilder.d.ts.map +1 -1
- package/dist/core/index.cjs +2 -2
- package/dist/core/index.js +1 -1
- package/dist/index.cjs +2 -2
- package/dist/index.js +1 -1
- package/dist/types/index.d.ts +0 -4
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-GFUVJS5G.js +0 -2526
|
@@ -0,0 +1,2527 @@
|
|
|
1
|
+
// src/core/api/CorrelationIdGenerator.ts
|
|
2
|
+
function generateUUID() {
|
|
3
|
+
if (typeof crypto !== "undefined" && crypto.randomUUID) {
|
|
4
|
+
return crypto.randomUUID();
|
|
5
|
+
}
|
|
6
|
+
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
|
|
7
|
+
const r = Math.random() * 16 | 0;
|
|
8
|
+
const v = c === "x" ? r : r & 3 | 8;
|
|
9
|
+
return v.toString(16);
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
function generateCorrelationId(prefix) {
|
|
13
|
+
const uuid = generateUUID();
|
|
14
|
+
return prefix ? `${prefix}-${uuid}` : uuid;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// src/core/api/Errors/ErrorNormalizer.ts
|
|
18
|
+
var ErrorNormalizer = class {
|
|
19
|
+
/**
|
|
20
|
+
* Maps an HTTP status code to a standardized error type category.
|
|
21
|
+
*
|
|
22
|
+
* This categorization helps consumers handle different error classes appropriately:
|
|
23
|
+
* - `validation_error` (400): Client sent invalid data
|
|
24
|
+
* - `client_error` (401-499): Client-side issues (auth, permissions, not found, etc.)
|
|
25
|
+
* - `server_error` (500-599): Server-side failures
|
|
26
|
+
* - `unknown_error`: Unrecognized status codes
|
|
27
|
+
*
|
|
28
|
+
* @param status - HTTP status code from the response
|
|
29
|
+
* @returns The error type category as a string
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```typescript
|
|
33
|
+
* normalizer.getErrorType(400); // => 'validation_error'
|
|
34
|
+
* normalizer.getErrorType(404); // => 'client_error'
|
|
35
|
+
* normalizer.getErrorType(500); // => 'server_error'
|
|
36
|
+
* normalizer.getErrorType(0); // => 'unknown_error'
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
getErrorType(status) {
|
|
40
|
+
if (status >= 400 && status < 500) {
|
|
41
|
+
return status === 400 ? "validation_error" : "client_error";
|
|
42
|
+
} else if (status >= 500) {
|
|
43
|
+
return "server_error";
|
|
44
|
+
}
|
|
45
|
+
return "unknown_error";
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Maps an HTTP status code to a human-readable error title.
|
|
49
|
+
*
|
|
50
|
+
* Provides user-friendly error messages for common HTTP status codes.
|
|
51
|
+
* Falls back to a generic "HTTP Error {status}" format for unmapped codes.
|
|
52
|
+
*
|
|
53
|
+
* @param status - HTTP status code from the response
|
|
54
|
+
* @returns A human-readable error title
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* ```typescript
|
|
58
|
+
* normalizer.getErrorTitle(404); // => 'Not Found'
|
|
59
|
+
* normalizer.getErrorTitle(500); // => 'Internal Server Error'
|
|
60
|
+
* normalizer.getErrorTitle(999); // => 'HTTP Error 999'
|
|
61
|
+
* ```
|
|
62
|
+
*/
|
|
63
|
+
getErrorTitle(status) {
|
|
64
|
+
const titles = {
|
|
65
|
+
400: "Bad Request",
|
|
66
|
+
401: "Unauthorized",
|
|
67
|
+
403: "Forbidden",
|
|
68
|
+
404: "Not Found",
|
|
69
|
+
405: "Method Not Allowed",
|
|
70
|
+
408: "Request Timeout",
|
|
71
|
+
409: "Conflict",
|
|
72
|
+
422: "Unprocessable Entity",
|
|
73
|
+
429: "Too Many Requests",
|
|
74
|
+
500: "Internal Server Error",
|
|
75
|
+
502: "Bad Gateway",
|
|
76
|
+
503: "Service Unavailable",
|
|
77
|
+
504: "Gateway Timeout"
|
|
78
|
+
};
|
|
79
|
+
return titles[status] || `HTTP Error ${status}`;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Normalizes any error into a consistent, structured ApiError format.
|
|
83
|
+
*
|
|
84
|
+
* This method handles various error scenarios and ensures they all conform to
|
|
85
|
+
* the {@link ApiError} interface with appropriate categorization and metadata:
|
|
86
|
+
*
|
|
87
|
+
* - **Existing ApiErrors**: Enhances with missing fields (traceId, config)
|
|
88
|
+
* - **AbortErrors**: Marks as `request_cancelled` with isAborted flag
|
|
89
|
+
* - **Timeout Errors**: Categorizes as `timeout_error` with 408 status
|
|
90
|
+
* - **Network Errors**: Categorizes as `network_error` with 0 status
|
|
91
|
+
* - **Unknown Errors**: Fallback category for unexpected error types
|
|
92
|
+
*
|
|
93
|
+
* All normalized errors include:
|
|
94
|
+
* - `type`: Error category for programmatic handling
|
|
95
|
+
* - `title`: Human-readable error title
|
|
96
|
+
* - `status`: HTTP status code (or 0 for non-HTTP errors)
|
|
97
|
+
* - `traceId`: Correlation ID for distributed tracing
|
|
98
|
+
* - `isAborted`: Boolean flag indicating if request was cancelled
|
|
99
|
+
* - `config`: Original request configuration for debugging
|
|
100
|
+
*
|
|
101
|
+
* @param error - The error to normalize (can be any type)
|
|
102
|
+
* @param config - The request configuration that led to this error
|
|
103
|
+
* @param correlationId - Optional correlation ID for tracing
|
|
104
|
+
* @returns A fully structured ApiError instance
|
|
105
|
+
*
|
|
106
|
+
* @example
|
|
107
|
+
* Normalizing a fetch AbortError:
|
|
108
|
+
* ```typescript
|
|
109
|
+
* try {
|
|
110
|
+
* await fetch(url, { signal });
|
|
111
|
+
* } catch (error) {
|
|
112
|
+
* const apiError = normalizer.normalizeError(error, config, 'req-123');
|
|
113
|
+
* // apiError.type === 'request_cancelled'
|
|
114
|
+
* // apiError.isAborted === true
|
|
115
|
+
* }
|
|
116
|
+
* ```
|
|
117
|
+
*
|
|
118
|
+
* @example
|
|
119
|
+
* Normalizing a timeout:
|
|
120
|
+
* ```typescript
|
|
121
|
+
* const timeoutError = new Error('Request timeout after 30000ms');
|
|
122
|
+
* const apiError = normalizer.normalizeError(timeoutError, config);
|
|
123
|
+
* // apiError.type === 'timeout_error'
|
|
124
|
+
* // apiError.status === 408
|
|
125
|
+
* ```
|
|
126
|
+
*/
|
|
127
|
+
normalizeError(error, config, correlationId) {
|
|
128
|
+
if (error === null || error === void 0) {
|
|
129
|
+
return Object.assign(new Error("An unknown error occurred"), {
|
|
130
|
+
type: "unknown_error",
|
|
131
|
+
title: "Unknown Error",
|
|
132
|
+
status: 0,
|
|
133
|
+
traceId: correlationId,
|
|
134
|
+
isAborted: false,
|
|
135
|
+
config
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
if (typeof error === "string") {
|
|
139
|
+
return Object.assign(new Error(error), {
|
|
140
|
+
type: "unknown_error",
|
|
141
|
+
title: "Unknown Error",
|
|
142
|
+
status: 0,
|
|
143
|
+
traceId: correlationId,
|
|
144
|
+
isAborted: false,
|
|
145
|
+
config
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
const err = error;
|
|
149
|
+
if (err.type || err.title || err.errors) {
|
|
150
|
+
return Object.assign(
|
|
151
|
+
error instanceof Error ? error : new Error(err.message ?? "Unknown error"),
|
|
152
|
+
{
|
|
153
|
+
type: err.type,
|
|
154
|
+
title: err.title,
|
|
155
|
+
status: err.status,
|
|
156
|
+
traceId: err.traceId || correlationId,
|
|
157
|
+
errors: err.errors,
|
|
158
|
+
isAborted: err.isAborted || false,
|
|
159
|
+
config
|
|
160
|
+
}
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
if (err.name === "AbortError" || err.isAborted) {
|
|
164
|
+
return Object.assign(new Error(err.message ?? "Request was aborted"), {
|
|
165
|
+
type: "request_cancelled",
|
|
166
|
+
title: "Request was cancelled",
|
|
167
|
+
status: 0,
|
|
168
|
+
traceId: correlationId,
|
|
169
|
+
isAborted: true,
|
|
170
|
+
config
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
if (err.message?.includes("timeout")) {
|
|
174
|
+
return Object.assign(new Error(err.message), {
|
|
175
|
+
type: "timeout_error",
|
|
176
|
+
title: "Request Timeout",
|
|
177
|
+
status: 408,
|
|
178
|
+
traceId: correlationId,
|
|
179
|
+
isAborted: true,
|
|
180
|
+
config
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
if (err.message?.includes("network")) {
|
|
184
|
+
return Object.assign(new Error(err.message ?? "Network request failed"), {
|
|
185
|
+
type: "network_error",
|
|
186
|
+
title: "Network Error",
|
|
187
|
+
status: 0,
|
|
188
|
+
traceId: correlationId,
|
|
189
|
+
isAborted: false,
|
|
190
|
+
config
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
return Object.assign(
|
|
194
|
+
new Error(err.message ?? "An unknown error occurred"),
|
|
195
|
+
{
|
|
196
|
+
type: "unknown_error",
|
|
197
|
+
title: "Unknown Error",
|
|
198
|
+
status: 0,
|
|
199
|
+
traceId: correlationId,
|
|
200
|
+
isAborted: false,
|
|
201
|
+
config
|
|
202
|
+
}
|
|
203
|
+
);
|
|
204
|
+
}
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
// src/core/api/Interceptors/InterceptorManager.ts
|
|
208
|
+
var InterceptorManager = class {
|
|
209
|
+
/**
|
|
210
|
+
* Array of registered request interceptors
|
|
211
|
+
* @private
|
|
212
|
+
*/
|
|
213
|
+
requestInterceptors = [];
|
|
214
|
+
/**
|
|
215
|
+
* Array of registered response interceptors
|
|
216
|
+
* @private
|
|
217
|
+
*/
|
|
218
|
+
responseInterceptors = [];
|
|
219
|
+
/**
|
|
220
|
+
* Array of registered error interceptors
|
|
221
|
+
* @private
|
|
222
|
+
*/
|
|
223
|
+
errorInterceptors = [];
|
|
224
|
+
/**
|
|
225
|
+
* Registers a request interceptor to modify requests before they are sent.
|
|
226
|
+
*
|
|
227
|
+
* Request interceptors can:
|
|
228
|
+
* - Add or modify headers
|
|
229
|
+
* - Transform request bodies
|
|
230
|
+
* - Add query parameters
|
|
231
|
+
* - Implement request signing
|
|
232
|
+
* - Log outgoing requests
|
|
233
|
+
*
|
|
234
|
+
* @param interceptor - Async function that receives and returns RequestConfig
|
|
235
|
+
* @returns Cleanup function to unregister this interceptor
|
|
236
|
+
*
|
|
237
|
+
* @example
|
|
238
|
+
* ```typescript
|
|
239
|
+
* // Add authentication header
|
|
240
|
+
* const unregister = manager.addRequestInterceptor(async (config) => {
|
|
241
|
+
* const token = await getAuthToken();
|
|
242
|
+
* config.headers = config.headers || new Headers();
|
|
243
|
+
* config.headers.set('Authorization', `Bearer ${token}`);
|
|
244
|
+
* return config;
|
|
245
|
+
* });
|
|
246
|
+
*
|
|
247
|
+
* // Later, remove the interceptor
|
|
248
|
+
* unregister();
|
|
249
|
+
* ```
|
|
250
|
+
*/
|
|
251
|
+
addRequestInterceptor(interceptor) {
|
|
252
|
+
this.requestInterceptors.push(interceptor);
|
|
253
|
+
return () => {
|
|
254
|
+
const index = this.requestInterceptors.indexOf(interceptor);
|
|
255
|
+
if (index > -1) this.requestInterceptors.splice(index, 1);
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* Registers a response interceptor to transform responses before they are returned.
|
|
260
|
+
*
|
|
261
|
+
* Response interceptors can:
|
|
262
|
+
* - Transform response data format
|
|
263
|
+
* - Extract nested data structures
|
|
264
|
+
* - Add computed properties
|
|
265
|
+
* - Cache responses
|
|
266
|
+
* - Log successful responses
|
|
267
|
+
*
|
|
268
|
+
* @param interceptor - Async function that receives and returns ApiResponse
|
|
269
|
+
* @returns Cleanup function to unregister this interceptor
|
|
270
|
+
*
|
|
271
|
+
* @example
|
|
272
|
+
* ```typescript
|
|
273
|
+
* // Extract data from envelope
|
|
274
|
+
* manager.addResponseInterceptor(async (response) => {
|
|
275
|
+
* if (response.apiData?.result) {
|
|
276
|
+
* response.apiData = response.apiData.result;
|
|
277
|
+
* }
|
|
278
|
+
* return response;
|
|
279
|
+
* });
|
|
280
|
+
*
|
|
281
|
+
* // Add timestamps
|
|
282
|
+
* manager.addResponseInterceptor(async (response) => {
|
|
283
|
+
* return {
|
|
284
|
+
* ...response,
|
|
285
|
+
* receivedAt: new Date().toISOString()
|
|
286
|
+
* };
|
|
287
|
+
* });
|
|
288
|
+
* ```
|
|
289
|
+
*/
|
|
290
|
+
addResponseInterceptor(interceptor) {
|
|
291
|
+
this.responseInterceptors.push(interceptor);
|
|
292
|
+
return () => {
|
|
293
|
+
const index = this.responseInterceptors.indexOf(interceptor);
|
|
294
|
+
if (index > -1) this.responseInterceptors.splice(index, 1);
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
/**
|
|
298
|
+
* Registers an error interceptor to handle or transform errors before they are thrown.
|
|
299
|
+
*
|
|
300
|
+
* Error interceptors can:
|
|
301
|
+
* - Log errors to monitoring services
|
|
302
|
+
* - Transform error formats
|
|
303
|
+
* - Implement retry logic
|
|
304
|
+
* - Show user notifications
|
|
305
|
+
* - Extract validation errors
|
|
306
|
+
*
|
|
307
|
+
* **Note:** Error interceptors should re-throw the error (or a transformed version)
|
|
308
|
+
* to maintain the error flow. The final error is always thrown.
|
|
309
|
+
*
|
|
310
|
+
* @param interceptor - Async function that receives and returns (or throws) ApiError
|
|
311
|
+
* @returns Cleanup function to unregister this interceptor
|
|
312
|
+
*
|
|
313
|
+
* @example
|
|
314
|
+
* ```typescript
|
|
315
|
+
* // Log to monitoring service
|
|
316
|
+
* manager.addErrorInterceptor(async (error) => {
|
|
317
|
+
* if (error.status >= 500) {
|
|
318
|
+
* await Sentry.captureException(error, {
|
|
319
|
+
* extra: { traceId: error.traceId }
|
|
320
|
+
* });
|
|
321
|
+
* }
|
|
322
|
+
* throw error; // Re-throw to continue error flow
|
|
323
|
+
* });
|
|
324
|
+
*
|
|
325
|
+
* // Transform error messages
|
|
326
|
+
* manager.addErrorInterceptor(async (error) => {
|
|
327
|
+
* if (error.status === 404) {
|
|
328
|
+
* error.title = 'Resource not found';
|
|
329
|
+
* }
|
|
330
|
+
* throw error;
|
|
331
|
+
* });
|
|
332
|
+
* ```
|
|
333
|
+
*/
|
|
334
|
+
addErrorInterceptor(interceptor) {
|
|
335
|
+
this.errorInterceptors.push(interceptor);
|
|
336
|
+
return () => {
|
|
337
|
+
const index = this.errorInterceptors.indexOf(interceptor);
|
|
338
|
+
if (index > -1) this.errorInterceptors.splice(index, 1);
|
|
339
|
+
};
|
|
340
|
+
}
|
|
341
|
+
/**
|
|
342
|
+
* Applies all registered request interceptors in sequential order.
|
|
343
|
+
*
|
|
344
|
+
* Each interceptor receives the config modified by the previous interceptor,
|
|
345
|
+
* forming a processing pipeline. If any interceptor throws an error,
|
|
346
|
+
* the pipeline stops and the error propagates.
|
|
347
|
+
*
|
|
348
|
+
* @param config - The initial request configuration
|
|
349
|
+
* @returns The modified request configuration after all interceptors
|
|
350
|
+
*
|
|
351
|
+
* @example
|
|
352
|
+
* ```typescript
|
|
353
|
+
* const config = { method: 'GET', url: '/users' };
|
|
354
|
+
* const finalConfig = await manager.applyRequestInterceptors(config);
|
|
355
|
+
* // finalConfig has been processed by all registered interceptors
|
|
356
|
+
* ```
|
|
357
|
+
*/
|
|
358
|
+
async applyRequestInterceptors(config) {
|
|
359
|
+
let modifiedConfig = { ...config };
|
|
360
|
+
for (const interceptor of this.requestInterceptors) {
|
|
361
|
+
modifiedConfig = await interceptor(modifiedConfig);
|
|
362
|
+
}
|
|
363
|
+
return modifiedConfig;
|
|
364
|
+
}
|
|
365
|
+
/**
|
|
366
|
+
* Applies all registered response interceptors in sequential order.
|
|
367
|
+
*
|
|
368
|
+
* Each interceptor receives the response modified by the previous interceptor,
|
|
369
|
+
* forming a processing pipeline. If any interceptor throws an error,
|
|
370
|
+
* the pipeline stops and the error propagates.
|
|
371
|
+
*
|
|
372
|
+
* @template T - The type of the response data
|
|
373
|
+
* @param response - The initial API response
|
|
374
|
+
* @returns The modified response after all interceptors
|
|
375
|
+
*
|
|
376
|
+
* @example
|
|
377
|
+
* ```typescript
|
|
378
|
+
* const response = { data: { id: 1, name: 'John' } };
|
|
379
|
+
* const finalResponse = await manager.applyResponseInterceptors(response);
|
|
380
|
+
* // finalResponse has been processed by all registered interceptors
|
|
381
|
+
* ```
|
|
382
|
+
*/
|
|
383
|
+
async applyResponseInterceptors(response) {
|
|
384
|
+
let modifiedResponse = response;
|
|
385
|
+
for (const interceptor of this.responseInterceptors) {
|
|
386
|
+
modifiedResponse = await interceptor(modifiedResponse);
|
|
387
|
+
}
|
|
388
|
+
return modifiedResponse;
|
|
389
|
+
}
|
|
390
|
+
/**
|
|
391
|
+
* Applies all registered error interceptors in sequential order and re-throws.
|
|
392
|
+
*
|
|
393
|
+
* Each interceptor receives the error (potentially modified by previous interceptors).
|
|
394
|
+
* Interceptors can transform the error before re-throwing it. The final error
|
|
395
|
+
* is always thrown to maintain error flow.
|
|
396
|
+
*
|
|
397
|
+
* If an interceptor itself throws an error, that becomes the new error to process
|
|
398
|
+
* by subsequent interceptors.
|
|
399
|
+
*
|
|
400
|
+
* @param error - The initial API error
|
|
401
|
+
* @returns Never returns (always throws)
|
|
402
|
+
* @throws The final error after all interceptors have processed it
|
|
403
|
+
*
|
|
404
|
+
* @example
|
|
405
|
+
* ```typescript
|
|
406
|
+
* try {
|
|
407
|
+
* await manager.applyErrorInterceptors(error);
|
|
408
|
+
* } catch (finalError) {
|
|
409
|
+
* // finalError has been processed by all registered error interceptors
|
|
410
|
+
* }
|
|
411
|
+
* ```
|
|
412
|
+
*/
|
|
413
|
+
async applyErrorInterceptors(error) {
|
|
414
|
+
let modifiedError = error;
|
|
415
|
+
for (const interceptor of this.errorInterceptors) {
|
|
416
|
+
try {
|
|
417
|
+
modifiedError = await interceptor(modifiedError);
|
|
418
|
+
} catch (e) {
|
|
419
|
+
modifiedError = e;
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
throw modifiedError;
|
|
423
|
+
}
|
|
424
|
+
};
|
|
425
|
+
|
|
426
|
+
// src/core/api/RequestManager.ts
|
|
427
|
+
var RequestManager = class {
|
|
428
|
+
/**
|
|
429
|
+
* Map of active request keys to their abort controllers
|
|
430
|
+
* @private
|
|
431
|
+
*/
|
|
432
|
+
activeRequests = /* @__PURE__ */ new Map();
|
|
433
|
+
/**
|
|
434
|
+
* Map of request keys to their correlation IDs for tracing
|
|
435
|
+
* @private
|
|
436
|
+
*/
|
|
437
|
+
correlationMap = /* @__PURE__ */ new Map();
|
|
438
|
+
/**
|
|
439
|
+
* Registers a new request for tracking and cancellation management.
|
|
440
|
+
*
|
|
441
|
+
* If a request with the same key already exists, it will be automatically
|
|
442
|
+
* cancelled before the new one is registered (request deduplication).
|
|
443
|
+
*
|
|
444
|
+
* @param key - Unique identifier for the request (typically method + URL + timestamp)
|
|
445
|
+
* @param controller - AbortController for cancelling the request
|
|
446
|
+
* @param correlationId - Correlation ID for distributed tracing
|
|
447
|
+
*
|
|
448
|
+
* @example
|
|
449
|
+
* ```typescript
|
|
450
|
+
* const controller = new AbortController();
|
|
451
|
+
* manager.add('GET_/api/users_1699999999', controller, 'api-abc123');
|
|
452
|
+
* ```
|
|
453
|
+
*/
|
|
454
|
+
add(key, controller, correlationId) {
|
|
455
|
+
this.cancel(key);
|
|
456
|
+
this.activeRequests.set(key, controller);
|
|
457
|
+
this.correlationMap.set(key, correlationId);
|
|
458
|
+
}
|
|
459
|
+
/**
|
|
460
|
+
* Removes a request from tracking without cancelling it.
|
|
461
|
+
*
|
|
462
|
+
* This is typically called when a request completes successfully or fails.
|
|
463
|
+
* Use {@link cancel} instead if you need to abort the request.
|
|
464
|
+
*
|
|
465
|
+
* @param key - Unique identifier for the request to remove
|
|
466
|
+
*
|
|
467
|
+
* @example
|
|
468
|
+
* ```typescript
|
|
469
|
+
* // Called automatically after request completes
|
|
470
|
+
* manager.remove('GET_/api/users_1699999999');
|
|
471
|
+
* ```
|
|
472
|
+
*/
|
|
473
|
+
remove(key) {
|
|
474
|
+
this.activeRequests.delete(key);
|
|
475
|
+
this.correlationMap.delete(key);
|
|
476
|
+
}
|
|
477
|
+
/**
|
|
478
|
+
* Cancels a specific request and removes it from tracking.
|
|
479
|
+
*
|
|
480
|
+
* If the request doesn't exist or was already cancelled, this operation is a no-op.
|
|
481
|
+
* The associated AbortController's signal will be triggered, causing any active
|
|
482
|
+
* fetch operations to abort.
|
|
483
|
+
*
|
|
484
|
+
* @param key - Unique identifier for the request to cancel
|
|
485
|
+
*
|
|
486
|
+
* @example
|
|
487
|
+
* ```typescript
|
|
488
|
+
* // User navigates away, cancel the pending request
|
|
489
|
+
* manager.cancel('GET_/api/users_1699999999');
|
|
490
|
+
* ```
|
|
491
|
+
*/
|
|
492
|
+
cancel(key) {
|
|
493
|
+
const controller = this.activeRequests.get(key);
|
|
494
|
+
if (controller) {
|
|
495
|
+
controller.abort();
|
|
496
|
+
this.activeRequests.delete(key);
|
|
497
|
+
this.correlationMap.delete(key);
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
/**
|
|
501
|
+
* Cancels all active requests and clears all tracking data.
|
|
502
|
+
*
|
|
503
|
+
* This is useful for cleanup scenarios such as:
|
|
504
|
+
* - User logout
|
|
505
|
+
* - Component unmount
|
|
506
|
+
* - Navigation to a different part of the application
|
|
507
|
+
* - Error recovery that requires a clean slate
|
|
508
|
+
*
|
|
509
|
+
* @example
|
|
510
|
+
* ```typescript
|
|
511
|
+
* // Cancel all pending requests on logout
|
|
512
|
+
* function handleLogout() {
|
|
513
|
+
* apiClient.cancelAllRequests();
|
|
514
|
+
* // ... rest of logout logic
|
|
515
|
+
* }
|
|
516
|
+
* ```
|
|
517
|
+
*/
|
|
518
|
+
cancelAll() {
|
|
519
|
+
this.activeRequests.forEach((controller) => controller.abort());
|
|
520
|
+
this.activeRequests.clear();
|
|
521
|
+
this.correlationMap.clear();
|
|
522
|
+
}
|
|
523
|
+
/**
|
|
524
|
+
* Checks if a request with the given key is currently being tracked.
|
|
525
|
+
*
|
|
526
|
+
* @param key - Unique identifier for the request
|
|
527
|
+
* @returns `true` if the request is active, `false` otherwise
|
|
528
|
+
*
|
|
529
|
+
* @example
|
|
530
|
+
* ```typescript
|
|
531
|
+
* if (manager.has('GET_/api/users_1699999999')) {
|
|
532
|
+
* console.log('Request is still pending');
|
|
533
|
+
* }
|
|
534
|
+
* ```
|
|
535
|
+
*/
|
|
536
|
+
has(key) {
|
|
537
|
+
return this.activeRequests.has(key);
|
|
538
|
+
}
|
|
539
|
+
/**
|
|
540
|
+
* Retrieves the correlation ID for a given request key.
|
|
541
|
+
*
|
|
542
|
+
* Correlation IDs are used for distributed tracing and request tracking
|
|
543
|
+
* across services and logs.
|
|
544
|
+
*
|
|
545
|
+
* @param key - Unique identifier for the request
|
|
546
|
+
* @returns The correlation ID if found, `undefined` otherwise
|
|
547
|
+
*
|
|
548
|
+
* @example
|
|
549
|
+
* ```typescript
|
|
550
|
+
* const correlationId = manager.getCorrelationId('GET_/api/users_1699999999');
|
|
551
|
+
* if (correlationId) {
|
|
552
|
+
* console.log('Trace request with ID:', correlationId);
|
|
553
|
+
* }
|
|
554
|
+
* ```
|
|
555
|
+
*/
|
|
556
|
+
getCorrelationId(key) {
|
|
557
|
+
return this.correlationMap.get(key);
|
|
558
|
+
}
|
|
559
|
+
};
|
|
560
|
+
|
|
561
|
+
// src/core/api/Retry/RetryHandler.ts
|
|
562
|
+
var RetryHandler = class {
|
|
563
|
+
/**
|
|
564
|
+
* Retries a failed request with exponential backoff strategy.
|
|
565
|
+
*
|
|
566
|
+
* The retry logic works as follows:
|
|
567
|
+
* 1. Attempts the request immediately
|
|
568
|
+
* 2. On failure, checks if the error is retryable
|
|
569
|
+
* 3. If retryable and retries remain, waits for the current delay
|
|
570
|
+
* 4. Doubles the delay for the next attempt
|
|
571
|
+
* 5. Repeats until success or retries exhausted
|
|
572
|
+
*
|
|
573
|
+
* **Non-Retryable Errors:**
|
|
574
|
+
* - Validation errors (400) - Client sent bad data
|
|
575
|
+
* - AbortErrors - Request was explicitly cancelled
|
|
576
|
+
* - Requests with aborted signals
|
|
577
|
+
*
|
|
578
|
+
* **Abort Handling:**
|
|
579
|
+
* If the signal is aborted during a retry delay, the retry is immediately
|
|
580
|
+
* cancelled and an AbortError is thrown.
|
|
581
|
+
*
|
|
582
|
+
* @template T - The return type of the function being retried
|
|
583
|
+
* @param fn - Async function to retry on failure
|
|
584
|
+
* @param retries - Number of retry attempts remaining (decrements each retry)
|
|
585
|
+
* @param delay - Current delay in milliseconds before next retry
|
|
586
|
+
* @param signal - Optional AbortSignal to cancel retries
|
|
587
|
+
* @returns Promise resolving to the function's result on success
|
|
588
|
+
* @throws The last error encountered if all retries are exhausted
|
|
589
|
+
* @throws AbortError if the signal is aborted during execution or delay
|
|
590
|
+
*
|
|
591
|
+
* @example
|
|
592
|
+
* Basic retry usage:
|
|
593
|
+
* ```typescript
|
|
594
|
+
* const handler = new RetryHandler();
|
|
595
|
+
* const fetchUser = () => fetch('/api/users/123').then(r => r.json());
|
|
596
|
+
*
|
|
597
|
+
* try {
|
|
598
|
+
* const user = await handler.retryRequest(
|
|
599
|
+
* fetchUser,
|
|
600
|
+
* 3, // 3 retries
|
|
601
|
+
* 1000 // Start with 1s delay
|
|
602
|
+
* );
|
|
603
|
+
* console.log('User:', user);
|
|
604
|
+
* } catch (error) {
|
|
605
|
+
* console.error('Failed after all retries:', error);
|
|
606
|
+
* }
|
|
607
|
+
* ```
|
|
608
|
+
*
|
|
609
|
+
* @example
|
|
610
|
+
* With cancellation support:
|
|
611
|
+
* ```typescript
|
|
612
|
+
* const controller = new AbortController();
|
|
613
|
+
* const signal = controller.signal;
|
|
614
|
+
*
|
|
615
|
+
* // Cancel after 5 seconds
|
|
616
|
+
* setTimeout(() => controller.abort(), 5000);
|
|
617
|
+
*
|
|
618
|
+
* try {
|
|
619
|
+
* await handler.retryRequest(fetchUser, 5, 1000, signal);
|
|
620
|
+
* } catch (error) {
|
|
621
|
+
* if (error.name === 'AbortError') {
|
|
622
|
+
* console.log('Retry cancelled');
|
|
623
|
+
* }
|
|
624
|
+
* }
|
|
625
|
+
* ```
|
|
626
|
+
*/
|
|
627
|
+
async retryRequest(fn, retries, delay, signal) {
|
|
628
|
+
try {
|
|
629
|
+
if (signal?.aborted) {
|
|
630
|
+
throw new Error(signal.reason || "Request aborted");
|
|
631
|
+
}
|
|
632
|
+
return await fn();
|
|
633
|
+
} catch (error) {
|
|
634
|
+
const err = error;
|
|
635
|
+
if (err.name === "AbortError" || signal?.aborted) {
|
|
636
|
+
throw error;
|
|
637
|
+
}
|
|
638
|
+
if (err.type === "validation_error" || err.status === 400) {
|
|
639
|
+
throw error;
|
|
640
|
+
}
|
|
641
|
+
if (retries === 0) throw error;
|
|
642
|
+
await new Promise((resolve, reject) => {
|
|
643
|
+
const timeoutId = setTimeout(resolve, delay);
|
|
644
|
+
if (signal) {
|
|
645
|
+
signal.addEventListener(
|
|
646
|
+
"abort",
|
|
647
|
+
() => {
|
|
648
|
+
clearTimeout(timeoutId);
|
|
649
|
+
reject(new Error(signal.reason || "Request aborted"));
|
|
650
|
+
},
|
|
651
|
+
{ once: true }
|
|
652
|
+
);
|
|
653
|
+
}
|
|
654
|
+
});
|
|
655
|
+
return this.retryRequest(fn, retries - 1, delay * 2, signal);
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
};
|
|
659
|
+
|
|
660
|
+
// src/core/api/Signals/SignalManager.ts
|
|
661
|
+
var SignalManager = class {
|
|
662
|
+
/**
|
|
663
|
+
* Creates a combined AbortController that aborts when any source signal aborts.
|
|
664
|
+
*
|
|
665
|
+
* This method implements the "any" pattern for cancellation: the combined signal
|
|
666
|
+
* will abort as soon as ANY of the source signals abort. This is useful for
|
|
667
|
+
* coordinating multiple cancellation conditions:
|
|
668
|
+
* - User clicks cancel button
|
|
669
|
+
* - Request timeout expires
|
|
670
|
+
* - Component unmounts
|
|
671
|
+
* - Parent request is cancelled
|
|
672
|
+
*
|
|
673
|
+
* **Early Abort Optimization:**
|
|
674
|
+
* If any source signal is already aborted when this method is called,
|
|
675
|
+
* the returned controller is immediately aborted without setting up listeners.
|
|
676
|
+
*
|
|
677
|
+
* **Memory Management:**
|
|
678
|
+
* Event listeners are registered with `{ once: true }` to prevent memory leaks,
|
|
679
|
+
* as they automatically clean up after firing.
|
|
680
|
+
*
|
|
681
|
+
* @param signals - Array of AbortSignals to combine (undefined values are ignored)
|
|
682
|
+
* @returns A new AbortController that aborts when any source signal aborts
|
|
683
|
+
*
|
|
684
|
+
* @example
|
|
685
|
+
* User cancellation + timeout:
|
|
686
|
+
* ```typescript
|
|
687
|
+
* const userController = new AbortController();
|
|
688
|
+
* const timeout = manager.createTimeoutSignal(30000);
|
|
689
|
+
*
|
|
690
|
+
* const combined = manager.createCombinedSignal([
|
|
691
|
+
* userController.signal,
|
|
692
|
+
* timeout.signal
|
|
693
|
+
* ]);
|
|
694
|
+
*
|
|
695
|
+
* // Request will be cancelled after 30s OR when user clicks cancel
|
|
696
|
+
* fetch('/api/data', { signal: combined.signal });
|
|
697
|
+
* ```
|
|
698
|
+
*
|
|
699
|
+
* @example
|
|
700
|
+
* React component with cleanup:
|
|
701
|
+
* ```typescript
|
|
702
|
+
* useEffect(() => {
|
|
703
|
+
* const controller = new AbortController();
|
|
704
|
+
*
|
|
705
|
+
* const combined = manager.createCombinedSignal([
|
|
706
|
+
* controller.signal,
|
|
707
|
+
* unmountSignal // From component lifecycle
|
|
708
|
+
* ]);
|
|
709
|
+
*
|
|
710
|
+
* fetchData(combined.signal);
|
|
711
|
+
*
|
|
712
|
+
* return () => controller.abort(); // Cleanup
|
|
713
|
+
* }, []);
|
|
714
|
+
* ```
|
|
715
|
+
*/
|
|
716
|
+
createCombinedSignal(signals) {
|
|
717
|
+
const controller = new AbortController();
|
|
718
|
+
for (const signal of signals) {
|
|
719
|
+
if (signal) {
|
|
720
|
+
if (signal.aborted) {
|
|
721
|
+
controller.abort(signal.reason);
|
|
722
|
+
break;
|
|
723
|
+
}
|
|
724
|
+
signal.addEventListener(
|
|
725
|
+
"abort",
|
|
726
|
+
() => {
|
|
727
|
+
controller.abort(signal.reason);
|
|
728
|
+
},
|
|
729
|
+
{ once: true }
|
|
730
|
+
);
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
return controller;
|
|
734
|
+
}
|
|
735
|
+
/**
|
|
736
|
+
* Creates an AbortController that automatically aborts after a specified timeout.
|
|
737
|
+
*
|
|
738
|
+
* This method creates a time-based cancellation mechanism useful for implementing
|
|
739
|
+
* request timeouts and deadlines. The signal will automatically abort after the
|
|
740
|
+
* specified duration, providing a consistent timeout experience.
|
|
741
|
+
*
|
|
742
|
+
* **Automatic Cleanup:**
|
|
743
|
+
* If the signal is aborted by other means before the timeout expires, the internal
|
|
744
|
+
* setTimeout is automatically cleared to prevent memory leaks.
|
|
745
|
+
*
|
|
746
|
+
* **Abort Reason:**
|
|
747
|
+
* The abort reason includes the timeout duration for debugging purposes:
|
|
748
|
+
* `"Request timeout after {timeout}ms"`
|
|
749
|
+
*
|
|
750
|
+
* @param timeout - Timeout duration in milliseconds
|
|
751
|
+
* @returns An AbortController that will abort after the timeout
|
|
752
|
+
*
|
|
753
|
+
* @example
|
|
754
|
+
* Simple request timeout:
|
|
755
|
+
* ```typescript
|
|
756
|
+
* const manager = new SignalManager();
|
|
757
|
+
* const timeout = manager.createTimeoutSignal(5000); // 5 seconds
|
|
758
|
+
*
|
|
759
|
+
* try {
|
|
760
|
+
* const response = await fetch('/api/slow-endpoint', {
|
|
761
|
+
* signal: timeout.signal
|
|
762
|
+
* });
|
|
763
|
+
* const data = await response.json();
|
|
764
|
+
* } catch (error) {
|
|
765
|
+
* if (error.name === 'AbortError') {
|
|
766
|
+
* console.error('Request timed out after 5 seconds');
|
|
767
|
+
* }
|
|
768
|
+
* }
|
|
769
|
+
* ```
|
|
770
|
+
*
|
|
771
|
+
* @example
|
|
772
|
+
* Different timeouts for different operations:
|
|
773
|
+
* ```typescript
|
|
774
|
+
* // Short timeout for quick operations
|
|
775
|
+
* const quickTimeout = manager.createTimeoutSignal(2000);
|
|
776
|
+
* await fetch('/api/health', { signal: quickTimeout.signal });
|
|
777
|
+
*
|
|
778
|
+
* // Long timeout for heavy operations
|
|
779
|
+
* const longTimeout = manager.createTimeoutSignal(60000);
|
|
780
|
+
* await fetch('/api/export', { signal: longTimeout.signal });
|
|
781
|
+
* ```
|
|
782
|
+
*
|
|
783
|
+
* @example
|
|
784
|
+
* Manual cancellation before timeout:
|
|
785
|
+
* ```typescript
|
|
786
|
+
* const timeout = manager.createTimeoutSignal(30000);
|
|
787
|
+
*
|
|
788
|
+
* // If user cancels, timeout is automatically cleaned up
|
|
789
|
+
* timeout.abort('User cancelled');
|
|
790
|
+
* // Internal setTimeout is cleared, no memory leak
|
|
791
|
+
* ```
|
|
792
|
+
*/
|
|
793
|
+
createTimeoutSignal(timeout) {
|
|
794
|
+
const controller = new AbortController();
|
|
795
|
+
const timeoutId = setTimeout(() => {
|
|
796
|
+
controller.abort(`Request timeout after ${timeout}ms`);
|
|
797
|
+
}, timeout);
|
|
798
|
+
controller.signal.addEventListener(
|
|
799
|
+
"abort",
|
|
800
|
+
() => {
|
|
801
|
+
clearTimeout(timeoutId);
|
|
802
|
+
},
|
|
803
|
+
{ once: true }
|
|
804
|
+
);
|
|
805
|
+
return controller;
|
|
806
|
+
}
|
|
807
|
+
};
|
|
808
|
+
|
|
809
|
+
// src/core/api/Utils/ResponseParser.ts
|
|
810
|
+
var ResponseParser = class {
|
|
811
|
+
/**
|
|
812
|
+
* Parses the HTTP response body into an appropriate JavaScript type.
|
|
813
|
+
*
|
|
814
|
+
* The parsing strategy is determined by the Content-Type header:
|
|
815
|
+
* 1. **JSON** (application/json): Calls `response.json()`
|
|
816
|
+
* 2. **Text** (text/*): Calls `response.text()`
|
|
817
|
+
* 3. **Binary** (application/octet-stream): Calls `response.blob()`
|
|
818
|
+
* 4. **Unknown**: Reads as text, attempts JSON parse, falls back to raw text
|
|
819
|
+
*
|
|
820
|
+
* **Fallback Behavior:**
|
|
821
|
+
* For responses without a Content-Type header or with unknown types, the parser
|
|
822
|
+
* attempts to parse as JSON first (common for APIs that don't set proper headers).
|
|
823
|
+
* If JSON parsing fails, it returns the raw text.
|
|
824
|
+
*
|
|
825
|
+
* @param response - The Fetch API Response object to parse
|
|
826
|
+
* @returns Promise resolving to the parsed response data
|
|
827
|
+
* @returns Can be: JSON object/array, string, or Blob depending on Content-Type
|
|
828
|
+
*
|
|
829
|
+
* @example
|
|
830
|
+
* API response parsing:
|
|
831
|
+
* ```typescript
|
|
832
|
+
* const response = await fetch('/api/users');
|
|
833
|
+
* const data = await parser.parseResponse(response);
|
|
834
|
+
*
|
|
835
|
+
* if (typeof data === 'string') {
|
|
836
|
+
* console.log('Text response:', data);
|
|
837
|
+
* } else if (data instanceof Blob) {
|
|
838
|
+
* console.log('Binary response:', data.size, 'bytes');
|
|
839
|
+
* } else {
|
|
840
|
+
* console.log('JSON response:', data);
|
|
841
|
+
* }
|
|
842
|
+
* ```
|
|
843
|
+
*
|
|
844
|
+
* @example
|
|
845
|
+
* Handling different content types:
|
|
846
|
+
* ```typescript
|
|
847
|
+
* // CSV file download
|
|
848
|
+
* const csvResponse = await fetch('/api/export.csv');
|
|
849
|
+
* const blob = await parser.parseResponse(csvResponse);
|
|
850
|
+
* // Returns Blob for download
|
|
851
|
+
*
|
|
852
|
+
* // JSON API
|
|
853
|
+
* const jsonResponse = await fetch('/api/users');
|
|
854
|
+
* const users = await parser.parseResponse(jsonResponse);
|
|
855
|
+
* // Returns parsed JSON array
|
|
856
|
+
*
|
|
857
|
+
* // Plain text logs
|
|
858
|
+
* const logResponse = await fetch('/api/logs');
|
|
859
|
+
* const logs = await parser.parseResponse(logResponse);
|
|
860
|
+
* // Returns string
|
|
861
|
+
* ```
|
|
862
|
+
*/
|
|
863
|
+
async parseResponse(response) {
|
|
864
|
+
const contentType = response.headers.get("content-type");
|
|
865
|
+
if (contentType?.includes("application/json")) {
|
|
866
|
+
return response.json();
|
|
867
|
+
} else if (contentType?.includes("text/")) {
|
|
868
|
+
return response.text();
|
|
869
|
+
} else if (contentType?.includes("application/octet-stream")) {
|
|
870
|
+
return response.blob();
|
|
871
|
+
} else {
|
|
872
|
+
const text = await response.text();
|
|
873
|
+
try {
|
|
874
|
+
return JSON.parse(text);
|
|
875
|
+
} catch {
|
|
876
|
+
return text;
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
};
|
|
881
|
+
|
|
882
|
+
// src/core/api/Utils/UrlBuilder.ts
|
|
883
|
+
var UrlBuilder = class {
|
|
884
|
+
/**
|
|
885
|
+
* Builds a complete URL by combining base URL, endpoint, and query parameters.
|
|
886
|
+
*
|
|
887
|
+
* The URL construction process:
|
|
888
|
+
* 1. Combines `baseURL` and `endpoint` using URL API
|
|
889
|
+
* 2. Iterates through query parameters
|
|
890
|
+
* 3. Skips null/undefined values
|
|
891
|
+
* 4. Handles arrays by appending multiple values with same key
|
|
892
|
+
* 5. Converts all values to strings
|
|
893
|
+
* 6. Returns fully-qualified URL string
|
|
894
|
+
*
|
|
895
|
+
* **Path Handling:**
|
|
896
|
+
* The endpoint can be either relative or absolute:
|
|
897
|
+
* - Relative: `/users` → Combined with baseURL
|
|
898
|
+
* - Absolute: `https://other-api.com/users` → Uses absolute URL
|
|
899
|
+
*
|
|
900
|
+
* **Encoding:**
|
|
901
|
+
* All parameter values are automatically URL-encoded by the URL API,
|
|
902
|
+
* so special characters (spaces, &, =, etc.) are safely handled.
|
|
903
|
+
*
|
|
904
|
+
* @param baseURL - Base URL for the API (e.g., 'https://api.example.com')
|
|
905
|
+
* @param endpoint - API endpoint path relative to baseURL (e.g., '/users/123')
|
|
906
|
+
* @param params - Optional query parameters as key-value pairs
|
|
907
|
+
* @returns The fully-qualified URL string with encoded query parameters
|
|
908
|
+
*
|
|
909
|
+
* @example
|
|
910
|
+
* Basic URL construction:
|
|
911
|
+
* ```typescript
|
|
912
|
+
* const url = builder.buildURL(
|
|
913
|
+
* 'https://api.example.com',
|
|
914
|
+
* '/search',
|
|
915
|
+
* { q: 'hello world', limit: 10 }
|
|
916
|
+
* );
|
|
917
|
+
* // => "https://api.example.com/search?q=hello+world&limit=10"
|
|
918
|
+
* ```
|
|
919
|
+
*
|
|
920
|
+
* @example
|
|
921
|
+
* Array parameters:
|
|
922
|
+
* ```typescript
|
|
923
|
+
* const url = builder.buildURL(
|
|
924
|
+
* 'https://api.example.com',
|
|
925
|
+
* '/posts',
|
|
926
|
+
* { tags: ['javascript', 'typescript', 'react'] }
|
|
927
|
+
* );
|
|
928
|
+
* // => "https://api.example.com/posts?tags=javascript&tags=typescript&tags=react"
|
|
929
|
+
* ```
|
|
930
|
+
*
|
|
931
|
+
* @example
|
|
932
|
+
* Null/undefined handling:
|
|
933
|
+
* ```typescript
|
|
934
|
+
* const url = builder.buildURL(
|
|
935
|
+
* 'https://api.example.com',
|
|
936
|
+
* '/users',
|
|
937
|
+
* {
|
|
938
|
+
* name: 'John',
|
|
939
|
+
* age: null, // Skipped
|
|
940
|
+
* email: undefined // Skipped
|
|
941
|
+
* }
|
|
942
|
+
* );
|
|
943
|
+
* // => "https://api.example.com/users?name=John"
|
|
944
|
+
* ```
|
|
945
|
+
*
|
|
946
|
+
* @example
|
|
947
|
+
* Special characters encoding:
|
|
948
|
+
* ```typescript
|
|
949
|
+
* const url = builder.buildURL(
|
|
950
|
+
* 'https://api.example.com',
|
|
951
|
+
* '/search',
|
|
952
|
+
* { q: 'foo & bar', category: 'code/examples' }
|
|
953
|
+
* );
|
|
954
|
+
* // => "https://api.example.com/search?q=foo+%26+bar&category=code%2Fexamples"
|
|
955
|
+
* ```
|
|
956
|
+
*/
|
|
957
|
+
buildURL(baseURL, endpoint, params) {
|
|
958
|
+
const normalizedEndpoint = endpoint.startsWith("/") ? endpoint : `/${endpoint}`;
|
|
959
|
+
const url = new URL(normalizedEndpoint, baseURL);
|
|
960
|
+
if (params) {
|
|
961
|
+
Object.keys(params).forEach((key) => {
|
|
962
|
+
const value = params[key];
|
|
963
|
+
if (value !== void 0 && value !== null) {
|
|
964
|
+
if (Array.isArray(value)) {
|
|
965
|
+
value.forEach((v) => url.searchParams.append(key, String(v)));
|
|
966
|
+
} else {
|
|
967
|
+
url.searchParams.append(key, String(value));
|
|
968
|
+
}
|
|
969
|
+
}
|
|
970
|
+
});
|
|
971
|
+
}
|
|
972
|
+
return url.toString();
|
|
973
|
+
}
|
|
974
|
+
};
|
|
975
|
+
|
|
976
|
+
// src/core/api/ApiClient.ts
|
|
977
|
+
var ApiClient = class {
|
|
978
|
+
baseURL;
|
|
979
|
+
defaultTimeout;
|
|
980
|
+
interceptorManager = new InterceptorManager();
|
|
981
|
+
signalManager = new SignalManager();
|
|
982
|
+
errorNormalizer = new ErrorNormalizer();
|
|
983
|
+
responseParser = new ResponseParser();
|
|
984
|
+
urlBuilder = new UrlBuilder();
|
|
985
|
+
retryHandler = new RetryHandler();
|
|
986
|
+
requestManager = new RequestManager();
|
|
987
|
+
authToken = null;
|
|
988
|
+
correlationIdPrefix = "api";
|
|
989
|
+
includeCorrelationId = true;
|
|
990
|
+
/**
|
|
991
|
+
* Creates a new API client instance
|
|
992
|
+
* @param baseURL - Base URL for all API requests (default: empty string for relative URLs)
|
|
993
|
+
* @param defaultTimeout - Default request timeout in milliseconds (default: 30000)
|
|
994
|
+
*/
|
|
995
|
+
constructor(baseURL = "", defaultTimeout = 3e4) {
|
|
996
|
+
this.baseURL = baseURL;
|
|
997
|
+
this.defaultTimeout = defaultTimeout;
|
|
998
|
+
}
|
|
999
|
+
/**
|
|
1000
|
+
* Sets the prefix for auto-generated correlation IDs
|
|
1001
|
+
* @param prefix - The prefix to use for correlation IDs (e.g., 'api', 'web', 'mobile')
|
|
1002
|
+
*/
|
|
1003
|
+
setCorrelationIdPrefix(prefix) {
|
|
1004
|
+
this.correlationIdPrefix = prefix;
|
|
1005
|
+
}
|
|
1006
|
+
/**
|
|
1007
|
+
* Enables or disables automatic correlation ID generation
|
|
1008
|
+
* @param include - Whether to include correlation IDs in requests
|
|
1009
|
+
*/
|
|
1010
|
+
setIncludeCorrelationId(include) {
|
|
1011
|
+
this.includeCorrelationId = include;
|
|
1012
|
+
}
|
|
1013
|
+
/**
|
|
1014
|
+
* Registers a request interceptor to modify requests before they're sent
|
|
1015
|
+
* @param interceptor - Function to intercept and potentially modify request config
|
|
1016
|
+
* @returns Function to unregister this interceptor
|
|
1017
|
+
*
|
|
1018
|
+
* @example
|
|
1019
|
+
* ```typescript
|
|
1020
|
+
* const unregister = client.addRequestInterceptor(async (config) => {
|
|
1021
|
+
* config.headers = config.headers || new Headers();
|
|
1022
|
+
* config.headers.set('X-Client-Version', '1.0.0');
|
|
1023
|
+
* return config;
|
|
1024
|
+
* });
|
|
1025
|
+
*
|
|
1026
|
+
* // Later, to remove the interceptor:
|
|
1027
|
+
* unregister();
|
|
1028
|
+
* ```
|
|
1029
|
+
*/
|
|
1030
|
+
addRequestInterceptor(interceptor) {
|
|
1031
|
+
return this.interceptorManager.addRequestInterceptor(interceptor);
|
|
1032
|
+
}
|
|
1033
|
+
/**
|
|
1034
|
+
* Registers a response interceptor to modify responses before they're returned
|
|
1035
|
+
* @param interceptor - Function to intercept and potentially modify responses
|
|
1036
|
+
* @returns Function to unregister this interceptor
|
|
1037
|
+
*
|
|
1038
|
+
* @example
|
|
1039
|
+
* ```typescript
|
|
1040
|
+
* client.addResponseInterceptor(async (response) => {
|
|
1041
|
+
* // Transform data format
|
|
1042
|
+
* if (response.apiData) {
|
|
1043
|
+
* response.apiData = camelCaseKeys(response.apiData);
|
|
1044
|
+
* }
|
|
1045
|
+
* return response;
|
|
1046
|
+
* });
|
|
1047
|
+
* ```
|
|
1048
|
+
*/
|
|
1049
|
+
addResponseInterceptor(interceptor) {
|
|
1050
|
+
return this.interceptorManager.addResponseInterceptor(interceptor);
|
|
1051
|
+
}
|
|
1052
|
+
/**
|
|
1053
|
+
* Registers an error interceptor to handle or transform errors
|
|
1054
|
+
* @param interceptor - Function to intercept and potentially modify errors
|
|
1055
|
+
* @returns Function to unregister this interceptor
|
|
1056
|
+
*
|
|
1057
|
+
* @example
|
|
1058
|
+
* ```typescript
|
|
1059
|
+
* client.addErrorInterceptor(async (error) => {
|
|
1060
|
+
* // Log errors to monitoring service
|
|
1061
|
+
* if (error.status >= 500) {
|
|
1062
|
+
* await monitoringService.logError(error);
|
|
1063
|
+
* }
|
|
1064
|
+
* return error; // Re-throw the error
|
|
1065
|
+
* });
|
|
1066
|
+
* ```
|
|
1067
|
+
*/
|
|
1068
|
+
addErrorInterceptor(interceptor) {
|
|
1069
|
+
return this.interceptorManager.addErrorInterceptor(interceptor);
|
|
1070
|
+
}
|
|
1071
|
+
/**
|
|
1072
|
+
* Sets the authentication token for subsequent requests
|
|
1073
|
+
* @param token - JWT token or null to clear authentication
|
|
1074
|
+
*
|
|
1075
|
+
* @example
|
|
1076
|
+
* ```typescript
|
|
1077
|
+
* // Set token after login
|
|
1078
|
+
* client.setAuthToken(loginResponse.accessToken);
|
|
1079
|
+
*
|
|
1080
|
+
* // Clear token on logout
|
|
1081
|
+
* client.setAuthToken(null);
|
|
1082
|
+
* ```
|
|
1083
|
+
*/
|
|
1084
|
+
setAuthToken(token) {
|
|
1085
|
+
this.authToken = token;
|
|
1086
|
+
}
|
|
1087
|
+
/**
|
|
1088
|
+
* Retrieves the current authentication token
|
|
1089
|
+
* @returns The current auth token or null if not set
|
|
1090
|
+
*/
|
|
1091
|
+
getAuthToken() {
|
|
1092
|
+
return this.authToken;
|
|
1093
|
+
}
|
|
1094
|
+
/**
|
|
1095
|
+
* Cancels a specific request by its key
|
|
1096
|
+
* @param key - The unique key identifying the request to cancel
|
|
1097
|
+
*/
|
|
1098
|
+
cancelRequest(key) {
|
|
1099
|
+
this.requestManager.cancel(key);
|
|
1100
|
+
}
|
|
1101
|
+
/**
|
|
1102
|
+
* Cancels all pending requests
|
|
1103
|
+
* Useful for cleanup on navigation or component unmount
|
|
1104
|
+
*/
|
|
1105
|
+
cancelAllRequests() {
|
|
1106
|
+
this.requestManager.cancelAll();
|
|
1107
|
+
}
|
|
1108
|
+
/**
|
|
1109
|
+
* Core request method that handles all HTTP operations
|
|
1110
|
+
* @template T - The expected response data type
|
|
1111
|
+
* @param endpoint - API endpoint relative to baseURL
|
|
1112
|
+
* @param config - Request configuration options
|
|
1113
|
+
* @returns Promise resolving to ApiResponse with data or error
|
|
1114
|
+
*
|
|
1115
|
+
* @example
|
|
1116
|
+
* ```typescript
|
|
1117
|
+
* const response = await client.request<User>('/users/123', {
|
|
1118
|
+
* method: 'GET',
|
|
1119
|
+
* timeout: 5000,
|
|
1120
|
+
* throwErrors: false
|
|
1121
|
+
* });
|
|
1122
|
+
* ```
|
|
1123
|
+
*/
|
|
1124
|
+
async request(endpoint, config = {}) {
|
|
1125
|
+
const correlationId = config.correlationId || (!config.skipCorrelationId && this.includeCorrelationId ? generateCorrelationId(this.correlationIdPrefix) : void 0);
|
|
1126
|
+
const requestKey = `${config.method || "GET"}_${endpoint}_${Date.now()}`;
|
|
1127
|
+
const masterController = new AbortController();
|
|
1128
|
+
try {
|
|
1129
|
+
const signals = [
|
|
1130
|
+
config.signal,
|
|
1131
|
+
config.cancelToken?.signal,
|
|
1132
|
+
masterController.signal
|
|
1133
|
+
];
|
|
1134
|
+
const timeout = config.timeout || this.defaultTimeout;
|
|
1135
|
+
const timeoutController = this.signalManager.createTimeoutSignal(timeout);
|
|
1136
|
+
signals.push(timeoutController.signal);
|
|
1137
|
+
const combinedController = this.signalManager.createCombinedSignal(signals);
|
|
1138
|
+
if (correlationId) {
|
|
1139
|
+
this.requestManager.add(requestKey, masterController, correlationId);
|
|
1140
|
+
}
|
|
1141
|
+
const finalConfig = await this.interceptorManager.applyRequestInterceptors({
|
|
1142
|
+
...config,
|
|
1143
|
+
signal: combinedController.signal,
|
|
1144
|
+
correlationId
|
|
1145
|
+
});
|
|
1146
|
+
const url = this.urlBuilder.buildURL(
|
|
1147
|
+
this.baseURL,
|
|
1148
|
+
endpoint,
|
|
1149
|
+
finalConfig.params
|
|
1150
|
+
);
|
|
1151
|
+
const headers = new Headers(finalConfig.headers);
|
|
1152
|
+
if (correlationId) {
|
|
1153
|
+
headers.set("X-Correlation-Id", correlationId);
|
|
1154
|
+
headers.set("X-Request-Id", correlationId);
|
|
1155
|
+
}
|
|
1156
|
+
if (this.authToken && !finalConfig.skipAuthRefresh) {
|
|
1157
|
+
headers.set("Authorization", `Bearer ${this.authToken}`);
|
|
1158
|
+
}
|
|
1159
|
+
let fetchBody = finalConfig.body;
|
|
1160
|
+
if (finalConfig.body && typeof finalConfig.body === "object" && !(finalConfig.body instanceof FormData) && !(finalConfig.body instanceof Blob) && !(finalConfig.body instanceof ArrayBuffer) && !(finalConfig.body instanceof URLSearchParams) && !(finalConfig.body instanceof ReadableStream)) {
|
|
1161
|
+
headers.set("Content-Type", "application/json");
|
|
1162
|
+
fetchBody = JSON.stringify(finalConfig.body);
|
|
1163
|
+
}
|
|
1164
|
+
finalConfig.headers = headers;
|
|
1165
|
+
const fetchPromise = async () => {
|
|
1166
|
+
try {
|
|
1167
|
+
const response = await fetch(url, {
|
|
1168
|
+
...finalConfig,
|
|
1169
|
+
body: fetchBody,
|
|
1170
|
+
signal: combinedController.signal
|
|
1171
|
+
});
|
|
1172
|
+
const responseData = await this.responseParser.parseResponse(response);
|
|
1173
|
+
if (!response.ok) {
|
|
1174
|
+
const errorData = responseData;
|
|
1175
|
+
const error = Object.assign(
|
|
1176
|
+
new Error(
|
|
1177
|
+
errorData.title || `HTTP ${response.status}: ${response.statusText}`
|
|
1178
|
+
),
|
|
1179
|
+
{
|
|
1180
|
+
type: errorData.type || this.errorNormalizer.getErrorType(response.status),
|
|
1181
|
+
title: errorData.title || this.errorNormalizer.getErrorTitle(response.status),
|
|
1182
|
+
status: response.status,
|
|
1183
|
+
traceId: errorData.traceId || correlationId,
|
|
1184
|
+
errors: errorData.errors,
|
|
1185
|
+
isAborted: false,
|
|
1186
|
+
config: finalConfig
|
|
1187
|
+
}
|
|
1188
|
+
);
|
|
1189
|
+
if (finalConfig.throwErrors !== false) {
|
|
1190
|
+
throw error;
|
|
1191
|
+
} else {
|
|
1192
|
+
return await this.interceptorManager.applyResponseInterceptors({
|
|
1193
|
+
error
|
|
1194
|
+
});
|
|
1195
|
+
}
|
|
1196
|
+
}
|
|
1197
|
+
const apiResponse = {
|
|
1198
|
+
data: responseData
|
|
1199
|
+
};
|
|
1200
|
+
return await this.interceptorManager.applyResponseInterceptors(
|
|
1201
|
+
apiResponse
|
|
1202
|
+
);
|
|
1203
|
+
} catch (error) {
|
|
1204
|
+
if (error.name === "AbortError") {
|
|
1205
|
+
const abortError = Object.assign(
|
|
1206
|
+
new Error(error.message || "Request aborted"),
|
|
1207
|
+
{
|
|
1208
|
+
type: "request_cancelled",
|
|
1209
|
+
title: "Request was cancelled",
|
|
1210
|
+
status: 0,
|
|
1211
|
+
traceId: correlationId,
|
|
1212
|
+
isAborted: true,
|
|
1213
|
+
config: finalConfig
|
|
1214
|
+
}
|
|
1215
|
+
);
|
|
1216
|
+
if (finalConfig.throwErrors !== false) {
|
|
1217
|
+
throw abortError;
|
|
1218
|
+
} else {
|
|
1219
|
+
return await this.interceptorManager.applyResponseInterceptors({
|
|
1220
|
+
error: abortError
|
|
1221
|
+
});
|
|
1222
|
+
}
|
|
1223
|
+
}
|
|
1224
|
+
throw error;
|
|
1225
|
+
}
|
|
1226
|
+
};
|
|
1227
|
+
if (finalConfig.retries && finalConfig.retries > 0) {
|
|
1228
|
+
return await this.retryHandler.retryRequest(
|
|
1229
|
+
fetchPromise,
|
|
1230
|
+
finalConfig.retries,
|
|
1231
|
+
finalConfig.retryDelay || 1e3,
|
|
1232
|
+
combinedController.signal
|
|
1233
|
+
);
|
|
1234
|
+
}
|
|
1235
|
+
return await fetchPromise();
|
|
1236
|
+
} catch (error) {
|
|
1237
|
+
const apiError = this.errorNormalizer.normalizeError(
|
|
1238
|
+
error,
|
|
1239
|
+
config,
|
|
1240
|
+
correlationId
|
|
1241
|
+
);
|
|
1242
|
+
if (config.throwErrors !== false) {
|
|
1243
|
+
await this.interceptorManager.applyErrorInterceptors(apiError);
|
|
1244
|
+
throw apiError;
|
|
1245
|
+
} else {
|
|
1246
|
+
return {
|
|
1247
|
+
error: apiError
|
|
1248
|
+
};
|
|
1249
|
+
}
|
|
1250
|
+
} finally {
|
|
1251
|
+
this.requestManager.remove(requestKey);
|
|
1252
|
+
}
|
|
1253
|
+
}
|
|
1254
|
+
/**
|
|
1255
|
+
* Performs a GET request
|
|
1256
|
+
* @template T - The expected response data type
|
|
1257
|
+
* @param endpoint - API endpoint
|
|
1258
|
+
* @param config - Optional request configuration
|
|
1259
|
+
* @returns Promise resolving to ApiResponse
|
|
1260
|
+
*
|
|
1261
|
+
* @example
|
|
1262
|
+
* ```typescript
|
|
1263
|
+
* const { apiData, error } = await client.get<User[]>('/users', {
|
|
1264
|
+
* params: { active: true },
|
|
1265
|
+
* timeout: 5000
|
|
1266
|
+
* });
|
|
1267
|
+
* ```
|
|
1268
|
+
*/
|
|
1269
|
+
get(endpoint, config) {
|
|
1270
|
+
return this.request(endpoint, { ...config, method: "GET" });
|
|
1271
|
+
}
|
|
1272
|
+
/**
|
|
1273
|
+
* Performs a POST request
|
|
1274
|
+
* @template T - The expected response data type
|
|
1275
|
+
* @template TData - The request body data type
|
|
1276
|
+
* @param endpoint - API endpoint
|
|
1277
|
+
* @param data - Request body data
|
|
1278
|
+
* @param config - Optional request configuration
|
|
1279
|
+
* @returns Promise resolving to ApiResponse
|
|
1280
|
+
*
|
|
1281
|
+
* @example
|
|
1282
|
+
* ```typescript
|
|
1283
|
+
* const { apiData, error } = await client.post<User, CreateUserDto>('/users', {
|
|
1284
|
+
* name: 'John Doe',
|
|
1285
|
+
* email: 'john@example.com'
|
|
1286
|
+
* });
|
|
1287
|
+
* ```
|
|
1288
|
+
*/
|
|
1289
|
+
post(endpoint, data, config) {
|
|
1290
|
+
return this.request(endpoint, { ...config, method: "POST", body: data });
|
|
1291
|
+
}
|
|
1292
|
+
/**
|
|
1293
|
+
* Performs a PUT request
|
|
1294
|
+
* @template T - The expected response data type
|
|
1295
|
+
* @template TData - The request body data type
|
|
1296
|
+
* @param endpoint - API endpoint
|
|
1297
|
+
* @param data - Request body data
|
|
1298
|
+
* @param config - Optional request configuration
|
|
1299
|
+
* @returns Promise resolving to ApiResponse
|
|
1300
|
+
*
|
|
1301
|
+
* @example
|
|
1302
|
+
* ```typescript
|
|
1303
|
+
* const { apiData, error } = await client.put<User, UpdateUserDto>(
|
|
1304
|
+
* '/users/123',
|
|
1305
|
+
* { name: 'Jane Doe' }
|
|
1306
|
+
* );
|
|
1307
|
+
* ```
|
|
1308
|
+
*/
|
|
1309
|
+
put(endpoint, data, config) {
|
|
1310
|
+
return this.request(endpoint, { ...config, method: "PUT", body: data });
|
|
1311
|
+
}
|
|
1312
|
+
/**
|
|
1313
|
+
* Performs a PATCH request
|
|
1314
|
+
* @template T - The expected response data type
|
|
1315
|
+
* @template TData - The request body data type
|
|
1316
|
+
* @param endpoint - API endpoint
|
|
1317
|
+
* @param data - Request body data
|
|
1318
|
+
* @param config - Optional request configuration
|
|
1319
|
+
* @returns Promise resolving to ApiResponse
|
|
1320
|
+
*
|
|
1321
|
+
* @example
|
|
1322
|
+
* ```typescript
|
|
1323
|
+
* const { apiData, error } = await client.patch<User>(
|
|
1324
|
+
* '/users/123',
|
|
1325
|
+
* { status: 'active' }
|
|
1326
|
+
* );
|
|
1327
|
+
* ```
|
|
1328
|
+
*/
|
|
1329
|
+
patch(endpoint, data, config) {
|
|
1330
|
+
return this.request(endpoint, {
|
|
1331
|
+
...config,
|
|
1332
|
+
method: "PATCH",
|
|
1333
|
+
body: data
|
|
1334
|
+
});
|
|
1335
|
+
}
|
|
1336
|
+
/**
|
|
1337
|
+
* Performs a DELETE request
|
|
1338
|
+
* @template T - The expected response data type
|
|
1339
|
+
* @param endpoint - API endpoint
|
|
1340
|
+
* @param config - Optional request configuration
|
|
1341
|
+
* @returns Promise resolving to ApiResponse
|
|
1342
|
+
*
|
|
1343
|
+
* @example
|
|
1344
|
+
* ```typescript
|
|
1345
|
+
* const { error } = await client.delete('/users/123');
|
|
1346
|
+
* if (!error) {
|
|
1347
|
+
* console.log('User deleted successfully');
|
|
1348
|
+
* }
|
|
1349
|
+
* ```
|
|
1350
|
+
*/
|
|
1351
|
+
delete(endpoint, config) {
|
|
1352
|
+
return this.request(endpoint, { ...config, method: "DELETE" });
|
|
1353
|
+
}
|
|
1354
|
+
/**
|
|
1355
|
+
* Performs a filtered list request with pagination and sorting
|
|
1356
|
+
* @template TListModel - The type of individual list items
|
|
1357
|
+
* @template TFilter - The filter criteria type
|
|
1358
|
+
* @param url - API endpoint
|
|
1359
|
+
* @param data - Pagination and filter data
|
|
1360
|
+
* @param config - Optional request configuration
|
|
1361
|
+
* @returns Promise resolving to paginated list response
|
|
1362
|
+
*
|
|
1363
|
+
* @example
|
|
1364
|
+
* ```typescript
|
|
1365
|
+
* const { apiData, error } = await client.filter<User, UserFilter>(
|
|
1366
|
+
* '/users/filter',
|
|
1367
|
+
* {
|
|
1368
|
+
* pageOffset: 0,
|
|
1369
|
+
* pageSize: 20,
|
|
1370
|
+
* sortField: 'createdAt',
|
|
1371
|
+
* sortOrder: 'desc',
|
|
1372
|
+
* filterModel: { status: 'active' }
|
|
1373
|
+
* }
|
|
1374
|
+
* );
|
|
1375
|
+
*
|
|
1376
|
+
* if (apiData) {
|
|
1377
|
+
* console.log(`Found ${apiData.Total} users`);
|
|
1378
|
+
* console.log('Users:', apiData.Data);
|
|
1379
|
+
* }
|
|
1380
|
+
* ```
|
|
1381
|
+
*/
|
|
1382
|
+
filter(url, data, config) {
|
|
1383
|
+
const mergedData = { ...data, ...data.filterModel };
|
|
1384
|
+
return this.request(url, {
|
|
1385
|
+
...config,
|
|
1386
|
+
method: "POST",
|
|
1387
|
+
body: mergedData
|
|
1388
|
+
});
|
|
1389
|
+
}
|
|
1390
|
+
};
|
|
1391
|
+
|
|
1392
|
+
// src/core/api/createApiClient.ts
|
|
1393
|
+
var globalApiClient = null;
|
|
1394
|
+
function createApiClient(config) {
|
|
1395
|
+
const {
|
|
1396
|
+
baseURL,
|
|
1397
|
+
timeout = 3e4,
|
|
1398
|
+
correlationIdPrefix,
|
|
1399
|
+
includeCorrelationId = true,
|
|
1400
|
+
tokenStorageKey,
|
|
1401
|
+
requestInterceptors = [],
|
|
1402
|
+
responseInterceptors = [],
|
|
1403
|
+
errorInterceptors = []
|
|
1404
|
+
} = config;
|
|
1405
|
+
const client = new ApiClient(baseURL, timeout);
|
|
1406
|
+
client.addRequestInterceptor((config2) => {
|
|
1407
|
+
const token = localStorage.getItem(tokenStorageKey);
|
|
1408
|
+
if (token && !config2.skipAuthRefresh) {
|
|
1409
|
+
config2.headers = {
|
|
1410
|
+
...config2.headers,
|
|
1411
|
+
Authorization: `Bearer ${token}`
|
|
1412
|
+
};
|
|
1413
|
+
}
|
|
1414
|
+
return config2;
|
|
1415
|
+
});
|
|
1416
|
+
client.setCorrelationIdPrefix(correlationIdPrefix);
|
|
1417
|
+
client.setIncludeCorrelationId(includeCorrelationId);
|
|
1418
|
+
requestInterceptors.forEach((interceptor) => {
|
|
1419
|
+
client.addRequestInterceptor(interceptor);
|
|
1420
|
+
});
|
|
1421
|
+
responseInterceptors.forEach((interceptor) => {
|
|
1422
|
+
client.addResponseInterceptor(interceptor);
|
|
1423
|
+
});
|
|
1424
|
+
errorInterceptors.forEach((interceptor) => {
|
|
1425
|
+
client.addErrorInterceptor(interceptor);
|
|
1426
|
+
});
|
|
1427
|
+
return client;
|
|
1428
|
+
}
|
|
1429
|
+
function getGlobalApiClient() {
|
|
1430
|
+
if (!globalApiClient) {
|
|
1431
|
+
throw new Error(
|
|
1432
|
+
"getGlobalApiClient: No global client exists. Call initializeGlobalApiClient() first to configure the client."
|
|
1433
|
+
);
|
|
1434
|
+
}
|
|
1435
|
+
return globalApiClient;
|
|
1436
|
+
}
|
|
1437
|
+
function initializeGlobalApiClient(config) {
|
|
1438
|
+
if (globalApiClient) {
|
|
1439
|
+
throw new Error(
|
|
1440
|
+
"initializeGlobalApiClient: Global client already initialized. Use resetGlobalApiClient() first if you need to reinitialize."
|
|
1441
|
+
);
|
|
1442
|
+
}
|
|
1443
|
+
globalApiClient = createApiClient(config);
|
|
1444
|
+
return globalApiClient;
|
|
1445
|
+
}
|
|
1446
|
+
function setGlobalApiClient(client) {
|
|
1447
|
+
globalApiClient = client;
|
|
1448
|
+
}
|
|
1449
|
+
function resetGlobalApiClient() {
|
|
1450
|
+
globalApiClient = null;
|
|
1451
|
+
}
|
|
1452
|
+
|
|
1453
|
+
// src/core/api/types/CancelToken.ts
|
|
1454
|
+
var CancelToken = class _CancelToken {
|
|
1455
|
+
abortController;
|
|
1456
|
+
cancelPromise;
|
|
1457
|
+
cancelResolve;
|
|
1458
|
+
constructor() {
|
|
1459
|
+
this.abortController = new AbortController();
|
|
1460
|
+
this.cancelPromise = new Promise((resolve) => {
|
|
1461
|
+
this.cancelResolve = resolve;
|
|
1462
|
+
});
|
|
1463
|
+
}
|
|
1464
|
+
get signal() {
|
|
1465
|
+
return this.abortController.signal;
|
|
1466
|
+
}
|
|
1467
|
+
cancel(reason) {
|
|
1468
|
+
this.abortController.abort(reason);
|
|
1469
|
+
this.cancelResolve?.();
|
|
1470
|
+
}
|
|
1471
|
+
get isCancelled() {
|
|
1472
|
+
return this.abortController.signal.aborted;
|
|
1473
|
+
}
|
|
1474
|
+
throwIfCancelled() {
|
|
1475
|
+
if (this.isCancelled) {
|
|
1476
|
+
throw new Error("Request cancelled");
|
|
1477
|
+
}
|
|
1478
|
+
}
|
|
1479
|
+
static source() {
|
|
1480
|
+
const token = new _CancelToken();
|
|
1481
|
+
return {
|
|
1482
|
+
token,
|
|
1483
|
+
cancel: (reason) => token.cancel(reason)
|
|
1484
|
+
};
|
|
1485
|
+
}
|
|
1486
|
+
};
|
|
1487
|
+
|
|
1488
|
+
// src/core/api/useValidationErrors.ts
|
|
1489
|
+
import { useCallback } from "react";
|
|
1490
|
+
function useValidationErrors(error) {
|
|
1491
|
+
const getFieldError = useCallback(
|
|
1492
|
+
(field) => {
|
|
1493
|
+
if (!error?.errors || !error.errors[field]) return null;
|
|
1494
|
+
const fieldError = error.errors[field];
|
|
1495
|
+
if (typeof fieldError === "string") return fieldError;
|
|
1496
|
+
if (Array.isArray(fieldError)) return fieldError[0];
|
|
1497
|
+
if (typeof fieldError === "object" && "message" in fieldError) {
|
|
1498
|
+
return fieldError.message;
|
|
1499
|
+
}
|
|
1500
|
+
return null;
|
|
1501
|
+
},
|
|
1502
|
+
[error]
|
|
1503
|
+
);
|
|
1504
|
+
const hasFieldError = useCallback(
|
|
1505
|
+
(field) => {
|
|
1506
|
+
return !!getFieldError(field);
|
|
1507
|
+
},
|
|
1508
|
+
[getFieldError]
|
|
1509
|
+
);
|
|
1510
|
+
const getAllErrors = useCallback(() => {
|
|
1511
|
+
if (!error?.errors) return {};
|
|
1512
|
+
const result = {};
|
|
1513
|
+
Object.entries(error.errors).forEach(([key, value]) => {
|
|
1514
|
+
if (typeof value === "string") {
|
|
1515
|
+
result[key] = value;
|
|
1516
|
+
} else if (Array.isArray(value)) {
|
|
1517
|
+
result[key] = value.join(", ");
|
|
1518
|
+
} else if (typeof value === "object" && value && "message" in value) {
|
|
1519
|
+
result[key] = value.message;
|
|
1520
|
+
}
|
|
1521
|
+
});
|
|
1522
|
+
return result;
|
|
1523
|
+
}, [error]);
|
|
1524
|
+
return {
|
|
1525
|
+
getFieldError,
|
|
1526
|
+
hasFieldError,
|
|
1527
|
+
getAllErrors,
|
|
1528
|
+
hasErrors: error?.errors
|
|
1529
|
+
};
|
|
1530
|
+
}
|
|
1531
|
+
|
|
1532
|
+
// src/core/components/AuthorizedView/AuthorizedView.tsx
|
|
1533
|
+
import { Fragment, jsx } from "react/jsx-runtime";
|
|
1534
|
+
var AuthorizedView = ({ children, show }) => {
|
|
1535
|
+
if (!show) return /* @__PURE__ */ jsx(Fragment, {});
|
|
1536
|
+
return /* @__PURE__ */ jsx(Fragment, { children });
|
|
1537
|
+
};
|
|
1538
|
+
|
|
1539
|
+
// src/core/components/CancelButton/CancelButton.tsx
|
|
1540
|
+
import { Button } from "@mui/material";
|
|
1541
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
1542
|
+
var CancelButton = ({
|
|
1543
|
+
children = "Cancel",
|
|
1544
|
+
variant = "outlined",
|
|
1545
|
+
sx,
|
|
1546
|
+
...rest
|
|
1547
|
+
}) => /* @__PURE__ */ jsx2(Button, { variant, sx: { width: "6rem", ...sx }, ...rest, children });
|
|
1548
|
+
|
|
1549
|
+
// src/core/components/ClearButton/ClearButton.tsx
|
|
1550
|
+
import { Button as Button2 } from "@mui/material";
|
|
1551
|
+
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
1552
|
+
var ClearButton = ({
|
|
1553
|
+
isSubmitting,
|
|
1554
|
+
handleClear,
|
|
1555
|
+
sx,
|
|
1556
|
+
storeKey
|
|
1557
|
+
}) => {
|
|
1558
|
+
const onClick = () => {
|
|
1559
|
+
handleClear();
|
|
1560
|
+
if (storeKey != null) {
|
|
1561
|
+
localStorage.removeItem(storeKey);
|
|
1562
|
+
}
|
|
1563
|
+
};
|
|
1564
|
+
return /* @__PURE__ */ jsx3(
|
|
1565
|
+
Button2,
|
|
1566
|
+
{
|
|
1567
|
+
variant: "outlined",
|
|
1568
|
+
onClick,
|
|
1569
|
+
disabled: isSubmitting,
|
|
1570
|
+
sx,
|
|
1571
|
+
children: "Clear"
|
|
1572
|
+
}
|
|
1573
|
+
);
|
|
1574
|
+
};
|
|
1575
|
+
|
|
1576
|
+
// src/core/components/Containers/SimpleContainer.tsx
|
|
1577
|
+
import { Container } from "@mui/material";
|
|
1578
|
+
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
1579
|
+
var SimpleContainer = ({
|
|
1580
|
+
children,
|
|
1581
|
+
className,
|
|
1582
|
+
sx
|
|
1583
|
+
}) => /* @__PURE__ */ jsx4(Container, { className, sx: { ...sx }, children });
|
|
1584
|
+
|
|
1585
|
+
// src/core/components/FilterButton/FilterButton.tsx
|
|
1586
|
+
import FilterAltIcon from "@mui/icons-material/FilterAlt";
|
|
1587
|
+
import { LoadingButton } from "@mui/lab";
|
|
1588
|
+
import { Badge } from "@mui/material";
|
|
1589
|
+
import { jsx as jsx5 } from "react/jsx-runtime";
|
|
1590
|
+
var FilterButton = ({
|
|
1591
|
+
isSubmitting,
|
|
1592
|
+
show,
|
|
1593
|
+
title,
|
|
1594
|
+
icon,
|
|
1595
|
+
sx,
|
|
1596
|
+
iconSx
|
|
1597
|
+
}) => {
|
|
1598
|
+
return /* @__PURE__ */ jsx5(
|
|
1599
|
+
LoadingButton,
|
|
1600
|
+
{
|
|
1601
|
+
type: "submit",
|
|
1602
|
+
variant: "contained",
|
|
1603
|
+
loading: isSubmitting,
|
|
1604
|
+
disabled: !show,
|
|
1605
|
+
disableRipple: true,
|
|
1606
|
+
color: "primary",
|
|
1607
|
+
sx: {
|
|
1608
|
+
display: "flex",
|
|
1609
|
+
alignItems: "center",
|
|
1610
|
+
...sx
|
|
1611
|
+
},
|
|
1612
|
+
startIcon: /* @__PURE__ */ jsx5(Badge, { color: "error", variant: "standard", children: icon ? icon : /* @__PURE__ */ jsx5(FilterAltIcon, { width: "20", height: "20", sx: iconSx }) }),
|
|
1613
|
+
children: title?.trim() === "" || !title ? "Filter" : title
|
|
1614
|
+
}
|
|
1615
|
+
);
|
|
1616
|
+
};
|
|
1617
|
+
|
|
1618
|
+
// src/core/components/FilterDisplay/FilterChip.tsx
|
|
1619
|
+
import Chip from "@mui/material/Chip";
|
|
1620
|
+
import { memo } from "react";
|
|
1621
|
+
import { jsx as jsx6 } from "react/jsx-runtime";
|
|
1622
|
+
var FilterChip = memo(
|
|
1623
|
+
({
|
|
1624
|
+
fieldKey,
|
|
1625
|
+
filter,
|
|
1626
|
+
onDelete
|
|
1627
|
+
}) => {
|
|
1628
|
+
const hasValue = filter.Value !== null && filter.Value !== void 0 && filter.Value !== "";
|
|
1629
|
+
const label = `${fieldKey.replace("PK", "")}: ${filter.Label}`;
|
|
1630
|
+
return /* @__PURE__ */ jsx6(
|
|
1631
|
+
Chip,
|
|
1632
|
+
{
|
|
1633
|
+
label,
|
|
1634
|
+
variant: hasValue ? "filled" : "outlined",
|
|
1635
|
+
size: "small",
|
|
1636
|
+
onDelete: hasValue ? onDelete : void 0
|
|
1637
|
+
},
|
|
1638
|
+
fieldKey
|
|
1639
|
+
);
|
|
1640
|
+
}
|
|
1641
|
+
);
|
|
1642
|
+
FilterChip.displayName = "FilterChip";
|
|
1643
|
+
|
|
1644
|
+
// src/core/components/FilterDisplay/FilterDisplay.tsx
|
|
1645
|
+
import { Card, CardContent, Typography, Box } from "@mui/material";
|
|
1646
|
+
import { memo as memo2, useMemo } from "react";
|
|
1647
|
+
import { jsx as jsx7, jsxs } from "react/jsx-runtime";
|
|
1648
|
+
var ProgramsFilterDisplay = memo2(
|
|
1649
|
+
(props) => {
|
|
1650
|
+
const { friendlyFilter, onFriendlyFilterChange } = props;
|
|
1651
|
+
const deleteHandlers = useMemo(() => {
|
|
1652
|
+
if (!onFriendlyFilterChange) return {};
|
|
1653
|
+
const handlers = {};
|
|
1654
|
+
for (const key of Object.keys(friendlyFilter)) {
|
|
1655
|
+
handlers[key] = () => onFriendlyFilterChange(key);
|
|
1656
|
+
}
|
|
1657
|
+
return handlers;
|
|
1658
|
+
}, [onFriendlyFilterChange, friendlyFilter]);
|
|
1659
|
+
const chipList = useMemo(() => {
|
|
1660
|
+
return Object.entries(friendlyFilter).map(([key, filter]) => /* @__PURE__ */ jsx7(
|
|
1661
|
+
FilterChip,
|
|
1662
|
+
{
|
|
1663
|
+
fieldKey: key,
|
|
1664
|
+
filter,
|
|
1665
|
+
onDelete: deleteHandlers[key]
|
|
1666
|
+
},
|
|
1667
|
+
key
|
|
1668
|
+
));
|
|
1669
|
+
}, [friendlyFilter, deleteHandlers]);
|
|
1670
|
+
return /* @__PURE__ */ jsx7(Card, { sx: { mb: 2 }, children: /* @__PURE__ */ jsxs(CardContent, { children: [
|
|
1671
|
+
/* @__PURE__ */ jsx7(Typography, { variant: "h6", gutterBottom: true, children: "Active Filters" }),
|
|
1672
|
+
/* @__PURE__ */ jsx7(Box, { display: "flex", gap: 1, flexWrap: "wrap", children: chipList })
|
|
1673
|
+
] }) });
|
|
1674
|
+
}
|
|
1675
|
+
);
|
|
1676
|
+
ProgramsFilterDisplay.displayName = "FilterDisplay";
|
|
1677
|
+
|
|
1678
|
+
// src/core/components/FilterWrapper/FilterWrapper.tsx
|
|
1679
|
+
import ManageSearchIcon from "@mui/icons-material/ManageSearch";
|
|
1680
|
+
import {
|
|
1681
|
+
Box as Box2,
|
|
1682
|
+
Card as Card2,
|
|
1683
|
+
CardContent as CardContent2,
|
|
1684
|
+
CardHeader,
|
|
1685
|
+
Divider,
|
|
1686
|
+
Grid,
|
|
1687
|
+
Typography as Typography2,
|
|
1688
|
+
useTheme
|
|
1689
|
+
} from "@mui/material";
|
|
1690
|
+
import { Fragment as Fragment2, jsx as jsx8, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
1691
|
+
var FilterWrapper = ({
|
|
1692
|
+
children,
|
|
1693
|
+
title,
|
|
1694
|
+
filterCount,
|
|
1695
|
+
cardSx,
|
|
1696
|
+
textSx,
|
|
1697
|
+
icon,
|
|
1698
|
+
iconSx,
|
|
1699
|
+
showCount
|
|
1700
|
+
}) => {
|
|
1701
|
+
const theme = useTheme();
|
|
1702
|
+
return /* @__PURE__ */ jsxs2(
|
|
1703
|
+
Card2,
|
|
1704
|
+
{
|
|
1705
|
+
sx: {
|
|
1706
|
+
position: "relative",
|
|
1707
|
+
borderRadius: "0px",
|
|
1708
|
+
mb: 2,
|
|
1709
|
+
...cardSx
|
|
1710
|
+
},
|
|
1711
|
+
children: [
|
|
1712
|
+
/* @__PURE__ */ jsx8(
|
|
1713
|
+
CardHeader,
|
|
1714
|
+
{
|
|
1715
|
+
sx: {
|
|
1716
|
+
display: "flex",
|
|
1717
|
+
flexWrap: "wrap",
|
|
1718
|
+
p: "1rem",
|
|
1719
|
+
".MuiCardHeader-action": {
|
|
1720
|
+
margin: 0,
|
|
1721
|
+
alignSelf: "center"
|
|
1722
|
+
},
|
|
1723
|
+
alignItems: "center"
|
|
1724
|
+
},
|
|
1725
|
+
title: /* @__PURE__ */ jsxs2(Box2, { sx: { display: "flex", alignItems: "center", gap: 0.5 }, children: [
|
|
1726
|
+
icon ? icon : /* @__PURE__ */ jsx8(
|
|
1727
|
+
ManageSearchIcon,
|
|
1728
|
+
{
|
|
1729
|
+
sx: {
|
|
1730
|
+
height: "2.5rem",
|
|
1731
|
+
color: theme.palette.primary.main,
|
|
1732
|
+
...iconSx
|
|
1733
|
+
}
|
|
1734
|
+
}
|
|
1735
|
+
),
|
|
1736
|
+
/* @__PURE__ */ jsxs2(
|
|
1737
|
+
Typography2,
|
|
1738
|
+
{
|
|
1739
|
+
variant: "h5",
|
|
1740
|
+
sx: {
|
|
1741
|
+
fontWeight: "bold",
|
|
1742
|
+
color: theme.palette.primary.main,
|
|
1743
|
+
...textSx
|
|
1744
|
+
},
|
|
1745
|
+
children: [
|
|
1746
|
+
title ? title : "Filter",
|
|
1747
|
+
" ",
|
|
1748
|
+
showCount ? `(${filterCount ? filterCount : 0})` : /* @__PURE__ */ jsx8(Fragment2, {})
|
|
1749
|
+
]
|
|
1750
|
+
}
|
|
1751
|
+
)
|
|
1752
|
+
] })
|
|
1753
|
+
}
|
|
1754
|
+
),
|
|
1755
|
+
/* @__PURE__ */ jsx8(Divider, {}),
|
|
1756
|
+
/* @__PURE__ */ jsx8(CardContent2, { sx: { py: 2 }, children: /* @__PURE__ */ jsx8(Grid, { container: true, spacing: 2, children }) })
|
|
1757
|
+
]
|
|
1758
|
+
}
|
|
1759
|
+
);
|
|
1760
|
+
};
|
|
1761
|
+
|
|
1762
|
+
// src/core/components/Footer/Footer.tsx
|
|
1763
|
+
import { Box as Box3, Typography as Typography3 } from "@mui/material";
|
|
1764
|
+
import { jsx as jsx9 } from "react/jsx-runtime";
|
|
1765
|
+
var Footer = () => {
|
|
1766
|
+
const currentYear = (/* @__PURE__ */ new Date()).getFullYear();
|
|
1767
|
+
return /* @__PURE__ */ jsx9(
|
|
1768
|
+
Box3,
|
|
1769
|
+
{
|
|
1770
|
+
component: "footer",
|
|
1771
|
+
sx: {
|
|
1772
|
+
py: 2,
|
|
1773
|
+
px: 4,
|
|
1774
|
+
mt: "auto",
|
|
1775
|
+
backgroundColor: (theme) => theme.palette.mode === "light" ? theme.palette.grey[200] : theme.palette.grey[800]
|
|
1776
|
+
},
|
|
1777
|
+
children: /* @__PURE__ */ jsx9(Typography3, { variant: "body2", color: "text.secondary", align: "center", children: `\xA9 Copyright ${currentYear} GN. All rights reserved by Parul University.` })
|
|
1778
|
+
}
|
|
1779
|
+
);
|
|
1780
|
+
};
|
|
1781
|
+
|
|
1782
|
+
// src/core/components/LabelText/LabelText.tsx
|
|
1783
|
+
import { Grid as Grid2, Tooltip, Typography as Typography4 } from "@mui/material";
|
|
1784
|
+
import { jsx as jsx10, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
1785
|
+
var LabelText = ({
|
|
1786
|
+
label,
|
|
1787
|
+
value,
|
|
1788
|
+
gridSize,
|
|
1789
|
+
containerSize,
|
|
1790
|
+
labelSx,
|
|
1791
|
+
valueSx
|
|
1792
|
+
}) => {
|
|
1793
|
+
const defaultGridSize = {
|
|
1794
|
+
labelSize: { xs: 6, sm: 6, md: 6 },
|
|
1795
|
+
valueSize: { xs: 12, sm: 6, md: 6 }
|
|
1796
|
+
};
|
|
1797
|
+
const defaultContainerSize = { xs: 12, sm: 6, md: 6 };
|
|
1798
|
+
const size = gridSize || defaultGridSize;
|
|
1799
|
+
const container = containerSize || defaultContainerSize;
|
|
1800
|
+
return /* @__PURE__ */ jsxs3(
|
|
1801
|
+
Grid2,
|
|
1802
|
+
{
|
|
1803
|
+
size: container,
|
|
1804
|
+
sx: {
|
|
1805
|
+
display: "flex",
|
|
1806
|
+
flexDirection: { xs: "column", sm: "row", md: "row" },
|
|
1807
|
+
"&:hover": { bgcolor: "#efefef", overflow: "hidden" }
|
|
1808
|
+
},
|
|
1809
|
+
children: [
|
|
1810
|
+
/* @__PURE__ */ jsxs3(
|
|
1811
|
+
Grid2,
|
|
1812
|
+
{
|
|
1813
|
+
size: size.labelSize,
|
|
1814
|
+
sx: {
|
|
1815
|
+
padding: "5px",
|
|
1816
|
+
fontSize: "14px",
|
|
1817
|
+
textAlign: { xs: "left", sm: "right", md: "right" },
|
|
1818
|
+
...labelSx
|
|
1819
|
+
},
|
|
1820
|
+
children: [
|
|
1821
|
+
label,
|
|
1822
|
+
" :"
|
|
1823
|
+
]
|
|
1824
|
+
}
|
|
1825
|
+
),
|
|
1826
|
+
/* @__PURE__ */ jsx10(
|
|
1827
|
+
Grid2,
|
|
1828
|
+
{
|
|
1829
|
+
size: size.valueSize,
|
|
1830
|
+
sx: { padding: "5px", display: "flex", flexWrap: "wrap" },
|
|
1831
|
+
children: /* @__PURE__ */ jsx10(Tooltip, { title: value, arrow: true, children: /* @__PURE__ */ jsx10(
|
|
1832
|
+
Typography4,
|
|
1833
|
+
{
|
|
1834
|
+
sx: {
|
|
1835
|
+
fontSize: "14px",
|
|
1836
|
+
wordBreak: "break-word",
|
|
1837
|
+
overflow: "hidden",
|
|
1838
|
+
display: "-webkit-box",
|
|
1839
|
+
textOverflow: "ellipsis",
|
|
1840
|
+
WebkitLineClamp: 2,
|
|
1841
|
+
WebkitBoxOrient: "vertical",
|
|
1842
|
+
...valueSx,
|
|
1843
|
+
color: "#078dee"
|
|
1844
|
+
},
|
|
1845
|
+
children: value ? value : "-"
|
|
1846
|
+
}
|
|
1847
|
+
) })
|
|
1848
|
+
}
|
|
1849
|
+
)
|
|
1850
|
+
]
|
|
1851
|
+
}
|
|
1852
|
+
);
|
|
1853
|
+
};
|
|
1854
|
+
|
|
1855
|
+
// src/core/components/RenderIf/RenderIf.tsx
|
|
1856
|
+
import { Fragment as Fragment3, jsx as jsx11 } from "react/jsx-runtime";
|
|
1857
|
+
var RenderIf = ({
|
|
1858
|
+
show,
|
|
1859
|
+
children
|
|
1860
|
+
}) => {
|
|
1861
|
+
return show ? /* @__PURE__ */ jsx11(Fragment3, { children }) : null;
|
|
1862
|
+
};
|
|
1863
|
+
|
|
1864
|
+
// src/core/components/SectionBox/SectionBox.tsx
|
|
1865
|
+
import { Box as Box4, Divider as Divider2, Grid as Grid3, Stack, Typography as Typography5 } from "@mui/material";
|
|
1866
|
+
import { memo as memo3, useMemo as useMemo2 } from "react";
|
|
1867
|
+
import { Fragment as Fragment4, jsx as jsx12, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
1868
|
+
var getSectionTheme = (variant = "default") => {
|
|
1869
|
+
const themes = {
|
|
1870
|
+
default: {
|
|
1871
|
+
bgcolor: "#faebd7",
|
|
1872
|
+
color: "#925d21"
|
|
1873
|
+
},
|
|
1874
|
+
form: {
|
|
1875
|
+
bgcolor: "#cdced1",
|
|
1876
|
+
color: "black"
|
|
1877
|
+
},
|
|
1878
|
+
info: {
|
|
1879
|
+
bgcolor: "#e3f2fd",
|
|
1880
|
+
color: "#1976d2"
|
|
1881
|
+
},
|
|
1882
|
+
warning: {
|
|
1883
|
+
bgcolor: "#fff3e0",
|
|
1884
|
+
color: "#f57c00"
|
|
1885
|
+
},
|
|
1886
|
+
error: {
|
|
1887
|
+
bgcolor: "#ffebee",
|
|
1888
|
+
color: "#d32f2f"
|
|
1889
|
+
}
|
|
1890
|
+
};
|
|
1891
|
+
return themes[variant];
|
|
1892
|
+
};
|
|
1893
|
+
var SectionBox = memo3(
|
|
1894
|
+
({
|
|
1895
|
+
title,
|
|
1896
|
+
children,
|
|
1897
|
+
spacing = 0,
|
|
1898
|
+
containerSx,
|
|
1899
|
+
titleSx,
|
|
1900
|
+
variant = "default",
|
|
1901
|
+
icon,
|
|
1902
|
+
actions
|
|
1903
|
+
}) => {
|
|
1904
|
+
const themeColors = useMemo2(() => getSectionTheme(variant), [variant]);
|
|
1905
|
+
const headerSx = useMemo2(
|
|
1906
|
+
() => ({
|
|
1907
|
+
px: 1.5,
|
|
1908
|
+
py: 0.1,
|
|
1909
|
+
width: "fit-content",
|
|
1910
|
+
...themeColors,
|
|
1911
|
+
...titleSx
|
|
1912
|
+
}),
|
|
1913
|
+
[themeColors, titleSx]
|
|
1914
|
+
);
|
|
1915
|
+
const contentSx = useMemo2(
|
|
1916
|
+
() => ({
|
|
1917
|
+
padding: "16px",
|
|
1918
|
+
...containerSx
|
|
1919
|
+
}),
|
|
1920
|
+
[containerSx]
|
|
1921
|
+
);
|
|
1922
|
+
return /* @__PURE__ */ jsxs4(Fragment4, { children: [
|
|
1923
|
+
/* @__PURE__ */ jsxs4(Box4, { sx: { display: "flex", flexDirection: "column", width: "100%" }, children: [
|
|
1924
|
+
/* @__PURE__ */ jsxs4(
|
|
1925
|
+
Stack,
|
|
1926
|
+
{
|
|
1927
|
+
direction: "row",
|
|
1928
|
+
justifyContent: "space-between",
|
|
1929
|
+
alignItems: "center",
|
|
1930
|
+
sx: headerSx,
|
|
1931
|
+
children: [
|
|
1932
|
+
/* @__PURE__ */ jsxs4(Stack, { direction: "row", alignItems: "center", spacing: 1, children: [
|
|
1933
|
+
icon,
|
|
1934
|
+
/* @__PURE__ */ jsx12(Typography5, { sx: { fontSize: "15px", fontWeight: 400 }, children: title })
|
|
1935
|
+
] }),
|
|
1936
|
+
actions
|
|
1937
|
+
]
|
|
1938
|
+
}
|
|
1939
|
+
),
|
|
1940
|
+
/* @__PURE__ */ jsx12(Divider2, {})
|
|
1941
|
+
] }),
|
|
1942
|
+
/* @__PURE__ */ jsx12(Grid3, { container: true, spacing, sx: contentSx, children })
|
|
1943
|
+
] });
|
|
1944
|
+
}
|
|
1945
|
+
);
|
|
1946
|
+
|
|
1947
|
+
// src/core/components/SimpleTabs/SimpleTabs.tsx
|
|
1948
|
+
import { TabContext } from "@mui/lab";
|
|
1949
|
+
import { Box as Box5, Tab, Tabs } from "@mui/material";
|
|
1950
|
+
import { useState } from "react";
|
|
1951
|
+
import { jsx as jsx13, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
1952
|
+
var SimpleTabs = ({
|
|
1953
|
+
tabs,
|
|
1954
|
+
defaultValue = 1,
|
|
1955
|
+
onTabChange,
|
|
1956
|
+
children,
|
|
1957
|
+
tabSx,
|
|
1958
|
+
tabsSx
|
|
1959
|
+
}) => {
|
|
1960
|
+
const [value, setValue] = useState(defaultValue);
|
|
1961
|
+
const handleChange = (event, newValue) => {
|
|
1962
|
+
setValue(newValue);
|
|
1963
|
+
if (onTabChange) onTabChange(newValue);
|
|
1964
|
+
};
|
|
1965
|
+
return /* @__PURE__ */ jsxs5(TabContext, { value, children: [
|
|
1966
|
+
/* @__PURE__ */ jsx13(Box5, { sx: { borderBottom: 1, borderColor: "divider", width: "100%" }, children: /* @__PURE__ */ jsx13(
|
|
1967
|
+
Tabs,
|
|
1968
|
+
{
|
|
1969
|
+
value,
|
|
1970
|
+
onChange: handleChange,
|
|
1971
|
+
sx: { px: 2, py: 0, ...tabsSx },
|
|
1972
|
+
children: tabs.map((tab) => /* @__PURE__ */ jsx13(
|
|
1973
|
+
Tab,
|
|
1974
|
+
{
|
|
1975
|
+
label: tab.label,
|
|
1976
|
+
value: tab.value,
|
|
1977
|
+
disabled: tab.permission === false,
|
|
1978
|
+
sx: { fontSize: "1rem", ...tabSx }
|
|
1979
|
+
},
|
|
1980
|
+
tab.value
|
|
1981
|
+
))
|
|
1982
|
+
}
|
|
1983
|
+
) }),
|
|
1984
|
+
children
|
|
1985
|
+
] });
|
|
1986
|
+
};
|
|
1987
|
+
|
|
1988
|
+
// src/core/components/SubmitButton/SubmitButton.tsx
|
|
1989
|
+
import { LoadingButton as LoadingButton2 } from "@mui/lab";
|
|
1990
|
+
import { jsx as jsx14 } from "react/jsx-runtime";
|
|
1991
|
+
var SubmitButton = ({
|
|
1992
|
+
loading = false,
|
|
1993
|
+
...rest
|
|
1994
|
+
}) => /* @__PURE__ */ jsx14(
|
|
1995
|
+
LoadingButton2,
|
|
1996
|
+
{
|
|
1997
|
+
loading,
|
|
1998
|
+
variant: "contained",
|
|
1999
|
+
color: "primary",
|
|
2000
|
+
type: "submit",
|
|
2001
|
+
...rest,
|
|
2002
|
+
sx: { fontWeight: 400 },
|
|
2003
|
+
children: "Submit"
|
|
2004
|
+
}
|
|
2005
|
+
);
|
|
2006
|
+
|
|
2007
|
+
// src/core/components/WithRef/WithRef.tsx
|
|
2008
|
+
import { forwardRef } from "react";
|
|
2009
|
+
function withDataModal(component) {
|
|
2010
|
+
return forwardRef(
|
|
2011
|
+
(props, ref) => component({ ...props, ref })
|
|
2012
|
+
);
|
|
2013
|
+
}
|
|
2014
|
+
|
|
2015
|
+
// src/core/config.ts
|
|
2016
|
+
var Config = {
|
|
2017
|
+
defaultPageSize: 20,
|
|
2018
|
+
apiBaseUrl: "http://localhost:5143"
|
|
2019
|
+
// apiBaseUrl: 'http://192.168.1.246:5143',
|
|
2020
|
+
};
|
|
2021
|
+
var dateTimePatterns = {
|
|
2022
|
+
dateTime: "DD MMM YYYY h:mm A",
|
|
2023
|
+
// 17 Apr 2022 12:00 am
|
|
2024
|
+
date: "DD MMM YYYY",
|
|
2025
|
+
// 17 Apr 2022
|
|
2026
|
+
month_year_short_format: "MMM YYYY",
|
|
2027
|
+
month_year_full_format: "MMMM YYYY",
|
|
2028
|
+
year: "YYYY",
|
|
2029
|
+
time: "h:mm a",
|
|
2030
|
+
// 12:00 am
|
|
2031
|
+
split: {
|
|
2032
|
+
dateTime: "DD/MM/YYYY h:mm A",
|
|
2033
|
+
// 17/04/2022 12:00 am
|
|
2034
|
+
date: "DD/MM/YYYY"
|
|
2035
|
+
// 17/04/2022
|
|
2036
|
+
},
|
|
2037
|
+
paramCase: {
|
|
2038
|
+
dateTime: "DD-MM-YYYY h:mm A",
|
|
2039
|
+
// 17-04-2022 12:00 am
|
|
2040
|
+
date: "DD-MM-YYYY",
|
|
2041
|
+
// 17-04-2022
|
|
2042
|
+
dateReverse: "YYYY-MM-DD",
|
|
2043
|
+
// 2022-04-17 for compare date
|
|
2044
|
+
MonthYear: "MMM-YYYY"
|
|
2045
|
+
}
|
|
2046
|
+
};
|
|
2047
|
+
|
|
2048
|
+
// src/core/hooks/useApiClient.ts
|
|
2049
|
+
import { useMemo as useMemo3 } from "react";
|
|
2050
|
+
function useApiClient(config) {
|
|
2051
|
+
return useMemo3(
|
|
2052
|
+
() => createApiClient(config),
|
|
2053
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
2054
|
+
[
|
|
2055
|
+
config.baseURL,
|
|
2056
|
+
config.timeout,
|
|
2057
|
+
config.correlationIdPrefix,
|
|
2058
|
+
config.includeCorrelationId,
|
|
2059
|
+
config.tokenStorageKey,
|
|
2060
|
+
config.authToken,
|
|
2061
|
+
config.requestInterceptors,
|
|
2062
|
+
config.responseInterceptors,
|
|
2063
|
+
config.errorInterceptors
|
|
2064
|
+
]
|
|
2065
|
+
);
|
|
2066
|
+
}
|
|
2067
|
+
|
|
2068
|
+
// src/core/hooks/useFormErrorHandler.ts
|
|
2069
|
+
import { useCallback as useCallback2 } from "react";
|
|
2070
|
+
import { toast } from "sonner";
|
|
2071
|
+
var useFormErrorHandler = ({
|
|
2072
|
+
setError,
|
|
2073
|
+
successMessage = {
|
|
2074
|
+
create: "Created successfully",
|
|
2075
|
+
update: "Updated successfully"
|
|
2076
|
+
},
|
|
2077
|
+
errorMessage = {
|
|
2078
|
+
noChanges: "No changes were made",
|
|
2079
|
+
general: "Failed to save. Please try again."
|
|
2080
|
+
}
|
|
2081
|
+
}) => {
|
|
2082
|
+
const getFieldError = useCallback2(
|
|
2083
|
+
(fields, fieldName) => {
|
|
2084
|
+
if (!fields || !fields[fieldName]) return void 0;
|
|
2085
|
+
const fieldError = fields[fieldName];
|
|
2086
|
+
if (typeof fieldError === "string") {
|
|
2087
|
+
return fieldError;
|
|
2088
|
+
}
|
|
2089
|
+
if (Array.isArray(fieldError)) {
|
|
2090
|
+
return fieldError.join(", ");
|
|
2091
|
+
}
|
|
2092
|
+
if (typeof fieldError === "object" && "message" in fieldError) {
|
|
2093
|
+
return fieldError.message;
|
|
2094
|
+
}
|
|
2095
|
+
return void 0;
|
|
2096
|
+
},
|
|
2097
|
+
[]
|
|
2098
|
+
);
|
|
2099
|
+
const handleSuccess = useCallback2(
|
|
2100
|
+
(isEditing, rowsAffected) => {
|
|
2101
|
+
if (rowsAffected !== void 0 && rowsAffected > 0) {
|
|
2102
|
+
toast.success(
|
|
2103
|
+
isEditing ? successMessage.update : successMessage.create
|
|
2104
|
+
);
|
|
2105
|
+
return true;
|
|
2106
|
+
} else if (rowsAffected === 0) {
|
|
2107
|
+
toast.error(errorMessage.noChanges);
|
|
2108
|
+
return false;
|
|
2109
|
+
}
|
|
2110
|
+
toast.success(isEditing ? successMessage.update : successMessage.create);
|
|
2111
|
+
return true;
|
|
2112
|
+
},
|
|
2113
|
+
[successMessage, errorMessage]
|
|
2114
|
+
);
|
|
2115
|
+
const handleError = useCallback2(
|
|
2116
|
+
(processedError) => {
|
|
2117
|
+
if (processedError.type === "validation_error" && processedError.errors && setError) {
|
|
2118
|
+
Object.keys(processedError.errors).forEach((fieldName) => {
|
|
2119
|
+
const fieldError = getFieldError(processedError.errors, fieldName);
|
|
2120
|
+
if (fieldError) {
|
|
2121
|
+
setError(fieldName, {
|
|
2122
|
+
type: "server",
|
|
2123
|
+
message: fieldError
|
|
2124
|
+
});
|
|
2125
|
+
}
|
|
2126
|
+
});
|
|
2127
|
+
toast.error(
|
|
2128
|
+
processedError.title || "Please check the form for validation errors"
|
|
2129
|
+
);
|
|
2130
|
+
} else {
|
|
2131
|
+
toast.error(processedError.title || errorMessage.general);
|
|
2132
|
+
}
|
|
2133
|
+
},
|
|
2134
|
+
[errorMessage.general, getFieldError, setError]
|
|
2135
|
+
);
|
|
2136
|
+
return {
|
|
2137
|
+
handleSuccess,
|
|
2138
|
+
handleError
|
|
2139
|
+
};
|
|
2140
|
+
};
|
|
2141
|
+
var useDeleteHandler = ({
|
|
2142
|
+
successMessage = "Deleted successfully",
|
|
2143
|
+
errorMessage = "Failed to delete. Please try again."
|
|
2144
|
+
} = {}) => {
|
|
2145
|
+
return useFormErrorHandler({
|
|
2146
|
+
successMessage: {
|
|
2147
|
+
create: successMessage,
|
|
2148
|
+
// Not used for delete, but required for type
|
|
2149
|
+
update: successMessage
|
|
2150
|
+
},
|
|
2151
|
+
errorMessage: {
|
|
2152
|
+
noChanges: "No changes were made",
|
|
2153
|
+
// Not typically used for delete
|
|
2154
|
+
general: errorMessage
|
|
2155
|
+
}
|
|
2156
|
+
// setError is omitted (undefined) for delete operations
|
|
2157
|
+
});
|
|
2158
|
+
};
|
|
2159
|
+
|
|
2160
|
+
// src/core/utils/CacheUtility/index.ts
|
|
2161
|
+
import { useQueryClient } from "@tanstack/react-query";
|
|
2162
|
+
import { useMemo as useMemo4 } from "react";
|
|
2163
|
+
var CacheUtility = class {
|
|
2164
|
+
constructor(queryClient) {
|
|
2165
|
+
this.queryClient = queryClient;
|
|
2166
|
+
}
|
|
2167
|
+
/**
|
|
2168
|
+
* Get cached data using only the queryKey from query factory
|
|
2169
|
+
*/
|
|
2170
|
+
getCachedData(queryKey) {
|
|
2171
|
+
return this.queryClient.getQueryData(queryKey);
|
|
2172
|
+
}
|
|
2173
|
+
/**
|
|
2174
|
+
* Get cached data with transformation using select function
|
|
2175
|
+
*/
|
|
2176
|
+
getCachedDataWithSelect(queryKey, select) {
|
|
2177
|
+
const cachedData = this.queryClient.getQueryData(queryKey);
|
|
2178
|
+
if (cachedData === void 0) {
|
|
2179
|
+
return void 0;
|
|
2180
|
+
}
|
|
2181
|
+
return select(cachedData);
|
|
2182
|
+
}
|
|
2183
|
+
};
|
|
2184
|
+
function useCacheUtility() {
|
|
2185
|
+
const queryClient = useQueryClient();
|
|
2186
|
+
return useMemo4(() => new CacheUtility(queryClient), [queryClient]);
|
|
2187
|
+
}
|
|
2188
|
+
|
|
2189
|
+
// src/core/utils/watch/core.ts
|
|
2190
|
+
import { useWatch } from "react-hook-form";
|
|
2191
|
+
var useWatchForm = (control) => useWatch({ control });
|
|
2192
|
+
var useWatchField = (control, name) => useWatch({ control, name });
|
|
2193
|
+
var useWatchFields = (control, names) => useWatch({ control, name: names });
|
|
2194
|
+
|
|
2195
|
+
// src/core/utils/watch/utilities.ts
|
|
2196
|
+
import { useEffect, useMemo as useMemo5, useState as useState2 } from "react";
|
|
2197
|
+
import { useWatch as useWatch2 } from "react-hook-form";
|
|
2198
|
+
var useWatchTransform = (control, name, transform) => {
|
|
2199
|
+
const value = useWatch2({ control, name });
|
|
2200
|
+
return useMemo5(() => transform(value), [value, transform]);
|
|
2201
|
+
};
|
|
2202
|
+
var useWatchDefault = (control, name, defaultValue) => {
|
|
2203
|
+
const value = useWatch2({ control, name });
|
|
2204
|
+
return value ?? defaultValue;
|
|
2205
|
+
};
|
|
2206
|
+
var useWatchBoolean = (control, name, defaultValue = false) => {
|
|
2207
|
+
const value = useWatch2({ control, name });
|
|
2208
|
+
return Boolean(value ?? defaultValue);
|
|
2209
|
+
};
|
|
2210
|
+
var useWatchBatch = (control, fields) => {
|
|
2211
|
+
const values = useWatch2({ control, name: fields });
|
|
2212
|
+
return useMemo5(() => {
|
|
2213
|
+
const result = {};
|
|
2214
|
+
fields.forEach((field, index) => {
|
|
2215
|
+
result[field] = values[index];
|
|
2216
|
+
});
|
|
2217
|
+
return result;
|
|
2218
|
+
}, [values, fields]);
|
|
2219
|
+
};
|
|
2220
|
+
var useWatchConditional = (control, name, shouldWatch, fallback) => {
|
|
2221
|
+
const activeValue = useWatch2({
|
|
2222
|
+
control,
|
|
2223
|
+
name,
|
|
2224
|
+
disabled: !shouldWatch
|
|
2225
|
+
});
|
|
2226
|
+
return shouldWatch ? activeValue : fallback;
|
|
2227
|
+
};
|
|
2228
|
+
var useWatchDebounced = (control, name, delay = 300) => {
|
|
2229
|
+
const value = useWatch2({ control, name });
|
|
2230
|
+
const [debouncedValue, setDebouncedValue] = useState2(value);
|
|
2231
|
+
useEffect(() => {
|
|
2232
|
+
const timer = setTimeout(() => {
|
|
2233
|
+
setDebouncedValue(value);
|
|
2234
|
+
}, delay);
|
|
2235
|
+
return () => clearTimeout(timer);
|
|
2236
|
+
}, [value, delay]);
|
|
2237
|
+
return debouncedValue;
|
|
2238
|
+
};
|
|
2239
|
+
var useWatchSelector = (control, name, selector, deps = []) => {
|
|
2240
|
+
const value = useWatch2({ control, name });
|
|
2241
|
+
return useMemo5(
|
|
2242
|
+
() => selector(value),
|
|
2243
|
+
[value, selector, ...deps]
|
|
2244
|
+
// eslint-disable-line react-hooks/exhaustive-deps
|
|
2245
|
+
);
|
|
2246
|
+
};
|
|
2247
|
+
|
|
2248
|
+
// src/core/utils/watch/index.ts
|
|
2249
|
+
var typedWatch = {
|
|
2250
|
+
// === CORE FUNCTIONS ===
|
|
2251
|
+
/** Watch entire form */
|
|
2252
|
+
form: useWatchForm,
|
|
2253
|
+
/** Watch single field */
|
|
2254
|
+
field: useWatchField,
|
|
2255
|
+
/** Watch multiple fields */
|
|
2256
|
+
fields: useWatchFields,
|
|
2257
|
+
// === UTILITY FUNCTIONS ===
|
|
2258
|
+
/** Watch with transformation */
|
|
2259
|
+
transform: useWatchTransform,
|
|
2260
|
+
/** Watch with default value */
|
|
2261
|
+
withDefault: useWatchDefault,
|
|
2262
|
+
/** Watch as boolean */
|
|
2263
|
+
boolean: useWatchBoolean,
|
|
2264
|
+
/** Watch multiple with custom keys */
|
|
2265
|
+
batch: useWatchBatch,
|
|
2266
|
+
/** Watch conditionally */
|
|
2267
|
+
conditional: useWatchConditional,
|
|
2268
|
+
/** Watch with debouncing */
|
|
2269
|
+
debounced: useWatchDebounced,
|
|
2270
|
+
/** Watch with selector */
|
|
2271
|
+
selector: useWatchSelector
|
|
2272
|
+
};
|
|
2273
|
+
|
|
2274
|
+
// src/core/utils/calculateFilterCount.ts
|
|
2275
|
+
var calculateFilterCount = (model) => Object.values(model).filter(
|
|
2276
|
+
(v) => v !== null && v !== void 0 && String(v).trim() !== ""
|
|
2277
|
+
).length;
|
|
2278
|
+
|
|
2279
|
+
// src/core/utils/format-time.ts
|
|
2280
|
+
import dayjs from "dayjs";
|
|
2281
|
+
import duration from "dayjs/plugin/duration";
|
|
2282
|
+
import relativeTime from "dayjs/plugin/relativeTime";
|
|
2283
|
+
dayjs.extend(duration);
|
|
2284
|
+
dayjs.extend(relativeTime);
|
|
2285
|
+
var formatPatterns = {
|
|
2286
|
+
dateTime: "DD MMM YYYY h:mm A",
|
|
2287
|
+
// 17 Apr 2022 12:00 am
|
|
2288
|
+
date: "DD MMM YYYY",
|
|
2289
|
+
// 17 Apr 2022
|
|
2290
|
+
month_year_short_format: "MMM YYYY",
|
|
2291
|
+
month_year_full_format: "MMMM YYYY",
|
|
2292
|
+
year: "YYYY",
|
|
2293
|
+
time: "h:mm a",
|
|
2294
|
+
// 12:00 am
|
|
2295
|
+
split: {
|
|
2296
|
+
dateTime: "DD/MM/YYYY h:mm A",
|
|
2297
|
+
// 17/04/2022 12:00 am
|
|
2298
|
+
date: "DD/MM/YYYY"
|
|
2299
|
+
// 17/04/2022
|
|
2300
|
+
},
|
|
2301
|
+
paramCase: {
|
|
2302
|
+
dateTime: "DD-MM-YYYY h:mm A",
|
|
2303
|
+
// 17-04-2022 12:00 am
|
|
2304
|
+
date: "DD-MM-YYYY",
|
|
2305
|
+
// 17-04-2022
|
|
2306
|
+
dateReverse: "YYYY-MM-DD",
|
|
2307
|
+
// 2022-04-17 for compare date
|
|
2308
|
+
MonthYear: "MMM-YYYY"
|
|
2309
|
+
}
|
|
2310
|
+
};
|
|
2311
|
+
var isValidDate = (date) => date !== null && date !== void 0 && dayjs(date).isValid();
|
|
2312
|
+
function today(template) {
|
|
2313
|
+
return dayjs(/* @__PURE__ */ new Date()).startOf("day").format(template);
|
|
2314
|
+
}
|
|
2315
|
+
function fDateTime(date, template) {
|
|
2316
|
+
if (!isValidDate(date)) {
|
|
2317
|
+
return "Invalid date";
|
|
2318
|
+
}
|
|
2319
|
+
return dayjs(date).format(template ?? formatPatterns.dateTime);
|
|
2320
|
+
}
|
|
2321
|
+
function fDate(date, template) {
|
|
2322
|
+
if (!isValidDate(date)) {
|
|
2323
|
+
return "Invalid date";
|
|
2324
|
+
}
|
|
2325
|
+
return dayjs(date).format(template ?? formatPatterns.date);
|
|
2326
|
+
}
|
|
2327
|
+
function fTime(date, template) {
|
|
2328
|
+
if (!isValidDate(date)) {
|
|
2329
|
+
return "Invalid date";
|
|
2330
|
+
}
|
|
2331
|
+
return dayjs(date).format(template ?? formatPatterns.time);
|
|
2332
|
+
}
|
|
2333
|
+
function fTimestamp(date) {
|
|
2334
|
+
if (!isValidDate(date)) {
|
|
2335
|
+
return "Invalid date";
|
|
2336
|
+
}
|
|
2337
|
+
return dayjs(date).valueOf();
|
|
2338
|
+
}
|
|
2339
|
+
function fToNow(date) {
|
|
2340
|
+
if (!isValidDate(date)) {
|
|
2341
|
+
return "Invalid date";
|
|
2342
|
+
}
|
|
2343
|
+
return dayjs(date).toNow(true);
|
|
2344
|
+
}
|
|
2345
|
+
function fIsBetween(inputDate, startDate, endDate) {
|
|
2346
|
+
if (!isValidDate(inputDate) || !isValidDate(startDate) || !isValidDate(endDate)) {
|
|
2347
|
+
return false;
|
|
2348
|
+
}
|
|
2349
|
+
const formattedInputDate = fTimestamp(inputDate);
|
|
2350
|
+
const formattedStartDate = fTimestamp(startDate);
|
|
2351
|
+
const formattedEndDate = fTimestamp(endDate);
|
|
2352
|
+
if (formattedInputDate === "Invalid date" || formattedStartDate === "Invalid date" || formattedEndDate === "Invalid date") {
|
|
2353
|
+
return false;
|
|
2354
|
+
}
|
|
2355
|
+
return formattedInputDate >= formattedStartDate && formattedInputDate <= formattedEndDate;
|
|
2356
|
+
}
|
|
2357
|
+
function fIsAfter(startDate, endDate) {
|
|
2358
|
+
if (!isValidDate(startDate) || !isValidDate(endDate)) {
|
|
2359
|
+
return false;
|
|
2360
|
+
}
|
|
2361
|
+
return dayjs(startDate).isAfter(endDate);
|
|
2362
|
+
}
|
|
2363
|
+
function fIsSame(startDate, endDate, unitToCompare) {
|
|
2364
|
+
if (!isValidDate(startDate) || !isValidDate(endDate)) {
|
|
2365
|
+
return false;
|
|
2366
|
+
}
|
|
2367
|
+
return dayjs(startDate).isSame(endDate, unitToCompare ?? "year");
|
|
2368
|
+
}
|
|
2369
|
+
function fDateRangeShortLabel(startDate, endDate, initial) {
|
|
2370
|
+
if (!isValidDate(startDate) || !isValidDate(endDate) || fIsAfter(startDate, endDate)) {
|
|
2371
|
+
return "Invalid date";
|
|
2372
|
+
}
|
|
2373
|
+
let label = `${fDate(startDate)} - ${fDate(endDate)}`;
|
|
2374
|
+
if (initial) {
|
|
2375
|
+
return label;
|
|
2376
|
+
}
|
|
2377
|
+
const isSameYear = fIsSame(startDate, endDate, "year");
|
|
2378
|
+
const isSameMonth = fIsSame(startDate, endDate, "month");
|
|
2379
|
+
const isSameDay = fIsSame(startDate, endDate, "day");
|
|
2380
|
+
if (isSameYear && !isSameMonth) {
|
|
2381
|
+
label = `${fDate(startDate, "DD MMM")} - ${fDate(endDate)}`;
|
|
2382
|
+
} else if (isSameYear && isSameMonth && !isSameDay) {
|
|
2383
|
+
label = `${fDate(startDate, "DD")} - ${fDate(endDate)}`;
|
|
2384
|
+
} else if (isSameYear && isSameMonth && isSameDay) {
|
|
2385
|
+
label = `${fDate(endDate)}`;
|
|
2386
|
+
}
|
|
2387
|
+
return label;
|
|
2388
|
+
}
|
|
2389
|
+
function fAdd({
|
|
2390
|
+
years = 0,
|
|
2391
|
+
months = 0,
|
|
2392
|
+
days = 0,
|
|
2393
|
+
hours = 0,
|
|
2394
|
+
minutes = 0,
|
|
2395
|
+
seconds = 0,
|
|
2396
|
+
milliseconds = 0
|
|
2397
|
+
}) {
|
|
2398
|
+
const result = dayjs().add(
|
|
2399
|
+
dayjs.duration({
|
|
2400
|
+
years,
|
|
2401
|
+
months,
|
|
2402
|
+
days,
|
|
2403
|
+
hours,
|
|
2404
|
+
minutes,
|
|
2405
|
+
seconds,
|
|
2406
|
+
milliseconds
|
|
2407
|
+
})
|
|
2408
|
+
).format();
|
|
2409
|
+
return result;
|
|
2410
|
+
}
|
|
2411
|
+
function fSub({
|
|
2412
|
+
years = 0,
|
|
2413
|
+
months = 0,
|
|
2414
|
+
days = 0,
|
|
2415
|
+
hours = 0,
|
|
2416
|
+
minutes = 0,
|
|
2417
|
+
seconds = 0,
|
|
2418
|
+
milliseconds = 0
|
|
2419
|
+
}) {
|
|
2420
|
+
const result = dayjs().subtract(
|
|
2421
|
+
dayjs.duration({
|
|
2422
|
+
years,
|
|
2423
|
+
months,
|
|
2424
|
+
days,
|
|
2425
|
+
hours,
|
|
2426
|
+
minutes,
|
|
2427
|
+
seconds,
|
|
2428
|
+
milliseconds
|
|
2429
|
+
})
|
|
2430
|
+
).format();
|
|
2431
|
+
return result;
|
|
2432
|
+
}
|
|
2433
|
+
|
|
2434
|
+
// src/core/utils/getEmptyObject.ts
|
|
2435
|
+
function getEmptyObject(data, defaultValues = {}) {
|
|
2436
|
+
const obj = {};
|
|
2437
|
+
for (const key of Object.keys(data)) {
|
|
2438
|
+
const value = data[key];
|
|
2439
|
+
const type = typeof value;
|
|
2440
|
+
if (type === "number") {
|
|
2441
|
+
obj[key] = 0;
|
|
2442
|
+
} else if (type === "string" || type === "boolean") {
|
|
2443
|
+
obj[key] = null;
|
|
2444
|
+
} else if (value instanceof Date) {
|
|
2445
|
+
obj[key] = null;
|
|
2446
|
+
} else {
|
|
2447
|
+
obj[key] = null;
|
|
2448
|
+
}
|
|
2449
|
+
}
|
|
2450
|
+
return { ...obj, ...defaultValues };
|
|
2451
|
+
}
|
|
2452
|
+
|
|
2453
|
+
// src/core/utils/useStableRowCount.ts
|
|
2454
|
+
import { useRef, useMemo as useMemo6 } from "react";
|
|
2455
|
+
function useStableRowCount(currentTotal) {
|
|
2456
|
+
const rowCountRef = useRef(currentTotal || 0);
|
|
2457
|
+
const stableRowCount = useMemo6(() => {
|
|
2458
|
+
if (currentTotal !== void 0) {
|
|
2459
|
+
rowCountRef.current = currentTotal;
|
|
2460
|
+
}
|
|
2461
|
+
return rowCountRef.current;
|
|
2462
|
+
}, [currentTotal]);
|
|
2463
|
+
return stableRowCount;
|
|
2464
|
+
}
|
|
2465
|
+
|
|
2466
|
+
export {
|
|
2467
|
+
generateCorrelationId,
|
|
2468
|
+
RequestManager,
|
|
2469
|
+
ApiClient,
|
|
2470
|
+
createApiClient,
|
|
2471
|
+
getGlobalApiClient,
|
|
2472
|
+
initializeGlobalApiClient,
|
|
2473
|
+
setGlobalApiClient,
|
|
2474
|
+
resetGlobalApiClient,
|
|
2475
|
+
CancelToken,
|
|
2476
|
+
useValidationErrors,
|
|
2477
|
+
AuthorizedView,
|
|
2478
|
+
CancelButton,
|
|
2479
|
+
ClearButton,
|
|
2480
|
+
SimpleContainer,
|
|
2481
|
+
FilterButton,
|
|
2482
|
+
FilterChip,
|
|
2483
|
+
ProgramsFilterDisplay,
|
|
2484
|
+
FilterWrapper,
|
|
2485
|
+
Footer,
|
|
2486
|
+
LabelText,
|
|
2487
|
+
RenderIf,
|
|
2488
|
+
SectionBox,
|
|
2489
|
+
SimpleTabs,
|
|
2490
|
+
SubmitButton,
|
|
2491
|
+
withDataModal,
|
|
2492
|
+
Config,
|
|
2493
|
+
dateTimePatterns,
|
|
2494
|
+
useApiClient,
|
|
2495
|
+
useFormErrorHandler,
|
|
2496
|
+
useDeleteHandler,
|
|
2497
|
+
CacheUtility,
|
|
2498
|
+
useCacheUtility,
|
|
2499
|
+
useWatchForm,
|
|
2500
|
+
useWatchField,
|
|
2501
|
+
useWatchFields,
|
|
2502
|
+
useWatchTransform,
|
|
2503
|
+
useWatchDefault,
|
|
2504
|
+
useWatchBoolean,
|
|
2505
|
+
useWatchBatch,
|
|
2506
|
+
useWatchConditional,
|
|
2507
|
+
useWatchDebounced,
|
|
2508
|
+
useWatchSelector,
|
|
2509
|
+
typedWatch,
|
|
2510
|
+
calculateFilterCount,
|
|
2511
|
+
formatPatterns,
|
|
2512
|
+
today,
|
|
2513
|
+
fDateTime,
|
|
2514
|
+
fDate,
|
|
2515
|
+
fTime,
|
|
2516
|
+
fTimestamp,
|
|
2517
|
+
fToNow,
|
|
2518
|
+
fIsBetween,
|
|
2519
|
+
fIsAfter,
|
|
2520
|
+
fIsSame,
|
|
2521
|
+
fDateRangeShortLabel,
|
|
2522
|
+
fAdd,
|
|
2523
|
+
fSub,
|
|
2524
|
+
getEmptyObject,
|
|
2525
|
+
useStableRowCount
|
|
2526
|
+
};
|
|
2527
|
+
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vc3JjL2NvcmUvYXBpL0NvcnJlbGF0aW9uSWRHZW5lcmF0b3IudHMiLCAiLi4vc3JjL2NvcmUvYXBpL0Vycm9ycy9FcnJvck5vcm1hbGl6ZXIudHMiLCAiLi4vc3JjL2NvcmUvYXBpL0ludGVyY2VwdG9ycy9JbnRlcmNlcHRvck1hbmFnZXIudHMiLCAiLi4vc3JjL2NvcmUvYXBpL1JlcXVlc3RNYW5hZ2VyLnRzIiwgIi4uL3NyYy9jb3JlL2FwaS9SZXRyeS9SZXRyeUhhbmRsZXIudHMiLCAiLi4vc3JjL2NvcmUvYXBpL1NpZ25hbHMvU2lnbmFsTWFuYWdlci50cyIsICIuLi9zcmMvY29yZS9hcGkvVXRpbHMvUmVzcG9uc2VQYXJzZXIudHMiLCAiLi4vc3JjL2NvcmUvYXBpL1V0aWxzL1VybEJ1aWxkZXIudHMiLCAiLi4vc3JjL2NvcmUvYXBpL0FwaUNsaWVudC50cyIsICIuLi9zcmMvY29yZS9hcGkvY3JlYXRlQXBpQ2xpZW50LnRzIiwgIi4uL3NyYy9jb3JlL2FwaS90eXBlcy9DYW5jZWxUb2tlbi50cyIsICIuLi9zcmMvY29yZS9hcGkvdXNlVmFsaWRhdGlvbkVycm9ycy50cyIsICIuLi9zcmMvY29yZS9jb21wb25lbnRzL0F1dGhvcml6ZWRWaWV3L0F1dGhvcml6ZWRWaWV3LnRzeCIsICIuLi9zcmMvY29yZS9jb21wb25lbnRzL0NhbmNlbEJ1dHRvbi9DYW5jZWxCdXR0b24udHN4IiwgIi4uL3NyYy9jb3JlL2NvbXBvbmVudHMvQ2xlYXJCdXR0b24vQ2xlYXJCdXR0b24udHN4IiwgIi4uL3NyYy9jb3JlL2NvbXBvbmVudHMvQ29udGFpbmVycy9TaW1wbGVDb250YWluZXIudHN4IiwgIi4uL3NyYy9jb3JlL2NvbXBvbmVudHMvRmlsdGVyQnV0dG9uL0ZpbHRlckJ1dHRvbi50c3giLCAiLi4vc3JjL2NvcmUvY29tcG9uZW50cy9GaWx0ZXJEaXNwbGF5L0ZpbHRlckNoaXAudHN4IiwgIi4uL3NyYy9jb3JlL2NvbXBvbmVudHMvRmlsdGVyRGlzcGxheS9GaWx0ZXJEaXNwbGF5LnRzeCIsICIuLi9zcmMvY29yZS9jb21wb25lbnRzL0ZpbHRlcldyYXBwZXIvRmlsdGVyV3JhcHBlci50c3giLCAiLi4vc3JjL2NvcmUvY29tcG9uZW50cy9Gb290ZXIvRm9vdGVyLnRzeCIsICIuLi9zcmMvY29yZS9jb21wb25lbnRzL0xhYmVsVGV4dC9MYWJlbFRleHQudHN4IiwgIi4uL3NyYy9jb3JlL2NvbXBvbmVudHMvUmVuZGVySWYvUmVuZGVySWYudHN4IiwgIi4uL3NyYy9jb3JlL2NvbXBvbmVudHMvU2VjdGlvbkJveC9TZWN0aW9uQm94LnRzeCIsICIuLi9zcmMvY29yZS9jb21wb25lbnRzL1NpbXBsZVRhYnMvU2ltcGxlVGFicy50c3giLCAiLi4vc3JjL2NvcmUvY29tcG9uZW50cy9TdWJtaXRCdXR0b24vU3VibWl0QnV0dG9uLnRzeCIsICIuLi9zcmMvY29yZS9jb21wb25lbnRzL1dpdGhSZWYvV2l0aFJlZi50c3giLCAiLi4vc3JjL2NvcmUvY29uZmlnLnRzIiwgIi4uL3NyYy9jb3JlL2hvb2tzL3VzZUFwaUNsaWVudC50cyIsICIuLi9zcmMvY29yZS9ob29rcy91c2VGb3JtRXJyb3JIYW5kbGVyLnRzIiwgIi4uL3NyYy9jb3JlL3V0aWxzL0NhY2hlVXRpbGl0eS9pbmRleC50cyIsICIuLi9zcmMvY29yZS91dGlscy93YXRjaC9jb3JlLnRzIiwgIi4uL3NyYy9jb3JlL3V0aWxzL3dhdGNoL3V0aWxpdGllcy50cyIsICIuLi9zcmMvY29yZS91dGlscy93YXRjaC9pbmRleC50cyIsICIuLi9zcmMvY29yZS91dGlscy9jYWxjdWxhdGVGaWx0ZXJDb3VudC50cyIsICIuLi9zcmMvY29yZS91dGlscy9mb3JtYXQtdGltZS50cyIsICIuLi9zcmMvY29yZS91dGlscy9nZXRFbXB0eU9iamVjdC50cyIsICIuLi9zcmMvY29yZS91dGlscy91c2VTdGFibGVSb3dDb3VudC50cyJdLAogICJzb3VyY2VzQ29udGVudCI6IFsiLyoqXG4gKiBAZmlsZW92ZXJ2aWV3IFV0aWxpdGllcyBmb3IgZ2VuZXJhdGluZyBjb3JyZWxhdGlvbiBJRHMgZm9yIGRpc3RyaWJ1dGVkIHJlcXVlc3QgdHJhY2luZy5cbiAqXG4gKiBDb3JyZWxhdGlvbiBJRHMgYXJlIHVuaXF1ZSBpZGVudGlmaWVycyBhdHRhY2hlZCB0byBlYWNoIEFQSSByZXF1ZXN0IHRvIGVuYWJsZVxuICogdHJhY2tpbmcgYW5kIGRlYnVnZ2luZyBhY3Jvc3MgZGlzdHJpYnV0ZWQgc3lzdGVtcywgbWljcm9zZXJ2aWNlcywgYW5kIGxvZyBhZ2dyZWdhdGlvbi5cbiAqXG4gKiBAbW9kdWxlIENvcnJlbGF0aW9uSWRHZW5lcmF0b3JcbiAqL1xuXG4vKipcbiAqIEdlbmVyYXRlcyBhIGNyeXB0b2dyYXBoaWNhbGx5IHJhbmRvbSBVVUlEIHY0IHN0cmluZy5cbiAqXG4gKiBQcmVmZXJzIG5hdGl2ZSBgY3J5cHRvLnJhbmRvbVVVSUQoKWAgd2hlbiBhdmFpbGFibGUgKG1vZGVybiBicm93c2VycyBhbmQgTm9kZS5qcyAxOSspLFxuICogZmFsbGluZyBiYWNrIHRvIGEgY29tcGxpYW50IFVVSUQgdjQgaW1wbGVtZW50YXRpb24gdXNpbmcgYE1hdGgucmFuZG9tKClgLlxuICpcbiAqIEBpbnRlcm5hbCBUaGlzIGZ1bmN0aW9uIGlzIG5vdCBleHBvcnRlZCBmcm9tIHRoZSBwdWJsaWMgQVBJXG4gKiBAcmV0dXJucyBBIFVVSUQgdjQgc3RyaW5nIGluIHRoZSBmb3JtYXQgYHh4eHh4eHh4LXh4eHgtNHh4eC15eHh4LXh4eHh4eHh4eHh4eGBcbiAqXG4gKiBAZXhhbXBsZVxuICogYGBgdHlwZXNjcmlwdFxuICogY29uc3QgdXVpZCA9IGdlbmVyYXRlVVVJRCgpO1xuICogLy8gPT4gXCJhMWIyYzNkNC1lNWY2LTQ3ODktYTAxMi1iM2M0ZDVlNmY3YThcIlxuICogYGBgXG4gKi9cbmZ1bmN0aW9uIGdlbmVyYXRlVVVJRCgpOiBzdHJpbmcge1xuICBpZiAodHlwZW9mIGNyeXB0byAhPT0gJ3VuZGVmaW5lZCcgJiYgY3J5cHRvLnJhbmRvbVVVSUQpIHtcbiAgICByZXR1cm4gY3J5cHRvLnJhbmRvbVVVSUQoKTtcbiAgfVxuXG4gIC8vIEZhbGxiYWNrIFVVSUQgdjQgZ2VuZXJhdG9yXG4gIHJldHVybiAneHh4eHh4eHgteHh4eC00eHh4LXl4eHgteHh4eHh4eHh4eHh4Jy5yZXBsYWNlKC9beHldL2csIGMgPT4ge1xuICAgIGNvbnN0IHIgPSAoTWF0aC5yYW5kb20oKSAqIDE2KSB8IDA7XG4gICAgY29uc3QgdiA9IGMgPT09ICd4JyA/IHIgOiAociAmIDB4MykgfCAweDg7XG5cbiAgICByZXR1cm4gdi50b1N0cmluZygxNik7XG4gIH0pO1xufVxuXG4vKipcbiAqIEdlbmVyYXRlcyBhIHVuaXF1ZSBjb3JyZWxhdGlvbiBJRCBmb3IgQVBJIHJlcXVlc3QgdHJhY2tpbmcgYW5kIGRpc3RyaWJ1dGVkIHRyYWNpbmcuXG4gKlxuICogQ29ycmVsYXRpb24gSURzIGhlbHAgdHJhY2sgcmVxdWVzdHMgYWNyb3NzIG11bHRpcGxlIHNlcnZpY2VzIGFuZCBzeXN0ZW1zLiBUaGV5IGFyZVxuICogYXV0b21hdGljYWxseSBhdHRhY2hlZCB0byBvdXRnb2luZyByZXF1ZXN0cyB2aWEgSFRUUCBoZWFkZXJzIChgWC1Db3JyZWxhdGlvbi1JZGAgYW5kXG4gKiBgWC1SZXF1ZXN0LUlkYCkgYW5kIGNhbiBiZSB1c2VkIHRvOlxuICogLSBDb3JyZWxhdGUgbG9ncyBhY3Jvc3MgZGlzdHJpYnV0ZWQgc3lzdGVtc1xuICogLSBUcmFjayByZXF1ZXN0IGZsb3dzIGluIG1pY3Jvc2VydmljZXMgYXJjaGl0ZWN0dXJlc1xuICogLSBEZWJ1ZyBpc3N1ZXMgYnkgdHJhY2luZyBhIHNwZWNpZmljIHJlcXVlc3QncyBqb3VybmV5XG4gKiAtIE1vbml0b3IgcGVyZm9ybWFuY2UgYWNyb3NzIHNlcnZpY2UgYm91bmRhcmllc1xuICpcbiAqIFRoZSBnZW5lcmF0ZWQgSUQgZm9sbG93cyB0aGUgZm9ybWF0OiBge3ByZWZpeH0te3V1aWR9YCBvciBqdXN0IGB7dXVpZH1gIGlmIG5vIHByZWZpeCBpcyBwcm92aWRlZC5cbiAqXG4gKiBAcGFyYW0gcHJlZml4IC0gT3B0aW9uYWwgcHJlZml4IHRvIG5hbWVzcGFjZSBjb3JyZWxhdGlvbiBJRHMgYnkgY29udGV4dCAoZS5nLiwgJ2FwaScsICd3ZWInLCAnbW9iaWxlJylcbiAqIEByZXR1cm5zIEEgY29ycmVsYXRpb24gSUQgc3RyaW5nLCBvcHRpb25hbGx5IHByZWZpeGVkXG4gKiBAcHVibGljXG4gKlxuICogQGV4YW1wbGVcbiAqIEJhc2ljIHVzYWdlOlxuICogYGBgdHlwZXNjcmlwdFxuICogY29uc3QgaWQgPSBnZW5lcmF0ZUNvcnJlbGF0aW9uSWQoKTtcbiAqIC8vID0+IFwiYTFiMmMzZDQtZTVmNi00Nzg5LWEwMTItYjNjNGQ1ZTZmN2E4XCJcbiAqIGBgYFxuICpcbiAqIEBleGFtcGxlXG4gKiBXaXRoIHByZWZpeCBmb3IgY29udGV4dCBpZGVudGlmaWNhdGlvbjpcbiAqIGBgYHR5cGVzY3JpcHRcbiAqIGNvbnN0IHdlYklkID0gZ2VuZXJhdGVDb3JyZWxhdGlvbklkKCd3ZWInKTtcbiAqIC8vID0+IFwid2ViLWExYjJjM2Q0LWU1ZjYtNDc4OS1hMDEyLWIzYzRkNWU2ZjdhOFwiXG4gKlxuICogY29uc3QgYXBpSWQgPSBnZW5lcmF0ZUNvcnJlbGF0aW9uSWQoJ2FwaScpO1xuICogLy8gPT4gXCJhcGktZjFlMmQzYzQtYjVhNi00OTg3LWEwMTItYjNjNGQ1ZTZmN2E4XCJcbiAqIGBgYFxuICpcbiAqIEBleGFtcGxlXG4gKiBDb25maWd1cmluZyBpbiBBcGlDbGllbnQ6XG4gKiBgYGB0eXBlc2NyaXB0XG4gKiBjb25zdCBjbGllbnQgPSBuZXcgQXBpQ2xpZW50KCdodHRwczovL2FwaS5leGFtcGxlLmNvbScpO1xuICogY2xpZW50LnNldENvcnJlbGF0aW9uSWRQcmVmaXgoJ21vYmlsZScpO1xuICogLy8gQWxsIHJlcXVlc3RzIHdpbGwgaGF2ZSBjb3JyZWxhdGlvbiBJRHMgbGlrZSBcIm1vYmlsZS17dXVpZH1cIlxuICogYGBgXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZW5lcmF0ZUNvcnJlbGF0aW9uSWQocHJlZml4Pzogc3RyaW5nKTogc3RyaW5nIHtcbiAgY29uc3QgdXVpZCA9IGdlbmVyYXRlVVVJRCgpO1xuXG4gIHJldHVybiBwcmVmaXggPyBgJHtwcmVmaXh9LSR7dXVpZH1gIDogdXVpZDtcbn1cbiIsICJpbXBvcnQgdHlwZSB7IEFwaUVycm9yLCBBcGlFcnJvclR5cGUgfSBmcm9tICcuLi90eXBlcy9BcGlFcnJvcic7XHJcbmltcG9ydCB0eXBlIHsgUmVxdWVzdENvbmZpZyB9IGZyb20gJy4uL3R5cGVzL1JlcXVlc3RDb25maWcnO1xyXG5cclxuLyoqXHJcbiAqIE5vcm1hbGl6ZXMgdmFyaW91cyBlcnJvciB0eXBlcyBpbnRvIGEgY29uc2lzdGVudCwgc3RydWN0dXJlZCBBcGlFcnJvciBmb3JtYXQuXHJcbiAqXHJcbiAqIFRoaXMgaW50ZXJuYWwgY2xhc3MgaGFuZGxlcyB0aGUgY29tcGxleCB0YXNrIG9mIGNvbnZlcnRpbmcgYW55IHR5cGUgb2YgZXJyb3JcclxuICogKG5ldHdvcmsgZXJyb3JzLCBIVFRQIGVycm9ycywgYWJvcnQgZXJyb3JzLCB0aW1lb3V0cywgZXRjLikgaW50byBhIHN0YW5kYXJkaXplZFxyXG4gKiB7QGxpbmsgQXBpRXJyb3J9IHN0cnVjdHVyZSB3aXRoIHByb3BlciBjYXRlZ29yaXphdGlvbiBhbmQgbWV0YWRhdGEuXHJcbiAqXHJcbiAqIEtleSBGZWF0dXJlczpcclxuICogLSAqKkVycm9yIENhdGVnb3JpemF0aW9uKio6IENsYXNzaWZpZXMgZXJyb3JzIGJ5IHR5cGUgKHZhbGlkYXRpb24sIGNsaWVudCwgc2VydmVyLCBuZXR3b3JrLCBldGMuKVxyXG4gKiAtICoqSFRUUCBTdGF0dXMgTWFwcGluZyoqOiBDb252ZXJ0cyBzdGF0dXMgY29kZXMgdG8gaHVtYW4tcmVhZGFibGUgdGl0bGVzXHJcbiAqIC0gKipDb3JyZWxhdGlvbiBJRCBUcmFja2luZyoqOiBQcmVzZXJ2ZXMgb3IgaW5qZWN0cyBjb3JyZWxhdGlvbiBJRHMgZm9yIHRyYWNpbmdcclxuICogLSAqKkFib3J0IERldGVjdGlvbioqOiBJZGVudGlmaWVzIGFuZCBwcm9wZXJseSBoYW5kbGVzIHJlcXVlc3QgY2FuY2VsbGF0aW9uc1xyXG4gKiAtICoqQ29uc2lzdGVudCBTdHJ1Y3R1cmUqKjogRW5zdXJlcyBhbGwgZXJyb3JzIGNvbmZvcm0gdG8gdGhlIEFwaUVycm9yIGludGVyZmFjZVxyXG4gKlxyXG4gKiBAaW50ZXJuYWwgVGhpcyBjbGFzcyBpcyBub3QgZXhwb3J0ZWQgZnJvbSB0aGUgcHVibGljIEFQSVxyXG4gKi9cclxuZXhwb3J0IGNsYXNzIEVycm9yTm9ybWFsaXplciB7XHJcbiAgLyoqXHJcbiAgICogTWFwcyBhbiBIVFRQIHN0YXR1cyBjb2RlIHRvIGEgc3RhbmRhcmRpemVkIGVycm9yIHR5cGUgY2F0ZWdvcnkuXHJcbiAgICpcclxuICAgKiBUaGlzIGNhdGVnb3JpemF0aW9uIGhlbHBzIGNvbnN1bWVycyBoYW5kbGUgZGlmZmVyZW50IGVycm9yIGNsYXNzZXMgYXBwcm9wcmlhdGVseTpcclxuICAgKiAtIGB2YWxpZGF0aW9uX2Vycm9yYCAoNDAwKTogQ2xpZW50IHNlbnQgaW52YWxpZCBkYXRhXHJcbiAgICogLSBgY2xpZW50X2Vycm9yYCAoNDAxLTQ5OSk6IENsaWVudC1zaWRlIGlzc3VlcyAoYXV0aCwgcGVybWlzc2lvbnMsIG5vdCBmb3VuZCwgZXRjLilcclxuICAgKiAtIGBzZXJ2ZXJfZXJyb3JgICg1MDAtNTk5KTogU2VydmVyLXNpZGUgZmFpbHVyZXNcclxuICAgKiAtIGB1bmtub3duX2Vycm9yYDogVW5yZWNvZ25pemVkIHN0YXR1cyBjb2Rlc1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHN0YXR1cyAtIEhUVFAgc3RhdHVzIGNvZGUgZnJvbSB0aGUgcmVzcG9uc2VcclxuICAgKiBAcmV0dXJucyBUaGUgZXJyb3IgdHlwZSBjYXRlZ29yeSBhcyBhIHN0cmluZ1xyXG4gICAqXHJcbiAgICogQGV4YW1wbGVcclxuICAgKiBgYGB0eXBlc2NyaXB0XHJcbiAgICogbm9ybWFsaXplci5nZXRFcnJvclR5cGUoNDAwKTsgLy8gPT4gJ3ZhbGlkYXRpb25fZXJyb3InXHJcbiAgICogbm9ybWFsaXplci5nZXRFcnJvclR5cGUoNDA0KTsgLy8gPT4gJ2NsaWVudF9lcnJvcidcclxuICAgKiBub3JtYWxpemVyLmdldEVycm9yVHlwZSg1MDApOyAvLyA9PiAnc2VydmVyX2Vycm9yJ1xyXG4gICAqIG5vcm1hbGl6ZXIuZ2V0RXJyb3JUeXBlKDApOyAgIC8vID0+ICd1bmtub3duX2Vycm9yJ1xyXG4gICAqIGBgYFxyXG4gICAqL1xyXG4gIGdldEVycm9yVHlwZShzdGF0dXM6IG51bWJlcik6IEFwaUVycm9yVHlwZSB7XHJcbiAgICBpZiAoc3RhdHVzID49IDQwMCAmJiBzdGF0dXMgPCA1MDApIHtcclxuICAgICAgcmV0dXJuIHN0YXR1cyA9PT0gNDAwID8gJ3ZhbGlkYXRpb25fZXJyb3InIDogJ2NsaWVudF9lcnJvcic7XHJcbiAgICB9IGVsc2UgaWYgKHN0YXR1cyA+PSA1MDApIHtcclxuICAgICAgcmV0dXJuICdzZXJ2ZXJfZXJyb3InO1xyXG4gICAgfVxyXG5cclxuICAgIHJldHVybiAndW5rbm93bl9lcnJvcic7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBNYXBzIGFuIEhUVFAgc3RhdHVzIGNvZGUgdG8gYSBodW1hbi1yZWFkYWJsZSBlcnJvciB0aXRsZS5cclxuICAgKlxyXG4gICAqIFByb3ZpZGVzIHVzZXItZnJpZW5kbHkgZXJyb3IgbWVzc2FnZXMgZm9yIGNvbW1vbiBIVFRQIHN0YXR1cyBjb2Rlcy5cclxuICAgKiBGYWxscyBiYWNrIHRvIGEgZ2VuZXJpYyBcIkhUVFAgRXJyb3Ige3N0YXR1c31cIiBmb3JtYXQgZm9yIHVubWFwcGVkIGNvZGVzLlxyXG4gICAqXHJcbiAgICogQHBhcmFtIHN0YXR1cyAtIEhUVFAgc3RhdHVzIGNvZGUgZnJvbSB0aGUgcmVzcG9uc2VcclxuICAgKiBAcmV0dXJucyBBIGh1bWFuLXJlYWRhYmxlIGVycm9yIHRpdGxlXHJcbiAgICpcclxuICAgKiBAZXhhbXBsZVxyXG4gICAqIGBgYHR5cGVzY3JpcHRcclxuICAgKiBub3JtYWxpemVyLmdldEVycm9yVGl0bGUoNDA0KTsgLy8gPT4gJ05vdCBGb3VuZCdcclxuICAgKiBub3JtYWxpemVyLmdldEVycm9yVGl0bGUoNTAwKTsgLy8gPT4gJ0ludGVybmFsIFNlcnZlciBFcnJvcidcclxuICAgKiBub3JtYWxpemVyLmdldEVycm9yVGl0bGUoOTk5KTsgLy8gPT4gJ0hUVFAgRXJyb3IgOTk5J1xyXG4gICAqIGBgYFxyXG4gICAqL1xyXG4gIGdldEVycm9yVGl0bGUoc3RhdHVzOiBudW1iZXIpOiBzdHJpbmcge1xyXG4gICAgY29uc3QgdGl0bGVzOiBSZWNvcmQ8bnVtYmVyLCBzdHJpbmc+ID0ge1xyXG4gICAgICA0MDA6ICdCYWQgUmVxdWVzdCcsXHJcbiAgICAgIDQwMTogJ1VuYXV0aG9yaXplZCcsXHJcbiAgICAgIDQwMzogJ0ZvcmJpZGRlbicsXHJcbiAgICAgIDQwNDogJ05vdCBGb3VuZCcsXHJcbiAgICAgIDQwNTogJ01ldGhvZCBOb3QgQWxsb3dlZCcsXHJcbiAgICAgIDQwODogJ1JlcXVlc3QgVGltZW91dCcsXHJcbiAgICAgIDQwOTogJ0NvbmZsaWN0JyxcclxuICAgICAgNDIyOiAnVW5wcm9jZXNzYWJsZSBFbnRpdHknLFxyXG4gICAgICA0Mjk6ICdUb28gTWFueSBSZXF1ZXN0cycsXHJcbiAgICAgIDUwMDogJ0ludGVybmFsIFNlcnZlciBFcnJvcicsXHJcbiAgICAgIDUwMjogJ0JhZCBHYXRld2F5JyxcclxuICAgICAgNTAzOiAnU2VydmljZSBVbmF2YWlsYWJsZScsXHJcbiAgICAgIDUwNDogJ0dhdGV3YXkgVGltZW91dCcsXHJcbiAgICB9O1xyXG5cclxuICAgIHJldHVybiB0aXRsZXNbc3RhdHVzXSB8fCBgSFRUUCBFcnJvciAke3N0YXR1c31gO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogTm9ybWFsaXplcyBhbnkgZXJyb3IgaW50byBhIGNvbnNpc3RlbnQsIHN0cnVjdHVyZWQgQXBpRXJyb3IgZm9ybWF0LlxyXG4gICAqXHJcbiAgICogVGhpcyBtZXRob2QgaGFuZGxlcyB2YXJpb3VzIGVycm9yIHNjZW5hcmlvcyBhbmQgZW5zdXJlcyB0aGV5IGFsbCBjb25mb3JtIHRvXHJcbiAgICogdGhlIHtAbGluayBBcGlFcnJvcn0gaW50ZXJmYWNlIHdpdGggYXBwcm9wcmlhdGUgY2F0ZWdvcml6YXRpb24gYW5kIG1ldGFkYXRhOlxyXG4gICAqXHJcbiAgICogLSAqKkV4aXN0aW5nIEFwaUVycm9ycyoqOiBFbmhhbmNlcyB3aXRoIG1pc3NpbmcgZmllbGRzICh0cmFjZUlkLCBjb25maWcpXHJcbiAgICogLSAqKkFib3J0RXJyb3JzKio6IE1hcmtzIGFzIGByZXF1ZXN0X2NhbmNlbGxlZGAgd2l0aCBpc0Fib3J0ZWQgZmxhZ1xyXG4gICAqIC0gKipUaW1lb3V0IEVycm9ycyoqOiBDYXRlZ29yaXplcyBhcyBgdGltZW91dF9lcnJvcmAgd2l0aCA0MDggc3RhdHVzXHJcbiAgICogLSAqKk5ldHdvcmsgRXJyb3JzKio6IENhdGVnb3JpemVzIGFzIGBuZXR3b3JrX2Vycm9yYCB3aXRoIDAgc3RhdHVzXHJcbiAgICogLSAqKlVua25vd24gRXJyb3JzKio6IEZhbGxiYWNrIGNhdGVnb3J5IGZvciB1bmV4cGVjdGVkIGVycm9yIHR5cGVzXHJcbiAgICpcclxuICAgKiBBbGwgbm9ybWFsaXplZCBlcnJvcnMgaW5jbHVkZTpcclxuICAgKiAtIGB0eXBlYDogRXJyb3IgY2F0ZWdvcnkgZm9yIHByb2dyYW1tYXRpYyBoYW5kbGluZ1xyXG4gICAqIC0gYHRpdGxlYDogSHVtYW4tcmVhZGFibGUgZXJyb3IgdGl0bGVcclxuICAgKiAtIGBzdGF0dXNgOiBIVFRQIHN0YXR1cyBjb2RlIChvciAwIGZvciBub24tSFRUUCBlcnJvcnMpXHJcbiAgICogLSBgdHJhY2VJZGA6IENvcnJlbGF0aW9uIElEIGZvciBkaXN0cmlidXRlZCB0cmFjaW5nXHJcbiAgICogLSBgaXNBYm9ydGVkYDogQm9vbGVhbiBmbGFnIGluZGljYXRpbmcgaWYgcmVxdWVzdCB3YXMgY2FuY2VsbGVkXHJcbiAgICogLSBgY29uZmlnYDogT3JpZ2luYWwgcmVxdWVzdCBjb25maWd1cmF0aW9uIGZvciBkZWJ1Z2dpbmdcclxuICAgKlxyXG4gICAqIEBwYXJhbSBlcnJvciAtIFRoZSBlcnJvciB0byBub3JtYWxpemUgKGNhbiBiZSBhbnkgdHlwZSlcclxuICAgKiBAcGFyYW0gY29uZmlnIC0gVGhlIHJlcXVlc3QgY29uZmlndXJhdGlvbiB0aGF0IGxlZCB0byB0aGlzIGVycm9yXHJcbiAgICogQHBhcmFtIGNvcnJlbGF0aW9uSWQgLSBPcHRpb25hbCBjb3JyZWxhdGlvbiBJRCBmb3IgdHJhY2luZ1xyXG4gICAqIEByZXR1cm5zIEEgZnVsbHkgc3RydWN0dXJlZCBBcGlFcnJvciBpbnN0YW5jZVxyXG4gICAqXHJcbiAgICogQGV4YW1wbGVcclxuICAgKiBOb3JtYWxpemluZyBhIGZldGNoIEFib3J0RXJyb3I6XHJcbiAgICogYGBgdHlwZXNjcmlwdFxyXG4gICAqIHRyeSB7XHJcbiAgICogICBhd2FpdCBmZXRjaCh1cmwsIHsgc2lnbmFsIH0pO1xyXG4gICAqIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICogICBjb25zdCBhcGlFcnJvciA9IG5vcm1hbGl6ZXIubm9ybWFsaXplRXJyb3IoZXJyb3IsIGNvbmZpZywgJ3JlcS0xMjMnKTtcclxuICAgKiAgIC8vIGFwaUVycm9yLnR5cGUgPT09ICdyZXF1ZXN0X2NhbmNlbGxlZCdcclxuICAgKiAgIC8vIGFwaUVycm9yLmlzQWJvcnRlZCA9PT0gdHJ1ZVxyXG4gICAqIH1cclxuICAgKiBgYGBcclxuICAgKlxyXG4gICAqIEBleGFtcGxlXHJcbiAgICogTm9ybWFsaXppbmcgYSB0aW1lb3V0OlxyXG4gICAqIGBgYHR5cGVzY3JpcHRcclxuICAgKiBjb25zdCB0aW1lb3V0RXJyb3IgPSBuZXcgRXJyb3IoJ1JlcXVlc3QgdGltZW91dCBhZnRlciAzMDAwMG1zJyk7XHJcbiAgICogY29uc3QgYXBpRXJyb3IgPSBub3JtYWxpemVyLm5vcm1hbGl6ZUVycm9yKHRpbWVvdXRFcnJvciwgY29uZmlnKTtcclxuICAgKiAvLyBhcGlFcnJvci50eXBlID09PSAndGltZW91dF9lcnJvcidcclxuICAgKiAvLyBhcGlFcnJvci5zdGF0dXMgPT09IDQwOFxyXG4gICAqIGBgYFxyXG4gICAqL1xyXG4gIG5vcm1hbGl6ZUVycm9yKFxyXG4gICAgZXJyb3I6IHVua25vd24sXHJcbiAgICBjb25maWc6IFJlcXVlc3RDb25maWcsXHJcbiAgICBjb3JyZWxhdGlvbklkPzogc3RyaW5nXHJcbiAgKTogQXBpRXJyb3Ige1xyXG4gICAgLy8gSGFuZGxlIHByaW1pdGl2ZSBlcnJvcnMgKHN0cmluZ3MsIG51bWJlcnMsIGV0Yy4pXHJcbiAgICBpZiAoZXJyb3IgPT09IG51bGwgfHwgZXJyb3IgPT09IHVuZGVmaW5lZCkge1xyXG4gICAgICByZXR1cm4gT2JqZWN0LmFzc2lnbihuZXcgRXJyb3IoJ0FuIHVua25vd24gZXJyb3Igb2NjdXJyZWQnKSwge1xyXG4gICAgICAgIHR5cGU6ICd1bmtub3duX2Vycm9yJyxcclxuICAgICAgICB0aXRsZTogJ1Vua25vd24gRXJyb3InLFxyXG4gICAgICAgIHN0YXR1czogMCxcclxuICAgICAgICB0cmFjZUlkOiBjb3JyZWxhdGlvbklkLFxyXG4gICAgICAgIGlzQWJvcnRlZDogZmFsc2UsXHJcbiAgICAgICAgY29uZmlnLFxyXG4gICAgICB9IGFzIEFwaUVycm9yKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBIYW5kbGUgc3RyaW5nIGVycm9yc1xyXG4gICAgaWYgKHR5cGVvZiBlcnJvciA9PT0gJ3N0cmluZycpIHtcclxuICAgICAgcmV0dXJuIE9iamVjdC5hc3NpZ24obmV3IEVycm9yKGVycm9yKSwge1xyXG4gICAgICAgIHR5cGU6ICd1bmtub3duX2Vycm9yJyxcclxuICAgICAgICB0aXRsZTogJ1Vua25vd24gRXJyb3InLFxyXG4gICAgICAgIHN0YXR1czogMCxcclxuICAgICAgICB0cmFjZUlkOiBjb3JyZWxhdGlvbklkLFxyXG4gICAgICAgIGlzQWJvcnRlZDogZmFsc2UsXHJcbiAgICAgICAgY29uZmlnLFxyXG4gICAgICB9IGFzIEFwaUVycm9yKTtcclxuICAgIH1cclxuXHJcbiAgICBjb25zdCBlcnIgPSBlcnJvciBhcyBQYXJ0aWFsPEFwaUVycm9yPiAmIHsgbWVzc2FnZT86IHN0cmluZzsgbmFtZT86IHN0cmluZyB9O1xyXG5cclxuICAgIC8vIElmIGVycm9yIGFscmVhZHkgaGFzIEFwaUVycm9yIHN0cnVjdHVyZSwgZW5oYW5jZSBpdFxyXG4gICAgaWYgKGVyci50eXBlIHx8IGVyci50aXRsZSB8fCBlcnIuZXJyb3JzKSB7XHJcbiAgICAgIHJldHVybiBPYmplY3QuYXNzaWduKFxyXG4gICAgICAgIGVycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBlcnJvciA6IG5ldyBFcnJvcihlcnIubWVzc2FnZSA/PyAnVW5rbm93biBlcnJvcicpLFxyXG4gICAgICAgIHtcclxuICAgICAgICAgIHR5cGU6IGVyci50eXBlLFxyXG4gICAgICAgICAgdGl0bGU6IGVyci50aXRsZSxcclxuICAgICAgICAgIHN0YXR1czogZXJyLnN0YXR1cyxcclxuICAgICAgICAgIHRyYWNlSWQ6IGVyci50cmFjZUlkIHx8IGNvcnJlbGF0aW9uSWQsXHJcbiAgICAgICAgICBlcnJvcnM6IGVyci5lcnJvcnMsXHJcbiAgICAgICAgICBpc0Fib3J0ZWQ6IGVyci5pc0Fib3J0ZWQgfHwgZmFsc2UsXHJcbiAgICAgICAgICBjb25maWcsXHJcbiAgICAgICAgfVxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIGlmIChlcnIubmFtZSA9PT0gJ0Fib3J0RXJyb3InIHx8IGVyci5pc0Fib3J0ZWQpIHtcclxuICAgICAgcmV0dXJuIE9iamVjdC5hc3NpZ24obmV3IEVycm9yKGVyci5tZXNzYWdlID8/ICdSZXF1ZXN0IHdhcyBhYm9ydGVkJyksIHtcclxuICAgICAgICB0eXBlOiAncmVxdWVzdF9jYW5jZWxsZWQnLFxyXG4gICAgICAgIHRpdGxlOiAnUmVxdWVzdCB3YXMgY2FuY2VsbGVkJyxcclxuICAgICAgICBzdGF0dXM6IDAsXHJcbiAgICAgICAgdHJhY2VJZDogY29ycmVsYXRpb25JZCxcclxuICAgICAgICBpc0Fib3J0ZWQ6IHRydWUsXHJcbiAgICAgICAgY29uZmlnLFxyXG4gICAgICB9IGFzIEFwaUVycm9yKTtcclxuICAgIH1cclxuXHJcbiAgICBpZiAoZXJyLm1lc3NhZ2U/LmluY2x1ZGVzKCd0aW1lb3V0JykpIHtcclxuICAgICAgcmV0dXJuIE9iamVjdC5hc3NpZ24obmV3IEVycm9yKGVyci5tZXNzYWdlKSwge1xyXG4gICAgICAgIHR5cGU6ICd0aW1lb3V0X2Vycm9yJyxcclxuICAgICAgICB0aXRsZTogJ1JlcXVlc3QgVGltZW91dCcsXHJcbiAgICAgICAgc3RhdHVzOiA0MDgsXHJcbiAgICAgICAgdHJhY2VJZDogY29ycmVsYXRpb25JZCxcclxuICAgICAgICBpc0Fib3J0ZWQ6IHRydWUsXHJcbiAgICAgICAgY29uZmlnLFxyXG4gICAgICB9IGFzIEFwaUVycm9yKTtcclxuICAgIH1cclxuXHJcbiAgICBpZiAoZXJyLm1lc3NhZ2U/LmluY2x1ZGVzKCduZXR3b3JrJykpIHtcclxuICAgICAgcmV0dXJuIE9iamVjdC5hc3NpZ24obmV3IEVycm9yKGVyci5tZXNzYWdlID8/ICdOZXR3b3JrIHJlcXVlc3QgZmFpbGVkJyksIHtcclxuICAgICAgICB0eXBlOiAnbmV0d29ya19lcnJvcicsXHJcbiAgICAgICAgdGl0bGU6ICdOZXR3b3JrIEVycm9yJyxcclxuICAgICAgICBzdGF0dXM6IDAsXHJcbiAgICAgICAgdHJhY2VJZDogY29ycmVsYXRpb25JZCxcclxuICAgICAgICBpc0Fib3J0ZWQ6IGZhbHNlLFxyXG4gICAgICAgIGNvbmZpZyxcclxuICAgICAgfSBhcyBBcGlFcnJvcik7XHJcbiAgICB9XHJcblxyXG4gICAgcmV0dXJuIE9iamVjdC5hc3NpZ24oXHJcbiAgICAgIG5ldyBFcnJvcihlcnIubWVzc2FnZSA/PyAnQW4gdW5rbm93biBlcnJvciBvY2N1cnJlZCcpLFxyXG4gICAgICB7XHJcbiAgICAgICAgdHlwZTogJ3Vua25vd25fZXJyb3InLFxyXG4gICAgICAgIHRpdGxlOiAnVW5rbm93biBFcnJvcicsXHJcbiAgICAgICAgc3RhdHVzOiAwLFxyXG4gICAgICAgIHRyYWNlSWQ6IGNvcnJlbGF0aW9uSWQsXHJcbiAgICAgICAgaXNBYm9ydGVkOiBmYWxzZSxcclxuICAgICAgICBjb25maWcsXHJcbiAgICAgIH0gYXMgQXBpRXJyb3JcclxuICAgICk7XHJcbiAgfVxyXG59XHJcbiIsICJpbXBvcnQgdHlwZSB7IEFwaUVycm9yIH0gZnJvbSAnLi4vdHlwZXMvQXBpRXJyb3InO1xuaW1wb3J0IHR5cGUgeyBFcnJvckludGVyY2VwdG9yIH0gZnJvbSAnLi4vdHlwZXMvRXJyb3JJbnRlcmNlcHRvcic7XG5pbXBvcnQgdHlwZSB7IFJlcXVlc3RDb25maWcgfSBmcm9tICcuLi90eXBlcy9SZXF1ZXN0Q29uZmlnJztcbmltcG9ydCB0eXBlIHsgUmVxdWVzdEludGVyY2VwdG9yIH0gZnJvbSAnLi4vdHlwZXMvUmVxdWVzdEludGVyY2VwdG9yJztcbmltcG9ydCB0eXBlIHsgUmVzcG9uc2VJbnRlcmNlcHRvciB9IGZyb20gJy4uL3R5cGVzL1Jlc3BvbnNlSW50ZXJjZXB0b3InO1xuXG5pbXBvcnQgdHlwZSB7IEFwaVJlc3BvbnNlIH0gZnJvbSAnQC90eXBlcyc7XG5cbi8qKlxuICogTWFuYWdlcyB0aGUgcmVnaXN0cmF0aW9uIGFuZCBleGVjdXRpb24gb2YgcmVxdWVzdC9yZXNwb25zZS9lcnJvciBpbnRlcmNlcHRvcnMuXG4gKlxuICogVGhpcyBpbnRlcm5hbCBjbGFzcyBpbXBsZW1lbnRzIHRoZSBpbnRlcmNlcHRvciBwYXR0ZXJuLCBhbGxvd2luZyBtaWRkbGV3YXJlLXN0eWxlXG4gKiBmdW5jdGlvbnMgdG8gYmUgcmVnaXN0ZXJlZCBhbmQgZXhlY3V0ZWQgYXQgZGlmZmVyZW50IHBvaW50cyBpbiB0aGUgcmVxdWVzdCBsaWZlY3ljbGU6XG4gKiAtICoqUmVxdWVzdCBJbnRlcmNlcHRvcnMqKjogTW9kaWZ5IHJlcXVlc3RzIGJlZm9yZSB0aGV5IGFyZSBzZW50XG4gKiAtICoqUmVzcG9uc2UgSW50ZXJjZXB0b3JzKio6IFRyYW5zZm9ybSByZXNwb25zZXMgYmVmb3JlIHRoZXkgYXJlIHJldHVybmVkXG4gKiAtICoqRXJyb3IgSW50ZXJjZXB0b3JzKio6IEhhbmRsZSBvciB0cmFuc2Zvcm0gZXJyb3JzIGJlZm9yZSB0aGV5IGFyZSB0aHJvd25cbiAqXG4gKiBJbnRlcmNlcHRvcnMgYXJlIGV4ZWN1dGVkIHNlcXVlbnRpYWxseSBpbiB0aGUgb3JkZXIgdGhleSB3ZXJlIHJlZ2lzdGVyZWQsXG4gKiBmb3JtaW5nIGEgcHJvY2Vzc2luZyBwaXBlbGluZS4gRWFjaCBpbnRlcmNlcHRvciBjYW46XG4gKiAtIEluc3BlY3QgdGhlIGRhdGEgcGFzc2luZyB0aHJvdWdoXG4gKiAtIFRyYW5zZm9ybSBvciBlbmhhbmNlIHRoZSBkYXRhXG4gKiAtIFNob3J0LWNpcmN1aXQgdGhlIHBpcGVsaW5lIChmb3IgZXJyb3JzKVxuICogLSBQZXJmb3JtIHNpZGUgZWZmZWN0cyAobG9nZ2luZywgbW9uaXRvcmluZywgZXRjLilcbiAqXG4gKiBLZXkgRmVhdHVyZXM6XG4gKiAtICoqU2VxdWVudGlhbCBFeGVjdXRpb24qKjogSW50ZXJjZXB0b3JzIHJ1biBpbiByZWdpc3RyYXRpb24gb3JkZXJcbiAqIC0gKipVbnJlZ2lzdHJhdGlvbiBTdXBwb3J0Kio6IFJldHVybnMgY2xlYW51cCBmdW5jdGlvbiBmb3IgZWFjaCBpbnRlcmNlcHRvclxuICogLSAqKlR5cGUgU2FmZXR5Kio6IEZ1bGx5IHR5cGVkIGludGVyY2VwdG9yIGZ1bmN0aW9ucyB3aXRoIGdlbmVyaWNzXG4gKiAtICoqRXJyb3IgSGFuZGxpbmcqKjogR3JhY2VmdWwgaGFuZGxpbmcgb2YgaW50ZXJjZXB0b3IgZmFpbHVyZXNcbiAqXG4gKiBAaW50ZXJuYWwgVGhpcyBjbGFzcyBpcyBub3QgZXhwb3J0ZWQgZnJvbSB0aGUgcHVibGljIEFQSVxuICpcbiAqIEBleGFtcGxlXG4gKiBDb21tb24gaW50ZXJjZXB0b3IgcGF0dGVybnM6XG4gKiBgYGB0eXBlc2NyaXB0XG4gKiBjb25zdCBtYW5hZ2VyID0gbmV3IEludGVyY2VwdG9yTWFuYWdlcigpO1xuICpcbiAqIC8vIFJlcXVlc3QgbG9nZ2luZ1xuICogbWFuYWdlci5hZGRSZXF1ZXN0SW50ZXJjZXB0b3IoYXN5bmMgKGNvbmZpZykgPT4ge1xuICogICBjb25zb2xlLmxvZygnUmVxdWVzdDonLCBjb25maWcubWV0aG9kLCBjb25maWcudXJsKTtcbiAqICAgcmV0dXJuIGNvbmZpZztcbiAqIH0pO1xuICpcbiAqIC8vIFJlc3BvbnNlIHRyYW5zZm9ybWF0aW9uXG4gKiBtYW5hZ2VyLmFkZFJlc3BvbnNlSW50ZXJjZXB0b3IoYXN5bmMgKHJlc3BvbnNlKSA9PiB7XG4gKiAgIGlmIChyZXNwb25zZS5hcGlEYXRhKSB7XG4gKiAgICAgcmVzcG9uc2UuYXBpRGF0YSA9IGNhbWVsQ2FzZUtleXMocmVzcG9uc2UuYXBpRGF0YSk7XG4gKiAgIH1cbiAqICAgcmV0dXJuIHJlc3BvbnNlO1xuICogfSk7XG4gKlxuICogLy8gRXJyb3IgbW9uaXRvcmluZ1xuICogbWFuYWdlci5hZGRFcnJvckludGVyY2VwdG9yKGFzeW5jIChlcnJvcikgPT4ge1xuICogICBpZiAoZXJyb3Iuc3RhdHVzID49IDUwMCkge1xuICogICAgIGF3YWl0IGxvZ1RvTW9uaXRvcmluZyhlcnJvcik7XG4gKiAgIH1cbiAqICAgdGhyb3cgZXJyb3I7IC8vIFJlLXRocm93IHRvIG1haW50YWluIGVycm9yIGZsb3dcbiAqIH0pO1xuICogYGBgXG4gKi9cbmV4cG9ydCBjbGFzcyBJbnRlcmNlcHRvck1hbmFnZXIge1xuICAvKipcbiAgICogQXJyYXkgb2YgcmVnaXN0ZXJlZCByZXF1ZXN0IGludGVyY2VwdG9yc1xuICAgKiBAcHJpdmF0ZVxuICAgKi9cbiAgcHJpdmF0ZSByZWFkb25seSByZXF1ZXN0SW50ZXJjZXB0b3JzOiBSZXF1ZXN0SW50ZXJjZXB0b3JbXSA9IFtdO1xuXG4gIC8qKlxuICAgKiBBcnJheSBvZiByZWdpc3RlcmVkIHJlc3BvbnNlIGludGVyY2VwdG9yc1xuICAgKiBAcHJpdmF0ZVxuICAgKi9cbiAgcHJpdmF0ZSByZWFkb25seSByZXNwb25zZUludGVyY2VwdG9yczogUmVzcG9uc2VJbnRlcmNlcHRvcltdID0gW107XG5cbiAgLyoqXG4gICAqIEFycmF5IG9mIHJlZ2lzdGVyZWQgZXJyb3IgaW50ZXJjZXB0b3JzXG4gICAqIEBwcml2YXRlXG4gICAqL1xuICBwcml2YXRlIHJlYWRvbmx5IGVycm9ySW50ZXJjZXB0b3JzOiBFcnJvckludGVyY2VwdG9yW10gPSBbXTtcblxuICAvKipcbiAgICogUmVnaXN0ZXJzIGEgcmVxdWVzdCBpbnRlcmNlcHRvciB0byBtb2RpZnkgcmVxdWVzdHMgYmVmb3JlIHRoZXkgYXJlIHNlbnQuXG4gICAqXG4gICAqIFJlcXVlc3QgaW50ZXJjZXB0b3JzIGNhbjpcbiAgICogLSBBZGQgb3IgbW9kaWZ5IGhlYWRlcnNcbiAgICogLSBUcmFuc2Zvcm0gcmVxdWVzdCBib2RpZXNcbiAgICogLSBBZGQgcXVlcnkgcGFyYW1ldGVyc1xuICAgKiAtIEltcGxlbWVudCByZXF1ZXN0IHNpZ25pbmdcbiAgICogLSBMb2cgb3V0Z29pbmcgcmVxdWVzdHNcbiAgICpcbiAgICogQHBhcmFtIGludGVyY2VwdG9yIC0gQXN5bmMgZnVuY3Rpb24gdGhhdCByZWNlaXZlcyBhbmQgcmV0dXJucyBSZXF1ZXN0Q29uZmlnXG4gICAqIEByZXR1cm5zIENsZWFudXAgZnVuY3Rpb24gdG8gdW5yZWdpc3RlciB0aGlzIGludGVyY2VwdG9yXG4gICAqXG4gICAqIEBleGFtcGxlXG4gICAqIGBgYHR5cGVzY3JpcHRcbiAgICogLy8gQWRkIGF1dGhlbnRpY2F0aW9uIGhlYWRlclxuICAgKiBjb25zdCB1bnJlZ2lzdGVyID0gbWFuYWdlci5hZGRSZXF1ZXN0SW50ZXJjZXB0b3IoYXN5bmMgKGNvbmZpZykgPT4ge1xuICAgKiAgIGNvbnN0IHRva2VuID0gYXdhaXQgZ2V0QXV0aFRva2VuKCk7XG4gICAqICAgY29uZmlnLmhlYWRlcnMgPSBjb25maWcuaGVhZGVycyB8fCBuZXcgSGVhZGVycygpO1xuICAgKiAgIGNvbmZpZy5oZWFkZXJzLnNldCgnQXV0aG9yaXphdGlvbicsIGBCZWFyZXIgJHt0b2tlbn1gKTtcbiAgICogICByZXR1cm4gY29uZmlnO1xuICAgKiB9KTtcbiAgICpcbiAgICogLy8gTGF0ZXIsIHJlbW92ZSB0aGUgaW50ZXJjZXB0b3JcbiAgICogdW5yZWdpc3RlcigpO1xuICAgKiBgYGBcbiAgICovXG4gIGFkZFJlcXVlc3RJbnRlcmNlcHRvcihpbnRlcmNlcHRvcjogUmVxdWVzdEludGVyY2VwdG9yKTogKCkgPT4gdm9pZCB7XG4gICAgdGhpcy5yZXF1ZXN0SW50ZXJjZXB0b3JzLnB1c2goaW50ZXJjZXB0b3IpO1xuXG4gICAgcmV0dXJuICgpID0+IHtcbiAgICAgIGNvbnN0IGluZGV4ID0gdGhpcy5yZXF1ZXN0SW50ZXJjZXB0b3JzLmluZGV4T2YoaW50ZXJjZXB0b3IpO1xuXG4gICAgICBpZiAoaW5kZXggPiAtMSkgdGhpcy5yZXF1ZXN0SW50ZXJjZXB0b3JzLnNwbGljZShpbmRleCwgMSk7XG4gICAgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZWdpc3RlcnMgYSByZXNwb25zZSBpbnRlcmNlcHRvciB0byB0cmFuc2Zvcm0gcmVzcG9uc2VzIGJlZm9yZSB0aGV5IGFyZSByZXR1cm5lZC5cbiAgICpcbiAgICogUmVzcG9uc2UgaW50ZXJjZXB0b3JzIGNhbjpcbiAgICogLSBUcmFuc2Zvcm0gcmVzcG9uc2UgZGF0YSBmb3JtYXRcbiAgICogLSBFeHRyYWN0IG5lc3RlZCBkYXRhIHN0cnVjdHVyZXNcbiAgICogLSBBZGQgY29tcHV0ZWQgcHJvcGVydGllc1xuICAgKiAtIENhY2hlIHJlc3BvbnNlc1xuICAgKiAtIExvZyBzdWNjZXNzZnVsIHJlc3BvbnNlc1xuICAgKlxuICAgKiBAcGFyYW0gaW50ZXJjZXB0b3IgLSBBc3luYyBmdW5jdGlvbiB0aGF0IHJlY2VpdmVzIGFuZCByZXR1cm5zIEFwaVJlc3BvbnNlXG4gICAqIEByZXR1cm5zIENsZWFudXAgZnVuY3Rpb24gdG8gdW5yZWdpc3RlciB0aGlzIGludGVyY2VwdG9yXG4gICAqXG4gICAqIEBleGFtcGxlXG4gICAqIGBgYHR5cGVzY3JpcHRcbiAgICogLy8gRXh0cmFjdCBkYXRhIGZyb20gZW52ZWxvcGVcbiAgICogbWFuYWdlci5hZGRSZXNwb25zZUludGVyY2VwdG9yKGFzeW5jIChyZXNwb25zZSkgPT4ge1xuICAgKiAgIGlmIChyZXNwb25zZS5hcGlEYXRhPy5yZXN1bHQpIHtcbiAgICogICAgIHJlc3BvbnNlLmFwaURhdGEgPSByZXNwb25zZS5hcGlEYXRhLnJlc3VsdDtcbiAgICogICB9XG4gICAqICAgcmV0dXJuIHJlc3BvbnNlO1xuICAgKiB9KTtcbiAgICpcbiAgICogLy8gQWRkIHRpbWVzdGFtcHNcbiAgICogbWFuYWdlci5hZGRSZXNwb25zZUludGVyY2VwdG9yKGFzeW5jIChyZXNwb25zZSkgPT4ge1xuICAgKiAgIHJldHVybiB7XG4gICAqICAgICAuLi5yZXNwb25zZSxcbiAgICogICAgIHJlY2VpdmVkQXQ6IG5ldyBEYXRlKCkudG9JU09TdHJpbmcoKVxuICAgKiAgIH07XG4gICAqIH0pO1xuICAgKiBgYGBcbiAgICovXG4gIGFkZFJlc3BvbnNlSW50ZXJjZXB0b3IoaW50ZXJjZXB0b3I6IFJlc3BvbnNlSW50ZXJjZXB0b3IpOiAoKSA9PiB2b2lkIHtcbiAgICB0aGlzLnJlc3BvbnNlSW50ZXJjZXB0b3JzLnB1c2goaW50ZXJjZXB0b3IpO1xuXG4gICAgcmV0dXJuICgpID0+IHtcbiAgICAgIGNvbnN0IGluZGV4ID0gdGhpcy5yZXNwb25zZUludGVyY2VwdG9ycy5pbmRleE9mKGludGVyY2VwdG9yKTtcblxuICAgICAgaWYgKGluZGV4ID4gLTEpIHRoaXMucmVzcG9uc2VJbnRlcmNlcHRvcnMuc3BsaWNlKGluZGV4LCAxKTtcbiAgICB9O1xuICB9XG5cbiAgLyoqXG4gICAqIFJlZ2lzdGVycyBhbiBlcnJvciBpbnRlcmNlcHRvciB0byBoYW5kbGUgb3IgdHJhbnNmb3JtIGVycm9ycyBiZWZvcmUgdGhleSBhcmUgdGhyb3duLlxuICAgKlxuICAgKiBFcnJvciBpbnRlcmNlcHRvcnMgY2FuOlxuICAgKiAtIExvZyBlcnJvcnMgdG8gbW9uaXRvcmluZyBzZXJ2aWNlc1xuICAgKiAtIFRyYW5zZm9ybSBlcnJvciBmb3JtYXRzXG4gICAqIC0gSW1wbGVtZW50IHJldHJ5IGxvZ2ljXG4gICAqIC0gU2hvdyB1c2VyIG5vdGlmaWNhdGlvbnNcbiAgICogLSBFeHRyYWN0IHZhbGlkYXRpb24gZXJyb3JzXG4gICAqXG4gICAqICoqTm90ZToqKiBFcnJvciBpbnRlcmNlcHRvcnMgc2hvdWxkIHJlLXRocm93IHRoZSBlcnJvciAob3IgYSB0cmFuc2Zvcm1lZCB2ZXJzaW9uKVxuICAgKiB0byBtYWludGFpbiB0aGUgZXJyb3IgZmxvdy4gVGhlIGZpbmFsIGVycm9yIGlzIGFsd2F5cyB0aHJvd24uXG4gICAqXG4gICAqIEBwYXJhbSBpbnRlcmNlcHRvciAtIEFzeW5jIGZ1bmN0aW9uIHRoYXQgcmVjZWl2ZXMgYW5kIHJldHVybnMgKG9yIHRocm93cykgQXBpRXJyb3JcbiAgICogQHJldHVybnMgQ2xlYW51cCBmdW5jdGlvbiB0byB1bnJlZ2lzdGVyIHRoaXMgaW50ZXJjZXB0b3JcbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICogYGBgdHlwZXNjcmlwdFxuICAgKiAvLyBMb2cgdG8gbW9uaXRvcmluZyBzZXJ2aWNlXG4gICAqIG1hbmFnZXIuYWRkRXJyb3JJbnRlcmNlcHRvcihhc3luYyAoZXJyb3IpID0+IHtcbiAgICogICBpZiAoZXJyb3Iuc3RhdHVzID49IDUwMCkge1xuICAgKiAgICAgYXdhaXQgU2VudHJ5LmNhcHR1cmVFeGNlcHRpb24oZXJyb3IsIHtcbiAgICogICAgICAgZXh0cmE6IHsgdHJhY2VJZDogZXJyb3IudHJhY2VJZCB9XG4gICAqICAgICB9KTtcbiAgICogICB9XG4gICAqICAgdGhyb3cgZXJyb3I7IC8vIFJlLXRocm93IHRvIGNvbnRpbnVlIGVycm9yIGZsb3dcbiAgICogfSk7XG4gICAqXG4gICAqIC8vIFRyYW5zZm9ybSBlcnJvciBtZXNzYWdlc1xuICAgKiBtYW5hZ2VyLmFkZEVycm9ySW50ZXJjZXB0b3IoYXN5bmMgKGVycm9yKSA9PiB7XG4gICAqICAgaWYgKGVycm9yLnN0YXR1cyA9PT0gNDA0KSB7XG4gICAqICAgICBlcnJvci50aXRsZSA9ICdSZXNvdXJjZSBub3QgZm91bmQnO1xuICAgKiAgIH1cbiAgICogICB0aHJvdyBlcnJvcjtcbiAgICogfSk7XG4gICAqIGBgYFxuICAgKi9cbiAgYWRkRXJyb3JJbnRlcmNlcHRvcihpbnRlcmNlcHRvcjogRXJyb3JJbnRlcmNlcHRvcik6ICgpID0+IHZvaWQge1xuICAgIHRoaXMuZXJyb3JJbnRlcmNlcHRvcnMucHVzaChpbnRlcmNlcHRvcik7XG5cbiAgICByZXR1cm4gKCkgPT4ge1xuICAgICAgY29uc3QgaW5kZXggPSB0aGlzLmVycm9ySW50ZXJjZXB0b3JzLmluZGV4T2YoaW50ZXJjZXB0b3IpO1xuXG4gICAgICBpZiAoaW5kZXggPiAtMSkgdGhpcy5lcnJvckludGVyY2VwdG9ycy5zcGxpY2UoaW5kZXgsIDEpO1xuICAgIH07XG4gIH1cblxuICAvKipcbiAgICogQXBwbGllcyBhbGwgcmVnaXN0ZXJlZCByZXF1ZXN0IGludGVyY2VwdG9ycyBpbiBzZXF1ZW50aWFsIG9yZGVyLlxuICAgKlxuICAgKiBFYWNoIGludGVyY2VwdG9yIHJlY2VpdmVzIHRoZSBjb25maWcgbW9kaWZpZWQgYnkgdGhlIHByZXZpb3VzIGludGVyY2VwdG9yLFxuICAgKiBmb3JtaW5nIGEgcHJvY2Vzc2luZyBwaXBlbGluZS4gSWYgYW55IGludGVyY2VwdG9yIHRocm93cyBhbiBlcnJvcixcbiAgICogdGhlIHBpcGVsaW5lIHN0b3BzIGFuZCB0aGUgZXJyb3IgcHJvcGFnYXRlcy5cbiAgICpcbiAgICogQHBhcmFtIGNvbmZpZyAtIFRoZSBpbml0aWFsIHJlcXVlc3QgY29uZmlndXJhdGlvblxuICAgKiBAcmV0dXJucyBUaGUgbW9kaWZpZWQgcmVxdWVzdCBjb25maWd1cmF0aW9uIGFmdGVyIGFsbCBpbnRlcmNlcHRvcnNcbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICogYGBgdHlwZXNjcmlwdFxuICAgKiBjb25zdCBjb25maWcgPSB7IG1ldGhvZDogJ0dFVCcsIHVybDogJy91c2VycycgfTtcbiAgICogY29uc3QgZmluYWxDb25maWcgPSBhd2FpdCBtYW5hZ2VyLmFwcGx5UmVxdWVzdEludGVyY2VwdG9ycyhjb25maWcpO1xuICAgKiAvLyBmaW5hbENvbmZpZyBoYXMgYmVlbiBwcm9jZXNzZWQgYnkgYWxsIHJlZ2lzdGVyZWQgaW50ZXJjZXB0b3JzXG4gICAqIGBgYFxuICAgKi9cbiAgYXN5bmMgYXBwbHlSZXF1ZXN0SW50ZXJjZXB0b3JzKFxuICAgIGNvbmZpZzogUmVxdWVzdENvbmZpZ1xuICApOiBQcm9taXNlPFJlcXVlc3RDb25maWc+IHtcbiAgICBsZXQgbW9kaWZpZWRDb25maWcgPSB7IC4uLmNvbmZpZyB9O1xuXG4gICAgZm9yIChjb25zdCBpbnRlcmNlcHRvciBvZiB0aGlzLnJlcXVlc3RJbnRlcmNlcHRvcnMpIHtcbiAgICAgIG1vZGlmaWVkQ29uZmlnID0gYXdhaXQgaW50ZXJjZXB0b3IobW9kaWZpZWRDb25maWcpO1xuICAgIH1cblxuICAgIHJldHVybiBtb2RpZmllZENvbmZpZztcbiAgfVxuXG4gIC8qKlxuICAgKiBBcHBsaWVzIGFsbCByZWdpc3RlcmVkIHJlc3BvbnNlIGludGVyY2VwdG9ycyBpbiBzZXF1ZW50aWFsIG9yZGVyLlxuICAgKlxuICAgKiBFYWNoIGludGVyY2VwdG9yIHJlY2VpdmVzIHRoZSByZXNwb25zZSBtb2RpZmllZCBieSB0aGUgcHJldmlvdXMgaW50ZXJjZXB0b3IsXG4gICAqIGZvcm1pbmcgYSBwcm9jZXNzaW5nIHBpcGVsaW5lLiBJZiBhbnkgaW50ZXJjZXB0b3IgdGhyb3dzIGFuIGVycm9yLFxuICAgKiB0aGUgcGlwZWxpbmUgc3RvcHMgYW5kIHRoZSBlcnJvciBwcm9wYWdhdGVzLlxuICAgKlxuICAgKiBAdGVtcGxhdGUgVCAtIFRoZSB0eXBlIG9mIHRoZSByZXNwb25zZSBkYXRhXG4gICAqIEBwYXJhbSByZXNwb25zZSAtIFRoZSBpbml0aWFsIEFQSSByZXNwb25zZVxuICAgKiBAcmV0dXJucyBUaGUgbW9kaWZpZWQgcmVzcG9uc2UgYWZ0ZXIgYWxsIGludGVyY2VwdG9yc1xuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKiBgYGB0eXBlc2NyaXB0XG4gICAqIGNvbnN0IHJlc3BvbnNlID0geyBkYXRhOiB7IGlkOiAxLCBuYW1lOiAnSm9obicgfSB9O1xuICAgKiBjb25zdCBmaW5hbFJlc3BvbnNlID0gYXdhaXQgbWFuYWdlci5hcHBseVJlc3BvbnNlSW50ZXJjZXB0b3JzKHJlc3BvbnNlKTtcbiAgICogLy8gZmluYWxSZXNwb25zZSBoYXMgYmVlbiBwcm9jZXNzZWQgYnkgYWxsIHJlZ2lzdGVyZWQgaW50ZXJjZXB0b3JzXG4gICAqIGBgYFxuICAgKi9cbiAgYXN5bmMgYXBwbHlSZXNwb25zZUludGVyY2VwdG9yczxUPihcbiAgICByZXNwb25zZTogQXBpUmVzcG9uc2U8VD5cbiAgKTogUHJvbWlzZTxBcGlSZXNwb25zZTxUPj4ge1xuICAgIGxldCBtb2RpZmllZFJlc3BvbnNlID0gcmVzcG9uc2U7XG5cbiAgICBmb3IgKGNvbnN0IGludGVyY2VwdG9yIG9mIHRoaXMucmVzcG9uc2VJbnRlcmNlcHRvcnMpIHtcbiAgICAgIG1vZGlmaWVkUmVzcG9uc2UgPSBhd2FpdCBpbnRlcmNlcHRvcihtb2RpZmllZFJlc3BvbnNlKTtcbiAgICB9XG5cbiAgICByZXR1cm4gbW9kaWZpZWRSZXNwb25zZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBcHBsaWVzIGFsbCByZWdpc3RlcmVkIGVycm9yIGludGVyY2VwdG9ycyBpbiBzZXF1ZW50aWFsIG9yZGVyIGFuZCByZS10aHJvd3MuXG4gICAqXG4gICAqIEVhY2ggaW50ZXJjZXB0b3IgcmVjZWl2ZXMgdGhlIGVycm9yIChwb3RlbnRpYWxseSBtb2RpZmllZCBieSBwcmV2aW91cyBpbnRlcmNlcHRvcnMpLlxuICAgKiBJbnRlcmNlcHRvcnMgY2FuIHRyYW5zZm9ybSB0aGUgZXJyb3IgYmVmb3JlIHJlLXRocm93aW5nIGl0LiBUaGUgZmluYWwgZXJyb3JcbiAgICogaXMgYWx3YXlzIHRocm93biB0byBtYWludGFpbiBlcnJvciBmbG93LlxuICAgKlxuICAgKiBJZiBhbiBpbnRlcmNlcHRvciBpdHNlbGYgdGhyb3dzIGFuIGVycm9yLCB0aGF0IGJlY29tZXMgdGhlIG5ldyBlcnJvciB0byBwcm9jZXNzXG4gICAqIGJ5IHN1YnNlcXVlbnQgaW50ZXJjZXB0b3JzLlxuICAgKlxuICAgKiBAcGFyYW0gZXJyb3IgLSBUaGUgaW5pdGlhbCBBUEkgZXJyb3JcbiAgICogQHJldHVybnMgTmV2ZXIgcmV0dXJucyAoYWx3YXlzIHRocm93cylcbiAgICogQHRocm93cyBUaGUgZmluYWwgZXJyb3IgYWZ0ZXIgYWxsIGludGVyY2VwdG9ycyBoYXZlIHByb2Nlc3NlZCBpdFxuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKiBgYGB0eXBlc2NyaXB0XG4gICAqIHRyeSB7XG4gICAqICAgYXdhaXQgbWFuYWdlci5hcHBseUVycm9ySW50ZXJjZXB0b3JzKGVycm9yKTtcbiAgICogfSBjYXRjaCAoZmluYWxFcnJvcikge1xuICAgKiAgIC8vIGZpbmFsRXJyb3IgaGFzIGJlZW4gcHJvY2Vzc2VkIGJ5IGFsbCByZWdpc3RlcmVkIGVycm9yIGludGVyY2VwdG9yc1xuICAgKiB9XG4gICAqIGBgYFxuICAgKi9cbiAgYXN5bmMgYXBwbHlFcnJvckludGVyY2VwdG9ycyhlcnJvcjogQXBpRXJyb3IpOiBQcm9taXNlPG5ldmVyPiB7XG4gICAgbGV0IG1vZGlmaWVkRXJyb3IgPSBlcnJvcjtcblxuICAgIGZvciAoY29uc3QgaW50ZXJjZXB0b3Igb2YgdGhpcy5lcnJvckludGVyY2VwdG9ycykge1xuICAgICAgdHJ5IHtcbiAgICAgICAgbW9kaWZpZWRFcnJvciA9IGF3YWl0IGludGVyY2VwdG9yKG1vZGlmaWVkRXJyb3IpO1xuICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICBtb2RpZmllZEVycm9yID0gZSBhcyBBcGlFcnJvcjtcbiAgICAgIH1cbiAgICB9XG5cbiAgICB0aHJvdyBtb2RpZmllZEVycm9yO1xuICB9XG59XG4iLCAiLyoqXG4gKiBNYW5hZ2VzIGFjdGl2ZSBIVFRQIHJlcXVlc3RzIHdpdGggc3VwcG9ydCBmb3IgY2FuY2VsbGF0aW9uIGFuZCBjb3JyZWxhdGlvbiB0cmFja2luZy5cbiAqXG4gKiBUaGlzIGludGVybmFsIGNsYXNzIG1haW50YWlucyBhIHJlZ2lzdHJ5IG9mIGluLWZsaWdodCByZXF1ZXN0cywgYWxsb3dpbmcgdGhlbSB0byBiZVxuICogY2FuY2VsbGVkIGluZGl2aWR1YWxseSBvciBpbiBidWxrLiBFYWNoIHJlcXVlc3QgaXMgdHJhY2tlZCBieSBhIHVuaXF1ZSBrZXkgYW5kXG4gKiBhc3NvY2lhdGVkIHdpdGggYSBjb3JyZWxhdGlvbiBJRCBmb3IgZGlzdHJpYnV0ZWQgdHJhY2luZy5cbiAqXG4gKiBLZXkgRmVhdHVyZXM6XG4gKiAtICoqUmVxdWVzdCBEZWR1cGxpY2F0aW9uKio6IEF1dG9tYXRpY2FsbHkgY2FuY2VscyBkdXBsaWNhdGUgcmVxdWVzdHMgd2l0aCB0aGUgc2FtZSBrZXlcbiAqIC0gKipDb3JyZWxhdGlvbiBUcmFja2luZyoqOiBNYXBzIHJlcXVlc3Qga2V5cyB0byBjb3JyZWxhdGlvbiBJRHMgZm9yIHRyYWNpbmdcbiAqIC0gKipCdWxrIENhbmNlbGxhdGlvbioqOiBDYW5jZWwgYWxsIHBlbmRpbmcgcmVxdWVzdHMgYXQgb25jZSAodXNlZnVsIGZvciBjbGVhbnVwKVxuICogLSAqKk1lbW9yeSBNYW5hZ2VtZW50Kio6IEF1dG9tYXRpY2FsbHkgY2xlYW5zIHVwIHRyYWNraW5nIGRhdGEgd2hlbiByZXF1ZXN0cyBjb21wbGV0ZVxuICpcbiAqIEBpbnRlcm5hbCBUaGlzIGNsYXNzIGlzIG5vdCBleHBvcnRlZCBmcm9tIHRoZSBwdWJsaWMgQVBJXG4gKlxuICogQGV4YW1wbGVcbiAqIGBgYHR5cGVzY3JpcHRcbiAqIGNvbnN0IG1hbmFnZXIgPSBuZXcgUmVxdWVzdE1hbmFnZXIoKTtcbiAqIGNvbnN0IGNvbnRyb2xsZXIgPSBuZXcgQWJvcnRDb250cm9sbGVyKCk7XG4gKlxuICogLy8gVHJhY2sgYSByZXF1ZXN0XG4gKiBtYW5hZ2VyLmFkZCgnR0VUXy91c2Vycy8xMjMnLCBjb250cm9sbGVyLCAnYXBpLWFiYzEyMycpO1xuICpcbiAqIC8vIENhbmNlbCBzcGVjaWZpYyByZXF1ZXN0XG4gKiBtYW5hZ2VyLmNhbmNlbCgnR0VUXy91c2Vycy8xMjMnKTtcbiAqXG4gKiAvLyBPciBjYW5jZWwgYWxsIHJlcXVlc3RzXG4gKiBtYW5hZ2VyLmNhbmNlbEFsbCgpO1xuICogYGBgXG4gKi9cbmV4cG9ydCBjbGFzcyBSZXF1ZXN0TWFuYWdlciB7XG4gIC8qKlxuICAgKiBNYXAgb2YgYWN0aXZlIHJlcXVlc3Qga2V5cyB0byB0aGVpciBhYm9ydCBjb250cm9sbGVyc1xuICAgKiBAcHJpdmF0ZVxuICAgKi9cbiAgcHJpdmF0ZSBhY3RpdmVSZXF1ZXN0czogTWFwPHN0cmluZywgQWJvcnRDb250cm9sbGVyPiA9IG5ldyBNYXAoKTtcblxuICAvKipcbiAgICogTWFwIG9mIHJlcXVlc3Qga2V5cyB0byB0aGVpciBjb3JyZWxhdGlvbiBJRHMgZm9yIHRyYWNpbmdcbiAgICogQHByaXZhdGVcbiAgICovXG4gIHByaXZhdGUgY29ycmVsYXRpb25NYXA6IE1hcDxzdHJpbmcsIHN0cmluZz4gPSBuZXcgTWFwKCk7XG5cbiAgLyoqXG4gICAqIFJlZ2lzdGVycyBhIG5ldyByZXF1ZXN0IGZvciB0cmFja2luZyBhbmQgY2FuY2VsbGF0aW9uIG1hbmFnZW1lbnQuXG4gICAqXG4gICAqIElmIGEgcmVxdWVzdCB3aXRoIHRoZSBzYW1lIGtleSBhbHJlYWR5IGV4aXN0cywgaXQgd2lsbCBiZSBhdXRvbWF0aWNhbGx5XG4gICAqIGNhbmNlbGxlZCBiZWZvcmUgdGhlIG5ldyBvbmUgaXMgcmVnaXN0ZXJlZCAocmVxdWVzdCBkZWR1cGxpY2F0aW9uKS5cbiAgICpcbiAgICogQHBhcmFtIGtleSAtIFVuaXF1ZSBpZGVudGlmaWVyIGZvciB0aGUgcmVxdWVzdCAodHlwaWNhbGx5IG1ldGhvZCArIFVSTCArIHRpbWVzdGFtcClcbiAgICogQHBhcmFtIGNvbnRyb2xsZXIgLSBBYm9ydENvbnRyb2xsZXIgZm9yIGNhbmNlbGxpbmcgdGhlIHJlcXVlc3RcbiAgICogQHBhcmFtIGNvcnJlbGF0aW9uSWQgLSBDb3JyZWxhdGlvbiBJRCBmb3IgZGlzdHJpYnV0ZWQgdHJhY2luZ1xuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKiBgYGB0eXBlc2NyaXB0XG4gICAqIGNvbnN0IGNvbnRyb2xsZXIgPSBuZXcgQWJvcnRDb250cm9sbGVyKCk7XG4gICAqIG1hbmFnZXIuYWRkKCdHRVRfL2FwaS91c2Vyc18xNjk5OTk5OTk5JywgY29udHJvbGxlciwgJ2FwaS1hYmMxMjMnKTtcbiAgICogYGBgXG4gICAqL1xuICBhZGQoa2V5OiBzdHJpbmcsIGNvbnRyb2xsZXI6IEFib3J0Q29udHJvbGxlciwgY29ycmVsYXRpb25JZDogc3RyaW5nKTogdm9pZCB7XG4gICAgLy8gQ2FuY2VsIGV4aXN0aW5nIHJlcXVlc3Qgd2l0aCBzYW1lIGtleSBpZiBleGlzdHNcbiAgICB0aGlzLmNhbmNlbChrZXkpO1xuICAgIHRoaXMuYWN0aXZlUmVxdWVzdHMuc2V0KGtleSwgY29udHJvbGxlcik7XG4gICAgdGhpcy5jb3JyZWxhdGlvbk1hcC5zZXQoa2V5LCBjb3JyZWxhdGlvbklkKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZW1vdmVzIGEgcmVxdWVzdCBmcm9tIHRyYWNraW5nIHdpdGhvdXQgY2FuY2VsbGluZyBpdC5cbiAgICpcbiAgICogVGhpcyBpcyB0eXBpY2FsbHkgY2FsbGVkIHdoZW4gYSByZXF1ZXN0IGNvbXBsZXRlcyBzdWNjZXNzZnVsbHkgb3IgZmFpbHMuXG4gICAqIFVzZSB7QGxpbmsgY2FuY2VsfSBpbnN0ZWFkIGlmIHlvdSBuZWVkIHRvIGFib3J0IHRoZSByZXF1ZXN0LlxuICAgKlxuICAgKiBAcGFyYW0ga2V5IC0gVW5pcXVlIGlkZW50aWZpZXIgZm9yIHRoZSByZXF1ZXN0IHRvIHJlbW92ZVxuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKiBgYGB0eXBlc2NyaXB0XG4gICAqIC8vIENhbGxlZCBhdXRvbWF0aWNhbGx5IGFmdGVyIHJlcXVlc3QgY29tcGxldGVzXG4gICAqIG1hbmFnZXIucmVtb3ZlKCdHRVRfL2FwaS91c2Vyc18xNjk5OTk5OTk5Jyk7XG4gICAqIGBgYFxuICAgKi9cbiAgcmVtb3ZlKGtleTogc3RyaW5nKTogdm9pZCB7XG4gICAgdGhpcy5hY3RpdmVSZXF1ZXN0cy5kZWxldGUoa2V5KTtcbiAgICB0aGlzLmNvcnJlbGF0aW9uTWFwLmRlbGV0ZShrZXkpO1xuICB9XG5cbiAgLyoqXG4gICAqIENhbmNlbHMgYSBzcGVjaWZpYyByZXF1ZXN0IGFuZCByZW1vdmVzIGl0IGZyb20gdHJhY2tpbmcuXG4gICAqXG4gICAqIElmIHRoZSByZXF1ZXN0IGRvZXNuJ3QgZXhpc3Qgb3Igd2FzIGFscmVhZHkgY2FuY2VsbGVkLCB0aGlzIG9wZXJhdGlvbiBpcyBhIG5vLW9wLlxuICAgKiBUaGUgYXNzb2NpYXRlZCBBYm9ydENvbnRyb2xsZXIncyBzaWduYWwgd2lsbCBiZSB0cmlnZ2VyZWQsIGNhdXNpbmcgYW55IGFjdGl2ZVxuICAgKiBmZXRjaCBvcGVyYXRpb25zIHRvIGFib3J0LlxuICAgKlxuICAgKiBAcGFyYW0ga2V5IC0gVW5pcXVlIGlkZW50aWZpZXIgZm9yIHRoZSByZXF1ZXN0IHRvIGNhbmNlbFxuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKiBgYGB0eXBlc2NyaXB0XG4gICAqIC8vIFVzZXIgbmF2aWdhdGVzIGF3YXksIGNhbmNlbCB0aGUgcGVuZGluZyByZXF1ZXN0XG4gICAqIG1hbmFnZXIuY2FuY2VsKCdHRVRfL2FwaS91c2Vyc18xNjk5OTk5OTk5Jyk7XG4gICAqIGBgYFxuICAgKi9cbiAgY2FuY2VsKGtleTogc3RyaW5nKTogdm9pZCB7XG4gICAgY29uc3QgY29udHJvbGxlciA9IHRoaXMuYWN0aXZlUmVxdWVzdHMuZ2V0KGtleSk7XG5cbiAgICBpZiAoY29udHJvbGxlcikge1xuICAgICAgY29udHJvbGxlci5hYm9ydCgpO1xuICAgICAgdGhpcy5hY3RpdmVSZXF1ZXN0cy5kZWxldGUoa2V5KTtcbiAgICAgIHRoaXMuY29ycmVsYXRpb25NYXAuZGVsZXRlKGtleSk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIENhbmNlbHMgYWxsIGFjdGl2ZSByZXF1ZXN0cyBhbmQgY2xlYXJzIGFsbCB0cmFja2luZyBkYXRhLlxuICAgKlxuICAgKiBUaGlzIGlzIHVzZWZ1bCBmb3IgY2xlYW51cCBzY2VuYXJpb3Mgc3VjaCBhczpcbiAgICogLSBVc2VyIGxvZ291dFxuICAgKiAtIENvbXBvbmVudCB1bm1vdW50XG4gICAqIC0gTmF2aWdhdGlvbiB0byBhIGRpZmZlcmVudCBwYXJ0IG9mIHRoZSBhcHBsaWNhdGlvblxuICAgKiAtIEVycm9yIHJlY292ZXJ5IHRoYXQgcmVxdWlyZXMgYSBjbGVhbiBzbGF0ZVxuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKiBgYGB0eXBlc2NyaXB0XG4gICAqIC8vIENhbmNlbCBhbGwgcGVuZGluZyByZXF1ZXN0cyBvbiBsb2dvdXRcbiAgICogZnVuY3Rpb24gaGFuZGxlTG9nb3V0KCkge1xuICAgKiAgIGFwaUNsaWVudC5jYW5jZWxBbGxSZXF1ZXN0cygpO1xuICAgKiAgIC8vIC4uLiByZXN0IG9mIGxvZ291dCBsb2dpY1xuICAgKiB9XG4gICAqIGBgYFxuICAgKi9cbiAgY2FuY2VsQWxsKCk6IHZvaWQge1xuICAgIHRoaXMuYWN0aXZlUmVxdWVzdHMuZm9yRWFjaChjb250cm9sbGVyID0+IGNvbnRyb2xsZXIuYWJvcnQoKSk7XG4gICAgdGhpcy5hY3RpdmVSZXF1ZXN0cy5jbGVhcigpO1xuICAgIHRoaXMuY29ycmVsYXRpb25NYXAuY2xlYXIoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDaGVja3MgaWYgYSByZXF1ZXN0IHdpdGggdGhlIGdpdmVuIGtleSBpcyBjdXJyZW50bHkgYmVpbmcgdHJhY2tlZC5cbiAgICpcbiAgICogQHBhcmFtIGtleSAtIFVuaXF1ZSBpZGVudGlmaWVyIGZvciB0aGUgcmVxdWVzdFxuICAgKiBAcmV0dXJucyBgdHJ1ZWAgaWYgdGhlIHJlcXVlc3QgaXMgYWN0aXZlLCBgZmFsc2VgIG90aGVyd2lzZVxuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKiBgYGB0eXBlc2NyaXB0XG4gICAqIGlmIChtYW5hZ2VyLmhhcygnR0VUXy9hcGkvdXNlcnNfMTY5OTk5OTk5OScpKSB7XG4gICAqICAgY29uc29sZS5sb2coJ1JlcXVlc3QgaXMgc3RpbGwgcGVuZGluZycpO1xuICAgKiB9XG4gICAqIGBgYFxuICAgKi9cbiAgaGFzKGtleTogc3RyaW5nKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMuYWN0aXZlUmVxdWVzdHMuaGFzKGtleSk7XG4gIH1cblxuICAvKipcbiAgICogUmV0cmlldmVzIHRoZSBjb3JyZWxhdGlvbiBJRCBmb3IgYSBnaXZlbiByZXF1ZXN0IGtleS5cbiAgICpcbiAgICogQ29ycmVsYXRpb24gSURzIGFyZSB1c2VkIGZvciBkaXN0cmlidXRlZCB0cmFjaW5nIGFuZCByZXF1ZXN0IHRyYWNraW5nXG4gICAqIGFjcm9zcyBzZXJ2aWNlcyBhbmQgbG9ncy5cbiAgICpcbiAgICogQHBhcmFtIGtleSAtIFVuaXF1ZSBpZGVudGlmaWVyIGZvciB0aGUgcmVxdWVzdFxuICAgKiBAcmV0dXJucyBUaGUgY29ycmVsYXRpb24gSUQgaWYgZm91bmQsIGB1bmRlZmluZWRgIG90aGVyd2lzZVxuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKiBgYGB0eXBlc2NyaXB0XG4gICAqIGNvbnN0IGNvcnJlbGF0aW9uSWQgPSBtYW5hZ2VyLmdldENvcnJlbGF0aW9uSWQoJ0dFVF8vYXBpL3VzZXJzXzE2OTk5OTk5OTknKTtcbiAgICogaWYgKGNvcnJlbGF0aW9uSWQpIHtcbiAgICogICBjb25zb2xlLmxvZygnVHJhY2UgcmVxdWVzdCB3aXRoIElEOicsIGNvcnJlbGF0aW9uSWQpO1xuICAgKiB9XG4gICAqIGBgYFxuICAgKi9cbiAgZ2V0Q29ycmVsYXRpb25JZChrZXk6IHN0cmluZyk6IHN0cmluZyB8IHVuZGVmaW5lZCB7XG4gICAgcmV0dXJuIHRoaXMuY29ycmVsYXRpb25NYXAuZ2V0KGtleSk7XG4gIH1cbn1cbiIsICJpbXBvcnQgdHlwZSB7IEFwaUVycm9yIH0gZnJvbSAnLi4vdHlwZXMvQXBpRXJyb3InO1xuXG4vKipcbiAqIEltcGxlbWVudHMgYXV0b21hdGljIHJldHJ5IGxvZ2ljIHdpdGggZXhwb25lbnRpYWwgYmFja29mZiBmb3IgZmFpbGVkIEhUVFAgcmVxdWVzdHMuXG4gKlxuICogVGhpcyBpbnRlcm5hbCBjbGFzcyBoYW5kbGVzIHRyYW5zaWVudCBmYWlsdXJlcyBieSBhdXRvbWF0aWNhbGx5IHJldHJ5aW5nIHJlcXVlc3RzXG4gKiB3aXRoIHByb2dyZXNzaXZlbHkgaW5jcmVhc2luZyBkZWxheXMgYmV0d2VlbiBhdHRlbXB0cy4gVGhlIGV4cG9uZW50aWFsIGJhY2tvZmZcbiAqIHN0cmF0ZWd5IGhlbHBzIHByZXZlbnQgb3ZlcndoZWxtaW5nIGEgc3RydWdnbGluZyBzZXJ2ZXIgd2hpbGUgZ2l2aW5nIHRlbXBvcmFyeVxuICogaXNzdWVzIHRpbWUgdG8gcmVzb2x2ZS5cbiAqXG4gKiBLZXkgRmVhdHVyZXM6XG4gKiAtICoqRXhwb25lbnRpYWwgQmFja29mZioqOiBEb3VibGVzIGRlbGF5IGJldHdlZW4gcmV0cmllcyAoZS5nLiwgMXMsIDJzLCA0cywgOHMpXG4gKiAtICoqU21hcnQgRXJyb3IgRGV0ZWN0aW9uKio6IFNraXBzIHJldHJ5IGZvciBub24tcmV0cnlhYmxlIGVycm9ycyAodmFsaWRhdGlvbiwgYWJvcnRzKVxuICogLSAqKkFib3J0IFN1cHBvcnQqKjogUmVzcGVjdHMgY2FuY2VsbGF0aW9uIHNpZ25hbHMgZHVyaW5nIHJldHJ5IGRlbGF5c1xuICogLSAqKlR5cGUgU2FmZXR5Kio6IEZ1bGx5IGdlbmVyaWMgaW1wbGVtZW50YXRpb24gcHJlc2VydmluZyByZXR1cm4gdHlwZXNcbiAqXG4gKiBSZXRyeSBTdHJhdGVneTpcbiAqIC0gKipSZXRyeWFibGUqKjogTmV0d29yayBlcnJvcnMsIDV4eCBzZXJ2ZXIgZXJyb3JzLCB0aW1lb3V0c1xuICogLSAqKk5vbi1SZXRyeWFibGUqKjogVmFsaWRhdGlvbiBlcnJvcnMgKDQwMCksIEFib3J0RXJyb3JzLCBjYW5jZWxsZWQgcmVxdWVzdHNcbiAqXG4gKiBAaW50ZXJuYWwgVGhpcyBjbGFzcyBpcyBub3QgZXhwb3J0ZWQgZnJvbSB0aGUgcHVibGljIEFQSVxuICpcbiAqIEBleGFtcGxlXG4gKiBSZXRyeSBjb25maWd1cmF0aW9uIGluIEFwaUNsaWVudDpcbiAqIGBgYHR5cGVzY3JpcHRcbiAqIGNvbnN0IGNsaWVudCA9IG5ldyBBcGlDbGllbnQoJ2h0dHBzOi8vYXBpLmV4YW1wbGUuY29tJyk7XG4gKlxuICogLy8gUmV0cnkgdXAgdG8gMyB0aW1lcyB3aXRoIDFzIGluaXRpYWwgZGVsYXlcbiAqIGNvbnN0IHsgYXBpRGF0YSB9ID0gYXdhaXQgY2xpZW50LmdldCgnL3VzZXJzJywge1xuICogICByZXRyaWVzOiAzLFxuICogICByZXRyeURlbGF5OiAxMDAwICAvLyAxcywgMnMsIDRzXG4gKiB9KTtcbiAqIGBgYFxuICovXG5leHBvcnQgY2xhc3MgUmV0cnlIYW5kbGVyIHtcbiAgLyoqXG4gICAqIFJldHJpZXMgYSBmYWlsZWQgcmVxdWVzdCB3aXRoIGV4cG9uZW50aWFsIGJhY2tvZmYgc3RyYXRlZ3kuXG4gICAqXG4gICAqIFRoZSByZXRyeSBsb2dpYyB3b3JrcyBhcyBmb2xsb3dzOlxuICAgKiAxLiBBdHRlbXB0cyB0aGUgcmVxdWVzdCBpbW1lZGlhdGVseVxuICAgKiAyLiBPbiBmYWlsdXJlLCBjaGVja3MgaWYgdGhlIGVycm9yIGlzIHJldHJ5YWJsZVxuICAgKiAzLiBJZiByZXRyeWFibGUgYW5kIHJldHJpZXMgcmVtYWluLCB3YWl0cyBmb3IgdGhlIGN1cnJlbnQgZGVsYXlcbiAgICogNC4gRG91YmxlcyB0aGUgZGVsYXkgZm9yIHRoZSBuZXh0IGF0dGVtcHRcbiAgICogNS4gUmVwZWF0cyB1bnRpbCBzdWNjZXNzIG9yIHJldHJpZXMgZXhoYXVzdGVkXG4gICAqXG4gICAqICoqTm9uLVJldHJ5YWJsZSBFcnJvcnM6KipcbiAgICogLSBWYWxpZGF0aW9uIGVycm9ycyAoNDAwKSAtIENsaWVudCBzZW50IGJhZCBkYXRhXG4gICAqIC0gQWJvcnRFcnJvcnMgLSBSZXF1ZXN0IHdhcyBleHBsaWNpdGx5IGNhbmNlbGxlZFxuICAgKiAtIFJlcXVlc3RzIHdpdGggYWJvcnRlZCBzaWduYWxzXG4gICAqXG4gICAqICoqQWJvcnQgSGFuZGxpbmc6KipcbiAgICogSWYgdGhlIHNpZ25hbCBpcyBhYm9ydGVkIGR1cmluZyBhIHJldHJ5IGRlbGF5LCB0aGUgcmV0cnkgaXMgaW1tZWRpYXRlbHlcbiAgICogY2FuY2VsbGVkIGFuZCBhbiBBYm9ydEVycm9yIGlzIHRocm93bi5cbiAgICpcbiAgICogQHRlbXBsYXRlIFQgLSBUaGUgcmV0dXJuIHR5cGUgb2YgdGhlIGZ1bmN0aW9uIGJlaW5nIHJldHJpZWRcbiAgICogQHBhcmFtIGZuIC0gQXN5bmMgZnVuY3Rpb24gdG8gcmV0cnkgb24gZmFpbHVyZVxuICAgKiBAcGFyYW0gcmV0cmllcyAtIE51bWJlciBvZiByZXRyeSBhdHRlbXB0cyByZW1haW5pbmcgKGRlY3JlbWVudHMgZWFjaCByZXRyeSlcbiAgICogQHBhcmFtIGRlbGF5IC0gQ3VycmVudCBkZWxheSBpbiBtaWxsaXNlY29uZHMgYmVmb3JlIG5leHQgcmV0cnlcbiAgICogQHBhcmFtIHNpZ25hbCAtIE9wdGlvbmFsIEFib3J0U2lnbmFsIHRvIGNhbmNlbCByZXRyaWVzXG4gICAqIEByZXR1cm5zIFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSBmdW5jdGlvbidzIHJlc3VsdCBvbiBzdWNjZXNzXG4gICAqIEB0aHJvd3MgVGhlIGxhc3QgZXJyb3IgZW5jb3VudGVyZWQgaWYgYWxsIHJldHJpZXMgYXJlIGV4aGF1c3RlZFxuICAgKiBAdGhyb3dzIEFib3J0RXJyb3IgaWYgdGhlIHNpZ25hbCBpcyBhYm9ydGVkIGR1cmluZyBleGVjdXRpb24gb3IgZGVsYXlcbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICogQmFzaWMgcmV0cnkgdXNhZ2U6XG4gICAqIGBgYHR5cGVzY3JpcHRcbiAgICogY29uc3QgaGFuZGxlciA9IG5ldyBSZXRyeUhhbmRsZXIoKTtcbiAgICogY29uc3QgZmV0Y2hVc2VyID0gKCkgPT4gZmV0Y2goJy9hcGkvdXNlcnMvMTIzJykudGhlbihyID0+IHIuanNvbigpKTtcbiAgICpcbiAgICogdHJ5IHtcbiAgICogICBjb25zdCB1c2VyID0gYXdhaXQgaGFuZGxlci5yZXRyeVJlcXVlc3QoXG4gICAqICAgICBmZXRjaFVzZXIsXG4gICAqICAgICAzLCAgICAgIC8vIDMgcmV0cmllc1xuICAgKiAgICAgMTAwMCAgICAvLyBTdGFydCB3aXRoIDFzIGRlbGF5XG4gICAqICAgKTtcbiAgICogICBjb25zb2xlLmxvZygnVXNlcjonLCB1c2VyKTtcbiAgICogfSBjYXRjaCAoZXJyb3IpIHtcbiAgICogICBjb25zb2xlLmVycm9yKCdGYWlsZWQgYWZ0ZXIgYWxsIHJldHJpZXM6JywgZXJyb3IpO1xuICAgKiB9XG4gICAqIGBgYFxuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKiBXaXRoIGNhbmNlbGxhdGlvbiBzdXBwb3J0OlxuICAgKiBgYGB0eXBlc2NyaXB0XG4gICAqIGNvbnN0IGNvbnRyb2xsZXIgPSBuZXcgQWJvcnRDb250cm9sbGVyKCk7XG4gICAqIGNvbnN0IHNpZ25hbCA9IGNvbnRyb2xsZXIuc2lnbmFsO1xuICAgKlxuICAgKiAvLyBDYW5jZWwgYWZ0ZXIgNSBzZWNvbmRzXG4gICAqIHNldFRpbWVvdXQoKCkgPT4gY29udHJvbGxlci5hYm9ydCgpLCA1MDAwKTtcbiAgICpcbiAgICogdHJ5IHtcbiAgICogICBhd2FpdCBoYW5kbGVyLnJldHJ5UmVxdWVzdChmZXRjaFVzZXIsIDUsIDEwMDAsIHNpZ25hbCk7XG4gICAqIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAqICAgaWYgKGVycm9yLm5hbWUgPT09ICdBYm9ydEVycm9yJykge1xuICAgKiAgICAgY29uc29sZS5sb2coJ1JldHJ5IGNhbmNlbGxlZCcpO1xuICAgKiAgIH1cbiAgICogfVxuICAgKiBgYGBcbiAgICovXG4gIGFzeW5jIHJldHJ5UmVxdWVzdDxUPihcbiAgICBmbjogKCkgPT4gUHJvbWlzZTxUPixcbiAgICByZXRyaWVzOiBudW1iZXIsXG4gICAgZGVsYXk6IG51bWJlcixcbiAgICBzaWduYWw/OiBBYm9ydFNpZ25hbFxuICApOiBQcm9taXNlPFQ+IHtcbiAgICB0cnkge1xuICAgICAgLy8gQ2hlY2sgaWYgYWxyZWFkeSBhYm9ydGVkXG4gICAgICBpZiAoc2lnbmFsPy5hYm9ydGVkKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihzaWduYWwucmVhc29uIHx8ICdSZXF1ZXN0IGFib3J0ZWQnKTtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIGF3YWl0IGZuKCk7XG4gICAgfSBjYXRjaCAoZXJyb3I6IHVua25vd24pIHtcbiAgICAgIGNvbnN0IGVyciA9IGVycm9yIGFzIEFwaUVycm9yO1xuXG4gICAgICAvLyBEb24ndCByZXRyeSBpZiBhYm9ydGVkXG4gICAgICBpZiAoZXJyLm5hbWUgPT09ICdBYm9ydEVycm9yJyB8fCBzaWduYWw/LmFib3J0ZWQpIHtcbiAgICAgICAgdGhyb3cgZXJyb3I7XG4gICAgICB9XG5cbiAgICAgIC8vIERvbid0IHJldHJ5IHZhbGlkYXRpb24gZXJyb3JzXG4gICAgICBpZiAoZXJyLnR5cGUgPT09ICd2YWxpZGF0aW9uX2Vycm9yJyB8fCBlcnIuc3RhdHVzID09PSA0MDApIHtcbiAgICAgICAgdGhyb3cgZXJyb3I7XG4gICAgICB9XG5cbiAgICAgIGlmIChyZXRyaWVzID09PSAwKSB0aHJvdyBlcnJvcjtcblxuICAgICAgLy8gV2FpdCB3aXRoIGFib3J0IHN1cHBvcnRcbiAgICAgIGF3YWl0IG5ldyBQcm9taXNlPHZvaWQ+KChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgICAgY29uc3QgdGltZW91dElkID0gc2V0VGltZW91dChyZXNvbHZlLCBkZWxheSk7XG5cbiAgICAgICAgaWYgKHNpZ25hbCkge1xuICAgICAgICAgIHNpZ25hbC5hZGRFdmVudExpc3RlbmVyKFxuICAgICAgICAgICAgJ2Fib3J0JyxcbiAgICAgICAgICAgICgpID0+IHtcbiAgICAgICAgICAgICAgY2xlYXJUaW1lb3V0KHRpbWVvdXRJZCk7XG4gICAgICAgICAgICAgIHJlamVjdChuZXcgRXJyb3Ioc2lnbmFsLnJlYXNvbiB8fCAnUmVxdWVzdCBhYm9ydGVkJykpO1xuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHsgb25jZTogdHJ1ZSB9XG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgICAgfSk7XG5cbiAgICAgIHJldHVybiB0aGlzLnJldHJ5UmVxdWVzdChmbiwgcmV0cmllcyAtIDEsIGRlbGF5ICogMiwgc2lnbmFsKTtcbiAgICB9XG4gIH1cbn1cbiIsICIvKipcbiAqIE1hbmFnZXMgQWJvcnRTaWduYWwgY3JlYXRpb24gYW5kIGNvbXBvc2l0aW9uIGZvciByZXF1ZXN0IGNhbmNlbGxhdGlvbiBhbmQgdGltZW91dHMuXG4gKlxuICogVGhpcyBpbnRlcm5hbCBjbGFzcyBwcm92aWRlcyB1dGlsaXRpZXMgZm9yIHdvcmtpbmcgd2l0aCB0aGUgQWJvcnRTaWduYWwgQVBJLFxuICogZW5hYmxpbmcgc29waGlzdGljYXRlZCBjYW5jZWxsYXRpb24gcGF0dGVybnMgYnkgY29tYmluaW5nIG11bHRpcGxlIGNhbmNlbGxhdGlvblxuICogc291cmNlcyBhbmQgY3JlYXRpbmcgdGltZW91dC1iYXNlZCBzaWduYWxzLlxuICpcbiAqIEtleSBGZWF0dXJlczpcbiAqIC0gKipTaWduYWwgQ29tcG9zaXRpb24qKjogQ29tYmluZSBtdWx0aXBsZSBBYm9ydFNpZ25hbHMgaW50byBvbmVcbiAqIC0gKipUaW1lb3V0IFNpZ25hbHMqKjogQ3JlYXRlIHNpZ25hbHMgdGhhdCBhdXRvLWFib3J0IGFmdGVyIGEgZGVsYXlcbiAqIC0gKipFYXJseSBBYm9ydCBEZXRlY3Rpb24qKjogSW1tZWRpYXRlbHkgYWJvcnQgaWYgYW55IHNvdXJjZSBpcyBhbHJlYWR5IGFib3J0ZWRcbiAqIC0gKipSZXNvdXJjZSBDbGVhbnVwKio6IEF1dG9tYXRpYyB0aW1lb3V0IGNsZWFudXAgb24gYWJvcnRcbiAqXG4gKiBVc2UgQ2FzZXM6XG4gKiAtIENvbWJpbmUgdXNlciBjYW5jZWxsYXRpb24gKyB0aW1lb3V0ICsgY29tcG9uZW50IHVubW91bnQgc2lnbmFsc1xuICogLSBDcmVhdGUgcmVxdWVzdCBkZWFkbGluZXNcbiAqIC0gSW1wbGVtZW50IGNhc2NhZGluZyBjYW5jZWxsYXRpb25cbiAqXG4gKiBAaW50ZXJuYWwgVGhpcyBjbGFzcyBpcyBub3QgZXhwb3J0ZWQgZnJvbSB0aGUgcHVibGljIEFQSVxuICpcbiAqIEBleGFtcGxlXG4gKiBDb21iaW5pbmcgbXVsdGlwbGUgY2FuY2VsbGF0aW9uIHNvdXJjZXM6XG4gKiBgYGB0eXBlc2NyaXB0XG4gKiBjb25zdCBtYW5hZ2VyID0gbmV3IFNpZ25hbE1hbmFnZXIoKTtcbiAqIGNvbnN0IHVzZXJDYW5jZWwgPSBuZXcgQWJvcnRDb250cm9sbGVyKCk7XG4gKiBjb25zdCB1bm1vdW50U2lnbmFsID0gY29tcG9uZW50VW5tb3VudFNpZ25hbDtcbiAqXG4gKiAvLyBSZXF1ZXN0IHdpbGwgYmUgY2FuY2VsbGVkIGlmIGVpdGhlciB1c2VyIGNsaWNrcyBjYW5jZWwgT1IgY29tcG9uZW50IHVubW91bnRzXG4gKiBjb25zdCBjb21iaW5lZCA9IG1hbmFnZXIuY3JlYXRlQ29tYmluZWRTaWduYWwoW1xuICogICB1c2VyQ2FuY2VsLnNpZ25hbCxcbiAqICAgdW5tb3VudFNpZ25hbFxuICogXSk7XG4gKlxuICogZmV0Y2goJy9hcGkvZGF0YScsIHsgc2lnbmFsOiBjb21iaW5lZC5zaWduYWwgfSk7XG4gKiBgYGBcbiAqL1xuZXhwb3J0IGNsYXNzIFNpZ25hbE1hbmFnZXIge1xuICAvKipcbiAgICogQ3JlYXRlcyBhIGNvbWJpbmVkIEFib3J0Q29udHJvbGxlciB0aGF0IGFib3J0cyB3aGVuIGFueSBzb3VyY2Ugc2lnbmFsIGFib3J0cy5cbiAgICpcbiAgICogVGhpcyBtZXRob2QgaW1wbGVtZW50cyB0aGUgXCJhbnlcIiBwYXR0ZXJuIGZvciBjYW5jZWxsYXRpb246IHRoZSBjb21iaW5lZCBzaWduYWxcbiAgICogd2lsbCBhYm9ydCBhcyBzb29uIGFzIEFOWSBvZiB0aGUgc291cmNlIHNpZ25hbHMgYWJvcnQuIFRoaXMgaXMgdXNlZnVsIGZvclxuICAgKiBjb29yZGluYXRpbmcgbXVsdGlwbGUgY2FuY2VsbGF0aW9uIGNvbmRpdGlvbnM6XG4gICAqIC0gVXNlciBjbGlja3MgY2FuY2VsIGJ1dHRvblxuICAgKiAtIFJlcXVlc3QgdGltZW91dCBleHBpcmVzXG4gICAqIC0gQ29tcG9uZW50IHVubW91bnRzXG4gICAqIC0gUGFyZW50IHJlcXVlc3QgaXMgY2FuY2VsbGVkXG4gICAqXG4gICAqICoqRWFybHkgQWJvcnQgT3B0aW1pemF0aW9uOioqXG4gICAqIElmIGFueSBzb3VyY2Ugc2lnbmFsIGlzIGFscmVhZHkgYWJvcnRlZCB3aGVuIHRoaXMgbWV0aG9kIGlzIGNhbGxlZCxcbiAgICogdGhlIHJldHVybmVkIGNvbnRyb2xsZXIgaXMgaW1tZWRpYXRlbHkgYWJvcnRlZCB3aXRob3V0IHNldHRpbmcgdXAgbGlzdGVuZXJzLlxuICAgKlxuICAgKiAqKk1lbW9yeSBNYW5hZ2VtZW50OioqXG4gICAqIEV2ZW50IGxpc3RlbmVycyBhcmUgcmVnaXN0ZXJlZCB3aXRoIGB7IG9uY2U6IHRydWUgfWAgdG8gcHJldmVudCBtZW1vcnkgbGVha3MsXG4gICAqIGFzIHRoZXkgYXV0b21hdGljYWxseSBjbGVhbiB1cCBhZnRlciBmaXJpbmcuXG4gICAqXG4gICAqIEBwYXJhbSBzaWduYWxzIC0gQXJyYXkgb2YgQWJvcnRTaWduYWxzIHRvIGNvbWJpbmUgKHVuZGVmaW5lZCB2YWx1ZXMgYXJlIGlnbm9yZWQpXG4gICAqIEByZXR1cm5zIEEgbmV3IEFib3J0Q29udHJvbGxlciB0aGF0IGFib3J0cyB3aGVuIGFueSBzb3VyY2Ugc2lnbmFsIGFib3J0c1xuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKiBVc2VyIGNhbmNlbGxhdGlvbiArIHRpbWVvdXQ6XG4gICAqIGBgYHR5cGVzY3JpcHRcbiAgICogY29uc3QgdXNlckNvbnRyb2xsZXIgPSBuZXcgQWJvcnRDb250cm9sbGVyKCk7XG4gICAqIGNvbnN0IHRpbWVvdXQgPSBtYW5hZ2VyLmNyZWF0ZVRpbWVvdXRTaWduYWwoMzAwMDApO1xuICAgKlxuICAgKiBjb25zdCBjb21iaW5lZCA9IG1hbmFnZXIuY3JlYXRlQ29tYmluZWRTaWduYWwoW1xuICAgKiAgIHVzZXJDb250cm9sbGVyLnNpZ25hbCxcbiAgICogICB0aW1lb3V0LnNpZ25hbFxuICAgKiBdKTtcbiAgICpcbiAgICogLy8gUmVxdWVzdCB3aWxsIGJlIGNhbmNlbGxlZCBhZnRlciAzMHMgT1Igd2hlbiB1c2VyIGNsaWNrcyBjYW5jZWxcbiAgICogZmV0Y2goJy9hcGkvZGF0YScsIHsgc2lnbmFsOiBjb21iaW5lZC5zaWduYWwgfSk7XG4gICAqIGBgYFxuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKiBSZWFjdCBjb21wb25lbnQgd2l0aCBjbGVhbnVwOlxuICAgKiBgYGB0eXBlc2NyaXB0XG4gICAqIHVzZUVmZmVjdCgoKSA9PiB7XG4gICAqICAgY29uc3QgY29udHJvbGxlciA9IG5ldyBBYm9ydENvbnRyb2xsZXIoKTtcbiAgICpcbiAgICogICBjb25zdCBjb21iaW5lZCA9IG1hbmFnZXIuY3JlYXRlQ29tYmluZWRTaWduYWwoW1xuICAgKiAgICAgY29udHJvbGxlci5zaWduYWwsXG4gICAqICAgICB1bm1vdW50U2lnbmFsICAvLyBGcm9tIGNvbXBvbmVudCBsaWZlY3ljbGVcbiAgICogICBdKTtcbiAgICpcbiAgICogICBmZXRjaERhdGEoY29tYmluZWQuc2lnbmFsKTtcbiAgICpcbiAgICogICByZXR1cm4gKCkgPT4gY29udHJvbGxlci5hYm9ydCgpOyAvLyBDbGVhbnVwXG4gICAqIH0sIFtdKTtcbiAgICogYGBgXG4gICAqL1xuICBjcmVhdGVDb21iaW5lZFNpZ25hbChcbiAgICBzaWduYWxzOiBBcnJheTxBYm9ydFNpZ25hbCB8IHVuZGVmaW5lZD5cbiAgKTogQWJvcnRDb250cm9sbGVyIHtcbiAgICBjb25zdCBjb250cm9sbGVyID0gbmV3IEFib3J0Q29udHJvbGxlcigpO1xuXG4gICAgZm9yIChjb25zdCBzaWduYWwgb2Ygc2lnbmFscykge1xuICAgICAgaWYgKHNpZ25hbCkge1xuICAgICAgICBpZiAoc2lnbmFsLmFib3J0ZWQpIHtcbiAgICAgICAgICBjb250cm9sbGVyLmFib3J0KHNpZ25hbC5yZWFzb24pO1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgICB9XG5cbiAgICAgICAgc2lnbmFsLmFkZEV2ZW50TGlzdGVuZXIoXG4gICAgICAgICAgJ2Fib3J0JyxcbiAgICAgICAgICAoKSA9PiB7XG4gICAgICAgICAgICBjb250cm9sbGVyLmFib3J0KHNpZ25hbC5yZWFzb24pO1xuICAgICAgICAgIH0sXG4gICAgICAgICAgeyBvbmNlOiB0cnVlIH1cbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gY29udHJvbGxlcjtcbiAgfVxuXG4gIC8qKlxuICAgKiBDcmVhdGVzIGFuIEFib3J0Q29udHJvbGxlciB0aGF0IGF1dG9tYXRpY2FsbHkgYWJvcnRzIGFmdGVyIGEgc3BlY2lmaWVkIHRpbWVvdXQuXG4gICAqXG4gICAqIFRoaXMgbWV0aG9kIGNyZWF0ZXMgYSB0aW1lLWJhc2VkIGNhbmNlbGxhdGlvbiBtZWNoYW5pc20gdXNlZnVsIGZvciBpbXBsZW1lbnRpbmdcbiAgICogcmVxdWVzdCB0aW1lb3V0cyBhbmQgZGVhZGxpbmVzLiBUaGUgc2lnbmFsIHdpbGwgYXV0b21hdGljYWxseSBhYm9ydCBhZnRlciB0aGVcbiAgICogc3BlY2lmaWVkIGR1cmF0aW9uLCBwcm92aWRpbmcgYSBjb25zaXN0ZW50IHRpbWVvdXQgZXhwZXJpZW5jZS5cbiAgICpcbiAgICogKipBdXRvbWF0aWMgQ2xlYW51cDoqKlxuICAgKiBJZiB0aGUgc2lnbmFsIGlzIGFib3J0ZWQgYnkgb3RoZXIgbWVhbnMgYmVmb3JlIHRoZSB0aW1lb3V0IGV4cGlyZXMsIHRoZSBpbnRlcm5hbFxuICAgKiBzZXRUaW1lb3V0IGlzIGF1dG9tYXRpY2FsbHkgY2xlYXJlZCB0byBwcmV2ZW50IG1lbW9yeSBsZWFrcy5cbiAgICpcbiAgICogKipBYm9ydCBSZWFzb246KipcbiAgICogVGhlIGFib3J0IHJlYXNvbiBpbmNsdWRlcyB0aGUgdGltZW91dCBkdXJhdGlvbiBmb3IgZGVidWdnaW5nIHB1cnBvc2VzOlxuICAgKiBgXCJSZXF1ZXN0IHRpbWVvdXQgYWZ0ZXIge3RpbWVvdXR9bXNcImBcbiAgICpcbiAgICogQHBhcmFtIHRpbWVvdXQgLSBUaW1lb3V0IGR1cmF0aW9uIGluIG1pbGxpc2Vjb25kc1xuICAgKiBAcmV0dXJucyBBbiBBYm9ydENvbnRyb2xsZXIgdGhhdCB3aWxsIGFib3J0IGFmdGVyIHRoZSB0aW1lb3V0XG4gICAqXG4gICAqIEBleGFtcGxlXG4gICAqIFNpbXBsZSByZXF1ZXN0IHRpbWVvdXQ6XG4gICAqIGBgYHR5cGVzY3JpcHRcbiAgICogY29uc3QgbWFuYWdlciA9IG5ldyBTaWduYWxNYW5hZ2VyKCk7XG4gICAqIGNvbnN0IHRpbWVvdXQgPSBtYW5hZ2VyLmNyZWF0ZVRpbWVvdXRTaWduYWwoNTAwMCk7IC8vIDUgc2Vjb25kc1xuICAgKlxuICAgKiB0cnkge1xuICAgKiAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgZmV0Y2goJy9hcGkvc2xvdy1lbmRwb2ludCcsIHtcbiAgICogICAgIHNpZ25hbDogdGltZW91dC5zaWduYWxcbiAgICogICB9KTtcbiAgICogICBjb25zdCBkYXRhID0gYXdhaXQgcmVzcG9uc2UuanNvbigpO1xuICAgKiB9IGNhdGNoIChlcnJvcikge1xuICAgKiAgIGlmIChlcnJvci5uYW1lID09PSAnQWJvcnRFcnJvcicpIHtcbiAgICogICAgIGNvbnNvbGUuZXJyb3IoJ1JlcXVlc3QgdGltZWQgb3V0IGFmdGVyIDUgc2Vjb25kcycpO1xuICAgKiAgIH1cbiAgICogfVxuICAgKiBgYGBcbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICogRGlmZmVyZW50IHRpbWVvdXRzIGZvciBkaWZmZXJlbnQgb3BlcmF0aW9uczpcbiAgICogYGBgdHlwZXNjcmlwdFxuICAgKiAvLyBTaG9ydCB0aW1lb3V0IGZvciBxdWljayBvcGVyYXRpb25zXG4gICAqIGNvbnN0IHF1aWNrVGltZW91dCA9IG1hbmFnZXIuY3JlYXRlVGltZW91dFNpZ25hbCgyMDAwKTtcbiAgICogYXdhaXQgZmV0Y2goJy9hcGkvaGVhbHRoJywgeyBzaWduYWw6IHF1aWNrVGltZW91dC5zaWduYWwgfSk7XG4gICAqXG4gICAqIC8vIExvbmcgdGltZW91dCBmb3IgaGVhdnkgb3BlcmF0aW9uc1xuICAgKiBjb25zdCBsb25nVGltZW91dCA9IG1hbmFnZXIuY3JlYXRlVGltZW91dFNpZ25hbCg2MDAwMCk7XG4gICAqIGF3YWl0IGZldGNoKCcvYXBpL2V4cG9ydCcsIHsgc2lnbmFsOiBsb25nVGltZW91dC5zaWduYWwgfSk7XG4gICAqIGBgYFxuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKiBNYW51YWwgY2FuY2VsbGF0aW9uIGJlZm9yZSB0aW1lb3V0OlxuICAgKiBgYGB0eXBlc2NyaXB0XG4gICAqIGNvbnN0IHRpbWVvdXQgPSBtYW5hZ2VyLmNyZWF0ZVRpbWVvdXRTaWduYWwoMzAwMDApO1xuICAgKlxuICAgKiAvLyBJZiB1c2VyIGNhbmNlbHMsIHRpbWVvdXQgaXMgYXV0b21hdGljYWxseSBjbGVhbmVkIHVwXG4gICAqIHRpbWVvdXQuYWJvcnQoJ1VzZXIgY2FuY2VsbGVkJyk7XG4gICAqIC8vIEludGVybmFsIHNldFRpbWVvdXQgaXMgY2xlYXJlZCwgbm8gbWVtb3J5IGxlYWtcbiAgICogYGBgXG4gICAqL1xuICBjcmVhdGVUaW1lb3V0U2lnbmFsKHRpbWVvdXQ6IG51bWJlcik6IEFib3J0Q29udHJvbGxlciB7XG4gICAgY29uc3QgY29udHJvbGxlciA9IG5ldyBBYm9ydENvbnRyb2xsZXIoKTtcblxuICAgIGNvbnN0IHRpbWVvdXRJZCA9IHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgY29udHJvbGxlci5hYm9ydChgUmVxdWVzdCB0aW1lb3V0IGFmdGVyICR7dGltZW91dH1tc2ApO1xuICAgIH0sIHRpbWVvdXQpO1xuXG4gICAgLy8gQ2xlYW4gdXAgdGltZW91dCB3aGVuIHNpZ25hbCBpcyBhYm9ydGVkXG4gICAgY29udHJvbGxlci5zaWduYWwuYWRkRXZlbnRMaXN0ZW5lcihcbiAgICAgICdhYm9ydCcsXG4gICAgICAoKSA9PiB7XG4gICAgICAgIGNsZWFyVGltZW91dCh0aW1lb3V0SWQpO1xuICAgICAgfSxcbiAgICAgIHsgb25jZTogdHJ1ZSB9XG4gICAgKTtcblxuICAgIHJldHVybiBjb250cm9sbGVyO1xuICB9XG59XG4iLCAiaW1wb3J0IHR5cGUgeyBSZXNwb25zZURhdGEgfSBmcm9tICcuLi9Nb2RlbHMnO1xuXG4vKipcbiAqIFBhcnNlcyBIVFRQIHJlc3BvbnNlIGJvZGllcyBpbnRvIGFwcHJvcHJpYXRlIEphdmFTY3JpcHQgdHlwZXMgYmFzZWQgb24gQ29udGVudC1UeXBlIGhlYWRlcnMuXG4gKlxuICogVGhpcyBpbnRlcm5hbCBjbGFzcyBoYW5kbGVzIHRoZSBjb21wbGV4aXR5IG9mIGNvbnZlcnRpbmcgdmFyaW91cyBIVFRQIHJlc3BvbnNlIGZvcm1hdHNcbiAqIGludG8gdXNhYmxlIEphdmFTY3JpcHQgZGF0YSBzdHJ1Y3R1cmVzLiBJdCBpbnRlbGxpZ2VudGx5IGRldGVjdHMgdGhlIHJlc3BvbnNlIHR5cGVcbiAqIGFuZCBhcHBsaWVzIHRoZSBhcHByb3ByaWF0ZSBwYXJzaW5nIHN0cmF0ZWd5LlxuICpcbiAqIFN1cHBvcnRlZCBDb250ZW50IFR5cGVzOlxuICogLSAqKmFwcGxpY2F0aW9uL2pzb24qKjogUGFyc2VkIGFzIEpTT04gb2JqZWN0cy9hcnJheXNcbiAqIC0gKip0ZXh0LyoqKiAodGV4dC9wbGFpbiwgdGV4dC9odG1sLCBldGMuKTogUmV0dXJuZWQgYXMgc3RyaW5nXG4gKiAtICoqYXBwbGljYXRpb24vb2N0ZXQtc3RyZWFtKio6IFJldHVybmVkIGFzIEJsb2IgZm9yIGJpbmFyeSBkYXRhXG4gKiAtICoqVW5rbm93bi9NaXNzaW5nKio6IEF0dGVtcHRzIEpTT04gcGFyc2UsIGZhbGxzIGJhY2sgdG8gdGV4dFxuICpcbiAqIEtleSBGZWF0dXJlczpcbiAqIC0gKipBdXRvbWF0aWMgRGV0ZWN0aW9uKio6IFVzZXMgQ29udGVudC1UeXBlIGhlYWRlciB0byBkZXRlcm1pbmUgcGFyc2luZyBzdHJhdGVneVxuICogLSAqKkdyYWNlZnVsIEZhbGxiYWNrKio6IEF0dGVtcHRzIEpTT04gcGFyc2luZyBmb3IgdW5rbm93biB0eXBlcywgZmFsbHMgYmFjayB0byB0ZXh0XG4gKiAtICoqQmluYXJ5IFN1cHBvcnQqKjogSGFuZGxlcyBiaW5hcnkgZGF0YSB2aWEgQmxvYlxuICogLSAqKlR5cGUgU2FmZXR5Kio6IFJldHVybnMgdHlwZWQgUmVzcG9uc2VEYXRhIHVuaW9uXG4gKlxuICogQGludGVybmFsIFRoaXMgY2xhc3MgaXMgbm90IGV4cG9ydGVkIGZyb20gdGhlIHB1YmxpYyBBUElcbiAqXG4gKiBAZXhhbXBsZVxuICogUGFyc2luZyBkaWZmZXJlbnQgcmVzcG9uc2UgdHlwZXM6XG4gKiBgYGB0eXBlc2NyaXB0XG4gKiBjb25zdCBwYXJzZXIgPSBuZXcgUmVzcG9uc2VQYXJzZXIoKTtcbiAqXG4gKiAvLyBKU09OIHJlc3BvbnNlXG4gKiBjb25zdCBqc29uUmVzcG9uc2UgPSBuZXcgUmVzcG9uc2UoJ3tcImlkXCI6IDF9Jywge1xuICogICBoZWFkZXJzOiB7ICdDb250ZW50LVR5cGUnOiAnYXBwbGljYXRpb24vanNvbicgfVxuICogfSk7XG4gKiBjb25zdCBkYXRhID0gYXdhaXQgcGFyc2VyLnBhcnNlUmVzcG9uc2UoanNvblJlc3BvbnNlKTtcbiAqIC8vID0+IHsgaWQ6IDEgfVxuICpcbiAqIC8vIFRleHQgcmVzcG9uc2VcbiAqIGNvbnN0IHRleHRSZXNwb25zZSA9IG5ldyBSZXNwb25zZSgnSGVsbG8gV29ybGQnLCB7XG4gKiAgIGhlYWRlcnM6IHsgJ0NvbnRlbnQtVHlwZSc6ICd0ZXh0L3BsYWluJyB9XG4gKiB9KTtcbiAqIGNvbnN0IHRleHQgPSBhd2FpdCBwYXJzZXIucGFyc2VSZXNwb25zZSh0ZXh0UmVzcG9uc2UpO1xuICogLy8gPT4gXCJIZWxsbyBXb3JsZFwiXG4gKlxuICogLy8gQmluYXJ5IHJlc3BvbnNlXG4gKiBjb25zdCBibG9iUmVzcG9uc2UgPSBuZXcgUmVzcG9uc2UoYmluYXJ5RGF0YSwge1xuICogICBoZWFkZXJzOiB7ICdDb250ZW50LVR5cGUnOiAnYXBwbGljYXRpb24vb2N0ZXQtc3RyZWFtJyB9XG4gKiB9KTtcbiAqIGNvbnN0IGJsb2IgPSBhd2FpdCBwYXJzZXIucGFyc2VSZXNwb25zZShibG9iUmVzcG9uc2UpO1xuICogLy8gPT4gQmxvYiB7IC4uLiB9XG4gKiBgYGBcbiAqL1xuZXhwb3J0IGNsYXNzIFJlc3BvbnNlUGFyc2VyIHtcbiAgLyoqXG4gICAqIFBhcnNlcyB0aGUgSFRUUCByZXNwb25zZSBib2R5IGludG8gYW4gYXBwcm9wcmlhdGUgSmF2YVNjcmlwdCB0eXBlLlxuICAgKlxuICAgKiBUaGUgcGFyc2luZyBzdHJhdGVneSBpcyBkZXRlcm1pbmVkIGJ5IHRoZSBDb250ZW50LVR5cGUgaGVhZGVyOlxuICAgKiAxLiAqKkpTT04qKiAoYXBwbGljYXRpb24vanNvbik6IENhbGxzIGByZXNwb25zZS5qc29uKClgXG4gICAqIDIuICoqVGV4dCoqICh0ZXh0LyopOiBDYWxscyBgcmVzcG9uc2UudGV4dCgpYFxuICAgKiAzLiAqKkJpbmFyeSoqIChhcHBsaWNhdGlvbi9vY3RldC1zdHJlYW0pOiBDYWxscyBgcmVzcG9uc2UuYmxvYigpYFxuICAgKiA0LiAqKlVua25vd24qKjogUmVhZHMgYXMgdGV4dCwgYXR0ZW1wdHMgSlNPTiBwYXJzZSwgZmFsbHMgYmFjayB0byByYXcgdGV4dFxuICAgKlxuICAgKiAqKkZhbGxiYWNrIEJlaGF2aW9yOioqXG4gICAqIEZvciByZXNwb25zZXMgd2l0aG91dCBhIENvbnRlbnQtVHlwZSBoZWFkZXIgb3Igd2l0aCB1bmtub3duIHR5cGVzLCB0aGUgcGFyc2VyXG4gICAqIGF0dGVtcHRzIHRvIHBhcnNlIGFzIEpTT04gZmlyc3QgKGNvbW1vbiBmb3IgQVBJcyB0aGF0IGRvbid0IHNldCBwcm9wZXIgaGVhZGVycykuXG4gICAqIElmIEpTT04gcGFyc2luZyBmYWlscywgaXQgcmV0dXJucyB0aGUgcmF3IHRleHQuXG4gICAqXG4gICAqIEBwYXJhbSByZXNwb25zZSAtIFRoZSBGZXRjaCBBUEkgUmVzcG9uc2Ugb2JqZWN0IHRvIHBhcnNlXG4gICAqIEByZXR1cm5zIFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSBwYXJzZWQgcmVzcG9uc2UgZGF0YVxuICAgKiBAcmV0dXJucyBDYW4gYmU6IEpTT04gb2JqZWN0L2FycmF5LCBzdHJpbmcsIG9yIEJsb2IgZGVwZW5kaW5nIG9uIENvbnRlbnQtVHlwZVxuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKiBBUEkgcmVzcG9uc2UgcGFyc2luZzpcbiAgICogYGBgdHlwZXNjcmlwdFxuICAgKiBjb25zdCByZXNwb25zZSA9IGF3YWl0IGZldGNoKCcvYXBpL3VzZXJzJyk7XG4gICAqIGNvbnN0IGRhdGEgPSBhd2FpdCBwYXJzZXIucGFyc2VSZXNwb25zZShyZXNwb25zZSk7XG4gICAqXG4gICAqIGlmICh0eXBlb2YgZGF0YSA9PT0gJ3N0cmluZycpIHtcbiAgICogICBjb25zb2xlLmxvZygnVGV4dCByZXNwb25zZTonLCBkYXRhKTtcbiAgICogfSBlbHNlIGlmIChkYXRhIGluc3RhbmNlb2YgQmxvYikge1xuICAgKiAgIGNvbnNvbGUubG9nKCdCaW5hcnkgcmVzcG9uc2U6JywgZGF0YS5zaXplLCAnYnl0ZXMnKTtcbiAgICogfSBlbHNlIHtcbiAgICogICBjb25zb2xlLmxvZygnSlNPTiByZXNwb25zZTonLCBkYXRhKTtcbiAgICogfVxuICAgKiBgYGBcbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICogSGFuZGxpbmcgZGlmZmVyZW50IGNvbnRlbnQgdHlwZXM6XG4gICAqIGBgYHR5cGVzY3JpcHRcbiAgICogLy8gQ1NWIGZpbGUgZG93bmxvYWRcbiAgICogY29uc3QgY3N2UmVzcG9uc2UgPSBhd2FpdCBmZXRjaCgnL2FwaS9leHBvcnQuY3N2Jyk7XG4gICAqIGNvbnN0IGJsb2IgPSBhd2FpdCBwYXJzZXIucGFyc2VSZXNwb25zZShjc3ZSZXNwb25zZSk7XG4gICAqIC8vIFJldHVybnMgQmxvYiBmb3IgZG93bmxvYWRcbiAgICpcbiAgICogLy8gSlNPTiBBUElcbiAgICogY29uc3QganNvblJlc3BvbnNlID0gYXdhaXQgZmV0Y2goJy9hcGkvdXNlcnMnKTtcbiAgICogY29uc3QgdXNlcnMgPSBhd2FpdCBwYXJzZXIucGFyc2VSZXNwb25zZShqc29uUmVzcG9uc2UpO1xuICAgKiAvLyBSZXR1cm5zIHBhcnNlZCBKU09OIGFycmF5XG4gICAqXG4gICAqIC8vIFBsYWluIHRleHQgbG9nc1xuICAgKiBjb25zdCBsb2dSZXNwb25zZSA9IGF3YWl0IGZldGNoKCcvYXBpL2xvZ3MnKTtcbiAgICogY29uc3QgbG9ncyA9IGF3YWl0IHBhcnNlci5wYXJzZVJlc3BvbnNlKGxvZ1Jlc3BvbnNlKTtcbiAgICogLy8gUmV0dXJucyBzdHJpbmdcbiAgICogYGBgXG4gICAqL1xuICBhc3luYyBwYXJzZVJlc3BvbnNlKHJlc3BvbnNlOiBSZXNwb25zZSk6IFByb21pc2U8UmVzcG9uc2VEYXRhPiB7XG4gICAgY29uc3QgY29udGVudFR5cGUgPSByZXNwb25zZS5oZWFkZXJzLmdldCgnY29udGVudC10eXBlJyk7XG5cbiAgICBpZiAoY29udGVudFR5cGU/LmluY2x1ZGVzKCdhcHBsaWNhdGlvbi9qc29uJykpIHtcbiAgICAgIHJldHVybiByZXNwb25zZS5qc29uKCk7XG4gICAgfSBlbHNlIGlmIChjb250ZW50VHlwZT8uaW5jbHVkZXMoJ3RleHQvJykpIHtcbiAgICAgIHJldHVybiByZXNwb25zZS50ZXh0KCk7XG4gICAgfSBlbHNlIGlmIChjb250ZW50VHlwZT8uaW5jbHVkZXMoJ2FwcGxpY2F0aW9uL29jdGV0LXN0cmVhbScpKSB7XG4gICAgICByZXR1cm4gcmVzcG9uc2UuYmxvYigpO1xuICAgIH0gZWxzZSB7XG4gICAgICAvLyBUcnkgSlNPTiBmaXJzdCwgZmFsbGJhY2sgdG8gdGV4dFxuICAgICAgY29uc3QgdGV4dCA9IGF3YWl0IHJlc3BvbnNlLnRleHQoKTtcblxuICAgICAgdHJ5IHtcbiAgICAgICAgcmV0dXJuIEpTT04ucGFyc2UodGV4dCkgYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj47XG4gICAgICB9IGNhdGNoIHtcbiAgICAgICAgcmV0dXJuIHRleHQ7XG4gICAgICB9XG4gICAgfVxuICB9XG59XG4iLCAiaW1wb3J0IHR5cGUgeyBRdWVyeVBhcmFtcyB9IGZyb20gJy4uL01vZGVscyc7XHJcblxyXG4vKipcclxuICogQ29uc3RydWN0cyBmdWxseS1xdWFsaWZpZWQgVVJMcyB3aXRoIHByb3BlciBxdWVyeSBwYXJhbWV0ZXIgZW5jb2RpbmcuXHJcbiAqXHJcbiAqIFRoaXMgaW50ZXJuYWwgY2xhc3MgaGFuZGxlcyB0aGUgY29tcGxleGl0eSBvZiBVUkwgY29uc3RydWN0aW9uLCBjb21iaW5pbmdcclxuICogYmFzZSBVUkxzLCBlbmRwb2ludHMsIGFuZCBxdWVyeSBwYXJhbWV0ZXJzIHdpdGggcHJvcGVyIGVuY29kaW5nIGFuZCBhcnJheVxyXG4gKiBoYW5kbGluZy4gSXQgdXNlcyB0aGUgbmF0aXZlIFVSTCBBUEkgZm9yIHJlbGlhYmxlIFVSTCBjb21wb3NpdGlvbi5cclxuICpcclxuICogS2V5IEZlYXR1cmVzOlxyXG4gKiAtICoqVVJMIENvbXBvc2l0aW9uKio6IFNhZmVseSBjb21iaW5lcyBiYXNlIFVSTCBhbmQgZW5kcG9pbnQgcGF0aHNcclxuICogLSAqKlF1ZXJ5IFBhcmFtZXRlciBFbmNvZGluZyoqOiBBdXRvbWF0aWMgZW5jb2Rpbmcgb2Ygc3BlY2lhbCBjaGFyYWN0ZXJzXHJcbiAqIC0gKipBcnJheSBTdXBwb3J0Kio6IEhhbmRsZXMgYXJyYXkgcGFyYW1ldGVycyB3aXRoIG11bHRpcGxlIHZhbHVlc1xyXG4gKiAtICoqTnVsbC9VbmRlZmluZWQgRmlsdGVyaW5nKio6IEF1dG9tYXRpY2FsbHkgc2tpcHMgbnVsbC91bmRlZmluZWQgdmFsdWVzXHJcbiAqIC0gKipUeXBlIFNhZmV0eSoqOiBTdHJvbmdseSB0eXBlZCBxdWVyeSBwYXJhbWV0ZXIgdmFsdWVzXHJcbiAqXHJcbiAqIEFycmF5IEhhbmRsaW5nOlxyXG4gKiBBcnJheSBwYXJhbWV0ZXJzIGFyZSBzZXJpYWxpemVkIGJ5IGFwcGVuZGluZyB0aGUgc2FtZSBrZXkgbXVsdGlwbGUgdGltZXM6XHJcbiAqIGA/dGFncz1qYXZhc2NyaXB0JnRhZ3M9dHlwZXNjcmlwdCZ0YWdzPXJlYWN0YFxyXG4gKlxyXG4gKiBAaW50ZXJuYWwgVGhpcyBjbGFzcyBpcyBub3QgZXhwb3J0ZWQgZnJvbSB0aGUgcHVibGljIEFQSVxyXG4gKlxyXG4gKiBAZXhhbXBsZVxyXG4gKiBCdWlsZGluZyBVUkxzIHdpdGggcXVlcnkgcGFyYW1ldGVyczpcclxuICogYGBgdHlwZXNjcmlwdFxyXG4gKiBjb25zdCBidWlsZGVyID0gbmV3IFVybEJ1aWxkZXIoKTtcclxuICpcclxuICogY29uc3QgdXJsID0gYnVpbGRlci5idWlsZFVSTChcclxuICogICAnaHR0cHM6Ly9hcGkuZXhhbXBsZS5jb20nLFxyXG4gKiAgICcvdXNlcnMnLFxyXG4gKiAgIHsgYWN0aXZlOiB0cnVlLCByb2xlOiAnYWRtaW4nLCBwYWdlOiAxIH1cclxuICogKTtcclxuICogLy8gPT4gXCJodHRwczovL2FwaS5leGFtcGxlLmNvbS91c2Vycz9hY3RpdmU9dHJ1ZSZyb2xlPWFkbWluJnBhZ2U9MVwiXHJcbiAqIGBgYFxyXG4gKi9cclxuZXhwb3J0IGNsYXNzIFVybEJ1aWxkZXIge1xyXG4gIC8qKlxyXG4gICAqIEJ1aWxkcyBhIGNvbXBsZXRlIFVSTCBieSBjb21iaW5pbmcgYmFzZSBVUkwsIGVuZHBvaW50LCBhbmQgcXVlcnkgcGFyYW1ldGVycy5cclxuICAgKlxyXG4gICAqIFRoZSBVUkwgY29uc3RydWN0aW9uIHByb2Nlc3M6XHJcbiAgICogMS4gQ29tYmluZXMgYGJhc2VVUkxgIGFuZCBgZW5kcG9pbnRgIHVzaW5nIFVSTCBBUElcclxuICAgKiAyLiBJdGVyYXRlcyB0aHJvdWdoIHF1ZXJ5IHBhcmFtZXRlcnNcclxuICAgKiAzLiBTa2lwcyBudWxsL3VuZGVmaW5lZCB2YWx1ZXNcclxuICAgKiA0LiBIYW5kbGVzIGFycmF5cyBieSBhcHBlbmRpbmcgbXVsdGlwbGUgdmFsdWVzIHdpdGggc2FtZSBrZXlcclxuICAgKiA1LiBDb252ZXJ0cyBhbGwgdmFsdWVzIHRvIHN0cmluZ3NcclxuICAgKiA2LiBSZXR1cm5zIGZ1bGx5LXF1YWxpZmllZCBVUkwgc3RyaW5nXHJcbiAgICpcclxuICAgKiAqKlBhdGggSGFuZGxpbmc6KipcclxuICAgKiBUaGUgZW5kcG9pbnQgY2FuIGJlIGVpdGhlciByZWxhdGl2ZSBvciBhYnNvbHV0ZTpcclxuICAgKiAtIFJlbGF0aXZlOiBgL3VzZXJzYCBcdTIxOTIgQ29tYmluZWQgd2l0aCBiYXNlVVJMXHJcbiAgICogLSBBYnNvbHV0ZTogYGh0dHBzOi8vb3RoZXItYXBpLmNvbS91c2Vyc2AgXHUyMTkyIFVzZXMgYWJzb2x1dGUgVVJMXHJcbiAgICpcclxuICAgKiAqKkVuY29kaW5nOioqXHJcbiAgICogQWxsIHBhcmFtZXRlciB2YWx1ZXMgYXJlIGF1dG9tYXRpY2FsbHkgVVJMLWVuY29kZWQgYnkgdGhlIFVSTCBBUEksXHJcbiAgICogc28gc3BlY2lhbCBjaGFyYWN0ZXJzIChzcGFjZXMsICYsID0sIGV0Yy4pIGFyZSBzYWZlbHkgaGFuZGxlZC5cclxuICAgKlxyXG4gICAqIEBwYXJhbSBiYXNlVVJMIC0gQmFzZSBVUkwgZm9yIHRoZSBBUEkgKGUuZy4sICdodHRwczovL2FwaS5leGFtcGxlLmNvbScpXHJcbiAgICogQHBhcmFtIGVuZHBvaW50IC0gQVBJIGVuZHBvaW50IHBhdGggcmVsYXRpdmUgdG8gYmFzZVVSTCAoZS5nLiwgJy91c2Vycy8xMjMnKVxyXG4gICAqIEBwYXJhbSBwYXJhbXMgLSBPcHRpb25hbCBxdWVyeSBwYXJhbWV0ZXJzIGFzIGtleS12YWx1ZSBwYWlyc1xyXG4gICAqIEByZXR1cm5zIFRoZSBmdWxseS1xdWFsaWZpZWQgVVJMIHN0cmluZyB3aXRoIGVuY29kZWQgcXVlcnkgcGFyYW1ldGVyc1xyXG4gICAqXHJcbiAgICogQGV4YW1wbGVcclxuICAgKiBCYXNpYyBVUkwgY29uc3RydWN0aW9uOlxyXG4gICAqIGBgYHR5cGVzY3JpcHRcclxuICAgKiBjb25zdCB1cmwgPSBidWlsZGVyLmJ1aWxkVVJMKFxyXG4gICAqICAgJ2h0dHBzOi8vYXBpLmV4YW1wbGUuY29tJyxcclxuICAgKiAgICcvc2VhcmNoJyxcclxuICAgKiAgIHsgcTogJ2hlbGxvIHdvcmxkJywgbGltaXQ6IDEwIH1cclxuICAgKiApO1xyXG4gICAqIC8vID0+IFwiaHR0cHM6Ly9hcGkuZXhhbXBsZS5jb20vc2VhcmNoP3E9aGVsbG8rd29ybGQmbGltaXQ9MTBcIlxyXG4gICAqIGBgYFxyXG4gICAqXHJcbiAgICogQGV4YW1wbGVcclxuICAgKiBBcnJheSBwYXJhbWV0ZXJzOlxyXG4gICAqIGBgYHR5cGVzY3JpcHRcclxuICAgKiBjb25zdCB1cmwgPSBidWlsZGVyLmJ1aWxkVVJMKFxyXG4gICAqICAgJ2h0dHBzOi8vYXBpLmV4YW1wbGUuY29tJyxcclxuICAgKiAgICcvcG9zdHMnLFxyXG4gICAqICAgeyB0YWdzOiBbJ2phdmFzY3JpcHQnLCAndHlwZXNjcmlwdCcsICdyZWFjdCddIH1cclxuICAgKiApO1xyXG4gICAqIC8vID0+IFwiaHR0cHM6Ly9hcGkuZXhhbXBsZS5jb20vcG9zdHM/dGFncz1qYXZhc2NyaXB0JnRhZ3M9dHlwZXNjcmlwdCZ0YWdzPXJlYWN0XCJcclxuICAgKiBgYGBcclxuICAgKlxyXG4gICAqIEBleGFtcGxlXHJcbiAgICogTnVsbC91bmRlZmluZWQgaGFuZGxpbmc6XHJcbiAgICogYGBgdHlwZXNjcmlwdFxyXG4gICAqIGNvbnN0IHVybCA9IGJ1aWxkZXIuYnVpbGRVUkwoXHJcbiAgICogICAnaHR0cHM6Ly9hcGkuZXhhbXBsZS5jb20nLFxyXG4gICAqICAgJy91c2VycycsXHJcbiAgICogICB7XHJcbiAgICogICAgIG5hbWU6ICdKb2huJyxcclxuICAgKiAgICAgYWdlOiBudWxsLCAgICAgICAgLy8gU2tpcHBlZFxyXG4gICAqICAgICBlbWFpbDogdW5kZWZpbmVkICAvLyBTa2lwcGVkXHJcbiAgICogICB9XHJcbiAgICogKTtcclxuICAgKiAvLyA9PiBcImh0dHBzOi8vYXBpLmV4YW1wbGUuY29tL3VzZXJzP25hbWU9Sm9oblwiXHJcbiAgICogYGBgXHJcbiAgICpcclxuICAgKiBAZXhhbXBsZVxyXG4gICAqIFNwZWNpYWwgY2hhcmFjdGVycyBlbmNvZGluZzpcclxuICAgKiBgYGB0eXBlc2NyaXB0XHJcbiAgICogY29uc3QgdXJsID0gYnVpbGRlci5idWlsZFVSTChcclxuICAgKiAgICdodHRwczovL2FwaS5leGFtcGxlLmNvbScsXHJcbiAgICogICAnL3NlYXJjaCcsXHJcbiAgICogICB7IHE6ICdmb28gJiBiYXInLCBjYXRlZ29yeTogJ2NvZGUvZXhhbXBsZXMnIH1cclxuICAgKiApO1xyXG4gICAqIC8vID0+IFwiaHR0cHM6Ly9hcGkuZXhhbXBsZS5jb20vc2VhcmNoP3E9Zm9vKyUyNitiYXImY2F0ZWdvcnk9Y29kZSUyRmV4YW1wbGVzXCJcclxuICAgKiBgYGBcclxuICAgKi9cclxuICBidWlsZFVSTChiYXNlVVJMOiBzdHJpbmcsIGVuZHBvaW50OiBzdHJpbmcsIHBhcmFtcz86IFF1ZXJ5UGFyYW1zKTogc3RyaW5nIHtcclxuICAgIC8vIEVuc3VyZSBlbmRwb2ludCBoYXMgbGVhZGluZyBzbGFzaCBmb3IgcHJvcGVyIFVSTCByZXNvbHV0aW9uXHJcbiAgICBjb25zdCBub3JtYWxpemVkRW5kcG9pbnQgPSBlbmRwb2ludC5zdGFydHNXaXRoKCcvJykgPyBlbmRwb2ludCA6IGAvJHtlbmRwb2ludH1gO1xyXG4gICAgY29uc3QgdXJsID0gbmV3IFVSTChub3JtYWxpemVkRW5kcG9pbnQsIGJhc2VVUkwpO1xyXG5cclxuICAgIGlmIChwYXJhbXMpIHtcclxuICAgICAgT2JqZWN0LmtleXMocGFyYW1zKS5mb3JFYWNoKGtleSA9PiB7XHJcbiAgICAgICAgY29uc3QgdmFsdWUgPSBwYXJhbXNba2V5XTtcclxuXHJcbiAgICAgICAgaWYgKHZhbHVlICE9PSB1bmRlZmluZWQgJiYgdmFsdWUgIT09IG51bGwpIHtcclxuICAgICAgICAgIGlmIChBcnJheS5pc0FycmF5KHZhbHVlKSkge1xyXG4gICAgICAgICAgICB2YWx1ZS5mb3JFYWNoKHYgPT4gdXJsLnNlYXJjaFBhcmFtcy5hcHBlbmQoa2V5LCBTdHJpbmcodikpKTtcclxuICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgIHVybC5zZWFyY2hQYXJhbXMuYXBwZW5kKGtleSwgU3RyaW5nKHZhbHVlKSk7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICB9KTtcclxuICAgIH1cclxuXHJcbiAgICByZXR1cm4gdXJsLnRvU3RyaW5nKCk7XHJcbiAgfVxyXG59XHJcbiIsICJpbXBvcnQgeyBnZW5lcmF0ZUNvcnJlbGF0aW9uSWQgfSBmcm9tICcuL0NvcnJlbGF0aW9uSWRHZW5lcmF0b3InO1xyXG5pbXBvcnQgeyBFcnJvck5vcm1hbGl6ZXIgfSBmcm9tICcuL0Vycm9ycy9FcnJvck5vcm1hbGl6ZXInO1xyXG5pbXBvcnQgeyBJbnRlcmNlcHRvck1hbmFnZXIgfSBmcm9tICcuL0ludGVyY2VwdG9ycy9JbnRlcmNlcHRvck1hbmFnZXInO1xyXG5pbXBvcnQgdHlwZSB7XHJcbiAgUGFnaW5hdGVkUmVzcG9uc2UsXHJcbiAgUG9zdE1vZGVsLFxyXG4gIFF1ZXJ5UGFyYW1zLFxyXG4gIFJlc3BvbnNlRGF0YSxcclxufSBmcm9tICcuL01vZGVscyc7XHJcbmltcG9ydCB7IFJlcXVlc3RNYW5hZ2VyIH0gZnJvbSAnLi9SZXF1ZXN0TWFuYWdlcic7XHJcbmltcG9ydCB7IFJldHJ5SGFuZGxlciB9IGZyb20gJy4vUmV0cnkvUmV0cnlIYW5kbGVyJztcclxuaW1wb3J0IHsgU2lnbmFsTWFuYWdlciB9IGZyb20gJy4vU2lnbmFscy9TaWduYWxNYW5hZ2VyJztcclxuaW1wb3J0IHR5cGUgeyBBcGlFcnJvciB9IGZyb20gJy4vdHlwZXMvQXBpRXJyb3InO1xyXG5pbXBvcnQgdHlwZSB7IEVycm9ySW50ZXJjZXB0b3IgfSBmcm9tICcuL3R5cGVzL0Vycm9ySW50ZXJjZXB0b3InO1xyXG5pbXBvcnQgdHlwZSB7IEVycm9yUmVzcG9uc2VEYXRhIH0gZnJvbSAnLi90eXBlcy9FcnJvclJlc3BvbnNlRGF0YSc7XHJcbmltcG9ydCB0eXBlIHsgUmVxdWVzdENvbmZpZyB9IGZyb20gJy4vdHlwZXMvUmVxdWVzdENvbmZpZyc7XHJcbmltcG9ydCB0eXBlIHsgUmVxdWVzdEludGVyY2VwdG9yIH0gZnJvbSAnLi90eXBlcy9SZXF1ZXN0SW50ZXJjZXB0b3InO1xyXG5pbXBvcnQgdHlwZSB7IFJlc3BvbnNlSW50ZXJjZXB0b3IgfSBmcm9tICcuL3R5cGVzL1Jlc3BvbnNlSW50ZXJjZXB0b3InO1xyXG5pbXBvcnQgeyBSZXNwb25zZVBhcnNlciB9IGZyb20gJy4vVXRpbHMvUmVzcG9uc2VQYXJzZXInO1xyXG5pbXBvcnQgeyBVcmxCdWlsZGVyIH0gZnJvbSAnLi9VdGlscy9VcmxCdWlsZGVyJztcclxuXHJcbmltcG9ydCB0eXBlIHsgQXBpUmVzcG9uc2UgfSBmcm9tICdAL3R5cGVzJztcclxuXHJcbi8qKlxyXG4gKiBFbnRlcnByaXNlLWdyYWRlIEFQSSBjbGllbnQgd2l0aCBhZHZhbmNlZCBmZWF0dXJlcyBmb3IgcHJvZHVjdGlvbiBhcHBsaWNhdGlvbnMuXHJcbiAqXHJcbiAqIFRoaXMgY2xpZW50IHByb3ZpZGVzIGEgcm9idXN0LCB0eXBlLXNhZmUgYWJzdHJhY3Rpb24gb3ZlciB0aGUgRmV0Y2ggQVBJIHdpdGg6XHJcbiAqIC0gQ29tcHJlaGVuc2l2ZSByZXF1ZXN0L3Jlc3BvbnNlL2Vycm9yIGludGVyY2VwdG9yIHN5c3RlbVxyXG4gKiAtIEF1dG9tYXRpYyByZXRyeSBsb2dpYyB3aXRoIGV4cG9uZW50aWFsIGJhY2tvZmZcclxuICogLSBSZXF1ZXN0IGNvcnJlbGF0aW9uIElEIHRyYWNraW5nIGZvciBkaXN0cmlidXRlZCB0cmFjaW5nXHJcbiAqIC0gVG9rZW4tYmFzZWQgYXV0aGVudGljYXRpb24gd2l0aCBhdXRvbWF0aWMgaGVhZGVyIGluamVjdGlvblxyXG4gKiAtIFJlcXVlc3QgY2FuY2VsbGF0aW9uIGFuZCB0aW1lb3V0IG1hbmFnZW1lbnRcclxuICogLSBUeXBlLXNhZmUgZXJyb3IgaGFuZGxpbmcgd2l0aCBzdHJ1Y3R1cmVkIGVycm9yIHJlc3BvbnNlc1xyXG4gKiAtIFJlYWN0IFF1ZXJ5IGludGVncmF0aW9uIHN1cHBvcnRcclxuICpcclxuICogQXJjaGl0ZWN0dXJlIFByaW5jaXBsZXM6XHJcbiAqIC0gKipUeXBlIFNhZmV0eSoqOiBGdWxsIFR5cGVTY3JpcHQgaW5mZXJlbmNlIHdpdGggbm8gYGFueWAgdHlwZXNcclxuICogLSAqKkV4dGVuc2liaWxpdHkqKjogSW50ZXJjZXB0b3IgcGF0dGVybiBhbGxvd3MgZm9yIGZsZXhpYmxlIG1pZGRsZXdhcmVcclxuICogLSAqKk9ic2VydmFiaWxpdHkqKjogQnVpbHQtaW4gY29ycmVsYXRpb24gSURzIGZvciByZXF1ZXN0IHRyYWNpbmdcclxuICogLSAqKlJlc2lsaWVuY2UqKjogQXV0b21hdGljIHJldHJpZXMsIHRpbWVvdXRzLCBhbmQgZ3JhY2VmdWwgZXJyb3IgaGFuZGxpbmdcclxuICogLSAqKlBlcmZvcm1hbmNlKio6IFJlcXVlc3QgZGVkdXBsaWNhdGlvbiBhbmQgY2FuY2VsbGF0aW9uIHN1cHBvcnRcclxuICogLSAqKk1vZHVsYXJpdHkqKjogT3JnYW5pemVkIGludG8gZm9jdXNlZCwgc2luZ2xlLXJlc3BvbnNpYmlsaXR5IG1vZHVsZXNcclxuICpcclxuICogQGV4YW1wbGVcclxuICogQmFzaWMgdXNhZ2U6XHJcbiAqIGBgYHR5cGVzY3JpcHRcclxuICogY29uc3QgY2xpZW50ID0gbmV3IEFwaUNsaWVudCgnaHR0cHM6Ly9hcGkuZXhhbXBsZS5jb20nLCAzMDAwMCk7XHJcbiAqIGNsaWVudC5zZXRBdXRoVG9rZW4oJ3lvdXItand0LXRva2VuJyk7XHJcbiAqXHJcbiAqIC8vIFR5cGUtc2FmZSBHRVQgcmVxdWVzdFxyXG4gKiBjb25zdCB7IGFwaURhdGEsIGVycm9yIH0gPSBhd2FpdCBjbGllbnQuZ2V0PFVzZXI+KCcvdXNlcnMvMTIzJyk7XHJcbiAqIGlmIChlcnJvcikge1xyXG4gKiAgIGNvbnNvbGUuZXJyb3IoJ0ZhaWxlZCB0byBmZXRjaCB1c2VyOicsIGVycm9yKTtcclxuICogfSBlbHNlIHtcclxuICogICBjb25zb2xlLmxvZygnVXNlciBkYXRhOicsIGRhdGEpO1xyXG4gKiB9XHJcbiAqIGBgYFxyXG4gKlxyXG4gKiBAZXhhbXBsZVxyXG4gKiBXaXRoIFJlYWN0IFF1ZXJ5OlxyXG4gKiBgYGB0eXBlc2NyaXB0XHJcbiAqIGNvbnN0IHF1ZXJ5Q2xpZW50ID0gbmV3IFF1ZXJ5Q2xpZW50KCk7XHJcbiAqIGNvbnN0IGFwaUNsaWVudCA9IG5ldyBBcGlDbGllbnQocHJvY2Vzcy5lbnYuQVBJX0JBU0VfVVJMKTtcclxuICpcclxuICogLy8gQWRkIGxvZ2dpbmcgaW50ZXJjZXB0b3JcclxuICogYXBpQ2xpZW50LmFkZFJlc3BvbnNlSW50ZXJjZXB0b3IoYXN5bmMgKHJlc3BvbnNlKSA9PiB7XHJcbiAqICAgY29uc29sZS5sb2coJ1Jlc3BvbnNlIHJlY2VpdmVkOicsIHJlc3BvbnNlKTtcclxuICogICByZXR1cm4gcmVzcG9uc2U7XHJcbiAqIH0pO1xyXG4gKlxyXG4gKiAvLyBVc2UgaW4gcXVlcmllc1xyXG4gKiBjb25zdCB7IGFwaURhdGEgfSA9IHVzZVF1ZXJ5KHtcclxuICogICBxdWVyeUtleTogWyd1c2VycycsIHVzZXJJZF0sXHJcbiAqICAgcXVlcnlGbjogKCkgPT4gYXBpQ2xpZW50LmdldDxVc2VyPihgL3VzZXJzLyR7dXNlcklkfWApXHJcbiAqIH0pO1xyXG4gKiBgYGBcclxuICpcclxuICogQGV4YW1wbGVcclxuICogQWR2YW5jZWQgZXJyb3IgaGFuZGxpbmc6XHJcbiAqIGBgYHR5cGVzY3JpcHRcclxuICogLy8gT3B0aW9uIDE6IEVycm9ycyB0aHJvd24gKGRlZmF1bHQpXHJcbiAqIHRyeSB7XHJcbiAqICAgY29uc3QgeyBhcGlEYXRhIH0gPSBhd2FpdCBjbGllbnQuZ2V0PFVzZXI+KCcvdXNlcnMvMTIzJyk7XHJcbiAqICAgY29uc29sZS5sb2coZGF0YSk7XHJcbiAqIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAqICAgaWYgKGVycm9yLnN0YXR1cyA9PT0gNDA0KSB7XHJcbiAqICAgICBjb25zb2xlLmxvZygnVXNlciBub3QgZm91bmQnKTtcclxuICogICB9XHJcbiAqIH1cclxuICpcclxuICogLy8gT3B0aW9uIDI6IEVycm9ycyByZXR1cm5lZCBpbiByZXNwb25zZVxyXG4gKiBjb25zdCB7IGFwaURhdGEsIGVycm9yIH0gPSBhd2FpdCBjbGllbnQuZ2V0PFVzZXI+KCcvdXNlcnMvMTIzJywge1xyXG4gKiAgIHRocm93RXJyb3JzOiBmYWxzZVxyXG4gKiB9KTtcclxuICogaWYgKGVycm9yKSB7XHJcbiAqICAgY29uc29sZS5lcnJvcignUmVxdWVzdCBmYWlsZWQ6JywgZXJyb3IpO1xyXG4gKiB9XHJcbiAqIGBgYFxyXG4gKlxyXG4gKiBAcHVibGljXHJcbiAqL1xyXG5leHBvcnQgY2xhc3MgQXBpQ2xpZW50IHtcclxuICBwcml2YXRlIHJlYWRvbmx5IGJhc2VVUkw6IHN0cmluZztcclxuICBwcml2YXRlIHJlYWRvbmx5IGRlZmF1bHRUaW1lb3V0OiBudW1iZXI7XHJcbiAgcHJpdmF0ZSByZWFkb25seSBpbnRlcmNlcHRvck1hbmFnZXI6IEludGVyY2VwdG9yTWFuYWdlciA9XHJcbiAgICBuZXcgSW50ZXJjZXB0b3JNYW5hZ2VyKCk7XHJcbiAgcHJpdmF0ZSByZWFkb25seSBzaWduYWxNYW5hZ2VyOiBTaWduYWxNYW5hZ2VyID0gbmV3IFNpZ25hbE1hbmFnZXIoKTtcclxuICBwcml2YXRlIHJlYWRvbmx5IGVycm9yTm9ybWFsaXplcjogRXJyb3JOb3JtYWxpemVyID0gbmV3IEVycm9yTm9ybWFsaXplcigpO1xyXG4gIHByaXZhdGUgcmVhZG9ubHkgcmVzcG9uc2VQYXJzZXI6IFJlc3BvbnNlUGFyc2VyID0gbmV3IFJlc3BvbnNlUGFyc2VyKCk7XHJcbiAgcHJpdmF0ZSByZWFkb25seSB1cmxCdWlsZGVyOiBVcmxCdWlsZGVyID0gbmV3IFVybEJ1aWxkZXIoKTtcclxuICBwcml2YXRlIHJlYWRvbmx5IHJldHJ5SGFuZGxlcjogUmV0cnlIYW5kbGVyID0gbmV3IFJldHJ5SGFuZGxlcigpO1xyXG4gIHByaXZhdGUgcmVhZG9ubHkgcmVxdWVzdE1hbmFnZXI6IFJlcXVlc3RNYW5hZ2VyID0gbmV3IFJlcXVlc3RNYW5hZ2VyKCk7XHJcbiAgcHJpdmF0ZSBhdXRoVG9rZW46IHN0cmluZyB8IG51bGwgPSBudWxsO1xyXG4gIHByaXZhdGUgY29ycmVsYXRpb25JZFByZWZpeDogc3RyaW5nID0gJ2FwaSc7XHJcbiAgcHJpdmF0ZSBpbmNsdWRlQ29ycmVsYXRpb25JZDogYm9vbGVhbiA9IHRydWU7XHJcblxyXG4gIC8qKlxyXG4gICAqIENyZWF0ZXMgYSBuZXcgQVBJIGNsaWVudCBpbnN0YW5jZVxyXG4gICAqIEBwYXJhbSBiYXNlVVJMIC0gQmFzZSBVUkwgZm9yIGFsbCBBUEkgcmVxdWVzdHMgKGRlZmF1bHQ6IGVtcHR5IHN0cmluZyBmb3IgcmVsYXRpdmUgVVJMcylcclxuICAgKiBAcGFyYW0gZGVmYXVsdFRpbWVvdXQgLSBEZWZhdWx0IHJlcXVlc3QgdGltZW91dCBpbiBtaWxsaXNlY29uZHMgKGRlZmF1bHQ6IDMwMDAwKVxyXG4gICAqL1xyXG4gIGNvbnN0cnVjdG9yKGJhc2VVUkw6IHN0cmluZyA9ICcnLCBkZWZhdWx0VGltZW91dDogbnVtYmVyID0gMzAwMDApIHtcclxuICAgIHRoaXMuYmFzZVVSTCA9IGJhc2VVUkw7XHJcbiAgICB0aGlzLmRlZmF1bHRUaW1lb3V0ID0gZGVmYXVsdFRpbWVvdXQ7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBTZXRzIHRoZSBwcmVmaXggZm9yIGF1dG8tZ2VuZXJhdGVkIGNvcnJlbGF0aW9uIElEc1xyXG4gICAqIEBwYXJhbSBwcmVmaXggLSBUaGUgcHJlZml4IHRvIHVzZSBmb3IgY29ycmVsYXRpb24gSURzIChlLmcuLCAnYXBpJywgJ3dlYicsICdtb2JpbGUnKVxyXG4gICAqL1xyXG4gIHNldENvcnJlbGF0aW9uSWRQcmVmaXgocHJlZml4OiBzdHJpbmcpOiB2b2lkIHtcclxuICAgIHRoaXMuY29ycmVsYXRpb25JZFByZWZpeCA9IHByZWZpeDtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIEVuYWJsZXMgb3IgZGlzYWJsZXMgYXV0b21hdGljIGNvcnJlbGF0aW9uIElEIGdlbmVyYXRpb25cclxuICAgKiBAcGFyYW0gaW5jbHVkZSAtIFdoZXRoZXIgdG8gaW5jbHVkZSBjb3JyZWxhdGlvbiBJRHMgaW4gcmVxdWVzdHNcclxuICAgKi9cclxuICBzZXRJbmNsdWRlQ29ycmVsYXRpb25JZChpbmNsdWRlOiBib29sZWFuKTogdm9pZCB7XHJcbiAgICB0aGlzLmluY2x1ZGVDb3JyZWxhdGlvbklkID0gaW5jbHVkZTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIFJlZ2lzdGVycyBhIHJlcXVlc3QgaW50ZXJjZXB0b3IgdG8gbW9kaWZ5IHJlcXVlc3RzIGJlZm9yZSB0aGV5J3JlIHNlbnRcclxuICAgKiBAcGFyYW0gaW50ZXJjZXB0b3IgLSBGdW5jdGlvbiB0byBpbnRlcmNlcHQgYW5kIHBvdGVudGlhbGx5IG1vZGlmeSByZXF1ZXN0IGNvbmZpZ1xyXG4gICAqIEByZXR1cm5zIEZ1bmN0aW9uIHRvIHVucmVnaXN0ZXIgdGhpcyBpbnRlcmNlcHRvclxyXG4gICAqXHJcbiAgICogQGV4YW1wbGVcclxuICAgKiBgYGB0eXBlc2NyaXB0XHJcbiAgICogY29uc3QgdW5yZWdpc3RlciA9IGNsaWVudC5hZGRSZXF1ZXN0SW50ZXJjZXB0b3IoYXN5bmMgKGNvbmZpZykgPT4ge1xyXG4gICAqICAgY29uZmlnLmhlYWRlcnMgPSBjb25maWcuaGVhZGVycyB8fCBuZXcgSGVhZGVycygpO1xyXG4gICAqICAgY29uZmlnLmhlYWRlcnMuc2V0KCdYLUNsaWVudC1WZXJzaW9uJywgJzEuMC4wJyk7XHJcbiAgICogICByZXR1cm4gY29uZmlnO1xyXG4gICAqIH0pO1xyXG4gICAqXHJcbiAgICogLy8gTGF0ZXIsIHRvIHJlbW92ZSB0aGUgaW50ZXJjZXB0b3I6XHJcbiAgICogdW5yZWdpc3RlcigpO1xyXG4gICAqIGBgYFxyXG4gICAqL1xyXG4gIGFkZFJlcXVlc3RJbnRlcmNlcHRvcihpbnRlcmNlcHRvcjogUmVxdWVzdEludGVyY2VwdG9yKTogKCkgPT4gdm9pZCB7XHJcbiAgICByZXR1cm4gdGhpcy5pbnRlcmNlcHRvck1hbmFnZXIuYWRkUmVxdWVzdEludGVyY2VwdG9yKGludGVyY2VwdG9yKTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIFJlZ2lzdGVycyBhIHJlc3BvbnNlIGludGVyY2VwdG9yIHRvIG1vZGlmeSByZXNwb25zZXMgYmVmb3JlIHRoZXkncmUgcmV0dXJuZWRcclxuICAgKiBAcGFyYW0gaW50ZXJjZXB0b3IgLSBGdW5jdGlvbiB0byBpbnRlcmNlcHQgYW5kIHBvdGVudGlhbGx5IG1vZGlmeSByZXNwb25zZXNcclxuICAgKiBAcmV0dXJucyBGdW5jdGlvbiB0byB1bnJlZ2lzdGVyIHRoaXMgaW50ZXJjZXB0b3JcclxuICAgKlxyXG4gICAqIEBleGFtcGxlXHJcbiAgICogYGBgdHlwZXNjcmlwdFxyXG4gICAqIGNsaWVudC5hZGRSZXNwb25zZUludGVyY2VwdG9yKGFzeW5jIChyZXNwb25zZSkgPT4ge1xyXG4gICAqICAgLy8gVHJhbnNmb3JtIGRhdGEgZm9ybWF0XHJcbiAgICogICBpZiAocmVzcG9uc2UuYXBpRGF0YSkge1xyXG4gICAqICAgICByZXNwb25zZS5hcGlEYXRhID0gY2FtZWxDYXNlS2V5cyhyZXNwb25zZS5hcGlEYXRhKTtcclxuICAgKiAgIH1cclxuICAgKiAgIHJldHVybiByZXNwb25zZTtcclxuICAgKiB9KTtcclxuICAgKiBgYGBcclxuICAgKi9cclxuICBhZGRSZXNwb25zZUludGVyY2VwdG9yKGludGVyY2VwdG9yOiBSZXNwb25zZUludGVyY2VwdG9yKTogKCkgPT4gdm9pZCB7XHJcbiAgICByZXR1cm4gdGhpcy5pbnRlcmNlcHRvck1hbmFnZXIuYWRkUmVzcG9uc2VJbnRlcmNlcHRvcihpbnRlcmNlcHRvcik7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBSZWdpc3RlcnMgYW4gZXJyb3IgaW50ZXJjZXB0b3IgdG8gaGFuZGxlIG9yIHRyYW5zZm9ybSBlcnJvcnNcclxuICAgKiBAcGFyYW0gaW50ZXJjZXB0b3IgLSBGdW5jdGlvbiB0byBpbnRlcmNlcHQgYW5kIHBvdGVudGlhbGx5IG1vZGlmeSBlcnJvcnNcclxuICAgKiBAcmV0dXJucyBGdW5jdGlvbiB0byB1bnJlZ2lzdGVyIHRoaXMgaW50ZXJjZXB0b3JcclxuICAgKlxyXG4gICAqIEBleGFtcGxlXHJcbiAgICogYGBgdHlwZXNjcmlwdFxyXG4gICAqIGNsaWVudC5hZGRFcnJvckludGVyY2VwdG9yKGFzeW5jIChlcnJvcikgPT4ge1xyXG4gICAqICAgLy8gTG9nIGVycm9ycyB0byBtb25pdG9yaW5nIHNlcnZpY2VcclxuICAgKiAgIGlmIChlcnJvci5zdGF0dXMgPj0gNTAwKSB7XHJcbiAgICogICAgIGF3YWl0IG1vbml0b3JpbmdTZXJ2aWNlLmxvZ0Vycm9yKGVycm9yKTtcclxuICAgKiAgIH1cclxuICAgKiAgIHJldHVybiBlcnJvcjsgLy8gUmUtdGhyb3cgdGhlIGVycm9yXHJcbiAgICogfSk7XHJcbiAgICogYGBgXHJcbiAgICovXHJcbiAgYWRkRXJyb3JJbnRlcmNlcHRvcihpbnRlcmNlcHRvcjogRXJyb3JJbnRlcmNlcHRvcik6ICgpID0+IHZvaWQge1xyXG4gICAgcmV0dXJuIHRoaXMuaW50ZXJjZXB0b3JNYW5hZ2VyLmFkZEVycm9ySW50ZXJjZXB0b3IoaW50ZXJjZXB0b3IpO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogU2V0cyB0aGUgYXV0aGVudGljYXRpb24gdG9rZW4gZm9yIHN1YnNlcXVlbnQgcmVxdWVzdHNcclxuICAgKiBAcGFyYW0gdG9rZW4gLSBKV1QgdG9rZW4gb3IgbnVsbCB0byBjbGVhciBhdXRoZW50aWNhdGlvblxyXG4gICAqXHJcbiAgICogQGV4YW1wbGVcclxuICAgKiBgYGB0eXBlc2NyaXB0XHJcbiAgICogLy8gU2V0IHRva2VuIGFmdGVyIGxvZ2luXHJcbiAgICogY2xpZW50LnNldEF1dGhUb2tlbihsb2dpblJlc3BvbnNlLmFjY2Vzc1Rva2VuKTtcclxuICAgKlxyXG4gICAqIC8vIENsZWFyIHRva2VuIG9uIGxvZ291dFxyXG4gICAqIGNsaWVudC5zZXRBdXRoVG9rZW4obnVsbCk7XHJcbiAgICogYGBgXHJcbiAgICovXHJcbiAgc2V0QXV0aFRva2VuKHRva2VuOiBzdHJpbmcgfCBudWxsKTogdm9pZCB7XHJcbiAgICB0aGlzLmF1dGhUb2tlbiA9IHRva2VuO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogUmV0cmlldmVzIHRoZSBjdXJyZW50IGF1dGhlbnRpY2F0aW9uIHRva2VuXHJcbiAgICogQHJldHVybnMgVGhlIGN1cnJlbnQgYXV0aCB0b2tlbiBvciBudWxsIGlmIG5vdCBzZXRcclxuICAgKi9cclxuICBnZXRBdXRoVG9rZW4oKTogc3RyaW5nIHwgbnVsbCB7XHJcbiAgICByZXR1cm4gdGhpcy5hdXRoVG9rZW47XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBDYW5jZWxzIGEgc3BlY2lmaWMgcmVxdWVzdCBieSBpdHMga2V5XHJcbiAgICogQHBhcmFtIGtleSAtIFRoZSB1bmlxdWUga2V5IGlkZW50aWZ5aW5nIHRoZSByZXF1ZXN0IHRvIGNhbmNlbFxyXG4gICAqL1xyXG4gIGNhbmNlbFJlcXVlc3Qoa2V5OiBzdHJpbmcpOiB2b2lkIHtcclxuICAgIHRoaXMucmVxdWVzdE1hbmFnZXIuY2FuY2VsKGtleSk7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBDYW5jZWxzIGFsbCBwZW5kaW5nIHJlcXVlc3RzXHJcbiAgICogVXNlZnVsIGZvciBjbGVhbnVwIG9uIG5hdmlnYXRpb24gb3IgY29tcG9uZW50IHVubW91bnRcclxuICAgKi9cclxuICBjYW5jZWxBbGxSZXF1ZXN0cygpOiB2b2lkIHtcclxuICAgIHRoaXMucmVxdWVzdE1hbmFnZXIuY2FuY2VsQWxsKCk7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBDb3JlIHJlcXVlc3QgbWV0aG9kIHRoYXQgaGFuZGxlcyBhbGwgSFRUUCBvcGVyYXRpb25zXHJcbiAgICogQHRlbXBsYXRlIFQgLSBUaGUgZXhwZWN0ZWQgcmVzcG9uc2UgZGF0YSB0eXBlXHJcbiAgICogQHBhcmFtIGVuZHBvaW50IC0gQVBJIGVuZHBvaW50IHJlbGF0aXZlIHRvIGJhc2VVUkxcclxuICAgKiBAcGFyYW0gY29uZmlnIC0gUmVxdWVzdCBjb25maWd1cmF0aW9uIG9wdGlvbnNcclxuICAgKiBAcmV0dXJucyBQcm9taXNlIHJlc29sdmluZyB0byBBcGlSZXNwb25zZSB3aXRoIGRhdGEgb3IgZXJyb3JcclxuICAgKlxyXG4gICAqIEBleGFtcGxlXHJcbiAgICogYGBgdHlwZXNjcmlwdFxyXG4gICAqIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgY2xpZW50LnJlcXVlc3Q8VXNlcj4oJy91c2Vycy8xMjMnLCB7XHJcbiAgICogICBtZXRob2Q6ICdHRVQnLFxyXG4gICAqICAgdGltZW91dDogNTAwMCxcclxuICAgKiAgIHRocm93RXJyb3JzOiBmYWxzZVxyXG4gICAqIH0pO1xyXG4gICAqIGBgYFxyXG4gICAqL1xyXG4gIGFzeW5jIHJlcXVlc3Q8VCA9IFJlc3BvbnNlRGF0YT4oXHJcbiAgICBlbmRwb2ludDogc3RyaW5nLFxyXG4gICAgY29uZmlnOiBSZXF1ZXN0Q29uZmlnID0ge31cclxuICApOiBQcm9taXNlPEFwaVJlc3BvbnNlPFQsIEFwaUVycm9yPj4ge1xyXG4gICAgLy8gR2VuZXJhdGUgY29ycmVsYXRpb24gSURcclxuICAgIGNvbnN0IGNvcnJlbGF0aW9uSWQgPVxyXG4gICAgICBjb25maWcuY29ycmVsYXRpb25JZCB8fFxyXG4gICAgICAoIWNvbmZpZy5za2lwQ29ycmVsYXRpb25JZCAmJiB0aGlzLmluY2x1ZGVDb3JyZWxhdGlvbklkXHJcbiAgICAgICAgPyBnZW5lcmF0ZUNvcnJlbGF0aW9uSWQodGhpcy5jb3JyZWxhdGlvbklkUHJlZml4KVxyXG4gICAgICAgIDogdW5kZWZpbmVkKTtcclxuICAgIC8vIEdlbmVyYXRlIHJlcXVlc3Qga2V5IGZvciB0cmFja2luZ1xyXG4gICAgY29uc3QgcmVxdWVzdEtleSA9IGAke2NvbmZpZy5tZXRob2QgfHwgJ0dFVCd9XyR7ZW5kcG9pbnR9XyR7RGF0ZS5ub3coKX1gO1xyXG5cclxuICAgIC8vIENyZWF0ZSBtYXN0ZXIgY29udHJvbGxlciBmb3IgdGhpcyByZXF1ZXN0XHJcbiAgICBjb25zdCBtYXN0ZXJDb250cm9sbGVyID0gbmV3IEFib3J0Q29udHJvbGxlcigpO1xyXG5cclxuICAgIHRyeSB7XHJcbiAgICAgIC8vIENvbWJpbmUgYWxsIGFib3J0IHNpZ25hbHNcclxuICAgICAgY29uc3Qgc2lnbmFsczogQXJyYXk8QWJvcnRTaWduYWwgfCB1bmRlZmluZWQ+ID0gW1xyXG4gICAgICAgIGNvbmZpZy5zaWduYWwsXHJcbiAgICAgICAgY29uZmlnLmNhbmNlbFRva2VuPy5zaWduYWwsXHJcbiAgICAgICAgbWFzdGVyQ29udHJvbGxlci5zaWduYWwsXHJcbiAgICAgIF07XHJcblxyXG4gICAgICAvLyBBZGQgdGltZW91dCBzaWduYWwgaWYgY29uZmlndXJlZFxyXG4gICAgICBjb25zdCB0aW1lb3V0ID0gY29uZmlnLnRpbWVvdXQgfHwgdGhpcy5kZWZhdWx0VGltZW91dDtcclxuICAgICAgY29uc3QgdGltZW91dENvbnRyb2xsZXIgPSB0aGlzLnNpZ25hbE1hbmFnZXIuY3JlYXRlVGltZW91dFNpZ25hbCh0aW1lb3V0KTtcclxuXHJcbiAgICAgIHNpZ25hbHMucHVzaCh0aW1lb3V0Q29udHJvbGxlci5zaWduYWwpO1xyXG5cclxuICAgICAgLy8gQ3JlYXRlIGNvbWJpbmVkIHNpZ25hbFxyXG4gICAgICBjb25zdCBjb21iaW5lZENvbnRyb2xsZXIgPVxyXG4gICAgICAgIHRoaXMuc2lnbmFsTWFuYWdlci5jcmVhdGVDb21iaW5lZFNpZ25hbChzaWduYWxzKTtcclxuXHJcbiAgICAgIC8vIFRyYWNrIHRoaXMgcmVxdWVzdFxyXG4gICAgICBpZiAoY29ycmVsYXRpb25JZCkge1xyXG4gICAgICAgIHRoaXMucmVxdWVzdE1hbmFnZXIuYWRkKHJlcXVlc3RLZXksIG1hc3RlckNvbnRyb2xsZXIsIGNvcnJlbGF0aW9uSWQpO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBBcHBseSByZXF1ZXN0IGludGVyY2VwdG9yc1xyXG4gICAgICBjb25zdCBmaW5hbENvbmZpZyA9XHJcbiAgICAgICAgYXdhaXQgdGhpcy5pbnRlcmNlcHRvck1hbmFnZXIuYXBwbHlSZXF1ZXN0SW50ZXJjZXB0b3JzKHtcclxuICAgICAgICAgIC4uLmNvbmZpZyxcclxuICAgICAgICAgIHNpZ25hbDogY29tYmluZWRDb250cm9sbGVyLnNpZ25hbCxcclxuICAgICAgICAgIGNvcnJlbGF0aW9uSWQsXHJcbiAgICAgICAgfSk7XHJcblxyXG4gICAgICAvLyBCdWlsZCBmdWxsIFVSTFxyXG4gICAgICBjb25zdCB1cmwgPSB0aGlzLnVybEJ1aWxkZXIuYnVpbGRVUkwoXHJcbiAgICAgICAgdGhpcy5iYXNlVVJMLFxyXG4gICAgICAgIGVuZHBvaW50LFxyXG4gICAgICAgIGZpbmFsQ29uZmlnLnBhcmFtcyBhcyBRdWVyeVBhcmFtc1xyXG4gICAgICApO1xyXG5cclxuICAgICAgLy8gQWRkIGRlZmF1bHQgaGVhZGVyc1xyXG4gICAgICBjb25zdCBoZWFkZXJzID0gbmV3IEhlYWRlcnMoZmluYWxDb25maWcuaGVhZGVycyk7XHJcblxyXG4gICAgICAvLyBBZGQgY29ycmVsYXRpb24gSUQgaGVhZGVyXHJcbiAgICAgIGlmIChjb3JyZWxhdGlvbklkKSB7XHJcbiAgICAgICAgaGVhZGVycy5zZXQoJ1gtQ29ycmVsYXRpb24tSWQnLCBjb3JyZWxhdGlvbklkKTtcclxuICAgICAgICBoZWFkZXJzLnNldCgnWC1SZXF1ZXN0LUlkJywgY29ycmVsYXRpb25JZCk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIEFkZCBhdXRoIGhlYWRlciBpZiB0b2tlbiBleGlzdHNcclxuICAgICAgaWYgKHRoaXMuYXV0aFRva2VuICYmICFmaW5hbENvbmZpZy5za2lwQXV0aFJlZnJlc2gpIHtcclxuICAgICAgICBoZWFkZXJzLnNldCgnQXV0aG9yaXphdGlvbicsIGBCZWFyZXIgJHt0aGlzLmF1dGhUb2tlbn1gKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gU2V0IGNvbnRlbnQtdHlwZSBmb3IgSlNPTiBwYXlsb2Fkc1xyXG5cclxuICAgICAgbGV0IGZldGNoQm9keTogQm9keUluaXQgfCBudWxsIHwgdW5kZWZpbmVkID0gZmluYWxDb25maWcuYm9keSBhc1xyXG4gICAgICAgIHwgQm9keUluaXRcclxuICAgICAgICB8IG51bGxcclxuICAgICAgICB8IHVuZGVmaW5lZDtcclxuXHJcbiAgICAgIGlmIChcclxuICAgICAgICBmaW5hbENvbmZpZy5ib2R5ICYmXHJcbiAgICAgICAgdHlwZW9mIGZpbmFsQ29uZmlnLmJvZHkgPT09ICdvYmplY3QnICYmXHJcbiAgICAgICAgIShmaW5hbENvbmZpZy5ib2R5IGluc3RhbmNlb2YgRm9ybURhdGEpICYmXHJcbiAgICAgICAgIShmaW5hbENvbmZpZy5ib2R5IGluc3RhbmNlb2YgQmxvYikgJiZcclxuICAgICAgICAhKGZpbmFsQ29uZmlnLmJvZHkgaW5zdGFuY2VvZiBBcnJheUJ1ZmZlcikgJiZcclxuICAgICAgICAhKGZpbmFsQ29uZmlnLmJvZHkgaW5zdGFuY2VvZiBVUkxTZWFyY2hQYXJhbXMpICYmXHJcbiAgICAgICAgIShmaW5hbENvbmZpZy5ib2R5IGluc3RhbmNlb2YgUmVhZGFibGVTdHJlYW0pXHJcbiAgICAgICkge1xyXG4gICAgICAgIGhlYWRlcnMuc2V0KCdDb250ZW50LVR5cGUnLCAnYXBwbGljYXRpb24vanNvbicpO1xyXG4gICAgICAgIGZldGNoQm9keSA9IEpTT04uc3RyaW5naWZ5KGZpbmFsQ29uZmlnLmJvZHkpO1xyXG4gICAgICB9XHJcblxyXG4gICAgICBmaW5hbENvbmZpZy5oZWFkZXJzID0gaGVhZGVycztcclxuXHJcbiAgICAgIC8vIENyZWF0ZSBmZXRjaCBwcm9taXNlXHJcbiAgICAgIGNvbnN0IGZldGNoUHJvbWlzZSA9IGFzeW5jICgpOiBQcm9taXNlPEFwaVJlc3BvbnNlPFQsIEFwaUVycm9yPj4gPT4ge1xyXG4gICAgICAgIHRyeSB7XHJcbiAgICAgICAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IGZldGNoKHVybCwge1xyXG4gICAgICAgICAgICAuLi5maW5hbENvbmZpZyxcclxuICAgICAgICAgICAgYm9keTogZmV0Y2hCb2R5LFxyXG4gICAgICAgICAgICBzaWduYWw6IGNvbWJpbmVkQ29udHJvbGxlci5zaWduYWwsXHJcbiAgICAgICAgICB9IGFzIFJlcXVlc3RJbml0KTtcclxuXHJcbiAgICAgICAgICAvLyBQYXJzZSByZXNwb25zZSBkYXRhXHJcbiAgICAgICAgICBjb25zdCByZXNwb25zZURhdGEgPVxyXG4gICAgICAgICAgICBhd2FpdCB0aGlzLnJlc3BvbnNlUGFyc2VyLnBhcnNlUmVzcG9uc2UocmVzcG9uc2UpO1xyXG5cclxuICAgICAgICAgIC8vIEhhbmRsZSBlcnJvciByZXNwb25zZXNcclxuICAgICAgICAgIGlmICghcmVzcG9uc2Uub2spIHtcclxuICAgICAgICAgICAgLy8gQ2FzdCB0byBFcnJvclJlc3BvbnNlRGF0YSBmb3Igc3RydWN0dXJlZCBlcnJvciByZXNwb25zZXMgZnJvbSBiYWNrZW5kXHJcbiAgICAgICAgICAgIGNvbnN0IGVycm9yRGF0YSA9IHJlc3BvbnNlRGF0YSBhcyBFcnJvclJlc3BvbnNlRGF0YTtcclxuXHJcbiAgICAgICAgICAgIGNvbnN0IGVycm9yOiBBcGlFcnJvciA9IE9iamVjdC5hc3NpZ24oXHJcbiAgICAgICAgICAgICAgbmV3IEVycm9yKFxyXG4gICAgICAgICAgICAgICAgZXJyb3JEYXRhLnRpdGxlIHx8XHJcbiAgICAgICAgICAgICAgICAgIGBIVFRQICR7cmVzcG9uc2Uuc3RhdHVzfTogJHtyZXNwb25zZS5zdGF0dXNUZXh0fWBcclxuICAgICAgICAgICAgICApLFxyXG4gICAgICAgICAgICAgIHtcclxuICAgICAgICAgICAgICAgIHR5cGU6XHJcbiAgICAgICAgICAgICAgICAgIGVycm9yRGF0YS50eXBlIHx8XHJcbiAgICAgICAgICAgICAgICAgIHRoaXMuZXJyb3JOb3JtYWxpemVyLmdldEVycm9yVHlwZShyZXNwb25zZS5zdGF0dXMpLFxyXG4gICAgICAgICAgICAgICAgdGl0bGU6XHJcbiAgICAgICAgICAgICAgICAgIGVycm9yRGF0YS50aXRsZSB8fFxyXG4gICAgICAgICAgICAgICAgICB0aGlzLmVycm9yTm9ybWFsaXplci5nZXRFcnJvclRpdGxlKHJlc3BvbnNlLnN0YXR1cyksXHJcbiAgICAgICAgICAgICAgICBzdGF0dXM6IHJlc3BvbnNlLnN0YXR1cyxcclxuICAgICAgICAgICAgICAgIHRyYWNlSWQ6IGVycm9yRGF0YS50cmFjZUlkIHx8IGNvcnJlbGF0aW9uSWQsXHJcbiAgICAgICAgICAgICAgICBlcnJvcnM6IGVycm9yRGF0YS5lcnJvcnMsXHJcbiAgICAgICAgICAgICAgICBpc0Fib3J0ZWQ6IGZhbHNlLFxyXG4gICAgICAgICAgICAgICAgY29uZmlnOiBmaW5hbENvbmZpZyxcclxuICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICk7XHJcblxyXG4gICAgICAgICAgICAvLyBDaGVjayBpZiB3ZSBzaG91bGQgdGhyb3cgb3IgcmV0dXJuIGVycm9yIGluIHJlc3BvbnNlXHJcbiAgICAgICAgICAgIGlmIChmaW5hbENvbmZpZy50aHJvd0Vycm9ycyAhPT0gZmFsc2UpIHtcclxuICAgICAgICAgICAgICB0aHJvdyBlcnJvcjtcclxuICAgICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgICAvLyBSZXR1cm4gZXJyb3IgaW4gQXBpUmVzcG9uc2UuZXJyb3IgZmllbGRcclxuICAgICAgICAgICAgICByZXR1cm4gYXdhaXQgdGhpcy5pbnRlcmNlcHRvck1hbmFnZXIuYXBwbHlSZXNwb25zZUludGVyY2VwdG9ycyh7XHJcbiAgICAgICAgICAgICAgICBlcnJvcixcclxuICAgICAgICAgICAgICB9IGFzIEFwaVJlc3BvbnNlPFQsIEFwaUVycm9yPik7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAvLyBGb3JtYXQgc3VjY2Vzc2Z1bCByZXNwb25zZVxyXG4gICAgICAgICAgY29uc3QgYXBpUmVzcG9uc2U6IEFwaVJlc3BvbnNlPFQ+ID0ge1xyXG4gICAgICAgICAgICBkYXRhOiByZXNwb25zZURhdGEgYXMgVCxcclxuICAgICAgICAgIH07XHJcblxyXG4gICAgICAgICAgLy8gQXBwbHkgcmVzcG9uc2UgaW50ZXJjZXB0b3JzXHJcbiAgICAgICAgICByZXR1cm4gYXdhaXQgdGhpcy5pbnRlcmNlcHRvck1hbmFnZXIuYXBwbHlSZXNwb25zZUludGVyY2VwdG9ycyhcclxuICAgICAgICAgICAgYXBpUmVzcG9uc2VcclxuICAgICAgICAgICk7XHJcbiAgICAgICAgfSBjYXRjaCAoZXJyb3I6IHVua25vd24pIHtcclxuICAgICAgICAgIC8vIEhhbmRsZSBhYm9ydCBlcnJvcnNcclxuICAgICAgICAgIGlmICgoZXJyb3IgYXMgRXJyb3IpLm5hbWUgPT09ICdBYm9ydEVycm9yJykge1xyXG4gICAgICAgICAgICBjb25zdCBhYm9ydEVycm9yID0gT2JqZWN0LmFzc2lnbihcclxuICAgICAgICAgICAgICBuZXcgRXJyb3IoKGVycm9yIGFzIEVycm9yKS5tZXNzYWdlIHx8ICdSZXF1ZXN0IGFib3J0ZWQnKSxcclxuICAgICAgICAgICAgICB7XHJcbiAgICAgICAgICAgICAgICB0eXBlOiAncmVxdWVzdF9jYW5jZWxsZWQnLFxyXG4gICAgICAgICAgICAgICAgdGl0bGU6ICdSZXF1ZXN0IHdhcyBjYW5jZWxsZWQnLFxyXG4gICAgICAgICAgICAgICAgc3RhdHVzOiAwLFxyXG4gICAgICAgICAgICAgICAgdHJhY2VJZDogY29ycmVsYXRpb25JZCxcclxuICAgICAgICAgICAgICAgIGlzQWJvcnRlZDogdHJ1ZSxcclxuICAgICAgICAgICAgICAgIGNvbmZpZzogZmluYWxDb25maWcsXHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICApO1xyXG5cclxuICAgICAgICAgICAgLy8gQ2hlY2sgaWYgd2Ugc2hvdWxkIHRocm93IG9yIHJldHVybiBlcnJvciBpbiByZXNwb25zZVxyXG4gICAgICAgICAgICBpZiAoZmluYWxDb25maWcudGhyb3dFcnJvcnMgIT09IGZhbHNlKSB7XHJcbiAgICAgICAgICAgICAgdGhyb3cgYWJvcnRFcnJvcjtcclxuICAgICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgICAvLyBSZXR1cm4gZXJyb3IgaW4gQXBpUmVzcG9uc2UuZXJyb3IgZmllbGRcclxuICAgICAgICAgICAgICByZXR1cm4gYXdhaXQgdGhpcy5pbnRlcmNlcHRvck1hbmFnZXIuYXBwbHlSZXNwb25zZUludGVyY2VwdG9ycyh7XHJcbiAgICAgICAgICAgICAgICBlcnJvcjogYWJvcnRFcnJvcixcclxuICAgICAgICAgICAgICB9IGFzIEFwaVJlc3BvbnNlPFQsIEFwaUVycm9yPik7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICB0aHJvdyBlcnJvcjtcclxuICAgICAgICB9XHJcbiAgICAgIH07XHJcblxyXG4gICAgICAvLyBIYW5kbGUgcmV0cmllcyBpZiBjb25maWd1cmVkXHJcbiAgICAgIGlmIChmaW5hbENvbmZpZy5yZXRyaWVzICYmIGZpbmFsQ29uZmlnLnJldHJpZXMgPiAwKSB7XHJcbiAgICAgICAgcmV0dXJuIGF3YWl0IHRoaXMucmV0cnlIYW5kbGVyLnJldHJ5UmVxdWVzdChcclxuICAgICAgICAgIGZldGNoUHJvbWlzZSxcclxuICAgICAgICAgIGZpbmFsQ29uZmlnLnJldHJpZXMsXHJcbiAgICAgICAgICBmaW5hbENvbmZpZy5yZXRyeURlbGF5IHx8IDEwMDAsXHJcbiAgICAgICAgICBjb21iaW5lZENvbnRyb2xsZXIuc2lnbmFsXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgcmV0dXJuIGF3YWl0IGZldGNoUHJvbWlzZSgpO1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgLy8gSGFuZGxlIGVycm9yc1xyXG4gICAgICBjb25zdCBhcGlFcnJvcjogQXBpRXJyb3IgPSB0aGlzLmVycm9yTm9ybWFsaXplci5ub3JtYWxpemVFcnJvcihcclxuICAgICAgICBlcnJvcixcclxuICAgICAgICBjb25maWcsXHJcbiAgICAgICAgY29ycmVsYXRpb25JZFxyXG4gICAgICApO1xyXG5cclxuICAgICAgLy8gQ2hlY2sgaWYgd2Ugc2hvdWxkIHRocm93IG9yIHJldHVybiBlcnJvciBpbiByZXNwb25zZVxyXG4gICAgICBpZiAoY29uZmlnLnRocm93RXJyb3JzICE9PSBmYWxzZSkge1xyXG4gICAgICAgIGF3YWl0IHRoaXMuaW50ZXJjZXB0b3JNYW5hZ2VyLmFwcGx5RXJyb3JJbnRlcmNlcHRvcnMoYXBpRXJyb3IpO1xyXG4gICAgICAgIC8vIFRoaXMgbGluZSB3aWxsIG5ldmVyIGJlIHJlYWNoZWQgYXMgYXBwbHlFcnJvckludGVyY2VwdG9ycyBhbHdheXMgdGhyb3dzLFxyXG4gICAgICAgIC8vIGJ1dCBUeXBlU2NyaXB0IHJlcXVpcmVzIGEgcmV0dXJuIHN0YXRlbWVudFxyXG4gICAgICAgIHRocm93IGFwaUVycm9yO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIC8vIFJldHVybiBlcnJvciBpbiBBcGlSZXNwb25zZS5lcnJvciBmaWVsZFxyXG4gICAgICAgIHJldHVybiB7XHJcbiAgICAgICAgICBlcnJvcjogYXBpRXJyb3IsXHJcbiAgICAgICAgfSBhcyBBcGlSZXNwb25zZTxULCBBcGlFcnJvcj47XHJcbiAgICAgIH1cclxuICAgIH0gZmluYWxseSB7XHJcbiAgICAgIC8vIENsZWFuIHVwIHJlcXVlc3QgdHJhY2tpbmdcclxuICAgICAgdGhpcy5yZXF1ZXN0TWFuYWdlci5yZW1vdmUocmVxdWVzdEtleSk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBQZXJmb3JtcyBhIEdFVCByZXF1ZXN0XHJcbiAgICogQHRlbXBsYXRlIFQgLSBUaGUgZXhwZWN0ZWQgcmVzcG9uc2UgZGF0YSB0eXBlXHJcbiAgICogQHBhcmFtIGVuZHBvaW50IC0gQVBJIGVuZHBvaW50XHJcbiAgICogQHBhcmFtIGNvbmZpZyAtIE9wdGlvbmFsIHJlcXVlc3QgY29uZmlndXJhdGlvblxyXG4gICAqIEByZXR1cm5zIFByb21pc2UgcmVzb2x2aW5nIHRvIEFwaVJlc3BvbnNlXHJcbiAgICpcclxuICAgKiBAZXhhbXBsZVxyXG4gICAqIGBgYHR5cGVzY3JpcHRcclxuICAgKiBjb25zdCB7IGFwaURhdGEsIGVycm9yIH0gPSBhd2FpdCBjbGllbnQuZ2V0PFVzZXJbXT4oJy91c2VycycsIHtcclxuICAgKiAgIHBhcmFtczogeyBhY3RpdmU6IHRydWUgfSxcclxuICAgKiAgIHRpbWVvdXQ6IDUwMDBcclxuICAgKiB9KTtcclxuICAgKiBgYGBcclxuICAgKi9cclxuICBnZXQ8VCA9IFJlc3BvbnNlRGF0YT4oXHJcbiAgICBlbmRwb2ludDogc3RyaW5nLFxyXG4gICAgY29uZmlnPzogUmVxdWVzdENvbmZpZ1xyXG4gICk6IFByb21pc2U8QXBpUmVzcG9uc2U8VCwgQXBpRXJyb3I+PiB7XHJcbiAgICByZXR1cm4gdGhpcy5yZXF1ZXN0PFQ+KGVuZHBvaW50LCB7IC4uLmNvbmZpZywgbWV0aG9kOiAnR0VUJyB9KTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIFBlcmZvcm1zIGEgUE9TVCByZXF1ZXN0XHJcbiAgICogQHRlbXBsYXRlIFQgLSBUaGUgZXhwZWN0ZWQgcmVzcG9uc2UgZGF0YSB0eXBlXHJcbiAgICogQHRlbXBsYXRlIFREYXRhIC0gVGhlIHJlcXVlc3QgYm9keSBkYXRhIHR5cGVcclxuICAgKiBAcGFyYW0gZW5kcG9pbnQgLSBBUEkgZW5kcG9pbnRcclxuICAgKiBAcGFyYW0gZGF0YSAtIFJlcXVlc3QgYm9keSBkYXRhXHJcbiAgICogQHBhcmFtIGNvbmZpZyAtIE9wdGlvbmFsIHJlcXVlc3QgY29uZmlndXJhdGlvblxyXG4gICAqIEByZXR1cm5zIFByb21pc2UgcmVzb2x2aW5nIHRvIEFwaVJlc3BvbnNlXHJcbiAgICpcclxuICAgKiBAZXhhbXBsZVxyXG4gICAqIGBgYHR5cGVzY3JpcHRcclxuICAgKiBjb25zdCB7IGFwaURhdGEsIGVycm9yIH0gPSBhd2FpdCBjbGllbnQucG9zdDxVc2VyLCBDcmVhdGVVc2VyRHRvPignL3VzZXJzJywge1xyXG4gICAqICAgbmFtZTogJ0pvaG4gRG9lJyxcclxuICAgKiAgIGVtYWlsOiAnam9obkBleGFtcGxlLmNvbSdcclxuICAgKiB9KTtcclxuICAgKiBgYGBcclxuICAgKi9cclxuICBwb3N0PFxyXG4gICAgVCA9IFJlc3BvbnNlRGF0YSxcclxuICAgIFREYXRhIGV4dGVuZHMgQm9keUluaXQgfCBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiB8IG51bGwgPSBSZWNvcmQ8XHJcbiAgICAgIHN0cmluZyxcclxuICAgICAgdW5rbm93blxyXG4gICAgPixcclxuICA+KFxyXG4gICAgZW5kcG9pbnQ6IHN0cmluZyxcclxuICAgIGRhdGE/OiBURGF0YSxcclxuICAgIGNvbmZpZz86IFJlcXVlc3RDb25maWdcclxuICApOiBQcm9taXNlPEFwaVJlc3BvbnNlPFQsIEFwaUVycm9yPj4ge1xyXG4gICAgcmV0dXJuIHRoaXMucmVxdWVzdDxUPihlbmRwb2ludCwgeyAuLi5jb25maWcsIG1ldGhvZDogJ1BPU1QnLCBib2R5OiBkYXRhIH0pO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogUGVyZm9ybXMgYSBQVVQgcmVxdWVzdFxyXG4gICAqIEB0ZW1wbGF0ZSBUIC0gVGhlIGV4cGVjdGVkIHJlc3BvbnNlIGRhdGEgdHlwZVxyXG4gICAqIEB0ZW1wbGF0ZSBURGF0YSAtIFRoZSByZXF1ZXN0IGJvZHkgZGF0YSB0eXBlXHJcbiAgICogQHBhcmFtIGVuZHBvaW50IC0gQVBJIGVuZHBvaW50XHJcbiAgICogQHBhcmFtIGRhdGEgLSBSZXF1ZXN0IGJvZHkgZGF0YVxyXG4gICAqIEBwYXJhbSBjb25maWcgLSBPcHRpb25hbCByZXF1ZXN0IGNvbmZpZ3VyYXRpb25cclxuICAgKiBAcmV0dXJucyBQcm9taXNlIHJlc29sdmluZyB0byBBcGlSZXNwb25zZVxyXG4gICAqXHJcbiAgICogQGV4YW1wbGVcclxuICAgKiBgYGB0eXBlc2NyaXB0XHJcbiAgICogY29uc3QgeyBhcGlEYXRhLCBlcnJvciB9ID0gYXdhaXQgY2xpZW50LnB1dDxVc2VyLCBVcGRhdGVVc2VyRHRvPihcclxuICAgKiAgICcvdXNlcnMvMTIzJyxcclxuICAgKiAgIHsgbmFtZTogJ0phbmUgRG9lJyB9XHJcbiAgICogKTtcclxuICAgKiBgYGBcclxuICAgKi9cclxuICBwdXQ8XHJcbiAgICBUID0gUmVzcG9uc2VEYXRhLFxyXG4gICAgVERhdGEgZXh0ZW5kcyBCb2R5SW5pdCB8IFJlY29yZDxzdHJpbmcsIHVua25vd24+IHwgbnVsbCA9IFJlY29yZDxcclxuICAgICAgc3RyaW5nLFxyXG4gICAgICB1bmtub3duXHJcbiAgICA+LFxyXG4gID4oXHJcbiAgICBlbmRwb2ludDogc3RyaW5nLFxyXG4gICAgZGF0YT86IFREYXRhLFxyXG4gICAgY29uZmlnPzogUmVxdWVzdENvbmZpZ1xyXG4gICk6IFByb21pc2U8QXBpUmVzcG9uc2U8VCwgQXBpRXJyb3I+PiB7XHJcbiAgICByZXR1cm4gdGhpcy5yZXF1ZXN0PFQ+KGVuZHBvaW50LCB7IC4uLmNvbmZpZywgbWV0aG9kOiAnUFVUJywgYm9keTogZGF0YSB9KTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIFBlcmZvcm1zIGEgUEFUQ0ggcmVxdWVzdFxyXG4gICAqIEB0ZW1wbGF0ZSBUIC0gVGhlIGV4cGVjdGVkIHJlc3BvbnNlIGRhdGEgdHlwZVxyXG4gICAqIEB0ZW1wbGF0ZSBURGF0YSAtIFRoZSByZXF1ZXN0IGJvZHkgZGF0YSB0eXBlXHJcbiAgICogQHBhcmFtIGVuZHBvaW50IC0gQVBJIGVuZHBvaW50XHJcbiAgICogQHBhcmFtIGRhdGEgLSBSZXF1ZXN0IGJvZHkgZGF0YVxyXG4gICAqIEBwYXJhbSBjb25maWcgLSBPcHRpb25hbCByZXF1ZXN0IGNvbmZpZ3VyYXRpb25cclxuICAgKiBAcmV0dXJucyBQcm9taXNlIHJlc29sdmluZyB0byBBcGlSZXNwb25zZVxyXG4gICAqXHJcbiAgICogQGV4YW1wbGVcclxuICAgKiBgYGB0eXBlc2NyaXB0XHJcbiAgICogY29uc3QgeyBhcGlEYXRhLCBlcnJvciB9ID0gYXdhaXQgY2xpZW50LnBhdGNoPFVzZXI+KFxyXG4gICAqICAgJy91c2Vycy8xMjMnLFxyXG4gICAqICAgeyBzdGF0dXM6ICdhY3RpdmUnIH1cclxuICAgKiApO1xyXG4gICAqIGBgYFxyXG4gICAqL1xyXG4gIHBhdGNoPFxyXG4gICAgVCA9IFJlc3BvbnNlRGF0YSxcclxuICAgIFREYXRhIGV4dGVuZHMgQm9keUluaXQgfCBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiB8IG51bGwgPSBSZWNvcmQ8XHJcbiAgICAgIHN0cmluZyxcclxuICAgICAgdW5rbm93blxyXG4gICAgPixcclxuICA+KFxyXG4gICAgZW5kcG9pbnQ6IHN0cmluZyxcclxuICAgIGRhdGE/OiBURGF0YSxcclxuICAgIGNvbmZpZz86IFJlcXVlc3RDb25maWdcclxuICApOiBQcm9taXNlPEFwaVJlc3BvbnNlPFQsIEFwaUVycm9yPj4ge1xyXG4gICAgcmV0dXJuIHRoaXMucmVxdWVzdDxUPihlbmRwb2ludCwge1xyXG4gICAgICAuLi5jb25maWcsXHJcbiAgICAgIG1ldGhvZDogJ1BBVENIJyxcclxuICAgICAgYm9keTogZGF0YSxcclxuICAgIH0pO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogUGVyZm9ybXMgYSBERUxFVEUgcmVxdWVzdFxyXG4gICAqIEB0ZW1wbGF0ZSBUIC0gVGhlIGV4cGVjdGVkIHJlc3BvbnNlIGRhdGEgdHlwZVxyXG4gICAqIEBwYXJhbSBlbmRwb2ludCAtIEFQSSBlbmRwb2ludFxyXG4gICAqIEBwYXJhbSBjb25maWcgLSBPcHRpb25hbCByZXF1ZXN0IGNvbmZpZ3VyYXRpb25cclxuICAgKiBAcmV0dXJucyBQcm9taXNlIHJlc29sdmluZyB0byBBcGlSZXNwb25zZVxyXG4gICAqXHJcbiAgICogQGV4YW1wbGVcclxuICAgKiBgYGB0eXBlc2NyaXB0XHJcbiAgICogY29uc3QgeyBlcnJvciB9ID0gYXdhaXQgY2xpZW50LmRlbGV0ZSgnL3VzZXJzLzEyMycpO1xyXG4gICAqIGlmICghZXJyb3IpIHtcclxuICAgKiAgIGNvbnNvbGUubG9nKCdVc2VyIGRlbGV0ZWQgc3VjY2Vzc2Z1bGx5Jyk7XHJcbiAgICogfVxyXG4gICAqIGBgYFxyXG4gICAqL1xyXG4gIGRlbGV0ZTxUID0gUmVzcG9uc2VEYXRhPihcclxuICAgIGVuZHBvaW50OiBzdHJpbmcsXHJcbiAgICBjb25maWc/OiBSZXF1ZXN0Q29uZmlnXHJcbiAgKTogUHJvbWlzZTxBcGlSZXNwb25zZTxULCBBcGlFcnJvcj4+IHtcclxuICAgIHJldHVybiB0aGlzLnJlcXVlc3Q8VD4oZW5kcG9pbnQsIHsgLi4uY29uZmlnLCBtZXRob2Q6ICdERUxFVEUnIH0pO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogUGVyZm9ybXMgYSBmaWx0ZXJlZCBsaXN0IHJlcXVlc3Qgd2l0aCBwYWdpbmF0aW9uIGFuZCBzb3J0aW5nXHJcbiAgICogQHRlbXBsYXRlIFRMaXN0TW9kZWwgLSBUaGUgdHlwZSBvZiBpbmRpdmlkdWFsIGxpc3QgaXRlbXNcclxuICAgKiBAdGVtcGxhdGUgVEZpbHRlciAtIFRoZSBmaWx0ZXIgY3JpdGVyaWEgdHlwZVxyXG4gICAqIEBwYXJhbSB1cmwgLSBBUEkgZW5kcG9pbnRcclxuICAgKiBAcGFyYW0gZGF0YSAtIFBhZ2luYXRpb24gYW5kIGZpbHRlciBkYXRhXHJcbiAgICogQHBhcmFtIGNvbmZpZyAtIE9wdGlvbmFsIHJlcXVlc3QgY29uZmlndXJhdGlvblxyXG4gICAqIEByZXR1cm5zIFByb21pc2UgcmVzb2x2aW5nIHRvIHBhZ2luYXRlZCBsaXN0IHJlc3BvbnNlXHJcbiAgICpcclxuICAgKiBAZXhhbXBsZVxyXG4gICAqIGBgYHR5cGVzY3JpcHRcclxuICAgKiBjb25zdCB7IGFwaURhdGEsIGVycm9yIH0gPSBhd2FpdCBjbGllbnQuZmlsdGVyPFVzZXIsIFVzZXJGaWx0ZXI+KFxyXG4gICAqICAgJy91c2Vycy9maWx0ZXInLFxyXG4gICAqICAge1xyXG4gICAqICAgICBwYWdlT2Zmc2V0OiAwLFxyXG4gICAqICAgICBwYWdlU2l6ZTogMjAsXHJcbiAgICogICAgIHNvcnRGaWVsZDogJ2NyZWF0ZWRBdCcsXHJcbiAgICogICAgIHNvcnRPcmRlcjogJ2Rlc2MnLFxyXG4gICAqICAgICBmaWx0ZXJNb2RlbDogeyBzdGF0dXM6ICdhY3RpdmUnIH1cclxuICAgKiAgIH1cclxuICAgKiApO1xyXG4gICAqXHJcbiAgICogaWYgKGFwaURhdGEpIHtcclxuICAgKiAgIGNvbnNvbGUubG9nKGBGb3VuZCAke2FwaURhdGEuVG90YWx9IHVzZXJzYCk7XHJcbiAgICogICBjb25zb2xlLmxvZygnVXNlcnM6JywgYXBpRGF0YS5EYXRhKTtcclxuICAgKiB9XHJcbiAgICogYGBgXHJcbiAgICovXHJcbiAgZmlsdGVyPFRMaXN0TW9kZWwsIFRGaWx0ZXIgPSBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPj4oXHJcbiAgICB1cmw6IHN0cmluZyxcclxuICAgIGRhdGE6IFBvc3RNb2RlbDxURmlsdGVyPixcclxuICAgIGNvbmZpZz86IFJlcXVlc3RDb25maWdcclxuICApOiBQcm9taXNlPEFwaVJlc3BvbnNlPFBhZ2luYXRlZFJlc3BvbnNlPFRMaXN0TW9kZWw+LCBBcGlFcnJvcj4+IHtcclxuICAgIC8vIE1lcmdlIGJvZHk6IHsgLi4ucG9zdE1vZGVsLCAuLi5wb3N0TW9kZWwuZmlsdGVyTW9kZWwgfVxyXG4gICAgY29uc3QgbWVyZ2VkRGF0YSA9IHsgLi4uZGF0YSwgLi4uZGF0YS5maWx0ZXJNb2RlbCB9O1xyXG5cclxuICAgIHJldHVybiB0aGlzLnJlcXVlc3Q8UGFnaW5hdGVkUmVzcG9uc2U8VExpc3RNb2RlbD4+KHVybCwge1xyXG4gICAgICAuLi5jb25maWcsXHJcbiAgICAgIG1ldGhvZDogJ1BPU1QnLFxyXG4gICAgICBib2R5OiBtZXJnZWREYXRhLFxyXG4gICAgfSk7XHJcbiAgfVxyXG59XHJcbiIsICIvKipcclxuICogQGZpbGVvdmVydmlldyBGYWN0b3J5IGZ1bmN0aW9ucyBmb3IgY3JlYXRpbmcgYW5kIG1hbmFnaW5nIEFwaUNsaWVudCBpbnN0YW5jZXMuXHJcbiAqXHJcbiAqIFByb3ZpZGVzIGNvbnZlbmllbnQgZmFjdG9yeSBtZXRob2RzIGZvciBjcmVhdGluZyBwcmUtY29uZmlndXJlZCBBcGlDbGllbnQgaW5zdGFuY2VzXHJcbiAqIHdpdGggc2Vuc2libGUgZGVmYXVsdHMgYW5kIGF1dG9tYXRpYyB0b2tlbiBtYW5hZ2VtZW50IGZyb20gbG9jYWxTdG9yYWdlLlxyXG4gKlxyXG4gKiBAbW9kdWxlIGNyZWF0ZUFwaUNsaWVudFxyXG4gKi9cclxuXHJcbmltcG9ydCB7IEFwaUNsaWVudCB9IGZyb20gJy4vQXBpQ2xpZW50JztcclxuaW1wb3J0IHR5cGUgeyBFcnJvckludGVyY2VwdG9yIH0gZnJvbSAnLi90eXBlcy9FcnJvckludGVyY2VwdG9yJztcclxuaW1wb3J0IHR5cGUgeyBSZXF1ZXN0SW50ZXJjZXB0b3IgfSBmcm9tICcuL3R5cGVzL1JlcXVlc3RJbnRlcmNlcHRvcic7XHJcbmltcG9ydCB0eXBlIHsgUmVzcG9uc2VJbnRlcmNlcHRvciB9IGZyb20gJy4vdHlwZXMvUmVzcG9uc2VJbnRlcmNlcHRvcic7XHJcblxyXG4vKipcclxuICogQ29uZmlndXJhdGlvbiBvcHRpb25zIGZvciBjcmVhdGluZyBhbiBBcGlDbGllbnQgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEBwdWJsaWNcclxuICovXHJcbmV4cG9ydCBpbnRlcmZhY2UgQXBpQ2xpZW50Q29uZmlnIHtcclxuICAvKipcclxuICAgKiBCYXNlIFVSTCBmb3IgYWxsIEFQSSByZXF1ZXN0cy5cclxuICAgKiBAZXhhbXBsZSAnaHR0cHM6Ly9hcGkuZXhhbXBsZS5jb20nXHJcbiAgICovXHJcbiAgYmFzZVVSTDogc3RyaW5nO1xyXG5cclxuICAvKipcclxuICAgKiBEZWZhdWx0IHRpbWVvdXQgZm9yIHJlcXVlc3RzIGluIG1pbGxpc2Vjb25kcy5cclxuICAgKiBAZGVmYXVsdCAzMDAwMFxyXG4gICAqL1xyXG4gIHRpbWVvdXQ/OiBudW1iZXI7XHJcblxyXG4gIC8qKlxyXG4gICAqIFByZWZpeCBmb3IgYXV0by1nZW5lcmF0ZWQgY29ycmVsYXRpb24gSURzIChlLmcuLCAnYXBpJywgJ3dlYicsICdtb2JpbGUnKS5cclxuICAgKiBAZGVmYXVsdCAnYXBpJ1xyXG4gICAqL1xyXG4gIGNvcnJlbGF0aW9uSWRQcmVmaXg6IHN0cmluZztcclxuXHJcbiAgLyoqXHJcbiAgICogV2hldGhlciB0byBhdXRvbWF0aWNhbGx5IGdlbmVyYXRlIGFuZCBpbmNsdWRlIGNvcnJlbGF0aW9uIElEcyBpbiByZXF1ZXN0cy5cclxuICAgKiBAZGVmYXVsdCB0cnVlXHJcbiAgICovXHJcbiAgaW5jbHVkZUNvcnJlbGF0aW9uSWQ/OiBib29sZWFuO1xyXG5cclxuICAvKipcclxuICAgKiBsb2NhbFN0b3JhZ2Uga2V5IHVzZWQgdG8gcmV0cmlldmUgdGhlIGF1dGggdG9rZW4uXHJcbiAgICogQGV4YW1wbGUgJ3NlcnZpY2VUb2tlbidcclxuICAgKi9cclxuICB0b2tlblN0b3JhZ2VLZXk6IHN0cmluZztcclxuXHJcbiAgLyoqXHJcbiAgICogSW5pdGlhbCBhdXRoZW50aWNhdGlvbiB0b2tlbiB0byBzZXQgb24gdGhlIGNsaWVudC5cclxuICAgKiBAZGVmYXVsdCB1bmRlZmluZWRcclxuICAgKi9cclxuICBhdXRoVG9rZW4/OiBzdHJpbmcgfCBudWxsO1xyXG5cclxuICAvKipcclxuICAgKiBBcnJheSBvZiByZXF1ZXN0IGludGVyY2VwdG9ycyB0byByZWdpc3RlciBkdXJpbmcgY2xpZW50IGNyZWF0aW9uLlxyXG4gICAqIEBkZWZhdWx0IFtdXHJcbiAgICovXHJcbiAgcmVxdWVzdEludGVyY2VwdG9ycz86IFJlcXVlc3RJbnRlcmNlcHRvcltdO1xyXG5cclxuICAvKipcclxuICAgKiBBcnJheSBvZiByZXNwb25zZSBpbnRlcmNlcHRvcnMgdG8gcmVnaXN0ZXIgZHVyaW5nIGNsaWVudCBjcmVhdGlvbi5cclxuICAgKiBAZGVmYXVsdCBbXVxyXG4gICAqL1xyXG4gIHJlc3BvbnNlSW50ZXJjZXB0b3JzPzogUmVzcG9uc2VJbnRlcmNlcHRvcltdO1xyXG5cclxuICAvKipcclxuICAgKiBBcnJheSBvZiBlcnJvciBpbnRlcmNlcHRvcnMgdG8gcmVnaXN0ZXIgZHVyaW5nIGNsaWVudCBjcmVhdGlvbi5cclxuICAgKiBAZGVmYXVsdCBbXVxyXG4gICAqL1xyXG4gIGVycm9ySW50ZXJjZXB0b3JzPzogRXJyb3JJbnRlcmNlcHRvcltdO1xyXG59XHJcblxyXG4vKipcclxuICogR2xvYmFsIHNpbmdsZXRvbiBBcGlDbGllbnQgaW5zdGFuY2UuXHJcbiAqIEBpbnRlcm5hbFxyXG4gKi9cclxubGV0IGdsb2JhbEFwaUNsaWVudDogQXBpQ2xpZW50IHwgbnVsbCA9IG51bGw7XHJcblxyXG4vKipcclxuICogQ3JlYXRlcyBhIG5ldyBBcGlDbGllbnQgaW5zdGFuY2Ugd2l0aCBhdXRvbWF0aWMgdG9rZW4gbWFuYWdlbWVudC5cclxuICpcclxuICogVGhpcyBmYWN0b3J5IGZ1bmN0aW9uOlxyXG4gKiAtIFJlcXVpcmVzIGJhc2UgVVJMLCBjb3JyZWxhdGlvbiBJRCBwcmVmaXgsIGFuZCB0b2tlbiBzdG9yYWdlIGtleSB0byBiZSBleHBsaWNpdGx5IHByb3ZpZGVkXHJcbiAqIC0gU2V0cyB1cCBhdXRvbWF0aWMgYXV0aGVudGljYXRpb24gdG9rZW4gaW5qZWN0aW9uIGZyb20gbG9jYWxTdG9yYWdlXHJcbiAqIC0gQ29uZmlndXJlcyBjb3JyZWxhdGlvbiBJRCBnZW5lcmF0aW9uXHJcbiAqIC0gUmVnaXN0ZXJzIHByb3ZpZGVkIGludGVyY2VwdG9yc1xyXG4gKlxyXG4gKiAqKk5vdGU6KiogRWFjaCBjYWxsIGNyZWF0ZXMgYSBORVcgaW5zdGFuY2UuIFVzZSB7QGxpbmsgZ2V0R2xvYmFsQXBpQ2xpZW50fSBmb3Igc2luZ2xldG9uIGJlaGF2aW9yLlxyXG4gKlxyXG4gKiBAcGFyYW0gY29uZmlnIC0gQ29uZmlndXJhdGlvbiBvcHRpb25zIGZvciB0aGUgQVBJIGNsaWVudCAoYmFzZVVSTCwgY29ycmVsYXRpb25JZFByZWZpeCwgdG9rZW5TdG9yYWdlS2V5IGFyZSByZXF1aXJlZClcclxuICogQHJldHVybnMgQSBmdWxseSBjb25maWd1cmVkIEFwaUNsaWVudCBpbnN0YW5jZVxyXG4gKiBAcHVibGljXHJcbiAqXHJcbiAqIEBleGFtcGxlXHJcbiAqIEJhc2ljIHVzYWdlOlxyXG4gKiBgYGB0eXBlc2NyaXB0XHJcbiAqIGNvbnN0IGNsaWVudCA9IGNyZWF0ZUFwaUNsaWVudCh7XHJcbiAqICAgYmFzZVVSTDogJ2h0dHBzOi8vYXBpLmV4YW1wbGUuY29tJyxcclxuICogICBjb3JyZWxhdGlvbklkUHJlZml4OiAnd2ViJyxcclxuICogICB0b2tlblN0b3JhZ2VLZXk6ICdzZXJ2aWNlVG9rZW4nXHJcbiAqIH0pO1xyXG4gKiBgYGBcclxuICpcclxuICogQGV4YW1wbGVcclxuICogQ3VzdG9tIGNvbmZpZ3VyYXRpb24gd2l0aCBpbnRlcmNlcHRvcnM6XHJcbiAqIGBgYHR5cGVzY3JpcHRcclxuICogY29uc3QgY2xpZW50ID0gY3JlYXRlQXBpQ2xpZW50KHtcclxuICogICBiYXNlVVJMOiAnaHR0cHM6Ly9hcGkuZXhhbXBsZS5jb20nLFxyXG4gKiAgIGNvcnJlbGF0aW9uSWRQcmVmaXg6ICd3ZWInLFxyXG4gKiAgIHRva2VuU3RvcmFnZUtleTogJ2F1dGhUb2tlbicsXHJcbiAqICAgdGltZW91dDogNjAwMDAsXHJcbiAqICAgcmVxdWVzdEludGVyY2VwdG9yczogW1xyXG4gKiAgICAgYXN5bmMgKGNvbmZpZykgPT4ge1xyXG4gKiAgICAgICBjb25zb2xlLmxvZygnTWFraW5nIHJlcXVlc3Q6JywgY29uZmlnLnVybCk7XHJcbiAqICAgICAgIHJldHVybiBjb25maWc7XHJcbiAqICAgICB9XHJcbiAqICAgXVxyXG4gKiB9KTtcclxuICogYGBgXHJcbiAqXHJcbiAqIEBleGFtcGxlXHJcbiAqIFdpdGggUmVhY3QgUXVlcnk6XHJcbiAqIGBgYHR5cGVzY3JpcHRcclxuICogY29uc3QgYXBpQ2xpZW50ID0gY3JlYXRlQXBpQ2xpZW50KHtcclxuICogICBiYXNlVVJMOiBwcm9jZXNzLmVudi5SRUFDVF9BUFBfQVBJX1VSTCxcclxuICogICBjb3JyZWxhdGlvbklkUHJlZml4OiAnd2ViJyxcclxuICogICB0b2tlblN0b3JhZ2VLZXk6ICdzZXJ2aWNlVG9rZW4nXHJcbiAqIH0pO1xyXG4gKlxyXG4gKiBjb25zdCBxdWVyeUNsaWVudCA9IG5ldyBRdWVyeUNsaWVudCgpO1xyXG4gKlxyXG4gKiBmdW5jdGlvbiBVc2VyUHJvZmlsZSh7IHVzZXJJZCB9KSB7XHJcbiAqICAgY29uc3QgeyBkYXRhOiByZXNwb25zZSB9ID0gdXNlUXVlcnkoe1xyXG4gKiAgICAgcXVlcnlLZXk6IFsndXNlcicsIHVzZXJJZF0sXHJcbiAqICAgICBxdWVyeUZuOiAoKSA9PiBhcGlDbGllbnQuZ2V0KGAvdXNlcnMvJHt1c2VySWR9YClcclxuICogICB9KTtcclxuICogICBjb25zdCB1c2VyID0gcmVzcG9uc2U/LmFwaURhdGE7IC8vIEFjY2VzcyB0aGUgYWN0dWFsIGRhdGFcclxuICogICAvLyAuLi5cclxuICogfVxyXG4gKiBgYGBcclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVBcGlDbGllbnQoY29uZmlnOiBBcGlDbGllbnRDb25maWcpOiBBcGlDbGllbnQge1xyXG4gIGNvbnN0IHtcclxuICAgIGJhc2VVUkwsXHJcbiAgICB0aW1lb3V0ID0gMzAwMDAsXHJcbiAgICBjb3JyZWxhdGlvbklkUHJlZml4LFxyXG4gICAgaW5jbHVkZUNvcnJlbGF0aW9uSWQgPSB0cnVlLFxyXG4gICAgdG9rZW5TdG9yYWdlS2V5LFxyXG4gICAgcmVxdWVzdEludGVyY2VwdG9ycyA9IFtdLFxyXG4gICAgcmVzcG9uc2VJbnRlcmNlcHRvcnMgPSBbXSxcclxuICAgIGVycm9ySW50ZXJjZXB0b3JzID0gW10sXHJcbiAgfSA9IGNvbmZpZztcclxuXHJcbiAgY29uc3QgY2xpZW50ID0gbmV3IEFwaUNsaWVudChiYXNlVVJMLCB0aW1lb3V0KTtcclxuXHJcbiAgY2xpZW50LmFkZFJlcXVlc3RJbnRlcmNlcHRvcihjb25maWcgPT4ge1xyXG4gICAgY29uc3QgdG9rZW4gPSBsb2NhbFN0b3JhZ2UuZ2V0SXRlbSh0b2tlblN0b3JhZ2VLZXkpO1xyXG5cclxuICAgIGlmICh0b2tlbiAmJiAhY29uZmlnLnNraXBBdXRoUmVmcmVzaCkge1xyXG4gICAgICBjb25maWcuaGVhZGVycyA9IHtcclxuICAgICAgICAuLi5jb25maWcuaGVhZGVycyxcclxuICAgICAgICBBdXRob3JpemF0aW9uOiBgQmVhcmVyICR7dG9rZW59YCxcclxuICAgICAgfTtcclxuICAgIH1cclxuXHJcbiAgICByZXR1cm4gY29uZmlnO1xyXG4gIH0pO1xyXG5cclxuICAvLyBDb25maWd1cmUgY29ycmVsYXRpb24gSURcclxuICBjbGllbnQuc2V0Q29ycmVsYXRpb25JZFByZWZpeChjb3JyZWxhdGlvbklkUHJlZml4KTtcclxuICBjbGllbnQuc2V0SW5jbHVkZUNvcnJlbGF0aW9uSWQoaW5jbHVkZUNvcnJlbGF0aW9uSWQpO1xyXG5cclxuICAvLyAvLyBTZXQgYXV0aCB0b2tlbiBpZiBwcm92aWRlZFxyXG4gIC8vIGlmIChhdXRoVG9rZW4gIT09IHVuZGVmaW5lZCkge1xyXG4gIC8vICAgY2xpZW50LnNldEF1dGhUb2tlbihhdXRoVG9rZW4pO1xyXG4gIC8vIH1cclxuXHJcbiAgLy8gQWRkIGludGVyY2VwdG9yc1xyXG4gIHJlcXVlc3RJbnRlcmNlcHRvcnMuZm9yRWFjaChpbnRlcmNlcHRvciA9PiB7XHJcbiAgICBjbGllbnQuYWRkUmVxdWVzdEludGVyY2VwdG9yKGludGVyY2VwdG9yKTtcclxuICB9KTtcclxuXHJcbiAgcmVzcG9uc2VJbnRlcmNlcHRvcnMuZm9yRWFjaChpbnRlcmNlcHRvciA9PiB7XHJcbiAgICBjbGllbnQuYWRkUmVzcG9uc2VJbnRlcmNlcHRvcihpbnRlcmNlcHRvcik7XHJcbiAgfSk7XHJcblxyXG4gIGVycm9ySW50ZXJjZXB0b3JzLmZvckVhY2goaW50ZXJjZXB0b3IgPT4ge1xyXG4gICAgY2xpZW50LmFkZEVycm9ySW50ZXJjZXB0b3IoaW50ZXJjZXB0b3IpO1xyXG4gIH0pO1xyXG5cclxuICByZXR1cm4gY2xpZW50O1xyXG59XHJcblxyXG4vKipcclxuICogR2V0cyB0aGUgZ2xvYmFsIHNpbmdsZXRvbiBBcGlDbGllbnQgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIFRoaXMgZnVuY3Rpb24gcmV0dXJucyB0aGUgZXhpc3RpbmcgZ2xvYmFsIEFwaUNsaWVudC4gVGhlIGNsaWVudCBtdXN0IGZpcnN0IGJlXHJcbiAqIGluaXRpYWxpemVkIHVzaW5nIHtAbGluayBpbml0aWFsaXplR2xvYmFsQXBpQ2xpZW50fS5cclxuICpcclxuICogQHJldHVybnMgVGhlIGdsb2JhbCBBcGlDbGllbnQgc2luZ2xldG9uIGluc3RhbmNlXHJcbiAqIEB0aHJvd3MgRXJyb3IgaWYgdGhlIGdsb2JhbCBjbGllbnQgaGFzIG5vdCBiZWVuIGluaXRpYWxpemVkXHJcbiAqIEBwdWJsaWNcclxuICpcclxuICogQGV4YW1wbGVcclxuICogYGBgdHlwZXNjcmlwdFxyXG4gKiAvLyBzcmMvZmVhdHVyZXMvdXNlcnMvYXBpLnRzXHJcbiAqIGltcG9ydCB7IGdldEdsb2JhbEFwaUNsaWVudCB9IGZyb20gJ0BnbndlYnNvZnQvdWknO1xyXG4gKlxyXG4gKiBjb25zdCBjbGllbnQgPSBnZXRHbG9iYWxBcGlDbGllbnQoKTtcclxuICpcclxuICogZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGZldGNoVXNlcnMoKSB7XHJcbiAqICAgY29uc3QgeyBhcGlEYXRhIH0gPSBhd2FpdCBjbGllbnQuZ2V0KCcvdXNlcnMnKTtcclxuICogICByZXR1cm4gYXBpRGF0YTtcclxuICogfVxyXG4gKiBgYGBcclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBnZXRHbG9iYWxBcGlDbGllbnQoKTogQXBpQ2xpZW50IHtcclxuICBpZiAoIWdsb2JhbEFwaUNsaWVudCkge1xyXG4gICAgdGhyb3cgbmV3IEVycm9yKFxyXG4gICAgICAnZ2V0R2xvYmFsQXBpQ2xpZW50OiBObyBnbG9iYWwgY2xpZW50IGV4aXN0cy4gQ2FsbCBpbml0aWFsaXplR2xvYmFsQXBpQ2xpZW50KCkgZmlyc3QgdG8gY29uZmlndXJlIHRoZSBjbGllbnQuJ1xyXG4gICAgKTtcclxuICB9XHJcblxyXG4gIHJldHVybiBnbG9iYWxBcGlDbGllbnQ7XHJcbn1cclxuXHJcblxyXG4vKipcclxuICogSW5pdGlhbGl6ZXMgdGhlIGdsb2JhbCBzaW5nbGV0b24gQXBpQ2xpZW50IHdpdGggdGhlIHByb3ZpZGVkIGNvbmZpZ3VyYXRpb24uXHJcbiAqXHJcbiAqIFRoaXMgc2hvdWxkIGJlIGNhbGxlZCBvbmNlIGR1cmluZyBhcHAgaW5pdGlhbGl6YXRpb24gKGUuZy4sIGluIHlvdXIgbWFpbiBlbnRyeSBwb2ludCkuXHJcbiAqIEFmdGVyIGluaXRpYWxpemF0aW9uLCB1c2Uge0BsaW5rIGdldEdsb2JhbEFwaUNsaWVudH0gdG8gcmV0cmlldmUgdGhlIGNsaWVudCBhbnl3aGVyZSBpbiB5b3VyIGFwcC5cclxuICpcclxuICogQHBhcmFtIGNvbmZpZyAtIENvbmZpZ3VyYXRpb24gb3B0aW9ucyAoYmFzZVVSTCwgY29ycmVsYXRpb25JZFByZWZpeCwgdG9rZW5TdG9yYWdlS2V5IGFyZSByZXF1aXJlZClcclxuICogQHJldHVybnMgVGhlIGluaXRpYWxpemVkIEFwaUNsaWVudCBpbnN0YW5jZVxyXG4gKiBAdGhyb3dzIEVycm9yIGlmIHRoZSBnbG9iYWwgY2xpZW50IGhhcyBhbHJlYWR5IGJlZW4gaW5pdGlhbGl6ZWRcclxuICogQHB1YmxpY1xyXG4gKlxyXG4gKiBAZXhhbXBsZVxyXG4gKiBgYGB0eXBlc2NyaXB0XHJcbiAqIC8vIHNyYy9tYWluLnRzeCBvciBzcmMvaW5kZXgudHN4XHJcbiAqIGltcG9ydCB7IGluaXRpYWxpemVHbG9iYWxBcGlDbGllbnQgfSBmcm9tICdAZ253ZWJzb2Z0L3VpJztcclxuICpcclxuICogaW5pdGlhbGl6ZUdsb2JhbEFwaUNsaWVudCh7XHJcbiAqICAgYmFzZVVSTDogaW1wb3J0Lm1ldGEuZW52LlZJVEVfQVBJX1VSTCxcclxuICogICBjb3JyZWxhdGlvbklkUHJlZml4OiAnd2ViJyxcclxuICogICB0b2tlblN0b3JhZ2VLZXk6ICdzZXJ2aWNlVG9rZW4nXHJcbiAqIH0pO1xyXG4gKiBgYGBcclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBpbml0aWFsaXplR2xvYmFsQXBpQ2xpZW50KGNvbmZpZzogQXBpQ2xpZW50Q29uZmlnKTogQXBpQ2xpZW50IHtcclxuICBpZiAoZ2xvYmFsQXBpQ2xpZW50KSB7XHJcbiAgICB0aHJvdyBuZXcgRXJyb3IoXHJcbiAgICAgICdpbml0aWFsaXplR2xvYmFsQXBpQ2xpZW50OiBHbG9iYWwgY2xpZW50IGFscmVhZHkgaW5pdGlhbGl6ZWQuIFVzZSByZXNldEdsb2JhbEFwaUNsaWVudCgpIGZpcnN0IGlmIHlvdSBuZWVkIHRvIHJlaW5pdGlhbGl6ZS4nXHJcbiAgICApO1xyXG4gIH1cclxuXHJcbiAgZ2xvYmFsQXBpQ2xpZW50ID0gY3JlYXRlQXBpQ2xpZW50KGNvbmZpZyk7XHJcbiAgcmV0dXJuIGdsb2JhbEFwaUNsaWVudDtcclxufVxyXG5cclxuLyoqXHJcbiAqIFJlcGxhY2VzIHRoZSBnbG9iYWwgc2luZ2xldG9uIEFwaUNsaWVudCB3aXRoIGEgY3VzdG9tIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBVc2UgdGhpcyB3aGVuIHlvdSBuZWVkIGZpbmUtZ3JhaW5lZCBjb250cm9sIG92ZXIgdGhlIGdsb2JhbCBjbGllbnQgaW5zdGFuY2UsXHJcbiAqIHN1Y2ggYXMgaW4gdGVzdGluZyBzY2VuYXJpb3Mgb3Igd2hlbiB5b3UndmUgbWFudWFsbHkgY3JlYXRlZCBhIGNsaWVudCB3aXRoXHJcbiAqIHNwZWNpZmljIGNvbmZpZ3VyYXRpb24uXHJcbiAqXHJcbiAqIEBwYXJhbSBjbGllbnQgLSBUaGUgQXBpQ2xpZW50IGluc3RhbmNlIHRvIHVzZSBhcyB0aGUgZ2xvYmFsIHNpbmdsZXRvblxyXG4gKiBAcHVibGljXHJcbiAqXHJcbiAqIEBleGFtcGxlXHJcbiAqIFRlc3Rpbmcgd2l0aCBhIG1vY2sgY2xpZW50OlxyXG4gKiBgYGB0eXBlc2NyaXB0XHJcbiAqIGNvbnN0IG1vY2tDbGllbnQgPSBuZXcgQXBpQ2xpZW50KCdodHRwOi8vdGVzdC5sb2NhbCcpO1xyXG4gKiBtb2NrQ2xpZW50LmFkZFJlc3BvbnNlSW50ZXJjZXB0b3IoYXN5bmMgKHJlc3BvbnNlKSA9PiB7XHJcbiAqICAgLy8gTW9jayByZXNwb25zZSBkYXRhXHJcbiAqICAgcmV0dXJuIHsgZGF0YTogbW9ja0RhdGEgfTtcclxuICogfSk7XHJcbiAqXHJcbiAqIHNldEdsb2JhbEFwaUNsaWVudChtb2NrQ2xpZW50KTtcclxuICogYGBgXHJcbiAqXHJcbiAqIEBleGFtcGxlXHJcbiAqIEFkdmFuY2VkIGNvbmZpZ3VyYXRpb246XHJcbiAqIGBgYHR5cGVzY3JpcHRcclxuICogY29uc3QgY2xpZW50ID0gbmV3IEFwaUNsaWVudCgnaHR0cHM6Ly9hcGkuZXhhbXBsZS5jb20nLCA2MDAwMCk7XHJcbiAqIGNsaWVudC5zZXRDb3JyZWxhdGlvbklkUHJlZml4KCdjdXN0b20nKTtcclxuICogY2xpZW50LmFkZFJlcXVlc3RJbnRlcmNlcHRvcihjdXN0b21JbnRlcmNlcHRvcik7XHJcbiAqXHJcbiAqIHNldEdsb2JhbEFwaUNsaWVudChjbGllbnQpO1xyXG4gKiBgYGBcclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBzZXRHbG9iYWxBcGlDbGllbnQoY2xpZW50OiBBcGlDbGllbnQpOiB2b2lkIHtcclxuICBnbG9iYWxBcGlDbGllbnQgPSBjbGllbnQ7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBSZXNldHMgdGhlIGdsb2JhbCBBcGlDbGllbnQgc2luZ2xldG9uIHRvIG51bGwuXHJcbiAqXHJcbiAqIEFmdGVyIGNhbGxpbmcgdGhpcywgdGhlIG5leHQgY2FsbCB0byB7QGxpbmsgZ2V0R2xvYmFsQXBpQ2xpZW50fSB3aWxsIGNyZWF0ZVxyXG4gKiBhIGZyZXNoIGluc3RhbmNlLiBUaGlzIGlzIHBhcnRpY3VsYXJseSB1c2VmdWwgaW46XHJcbiAqIC0gVGVzdCBjbGVhbnVwIHRvIGVuc3VyZSB0ZXN0IGlzb2xhdGlvblxyXG4gKiAtIEFwcGxpY2F0aW9uIGxvZ291dCB0byBjbGVhciBhbnkgY2FjaGVkIHN0YXRlXHJcbiAqIC0gSG90IG1vZHVsZSByZWxvYWRpbmcgZHVyaW5nIGRldmVsb3BtZW50XHJcbiAqXHJcbiAqIEBwdWJsaWNcclxuICpcclxuICogQGV4YW1wbGVcclxuICogVGVzdCBjbGVhbnVwOlxyXG4gKiBgYGB0eXBlc2NyaXB0XHJcbiAqIGFmdGVyRWFjaCgoKSA9PiB7XHJcbiAqICAgcmVzZXRHbG9iYWxBcGlDbGllbnQoKTtcclxuICogfSk7XHJcbiAqIGBgYFxyXG4gKlxyXG4gKiBAZXhhbXBsZVxyXG4gKiBMb2dvdXQgZmxvdzpcclxuICogYGBgdHlwZXNjcmlwdFxyXG4gKiBmdW5jdGlvbiBoYW5kbGVMb2dvdXQoKSB7XHJcbiAqICAgLy8gQ2xlYXIgYXV0aGVudGljYXRpb25cclxuICogICBsb2NhbFN0b3JhZ2UucmVtb3ZlSXRlbSgnc2VydmljZVRva2VuJyk7XHJcbiAqXHJcbiAqICAgLy8gQ2FuY2VsIGFsbCBwZW5kaW5nIHJlcXVlc3RzIGFuZCByZXNldCBjbGllbnRcclxuICogICBjb25zdCBjbGllbnQgPSBnZXRHbG9iYWxBcGlDbGllbnQoKTtcclxuICogICBjbGllbnQuY2FuY2VsQWxsUmVxdWVzdHMoKTtcclxuICogICByZXNldEdsb2JhbEFwaUNsaWVudCgpO1xyXG4gKlxyXG4gKiAgIC8vIFJlZGlyZWN0IHRvIGxvZ2luXHJcbiAqICAgbmF2aWdhdGUoJy9sb2dpbicpO1xyXG4gKiB9XHJcbiAqIGBgYFxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIHJlc2V0R2xvYmFsQXBpQ2xpZW50KCk6IHZvaWQge1xyXG4gIGdsb2JhbEFwaUNsaWVudCA9IG51bGw7XHJcbn1cclxuIiwgIi8vIENhbmNlbFRva2VuIGltcGxlbWVudGF0aW9uXHJcbmV4cG9ydCBjbGFzcyBDYW5jZWxUb2tlbiB7XHJcbiAgcHJpdmF0ZSBhYm9ydENvbnRyb2xsZXI6IEFib3J0Q29udHJvbGxlcjtcclxuICBwcml2YXRlIGNhbmNlbFByb21pc2U6IFByb21pc2U8dm9pZD47XHJcbiAgcHJpdmF0ZSBjYW5jZWxSZXNvbHZlPzogKCkgPT4gdm9pZDtcclxuXHJcbiAgY29uc3RydWN0b3IoKSB7XHJcbiAgICB0aGlzLmFib3J0Q29udHJvbGxlciA9IG5ldyBBYm9ydENvbnRyb2xsZXIoKTtcclxuICAgIHRoaXMuY2FuY2VsUHJvbWlzZSA9IG5ldyBQcm9taXNlKHJlc29sdmUgPT4ge1xyXG4gICAgICB0aGlzLmNhbmNlbFJlc29sdmUgPSByZXNvbHZlO1xyXG4gICAgfSk7XHJcbiAgfVxyXG5cclxuICBnZXQgc2lnbmFsKCk6IEFib3J0U2lnbmFsIHtcclxuICAgIHJldHVybiB0aGlzLmFib3J0Q29udHJvbGxlci5zaWduYWw7XHJcbiAgfVxyXG5cclxuICBjYW5jZWwocmVhc29uPzogc3RyaW5nKTogdm9pZCB7XHJcbiAgICB0aGlzLmFib3J0Q29udHJvbGxlci5hYm9ydChyZWFzb24pO1xyXG4gICAgdGhpcy5jYW5jZWxSZXNvbHZlPy4oKTtcclxuICB9XHJcblxyXG4gIGdldCBpc0NhbmNlbGxlZCgpOiBib29sZWFuIHtcclxuICAgIHJldHVybiB0aGlzLmFib3J0Q29udHJvbGxlci5zaWduYWwuYWJvcnRlZDtcclxuICB9XHJcblxyXG4gIHRocm93SWZDYW5jZWxsZWQoKTogdm9pZCB7XHJcbiAgICBpZiAodGhpcy5pc0NhbmNlbGxlZCkge1xyXG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ1JlcXVlc3QgY2FuY2VsbGVkJyk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBzdGF0aWMgc291cmNlKCk6IHsgdG9rZW46IENhbmNlbFRva2VuOyBjYW5jZWw6IChyZWFzb24/OiBzdHJpbmcpID0+IHZvaWQgfSB7XHJcbiAgICBjb25zdCB0b2tlbiA9IG5ldyBDYW5jZWxUb2tlbigpO1xyXG5cclxuICAgIHJldHVybiB7XHJcbiAgICAgIHRva2VuLFxyXG4gICAgICBjYW5jZWw6IChyZWFzb24/OiBzdHJpbmcpID0+IHRva2VuLmNhbmNlbChyZWFzb24pLFxyXG4gICAgfTtcclxuICB9XHJcbn1cclxuIiwgIi8vIFJlYWN0IEhvb2tzIHdpdGggQXBpUmVzcG9uc2UgZm9ybWF0XHJcbmltcG9ydCB7IHVzZUNhbGxiYWNrIH0gZnJvbSAncmVhY3QnO1xyXG5cclxuaW1wb3J0IHR5cGUgeyBBcGlFcnJvciB9IGZyb20gJy4vdHlwZXMnO1xyXG5cclxuLy8gRXhwb3J0IGZhY3RvcnkgbWV0aG9kcyBhbmQgdHlwZXNcclxuZXhwb3J0IHtcclxuICBjcmVhdGVBcGlDbGllbnQsXHJcbiAgZ2V0R2xvYmFsQXBpQ2xpZW50LFxyXG4gIHNldEdsb2JhbEFwaUNsaWVudCxcclxuICByZXNldEdsb2JhbEFwaUNsaWVudCxcclxufSBmcm9tICcuL2NyZWF0ZUFwaUNsaWVudCc7XHJcblxyXG5leHBvcnQgdHlwZSB7IEFwaUNsaWVudENvbmZpZyB9IGZyb20gJy4vY3JlYXRlQXBpQ2xpZW50JztcclxuXHJcbmV4cG9ydCB7IEFwaUNsaWVudCB9IGZyb20gJy4vQXBpQ2xpZW50JztcclxuXHJcbi8vIEhlbHBlciBob29rIGZvciBmb3JtIHZhbGlkYXRpb24gZXJyb3JzXHJcbmV4cG9ydCBmdW5jdGlvbiB1c2VWYWxpZGF0aW9uRXJyb3JzKGVycm9yOiBBcGlFcnJvciB8IG51bGwpIHtcclxuICBjb25zdCBnZXRGaWVsZEVycm9yID0gdXNlQ2FsbGJhY2soXHJcbiAgICAoZmllbGQ6IHN0cmluZyk6IHN0cmluZyB8IG51bGwgPT4ge1xyXG4gICAgICBpZiAoIWVycm9yPy5lcnJvcnMgfHwgIWVycm9yLmVycm9yc1tmaWVsZF0pIHJldHVybiBudWxsO1xyXG5cclxuICAgICAgY29uc3QgZmllbGRFcnJvciA9IGVycm9yLmVycm9yc1tmaWVsZF07XHJcblxyXG4gICAgICBpZiAodHlwZW9mIGZpZWxkRXJyb3IgPT09ICdzdHJpbmcnKSByZXR1cm4gZmllbGRFcnJvcjtcclxuICAgICAgaWYgKEFycmF5LmlzQXJyYXkoZmllbGRFcnJvcikpIHJldHVybiBmaWVsZEVycm9yWzBdO1xyXG4gICAgICBpZiAodHlwZW9mIGZpZWxkRXJyb3IgPT09ICdvYmplY3QnICYmICdtZXNzYWdlJyBpbiBmaWVsZEVycm9yKSB7XHJcbiAgICAgICAgcmV0dXJuIGZpZWxkRXJyb3IubWVzc2FnZTtcclxuICAgICAgfVxyXG5cclxuICAgICAgcmV0dXJuIG51bGw7XHJcbiAgICB9LFxyXG4gICAgW2Vycm9yXVxyXG4gICk7XHJcblxyXG4gIGNvbnN0IGhhc0ZpZWxkRXJyb3IgPSB1c2VDYWxsYmFjayhcclxuICAgIChmaWVsZDogc3RyaW5nKTogYm9vbGVhbiA9PiB7XHJcbiAgICAgIHJldHVybiAhIWdldEZpZWxkRXJyb3IoZmllbGQpO1xyXG4gICAgfSxcclxuICAgIFtnZXRGaWVsZEVycm9yXVxyXG4gICk7XHJcblxyXG4gIGNvbnN0IGdldEFsbEVycm9ycyA9IHVzZUNhbGxiYWNrKCgpOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+ID0+IHtcclxuICAgIGlmICghZXJyb3I/LmVycm9ycykgcmV0dXJuIHt9O1xyXG5cclxuICAgIGNvbnN0IHJlc3VsdDogUmVjb3JkPHN0cmluZywgc3RyaW5nPiA9IHt9O1xyXG5cclxuICAgIE9iamVjdC5lbnRyaWVzKGVycm9yLmVycm9ycykuZm9yRWFjaCgoW2tleSwgdmFsdWVdKSA9PiB7XHJcbiAgICAgIGlmICh0eXBlb2YgdmFsdWUgPT09ICdzdHJpbmcnKSB7XHJcbiAgICAgICAgcmVzdWx0W2tleV0gPSB2YWx1ZTtcclxuICAgICAgfSBlbHNlIGlmIChBcnJheS5pc0FycmF5KHZhbHVlKSkge1xyXG4gICAgICAgIHJlc3VsdFtrZXldID0gdmFsdWUuam9pbignLCAnKTtcclxuICAgICAgfSBlbHNlIGlmICh0eXBlb2YgdmFsdWUgPT09ICdvYmplY3QnICYmIHZhbHVlICYmICdtZXNzYWdlJyBpbiB2YWx1ZSkge1xyXG4gICAgICAgIHJlc3VsdFtrZXldID0gdmFsdWUubWVzc2FnZTtcclxuICAgICAgfVxyXG4gICAgfSk7XHJcblxyXG4gICAgcmV0dXJuIHJlc3VsdDtcclxuICB9LCBbZXJyb3JdKTtcclxuXHJcbiAgcmV0dXJuIHtcclxuICAgIGdldEZpZWxkRXJyb3IsXHJcbiAgICBoYXNGaWVsZEVycm9yLFxyXG4gICAgZ2V0QWxsRXJyb3JzLFxyXG4gICAgaGFzRXJyb3JzOiBlcnJvcj8uZXJyb3JzLFxyXG4gIH07XHJcbn1cclxuIiwgImltcG9ydCB0eXBlIHsgUHJvcHNXaXRoQ2hpbGRyZW4gfSBmcm9tICdyZWFjdCc7XG5cbnR5cGUgQXV0aG9yaXplZFZpZXdQcm9wcyA9IFByb3BzV2l0aENoaWxkcmVuICYge1xuICBzaG93OiBib29sZWFuO1xufTtcblxuZXhwb3J0IGNvbnN0IEF1dGhvcml6ZWRWaWV3ID0gKHsgY2hpbGRyZW4sIHNob3cgfTogQXV0aG9yaXplZFZpZXdQcm9wcykgPT4ge1xuICBpZiAoIXNob3cpIHJldHVybiA8PjwvPjtcblxuICByZXR1cm4gPD57Y2hpbGRyZW59PC8+O1xufTtcbiIsICJpbXBvcnQgdHlwZSB7IEJ1dHRvblByb3BzIH0gZnJvbSAnQG11aS9tYXRlcmlhbCc7XG5pbXBvcnQgeyBCdXR0b24gfSBmcm9tICdAbXVpL21hdGVyaWFsJztcbmltcG9ydCBSZWFjdCBmcm9tICdyZWFjdCc7XG5cbmV4cG9ydCBjb25zdCBDYW5jZWxCdXR0b246IFJlYWN0LkZDPEJ1dHRvblByb3BzPiA9ICh7XG4gIGNoaWxkcmVuID0gJ0NhbmNlbCcsXG4gIHZhcmlhbnQgPSAnb3V0bGluZWQnLFxuICBzeCxcbiAgLi4ucmVzdFxufSkgPT4gKFxuICA8QnV0dG9uIHZhcmlhbnQ9e3ZhcmlhbnR9IHN4PXt7IHdpZHRoOiAnNnJlbScsIC4uLnN4IH19IHsuLi5yZXN0fT5cbiAgICB7Y2hpbGRyZW59XG4gIDwvQnV0dG9uPlxuKTtcbiIsICJpbXBvcnQgdHlwZSB7IFN4UHJvcHMgfSBmcm9tICdAbXVpL21hdGVyaWFsJztcbmltcG9ydCB7IEJ1dHRvbiB9IGZyb20gJ0BtdWkvbWF0ZXJpYWwnO1xuXG4vKipcbiAqIFByb3BzIGZvciB0aGUgQ2xlYXJCdXR0b24gY29tcG9uZW50LlxuICpcbiAqIEBwdWJsaWNcbiAqL1xuaW50ZXJmYWNlIENsZWFyQnV0dG9uUHJvcHMge1xuICAvKipcbiAgICogSW5kaWNhdGVzIGlmIGEgZm9ybSBvciBvcGVyYXRpb24gaXMgY3VycmVudGx5IGJlaW5nIHN1Ym1pdHRlZC5cbiAgICogV2hlbiB0cnVlLCB0aGUgYnV0dG9uIGlzIGRpc2FibGVkIHRvIHByZXZlbnQgbXVsdGlwbGUgY2xlYXIgYWN0aW9ucy5cbiAgICovXG4gIGlzU3VibWl0dGluZzogYm9vbGVhbjtcbiAgLyoqXG4gICAqIENhbGxiYWNrIGZ1bmN0aW9uIGV4ZWN1dGVkIHdoZW4gdGhlIGNsZWFyIGJ1dHRvbiBpcyBjbGlja2VkLlxuICAgKiBTaG91bGQgaGFuZGxlIHRoZSBjbGVhcmluZyBsb2dpYyAoZS5nLiwgZm9ybSByZXNldCwgZGF0YSBjbGVhcmluZykuXG4gICAqL1xuICBoYW5kbGVDbGVhcjogKCkgPT4gdm9pZDtcbiAgLyoqXG4gICAqIE9wdGlvbmFsIE1VSSBzeCBwcm9wIGZvciBjdXN0b20gc3R5bGluZy5cbiAgICogQGV4YW1wbGUgeyBtdDogMiwgY29sb3I6ICd3YXJuaW5nLm1haW4nIH1cbiAgICovXG4gIHN4PzogU3hQcm9wcztcbiAgLyoqXG4gICAqIE9wdGlvbmFsIGxvY2FsU3RvcmFnZSBrZXkgdG8gcmVtb3ZlIHdoZW4gY2xlYXJpbmcuXG4gICAqIElmIHByb3ZpZGVkLCB0aGUgY29ycmVzcG9uZGluZyBsb2NhbFN0b3JhZ2UgaXRlbSB3aWxsIGJlIHJlbW92ZWQgb24gY2xpY2suXG4gICAqIEBleGFtcGxlIFwidXNlci1wcmVmZXJlbmNlc1wiIG9yIFwiZm9ybS1kYXRhXCJcbiAgICovXG4gIHN0b3JlS2V5Pzogc3RyaW5nO1xufVxuXG4vKipcbiAqIFN0YW5kYXJkaXplZCBjbGVhciBidXR0b24gY29tcG9uZW50IHdpdGggbG9jYWxTdG9yYWdlIGludGVncmF0aW9uLlxuICpcbiAqIFRoaXMgY29tcG9uZW50IHByb3ZpZGVzIGEgY29uc2lzdGVudCBjbGVhciBidXR0b24gaW1wbGVtZW50YXRpb24gdGhhdCBoYW5kbGVzXG4gKiBib3RoIGNhbGxiYWNrIGV4ZWN1dGlvbiBhbmQgb3B0aW9uYWwgbG9jYWxTdG9yYWdlIGNsZWFudXAuIEl0IGF1dG9tYXRpY2FsbHlcbiAqIGRpc2FibGVzIGR1cmluZyBmb3JtIHN1Ym1pc3Npb25zIGFuZCBjYW4gY2xlYXIgc3RvcmVkIGRhdGEgd2hlbiBuZWVkZWQuXG4gKlxuICogQGV4YW1wbGVcbiAqIEJhc2ljIHVzYWdlOlxuICogYGBgdHN4XG4gKiA8Q2xlYXJCdXR0b25cbiAqICAgaXNTdWJtaXR0aW5nPXtpc0xvYWRpbmd9XG4gKiAgIGhhbmRsZUNsZWFyPXsoKSA9PiBmb3JtLnJlc2V0KCl9XG4gKiAvPlxuICogYGBgXG4gKlxuICogQGV4YW1wbGVcbiAqIFdpdGggbG9jYWxTdG9yYWdlIGNsZWFudXA6XG4gKiBgYGB0c3hcbiAqIDxDbGVhckJ1dHRvblxuICogICBpc1N1Ym1pdHRpbmc9e2Zvcm0uZm9ybVN0YXRlLmlzU3VibWl0dGluZ31cbiAqICAgaGFuZGxlQ2xlYXI9eygpID0+IHNldEZpbHRlcnMoe30pfVxuICogICBzdG9yZUtleT1cInVzZXItZmlsdGVyc1wiXG4gKiAvPlxuICogYGBgXG4gKlxuICogQHBhcmFtIHByb3BzIC0gQ29tcG9uZW50IHByb3BzIGZvciBjbGVhciBidXR0b24gY29uZmlndXJhdGlvblxuICogQHJldHVybnMgTVVJIEJ1dHRvbiBjb21wb25lbnQgY29uZmlndXJlZCBhcyBhIGNsZWFyIGJ1dHRvblxuICpcbiAqIEBwdWJsaWNcbiAqL1xuZXhwb3J0IGNvbnN0IENsZWFyQnV0dG9uID0gKHtcbiAgaXNTdWJtaXR0aW5nLFxuICBoYW5kbGVDbGVhcixcbiAgc3gsXG4gIHN0b3JlS2V5LFxufTogQ2xlYXJCdXR0b25Qcm9wcykgPT4ge1xuICBjb25zdCBvbkNsaWNrID0gKCkgPT4ge1xuICAgIGhhbmRsZUNsZWFyKCk7XG4gICAgaWYgKHN0b3JlS2V5ICE9IG51bGwpIHtcbiAgICAgIGxvY2FsU3RvcmFnZS5yZW1vdmVJdGVtKHN0b3JlS2V5KTtcbiAgICB9XG4gIH07XG5cbiAgcmV0dXJuIChcbiAgICA8QnV0dG9uXG4gICAgICB2YXJpYW50PVwib3V0bGluZWRcIlxuICAgICAgb25DbGljaz17b25DbGlja31cbiAgICAgIGRpc2FibGVkPXtpc1N1Ym1pdHRpbmd9XG4gICAgICBzeD17c3h9XG4gICAgPlxuICAgICAgQ2xlYXJcbiAgICA8L0J1dHRvbj5cbiAgKTtcbn07XG4iLCAiaW1wb3J0IHsgQ29udGFpbmVyLCB0eXBlIFN4UHJvcHMgfSBmcm9tICdAbXVpL21hdGVyaWFsJztcclxuaW1wb3J0IHR5cGUgeyBSZWFjdE5vZGUgfSBmcm9tICdyZWFjdCc7XHJcblxyXG5pbnRlcmZhY2UgU2ltcGxlQ29udGFpbmVyUHJvcHMge1xyXG4gIGNoaWxkcmVuOiBSZWFjdE5vZGU7XHJcbiAgY2xhc3NOYW1lPzogc3RyaW5nO1xyXG4gIHN4PzogU3hQcm9wcztcclxufVxyXG5cclxuZXhwb3J0IGNvbnN0IFNpbXBsZUNvbnRhaW5lciA9ICh7XHJcbiAgY2hpbGRyZW4sXHJcbiAgY2xhc3NOYW1lLFxyXG4gIHN4LFxyXG59OiBTaW1wbGVDb250YWluZXJQcm9wcykgPT4gKFxyXG4gIDxDb250YWluZXIgY2xhc3NOYW1lPXtjbGFzc05hbWV9IHN4PXt7IC4uLnN4IH19PlxyXG4gICAge2NoaWxkcmVufVxyXG4gIDwvQ29udGFpbmVyPlxyXG4pO1xyXG4iLCAiaW1wb3J0IEZpbHRlckFsdEljb24gZnJvbSAnQG11aS9pY29ucy1tYXRlcmlhbC9GaWx0ZXJBbHQnO1xuaW1wb3J0IHsgTG9hZGluZ0J1dHRvbiB9IGZyb20gJ0BtdWkvbGFiJztcbmltcG9ydCB0eXBlIHsgU3hQcm9wcyB9IGZyb20gJ0BtdWkvbWF0ZXJpYWwnO1xuaW1wb3J0IHsgQmFkZ2UgfSBmcm9tICdAbXVpL21hdGVyaWFsJztcblxuLyoqXG4gKiBQcm9wcyBmb3IgdGhlIEZpbHRlckJ1dHRvbiBjb21wb25lbnQuXG4gKlxuICogQHB1YmxpY1xuICovXG5pbnRlcmZhY2UgRmlsdGVyQnV0dG9uUHJvcHMge1xuICAvKipcbiAgICogSW5kaWNhdGVzIGlmIGEgZmlsdGVyIG9wZXJhdGlvbiBpcyBjdXJyZW50bHkgYmVpbmcgcHJvY2Vzc2VkLlxuICAgKiBXaGVuIHRydWUsIHNob3dzIGxvYWRpbmcgc3Bpbm5lciBhbmQgZGlzYWJsZXMgdGhlIGJ1dHRvbi5cbiAgICovXG4gIGlzU3VibWl0dGluZzogYm9vbGVhbjtcbiAgLyoqXG4gICAqIENvbnRyb2xzIGJ1dHRvbiB2aXNpYmlsaXR5IGFuZCBlbmFibGVkIHN0YXRlLlxuICAgKiBXaGVuIGZhbHNlLCB0aGUgYnV0dG9uIGlzIGRpc2FibGVkLlxuICAgKiBAZGVmYXVsdFZhbHVlIHRydWVcbiAgICovXG4gIHNob3c/OiBib29sZWFuO1xuICAvKipcbiAgICogQ3VzdG9tIHRleHQgdG8gZGlzcGxheSBvbiB0aGUgYnV0dG9uLlxuICAgKiBAZGVmYXVsdFZhbHVlIFwiRmlsdGVyXCJcbiAgICogQGV4YW1wbGUgXCJBcHBseSBGaWx0ZXJzXCIgb3IgXCJTZWFyY2hcIlxuICAgKi9cbiAgdGl0bGU/OiBzdHJpbmc7XG4gIC8qKlxuICAgKiBDdXN0b20gaWNvbiB0byBkaXNwbGF5IGluc3RlYWQgb2YgdGhlIGRlZmF1bHQgZmlsdGVyIGljb24uXG4gICAqIEBleGFtcGxlIDxTZWFyY2hJY29uIC8+XG4gICAqL1xuICBpY29uPzogUmVhY3QuUmVhY3ROb2RlO1xuICAvKipcbiAgICogT3B0aW9uYWwgTVVJIHN4IHByb3AgZm9yIGN1c3RvbSBidXR0b24gc3R5bGluZy5cbiAgICogQGV4YW1wbGUgeyBtdDogMiwgbWluV2lkdGg6IDEyMCB9XG4gICAqL1xuICBzeD86IFN4UHJvcHM7XG4gIC8qKlxuICAgKiBPcHRpb25hbCBNVUkgc3ggcHJvcCBmb3IgY3VzdG9tIGljb24gc3R5bGluZy5cbiAgICogQGV4YW1wbGUgeyBjb2xvcjogJ3ByaW1hcnkubWFpbicsIGZvbnRTaXplOiAxOCB9XG4gICAqL1xuICBpY29uU3g/OiBTeFByb3BzO1xufVxuXG4vKipcbiAqIEZpbHRlciBidXR0b24gY29tcG9uZW50IHdpdGggbG9hZGluZyBzdGF0ZXMgYW5kIGN1c3RvbWl6YWJsZSBhcHBlYXJhbmNlLlxuICpcbiAqIFRoaXMgY29tcG9uZW50IHByb3ZpZGVzIGEgc3RhbmRhcmRpemVkIGZpbHRlci9zdWJtaXQgYnV0dG9uIHdpdGggaW50ZWdyYXRlZCBsb2FkaW5nXG4gKiBzdGF0ZXMsIGljb24gc3VwcG9ydCwgYW5kIGJhZGdlIHN0eWxpbmcuIEl0J3MgZGVzaWduZWQgZm9yIHVzZSBpbiBmaWx0ZXIgZm9ybXNcbiAqIGFuZCBzZWFyY2ggaW50ZXJmYWNlcyB3aGVyZSB1c2VycyBuZWVkIHRvIGFwcGx5IGZpbHRlcmluZyBjcml0ZXJpYS5cbiAqXG4gKiBAZXhhbXBsZVxuICogQmFzaWMgdXNhZ2U6XG4gKiBgYGB0c3hcbiAqIDxGaWx0ZXJCdXR0b25cbiAqICAgaXNTdWJtaXR0aW5nPXtpc0xvYWRpbmd9XG4gKiAgIHNob3c9e2hhc0ZpbHRlcnN9XG4gKiAvPlxuICogYGBgXG4gKlxuICogQGV4YW1wbGVcbiAqIEN1c3RvbSB0aXRsZSBhbmQgaWNvbjpcbiAqIGBgYHRzeFxuICogPEZpbHRlckJ1dHRvblxuICogICBpc1N1Ym1pdHRpbmc9e2Zvcm0uZm9ybVN0YXRlLmlzU3VibWl0dGluZ31cbiAqICAgdGl0bGU9XCJBcHBseSBTZWFyY2hcIlxuICogICBpY29uPXs8U2VhcmNoSWNvbiAvPn1cbiAqICAgc2hvdz17dHJ1ZX1cbiAqIC8+XG4gKiBgYGBcbiAqXG4gKiBAZXhhbXBsZVxuICogV2l0aCBjdXN0b20gc3R5bGluZzpcbiAqIGBgYHRzeFxuICogPEZpbHRlckJ1dHRvblxuICogICBpc1N1Ym1pdHRpbmc9e2lzUHJvY2Vzc2luZ31cbiAqICAgdGl0bGU9XCJGaWx0ZXIgUmVzdWx0c1wiXG4gKiAgIHN4PXt7IG1pbldpZHRoOiAxNTAsIG10OiAyIH19XG4gKiAgIGljb25TeD17eyBmb250U2l6ZTogMjAgfX1cbiAqIC8+XG4gKiBgYGBcbiAqXG4gKiBAcGFyYW0gcHJvcHMgLSBDb21wb25lbnQgcHJvcHMgZm9yIGZpbHRlciBidXR0b24gY29uZmlndXJhdGlvblxuICogQHJldHVybnMgTVVJIExvYWRpbmdCdXR0b24gY29tcG9uZW50IGNvbmZpZ3VyZWQgYXMgYSBmaWx0ZXIgYnV0dG9uXG4gKlxuICogQHB1YmxpY1xuICovXG5leHBvcnQgY29uc3QgRmlsdGVyQnV0dG9uID0gKHtcbiAgaXNTdWJtaXR0aW5nLFxuICBzaG93LFxuICB0aXRsZSxcbiAgaWNvbixcbiAgc3gsXG4gIGljb25TeCxcbn06IEZpbHRlckJ1dHRvblByb3BzKSA9PiB7XG4gIHJldHVybiAoXG4gICAgPExvYWRpbmdCdXR0b25cbiAgICAgIHR5cGU9XCJzdWJtaXRcIlxuICAgICAgdmFyaWFudD1cImNvbnRhaW5lZFwiXG4gICAgICBsb2FkaW5nPXtpc1N1Ym1pdHRpbmd9XG4gICAgICBkaXNhYmxlZD17IXNob3d9XG4gICAgICBkaXNhYmxlUmlwcGxlXG4gICAgICBjb2xvcj1cInByaW1hcnlcIlxuICAgICAgc3g9e3tcbiAgICAgICAgZGlzcGxheTogJ2ZsZXgnLFxuICAgICAgICBhbGlnbkl0ZW1zOiAnY2VudGVyJyxcbiAgICAgICAgLi4uc3gsXG4gICAgICB9fVxuICAgICAgc3RhcnRJY29uPXtcbiAgICAgICAgPEJhZGdlIGNvbG9yPVwiZXJyb3JcIiB2YXJpYW50PVwic3RhbmRhcmRcIj5cbiAgICAgICAgICB7aWNvbiA/IGljb24gOiA8RmlsdGVyQWx0SWNvbiB3aWR0aD1cIjIwXCIgaGVpZ2h0PVwiMjBcIiBzeD17aWNvblN4fSAvPn1cbiAgICAgICAgPC9CYWRnZT5cbiAgICAgIH1cbiAgICA+XG4gICAgICB7dGl0bGU/LnRyaW0oKSA9PT0gJycgfHwgIXRpdGxlID8gJ0ZpbHRlcicgOiB0aXRsZX1cbiAgICA8L0xvYWRpbmdCdXR0b24+XG4gICk7XG59O1xuIiwgImltcG9ydCBDaGlwIGZyb20gJ0BtdWkvbWF0ZXJpYWwvQ2hpcCc7XHJcbmltcG9ydCB7IG1lbW8gfSBmcm9tICdyZWFjdCc7XHJcblxyXG4vLyBJbmRpdmlkdWFsIGNoaXAgY29tcG9uZW50IHRvIHByZXZlbnQgdW5uZWNlc3NhcnkgcmVyZW5kZXJzIG9mIHNpYmxpbmcgY2hpcHNcclxuZXhwb3J0IGNvbnN0IEZpbHRlckNoaXAgPSBtZW1vKFxyXG4gICh7XHJcbiAgICBmaWVsZEtleSxcclxuICAgIGZpbHRlcixcclxuICAgIG9uRGVsZXRlLFxyXG4gIH06IHtcclxuICAgIGZpZWxkS2V5OiBzdHJpbmc7XHJcbiAgICBmaWx0ZXI6IHsgTGFiZWw6IHN0cmluZzsgVmFsdWU6IHVua25vd24gfTtcclxuICAgIG9uRGVsZXRlPzogKCkgPT4gdm9pZDtcclxuICB9KSA9PiB7XHJcbiAgICBjb25zdCBoYXNWYWx1ZSA9XHJcbiAgICAgIGZpbHRlci5WYWx1ZSAhPT0gbnVsbCAmJlxyXG4gICAgICBmaWx0ZXIuVmFsdWUgIT09IHVuZGVmaW5lZCAmJlxyXG4gICAgICBmaWx0ZXIuVmFsdWUgIT09ICcnO1xyXG4gICAgY29uc3QgbGFiZWwgPSBgJHtmaWVsZEtleS5yZXBsYWNlKCdQSycsICcnKX06ICR7ZmlsdGVyLkxhYmVsfWA7XHJcblxyXG4gICAgcmV0dXJuIChcclxuICAgICAgPENoaXBcclxuICAgICAgICBrZXk9e2ZpZWxkS2V5fVxyXG4gICAgICAgIGxhYmVsPXtsYWJlbH1cclxuICAgICAgICB2YXJpYW50PXtoYXNWYWx1ZSA/ICdmaWxsZWQnIDogJ291dGxpbmVkJ31cclxuICAgICAgICBzaXplPVwic21hbGxcIlxyXG4gICAgICAgIG9uRGVsZXRlPXtoYXNWYWx1ZSA/IG9uRGVsZXRlIDogdW5kZWZpbmVkfVxyXG4gICAgICAvPlxyXG4gICAgKTtcclxuICB9XHJcbik7XHJcblxyXG5GaWx0ZXJDaGlwLmRpc3BsYXlOYW1lID0gJ0ZpbHRlckNoaXAnO1xyXG4iLCAiaW1wb3J0IHsgQ2FyZCwgQ2FyZENvbnRlbnQsIFR5cG9ncmFwaHksIEJveCB9IGZyb20gJ0BtdWkvbWF0ZXJpYWwnO1xyXG5pbXBvcnQgeyBtZW1vLCB1c2VNZW1vIH0gZnJvbSAncmVhY3QnO1xyXG5cclxuaW1wb3J0IHsgRmlsdGVyQ2hpcCB9IGZyb20gJy4vRmlsdGVyQ2hpcCc7XHJcblxyXG5pbnRlcmZhY2UgRmlsdGVyRGlzcGxheVByb3BzPFRGaWx0ZXJNb2RlbD4ge1xyXG4gIGZyaWVuZGx5RmlsdGVyOiBSZWNvcmQ8c3RyaW5nLCB7IExhYmVsOiBzdHJpbmc7IFZhbHVlOiB1bmtub3duIH0+O1xyXG4gIG9uRnJpZW5kbHlGaWx0ZXJDaGFuZ2U/OiAoZmllbGRLZXk6IGtleW9mIFRGaWx0ZXJNb2RlbCkgPT4gdm9pZDtcclxufVxyXG5cclxuZXhwb3J0IGNvbnN0IFByb2dyYW1zRmlsdGVyRGlzcGxheSA9IG1lbW8oXHJcbiAgPFRGaWx0ZXJNb2RlbCBleHRlbmRzIFJlY29yZDxzdHJpbmcsIHVua25vd24+PihcclxuICAgIHByb3BzOiBGaWx0ZXJEaXNwbGF5UHJvcHM8VEZpbHRlck1vZGVsPlxyXG4gICkgPT4ge1xyXG4gICAgY29uc3QgeyBmcmllbmRseUZpbHRlciwgb25GcmllbmRseUZpbHRlckNoYW5nZSB9ID0gcHJvcHM7XHJcblxyXG4gICAgLy8gTWVtb2l6ZSBkZWxldGUgaGFuZGxlcnMgdG8gcHJldmVudCByZWNyZWF0aW9uXHJcbiAgICBjb25zdCBkZWxldGVIYW5kbGVycyA9IHVzZU1lbW8oKCkgPT4ge1xyXG4gICAgICBpZiAoIW9uRnJpZW5kbHlGaWx0ZXJDaGFuZ2UpIHJldHVybiB7fTtcclxuXHJcbiAgICAgIGNvbnN0IGhhbmRsZXJzOiBSZWNvcmQ8c3RyaW5nLCAoKSA9PiB2b2lkPiA9IHt9O1xyXG5cclxuICAgICAgZm9yIChjb25zdCBrZXkgb2YgT2JqZWN0LmtleXMoZnJpZW5kbHlGaWx0ZXIpKSB7XHJcbiAgICAgICAgaGFuZGxlcnNba2V5XSA9ICgpID0+IG9uRnJpZW5kbHlGaWx0ZXJDaGFuZ2Uoa2V5IGFzIGtleW9mIFRGaWx0ZXJNb2RlbCk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIHJldHVybiBoYW5kbGVycztcclxuICAgIH0sIFtvbkZyaWVuZGx5RmlsdGVyQ2hhbmdlLCBmcmllbmRseUZpbHRlcl0pO1xyXG5cclxuICAgIC8vIE1lbW9pemUgY2hpcCBsaXN0IHRvIHByZXZlbnQgdW5uZWNlc3NhcnkgcmVjYWxjdWxhdGlvbnNcclxuICAgIGNvbnN0IGNoaXBMaXN0ID0gdXNlTWVtbygoKSA9PiB7XHJcbiAgICAgIHJldHVybiBPYmplY3QuZW50cmllcyhmcmllbmRseUZpbHRlcikubWFwKChba2V5LCBmaWx0ZXJdKSA9PiAoXHJcbiAgICAgICAgPEZpbHRlckNoaXBcclxuICAgICAgICAgIGtleT17a2V5fVxyXG4gICAgICAgICAgZmllbGRLZXk9e2tleX1cclxuICAgICAgICAgIGZpbHRlcj17ZmlsdGVyIGFzIHsgTGFiZWw6IHN0cmluZzsgVmFsdWU6IHVua25vd24gfX1cclxuICAgICAgICAgIG9uRGVsZXRlPXtkZWxldGVIYW5kbGVyc1trZXldfVxyXG4gICAgICAgIC8+XHJcbiAgICAgICkpO1xyXG4gICAgfSwgW2ZyaWVuZGx5RmlsdGVyLCBkZWxldGVIYW5kbGVyc10pO1xyXG5cclxuICAgIHJldHVybiAoXHJcbiAgICAgIDxDYXJkIHN4PXt7IG1iOiAyIH19PlxyXG4gICAgICAgIDxDYXJkQ29udGVudD5cclxuICAgICAgICAgIDxUeXBvZ3JhcGh5IHZhcmlhbnQ9XCJoNlwiIGd1dHRlckJvdHRvbT5cclxuICAgICAgICAgICAgQWN0aXZlIEZpbHRlcnNcclxuICAgICAgICAgIDwvVHlwb2dyYXBoeT5cclxuICAgICAgICAgIDxCb3ggZGlzcGxheT1cImZsZXhcIiBnYXA9ezF9IGZsZXhXcmFwPVwid3JhcFwiPlxyXG4gICAgICAgICAgICB7Y2hpcExpc3R9XHJcbiAgICAgICAgICA8L0JveD5cclxuICAgICAgICA8L0NhcmRDb250ZW50PlxyXG4gICAgICA8L0NhcmQ+XHJcbiAgICApO1xyXG4gIH1cclxuKTtcclxuXHJcblByb2dyYW1zRmlsdGVyRGlzcGxheS5kaXNwbGF5TmFtZSA9ICdGaWx0ZXJEaXNwbGF5JztcclxuXHJcbmV4cG9ydCB0eXBlIHsgRmlsdGVyRGlzcGxheVByb3BzIH07XHJcbiIsICJpbXBvcnQgTWFuYWdlU2VhcmNoSWNvbiBmcm9tICdAbXVpL2ljb25zLW1hdGVyaWFsL01hbmFnZVNlYXJjaCc7XG5pbXBvcnQgdHlwZSB7IFN4UHJvcHMgfSBmcm9tICdAbXVpL21hdGVyaWFsJztcbmltcG9ydCB7XG4gIEJveCxcbiAgQ2FyZCxcbiAgQ2FyZENvbnRlbnQsXG4gIENhcmRIZWFkZXIsXG4gIERpdmlkZXIsXG4gIEdyaWQsXG4gIFR5cG9ncmFwaHksXG4gIHVzZVRoZW1lLFxufSBmcm9tICdAbXVpL21hdGVyaWFsJztcbmltcG9ydCB0eXBlIHsgUHJvcHNXaXRoQ2hpbGRyZW4sIFJlYWN0Tm9kZSB9IGZyb20gJ3JlYWN0JztcblxuLyoqXG4gKiBQcm9wcyBmb3IgdGhlIEZpbHRlcldyYXBwZXIgY29tcG9uZW50LlxuICpcbiAqIEBwdWJsaWNcbiAqL1xudHlwZSBGaWx0ZXJXcmFwcGVyUHJvcHMgPSBQcm9wc1dpdGhDaGlsZHJlbjx7XG4gIC8qKlxuICAgKiBUaXRsZSB0ZXh0IGRpc3BsYXllZCBpbiB0aGUgY2FyZCBoZWFkZXIuXG4gICAqIEBkZWZhdWx0VmFsdWUgXCJGaWx0ZXJcIlxuICAgKiBAZXhhbXBsZSBcIlNlYXJjaCBDcml0ZXJpYVwiIG9yIFwiQWR2YW5jZWQgRmlsdGVyc1wiXG4gICAqL1xuICB0aXRsZT86IHN0cmluZztcbiAgLyoqXG4gICAqIE51bWJlciBvZiBhY3RpdmUgZmlsdGVycyB0byBkaXNwbGF5IGluIHRoZSBoZWFkZXIuXG4gICAqIE9ubHkgc2hvd24gd2hlbiBzaG93Q291bnQgaXMgdHJ1ZS5cbiAgICogQGV4YW1wbGUgMyBmb3IgXCJGaWx0ZXIgKDMpXCJcbiAgICovXG4gIGZpbHRlckNvdW50PzogbnVtYmVyO1xuICAvKipcbiAgICogT3B0aW9uYWwgTVVJIHN4IHByb3AgZm9yIGN1c3RvbSBjYXJkIHN0eWxpbmcuXG4gICAqIEBleGFtcGxlIHsgbXQ6IDIsIGJveFNoYWRvdzogMiB9XG4gICAqL1xuICBjYXJkU3g/OiBTeFByb3BzO1xuICAvKipcbiAgICogT3B0aW9uYWwgTVVJIHN4IHByb3AgZm9yIGN1c3RvbSB0aXRsZSB0ZXh0IHN0eWxpbmcuXG4gICAqIEBleGFtcGxlIHsgZm9udFNpemU6IDE4LCBmb250V2VpZ2h0OiAnYm9sZCcgfVxuICAgKi9cbiAgdGV4dFN4PzogU3hQcm9wcztcbiAgLyoqXG4gICAqIEN1c3RvbSBpY29uIHRvIGRpc3BsYXkgaW5zdGVhZCBvZiB0aGUgZGVmYXVsdCBzZWFyY2ggaWNvbi5cbiAgICogQGV4YW1wbGUgPEZpbHRlckxpc3RJY29uIC8+XG4gICAqL1xuICBpY29uPzogUmVhY3ROb2RlO1xuICAvKipcbiAgICogT3B0aW9uYWwgTVVJIHN4IHByb3AgZm9yIGN1c3RvbSBpY29uIHN0eWxpbmcuXG4gICAqIEBleGFtcGxlIHsgY29sb3I6ICdzZWNvbmRhcnkubWFpbicsIGZvbnRTaXplOiAyNCB9XG4gICAqL1xuICBpY29uU3g/OiBTeFByb3BzO1xuICAvKipcbiAgICogV2hldGhlciB0byBkaXNwbGF5IHRoZSBmaWx0ZXIgY291bnQgaW4gdGhlIGhlYWRlci5cbiAgICogQGRlZmF1bHRWYWx1ZSBmYWxzZVxuICAgKi9cbiAgc2hvd0NvdW50PzogYm9vbGVhbjtcbn0+O1xuXG4vKipcbiAqIENhcmQtYmFzZWQgd3JhcHBlciBjb21wb25lbnQgZm9yIG9yZ2FuaXppbmcgZmlsdGVyIGNvbnRyb2xzIGFuZCBmb3JtIGVsZW1lbnRzLlxuICpcbiAqIFRoaXMgY29tcG9uZW50IHByb3ZpZGVzIGEgY29uc2lzdGVudCBsYXlvdXQgZm9yIGZpbHRlciBpbnRlcmZhY2VzIHdpdGggYSBoZWFkZXIsXG4gKiBvcHRpb25hbCBmaWx0ZXIgY291bnQgZGlzcGxheSwgYW5kIGEgZ3JpZC1iYXNlZCBjb250ZW50IGFyZWEuIEl0J3MgZGVzaWduZWQgdG9cbiAqIGNvbnRhaW4gZm9ybSBjb250cm9scyBhbmQgZmlsdGVyIGVsZW1lbnRzIGluIGEgdmlzdWFsbHkgb3JnYW5pemVkIG1hbm5lci5cbiAqXG4gKiBAZXhhbXBsZVxuICogQmFzaWMgdXNhZ2U6XG4gKiBgYGB0c3hcbiAqIDxGaWx0ZXJXcmFwcGVyPlxuICogICA8R3JpZCBpdGVtIHhzPXsxMn0gbWQ9ezZ9PlxuICogICAgIDxUZXh0RmllbGQgbGFiZWw9XCJTZWFyY2hcIiAvPlxuICogICA8L0dyaWQ+XG4gKiAgIDxHcmlkIGl0ZW0geHM9ezEyfSBtZD17Nn0+XG4gKiAgICAgPFNlbGVjdCBsYWJlbD1cIkNhdGVnb3J5XCIgLz5cbiAqICAgPC9HcmlkPlxuICogPC9GaWx0ZXJXcmFwcGVyPlxuICogYGBgXG4gKlxuICogQGV4YW1wbGVcbiAqIFdpdGggY3VzdG9tIHRpdGxlIGFuZCBjb3VudDpcbiAqIGBgYHRzeFxuICogPEZpbHRlcldyYXBwZXJcbiAqICAgdGl0bGU9XCJBZHZhbmNlZCBTZWFyY2hcIlxuICogICBmaWx0ZXJDb3VudD17YWN0aXZlRmlsdGVycy5sZW5ndGh9XG4gKiAgIHNob3dDb3VudD17dHJ1ZX1cbiAqID5cbiAqICAge2ZpbHRlckNvbnRyb2xzfVxuICogPC9GaWx0ZXJXcmFwcGVyPlxuICogYGBgXG4gKlxuICogQGV4YW1wbGVcbiAqIFdpdGggY3VzdG9tIHN0eWxpbmc6XG4gKiBgYGB0c3hcbiAqIDxGaWx0ZXJXcmFwcGVyXG4gKiAgIHRpdGxlPVwiUHJvZHVjdCBGaWx0ZXJzXCJcbiAqICAgaWNvbj17PEZpbHRlckxpc3RJY29uIC8+fVxuICogICBjYXJkU3g9e3sgbXQ6IDMsIGJvcmRlclJhZGl1czogMiB9fVxuICogICB0ZXh0U3g9e3sgY29sb3I6ICdzZWNvbmRhcnkubWFpbicgfX1cbiAqID5cbiAqICAge2NoaWxkcmVufVxuICogPC9GaWx0ZXJXcmFwcGVyPlxuICogYGBgXG4gKlxuICogQHBhcmFtIHByb3BzIC0gQ29tcG9uZW50IHByb3BzIGluY2x1ZGluZyBjaGlsZHJlbiBhbmQgc3R5bGluZyBvcHRpb25zXG4gKiBAcmV0dXJucyBNVUkgQ2FyZCBjb21wb25lbnQgd2l0aCBzdHJ1Y3R1cmVkIGZpbHRlciBsYXlvdXRcbiAqXG4gKiBAcHVibGljXG4gKi9cbmV4cG9ydCBjb25zdCBGaWx0ZXJXcmFwcGVyID0gKHtcbiAgY2hpbGRyZW4sXG4gIHRpdGxlLFxuICBmaWx0ZXJDb3VudCxcbiAgY2FyZFN4LFxuICB0ZXh0U3gsXG4gIGljb24sXG4gIGljb25TeCxcbiAgc2hvd0NvdW50LFxufTogRmlsdGVyV3JhcHBlclByb3BzKSA9PiB7XG4gIGNvbnN0IHRoZW1lID0gdXNlVGhlbWUoKTtcblxuICByZXR1cm4gKFxuICAgIDxDYXJkXG4gICAgICBzeD17e1xuICAgICAgICBwb3NpdGlvbjogJ3JlbGF0aXZlJyxcbiAgICAgICAgYm9yZGVyUmFkaXVzOiAnMHB4JyxcbiAgICAgICAgbWI6IDIsXG4gICAgICAgIC4uLmNhcmRTeCxcbiAgICAgIH19XG4gICAgPlxuICAgICAgPENhcmRIZWFkZXJcbiAgICAgICAgc3g9e3tcbiAgICAgICAgICBkaXNwbGF5OiAnZmxleCcsXG4gICAgICAgICAgZmxleFdyYXA6ICd3cmFwJyxcbiAgICAgICAgICBwOiAnMXJlbScsXG4gICAgICAgICAgJy5NdWlDYXJkSGVhZGVyLWFjdGlvbic6IHtcbiAgICAgICAgICAgIG1hcmdpbjogMCxcbiAgICAgICAgICAgIGFsaWduU2VsZjogJ2NlbnRlcicsXG4gICAgICAgICAgfSxcbiAgICAgICAgICBhbGlnbkl0ZW1zOiAnY2VudGVyJyxcbiAgICAgICAgfX1cbiAgICAgICAgdGl0bGU9e1xuICAgICAgICAgIDxCb3ggc3g9e3sgZGlzcGxheTogJ2ZsZXgnLCBhbGlnbkl0ZW1zOiAnY2VudGVyJywgZ2FwOiAwLjUgfX0+XG4gICAgICAgICAgICB7aWNvbiA/IChcbiAgICAgICAgICAgICAgaWNvblxuICAgICAgICAgICAgKSA6IChcbiAgICAgICAgICAgICAgPE1hbmFnZVNlYXJjaEljb25cbiAgICAgICAgICAgICAgICBzeD17e1xuICAgICAgICAgICAgICAgICAgaGVpZ2h0OiAnMi41cmVtJyxcbiAgICAgICAgICAgICAgICAgIGNvbG9yOiB0aGVtZS5wYWxldHRlLnByaW1hcnkubWFpbixcbiAgICAgICAgICAgICAgICAgIC4uLmljb25TeCxcbiAgICAgICAgICAgICAgICB9fVxuICAgICAgICAgICAgICAvPlxuICAgICAgICAgICAgKX1cbiAgICAgICAgICAgIDxUeXBvZ3JhcGh5XG4gICAgICAgICAgICAgIHZhcmlhbnQ9XCJoNVwiXG4gICAgICAgICAgICAgIHN4PXt7XG4gICAgICAgICAgICAgICAgZm9udFdlaWdodDogJ2JvbGQnLFxuICAgICAgICAgICAgICAgIGNvbG9yOiB0aGVtZS5wYWxldHRlLnByaW1hcnkubWFpbixcbiAgICAgICAgICAgICAgICAuLi50ZXh0U3gsXG4gICAgICAgICAgICAgIH19XG4gICAgICAgICAgICA+XG4gICAgICAgICAgICAgIHt0aXRsZSA/IHRpdGxlIDogJ0ZpbHRlcid9eycgJ31cbiAgICAgICAgICAgICAge3Nob3dDb3VudCA/IGAoJHtmaWx0ZXJDb3VudCA/IGZpbHRlckNvdW50IDogMH0pYCA6IDw+PC8+fVxuICAgICAgICAgICAgPC9UeXBvZ3JhcGh5PlxuICAgICAgICAgIDwvQm94PlxuICAgICAgICB9XG4gICAgICA+PC9DYXJkSGVhZGVyPlxuICAgICAgPERpdmlkZXIgLz5cbiAgICAgIDxDYXJkQ29udGVudCBzeD17eyBweTogMiB9fT5cbiAgICAgICAgPEdyaWQgY29udGFpbmVyIHNwYWNpbmc9ezJ9PlxuICAgICAgICAgIHtjaGlsZHJlbn1cbiAgICAgICAgPC9HcmlkPlxuICAgICAgPC9DYXJkQ29udGVudD5cbiAgICA8L0NhcmQ+XG4gICk7XG59O1xuIiwgIi8vIGNvcmUvY29tcG9uZW50cy9Gb290ZXIvaW5kZXgudHN4XHJcbmltcG9ydCB7IEJveCwgVHlwb2dyYXBoeSB9IGZyb20gJ0BtdWkvbWF0ZXJpYWwnO1xyXG5pbXBvcnQgUmVhY3QgZnJvbSAncmVhY3QnO1xyXG5cclxuZXhwb3J0IGNvbnN0IEZvb3RlcjogUmVhY3QuRkMgPSAoKSA9PiB7XHJcbiAgY29uc3QgY3VycmVudFllYXIgPSBuZXcgRGF0ZSgpLmdldEZ1bGxZZWFyKCk7XHJcblxyXG4gIHJldHVybiAoXHJcbiAgICA8Qm94XHJcbiAgICAgIGNvbXBvbmVudD1cImZvb3RlclwiXHJcbiAgICAgIHN4PXt7XHJcbiAgICAgICAgcHk6IDIsXHJcbiAgICAgICAgcHg6IDQsXHJcbiAgICAgICAgbXQ6ICdhdXRvJyxcclxuICAgICAgICBiYWNrZ3JvdW5kQ29sb3I6IHRoZW1lID0+XHJcbiAgICAgICAgICB0aGVtZS5wYWxldHRlLm1vZGUgPT09ICdsaWdodCdcclxuICAgICAgICAgICAgPyB0aGVtZS5wYWxldHRlLmdyZXlbMjAwXVxyXG4gICAgICAgICAgICA6IHRoZW1lLnBhbGV0dGUuZ3JleVs4MDBdLFxyXG4gICAgICB9fVxyXG4gICAgPlxyXG4gICAgICA8VHlwb2dyYXBoeSB2YXJpYW50PVwiYm9keTJcIiBjb2xvcj1cInRleHQuc2Vjb25kYXJ5XCIgYWxpZ249XCJjZW50ZXJcIj5cclxuICAgICAgICB7YFx1MDBBOSBDb3B5cmlnaHQgJHtjdXJyZW50WWVhcn0gR04uIEFsbCByaWdodHMgcmVzZXJ2ZWQgYnkgUGFydWwgVW5pdmVyc2l0eS5gfVxyXG4gICAgICA8L1R5cG9ncmFwaHk+XHJcbiAgICA8L0JveD5cclxuICApO1xyXG59O1xyXG4iLCAiaW1wb3J0IHR5cGUgeyBTeFByb3BzIH0gZnJvbSAnQG11aS9tYXRlcmlhbCc7XG5pbXBvcnQgeyBHcmlkLCBUb29sdGlwLCBUeXBvZ3JhcGh5IH0gZnJvbSAnQG11aS9tYXRlcmlhbCc7XG5cbi8qKlxuICogUHJvcHMgZm9yIHRoZSBMYWJlbFRleHQgY29tcG9uZW50LlxuICpcbiAqIEBwdWJsaWNcbiAqL1xuaW50ZXJmYWNlIExhYmVsVGV4dFByb3BzIHtcbiAgLyoqXG4gICAqIExhYmVsIHRleHQgdG8gZGlzcGxheSBvbiB0aGUgbGVmdCBzaWRlLlxuICAgKiBAZXhhbXBsZSBcIk5hbWVcIiBvciBcIkVtYWlsIEFkZHJlc3NcIlxuICAgKi9cbiAgbGFiZWw6IHN0cmluZztcbiAgLyoqXG4gICAqIFZhbHVlIGNvbnRlbnQgdG8gZGlzcGxheSBvbiB0aGUgcmlnaHQgc2lkZS5cbiAgICogQ2FuIGJlIHRleHQsIG51bWJlcnMsIG9yIFJlYWN0IGVsZW1lbnRzLlxuICAgKiBAZXhhbXBsZSBcIkpvaG4gRG9lXCIgb3IgPExpbms+VmlldyBEZXRhaWxzPC9MaW5rPlxuICAgKi9cbiAgdmFsdWU6IFJlYWN0LlJlYWN0Tm9kZTtcbiAgLyoqXG4gICAqIEN1c3RvbSBncmlkIHNpemluZyBmb3IgbGFiZWwgYW5kIHZhbHVlIHNlY3Rpb25zLlxuICAgKiBAZGVmYXVsdFZhbHVlIHsgbGFiZWxTaXplOiB7IHhzOiA2LCBzbTogNiwgbWQ6IDYgfSwgdmFsdWVTaXplOiB7IHhzOiAxMiwgc206IDYsIG1kOiA2IH0gfVxuICAgKi9cbiAgZ3JpZFNpemU/OiB7XG4gICAgLyoqIEdyaWQgc2l6ZSBjb25maWd1cmF0aW9uIGZvciB0aGUgbGFiZWwgc2VjdGlvbiAqL1xuICAgIGxhYmVsU2l6ZTogeyB4czogbnVtYmVyOyBzbTogbnVtYmVyOyBtZDogbnVtYmVyIH07XG4gICAgLyoqIEdyaWQgc2l6ZSBjb25maWd1cmF0aW9uIGZvciB0aGUgdmFsdWUgc2VjdGlvbiAqL1xuICAgIHZhbHVlU2l6ZTogeyB4czogbnVtYmVyOyBzbTogbnVtYmVyOyBtZDogbnVtYmVyIH07XG4gIH07XG4gIC8qKlxuICAgKiBHcmlkIHNpemUgY29uZmlndXJhdGlvbiBmb3IgdGhlIGVudGlyZSBjb250YWluZXIuXG4gICAqIEBkZWZhdWx0VmFsdWUgeyB4czogMTIsIHNtOiA2LCBtZDogNiB9XG4gICAqL1xuICBjb250YWluZXJTaXplPzogeyB4czogbnVtYmVyOyBzbTogbnVtYmVyOyBtZDogbnVtYmVyIH07XG4gIC8qKlxuICAgKiBPcHRpb25hbCBNVUkgc3ggcHJvcCBmb3IgY3VzdG9tIGxhYmVsIHN0eWxpbmcuXG4gICAqIEBleGFtcGxlIHsgZm9udFdlaWdodDogJ2JvbGQnLCBjb2xvcjogJ3ByaW1hcnkubWFpbicgfVxuICAgKi9cbiAgbGFiZWxTeD86IFN4UHJvcHM7XG4gIC8qKlxuICAgKiBPcHRpb25hbCBNVUkgc3ggcHJvcCBmb3IgY3VzdG9tIHZhbHVlIHN0eWxpbmcuXG4gICAqIEBleGFtcGxlIHsgY29sb3I6ICd0ZXh0LnNlY29uZGFyeScsIGZvbnRTdHlsZTogJ2l0YWxpYycgfVxuICAgKi9cbiAgdmFsdWVTeD86IFN4UHJvcHM7XG59XG5cbi8qKlxuICogUmVzcG9uc2l2ZSBsYWJlbC12YWx1ZSBkaXNwbGF5IGNvbXBvbmVudCB3aXRoIGhvdmVyIGVmZmVjdHMgYW5kIHRleHQgdHJ1bmNhdGlvbi5cbiAqXG4gKiBUaGlzIGNvbXBvbmVudCBjcmVhdGVzIGEgY29uc2lzdGVudCBsYWJlbC12YWx1ZSBwYWlyIGxheW91dCB0aGF0IGFkYXB0cyB0byBkaWZmZXJlbnRcbiAqIHNjcmVlbiBzaXplcy4gSXQgaW5jbHVkZXMgaG92ZXIgZWZmZWN0cywgdGV4dCB0cnVuY2F0aW9uIHdpdGggdG9vbHRpcHMsIGFuZFxuICogY3VzdG9taXphYmxlIGdyaWQgc2l6aW5nIGZvciBmbGV4aWJsZSBsYXlvdXRzLlxuICpcbiAqIEBleGFtcGxlXG4gKiBCYXNpYyB1c2FnZTpcbiAqIGBgYHRzeFxuICogPExhYmVsVGV4dFxuICogICBsYWJlbD1cIkZ1bGwgTmFtZVwiXG4gKiAgIHZhbHVlPVwiSm9obiBEb2VcIlxuICogLz5cbiAqIGBgYFxuICpcbiAqIEBleGFtcGxlXG4gKiBXaXRoIFJlYWN0IGVsZW1lbnQgdmFsdWU6XG4gKiBgYGB0c3hcbiAqIDxMYWJlbFRleHRcbiAqICAgbGFiZWw9XCJQcm9maWxlXCJcbiAqICAgdmFsdWU9ezxMaW5rIGhyZWY9XCIvcHJvZmlsZVwiPlZpZXcgUHJvZmlsZTwvTGluaz59XG4gKiAvPlxuICogYGBgXG4gKlxuICogQGV4YW1wbGVcbiAqIEN1c3RvbSBncmlkIHNpemluZzpcbiAqIGBgYHRzeFxuICogPExhYmVsVGV4dFxuICogICBsYWJlbD1cIkRlc2NyaXB0aW9uXCJcbiAqICAgdmFsdWU9e2xvbmdEZXNjcmlwdGlvbn1cbiAqICAgZ3JpZFNpemU9e3tcbiAqICAgICBsYWJlbFNpemU6IHsgeHM6IDEyLCBzbTogMywgbWQ6IDIgfSxcbiAqICAgICB2YWx1ZVNpemU6IHsgeHM6IDEyLCBzbTogOSwgbWQ6IDEwIH1cbiAqICAgfX1cbiAqICAgY29udGFpbmVyU2l6ZT17eyB4czogMTIsIHNtOiAxMiwgbWQ6IDEyIH19XG4gKiAvPlxuICogYGBgXG4gKlxuICogQHBhcmFtIHByb3BzIC0gQ29tcG9uZW50IHByb3BzIGZvciBsYWJlbC12YWx1ZSBjb25maWd1cmF0aW9uXG4gKiBAcmV0dXJucyBHcmlkLWJhc2VkIGxheW91dCB3aXRoIGxhYmVsIGFuZCB2YWx1ZSBzZWN0aW9uc1xuICpcbiAqIEBwdWJsaWNcbiAqL1xuZXhwb3J0IGNvbnN0IExhYmVsVGV4dCA9ICh7XG4gIGxhYmVsLFxuICB2YWx1ZSxcbiAgZ3JpZFNpemUsXG4gIGNvbnRhaW5lclNpemUsXG4gIGxhYmVsU3gsXG4gIHZhbHVlU3gsXG59OiBMYWJlbFRleHRQcm9wcykgPT4ge1xuICBjb25zdCBkZWZhdWx0R3JpZFNpemUgPSB7XG4gICAgbGFiZWxTaXplOiB7IHhzOiA2LCBzbTogNiwgbWQ6IDYgfSxcbiAgICB2YWx1ZVNpemU6IHsgeHM6IDEyLCBzbTogNiwgbWQ6IDYgfSxcbiAgfTtcbiAgY29uc3QgZGVmYXVsdENvbnRhaW5lclNpemUgPSB7IHhzOiAxMiwgc206IDYsIG1kOiA2IH07XG4gIGNvbnN0IHNpemUgPSBncmlkU2l6ZSB8fCBkZWZhdWx0R3JpZFNpemU7XG4gIGNvbnN0IGNvbnRhaW5lciA9IGNvbnRhaW5lclNpemUgfHwgZGVmYXVsdENvbnRhaW5lclNpemU7XG5cbiAgcmV0dXJuIChcbiAgICA8R3JpZFxuICAgICAgc2l6ZT17Y29udGFpbmVyfVxuICAgICAgc3g9e3tcbiAgICAgICAgZGlzcGxheTogJ2ZsZXgnLFxuICAgICAgICBmbGV4RGlyZWN0aW9uOiB7IHhzOiAnY29sdW1uJywgc206ICdyb3cnLCBtZDogJ3JvdycgfSxcbiAgICAgICAgJyY6aG92ZXInOiB7IGJnY29sb3I6ICcjZWZlZmVmJywgb3ZlcmZsb3c6ICdoaWRkZW4nIH0sXG4gICAgICB9fVxuICAgID5cbiAgICAgIDxHcmlkXG4gICAgICAgIHNpemU9e3NpemUubGFiZWxTaXplfVxuICAgICAgICBzeD17e1xuICAgICAgICAgIHBhZGRpbmc6ICc1cHgnLFxuICAgICAgICAgIGZvbnRTaXplOiAnMTRweCcsXG4gICAgICAgICAgdGV4dEFsaWduOiB7IHhzOiAnbGVmdCcsIHNtOiAncmlnaHQnLCBtZDogJ3JpZ2h0JyB9LFxuICAgICAgICAgIC4uLmxhYmVsU3gsXG4gICAgICAgIH19XG4gICAgICA+XG4gICAgICAgIHtsYWJlbH0gOlxuICAgICAgPC9HcmlkPlxuICAgICAgPEdyaWRcbiAgICAgICAgc2l6ZT17c2l6ZS52YWx1ZVNpemV9XG4gICAgICAgIHN4PXt7IHBhZGRpbmc6ICc1cHgnLCBkaXNwbGF5OiAnZmxleCcsIGZsZXhXcmFwOiAnd3JhcCcgfX1cbiAgICAgID5cbiAgICAgICAgPFRvb2x0aXAgdGl0bGU9e3ZhbHVlfSBhcnJvdz5cbiAgICAgICAgICA8VHlwb2dyYXBoeVxuICAgICAgICAgICAgc3g9e3tcbiAgICAgICAgICAgICAgZm9udFNpemU6ICcxNHB4JyxcbiAgICAgICAgICAgICAgd29yZEJyZWFrOiAnYnJlYWstd29yZCcsXG4gICAgICAgICAgICAgIG92ZXJmbG93OiAnaGlkZGVuJyxcbiAgICAgICAgICAgICAgZGlzcGxheTogJy13ZWJraXQtYm94JyxcbiAgICAgICAgICAgICAgdGV4dE92ZXJmbG93OiAnZWxsaXBzaXMnLFxuICAgICAgICAgICAgICBXZWJraXRMaW5lQ2xhbXA6IDIsXG4gICAgICAgICAgICAgIFdlYmtpdEJveE9yaWVudDogJ3ZlcnRpY2FsJyxcbiAgICAgICAgICAgICAgLi4udmFsdWVTeCxcbiAgICAgICAgICAgICAgY29sb3I6ICcjMDc4ZGVlJyxcbiAgICAgICAgICAgIH19XG4gICAgICAgICAgPlxuICAgICAgICAgICAge3ZhbHVlID8gdmFsdWUgOiAnLSd9XG4gICAgICAgICAgPC9UeXBvZ3JhcGh5PlxuICAgICAgICA8L1Rvb2x0aXA+XG4gICAgICA8L0dyaWQ+XG4gICAgPC9HcmlkPlxuICApO1xufTtcbiIsICJpbXBvcnQgdHlwZSB7IFByb3BzV2l0aENoaWxkcmVuIH0gZnJvbSAncmVhY3QnO1xyXG5cclxuaW50ZXJmYWNlIFJlbmRlcklmUHJvcHMge1xyXG4gIHNob3c6IGJvb2xlYW47XHJcbn1cclxuXHJcbmV4cG9ydCBjb25zdCBSZW5kZXJJZiA9ICh7XHJcbiAgc2hvdyxcclxuICBjaGlsZHJlbixcclxufTogUHJvcHNXaXRoQ2hpbGRyZW48UmVuZGVySWZQcm9wcz4pID0+IHtcclxuICByZXR1cm4gc2hvdyA/IDw+e2NoaWxkcmVufTwvPiA6IG51bGw7XHJcbn07XHJcbiIsICJpbXBvcnQgdHlwZSB7IFN4UHJvcHMsIFRoZW1lIH0gZnJvbSAnQG11aS9tYXRlcmlhbCc7XHJcbmltcG9ydCB7IEJveCwgRGl2aWRlciwgR3JpZCwgU3RhY2ssIFR5cG9ncmFwaHkgfSBmcm9tICdAbXVpL21hdGVyaWFsJztcclxuaW1wb3J0IHR5cGUgeyBQcm9wc1dpdGhDaGlsZHJlbiwgUmVhY3ROb2RlIH0gZnJvbSAncmVhY3QnO1xyXG5pbXBvcnQgeyBtZW1vLCB1c2VNZW1vIH0gZnJvbSAncmVhY3QnO1xyXG5cclxuLy8gU2VjdGlvbiBib3ggY29uZmlndXJhdGlvblxyXG5leHBvcnQgaW50ZXJmYWNlIFNlY3Rpb25Cb3hQcm9wcyBleHRlbmRzIFByb3BzV2l0aENoaWxkcmVuIHtcclxuICB0aXRsZTogc3RyaW5nO1xyXG4gIHNwYWNpbmc/OiBudW1iZXI7XHJcbiAgY29udGFpbmVyU3g/OiBTeFByb3BzPFRoZW1lPjtcclxuICB0aXRsZVN4PzogU3hQcm9wczxUaGVtZT47XHJcbiAgdmFyaWFudD86ICdkZWZhdWx0JyB8ICdmb3JtJyB8ICdpbmZvJyB8ICd3YXJuaW5nJyB8ICdlcnJvcic7XHJcbiAgaWNvbj86IFJlYWN0Tm9kZTtcclxuICBhY3Rpb25zPzogUmVhY3ROb2RlO1xyXG4gIGNvbGxhcHNpYmxlPzogYm9vbGVhbjtcclxuICBkZWZhdWx0RXhwYW5kZWQ/OiBib29sZWFuO1xyXG59XHJcblxyXG4vLyBUaGVtZSBjb25maWd1cmF0aW9uIGZvciBzZWN0aW9uIHZhcmlhbnRzXHJcbmNvbnN0IGdldFNlY3Rpb25UaGVtZSA9ICh2YXJpYW50OiBTZWN0aW9uQm94UHJvcHNbJ3ZhcmlhbnQnXSA9ICdkZWZhdWx0JykgPT4ge1xyXG4gIGNvbnN0IHRoZW1lcyA9IHtcclxuICAgIGRlZmF1bHQ6IHtcclxuICAgICAgYmdjb2xvcjogJyNmYWViZDcnLFxyXG4gICAgICBjb2xvcjogJyM5MjVkMjEnLFxyXG4gICAgfSxcclxuICAgIGZvcm06IHtcclxuICAgICAgYmdjb2xvcjogJyNjZGNlZDEnLFxyXG4gICAgICBjb2xvcjogJ2JsYWNrJyxcclxuICAgIH0sXHJcbiAgICBpbmZvOiB7XHJcbiAgICAgIGJnY29sb3I6ICcjZTNmMmZkJyxcclxuICAgICAgY29sb3I6ICcjMTk3NmQyJyxcclxuICAgIH0sXHJcbiAgICB3YXJuaW5nOiB7XHJcbiAgICAgIGJnY29sb3I6ICcjZmZmM2UwJyxcclxuICAgICAgY29sb3I6ICcjZjU3YzAwJyxcclxuICAgIH0sXHJcbiAgICBlcnJvcjoge1xyXG4gICAgICBiZ2NvbG9yOiAnI2ZmZWJlZScsXHJcbiAgICAgIGNvbG9yOiAnI2QzMmYyZicsXHJcbiAgICB9LFxyXG4gIH07XHJcblxyXG4gIHJldHVybiB0aGVtZXNbdmFyaWFudF07XHJcbn07XHJcblxyXG4vLyBNZW1vaXplZCBTZWN0aW9uQm94IGNvbXBvbmVudCBmb3IgcGVyZm9ybWFuY2VcclxuZXhwb3J0IGNvbnN0IFNlY3Rpb25Cb3ggPSBtZW1vPFNlY3Rpb25Cb3hQcm9wcz4oXHJcbiAgKHtcclxuICAgIHRpdGxlLFxyXG4gICAgY2hpbGRyZW4sXHJcbiAgICBzcGFjaW5nID0gMCxcclxuICAgIGNvbnRhaW5lclN4LFxyXG4gICAgdGl0bGVTeCxcclxuICAgIHZhcmlhbnQgPSAnZGVmYXVsdCcsXHJcbiAgICBpY29uLFxyXG4gICAgYWN0aW9ucyxcclxuICB9KSA9PiB7XHJcbiAgICBjb25zdCB0aGVtZUNvbG9ycyA9IHVzZU1lbW8oKCkgPT4gZ2V0U2VjdGlvblRoZW1lKHZhcmlhbnQpLCBbdmFyaWFudF0pO1xyXG5cclxuICAgIGNvbnN0IGhlYWRlclN4ID0gdXNlTWVtbyhcclxuICAgICAgKCkgPT4gKHtcclxuICAgICAgICBweDogMS41LFxyXG4gICAgICAgIHB5OiAwLjEsXHJcbiAgICAgICAgd2lkdGg6ICdmaXQtY29udGVudCcsXHJcbiAgICAgICAgLi4udGhlbWVDb2xvcnMsXHJcbiAgICAgICAgLi4udGl0bGVTeCxcclxuICAgICAgfSksXHJcbiAgICAgIFt0aGVtZUNvbG9ycywgdGl0bGVTeF1cclxuICAgICk7XHJcblxyXG4gICAgY29uc3QgY29udGVudFN4ID0gdXNlTWVtbyhcclxuICAgICAgKCkgPT4gKHtcclxuICAgICAgICBwYWRkaW5nOiAnMTZweCcsXHJcbiAgICAgICAgLi4uY29udGFpbmVyU3gsXHJcbiAgICAgIH0pLFxyXG4gICAgICBbY29udGFpbmVyU3hdXHJcbiAgICApO1xyXG5cclxuICAgIHJldHVybiAoXHJcbiAgICAgIDw+XHJcbiAgICAgICAgPEJveCBzeD17eyBkaXNwbGF5OiAnZmxleCcsIGZsZXhEaXJlY3Rpb246ICdjb2x1bW4nLCB3aWR0aDogJzEwMCUnIH19PlxyXG4gICAgICAgICAgPFN0YWNrXHJcbiAgICAgICAgICAgIGRpcmVjdGlvbj1cInJvd1wiXHJcbiAgICAgICAgICAgIGp1c3RpZnlDb250ZW50PVwic3BhY2UtYmV0d2VlblwiXHJcbiAgICAgICAgICAgIGFsaWduSXRlbXM9XCJjZW50ZXJcIlxyXG4gICAgICAgICAgICBzeD17aGVhZGVyU3h9XHJcbiAgICAgICAgICA+XHJcbiAgICAgICAgICAgIDxTdGFjayBkaXJlY3Rpb249XCJyb3dcIiBhbGlnbkl0ZW1zPVwiY2VudGVyXCIgc3BhY2luZz17MX0+XHJcbiAgICAgICAgICAgICAge2ljb259XHJcbiAgICAgICAgICAgICAgPFR5cG9ncmFwaHkgc3g9e3sgZm9udFNpemU6ICcxNXB4JywgZm9udFdlaWdodDogNDAwIH19PlxyXG4gICAgICAgICAgICAgICAge3RpdGxlfVxyXG4gICAgICAgICAgICAgIDwvVHlwb2dyYXBoeT5cclxuICAgICAgICAgICAgPC9TdGFjaz5cclxuICAgICAgICAgICAge2FjdGlvbnN9XHJcbiAgICAgICAgICA8L1N0YWNrPlxyXG4gICAgICAgICAgPERpdmlkZXIgLz5cclxuICAgICAgICA8L0JveD5cclxuICAgICAgICA8R3JpZCBjb250YWluZXIgc3BhY2luZz17c3BhY2luZ30gc3g9e2NvbnRlbnRTeH0+XHJcbiAgICAgICAgICB7Y2hpbGRyZW59XHJcbiAgICAgICAgPC9HcmlkPlxyXG4gICAgICA8Lz5cclxuICAgICk7XHJcbiAgfVxyXG4pO1xyXG4iLCAiaW1wb3J0IHsgVGFiQ29udGV4dCB9IGZyb20gJ0BtdWkvbGFiJztcclxuaW1wb3J0IHR5cGUgeyBTeFByb3BzIH0gZnJvbSAnQG11aS9tYXRlcmlhbCc7XHJcbmltcG9ydCB7IEJveCwgVGFiLCBUYWJzIH0gZnJvbSAnQG11aS9tYXRlcmlhbCc7XHJcbmltcG9ydCB0eXBlIHsgUHJvcHNXaXRoQ2hpbGRyZW4gfSBmcm9tICdyZWFjdCc7XHJcbmltcG9ydCBSZWFjdCwgeyB1c2VTdGF0ZSB9IGZyb20gJ3JlYWN0JztcclxuXHJcbmV4cG9ydCBpbnRlcmZhY2UgVGFiSXRlbSB7XHJcbiAgbGFiZWw6IHN0cmluZztcclxuICB2YWx1ZTogbnVtYmVyO1xyXG4gIHBlcm1pc3Npb24/OiBib29sZWFuO1xyXG59XHJcblxyXG5pbnRlcmZhY2UgQ3VzdG9tVGFic1Byb3BzIHtcclxuICB0YWJzOiBUYWJJdGVtW107XHJcbiAgZGVmYXVsdFZhbHVlPzogbnVtYmVyO1xyXG4gIG9uVGFiQ2hhbmdlPzogKG5ld1ZhbHVlOiBudW1iZXIpID0+IHZvaWQ7XHJcbiAgdGFiU3g/OiBTeFByb3BzO1xyXG4gIHRhYnNTeD86IFN4UHJvcHM7XHJcbn1cclxuXHJcbmV4cG9ydCBjb25zdCBTaW1wbGVUYWJzID0gKHtcclxuICB0YWJzLFxyXG4gIGRlZmF1bHRWYWx1ZSA9IDEsXHJcbiAgb25UYWJDaGFuZ2UsXHJcbiAgY2hpbGRyZW4sXHJcbiAgdGFiU3gsXHJcbiAgdGFic1N4LFxyXG59OiBDdXN0b21UYWJzUHJvcHMgJiBQcm9wc1dpdGhDaGlsZHJlbikgPT4ge1xyXG4gIGNvbnN0IFt2YWx1ZSwgc2V0VmFsdWVdID0gdXNlU3RhdGU8bnVtYmVyPihkZWZhdWx0VmFsdWUpO1xyXG5cclxuICBjb25zdCBoYW5kbGVDaGFuZ2UgPSAoZXZlbnQ6IFJlYWN0LlN5bnRoZXRpY0V2ZW50LCBuZXdWYWx1ZTogbnVtYmVyKSA9PiB7XHJcbiAgICBzZXRWYWx1ZShuZXdWYWx1ZSk7XHJcbiAgICBpZiAob25UYWJDaGFuZ2UpIG9uVGFiQ2hhbmdlKG5ld1ZhbHVlKTtcclxuICB9O1xyXG5cclxuICByZXR1cm4gKFxyXG4gICAgPFRhYkNvbnRleHQgdmFsdWU9e3ZhbHVlfT5cclxuICAgICAgPEJveCBzeD17eyBib3JkZXJCb3R0b206IDEsIGJvcmRlckNvbG9yOiAnZGl2aWRlcicsIHdpZHRoOiAnMTAwJScgfX0+XHJcbiAgICAgICAgPFRhYnNcclxuICAgICAgICAgIHZhbHVlPXt2YWx1ZX1cclxuICAgICAgICAgIG9uQ2hhbmdlPXtoYW5kbGVDaGFuZ2V9XHJcbiAgICAgICAgICBzeD17eyBweDogMiwgcHk6IDAsIC4uLnRhYnNTeCB9fVxyXG4gICAgICAgID5cclxuICAgICAgICAgIHt0YWJzLm1hcCh0YWIgPT4gKFxyXG4gICAgICAgICAgICA8VGFiXHJcbiAgICAgICAgICAgICAga2V5PXt0YWIudmFsdWV9XHJcbiAgICAgICAgICAgICAgbGFiZWw9e3RhYi5sYWJlbH1cclxuICAgICAgICAgICAgICB2YWx1ZT17dGFiLnZhbHVlfVxyXG4gICAgICAgICAgICAgIGRpc2FibGVkPXt0YWIucGVybWlzc2lvbiA9PT0gZmFsc2V9XHJcbiAgICAgICAgICAgICAgc3g9e3sgZm9udFNpemU6ICcxcmVtJywgLi4udGFiU3ggfX1cclxuICAgICAgICAgICAgLz5cclxuICAgICAgICAgICkpfVxyXG4gICAgICAgIDwvVGFicz5cclxuICAgICAgPC9Cb3g+XHJcblxyXG4gICAgICB7Y2hpbGRyZW59XHJcbiAgICA8L1RhYkNvbnRleHQ+XHJcbiAgKTtcclxufTtcclxuIiwgImltcG9ydCB0eXBlIHsgTG9hZGluZ0J1dHRvblByb3BzIH0gZnJvbSAnQG11aS9sYWInO1xyXG5pbXBvcnQgeyBMb2FkaW5nQnV0dG9uIH0gZnJvbSAnQG11aS9sYWInO1xyXG5pbXBvcnQgUmVhY3QgZnJvbSAncmVhY3QnO1xyXG5cclxudHlwZSBTdWJtaXRCdXR0b25Qcm9wcyA9IE9taXQ8XHJcbiAgTG9hZGluZ0J1dHRvblByb3BzLFxyXG4gICdjaGlsZHJlbicgfCAndmFyaWFudCcgfCAnY29sb3InIHwgJ3R5cGUnXHJcbj47XHJcblxyXG5leHBvcnQgY29uc3QgU3VibWl0QnV0dG9uOiBSZWFjdC5GQzxTdWJtaXRCdXR0b25Qcm9wcz4gPSAoe1xyXG4gIGxvYWRpbmcgPSBmYWxzZSxcclxuICAuLi5yZXN0XHJcbn0pID0+IChcclxuICA8TG9hZGluZ0J1dHRvblxyXG4gICAgbG9hZGluZz17bG9hZGluZ31cclxuICAgIHZhcmlhbnQ9XCJjb250YWluZWRcIlxyXG4gICAgY29sb3I9XCJwcmltYXJ5XCJcclxuICAgIHR5cGU9XCJzdWJtaXRcIlxyXG4gICAgey4uLnJlc3R9XHJcbiAgICBzeD17eyBmb250V2VpZ2h0OiA0MDAgfX1cclxuICA+XHJcbiAgICBTdWJtaXRcclxuICA8L0xvYWRpbmdCdXR0b24+XHJcbik7XHJcbiIsICJpbXBvcnQgdHlwZSBSZWFjdCBmcm9tICdyZWFjdCc7XHJcbmltcG9ydCB7IGZvcndhcmRSZWYgfSBmcm9tICdyZWFjdCc7XHJcblxyXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tXHJcbi8vIFNoYXJlZCB0eXBlc1xyXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tXHJcbmV4cG9ydCBpbnRlcmZhY2UgRGF0YU1vZGFsQnV0dG9ucyB7XHJcbiAgb25TdWJtaXQ/OiAoKSA9PiB2b2lkO1xyXG4gIG9uQ2FuY2VsPzogKCkgPT4gdm9pZDtcclxuICBpc1BlbmRpbmc/OiBib29sZWFuO1xyXG4gIGlzU3VjY2Vzcz86IGJvb2xlYW47XHJcbn1cclxuXHJcbmV4cG9ydCBpbnRlcmZhY2UgRGF0YU1vZGFsQ29tcG9uZW50UHJvcHM8VERhdGE+IHtcclxuICBkYXRhPzogVERhdGE7XHJcbiAgaXNFZGl0aW5nPzogYm9vbGVhbjtcclxuICByZWY/OiBSZWFjdC5SZWY8RGF0YU1vZGFsQnV0dG9ucz47IC8vIFx1RDgzRFx1REM0OCBwdXQgcmVmIGludG8gcHJvcHNcclxufVxyXG5cclxuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG4vLyBQcm9qZWN0LXNwZWNpZmljIEhPQ1xyXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tXHJcbmV4cG9ydCBmdW5jdGlvbiB3aXRoRGF0YU1vZGFsPFREYXRhPihcclxuICBjb21wb25lbnQ6IChcclxuICAgIHByb3BzOiBEYXRhTW9kYWxDb21wb25lbnRQcm9wczxURGF0YT5cclxuICApID0+IFJlYWN0LlJlYWN0RWxlbWVudCB8IG51bGxcclxuKSB7XHJcbiAgcmV0dXJuIGZvcndhcmRSZWY8RGF0YU1vZGFsQnV0dG9ucywgRGF0YU1vZGFsQ29tcG9uZW50UHJvcHM8VERhdGE+PihcclxuICAgIChwcm9wcywgcmVmKSA9PiBjb21wb25lbnQoeyAuLi5wcm9wcywgcmVmIH0pXHJcbiAgKTtcclxufVxyXG4iLCAiZXhwb3J0IGludGVyZmFjZSBDb25maWdWYWx1ZSB7XHJcbiAgYXBpQmFzZVVybDogc3RyaW5nO1xyXG4gIGRlZmF1bHRQYWdlU2l6ZTogbnVtYmVyO1xyXG59XHJcblxyXG5leHBvcnQgY29uc3QgQ29uZmlnOiBDb25maWdWYWx1ZSA9IHtcclxuICBkZWZhdWx0UGFnZVNpemU6IDIwLFxyXG4gIGFwaUJhc2VVcmw6ICdodHRwOi8vbG9jYWxob3N0OjUxNDMnLFxyXG4gIC8vIGFwaUJhc2VVcmw6ICdodHRwOi8vMTkyLjE2OC4xLjI0Njo1MTQzJyxcclxufTtcclxuXHJcbmV4cG9ydCBjb25zdCBkYXRlVGltZVBhdHRlcm5zID0ge1xyXG4gIGRhdGVUaW1lOiAnREQgTU1NIFlZWVkgaDptbSBBJywgLy8gMTcgQXByIDIwMjIgMTI6MDAgYW1cclxuICBkYXRlOiAnREQgTU1NIFlZWVknLCAvLyAxNyBBcHIgMjAyMlxyXG4gIG1vbnRoX3llYXJfc2hvcnRfZm9ybWF0OiAnTU1NIFlZWVknLFxyXG4gIG1vbnRoX3llYXJfZnVsbF9mb3JtYXQ6ICdNTU1NIFlZWVknLFxyXG4gIHllYXI6ICdZWVlZJyxcclxuICB0aW1lOiAnaDptbSBhJywgLy8gMTI6MDAgYW1cclxuICBzcGxpdDoge1xyXG4gICAgZGF0ZVRpbWU6ICdERC9NTS9ZWVlZIGg6bW0gQScsIC8vIDE3LzA0LzIwMjIgMTI6MDAgYW1cclxuICAgIGRhdGU6ICdERC9NTS9ZWVlZJywgLy8gMTcvMDQvMjAyMlxyXG4gIH0sXHJcbiAgcGFyYW1DYXNlOiB7XHJcbiAgICBkYXRlVGltZTogJ0RELU1NLVlZWVkgaDptbSBBJywgLy8gMTctMDQtMjAyMiAxMjowMCBhbVxyXG4gICAgZGF0ZTogJ0RELU1NLVlZWVknLCAvLyAxNy0wNC0yMDIyXHJcbiAgICBkYXRlUmV2ZXJzZTogJ1lZWVktTU0tREQnLCAvLyAyMDIyLTA0LTE3IGZvciBjb21wYXJlIGRhdGVcclxuICAgIE1vbnRoWWVhcjogJ01NTS1ZWVlZJyxcclxuICB9LFxyXG59O1xyXG4iLCAiaW1wb3J0IHsgdXNlTWVtbyB9IGZyb20gJ3JlYWN0JztcclxuXHJcbmltcG9ydCB7IGNyZWF0ZUFwaUNsaWVudCB9IGZyb20gJy4uL2FwaS9jcmVhdGVBcGlDbGllbnQnO1xyXG5pbXBvcnQgdHlwZSB7IEFwaUNsaWVudENvbmZpZyB9IGZyb20gJy4uL2FwaS9jcmVhdGVBcGlDbGllbnQnO1xyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIHVzZUFwaUNsaWVudChjb25maWc6IEFwaUNsaWVudENvbmZpZykge1xyXG4gIHJldHVybiB1c2VNZW1vKFxyXG4gICAgKCkgPT4gY3JlYXRlQXBpQ2xpZW50KGNvbmZpZyksXHJcbiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgcmVhY3QtaG9va3MvZXhoYXVzdGl2ZS1kZXBzXHJcbiAgICBbXHJcbiAgICAgIGNvbmZpZy5iYXNlVVJMLFxyXG4gICAgICBjb25maWcudGltZW91dCxcclxuICAgICAgY29uZmlnLmNvcnJlbGF0aW9uSWRQcmVmaXgsXHJcbiAgICAgIGNvbmZpZy5pbmNsdWRlQ29ycmVsYXRpb25JZCxcclxuICAgICAgY29uZmlnLnRva2VuU3RvcmFnZUtleSxcclxuICAgICAgY29uZmlnLmF1dGhUb2tlbixcclxuICAgICAgY29uZmlnLnJlcXVlc3RJbnRlcmNlcHRvcnMsXHJcbiAgICAgIGNvbmZpZy5yZXNwb25zZUludGVyY2VwdG9ycyxcclxuICAgICAgY29uZmlnLmVycm9ySW50ZXJjZXB0b3JzLFxyXG4gICAgXVxyXG4gICk7XHJcbn1cclxuIiwgImltcG9ydCB0eXBlIHsgVmFsaWRhdGlvbkVycm9ycyB9IGZyb20gJ0BnbndlYnNvZnQvdWknO1xyXG5pbXBvcnQgeyB1c2VDYWxsYmFjayB9IGZyb20gJ3JlYWN0JztcclxuaW1wb3J0IHR5cGUgeyBVc2VGb3JtU2V0RXJyb3IsIEZpZWxkVmFsdWVzLCBQYXRoIH0gZnJvbSAncmVhY3QtaG9vay1mb3JtJztcclxuaW1wb3J0IHsgdG9hc3QgfSBmcm9tICdzb25uZXInO1xyXG5cclxuaW1wb3J0IHR5cGUgeyBBcGlFcnJvciB9IGZyb20gJy4uL2FwaS90eXBlcyc7XHJcblxyXG5leHBvcnQgaW50ZXJmYWNlIFN1Y2Nlc3NNZXNzYWdlIHtcclxuICBjcmVhdGU6IHN0cmluZztcclxuICB1cGRhdGU6IHN0cmluZztcclxufVxyXG5cclxuZXhwb3J0IGludGVyZmFjZSBFcnJvck1lc3NhZ2Uge1xyXG4gIG5vQ2hhbmdlczogc3RyaW5nO1xyXG4gIGdlbmVyYWw6IHN0cmluZztcclxufVxyXG5cclxuZXhwb3J0IGludGVyZmFjZSBVc2VGb3JtRXJyb3JIYW5kbGVyT3B0aW9uczxURmllbGRWYWx1ZXMgZXh0ZW5kcyBGaWVsZFZhbHVlcz4ge1xyXG4gIHNldEVycm9yPzogVXNlRm9ybVNldEVycm9yPFRGaWVsZFZhbHVlcz47XHJcbiAgc3VjY2Vzc01lc3NhZ2U/OiBTdWNjZXNzTWVzc2FnZTtcclxuICBlcnJvck1lc3NhZ2U/OiBFcnJvck1lc3NhZ2U7XHJcbn1cclxuXHJcbmV4cG9ydCB0eXBlIFN1Y2Nlc3NIYW5kbGVyID0gKFxyXG4gIGlzRWRpdGluZzogYm9vbGVhbixcclxuICByb3dzQWZmZWN0ZWQ/OiBudW1iZXJcclxuKSA9PiBib29sZWFuO1xyXG5cclxuZXhwb3J0IHR5cGUgRXJyb3JIYW5kbGVyID0gKHByb2Nlc3NlZEVycm9yOiBBcGlFcnJvcikgPT4gdm9pZDtcclxuXHJcbmV4cG9ydCBpbnRlcmZhY2UgVXNlRm9ybUVycm9ySGFuZGxlclJldHVybiB7XHJcbiAgaGFuZGxlU3VjY2VzczogU3VjY2Vzc0hhbmRsZXI7XHJcbiAgaGFuZGxlRXJyb3I6IEVycm9ySGFuZGxlcjtcclxufVxyXG5cclxuZXhwb3J0IGludGVyZmFjZSBVc2VEZWxldGVIYW5kbGVyT3B0aW9ucyB7XHJcbiAgc3VjY2Vzc01lc3NhZ2U/OiBzdHJpbmc7XHJcbiAgZXJyb3JNZXNzYWdlPzogc3RyaW5nO1xyXG59XHJcblxyXG4vKipcclxuICogSG9vayB0byBoYW5kbGUgQVBJIGVycm9ycyBpbiBmb3JtcyB3aXRoIHN0YW5kYXJkaXplZCBlcnJvciBoYW5kbGluZyBhbmQgdG9hc3QgbWVzc2FnZXNcclxuICovXHJcbmV4cG9ydCBjb25zdCB1c2VGb3JtRXJyb3JIYW5kbGVyID0gPFRGaWVsZFZhbHVlcyBleHRlbmRzIEZpZWxkVmFsdWVzPih7XHJcbiAgc2V0RXJyb3IsXHJcbiAgc3VjY2Vzc01lc3NhZ2UgPSB7XHJcbiAgICBjcmVhdGU6ICdDcmVhdGVkIHN1Y2Nlc3NmdWxseScsXHJcbiAgICB1cGRhdGU6ICdVcGRhdGVkIHN1Y2Nlc3NmdWxseScsXHJcbiAgfSxcclxuICBlcnJvck1lc3NhZ2UgPSB7XHJcbiAgICBub0NoYW5nZXM6ICdObyBjaGFuZ2VzIHdlcmUgbWFkZScsXHJcbiAgICBnZW5lcmFsOiAnRmFpbGVkIHRvIHNhdmUuIFBsZWFzZSB0cnkgYWdhaW4uJyxcclxuICB9LFxyXG59OiBVc2VGb3JtRXJyb3JIYW5kbGVyT3B0aW9uczxURmllbGRWYWx1ZXM+KTogVXNlRm9ybUVycm9ySGFuZGxlclJldHVybiA9PiB7XHJcbiAgY29uc3QgZ2V0RmllbGRFcnJvciA9IHVzZUNhbGxiYWNrKFxyXG4gICAgKFxyXG4gICAgICBmaWVsZHM6IFZhbGlkYXRpb25FcnJvcnMgfCB1bmRlZmluZWQsXHJcbiAgICAgIGZpZWxkTmFtZTogc3RyaW5nXHJcbiAgICApOiBzdHJpbmcgfCB1bmRlZmluZWQgPT4ge1xyXG4gICAgICBpZiAoIWZpZWxkcyB8fCAhZmllbGRzW2ZpZWxkTmFtZV0pIHJldHVybiB1bmRlZmluZWQ7XHJcblxyXG4gICAgICBjb25zdCBmaWVsZEVycm9yID0gZmllbGRzW2ZpZWxkTmFtZV07XHJcblxyXG4gICAgICBpZiAodHlwZW9mIGZpZWxkRXJyb3IgPT09ICdzdHJpbmcnKSB7XHJcbiAgICAgICAgcmV0dXJuIGZpZWxkRXJyb3I7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIGlmIChBcnJheS5pc0FycmF5KGZpZWxkRXJyb3IpKSB7XHJcbiAgICAgICAgcmV0dXJuIGZpZWxkRXJyb3Iuam9pbignLCAnKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgaWYgKHR5cGVvZiBmaWVsZEVycm9yID09PSAnb2JqZWN0JyAmJiAnbWVzc2FnZScgaW4gZmllbGRFcnJvcikge1xyXG4gICAgICAgIHJldHVybiBmaWVsZEVycm9yLm1lc3NhZ2U7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIHJldHVybiB1bmRlZmluZWQ7XHJcbiAgICB9LFxyXG4gICAgW11cclxuICApO1xyXG5cclxuICBjb25zdCBoYW5kbGVTdWNjZXNzID0gdXNlQ2FsbGJhY2soXHJcbiAgICAoaXNFZGl0aW5nOiBib29sZWFuLCByb3dzQWZmZWN0ZWQ/OiBudW1iZXIpID0+IHtcclxuICAgICAgaWYgKHJvd3NBZmZlY3RlZCAhPT0gdW5kZWZpbmVkICYmIHJvd3NBZmZlY3RlZCA+IDApIHtcclxuICAgICAgICB0b2FzdC5zdWNjZXNzKFxyXG4gICAgICAgICAgaXNFZGl0aW5nID8gc3VjY2Vzc01lc3NhZ2UudXBkYXRlIDogc3VjY2Vzc01lc3NhZ2UuY3JlYXRlXHJcbiAgICAgICAgKTtcclxuXHJcbiAgICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICAgIH0gZWxzZSBpZiAocm93c0FmZmVjdGVkID09PSAwKSB7XHJcbiAgICAgICAgdG9hc3QuZXJyb3IoZXJyb3JNZXNzYWdlLm5vQ2hhbmdlcyk7XHJcblxyXG4gICAgICAgIHJldHVybiBmYWxzZTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gSWYgcm93c0FmZmVjdGVkIGlzIHVuZGVmaW5lZCwgYXNzdW1lIHN1Y2Nlc3NcclxuICAgICAgdG9hc3Quc3VjY2Vzcyhpc0VkaXRpbmcgPyBzdWNjZXNzTWVzc2FnZS51cGRhdGUgOiBzdWNjZXNzTWVzc2FnZS5jcmVhdGUpO1xyXG5cclxuICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICB9LFxyXG4gICAgW3N1Y2Nlc3NNZXNzYWdlLCBlcnJvck1lc3NhZ2VdXHJcbiAgKTtcclxuXHJcbiAgY29uc3QgaGFuZGxlRXJyb3IgPSB1c2VDYWxsYmFjayhcclxuICAgIChwcm9jZXNzZWRFcnJvcjogQXBpRXJyb3IpID0+IHtcclxuICAgICAgaWYgKFxyXG4gICAgICAgIHByb2Nlc3NlZEVycm9yLnR5cGUgPT09ICd2YWxpZGF0aW9uX2Vycm9yJyAmJlxyXG4gICAgICAgIHByb2Nlc3NlZEVycm9yLmVycm9ycyAmJlxyXG4gICAgICAgIHNldEVycm9yXHJcbiAgICAgICkge1xyXG4gICAgICAgIC8vIFNldCBmaWVsZC1zcGVjaWZpYyBlcnJvcnMgdXNpbmcgcmVhY3QtaG9vay1mb3JtJ3Mgc2V0RXJyb3IgKG9ubHkgaWYgc2V0RXJyb3IgaXMgcHJvdmlkZWQpXHJcbiAgICAgICAgT2JqZWN0LmtleXMocHJvY2Vzc2VkRXJyb3IuZXJyb3JzKS5mb3JFYWNoKGZpZWxkTmFtZSA9PiB7XHJcbiAgICAgICAgICBjb25zdCBmaWVsZEVycm9yID0gZ2V0RmllbGRFcnJvcihwcm9jZXNzZWRFcnJvci5lcnJvcnMsIGZpZWxkTmFtZSk7XHJcblxyXG4gICAgICAgICAgaWYgKGZpZWxkRXJyb3IpIHtcclxuICAgICAgICAgICAgc2V0RXJyb3IoZmllbGROYW1lIGFzIFBhdGg8VEZpZWxkVmFsdWVzPiwge1xyXG4gICAgICAgICAgICAgIHR5cGU6ICdzZXJ2ZXInLFxyXG4gICAgICAgICAgICAgIG1lc3NhZ2U6IGZpZWxkRXJyb3IsXHJcbiAgICAgICAgICAgIH0pO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH0pO1xyXG5cclxuICAgICAgICAvLyBTaG93IGdlbmVyYWwgdmFsaWRhdGlvbiBlcnJvciB0b2FzdFxyXG4gICAgICAgIHRvYXN0LmVycm9yKFxyXG4gICAgICAgICAgcHJvY2Vzc2VkRXJyb3IudGl0bGUgfHwgJ1BsZWFzZSBjaGVjayB0aGUgZm9ybSBmb3IgdmFsaWRhdGlvbiBlcnJvcnMnXHJcbiAgICAgICAgKTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICAvLyBTaG93IGdlbmVyYWwgZXJyb3IgdG9hc3QgZm9yIG5vbi12YWxpZGF0aW9uIGVycm9ycyBvciB3aGVuIHNldEVycm9yIGlzIG5vdCBhdmFpbGFibGVcclxuICAgICAgICB0b2FzdC5lcnJvcihwcm9jZXNzZWRFcnJvci50aXRsZSB8fCBlcnJvck1lc3NhZ2UuZ2VuZXJhbCk7XHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBbZXJyb3JNZXNzYWdlLmdlbmVyYWwsIGdldEZpZWxkRXJyb3IsIHNldEVycm9yXVxyXG4gICk7XHJcblxyXG4gIHJldHVybiB7XHJcbiAgICBoYW5kbGVTdWNjZXNzLFxyXG4gICAgaGFuZGxlRXJyb3IsXHJcbiAgfTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBDb252ZW5pZW5jZSBob29rIGZvciBkZWxldGUgb3BlcmF0aW9ucyB0aGF0IGRvbid0IG5lZWQgZm9ybSBmaWVsZCB2YWxpZGF0aW9uXHJcbiAqIFVzZXMgdXNlRm9ybUVycm9ySGFuZGxlciBpbnRlcm5hbGx5IGJ1dCB3aXRoIHNpbXBsaWZpZWQgb3B0aW9uc1xyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHVzZURlbGV0ZUhhbmRsZXIgPSAoe1xyXG4gIHN1Y2Nlc3NNZXNzYWdlID0gJ0RlbGV0ZWQgc3VjY2Vzc2Z1bGx5JyxcclxuICBlcnJvck1lc3NhZ2UgPSAnRmFpbGVkIHRvIGRlbGV0ZS4gUGxlYXNlIHRyeSBhZ2Fpbi4nLFxyXG59OiBVc2VEZWxldGVIYW5kbGVyT3B0aW9ucyA9IHt9KTogVXNlRm9ybUVycm9ySGFuZGxlclJldHVybiA9PiB7XHJcbiAgcmV0dXJuIHVzZUZvcm1FcnJvckhhbmRsZXIoe1xyXG4gICAgc3VjY2Vzc01lc3NhZ2U6IHtcclxuICAgICAgY3JlYXRlOiBzdWNjZXNzTWVzc2FnZSwgLy8gTm90IHVzZWQgZm9yIGRlbGV0ZSwgYnV0IHJlcXVpcmVkIGZvciB0eXBlXHJcbiAgICAgIHVwZGF0ZTogc3VjY2Vzc01lc3NhZ2UsXHJcbiAgICB9LFxyXG4gICAgZXJyb3JNZXNzYWdlOiB7XHJcbiAgICAgIG5vQ2hhbmdlczogJ05vIGNoYW5nZXMgd2VyZSBtYWRlJywgLy8gTm90IHR5cGljYWxseSB1c2VkIGZvciBkZWxldGVcclxuICAgICAgZ2VuZXJhbDogZXJyb3JNZXNzYWdlLFxyXG4gICAgfSxcclxuICAgIC8vIHNldEVycm9yIGlzIG9taXR0ZWQgKHVuZGVmaW5lZCkgZm9yIGRlbGV0ZSBvcGVyYXRpb25zXHJcbiAgfSk7XHJcbn07XHJcbiIsICJpbXBvcnQgdHlwZSB7IFF1ZXJ5Q2xpZW50LCBRdWVyeUtleSB9IGZyb20gJ0B0YW5zdGFjay9yZWFjdC1xdWVyeSc7XHJcbmltcG9ydCB7IHVzZVF1ZXJ5Q2xpZW50IH0gZnJvbSAnQHRhbnN0YWNrL3JlYWN0LXF1ZXJ5JztcclxuaW1wb3J0IHsgdXNlTWVtbyB9IGZyb20gJ3JlYWN0JztcclxuXHJcbi8vIE1pbmltYWwgdHlwZS1zYWZlIGNhY2hlIHV0aWxpdHkgZm9yIHF1ZXJ5IGtleSBmYWN0b3JpZXNcclxuZXhwb3J0IGNsYXNzIENhY2hlVXRpbGl0eSB7XHJcbiAgY29uc3RydWN0b3IocHJpdmF0ZSBxdWVyeUNsaWVudDogUXVlcnlDbGllbnQpIHt9XHJcblxyXG4gIC8qKlxyXG4gICAqIEdldCBjYWNoZWQgZGF0YSB1c2luZyBvbmx5IHRoZSBxdWVyeUtleSBmcm9tIHF1ZXJ5IGZhY3RvcnlcclxuICAgKi9cclxuICBnZXRDYWNoZWREYXRhPFQ+KHF1ZXJ5S2V5OiBRdWVyeUtleSk6IFQgfCB1bmRlZmluZWQge1xyXG4gICAgcmV0dXJuIHRoaXMucXVlcnlDbGllbnQuZ2V0UXVlcnlEYXRhPFQ+KHF1ZXJ5S2V5KTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIEdldCBjYWNoZWQgZGF0YSB3aXRoIHRyYW5zZm9ybWF0aW9uIHVzaW5nIHNlbGVjdCBmdW5jdGlvblxyXG4gICAqL1xyXG4gIGdldENhY2hlZERhdGFXaXRoU2VsZWN0PFQsIFI+KFxyXG4gICAgcXVlcnlLZXk6IFF1ZXJ5S2V5LFxyXG4gICAgc2VsZWN0OiAoZGF0YTogVCkgPT4gUlxyXG4gICk6IFIgfCB1bmRlZmluZWQge1xyXG4gICAgY29uc3QgY2FjaGVkRGF0YSA9IHRoaXMucXVlcnlDbGllbnQuZ2V0UXVlcnlEYXRhPFQ+KHF1ZXJ5S2V5KTtcclxuXHJcbiAgICBpZiAoY2FjaGVkRGF0YSA9PT0gdW5kZWZpbmVkKSB7XHJcbiAgICAgIHJldHVybiB1bmRlZmluZWQ7XHJcbiAgICB9XHJcblxyXG4gICAgcmV0dXJuIHNlbGVjdChjYWNoZWREYXRhKTtcclxuICB9XHJcbn1cclxuXHJcbmV4cG9ydCBmdW5jdGlvbiB1c2VDYWNoZVV0aWxpdHkoKTogQ2FjaGVVdGlsaXR5IHtcclxuICBjb25zdCBxdWVyeUNsaWVudCA9IHVzZVF1ZXJ5Q2xpZW50KCk7XHJcblxyXG4gIHJldHVybiB1c2VNZW1vKCgpID0+IG5ldyBDYWNoZVV0aWxpdHkocXVlcnlDbGllbnQpLCBbcXVlcnlDbGllbnRdKTtcclxufVxyXG4iLCAiaW1wb3J0IHR5cGUge1xyXG4gIENvbnRyb2wsXHJcbiAgRGVlcFBhcnRpYWxTa2lwQXJyYXlLZXksXHJcbiAgRmllbGRWYWx1ZXMsXHJcbiAgUGF0aCxcclxuICBQYXRoVmFsdWUsXHJcbn0gZnJvbSAncmVhY3QtaG9vay1mb3JtJztcclxuaW1wb3J0IHsgdXNlV2F0Y2ggfSBmcm9tICdyZWFjdC1ob29rLWZvcm0nO1xyXG5cclxuLyoqXHJcbiAqIENvcmUgd2F0Y2ggZnVuY3Rpb25zIGZvciBSZWFjdCBIb29rIEZvcm1cclxuICogVGhlc2UgYXJlIHRoZSBwcmltYXJ5IGJ1aWxkaW5nIGJsb2NrcyBmb3IgZm9ybSB3YXRjaGluZ1xyXG4gKi9cclxuXHJcbi8qKlxyXG4gKiBVdGlsaXR5IHR5cGUgdG8gZW5zdXJlIGFycmF5IGVsZW1lbnRzIGFyZSBhbGwgUGF0aDxUPlxyXG4gKi9cclxuZXhwb3J0IHR5cGUgUGF0aEFycmF5PFQgZXh0ZW5kcyBGaWVsZFZhbHVlcz4gPSBSZWFkb25seUFycmF5PFBhdGg8VD4+O1xyXG5cclxuLyoqXHJcbiAqIEhvb2sgdG8gd2F0Y2ggZW50aXJlIGZvcm0gLSByZXR1cm5zIGFsbCBmb3JtIHZhbHVlc1xyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHVzZVdhdGNoRm9ybSA9IDxURmllbGRWYWx1ZXMgZXh0ZW5kcyBGaWVsZFZhbHVlcz4oXHJcbiAgY29udHJvbDogQ29udHJvbDxURmllbGRWYWx1ZXM+XHJcbik6IERlZXBQYXJ0aWFsU2tpcEFycmF5S2V5PFRGaWVsZFZhbHVlcz4gPT4gdXNlV2F0Y2goeyBjb250cm9sIH0pO1xyXG5cclxuLyoqXHJcbiAqIEhvb2sgdG8gd2F0Y2ggc2luZ2xlIGZpZWxkIGJ5IHBhdGggLSBzdXBwb3J0cyBhbnkgbmVzdGVkIHBhdGhcclxuICovXHJcbmV4cG9ydCBjb25zdCB1c2VXYXRjaEZpZWxkID0gPFxyXG4gIFRGaWVsZFZhbHVlcyBleHRlbmRzIEZpZWxkVmFsdWVzLFxyXG4gIFROYW1lIGV4dGVuZHMgUGF0aDxURmllbGRWYWx1ZXM+LFxyXG4+KFxyXG4gIGNvbnRyb2w6IENvbnRyb2w8VEZpZWxkVmFsdWVzPixcclxuICBuYW1lOiBUTmFtZVxyXG4pOiBQYXRoVmFsdWU8VEZpZWxkVmFsdWVzLCBUTmFtZT4gPT4gdXNlV2F0Y2goeyBjb250cm9sLCBuYW1lIH0pO1xyXG5cclxuLyoqXHJcbiAqIEhvb2sgdG8gd2F0Y2ggbXVsdGlwbGUgZmllbGRzIGJ5IHBhdGhzIC0gcmV0dXJucyBhcnJheSBvZiB2YWx1ZXNcclxuICovXHJcbmV4cG9ydCBjb25zdCB1c2VXYXRjaEZpZWxkcyA9IDxcclxuICBURmllbGRWYWx1ZXMgZXh0ZW5kcyBGaWVsZFZhbHVlcyxcclxuICBUTmFtZXMgZXh0ZW5kcyBSZWFkb25seUFycmF5PFBhdGg8VEZpZWxkVmFsdWVzPj4sXHJcbj4oXHJcbiAgY29udHJvbDogQ29udHJvbDxURmllbGRWYWx1ZXM+LFxyXG4gIG5hbWVzOiBUTmFtZXNcclxuKTogQXJyYXk8UGF0aFZhbHVlPFRGaWVsZFZhbHVlcywgVE5hbWVzW251bWJlcl0+PiA9PlxyXG4gIHVzZVdhdGNoKHsgY29udHJvbCwgbmFtZTogbmFtZXMgfSkgYXMgQXJyYXk8XHJcbiAgICBQYXRoVmFsdWU8VEZpZWxkVmFsdWVzLCBUTmFtZXNbbnVtYmVyXT5cclxuICA+O1xyXG4iLCAiaW1wb3J0IHsgdXNlRWZmZWN0LCB1c2VNZW1vLCB1c2VTdGF0ZSB9IGZyb20gJ3JlYWN0JztcclxuaW1wb3J0IHR5cGUgeyBDb250cm9sLCBGaWVsZFZhbHVlcywgUGF0aCwgUGF0aFZhbHVlIH0gZnJvbSAncmVhY3QtaG9vay1mb3JtJztcclxuaW1wb3J0IHsgdXNlV2F0Y2ggfSBmcm9tICdyZWFjdC1ob29rLWZvcm0nO1xyXG5cclxuLyoqXHJcbiAqIFV0aWxpdHkgd2F0Y2ggZnVuY3Rpb25zIGZvciBSZWFjdCBIb29rIEZvcm1cclxuICogRW5oYW5jZWQgZnVuY3Rpb25hbGl0eSBmb3Igc3BlY2lmaWMgdXNlIGNhc2VzXHJcbiAqL1xyXG5cclxuLyoqXHJcbiAqIFdhdGNoIGZpZWxkIHdpdGggdHJhbnNmb3JtYXRpb24vc2VsZWN0b3JcclxuICovXHJcbmV4cG9ydCBjb25zdCB1c2VXYXRjaFRyYW5zZm9ybSA9IDxcclxuICBURmllbGRWYWx1ZXMgZXh0ZW5kcyBGaWVsZFZhbHVlcyxcclxuICBUTmFtZSBleHRlbmRzIFBhdGg8VEZpZWxkVmFsdWVzPixcclxuICBUT3V0cHV0LFxyXG4+KFxyXG4gIGNvbnRyb2w6IENvbnRyb2w8VEZpZWxkVmFsdWVzPixcclxuICBuYW1lOiBUTmFtZSxcclxuICB0cmFuc2Zvcm06ICh2YWx1ZTogUGF0aFZhbHVlPFRGaWVsZFZhbHVlcywgVE5hbWU+KSA9PiBUT3V0cHV0XHJcbik6IFRPdXRwdXQgPT4ge1xyXG4gIGNvbnN0IHZhbHVlID0gdXNlV2F0Y2goeyBjb250cm9sLCBuYW1lIH0pO1xyXG5cclxuICByZXR1cm4gdXNlTWVtbygoKSA9PiB0cmFuc2Zvcm0odmFsdWUpLCBbdmFsdWUsIHRyYW5zZm9ybV0pO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIFdhdGNoIGZpZWxkIHdpdGggZGVmYXVsdCBmYWxsYmFjayB2YWx1ZVxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHVzZVdhdGNoRGVmYXVsdCA9IDxcclxuICBURmllbGRWYWx1ZXMgZXh0ZW5kcyBGaWVsZFZhbHVlcyxcclxuICBUTmFtZSBleHRlbmRzIFBhdGg8VEZpZWxkVmFsdWVzPixcclxuPihcclxuICBjb250cm9sOiBDb250cm9sPFRGaWVsZFZhbHVlcz4sXHJcbiAgbmFtZTogVE5hbWUsXHJcbiAgZGVmYXVsdFZhbHVlOiBQYXRoVmFsdWU8VEZpZWxkVmFsdWVzLCBUTmFtZT5cclxuKTogUGF0aFZhbHVlPFRGaWVsZFZhbHVlcywgVE5hbWU+ID0+IHtcclxuICBjb25zdCB2YWx1ZSA9IHVzZVdhdGNoKHsgY29udHJvbCwgbmFtZSB9KTtcclxuXHJcbiAgcmV0dXJuIHZhbHVlID8/IGRlZmF1bHRWYWx1ZTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBXYXRjaCBmaWVsZCBhcyBib29sZWFuIHdpdGggZ3VhcmFudGVlZCBib29sZWFuIHJldHVyblxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHVzZVdhdGNoQm9vbGVhbiA9IDxcclxuICBURmllbGRWYWx1ZXMgZXh0ZW5kcyBGaWVsZFZhbHVlcyxcclxuICBUTmFtZSBleHRlbmRzIFBhdGg8VEZpZWxkVmFsdWVzPixcclxuPihcclxuICBjb250cm9sOiBDb250cm9sPFRGaWVsZFZhbHVlcz4sXHJcbiAgbmFtZTogVE5hbWUsXHJcbiAgZGVmYXVsdFZhbHVlID0gZmFsc2VcclxuKTogYm9vbGVhbiA9PiB7XHJcbiAgY29uc3QgdmFsdWUgPSB1c2VXYXRjaCh7IGNvbnRyb2wsIG5hbWUgfSk7XHJcblxyXG4gIHJldHVybiBCb29sZWFuKHZhbHVlID8/IGRlZmF1bHRWYWx1ZSk7XHJcbn07XHJcblxyXG4vKipcclxuICogV2F0Y2ggbXVsdGlwbGUgZmllbGRzIGFuZCByZXR1cm4gYW4gb2JqZWN0IHdpdGggZmllbGQgcGF0aHMgYXMga2V5c1xyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHVzZVdhdGNoQmF0Y2ggPSA8XHJcbiAgVEZpZWxkVmFsdWVzIGV4dGVuZHMgRmllbGRWYWx1ZXMsXHJcbiAgVEZpZWxkcyBleHRlbmRzIFJlYWRvbmx5QXJyYXk8UGF0aDxURmllbGRWYWx1ZXM+PixcclxuPihcclxuICBjb250cm9sOiBDb250cm9sPFRGaWVsZFZhbHVlcz4sXHJcbiAgZmllbGRzOiBURmllbGRzXHJcbik6IHsgW0sgaW4gVEZpZWxkc1tudW1iZXJdXTogUGF0aFZhbHVlPFRGaWVsZFZhbHVlcywgSz4gfSA9PiB7XHJcbiAgY29uc3QgdmFsdWVzID0gdXNlV2F0Y2goeyBjb250cm9sLCBuYW1lOiBmaWVsZHMgfSk7XHJcblxyXG4gIHJldHVybiB1c2VNZW1vKCgpID0+IHtcclxuICAgIGNvbnN0IHJlc3VsdCA9IHt9IGFzIHsgW0sgaW4gVEZpZWxkc1tudW1iZXJdXTogUGF0aFZhbHVlPFRGaWVsZFZhbHVlcywgSz4gfTtcclxuXHJcbiAgICBmaWVsZHMuZm9yRWFjaCgoZmllbGQsIGluZGV4KSA9PiB7XHJcbiAgICAgIHJlc3VsdFtmaWVsZCBhcyBURmllbGRzW251bWJlcl1dID0gdmFsdWVzW2luZGV4XTtcclxuICAgIH0pO1xyXG5cclxuICAgIHJldHVybiByZXN1bHQ7XHJcbiAgfSwgW3ZhbHVlcywgZmllbGRzXSk7XHJcbn07XHJcblxyXG4vKipcclxuICogV2F0Y2ggZmllbGQgY29uZGl0aW9uYWxseSBiYXNlZCBvbiBib29sZWFuIGZsYWdcclxuICovXHJcbmV4cG9ydCBjb25zdCB1c2VXYXRjaENvbmRpdGlvbmFsID0gPFxyXG4gIFRGaWVsZFZhbHVlcyBleHRlbmRzIEZpZWxkVmFsdWVzLFxyXG4gIFROYW1lIGV4dGVuZHMgUGF0aDxURmllbGRWYWx1ZXM+LFxyXG4+KFxyXG4gIGNvbnRyb2w6IENvbnRyb2w8VEZpZWxkVmFsdWVzPixcclxuICBuYW1lOiBUTmFtZSxcclxuICBzaG91bGRXYXRjaDogYm9vbGVhbixcclxuICBmYWxsYmFjaz86IFBhdGhWYWx1ZTxURmllbGRWYWx1ZXMsIFROYW1lPlxyXG4pOiBQYXRoVmFsdWU8VEZpZWxkVmFsdWVzLCBUTmFtZT4gfCB1bmRlZmluZWQgPT4ge1xyXG4gIGNvbnN0IGFjdGl2ZVZhbHVlID0gdXNlV2F0Y2goe1xyXG4gICAgY29udHJvbCxcclxuICAgIG5hbWUsXHJcbiAgICBkaXNhYmxlZDogIXNob3VsZFdhdGNoLFxyXG4gIH0pO1xyXG5cclxuICByZXR1cm4gc2hvdWxkV2F0Y2ggPyBhY3RpdmVWYWx1ZSA6IGZhbGxiYWNrO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIFdhdGNoIGZpZWxkIHdpdGggZGVib3VuY2VkIHVwZGF0ZXNcclxuICovXHJcbmV4cG9ydCBjb25zdCB1c2VXYXRjaERlYm91bmNlZCA9IDxcclxuICBURmllbGRWYWx1ZXMgZXh0ZW5kcyBGaWVsZFZhbHVlcyxcclxuICBUTmFtZSBleHRlbmRzIFBhdGg8VEZpZWxkVmFsdWVzPixcclxuPihcclxuICBjb250cm9sOiBDb250cm9sPFRGaWVsZFZhbHVlcz4sXHJcbiAgbmFtZTogVE5hbWUsXHJcbiAgZGVsYXkgPSAzMDBcclxuKTogUGF0aFZhbHVlPFRGaWVsZFZhbHVlcywgVE5hbWU+ID0+IHtcclxuICBjb25zdCB2YWx1ZSA9IHVzZVdhdGNoKHsgY29udHJvbCwgbmFtZSB9KTtcclxuICBjb25zdCBbZGVib3VuY2VkVmFsdWUsIHNldERlYm91bmNlZFZhbHVlXSA9XHJcbiAgICB1c2VTdGF0ZTxQYXRoVmFsdWU8VEZpZWxkVmFsdWVzLCBUTmFtZT4+KHZhbHVlKTtcclxuXHJcbiAgdXNlRWZmZWN0KCgpID0+IHtcclxuICAgIGNvbnN0IHRpbWVyID0gc2V0VGltZW91dCgoKSA9PiB7XHJcbiAgICAgIHNldERlYm91bmNlZFZhbHVlKHZhbHVlKTtcclxuICAgIH0sIGRlbGF5KTtcclxuXHJcbiAgICByZXR1cm4gKCkgPT4gY2xlYXJUaW1lb3V0KHRpbWVyKTtcclxuICB9LCBbdmFsdWUsIGRlbGF5XSk7XHJcblxyXG4gIHJldHVybiBkZWJvdW5jZWRWYWx1ZTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBXYXRjaCBmaWVsZCB3aXRoIG1lbW9pemVkIHNlbGVjdG9yIGZ1bmN0aW9uXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgdXNlV2F0Y2hTZWxlY3RvciA9IDxcclxuICBURmllbGRWYWx1ZXMgZXh0ZW5kcyBGaWVsZFZhbHVlcyxcclxuICBUTmFtZSBleHRlbmRzIFBhdGg8VEZpZWxkVmFsdWVzPixcclxuICBUT3V0cHV0LFxyXG4+KFxyXG4gIGNvbnRyb2w6IENvbnRyb2w8VEZpZWxkVmFsdWVzPixcclxuICBuYW1lOiBUTmFtZSxcclxuICBzZWxlY3RvcjogKHZhbHVlOiBQYXRoVmFsdWU8VEZpZWxkVmFsdWVzLCBUTmFtZT4pID0+IFRPdXRwdXQsXHJcbiAgZGVwczogUmVhY3QuRGVwZW5kZW5jeUxpc3QgPSBbXVxyXG4pOiBUT3V0cHV0ID0+IHtcclxuICBjb25zdCB2YWx1ZSA9IHVzZVdhdGNoKHsgY29udHJvbCwgbmFtZSB9KTtcclxuXHJcbiAgcmV0dXJuIHVzZU1lbW8oXHJcbiAgICAoKSA9PiBzZWxlY3Rvcih2YWx1ZSksXHJcbiAgICBbdmFsdWUsIHNlbGVjdG9yLCAuLi5kZXBzXSAvLyBlc2xpbnQtZGlzYWJsZS1saW5lIHJlYWN0LWhvb2tzL2V4aGF1c3RpdmUtZGVwc1xyXG4gICk7XHJcbn07XHJcbiIsICIvKipcclxuICogRW5oYW5jZWQgVHlwZVNjcmlwdCB1dGlsaXRpZXMgZm9yIFJlYWN0IEhvb2sgRm9ybSdzIHVzZVdhdGNoXHJcbiAqXHJcbiAqIFRoaXMgbW9kdWxlIHByb3ZpZGVzIGEgY29tcHJlaGVuc2l2ZSBzZXQgb2YgdHlwZS1zYWZlIHdhdGNoIGZ1bmN0aW9uc1xyXG4gKiB3aXRoIGJldHRlciBlcmdvbm9taWNzIGFuZCBhZGRpdGlvbmFsIGZ1bmN0aW9uYWxpdHkuXHJcbiAqXHJcbiAqIEBleGFtcGxlXHJcbiAqIGBgYHR5cGVzY3JpcHRcclxuICogaW1wb3J0IHsgdXNlV2F0Y2hGaWVsZCwgdXNlV2F0Y2hCb29sZWFuLCB0eXBlZFdhdGNoIH0gZnJvbSAnc3JjL3V0aWxzL3dhdGNoJztcclxuICpcclxuICogLy8gRGlyZWN0IHVzYWdlIChpbnNpZGUgUmVhY3QgY29tcG9uZW50cylcclxuICogY29uc3QgZW1haWwgPSB1c2VXYXRjaEZpZWxkKGNvbnRyb2wsICd1c2VyLmVtYWlsJyk7XHJcbiAqIGNvbnN0IGlzQWRtaW4gPSB1c2VXYXRjaEJvb2xlYW4oY29udHJvbCwgJ3VzZXIuaXNBZG1pbicpO1xyXG4gKlxyXG4gKiAvLyBPYmplY3QtYmFzZWQgdXNhZ2UgKGluc2lkZSBSZWFjdCBjb21wb25lbnRzKVxyXG4gKiBjb25zdCBlbWFpbCA9IHR5cGVkV2F0Y2guZmllbGQoY29udHJvbCwgJ3VzZXIuZW1haWwnKTtcclxuICogY29uc3QgaXNBZG1pbiA9IHR5cGVkV2F0Y2guYm9vbGVhbihjb250cm9sLCAndXNlci5pc0FkbWluJyk7XHJcbiAqIGBgYFxyXG4gKi9cclxuXHJcbi8vIENvcmUgZnVuY3Rpb25zXHJcbmV4cG9ydCB7IHVzZVdhdGNoRmllbGQsIHVzZVdhdGNoRmllbGRzLCB1c2VXYXRjaEZvcm0gfSBmcm9tICcuL2NvcmUnO1xyXG5cclxuLy8gVXRpbGl0eSBmdW5jdGlvbnNcclxuZXhwb3J0IHtcclxuICB1c2VXYXRjaEJhdGNoLFxyXG4gIHVzZVdhdGNoQm9vbGVhbixcclxuICB1c2VXYXRjaENvbmRpdGlvbmFsLFxyXG4gIHVzZVdhdGNoRGVib3VuY2VkLFxyXG4gIHVzZVdhdGNoRGVmYXVsdCxcclxuICB1c2VXYXRjaFNlbGVjdG9yLFxyXG4gIHVzZVdhdGNoVHJhbnNmb3JtLFxyXG59IGZyb20gJy4vdXRpbGl0aWVzJztcclxuXHJcbmV4cG9ydCB0eXBlIHsgUGF0aEFycmF5IH0gZnJvbSAnLi9jb3JlJztcclxuXHJcbi8vIEltcG9ydCBhbGwgZnVuY3Rpb25zIGZvciBkZWZhdWx0IGV4cG9ydFxyXG5pbXBvcnQgeyB1c2VXYXRjaEZpZWxkLCB1c2VXYXRjaEZpZWxkcywgdXNlV2F0Y2hGb3JtIH0gZnJvbSAnLi9jb3JlJztcclxuaW1wb3J0IHtcclxuICB1c2VXYXRjaEJhdGNoLFxyXG4gIHVzZVdhdGNoQm9vbGVhbixcclxuICB1c2VXYXRjaENvbmRpdGlvbmFsLFxyXG4gIHVzZVdhdGNoRGVib3VuY2VkLFxyXG4gIHVzZVdhdGNoRGVmYXVsdCxcclxuICB1c2VXYXRjaFNlbGVjdG9yLFxyXG4gIHVzZVdhdGNoVHJhbnNmb3JtLFxyXG59IGZyb20gJy4vdXRpbGl0aWVzJztcclxuXHJcbi8qKlxyXG4gKiBPcmdhbml6ZWQgdXRpbGl0aWVzIGJ5IHVzZSBjYXNlXHJcbiAqIFByb3ZpZGVzIGEgY29udmVuaWVudCBvYmplY3QtYmFzZWQgQVBJIGZvciBhbGwgd2F0Y2ggZnVuY3Rpb25zXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgdHlwZWRXYXRjaCA9IHtcclxuICAvLyA9PT0gQ09SRSBGVU5DVElPTlMgPT09XHJcbiAgLyoqIFdhdGNoIGVudGlyZSBmb3JtICovXHJcbiAgZm9ybTogdXNlV2F0Y2hGb3JtLFxyXG4gIC8qKiBXYXRjaCBzaW5nbGUgZmllbGQgKi9cclxuICBmaWVsZDogdXNlV2F0Y2hGaWVsZCxcclxuICAvKiogV2F0Y2ggbXVsdGlwbGUgZmllbGRzICovXHJcbiAgZmllbGRzOiB1c2VXYXRjaEZpZWxkcyxcclxuXHJcbiAgLy8gPT09IFVUSUxJVFkgRlVOQ1RJT05TID09PVxyXG4gIC8qKiBXYXRjaCB3aXRoIHRyYW5zZm9ybWF0aW9uICovXHJcbiAgdHJhbnNmb3JtOiB1c2VXYXRjaFRyYW5zZm9ybSxcclxuICAvKiogV2F0Y2ggd2l0aCBkZWZhdWx0IHZhbHVlICovXHJcbiAgd2l0aERlZmF1bHQ6IHVzZVdhdGNoRGVmYXVsdCxcclxuICAvKiogV2F0Y2ggYXMgYm9vbGVhbiAqL1xyXG4gIGJvb2xlYW46IHVzZVdhdGNoQm9vbGVhbixcclxuICAvKiogV2F0Y2ggbXVsdGlwbGUgd2l0aCBjdXN0b20ga2V5cyAqL1xyXG4gIGJhdGNoOiB1c2VXYXRjaEJhdGNoLFxyXG4gIC8qKiBXYXRjaCBjb25kaXRpb25hbGx5ICovXHJcbiAgY29uZGl0aW9uYWw6IHVzZVdhdGNoQ29uZGl0aW9uYWwsXHJcbiAgLyoqIFdhdGNoIHdpdGggZGVib3VuY2luZyAqL1xyXG4gIGRlYm91bmNlZDogdXNlV2F0Y2hEZWJvdW5jZWQsXHJcbiAgLyoqIFdhdGNoIHdpdGggc2VsZWN0b3IgKi9cclxuICBzZWxlY3RvcjogdXNlV2F0Y2hTZWxlY3RvcixcclxufSBhcyBjb25zdDtcclxuIiwgImV4cG9ydCBjb25zdCBjYWxjdWxhdGVGaWx0ZXJDb3VudCA9IChtb2RlbDogb2JqZWN0KTogbnVtYmVyID0+XHJcbiAgT2JqZWN0LnZhbHVlcyhtb2RlbCkuZmlsdGVyKFxyXG4gICAgdiA9PiB2ICE9PSBudWxsICYmIHYgIT09IHVuZGVmaW5lZCAmJiBTdHJpbmcodikudHJpbSgpICE9PSAnJ1xyXG4gICkubGVuZ3RoO1xyXG4iLCAiaW1wb3J0IHR5cGUgeyBEYXlqcywgT3BVbml0VHlwZSB9IGZyb20gJ2RheWpzJztcclxuaW1wb3J0IGRheWpzIGZyb20gJ2RheWpzJztcclxuaW1wb3J0IGR1cmF0aW9uIGZyb20gJ2RheWpzL3BsdWdpbi9kdXJhdGlvbic7XHJcbmltcG9ydCByZWxhdGl2ZVRpbWUgZnJvbSAnZGF5anMvcGx1Z2luL3JlbGF0aXZlVGltZSc7XHJcblxyXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXHJcblxyXG4vKipcclxuICogQERvY3NcclxuICogaHR0cHM6Ly9kYXkuanMub3JnL2RvY3MvZW4vZGlzcGxheS9mb3JtYXRcclxuICovXHJcblxyXG4vKipcclxuICogRGVmYXVsdCB0aW1lem9uZXNcclxuICogaHR0cHM6Ly9kYXkuanMub3JnL2RvY3MvZW4vdGltZXpvbmUvc2V0LWRlZmF1bHQtdGltZXpvbmUjZG9jc05hdlxyXG4gKlxyXG4gKi9cclxuXHJcbi8qKlxyXG4gKiBVVENcclxuICogaHR0cHM6Ly9kYXkuanMub3JnL2RvY3MvZW4vcGx1Z2luL3V0Y1xyXG4gKiBAaW5zdGFsbFxyXG4gKiBpbXBvcnQgdXRjIGZyb20gJ2RheWpzL3BsdWdpbi91dGMnO1xyXG4gKiBkYXlqcy5leHRlbmQodXRjKTtcclxuICogQHVzYWdlXHJcbiAqIGRheWpzKCkudXRjKCkuZm9ybWF0KClcclxuICpcclxuICovXHJcblxyXG5kYXlqcy5leHRlbmQoZHVyYXRpb24pO1xyXG5kYXlqcy5leHRlbmQocmVsYXRpdmVUaW1lKTtcclxuXHJcbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuXHJcbmV4cG9ydCB0eXBlIERhdGVQaWNrZXJGb3JtYXQgPVxyXG4gIHwgRGF5anNcclxuICB8IERhdGVcclxuICB8IHN0cmluZ1xyXG4gIHwgbnVtYmVyXHJcbiAgfCBudWxsXHJcbiAgfCB1bmRlZmluZWQ7XHJcblxyXG5leHBvcnQgY29uc3QgZm9ybWF0UGF0dGVybnMgPSB7XHJcbiAgZGF0ZVRpbWU6ICdERCBNTU0gWVlZWSBoOm1tIEEnLCAvLyAxNyBBcHIgMjAyMiAxMjowMCBhbVxyXG4gIGRhdGU6ICdERCBNTU0gWVlZWScsIC8vIDE3IEFwciAyMDIyXHJcbiAgbW9udGhfeWVhcl9zaG9ydF9mb3JtYXQ6ICdNTU0gWVlZWScsXHJcbiAgbW9udGhfeWVhcl9mdWxsX2Zvcm1hdDogJ01NTU0gWVlZWScsXHJcbiAgeWVhcjogJ1lZWVknLFxyXG4gIHRpbWU6ICdoOm1tIGEnLCAvLyAxMjowMCBhbVxyXG4gIHNwbGl0OiB7XHJcbiAgICBkYXRlVGltZTogJ0REL01NL1lZWVkgaDptbSBBJywgLy8gMTcvMDQvMjAyMiAxMjowMCBhbVxyXG4gICAgZGF0ZTogJ0REL01NL1lZWVknLCAvLyAxNy8wNC8yMDIyXHJcbiAgfSxcclxuICBwYXJhbUNhc2U6IHtcclxuICAgIGRhdGVUaW1lOiAnREQtTU0tWVlZWSBoOm1tIEEnLCAvLyAxNy0wNC0yMDIyIDEyOjAwIGFtXHJcbiAgICBkYXRlOiAnREQtTU0tWVlZWScsIC8vIDE3LTA0LTIwMjJcclxuICAgIGRhdGVSZXZlcnNlOiAnWVlZWS1NTS1ERCcsIC8vIDIwMjItMDQtMTcgZm9yIGNvbXBhcmUgZGF0ZVxyXG4gICAgTW9udGhZZWFyOiAnTU1NLVlZWVknLFxyXG4gIH0sXHJcbn07XHJcblxyXG5jb25zdCBpc1ZhbGlkRGF0ZSA9IChkYXRlOiBEYXRlUGlja2VyRm9ybWF0KSA9PlxyXG4gIGRhdGUgIT09IG51bGwgJiYgZGF0ZSAhPT0gdW5kZWZpbmVkICYmIGRheWpzKGRhdGUpLmlzVmFsaWQoKTtcclxuXHJcbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuXHJcbmV4cG9ydCBmdW5jdGlvbiB0b2RheSh0ZW1wbGF0ZT86IHN0cmluZyk6IHN0cmluZyB7XHJcbiAgcmV0dXJuIGRheWpzKG5ldyBEYXRlKCkpLnN0YXJ0T2YoJ2RheScpLmZvcm1hdCh0ZW1wbGF0ZSk7XHJcbn1cclxuXHJcbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuXHJcbi8qKlxyXG4gKiBAb3V0cHV0IDE3IEFwciAyMDIyIDEyOjAwIGFtXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZkRhdGVUaW1lKGRhdGU6IERhdGVQaWNrZXJGb3JtYXQsIHRlbXBsYXRlPzogc3RyaW5nKTogc3RyaW5nIHtcclxuICBpZiAoIWlzVmFsaWREYXRlKGRhdGUpKSB7XHJcbiAgICByZXR1cm4gJ0ludmFsaWQgZGF0ZSc7XHJcbiAgfVxyXG5cclxuICByZXR1cm4gZGF5anMoZGF0ZSkuZm9ybWF0KHRlbXBsYXRlID8/IGZvcm1hdFBhdHRlcm5zLmRhdGVUaW1lKTtcclxufVxyXG5cclxuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG5cclxuLyoqXHJcbiAqIEBvdXRwdXQgMTcgQXByIDIwMjJcclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBmRGF0ZShkYXRlOiBEYXRlUGlja2VyRm9ybWF0LCB0ZW1wbGF0ZT86IHN0cmluZyk6IHN0cmluZyB7XHJcbiAgaWYgKCFpc1ZhbGlkRGF0ZShkYXRlKSkge1xyXG4gICAgcmV0dXJuICdJbnZhbGlkIGRhdGUnO1xyXG4gIH1cclxuXHJcbiAgcmV0dXJuIGRheWpzKGRhdGUpLmZvcm1hdCh0ZW1wbGF0ZSA/PyBmb3JtYXRQYXR0ZXJucy5kYXRlKTtcclxufVxyXG5cclxuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG5cclxuLyoqXHJcbiAqIEBvdXRwdXQgMTI6MDAgYW1cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBmVGltZShkYXRlOiBEYXRlUGlja2VyRm9ybWF0LCB0ZW1wbGF0ZT86IHN0cmluZyk6IHN0cmluZyB7XHJcbiAgaWYgKCFpc1ZhbGlkRGF0ZShkYXRlKSkge1xyXG4gICAgcmV0dXJuICdJbnZhbGlkIGRhdGUnO1xyXG4gIH1cclxuXHJcbiAgcmV0dXJuIGRheWpzKGRhdGUpLmZvcm1hdCh0ZW1wbGF0ZSA/PyBmb3JtYXRQYXR0ZXJucy50aW1lKTtcclxufVxyXG5cclxuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG5cclxuLyoqXHJcbiAqIEBvdXRwdXQgMTcxMzI1MDEwMFxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGZUaW1lc3RhbXAoZGF0ZTogRGF0ZVBpY2tlckZvcm1hdCk6IG51bWJlciB8ICdJbnZhbGlkIGRhdGUnIHtcclxuICBpZiAoIWlzVmFsaWREYXRlKGRhdGUpKSB7XHJcbiAgICByZXR1cm4gJ0ludmFsaWQgZGF0ZSc7XHJcbiAgfVxyXG5cclxuICByZXR1cm4gZGF5anMoZGF0ZSkudmFsdWVPZigpO1xyXG59XHJcblxyXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXHJcblxyXG4vKipcclxuICogQG91dHB1dCBhIGZldyBzZWNvbmRzLCAyIHllYXJzXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZlRvTm93KGRhdGU6IERhdGVQaWNrZXJGb3JtYXQpOiBzdHJpbmcge1xyXG4gIGlmICghaXNWYWxpZERhdGUoZGF0ZSkpIHtcclxuICAgIHJldHVybiAnSW52YWxpZCBkYXRlJztcclxuICB9XHJcblxyXG4gIHJldHVybiBkYXlqcyhkYXRlKS50b05vdyh0cnVlKTtcclxufVxyXG5cclxuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG5cclxuLyoqXHJcbiAqIEBvdXRwdXQgYm9vbGVhblxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGZJc0JldHdlZW4oXHJcbiAgaW5wdXREYXRlOiBEYXRlUGlja2VyRm9ybWF0LFxyXG4gIHN0YXJ0RGF0ZTogRGF0ZVBpY2tlckZvcm1hdCxcclxuICBlbmREYXRlOiBEYXRlUGlja2VyRm9ybWF0XHJcbik6IGJvb2xlYW4ge1xyXG4gIGlmIChcclxuICAgICFpc1ZhbGlkRGF0ZShpbnB1dERhdGUpIHx8XHJcbiAgICAhaXNWYWxpZERhdGUoc3RhcnREYXRlKSB8fFxyXG4gICAgIWlzVmFsaWREYXRlKGVuZERhdGUpXHJcbiAgKSB7XHJcbiAgICByZXR1cm4gZmFsc2U7XHJcbiAgfVxyXG5cclxuICBjb25zdCBmb3JtYXR0ZWRJbnB1dERhdGUgPSBmVGltZXN0YW1wKGlucHV0RGF0ZSk7XHJcbiAgY29uc3QgZm9ybWF0dGVkU3RhcnREYXRlID0gZlRpbWVzdGFtcChzdGFydERhdGUpO1xyXG4gIGNvbnN0IGZvcm1hdHRlZEVuZERhdGUgPSBmVGltZXN0YW1wKGVuZERhdGUpO1xyXG5cclxuICBpZiAoXHJcbiAgICBmb3JtYXR0ZWRJbnB1dERhdGUgPT09ICdJbnZhbGlkIGRhdGUnIHx8XHJcbiAgICBmb3JtYXR0ZWRTdGFydERhdGUgPT09ICdJbnZhbGlkIGRhdGUnIHx8XHJcbiAgICBmb3JtYXR0ZWRFbmREYXRlID09PSAnSW52YWxpZCBkYXRlJ1xyXG4gICkge1xyXG4gICAgcmV0dXJuIGZhbHNlO1xyXG4gIH1cclxuXHJcbiAgcmV0dXJuIChcclxuICAgIGZvcm1hdHRlZElucHV0RGF0ZSA+PSBmb3JtYXR0ZWRTdGFydERhdGUgJiZcclxuICAgIGZvcm1hdHRlZElucHV0RGF0ZSA8PSBmb3JtYXR0ZWRFbmREYXRlXHJcbiAgKTtcclxufVxyXG5cclxuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG5cclxuLyoqXHJcbiAqIEBvdXRwdXQgYm9vbGVhblxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGZJc0FmdGVyKFxyXG4gIHN0YXJ0RGF0ZTogRGF0ZVBpY2tlckZvcm1hdCxcclxuICBlbmREYXRlOiBEYXRlUGlja2VyRm9ybWF0XHJcbik6IGJvb2xlYW4ge1xyXG4gIGlmICghaXNWYWxpZERhdGUoc3RhcnREYXRlKSB8fCAhaXNWYWxpZERhdGUoZW5kRGF0ZSkpIHtcclxuICAgIHJldHVybiBmYWxzZTtcclxuICB9XHJcblxyXG4gIHJldHVybiBkYXlqcyhzdGFydERhdGUpLmlzQWZ0ZXIoZW5kRGF0ZSk7XHJcbn1cclxuXHJcbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuXHJcbi8qKlxyXG4gKiBAb3V0cHV0IGJvb2xlYW5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBmSXNTYW1lKFxyXG4gIHN0YXJ0RGF0ZTogRGF0ZVBpY2tlckZvcm1hdCxcclxuICBlbmREYXRlOiBEYXRlUGlja2VyRm9ybWF0LFxyXG4gIHVuaXRUb0NvbXBhcmU/OiBPcFVuaXRUeXBlXHJcbik6IGJvb2xlYW4ge1xyXG4gIGlmICghaXNWYWxpZERhdGUoc3RhcnREYXRlKSB8fCAhaXNWYWxpZERhdGUoZW5kRGF0ZSkpIHtcclxuICAgIHJldHVybiBmYWxzZTtcclxuICB9XHJcblxyXG4gIHJldHVybiBkYXlqcyhzdGFydERhdGUpLmlzU2FtZShlbmREYXRlLCB1bml0VG9Db21wYXJlID8/ICd5ZWFyJyk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBAb3V0cHV0XHJcbiAqIFNhbWUgZGF5OiAyNiBBcHIgMjAyNFxyXG4gKiBTYW1lIG1vbnRoOiAyNSAtIDI2IEFwciAyMDI0XHJcbiAqIFNhbWUgbW9udGg6IDI1IC0gMjYgQXByIDIwMjRcclxuICogU2FtZSB5ZWFyOiAyNSBBcHIgLSAyNiBNYXkgMjAyNFxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGZEYXRlUmFuZ2VTaG9ydExhYmVsKFxyXG4gIHN0YXJ0RGF0ZTogRGF0ZVBpY2tlckZvcm1hdCxcclxuICBlbmREYXRlOiBEYXRlUGlja2VyRm9ybWF0LFxyXG4gIGluaXRpYWw/OiBib29sZWFuXHJcbik6IHN0cmluZyB7XHJcbiAgaWYgKFxyXG4gICAgIWlzVmFsaWREYXRlKHN0YXJ0RGF0ZSkgfHxcclxuICAgICFpc1ZhbGlkRGF0ZShlbmREYXRlKSB8fFxyXG4gICAgZklzQWZ0ZXIoc3RhcnREYXRlLCBlbmREYXRlKVxyXG4gICkge1xyXG4gICAgcmV0dXJuICdJbnZhbGlkIGRhdGUnO1xyXG4gIH1cclxuXHJcbiAgbGV0IGxhYmVsID0gYCR7ZkRhdGUoc3RhcnREYXRlKX0gLSAke2ZEYXRlKGVuZERhdGUpfWA7XHJcblxyXG4gIGlmIChpbml0aWFsKSB7XHJcbiAgICByZXR1cm4gbGFiZWw7XHJcbiAgfVxyXG5cclxuICBjb25zdCBpc1NhbWVZZWFyID0gZklzU2FtZShzdGFydERhdGUsIGVuZERhdGUsICd5ZWFyJyk7XHJcbiAgY29uc3QgaXNTYW1lTW9udGggPSBmSXNTYW1lKHN0YXJ0RGF0ZSwgZW5kRGF0ZSwgJ21vbnRoJyk7XHJcbiAgY29uc3QgaXNTYW1lRGF5ID0gZklzU2FtZShzdGFydERhdGUsIGVuZERhdGUsICdkYXknKTtcclxuXHJcbiAgaWYgKGlzU2FtZVllYXIgJiYgIWlzU2FtZU1vbnRoKSB7XHJcbiAgICBsYWJlbCA9IGAke2ZEYXRlKHN0YXJ0RGF0ZSwgJ0REIE1NTScpfSAtICR7ZkRhdGUoZW5kRGF0ZSl9YDtcclxuICB9IGVsc2UgaWYgKGlzU2FtZVllYXIgJiYgaXNTYW1lTW9udGggJiYgIWlzU2FtZURheSkge1xyXG4gICAgbGFiZWwgPSBgJHtmRGF0ZShzdGFydERhdGUsICdERCcpfSAtICR7ZkRhdGUoZW5kRGF0ZSl9YDtcclxuICB9IGVsc2UgaWYgKGlzU2FtZVllYXIgJiYgaXNTYW1lTW9udGggJiYgaXNTYW1lRGF5KSB7XHJcbiAgICBsYWJlbCA9IGAke2ZEYXRlKGVuZERhdGUpfWA7XHJcbiAgfVxyXG5cclxuICByZXR1cm4gbGFiZWw7XHJcbn1cclxuXHJcbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuXHJcbi8qKlxyXG4gKiBAb3V0cHV0IDIwMjQtMDUtMjhUMDU6NTU6MzErMDA6MDBcclxuICovXHJcbmV4cG9ydCBpbnRlcmZhY2UgRHVyYXRpb25Qcm9wcyB7XHJcbiAgeWVhcnM/OiBudW1iZXI7XHJcbiAgbW9udGhzPzogbnVtYmVyO1xyXG4gIGRheXM/OiBudW1iZXI7XHJcbiAgaG91cnM/OiBudW1iZXI7XHJcbiAgbWludXRlcz86IG51bWJlcjtcclxuICBzZWNvbmRzPzogbnVtYmVyO1xyXG4gIG1pbGxpc2Vjb25kcz86IG51bWJlcjtcclxufVxyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIGZBZGQoe1xyXG4gIHllYXJzID0gMCxcclxuICBtb250aHMgPSAwLFxyXG4gIGRheXMgPSAwLFxyXG4gIGhvdXJzID0gMCxcclxuICBtaW51dGVzID0gMCxcclxuICBzZWNvbmRzID0gMCxcclxuICBtaWxsaXNlY29uZHMgPSAwLFxyXG59OiBEdXJhdGlvblByb3BzKSB7XHJcbiAgY29uc3QgcmVzdWx0ID0gZGF5anMoKVxyXG4gICAgLmFkZChcclxuICAgICAgZGF5anMuZHVyYXRpb24oe1xyXG4gICAgICAgIHllYXJzLFxyXG4gICAgICAgIG1vbnRocyxcclxuICAgICAgICBkYXlzLFxyXG4gICAgICAgIGhvdXJzLFxyXG4gICAgICAgIG1pbnV0ZXMsXHJcbiAgICAgICAgc2Vjb25kcyxcclxuICAgICAgICBtaWxsaXNlY29uZHMsXHJcbiAgICAgIH0pXHJcbiAgICApXHJcbiAgICAuZm9ybWF0KCk7XHJcblxyXG4gIHJldHVybiByZXN1bHQ7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBAb3V0cHV0IDIwMjQtMDUtMjhUMDU6NTU6MzErMDA6MDBcclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBmU3ViKHtcclxuICB5ZWFycyA9IDAsXHJcbiAgbW9udGhzID0gMCxcclxuICBkYXlzID0gMCxcclxuICBob3VycyA9IDAsXHJcbiAgbWludXRlcyA9IDAsXHJcbiAgc2Vjb25kcyA9IDAsXHJcbiAgbWlsbGlzZWNvbmRzID0gMCxcclxufTogRHVyYXRpb25Qcm9wcykge1xyXG4gIGNvbnN0IHJlc3VsdCA9IGRheWpzKClcclxuICAgIC5zdWJ0cmFjdChcclxuICAgICAgZGF5anMuZHVyYXRpb24oe1xyXG4gICAgICAgIHllYXJzLFxyXG4gICAgICAgIG1vbnRocyxcclxuICAgICAgICBkYXlzLFxyXG4gICAgICAgIGhvdXJzLFxyXG4gICAgICAgIG1pbnV0ZXMsXHJcbiAgICAgICAgc2Vjb25kcyxcclxuICAgICAgICBtaWxsaXNlY29uZHMsXHJcbiAgICAgIH0pXHJcbiAgICApXHJcbiAgICAuZm9ybWF0KCk7XHJcblxyXG4gIHJldHVybiByZXN1bHQ7XHJcbn1cclxuIiwgInR5cGUgRW1wdHlWYWx1ZTxUPiA9IFQgZXh0ZW5kcyBudW1iZXJcclxuICA/IDBcclxuICA6IFQgZXh0ZW5kcyBzdHJpbmdcclxuICAgID8gbnVsbFxyXG4gICAgOiBUIGV4dGVuZHMgYm9vbGVhblxyXG4gICAgICA/IG51bGxcclxuICAgICAgOiBUIGV4dGVuZHMgRGF0ZVxyXG4gICAgICAgID8gbnVsbFxyXG4gICAgICAgIDogVCBleHRlbmRzIG9iamVjdFxyXG4gICAgICAgICAgPyBudWxsXHJcbiAgICAgICAgICA6IG51bGw7XHJcblxyXG50eXBlIEVtcHR5T2JqZWN0PFQgZXh0ZW5kcyBvYmplY3Q+ID0ge1xyXG4gIFtLIGluIGtleW9mIFRdOiBFbXB0eVZhbHVlPFRbS10+O1xyXG59O1xyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIGdldEVtcHR5T2JqZWN0PFQgZXh0ZW5kcyBvYmplY3Q+KFxyXG4gIGRhdGE6IFQsXHJcbiAgZGVmYXVsdFZhbHVlczogUGFydGlhbDxUPiA9IHt9XHJcbik6IEVtcHR5T2JqZWN0PFQ+ICYgUGFydGlhbDxUPiB7XHJcbiAgY29uc3Qgb2JqID0ge30gYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj47XHJcblxyXG4gIGZvciAoY29uc3Qga2V5IG9mIE9iamVjdC5rZXlzKGRhdGEpIGFzIEFycmF5PGtleW9mIFQ+KSB7XHJcbiAgICBjb25zdCB2YWx1ZSA9IGRhdGFba2V5XTtcclxuICAgIGNvbnN0IHR5cGUgPSB0eXBlb2YgdmFsdWU7XHJcblxyXG4gICAgaWYgKHR5cGUgPT09ICdudW1iZXInKSB7XHJcbiAgICAgIG9ialtrZXkgYXMgc3RyaW5nXSA9IDA7XHJcbiAgICB9IGVsc2UgaWYgKHR5cGUgPT09ICdzdHJpbmcnIHx8IHR5cGUgPT09ICdib29sZWFuJykge1xyXG4gICAgICBvYmpba2V5IGFzIHN0cmluZ10gPSBudWxsO1xyXG4gICAgfSBlbHNlIGlmICh2YWx1ZSBpbnN0YW5jZW9mIERhdGUpIHtcclxuICAgICAgb2JqW2tleSBhcyBzdHJpbmddID0gbnVsbDtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIG9ialtrZXkgYXMgc3RyaW5nXSA9IG51bGw7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICByZXR1cm4geyAuLi5vYmosIC4uLmRlZmF1bHRWYWx1ZXMgfSBhcyBFbXB0eU9iamVjdDxUPiAmIFBhcnRpYWw8VD47XHJcbn1cclxuIiwgImltcG9ydCB7IHVzZVJlZiwgdXNlTWVtbyB9IGZyb20gJ3JlYWN0JztcclxuXHJcbi8qKlxyXG4gKiBIb29rIHRvIG1haW50YWluIHN0YWJsZSByb3cgY291bnQgZm9yIGRhdGEgZ3JpZHMgZHVyaW5nIGxvYWRpbmcgc3RhdGVzLlxyXG4gKiBQcmV2ZW50cyBwYWdpbmF0aW9uIGp1bXBpbmcgYnkgcHJlc2VydmluZyB0aGUgbGFzdCBrbm93biB0b3RhbCBjb3VudC5cclxuICpcclxuICogQHBhcmFtIGN1cnJlbnRUb3RhbCAtIEN1cnJlbnQgdG90YWwgZnJvbSBBUEkgcmVzcG9uc2VcclxuICogQHJldHVybnMgU3RhYmxlIHJvdyBjb3VudCB0aGF0IHBlcnNpc3RzIGR1cmluZyBsb2FkaW5nXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gdXNlU3RhYmxlUm93Q291bnQoY3VycmVudFRvdGFsOiBudW1iZXIgfCB1bmRlZmluZWQpOiBudW1iZXIge1xyXG4gIGNvbnN0IHJvd0NvdW50UmVmID0gdXNlUmVmKGN1cnJlbnRUb3RhbCB8fCAwKTtcclxuXHJcbiAgY29uc3Qgc3RhYmxlUm93Q291bnQgPSB1c2VNZW1vKCgpID0+IHtcclxuICAgIGlmIChjdXJyZW50VG90YWwgIT09IHVuZGVmaW5lZCkge1xyXG4gICAgICByb3dDb3VudFJlZi5jdXJyZW50ID0gY3VycmVudFRvdGFsO1xyXG4gICAgfVxyXG5cclxuICAgIHJldHVybiByb3dDb3VudFJlZi5jdXJyZW50O1xyXG4gIH0sIFtjdXJyZW50VG90YWxdKTtcclxuXHJcbiAgcmV0dXJuIHN0YWJsZVJvd0NvdW50O1xyXG59XHJcbiJdLAogICJtYXBwaW5ncyI6ICI7QUF3QkEsU0FBUyxlQUF1QjtBQUM5QixNQUFJLE9BQU8sV0FBVyxlQUFlLE9BQU8sWUFBWTtBQUN0RCxXQUFPLE9BQU8sV0FBVztBQUFBLEVBQzNCO0FBR0EsU0FBTyx1Q0FBdUMsUUFBUSxTQUFTLE9BQUs7QUFDbEUsVUFBTSxJQUFLLEtBQUssT0FBTyxJQUFJLEtBQU07QUFDakMsVUFBTSxJQUFJLE1BQU0sTUFBTSxJQUFLLElBQUksSUFBTztBQUV0QyxXQUFPLEVBQUUsU0FBUyxFQUFFO0FBQUEsRUFDdEIsQ0FBQztBQUNIO0FBNENPLFNBQVMsc0JBQXNCLFFBQXlCO0FBQzdELFFBQU0sT0FBTyxhQUFhO0FBRTFCLFNBQU8sU0FBUyxHQUFHLE1BQU0sSUFBSSxJQUFJLEtBQUs7QUFDeEM7OztBQ2pFTyxJQUFNLGtCQUFOLE1BQXNCO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBLEVBcUIzQixhQUFhLFFBQThCO0FBQ3pDLFFBQUksVUFBVSxPQUFPLFNBQVMsS0FBSztBQUNqQyxhQUFPLFdBQVcsTUFBTSxxQkFBcUI7QUFBQSxJQUMvQyxXQUFXLFVBQVUsS0FBSztBQUN4QixhQUFPO0FBQUEsSUFDVDtBQUVBLFdBQU87QUFBQSxFQUNUO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQSxFQWtCQSxjQUFjLFFBQXdCO0FBQ3BDLFVBQU0sU0FBaUM7QUFBQSxNQUNyQyxLQUFLO0FBQUEsTUFDTCxLQUFLO0FBQUEsTUFDTCxLQUFLO0FBQUEsTUFDTCxLQUFLO0FBQUEsTUFDTCxLQUFLO0FBQUEsTUFD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QSxNQUNBO0FBQUEsTUFDQTtBQUFBLE1BQ0E7QUFBQSxNQUNBO0FBQUEsSUFDRixDQUFDO0FBQUEsRUFDSCxFQUNDLE9BQU87QUFFVixTQUFPO0FBQ1Q7OztBQ3pTTyxTQUFTLGVBQ2QsTUFDQSxnQkFBNEIsQ0FBQyxHQUNBO0FBQzdCLFFBQU0sTUFBTSxDQUFDO0FBRWIsYUFBVyxPQUFPLE9BQU8sS0FBSyxJQUFJLEdBQXFCO0FBQ3JELFVBQU0sUUFBUSxLQUFLLEdBQUc7QUFDdEIsVUFBTSxPQUFPLE9BQU87QUFFcEIsUUFBSSxTQUFTLFVBQVU7QUFDckIsVUFBSSxHQUFhLElBQUk7QUFBQSxJQUN2QixXQUFXLFNBQVMsWUFBWSxTQUFTLFdBQVc7QUFDbEQsVUFBSSxHQUFhLElBQUk7QUFBQSxJQUN2QixXQUFXLGlCQUFpQixNQUFNO0FBQ2hDLFVBQUksR0FBYSxJQUFJO0FBQUEsSUFDdkIsT0FBTztBQUNMLFVBQUksR0FBYSxJQUFJO0FBQUEsSUFDdkI7QUFBQSxFQUNGO0FBRUEsU0FBTyxFQUFFLEdBQUcsS0FBSyxHQUFHLGNBQWM7QUFDcEM7OztBQ3RDQSxTQUFTLFFBQVEsV0FBQUcsZ0JBQWU7QUFTekIsU0FBUyxrQkFBa0IsY0FBMEM7QUFDMUUsUUFBTSxjQUFjLE9BQU8sZ0JBQWdCLENBQUM7QUFFNUMsUUFBTSxpQkFBaUJBLFNBQVEsTUFBTTtBQUNuQyxRQUFJLGlCQUFpQixRQUFXO0FBQzlCLGtCQUFZLFVBQVU7QUFBQSxJQUN4QjtBQUVBLFdBQU8sWUFBWTtBQUFBLEVBQ3JCLEdBQUcsQ0FBQyxZQUFZLENBQUM7QUFFakIsU0FBTztBQUNUOyIsCiAgIm5hbWVzIjogWyJjb25maWciLCAianN4IiwgIkJ1dHRvbiIsICJqc3giLCAianN4IiwgImpzeCIsICJqc3giLCAibWVtbyIsICJqc3giLCAibWVtbyIsICJCb3giLCAiQ2FyZCIsICJDYXJkQ29udGVudCIsICJUeXBvZ3JhcGh5IiwgIkZyYWdtZW50IiwgImpzeCIsICJqc3hzIiwgIkJveCIsICJUeXBvZ3JhcGh5IiwgImpzeCIsICJHcmlkIiwgIlR5cG9ncmFwaHkiLCAianN4IiwgImpzeHMiLCAiRnJhZ21lbnQiLCAianN4IiwgIkJveCIsICJEaXZpZGVyIiwgIkdyaWQiLCAiVHlwb2dyYXBoeSIsICJtZW1vIiwgInVzZU1lbW8iLCAiRnJhZ21lbnQiLCAianN4IiwgImpzeHMiLCAiQm94IiwgImpzeCIsICJqc3hzIiwgIkxvYWRpbmdCdXR0b24iLCAianN4IiwgInVzZU1lbW8iLCAidXNlTWVtbyIsICJ1c2VDYWxsYmFjayIsICJ1c2VNZW1vIiwgInVzZU1lbW8iLCAidXNlU3RhdGUiLCAidXNlV2F0Y2giLCAidXNlTWVtbyJdCn0K
|