@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.
- package/README.md +1 -1
- package/dist/logging.cjs +2 -2086
- package/dist/logging.cjs.map +1 -0
- package/dist/logging.js +2 -0
- package/dist/logging.js.map +1 -0
- package/lib/LoggedClass.cjs +1 -1
- package/lib/LoggedClass.js.map +1 -0
- package/lib/constants.cjs +1 -1
- package/lib/constants.js.map +1 -0
- package/lib/decorators.cjs +1 -1
- package/lib/decorators.js.map +1 -0
- package/lib/environment.cjs +1 -1
- package/lib/environment.js.map +1 -0
- package/lib/esm/LoggedClass.js +1 -1
- package/lib/esm/LoggedClass.js.map +1 -0
- package/lib/esm/constants.js +1 -1
- package/lib/esm/constants.js.map +1 -0
- package/lib/esm/decorators.js +1 -1
- package/lib/esm/decorators.js.map +1 -0
- package/lib/esm/environment.js +1 -1
- package/lib/esm/environment.js.map +1 -0
- package/lib/esm/filters/LogFilter.js +1 -1
- package/lib/esm/filters/LogFilter.js.map +1 -0
- package/lib/esm/filters/PatternFilter.js +1 -1
- package/lib/esm/filters/PatternFilter.js.map +1 -0
- package/lib/esm/filters/index.js +1 -1
- package/lib/esm/filters/index.js.map +1 -0
- package/lib/esm/index.js +3 -3
- package/lib/esm/index.js.map +1 -0
- package/lib/esm/logging.js +1 -1
- package/lib/esm/logging.js.map +1 -0
- package/lib/esm/text.js +1 -1
- package/lib/esm/text.js.map +1 -0
- package/lib/esm/time.js +1 -1
- package/lib/esm/time.js.map +1 -0
- package/lib/esm/types.js +1 -1
- package/lib/esm/types.js.map +1 -0
- package/lib/esm/utils.js +1 -1
- package/lib/esm/utils.js.map +1 -0
- package/lib/esm/web.js +1 -1
- package/lib/esm/web.js.map +1 -0
- package/lib/esm/winston/index.js +1 -1
- package/lib/esm/winston/index.js.map +1 -0
- package/lib/esm/winston/winston.js +1 -1
- package/lib/esm/winston/winston.js.map +1 -0
- package/lib/filters/LogFilter.cjs +1 -1
- package/lib/filters/LogFilter.js.map +1 -0
- package/lib/filters/PatternFilter.cjs +1 -1
- package/lib/filters/PatternFilter.js.map +1 -0
- package/lib/filters/index.cjs +1 -1
- package/lib/filters/index.js.map +1 -0
- package/lib/index.cjs +3 -3
- package/lib/index.js.map +1 -0
- package/lib/logging.cjs +1 -1
- package/lib/logging.js.map +1 -0
- package/lib/text.cjs +1 -1
- package/lib/text.js.map +1 -0
- package/lib/time.cjs +1 -1
- package/lib/time.js.map +1 -0
- package/lib/types.cjs +1 -1
- package/lib/types.js.map +1 -0
- package/lib/utils.cjs +1 -1
- package/lib/utils.js.map +1 -0
- package/lib/web.cjs +1 -1
- package/lib/web.js.map +1 -0
- package/lib/winston/index.cjs +1 -1
- package/lib/winston/index.js.map +1 -0
- package/lib/winston/winston.cjs +1 -1
- package/lib/winston/winston.js.map +1 -0
- package/package.json +1 -1
- package/dist/logging.esm.cjs +0 -2044
package/dist/logging.esm.cjs
DELETED
|
@@ -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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
|