@decaf-ts/logging 0.3.27 → 0.3.28

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/README.md +1 -1
  2. package/dist/logging.cjs +2 -2086
  3. package/dist/logging.cjs.map +1 -0
  4. package/dist/logging.js +2 -0
  5. package/dist/logging.js.map +1 -0
  6. package/lib/LoggedClass.cjs +1 -1
  7. package/lib/LoggedClass.js.map +1 -0
  8. package/lib/constants.cjs +1 -1
  9. package/lib/constants.js.map +1 -0
  10. package/lib/decorators.cjs +1 -1
  11. package/lib/decorators.js.map +1 -0
  12. package/lib/environment.cjs +1 -1
  13. package/lib/environment.js.map +1 -0
  14. package/lib/esm/LoggedClass.js +1 -1
  15. package/lib/esm/LoggedClass.js.map +1 -0
  16. package/lib/esm/constants.js +1 -1
  17. package/lib/esm/constants.js.map +1 -0
  18. package/lib/esm/decorators.js +1 -1
  19. package/lib/esm/decorators.js.map +1 -0
  20. package/lib/esm/environment.js +1 -1
  21. package/lib/esm/environment.js.map +1 -0
  22. package/lib/esm/filters/LogFilter.js +1 -1
  23. package/lib/esm/filters/LogFilter.js.map +1 -0
  24. package/lib/esm/filters/PatternFilter.js +1 -1
  25. package/lib/esm/filters/PatternFilter.js.map +1 -0
  26. package/lib/esm/filters/index.js +1 -1
  27. package/lib/esm/filters/index.js.map +1 -0
  28. package/lib/esm/index.js +3 -3
  29. package/lib/esm/index.js.map +1 -0
  30. package/lib/esm/logging.js +1 -1
  31. package/lib/esm/logging.js.map +1 -0
  32. package/lib/esm/text.js +1 -1
  33. package/lib/esm/text.js.map +1 -0
  34. package/lib/esm/time.js +1 -1
  35. package/lib/esm/time.js.map +1 -0
  36. package/lib/esm/types.js +1 -1
  37. package/lib/esm/types.js.map +1 -0
  38. package/lib/esm/utils.js +1 -1
  39. package/lib/esm/utils.js.map +1 -0
  40. package/lib/esm/web.js +1 -1
  41. package/lib/esm/web.js.map +1 -0
  42. package/lib/esm/winston/index.js +1 -1
  43. package/lib/esm/winston/index.js.map +1 -0
  44. package/lib/esm/winston/winston.js +1 -1
  45. package/lib/esm/winston/winston.js.map +1 -0
  46. package/lib/filters/LogFilter.cjs +1 -1
  47. package/lib/filters/LogFilter.js.map +1 -0
  48. package/lib/filters/PatternFilter.cjs +1 -1
  49. package/lib/filters/PatternFilter.js.map +1 -0
  50. package/lib/filters/index.cjs +1 -1
  51. package/lib/filters/index.js.map +1 -0
  52. package/lib/index.cjs +3 -3
  53. package/lib/index.js.map +1 -0
  54. package/lib/logging.cjs +1 -1
  55. package/lib/logging.js.map +1 -0
  56. package/lib/text.cjs +1 -1
  57. package/lib/text.js.map +1 -0
  58. package/lib/time.cjs +1 -1
  59. package/lib/time.js.map +1 -0
  60. package/lib/types.cjs +1 -1
  61. package/lib/types.js.map +1 -0
  62. package/lib/utils.cjs +1 -1
  63. package/lib/utils.js.map +1 -0
  64. package/lib/web.cjs +1 -1
  65. package/lib/web.js.map +1 -0
  66. package/lib/winston/index.cjs +1 -1
  67. package/lib/winston/index.js.map +1 -0
  68. package/lib/winston/winston.cjs +1 -1
  69. package/lib/winston/winston.js.map +1 -0
  70. package/package.json +1 -1
  71. package/dist/logging.esm.cjs +0 -2044
@@ -1,2044 +0,0 @@
1
- import { style } from 'styled-string-builder';
2
- import { ObjectAccumulator } from 'typed-object-accumulator';
3
- import { __decorate, __metadata } from 'tslib';
4
-
5
- /**
6
- * @description Global key used to store environment variables in browser contexts.
7
- * @summary Enables the logging environment helpers to locate serialized environment configuration on `globalThis`.
8
- * @const BrowserEnvKey
9
- * @type {string}
10
- * @memberOf module:Logging
11
- */
12
- const BrowserEnvKey = "ENV";
13
- /**
14
- * @description Delimiter used for composing nested environment variable names.
15
- * @summary Joins parent and child keys when mapping object paths to ENV strings.
16
- * @const ENV_PATH_DELIMITER
17
- * @type {string}
18
- * @memberOf module:Logging
19
- */
20
- const ENV_PATH_DELIMITER = "__";
21
- /**
22
- * @description Default prefix and suffix used for template placeholders.
23
- * @summary Provides wrapper strings applied when interpolating messages with {@link patchPlaceholders}.
24
- * @const DefaultPlaceholderWrappers
25
- * @type {string[]}
26
- * @memberOf module:Logging
27
- */
28
- const DefaultPlaceholderWrappers = ["${", "}"];
29
- /**
30
- * @description Enum for log levels.
31
- * @summary Defines different levels of logging for the application.
32
- * @enum {string}
33
- * @readonly
34
- * @memberOf module:Logging
35
- */
36
- var LogLevel;
37
- (function (LogLevel) {
38
- /** @description Benchmark events that capture performance metrics. */
39
- LogLevel["benchmark"] = "benchmark";
40
- /** @description Error events that indicate failures requiring attention. */
41
- LogLevel["error"] = "error";
42
- /** @description Warning events that may indicate issues. */
43
- LogLevel["warn"] = "warn";
44
- /** @description Informational events describing normal operation. */
45
- LogLevel["info"] = "info";
46
- /** @description Verbose diagnostic information for detailed tracing. */
47
- LogLevel["verbose"] = "verbose";
48
- /** @description Debug or trace details aimed at developers. */
49
- LogLevel["debug"] = "debug";
50
- /** @description trace details aimed at developers */
51
- LogLevel["trace"] = "trace";
52
- /** @description Extremely chatty or playful log entries. */
53
- LogLevel["silly"] = "silly";
54
- })(LogLevel || (LogLevel = {}));
55
- /**
56
- * @description Numeric values associated with log levels.
57
- * @summary Provides a numeric representation of log levels for comparison and filtering.
58
- * @typedef {Object} NumericLogLevelsShape
59
- * @property {number} benchmark - Numeric value for benchmark level (0).
60
- * @property {number} error - Numeric value for error level (2).
61
- * @property {number} info - Numeric value for info level (4).
62
- * @property {number} verbose - Numeric value for verbose level (6).
63
- * @property {number} debug - Numeric value for debug level (7).
64
- * @property {number} silly - Numeric value for silly level (9).
65
- * @memberOf module:Logging
66
- */
67
- /**
68
- * @description Numeric values associated with log levels.
69
- * @summary Provides a numeric representation of log levels for comparison and filtering.
70
- * @const NumericLogLevels
71
- * @type {NumericLogLevelsShape}
72
- * @memberOf module:Logging
73
- */
74
- const NumericLogLevels = {
75
- benchmark: 0,
76
- error: 3,
77
- warn: 6,
78
- info: 9,
79
- verbose: 12,
80
- debug: 15,
81
- trace: 18,
82
- silly: 21,
83
- };
84
- /**
85
- * @description Enum for logging output modes.
86
- * @summary Defines different output formats for log messages.
87
- * @enum {string}
88
- * @memberOf module:Logging
89
- */
90
- var LoggingMode;
91
- (function (LoggingMode) {
92
- /** Raw text format for human readability */
93
- LoggingMode["RAW"] = "raw";
94
- /** JSON format for machine parsing */
95
- LoggingMode["JSON"] = "json";
96
- })(LoggingMode || (LoggingMode = {}));
97
- /**
98
- * @description Default theme for styling log output.
99
- * @summary Defines the default color and style settings for various components of log messages.
100
- * @typedef {Theme} DefaultTheme
101
- * @property {Object} class - Styling for class names.
102
- * @property {number} class.fg - Foreground color code for class names (34).
103
- * @property {Object} id - Styling for identifiers.
104
- * @property {number} id.fg - Foreground color code for identifiers (36).
105
- * @property {Object} stack - Styling for stack traces (empty object).
106
- * @property {Object} timestamp - Styling for timestamps (empty object).
107
- * @property {Object} message - Styling for different types of messages.
108
- * @property {Object} message.error - Styling for error messages.
109
- * @property {number} message.error.fg - Foreground color code for error messages (31).
110
- * @property {Object} method - Styling for method names (empty object).
111
- * @property {Object} logLevel - Styling for different log levels.
112
- * @property {Object} logLevel.error - Styling for error level logs.
113
- * @property {number} logLevel.error.fg - Foreground color code for error level logs (31).
114
- * @property {string[]} logLevel.error.style - Style attributes for error level logs (["bold"]).
115
- * @property {Object} logLevel.info - Styling for info level logs (empty object).
116
- * @property {Object} logLevel.verbose - Styling for verbose level logs (empty object).
117
- * @property {Object} logLevel.debug - Styling for debug level logs.
118
- * @property {number} logLevel.debug.fg - Foreground color code for debug level logs (33).
119
- * @const DefaultTheme
120
- * @memberOf module:Logging
121
- */
122
- const DefaultTheme = {
123
- app: {},
124
- separator: {},
125
- class: {
126
- fg: 34,
127
- },
128
- id: {
129
- fg: 36,
130
- },
131
- stack: {},
132
- timestamp: {},
133
- message: {
134
- error: {
135
- fg: 31,
136
- },
137
- },
138
- method: {},
139
- logLevel: {
140
- benchmark: {
141
- fg: 32,
142
- style: ["bold"],
143
- },
144
- error: {
145
- fg: 31,
146
- style: ["bold"],
147
- },
148
- info: {
149
- fg: 34,
150
- style: ["bold"],
151
- },
152
- verbose: {
153
- fg: 34,
154
- style: ["bold"],
155
- },
156
- debug: {
157
- fg: 33,
158
- style: ["bold"],
159
- },
160
- trace: {
161
- fg: 33,
162
- style: ["bold"],
163
- },
164
- silly: {
165
- fg: 33,
166
- style: ["bold"],
167
- },
168
- },
169
- };
170
- /**
171
- * @description Default configuration for logging.
172
- * @summary Defines the default settings for the logging system, including verbosity, log level, styling, and timestamp format.
173
- * @const DefaultLoggingConfig
174
- * @typedef {LoggingConfig} DefaultLoggingConfig
175
- * @property {number} verbose - Verbosity level (0).
176
- * @property {LogLevel} level - Default log level (LogLevel.info).
177
- * @property {boolean} logLevel - Whether to display log level in output (true).
178
- * @property {LoggingMode} mode - Output format mode (LoggingMode.RAW).
179
- * @property {boolean} style - Whether to apply styling to log output (false).
180
- * @property {string} separator - Separator between log components (" - ").
181
- * @property {boolean} timestamp - Whether to include timestamps in log messages (true).
182
- * @property {string} timestampFormat - Format for timestamps ("HH:mm:ss.SSS").
183
- * @property {boolean} context - Whether to include context information in log messages (true).
184
- * @property {Theme} theme - The theme to use for styling log messages (DefaultTheme).
185
- * @memberOf module:Logging
186
- */
187
- const DefaultLoggingConfig = {
188
- env: "development",
189
- verbose: 0,
190
- level: LogLevel.info,
191
- logLevel: true,
192
- style: false,
193
- contextSeparator: ".",
194
- separator: "-",
195
- timestamp: true,
196
- timestampFormat: "HH:mm:ss.SSS",
197
- context: true,
198
- format: LoggingMode.RAW,
199
- pattern: "{level} [{timestamp}] {app} {context} {separator} {message} {stack}",
200
- theme: DefaultTheme,
201
- };
202
-
203
- /**
204
- * @description Pads the end of a string with a specified character.
205
- * @summary Extends the input string to a specified length by adding a padding character to the end.
206
- * If the input string is already longer than the specified length, it is returned unchanged.
207
- *
208
- * @param {string} str - The input string to be padded.
209
- * @param {number} length - The desired total length of the resulting string.
210
- * @param {string} [char=" "] - The character to use for padding. Defaults to a space.
211
- * @return {string} The padded string.
212
- * @throws {Error} If the padding character is not exactly one character long.
213
- *
214
- * @function padEnd
215
- *
216
- * @memberOf module:Logging
217
- */
218
- function padEnd(str, length, char = " ") {
219
- if (char.length !== 1)
220
- throw new Error("Invalid character length for padding. must be one!");
221
- return str.padEnd(length, char);
222
- }
223
- /**
224
- * @description Replaces placeholders in a string with provided values.
225
- * @summary Interpolates a string by replacing placeholders of the form ${variableName}
226
- * with corresponding values from the provided object. If a placeholder doesn't have
227
- * a corresponding value, it is left unchanged in the string.
228
- *
229
- * @param {string} input - The input string containing placeholders to be replaced.
230
- * @param {Record<string, number | string>} values - An object containing key-value pairs for replacement.
231
- * @param prefix
232
- * @param suffix
233
- * @param flags
234
- * @return {string} The interpolated string with placeholders replaced by their corresponding values.
235
- *
236
- * @function patchPlaceholders
237
- *
238
- * @mermaid
239
- * sequenceDiagram
240
- * participant Caller
241
- * participant patchString
242
- * participant String.replace
243
- * Caller->>patchString: Call with input and values
244
- * patchString->>String.replace: Call with regex and replacement function
245
- * String.replace->>patchString: Return replaced string
246
- * patchString-->>Caller: Return patched string
247
- *
248
- * @memberOf module:Logging
249
- */
250
- function patchPlaceholders(input, values, prefix = DefaultPlaceholderWrappers[0], suffix = DefaultPlaceholderWrappers[1], flags = "g") {
251
- const placeholders = Object.entries(values).reduce((acc, [key, val]) => {
252
- acc[`${prefix}${key}${suffix}`] = val;
253
- return acc;
254
- }, {});
255
- return patchString(input, placeholders, flags);
256
- }
257
- /**
258
- * @description Replaces occurrences of keys with their corresponding values in a string.
259
- * @summary Iterates through a set of key-value pairs and replaces all occurrences of each key
260
- * in the input string with its corresponding value. Supports regular expression flags for customized replacement.
261
- *
262
- * @param {string} input - The input string in which replacements will be made.
263
- * @param {Record<string, number | string>} values - An object containing key-value pairs for replacement.
264
- * @param {string} [flags="g"] - Regular expression flags to control the replacement behavior.
265
- * @return {string} The string with all specified replacements applied.
266
- *
267
- * @function patchString
268
- *
269
- * @memberOf module:Logging
270
- */
271
- function patchString(input, values, flags = "g") {
272
- Object.entries(values).forEach(([key, val]) => {
273
- const regexp = new RegExp(escapeRegExp(key), flags);
274
- input = input.replace(regexp, val);
275
- });
276
- return input;
277
- }
278
- /**
279
- * @description Converts a string to camelCase.
280
- * @summary Transforms the input string into camelCase format, where words are joined without spaces
281
- * and each word after the first starts with a capital letter.
282
- *
283
- * @param {string} text - The input string to be converted.
284
- * @return {string} The input string converted to camelCase.
285
- *
286
- * @function toCamelCase
287
- *
288
- * @memberOf module:Logging
289
- */
290
- function toCamelCase(text) {
291
- return text
292
- .replace(/(?:^\w|[A-Z]|\b\w)/g, (word, index) => index === 0 ? word.toLowerCase() : word.toUpperCase())
293
- .replace(/\s+/g, "");
294
- }
295
- /**
296
- * @description Converts a string to ENVIRONMENT_VARIABLE format.
297
- * @summary Transforms the input string into uppercase with words separated by underscores,
298
- * typically used for environment variable names.
299
- *
300
- * @param {string} text - The input string to be converted.
301
- * @return {string} The input string converted to ENVIRONMENT_VARIABLE format.
302
- *
303
- * @function toENVFormat
304
- *
305
- * @memberOf module:Logging
306
- */
307
- function toENVFormat(text) {
308
- return toSnakeCase(text).toUpperCase();
309
- }
310
- /**
311
- * @description Converts a string to snake_case.
312
- * @summary Transforms the input string into lowercase with words separated by underscores.
313
- *
314
- * @param {string} text - The input string to be converted.
315
- * @return {string} The input string converted to snake_case.
316
- *
317
- * @function toSnakeCase
318
- *
319
- * @memberOf module:Logging
320
- */
321
- function toSnakeCase(text) {
322
- return text
323
- .replace(/([a-z])([A-Z])/g, "$1_$2")
324
- .replace(/[\s-]+/g, "_")
325
- .toLowerCase();
326
- }
327
- /**
328
- * @description Converts a string to kebab-case.
329
- * @summary Transforms the input string into lowercase with words separated by hyphens.
330
- *
331
- * @param {string} text - The input string to be converted.
332
- * @return {string} The input string converted to kebab-case.
333
- *
334
- * @function toKebabCase
335
- *
336
- * @memberOf module:Logging
337
- */
338
- function toKebabCase(text) {
339
- return text
340
- .replace(/([a-z])([A-Z])/g, "$1-$2")
341
- .replace(/[\s_]+/g, "-")
342
- .toLowerCase();
343
- }
344
- /**
345
- * @description Converts a string to PascalCase.
346
- * @summary Transforms the input string into PascalCase format, where words are joined without spaces
347
- * and each word starts with a capital letter.
348
- *
349
- * @param {string} text - The input string to be converted.
350
- * @return {string} The input string converted to PascalCase.
351
- *
352
- * @function toPascalCase
353
- *
354
- * @memberOf module:Logging
355
- */
356
- function toPascalCase(text) {
357
- return text
358
- .replace(/(?:^\w|[A-Z]|\b\w)/g, (word) => word.toUpperCase())
359
- .replace(/\s+/g, "");
360
- }
361
- /**
362
- * @description Escapes special characters in a string for use in a regular expression.
363
- * @summary Adds backslashes before characters that have special meaning in regular expressions,
364
- * allowing the string to be used as a literal match in a RegExp.
365
- *
366
- * @param {string} string - The string to escape for regular expression use.
367
- * @return {string} The escaped string safe for use in regular expressions.
368
- *
369
- * @function escapeRegExp
370
- *
371
- * @memberOf module:Logging
372
- */
373
- function escapeRegExp(string) {
374
- return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); // $& means the whole matched string
375
- }
376
- /**
377
- * @summary Util function to provide string format functionality similar to C#'s string.format
378
- *
379
- * @param {string} string
380
- * @param {Array<string | number> | Record<string, any>} [args] replacements made by order of appearance (replacement0 wil replace {0} and so on)
381
- * @return {string} formatted string
382
- *
383
- * @function sf
384
- * @memberOf module:Logging
385
- */
386
- function sf(string, ...args) {
387
- if (args.length > 1) {
388
- if (!args.every((arg) => typeof arg === "string" || typeof arg === "number"))
389
- throw new Error(`Only string and number arguments are supported for multiple replacements.`);
390
- }
391
- if (args.length === 1 && typeof args[0] === "object") {
392
- const obj = args[0];
393
- return Object.entries(obj).reduce((acc, [key, val]) => {
394
- return acc.replace(new RegExp(`\\{${key}\\}`, "g"), function () {
395
- return val;
396
- });
397
- }, string);
398
- }
399
- return string.replace(/{(\d+)}/g, function (match, number) {
400
- return typeof args[number] !== "undefined"
401
- ? args[number].toString()
402
- : "undefined";
403
- });
404
- }
405
- /**
406
- * @summary Util function to provide string format functionality similar to C#'s string.format
407
- *
408
- * @see sf
409
- *
410
- * @deprecated
411
- * @function stringFormat
412
- * @memberOf module:Logging
413
- */
414
- const stringFormat = sf;
415
-
416
- /**
417
- * @description Determines if the current environment is a browser by checking the prototype chain of the global object.
418
- * @summary Checks if the code is running in a browser environment.
419
- * @return {boolean} True if the environment is a browser, false otherwise.
420
- * @function isBrowser
421
- * @memberOf module:Logging
422
- */
423
- function isBrowser() {
424
- return (Object.getPrototypeOf(Object.getPrototypeOf(globalThis)) !==
425
- Object.prototype);
426
- }
427
-
428
- /**
429
- * @description Environment accumulator that lazily reads from runtime sources.
430
- * @summary Extends {@link ObjectAccumulator} to merge configuration objects while resolving values from Node or browser environment variables on demand.
431
- * @template T
432
- * @class Environment
433
- * @example
434
- * const Config = Environment.accumulate({ logging: { level: "info" } });
435
- * console.log(Config.logging.level);
436
- * console.log(String(Config.logging.level)); // => LOGGING__LEVEL key when serialized
437
- * @mermaid
438
- * sequenceDiagram
439
- * participant Client
440
- * participant Env as Environment
441
- * participant Process as process.env
442
- * participant Browser as globalThis.ENV
443
- * Client->>Env: accumulate(partialConfig)
444
- * Env->>Env: expand(values)
445
- * Client->>Env: Config.logging.level
446
- * alt Browser runtime
447
- * Env->>Browser: lookup ENV key
448
- * Browser-->>Env: resolved value
449
- * else Node runtime
450
- * Env->>Process: lookup ENV key
451
- * Process-->>Env: resolved value
452
- * end
453
- * Env-->>Client: merged value
454
- */
455
- const EmptyValue = Symbol("EnvironmentEmpty");
456
- const ModelSymbol = Symbol("EnvironmentModel");
457
- class Environment extends ObjectAccumulator {
458
- /**
459
- * @static
460
- * @protected
461
- * @description A factory function for creating Environment instances.
462
- * @summary Defines how new instances of the Environment class should be created.
463
- * @return {Environment<any>} A new instance of the Environment class.
464
- */
465
- static { this.factory = () => new Environment(); }
466
- constructor() {
467
- super();
468
- Object.defineProperty(this, ModelSymbol, {
469
- value: {},
470
- writable: true,
471
- enumerable: false,
472
- configurable: false,
473
- });
474
- }
475
- /**
476
- * @description Retrieves a value from the runtime environment.
477
- * @summary Handles browser and Node.js environments by normalizing keys and parsing values.
478
- * @param {string} k - Key to resolve from the environment.
479
- * @return {unknown} Value resolved from the environment or `undefined` when absent.
480
- */
481
- fromEnv(k) {
482
- let env;
483
- if (isBrowser()) {
484
- env =
485
- globalThis[BrowserEnvKey] || {};
486
- }
487
- else {
488
- env = globalThis.process.env;
489
- k = toENVFormat(k);
490
- }
491
- return this.parseEnvValue(env[k]);
492
- }
493
- /**
494
- * @description Converts stringified environment values into native types.
495
- * @summary Interprets booleans and numbers while leaving other types unchanged.
496
- * @param {unknown} val - Raw value retrieved from the environment.
497
- * @return {unknown} Parsed value converted to boolean, number, or left as-is.
498
- */
499
- parseEnvValue(val) {
500
- if (typeof val !== "string")
501
- return val;
502
- if (val === "true")
503
- return true;
504
- if (val === "false")
505
- return false;
506
- const result = parseFloat(val);
507
- if (!isNaN(result))
508
- return result;
509
- return val;
510
- }
511
- /**
512
- * @description Expands an object into the environment.
513
- * @summary Defines lazy properties that first consult runtime variables before falling back to seeded values.
514
- * @template V - Type of the object being expanded.
515
- * @param {V} value - Object to expose through environment getters and setters.
516
- * @return {void}
517
- */
518
- expand(value) {
519
- Object.entries(value).forEach(([k, v]) => {
520
- Environment.mergeModel(this[ModelSymbol], k, v);
521
- Object.defineProperty(this, k, {
522
- get: () => {
523
- const fromEnv = this.fromEnv(k);
524
- if (typeof fromEnv !== "undefined")
525
- return fromEnv;
526
- if (v && typeof v === "object") {
527
- return Environment.buildEnvProxy(v, [k]);
528
- }
529
- // If the model provides an empty string, mark with EmptyValue so instance proxy can return undefined without enabling key composition
530
- if (v === "") {
531
- return EmptyValue;
532
- }
533
- return v;
534
- },
535
- set: (val) => {
536
- v = val;
537
- },
538
- configurable: true,
539
- enumerable: true,
540
- });
541
- });
542
- }
543
- /**
544
- * @description Returns a proxy enforcing required environment variables.
545
- * @summary Accessing a property that resolves to `undefined` or an empty string when declared in the model throws an error.
546
- * @return {this} Proxy of the environment enforcing required variables.
547
- */
548
- orThrow() {
549
- // eslint-disable-next-line @typescript-eslint/no-this-alias
550
- const base = this;
551
- const modelRoot = base[ModelSymbol];
552
- const buildKey = (path) => path.map((segment) => toENVFormat(segment)).join(ENV_PATH_DELIMITER);
553
- const readRuntime = (key) => Environment.readRuntimeEnv(key);
554
- const parseRuntime = (raw) => typeof raw !== "undefined" ? this.parseEnvValue(raw) : undefined;
555
- const missing = (key, empty = false) => Environment.missingEnvError(key, empty);
556
- const createNestedProxy = (model, path) => {
557
- const handler = {
558
- get(_target, prop) {
559
- if (typeof prop !== "string")
560
- return undefined;
561
- const nextPath = [...path, prop];
562
- const envKey = buildKey(nextPath);
563
- const runtimeRaw = readRuntime(envKey);
564
- if (typeof runtimeRaw === "string" && runtimeRaw.length === 0)
565
- throw missing(envKey, true);
566
- const runtimeValue = parseRuntime(runtimeRaw);
567
- if (typeof runtimeValue !== "undefined") {
568
- if (typeof runtimeValue === "string" && runtimeValue.length === 0)
569
- throw missing(envKey, true);
570
- return runtimeValue;
571
- }
572
- const hasProp = model && Object.prototype.hasOwnProperty.call(model, prop);
573
- if (!hasProp)
574
- throw missing(envKey);
575
- const modelValue = model[prop];
576
- if (typeof modelValue === "undefined")
577
- return undefined;
578
- if (modelValue === "")
579
- throw missing(envKey);
580
- if (modelValue &&
581
- typeof modelValue === "object" &&
582
- !Array.isArray(modelValue)) {
583
- return createNestedProxy(modelValue, nextPath);
584
- }
585
- return modelValue;
586
- },
587
- ownKeys() {
588
- return model ? Reflect.ownKeys(model) : [];
589
- },
590
- getOwnPropertyDescriptor(_target, prop) {
591
- if (!model)
592
- return undefined;
593
- if (Object.prototype.hasOwnProperty.call(model, prop)) {
594
- return {
595
- enumerable: true,
596
- configurable: true,
597
- };
598
- }
599
- return undefined;
600
- },
601
- };
602
- return new Proxy({}, handler);
603
- };
604
- const handler = {
605
- get(target, prop, receiver) {
606
- if (typeof prop !== "string")
607
- return Reflect.get(target, prop, receiver);
608
- const hasModelProp = Object.prototype.hasOwnProperty.call(modelRoot, prop);
609
- if (!hasModelProp)
610
- return Reflect.get(target, prop, receiver);
611
- const envKey = buildKey([prop]);
612
- const runtimeRaw = readRuntime(envKey);
613
- if (typeof runtimeRaw === "string" && runtimeRaw.length === 0)
614
- throw missing(envKey, true);
615
- const runtimeValue = parseRuntime(runtimeRaw);
616
- if (typeof runtimeValue !== "undefined") {
617
- if (typeof runtimeValue === "string" && runtimeValue.length === 0)
618
- throw missing(envKey, true);
619
- return runtimeValue;
620
- }
621
- const modelValue = modelRoot[prop];
622
- if (modelValue &&
623
- typeof modelValue === "object" &&
624
- !Array.isArray(modelValue)) {
625
- return createNestedProxy(modelValue, [prop]);
626
- }
627
- if (typeof modelValue === "undefined")
628
- return Reflect.get(target, prop, receiver);
629
- const actual = Reflect.get(target, prop);
630
- if (typeof actual === "undefined" || actual === "")
631
- throw missing(envKey, actual === "");
632
- return actual;
633
- },
634
- };
635
- return new Proxy(base, handler);
636
- }
637
- /**
638
- * @protected
639
- * @static
640
- * @description Retrieves or creates the singleton instance of the Environment class.
641
- * @summary Ensures only one {@link Environment} instance is created, wrapping it in a proxy to compose ENV keys on demand.
642
- * @template E
643
- * @param {...unknown[]} args - Arguments forwarded to the factory when instantiating the singleton.
644
- * @return {E} Singleton environment instance.
645
- */
646
- static instance(...args) {
647
- if (!Environment._instance) {
648
- const base = Environment.factory(...args);
649
- const proxied = new Proxy(base, {
650
- get(target, prop, receiver) {
651
- const value = Reflect.get(target, prop, receiver);
652
- if (value === EmptyValue)
653
- return undefined;
654
- // If the property exists on the instance but resolves to undefined, return undefined (no proxy)
655
- if (typeof prop === "string" &&
656
- Object.prototype.hasOwnProperty.call(target, prop)) {
657
- if (typeof value === "undefined")
658
- return undefined;
659
- }
660
- if (typeof value !== "undefined")
661
- return value;
662
- if (typeof prop === "string") {
663
- // Avoid interfering with logging config lookups for optional fields like 'app'
664
- if (prop === "app")
665
- return undefined;
666
- return Environment.buildEnvProxy(undefined, [prop]);
667
- }
668
- return value;
669
- },
670
- });
671
- Environment._instance = proxied;
672
- }
673
- return Environment._instance;
674
- }
675
- /**
676
- * @static
677
- * @description Accumulates the given value into the environment.
678
- * @summary Adds new properties, hiding raw descriptors to avoid leaking enumeration semantics.
679
- * @template T
680
- * @template V
681
- * @param {V} value - Object to merge into the environment.
682
- * @return {Environment} Updated environment reference.
683
- */
684
- static accumulate(value) {
685
- const instance = Environment.instance();
686
- Object.keys(instance).forEach((key) => {
687
- const desc = Object.getOwnPropertyDescriptor(instance, key);
688
- if (desc && desc.configurable && desc.enumerable) {
689
- Object.defineProperty(instance, key, {
690
- ...desc,
691
- enumerable: false,
692
- });
693
- }
694
- });
695
- return instance.accumulate(value);
696
- }
697
- /**
698
- * @description Retrieves a value using a dot-path key from the accumulated environment.
699
- * @summary Delegates to the singleton instance to access stored configuration.
700
- * @param {string} key - Key to resolve from the environment store.
701
- * @return {unknown} Stored value corresponding to the provided key.
702
- */
703
- static get(key) {
704
- return Environment._instance.get(key);
705
- }
706
- /**
707
- * @description Builds a proxy that composes environment keys for nested properties.
708
- * @summary Allows chained property access to emit uppercase ENV identifiers while honoring existing runtime overrides.
709
- * @param {any} current - Seed model segment used when projecting nested structures.
710
- * @param {string[]} path - Accumulated path segments leading to the proxy.
711
- * @return {any} Proxy that resolves environment values or composes additional proxies for deeper paths.
712
- */
713
- static buildEnvProxy(current, path) {
714
- const buildKey = (p) => p.map((seg) => toENVFormat(seg)).join(ENV_PATH_DELIMITER);
715
- // Helper to read from the active environment given a composed key
716
- const readEnv = (key) => {
717
- return Environment.readRuntimeEnv(key);
718
- };
719
- const handler = {
720
- get(_target, prop) {
721
- if (prop === Symbol.toPrimitive) {
722
- return () => buildKey(path);
723
- }
724
- if (prop === "toString") {
725
- return () => buildKey(path);
726
- }
727
- if (prop === "valueOf") {
728
- return () => buildKey(path);
729
- }
730
- if (typeof prop === "symbol")
731
- return undefined;
732
- const hasProp = !!current && Object.prototype.hasOwnProperty.call(current, prop);
733
- const nextModel = hasProp ? current[prop] : undefined;
734
- const nextPath = [...path, prop];
735
- const composedKey = buildKey(nextPath);
736
- // If an ENV value exists for this path, return it directly
737
- const envValue = readEnv(composedKey);
738
- if (typeof envValue !== "undefined")
739
- return envValue;
740
- // Otherwise, if the model has an object at this path, keep drilling with a proxy
741
- const isNextObject = nextModel && typeof nextModel === "object";
742
- if (isNextObject)
743
- return Environment.buildEnvProxy(nextModel, nextPath);
744
- // If the model marks this leaf as an empty string, treat as undefined (no proxy)
745
- if (hasProp && nextModel === "")
746
- return undefined;
747
- // If the model explicitly contains the property with value undefined, treat as undefined (no proxy)
748
- if (hasProp && typeof nextModel === "undefined")
749
- return undefined;
750
- // Always return a proxy for further path composition when no ENV value;
751
- // do not surface primitive model defaults here (this API is for key composition).
752
- return Environment.buildEnvProxy(undefined, nextPath);
753
- },
754
- ownKeys() {
755
- return current ? Reflect.ownKeys(current) : [];
756
- },
757
- getOwnPropertyDescriptor(_t, p) {
758
- if (!current)
759
- return undefined;
760
- if (Object.prototype.hasOwnProperty.call(current, p)) {
761
- return { enumerable: true, configurable: true };
762
- }
763
- return undefined;
764
- },
765
- };
766
- const target = {};
767
- return new Proxy(target, handler);
768
- }
769
- /**
770
- * @static
771
- * @description Retrieves the keys of the environment, optionally converting them to ENV format.
772
- * @summary Gets all keys in the environment, with an option to format them for environment variables.
773
- * @param {boolean} [toEnv=true] - Whether to convert the keys to ENV format.
774
- * @return {string[]} An array of keys from the environment.
775
- */
776
- static keys(toEnv = true) {
777
- return Environment.instance()
778
- .keys()
779
- .map((k) => (toEnv ? toENVFormat(k) : k));
780
- }
781
- static mergeModel(model, key, value) {
782
- if (!model)
783
- return;
784
- if (value && typeof value === "object" && !Array.isArray(value)) {
785
- const existing = model[key];
786
- const target = existing && typeof existing === "object" && !Array.isArray(existing)
787
- ? existing
788
- : {};
789
- model[key] = target;
790
- Object.entries(value).forEach(([childKey, childValue]) => {
791
- Environment.mergeModel(target, childKey, childValue);
792
- });
793
- return;
794
- }
795
- model[key] = value;
796
- }
797
- static readRuntimeEnv(key) {
798
- if (isBrowser()) {
799
- const env = globalThis[BrowserEnvKey];
800
- return env ? env[key] : undefined;
801
- }
802
- return globalThis?.process?.env?.[key];
803
- }
804
- static missingEnvError(key, empty) {
805
- const suffix = empty ? "an empty string" : "undefined";
806
- return new Error(`Environment variable ${key} is required but was ${suffix}.`);
807
- }
808
- }
809
- /**
810
- * @description Singleton environment instance seeded with default logging configuration.
811
- * @summary Combines {@link DefaultLoggingConfig} with runtime environment variables to provide consistent logging defaults across platforms.
812
- * @const LoggedEnvironment
813
- * @memberOf module:Logging
814
- */
815
- const LoggedEnvironment = Environment.accumulate(Object.assign({}, DefaultLoggingConfig, {
816
- env: (isBrowser() && globalThis[BrowserEnvKey]
817
- ? globalThis[BrowserEnvKey]["NODE_ENV"]
818
- : globalThis.process.env["NODE_ENV"]) || "development",
819
- }));
820
-
821
- /**
822
- * @description A minimal logger implementation.
823
- * @summary MiniLogger is a lightweight logging class that implements the Logger interface.
824
- * It provides basic logging functionality with support for different log levels, verbosity,
825
- * context-aware logging, and customizable formatting.
826
- * @param {string} context - The context (typically class name) this logger is associated with
827
- * @param {Partial<LoggingConfig>} conf - Optional configuration to override global settings
828
- * @class MiniLogger
829
- * @example
830
- * // Create a new logger for a class
831
- * const logger = new MiniLogger('MyClass');
832
- *
833
- * // Log messages at different levels
834
- * logger.info('This is an info message');
835
- * logger.debug('This is a debug message');
836
- * logger.error('Something went wrong');
837
- *
838
- * // Create a child logger for a specific method
839
- * const methodLogger = logger.for('myMethod');
840
- * methodLogger.verbose('Detailed information', 2);
841
- *
842
- * // Log with custom configuration
843
- * logger.for('specialMethod', { style: true }).info('Styled message');
844
- */
845
- class MiniLogger {
846
- constructor(context, conf) {
847
- this.context = context;
848
- this.conf = conf;
849
- }
850
- config(key) {
851
- if (this.conf && key in this.conf)
852
- return this.conf[key];
853
- return Logging.getConfig()[key];
854
- }
855
- /**
856
- * @description Creates a child logger for a specific method or context
857
- * @summary Returns a new logger instance with the current context extended by the specified method name
858
- * @param {string | Function} method - The method name or function to create a logger for
859
- * @param {Partial<LoggingConfig>} config - Optional configuration to override settings
860
- * @param {...any[]} args - Additional arguments to pass to the logger factory
861
- * @return {Logger} A new logger instance for the specified method
862
- */
863
- for(method, config,
864
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
865
- ...args) {
866
- if (!config && typeof method === "object") {
867
- config = method;
868
- method = undefined;
869
- }
870
- else {
871
- method = method
872
- ? typeof method === "string"
873
- ? method
874
- : method.name
875
- : undefined;
876
- }
877
- return new Proxy(this, {
878
- get: (target, p, receiver) => {
879
- const result = Reflect.get(target, p, receiver);
880
- if (p === "config") {
881
- return new Proxy(this.config, {
882
- get: (target, p) => {
883
- if (config && p in config)
884
- return config[p];
885
- return Reflect.get(target, p, receiver);
886
- },
887
- });
888
- }
889
- if (p === "context" && method) {
890
- return [result, method].join(".");
891
- }
892
- return result;
893
- },
894
- });
895
- }
896
- /**
897
- * @description Creates a formatted log string
898
- * @summary Generates a log string with timestamp, colored log level, context, and message
899
- * @param {LogLevel} level - The log level for this message
900
- * @param {StringLike | Error} message - The message to log or an Error object
901
- * @param {string} [error] - Optional error to extract stack trace to include in the log
902
- * @return {string} A formatted log string with all components
903
- */
904
- createLog(level, message, error) {
905
- const log = {};
906
- const style = this.config("style");
907
- const separator = this.config("separator");
908
- const app = this.config("app");
909
- if (app)
910
- log.app = style
911
- ? Logging.theme(app, "app", level)
912
- : app;
913
- if (separator)
914
- log.separator = style
915
- ? Logging.theme(separator, "separator", level)
916
- : separator;
917
- if (this.config("timestamp")) {
918
- const date = new Date().toISOString();
919
- const timestamp = style ? Logging.theme(date, "timestamp", level) : date;
920
- log.timestamp = timestamp;
921
- }
922
- if (this.config("logLevel")) {
923
- const lvl = style
924
- ? Logging.theme(level, "logLevel", level)
925
- : level;
926
- log.level = lvl.toUpperCase();
927
- }
928
- if (this.config("context")) {
929
- const context = style
930
- ? Logging.theme(this.context, "class", level)
931
- : this.context;
932
- log.context = context;
933
- }
934
- if (this.config("correlationId")) {
935
- {
936
- const id = style
937
- ? Logging.theme(this.config("correlationId").toString(), "id", level)
938
- : this.config("correlationId").toString();
939
- log.correlationId = id;
940
- }
941
- }
942
- const msg = style
943
- ? Logging.theme(typeof message === "string" ? message : message.message, "message", level)
944
- : typeof message === "string"
945
- ? message
946
- : message.message;
947
- log.message = msg;
948
- if (error || message instanceof Error) {
949
- const stack = style
950
- ? Logging.theme((error?.stack || message.stack), "stack", level)
951
- : error?.stack || "";
952
- log.stack = ` | ${(error || message).message} - Stack trace:\n${stack}`;
953
- }
954
- switch (this.config("format")) {
955
- case "json":
956
- return JSON.stringify(log);
957
- case "raw":
958
- return this.config("pattern")
959
- .split(" ")
960
- .map((s) => {
961
- if (!s.match(/\{.*?}/g))
962
- return s;
963
- const formattedS = sf(s, log);
964
- if (formattedS !== s)
965
- return formattedS;
966
- return undefined;
967
- })
968
- .filter((s) => s)
969
- .join(" ");
970
- default:
971
- throw new Error(`Unsupported logging format: ${this.config("format")}`);
972
- }
973
- }
974
- /**
975
- * @description Logs a message with the specified log level
976
- * @summary Checks if the message should be logged based on the current log level,
977
- * then uses the appropriate console method to output the formatted log
978
- * @param {LogLevel} level - The log level of the message
979
- * @param {StringLike | Error} msg - The message to be logged or an Error object
980
- * @param {string} [error] - Optional stack trace to include in the log
981
- * @return {void}
982
- */
983
- log(level, msg, error) {
984
- const confLvl = this.config("level");
985
- if (NumericLogLevels[confLvl] < NumericLogLevels[level])
986
- return;
987
- let method;
988
- switch (level) {
989
- case LogLevel.benchmark:
990
- method = console.log;
991
- break;
992
- case LogLevel.info:
993
- method = console.log;
994
- break;
995
- case LogLevel.verbose:
996
- case LogLevel.debug:
997
- method = console.debug;
998
- break;
999
- case LogLevel.error:
1000
- method = console.error;
1001
- break;
1002
- case LogLevel.trace:
1003
- method = console.trace;
1004
- break;
1005
- case LogLevel.silly:
1006
- method = console.trace;
1007
- break;
1008
- default:
1009
- throw new Error("Invalid log level");
1010
- }
1011
- method(this.createLog(level, msg, error));
1012
- }
1013
- /**
1014
- * @description Logs a message at the benchmark level
1015
- * @summary Logs a message at the benchmark level if the current verbosity setting allows it
1016
- * @param {StringLike} msg - The message to be logged
1017
- * @return {void}
1018
- */
1019
- benchmark(msg) {
1020
- this.log(LogLevel.benchmark, msg);
1021
- }
1022
- /**
1023
- * @description Logs a message at the silly level
1024
- * @summary Logs a message at the silly level if the current verbosity setting allows it
1025
- * @param {StringLike} msg - The message to be logged
1026
- * @param {number} [verbosity=0] - The verbosity level of the message
1027
- * @return {void}
1028
- */
1029
- silly(msg, verbosity = 0) {
1030
- if (this.config("verbose") >= verbosity)
1031
- this.log(LogLevel.verbose, msg);
1032
- }
1033
- /**
1034
- * @description Logs a message at the verbose level
1035
- * @summary Logs a message at the verbose level if the current verbosity setting allows it
1036
- * @param {StringLike} msg - The message to be logged
1037
- * @param {number} [verbosity=0] - The verbosity level of the message
1038
- * @return {void}
1039
- */
1040
- verbose(msg, verbosity = 0) {
1041
- if (this.config("verbose") >= verbosity)
1042
- this.log(LogLevel.verbose, msg);
1043
- }
1044
- /**
1045
- * @description Logs a message at the info level
1046
- * @summary Logs a message at the info level for general application information
1047
- * @param {StringLike} msg - The message to be logged
1048
- * @return {void}
1049
- */
1050
- info(msg) {
1051
- this.log(LogLevel.info, msg);
1052
- }
1053
- /**
1054
- * @description Logs a message at the debug level
1055
- * @summary Logs a message at the debug level for detailed troubleshooting information
1056
- * @param {StringLike} msg - The message to be logged
1057
- * @return {void}
1058
- */
1059
- debug(msg) {
1060
- this.log(LogLevel.debug, msg);
1061
- }
1062
- /**
1063
- * @description Logs a message at the error level
1064
- * @summary Logs a message at the error level for errors and exceptions
1065
- * @param {StringLike | Error} msg - The message to be logged or an Error object
1066
- * @param e
1067
- * @return {void}
1068
- */
1069
- error(msg, e) {
1070
- this.log(LogLevel.error, msg, e);
1071
- }
1072
- /**
1073
- * @description Logs a message at the error level
1074
- * @summary Logs a message at the error level for errors and exceptions
1075
- * @param {StringLike} msg - The message to be logged or an Error object
1076
- * @return {void}
1077
- */
1078
- warn(msg) {
1079
- this.log(LogLevel.warn, msg);
1080
- }
1081
- /**
1082
- * @description Logs a message at the error level
1083
- * @summary Logs a message at the error level for errors and exceptions
1084
- * @param {StringLike} msg - The message to be logged or an Error object
1085
- * @return {void}
1086
- */
1087
- trace(msg) {
1088
- this.log(LogLevel.trace, msg);
1089
- }
1090
- /**
1091
- * @description Updates the logger configuration
1092
- * @summary Merges the provided configuration with the existing configuration
1093
- * @param {Partial<LoggingConfig>} config - The configuration options to apply
1094
- * @return {void}
1095
- */
1096
- setConfig(config) {
1097
- this.conf = { ...(this.conf || {}), ...config };
1098
- }
1099
- }
1100
- /**
1101
- * @description A static class for managing logging operations
1102
- * @summary The Logging class provides a centralized logging mechanism with support for
1103
- * different log levels, verbosity, and styling. It uses a singleton pattern to maintain a global
1104
- * logger instance and allows creating specific loggers for different classes and methods.
1105
- * @class Logging
1106
- * @example
1107
- * // Set global configuration
1108
- * Logging.setConfig({ level: LogLevel.debug, style: true });
1109
- *
1110
- * // Get a logger for a specific class
1111
- * const logger = Logging.for('MyClass');
1112
- *
1113
- * // Log messages at different levels
1114
- * logger.info('Application started');
1115
- * logger.debug('Processing data...');
1116
- *
1117
- * // Log with context
1118
- * const methodLogger = Logging.for('MyClass.myMethod');
1119
- * methodLogger.verbose('Detailed operation information', 1);
1120
- *
1121
- * // Log errors
1122
- * try {
1123
- * // some operation
1124
- * } catch (error) {
1125
- * logger.error(error);
1126
- * }
1127
- * @mermaid
1128
- * classDiagram
1129
- * class Logger {
1130
- * <<interface>>
1131
- * +for(method, config, ...args)
1132
- * +silly(msg, verbosity)
1133
- * +verbose(msg, verbosity)
1134
- * +info(msg)
1135
- * +debug(msg)
1136
- * +error(msg)
1137
- * +setConfig(config)
1138
- * }
1139
- *
1140
- * class Logging {
1141
- * -global: Logger
1142
- * -_factory: LoggerFactory
1143
- * -_config: LoggingConfig
1144
- * +setFactory(factory)
1145
- * +setConfig(config)
1146
- * +getConfig()
1147
- * +get()
1148
- * +verbose(msg, verbosity)
1149
- * +info(msg)
1150
- * +debug(msg)
1151
- * +silly(msg)
1152
- * +error(msg)
1153
- * +for(object, config, ...args)
1154
- * +because(reason, id)
1155
- * +theme(text, type, loggerLevel, template)
1156
- * }
1157
- *
1158
- * class MiniLogger {
1159
- * +constructor(context, conf?)
1160
- * }
1161
- *
1162
- * Logging ..> Logger : creates
1163
- * Logging ..> MiniLogger : creates by default
1164
- */
1165
- class Logging {
1166
- /**
1167
- * @description Factory function for creating logger instances
1168
- * @summary A function that creates new Logger instances. By default, it creates a MiniLogger.
1169
- */
1170
- static { this._factory = (object, config) => {
1171
- return new MiniLogger(object, config);
1172
- }; }
1173
- static { this._config = LoggedEnvironment; }
1174
- constructor() { }
1175
- /**
1176
- * @description Sets the factory function for creating logger instances
1177
- * @summary Allows customizing how logger instances are created
1178
- * @param {LoggerFactory} factory - The factory function to use for creating loggers
1179
- * @return {void}
1180
- */
1181
- static setFactory(factory) {
1182
- Logging._factory = factory;
1183
- }
1184
- /**
1185
- * @description Updates the global logging configuration
1186
- * @summary Allows updating the global logging configuration with new settings
1187
- * @param {Partial<LoggingConfig>} config - The configuration options to apply
1188
- * @return {void}
1189
- */
1190
- static setConfig(config) {
1191
- Object.entries(config).forEach(([k, v]) => {
1192
- this._config[k] = v;
1193
- });
1194
- }
1195
- /**
1196
- * @description Gets a copy of the current global logging configuration
1197
- * @summary Returns a copy of the current global logging configuration
1198
- * @return {LoggingConfig} A copy of the current configuration
1199
- */
1200
- static getConfig() {
1201
- return this._config;
1202
- }
1203
- /**
1204
- * @description Retrieves or creates the global logger instance.
1205
- * @summary Returns the existing global logger or creates a new one if it doesn't exist.
1206
- *
1207
- * @return The global VerbosityLogger instance.
1208
- */
1209
- static get() {
1210
- this.global = this.global ? this.global : this._factory("Logging");
1211
- return this.global;
1212
- }
1213
- /**
1214
- * @description Logs a verbose message.
1215
- * @summary Delegates the verbose logging to the global logger instance.
1216
- *
1217
- * @param msg - The message to be logged.
1218
- * @param verbosity - The verbosity level of the message (default: 0).
1219
- */
1220
- static verbose(msg, verbosity = 0) {
1221
- return this.get().verbose(msg, verbosity);
1222
- }
1223
- /**
1224
- * @description Logs an info message.
1225
- * @summary Delegates the info logging to the global logger instance.
1226
- *
1227
- * @param msg - The message to be logged.
1228
- */
1229
- static info(msg) {
1230
- return this.get().info(msg);
1231
- }
1232
- /**
1233
- * @description Logs an info message.
1234
- * @summary Delegates the info logging to the global logger instance.
1235
- *
1236
- * @param msg - The message to be logged.
1237
- */
1238
- static trace(msg) {
1239
- return this.get().trace(msg);
1240
- }
1241
- /**
1242
- * @description Logs a debug message.
1243
- * @summary Delegates the debug logging to the global logger instance.
1244
- *
1245
- * @param msg - The message to be logged.
1246
- */
1247
- static debug(msg) {
1248
- return this.get().debug(msg);
1249
- }
1250
- /**
1251
- * @description Logs a benchmark message.
1252
- * @summary Delegates the benchmark logging to the global logger instance.
1253
- *
1254
- * @param msg - The message to be logged.
1255
- */
1256
- static benchmark(msg) {
1257
- return this.get().benchmark(msg);
1258
- }
1259
- /**
1260
- * @description Logs a silly message.
1261
- * @summary Delegates the debug logging to the global logger instance.
1262
- *
1263
- * @param msg - The message to be logged.
1264
- */
1265
- static silly(msg) {
1266
- return this.get().silly(msg);
1267
- }
1268
- /**
1269
- * @description Logs a silly message.
1270
- * @summary Delegates the debug logging to the global logger instance.
1271
- *
1272
- * @param msg - The message to be logged.
1273
- */
1274
- static warn(msg) {
1275
- return this.get().warn(msg);
1276
- }
1277
- /**
1278
- * @description Logs an error message.
1279
- * @summary Delegates the error logging to the global logger instance.
1280
- *
1281
- * @param msg - The message to be logged.
1282
- * @param e
1283
- */
1284
- static error(msg, e) {
1285
- return this.get().error(msg, e);
1286
- }
1287
- /**
1288
- * @description Creates a logger for a specific object or context
1289
- * @summary Creates a new logger instance for the given object or context using the factory function
1290
- * @param {LoggingContext} object - The object, class, or context to create a logger for
1291
- * @param {Partial<LoggingConfig>} [config] - Optional configuration to override global settings
1292
- * @param {...any} args - Additional arguments to pass to the logger factory
1293
- * @return {Logger} A new logger instance for the specified object or context
1294
- */
1295
- static for(object, config, ...args) {
1296
- object =
1297
- typeof object === "string"
1298
- ? object
1299
- : object.constructor
1300
- ? object.constructor.name
1301
- : object.name;
1302
- return this._factory(object, config, ...args);
1303
- }
1304
- /**
1305
- * @description Creates a logger for a specific reason or correlation context
1306
- * @summary Utility to quickly create a logger labeled with a free-form reason and optional identifier
1307
- * so that ad-hoc operations can be traced without tying the logger to a class or method name.
1308
- * @param {string} reason - A textual reason or context label for this logger instance
1309
- * @param {string} [id] - Optional identifier to help correlate related log entries
1310
- * @return {Logger} A new logger instance labeled with the provided reason and id
1311
- */
1312
- static because(reason, id) {
1313
- return this._factory(reason, this._config, id);
1314
- }
1315
- /**
1316
- * @description Applies theme styling to text
1317
- * @summary Applies styling (colors, formatting) to text based on the theme configuration
1318
- * @param {string} text - The text to style
1319
- * @param {string} type - The type of element to style (e.g., "class", "message", "logLevel")
1320
- * @param {LogLevel} loggerLevel - The log level to use for styling
1321
- * @param {Theme} [template=DefaultTheme] - The theme to use for styling
1322
- * @return {string} The styled text
1323
- * @mermaid
1324
- * sequenceDiagram
1325
- * participant Caller
1326
- * participant Theme as Logging.theme
1327
- * participant Apply as apply function
1328
- * participant Style as styled-string-builder
1329
- *
1330
- * Caller->>Theme: theme(text, type, loggerLevel)
1331
- * Theme->>Theme: Check if styling is enabled
1332
- * alt styling disabled
1333
- * Theme-->>Caller: return original text
1334
- * else styling enabled
1335
- * Theme->>Theme: Get theme for type
1336
- * alt theme not found
1337
- * Theme-->>Caller: return original text
1338
- * else theme found
1339
- * Theme->>Theme: Determine actual theme based on log level
1340
- * Theme->>Apply: Apply each style property
1341
- * Apply->>Style: Apply colors and formatting
1342
- * Style-->>Apply: Return styled text
1343
- * Apply-->>Theme: Return styled text
1344
- * Theme-->>Caller: Return final styled text
1345
- * end
1346
- * end
1347
- */
1348
- static theme(text, type, loggerLevel, template = DefaultTheme) {
1349
- if (!this._config.style)
1350
- return text;
1351
- function apply(txt, option, value) {
1352
- try {
1353
- const t = txt;
1354
- let c = style(t);
1355
- function applyColor(val, isBg = false) {
1356
- let f = isBg ? c.background : c.foreground;
1357
- if (!Array.isArray(val)) {
1358
- return f.call(c, value);
1359
- }
1360
- switch (val.length) {
1361
- case 1:
1362
- f = isBg ? c.bgColor256 : c.color256;
1363
- return f(val[0]);
1364
- case 3:
1365
- f = isBg ? c.bgRgb : c.rgb;
1366
- return c.rgb(val[0], val[1], val[2]);
1367
- default:
1368
- console.error(`Not a valid color option: ${option}`);
1369
- return style(t);
1370
- }
1371
- }
1372
- function applyStyle(v) {
1373
- if (typeof v === "number") {
1374
- c = c.style(v);
1375
- }
1376
- else {
1377
- c = c[v];
1378
- }
1379
- }
1380
- switch (option) {
1381
- case "bg":
1382
- case "fg":
1383
- return applyColor(value).text;
1384
- case "style":
1385
- if (Array.isArray(value)) {
1386
- value.forEach(applyStyle);
1387
- }
1388
- else {
1389
- applyStyle(value);
1390
- }
1391
- return c.text;
1392
- default:
1393
- console.error(`Not a valid theme option: ${option}`);
1394
- return t;
1395
- }
1396
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
1397
- }
1398
- catch (e) {
1399
- console.error(`Error applying style: ${option} with value ${value}`);
1400
- return txt;
1401
- }
1402
- }
1403
- const individualTheme = template[type];
1404
- if (!individualTheme || !Object.keys(individualTheme).length) {
1405
- return text;
1406
- }
1407
- let actualTheme = individualTheme;
1408
- const logLevels = Object.assign({}, LogLevel);
1409
- if (Object.keys(individualTheme)[0] in logLevels)
1410
- actualTheme =
1411
- individualTheme[loggerLevel] || {};
1412
- return Object.keys(actualTheme).reduce((acc, key) => {
1413
- const val = actualTheme[key];
1414
- if (val)
1415
- return apply(acc, key, val);
1416
- return acc;
1417
- }, text);
1418
- }
1419
- }
1420
-
1421
- /**
1422
- * @description Base class that provides a ready-to-use logger instance.
1423
- * @summary Supplies inheriting classes with a lazily created, context-aware {@link Logger} via the protected `log` getter, promoting consistent structured logging without manual wiring.
1424
- * @class LoggedClass
1425
- * @example
1426
- * class UserService extends LoggedClass {
1427
- * create(user: User) {
1428
- * this.log.info(`Creating user ${user.id}`);
1429
- * }
1430
- * }
1431
- *
1432
- * const svc = new UserService();
1433
- * svc.create({ id: "42" });
1434
- * @mermaid
1435
- * sequenceDiagram
1436
- * participant Client
1437
- * participant Instance as Subclass Instance
1438
- * participant Getter as LoggedClass.log
1439
- * participant Logging as Logging
1440
- * participant Logger as Logger
1441
- *
1442
- * Client->>Instance: call someMethod()
1443
- * Instance->>Getter: access this.log
1444
- * Getter->>Logging: Logging.for(this)
1445
- * Logging-->>Getter: return Logger
1446
- * Getter-->>Instance: return Logger
1447
- * Instance->>Logger: info/debug/error(...)
1448
- */
1449
- class LoggedClass {
1450
- /**
1451
- * @description Lazily provides a context-aware logger for the current instance.
1452
- * @summary Calls {@link Logging.for} with the subclass instance to obtain a logger whose context matches the subclass name.
1453
- * @return {Logger} Logger bound to the subclass context.
1454
- */
1455
- get log() {
1456
- if (!this._log)
1457
- this._log = Logging.for(this);
1458
- return this._log;
1459
- }
1460
- constructor() { }
1461
- }
1462
-
1463
- /**
1464
- * @description Base class for message filters that plug into the logging pipeline.
1465
- * @summary Extends {@link LoggedClass} to supply a scoped logger and defines the contract required by {@link LoggingFilter} implementers that transform or drop log messages before emission.
1466
- * @class LogFilter
1467
- * @example
1468
- * class RedactSecretsFilter extends LogFilter {
1469
- * filter(config: LoggingConfig, message: string): string {
1470
- * return message.replace(/secret/gi, "***");
1471
- * }
1472
- * }
1473
- *
1474
- * const filter = new RedactSecretsFilter();
1475
- * filter.filter({ ...DefaultLoggingConfig, verbose: 0 }, "secret token");
1476
- * @mermaid
1477
- * sequenceDiagram
1478
- * participant Logger
1479
- * participant Filter as LogFilter
1480
- * participant Impl as ConcreteFilter
1481
- * participant Output
1482
- * Logger->>Filter: filter(config, message, context)
1483
- * Filter->>Impl: delegate to subclass implementation
1484
- * Impl-->>Filter: transformed message
1485
- * Filter-->>Output: return filtered message
1486
- */
1487
- class LogFilter extends LoggedClass {
1488
- /**
1489
- * @description Scoped logger that excludes other filters from the chain.
1490
- * @summary Returns a child logger dedicated to the filter, preventing recursive filter invocation when emitting diagnostic messages.
1491
- * @return {Logger} Context-aware logger for the filter instance.
1492
- */
1493
- get log() {
1494
- return super.log.for(this, { filters: [] });
1495
- }
1496
- }
1497
-
1498
- function safeNow() {
1499
- // Prefer performance.now when available
1500
- if (typeof globalThis !== "undefined" &&
1501
- typeof globalThis.performance?.now === "function") {
1502
- return () => globalThis.performance.now();
1503
- }
1504
- // Node: use process.hrtime.bigint for higher precision if available
1505
- if (typeof process !== "undefined" &&
1506
- typeof process.hrtime?.bigint === "function") {
1507
- return () => {
1508
- const ns = process.hrtime.bigint(); // nanoseconds
1509
- return Number(ns) / 1_000_000; // to ms
1510
- };
1511
- }
1512
- // Fallback
1513
- return () => Date.now();
1514
- }
1515
- /**
1516
- * @description High-resolution clock accessor returning milliseconds.
1517
- * @summary Chooses the most precise timer available in the current runtime, preferring `performance.now` or `process.hrtime.bigint`.
1518
- * @return {number} Milliseconds elapsed according to the best available clock.
1519
- */
1520
- const now = safeNow();
1521
- /**
1522
- * @description High-resolution stopwatch with pause, resume, and lap tracking.
1523
- * @summary Tracks elapsed time using the highest precision timer available, supports pausing, resuming, and recording labeled laps for diagnostics and benchmarking.
1524
- * @param {boolean} [autoStart=false] - When true, the stopwatch starts immediately upon construction.
1525
- * @class StopWatch
1526
- * @example
1527
- * const sw = new StopWatch(true);
1528
- * // ... work ...
1529
- * const lap = sw.lap("phase 1");
1530
- * sw.pause();
1531
- * console.log(`Elapsed: ${lap.totalMs}ms`);
1532
- * @mermaid
1533
- * sequenceDiagram
1534
- * participant Client
1535
- * participant StopWatch
1536
- * participant Clock as now()
1537
- * Client->>StopWatch: start()
1538
- * StopWatch->>Clock: now()
1539
- * Clock-->>StopWatch: timestamp
1540
- * Client->>StopWatch: lap()
1541
- * StopWatch->>Clock: now()
1542
- * Clock-->>StopWatch: timestamp
1543
- * StopWatch-->>Client: Lap
1544
- * Client->>StopWatch: pause()
1545
- * StopWatch->>Clock: now()
1546
- * Clock-->>StopWatch: timestamp
1547
- */
1548
- class StopWatch {
1549
- constructor(autoStart = false) {
1550
- this._startMs = null;
1551
- this._elapsedMs = 0;
1552
- this._running = false;
1553
- this._laps = [];
1554
- this._lastLapTotalMs = 0;
1555
- if (autoStart)
1556
- this.start();
1557
- }
1558
- /**
1559
- * @description Indicates whether the stopwatch is actively running.
1560
- * @summary Returns `true` when timing is in progress and `false` when paused or stopped.
1561
- * @return {boolean} Current running state.
1562
- */
1563
- get running() {
1564
- return this._running;
1565
- }
1566
- /**
1567
- * @description Elapsed time captured by the stopwatch.
1568
- * @summary Computes the total elapsed time in milliseconds, including the current session if running.
1569
- * @return {number} Milliseconds elapsed since the stopwatch started.
1570
- */
1571
- get elapsedMs() {
1572
- if (!this._running || this._startMs == null)
1573
- return this._elapsedMs;
1574
- return this._elapsedMs + (now() - this._startMs);
1575
- }
1576
- /**
1577
- * @description Starts timing if the stopwatch is not already running.
1578
- * @summary Records the current timestamp and transitions the stopwatch into the running state.
1579
- * @return {this} Fluent reference to the stopwatch.
1580
- */
1581
- start() {
1582
- if (!this._running) {
1583
- this._running = true;
1584
- this._startMs = now();
1585
- }
1586
- return this;
1587
- }
1588
- /**
1589
- * @description Pauses timing and accumulates elapsed milliseconds.
1590
- * @summary Captures the partial duration, updates the accumulator, and keeps the stopwatch ready to resume later.
1591
- * @return {this} Fluent reference to the stopwatch.
1592
- */
1593
- pause() {
1594
- if (this._running && this._startMs != null) {
1595
- this._elapsedMs += now() - this._startMs;
1596
- this._startMs = null;
1597
- this._running = false;
1598
- }
1599
- return this;
1600
- }
1601
- /**
1602
- * @description Resumes timing after a pause.
1603
- * @summary Captures a fresh start timestamp while keeping previous elapsed time intact.
1604
- * @return {this} Fluent reference to the stopwatch.
1605
- */
1606
- resume() {
1607
- if (!this._running) {
1608
- this._running = true;
1609
- this._startMs = now();
1610
- }
1611
- return this;
1612
- }
1613
- /**
1614
- * @description Stops timing and returns the total elapsed milliseconds.
1615
- * @summary Invokes {@link StopWatch.pause} to consolidate elapsed time, leaving the stopwatch in a non-running state.
1616
- * @return {number} Milliseconds accumulated across all runs.
1617
- */
1618
- stop() {
1619
- this.pause();
1620
- return this._elapsedMs;
1621
- }
1622
- /**
1623
- * @description Resets the stopwatch state while optionally continuing to run.
1624
- * @summary Clears elapsed time and lap history, preserving whether the stopwatch should continue ticking.
1625
- * @return {this} Fluent reference to the stopwatch.
1626
- */
1627
- reset() {
1628
- const wasRunning = this._running;
1629
- this._startMs = wasRunning ? now() : null;
1630
- this._elapsedMs = 0;
1631
- this._laps = [];
1632
- this._lastLapTotalMs = 0;
1633
- return this;
1634
- }
1635
- /**
1636
- * @description Records a lap split since the stopwatch started or since the previous lap.
1637
- * @summary Stores the lap metadata, updates cumulative tracking, and returns the newly created {@link Lap}.
1638
- * @param {string} [label] - Optional label describing the lap.
1639
- * @return {Lap} Lap snapshot capturing incremental and cumulative timings.
1640
- */
1641
- lap(label) {
1642
- const total = this.elapsedMs;
1643
- const ms = total - this._lastLapTotalMs;
1644
- const lap = {
1645
- index: this._laps.length,
1646
- label,
1647
- ms,
1648
- totalMs: total,
1649
- };
1650
- this._laps.push(lap);
1651
- this._lastLapTotalMs = total;
1652
- return lap;
1653
- }
1654
- /**
1655
- * @description Retrieves the recorded lap history.
1656
- * @summary Returns the internal lap array as a read-only view to prevent external mutation.
1657
- * @return {Lap[]} Laps captured by the stopwatch.
1658
- */
1659
- get laps() {
1660
- return this._laps;
1661
- }
1662
- /**
1663
- * @description Formats the elapsed time in a human-readable representation.
1664
- * @summary Uses {@link formatMs} to produce an `hh:mm:ss.mmm` string for display and logging.
1665
- * @return {string} Elapsed time formatted for presentation.
1666
- */
1667
- toString() {
1668
- return formatMs(this.elapsedMs);
1669
- }
1670
- /**
1671
- * @description Serializes the stopwatch state.
1672
- * @summary Provides a JSON-friendly snapshot including running state, elapsed time, and lap details.
1673
- * @return {{running: boolean, elapsedMs: number, laps: Lap[]}} Serializable stopwatch representation.
1674
- */
1675
- toJSON() {
1676
- return {
1677
- running: this._running,
1678
- elapsedMs: this.elapsedMs,
1679
- laps: this._laps.slice(),
1680
- };
1681
- }
1682
- }
1683
- /**
1684
- * @description Formats milliseconds into `hh:mm:ss.mmm`.
1685
- * @summary Breaks the duration into hours, minutes, seconds, and milliseconds, returning a zero-padded string.
1686
- * @param {number} ms - Milliseconds to format.
1687
- * @return {string} Formatted duration string.
1688
- * @function formatMs
1689
- * @memberOf module:Logging
1690
- * @mermaid
1691
- * sequenceDiagram
1692
- * participant Caller
1693
- * participant Formatter as formatMs
1694
- * Caller->>Formatter: formatMs(ms)
1695
- * Formatter->>Formatter: derive hours/minutes/seconds
1696
- * Formatter->>Formatter: pad segments
1697
- * Formatter-->>Caller: hh:mm:ss.mmm
1698
- */
1699
- function formatMs(ms) {
1700
- const sign = ms < 0 ? "-" : "";
1701
- const abs = Math.abs(ms);
1702
- const hours = Math.floor(abs / 3_600_000);
1703
- const minutes = Math.floor((abs % 3_600_000) / 60_000);
1704
- const seconds = Math.floor((abs % 60_000) / 1000);
1705
- const millis = Math.floor(abs % 1000);
1706
- const pad = (n, w) => n.toString().padStart(w, "0");
1707
- return `${sign}${pad(hours, 2)}:${pad(minutes, 2)}:${pad(seconds, 2)}.${pad(millis, 3)}`;
1708
- }
1709
-
1710
- /**
1711
- * @description Method decorator for logging function calls.
1712
- * @summary Wraps class methods to automatically log entry, exit, timing, and optional custom messages at a configurable {@link LogLevel}.
1713
- * @param {LogLevel} level - Log level applied to the generated log statements (defaults to `LogLevel.info`).
1714
- * @param {number} [verbosity=0] - Verbosity threshold required for the entry log to appear.
1715
- * @param {ArgFormatFunction} [entryMessage] - Formatter invoked with the original method arguments to describe the invocation.
1716
- * @param {ReturnFormatFunction} [exitMessage] - Optional formatter that describes the outcome or failure of the call.
1717
- * @return {function(any, any, PropertyDescriptor): void} Method decorator proxy that injects logging behavior.
1718
- * @function log
1719
- * @mermaid
1720
- * sequenceDiagram
1721
- * participant Client
1722
- * participant Decorator as log decorator
1723
- * participant Method as Original Method
1724
- * participant Logger as Logging instance
1725
- *
1726
- * Client->>Decorator: call decorated method
1727
- * Decorator->>Logger: log method call
1728
- * Decorator->>Method: call original method
1729
- * alt result is Promise
1730
- * Method-->>Decorator: return Promise
1731
- * Decorator->>Decorator: attach then handler
1732
- * Note over Decorator: Promise resolves
1733
- * Decorator->>Logger: log benchmark (if enabled)
1734
- * Decorator-->>Client: return result
1735
- * else result is not Promise
1736
- * Method-->>Decorator: return result
1737
- * Decorator->>Logger: log benchmark (if enabled)
1738
- * Decorator-->>Client: return result
1739
- * end
1740
- * @category Method Decorators
1741
- */
1742
- function log(level = LogLevel.info, verbosity = 0, entryMessage = (...args) => `called with ${args}`, exitMessage) {
1743
- return function log(target, propertyKey, descriptor) {
1744
- if (!descriptor || typeof descriptor === "number")
1745
- throw new Error(`Logging decoration only applies to methods`);
1746
- const logger = target instanceof LoggedClass
1747
- ? target["log"].for(target[propertyKey])
1748
- : Logging.for(target).for(target[propertyKey]);
1749
- const method = logger[level].bind(logger);
1750
- const originalMethod = descriptor.value;
1751
- descriptor.value = new Proxy(originalMethod, {
1752
- apply(fn, thisArg, args) {
1753
- method(entryMessage(...args), verbosity);
1754
- try {
1755
- const result = Reflect.apply(fn, thisArg, args);
1756
- if (result instanceof Promise) {
1757
- return result
1758
- .then((r) => {
1759
- if (exitMessage)
1760
- method(exitMessage(undefined, r));
1761
- return r;
1762
- })
1763
- .catch((e) => {
1764
- if (exitMessage)
1765
- logger.error(exitMessage(e));
1766
- throw e;
1767
- });
1768
- }
1769
- if (exitMessage)
1770
- method(exitMessage(undefined, result));
1771
- return result;
1772
- }
1773
- catch (err) {
1774
- if (exitMessage)
1775
- logger.error(exitMessage(err));
1776
- throw err;
1777
- }
1778
- },
1779
- });
1780
- return descriptor;
1781
- };
1782
- }
1783
- /**
1784
- * @description Method decorator that records execution time at the benchmark level.
1785
- * @summary Wraps the target method to emit {@link Logger.benchmark} entries capturing completion time or failure latency.
1786
- * @return {function(any, any, PropertyDescriptor): void} Method decorator proxy that benchmarks the original implementation.
1787
- * @function benchmark
1788
- * @mermaid
1789
- * sequenceDiagram
1790
- * participant Caller
1791
- * participant Decorator as benchmark
1792
- * participant Method as Original Method
1793
- * Caller->>Decorator: invoke()
1794
- * Decorator->>Method: Reflect.apply(...)
1795
- * alt Promise result
1796
- * Method-->>Decorator: Promise
1797
- * Decorator->>Decorator: attach then()
1798
- * Decorator->>Decorator: log completion duration
1799
- * else Synchronous result
1800
- * Method-->>Decorator: value
1801
- * Decorator->>Decorator: log completion duration
1802
- * end
1803
- * Decorator-->>Caller: return result
1804
- * @category Method Decorators
1805
- */
1806
- function benchmark() {
1807
- return function benchmark(target, propertyKey, descriptor) {
1808
- if (!descriptor || typeof descriptor === "number")
1809
- throw new Error(`benchmark decoration only applies to methods`);
1810
- const logger = target instanceof LoggedClass
1811
- ? target["log"].for(target[propertyKey])
1812
- : Logging.for(target).for(target[propertyKey]);
1813
- const originalMethod = descriptor.value;
1814
- descriptor.value = new Proxy(originalMethod, {
1815
- apply(fn, thisArg, args) {
1816
- const start = now();
1817
- try {
1818
- const result = Reflect.apply(fn, thisArg, args);
1819
- if (result instanceof Promise) {
1820
- return result
1821
- .then((r) => {
1822
- logger.benchmark(`completed in ${now() - start}ms`);
1823
- return r;
1824
- })
1825
- .catch((e) => {
1826
- logger.benchmark(`failed in ${now() - start}ms`);
1827
- throw e;
1828
- });
1829
- }
1830
- logger.benchmark(`completed in ${now() - start}ms`);
1831
- return result;
1832
- }
1833
- catch (err) {
1834
- logger.benchmark(`failed in ${now() - start}ms`);
1835
- throw err;
1836
- }
1837
- },
1838
- });
1839
- return descriptor;
1840
- };
1841
- }
1842
- /**
1843
- * @description Method decorator for logging function calls with debug level.
1844
- * @summary Convenience wrapper around {@link log} that logs using `LogLevel.debug`.
1845
- * @return {function(any, any, PropertyDescriptor): void} Debug-level logging decorator.
1846
- * @function debug
1847
- * @category Method Decorators
1848
- */
1849
- function debug() {
1850
- return log(LogLevel.debug, 0, (...args) => `called with ${args}`, (e, result) => e
1851
- ? `Failed with: ${e}`
1852
- : result
1853
- ? `Completed with ${JSON.stringify(result)}`
1854
- : "completed");
1855
- }
1856
- /**
1857
- * @description Method decorator for logging function calls with info level.
1858
- * @summary Convenience wrapper around {@link log} that logs using `LogLevel.info`.
1859
- * @return {function(any, any, PropertyDescriptor): void} Info-level logging decorator.
1860
- * @function info
1861
- * @category Method Decorators
1862
- */
1863
- function info() {
1864
- return log(LogLevel.info);
1865
- }
1866
- /**
1867
- * @description Method decorator for logging function calls with silly level.
1868
- * @summary Convenience wrapper around {@link log} that logs using `LogLevel.silly`.
1869
- * @return {function(any, any, PropertyDescriptor): void} Silly-level logging decorator.
1870
- * @function silly
1871
- * @category Method Decorators
1872
- */
1873
- function silly() {
1874
- return log(LogLevel.silly);
1875
- }
1876
- /**
1877
- * @description Method decorator for logging function calls with trace level.
1878
- * @summary Convenience wrapper around {@link log} that logs using `LogLevel.trace`.
1879
- * @return {function(any, any, PropertyDescriptor): void} Trace-level logging decorator.
1880
- * @function trace
1881
- * @category Method Decorators
1882
- */
1883
- function trace() {
1884
- return log(LogLevel.trace);
1885
- }
1886
- /**
1887
- * @description Method decorator for logging function calls with verbose level.
1888
- * @summary Convenience wrapper around {@link log} that logs using `LogLevel.verbose` with configurable verbosity and optional benchmarking.
1889
- * @param {number|boolean} verbosity - Verbosity level for log filtering or flag to enable benchmarking.
1890
- * @return {function(any, any,PropertyDescriptor): void} Verbose logging decorator.
1891
- * @function verbose
1892
- * @category Method Decorators
1893
- */
1894
- function verbose(verbosity = 0) {
1895
- if (!verbosity) {
1896
- verbosity = 0;
1897
- }
1898
- return log(LogLevel.verbose, verbosity);
1899
- }
1900
- /**
1901
- * @description Creates a decorator that makes a method non-configurable.
1902
- * @summary Prevents overriding by marking the method descriptor as non-configurable, throwing if applied to non-method targets.
1903
- * @return {function(object, any, PropertyDescriptor): PropertyDescriptor|undefined} Decorator that hardens the method descriptor.
1904
- * @function final
1905
- * @category Method Decorators
1906
- */
1907
- function final() {
1908
- return (target, propertyKey, descriptor) => {
1909
- if (!descriptor)
1910
- throw new Error("final decorator can only be used on methods");
1911
- if (descriptor?.configurable) {
1912
- descriptor.configurable = false;
1913
- }
1914
- return descriptor;
1915
- };
1916
- }
1917
-
1918
- /**
1919
- * @description Filter that patches log messages using regular expressions.
1920
- * @summary Applies a configured {@link RegExp} and replacement strategy to redact, mask, or restructure log payloads before they are emitted.
1921
- * @param {RegExp} regexp - Expression used to detect sensitive or formatted text.
1922
- * @param {string|ReplacementFunction} replacement - Replacement string or callback invoked for each match.
1923
- * @class PatternFilter
1924
- * @example
1925
- * const filter = new PatternFilter(/token=[^&]+/g, "token=***");
1926
- * const sanitized = filter.filter(config, "token=123&user=tom", []);
1927
- * // sanitized === "token=***&user=tom"
1928
- * @mermaid
1929
- * sequenceDiagram
1930
- * participant Logger
1931
- * participant Filter as PatternFilter
1932
- * participant RegExp
1933
- * Logger->>Filter: filter(config, message, context)
1934
- * Filter->>RegExp: execute match()
1935
- * alt match found
1936
- * RegExp-->>Filter: captures
1937
- * Filter->>RegExp: replace(message, replacement)
1938
- * RegExp-->>Filter: transformed message
1939
- * else no match
1940
- * RegExp-->>Filter: null
1941
- * end
1942
- * Filter-->>Logger: sanitized message
1943
- */
1944
- class PatternFilter extends LogFilter {
1945
- constructor(regexp, replacement) {
1946
- super();
1947
- this.regexp = regexp;
1948
- this.replacement = replacement;
1949
- }
1950
- /**
1951
- * @description Ensures deterministic RegExp matching.
1952
- * @summary Runs the configured expression, then resets its state so repeated invocations behave consistently.
1953
- * @param {string} message - Message to test for matches.
1954
- * @return {RegExpExecArray|null} Match result or null when no match is found.
1955
- */
1956
- match(message) {
1957
- const match = this.regexp.exec(message);
1958
- this.regexp.lastIndex = 0;
1959
- return match;
1960
- }
1961
- /**
1962
- * @description Applies the replacement strategy to the incoming message.
1963
- * @summary Executes {@link PatternFilter.match} and, when a match is found, replaces every occurrence using the configured replacement handler.
1964
- * @param {LoggingConfig} config - Active logging configuration (unused but part of the filter contract).
1965
- * @param {string} message - Message to be sanitized.
1966
- * @param {string[]} context - Context entries associated with the log event.
1967
- * @return {string} Sanitized log message.
1968
- */
1969
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
1970
- filter(config, message, context) {
1971
- const log = this.log.for(this.filter);
1972
- const match = this.match(message);
1973
- if (!match)
1974
- return message;
1975
- try {
1976
- return message.replace(this.regexp, this.replacement);
1977
- }
1978
- catch (e) {
1979
- log.error(`PatternFilter replacement error: ${e}`);
1980
- }
1981
- return "";
1982
- }
1983
- }
1984
- __decorate([
1985
- final(),
1986
- __metadata("design:type", Function),
1987
- __metadata("design:paramtypes", [String]),
1988
- __metadata("design:returntype", void 0)
1989
- ], PatternFilter.prototype, "match", null);
1990
-
1991
- function isClass(value) {
1992
- if (typeof value !== "function")
1993
- return false;
1994
- // 1) Native ES class? (fast path)
1995
- // e.g., "class Foo { ... }" → source starts with "class"
1996
- try {
1997
- const src = Function.prototype.toString.call(value);
1998
- if (/^\s*class[\s{]/.test(src))
1999
- return true;
2000
- }
2001
- catch {
2002
- // Some environments may block .toString; ignore and continue.
2003
- }
2004
- // 2) Has a prototype at all? (filters out arrow funcs, bound funcs)
2005
- const protoDesc = Object.getOwnPropertyDescriptor(value, "prototype");
2006
- if (!protoDesc || !protoDesc.value)
2007
- return false;
2008
- // 3) In native classes, the "prototype" property is non-writable.
2009
- // (In plain functions, it's writable.) This is a strong signal.
2010
- if (protoDesc.writable === false)
2011
- return true;
2012
- // 4) Classic constructor or transpiled class:
2013
- // Must have its own "constructor" and at least one prototype method.
2014
- const proto = value.prototype;
2015
- if (!Object.prototype.hasOwnProperty.call(proto, "constructor"))
2016
- return false;
2017
- const names = Object.getOwnPropertyNames(proto).filter((n) => n !== "constructor");
2018
- return names.length > 0;
2019
- }
2020
-
2021
- /**
2022
- * @description Comprehensive logging toolkit for browser and Node environments.
2023
- * @summary Exposes {@link Logging} and {@link MiniLogger} for runtime logging, decorators such as {@link log} for method instrumentation, and utilities like {@link PatternFilter}, {@link StopWatch}, and {@link LoggedEnvironment} to build configurable, theme-aware log pipelines.
2024
- * @module Logging
2025
- */
2026
- /**
2027
- * @description Current package version string.
2028
- * @summary Stores the package version for diagnostics and compatibility checks.
2029
- * @const VERSION
2030
- * @type {string}
2031
- * @memberOf module:Logging
2032
- */
2033
- const VERSION = "0.3.26";
2034
- /**
2035
- * @description Current package version string.
2036
- * @summary Stores the package version for diagnostics and compatibility checks.
2037
- * @const PACKAGE_NAME
2038
- * @type {string}
2039
- * @memberOf module:Logging
2040
- */
2041
- const PACKAGE_NAME = "@decaf-ts/logging";
2042
-
2043
- export { BrowserEnvKey, DefaultLoggingConfig, DefaultPlaceholderWrappers, DefaultTheme, ENV_PATH_DELIMITER, Environment, LogFilter, LogLevel, LoggedClass, LoggedEnvironment, Logging, LoggingMode, MiniLogger, NumericLogLevels, PACKAGE_NAME, PatternFilter, StopWatch, VERSION, benchmark, debug, escapeRegExp, final, formatMs, info, isBrowser, isClass, log, now, padEnd, patchPlaceholders, patchString, sf, silly, stringFormat, toCamelCase, toENVFormat, toKebabCase, toPascalCase, toSnakeCase, trace, verbose };
2044
- //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibG9nZ2luZy5lc20uY2pzIiwic291cmNlcyI6WyIuLi9zcmMvY29uc3RhbnRzLnRzIiwiLi4vc3JjL3RleHQudHMiLCIuLi9zcmMvd2ViLnRzIiwiLi4vc3JjL2Vudmlyb25tZW50LnRzIiwiLi4vc3JjL2xvZ2dpbmcudHMiLCIuLi9zcmMvTG9nZ2VkQ2xhc3MudHMiLCIuLi9zcmMvZmlsdGVycy9Mb2dGaWx0ZXIudHMiLCIuLi9zcmMvdGltZS50cyIsIi4uL3NyYy9kZWNvcmF0b3JzLnRzIiwiLi4vc3JjL2ZpbHRlcnMvUGF0dGVybkZpbHRlci50cyIsIi4uL3NyYy91dGlscy50cyIsIi4uL3NyYy9pbmRleC50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBMb2dnaW5nQ29uZmlnLCBUaGVtZSB9IGZyb20gXCIuL3R5cGVzXCI7XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIEdsb2JhbCBrZXkgdXNlZCB0byBzdG9yZSBlbnZpcm9ubWVudCB2YXJpYWJsZXMgaW4gYnJvd3NlciBjb250ZXh0cy5cbiAqIEBzdW1tYXJ5IEVuYWJsZXMgdGhlIGxvZ2dpbmcgZW52aXJvbm1lbnQgaGVscGVycyB0byBsb2NhdGUgc2VyaWFsaXplZCBlbnZpcm9ubWVudCBjb25maWd1cmF0aW9uIG9uIGBnbG9iYWxUaGlzYC5cbiAqIEBjb25zdCBCcm93c2VyRW52S2V5XG4gKiBAdHlwZSB7c3RyaW5nfVxuICogQG1lbWJlck9mIG1vZHVsZTpMb2dnaW5nXG4gKi9cbmV4cG9ydCBjb25zdCBCcm93c2VyRW52S2V5ID0gXCJFTlZcIjtcblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gRGVsaW1pdGVyIHVzZWQgZm9yIGNvbXBvc2luZyBuZXN0ZWQgZW52aXJvbm1lbnQgdmFyaWFibGUgbmFtZXMuXG4gKiBAc3VtbWFyeSBKb2lucyBwYXJlbnQgYW5kIGNoaWxkIGtleXMgd2hlbiBtYXBwaW5nIG9iamVjdCBwYXRocyB0byBFTlYgc3RyaW5ncy5cbiAqIEBjb25zdCBFTlZfUEFUSF9ERUxJTUlURVJcbiAqIEB0eXBlIHtzdHJpbmd9XG4gKiBAbWVtYmVyT2YgbW9kdWxlOkxvZ2dpbmdcbiAqL1xuZXhwb3J0IGNvbnN0IEVOVl9QQVRIX0RFTElNSVRFUiA9IFwiX19cIjtcblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gRGVmYXVsdCBwcmVmaXggYW5kIHN1ZmZpeCB1c2VkIGZvciB0ZW1wbGF0ZSBwbGFjZWhvbGRlcnMuXG4gKiBAc3VtbWFyeSBQcm92aWRlcyB3cmFwcGVyIHN0cmluZ3MgYXBwbGllZCB3aGVuIGludGVycG9sYXRpbmcgbWVzc2FnZXMgd2l0aCB7QGxpbmsgcGF0Y2hQbGFjZWhvbGRlcnN9LlxuICogQGNvbnN0IERlZmF1bHRQbGFjZWhvbGRlcldyYXBwZXJzXG4gKiBAdHlwZSB7c3RyaW5nW119XG4gKiBAbWVtYmVyT2YgbW9kdWxlOkxvZ2dpbmdcbiAqL1xuZXhwb3J0IGNvbnN0IERlZmF1bHRQbGFjZWhvbGRlcldyYXBwZXJzID0gW1wiJHtcIiwgXCJ9XCJdO1xuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBFbnVtIGZvciBsb2cgbGV2ZWxzLlxuICogQHN1bW1hcnkgRGVmaW5lcyBkaWZmZXJlbnQgbGV2ZWxzIG9mIGxvZ2dpbmcgZm9yIHRoZSBhcHBsaWNhdGlvbi5cbiAqIEBlbnVtIHtzdHJpbmd9XG4gKiBAcmVhZG9ubHlcbiAqIEBtZW1iZXJPZiBtb2R1bGU6TG9nZ2luZ1xuICovXG5leHBvcnQgZW51bSBMb2dMZXZlbCB7XG4gIC8qKiBAZGVzY3JpcHRpb24gQmVuY2htYXJrIGV2ZW50cyB0aGF0IGNhcHR1cmUgcGVyZm9ybWFuY2UgbWV0cmljcy4gKi9cbiAgYmVuY2htYXJrID0gXCJiZW5jaG1hcmtcIixcbiAgLyoqIEBkZXNjcmlwdGlvbiBFcnJvciBldmVudHMgdGhhdCBpbmRpY2F0ZSBmYWlsdXJlcyByZXF1aXJpbmcgYXR0ZW50aW9uLiAqL1xuICBlcnJvciA9IFwiZXJyb3JcIixcbiAgLyoqIEBkZXNjcmlwdGlvbiBXYXJuaW5nIGV2ZW50cyB0aGF0IG1heSBpbmRpY2F0ZSBpc3N1ZXMuICovXG4gIHdhcm4gPSBcIndhcm5cIixcbiAgLyoqIEBkZXNjcmlwdGlvbiBJbmZvcm1hdGlvbmFsIGV2ZW50cyBkZXNjcmliaW5nIG5vcm1hbCBvcGVyYXRpb24uICovXG4gIGluZm8gPSBcImluZm9cIixcbiAgLyoqIEBkZXNjcmlwdGlvbiBWZXJib3NlIGRpYWdub3N0aWMgaW5mb3JtYXRpb24gZm9yIGRldGFpbGVkIHRyYWNpbmcuICovXG4gIHZlcmJvc2UgPSBcInZlcmJvc2VcIixcbiAgLyoqIEBkZXNjcmlwdGlvbiBEZWJ1ZyBvciB0cmFjZSBkZXRhaWxzIGFpbWVkIGF0IGRldmVsb3BlcnMuICovXG4gIGRlYnVnID0gXCJkZWJ1Z1wiLFxuICAvKiogQGRlc2NyaXB0aW9uIHRyYWNlIGRldGFpbHMgYWltZWQgYXQgZGV2ZWxvcGVycyAqL1xuICB0cmFjZSA9IFwidHJhY2VcIixcbiAgLyoqIEBkZXNjcmlwdGlvbiBFeHRyZW1lbHkgY2hhdHR5IG9yIHBsYXlmdWwgbG9nIGVudHJpZXMuICovXG4gIHNpbGx5ID0gXCJzaWxseVwiLFxufVxuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBOdW1lcmljIHZhbHVlcyBhc3NvY2lhdGVkIHdpdGggbG9nIGxldmVscy5cbiAqIEBzdW1tYXJ5IFByb3ZpZGVzIGEgbnVtZXJpYyByZXByZXNlbnRhdGlvbiBvZiBsb2cgbGV2ZWxzIGZvciBjb21wYXJpc29uIGFuZCBmaWx0ZXJpbmcuXG4gKiBAdHlwZWRlZiB7T2JqZWN0fSBOdW1lcmljTG9nTGV2ZWxzU2hhcGVcbiAqIEBwcm9wZXJ0eSB7bnVtYmVyfSBiZW5jaG1hcmsgLSBOdW1lcmljIHZhbHVlIGZvciBiZW5jaG1hcmsgbGV2ZWwgKDApLlxuICogQHByb3BlcnR5IHtudW1iZXJ9IGVycm9yIC0gTnVtZXJpYyB2YWx1ZSBmb3IgZXJyb3IgbGV2ZWwgKDIpLlxuICogQHByb3BlcnR5IHtudW1iZXJ9IGluZm8gLSBOdW1lcmljIHZhbHVlIGZvciBpbmZvIGxldmVsICg0KS5cbiAqIEBwcm9wZXJ0eSB7bnVtYmVyfSB2ZXJib3NlIC0gTnVtZXJpYyB2YWx1ZSBmb3IgdmVyYm9zZSBsZXZlbCAoNikuXG4gKiBAcHJvcGVydHkge251bWJlcn0gZGVidWcgLSBOdW1lcmljIHZhbHVlIGZvciBkZWJ1ZyBsZXZlbCAoNykuXG4gKiBAcHJvcGVydHkge251bWJlcn0gc2lsbHkgLSBOdW1lcmljIHZhbHVlIGZvciBzaWxseSBsZXZlbCAoOSkuXG4gKiBAbWVtYmVyT2YgbW9kdWxlOkxvZ2dpbmdcbiAqL1xuLyoqXG4gKiBAZGVzY3JpcHRpb24gTnVtZXJpYyB2YWx1ZXMgYXNzb2NpYXRlZCB3aXRoIGxvZyBsZXZlbHMuXG4gKiBAc3VtbWFyeSBQcm92aWRlcyBhIG51bWVyaWMgcmVwcmVzZW50YXRpb24gb2YgbG9nIGxldmVscyBmb3IgY29tcGFyaXNvbiBhbmQgZmlsdGVyaW5nLlxuICogQGNvbnN0IE51bWVyaWNMb2dMZXZlbHNcbiAqIEB0eXBlIHtOdW1lcmljTG9nTGV2ZWxzU2hhcGV9XG4gKiBAbWVtYmVyT2YgbW9kdWxlOkxvZ2dpbmdcbiAqL1xuZXhwb3J0IGNvbnN0IE51bWVyaWNMb2dMZXZlbHMgPSB7XG4gIGJlbmNobWFyazogMCxcbiAgZXJyb3I6IDMsXG4gIHdhcm46IDYsXG4gIGluZm86IDksXG4gIHZlcmJvc2U6IDEyLFxuICBkZWJ1ZzogMTUsXG4gIHRyYWNlOiAxOCxcbiAgc2lsbHk6IDIxLFxufTtcblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gRW51bSBmb3IgbG9nZ2luZyBvdXRwdXQgbW9kZXMuXG4gKiBAc3VtbWFyeSBEZWZpbmVzIGRpZmZlcmVudCBvdXRwdXQgZm9ybWF0cyBmb3IgbG9nIG1lc3NhZ2VzLlxuICogQGVudW0ge3N0cmluZ31cbiAqIEBtZW1iZXJPZiBtb2R1bGU6TG9nZ2luZ1xuICovXG5leHBvcnQgZW51bSBMb2dnaW5nTW9kZSB7XG4gIC8qKiBSYXcgdGV4dCBmb3JtYXQgZm9yIGh1bWFuIHJlYWRhYmlsaXR5ICovXG4gIFJBVyA9IFwicmF3XCIsXG4gIC8qKiBKU09OIGZvcm1hdCBmb3IgbWFjaGluZSBwYXJzaW5nICovXG4gIEpTT04gPSBcImpzb25cIixcbn1cblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gRGVmYXVsdCB0aGVtZSBmb3Igc3R5bGluZyBsb2cgb3V0cHV0LlxuICogQHN1bW1hcnkgRGVmaW5lcyB0aGUgZGVmYXVsdCBjb2xvciBhbmQgc3R5bGUgc2V0dGluZ3MgZm9yIHZhcmlvdXMgY29tcG9uZW50cyBvZiBsb2cgbWVzc2FnZXMuXG4gKiBAdHlwZWRlZiB7VGhlbWV9IERlZmF1bHRUaGVtZVxuICogQHByb3BlcnR5IHtPYmplY3R9IGNsYXNzIC0gU3R5bGluZyBmb3IgY2xhc3MgbmFtZXMuXG4gKiBAcHJvcGVydHkge251bWJlcn0gY2xhc3MuZmcgLSBGb3JlZ3JvdW5kIGNvbG9yIGNvZGUgZm9yIGNsYXNzIG5hbWVzICgzNCkuXG4gKiBAcHJvcGVydHkge09iamVjdH0gaWQgLSBTdHlsaW5nIGZvciBpZGVudGlmaWVycy5cbiAqIEBwcm9wZXJ0eSB7bnVtYmVyfSBpZC5mZyAtIEZvcmVncm91bmQgY29sb3IgY29kZSBmb3IgaWRlbnRpZmllcnMgKDM2KS5cbiAqIEBwcm9wZXJ0eSB7T2JqZWN0fSBzdGFjayAtIFN0eWxpbmcgZm9yIHN0YWNrIHRyYWNlcyAoZW1wdHkgb2JqZWN0KS5cbiAqIEBwcm9wZXJ0eSB7T2JqZWN0fSB0aW1lc3RhbXAgLSBTdHlsaW5nIGZvciB0aW1lc3RhbXBzIChlbXB0eSBvYmplY3QpLlxuICogQHByb3BlcnR5IHtPYmplY3R9IG1lc3NhZ2UgLSBTdHlsaW5nIGZvciBkaWZmZXJlbnQgdHlwZXMgb2YgbWVzc2FnZXMuXG4gKiBAcHJvcGVydHkge09iamVjdH0gbWVzc2FnZS5lcnJvciAtIFN0eWxpbmcgZm9yIGVycm9yIG1lc3NhZ2VzLlxuICogQHByb3BlcnR5IHtudW1iZXJ9IG1lc3NhZ2UuZXJyb3IuZmcgLSBGb3JlZ3JvdW5kIGNvbG9yIGNvZGUgZm9yIGVycm9yIG1lc3NhZ2VzICgzMSkuXG4gKiBAcHJvcGVydHkge09iamVjdH0gbWV0aG9kIC0gU3R5bGluZyBmb3IgbWV0aG9kIG5hbWVzIChlbXB0eSBvYmplY3QpLlxuICogQHByb3BlcnR5IHtPYmplY3R9IGxvZ0xldmVsIC0gU3R5bGluZyBmb3IgZGlmZmVyZW50IGxvZyBsZXZlbHMuXG4gKiBAcHJvcGVydHkge09iamVjdH0gbG9nTGV2ZWwuZXJyb3IgLSBTdHlsaW5nIGZvciBlcnJvciBsZXZlbCBsb2dzLlxuICogQHByb3BlcnR5IHtudW1iZXJ9IGxvZ0xldmVsLmVycm9yLmZnIC0gRm9yZWdyb3VuZCBjb2xvciBjb2RlIGZvciBlcnJvciBsZXZlbCBsb2dzICgzMSkuXG4gKiBAcHJvcGVydHkge3N0cmluZ1tdfSBsb2dMZXZlbC5lcnJvci5zdHlsZSAtIFN0eWxlIGF0dHJpYnV0ZXMgZm9yIGVycm9yIGxldmVsIGxvZ3MgKFtcImJvbGRcIl0pLlxuICogQHByb3BlcnR5IHtPYmplY3R9IGxvZ0xldmVsLmluZm8gLSBTdHlsaW5nIGZvciBpbmZvIGxldmVsIGxvZ3MgKGVtcHR5IG9iamVjdCkuXG4gKiBAcHJvcGVydHkge09iamVjdH0gbG9nTGV2ZWwudmVyYm9zZSAtIFN0eWxpbmcgZm9yIHZlcmJvc2UgbGV2ZWwgbG9ncyAoZW1wdHkgb2JqZWN0KS5cbiAqIEBwcm9wZXJ0eSB7T2JqZWN0fSBsb2dMZXZlbC5kZWJ1ZyAtIFN0eWxpbmcgZm9yIGRlYnVnIGxldmVsIGxvZ3MuXG4gKiBAcHJvcGVydHkge251bWJlcn0gbG9nTGV2ZWwuZGVidWcuZmcgLSBGb3JlZ3JvdW5kIGNvbG9yIGNvZGUgZm9yIGRlYnVnIGxldmVsIGxvZ3MgKDMzKS5cbiAqIEBjb25zdCBEZWZhdWx0VGhlbWVcbiAqIEBtZW1iZXJPZiBtb2R1bGU6TG9nZ2luZ1xuICovXG5leHBvcnQgY29uc3QgRGVmYXVsdFRoZW1lOiBUaGVtZSA9IHtcbiAgYXBwOiB7fSxcbiAgc2VwYXJhdG9yOiB7fSxcbiAgY2xhc3M6IHtcbiAgICBmZzogMzQsXG4gIH0sXG4gIGlkOiB7XG4gICAgZmc6IDM2LFxuICB9LFxuICBzdGFjazoge30sXG4gIHRpbWVzdGFtcDoge30sXG4gIG1lc3NhZ2U6IHtcbiAgICBlcnJvcjoge1xuICAgICAgZmc6IDMxLFxuICAgIH0sXG4gIH0sXG4gIG1ldGhvZDoge30sXG4gIGxvZ0xldmVsOiB7XG4gICAgYmVuY2htYXJrOiB7XG4gICAgICBmZzogMzIsXG4gICAgICBzdHlsZTogW1wiYm9sZFwiXSxcbiAgICB9LFxuICAgIGVycm9yOiB7XG4gICAgICBmZzogMzEsXG4gICAgICBzdHlsZTogW1wiYm9sZFwiXSxcbiAgICB9LFxuICAgIGluZm86IHtcbiAgICAgIGZnOiAzNCxcbiAgICAgIHN0eWxlOiBbXCJib2xkXCJdLFxuICAgIH0sXG4gICAgdmVyYm9zZToge1xuICAgICAgZmc6IDM0LFxuICAgICAgc3R5bGU6IFtcImJvbGRcIl0sXG4gICAgfSxcbiAgICBkZWJ1Zzoge1xuICAgICAgZmc6IDMzLFxuICAgICAgc3R5bGU6IFtcImJvbGRcIl0sXG4gICAgfSxcbiAgICB0cmFjZToge1xuICAgICAgZmc6IDMzLFxuICAgICAgc3R5bGU6IFtcImJvbGRcIl0sXG4gICAgfSxcbiAgICBzaWxseToge1xuICAgICAgZmc6IDMzLFxuICAgICAgc3R5bGU6IFtcImJvbGRcIl0sXG4gICAgfSxcbiAgfSxcbn07XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIERlZmF1bHQgY29uZmlndXJhdGlvbiBmb3IgbG9nZ2luZy5cbiAqIEBzdW1tYXJ5IERlZmluZXMgdGhlIGRlZmF1bHQgc2V0dGluZ3MgZm9yIHRoZSBsb2dnaW5nIHN5c3RlbSwgaW5jbHVkaW5nIHZlcmJvc2l0eSwgbG9nIGxldmVsLCBzdHlsaW5nLCBhbmQgdGltZXN0YW1wIGZvcm1hdC5cbiAqIEBjb25zdCBEZWZhdWx0TG9nZ2luZ0NvbmZpZ1xuICogQHR5cGVkZWYge0xvZ2dpbmdDb25maWd9IERlZmF1bHRMb2dnaW5nQ29uZmlnXG4gKiBAcHJvcGVydHkge251bWJlcn0gdmVyYm9zZSAtIFZlcmJvc2l0eSBsZXZlbCAoMCkuXG4gKiBAcHJvcGVydHkge0xvZ0xldmVsfSBsZXZlbCAtIERlZmF1bHQgbG9nIGxldmVsIChMb2dMZXZlbC5pbmZvKS5cbiAqIEBwcm9wZXJ0eSB7Ym9vbGVhbn0gbG9nTGV2ZWwgLSBXaGV0aGVyIHRvIGRpc3BsYXkgbG9nIGxldmVsIGluIG91dHB1dCAodHJ1ZSkuXG4gKiBAcHJvcGVydHkge0xvZ2dpbmdNb2RlfSBtb2RlIC0gT3V0cHV0IGZvcm1hdCBtb2RlIChMb2dnaW5nTW9kZS5SQVcpLlxuICogQHByb3BlcnR5IHtib29sZWFufSBzdHlsZSAtIFdoZXRoZXIgdG8gYXBwbHkgc3R5bGluZyB0byBsb2cgb3V0cHV0IChmYWxzZSkuXG4gKiBAcHJvcGVydHkge3N0cmluZ30gc2VwYXJhdG9yIC0gU2VwYXJhdG9yIGJldHdlZW4gbG9nIGNvbXBvbmVudHMgKFwiIC0gXCIpLlxuICogQHByb3BlcnR5IHtib29sZWFufSB0aW1lc3RhbXAgLSBXaGV0aGVyIHRvIGluY2x1ZGUgdGltZXN0YW1wcyBpbiBsb2cgbWVzc2FnZXMgKHRydWUpLlxuICogQHByb3BlcnR5IHtzdHJpbmd9IHRpbWVzdGFtcEZvcm1hdCAtIEZvcm1hdCBmb3IgdGltZXN0YW1wcyAoXCJISDptbTpzcy5TU1NcIikuXG4gKiBAcHJvcGVydHkge2Jvb2xlYW59IGNvbnRleHQgLSBXaGV0aGVyIHRvIGluY2x1ZGUgY29udGV4dCBpbmZvcm1hdGlvbiBpbiBsb2cgbWVzc2FnZXMgKHRydWUpLlxuICogQHByb3BlcnR5IHtUaGVtZX0gdGhlbWUgLSBUaGUgdGhlbWUgdG8gdXNlIGZvciBzdHlsaW5nIGxvZyBtZXNzYWdlcyAoRGVmYXVsdFRoZW1lKS5cbiAqIEBtZW1iZXJPZiBtb2R1bGU6TG9nZ2luZ1xuICovXG5leHBvcnQgY29uc3QgRGVmYXVsdExvZ2dpbmdDb25maWc6IExvZ2dpbmdDb25maWcgPSB7XG4gIGVudjogXCJkZXZlbG9wbWVudFwiLFxuICB2ZXJib3NlOiAwLFxuICBsZXZlbDogTG9nTGV2ZWwuaW5mbyxcbiAgbG9nTGV2ZWw6IHRydWUsXG4gIHN0eWxlOiBmYWxzZSxcbiAgY29udGV4dFNlcGFyYXRvcjogXCIuXCIsXG4gIHNlcGFyYXRvcjogXCItXCIsXG4gIHRpbWVzdGFtcDogdHJ1ZSxcbiAgdGltZXN0YW1wRm9ybWF0OiBcIkhIOm1tOnNzLlNTU1wiLFxuICBjb250ZXh0OiB0cnVlLFxuICBmb3JtYXQ6IExvZ2dpbmdNb2RlLlJBVyxcbiAgcGF0dGVybjpcbiAgICBcIntsZXZlbH0gW3t0aW1lc3RhbXB9XSB7YXBwfSB7Y29udGV4dH0ge3NlcGFyYXRvcn0ge21lc3NhZ2V9IHtzdGFja31cIixcbiAgdGhlbWU6IERlZmF1bHRUaGVtZSxcbn07XG4iLCJpbXBvcnQgeyBEZWZhdWx0UGxhY2Vob2xkZXJXcmFwcGVycyB9IGZyb20gXCIuL2NvbnN0YW50c1wiO1xuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBQYWRzIHRoZSBlbmQgb2YgYSBzdHJpbmcgd2l0aCBhIHNwZWNpZmllZCBjaGFyYWN0ZXIuXG4gKiBAc3VtbWFyeSBFeHRlbmRzIHRoZSBpbnB1dCBzdHJpbmcgdG8gYSBzcGVjaWZpZWQgbGVuZ3RoIGJ5IGFkZGluZyBhIHBhZGRpbmcgY2hhcmFjdGVyIHRvIHRoZSBlbmQuXG4gKiBJZiB0aGUgaW5wdXQgc3RyaW5nIGlzIGFscmVhZHkgbG9uZ2VyIHRoYW4gdGhlIHNwZWNpZmllZCBsZW5ndGgsIGl0IGlzIHJldHVybmVkIHVuY2hhbmdlZC5cbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gc3RyIC0gVGhlIGlucHV0IHN0cmluZyB0byBiZSBwYWRkZWQuXG4gKiBAcGFyYW0ge251bWJlcn0gbGVuZ3RoIC0gVGhlIGRlc2lyZWQgdG90YWwgbGVuZ3RoIG9mIHRoZSByZXN1bHRpbmcgc3RyaW5nLlxuICogQHBhcmFtIHtzdHJpbmd9IFtjaGFyPVwiIFwiXSAtIFRoZSBjaGFyYWN0ZXIgdG8gdXNlIGZvciBwYWRkaW5nLiBEZWZhdWx0cyB0byBhIHNwYWNlLlxuICogQHJldHVybiB7c3RyaW5nfSBUaGUgcGFkZGVkIHN0cmluZy5cbiAqIEB0aHJvd3Mge0Vycm9yfSBJZiB0aGUgcGFkZGluZyBjaGFyYWN0ZXIgaXMgbm90IGV4YWN0bHkgb25lIGNoYXJhY3RlciBsb25nLlxuICpcbiAqIEBmdW5jdGlvbiBwYWRFbmRcbiAqXG4gKiBAbWVtYmVyT2YgbW9kdWxlOkxvZ2dpbmdcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHBhZEVuZChcbiAgc3RyOiBzdHJpbmcsXG4gIGxlbmd0aDogbnVtYmVyLFxuICBjaGFyOiBzdHJpbmcgPSBcIiBcIlxuKTogc3RyaW5nIHtcbiAgaWYgKGNoYXIubGVuZ3RoICE9PSAxKVxuICAgIHRocm93IG5ldyBFcnJvcihcIkludmFsaWQgY2hhcmFjdGVyIGxlbmd0aCBmb3IgcGFkZGluZy4gbXVzdCBiZSBvbmUhXCIpO1xuICByZXR1cm4gc3RyLnBhZEVuZChsZW5ndGgsIGNoYXIpO1xufVxuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBSZXBsYWNlcyBwbGFjZWhvbGRlcnMgaW4gYSBzdHJpbmcgd2l0aCBwcm92aWRlZCB2YWx1ZXMuXG4gKiBAc3VtbWFyeSBJbnRlcnBvbGF0ZXMgYSBzdHJpbmcgYnkgcmVwbGFjaW5nIHBsYWNlaG9sZGVycyBvZiB0aGUgZm9ybSAke3ZhcmlhYmxlTmFtZX1cbiAqIHdpdGggY29ycmVzcG9uZGluZyB2YWx1ZXMgZnJvbSB0aGUgcHJvdmlkZWQgb2JqZWN0LiBJZiBhIHBsYWNlaG9sZGVyIGRvZXNuJ3QgaGF2ZVxuICogYSBjb3JyZXNwb25kaW5nIHZhbHVlLCBpdCBpcyBsZWZ0IHVuY2hhbmdlZCBpbiB0aGUgc3RyaW5nLlxuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSBpbnB1dCAtIFRoZSBpbnB1dCBzdHJpbmcgY29udGFpbmluZyBwbGFjZWhvbGRlcnMgdG8gYmUgcmVwbGFjZWQuXG4gKiBAcGFyYW0ge1JlY29yZDxzdHJpbmcsIG51bWJlciB8IHN0cmluZz59IHZhbHVlcyAtIEFuIG9iamVjdCBjb250YWluaW5nIGtleS12YWx1ZSBwYWlycyBmb3IgcmVwbGFjZW1lbnQuXG4gKiBAcGFyYW0gcHJlZml4XG4gKiBAcGFyYW0gc3VmZml4XG4gKiBAcGFyYW0gZmxhZ3NcbiAqIEByZXR1cm4ge3N0cmluZ30gVGhlIGludGVycG9sYXRlZCBzdHJpbmcgd2l0aCBwbGFjZWhvbGRlcnMgcmVwbGFjZWQgYnkgdGhlaXIgY29ycmVzcG9uZGluZyB2YWx1ZXMuXG4gKlxuICogQGZ1bmN0aW9uIHBhdGNoUGxhY2Vob2xkZXJzXG4gKlxuICogQG1lcm1haWRcbiAqIHNlcXVlbmNlRGlhZ3JhbVxuICogICBwYXJ0aWNpcGFudCBDYWxsZXJcbiAqICAgcGFydGljaXBhbnQgcGF0Y2hTdHJpbmdcbiAqICAgcGFydGljaXBhbnQgU3RyaW5nLnJlcGxhY2VcbiAqICAgQ2FsbGVyLT4+cGF0Y2hTdHJpbmc6IENhbGwgd2l0aCBpbnB1dCBhbmQgdmFsdWVzXG4gKiAgIHBhdGNoU3RyaW5nLT4+U3RyaW5nLnJlcGxhY2U6IENhbGwgd2l0aCByZWdleCBhbmQgcmVwbGFjZW1lbnQgZnVuY3Rpb25cbiAqICAgU3RyaW5nLnJlcGxhY2UtPj5wYXRjaFN0cmluZzogUmV0dXJuIHJlcGxhY2VkIHN0cmluZ1xuICogICBwYXRjaFN0cmluZy0tPj5DYWxsZXI6IFJldHVybiBwYXRjaGVkIHN0cmluZ1xuICpcbiAqIEBtZW1iZXJPZiBtb2R1bGU6TG9nZ2luZ1xuICovXG5leHBvcnQgZnVuY3Rpb24gcGF0Y2hQbGFjZWhvbGRlcnMoXG4gIGlucHV0OiBzdHJpbmcsXG4gIHZhbHVlczogUmVjb3JkPHN0cmluZywgbnVtYmVyIHwgc3RyaW5nPixcbiAgcHJlZml4OiBzdHJpbmcgPSBEZWZhdWx0UGxhY2Vob2xkZXJXcmFwcGVyc1swXSxcbiAgc3VmZml4OiBzdHJpbmcgPSBEZWZhdWx0UGxhY2Vob2xkZXJXcmFwcGVyc1sxXSxcbiAgZmxhZ3M6IHN0cmluZyA9IFwiZ1wiXG4pOiBzdHJpbmcge1xuICBjb25zdCBwbGFjZWhvbGRlcnMgPSBPYmplY3QuZW50cmllcyh2YWx1ZXMpLnJlZHVjZShcbiAgICAoYWNjOiBSZWNvcmQ8c3RyaW5nLCBhbnk+LCBba2V5LCB2YWxdKSA9PiB7XG4gICAgICBhY2NbYCR7cHJlZml4fSR7a2V5fSR7c3VmZml4fWBdID0gdmFsO1xuICAgICAgcmV0dXJuIGFjYztcbiAgICB9LFxuICAgIHt9XG4gICk7XG4gIHJldHVybiBwYXRjaFN0cmluZyhpbnB1dCwgcGxhY2Vob2xkZXJzLCBmbGFncyk7XG59XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIFJlcGxhY2VzIG9jY3VycmVuY2VzIG9mIGtleXMgd2l0aCB0aGVpciBjb3JyZXNwb25kaW5nIHZhbHVlcyBpbiBhIHN0cmluZy5cbiAqIEBzdW1tYXJ5IEl0ZXJhdGVzIHRocm91Z2ggYSBzZXQgb2Yga2V5LXZhbHVlIHBhaXJzIGFuZCByZXBsYWNlcyBhbGwgb2NjdXJyZW5jZXMgb2YgZWFjaCBrZXlcbiAqIGluIHRoZSBpbnB1dCBzdHJpbmcgd2l0aCBpdHMgY29ycmVzcG9uZGluZyB2YWx1ZS4gU3VwcG9ydHMgcmVndWxhciBleHByZXNzaW9uIGZsYWdzIGZvciBjdXN0b21pemVkIHJlcGxhY2VtZW50LlxuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSBpbnB1dCAtIFRoZSBpbnB1dCBzdHJpbmcgaW4gd2hpY2ggcmVwbGFjZW1lbnRzIHdpbGwgYmUgbWFkZS5cbiAqIEBwYXJhbSB7UmVjb3JkPHN0cmluZywgbnVtYmVyIHwgc3RyaW5nPn0gdmFsdWVzIC0gQW4gb2JqZWN0IGNvbnRhaW5pbmcga2V5LXZhbHVlIHBhaXJzIGZvciByZXBsYWNlbWVudC5cbiAqIEBwYXJhbSB7c3RyaW5nfSBbZmxhZ3M9XCJnXCJdIC0gUmVndWxhciBleHByZXNzaW9uIGZsYWdzIHRvIGNvbnRyb2wgdGhlIHJlcGxhY2VtZW50IGJlaGF2aW9yLlxuICogQHJldHVybiB7c3RyaW5nfSBUaGUgc3RyaW5nIHdpdGggYWxsIHNwZWNpZmllZCByZXBsYWNlbWVudHMgYXBwbGllZC5cbiAqXG4gKiBAZnVuY3Rpb24gcGF0Y2hTdHJpbmdcbiAqXG4gKiBAbWVtYmVyT2YgbW9kdWxlOkxvZ2dpbmdcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHBhdGNoU3RyaW5nKFxuICBpbnB1dDogc3RyaW5nLFxuICB2YWx1ZXM6IFJlY29yZDxzdHJpbmcsIG51bWJlciB8IHN0cmluZz4sXG4gIGZsYWdzOiBzdHJpbmcgPSBcImdcIlxuKTogc3RyaW5nIHtcbiAgT2JqZWN0LmVudHJpZXModmFsdWVzKS5mb3JFYWNoKChba2V5LCB2YWxdKSA9PiB7XG4gICAgY29uc3QgcmVnZXhwID0gbmV3IFJlZ0V4cChlc2NhcGVSZWdFeHAoa2V5KSwgZmxhZ3MpO1xuICAgIGlucHV0ID0gaW5wdXQucmVwbGFjZShyZWdleHAsIHZhbCBhcyBzdHJpbmcpO1xuICB9KTtcbiAgcmV0dXJuIGlucHV0O1xufVxuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBDb252ZXJ0cyBhIHN0cmluZyB0byBjYW1lbENhc2UuXG4gKiBAc3VtbWFyeSBUcmFuc2Zvcm1zIHRoZSBpbnB1dCBzdHJpbmcgaW50byBjYW1lbENhc2UgZm9ybWF0LCB3aGVyZSB3b3JkcyBhcmUgam9pbmVkIHdpdGhvdXQgc3BhY2VzXG4gKiBhbmQgZWFjaCB3b3JkIGFmdGVyIHRoZSBmaXJzdCBzdGFydHMgd2l0aCBhIGNhcGl0YWwgbGV0dGVyLlxuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSB0ZXh0IC0gVGhlIGlucHV0IHN0cmluZyB0byBiZSBjb252ZXJ0ZWQuXG4gKiBAcmV0dXJuIHtzdHJpbmd9IFRoZSBpbnB1dCBzdHJpbmcgY29udmVydGVkIHRvIGNhbWVsQ2FzZS5cbiAqXG4gKiBAZnVuY3Rpb24gdG9DYW1lbENhc2VcbiAqXG4gKiBAbWVtYmVyT2YgbW9kdWxlOkxvZ2dpbmdcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHRvQ2FtZWxDYXNlKHRleHQ6IHN0cmluZyk6IHN0cmluZyB7XG4gIHJldHVybiB0ZXh0XG4gICAgLnJlcGxhY2UoLyg/Ol5cXHd8W0EtWl18XFxiXFx3KS9nLCAod29yZCwgaW5kZXgpID0+XG4gICAgICBpbmRleCA9PT0gMCA/IHdvcmQudG9Mb3dlckNhc2UoKSA6IHdvcmQudG9VcHBlckNhc2UoKVxuICAgIClcbiAgICAucmVwbGFjZSgvXFxzKy9nLCBcIlwiKTtcbn1cblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gQ29udmVydHMgYSBzdHJpbmcgdG8gRU5WSVJPTk1FTlRfVkFSSUFCTEUgZm9ybWF0LlxuICogQHN1bW1hcnkgVHJhbnNmb3JtcyB0aGUgaW5wdXQgc3RyaW5nIGludG8gdXBwZXJjYXNlIHdpdGggd29yZHMgc2VwYXJhdGVkIGJ5IHVuZGVyc2NvcmVzLFxuICogdHlwaWNhbGx5IHVzZWQgZm9yIGVudmlyb25tZW50IHZhcmlhYmxlIG5hbWVzLlxuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSB0ZXh0IC0gVGhlIGlucHV0IHN0cmluZyB0byBiZSBjb252ZXJ0ZWQuXG4gKiBAcmV0dXJuIHtzdHJpbmd9IFRoZSBpbnB1dCBzdHJpbmcgY29udmVydGVkIHRvIEVOVklST05NRU5UX1ZBUklBQkxFIGZvcm1hdC5cbiAqXG4gKiBAZnVuY3Rpb24gdG9FTlZGb3JtYXRcbiAqXG4gKiBAbWVtYmVyT2YgbW9kdWxlOkxvZ2dpbmdcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHRvRU5WRm9ybWF0KHRleHQ6IHN0cmluZyk6IHN0cmluZyB7XG4gIHJldHVybiB0b1NuYWtlQ2FzZSh0ZXh0KS50b1VwcGVyQ2FzZSgpO1xufVxuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBDb252ZXJ0cyBhIHN0cmluZyB0byBzbmFrZV9jYXNlLlxuICogQHN1bW1hcnkgVHJhbnNmb3JtcyB0aGUgaW5wdXQgc3RyaW5nIGludG8gbG93ZXJjYXNlIHdpdGggd29yZHMgc2VwYXJhdGVkIGJ5IHVuZGVyc2NvcmVzLlxuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSB0ZXh0IC0gVGhlIGlucHV0IHN0cmluZyB0byBiZSBjb252ZXJ0ZWQuXG4gKiBAcmV0dXJuIHtzdHJpbmd9IFRoZSBpbnB1dCBzdHJpbmcgY29udmVydGVkIHRvIHNuYWtlX2Nhc2UuXG4gKlxuICogQGZ1bmN0aW9uIHRvU25ha2VDYXNlXG4gKlxuICogQG1lbWJlck9mIG1vZHVsZTpMb2dnaW5nXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiB0b1NuYWtlQ2FzZSh0ZXh0OiBzdHJpbmcpOiBzdHJpbmcge1xuICByZXR1cm4gdGV4dFxuICAgIC5yZXBsYWNlKC8oW2Etel0pKFtBLVpdKS9nLCBcIiQxXyQyXCIpXG4gICAgLnJlcGxhY2UoL1tcXHMtXSsvZywgXCJfXCIpXG4gICAgLnRvTG93ZXJDYXNlKCk7XG59XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIENvbnZlcnRzIGEgc3RyaW5nIHRvIGtlYmFiLWNhc2UuXG4gKiBAc3VtbWFyeSBUcmFuc2Zvcm1zIHRoZSBpbnB1dCBzdHJpbmcgaW50byBsb3dlcmNhc2Ugd2l0aCB3b3JkcyBzZXBhcmF0ZWQgYnkgaHlwaGVucy5cbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gdGV4dCAtIFRoZSBpbnB1dCBzdHJpbmcgdG8gYmUgY29udmVydGVkLlxuICogQHJldHVybiB7c3RyaW5nfSBUaGUgaW5wdXQgc3RyaW5nIGNvbnZlcnRlZCB0byBrZWJhYi1jYXNlLlxuICpcbiAqIEBmdW5jdGlvbiB0b0tlYmFiQ2FzZVxuICpcbiAqIEBtZW1iZXJPZiBtb2R1bGU6TG9nZ2luZ1xuICovXG5leHBvcnQgZnVuY3Rpb24gdG9LZWJhYkNhc2UodGV4dDogc3RyaW5nKTogc3RyaW5nIHtcbiAgcmV0dXJuIHRleHRcbiAgICAucmVwbGFjZSgvKFthLXpdKShbQS1aXSkvZywgXCIkMS0kMlwiKVxuICAgIC5yZXBsYWNlKC9bXFxzX10rL2csIFwiLVwiKVxuICAgIC50b0xvd2VyQ2FzZSgpO1xufVxuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBDb252ZXJ0cyBhIHN0cmluZyB0byBQYXNjYWxDYXNlLlxuICogQHN1bW1hcnkgVHJhbnNmb3JtcyB0aGUgaW5wdXQgc3RyaW5nIGludG8gUGFzY2FsQ2FzZSBmb3JtYXQsIHdoZXJlIHdvcmRzIGFyZSBqb2luZWQgd2l0aG91dCBzcGFjZXNcbiAqIGFuZCBlYWNoIHdvcmQgc3RhcnRzIHdpdGggYSBjYXBpdGFsIGxldHRlci5cbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gdGV4dCAtIFRoZSBpbnB1dCBzdHJpbmcgdG8gYmUgY29udmVydGVkLlxuICogQHJldHVybiB7c3RyaW5nfSBUaGUgaW5wdXQgc3RyaW5nIGNvbnZlcnRlZCB0byBQYXNjYWxDYXNlLlxuICpcbiAqIEBmdW5jdGlvbiB0b1Bhc2NhbENhc2VcbiAqXG4gKiBAbWVtYmVyT2YgbW9kdWxlOkxvZ2dpbmdcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHRvUGFzY2FsQ2FzZSh0ZXh0OiBzdHJpbmcpOiBzdHJpbmcge1xuICByZXR1cm4gdGV4dFxuICAgIC5yZXBsYWNlKC8oPzpeXFx3fFtBLVpdfFxcYlxcdykvZywgKHdvcmQpID0+IHdvcmQudG9VcHBlckNhc2UoKSlcbiAgICAucmVwbGFjZSgvXFxzKy9nLCBcIlwiKTtcbn1cblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gRXNjYXBlcyBzcGVjaWFsIGNoYXJhY3RlcnMgaW4gYSBzdHJpbmcgZm9yIHVzZSBpbiBhIHJlZ3VsYXIgZXhwcmVzc2lvbi5cbiAqIEBzdW1tYXJ5IEFkZHMgYmFja3NsYXNoZXMgYmVmb3JlIGNoYXJhY3RlcnMgdGhhdCBoYXZlIHNwZWNpYWwgbWVhbmluZyBpbiByZWd1bGFyIGV4cHJlc3Npb25zLFxuICogYWxsb3dpbmcgdGhlIHN0cmluZyB0byBiZSB1c2VkIGFzIGEgbGl0ZXJhbCBtYXRjaCBpbiBhIFJlZ0V4cC5cbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gc3RyaW5nIC0gVGhlIHN0cmluZyB0byBlc2NhcGUgZm9yIHJlZ3VsYXIgZXhwcmVzc2lvbiB1c2UuXG4gKiBAcmV0dXJuIHtzdHJpbmd9IFRoZSBlc2NhcGVkIHN0cmluZyBzYWZlIGZvciB1c2UgaW4gcmVndWxhciBleHByZXNzaW9ucy5cbiAqXG4gKiBAZnVuY3Rpb24gZXNjYXBlUmVnRXhwXG4gKlxuICogQG1lbWJlck9mIG1vZHVsZTpMb2dnaW5nXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBlc2NhcGVSZWdFeHAoc3RyaW5nOiBzdHJpbmcpIHtcbiAgcmV0dXJuIHN0cmluZy5yZXBsYWNlKC9bLiorP14ke30oKXxbXFxdXFxcXF0vZywgXCJcXFxcJCZcIik7IC8vICQmIG1lYW5zIHRoZSB3aG9sZSBtYXRjaGVkIHN0cmluZ1xufVxuXG4vKipcbiAqIEBzdW1tYXJ5IFV0aWwgZnVuY3Rpb24gdG8gcHJvdmlkZSBzdHJpbmcgZm9ybWF0IGZ1bmN0aW9uYWxpdHkgc2ltaWxhciB0byBDIydzIHN0cmluZy5mb3JtYXRcbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gc3RyaW5nXG4gKiBAcGFyYW0ge0FycmF5PHN0cmluZyB8IG51bWJlcj4gfCBSZWNvcmQ8c3RyaW5nLCBhbnk+fSBbYXJnc10gcmVwbGFjZW1lbnRzIG1hZGUgYnkgb3JkZXIgb2YgYXBwZWFyYW5jZSAocmVwbGFjZW1lbnQwIHdpbCByZXBsYWNlIHswfSBhbmQgc28gb24pXG4gKiBAcmV0dXJuIHtzdHJpbmd9IGZvcm1hdHRlZCBzdHJpbmdcbiAqXG4gKiBAZnVuY3Rpb24gc2ZcbiAqIEBtZW1iZXJPZiBtb2R1bGU6TG9nZ2luZ1xuICovXG5leHBvcnQgZnVuY3Rpb24gc2YoXG4gIHN0cmluZzogc3RyaW5nLFxuICAuLi5hcmdzOiAoc3RyaW5nIHwgbnVtYmVyIHwgUmVjb3JkPHN0cmluZywgYW55PilbXVxuKSB7XG4gIGlmIChhcmdzLmxlbmd0aCA+IDEpIHtcbiAgICBpZiAoXG4gICAgICAhYXJncy5ldmVyeSgoYXJnKSA9PiB0eXBlb2YgYXJnID09PSBcInN0cmluZ1wiIHx8IHR5cGVvZiBhcmcgPT09IFwibnVtYmVyXCIpXG4gICAgKVxuICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICBgT25seSBzdHJpbmcgYW5kIG51bWJlciBhcmd1bWVudHMgYXJlIHN1cHBvcnRlZCBmb3IgbXVsdGlwbGUgcmVwbGFjZW1lbnRzLmBcbiAgICAgICk7XG4gIH1cblxuICBpZiAoYXJncy5sZW5ndGggPT09IDEgJiYgdHlwZW9mIGFyZ3NbMF0gPT09IFwib2JqZWN0XCIpIHtcbiAgICBjb25zdCBvYmogPSBhcmdzWzBdIGFzIFJlY29yZDxzdHJpbmcsIGFueT47XG4gICAgcmV0dXJuIE9iamVjdC5lbnRyaWVzKG9iaikucmVkdWNlKChhY2MsIFtrZXksIHZhbF0pID0+IHtcbiAgICAgIHJldHVybiBhY2MucmVwbGFjZShuZXcgUmVnRXhwKGBcXFxceyR7a2V5fVxcXFx9YCwgXCJnXCIpLCBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiB2YWw7XG4gICAgICB9KTtcbiAgICB9LCBzdHJpbmcpO1xuICB9XG5cbiAgcmV0dXJuIHN0cmluZy5yZXBsYWNlKC97KFxcZCspfS9nLCBmdW5jdGlvbiAobWF0Y2gsIG51bWJlcikge1xuICAgIHJldHVybiB0eXBlb2YgYXJnc1tudW1iZXJdICE9PSBcInVuZGVmaW5lZFwiXG4gICAgICA/IGFyZ3NbbnVtYmVyXS50b1N0cmluZygpXG4gICAgICA6IFwidW5kZWZpbmVkXCI7XG4gIH0pO1xufVxuXG4vKipcbiAqIEBzdW1tYXJ5IFV0aWwgZnVuY3Rpb24gdG8gcHJvdmlkZSBzdHJpbmcgZm9ybWF0IGZ1bmN0aW9uYWxpdHkgc2ltaWxhciB0byBDIydzIHN0cmluZy5mb3JtYXRcbiAqXG4gKiBAc2VlIHNmXG4gKlxuICogQGRlcHJlY2F0ZWRcbiAqIEBmdW5jdGlvbiBzdHJpbmdGb3JtYXRcbiAqIEBtZW1iZXJPZiBtb2R1bGU6TG9nZ2luZ1xuICovXG5leHBvcnQgY29uc3Qgc3RyaW5nRm9ybWF0ID0gc2Y7XG4iLCIvKipcbiAqIEBkZXNjcmlwdGlvbiBEZXRlcm1pbmVzIGlmIHRoZSBjdXJyZW50IGVudmlyb25tZW50IGlzIGEgYnJvd3NlciBieSBjaGVja2luZyB0aGUgcHJvdG90eXBlIGNoYWluIG9mIHRoZSBnbG9iYWwgb2JqZWN0LlxuICogQHN1bW1hcnkgQ2hlY2tzIGlmIHRoZSBjb2RlIGlzIHJ1bm5pbmcgaW4gYSBicm93c2VyIGVudmlyb25tZW50LlxuICogQHJldHVybiB7Ym9vbGVhbn0gVHJ1ZSBpZiB0aGUgZW52aXJvbm1lbnQgaXMgYSBicm93c2VyLCBmYWxzZSBvdGhlcndpc2UuXG4gKiBAZnVuY3Rpb24gaXNCcm93c2VyXG4gKiBAbWVtYmVyT2YgbW9kdWxlOkxvZ2dpbmdcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGlzQnJvd3NlcigpOiBib29sZWFuIHtcbiAgcmV0dXJuIChcbiAgICBPYmplY3QuZ2V0UHJvdG90eXBlT2YoT2JqZWN0LmdldFByb3RvdHlwZU9mKGdsb2JhbFRoaXMpKSAhPT1cbiAgICBPYmplY3QucHJvdG90eXBlXG4gICk7XG59XG4iLCJpbXBvcnQgeyBPYmplY3RBY2N1bXVsYXRvciB9IGZyb20gXCJ0eXBlZC1vYmplY3QtYWNjdW11bGF0b3JcIjtcbmltcG9ydCB7IHRvRU5WRm9ybWF0IH0gZnJvbSBcIi4vdGV4dFwiO1xuaW1wb3J0IHsgaXNCcm93c2VyIH0gZnJvbSBcIi4vd2ViXCI7XG5pbXBvcnQge1xuICBCcm93c2VyRW52S2V5LFxuICBEZWZhdWx0TG9nZ2luZ0NvbmZpZyxcbiAgRU5WX1BBVEhfREVMSU1JVEVSLFxufSBmcm9tIFwiLi9jb25zdGFudHNcIjtcblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gRmFjdG9yeSB0eXBlIGZvciBjcmVhdGluZyBFbnZpcm9ubWVudCBpbnN0YW5jZXMuXG4gKiBAc3VtbWFyeSBEZXNjcmliZXMgZmFjdG9yaWVzIHRoYXQgY29uc3RydWN0IHtAbGluayBFbnZpcm9ubWVudH0gZGVyaXZhdGl2ZXMgd2l0aCBjdXN0b20gaW5pdGlhbGl6YXRpb24uXG4gKiBAdGVtcGxhdGUgVCAtIFRoZSB0eXBlIG9mIG9iamVjdCB0aGUgRW52aXJvbm1lbnQgd2lsbCBhY2N1bXVsYXRlLlxuICogQHRlbXBsYXRlIEUgLSBUaGUgc3BlY2lmaWMgRW52aXJvbm1lbnQgdHlwZSB0byBiZSBjcmVhdGVkLCBleHRlbmRpbmcgRW52aXJvbm1lbnQ8VD4uXG4gKiBAdHlwZWRlZiB7ZnVuY3Rpb24odW5rbm93bltdKTogRX0gRW52aXJvbm1lbnRGYWN0b3J5XG4gKiBAbWVtYmVyT2YgbW9kdWxlOkxvZ2dpbmdcbiAqL1xuZXhwb3J0IHR5cGUgRW52aXJvbm1lbnRGYWN0b3J5PFQgZXh0ZW5kcyBvYmplY3QsIEUgZXh0ZW5kcyBFbnZpcm9ubWVudDxUPj4gPSAoXG4gIC4uLmFyZ3M6IHVua25vd25bXVxuKSA9PiBFO1xuXG5leHBvcnQgdHlwZSBFbnZpcm9ubWVudEluc3RhbmNlPFQgZXh0ZW5kcyBvYmplY3Q+ID0gRW52aXJvbm1lbnQ8VD4gJlxuICBUICYgeyBvclRocm93KCk6IEVudmlyb25tZW50SW5zdGFuY2U8VD4gfTtcblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gRW52aXJvbm1lbnQgYWNjdW11bGF0b3IgdGhhdCBsYXppbHkgcmVhZHMgZnJvbSBydW50aW1lIHNvdXJjZXMuXG4gKiBAc3VtbWFyeSBFeHRlbmRzIHtAbGluayBPYmplY3RBY2N1bXVsYXRvcn0gdG8gbWVyZ2UgY29uZmlndXJhdGlvbiBvYmplY3RzIHdoaWxlIHJlc29sdmluZyB2YWx1ZXMgZnJvbSBOb2RlIG9yIGJyb3dzZXIgZW52aXJvbm1lbnQgdmFyaWFibGVzIG9uIGRlbWFuZC5cbiAqIEB0ZW1wbGF0ZSBUXG4gKiBAY2xhc3MgRW52aXJvbm1lbnRcbiAqIEBleGFtcGxlXG4gKiBjb25zdCBDb25maWcgPSBFbnZpcm9ubWVudC5hY2N1bXVsYXRlKHsgbG9nZ2luZzogeyBsZXZlbDogXCJpbmZvXCIgfSB9KTtcbiAqIGNvbnNvbGUubG9nKENvbmZpZy5sb2dnaW5nLmxldmVsKTtcbiAqIGNvbnNvbGUubG9nKFN0cmluZyhDb25maWcubG9nZ2luZy5sZXZlbCkpOyAvLyA9PiBMT0dHSU5HX19MRVZFTCBrZXkgd2hlbiBzZXJpYWxpemVkXG4gKiBAbWVybWFpZFxuICogc2VxdWVuY2VEaWFncmFtXG4gKiAgIHBhcnRpY2lwYW50IENsaWVudFxuICogICBwYXJ0aWNpcGFudCBFbnYgYXMgRW52aXJvbm1lbnRcbiAqICAgcGFydGljaXBhbnQgUHJvY2VzcyBhcyBwcm9jZXNzLmVudlxuICogICBwYXJ0aWNpcGFudCBCcm93c2VyIGFzIGdsb2JhbFRoaXMuRU5WXG4gKiAgIENsaWVudC0+PkVudjogYWNjdW11bGF0ZShwYXJ0aWFsQ29uZmlnKVxuICogICBFbnYtPj5FbnY6IGV4cGFuZCh2YWx1ZXMpXG4gKiAgIENsaWVudC0+PkVudjogQ29uZmlnLmxvZ2dpbmcubGV2ZWxcbiAqICAgYWx0IEJyb3dzZXIgcnVudGltZVxuICogICAgIEVudi0+PkJyb3dzZXI6IGxvb2t1cCBFTlYga2V5XG4gKiAgICAgQnJvd3Nlci0tPj5FbnY6IHJlc29sdmVkIHZhbHVlXG4gKiAgIGVsc2UgTm9kZSBydW50aW1lXG4gKiAgICAgRW52LT4+UHJvY2VzczogbG9va3VwIEVOViBrZXlcbiAqICAgICBQcm9jZXNzLS0+PkVudjogcmVzb2x2ZWQgdmFsdWVcbiAqICAgZW5kXG4gKiAgIEVudi0tPj5DbGllbnQ6IG1lcmdlZCB2YWx1ZVxuICovXG5jb25zdCBFbXB0eVZhbHVlID0gU3ltYm9sKFwiRW52aXJvbm1lbnRFbXB0eVwiKTtcbmNvbnN0IE1vZGVsU3ltYm9sID0gU3ltYm9sKFwiRW52aXJvbm1lbnRNb2RlbFwiKTtcblxuZXhwb3J0IGNsYXNzIEVudmlyb25tZW50PFQgZXh0ZW5kcyBvYmplY3Q+IGV4dGVuZHMgT2JqZWN0QWNjdW11bGF0b3I8VD4ge1xuICAvKipcbiAgICogQHN0YXRpY1xuICAgKiBAcHJvdGVjdGVkXG4gICAqIEBkZXNjcmlwdGlvbiBBIGZhY3RvcnkgZnVuY3Rpb24gZm9yIGNyZWF0aW5nIEVudmlyb25tZW50IGluc3RhbmNlcy5cbiAgICogQHN1bW1hcnkgRGVmaW5lcyBob3cgbmV3IGluc3RhbmNlcyBvZiB0aGUgRW52aXJvbm1lbnQgY2xhc3Mgc2hvdWxkIGJlIGNyZWF0ZWQuXG4gICAqIEByZXR1cm4ge0Vudmlyb25tZW50PGFueT59IEEgbmV3IGluc3RhbmNlIG9mIHRoZSBFbnZpcm9ubWVudCBjbGFzcy5cbiAgICovXG4gIHByb3RlY3RlZCBzdGF0aWMgZmFjdG9yeTogRW52aXJvbm1lbnRGYWN0b3J5PGFueSwgYW55PiA9XG4gICAgKCk6IEVudmlyb25tZW50PGFueT4gPT4gbmV3IEVudmlyb25tZW50KCk7XG5cbiAgLyoqXG4gICAqIEBzdGF0aWNcbiAgICogQHByaXZhdGVcbiAgICogQGRlc2NyaXB0aW9uIFRoZSBzaW5nbGV0b24gaW5zdGFuY2Ugb2YgdGhlIEVudmlyb25tZW50IGNsYXNzLlxuICAgKiBAdHlwZSB7RW52aXJvbm1lbnQ8YW55Pn1cbiAgICovXG4gIHByaXZhdGUgc3RhdGljIF9pbnN0YW5jZTogRW52aXJvbm1lbnQ8YW55PjtcblxuICBwcm90ZWN0ZWQgY29uc3RydWN0b3IoKSB7XG4gICAgc3VwZXIoKTtcbiAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkodGhpcywgTW9kZWxTeW1ib2wsIHtcbiAgICAgIHZhbHVlOiB7fSxcbiAgICAgIHdyaXRhYmxlOiB0cnVlLFxuICAgICAgZW51bWVyYWJsZTogZmFsc2UsXG4gICAgICBjb25maWd1cmFibGU6IGZhbHNlLFxuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBSZXRyaWV2ZXMgYSB2YWx1ZSBmcm9tIHRoZSBydW50aW1lIGVudmlyb25tZW50LlxuICAgKiBAc3VtbWFyeSBIYW5kbGVzIGJyb3dzZXIgYW5kIE5vZGUuanMgZW52aXJvbm1lbnRzIGJ5IG5vcm1hbGl6aW5nIGtleXMgYW5kIHBhcnNpbmcgdmFsdWVzLlxuICAgKiBAcGFyYW0ge3N0cmluZ30gayAtIEtleSB0byByZXNvbHZlIGZyb20gdGhlIGVudmlyb25tZW50LlxuICAgKiBAcmV0dXJuIHt1bmtub3dufSBWYWx1ZSByZXNvbHZlZCBmcm9tIHRoZSBlbnZpcm9ubWVudCBvciBgdW5kZWZpbmVkYCB3aGVuIGFic2VudC5cbiAgICovXG4gIHByb3RlY3RlZCBmcm9tRW52KGs6IHN0cmluZykge1xuICAgIGxldCBlbnY6IFJlY29yZDxzdHJpbmcsIHVua25vd24+O1xuICAgIGlmIChpc0Jyb3dzZXIoKSkge1xuICAgICAgZW52ID1cbiAgICAgICAgKFxuICAgICAgICAgIGdsb2JhbFRoaXMgYXMgdHlwZW9mIGdsb2JhbFRoaXMgJiB7XG4gICAgICAgICAgICBbQnJvd3NlckVudktleV06IFJlY29yZDxzdHJpbmcsIGFueT47XG4gICAgICAgICAgfVxuICAgICAgICApW0Jyb3dzZXJFbnZLZXldIHx8IHt9O1xuICAgIH0gZWxzZSB7XG4gICAgICBlbnYgPSBnbG9iYWxUaGlzLnByb2Nlc3MuZW52O1xuICAgICAgayA9IHRvRU5WRm9ybWF0KGspO1xuICAgIH1cbiAgICByZXR1cm4gdGhpcy5wYXJzZUVudlZhbHVlKGVudltrXSk7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIENvbnZlcnRzIHN0cmluZ2lmaWVkIGVudmlyb25tZW50IHZhbHVlcyBpbnRvIG5hdGl2ZSB0eXBlcy5cbiAgICogQHN1bW1hcnkgSW50ZXJwcmV0cyBib29sZWFucyBhbmQgbnVtYmVycyB3aGlsZSBsZWF2aW5nIG90aGVyIHR5cGVzIHVuY2hhbmdlZC5cbiAgICogQHBhcmFtIHt1bmtub3dufSB2YWwgLSBSYXcgdmFsdWUgcmV0cmlldmVkIGZyb20gdGhlIGVudmlyb25tZW50LlxuICAgKiBAcmV0dXJuIHt1bmtub3dufSBQYXJzZWQgdmFsdWUgY29udmVydGVkIHRvIGJvb2xlYW4sIG51bWJlciwgb3IgbGVmdCBhcy1pcy5cbiAgICovXG4gIHByb3RlY3RlZCBwYXJzZUVudlZhbHVlKHZhbDogdW5rbm93bikge1xuICAgIGlmICh0eXBlb2YgdmFsICE9PSBcInN0cmluZ1wiKSByZXR1cm4gdmFsO1xuICAgIGlmICh2YWwgPT09IFwidHJ1ZVwiKSByZXR1cm4gdHJ1ZTtcbiAgICBpZiAodmFsID09PSBcImZhbHNlXCIpIHJldHVybiBmYWxzZTtcbiAgICBjb25zdCByZXN1bHQgPSBwYXJzZUZsb2F0KHZhbCk7XG4gICAgaWYgKCFpc05hTihyZXN1bHQpKSByZXR1cm4gcmVzdWx0O1xuICAgIHJldHVybiB2YWw7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIEV4cGFuZHMgYW4gb2JqZWN0IGludG8gdGhlIGVudmlyb25tZW50LlxuICAgKiBAc3VtbWFyeSBEZWZpbmVzIGxhenkgcHJvcGVydGllcyB0aGF0IGZpcnN0IGNvbnN1bHQgcnVudGltZSB2YXJpYWJsZXMgYmVmb3JlIGZhbGxpbmcgYmFjayB0byBzZWVkZWQgdmFsdWVzLlxuICAgKiBAdGVtcGxhdGUgViAtIFR5cGUgb2YgdGhlIG9iamVjdCBiZWluZyBleHBhbmRlZC5cbiAgICogQHBhcmFtIHtWfSB2YWx1ZSAtIE9iamVjdCB0byBleHBvc2UgdGhyb3VnaCBlbnZpcm9ubWVudCBnZXR0ZXJzIGFuZCBzZXR0ZXJzLlxuICAgKiBAcmV0dXJuIHt2b2lkfVxuICAgKi9cbiAgcHJvdGVjdGVkIG92ZXJyaWRlIGV4cGFuZDxWIGV4dGVuZHMgb2JqZWN0Pih2YWx1ZTogVik6IHZvaWQge1xuICAgIE9iamVjdC5lbnRyaWVzKHZhbHVlKS5mb3JFYWNoKChbaywgdl0pID0+IHtcbiAgICAgIEVudmlyb25tZW50Lm1lcmdlTW9kZWwoKHRoaXMgYXMgYW55KVtNb2RlbFN5bWJvbF0sIGssIHYpO1xuICAgICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KHRoaXMsIGssIHtcbiAgICAgICAgZ2V0OiAoKSA9PiB7XG4gICAgICAgICAgY29uc3QgZnJvbUVudiA9IHRoaXMuZnJvbUVudihrKTtcbiAgICAgICAgICBpZiAodHlwZW9mIGZyb21FbnYgIT09IFwidW5kZWZpbmVkXCIpIHJldHVybiBmcm9tRW52O1xuICAgICAgICAgIGlmICh2ICYmIHR5cGVvZiB2ID09PSBcIm9iamVjdFwiKSB7XG4gICAgICAgICAgICByZXR1cm4gRW52aXJvbm1lbnQuYnVpbGRFbnZQcm94eSh2IGFzIGFueSwgW2tdKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgLy8gSWYgdGhlIG1vZGVsIHByb3ZpZGVzIGFuIGVtcHR5IHN0cmluZywgbWFyayB3aXRoIEVtcHR5VmFsdWUgc28gaW5zdGFuY2UgcHJveHkgY2FuIHJldHVybiB1bmRlZmluZWQgd2l0aG91dCBlbmFibGluZyBrZXkgY29tcG9zaXRpb25cbiAgICAgICAgICBpZiAodiA9PT0gXCJcIikge1xuICAgICAgICAgICAgcmV0dXJuIEVtcHR5VmFsdWUgYXMgdW5rbm93biBhcyBWW2tleW9mIFZdO1xuICAgICAgICAgIH1cbiAgICAgICAgICByZXR1cm4gdjtcbiAgICAgICAgfSxcbiAgICAgICAgc2V0OiAodmFsOiBWW2tleW9mIFZdKSA9PiB7XG4gICAgICAgICAgdiA9IHZhbDtcbiAgICAgICAgfSxcbiAgICAgICAgY29uZmlndXJhYmxlOiB0cnVlLFxuICAgICAgICBlbnVtZXJhYmxlOiB0cnVlLFxuICAgICAgfSk7XG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFJldHVybnMgYSBwcm94eSBlbmZvcmNpbmcgcmVxdWlyZWQgZW52aXJvbm1lbnQgdmFyaWFibGVzLlxuICAgKiBAc3VtbWFyeSBBY2Nlc3NpbmcgYSBwcm9wZXJ0eSB0aGF0IHJlc29sdmVzIHRvIGB1bmRlZmluZWRgIG9yIGFuIGVtcHR5IHN0cmluZyB3aGVuIGRlY2xhcmVkIGluIHRoZSBtb2RlbCB0aHJvd3MgYW4gZXJyb3IuXG4gICAqIEByZXR1cm4ge3RoaXN9IFByb3h5IG9mIHRoZSBlbnZpcm9ubWVudCBlbmZvcmNpbmcgcmVxdWlyZWQgdmFyaWFibGVzLlxuICAgKi9cbiAgb3JUaHJvdygpOiBFbnZpcm9ubWVudEluc3RhbmNlPFQ+IHtcbiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLXRoaXMtYWxpYXNcbiAgICBjb25zdCBiYXNlID0gdGhpcztcbiAgICBjb25zdCBtb2RlbFJvb3QgPSAoYmFzZSBhcyBhbnkpW01vZGVsU3ltYm9sXSBhcyBSZWNvcmQ8c3RyaW5nLCBhbnk+O1xuICAgIGNvbnN0IGJ1aWxkS2V5ID0gKHBhdGg6IHN0cmluZ1tdKSA9PlxuICAgICAgcGF0aC5tYXAoKHNlZ21lbnQpID0+IHRvRU5WRm9ybWF0KHNlZ21lbnQpKS5qb2luKEVOVl9QQVRIX0RFTElNSVRFUik7XG4gICAgY29uc3QgcmVhZFJ1bnRpbWUgPSAoa2V5OiBzdHJpbmcpID0+IEVudmlyb25tZW50LnJlYWRSdW50aW1lRW52KGtleSk7XG4gICAgY29uc3QgcGFyc2VSdW50aW1lID0gKHJhdzogdW5rbm93bikgPT5cbiAgICAgIHR5cGVvZiByYXcgIT09IFwidW5kZWZpbmVkXCIgPyB0aGlzLnBhcnNlRW52VmFsdWUocmF3KSA6IHVuZGVmaW5lZDtcblxuICAgIGNvbnN0IG1pc3NpbmcgPSAoa2V5OiBzdHJpbmcsIGVtcHR5OiBib29sZWFuID0gZmFsc2UpID0+XG4gICAgICBFbnZpcm9ubWVudC5taXNzaW5nRW52RXJyb3Ioa2V5LCBlbXB0eSk7XG5cbiAgICBjb25zdCBjcmVhdGVOZXN0ZWRQcm94eSA9IChtb2RlbDogYW55LCBwYXRoOiBzdHJpbmdbXSk6IGFueSA9PiB7XG4gICAgICBjb25zdCBoYW5kbGVyOiBQcm94eUhhbmRsZXI8YW55PiA9IHtcbiAgICAgICAgZ2V0KF90YXJnZXQsIHByb3ApIHtcbiAgICAgICAgICBpZiAodHlwZW9mIHByb3AgIT09IFwic3RyaW5nXCIpIHJldHVybiB1bmRlZmluZWQ7XG4gICAgICAgICAgY29uc3QgbmV4dFBhdGggPSBbLi4ucGF0aCwgcHJvcF07XG4gICAgICAgICAgY29uc3QgZW52S2V5ID0gYnVpbGRLZXkobmV4dFBhdGgpO1xuICAgICAgICAgIGNvbnN0IHJ1bnRpbWVSYXcgPSByZWFkUnVudGltZShlbnZLZXkpO1xuICAgICAgICAgIGlmICh0eXBlb2YgcnVudGltZVJhdyA9PT0gXCJzdHJpbmdcIiAmJiBydW50aW1lUmF3Lmxlbmd0aCA9PT0gMClcbiAgICAgICAgICAgIHRocm93IG1pc3NpbmcoZW52S2V5LCB0cnVlKTtcbiAgICAgICAgICBjb25zdCBydW50aW1lVmFsdWUgPSBwYXJzZVJ1bnRpbWUocnVudGltZVJhdyk7XG4gICAgICAgICAgaWYgKHR5cGVvZiBydW50aW1lVmFsdWUgIT09IFwidW5kZWZpbmVkXCIpIHtcbiAgICAgICAgICAgIGlmICh0eXBlb2YgcnVudGltZVZhbHVlID09PSBcInN0cmluZ1wiICYmIHJ1bnRpbWVWYWx1ZS5sZW5ndGggPT09IDApXG4gICAgICAgICAgICAgIHRocm93IG1pc3NpbmcoZW52S2V5LCB0cnVlKTtcbiAgICAgICAgICAgIHJldHVybiBydW50aW1lVmFsdWU7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgY29uc3QgaGFzUHJvcCA9XG4gICAgICAgICAgICBtb2RlbCAmJiBPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwobW9kZWwsIHByb3ApO1xuICAgICAgICAgIGlmICghaGFzUHJvcCkgdGhyb3cgbWlzc2luZyhlbnZLZXkpO1xuXG4gICAgICAgICAgY29uc3QgbW9kZWxWYWx1ZSA9IG1vZGVsW3Byb3BdO1xuICAgICAgICAgIGlmICh0eXBlb2YgbW9kZWxWYWx1ZSA9PT0gXCJ1bmRlZmluZWRcIikgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICAgICAgICBpZiAobW9kZWxWYWx1ZSA9PT0gXCJcIikgdGhyb3cgbWlzc2luZyhlbnZLZXkpO1xuXG4gICAgICAgICAgaWYgKFxuICAgICAgICAgICAgbW9kZWxWYWx1ZSAmJlxuICAgICAgICAgICAgdHlwZW9mIG1vZGVsVmFsdWUgPT09IFwib2JqZWN0XCIgJiZcbiAgICAgICAgICAgICFBcnJheS5pc0FycmF5KG1vZGVsVmFsdWUpXG4gICAgICAgICAgKSB7XG4gICAgICAgICAgICByZXR1cm4gY3JlYXRlTmVzdGVkUHJveHkobW9kZWxWYWx1ZSwgbmV4dFBhdGgpO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIHJldHVybiBtb2RlbFZhbHVlO1xuICAgICAgICB9LFxuICAgICAgICBvd25LZXlzKCkge1xuICAgICAgICAgIHJldHVybiBtb2RlbCA/IFJlZmxlY3Qub3duS2V5cyhtb2RlbCkgOiBbXTtcbiAgICAgICAgfSxcbiAgICAgICAgZ2V0T3duUHJvcGVydHlEZXNjcmlwdG9yKF90YXJnZXQsIHByb3ApIHtcbiAgICAgICAgICBpZiAoIW1vZGVsKSByZXR1cm4gdW5kZWZpbmVkO1xuICAgICAgICAgIGlmIChPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwobW9kZWwsIHByb3ApKSB7XG4gICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICBlbnVtZXJhYmxlOiB0cnVlLFxuICAgICAgICAgICAgICBjb25maWd1cmFibGU6IHRydWUsXG4gICAgICAgICAgICB9IGFzIFByb3BlcnR5RGVzY3JpcHRvcjtcbiAgICAgICAgICB9XG4gICAgICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICAgICAgfSxcbiAgICAgIH07XG4gICAgICByZXR1cm4gbmV3IFByb3h5KHt9LCBoYW5kbGVyKTtcbiAgICB9O1xuXG4gICAgY29uc3QgaGFuZGxlcjogUHJveHlIYW5kbGVyPGFueT4gPSB7XG4gICAgICBnZXQodGFyZ2V0LCBwcm9wLCByZWNlaXZlcikge1xuICAgICAgICBpZiAodHlwZW9mIHByb3AgIT09IFwic3RyaW5nXCIpXG4gICAgICAgICAgcmV0dXJuIFJlZmxlY3QuZ2V0KHRhcmdldCwgcHJvcCwgcmVjZWl2ZXIpO1xuICAgICAgICBjb25zdCBoYXNNb2RlbFByb3AgPSBPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwoXG4gICAgICAgICAgbW9kZWxSb290LFxuICAgICAgICAgIHByb3BcbiAgICAgICAgKTtcbiAgICAgICAgaWYgKCFoYXNNb2RlbFByb3ApIHJldHVybiBSZWZsZWN0LmdldCh0YXJnZXQsIHByb3AsIHJlY2VpdmVyKTtcblxuICAgICAgICBjb25zdCBlbnZLZXkgPSBidWlsZEtleShbcHJvcF0pO1xuICAgICAgICBjb25zdCBydW50aW1lUmF3ID0gcmVhZFJ1bnRpbWUoZW52S2V5KTtcbiAgICAgICAgaWYgKHR5cGVvZiBydW50aW1lUmF3ID09PSBcInN0cmluZ1wiICYmIHJ1bnRpbWVSYXcubGVuZ3RoID09PSAwKVxuICAgICAgICAgIHRocm93IG1pc3NpbmcoZW52S2V5LCB0cnVlKTtcbiAgICAgICAgY29uc3QgcnVudGltZVZhbHVlID0gcGFyc2VSdW50aW1lKHJ1bnRpbWVSYXcpO1xuICAgICAgICBpZiAodHlwZW9mIHJ1bnRpbWVWYWx1ZSAhPT0gXCJ1bmRlZmluZWRcIikge1xuICAgICAgICAgIGlmICh0eXBlb2YgcnVudGltZVZhbHVlID09PSBcInN0cmluZ1wiICYmIHJ1bnRpbWVWYWx1ZS5sZW5ndGggPT09IDApXG4gICAgICAgICAgICB0aHJvdyBtaXNzaW5nKGVudktleSwgdHJ1ZSk7XG4gICAgICAgICAgcmV0dXJuIHJ1bnRpbWVWYWx1ZTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IG1vZGVsVmFsdWUgPSBtb2RlbFJvb3RbcHJvcF07XG4gICAgICAgIGlmIChcbiAgICAgICAgICBtb2RlbFZhbHVlICYmXG4gICAgICAgICAgdHlwZW9mIG1vZGVsVmFsdWUgPT09IFwib2JqZWN0XCIgJiZcbiAgICAgICAgICAhQXJyYXkuaXNBcnJheShtb2RlbFZhbHVlKVxuICAgICAgICApIHtcbiAgICAgICAgICByZXR1cm4gY3JlYXRlTmVzdGVkUHJveHkobW9kZWxWYWx1ZSwgW3Byb3BdKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICh0eXBlb2YgbW9kZWxWYWx1ZSA9PT0gXCJ1bmRlZmluZWRcIilcbiAgICAgICAgICByZXR1cm4gUmVmbGVjdC5nZXQodGFyZ2V0LCBwcm9wLCByZWNlaXZlcik7XG5cbiAgICAgICAgY29uc3QgYWN0dWFsID0gUmVmbGVjdC5nZXQodGFyZ2V0LCBwcm9wKTtcbiAgICAgICAgaWYgKHR5cGVvZiBhY3R1YWwgPT09IFwidW5kZWZpbmVkXCIgfHwgYWN0dWFsID09PSBcIlwiKVxuICAgICAgICAgIHRocm93IG1pc3NpbmcoZW52S2V5LCBhY3R1YWwgPT09IFwiXCIpO1xuXG4gICAgICAgIHJldHVybiBhY3R1YWw7XG4gICAgICB9LFxuICAgIH07XG5cbiAgICByZXR1cm4gbmV3IFByb3h5KGJhc2UsIGhhbmRsZXIpIGFzIEVudmlyb25tZW50SW5zdGFuY2U8VD47XG4gIH1cblxuICAvKipcbiAgICogQHByb3RlY3RlZFxuICAgKiBAc3RhdGljXG4gICAqIEBkZXNjcmlwdGlvbiBSZXRyaWV2ZXMgb3IgY3JlYXRlcyB0aGUgc2luZ2xldG9uIGluc3RhbmNlIG9mIHRoZSBFbnZpcm9ubWVudCBjbGFzcy5cbiAgICogQHN1bW1hcnkgRW5zdXJlcyBvbmx5IG9uZSB7QGxpbmsgRW52aXJvbm1lbnR9IGluc3RhbmNlIGlzIGNyZWF0ZWQsIHdyYXBwaW5nIGl0IGluIGEgcHJveHkgdG8gY29tcG9zZSBFTlYga2V5cyBvbiBkZW1hbmQuXG4gICAqIEB0ZW1wbGF0ZSBFXG4gICAqIEBwYXJhbSB7Li4udW5rbm93bltdfSBhcmdzIC0gQXJndW1lbnRzIGZvcndhcmRlZCB0byB0aGUgZmFjdG9yeSB3aGVuIGluc3RhbnRpYXRpbmcgdGhlIHNpbmdsZXRvbi5cbiAgICogQHJldHVybiB7RX0gU2luZ2xldG9uIGVudmlyb25tZW50IGluc3RhbmNlLlxuICAgKi9cbiAgcHJvdGVjdGVkIHN0YXRpYyBpbnN0YW5jZTxFIGV4dGVuZHMgRW52aXJvbm1lbnQ8YW55Pj4oXG4gICAgLi4uYXJnczogdW5rbm93bltdXG4gICk6IEUge1xuICAgIGlmICghRW52aXJvbm1lbnQuX2luc3RhbmNlKSB7XG4gICAgICBjb25zdCBiYXNlID0gRW52aXJvbm1lbnQuZmFjdG9yeSguLi5hcmdzKSBhcyBFO1xuICAgICAgY29uc3QgcHJveGllZCA9IG5ldyBQcm94eShiYXNlIGFzIGFueSwge1xuICAgICAgICBnZXQodGFyZ2V0LCBwcm9wLCByZWNlaXZlcikge1xuICAgICAgICAgIGNvbnN0IHZhbHVlID0gUmVmbGVjdC5nZXQodGFyZ2V0LCBwcm9wLCByZWNlaXZlcik7XG4gICAgICAgICAgaWYgKHZhbHVlID09PSBFbXB0eVZhbHVlKSByZXR1cm4gdW5kZWZpbmVkO1xuICAgICAgICAgIC8vIElmIHRoZSBwcm9wZXJ0eSBleGlzdHMgb24gdGhlIGluc3RhbmNlIGJ1dCByZXNvbHZlcyB0byB1bmRlZmluZWQsIHJldHVybiB1bmRlZmluZWQgKG5vIHByb3h5KVxuICAgICAgICAgIGlmIChcbiAgICAgICAgICAgIHR5cGVvZiBwcm9wID09PSBcInN0cmluZ1wiICYmXG4gICAgICAgICAgICBPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwodGFyZ2V0LCBwcm9wKVxuICAgICAgICAgICkge1xuICAgICAgICAgICAgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gXCJ1bmRlZmluZWRcIikgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICAgICAgICB9XG4gICAgICAgICAgaWYgKHR5cGVvZiB2YWx1ZSAhPT0gXCJ1bmRlZmluZWRcIikgcmV0dXJuIHZhbHVlO1xuICAgICAgICAgIGlmICh0eXBlb2YgcHJvcCA9PT0gXCJzdHJpbmdcIikge1xuICAgICAgICAgICAgLy8gQXZvaWQgaW50ZXJmZXJpbmcgd2l0aCBsb2dnaW5nIGNvbmZpZyBsb29rdXBzIGZvciBvcHRpb25hbCBmaWVsZHMgbGlrZSAnYXBwJ1xuICAgICAgICAgICAgaWYgKHByb3AgPT09IFwiYXBwXCIpIHJldHVybiB1bmRlZmluZWQ7XG4gICAgICAgICAgICByZXR1cm4gRW52aXJvbm1lbnQuYnVpbGRFbnZQcm94eSh1bmRlZmluZWQsIFtwcm9wXSk7XG4gICAgICAgICAgfVxuICAgICAgICAgIHJldHVybiB2YWx1ZTtcbiAgICAgICAgfSxcbiAgICAgIH0pO1xuICAgICAgRW52aXJvbm1lbnQuX2luc3RhbmNlID0gcHJveGllZCBhcyBhbnk7XG4gICAgfVxuICAgIHJldHVybiBFbnZpcm9ubWVudC5faW5zdGFuY2UgYXMgRTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAc3RhdGljXG4gICAqIEBkZXNjcmlwdGlvbiBBY2N1bXVsYXRlcyB0aGUgZ2l2ZW4gdmFsdWUgaW50byB0aGUgZW52aXJvbm1lbnQuXG4gICAqIEBzdW1tYXJ5IEFkZHMgbmV3IHByb3BlcnRpZXMsIGhpZGluZyByYXcgZGVzY3JpcHRvcnMgdG8gYXZvaWQgbGVha2luZyBlbnVtZXJhdGlvbiBzZW1hbnRpY3MuXG4gICAqIEB0ZW1wbGF0ZSBUXG4gICAqIEB0ZW1wbGF0ZSBWXG4gICAqIEBwYXJhbSB7Vn0gdmFsdWUgLSBPYmplY3QgdG8gbWVyZ2UgaW50byB0aGUgZW52aXJvbm1lbnQuXG4gICAqIEByZXR1cm4ge0Vudmlyb25tZW50fSBVcGRhdGVkIGVudmlyb25tZW50IHJlZmVyZW5jZS5cbiAgICovXG4gIHN0YXRpYyBhY2N1bXVsYXRlPFYgZXh0ZW5kcyBvYmplY3QsIFRCYXNlIGV4dGVuZHMgb2JqZWN0ID0gb2JqZWN0PihcbiAgICB2YWx1ZTogVlxuICApOiBFbnZpcm9ubWVudEluc3RhbmNlPFRCYXNlICYgVj4ge1xuICAgIGNvbnN0IGluc3RhbmNlID0gRW52aXJvbm1lbnQuaW5zdGFuY2U8RW52aXJvbm1lbnQ8VEJhc2UgJiBWPj4oKTtcbiAgICBPYmplY3Qua2V5cyhpbnN0YW5jZSBhcyBhbnkpLmZvckVhY2goKGtleSkgPT4ge1xuICAgICAgY29uc3QgZGVzYyA9IE9iamVjdC5nZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3IoaW5zdGFuY2UgYXMgYW55LCBrZXkpO1xuICAgICAgaWYgKGRlc2MgJiYgZGVzYy5jb25maWd1cmFibGUgJiYgZGVzYy5lbnVtZXJhYmxlKSB7XG4gICAgICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShpbnN0YW5jZSBhcyBhbnksIGtleSwge1xuICAgICAgICAgIC4uLmRlc2MsXG4gICAgICAgICAgZW51bWVyYWJsZTogZmFsc2UsXG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH0pO1xuICAgIHJldHVybiBpbnN0YW5jZS5hY2N1bXVsYXRlKHZhbHVlKSBhcyB1bmtub3duIGFzIEVudmlyb25tZW50SW5zdGFuY2U8XG4gICAgICBUQmFzZSAmXG4gICAgICAgIFZcbiAgICA+O1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBSZXRyaWV2ZXMgYSB2YWx1ZSB1c2luZyBhIGRvdC1wYXRoIGtleSBmcm9tIHRoZSBhY2N1bXVsYXRlZCBlbnZpcm9ubWVudC5cbiAgICogQHN1bW1hcnkgRGVsZWdhdGVzIHRvIHRoZSBzaW5nbGV0b24gaW5zdGFuY2UgdG8gYWNjZXNzIHN0b3JlZCBjb25maWd1cmF0aW9uLlxuICAgKiBAcGFyYW0ge3N0cmluZ30ga2V5IC0gS2V5IHRvIHJlc29sdmUgZnJvbSB0aGUgZW52aXJvbm1lbnQgc3RvcmUuXG4gICAqIEByZXR1cm4ge3Vua25vd259IFN0b3JlZCB2YWx1ZSBjb3JyZXNwb25kaW5nIHRvIHRoZSBwcm92aWRlZCBrZXkuXG4gICAqL1xuICBzdGF0aWMgZ2V0KGtleTogc3RyaW5nKSB7XG4gICAgcmV0dXJuIEVudmlyb25tZW50Ll9pbnN0YW5jZS5nZXQoa2V5KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gQnVpbGRzIGEgcHJveHkgdGhhdCBjb21wb3NlcyBlbnZpcm9ubWVudCBrZXlzIGZvciBuZXN0ZWQgcHJvcGVydGllcy5cbiAgICogQHN1bW1hcnkgQWxsb3dzIGNoYWluZWQgcHJvcGVydHkgYWNjZXNzIHRvIGVtaXQgdXBwZXJjYXNlIEVOViBpZGVudGlmaWVycyB3aGlsZSBob25vcmluZyBleGlzdGluZyBydW50aW1lIG92ZXJyaWRlcy5cbiAgICogQHBhcmFtIHthbnl9IGN1cnJlbnQgLSBTZWVkIG1vZGVsIHNlZ21lbnQgdXNlZCB3aGVuIHByb2plY3RpbmcgbmVzdGVkIHN0cnVjdHVyZXMuXG4gICAqIEBwYXJhbSB7c3RyaW5nW119IHBhdGggLSBBY2N1bXVsYXRlZCBwYXRoIHNlZ21lbnRzIGxlYWRpbmcgdG8gdGhlIHByb3h5LlxuICAgKiBAcmV0dXJuIHthbnl9IFByb3h5IHRoYXQgcmVzb2x2ZXMgZW52aXJvbm1lbnQgdmFsdWVzIG9yIGNvbXBvc2VzIGFkZGl0aW9uYWwgcHJveGllcyBmb3IgZGVlcGVyIHBhdGhzLlxuICAgKi9cbiAgcHJpdmF0ZSBzdGF0aWMgYnVpbGRFbnZQcm94eShjdXJyZW50OiBhbnksIHBhdGg6IHN0cmluZ1tdKTogYW55IHtcbiAgICBjb25zdCBidWlsZEtleSA9IChwOiBzdHJpbmdbXSkgPT5cbiAgICAgIHAubWFwKChzZWcpID0+IHRvRU5WRm9ybWF0KHNlZykpLmpvaW4oRU5WX1BBVEhfREVMSU1JVEVSKTtcblxuICAgIC8vIEhlbHBlciB0byByZWFkIGZyb20gdGhlIGFjdGl2ZSBlbnZpcm9ubWVudCBnaXZlbiBhIGNvbXBvc2VkIGtleVxuICAgIGNvbnN0IHJlYWRFbnYgPSAoa2V5OiBzdHJpbmcpOiB1bmtub3duID0+IHtcbiAgICAgIHJldHVybiBFbnZpcm9ubWVudC5yZWFkUnVudGltZUVudihrZXkpO1xuICAgIH07XG5cbiAgICBjb25zdCBoYW5kbGVyOiBQcm94eUhhbmRsZXI8YW55PiA9IHtcbiAgICAgIGdldChfdGFyZ2V0LCBwcm9wOiBzdHJpbmcgfCBzeW1ib2wpIHtcbiAgICAgICAgaWYgKHByb3AgPT09IFN5bWJvbC50b1ByaW1pdGl2ZSkge1xuICAgICAgICAgIHJldHVybiAoKSA9PiBidWlsZEtleShwYXRoKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAocHJvcCA9PT0gXCJ0b1N0cmluZ1wiKSB7XG4gICAgICAgICAgcmV0dXJuICgpID0+IGJ1aWxkS2V5KHBhdGgpO1xuICAgICAgICB9XG4gICAgICAgIGlmIChwcm9wID09PSBcInZhbHVlT2ZcIikge1xuICAgICAgICAgIHJldHVybiAoKSA9PiBidWlsZEtleShwYXRoKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAodHlwZW9mIHByb3AgPT09IFwic3ltYm9sXCIpIHJldHVybiB1bmRlZmluZWQ7XG5cbiAgICAgICAgY29uc3QgaGFzUHJvcCA9XG4gICAgICAgICAgISFjdXJyZW50ICYmIE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChjdXJyZW50LCBwcm9wKTtcbiAgICAgICAgY29uc3QgbmV4dE1vZGVsID0gaGFzUHJvcCA/IChjdXJyZW50IGFzIGFueSlbcHJvcF0gOiB1bmRlZmluZWQ7XG4gICAgICAgIGNvbnN0IG5leHRQYXRoID0gWy4uLnBhdGgsIHByb3BdO1xuICAgICAgICBjb25zdCBjb21wb3NlZEtleSA9IGJ1aWxkS2V5KG5leHRQYXRoKTtcblxuICAgICAgICAvLyBJZiBhbiBFTlYgdmFsdWUgZXhpc3RzIGZvciB0aGlzIHBhdGgsIHJldHVybiBpdCBkaXJlY3RseVxuICAgICAgICBjb25zdCBlbnZWYWx1ZSA9IHJlYWRFbnYoY29tcG9zZWRLZXkpO1xuICAgICAgICBpZiAodHlwZW9mIGVudlZhbHVlICE9PSBcInVuZGVmaW5lZFwiKSByZXR1cm4gZW52VmFsdWU7XG5cbiAgICAgICAgLy8gT3RoZXJ3aXNlLCBpZiB0aGUgbW9kZWwgaGFzIGFuIG9iamVjdCBhdCB0aGlzIHBhdGgsIGtlZXAgZHJpbGxpbmcgd2l0aCBhIHByb3h5XG4gICAgICAgIGNvbnN0IGlzTmV4dE9iamVjdCA9IG5leHRNb2RlbCAmJiB0eXBlb2YgbmV4dE1vZGVsID09PSBcIm9iamVjdFwiO1xuICAgICAgICBpZiAoaXNOZXh0T2JqZWN0KSByZXR1cm4gRW52aXJvbm1lbnQuYnVpbGRFbnZQcm94eShuZXh0TW9kZWwsIG5leHRQYXRoKTtcblxuICAgICAgICAvLyBJZiB0aGUgbW9kZWwgbWFya3MgdGhpcyBsZWFmIGFzIGFuIGVtcHR5IHN0cmluZywgdHJlYXQgYXMgdW5kZWZpbmVkIChubyBwcm94eSlcbiAgICAgICAgaWYgKGhhc1Byb3AgJiYgbmV4dE1vZGVsID09PSBcIlwiKSByZXR1cm4gdW5kZWZpbmVkO1xuICAgICAgICAvLyBJZiB0aGUgbW9kZWwgZXhwbGljaXRseSBjb250YWlucyB0aGUgcHJvcGVydHkgd2l0aCB2YWx1ZSB1bmRlZmluZWQsIHRyZWF0IGFzIHVuZGVmaW5lZCAobm8gcHJveHkpXG4gICAgICAgIGlmIChoYXNQcm9wICYmIHR5cGVvZiBuZXh0TW9kZWwgPT09IFwidW5kZWZpbmVkXCIpIHJldHVybiB1bmRlZmluZWQ7XG5cbiAgICAgICAgLy8gQWx3YXlzIHJldHVybiBhIHByb3h5IGZvciBmdXJ0aGVyIHBhdGggY29tcG9zaXRpb24gd2hlbiBubyBFTlYgdmFsdWU7XG4gICAgICAgIC8vIGRvIG5vdCBzdXJmYWNlIHByaW1pdGl2ZSBtb2RlbCBkZWZhdWx0cyBoZXJlICh0aGlzIEFQSSBpcyBmb3Iga2V5IGNvbXBvc2l0aW9uKS5cbiAgICAgICAgcmV0dXJuIEVudmlyb25tZW50LmJ1aWxkRW52UHJveHkodW5kZWZpbmVkLCBuZXh0UGF0aCk7XG4gICAgICB9LFxuICAgICAgb3duS2V5cygpIHtcbiAgICAgICAgcmV0dXJuIGN1cnJlbnQgPyBSZWZsZWN0Lm93bktleXMoY3VycmVudCkgOiBbXTtcbiAgICAgIH0sXG4gICAgICBnZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3IoX3QsIHApIHtcbiAgICAgICAgaWYgKCFjdXJyZW50KSByZXR1cm4gdW5kZWZpbmVkIGFzIGFueTtcbiAgICAgICAgaWYgKE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChjdXJyZW50LCBwKSkge1xuICAgICAgICAgIHJldHVybiB7IGVudW1lcmFibGU6IHRydWUsIGNvbmZpZ3VyYWJsZTogdHJ1ZSB9IGFzIFByb3BlcnR5RGVzY3JpcHRvcjtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdW5kZWZpbmVkIGFzIGFueTtcbiAgICAgIH0sXG4gICAgfTtcblxuICAgIGNvbnN0IHRhcmdldCA9IHt9IGFzIGFueTtcbiAgICByZXR1cm4gbmV3IFByb3h5KHRhcmdldCwgaGFuZGxlcik7XG4gIH1cblxuICAvKipcbiAgICogQHN0YXRpY1xuICAgKiBAZGVzY3JpcHRpb24gUmV0cmlldmVzIHRoZSBrZXlzIG9mIHRoZSBlbnZpcm9ubWVudCwgb3B0aW9uYWxseSBjb252ZXJ0aW5nIHRoZW0gdG8gRU5WIGZvcm1hdC5cbiAgICogQHN1bW1hcnkgR2V0cyBhbGwga2V5cyBpbiB0aGUgZW52aXJvbm1lbnQsIHdpdGggYW4gb3B0aW9uIHRvIGZvcm1hdCB0aGVtIGZvciBlbnZpcm9ubWVudCB2YXJpYWJsZXMuXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gW3RvRW52PXRydWVdIC0gV2hldGhlciB0byBjb252ZXJ0IHRoZSBrZXlzIHRvIEVOViBmb3JtYXQuXG4gICAqIEByZXR1cm4ge3N0cmluZ1tdfSBBbiBhcnJheSBvZiBrZXlzIGZyb20gdGhlIGVudmlyb25tZW50LlxuICAgKi9cbiAgc3RhdGljIGtleXModG9FbnY6IGJvb2xlYW4gPSB0cnVlKTogc3RyaW5nW10ge1xuICAgIHJldHVybiBFbnZpcm9ubWVudC5pbnN0YW5jZSgpXG4gICAgICAua2V5cygpXG4gICAgICAubWFwKChrKSA9PiAodG9FbnYgPyB0b0VOVkZvcm1hdChrKSA6IGspKTtcbiAgfVxuXG4gIHByaXZhdGUgc3RhdGljIG1lcmdlTW9kZWwoXG4gICAgbW9kZWw6IFJlY29yZDxzdHJpbmcsIGFueT4sXG4gICAga2V5OiBzdHJpbmcsXG4gICAgdmFsdWU6IGFueVxuICApIHtcbiAgICBpZiAoIW1vZGVsKSByZXR1cm47XG4gICAgaWYgKHZhbHVlICYmIHR5cGVvZiB2YWx1ZSA9PT0gXCJvYmplY3RcIiAmJiAhQXJyYXkuaXNBcnJheSh2YWx1ZSkpIHtcbiAgICAgIGNvbnN0IGV4aXN0aW5nID0gbW9kZWxba2V5XTtcbiAgICAgIGNvbnN0IHRhcmdldCA9XG4gICAgICAgIGV4aXN0aW5nICYmIHR5cGVvZiBleGlzdGluZyA9PT0gXCJvYmplY3RcIiAmJiAhQXJyYXkuaXNBcnJheShleGlzdGluZylcbiAgICAgICAgICA/IGV4aXN0aW5nXG4gICAgICAgICAgOiB7fTtcbiAgICAgIG1vZGVsW2tleV0gPSB0YXJnZXQ7XG4gICAgICBPYmplY3QuZW50cmllcyh2YWx1ZSkuZm9yRWFjaCgoW2NoaWxkS2V5LCBjaGlsZFZhbHVlXSkgPT4ge1xuICAgICAgICBFbnZpcm9ubWVudC5tZXJnZU1vZGVsKHRhcmdldCwgY2hpbGRLZXksIGNoaWxkVmFsdWUpO1xuICAgICAgfSk7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIG1vZGVsW2tleV0gPSB2YWx1ZTtcbiAgfVxuXG4gIHByaXZhdGUgc3RhdGljIHJlYWRSdW50aW1lRW52KGtleTogc3RyaW5nKTogdW5rbm93biB7XG4gICAgaWYgKGlzQnJvd3NlcigpKSB7XG4gICAgICBjb25zdCBlbnYgPSAoXG4gICAgICAgIGdsb2JhbFRoaXMgYXMgdHlwZW9mIGdsb2JhbFRoaXMgJiB7XG4gICAgICAgICAgW0Jyb3dzZXJFbnZLZXldPzogUmVjb3JkPHN0cmluZywgdW5rbm93bj47XG4gICAgICAgIH1cbiAgICAgIClbQnJvd3NlckVudktleV07XG4gICAgICByZXR1cm4gZW52ID8gZW52W2tleV0gOiB1bmRlZmluZWQ7XG4gICAgfVxuICAgIHJldHVybiAoZ2xvYmFsVGhpcyBhcyBhbnkpPy5wcm9jZXNzPy5lbnY/LltrZXldO1xuICB9XG5cbiAgcHJpdmF0ZSBzdGF0aWMgbWlzc2luZ0VudkVycm9yKGtleTogc3RyaW5nLCBlbXB0eTogYm9vbGVhbik6IEVycm9yIHtcbiAgICBjb25zdCBzdWZmaXggPSBlbXB0eSA/IFwiYW4gZW1wdHkgc3RyaW5nXCIgOiBcInVuZGVmaW5lZFwiO1xuICAgIHJldHVybiBuZXcgRXJyb3IoXG4gICAgICBgRW52aXJvbm1lbnQgdmFyaWFibGUgJHtrZXl9IGlzIHJlcXVpcmVkIGJ1dCB3YXMgJHtzdWZmaXh9LmBcbiAgICApO1xuICB9XG59XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIFNpbmdsZXRvbiBlbnZpcm9ubWVudCBpbnN0YW5jZSBzZWVkZWQgd2l0aCBkZWZhdWx0IGxvZ2dpbmcgY29uZmlndXJhdGlvbi5cbiAqIEBzdW1tYXJ5IENvbWJpbmVzIHtAbGluayBEZWZhdWx0TG9nZ2luZ0NvbmZpZ30gd2l0aCBydW50aW1lIGVudmlyb25tZW50IHZhcmlhYmxlcyB0byBwcm92aWRlIGNvbnNpc3RlbnQgbG9nZ2luZyBkZWZhdWx0cyBhY3Jvc3MgcGxhdGZvcm1zLlxuICogQGNvbnN0IExvZ2dlZEVudmlyb25tZW50XG4gKiBAbWVtYmVyT2YgbW9kdWxlOkxvZ2dpbmdcbiAqL1xuZXhwb3J0IGNvbnN0IExvZ2dlZEVudmlyb25tZW50ID0gRW52aXJvbm1lbnQuYWNjdW11bGF0ZShcbiAgT2JqZWN0LmFzc2lnbih7fSwgRGVmYXVsdExvZ2dpbmdDb25maWcsIHtcbiAgICBlbnY6XG4gICAgICAoaXNCcm93c2VyKCkgJiYgKGdsb2JhbFRoaXMgYXMgYW55KVtCcm93c2VyRW52S2V5XVxuICAgICAgICA/IChnbG9iYWxUaGlzIGFzIGFueSlbQnJvd3NlckVudktleV1bXCJOT0RFX0VOVlwiXVxuICAgICAgICA6IChnbG9iYWxUaGlzIGFzIGFueSkucHJvY2Vzcy5lbnZbXCJOT0RFX0VOVlwiXSkgfHwgXCJkZXZlbG9wbWVudFwiLFxuICB9KVxuKTtcbiIsImltcG9ydCB7XG4gIExvZ2dlckZhY3RvcnksXG4gIExvZ2dpbmdDb25maWcsXG4gIExvZ2dpbmdDb250ZXh0LFxuICBTdHJpbmdMaWtlLFxuICBUaGVtZSxcbiAgVGhlbWVPcHRpb24sXG4gIFRoZW1lT3B0aW9uQnlMb2dMZXZlbCxcbiAgTG9nZ2VyLFxufSBmcm9tIFwiLi90eXBlc1wiO1xuaW1wb3J0IHsgQ29sb3JpemVPcHRpb25zLCBzdHlsZSwgU3R5bGVkU3RyaW5nIH0gZnJvbSBcInN0eWxlZC1zdHJpbmctYnVpbGRlclwiO1xuaW1wb3J0IHsgRGVmYXVsdFRoZW1lLCBMb2dMZXZlbCwgTnVtZXJpY0xvZ0xldmVscyB9IGZyb20gXCIuL2NvbnN0YW50c1wiO1xuaW1wb3J0IHsgc2YgfSBmcm9tIFwiLi90ZXh0XCI7XG5pbXBvcnQgeyBMb2dnZWRFbnZpcm9ubWVudCB9IGZyb20gXCIuL2Vudmlyb25tZW50XCI7XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIEEgbWluaW1hbCBsb2dnZXIgaW1wbGVtZW50YXRpb24uXG4gKiBAc3VtbWFyeSBNaW5pTG9nZ2VyIGlzIGEgbGlnaHR3ZWlnaHQgbG9nZ2luZyBjbGFzcyB0aGF0IGltcGxlbWVudHMgdGhlIExvZ2dlciBpbnRlcmZhY2UuXG4gKiBJdCBwcm92aWRlcyBiYXNpYyBsb2dnaW5nIGZ1bmN0aW9uYWxpdHkgd2l0aCBzdXBwb3J0IGZvciBkaWZmZXJlbnQgbG9nIGxldmVscywgdmVyYm9zaXR5LFxuICogY29udGV4dC1hd2FyZSBsb2dnaW5nLCBhbmQgY3VzdG9taXphYmxlIGZvcm1hdHRpbmcuXG4gKiBAcGFyYW0ge3N0cmluZ30gY29udGV4dCAtIFRoZSBjb250ZXh0ICh0eXBpY2FsbHkgY2xhc3MgbmFtZSkgdGhpcyBsb2dnZXIgaXMgYXNzb2NpYXRlZCB3aXRoXG4gKiBAcGFyYW0ge1BhcnRpYWw8TG9nZ2luZ0NvbmZpZz59IGNvbmYgLSBPcHRpb25hbCBjb25maWd1cmF0aW9uIHRvIG92ZXJyaWRlIGdsb2JhbCBzZXR0aW5nc1xuICogQGNsYXNzIE1pbmlMb2dnZXJcbiAqIEBleGFtcGxlXG4gKiAvLyBDcmVhdGUgYSBuZXcgbG9nZ2VyIGZvciBhIGNsYXNzXG4gKiBjb25zdCBsb2dnZXIgPSBuZXcgTWluaUxvZ2dlcignTXlDbGFzcycpO1xuICpcbiAqIC8vIExvZyBtZXNzYWdlcyBhdCBkaWZmZXJlbnQgbGV2ZWxzXG4gKiBsb2dnZXIuaW5mbygnVGhpcyBpcyBhbiBpbmZvIG1lc3NhZ2UnKTtcbiAqIGxvZ2dlci5kZWJ1ZygnVGhpcyBpcyBhIGRlYnVnIG1lc3NhZ2UnKTtcbiAqIGxvZ2dlci5lcnJvcignU29tZXRoaW5nIHdlbnQgd3JvbmcnKTtcbiAqXG4gKiAvLyBDcmVhdGUgYSBjaGlsZCBsb2dnZXIgZm9yIGEgc3BlY2lmaWMgbWV0aG9kXG4gKiBjb25zdCBtZXRob2RMb2dnZXIgPSBsb2dnZXIuZm9yKCdteU1ldGhvZCcpO1xuICogbWV0aG9kTG9nZ2VyLnZlcmJvc2UoJ0RldGFpbGVkIGluZm9ybWF0aW9uJywgMik7XG4gKlxuICogLy8gTG9nIHdpdGggY3VzdG9tIGNvbmZpZ3VyYXRpb25cbiAqIGxvZ2dlci5mb3IoJ3NwZWNpYWxNZXRob2QnLCB7IHN0eWxlOiB0cnVlIH0pLmluZm8oJ1N0eWxlZCBtZXNzYWdlJyk7XG4gKi9cbmV4cG9ydCBjbGFzcyBNaW5pTG9nZ2VyIGltcGxlbWVudHMgTG9nZ2VyIHtcbiAgY29uc3RydWN0b3IoXG4gICAgcHJvdGVjdGVkIGNvbnRleHQ6IHN0cmluZyxcbiAgICBwcm90ZWN0ZWQgY29uZj86IFBhcnRpYWw8TG9nZ2luZ0NvbmZpZz5cbiAgKSB7fVxuXG4gIHByb3RlY3RlZCBjb25maWcoXG4gICAga2V5OiBrZXlvZiBMb2dnaW5nQ29uZmlnXG4gICk6IExvZ2dpbmdDb25maWdba2V5b2YgTG9nZ2luZ0NvbmZpZ10ge1xuICAgIGlmICh0aGlzLmNvbmYgJiYga2V5IGluIHRoaXMuY29uZikgcmV0dXJuIHRoaXMuY29uZltrZXldO1xuICAgIHJldHVybiBMb2dnaW5nLmdldENvbmZpZygpW2tleV07XG4gIH1cblxuICBmb3IobWV0aG9kOiBzdHJpbmcgfCAoKC4uLmFyZ3M6IGFueVtdKSA9PiBhbnkpKTogTG9nZ2VyO1xuICBmb3IoY29uZmlnOiBQYXJ0aWFsPExvZ2dpbmdDb25maWc+KTogTG9nZ2VyO1xuICBmb3IoXG4gICAgbWV0aG9kOiBzdHJpbmcgfCAoKC4uLmFyZ3M6IGFueVtdKSA9PiBhbnkpIHwgUGFydGlhbDxMb2dnaW5nQ29uZmlnPixcbiAgICBjb25maWc6IFBhcnRpYWw8TG9nZ2luZ0NvbmZpZz4sXG4gICAgLi4uYXJnczogYW55W11cbiAgKTogTG9nZ2VyO1xuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIENyZWF0ZXMgYSBjaGlsZCBsb2dnZXIgZm9yIGEgc3BlY2lmaWMgbWV0aG9kIG9yIGNvbnRleHRcbiAgICogQHN1bW1hcnkgUmV0dXJucyBhIG5ldyBsb2dnZXIgaW5zdGFuY2Ugd2l0aCB0aGUgY3VycmVudCBjb250ZXh0IGV4dGVuZGVkIGJ5IHRoZSBzcGVjaWZpZWQgbWV0aG9kIG5hbWVcbiAgICogQHBhcmFtIHtzdHJpbmcgfCBGdW5jdGlvbn0gbWV0aG9kIC0gVGhlIG1ldGhvZCBuYW1lIG9yIGZ1bmN0aW9uIHRvIGNyZWF0ZSBhIGxvZ2dlciBmb3JcbiAgICogQHBhcmFtIHtQYXJ0aWFsPExvZ2dpbmdDb25maWc+fSBjb25maWcgLSBPcHRpb25hbCBjb25maWd1cmF0aW9uIHRvIG92ZXJyaWRlIHNldHRpbmdzXG4gICAqIEBwYXJhbSB7Li4uYW55W119IGFyZ3MgLSBBZGRpdGlvbmFsIGFyZ3VtZW50cyB0byBwYXNzIHRvIHRoZSBsb2dnZXIgZmFjdG9yeVxuICAgKiBAcmV0dXJuIHtMb2dnZXJ9IEEgbmV3IGxvZ2dlciBpbnN0YW5jZSBmb3IgdGhlIHNwZWNpZmllZCBtZXRob2RcbiAgICovXG4gIGZvcihcbiAgICBtZXRob2Q/OiBzdHJpbmcgfCAoKC4uLmFyZ3M6IGFueVtdKSA9PiBhbnkpIHwgUGFydGlhbDxMb2dnaW5nQ29uZmlnPixcbiAgICBjb25maWc/OiBQYXJ0aWFsPExvZ2dpbmdDb25maWc+LFxuICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tdW51c2VkLXZhcnNcbiAgICAuLi5hcmdzOiBhbnlbXVxuICApOiBMb2dnZXIge1xuICAgIGlmICghY29uZmlnICYmIHR5cGVvZiBtZXRob2QgPT09IFwib2JqZWN0XCIpIHtcbiAgICAgIGNvbmZpZyA9IG1ldGhvZDtcbiAgICAgIG1ldGhvZCA9IHVuZGVmaW5lZDtcbiAgICB9IGVsc2Uge1xuICAgICAgbWV0aG9kID0gbWV0aG9kXG4gICAgICAgID8gdHlwZW9mIG1ldGhvZCA9PT0gXCJzdHJpbmdcIlxuICAgICAgICAgID8gbWV0aG9kXG4gICAgICAgICAgOiAobWV0aG9kIGFzIGFueSkubmFtZVxuICAgICAgICA6IHVuZGVmaW5lZDtcbiAgICB9XG5cbiAgICByZXR1cm4gbmV3IFByb3h5KHRoaXMsIHtcbiAgICAgIGdldDogKHRhcmdldDogdHlwZW9mIHRoaXMsIHA6IHN0cmluZyB8IHN5bWJvbCwgcmVjZWl2ZXI6IGFueSkgPT4ge1xuICAgICAgICBjb25zdCByZXN1bHQgPSBSZWZsZWN0LmdldCh0YXJnZXQsIHAsIHJlY2VpdmVyKTtcbiAgICAgICAgaWYgKHAgPT09IFwiY29uZmlnXCIpIHtcbiAgICAgICAgICByZXR1cm4gbmV3IFByb3h5KHRoaXMuY29uZmlnLCB7XG4gICAgICAgICAgICBnZXQ6ICh0YXJnZXQ6IHR5cGVvZiB0aGlzLmNvbmZpZywgcDogc3RyaW5nIHwgc3ltYm9sKSA9PiB7XG4gICAgICAgICAgICAgIGlmIChjb25maWcgJiYgcCBpbiBjb25maWcpXG4gICAgICAgICAgICAgICAgcmV0dXJuIGNvbmZpZ1twIGFzIGtleW9mIExvZ2dpbmdDb25maWddO1xuICAgICAgICAgICAgICByZXR1cm4gUmVmbGVjdC5nZXQodGFyZ2V0LCBwLCByZWNlaXZlcik7XG4gICAgICAgICAgICB9LFxuICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICAgIGlmIChwID09PSBcImNvbnRleHRcIiAmJiBtZXRob2QpIHtcbiAgICAgICAgICByZXR1cm4gW3Jlc3VsdCwgbWV0aG9kXS5qb2luKFwiLlwiKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gcmVzdWx0O1xuICAgICAgfSxcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gQ3JlYXRlcyBhIGZvcm1hdHRlZCBsb2cgc3RyaW5nXG4gICAqIEBzdW1tYXJ5IEdlbmVyYXRlcyBhIGxvZyBzdHJpbmcgd2l0aCB0aW1lc3RhbXAsIGNvbG9yZWQgbG9nIGxldmVsLCBjb250ZXh0LCBhbmQgbWVzc2FnZVxuICAgKiBAcGFyYW0ge0xvZ0xldmVsfSBsZXZlbCAtIFRoZSBsb2cgbGV2ZWwgZm9yIHRoaXMgbWVzc2FnZVxuICAgKiBAcGFyYW0ge1N0cmluZ0xpa2UgfCBFcnJvcn0gbWVzc2FnZSAtIFRoZSBtZXNzYWdlIHRvIGxvZyBvciBhbiBFcnJvciBvYmplY3RcbiAgICogQHBhcmFtIHtzdHJpbmd9IFtlcnJvcl0gLSBPcHRpb25hbCBlcnJvciB0byBleHRyYWN0IHN0YWNrIHRyYWNlIHRvIGluY2x1ZGUgaW4gdGhlIGxvZ1xuICAgKiBAcmV0dXJuIHtzdHJpbmd9IEEgZm9ybWF0dGVkIGxvZyBzdHJpbmcgd2l0aCBhbGwgY29tcG9uZW50c1xuICAgKi9cbiAgcHJvdGVjdGVkIGNyZWF0ZUxvZyhcbiAgICBsZXZlbDogTG9nTGV2ZWwsXG4gICAgbWVzc2FnZTogU3RyaW5nTGlrZSB8IEVycm9yLFxuICAgIGVycm9yPzogRXJyb3JcbiAgKTogc3RyaW5nIHtcbiAgICBjb25zdCBsb2c6IFJlY29yZDxcbiAgICAgIHwgXCJ0aW1lc3RhbXBcIlxuICAgICAgfCBcImxldmVsXCJcbiAgICAgIHwgXCJjb250ZXh0XCJcbiAgICAgIHwgXCJjb3JyZWxhdGlvbklkXCJcbiAgICAgIHwgXCJtZXNzYWdlXCJcbiAgICAgIHwgXCJzZXBhcmF0b3JcIlxuICAgICAgfCBcInN0YWNrXCJcbiAgICAgIHwgXCJhcHBcIixcbiAgICAgIHN0cmluZ1xuICAgID4gPSB7fSBhcyBhbnk7XG4gICAgY29uc3Qgc3R5bGUgPSB0aGlzLmNvbmZpZyhcInN0eWxlXCIpO1xuICAgIGNvbnN0IHNlcGFyYXRvciA9IHRoaXMuY29uZmlnKFwic2VwYXJhdG9yXCIpO1xuICAgIGNvbnN0IGFwcCA9IHRoaXMuY29uZmlnKFwiYXBwXCIpO1xuICAgIGlmIChhcHApXG4gICAgICBsb2cuYXBwID0gc3R5bGVcbiAgICAgICAgPyBMb2dnaW5nLnRoZW1lKGFwcCBhcyBzdHJpbmcsIFwiYXBwXCIsIGxldmVsKVxuICAgICAgICA6IChhcHAgYXMgc3RyaW5nKTtcblxuICAgIGlmIChzZXBhcmF0b3IpXG4gICAgICBsb2cuc2VwYXJhdG9yID0gc3R5bGVcbiAgICAgICAgPyBMb2dnaW5nLnRoZW1lKHNlcGFyYXRvciBhcyBzdHJpbmcsIFwic2VwYXJhdG9yXCIsIGxldmVsKVxuICAgICAgICA6IChzZXBhcmF0b3IgYXMgc3RyaW5nKTtcblxuICAgIGlmICh0aGlzLmNvbmZpZyhcInRpbWVzdGFtcFwiKSkge1xuICAgICAgY29uc3QgZGF0ZSA9IG5ldyBEYXRlKCkudG9JU09TdHJpbmcoKTtcbiAgICAgIGNvbnN0IHRpbWVzdGFtcCA9IHN0eWxlID8gTG9nZ2luZy50aGVtZShkYXRlLCBcInRpbWVzdGFtcFwiLCBsZXZlbCkgOiBkYXRlO1xuICAgICAgbG9nLnRpbWVzdGFtcCA9IHRpbWVzdGFtcDtcbiAgICB9XG5cbiAgICBpZiAodGhpcy5jb25maWcoXCJsb2dMZXZlbFwiKSkge1xuICAgICAgY29uc3QgbHZsOiBzdHJpbmcgPSBzdHlsZVxuICAgICAgICA/IExvZ2dpbmcudGhlbWUobGV2ZWwsIFwibG9nTGV2ZWxcIiwgbGV2ZWwpXG4gICAgICAgIDogbGV2ZWw7XG4gICAgICBsb2cubGV2ZWwgPSBsdmwudG9VcHBlckNhc2UoKTtcbiAgICB9XG5cbiAgICBpZiAodGhpcy5jb25maWcoXCJjb250ZXh0XCIpKSB7XG4gICAgICBjb25zdCBjb250ZXh0OiBzdHJpbmcgPSBzdHlsZVxuICAgICAgICA/IExvZ2dpbmcudGhlbWUodGhpcy5jb250ZXh0LCBcImNsYXNzXCIsIGxldmVsKVxuICAgICAgICA6IHRoaXMuY29udGV4dDtcbiAgICAgIGxvZy5jb250ZXh0ID0gY29udGV4dDtcbiAgICB9XG5cbiAgICBpZiAodGhpcy5jb25maWcoXCJjb3JyZWxhdGlvbklkXCIpKSB7XG4gICAgICB7XG4gICAgICAgIGNvbnN0IGlkOiBzdHJpbmcgPSBzdHlsZVxuICAgICAgICAgID8gTG9nZ2luZy50aGVtZSh0aGlzLmNvbmZpZyhcImNvcnJlbGF0aW9uSWRcIikhLnRvU3RyaW5nKCksIFwiaWRcIiwgbGV2ZWwpXG4gICAgICAgICAgOiB0aGlzLmNvbmZpZyhcImNvcnJlbGF0aW9uSWRcIikhLnRvU3RyaW5nKCk7XG4gICAgICAgIGxvZy5jb3JyZWxhdGlvbklkID0gaWQ7XG4gICAgICB9XG4gICAgfVxuXG4gICAgY29uc3QgbXNnOiBzdHJpbmcgPSBzdHlsZVxuICAgICAgPyBMb2dnaW5nLnRoZW1lKFxuICAgICAgICAgIHR5cGVvZiBtZXNzYWdlID09PSBcInN0cmluZ1wiID8gbWVzc2FnZSA6IChtZXNzYWdlIGFzIEVycm9yKS5tZXNzYWdlLFxuICAgICAgICAgIFwibWVzc2FnZVwiLFxuICAgICAgICAgIGxldmVsXG4gICAgICAgIClcbiAgICAgIDogdHlwZW9mIG1lc3NhZ2UgPT09IFwic3RyaW5nXCJcbiAgICAgICAgPyBtZXNzYWdlXG4gICAgICAgIDogKG1lc3NhZ2UgYXMgRXJyb3IpLm1lc3NhZ2U7XG4gICAgbG9nLm1lc3NhZ2UgPSBtc2c7XG4gICAgaWYgKGVycm9yIHx8IG1lc3NhZ2UgaW5zdGFuY2VvZiBFcnJvcikge1xuICAgICAgY29uc3Qgc3RhY2sgPSBzdHlsZVxuICAgICAgICA/IExvZ2dpbmcudGhlbWUoXG4gICAgICAgICAgICAoZXJyb3I/LnN0YWNrIHx8IChtZXNzYWdlIGFzIEVycm9yKS5zdGFjaykgYXMgc3RyaW5nLFxuICAgICAgICAgICAgXCJzdGFja1wiLFxuICAgICAgICAgICAgbGV2ZWxcbiAgICAgICAgICApXG4gICAgICAgIDogZXJyb3I/LnN0YWNrIHx8IFwiXCI7XG4gICAgICBsb2cuc3RhY2sgPSBgIHwgJHsoZXJyb3IgfHwgKG1lc3NhZ2UgYXMgRXJyb3IpKS5tZXNzYWdlfSAtIFN0YWNrIHRyYWNlOlxcbiR7c3RhY2t9YDtcbiAgICB9XG5cbiAgICBzd2l0Y2ggKHRoaXMuY29uZmlnKFwiZm9ybWF0XCIpKSB7XG4gICAgICBjYXNlIFwianNvblwiOlxuICAgICAgICByZXR1cm4gSlNPTi5zdHJpbmdpZnkobG9nKTtcbiAgICAgIGNhc2UgXCJyYXdcIjpcbiAgICAgICAgcmV0dXJuICh0aGlzLmNvbmZpZyhcInBhdHRlcm5cIikgYXMgc3RyaW5nKVxuICAgICAgICAgIC5zcGxpdChcIiBcIilcbiAgICAgICAgICAubWFwKChzKSA9PiB7XG4gICAgICAgICAgICBpZiAoIXMubWF0Y2goL1xcey4qP30vZykpIHJldHVybiBzO1xuICAgICAgICAgICAgY29uc3QgZm9ybWF0dGVkUyA9IHNmKHMsIGxvZyk7XG4gICAgICAgICAgICBpZiAoZm9ybWF0dGVkUyAhPT0gcykgcmV0dXJuIGZvcm1hdHRlZFM7XG4gICAgICAgICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgICAgICAgIH0pXG4gICAgICAgICAgLmZpbHRlcigocykgPT4gcylcbiAgICAgICAgICAuam9pbihcIiBcIik7XG4gICAgICBkZWZhdWx0OlxuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYFVuc3VwcG9ydGVkIGxvZ2dpbmcgZm9ybWF0OiAke3RoaXMuY29uZmlnKFwiZm9ybWF0XCIpfWApO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gTG9ncyBhIG1lc3NhZ2Ugd2l0aCB0aGUgc3BlY2lmaWVkIGxvZyBsZXZlbFxuICAgKiBAc3VtbWFyeSBDaGVja3MgaWYgdGhlIG1lc3NhZ2Ugc2hvdWxkIGJlIGxvZ2dlZCBiYXNlZCBvbiB0aGUgY3VycmVudCBsb2cgbGV2ZWwsXG4gICAqIHRoZW4gdXNlcyB0aGUgYXBwcm9wcmlhdGUgY29uc29sZSBtZXRob2QgdG8gb3V0cHV0IHRoZSBmb3JtYXR0ZWQgbG9nXG4gICAqIEBwYXJhbSB7TG9nTGV2ZWx9IGxldmVsIC0gVGhlIGxvZyBsZXZlbCBvZiB0aGUgbWVzc2FnZVxuICAgKiBAcGFyYW0ge1N0cmluZ0xpa2UgfCBFcnJvcn0gbXNnIC0gVGhlIG1lc3NhZ2UgdG8gYmUgbG9nZ2VkIG9yIGFuIEVycm9yIG9iamVjdFxuICAgKiBAcGFyYW0ge3N0cmluZ30gW2Vycm9yXSAtIE9wdGlvbmFsIHN0YWNrIHRyYWNlIHRvIGluY2x1ZGUgaW4gdGhlIGxvZ1xuICAgKiBAcmV0dXJuIHt2b2lkfVxuICAgKi9cbiAgcHJvdGVjdGVkIGxvZyhsZXZlbDogTG9nTGV2ZWwsIG1zZzogU3RyaW5nTGlrZSB8IEVycm9yLCBlcnJvcj86IEVycm9yKTogdm9pZCB7XG4gICAgY29uc3QgY29uZkx2bCA9IHRoaXMuY29uZmlnKFwibGV2ZWxcIikgYXMgTG9nTGV2ZWw7XG4gICAgaWYgKE51bWVyaWNMb2dMZXZlbHNbY29uZkx2bF0gPCBOdW1lcmljTG9nTGV2ZWxzW2xldmVsXSkgcmV0dXJuO1xuICAgIGxldCBtZXRob2Q7XG4gICAgc3dpdGNoIChsZXZlbCkge1xuICAgICAgY2FzZSBMb2dMZXZlbC5iZW5jaG1hcms6XG4gICAgICAgIG1ldGhvZCA9IGNvbnNvbGUubG9nO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgTG9nTGV2ZWwuaW5mbzpcbiAgICAgICAgbWV0aG9kID0gY29uc29sZS5sb2c7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSBMb2dMZXZlbC52ZXJib3NlOlxuICAgICAgY2FzZSBMb2dMZXZlbC5kZWJ1ZzpcbiAgICAgICAgbWV0aG9kID0gY29uc29sZS5kZWJ1ZztcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlIExvZ0xldmVsLmVycm9yOlxuICAgICAgICBtZXRob2QgPSBjb25zb2xlLmVycm9yO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgTG9nTGV2ZWwudHJhY2U6XG4gICAgICAgIG1ldGhvZCA9IGNvbnNvbGUudHJhY2U7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSBMb2dMZXZlbC5zaWxseTpcbiAgICAgICAgbWV0aG9kID0gY29uc29sZS50cmFjZTtcbiAgICAgICAgYnJlYWs7XG4gICAgICBkZWZhdWx0OlxuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJJbnZhbGlkIGxvZyBsZXZlbFwiKTtcbiAgICB9XG4gICAgbWV0aG9kKHRoaXMuY3JlYXRlTG9nKGxldmVsLCBtc2csIGVycm9yKSk7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIExvZ3MgYSBtZXNzYWdlIGF0IHRoZSBiZW5jaG1hcmsgbGV2ZWxcbiAgICogQHN1bW1hcnkgTG9ncyBhIG1lc3NhZ2UgYXQgdGhlIGJlbmNobWFyayBsZXZlbCBpZiB0aGUgY3VycmVudCB2ZXJib3NpdHkgc2V0dGluZyBhbGxvd3MgaXRcbiAgICogQHBhcmFtIHtTdHJpbmdMaWtlfSBtc2cgLSBUaGUgbWVzc2FnZSB0byBiZSBsb2dnZWRcbiAgICogQHJldHVybiB7dm9pZH1cbiAgICovXG4gIGJlbmNobWFyayhtc2c6IFN0cmluZ0xpa2UpOiB2b2lkIHtcbiAgICB0aGlzLmxvZyhMb2dMZXZlbC5iZW5jaG1hcmssIG1zZyk7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIExvZ3MgYSBtZXNzYWdlIGF0IHRoZSBzaWxseSBsZXZlbFxuICAgKiBAc3VtbWFyeSBMb2dzIGEgbWVzc2FnZSBhdCB0aGUgc2lsbHkgbGV2ZWwgaWYgdGhlIGN1cnJlbnQgdmVyYm9zaXR5IHNldHRpbmcgYWxsb3dzIGl0XG4gICAqIEBwYXJhbSB7U3RyaW5nTGlrZX0gbXNnIC0gVGhlIG1lc3NhZ2UgdG8gYmUgbG9nZ2VkXG4gICAqIEBwYXJhbSB7bnVtYmVyfSBbdmVyYm9zaXR5PTBdIC0gVGhlIHZlcmJvc2l0eSBsZXZlbCBvZiB0aGUgbWVzc2FnZVxuICAgKiBAcmV0dXJuIHt2b2lkfVxuICAgKi9cbiAgc2lsbHkobXNnOiBTdHJpbmdMaWtlLCB2ZXJib3NpdHk6IG51bWJlciA9IDApOiB2b2lkIHtcbiAgICBpZiAoKHRoaXMuY29uZmlnKFwidmVyYm9zZVwiKSBhcyBudW1iZXIpID49IHZlcmJvc2l0eSlcbiAgICAgIHRoaXMubG9nKExvZ0xldmVsLnZlcmJvc2UsIG1zZyk7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIExvZ3MgYSBtZXNzYWdlIGF0IHRoZSB2ZXJib3NlIGxldmVsXG4gICAqIEBzdW1tYXJ5IExvZ3MgYSBtZXNzYWdlIGF0IHRoZSB2ZXJib3NlIGxldmVsIGlmIHRoZSBjdXJyZW50IHZlcmJvc2l0eSBzZXR0aW5nIGFsbG93cyBpdFxuICAgKiBAcGFyYW0ge1N0cmluZ0xpa2V9IG1zZyAtIFRoZSBtZXNzYWdlIHRvIGJlIGxvZ2dlZFxuICAgKiBAcGFyYW0ge251bWJlcn0gW3ZlcmJvc2l0eT0wXSAtIFRoZSB2ZXJib3NpdHkgbGV2ZWwgb2YgdGhlIG1lc3NhZ2VcbiAgICogQHJldHVybiB7dm9pZH1cbiAgICovXG4gIHZlcmJvc2UobXNnOiBTdHJpbmdMaWtlLCB2ZXJib3NpdHk6IG51bWJlciA9IDApOiB2b2lkIHtcbiAgICBpZiAoKHRoaXMuY29uZmlnKFwidmVyYm9zZVwiKSBhcyBudW1iZXIpID49IHZlcmJvc2l0eSlcbiAgICAgIHRoaXMubG9nKExvZ0xldmVsLnZlcmJvc2UsIG1zZyk7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIExvZ3MgYSBtZXNzYWdlIGF0IHRoZSBpbmZvIGxldmVsXG4gICAqIEBzdW1tYXJ5IExvZ3MgYSBtZXNzYWdlIGF0IHRoZSBpbmZvIGxldmVsIGZvciBnZW5lcmFsIGFwcGxpY2F0aW9uIGluZm9ybWF0aW9uXG4gICAqIEBwYXJhbSB7U3RyaW5nTGlrZX0gbXNnIC0gVGhlIG1lc3NhZ2UgdG8gYmUgbG9nZ2VkXG4gICAqIEByZXR1cm4ge3ZvaWR9XG4gICAqL1xuICBpbmZvKG1zZzogU3RyaW5nTGlrZSk6IHZvaWQge1xuICAgIHRoaXMubG9nKExvZ0xldmVsLmluZm8sIG1zZyk7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIExvZ3MgYSBtZXNzYWdlIGF0IHRoZSBkZWJ1ZyBsZXZlbFxuICAgKiBAc3VtbWFyeSBMb2dzIGEgbWVzc2FnZSBhdCB0aGUgZGVidWcgbGV2ZWwgZm9yIGRldGFpbGVkIHRyb3VibGVzaG9vdGluZyBpbmZvcm1hdGlvblxuICAgKiBAcGFyYW0ge1N0cmluZ0xpa2V9IG1zZyAtIFRoZSBtZXNzYWdlIHRvIGJlIGxvZ2dlZFxuICAgKiBAcmV0dXJuIHt2b2lkfVxuICAgKi9cbiAgZGVidWcobXNnOiBTdHJpbmdMaWtlKTogdm9pZCB7XG4gICAgdGhpcy5sb2coTG9nTGV2ZWwuZGVidWcsIG1zZyk7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIExvZ3MgYSBtZXNzYWdlIGF0IHRoZSBlcnJvciBsZXZlbFxuICAgKiBAc3VtbWFyeSBMb2dzIGEgbWVzc2FnZSBhdCB0aGUgZXJyb3IgbGV2ZWwgZm9yIGVycm9ycyBhbmQgZXhjZXB0aW9uc1xuICAgKiBAcGFyYW0ge1N0cmluZ0xpa2UgfCBFcnJvcn0gbXNnIC0gVGhlIG1lc3NhZ2UgdG8gYmUgbG9nZ2VkIG9yIGFuIEVycm9yIG9iamVjdFxuICAgKiBAcGFyYW0gZVxuICAgKiBAcmV0dXJuIHt2b2lkfVxuICAgKi9cbiAgZXJyb3IobXNnOiBTdHJpbmdMaWtlIHwgRXJyb3IsIGU/OiBFcnJvcik6IHZvaWQge1xuICAgIHRoaXMubG9nKExvZ0xldmVsLmVycm9yLCBtc2csIGUpO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBMb2dzIGEgbWVzc2FnZSBhdCB0aGUgZXJyb3IgbGV2ZWxcbiAgICogQHN1bW1hcnkgTG9ncyBhIG1lc3NhZ2UgYXQgdGhlIGVycm9yIGxldmVsIGZvciBlcnJvcnMgYW5kIGV4Y2VwdGlvbnNcbiAgICogQHBhcmFtIHtTdHJpbmdMaWtlfSBtc2cgLSBUaGUgbWVzc2FnZSB0byBiZSBsb2dnZWQgb3IgYW4gRXJyb3Igb2JqZWN0XG4gICAqIEByZXR1cm4ge3ZvaWR9XG4gICAqL1xuICB3YXJuKG1zZzogU3RyaW5nTGlrZSk6IHZvaWQge1xuICAgIHRoaXMubG9nKExvZ0xldmVsLndhcm4sIG1zZyk7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIExvZ3MgYSBtZXNzYWdlIGF0IHRoZSBlcnJvciBsZXZlbFxuICAgKiBAc3VtbWFyeSBMb2dzIGEgbWVzc2FnZSBhdCB0aGUgZXJyb3IgbGV2ZWwgZm9yIGVycm9ycyBhbmQgZXhjZXB0aW9uc1xuICAgKiBAcGFyYW0ge1N0cmluZ0xpa2V9IG1zZyAtIFRoZSBtZXNzYWdlIHRvIGJlIGxvZ2dlZCBvciBhbiBFcnJvciBvYmplY3RcbiAgICogQHJldHVybiB7dm9pZH1cbiAgICovXG4gIHRyYWNlKG1zZzogU3RyaW5nTGlrZSk6IHZvaWQge1xuICAgIHRoaXMubG9nKExvZ0xldmVsLnRyYWNlLCBtc2cpO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBVcGRhdGVzIHRoZSBsb2dnZXIgY29uZmlndXJhdGlvblxuICAgKiBAc3VtbWFyeSBNZXJnZXMgdGhlIHByb3ZpZGVkIGNvbmZpZ3VyYXRpb24gd2l0aCB0aGUgZXhpc3RpbmcgY29uZmlndXJhdGlvblxuICAgKiBAcGFyYW0ge1BhcnRpYWw8TG9nZ2luZ0NvbmZpZz59IGNvbmZpZyAtIFRoZSBjb25maWd1cmF0aW9uIG9wdGlvbnMgdG8gYXBwbHlcbiAgICogQHJldHVybiB7dm9pZH1cbiAgICovXG4gIHNldENvbmZpZyhjb25maWc6IFBhcnRpYWw8TG9nZ2luZ0NvbmZpZz4pOiB2b2lkIHtcbiAgICB0aGlzLmNvbmYgPSB7IC4uLih0aGlzLmNvbmYgfHwge30pLCAuLi5jb25maWcgfTtcbiAgfVxufVxuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBBIHN0YXRpYyBjbGFzcyBmb3IgbWFuYWdpbmcgbG9nZ2luZyBvcGVyYXRpb25zXG4gKiBAc3VtbWFyeSBUaGUgTG9nZ2luZyBjbGFzcyBwcm92aWRlcyBhIGNlbnRyYWxpemVkIGxvZ2dpbmcgbWVjaGFuaXNtIHdpdGggc3VwcG9ydCBmb3JcbiAqIGRpZmZlcmVudCBsb2cgbGV2ZWxzLCB2ZXJib3NpdHksIGFuZCBzdHlsaW5nLiBJdCB1c2VzIGEgc2luZ2xldG9uIHBhdHRlcm4gdG8gbWFpbnRhaW4gYSBnbG9iYWxcbiAqIGxvZ2dlciBpbnN0YW5jZSBhbmQgYWxsb3dzIGNyZWF0aW5nIHNwZWNpZmljIGxvZ2dlcnMgZm9yIGRpZmZlcmVudCBjbGFzc2VzIGFuZCBtZXRob2RzLlxuICogQGNsYXNzIExvZ2dpbmdcbiAqIEBleGFtcGxlXG4gKiAvLyBTZXQgZ2xvYmFsIGNvbmZpZ3VyYXRpb25cbiAqIExvZ2dpbmcuc2V0Q29uZmlnKHsgbGV2ZWw6IExvZ0xldmVsLmRlYnVnLCBzdHlsZTogdHJ1ZSB9KTtcbiAqXG4gKiAvLyBHZXQgYSBsb2dnZXIgZm9yIGEgc3BlY2lmaWMgY2xhc3NcbiAqIGNvbnN0IGxvZ2dlciA9IExvZ2dpbmcuZm9yKCdNeUNsYXNzJyk7XG4gKlxuICogLy8gTG9nIG1lc3NhZ2VzIGF0IGRpZmZlcmVudCBsZXZlbHNcbiAqIGxvZ2dlci5pbmZvKCdBcHBsaWNhdGlvbiBzdGFydGVkJyk7XG4gKiBsb2dnZXIuZGVidWcoJ1Byb2Nlc3NpbmcgZGF0YS4uLicpO1xuICpcbiAqIC8vIExvZyB3aXRoIGNvbnRleHRcbiAqIGNvbnN0IG1ldGhvZExvZ2dlciA9IExvZ2dpbmcuZm9yKCdNeUNsYXNzLm15TWV0aG9kJyk7XG4gKiBtZXRob2RMb2dnZXIudmVyYm9zZSgnRGV0YWlsZWQgb3BlcmF0aW9uIGluZm9ybWF0aW9uJywgMSk7XG4gKlxuICogLy8gTG9nIGVycm9yc1xuICogdHJ5IHtcbiAqICAgLy8gc29tZSBvcGVyYXRpb25cbiAqIH0gY2F0Y2ggKGVycm9yKSB7XG4gKiAgIGxvZ2dlci5lcnJvcihlcnJvcik7XG4gKiB9XG4gKiBAbWVybWFpZFxuICogY2xhc3NEaWFncmFtXG4gKiAgIGNsYXNzIExvZ2dlciB7XG4gKiAgICAgPDxpbnRlcmZhY2U+PlxuICogICAgICtmb3IobWV0aG9kLCBjb25maWcsIC4uLmFyZ3MpXG4gKiAgICAgK3NpbGx5KG1zZywgdmVyYm9zaXR5KVxuICogICAgICt2ZXJib3NlKG1zZywgdmVyYm9zaXR5KVxuICogICAgICtpbmZvKG1zZylcbiAqICAgICArZGVidWcobXNnKVxuICogICAgICtlcnJvcihtc2cpXG4gKiAgICAgK3NldENvbmZpZyhjb25maWcpXG4gKiAgIH1cbiAqXG4gKiAgIGNsYXNzIExvZ2dpbmcge1xuICogICAgIC1nbG9iYWw6IExvZ2dlclxuICogICAgIC1fZmFjdG9yeTogTG9nZ2VyRmFjdG9yeVxuICogICAgIC1fY29uZmlnOiBMb2dnaW5nQ29uZmlnXG4gKiAgICAgK3NldEZhY3RvcnkoZmFjdG9yeSlcbiAqICAgICArc2V0Q29uZmlnKGNvbmZpZylcbiAqICAgICArZ2V0Q29uZmlnKClcbiAqICAgICArZ2V0KClcbiAqICAgICArdmVyYm9zZShtc2csIHZlcmJvc2l0eSlcbiAqICAgICAraW5mbyhtc2cpXG4gKiAgICAgK2RlYnVnKG1zZylcbiAqICAgICArc2lsbHkobXNnKVxuICogICAgICtlcnJvcihtc2cpXG4gKiAgICAgK2ZvcihvYmplY3QsIGNvbmZpZywgLi4uYXJncylcbiAqICAgICArYmVjYXVzZShyZWFzb24sIGlkKVxuICogICAgICt0aGVtZSh0ZXh0LCB0eXBlLCBsb2dnZXJMZXZlbCwgdGVtcGxhdGUpXG4gKiAgIH1cbiAqXG4gKiAgIGNsYXNzIE1pbmlMb2dnZXIge1xuICogICAgICtjb25zdHJ1Y3Rvcihjb250ZXh0LCBjb25mPylcbiAqICAgfVxuICpcbiAqICAgTG9nZ2luZyAuLj4gTG9nZ2VyIDogY3JlYXRlc1xuICogICBMb2dnaW5nIC4uPiBNaW5pTG9nZ2VyIDogY3JlYXRlcyBieSBkZWZhdWx0XG4gKi9cbmV4cG9ydCBjbGFzcyBMb2dnaW5nIHtcbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBUaGUgZ2xvYmFsIGxvZ2dlciBpbnN0YW5jZVxuICAgKiBAc3VtbWFyeSBBIHNpbmdsZXRvbiBpbnN0YW5jZSBvZiBMb2dnZXIgdXNlZCBmb3IgZ2xvYmFsIGxvZ2dpbmdcbiAgICovXG4gIHByaXZhdGUgc3RhdGljIGdsb2JhbD86IExvZ2dlcjtcblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIEZhY3RvcnkgZnVuY3Rpb24gZm9yIGNyZWF0aW5nIGxvZ2dlciBpbnN0YW5jZXNcbiAgICogQHN1bW1hcnkgQSBmdW5jdGlvbiB0aGF0IGNyZWF0ZXMgbmV3IExvZ2dlciBpbnN0YW5jZXMuIEJ5IGRlZmF1bHQsIGl0IGNyZWF0ZXMgYSBNaW5pTG9nZ2VyLlxuICAgKi9cbiAgcHJpdmF0ZSBzdGF0aWMgX2ZhY3Rvcnk6IExvZ2dlckZhY3RvcnkgPSAoXG4gICAgb2JqZWN0OiBzdHJpbmcsXG4gICAgY29uZmlnPzogUGFydGlhbDxMb2dnaW5nQ29uZmlnPlxuICApID0+IHtcbiAgICByZXR1cm4gbmV3IE1pbmlMb2dnZXIob2JqZWN0LCBjb25maWcpO1xuICB9O1xuXG4gIHByaXZhdGUgc3RhdGljIF9jb25maWc6IHR5cGVvZiBMb2dnZWRFbnZpcm9ubWVudCA9IExvZ2dlZEVudmlyb25tZW50O1xuXG4gIHByaXZhdGUgY29uc3RydWN0b3IoKSB7fVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gU2V0cyB0aGUgZmFjdG9yeSBmdW5jdGlvbiBmb3IgY3JlYXRpbmcgbG9nZ2VyIGluc3RhbmNlc1xuICAgKiBAc3VtbWFyeSBBbGxvd3MgY3VzdG9taXppbmcgaG93IGxvZ2dlciBpbnN0YW5jZXMgYXJlIGNyZWF0ZWRcbiAgICogQHBhcmFtIHtMb2dnZXJGYWN0b3J5fSBmYWN0b3J5IC0gVGhlIGZhY3RvcnkgZnVuY3Rpb24gdG8gdXNlIGZvciBjcmVhdGluZyBsb2dnZXJzXG4gICAqIEByZXR1cm4ge3ZvaWR9XG4gICAqL1xuICBzdGF0aWMgc2V0RmFjdG9yeShmYWN0b3J5OiBMb2dnZXJGYWN0b3J5KSB7XG4gICAgTG9nZ2luZy5fZmFjdG9yeSA9IGZhY3Rvcnk7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFVwZGF0ZXMgdGhlIGdsb2JhbCBsb2dnaW5nIGNvbmZpZ3VyYXRpb25cbiAgICogQHN1bW1hcnkgQWxsb3dzIHVwZGF0aW5nIHRoZSBnbG9iYWwgbG9nZ2luZyBjb25maWd1cmF0aW9uIHdpdGggbmV3IHNldHRpbmdzXG4gICAqIEBwYXJhbSB7UGFydGlhbDxMb2dnaW5nQ29uZmlnPn0gY29uZmlnIC0gVGhlIGNvbmZpZ3VyYXRpb24gb3B0aW9ucyB0byBhcHBseVxuICAgKiBAcmV0dXJuIHt2b2lkfVxuICAgKi9cbiAgc3RhdGljIHNldENvbmZpZyhjb25maWc6IFBhcnRpYWw8TG9nZ2luZ0NvbmZpZz4pOiB2b2lkIHtcbiAgICBPYmplY3QuZW50cmllcyhjb25maWcpLmZvckVhY2goKFtrLCB2XSkgPT4ge1xuICAgICAgKHRoaXMuX2NvbmZpZyBhcyBhbnkpW2tdID0gdiBhcyBhbnk7XG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIEdldHMgYSBjb3B5IG9mIHRoZSBjdXJyZW50IGdsb2JhbCBsb2dnaW5nIGNvbmZpZ3VyYXRpb25cbiAgICogQHN1bW1hcnkgUmV0dXJucyBhIGNvcHkgb2YgdGhlIGN1cnJlbnQgZ2xvYmFsIGxvZ2dpbmcgY29uZmlndXJhdGlvblxuICAgKiBAcmV0dXJuIHtMb2dnaW5nQ29uZmlnfSBBIGNvcHkgb2YgdGhlIGN1cnJlbnQgY29uZmlndXJhdGlvblxuICAgKi9cbiAgc3RhdGljIGdldENvbmZpZygpOiB0eXBlb2YgTG9nZ2VkRW52aXJvbm1lbnQge1xuICAgIHJldHVybiB0aGlzLl9jb25maWc7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFJldHJpZXZlcyBvciBjcmVhdGVzIHRoZSBnbG9iYWwgbG9nZ2VyIGluc3RhbmNlLlxuICAgKiBAc3VtbWFyeSBSZXR1cm5zIHRoZSBleGlzdGluZyBnbG9iYWwgbG9nZ2VyIG9yIGNyZWF0ZXMgYSBuZXcgb25lIGlmIGl0IGRvZXNuJ3QgZXhpc3QuXG4gICAqXG4gICAqIEByZXR1cm4gVGhlIGdsb2JhbCBWZXJib3NpdHlMb2dnZXIgaW5zdGFuY2UuXG4gICAqL1xuICBzdGF0aWMgZ2V0KCk6IExvZ2dlciB7XG4gICAgdGhpcy5nbG9iYWwgPSB0aGlzLmdsb2JhbCA/IHRoaXMuZ2xvYmFsIDogdGhpcy5fZmFjdG9yeShcIkxvZ2dpbmdcIik7XG4gICAgcmV0dXJuIHRoaXMuZ2xvYmFsO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBMb2dzIGEgdmVyYm9zZSBtZXNzYWdlLlxuICAgKiBAc3VtbWFyeSBEZWxlZ2F0ZXMgdGhlIHZlcmJvc2UgbG9nZ2luZyB0byB0aGUgZ2xvYmFsIGxvZ2dlciBpbnN0YW5jZS5cbiAgICpcbiAgICogQHBhcmFtIG1zZyAtIFRoZSBtZXNzYWdlIHRvIGJlIGxvZ2dlZC5cbiAgICogQHBhcmFtIHZlcmJvc2l0eSAtIFRoZSB2ZXJib3NpdHkgbGV2ZWwgb2YgdGhlIG1lc3NhZ2UgKGRlZmF1bHQ6IDApLlxuICAgKi9cbiAgc3RhdGljIHZlcmJvc2UobXNnOiBTdHJpbmdMaWtlLCB2ZXJib3NpdHk6IG51bWJlciA9IDApOiB2b2lkIHtcbiAgICByZXR1cm4gdGhpcy5nZXQoKS52ZXJib3NlKG1zZywgdmVyYm9zaXR5KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gTG9ncyBhbiBpbmZvIG1lc3NhZ2UuXG4gICAqIEBzdW1tYXJ5IERlbGVnYXRlcyB0aGUgaW5mbyBsb2dnaW5nIHRvIHRoZSBnbG9iYWwgbG9nZ2VyIGluc3RhbmNlLlxuICAgKlxuICAgKiBAcGFyYW0gbXNnIC0gVGhlIG1lc3NhZ2UgdG8gYmUgbG9nZ2VkLlxuICAgKi9cbiAgc3RhdGljIGluZm8obXNnOiBTdHJpbmdMaWtlKTogdm9pZCB7XG4gICAgcmV0dXJuIHRoaXMuZ2V0KCkuaW5mbyhtc2cpO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBMb2dzIGFuIGluZm8gbWVzc2FnZS5cbiAgICogQHN1bW1hcnkgRGVsZWdhdGVzIHRoZSBpbmZvIGxvZ2dpbmcgdG8gdGhlIGdsb2JhbCBsb2dnZXIgaW5zdGFuY2UuXG4gICAqXG4gICAqIEBwYXJhbSBtc2cgLSBUaGUgbWVzc2FnZSB0byBiZSBsb2dnZWQuXG4gICAqL1xuICBzdGF0aWMgdHJhY2UobXNnOiBTdHJpbmdMaWtlKTogdm9pZCB7XG4gICAgcmV0dXJuIHRoaXMuZ2V0KCkudHJhY2UobXNnKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gTG9ncyBhIGRlYnVnIG1lc3NhZ2UuXG4gICAqIEBzdW1tYXJ5IERlbGVnYXRlcyB0aGUgZGVidWcgbG9nZ2luZyB0byB0aGUgZ2xvYmFsIGxvZ2dlciBpbnN0YW5jZS5cbiAgICpcbiAgICogQHBhcmFtIG1zZyAtIFRoZSBtZXNzYWdlIHRvIGJlIGxvZ2dlZC5cbiAgICovXG4gIHN0YXRpYyBkZWJ1Zyhtc2c6IFN0cmluZ0xpa2UpOiB2b2lkIHtcbiAgICByZXR1cm4gdGhpcy5nZXQoKS5kZWJ1Zyhtc2cpO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBMb2dzIGEgYmVuY2htYXJrIG1lc3NhZ2UuXG4gICAqIEBzdW1tYXJ5IERlbGVnYXRlcyB0aGUgYmVuY2htYXJrIGxvZ2dpbmcgdG8gdGhlIGdsb2JhbCBsb2dnZXIgaW5zdGFuY2UuXG4gICAqXG4gICAqIEBwYXJhbSBtc2cgLSBUaGUgbWVzc2FnZSB0byBiZSBsb2dnZWQuXG4gICAqL1xuICBzdGF0aWMgYmVuY2htYXJrKG1zZzogU3RyaW5nTGlrZSk6IHZvaWQge1xuICAgIHJldHVybiB0aGlzLmdldCgpLmJlbmNobWFyayhtc2cpO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBMb2dzIGEgc2lsbHkgbWVzc2FnZS5cbiAgICogQHN1bW1hcnkgRGVsZWdhdGVzIHRoZSBkZWJ1ZyBsb2dnaW5nIHRvIHRoZSBnbG9iYWwgbG9nZ2VyIGluc3RhbmNlLlxuICAgKlxuICAgKiBAcGFyYW0gbXNnIC0gVGhlIG1lc3NhZ2UgdG8gYmUgbG9nZ2VkLlxuICAgKi9cbiAgc3RhdGljIHNpbGx5KG1zZzogU3RyaW5nTGlrZSk6IHZvaWQge1xuICAgIHJldHVybiB0aGlzLmdldCgpLnNpbGx5KG1zZyk7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIExvZ3MgYSBzaWxseSBtZXNzYWdlLlxuICAgKiBAc3VtbWFyeSBEZWxlZ2F0ZXMgdGhlIGRlYnVnIGxvZ2dpbmcgdG8gdGhlIGdsb2JhbCBsb2dnZXIgaW5zdGFuY2UuXG4gICAqXG4gICAqIEBwYXJhbSBtc2cgLSBUaGUgbWVzc2FnZSB0byBiZSBsb2dnZWQuXG4gICAqL1xuICBzdGF0aWMgd2Fybihtc2c6IFN0cmluZ0xpa2UpOiB2b2lkIHtcbiAgICByZXR1cm4gdGhpcy5nZXQoKS53YXJuKG1zZyk7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIExvZ3MgYW4gZXJyb3IgbWVzc2FnZS5cbiAgICogQHN1bW1hcnkgRGVsZWdhdGVzIHRoZSBlcnJvciBsb2dnaW5nIHRvIHRoZSBnbG9iYWwgbG9nZ2VyIGluc3RhbmNlLlxuICAgKlxuICAgKiBAcGFyYW0gbXNnIC0gVGhlIG1lc3NhZ2UgdG8gYmUgbG9nZ2VkLlxuICAgKiBAcGFyYW0gZVxuICAgKi9cbiAgc3RhdGljIGVycm9yKG1zZzogU3RyaW5nTGlrZSwgZT86IEVycm9yKTogdm9pZCB7XG4gICAgcmV0dXJuIHRoaXMuZ2V0KCkuZXJyb3IobXNnLCBlKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gQ3JlYXRlcyBhIGxvZ2dlciBmb3IgYSBzcGVjaWZpYyBvYmplY3Qgb3IgY29udGV4dFxuICAgKiBAc3VtbWFyeSBDcmVhdGVzIGEgbmV3IGxvZ2dlciBpbnN0YW5jZSBmb3IgdGhlIGdpdmVuIG9iamVjdCBvciBjb250ZXh0IHVzaW5nIHRoZSBmYWN0b3J5IGZ1bmN0aW9uXG4gICAqIEBwYXJhbSB7TG9nZ2luZ0NvbnRleHR9IG9iamVjdCAtIFRoZSBvYmplY3QsIGNsYXNzLCBvciBjb250ZXh0IHRvIGNyZWF0ZSBhIGxvZ2dlciBmb3JcbiAgICogQHBhcmFtIHtQYXJ0aWFsPExvZ2dpbmdDb25maWc+fSBbY29uZmlnXSAtIE9wdGlvbmFsIGNvbmZpZ3VyYXRpb24gdG8gb3ZlcnJpZGUgZ2xvYmFsIHNldHRpbmdzXG4gICAqIEBwYXJhbSB7Li4uYW55fSBhcmdzIC0gQWRkaXRpb25hbCBhcmd1bWVudHMgdG8gcGFzcyB0byB0aGUgbG9nZ2VyIGZhY3RvcnlcbiAgICogQHJldHVybiB7TG9nZ2VyfSBBIG5ldyBsb2dnZXIgaW5zdGFuY2UgZm9yIHRoZSBzcGVjaWZpZWQgb2JqZWN0IG9yIGNvbnRleHRcbiAgICovXG4gIHN0YXRpYyBmb3IoXG4gICAgb2JqZWN0OiBMb2dnaW5nQ29udGV4dCxcbiAgICBjb25maWc/OiBQYXJ0aWFsPExvZ2dpbmdDb25maWc+LFxuICAgIC4uLmFyZ3M6IGFueVtdXG4gICk6IExvZ2dlciB7XG4gICAgb2JqZWN0ID1cbiAgICAgIHR5cGVvZiBvYmplY3QgPT09IFwic3RyaW5nXCJcbiAgICAgICAgPyBvYmplY3RcbiAgICAgICAgOiBvYmplY3QuY29uc3RydWN0b3JcbiAgICAgICAgICA/IG9iamVjdC5jb25zdHJ1Y3Rvci5uYW1lXG4gICAgICAgICAgOiBvYmplY3QubmFtZTtcbiAgICByZXR1cm4gdGhpcy5fZmFjdG9yeShvYmplY3QsIGNvbmZpZywgLi4uYXJncyk7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIENyZWF0ZXMgYSBsb2dnZXIgZm9yIGEgc3BlY2lmaWMgcmVhc29uIG9yIGNvcnJlbGF0aW9uIGNvbnRleHRcbiAgICogQHN1bW1hcnkgVXRpbGl0eSB0byBxdWlja2x5IGNyZWF0ZSBhIGxvZ2dlciBsYWJlbGVkIHdpdGggYSBmcmVlLWZvcm0gcmVhc29uIGFuZCBvcHRpb25hbCBpZGVudGlmaWVyXG4gICAqIHNvIHRoYXQgYWQtaG9jIG9wZXJhdGlvbnMgY2FuIGJlIHRyYWNlZCB3aXRob3V0IHR5aW5nIHRoZSBsb2dnZXIgdG8gYSBjbGFzcyBvciBtZXRob2QgbmFtZS5cbiAgICogQHBhcmFtIHtzdHJpbmd9IHJlYXNvbiAtIEEgdGV4dHVhbCByZWFzb24gb3IgY29udGV4dCBsYWJlbCBmb3IgdGhpcyBsb2dnZXIgaW5zdGFuY2VcbiAgICogQHBhcmFtIHtzdHJpbmd9IFtpZF0gLSBPcHRpb25hbCBpZGVudGlmaWVyIHRvIGhlbHAgY29ycmVsYXRlIHJlbGF0ZWQgbG9nIGVudHJpZXNcbiAgICogQHJldHVybiB7TG9nZ2VyfSBBIG5ldyBsb2dnZXIgaW5zdGFuY2UgbGFiZWxlZCB3aXRoIHRoZSBwcm92aWRlZCByZWFzb24gYW5kIGlkXG4gICAqL1xuICBzdGF0aWMgYmVjYXVzZShyZWFzb246IHN0cmluZywgaWQ/OiBzdHJpbmcpOiBMb2dnZXIge1xuICAgIHJldHVybiB0aGlzLl9mYWN0b3J5KHJlYXNvbiwgdGhpcy5fY29uZmlnLCBpZCk7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIEFwcGxpZXMgdGhlbWUgc3R5bGluZyB0byB0ZXh0XG4gICAqIEBzdW1tYXJ5IEFwcGxpZXMgc3R5bGluZyAoY29sb3JzLCBmb3JtYXR0aW5nKSB0byB0ZXh0IGJhc2VkIG9uIHRoZSB0aGVtZSBjb25maWd1cmF0aW9uXG4gICAqIEBwYXJhbSB7c3RyaW5nfSB0ZXh0IC0gVGhlIHRleHQgdG8gc3R5bGVcbiAgICogQHBhcmFtIHtzdHJpbmd9IHR5cGUgLSBUaGUgdHlwZSBvZiBlbGVtZW50IHRvIHN0eWxlIChlLmcuLCBcImNsYXNzXCIsIFwibWVzc2FnZVwiLCBcImxvZ0xldmVsXCIpXG4gICAqIEBwYXJhbSB7TG9nTGV2ZWx9IGxvZ2dlckxldmVsIC0gVGhlIGxvZyBsZXZlbCB0byB1c2UgZm9yIHN0eWxpbmdcbiAgICogQHBhcmFtIHtUaGVtZX0gW3RlbXBsYXRlPURlZmF1bHRUaGVtZV0gLSBUaGUgdGhlbWUgdG8gdXNlIGZvciBzdHlsaW5nXG4gICAqIEByZXR1cm4ge3N0cmluZ30gVGhlIHN0eWxlZCB0ZXh0XG4gICAqIEBtZXJtYWlkXG4gICAqIHNlcXVlbmNlRGlhZ3JhbVxuICAgKiAgIHBhcnRpY2lwYW50IENhbGxlclxuICAgKiAgIHBhcnRpY2lwYW50IFRoZW1lIGFzIExvZ2dpbmcudGhlbWVcbiAgICogICBwYXJ0aWNpcGFudCBBcHBseSBhcyBhcHBseSBmdW5jdGlvblxuICAgKiAgIHBhcnRpY2lwYW50IFN0eWxlIGFzIHN0eWxlZC1zdHJpbmctYnVpbGRlclxuICAgKlxuICAgKiAgIENhbGxlci0+PlRoZW1lOiB0aGVtZSh0ZXh0LCB0eXBlLCBsb2dnZXJMZXZlbClcbiAgICogICBUaGVtZS0+PlRoZW1lOiBDaGVjayBpZiBzdHlsaW5nIGlzIGVuYWJsZWRcbiAgICogICBhbHQgc3R5bGluZyBkaXNhYmxlZFxuICAgKiAgICAgVGhlbWUtLT4+Q2FsbGVyOiByZXR1cm4gb3JpZ2luYWwgdGV4dFxuICAgKiAgIGVsc2Ugc3R5bGluZyBlbmFibGVkXG4gICAqICAgICBUaGVtZS0+PlRoZW1lOiBHZXQgdGhlbWUgZm9yIHR5cGVcbiAgICogICAgIGFsdCB0aGVtZSBub3QgZm91bmRcbiAgICogICAgICAgVGhlbWUtLT4+Q2FsbGVyOiByZXR1cm4gb3JpZ2luYWwgdGV4dFxuICAgKiAgICAgZWxzZSB0aGVtZSBmb3VuZFxuICAgKiAgICAgICBUaGVtZS0+PlRoZW1lOiBEZXRlcm1pbmUgYWN0dWFsIHRoZW1lIGJhc2VkIG9uIGxvZyBsZXZlbFxuICAgKiAgICAgICBUaGVtZS0+PkFwcGx5OiBBcHBseSBlYWNoIHN0eWxlIHByb3BlcnR5XG4gICAqICAgICAgIEFwcGx5LT4+U3R5bGU6IEFwcGx5IGNvbG9ycyBhbmQgZm9ybWF0dGluZ1xuICAgKiAgICAgICBTdHlsZS0tPj5BcHBseTogUmV0dXJuIHN0eWxlZCB0ZXh0XG4gICAqICAgICAgIEFwcGx5LS0+PlRoZW1lOiBSZXR1cm4gc3R5bGVkIHRleHRcbiAgICogICAgICAgVGhlbWUtLT4+Q2FsbGVyOiBSZXR1cm4gZmluYWwgc3R5bGVkIHRleHRcbiAgICogICAgIGVuZFxuICAgKiAgIGVuZFxuICAgKi9cbiAgc3RhdGljIHRoZW1lKFxuICAgIHRleHQ6IHN0cmluZyxcbiAgICB0eXBlOiBrZXlvZiBUaGVtZSB8IGtleW9mIExvZ0xldmVsLFxuICAgIGxvZ2dlckxldmVsOiBMb2dMZXZlbCxcbiAgICB0ZW1wbGF0ZTogVGhlbWUgPSBEZWZhdWx0VGhlbWVcbiAgKSB7XG4gICAgaWYgKCF0aGlzLl9jb25maWcuc3R5bGUpIHJldHVybiB0ZXh0O1xuICAgIGZ1bmN0aW9uIGFwcGx5KFxuICAgICAgdHh0OiBzdHJpbmcsXG4gICAgICBvcHRpb246IGtleW9mIFRoZW1lT3B0aW9uLFxuICAgICAgdmFsdWU6IG51bWJlciB8IFtudW1iZXJdIHwgW251bWJlciwgbnVtYmVyLCBudW1iZXJdIHwgbnVtYmVyW10gfCBzdHJpbmdbXVxuICAgICk6IHN0cmluZyB7XG4gICAgICB0cnkge1xuICAgICAgICBjb25zdCB0OiBzdHJpbmcgfCBTdHlsZWRTdHJpbmcgPSB0eHQ7XG4gICAgICAgIGxldCBjID0gc3R5bGUodCk7XG5cbiAgICAgICAgZnVuY3Rpb24gYXBwbHlDb2xvcihcbiAgICAgICAgICB2YWw6IG51bWJlciB8IFtudW1iZXJdIHwgW251bWJlciwgbnVtYmVyLCBudW1iZXJdLFxuICAgICAgICAgIGlzQmcgPSBmYWxzZVxuICAgICAgICApOiBTdHlsZWRTdHJpbmcge1xuICAgICAgICAgIGxldCBmOlxuICAgICAgICAgICAgfCB0eXBlb2YgYy5iYWNrZ3JvdW5kXG4gICAgICAgICAgICB8IHR5cGVvZiBjLmZvcmVncm91bmRcbiAgICAgICAgICAgIHwgdHlwZW9mIGMucmdiXG4gICAgICAgICAgICB8IHR5cGVvZiBjLmNvbG9yMjU2ID0gaXNCZyA/IGMuYmFja2dyb3VuZCA6IGMuZm9yZWdyb3VuZDtcbiAgICAgICAgICBpZiAoIUFycmF5LmlzQXJyYXkodmFsKSkge1xuICAgICAgICAgICAgcmV0dXJuIChmIGFzIHR5cGVvZiBjLmJhY2tncm91bmQgfCB0eXBlb2YgYy5mb3JlZ3JvdW5kKS5jYWxsKFxuICAgICAgICAgICAgICBjLFxuICAgICAgICAgICAgICB2YWx1ZSBhcyBudW1iZXJcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgfVxuICAgICAgICAgIHN3aXRjaCAodmFsLmxlbmd0aCkge1xuICAgICAgICAgICAgY2FzZSAxOlxuICAgICAgICAgICAgICBmID0gaXNCZyA/IGMuYmdDb2xvcjI1NiA6IGMuY29sb3IyNTY7XG4gICAgICAgICAgICAgIHJldHVybiAoZiBhcyB0eXBlb2YgYy5iZ0NvbG9yMjU2IHwgdHlwZW9mIGMuY29sb3IyNTYpKHZhbFswXSk7XG4gICAgICAgICAgICBjYXNlIDM6XG4gICAgICAgICAgICAgIGYgPSBpc0JnID8gYy5iZ1JnYiA6IGMucmdiO1xuICAgICAgICAgICAgICByZXR1cm4gYy5yZ2IodmFsWzBdLCB2YWxbMV0sIHZhbFsyXSk7XG4gICAgICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgICAgICBjb25zb2xlLmVycm9yKGBOb3QgYSB2YWxpZCBjb2xvciBvcHRpb246ICR7b3B0aW9ufWApO1xuICAgICAgICAgICAgICByZXR1cm4gc3R5bGUodCBhcyBzdHJpbmcpO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIGZ1bmN0aW9uIGFwcGx5U3R5bGUodjogbnVtYmVyIHwgc3RyaW5nKTogdm9pZCB7XG4gICAgICAgICAgaWYgKHR5cGVvZiB2ID09PSBcIm51bWJlclwiKSB7XG4gICAgICAgICAgICBjID0gYy5zdHlsZSh2KTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgYyA9IGNbdiBhcyBrZXlvZiBDb2xvcml6ZU9wdGlvbnNdIGFzIFN0eWxlZFN0cmluZztcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBzd2l0Y2ggKG9wdGlvbikge1xuICAgICAgICAgIGNhc2UgXCJiZ1wiOlxuICAgICAgICAgIGNhc2UgXCJmZ1wiOlxuICAgICAgICAgICAgcmV0dXJuIGFwcGx5Q29sb3IodmFsdWUgYXMgbnVtYmVyKS50ZXh0O1xuICAgICAgICAgIGNhc2UgXCJzdHlsZVwiOlxuICAgICAgICAgICAgaWYgKEFycmF5LmlzQXJyYXkodmFsdWUpKSB7XG4gICAgICAgICAgICAgIHZhbHVlLmZvckVhY2goYXBwbHlTdHlsZSk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICBhcHBseVN0eWxlKHZhbHVlIGFzIG51bWJlciB8IHN0cmluZyk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gYy50ZXh0O1xuICAgICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgICBjb25zb2xlLmVycm9yKGBOb3QgYSB2YWxpZCB0aGVtZSBvcHRpb246ICR7b3B0aW9ufWApO1xuICAgICAgICAgICAgcmV0dXJuIHQ7XG4gICAgICAgIH1cbiAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby11bnVzZWQtdmFyc1xuICAgICAgfSBjYXRjaCAoZTogdW5rbm93bikge1xuICAgICAgICBjb25zb2xlLmVycm9yKGBFcnJvciBhcHBseWluZyBzdHlsZTogJHtvcHRpb259IHdpdGggdmFsdWUgJHt2YWx1ZX1gKTtcbiAgICAgICAgcmV0dXJuIHR4dDtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBjb25zdCBpbmRpdmlkdWFsVGhlbWUgPSB0ZW1wbGF0ZVt0eXBlIGFzIGtleW9mIFRoZW1lXTtcbiAgICBpZiAoIWluZGl2aWR1YWxUaGVtZSB8fCAhT2JqZWN0LmtleXMoaW5kaXZpZHVhbFRoZW1lKS5sZW5ndGgpIHtcbiAgICAgIHJldHVybiB0ZXh0O1xuICAgIH1cblxuICAgIGxldCBhY3R1YWxUaGVtZTogVGhlbWVPcHRpb24gPSBpbmRpdmlkdWFsVGhlbWUgYXMgVGhlbWVPcHRpb247XG5cbiAgICBjb25zdCBsb2dMZXZlbHMgPSBPYmplY3QuYXNzaWduKHt9LCBMb2dMZXZlbCk7XG4gICAgaWYgKE9iamVjdC5rZXlzKGluZGl2aWR1YWxUaGVtZSlbMF0gaW4gbG9nTGV2ZWxzKVxuICAgICAgYWN0dWFsVGhlbWUgPVxuICAgICAgICAoaW5kaXZpZHVhbFRoZW1lIGFzIFRoZW1lT3B0aW9uQnlMb2dMZXZlbClbbG9nZ2VyTGV2ZWxdIHx8IHt9O1xuXG4gICAgcmV0dXJuIE9iamVjdC5rZXlzKGFjdHVhbFRoZW1lKS5yZWR1Y2UoKGFjYzogc3RyaW5nLCBrZXk6IHN0cmluZykgPT4ge1xuICAgICAgY29uc3QgdmFsID0gKGFjdHVhbFRoZW1lIGFzIFRoZW1lT3B0aW9uKVtrZXkgYXMga2V5b2YgVGhlbWVPcHRpb25dO1xuICAgICAgaWYgKHZhbClcbiAgICAgICAgcmV0dXJuIGFwcGx5KFxuICAgICAgICAgIGFjYyxcbiAgICAgICAgICBrZXkgYXMga2V5b2YgVGhlbWVPcHRpb24sXG4gICAgICAgICAgdmFsIGFzXG4gICAgICAgICAgICB8IG51bWJlclxuICAgICAgICAgICAgfCBbbnVtYmVyXVxuICAgICAgICAgICAgfCBbbnVtYmVyLCBudW1iZXIsIG51bWJlcl1cbiAgICAgICAgICAgIHwgbnVtYmVyW11cbiAgICAgICAgICAgIHwgc3RyaW5nW11cbiAgICAgICAgKTtcbiAgICAgIHJldHVybiBhY2M7XG4gICAgfSwgdGV4dCk7XG4gIH1cbn1cbiIsImltcG9ydCB7IExvZ2dpbmcgfSBmcm9tIFwiLi9sb2dnaW5nXCI7XG5pbXBvcnQgeyBMb2dnZXIgfSBmcm9tIFwiLi90eXBlc1wiO1xuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBCYXNlIGNsYXNzIHRoYXQgcHJvdmlkZXMgYSByZWFkeS10by11c2UgbG9nZ2VyIGluc3RhbmNlLlxuICogQHN1bW1hcnkgU3VwcGxpZXMgaW5oZXJpdGluZyBjbGFzc2VzIHdpdGggYSBsYXppbHkgY3JlYXRlZCwgY29udGV4dC1hd2FyZSB7QGxpbmsgTG9nZ2VyfSB2aWEgdGhlIHByb3RlY3RlZCBgbG9nYCBnZXR0ZXIsIHByb21vdGluZyBjb25zaXN0ZW50IHN0cnVjdHVyZWQgbG9nZ2luZyB3aXRob3V0IG1hbnVhbCB3aXJpbmcuXG4gKiBAY2xhc3MgTG9nZ2VkQ2xhc3NcbiAqIEBleGFtcGxlXG4gKiBjbGFzcyBVc2VyU2VydmljZSBleHRlbmRzIExvZ2dlZENsYXNzIHtcbiAqICAgY3JlYXRlKHVzZXI6IFVzZXIpIHtcbiAqICAgICB0aGlzLmxvZy5pbmZvKGBDcmVhdGluZyB1c2VyICR7dXNlci5pZH1gKTtcbiAqICAgfVxuICogfVxuICpcbiAqIGNvbnN0IHN2YyA9IG5ldyBVc2VyU2VydmljZSgpO1xuICogc3ZjLmNyZWF0ZSh7IGlkOiBcIjQyXCIgfSk7XG4gKiBAbWVybWFpZFxuICogc2VxdWVuY2VEaWFncmFtXG4gKiAgIHBhcnRpY2lwYW50IENsaWVudFxuICogICBwYXJ0aWNpcGFudCBJbnN0YW5jZSBhcyBTdWJjbGFzcyBJbnN0YW5jZVxuICogICBwYXJ0aWNpcGFudCBHZXR0ZXIgYXMgTG9nZ2VkQ2xhc3MubG9nXG4gKiAgIHBhcnRpY2lwYW50IExvZ2dpbmcgYXMgTG9nZ2luZ1xuICogICBwYXJ0aWNpcGFudCBMb2dnZXIgYXMgTG9nZ2VyXG4gKlxuICogICBDbGllbnQtPj5JbnN0YW5jZTogY2FsbCBzb21lTWV0aG9kKClcbiAqICAgSW5zdGFuY2UtPj5HZXR0ZXI6IGFjY2VzcyB0aGlzLmxvZ1xuICogICBHZXR0ZXItPj5Mb2dnaW5nOiBMb2dnaW5nLmZvcih0aGlzKVxuICogICBMb2dnaW5nLS0+PkdldHRlcjogcmV0dXJuIExvZ2dlclxuICogICBHZXR0ZXItLT4+SW5zdGFuY2U6IHJldHVybiBMb2dnZXJcbiAqICAgSW5zdGFuY2UtPj5Mb2dnZXI6IGluZm8vZGVidWcvZXJyb3IoLi4uKVxuICovXG5leHBvcnQgYWJzdHJhY3QgY2xhc3MgTG9nZ2VkQ2xhc3Mge1xuICBwcml2YXRlIF9sb2c/OiBMb2dnZXI7XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBMYXppbHkgcHJvdmlkZXMgYSBjb250ZXh0LWF3YXJlIGxvZ2dlciBmb3IgdGhlIGN1cnJlbnQgaW5zdGFuY2UuXG4gICAqIEBzdW1tYXJ5IENhbGxzIHtAbGluayBMb2dnaW5nLmZvcn0gd2l0aCB0aGUgc3ViY2xhc3MgaW5zdGFuY2UgdG8gb2J0YWluIGEgbG9nZ2VyIHdob3NlIGNvbnRleHQgbWF0Y2hlcyB0aGUgc3ViY2xhc3MgbmFtZS5cbiAgICogQHJldHVybiB7TG9nZ2VyfSBMb2dnZXIgYm91bmQgdG8gdGhlIHN1YmNsYXNzIGNvbnRleHQuXG4gICAqL1xuICBwcm90ZWN0ZWQgZ2V0IGxvZygpOiBMb2dnZXIge1xuICAgIGlmICghdGhpcy5fbG9nKSB0aGlzLl9sb2cgPSBMb2dnaW5nLmZvcih0aGlzIGFzIGFueSk7XG4gICAgcmV0dXJuIHRoaXMuX2xvZztcbiAgfVxuXG4gIHByb3RlY3RlZCBjb25zdHJ1Y3RvcigpIHt9XG59XG4iLCJpbXBvcnQgeyBMb2dnZXIsIExvZ2dpbmdDb25maWcsIExvZ2dpbmdGaWx0ZXIgfSBmcm9tIFwiLi4vdHlwZXNcIjtcbmltcG9ydCB7IExvZ2dlZENsYXNzIH0gZnJvbSBcIi4uL0xvZ2dlZENsYXNzXCI7XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIEJhc2UgY2xhc3MgZm9yIG1lc3NhZ2UgZmlsdGVycyB0aGF0IHBsdWcgaW50byB0aGUgbG9nZ2luZyBwaXBlbGluZS5cbiAqIEBzdW1tYXJ5IEV4dGVuZHMge0BsaW5rIExvZ2dlZENsYXNzfSB0byBzdXBwbHkgYSBzY29wZWQgbG9nZ2VyIGFuZCBkZWZpbmVzIHRoZSBjb250cmFjdCByZXF1aXJlZCBieSB7QGxpbmsgTG9nZ2luZ0ZpbHRlcn0gaW1wbGVtZW50ZXJzIHRoYXQgdHJhbnNmb3JtIG9yIGRyb3AgbG9nIG1lc3NhZ2VzIGJlZm9yZSBlbWlzc2lvbi5cbiAqIEBjbGFzcyBMb2dGaWx0ZXJcbiAqIEBleGFtcGxlXG4gKiBjbGFzcyBSZWRhY3RTZWNyZXRzRmlsdGVyIGV4dGVuZHMgTG9nRmlsdGVyIHtcbiAqICAgZmlsdGVyKGNvbmZpZzogTG9nZ2luZ0NvbmZpZywgbWVzc2FnZTogc3RyaW5nKTogc3RyaW5nIHtcbiAqICAgICByZXR1cm4gbWVzc2FnZS5yZXBsYWNlKC9zZWNyZXQvZ2ksIFwiKioqXCIpO1xuICogICB9XG4gKiB9XG4gKlxuICogY29uc3QgZmlsdGVyID0gbmV3IFJlZGFjdFNlY3JldHNGaWx0ZXIoKTtcbiAqIGZpbHRlci5maWx0ZXIoeyAuLi5EZWZhdWx0TG9nZ2luZ0NvbmZpZywgdmVyYm9zZTogMCB9LCBcInNlY3JldCB0b2tlblwiKTtcbiAqIEBtZXJtYWlkXG4gKiBzZXF1ZW5jZURpYWdyYW1cbiAqICAgcGFydGljaXBhbnQgTG9nZ2VyXG4gKiAgIHBhcnRpY2lwYW50IEZpbHRlciBhcyBMb2dGaWx0ZXJcbiAqICAgcGFydGljaXBhbnQgSW1wbCBhcyBDb25jcmV0ZUZpbHRlclxuICogICBwYXJ0aWNpcGFudCBPdXRwdXRcbiAqICAgTG9nZ2VyLT4+RmlsdGVyOiBmaWx0ZXIoY29uZmlnLCBtZXNzYWdlLCBjb250ZXh0KVxuICogICBGaWx0ZXItPj5JbXBsOiBkZWxlZ2F0ZSB0byBzdWJjbGFzcyBpbXBsZW1lbnRhdGlvblxuICogICBJbXBsLS0+PkZpbHRlcjogdHJhbnNmb3JtZWQgbWVzc2FnZVxuICogICBGaWx0ZXItLT4+T3V0cHV0OiByZXR1cm4gZmlsdGVyZWQgbWVzc2FnZVxuICovXG5leHBvcnQgYWJzdHJhY3QgY2xhc3MgTG9nRmlsdGVyIGV4dGVuZHMgTG9nZ2VkQ2xhc3MgaW1wbGVtZW50cyBMb2dnaW5nRmlsdGVyIHtcbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBTY29wZWQgbG9nZ2VyIHRoYXQgZXhjbHVkZXMgb3RoZXIgZmlsdGVycyBmcm9tIHRoZSBjaGFpbi5cbiAgICogQHN1bW1hcnkgUmV0dXJucyBhIGNoaWxkIGxvZ2dlciBkZWRpY2F0ZWQgdG8gdGhlIGZpbHRlciwgcHJldmVudGluZyByZWN1cnNpdmUgZmlsdGVyIGludm9jYXRpb24gd2hlbiBlbWl0dGluZyBkaWFnbm9zdGljIG1lc3NhZ2VzLlxuICAgKiBAcmV0dXJuIHtMb2dnZXJ9IENvbnRleHQtYXdhcmUgbG9nZ2VyIGZvciB0aGUgZmlsdGVyIGluc3RhbmNlLlxuICAgKi9cbiAgb3ZlcnJpZGUgZ2V0IGxvZygpOiBMb2dnZXIge1xuICAgIHJldHVybiBzdXBlci5sb2cuZm9yKHRoaXMgYXMgYW55LCB7IGZpbHRlcnM6IFtdIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBUcmFuc2Zvcm0gb3Igc3VwcHJlc3MgYSBsb2cgbWVzc2FnZS5cbiAgICogQHN1bW1hcnkgSW5zcGVjdCB0aGUgcHJvdmlkZWQgbWVzc2FnZSBhbmQgY29udGV4dCB0byBwcm9kdWNlIHRoZSB2YWx1ZSB0aGF0IHdpbGwgYmUgZm9yd2FyZGVkIHRvIHN1YnNlcXVlbnQgZmlsdGVycyBvciBlbWl0dGVycy5cbiAgICogQHBhcmFtIHtMb2dnaW5nQ29uZmlnfSBjb25maWcgLSBBY3RpdmUgbG9nZ2luZyBjb25maWd1cmF0aW9uLlxuICAgKiBAcGFyYW0ge3N0cmluZ30gbWVzc2FnZSAtIE9yaWdpbmFsIGxvZyBtZXNzYWdlIHBheWxvYWQuXG4gICAqIEBwYXJhbSB7c3RyaW5nW119IGNvbnRleHQgLSBDb250ZXh0IHZhbHVlcyBhdHRhY2hlZCB0byB0aGUgbWVzc2FnZS5cbiAgICogQHJldHVybiB7c3RyaW5nfSBGaWx0ZXJlZCBtZXNzYWdlIHRvIHBhc3MgdG8gZG93bnN0cmVhbSBwcm9jZXNzaW5nLlxuICAgKi9cbiAgYWJzdHJhY3QgZmlsdGVyKFxuICAgIGNvbmZpZzogTG9nZ2luZ0NvbmZpZyxcbiAgICBtZXNzYWdlOiBzdHJpbmcsXG4gICAgY29udGV4dDogc3RyaW5nW11cbiAgKTogc3RyaW5nO1xufVxuIiwiLyoqXG4gKiBAZGVzY3JpcHRpb24gU25hcHNob3Qgb2YgYSByZWNvcmRlZCBsYXAgaW50ZXJ2YWwuXG4gKiBAc3VtbWFyeSBDYXB0dXJlcyB0aGUgbGFwIGluZGV4LCBvcHRpb25hbCBsYWJlbCwgZWxhcHNlZCBtaWxsaXNlY29uZHMgZm9yIHRoZSBsYXAsIGFuZCBjdW11bGF0aXZlIGVsYXBzZWQgdGltZSBzaW5jZSB0aGUgc3RvcHdhdGNoIHN0YXJ0ZWQuXG4gKiBAdHlwZWRlZiB7T2JqZWN0fSBMYXBcbiAqIEBwcm9wZXJ0eSB7bnVtYmVyfSBpbmRleCAtIFplcm8tYmFzZWQgbGFwIG9yZGVyLlxuICogQHByb3BlcnR5IHtzdHJpbmd9IFtsYWJlbF0gLSBPcHRpb25hbCBsYWJlbCBkZXNjcmliaW5nIHRoZSBsYXAuXG4gKiBAcHJvcGVydHkge251bWJlcn0gbXMgLSBEdXJhdGlvbiBvZiB0aGUgbGFwIGluIG1pbGxpc2Vjb25kcy5cbiAqIEBwcm9wZXJ0eSB7bnVtYmVyfSB0b3RhbE1zIC0gVG90YWwgZWxhcHNlZCB0aW1lIHdoZW4gdGhlIGxhcCB3YXMgcmVjb3JkZWQuXG4gKiBAbWVtYmVyT2YgbW9kdWxlOkxvZ2dpbmdcbiAqL1xuZXhwb3J0IHR5cGUgTGFwID0ge1xuICBpbmRleDogbnVtYmVyO1xuICBsYWJlbD86IHN0cmluZztcbiAgLyoqIER1cmF0aW9uIG9mIHRoaXMgbGFwIGluIG1pbGxpc2Vjb25kcyAqL1xuICBtczogbnVtYmVyO1xuICAvKiogQ3VtdWxhdGl2ZSB0aW1lIHVwIHRvIHRoaXMgbGFwIGluIG1pbGxpc2Vjb25kcyAqL1xuICB0b3RhbE1zOiBudW1iZXI7XG59O1xuXG50eXBlIE5vd0ZuID0gKCkgPT4gbnVtYmVyOyAvLyBtaWxsaXNlY29uZHNcblxuZnVuY3Rpb24gc2FmZU5vdygpOiBOb3dGbiB7XG4gIC8vIFByZWZlciBwZXJmb3JtYW5jZS5ub3cgd2hlbiBhdmFpbGFibGVcbiAgaWYgKFxuICAgIHR5cGVvZiBnbG9iYWxUaGlzICE9PSBcInVuZGVmaW5lZFwiICYmXG4gICAgdHlwZW9mIGdsb2JhbFRoaXMucGVyZm9ybWFuY2U/Lm5vdyA9PT0gXCJmdW5jdGlvblwiXG4gICkge1xuICAgIHJldHVybiAoKSA9PiBnbG9iYWxUaGlzLnBlcmZvcm1hbmNlLm5vdygpO1xuICB9XG4gIC8vIE5vZGU6IHVzZSBwcm9jZXNzLmhydGltZS5iaWdpbnQgZm9yIGhpZ2hlciBwcmVjaXNpb24gaWYgYXZhaWxhYmxlXG4gIGlmIChcbiAgICB0eXBlb2YgcHJvY2VzcyAhPT0gXCJ1bmRlZmluZWRcIiAmJlxuICAgIHR5cGVvZiAocHJvY2VzcyBhcyBhbnkpLmhydGltZT8uYmlnaW50ID09PSBcImZ1bmN0aW9uXCJcbiAgKSB7XG4gICAgcmV0dXJuICgpID0+IHtcbiAgICAgIGNvbnN0IG5zID0gKHByb2Nlc3MgYXMgYW55KS5ocnRpbWUuYmlnaW50KCkgYXMgYmlnaW50OyAvLyBuYW5vc2Vjb25kc1xuICAgICAgcmV0dXJuIE51bWJlcihucykgLyAxXzAwMF8wMDA7IC8vIHRvIG1zXG4gICAgfTtcbiAgfVxuICAvLyBGYWxsYmFja1xuICByZXR1cm4gKCkgPT4gRGF0ZS5ub3coKTtcbn1cblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gSGlnaC1yZXNvbHV0aW9uIGNsb2NrIGFjY2Vzc29yIHJldHVybmluZyBtaWxsaXNlY29uZHMuXG4gKiBAc3VtbWFyeSBDaG9vc2VzIHRoZSBtb3N0IHByZWNpc2UgdGltZXIgYXZhaWxhYmxlIGluIHRoZSBjdXJyZW50IHJ1bnRpbWUsIHByZWZlcnJpbmcgYHBlcmZvcm1hbmNlLm5vd2Agb3IgYHByb2Nlc3MuaHJ0aW1lLmJpZ2ludGAuXG4gKiBAcmV0dXJuIHtudW1iZXJ9IE1pbGxpc2Vjb25kcyBlbGFwc2VkIGFjY29yZGluZyB0byB0aGUgYmVzdCBhdmFpbGFibGUgY2xvY2suXG4gKi9cbmV4cG9ydCBjb25zdCBub3cgPSBzYWZlTm93KCk7XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIEhpZ2gtcmVzb2x1dGlvbiBzdG9wd2F0Y2ggd2l0aCBwYXVzZSwgcmVzdW1lLCBhbmQgbGFwIHRyYWNraW5nLlxuICogQHN1bW1hcnkgVHJhY2tzIGVsYXBzZWQgdGltZSB1c2luZyB0aGUgaGlnaGVzdCBwcmVjaXNpb24gdGltZXIgYXZhaWxhYmxlLCBzdXBwb3J0cyBwYXVzaW5nLCByZXN1bWluZywgYW5kIHJlY29yZGluZyBsYWJlbGVkIGxhcHMgZm9yIGRpYWdub3N0aWNzIGFuZCBiZW5jaG1hcmtpbmcuXG4gKiBAcGFyYW0ge2Jvb2xlYW59IFthdXRvU3RhcnQ9ZmFsc2VdIC0gV2hlbiB0cnVlLCB0aGUgc3RvcHdhdGNoIHN0YXJ0cyBpbW1lZGlhdGVseSB1cG9uIGNvbnN0cnVjdGlvbi5cbiAqIEBjbGFzcyBTdG9wV2F0Y2hcbiAqIEBleGFtcGxlXG4gKiBjb25zdCBzdyA9IG5ldyBTdG9wV2F0Y2godHJ1ZSk7XG4gKiAvLyAuLi4gd29yayAuLi5cbiAqIGNvbnN0IGxhcCA9IHN3LmxhcChcInBoYXNlIDFcIik7XG4gKiBzdy5wYXVzZSgpO1xuICogY29uc29sZS5sb2coYEVsYXBzZWQ6ICR7bGFwLnRvdGFsTXN9bXNgKTtcbiAqIEBtZXJtYWlkXG4gKiBzZXF1ZW5jZURpYWdyYW1cbiAqICAgcGFydGljaXBhbnQgQ2xpZW50XG4gKiAgIHBhcnRpY2lwYW50IFN0b3BXYXRjaFxuICogICBwYXJ0aWNpcGFudCBDbG9jayBhcyBub3coKVxuICogICBDbGllbnQtPj5TdG9wV2F0Y2g6IHN0YXJ0KClcbiAqICAgU3RvcFdhdGNoLT4+Q2xvY2s6IG5vdygpXG4gKiAgIENsb2NrLS0+PlN0b3BXYXRjaDogdGltZXN0YW1wXG4gKiAgIENsaWVudC0+PlN0b3BXYXRjaDogbGFwKClcbiAqICAgU3RvcFdhdGNoLT4+Q2xvY2s6IG5vdygpXG4gKiAgIENsb2NrLS0+PlN0b3BXYXRjaDogdGltZXN0YW1wXG4gKiAgIFN0b3BXYXRjaC0tPj5DbGllbnQ6IExhcFxuICogICBDbGllbnQtPj5TdG9wV2F0Y2g6IHBhdXNlKClcbiAqICAgU3RvcFdhdGNoLT4+Q2xvY2s6IG5vdygpXG4gKiAgIENsb2NrLS0+PlN0b3BXYXRjaDogdGltZXN0YW1wXG4gKi9cbmV4cG9ydCBjbGFzcyBTdG9wV2F0Y2gge1xuICBwcml2YXRlIF9zdGFydE1zOiBudW1iZXIgfCBudWxsID0gbnVsbDtcbiAgcHJpdmF0ZSBfZWxhcHNlZE1zID0gMDtcbiAgcHJpdmF0ZSBfcnVubmluZyA9IGZhbHNlO1xuICBwcml2YXRlIF9sYXBzOiBMYXBbXSA9IFtdO1xuICBwcml2YXRlIF9sYXN0TGFwVG90YWxNcyA9IDA7XG5cbiAgY29uc3RydWN0b3IoYXV0b1N0YXJ0ID0gZmFsc2UpIHtcbiAgICBpZiAoYXV0b1N0YXJ0KSB0aGlzLnN0YXJ0KCk7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIEluZGljYXRlcyB3aGV0aGVyIHRoZSBzdG9wd2F0Y2ggaXMgYWN0aXZlbHkgcnVubmluZy5cbiAgICogQHN1bW1hcnkgUmV0dXJucyBgdHJ1ZWAgd2hlbiB0aW1pbmcgaXMgaW4gcHJvZ3Jlc3MgYW5kIGBmYWxzZWAgd2hlbiBwYXVzZWQgb3Igc3RvcHBlZC5cbiAgICogQHJldHVybiB7Ym9vbGVhbn0gQ3VycmVudCBydW5uaW5nIHN0YXRlLlxuICAgKi9cbiAgZ2V0IHJ1bm5pbmcoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMuX3J1bm5pbmc7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIEVsYXBzZWQgdGltZSBjYXB0dXJlZCBieSB0aGUgc3RvcHdhdGNoLlxuICAgKiBAc3VtbWFyeSBDb21wdXRlcyB0aGUgdG90YWwgZWxhcHNlZCB0aW1lIGluIG1pbGxpc2Vjb25kcywgaW5jbHVkaW5nIHRoZSBjdXJyZW50IHNlc3Npb24gaWYgcnVubmluZy5cbiAgICogQHJldHVybiB7bnVtYmVyfSBNaWxsaXNlY29uZHMgZWxhcHNlZCBzaW5jZSB0aGUgc3RvcHdhdGNoIHN0YXJ0ZWQuXG4gICAqL1xuICBnZXQgZWxhcHNlZE1zKCk6IG51bWJlciB7XG4gICAgaWYgKCF0aGlzLl9ydW5uaW5nIHx8IHRoaXMuX3N0YXJ0TXMgPT0gbnVsbCkgcmV0dXJuIHRoaXMuX2VsYXBzZWRNcztcbiAgICByZXR1cm4gdGhpcy5fZWxhcHNlZE1zICsgKG5vdygpIC0gdGhpcy5fc3RhcnRNcyk7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFN0YXJ0cyB0aW1pbmcgaWYgdGhlIHN0b3B3YXRjaCBpcyBub3QgYWxyZWFkeSBydW5uaW5nLlxuICAgKiBAc3VtbWFyeSBSZWNvcmRzIHRoZSBjdXJyZW50IHRpbWVzdGFtcCBhbmQgdHJhbnNpdGlvbnMgdGhlIHN0b3B3YXRjaCBpbnRvIHRoZSBydW5uaW5nIHN0YXRlLlxuICAgKiBAcmV0dXJuIHt0aGlzfSBGbHVlbnQgcmVmZXJlbmNlIHRvIHRoZSBzdG9wd2F0Y2guXG4gICAqL1xuICBzdGFydCgpOiB0aGlzIHtcbiAgICBpZiAoIXRoaXMuX3J1bm5pbmcpIHtcbiAgICAgIHRoaXMuX3J1bm5pbmcgPSB0cnVlO1xuICAgICAgdGhpcy5fc3RhcnRNcyA9IG5vdygpO1xuICAgIH1cbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gUGF1c2VzIHRpbWluZyBhbmQgYWNjdW11bGF0ZXMgZWxhcHNlZCBtaWxsaXNlY29uZHMuXG4gICAqIEBzdW1tYXJ5IENhcHR1cmVzIHRoZSBwYXJ0aWFsIGR1cmF0aW9uLCB1cGRhdGVzIHRoZSBhY2N1bXVsYXRvciwgYW5kIGtlZXBzIHRoZSBzdG9wd2F0Y2ggcmVhZHkgdG8gcmVzdW1lIGxhdGVyLlxuICAgKiBAcmV0dXJuIHt0aGlzfSBGbHVlbnQgcmVmZXJlbmNlIHRvIHRoZSBzdG9wd2F0Y2guXG4gICAqL1xuICBwYXVzZSgpOiB0aGlzIHtcbiAgICBpZiAodGhpcy5fcnVubmluZyAmJiB0aGlzLl9zdGFydE1zICE9IG51bGwpIHtcbiAgICAgIHRoaXMuX2VsYXBzZWRNcyArPSBub3coKSAtIHRoaXMuX3N0YXJ0TXM7XG4gICAgICB0aGlzLl9zdGFydE1zID0gbnVsbDtcbiAgICAgIHRoaXMuX3J1bm5pbmcgPSBmYWxzZTtcbiAgICB9XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFJlc3VtZXMgdGltaW5nIGFmdGVyIGEgcGF1c2UuXG4gICAqIEBzdW1tYXJ5IENhcHR1cmVzIGEgZnJlc2ggc3RhcnQgdGltZXN0YW1wIHdoaWxlIGtlZXBpbmcgcHJldmlvdXMgZWxhcHNlZCB0aW1lIGludGFjdC5cbiAgICogQHJldHVybiB7dGhpc30gRmx1ZW50IHJlZmVyZW5jZSB0byB0aGUgc3RvcHdhdGNoLlxuICAgKi9cbiAgcmVzdW1lKCk6IHRoaXMge1xuICAgIGlmICghdGhpcy5fcnVubmluZykge1xuICAgICAgdGhpcy5fcnVubmluZyA9IHRydWU7XG4gICAgICB0aGlzLl9zdGFydE1zID0gbm93KCk7XG4gICAgfVxuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBTdG9wcyB0aW1pbmcgYW5kIHJldHVybnMgdGhlIHRvdGFsIGVsYXBzZWQgbWlsbGlzZWNvbmRzLlxuICAgKiBAc3VtbWFyeSBJbnZva2VzIHtAbGluayBTdG9wV2F0Y2gucGF1c2V9IHRvIGNvbnNvbGlkYXRlIGVsYXBzZWQgdGltZSwgbGVhdmluZyB0aGUgc3RvcHdhdGNoIGluIGEgbm9uLXJ1bm5pbmcgc3RhdGUuXG4gICAqIEByZXR1cm4ge251bWJlcn0gTWlsbGlzZWNvbmRzIGFjY3VtdWxhdGVkIGFjcm9zcyBhbGwgcnVucy5cbiAgICovXG4gIHN0b3AoKTogbnVtYmVyIHtcbiAgICB0aGlzLnBhdXNlKCk7XG4gICAgcmV0dXJuIHRoaXMuX2VsYXBzZWRNcztcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gUmVzZXRzIHRoZSBzdG9wd2F0Y2ggc3RhdGUgd2hpbGUgb3B0aW9uYWxseSBjb250aW51aW5nIHRvIHJ1bi5cbiAgICogQHN1bW1hcnkgQ2xlYXJzIGVsYXBzZWQgdGltZSBhbmQgbGFwIGhpc3RvcnksIHByZXNlcnZpbmcgd2hldGhlciB0aGUgc3RvcHdhdGNoIHNob3VsZCBjb250aW51ZSB0aWNraW5nLlxuICAgKiBAcmV0dXJuIHt0aGlzfSBGbHVlbnQgcmVmZXJlbmNlIHRvIHRoZSBzdG9wd2F0Y2guXG4gICAqL1xuICByZXNldCgpOiB0aGlzIHtcbiAgICBjb25zdCB3YXNSdW5uaW5nID0gdGhpcy5fcnVubmluZztcbiAgICB0aGlzLl9zdGFydE1zID0gd2FzUnVubmluZyA/IG5vdygpIDogbnVsbDtcbiAgICB0aGlzLl9lbGFwc2VkTXMgPSAwO1xuICAgIHRoaXMuX2xhcHMgPSBbXTtcbiAgICB0aGlzLl9sYXN0TGFwVG90YWxNcyA9IDA7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFJlY29yZHMgYSBsYXAgc3BsaXQgc2luY2UgdGhlIHN0b3B3YXRjaCBzdGFydGVkIG9yIHNpbmNlIHRoZSBwcmV2aW91cyBsYXAuXG4gICAqIEBzdW1tYXJ5IFN0b3JlcyB0aGUgbGFwIG1ldGFkYXRhLCB1cGRhdGVzIGN1bXVsYXRpdmUgdHJhY2tpbmcsIGFuZCByZXR1cm5zIHRoZSBuZXdseSBjcmVhdGVkIHtAbGluayBMYXB9LlxuICAgKiBAcGFyYW0ge3N0cmluZ30gW2xhYmVsXSAtIE9wdGlvbmFsIGxhYmVsIGRlc2NyaWJpbmcgdGhlIGxhcC5cbiAgICogQHJldHVybiB7TGFwfSBMYXAgc25hcHNob3QgY2FwdHVyaW5nIGluY3JlbWVudGFsIGFuZCBjdW11bGF0aXZlIHRpbWluZ3MuXG4gICAqL1xuICBsYXAobGFiZWw/OiBzdHJpbmcpOiBMYXAge1xuICAgIGNvbnN0IHRvdGFsID0gdGhpcy5lbGFwc2VkTXM7XG4gICAgY29uc3QgbXMgPSB0b3RhbCAtIHRoaXMuX2xhc3RMYXBUb3RhbE1zO1xuICAgIGNvbnN0IGxhcDogTGFwID0ge1xuICAgICAgaW5kZXg6IHRoaXMuX2xhcHMubGVuZ3RoLFxuICAgICAgbGFiZWwsXG4gICAgICBtcyxcbiAgICAgIHRvdGFsTXM6IHRvdGFsLFxuICAgIH07XG4gICAgdGhpcy5fbGFwcy5wdXNoKGxhcCk7XG4gICAgdGhpcy5fbGFzdExhcFRvdGFsTXMgPSB0b3RhbDtcbiAgICByZXR1cm4gbGFwO1xuICB9XG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gUmV0cmlldmVzIHRoZSByZWNvcmRlZCBsYXAgaGlzdG9yeS5cbiAgICogQHN1bW1hcnkgUmV0dXJucyB0aGUgaW50ZXJuYWwgbGFwIGFycmF5IGFzIGEgcmVhZC1vbmx5IHZpZXcgdG8gcHJldmVudCBleHRlcm5hbCBtdXRhdGlvbi5cbiAgICogQHJldHVybiB7TGFwW119IExhcHMgY2FwdHVyZWQgYnkgdGhlIHN0b3B3YXRjaC5cbiAgICovXG4gIGdldCBsYXBzKCk6IHJlYWRvbmx5IExhcFtdIHtcbiAgICByZXR1cm4gdGhpcy5fbGFwcztcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gRm9ybWF0cyB0aGUgZWxhcHNlZCB0aW1lIGluIGEgaHVtYW4tcmVhZGFibGUgcmVwcmVzZW50YXRpb24uXG4gICAqIEBzdW1tYXJ5IFVzZXMge0BsaW5rIGZvcm1hdE1zfSB0byBwcm9kdWNlIGFuIGBoaDptbTpzcy5tbW1gIHN0cmluZyBmb3IgZGlzcGxheSBhbmQgbG9nZ2luZy5cbiAgICogQHJldHVybiB7c3RyaW5nfSBFbGFwc2VkIHRpbWUgZm9ybWF0dGVkIGZvciBwcmVzZW50YXRpb24uXG4gICAqL1xuICB0b1N0cmluZygpOiBzdHJpbmcge1xuICAgIHJldHVybiBmb3JtYXRNcyh0aGlzLmVsYXBzZWRNcyk7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFNlcmlhbGl6ZXMgdGhlIHN0b3B3YXRjaCBzdGF0ZS5cbiAgICogQHN1bW1hcnkgUHJvdmlkZXMgYSBKU09OLWZyaWVuZGx5IHNuYXBzaG90IGluY2x1ZGluZyBydW5uaW5nIHN0YXRlLCBlbGFwc2VkIHRpbWUsIGFuZCBsYXAgZGV0YWlscy5cbiAgICogQHJldHVybiB7e3J1bm5pbmc6IGJvb2xlYW4sIGVsYXBzZWRNczogbnVtYmVyLCBsYXBzOiBMYXBbXX19IFNlcmlhbGl6YWJsZSBzdG9wd2F0Y2ggcmVwcmVzZW50YXRpb24uXG4gICAqL1xuICB0b0pTT04oKSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIHJ1bm5pbmc6IHRoaXMuX3J1bm5pbmcsXG4gICAgICBlbGFwc2VkTXM6IHRoaXMuZWxhcHNlZE1zLFxuICAgICAgbGFwczogdGhpcy5fbGFwcy5zbGljZSgpLFxuICAgIH07XG4gIH1cbn1cbi8qKlxuICogQGRlc2NyaXB0aW9uIEZvcm1hdHMgbWlsbGlzZWNvbmRzIGludG8gYGhoOm1tOnNzLm1tbWAuXG4gKiBAc3VtbWFyeSBCcmVha3MgdGhlIGR1cmF0aW9uIGludG8gaG91cnMsIG1pbnV0ZXMsIHNlY29uZHMsIGFuZCBtaWxsaXNlY29uZHMsIHJldHVybmluZyBhIHplcm8tcGFkZGVkIHN0cmluZy5cbiAqIEBwYXJhbSB7bnVtYmVyfSBtcyAtIE1pbGxpc2Vjb25kcyB0byBmb3JtYXQuXG4gKiBAcmV0dXJuIHtzdHJpbmd9IEZvcm1hdHRlZCBkdXJhdGlvbiBzdHJpbmcuXG4gKiBAZnVuY3Rpb24gZm9ybWF0TXNcbiAqIEBtZW1iZXJPZiBtb2R1bGU6TG9nZ2luZ1xuICogQG1lcm1haWRcbiAqIHNlcXVlbmNlRGlhZ3JhbVxuICogICBwYXJ0aWNpcGFudCBDYWxsZXJcbiAqICAgcGFydGljaXBhbnQgRm9ybWF0dGVyIGFzIGZvcm1hdE1zXG4gKiAgIENhbGxlci0+PkZvcm1hdHRlcjogZm9ybWF0TXMobXMpXG4gKiAgIEZvcm1hdHRlci0+PkZvcm1hdHRlcjogZGVyaXZlIGhvdXJzL21pbnV0ZXMvc2Vjb25kc1xuICogICBGb3JtYXR0ZXItPj5Gb3JtYXR0ZXI6IHBhZCBzZWdtZW50c1xuICogICBGb3JtYXR0ZXItLT4+Q2FsbGVyOiBoaDptbTpzcy5tbW1cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGZvcm1hdE1zKG1zOiBudW1iZXIpOiBzdHJpbmcge1xuICBjb25zdCBzaWduID0gbXMgPCAwID8gXCItXCIgOiBcIlwiO1xuICBjb25zdCBhYnMgPSBNYXRoLmFicyhtcyk7XG4gIGNvbnN0IGhvdXJzID0gTWF0aC5mbG9vcihhYnMgLyAzXzYwMF8wMDApO1xuICBjb25zdCBtaW51dGVzID0gTWF0aC5mbG9vcigoYWJzICUgM182MDBfMDAwKSAvIDYwXzAwMCk7XG4gIGNvbnN0IHNlY29uZHMgPSBNYXRoLmZsb29yKChhYnMgJSA2MF8wMDApIC8gMTAwMCk7XG4gIGNvbnN0IG1pbGxpcyA9IE1hdGguZmxvb3IoYWJzICUgMTAwMCk7XG4gIGNvbnN0IHBhZCA9IChuOiBudW1iZXIsIHc6IG51bWJlcikgPT4gbi50b1N0cmluZygpLnBhZFN0YXJ0KHcsIFwiMFwiKTtcbiAgcmV0dXJuIGAke3NpZ259JHtwYWQoaG91cnMsIDIpfToke3BhZChtaW51dGVzLCAyKX06JHtwYWQoc2Vjb25kcywgMil9LiR7cGFkKG1pbGxpcywgMyl9YDtcbn1cbiIsImltcG9ydCB7IExvZ0xldmVsIH0gZnJvbSBcIi4vY29uc3RhbnRzXCI7XG5pbXBvcnQgeyBMb2dnaW5nIH0gZnJvbSBcIi4vbG9nZ2luZ1wiO1xuaW1wb3J0IHsgbm93IH0gZnJvbSBcIi4vdGltZVwiO1xuaW1wb3J0IHsgTG9nZ2VkQ2xhc3MgfSBmcm9tIFwiLi9Mb2dnZWRDbGFzc1wiO1xuaW1wb3J0IHsgTG9nZ2VyIH0gZnJvbSBcIi4vdHlwZXNcIjtcblxuZXhwb3J0IHR5cGUgQXJnRm9ybWF0RnVuY3Rpb24gPSAoLi4uYXJnczogYW55W10pID0+IHN0cmluZztcbmV4cG9ydCB0eXBlIFJldHVybkZvcm1hdEZ1bmN0aW9uID0gKGU/OiBFcnJvciwgcmVzdWx0PzogYW55KSA9PiBzdHJpbmc7XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIE1ldGhvZCBkZWNvcmF0b3IgZm9yIGxvZ2dpbmcgZnVuY3Rpb24gY2FsbHMuXG4gKiBAc3VtbWFyeSBXcmFwcyBjbGFzcyBtZXRob2RzIHRvIGF1dG9tYXRpY2FsbHkgbG9nIGVudHJ5LCBleGl0LCB0aW1pbmcsIGFuZCBvcHRpb25hbCBjdXN0b20gbWVzc2FnZXMgYXQgYSBjb25maWd1cmFibGUge0BsaW5rIExvZ0xldmVsfS5cbiAqIEBwYXJhbSB7TG9nTGV2ZWx9IGxldmVsIC0gTG9nIGxldmVsIGFwcGxpZWQgdG8gdGhlIGdlbmVyYXRlZCBsb2cgc3RhdGVtZW50cyAoZGVmYXVsdHMgdG8gYExvZ0xldmVsLmluZm9gKS5cbiAqIEBwYXJhbSB7bnVtYmVyfSBbdmVyYm9zaXR5PTBdIC0gVmVyYm9zaXR5IHRocmVzaG9sZCByZXF1aXJlZCBmb3IgdGhlIGVudHJ5IGxvZyB0byBhcHBlYXIuXG4gKiBAcGFyYW0ge0FyZ0Zvcm1hdEZ1bmN0aW9ufSBbZW50cnlNZXNzYWdlXSAtIEZvcm1hdHRlciBpbnZva2VkIHdpdGggdGhlIG9yaWdpbmFsIG1ldGhvZCBhcmd1bWVudHMgdG8gZGVzY3JpYmUgdGhlIGludm9jYXRpb24uXG4gKiBAcGFyYW0ge1JldHVybkZvcm1hdEZ1bmN0aW9ufSBbZXhpdE1lc3NhZ2VdIC0gT3B0aW9uYWwgZm9ybWF0dGVyIHRoYXQgZGVzY3JpYmVzIHRoZSBvdXRjb21lIG9yIGZhaWx1cmUgb2YgdGhlIGNhbGwuXG4gKiBAcmV0dXJuIHtmdW5jdGlvbihhbnksIGFueSwgUHJvcGVydHlEZXNjcmlwdG9yKTogdm9pZH0gTWV0aG9kIGRlY29yYXRvciBwcm94eSB0aGF0IGluamVjdHMgbG9nZ2luZyBiZWhhdmlvci5cbiAqIEBmdW5jdGlvbiBsb2dcbiAqIEBtZXJtYWlkXG4gKiBzZXF1ZW5jZURpYWdyYW1cbiAqICAgcGFydGljaXBhbnQgQ2xpZW50XG4gKiAgIHBhcnRpY2lwYW50IERlY29yYXRvciBhcyBsb2cgZGVjb3JhdG9yXG4gKiAgIHBhcnRpY2lwYW50IE1ldGhvZCBhcyBPcmlnaW5hbCBNZXRob2RcbiAqICAgcGFydGljaXBhbnQgTG9nZ2VyIGFzIExvZ2dpbmcgaW5zdGFuY2VcbiAqXG4gKiAgIENsaWVudC0+PkRlY29yYXRvcjogY2FsbCBkZWNvcmF0ZWQgbWV0aG9kXG4gKiAgIERlY29yYXRvci0+PkxvZ2dlcjogbG9nIG1ldGhvZCBjYWxsXG4gKiAgIERlY29yYXRvci0+Pk1ldGhvZDogY2FsbCBvcmlnaW5hbCBtZXRob2RcbiAqICAgYWx0IHJlc3VsdCBpcyBQcm9taXNlXG4gKiAgICAgTWV0aG9kLS0+PkRlY29yYXRvcjogcmV0dXJuIFByb21pc2VcbiAqICAgICBEZWNvcmF0b3ItPj5EZWNvcmF0b3I6IGF0dGFjaCB0aGVuIGhhbmRsZXJcbiAqICAgICBOb3RlIG92ZXIgRGVjb3JhdG9yOiBQcm9taXNlIHJlc29sdmVzXG4gKiAgICAgRGVjb3JhdG9yLT4+TG9nZ2VyOiBsb2cgYmVuY2htYXJrIChpZiBlbmFibGVkKVxuICogICAgIERlY29yYXRvci0tPj5DbGllbnQ6IHJldHVybiByZXN1bHRcbiAqICAgZWxzZSByZXN1bHQgaXMgbm90IFByb21pc2VcbiAqICAgICBNZXRob2QtLT4+RGVjb3JhdG9yOiByZXR1cm4gcmVzdWx0XG4gKiAgICAgRGVjb3JhdG9yLT4+TG9nZ2VyOiBsb2cgYmVuY2htYXJrIChpZiBlbmFibGVkKVxuICogICAgIERlY29yYXRvci0tPj5DbGllbnQ6IHJldHVybiByZXN1bHRcbiAqICAgZW5kXG4gKiBAY2F0ZWdvcnkgTWV0aG9kIERlY29yYXRvcnNcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGxvZyhcbiAgbGV2ZWw6IExvZ0xldmVsID0gTG9nTGV2ZWwuaW5mbyxcbiAgdmVyYm9zaXR5ID0gMCxcbiAgZW50cnlNZXNzYWdlOiBBcmdGb3JtYXRGdW5jdGlvbiA9ICguLi5hcmdzOiBhbnlbXSkgPT4gYGNhbGxlZCB3aXRoICR7YXJnc31gLFxuICBleGl0TWVzc2FnZT86IFJldHVybkZvcm1hdEZ1bmN0aW9uXG4pIHtcbiAgcmV0dXJuIGZ1bmN0aW9uIGxvZyh0YXJnZXQ6IGFueSwgcHJvcGVydHlLZXk/OiBhbnksIGRlc2NyaXB0b3I/OiBhbnkpIHtcbiAgICBpZiAoIWRlc2NyaXB0b3IgfHwgdHlwZW9mIGRlc2NyaXB0b3IgPT09IFwibnVtYmVyXCIpXG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYExvZ2dpbmcgZGVjb3JhdGlvbiBvbmx5IGFwcGxpZXMgdG8gbWV0aG9kc2ApO1xuICAgIGNvbnN0IGxvZ2dlcjogTG9nZ2VyID1cbiAgICAgIHRhcmdldCBpbnN0YW5jZW9mIExvZ2dlZENsYXNzXG4gICAgICAgID8gdGFyZ2V0W1wibG9nXCJdLmZvcih0YXJnZXRbcHJvcGVydHlLZXkgYXMga2V5b2YgdHlwZW9mIHRhcmdldF0pXG4gICAgICAgIDogTG9nZ2luZy5mb3IodGFyZ2V0KS5mb3IodGFyZ2V0W3Byb3BlcnR5S2V5XSk7XG4gICAgY29uc3QgbWV0aG9kID0gbG9nZ2VyW2xldmVsXS5iaW5kKGxvZ2dlcikgYXMgYW55O1xuICAgIGNvbnN0IG9yaWdpbmFsTWV0aG9kID0gZGVzY3JpcHRvci52YWx1ZTtcblxuICAgIGRlc2NyaXB0b3IudmFsdWUgPSBuZXcgUHJveHkob3JpZ2luYWxNZXRob2QsIHtcbiAgICAgIGFwcGx5KGZuLCB0aGlzQXJnLCBhcmdzOiBhbnlbXSkge1xuICAgICAgICBtZXRob2QoZW50cnlNZXNzYWdlKC4uLmFyZ3MpLCB2ZXJib3NpdHkpO1xuICAgICAgICB0cnkge1xuICAgICAgICAgIGNvbnN0IHJlc3VsdCA9IFJlZmxlY3QuYXBwbHkoZm4sIHRoaXNBcmcsIGFyZ3MpO1xuICAgICAgICAgIGlmIChyZXN1bHQgaW5zdGFuY2VvZiBQcm9taXNlKSB7XG4gICAgICAgICAgICByZXR1cm4gcmVzdWx0XG4gICAgICAgICAgICAgIC50aGVuKChyOiBhbnkpID0+IHtcbiAgICAgICAgICAgICAgICBpZiAoZXhpdE1lc3NhZ2UpIG1ldGhvZChleGl0TWVzc2FnZSh1bmRlZmluZWQsIHIpKTtcbiAgICAgICAgICAgICAgICByZXR1cm4gcjtcbiAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgLmNhdGNoKChlKSA9PiB7XG4gICAgICAgICAgICAgICAgaWYgKGV4aXRNZXNzYWdlKSBsb2dnZXIuZXJyb3IoZXhpdE1lc3NhZ2UoZSBhcyBFcnJvcikpO1xuICAgICAgICAgICAgICAgIHRocm93IGU7XG4gICAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH1cbiAgICAgICAgICBpZiAoZXhpdE1lc3NhZ2UpIG1ldGhvZChleGl0TWVzc2FnZSh1bmRlZmluZWQsIHJlc3VsdCkpO1xuICAgICAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgICAgIH0gY2F0Y2ggKGVycjogdW5rbm93bikge1xuICAgICAgICAgIGlmIChleGl0TWVzc2FnZSkgbG9nZ2VyLmVycm9yKGV4aXRNZXNzYWdlKGVyciBhcyBFcnJvcikpO1xuICAgICAgICAgIHRocm93IGVycjtcbiAgICAgICAgfVxuICAgICAgfSxcbiAgICB9KTtcbiAgICByZXR1cm4gZGVzY3JpcHRvcjtcbiAgfTtcbn1cblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gTWV0aG9kIGRlY29yYXRvciB0aGF0IHJlY29yZHMgZXhlY3V0aW9uIHRpbWUgYXQgdGhlIGJlbmNobWFyayBsZXZlbC5cbiAqIEBzdW1tYXJ5IFdyYXBzIHRoZSB0YXJnZXQgbWV0aG9kIHRvIGVtaXQge0BsaW5rIExvZ2dlci5iZW5jaG1hcmt9IGVudHJpZXMgY2FwdHVyaW5nIGNvbXBsZXRpb24gdGltZSBvciBmYWlsdXJlIGxhdGVuY3kuXG4gKiBAcmV0dXJuIHtmdW5jdGlvbihhbnksIGFueSwgIFByb3BlcnR5RGVzY3JpcHRvcik6IHZvaWR9IE1ldGhvZCBkZWNvcmF0b3IgcHJveHkgdGhhdCBiZW5jaG1hcmtzIHRoZSBvcmlnaW5hbCBpbXBsZW1lbnRhdGlvbi5cbiAqIEBmdW5jdGlvbiBiZW5jaG1hcmtcbiAqIEBtZXJtYWlkXG4gKiBzZXF1ZW5jZURpYWdyYW1cbiAqICAgcGFydGljaXBhbnQgQ2FsbGVyXG4gKiAgIHBhcnRpY2lwYW50IERlY29yYXRvciBhcyBiZW5jaG1hcmtcbiAqICAgcGFydGljaXBhbnQgTWV0aG9kIGFzIE9yaWdpbmFsIE1ldGhvZFxuICogICBDYWxsZXItPj5EZWNvcmF0b3I6IGludm9rZSgpXG4gKiAgIERlY29yYXRvci0+Pk1ldGhvZDogUmVmbGVjdC5hcHBseSguLi4pXG4gKiAgIGFsdCBQcm9taXNlIHJlc3VsdFxuICogICAgIE1ldGhvZC0tPj5EZWNvcmF0b3I6IFByb21pc2VcbiAqICAgICBEZWNvcmF0b3ItPj5EZWNvcmF0b3I6IGF0dGFjaCB0aGVuKClcbiAqICAgICBEZWNvcmF0b3ItPj5EZWNvcmF0b3I6IGxvZyBjb21wbGV0aW9uIGR1cmF0aW9uXG4gKiAgIGVsc2UgU3luY2hyb25vdXMgcmVzdWx0XG4gKiAgICAgTWV0aG9kLS0+PkRlY29yYXRvcjogdmFsdWVcbiAqICAgICBEZWNvcmF0b3ItPj5EZWNvcmF0b3I6IGxvZyBjb21wbGV0aW9uIGR1cmF0aW9uXG4gKiAgIGVuZFxuICogICBEZWNvcmF0b3ItLT4+Q2FsbGVyOiByZXR1cm4gcmVzdWx0XG4gKiBAY2F0ZWdvcnkgTWV0aG9kIERlY29yYXRvcnNcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGJlbmNobWFyaygpIHtcbiAgcmV0dXJuIGZ1bmN0aW9uIGJlbmNobWFyayh0YXJnZXQ6IGFueSwgcHJvcGVydHlLZXk/OiBhbnksIGRlc2NyaXB0b3I/OiBhbnkpIHtcbiAgICBpZiAoIWRlc2NyaXB0b3IgfHwgdHlwZW9mIGRlc2NyaXB0b3IgPT09IFwibnVtYmVyXCIpXG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYGJlbmNobWFyayBkZWNvcmF0aW9uIG9ubHkgYXBwbGllcyB0byBtZXRob2RzYCk7XG4gICAgY29uc3QgbG9nZ2VyOiBMb2dnZXIgPVxuICAgICAgdGFyZ2V0IGluc3RhbmNlb2YgTG9nZ2VkQ2xhc3NcbiAgICAgICAgPyB0YXJnZXRbXCJsb2dcIl0uZm9yKHRhcmdldFtwcm9wZXJ0eUtleSBhcyBrZXlvZiB0eXBlb2YgdGFyZ2V0XSlcbiAgICAgICAgOiBMb2dnaW5nLmZvcih0YXJnZXQpLmZvcih0YXJnZXRbcHJvcGVydHlLZXldKTtcbiAgICBjb25zdCBvcmlnaW5hbE1ldGhvZCA9IGRlc2NyaXB0b3IudmFsdWU7XG5cbiAgICBkZXNjcmlwdG9yLnZhbHVlID0gbmV3IFByb3h5KG9yaWdpbmFsTWV0aG9kLCB7XG4gICAgICBhcHBseShmbiwgdGhpc0FyZywgYXJnczogYW55W10pIHtcbiAgICAgICAgY29uc3Qgc3RhcnQgPSBub3coKTtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICBjb25zdCByZXN1bHQgPSBSZWZsZWN0LmFwcGx5KGZuLCB0aGlzQXJnLCBhcmdzKTtcbiAgICAgICAgICBpZiAocmVzdWx0IGluc3RhbmNlb2YgUHJvbWlzZSkge1xuICAgICAgICAgICAgcmV0dXJuIHJlc3VsdFxuICAgICAgICAgICAgICAudGhlbigocjogYW55KSA9PiB7XG4gICAgICAgICAgICAgICAgbG9nZ2VyLmJlbmNobWFyayhgY29tcGxldGVkIGluICR7bm93KCkgLSBzdGFydH1tc2ApO1xuICAgICAgICAgICAgICAgIHJldHVybiByO1xuICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgICAuY2F0Y2goKGUpID0+IHtcbiAgICAgICAgICAgICAgICBsb2dnZXIuYmVuY2htYXJrKGBmYWlsZWQgaW4gJHtub3coKSAtIHN0YXJ0fW1zYCk7XG4gICAgICAgICAgICAgICAgdGhyb3cgZTtcbiAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfVxuICAgICAgICAgIGxvZ2dlci5iZW5jaG1hcmsoYGNvbXBsZXRlZCBpbiAke25vdygpIC0gc3RhcnR9bXNgKTtcbiAgICAgICAgICByZXR1cm4gcmVzdWx0O1xuICAgICAgICB9IGNhdGNoIChlcnI6IHVua25vd24pIHtcbiAgICAgICAgICBsb2dnZXIuYmVuY2htYXJrKGBmYWlsZWQgaW4gJHtub3coKSAtIHN0YXJ0fW1zYCk7XG4gICAgICAgICAgdGhyb3cgZXJyO1xuICAgICAgICB9XG4gICAgICB9LFxuICAgIH0pO1xuXG4gICAgcmV0dXJuIGRlc2NyaXB0b3I7XG4gIH07XG59XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIE1ldGhvZCBkZWNvcmF0b3IgZm9yIGxvZ2dpbmcgZnVuY3Rpb24gY2FsbHMgd2l0aCBkZWJ1ZyBsZXZlbC5cbiAqIEBzdW1tYXJ5IENvbnZlbmllbmNlIHdyYXBwZXIgYXJvdW5kIHtAbGluayBsb2d9IHRoYXQgbG9ncyB1c2luZyBgTG9nTGV2ZWwuZGVidWdgLlxuICogQHJldHVybiB7ZnVuY3Rpb24oYW55LCBhbnksIFByb3BlcnR5RGVzY3JpcHRvcik6IHZvaWR9IERlYnVnLWxldmVsIGxvZ2dpbmcgZGVjb3JhdG9yLlxuICogQGZ1bmN0aW9uIGRlYnVnXG4gKiBAY2F0ZWdvcnkgTWV0aG9kIERlY29yYXRvcnNcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGRlYnVnKCkge1xuICByZXR1cm4gbG9nKFxuICAgIExvZ0xldmVsLmRlYnVnLFxuICAgIDAsXG4gICAgKC4uLmFyZ3M6IGFueVtdKSA9PiBgY2FsbGVkIHdpdGggJHthcmdzfWAsXG4gICAgKGU/OiBFcnJvciwgcmVzdWx0PzogYW55KSA9PlxuICAgICAgZVxuICAgICAgICA/IGBGYWlsZWQgd2l0aDogJHtlfWBcbiAgICAgICAgOiByZXN1bHRcbiAgICAgICAgICA/IGBDb21wbGV0ZWQgd2l0aCAke0pTT04uc3RyaW5naWZ5KHJlc3VsdCl9YFxuICAgICAgICAgIDogXCJjb21wbGV0ZWRcIlxuICApO1xufVxuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBNZXRob2QgZGVjb3JhdG9yIGZvciBsb2dnaW5nIGZ1bmN0aW9uIGNhbGxzIHdpdGggaW5mbyBsZXZlbC5cbiAqIEBzdW1tYXJ5IENvbnZlbmllbmNlIHdyYXBwZXIgYXJvdW5kIHtAbGluayBsb2d9IHRoYXQgbG9ncyB1c2luZyBgTG9nTGV2ZWwuaW5mb2AuXG4gKiBAcmV0dXJuIHtmdW5jdGlvbihhbnksIGFueSwgUHJvcGVydHlEZXNjcmlwdG9yKTogdm9pZH0gSW5mby1sZXZlbCBsb2dnaW5nIGRlY29yYXRvci5cbiAqIEBmdW5jdGlvbiBpbmZvXG4gKiBAY2F0ZWdvcnkgTWV0aG9kIERlY29yYXRvcnNcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGluZm8oKSB7XG4gIHJldHVybiBsb2coTG9nTGV2ZWwuaW5mbyk7XG59XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIE1ldGhvZCBkZWNvcmF0b3IgZm9yIGxvZ2dpbmcgZnVuY3Rpb24gY2FsbHMgd2l0aCBzaWxseSBsZXZlbC5cbiAqIEBzdW1tYXJ5IENvbnZlbmllbmNlIHdyYXBwZXIgYXJvdW5kIHtAbGluayBsb2d9IHRoYXQgbG9ncyB1c2luZyBgTG9nTGV2ZWwuc2lsbHlgLlxuICogQHJldHVybiB7ZnVuY3Rpb24oYW55LCBhbnksIFByb3BlcnR5RGVzY3JpcHRvcik6IHZvaWR9IFNpbGx5LWxldmVsIGxvZ2dpbmcgZGVjb3JhdG9yLlxuICogQGZ1bmN0aW9uIHNpbGx5XG4gKiBAY2F0ZWdvcnkgTWV0aG9kIERlY29yYXRvcnNcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHNpbGx5KCkge1xuICByZXR1cm4gbG9nKExvZ0xldmVsLnNpbGx5KTtcbn1cblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gTWV0aG9kIGRlY29yYXRvciBmb3IgbG9nZ2luZyBmdW5jdGlvbiBjYWxscyB3aXRoIHRyYWNlIGxldmVsLlxuICogQHN1bW1hcnkgQ29udmVuaWVuY2Ugd3JhcHBlciBhcm91bmQge0BsaW5rIGxvZ30gdGhhdCBsb2dzIHVzaW5nIGBMb2dMZXZlbC50cmFjZWAuXG4gKiBAcmV0dXJuIHtmdW5jdGlvbihhbnksIGFueSwgUHJvcGVydHlEZXNjcmlwdG9yKTogdm9pZH0gVHJhY2UtbGV2ZWwgbG9nZ2luZyBkZWNvcmF0b3IuXG4gKiBAZnVuY3Rpb24gdHJhY2VcbiAqIEBjYXRlZ29yeSBNZXRob2QgRGVjb3JhdG9yc1xuICovXG5leHBvcnQgZnVuY3Rpb24gdHJhY2UoKSB7XG4gIHJldHVybiBsb2coTG9nTGV2ZWwudHJhY2UpO1xufVxuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBNZXRob2QgZGVjb3JhdG9yIGZvciBsb2dnaW5nIGZ1bmN0aW9uIGNhbGxzIHdpdGggdmVyYm9zZSBsZXZlbC5cbiAqIEBzdW1tYXJ5IENvbnZlbmllbmNlIHdyYXBwZXIgYXJvdW5kIHtAbGluayBsb2d9IHRoYXQgbG9ncyB1c2luZyBgTG9nTGV2ZWwudmVyYm9zZWAgd2l0aCBjb25maWd1cmFibGUgdmVyYm9zaXR5LlxuICogQHJldHVybiB7ZnVuY3Rpb24oYW55LCBhbnksIFByb3BlcnR5RGVzY3JpcHRvcik6IHZvaWR9IFZlcmJvc2UgbG9nZ2luZyBkZWNvcmF0b3IuXG4gKiBAZnVuY3Rpb24gdmVyYm9zZVxuICogQGNhdGVnb3J5IE1ldGhvZCBEZWNvcmF0b3JzXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiB2ZXJib3NlKCk6IChcbiAgdGFyZ2V0OiBhbnksXG4gIHByb3BlcnR5S2V5PzogYW55LFxuICBkZXNjcmlwdG9yPzogYW55XG4pID0+IHZvaWQ7XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIE1ldGhvZCBkZWNvcmF0b3IgZm9yIGxvZ2dpbmcgZnVuY3Rpb24gY2FsbHMgd2l0aCB2ZXJib3NlIGxldmVsLlxuICogQHN1bW1hcnkgQ29udmVuaWVuY2Ugd3JhcHBlciBhcm91bmQge0BsaW5rIGxvZ30gdGhhdCBsb2dzIHVzaW5nIGBMb2dMZXZlbC52ZXJib3NlYCB3aGlsZSB0b2dnbGluZyBiZW5jaG1hcmtpbmcuXG4gKiBAcmV0dXJuIHtmdW5jdGlvbihhbnksIFByb3BlcnR5RGVzY3JpcHRvcik6IHZvaWR9IFZlcmJvc2UgbG9nZ2luZyBkZWNvcmF0b3IuXG4gKiBAZnVuY3Rpb24gdmVyYm9zZVxuICogQGNhdGVnb3J5IE1ldGhvZCBEZWNvcmF0b3JzXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiB2ZXJib3NlKCk6IChcbiAgdGFyZ2V0OiBhbnksXG4gIHByb3BlcnR5S2V5PzogYW55LFxuICBkZXNjcmlwdG9yPzogYW55XG4pID0+IHZvaWQ7XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIE1ldGhvZCBkZWNvcmF0b3IgZm9yIGxvZ2dpbmcgZnVuY3Rpb24gY2FsbHMgd2l0aCB2ZXJib3NlIGxldmVsLlxuICogQHN1bW1hcnkgQ29udmVuaWVuY2Ugd3JhcHBlciBhcm91bmQge0BsaW5rIGxvZ30gdGhhdCBsb2dzIHVzaW5nIGBMb2dMZXZlbC52ZXJib3NlYCB3aXRoIGNvbmZpZ3VyYWJsZSB2ZXJib3NpdHkgYW5kIG9wdGlvbmFsIGJlbmNobWFya2luZy5cbiAqIEBwYXJhbSB7bnVtYmVyfGJvb2xlYW59IHZlcmJvc2l0eSAtIFZlcmJvc2l0eSBsZXZlbCBmb3IgbG9nIGZpbHRlcmluZyBvciBmbGFnIHRvIGVuYWJsZSBiZW5jaG1hcmtpbmcuXG4gKiBAcmV0dXJuIHtmdW5jdGlvbihhbnksIGFueSxQcm9wZXJ0eURlc2NyaXB0b3IpOiB2b2lkfSBWZXJib3NlIGxvZ2dpbmcgZGVjb3JhdG9yLlxuICogQGZ1bmN0aW9uIHZlcmJvc2VcbiAqIEBjYXRlZ29yeSBNZXRob2QgRGVjb3JhdG9yc1xuICovXG5leHBvcnQgZnVuY3Rpb24gdmVyYm9zZSh2ZXJib3NpdHk6IG51bWJlciB8IGJvb2xlYW4gPSAwKSB7XG4gIGlmICghdmVyYm9zaXR5KSB7XG4gICAgdmVyYm9zaXR5ID0gMDtcbiAgfVxuICByZXR1cm4gbG9nKExvZ0xldmVsLnZlcmJvc2UsIHZlcmJvc2l0eSBhcyBudW1iZXIpO1xufVxuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBDcmVhdGVzIGEgZGVjb3JhdG9yIHRoYXQgbWFrZXMgYSBtZXRob2Qgbm9uLWNvbmZpZ3VyYWJsZS5cbiAqIEBzdW1tYXJ5IFByZXZlbnRzIG92ZXJyaWRpbmcgYnkgbWFya2luZyB0aGUgbWV0aG9kIGRlc2NyaXB0b3IgYXMgbm9uLWNvbmZpZ3VyYWJsZSwgdGhyb3dpbmcgaWYgYXBwbGllZCB0byBub24tbWV0aG9kIHRhcmdldHMuXG4gKiBAcmV0dXJuIHtmdW5jdGlvbihvYmplY3QsIGFueSwgUHJvcGVydHlEZXNjcmlwdG9yKTogUHJvcGVydHlEZXNjcmlwdG9yfHVuZGVmaW5lZH0gRGVjb3JhdG9yIHRoYXQgaGFyZGVucyB0aGUgbWV0aG9kIGRlc2NyaXB0b3IuXG4gKiBAZnVuY3Rpb24gZmluYWxcbiAqIEBjYXRlZ29yeSBNZXRob2QgRGVjb3JhdG9yc1xuICovXG5leHBvcnQgZnVuY3Rpb24gZmluYWwoKSB7XG4gIHJldHVybiAodGFyZ2V0OiBvYmplY3QsIHByb3BlcnR5S2V5PzogYW55LCBkZXNjcmlwdG9yPzogYW55KSA9PiB7XG4gICAgaWYgKCFkZXNjcmlwdG9yKVxuICAgICAgdGhyb3cgbmV3IEVycm9yKFwiZmluYWwgZGVjb3JhdG9yIGNhbiBvbmx5IGJlIHVzZWQgb24gbWV0aG9kc1wiKTtcbiAgICBpZiAoZGVzY3JpcHRvcj8uY29uZmlndXJhYmxlKSB7XG4gICAgICBkZXNjcmlwdG9yLmNvbmZpZ3VyYWJsZSA9IGZhbHNlO1xuICAgIH1cbiAgICByZXR1cm4gZGVzY3JpcHRvcjtcbiAgfTtcbn1cbiIsImltcG9ydCB7IExvZ0ZpbHRlciB9IGZyb20gXCIuL0xvZ0ZpbHRlclwiO1xuaW1wb3J0IHsgTG9nZ2luZ0NvbmZpZyB9IGZyb20gXCIuLi90eXBlc1wiO1xuaW1wb3J0IHsgZmluYWwgfSBmcm9tIFwiLi4vZGVjb3JhdG9yc1wiO1xuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBSZXBsYWNlbWVudCBjYWxsYmFjayB1c2VkIHRvIHRyYW5zZm9ybSBSZWdFeHAgbWF0Y2hlcy5cbiAqIEBzdW1tYXJ5IFJlY2VpdmVzIHRoZSBtYXRjaGVkIHN1YnN0cmluZyBhbmQgYWRkaXRpb25hbCBjYXB0dXJlIGFyZ3VtZW50cywgcmV0dXJuaW5nIHRoZSByZXBsYWNlbWVudCB0ZXh0IHRoYXQgd2lsbCBiZSBpbmplY3RlZCBpbnRvIHRoZSBsb2cgbWVzc2FnZS5cbiAqIEB0eXBlZGVmIHtmdW5jdGlvbihzdHJpbmcsIGFueVtdKTogc3RyaW5nfSBSZXBsYWNlbWVudEZ1bmN0aW9uXG4gKiBAbWVtYmVyT2YgbW9kdWxlOkxvZ2dpbmdcbiAqL1xuZXhwb3J0IHR5cGUgUmVwbGFjZW1lbnRGdW5jdGlvbiA9IChzdWJzdHJpbmc6IHN0cmluZywgLi4uYXJnczogYW55W10pID0+IHN0cmluZztcblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gRmlsdGVyIHRoYXQgcGF0Y2hlcyBsb2cgbWVzc2FnZXMgdXNpbmcgcmVndWxhciBleHByZXNzaW9ucy5cbiAqIEBzdW1tYXJ5IEFwcGxpZXMgYSBjb25maWd1cmVkIHtAbGluayBSZWdFeHB9IGFuZCByZXBsYWNlbWVudCBzdHJhdGVneSB0byByZWRhY3QsIG1hc2ssIG9yIHJlc3RydWN0dXJlIGxvZyBwYXlsb2FkcyBiZWZvcmUgdGhleSBhcmUgZW1pdHRlZC5cbiAqIEBwYXJhbSB7UmVnRXhwfSByZWdleHAgLSBFeHByZXNzaW9uIHVzZWQgdG8gZGV0ZWN0IHNlbnNpdGl2ZSBvciBmb3JtYXR0ZWQgdGV4dC5cbiAqIEBwYXJhbSB7c3RyaW5nfFJlcGxhY2VtZW50RnVuY3Rpb259IHJlcGxhY2VtZW50IC0gUmVwbGFjZW1lbnQgc3RyaW5nIG9yIGNhbGxiYWNrIGludm9rZWQgZm9yIGVhY2ggbWF0Y2guXG4gKiBAY2xhc3MgUGF0dGVybkZpbHRlclxuICogQGV4YW1wbGVcbiAqIGNvbnN0IGZpbHRlciA9IG5ldyBQYXR0ZXJuRmlsdGVyKC90b2tlbj1bXiZdKy9nLCBcInRva2VuPSoqKlwiKTtcbiAqIGNvbnN0IHNhbml0aXplZCA9IGZpbHRlci5maWx0ZXIoY29uZmlnLCBcInRva2VuPTEyMyZ1c2VyPXRvbVwiLCBbXSk7XG4gKiAvLyBzYW5pdGl6ZWQgPT09IFwidG9rZW49KioqJnVzZXI9dG9tXCJcbiAqIEBtZXJtYWlkXG4gKiBzZXF1ZW5jZURpYWdyYW1cbiAqICAgcGFydGljaXBhbnQgTG9nZ2VyXG4gKiAgIHBhcnRpY2lwYW50IEZpbHRlciBhcyBQYXR0ZXJuRmlsdGVyXG4gKiAgIHBhcnRpY2lwYW50IFJlZ0V4cFxuICogICBMb2dnZXItPj5GaWx0ZXI6IGZpbHRlcihjb25maWcsIG1lc3NhZ2UsIGNvbnRleHQpXG4gKiAgIEZpbHRlci0+PlJlZ0V4cDogZXhlY3V0ZSBtYXRjaCgpXG4gKiAgIGFsdCBtYXRjaCBmb3VuZFxuICogICAgIFJlZ0V4cC0tPj5GaWx0ZXI6IGNhcHR1cmVzXG4gKiAgICAgRmlsdGVyLT4+UmVnRXhwOiByZXBsYWNlKG1lc3NhZ2UsIHJlcGxhY2VtZW50KVxuICogICAgIFJlZ0V4cC0tPj5GaWx0ZXI6IHRyYW5zZm9ybWVkIG1lc3NhZ2VcbiAqICAgZWxzZSBubyBtYXRjaFxuICogICAgIFJlZ0V4cC0tPj5GaWx0ZXI6IG51bGxcbiAqICAgZW5kXG4gKiAgIEZpbHRlci0tPj5Mb2dnZXI6IHNhbml0aXplZCBtZXNzYWdlXG4gKi9cbmV4cG9ydCBjbGFzcyBQYXR0ZXJuRmlsdGVyIGV4dGVuZHMgTG9nRmlsdGVyIHtcbiAgY29uc3RydWN0b3IoXG4gICAgcHJvdGVjdGVkIHJlYWRvbmx5IHJlZ2V4cDogUmVnRXhwLFxuICAgIHByb3RlY3RlZCByZWFkb25seSByZXBsYWNlbWVudDogc3RyaW5nIHwgUmVwbGFjZW1lbnRGdW5jdGlvblxuICApIHtcbiAgICBzdXBlcigpO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBFbnN1cmVzIGRldGVybWluaXN0aWMgUmVnRXhwIG1hdGNoaW5nLlxuICAgKiBAc3VtbWFyeSBSdW5zIHRoZSBjb25maWd1cmVkIGV4cHJlc3Npb24sIHRoZW4gcmVzZXRzIGl0cyBzdGF0ZSBzbyByZXBlYXRlZCBpbnZvY2F0aW9ucyBiZWhhdmUgY29uc2lzdGVudGx5LlxuICAgKiBAcGFyYW0ge3N0cmluZ30gbWVzc2FnZSAtIE1lc3NhZ2UgdG8gdGVzdCBmb3IgbWF0Y2hlcy5cbiAgICogQHJldHVybiB7UmVnRXhwRXhlY0FycmF5fG51bGx9IE1hdGNoIHJlc3VsdCBvciBudWxsIHdoZW4gbm8gbWF0Y2ggaXMgZm91bmQuXG4gICAqL1xuICBAZmluYWwoKVxuICBwcm90ZWN0ZWQgbWF0Y2gobWVzc2FnZTogc3RyaW5nKSB7XG4gICAgY29uc3QgbWF0Y2ggPSB0aGlzLnJlZ2V4cC5leGVjKG1lc3NhZ2UpO1xuICAgIHRoaXMucmVnZXhwLmxhc3RJbmRleCA9IDA7XG4gICAgcmV0dXJuIG1hdGNoO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBBcHBsaWVzIHRoZSByZXBsYWNlbWVudCBzdHJhdGVneSB0byB0aGUgaW5jb21pbmcgbWVzc2FnZS5cbiAgICogQHN1bW1hcnkgRXhlY3V0ZXMge0BsaW5rIFBhdHRlcm5GaWx0ZXIubWF0Y2h9IGFuZCwgd2hlbiBhIG1hdGNoIGlzIGZvdW5kLCByZXBsYWNlcyBldmVyeSBvY2N1cnJlbmNlIHVzaW5nIHRoZSBjb25maWd1cmVkIHJlcGxhY2VtZW50IGhhbmRsZXIuXG4gICAqIEBwYXJhbSB7TG9nZ2luZ0NvbmZpZ30gY29uZmlnIC0gQWN0aXZlIGxvZ2dpbmcgY29uZmlndXJhdGlvbiAodW51c2VkIGJ1dCBwYXJ0IG9mIHRoZSBmaWx0ZXIgY29udHJhY3QpLlxuICAgKiBAcGFyYW0ge3N0cmluZ30gbWVzc2FnZSAtIE1lc3NhZ2UgdG8gYmUgc2FuaXRpemVkLlxuICAgKiBAcGFyYW0ge3N0cmluZ1tdfSBjb250ZXh0IC0gQ29udGV4dCBlbnRyaWVzIGFzc29jaWF0ZWQgd2l0aCB0aGUgbG9nIGV2ZW50LlxuICAgKiBAcmV0dXJuIHtzdHJpbmd9IFNhbml0aXplZCBsb2cgbWVzc2FnZS5cbiAgICovXG4gIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tdW51c2VkLXZhcnNcbiAgZmlsdGVyKGNvbmZpZzogTG9nZ2luZ0NvbmZpZywgbWVzc2FnZTogc3RyaW5nLCBjb250ZXh0OiBzdHJpbmdbXSk6IHN0cmluZyB7XG4gICAgY29uc3QgbG9nID0gdGhpcy5sb2cuZm9yKHRoaXMuZmlsdGVyKTtcbiAgICBjb25zdCBtYXRjaCA9IHRoaXMubWF0Y2gobWVzc2FnZSk7XG4gICAgaWYgKCFtYXRjaCkgcmV0dXJuIG1lc3NhZ2U7XG4gICAgdHJ5IHtcbiAgICAgIHJldHVybiBtZXNzYWdlLnJlcGxhY2UodGhpcy5yZWdleHAsIHRoaXMucmVwbGFjZW1lbnQgYXMgYW55KTtcbiAgICB9IGNhdGNoIChlOiB1bmtub3duKSB7XG4gICAgICBsb2cuZXJyb3IoYFBhdHRlcm5GaWx0ZXIgcmVwbGFjZW1lbnQgZXJyb3I6ICR7ZX1gKTtcbiAgICB9XG4gICAgcmV0dXJuIFwiXCI7XG4gIH1cbn1cbiIsImV4cG9ydCBmdW5jdGlvbiBpc0NsYXNzKFxuICB2YWx1ZTogdW5rbm93blxuKTogdmFsdWUgaXMgYWJzdHJhY3QgbmV3ICguLi5hcmdzOiBhbnlbXSkgPT4gYW55IHtcbiAgaWYgKHR5cGVvZiB2YWx1ZSAhPT0gXCJmdW5jdGlvblwiKSByZXR1cm4gZmFsc2U7XG5cbiAgLy8gMSkgTmF0aXZlIEVTIGNsYXNzPyAoZmFzdCBwYXRoKVxuICAvLyBlLmcuLCBcImNsYXNzIEZvbyB7IC4uLiB9XCIg4oaSIHNvdXJjZSBzdGFydHMgd2l0aCBcImNsYXNzXCJcbiAgdHJ5IHtcbiAgICBjb25zdCBzcmMgPSBGdW5jdGlvbi5wcm90b3R5cGUudG9TdHJpbmcuY2FsbCh2YWx1ZSk7XG4gICAgaWYgKC9eXFxzKmNsYXNzW1xcc3tdLy50ZXN0KHNyYykpIHJldHVybiB0cnVlO1xuICB9IGNhdGNoIHtcbiAgICAvLyBTb21lIGVudmlyb25tZW50cyBtYXkgYmxvY2sgLnRvU3RyaW5nOyBpZ25vcmUgYW5kIGNvbnRpbnVlLlxuICB9XG5cbiAgLy8gMikgSGFzIGEgcHJvdG90eXBlIGF0IGFsbD8gKGZpbHRlcnMgb3V0IGFycm93IGZ1bmNzLCBib3VuZCBmdW5jcylcbiAgY29uc3QgcHJvdG9EZXNjID0gT2JqZWN0LmdldE93blByb3BlcnR5RGVzY3JpcHRvcih2YWx1ZSwgXCJwcm90b3R5cGVcIik7XG4gIGlmICghcHJvdG9EZXNjIHx8ICFwcm90b0Rlc2MudmFsdWUpIHJldHVybiBmYWxzZTtcblxuICAvLyAzKSBJbiBuYXRpdmUgY2xhc3NlcywgdGhlIFwicHJvdG90eXBlXCIgcHJvcGVydHkgaXMgbm9uLXdyaXRhYmxlLlxuICAvLyAoSW4gcGxhaW4gZnVuY3Rpb25zLCBpdCdzIHdyaXRhYmxlLikgVGhpcyBpcyBhIHN0cm9uZyBzaWduYWwuXG4gIGlmIChwcm90b0Rlc2Mud3JpdGFibGUgPT09IGZhbHNlKSByZXR1cm4gdHJ1ZTtcblxuICAvLyA0KSBDbGFzc2ljIGNvbnN0cnVjdG9yIG9yIHRyYW5zcGlsZWQgY2xhc3M6XG4gIC8vIE11c3QgaGF2ZSBpdHMgb3duIFwiY29uc3RydWN0b3JcIiBhbmQgYXQgbGVhc3Qgb25lIHByb3RvdHlwZSBtZXRob2QuXG4gIGNvbnN0IHByb3RvID0gKHZhbHVlIGFzIGFueSkucHJvdG90eXBlO1xuICBpZiAoIU9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChwcm90bywgXCJjb25zdHJ1Y3RvclwiKSkgcmV0dXJuIGZhbHNlO1xuXG4gIGNvbnN0IG5hbWVzID0gT2JqZWN0LmdldE93blByb3BlcnR5TmFtZXMocHJvdG8pLmZpbHRlcihcbiAgICAobikgPT4gbiAhPT0gXCJjb25zdHJ1Y3RvclwiXG4gICk7XG4gIHJldHVybiBuYW1lcy5sZW5ndGggPiAwO1xufVxuIiwiZXhwb3J0ICogZnJvbSBcIi4vZmlsdGVyc1wiO1xuZXhwb3J0ICogZnJvbSBcIi4vY29uc3RhbnRzXCI7XG5leHBvcnQgKiBmcm9tIFwiLi9kZWNvcmF0b3JzXCI7XG5leHBvcnQgKiBmcm9tIFwiLi9lbnZpcm9ubWVudFwiO1xuZXhwb3J0ICogZnJvbSBcIi4vTG9nZ2VkQ2xhc3NcIjtcbmV4cG9ydCAqIGZyb20gXCIuL2xvZ2dpbmdcIjtcbmV4cG9ydCAqIGZyb20gXCIuL3RleHRcIjtcbmV4cG9ydCAqIGZyb20gXCIuL3RpbWVcIjtcbmV4cG9ydCAqIGZyb20gXCIuL3R5cGVzXCI7XG5leHBvcnQgKiBmcm9tIFwiLi93ZWJcIjtcbmV4cG9ydCAqIGZyb20gXCIuL3V0aWxzXCI7XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIENvbXByZWhlbnNpdmUgbG9nZ2luZyB0b29sa2l0IGZvciBicm93c2VyIGFuZCBOb2RlIGVudmlyb25tZW50cy5cbiAqIEBzdW1tYXJ5IEV4cG9zZXMge0BsaW5rIExvZ2dpbmd9IGFuZCB7QGxpbmsgTWluaUxvZ2dlcn0gZm9yIHJ1bnRpbWUgbG9nZ2luZywgZGVjb3JhdG9ycyBzdWNoIGFzIHtAbGluayBsb2d9IGZvciBtZXRob2QgaW5zdHJ1bWVudGF0aW9uLCBhbmQgdXRpbGl0aWVzIGxpa2Uge0BsaW5rIFBhdHRlcm5GaWx0ZXJ9LCB7QGxpbmsgU3RvcFdhdGNofSwgYW5kIHtAbGluayBMb2dnZWRFbnZpcm9ubWVudH0gdG8gYnVpbGQgY29uZmlndXJhYmxlLCB0aGVtZS1hd2FyZSBsb2cgcGlwZWxpbmVzLlxuICogQG1vZHVsZSBMb2dnaW5nXG4gKi9cblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gQ3VycmVudCBwYWNrYWdlIHZlcnNpb24gc3RyaW5nLlxuICogQHN1bW1hcnkgU3RvcmVzIHRoZSBwYWNrYWdlIHZlcnNpb24gZm9yIGRpYWdub3N0aWNzIGFuZCBjb21wYXRpYmlsaXR5IGNoZWNrcy5cbiAqIEBjb25zdCBWRVJTSU9OXG4gKiBAdHlwZSB7c3RyaW5nfVxuICogQG1lbWJlck9mIG1vZHVsZTpMb2dnaW5nXG4gKi9cbmV4cG9ydCBjb25zdCBWRVJTSU9OOiBzdHJpbmcgPSBcIiMjVkVSU0lPTiMjXCI7XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIEN1cnJlbnQgcGFja2FnZSB2ZXJzaW9uIHN0cmluZy5cbiAqIEBzdW1tYXJ5IFN0b3JlcyB0aGUgcGFja2FnZSB2ZXJzaW9uIGZvciBkaWFnbm9zdGljcyBhbmQgY29tcGF0aWJpbGl0eSBjaGVja3MuXG4gKiBAY29uc3QgUEFDS0FHRV9OQU1FXG4gKiBAdHlwZSB7c3RyaW5nfVxuICogQG1lbWJlck9mIG1vZHVsZTpMb2dnaW5nXG4gKi9cbmV4cG9ydCBjb25zdCBQQUNLQUdFX05BTUU6IHN0cmluZyA9IFwiIyNQQUNLQUdFIyNcIjtcbiJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7O0FBRUE7Ozs7OztBQU1HO0FBQ0ksTUFBTSxhQUFhLEdBQUcsTUFBTTtBQUVuQzs7Ozs7O0FBTUc7QUFDSSxNQUFNLGtCQUFrQixHQUFHLEtBQUs7QUFFdkM7Ozs7OztBQU1HO01BQ1UsMEJBQTBCLEdBQUcsQ0FBQyxJQUFJLEVBQUUsR0FBRyxFQUFFO0FBRXREOzs7Ozs7QUFNRztJQUNTLFNBaUJYO0FBakJELENBQUEsVUFBWSxRQUFRLEVBQUE7O0FBRWxCLElBQUEsUUFBQSxDQUFBLFdBQUEsQ0FBQSxHQUFBLFdBQXVCLENBQUE7O0FBRXZCLElBQUEsUUFBQSxDQUFBLE9BQUEsQ0FBQSxHQUFBLE9BQWUsQ0FBQTs7QUFFZixJQUFBLFFBQUEsQ0FBQSxNQUFBLENBQUEsR0FBQSxNQUFhLENBQUE7O0FBRWIsSUFBQSxRQUFBLENBQUEsTUFBQSxDQUFBLEdBQUEsTUFBYSxDQUFBOztBQUViLElBQUEsUUFBQSxDQUFBLFNBQUEsQ0FBQSxHQUFBLFNBQW1CLENBQUE7O0FBRW5CLElBQUEsUUFBQSxDQUFBLE9BQUEsQ0FBQSxHQUFBLE9BQWUsQ0FBQTs7QUFFZixJQUFBLFFBQUEsQ0FBQSxPQUFBLENBQUEs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