UNPKG

45.3 kBJavaScriptView Raw
1"use strict";
2var _a, _b, _c;
3Object.defineProperty(exports, "__esModule", { value: true });
4exports.SpaceDelimitedTextPattern = exports.FilterPattern = exports.JsonPattern = void 0;
5const jsiiDeprecationWarnings = require("../.warnings.jsii.js");
6const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti");
7/**
8 * Base class for patterns that only match JSON log events.
9 */
10class JsonPattern {
11 // This is a separate class so we have some type safety where users can't
12 // combine text patterns and JSON patterns with an 'and' operation.
13 constructor(jsonPatternString) {
14 this.jsonPatternString = jsonPatternString;
15 }
16 get logPatternString() {
17 return '{ ' + this.jsonPatternString + ' }';
18 }
19}
20exports.JsonPattern = JsonPattern;
21_a = JSII_RTTI_SYMBOL_1;
22JsonPattern[_a] = { fqn: "@aws-cdk/aws-logs.JsonPattern", version: "1.156.1" };
23/**
24 * A collection of static methods to generate appropriate ILogPatterns
25 */
26class FilterPattern {
27 /**
28 * Use the given string as log pattern.
29 *
30 * See https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/FilterAndPatternSyntax.html
31 * for information on writing log patterns.
32 *
33 * @param logPatternString The pattern string to use.
34 */
35 static literal(logPatternString) {
36 return new LiteralLogPattern(logPatternString);
37 }
38 /**
39 * A log pattern that matches all events.
40 */
41 static allEvents() {
42 return new LiteralLogPattern('');
43 }
44 /**
45 * A log pattern that matches if all the strings given appear in the event.
46 *
47 * @param terms The words to search for. All terms must match.
48 */
49 static allTerms(...terms) {
50 return new TextLogPattern([terms]);
51 }
52 /**
53 * A log pattern that matches if any of the strings given appear in the event.
54 *
55 * @param terms The words to search for. Any terms must match.
56 */
57 static anyTerm(...terms) {
58 return new TextLogPattern(terms.map(t => [t]));
59 }
60 /**
61 * A log pattern that matches if any of the given term groups matches the event.
62 *
63 * A term group matches an event if all the terms in it appear in the event string.
64 *
65 * @param termGroups A list of term groups to search for. Any one of the clauses must match.
66 */
67 static anyTermGroup(...termGroups) {
68 return new TextLogPattern(termGroups);
69 }
70 /**
71 * A JSON log pattern that compares string values.
72 *
73 * This pattern only matches if the event is a JSON event, and the indicated field inside
74 * compares with the string value.
75 *
76 * Use '$' to indicate the root of the JSON structure. The comparison operator can only
77 * compare equality or inequality. The '*' wildcard may appear in the value may at the
78 * start or at the end.
79 *
80 * For more information, see:
81 *
82 * https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/FilterAndPatternSyntax.html
83 *
84 * @param jsonField Field inside JSON. Example: "$.myField"
85 * @param comparison Comparison to carry out. Either = or !=.
86 * @param value The string value to compare to. May use '*' as wildcard at start or end of string.
87 */
88 static stringValue(jsonField, comparison, value) {
89 return new JSONStringPattern(jsonField, comparison, value);
90 }
91 /**
92 * A JSON log pattern that compares numerical values.
93 *
94 * This pattern only matches if the event is a JSON event, and the indicated field inside
95 * compares with the value in the indicated way.
96 *
97 * Use '$' to indicate the root of the JSON structure. The comparison operator can only
98 * compare equality or inequality. The '*' wildcard may appear in the value may at the
99 * start or at the end.
100 *
101 * For more information, see:
102 *
103 * https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/FilterAndPatternSyntax.html
104 *
105 * @param jsonField Field inside JSON. Example: "$.myField"
106 * @param comparison Comparison to carry out. One of =, !=, <, <=, >, >=.
107 * @param value The numerical value to compare to
108 */
109 static numberValue(jsonField, comparison, value) {
110 return new JSONNumberPattern(jsonField, comparison, value);
111 }
112 /**
113 * A JSON log pattern that matches if the field exists and has the special value 'null'.
114 *
115 * @param jsonField Field inside JSON. Example: "$.myField"
116 */
117 static isNull(jsonField) {
118 return new JSONPostfixPattern(jsonField, 'IS NULL');
119 }
120 /**
121 * A JSON log pattern that matches if the field does not exist.
122 *
123 * @param jsonField Field inside JSON. Example: "$.myField"
124 */
125 static notExists(jsonField) {
126 return new JSONPostfixPattern(jsonField, 'NOT EXISTS');
127 }
128 /**
129 * A JSON log patter that matches if the field exists.
130 *
131 * This is a readable convenience wrapper over 'field = *'
132 *
133 * @param jsonField Field inside JSON. Example: "$.myField"
134 */
135 static exists(jsonField) {
136 return new JSONStringPattern(jsonField, '=', '*');
137 }
138 /**
139 * A JSON log pattern that matches if the field exists and equals the boolean value.
140 *
141 * @param jsonField Field inside JSON. Example: "$.myField"
142 * @param value The value to match
143 */
144 static booleanValue(jsonField, value) {
145 return new JSONPostfixPattern(jsonField, value ? 'IS TRUE' : 'IS FALSE');
146 }
147 /**
148 * A JSON log pattern that matches if all given JSON log patterns match
149 */
150 static all(...patterns) {
151 try {
152 jsiiDeprecationWarnings._aws_cdk_aws_logs_JsonPattern(patterns);
153 }
154 catch (error) {
155 if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
156 Error.captureStackTrace(error, this.all);
157 }
158 throw error;
159 }
160 if (patterns.length === 0) {
161 throw new Error('Must supply at least one pattern, or use allEvents() to match all events.');
162 }
163 if (patterns.length === 1) {
164 return patterns[0];
165 }
166 return new JSONAggregatePattern('&&', patterns);
167 }
168 /**
169 * A JSON log pattern that matches if any of the given JSON log patterns match
170 */
171 static any(...patterns) {
172 try {
173 jsiiDeprecationWarnings._aws_cdk_aws_logs_JsonPattern(patterns);
174 }
175 catch (error) {
176 if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
177 Error.captureStackTrace(error, this.any);
178 }
179 throw error;
180 }
181 if (patterns.length === 0) {
182 throw new Error('Must supply at least one pattern');
183 }
184 if (patterns.length === 1) {
185 return patterns[0];
186 }
187 return new JSONAggregatePattern('||', patterns);
188 }
189 /**
190 * A space delimited log pattern matcher.
191 *
192 * The log event is divided into space-delimited columns (optionally
193 * enclosed by "" or [] to capture spaces into column values), and names
194 * are given to each column.
195 *
196 * '...' may be specified once to match any number of columns.
197 *
198 * Afterwards, conditions may be added to individual columns.
199 *
200 * @param columns The columns in the space-delimited log stream.
201 */
202 static spaceDelimited(...columns) {
203 return SpaceDelimitedTextPattern.construct(columns);
204 }
205}
206exports.FilterPattern = FilterPattern;
207_b = JSII_RTTI_SYMBOL_1;
208FilterPattern[_b] = { fqn: "@aws-cdk/aws-logs.FilterPattern", version: "1.156.1" };
209/**
210 * Use a string literal as a log pattern
211 */
212class LiteralLogPattern {
213 constructor(logPatternString) {
214 this.logPatternString = logPatternString;
215 }
216}
217/**
218 * Search for a set of set of terms
219 */
220class TextLogPattern {
221 constructor(clauses) {
222 const quotedClauses = clauses.map(terms => terms.map(quoteTerm).join(' '));
223 if (quotedClauses.length === 1) {
224 this.logPatternString = quotedClauses[0];
225 }
226 else {
227 this.logPatternString = quotedClauses.map(alt => '?' + alt).join(' ');
228 }
229 }
230}
231/**
232 * A string comparison for JSON values
233 */
234class JSONStringPattern extends JsonPattern {
235 constructor(jsonField, comparison, value) {
236 comparison = validateStringOperator(comparison);
237 super(`${jsonField} ${comparison} ${quoteTerm(value)}`);
238 }
239}
240/**
241 * A number comparison for JSON values
242 */
243class JSONNumberPattern extends JsonPattern {
244 constructor(jsonField, comparison, value) {
245 comparison = validateNumericalOperator(comparison);
246 super(`${jsonField} ${comparison} ${value}`);
247 }
248}
249/**
250 * A postfix operator for JSON patterns
251 */
252class JSONPostfixPattern extends JsonPattern {
253 constructor(jsonField, postfix) {
254 // No validation, we assume these are generated by trusted factory functions
255 super(`${jsonField} ${postfix}`);
256 }
257}
258/**
259 * Combines multiple other JSON patterns with an operator
260 */
261class JSONAggregatePattern extends JsonPattern {
262 constructor(operator, patterns) {
263 if (operator !== '&&' && operator !== '||') {
264 throw new Error('Operator must be one of && or ||');
265 }
266 const clauses = patterns.map(p => '(' + p.jsonPatternString + ')');
267 super(clauses.join(` ${operator} `));
268 }
269}
270const COL_ELLIPSIS = '...';
271/**
272 * Space delimited text pattern
273 */
274class SpaceDelimitedTextPattern {
275 // TODO: Temporarily changed from private to protected to unblock build. We need to think
276 // about how to handle jsii types with private constructors.
277 constructor(columns, restrictions) {
278 this.columns = columns;
279 this.restrictions = restrictions;
280 }
281 /**
282 * Construct a new instance of a space delimited text pattern
283 *
284 * Since this class must be public, we can't rely on the user only creating it through
285 * the `LogPattern.spaceDelimited()` factory function. We must therefore validate the
286 * argument in the constructor. Since we're returning a copy on every mutation, and we
287 * don't want to re-validate the same things on every construction, we provide a limited
288 * set of mutator functions and only validate the new data every time.
289 */
290 static construct(columns) {
291 // Validation happens here because a user could instantiate this object directly without
292 // going through the factory
293 for (const column of columns) {
294 if (!validColumnName(column)) {
295 throw new Error(`Invalid column name: ${column}`);
296 }
297 }
298 if (sum(columns.map(c => c === COL_ELLIPSIS ? 1 : 0)) > 1) {
299 throw new Error("Can use at most one '...' column");
300 }
301 return new SpaceDelimitedTextPattern(columns, {});
302 }
303 /**
304 * Restrict where the pattern applies
305 */
306 whereString(columnName, comparison, value) {
307 if (columnName === COL_ELLIPSIS) {
308 throw new Error("Can't use '...' in a restriction");
309 }
310 if (this.columns.indexOf(columnName) === -1) {
311 throw new Error(`Column in restrictions that is not in columns: ${columnName}`);
312 }
313 comparison = validateStringOperator(comparison);
314 return new SpaceDelimitedTextPattern(this.columns, this.addRestriction(columnName, {
315 comparison,
316 stringValue: value,
317 }));
318 }
319 /**
320 * Restrict where the pattern applies
321 */
322 whereNumber(columnName, comparison, value) {
323 if (columnName === COL_ELLIPSIS) {
324 throw new Error("Can't use '...' in a restriction");
325 }
326 if (this.columns.indexOf(columnName) === -1) {
327 throw new Error(`Column in restrictions that is not in columns: ${columnName}`);
328 }
329 comparison = validateNumericalOperator(comparison);
330 return new SpaceDelimitedTextPattern(this.columns, this.addRestriction(columnName, {
331 comparison,
332 numberValue: value,
333 }));
334 }
335 get logPatternString() {
336 return '[' + this.columns.map(this.columnExpression.bind(this)).join(', ') + ']';
337 }
338 /**
339 * Return the column expression for the given column
340 */
341 columnExpression(column) {
342 const restrictions = this.restrictions[column];
343 if (!restrictions) {
344 return column;
345 }
346 return restrictions.map(r => renderRestriction(column, r)).join(' && ');
347 }
348 /**
349 * Make a copy of the current restrictions and add one
350 */
351 addRestriction(columnName, restriction) {
352 const ret = {};
353 for (const key of Object.keys(this.restrictions)) {
354 ret[key] = this.restrictions[key].slice();
355 }
356 if (!(columnName in ret)) {
357 ret[columnName] = [];
358 }
359 ret[columnName].push(restriction);
360 return ret;
361 }
362}
363exports.SpaceDelimitedTextPattern = SpaceDelimitedTextPattern;
364_c = JSII_RTTI_SYMBOL_1;
365SpaceDelimitedTextPattern[_c] = { fqn: "@aws-cdk/aws-logs.SpaceDelimitedTextPattern", version: "1.156.1" };
366/**
367 * Quote a term for use in a pattern expression
368 *
369 * It's never wrong to quote a string term, and required if the term
370 * contains non-alphanumerical characters, so we just always do it.
371 *
372 * Inner double quotes are escaped using a backslash.
373 */
374function quoteTerm(term) {
375 return '"' + term.replace(/\\/g, '\\\\').replace(/"/g, '\\"') + '"';
376}
377/**
378 * Return whether the given column name is valid in a space-delimited table
379 */
380function validColumnName(column) {
381 return column === COL_ELLIPSIS || /^[a-zA-Z0-9_-]+$/.exec(column);
382}
383/**
384 * Validate and normalize the string comparison operator
385 *
386 * Correct for a common typo/confusion, treat '==' as '='
387 */
388function validateStringOperator(operator) {
389 if (operator === '==') {
390 operator = '=';
391 }
392 if (operator !== '=' && operator !== '!=') {
393 throw new Error(`Invalid comparison operator ('${operator}'), must be either '=' or '!='`);
394 }
395 return operator;
396}
397const VALID_OPERATORS = ['=', '!=', '<', '<=', '>', '>='];
398/**
399 * Validate and normalize numerical comparison operators
400 *
401 * Correct for a common typo/confusion, treat '==' as '='
402 */
403function validateNumericalOperator(operator) {
404 // Correct for a common typo, treat '==' as '='
405 if (operator === '==') {
406 operator = '=';
407 }
408 if (VALID_OPERATORS.indexOf(operator) === -1) {
409 throw new Error(`Invalid comparison operator ('${operator}'), must be one of ${VALID_OPERATORS.join(', ')}`);
410 }
411 return operator;
412}
413/**
414 * Render a table restriction
415 */
416function renderRestriction(column, restriction) {
417 if (restriction.numberValue !== undefined) {
418 return `${column} ${restriction.comparison} ${restriction.numberValue}`;
419 }
420 else if (restriction.stringValue) {
421 return `${column} ${restriction.comparison} ${quoteTerm(restriction.stringValue)}`;
422 }
423 else {
424 throw new Error('Invalid restriction');
425 }
426}
427function sum(xs) {
428 return xs.reduce((a, c) => a + c, 0);
429}
430//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGF0dGVybi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbInBhdHRlcm4udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7O0FBU0E7O0dBRUc7QUFDSCxNQUFzQixXQUFXO0lBQy9CLHlFQUF5RTtJQUN6RSxtRUFBbUU7SUFDbkUsWUFBNEIsaUJBQXlCO1FBQXpCLHNCQUFpQixHQUFqQixpQkFBaUIsQ0FBUTtLQUFLO0lBRTFELElBQVcsZ0JBQWdCO1FBQ3pCLE9BQU8sSUFBSSxHQUFHLElBQUksQ0FBQyxpQkFBaUIsR0FBRyxJQUFJLENBQUM7S0FDN0M7O0FBUEgsa0NBUUM7OztBQUVEOztHQUVHO0FBQ0gsTUFBYSxhQUFhO0lBRXhCOzs7Ozs7O09BT0c7SUFDSSxNQUFNLENBQUMsT0FBTyxDQUFDLGdCQUF3QjtRQUM1QyxPQUFPLElBQUksaUJBQWlCLENBQUMsZ0JBQWdCLENBQUMsQ0FBQztLQUNoRDtJQUVEOztPQUVHO0lBQ0ksTUFBTSxDQUFDLFNBQVM7UUFDckIsT0FBTyxJQUFJLGlCQUFpQixDQUFDLEVBQUUsQ0FBQyxDQUFDO0tBQ2xDO0lBRUQ7Ozs7T0FJRztJQUNJLE1BQU0sQ0FBQyxRQUFRLENBQUMsR0FBRyxLQUFlO1FBQ3ZDLE9BQU8sSUFBSSxjQUFjLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDO0tBQ3BDO0lBRUQ7Ozs7T0FJRztJQUNJLE1BQU0sQ0FBQyxPQUFPLENBQUMsR0FBRyxLQUFlO1FBQ3RDLE9BQU8sSUFBSSxjQUFjLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0tBQ2hEO0lBRUQ7Ozs7OztPQU1HO0lBQ0ksTUFBTSxDQUFDLFlBQVksQ0FBQyxHQUFHLFVBQXNCO1FBQ2xELE9BQU8sSUFBSSxjQUFjLENBQUMsVUFBVSxDQUFDLENBQUM7S0FDdkM7SUFFRDs7Ozs7Ozs7Ozs7Ozs7Ozs7T0FpQkc7SUFDSSxNQUFNLENB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QUFPLEdBQUcsTUFBTSxJQUFJLFdBQVcsQ0FBQyxVQUFVLElBQUksU0FBUyxDQUFDLFdBQVcsQ0FBQyxXQUFXLENBQUMsRUFBRSxDQUFDO0tBQ3BGO1NBQU07UUFDTCxNQUFNLElBQUksS0FBSyxDQUFDLHFCQUFxQixDQUFDLENBQUM7S0FDeEM7QUFDSCxDQUFDO0FBRUQsU0FBUyxHQUFHLENBQUMsRUFBWTtJQUN2QixPQUFPLEVBQUUsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDO0FBQ3ZDLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBJbXBsZW1lbnRhdGlvbiBvZiBtZXRyaWMgcGF0dGVybnNcblxuLyoqXG4gKiBJbnRlcmZhY2UgZm9yIG9iamVjdHMgdGhhdCBjYW4gcmVuZGVyIHRoZW1zZWx2ZXMgdG8gbG9nIHBhdHRlcm5zLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIElGaWx0ZXJQYXR0ZXJuIHtcbiAgcmVhZG9ubHkgbG9nUGF0dGVyblN0cmluZzogc3RyaW5nO1xufVxuXG4vKipcbiAqIEJhc2UgY2xhc3MgZm9yIHBhdHRlcm5zIHRoYXQgb25seSBtYXRjaCBKU09OIGxvZyBldmVudHMuXG4gKi9cbmV4cG9ydCBhYnN0cmFjdCBjbGFzcyBKc29uUGF0dGVybiBpbXBsZW1lbnRzIElGaWx0ZXJQYXR0ZXJuIHtcbiAgLy8gVGhpcyBpcyBhIHNlcGFyYXRlIGNsYXNzIHNvIHdlIGhhdmUgc29tZSB0eXBlIHNhZmV0eSB3aGVyZSB1c2VycyBjYW4ndFxuICAvLyBjb21iaW5lIHRleHQgcGF0dGVybnMgYW5kIEpTT04gcGF0dGVybnMgd2l0aCBhbiAnYW5kJyBvcGVyYXRpb24uXG4gIGNvbnN0cnVjdG9yKHB1YmxpYyByZWFkb25seSBqc29uUGF0dGVyblN0cmluZzogc3RyaW5nKSB7IH1cblxuICBwdWJsaWMgZ2V0IGxvZ1BhdHRlcm5TdHJpbmcoKTogc3RyaW5nIHtcbiAgICByZXR1cm4gJ3sgJyArIHRoaXMuanNvblBhdHRlcm5TdHJpbmcgKyAnIH0nO1xuICB9XG59XG5cbi8qKlxuICogQSBjb2xsZWN0aW9uIG9mIHN0YXRpYyBtZXRob2RzIHRvIGdlbmVyYXRlIGFwcHJvcHJpYXRlIElMb2dQYXR0ZXJuc1xuICovXG5leHBvcnQgY2xhc3MgRmlsdGVyUGF0dGVybiB7XG5cbiAgLyoqXG4gICAqIFVzZSB0aGUgZ2l2ZW4gc3RyaW5nIGFzIGxvZyBwYXR0ZXJuLlxuICAgKlxuICAgKiBTZWUgaHR0cHM6Ly9kb2NzLmF3cy5hbWF6b24uY29tL0FtYXpvbkNsb3VkV2F0Y2gvbGF0ZXN0L2xvZ3MvRmlsdGVyQW5kUGF0dGVyblN5bnRheC5odG1sXG4gICAqIGZvciBpbmZvcm1hdGlvbiBvbiB3cml0aW5nIGxvZyBwYXR0ZXJucy5cbiAgICpcbiAgICogQHBhcmFtIGxvZ1BhdHRlcm5TdHJpbmcgVGhlIHBhdHRlcm4gc3RyaW5nIHRvIHVzZS5cbiAgICovXG4gIHB1YmxpYyBzdGF0aWMgbGl0ZXJhbChsb2dQYXR0ZXJuU3RyaW5nOiBzdHJpbmcpOiBJRmlsdGVyUGF0dGVybiB7XG4gICAgcmV0dXJuIG5ldyBMaXRlcmFsTG9nUGF0dGVybihsb2dQYXR0ZXJuU3RyaW5nKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBIGxvZyBwYXR0ZXJuIHRoYXQgbWF0Y2hlcyBhbGwgZXZlbnRzLlxuICAgKi9cbiAgcHVibGljIHN0YXRpYyBhbGxFdmVudHMoKTogSUZpbHRlclBhdHRlcm4ge1xuICAgIHJldHVybiBuZXcgTGl0ZXJhbExvZ1BhdHRlcm4oJycpO1xuICB9XG5cbiAgLyoqXG4gICAqIEEgbG9nIHBhdHRlcm4gdGhhdCBtYXRjaGVzIGlmIGFsbCB0aGUgc3RyaW5ncyBnaXZlbiBhcHBlYXIgaW4gdGhlIGV2ZW50LlxuICAgKlxuICAgKiBAcGFyYW0gdGVybXMgVGhlIHdvcmRzIHRvIHNlYXJjaCBmb3IuIEFsbCB0ZXJtcyBtdXN0IG1hdGNoLlxuICAgKi9cbiAgcHVibGljIHN0YXRpYyBhbGxUZXJtcyguLi50ZXJtczogc3RyaW5nW10pOiBJRmlsdGVyUGF0dGVybiB7XG4gICAgcmV0dXJuIG5ldyBUZXh0TG9nUGF0dGVybihbdGVybXNdKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBIGxvZyBwYXR0ZXJuIHRoYXQgbWF0Y2hlcyBpZiBhbnkgb2YgdGhlIHN0cmluZ3MgZ2l2ZW4gYXBwZWFyIGluIHRoZSBldmVudC5cbiAgICpcbiAgICogQHBhcmFtIHRlcm1zIFRoZSB3b3JkcyB0byBzZWFyY2ggZm9yLiBBbnkgdGVybXMgbXVzdCBtYXRjaC5cbiAgICovXG4gIHB1YmxpYyBzdGF0aWMgYW55VGVybSguLi50ZXJtczogc3RyaW5nW10pOiBJRmlsdGVyUGF0dGVybiB7XG4gICAgcmV0dXJuIG5ldyBUZXh0TG9nUGF0dGVybih0ZXJtcy5tYXAodCA9PiBbdF0pKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBIGxvZyBwYXR0ZXJuIHRoYXQgbWF0Y2hlcyBpZiBhbnkgb2YgdGhlIGdpdmVuIHRlcm0gZ3JvdXBzIG1hdGNoZXMgdGhlIGV2ZW50LlxuICAgKlxuICAgKiBBIHRlcm0gZ3JvdXAgbWF0Y2hlcyBhbiBldmVudCBpZiBhbGwgdGhlIHRlcm1zIGluIGl0IGFwcGVhciBpbiB0aGUgZXZlbnQgc3RyaW5nLlxuICAgKlxuICAgKiBAcGFyYW0gdGVybUdyb3VwcyBBIGxpc3Qgb2YgdGVybSBncm91cHMgdG8gc2VhcmNoIGZvci4gQW55IG9uZSBvZiB0aGUgY2xhdXNlcyBtdXN0IG1hdGNoLlxuICAgKi9cbiAgcHVibGljIHN0YXRpYyBhbnlUZXJtR3JvdXAoLi4udGVybUdyb3Vwczogc3RyaW5nW11bXSk6IElGaWx0ZXJQYXR0ZXJuIHtcbiAgICByZXR1cm4gbmV3IFRleHRMb2dQYXR0ZXJuKHRlcm1Hcm91cHMpO1xuICB9XG5cbiAgLyoqXG4gICAqIEEgSlNPTiBsb2cgcGF0dGVybiB0aGF0IGNvbXBhcmVzIHN0cmluZyB2YWx1ZXMuXG4gICAqXG4gICAqIFRoaXMgcGF0dGVybiBvbmx5IG1hdGNoZXMgaWYgdGhlIGV2ZW50IGlzIGEgSlNPTiBldmVudCwgYW5kIHRoZSBpbmRpY2F0ZWQgZmllbGQgaW5zaWRlXG4gICAqIGNvbXBhcmVzIHdpdGggdGhlIHN0cmluZyB2YWx1ZS5cbiAgICpcbiAgICogVXNlICckJyB0byBpbmRpY2F0ZSB0aGUgcm9vdCBvZiB0aGUgSlNPTiBzdHJ1Y3R1cmUuIFRoZSBjb21wYXJpc29uIG9wZXJhdG9yIGNhbiBvbmx5XG4gICAqIGNvbXBhcmUgZXF1YWxpdHkgb3IgaW5lcXVhbGl0eS4gVGhlICcqJyB3aWxkY2FyZCBtYXkgYXBwZWFyIGluIHRoZSB2YWx1ZSBtYXkgYXQgdGhlXG4gICAqIHN0YXJ0IG9yIGF0IHRoZSBlbmQuXG4gICAqXG4gICAqIEZvciBtb3JlIGluZm9ybWF0aW9uLCBzZWU6XG4gICAqXG4gICAqIGh0dHBzOi8vZG9jcy5hd3MuYW1hem9uLmNvbS9BbWF6b25DbG91ZFdhdGNoL2xhdGVzdC9sb2dzL0ZpbHRlckFuZFBhdHRlcm5TeW50YXguaHRtbFxuICAgKlxuICAgKiBAcGFyYW0ganNvbkZpZWxkIEZpZWxkIGluc2lkZSBKU09OLiBFeGFtcGxlOiBcIiQubXlGaWVsZFwiXG4gICAqIEBwYXJhbSBjb21wYXJpc29uIENvbXBhcmlzb24gdG8gY2Fycnkgb3V0LiBFaXRoZXIgPSBvciAhPS5cbiAgICogQHBhcmFtIHZhbHVlIFRoZSBzdHJpbmcgdmFsdWUgdG8gY29tcGFyZSB0by4gTWF5IHVzZSAnKicgYXMgd2lsZGNhcmQgYXQgc3RhcnQgb3IgZW5kIG9mIHN0cmluZy5cbiAgICovXG4gIHB1YmxpYyBzdGF0aWMgc3RyaW5nVmFsdWUoanNvbkZpZWxkOiBzdHJpbmcsIGNvbXBhcmlzb246IHN0cmluZywgdmFsdWU6IHN0cmluZyk6IEpzb25QYXR0ZXJuIHtcbiAgICByZXR1cm4gbmV3IEpTT05TdHJpbmdQYXR0ZXJuKGpzb25GaWVsZCwgY29tcGFyaXNvbiwgdmFsdWUpO1xuICB9XG5cbiAgLyoqXG4gICAqIEEgSlNPTiBsb2cgcGF0dGVybiB0aGF0IGNvbXBhcmVzIG51bWVyaWNhbCB2YWx1ZXMuXG4gICAqXG4gICAqIFRoaXMgcGF0dGVybiBvbmx5IG1hdGNoZXMgaWYgdGhlIGV2ZW50IGlzIGEgSlNPTiBldmVudCwgYW5kIHRoZSBpbmRpY2F0ZWQgZmllbGQgaW5zaWRlXG4gICAqIGNvbXBhcmVzIHdpdGggdGhlIHZhbHVlIGluIHRoZSBpbmRpY2F0ZWQgd2F5LlxuICAgKlxuICAgKiBVc2UgJyQnIHRvIGluZGljYXRlIHRoZSByb290IG9mIHRoZSBKU09OIHN0cnVjdHVyZS4gVGhlIGNvbXBhcmlzb24gb3BlcmF0b3IgY2FuIG9ubHlcbiAgICogY29tcGFyZSBlcXVhbGl0eSBvciBpbmVxdWFsaXR5LiBUaGUgJyonIHdpbGRjYXJkIG1heSBhcHBlYXIgaW4gdGhlIHZhbHVlIG1heSBhdCB0aGVcbiAgICogc3RhcnQgb3IgYXQgdGhlIGVuZC5cbiAgICpcbiAgICogRm9yIG1vcmUgaW5mb3JtYXRpb24sIHNlZTpcbiAgICpcbiAgICogaHR0cHM6Ly9kb2NzLmF3cy5hbWF6b24uY29tL0FtYXpvbkNsb3VkV2F0Y2gvbGF0ZXN0L2xvZ3MvRmlsdGVyQW5kUGF0dGVyblN5bnRheC5odG1sXG4gICAqXG4gICAqIEBwYXJhbSBqc29uRmllbGQgRmllbGQgaW5zaWRlIEpTT04uIEV4YW1wbGU6IFwiJC5teUZpZWxkXCJcbiAgICogQHBhcmFtIGNvbXBhcmlzb24gQ29tcGFyaXNvbiB0byBjYXJyeSBvdXQuIE9uZSBvZiA9LCAhPSwgPCwgPD0sID4sID49LlxuICAgKiBAcGFyYW0gdmFsdWUgVGhlIG51bWVyaWNhbCB2YWx1ZSB0byBjb21wYXJlIHRvXG4gICAqL1xuICBwdWJsaWMgc3RhdGljIG51bWJlclZhbHVlKGpzb25GaWVsZDogc3RyaW5nLCBjb21wYXJpc29uOiBzdHJpbmcsIHZhbHVlOiBudW1iZXIpOiBKc29uUGF0dGVybiB7XG4gICAgcmV0dXJuIG5ldyBKU09OTnVtYmVyUGF0dGVybihqc29uRmllbGQsIGNvbXBhcmlzb24sIHZhbHVlKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBIEpTT04gbG9nIHBhdHRlcm4gdGhhdCBtYXRjaGVzIGlmIHRoZSBmaWVsZCBleGlzdHMgYW5kIGhhcyB0aGUgc3BlY2lhbCB2YWx1ZSAnbnVsbCcuXG4gICAqXG4gICAqIEBwYXJhbSBqc29uRmllbGQgRmllbGQgaW5zaWRlIEpTT04uIEV4YW1wbGU6IFwiJC5teUZpZWxkXCJcbiAgICovXG4gIHB1YmxpYyBzdGF0aWMgaXNOdWxsKGpzb25GaWVsZDogc3RyaW5nKTogSnNvblBhdHRlcm4ge1xuICAgIHJldHVybiBuZXcgSlNPTlBvc3RmaXhQYXR0ZXJuKGpzb25GaWVsZCwgJ0lTIE5VTEwnKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBIEpTT04gbG9nIHBhdHRlcm4gdGhhdCBtYXRjaGVzIGlmIHRoZSBmaWVsZCBkb2VzIG5vdCBleGlzdC5cbiAgICpcbiAgICogQHBhcmFtIGpzb25GaWVsZCBGaWVsZCBpbnNpZGUgSlNPTi4gRXhhbXBsZTogXCIkLm15RmllbGRcIlxuICAgKi9cbiAgcHVibGljIHN0YXRpYyBub3RFeGlzdHMoanNvbkZpZWxkOiBzdHJpbmcpOiBKc29uUGF0dGVybiB7XG4gICAgcmV0dXJuIG5ldyBKU09OUG9zdGZpeFBhdHRlcm4oanNvbkZpZWxkLCAnTk9UIEVYSVNUUycpO1xuICB9XG5cbiAgLyoqXG4gICAqIEEgSlNPTiBsb2cgcGF0dGVyIHRoYXQgbWF0Y2hlcyBpZiB0aGUgZmllbGQgZXhpc3RzLlxuICAgKlxuICAgKiBUaGlzIGlzIGEgcmVhZGFibGUgY29udmVuaWVuY2Ugd3JhcHBlciBvdmVyICdmaWVsZCA9IConXG4gICAqXG4gICAqIEBwYXJhbSBqc29uRmllbGQgRmllbGQgaW5zaWRlIEpTT04uIEV4YW1wbGU6IFwiJC5teUZpZWxkXCJcbiAgICovXG4gIHB1YmxpYyBzdGF0aWMgZXhpc3RzKGpzb25GaWVsZDogc3RyaW5nKTogSnNvblBhdHRlcm4ge1xuICAgIHJldHVybiBuZXcgSlNPTlN0cmluZ1BhdHRlcm4oanNvbkZpZWxkLCAnPScsICcqJyk7XG4gIH1cblxuICAvKipcbiAgICogQSBKU09OIGxvZyBwYXR0ZXJuIHRoYXQgbWF0Y2hlcyBpZiB0aGUgZmllbGQgZXhpc3RzIGFuZCBlcXVhbHMgdGhlIGJvb2xlYW4gdmFsdWUuXG4gICAqXG4gICAqIEBwYXJhbSBqc29uRmllbGQgRmllbGQgaW5zaWRlIEpTT04uIEV4YW1wbGU6IFwiJC5teUZpZWxkXCJcbiAgICogQHBhcmFtIHZhbHVlIFRoZSB2YWx1ZSB0byBtYXRjaFxuICAgKi9cbiAgcHVibGljIHN0YXRpYyBib29sZWFuVmFsdWUoanNvbkZpZWxkOiBzdHJpbmcsIHZhbHVlOiBib29sZWFuKTogSnNvblBhdHRlcm4ge1xuICAgIHJldHVybiBuZXcgSlNPTlBvc3RmaXhQYXR0ZXJuKGpzb25GaWVsZCwgdmFsdWUgPyAnSVMgVFJVRScgOiAnSVMgRkFMU0UnKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBIEpTT04gbG9nIHBhdHRlcm4gdGhhdCBtYXRjaGVzIGlmIGFsbCBnaXZlbiBKU09OIGxvZyBwYXR0ZXJucyBtYXRjaFxuICAgKi9cbiAgcHVibGljIHN0YXRpYyBhbGwoLi4ucGF0dGVybnM6IEpzb25QYXR0ZXJuW10pOiBKc29uUGF0dGVybiB7XG4gICAgaWYgKHBhdHRlcm5zLmxlbmd0aCA9PT0gMCkgeyB0aHJvdyBuZXcgRXJyb3IoJ011c3Qgc3VwcGx5IGF0IGxlYXN0IG9uZSBwYXR0ZXJuLCBvciB1c2UgYWxsRXZlbnRzKCkgdG8gbWF0Y2ggYWxsIGV2ZW50cy4nKTsgfVxuICAgIGlmIChwYXR0ZXJucy5sZW5ndGggPT09IDEpIHsgcmV0dXJuIHBhdHRlcm5zWzBdOyB9XG4gICAgcmV0dXJuIG5ldyBKU09OQWdncmVnYXRlUGF0dGVybignJiYnLCBwYXR0ZXJucyk7XG4gIH1cblxuICAvKipcbiAgICogQSBKU09OIGxvZyBwYXR0ZXJuIHRoYXQgbWF0Y2hlcyBpZiBhbnkgb2YgdGhlIGdpdmVuIEpTT04gbG9nIHBhdHRlcm5zIG1hdGNoXG4gICAqL1xuICBwdWJsaWMgc3RhdGljIGFueSguLi5wYXR0ZXJuczogSnNvblBhdHRlcm5bXSk6IEpzb25QYXR0ZXJuIHtcbiAgICBpZiAocGF0dGVybnMubGVuZ3RoID09PSAwKSB7IHRocm93IG5ldyBFcnJvcignTXVzdCBzdXBwbHkgYXQgbGVhc3Qgb25lIHBhdHRlcm4nKTsgfVxuICAgIGlmIChwYXR0ZXJucy5sZW5ndGggPT09IDEpIHsgcmV0dXJuIHBhdHRlcm5zWzBdOyB9XG4gICAgcmV0dXJuIG5ldyBKU09OQWdncmVnYXRlUGF0dGVybignfHwnLCBwYXR0ZXJucyk7XG4gIH1cblxuICAvKipcbiAgICogQSBzcGFjZSBkZWxpbWl0ZWQgbG9nIHBhdHRlcm4gbWF0Y2hlci5cbiAgICpcbiAgICogVGhlIGxvZyBldmVudCBpcyBkaXZpZGVkIGludG8gc3BhY2UtZGVsaW1pdGVkIGNvbHVtbnMgKG9wdGlvbmFsbHlcbiAgICogZW5jbG9zZWQgYnkgXCJcIiBvciBbXSB0byBjYXB0dXJlIHNwYWNlcyBpbnRvIGNvbHVtbiB2YWx1ZXMpLCBhbmQgbmFtZXNcbiAgICogYXJlIGdpdmVuIHRvIGVhY2ggY29sdW1uLlxuICAgKlxuICAgKiAnLi4uJyBtYXkgYmUgc3BlY2lmaWVkIG9uY2UgdG8gbWF0Y2ggYW55IG51bWJlciBvZiBjb2x1bW5zLlxuICAgKlxuICAgKiBBZnRlcndhcmRzLCBjb25kaXRpb25zIG1heSBiZSBhZGRlZCB0byBpbmRpdmlkdWFsIGNvbHVtbnMuXG4gICAqXG4gICAqIEBwYXJhbSBjb2x1bW5zIFRoZSBjb2x1bW5zIGluIHRoZSBzcGFjZS1kZWxpbWl0ZWQgbG9nIHN0cmVhbS5cbiAgICovXG4gIHB1YmxpYyBzdGF0aWMgc3BhY2VEZWxpbWl0ZWQoLi4uY29sdW1uczogc3RyaW5nW10pOiBTcGFjZURlbGltaXRlZFRleHRQYXR0ZXJuIHtcbiAgICByZXR1cm4gU3BhY2VEZWxpbWl0ZWRUZXh0UGF0dGVybi5jb25zdHJ1Y3QoY29sdW1ucyk7XG4gIH1cbn1cblxuLyoqXG4gKiBVc2UgYSBzdHJpbmcgbGl0ZXJhbCBhcyBhIGxvZyBwYXR0ZXJuXG4gKi9cbmNsYXNzIExpdGVyYWxMb2dQYXR0ZXJuIGltcGxlbWVudHMgSUZpbHRlclBhdHRlcm4ge1xuICBjb25zdHJ1Y3RvcihwdWJsaWMgcmVhZG9ubHkgbG9nUGF0dGVyblN0cmluZzogc3RyaW5nKSB7XG4gIH1cbn1cblxuLyoqXG4gKiBTZWFyY2ggZm9yIGEgc2V0IG9mIHNldCBvZiB0ZXJtc1xuICovXG5jbGFzcyBUZXh0TG9nUGF0dGVybiBpbXBsZW1lbnRzIElGaWx0ZXJQYXR0ZXJuIHtcbiAgcHVibGljIHJlYWRvbmx5IGxvZ1BhdHRlcm5TdHJpbmc6IHN0cmluZztcblxuICBjb25zdHJ1Y3RvcihjbGF1c2VzOiBzdHJpbmdbXVtdKSB7XG4gICAgY29uc3QgcXVvdGVkQ2xhdXNlcyA9IGNsYXVzZXMubWFwKHRlcm1zID0+IHRlcm1zLm1hcChxdW90ZVRlcm0pLmpvaW4oJyAnKSk7XG4gICAgaWYgKHF1b3RlZENsYXVzZXMubGVuZ3RoID09PSAxKSB7XG4gICAgICB0aGlzLmxvZ1BhdHRlcm5TdHJpbmcgPSBxdW90ZWRDbGF1c2VzWzBdO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLmxvZ1BhdHRlcm5TdHJpbmcgPSBxdW90ZWRDbGF1c2VzLm1hcChhbHQgPT4gJz8nICsgYWx0KS5qb2luKCcgJyk7XG4gICAgfVxuICB9XG59XG5cbi8qKlxuICogQSBzdHJpbmcgY29tcGFyaXNvbiBmb3IgSlNPTiB2YWx1ZXNcbiAqL1xuY2xhc3MgSlNPTlN0cmluZ1BhdHRlcm4gZXh0ZW5kcyBKc29uUGF0dGVybiB7XG4gIHB1YmxpYyBjb25zdHJ1Y3Rvcihqc29uRmllbGQ6IHN0cmluZywgY29tcGFyaXNvbjogc3RyaW5nLCB2YWx1ZTogc3RyaW5nKSB7XG4gICAgY29tcGFyaXNvbiA9IHZhbGlkYXRlU3RyaW5nT3BlcmF0b3IoY29tcGFyaXNvbik7XG4gICAgc3VwZXIoYCR7anNvbkZpZWxkfSAke2NvbXBhcmlzb259ICR7cXVvdGVUZXJtKHZhbHVlKX1gKTtcbiAgfVxufVxuXG4vKipcbiAqIEEgbnVtYmVyIGNvbXBhcmlzb24gZm9yIEpTT04gdmFsdWVzXG4gKi9cbmNsYXNzIEpTT05OdW1iZXJQYXR0ZXJuIGV4dGVuZHMgSnNvblBhdHRlcm4ge1xuICBwdWJsaWMgY29uc3RydWN0b3IoanNvbkZpZWxkOiBzdHJpbmcsIGNvbXBhcmlzb246IHN0cmluZywgdmFsdWU6IG51bWJlcikge1xuICAgIGNvbXBhcmlzb24gPSB2YWxpZGF0ZU51bWVyaWNhbE9wZXJhdG9yKGNvbXBhcmlzb24pO1xuICAgIHN1cGVyKGAke2pzb25GaWVsZH0gJHtjb21wYXJpc29ufSAke3ZhbHVlfWApO1xuICB9XG59XG5cbi8qKlxuICogQSBwb3N0Zml4IG9wZXJhdG9yIGZvciBKU09OIHBhdHRlcm5zXG4gKi9cbmNsYXNzIEpTT05Qb3N0Zml4UGF0dGVybiBleHRlbmRzIEpzb25QYXR0ZXJuIHtcbiAgcHVibGljIGNvbnN0cnVjdG9yKGpzb25GaWVsZDogc3RyaW5nLCBwb3N0Zml4OiBzdHJpbmcpIHtcbiAgICAvLyBObyB2YWxpZGF0aW9uLCB3ZSBhc3N1bWUgdGhlc2UgYXJlIGdlbmVyYXRlZCBieSB0cnVzdGVkIGZhY3RvcnkgZnVuY3Rpb25zXG4gICAgc3VwZXIoYCR7anNvbkZpZWxkfSAke3Bvc3RmaXh9YCk7XG4gIH1cbn1cblxuLyoqXG4gKiBDb21iaW5lcyBtdWx0aXBsZSBvdGhlciBKU09OIHBhdHRlcm5zIHdpdGggYW4gb3BlcmF0b3JcbiAqL1xuY2xhc3MgSlNPTkFnZ3JlZ2F0ZVBhdHRlcm4gZXh0ZW5kcyBKc29uUGF0dGVybiB7XG4gIHB1YmxpYyBjb25zdHJ1Y3RvcihvcGVyYXRvcjogc3RyaW5nLCBwYXR0ZXJuczogSnNvblBhdHRlcm5bXSkge1xuICAgIGlmIChvcGVyYXRvciAhPT0gJyYmJyAmJiBvcGVyYXRvciAhPT0gJ3x8Jykge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdPcGVyYXRvciBtdXN0IGJlIG9uZSBvZiAmJiBvciB8fCcpO1xuICAgIH1cblxuICAgIGNvbnN0IGNsYXVzZXMgPSBwYXR0ZXJucy5tYXAocCA9PiAnKCcgKyBwLmpzb25QYXR0ZXJuU3RyaW5nICsgJyknKTtcblxuICAgIHN1cGVyKGNsYXVzZXMuam9pbihgICR7b3BlcmF0b3J9IGApKTtcbiAgfVxufVxuXG5leHBvcnQgdHlwZSBSZXN0cmljdGlvbk1hcCA9IHtbY29sdW1uOiBzdHJpbmddOiBDb2x1bW5SZXN0cmljdGlvbltdfTtcblxuY29uc3QgQ09MX0VMTElQU0lTID0gJy4uLic7XG5cbi8qKlxuICogU3BhY2UgZGVsaW1pdGVkIHRleHQgcGF0dGVyblxuICovXG5leHBvcnQgY2xhc3MgU3BhY2VEZWxpbWl0ZWRUZXh0UGF0dGVybiBpbXBsZW1lbnRzIElGaWx0ZXJQYXR0ZXJuIHtcbiAgLyoqXG4gICAqIENvbnN0cnVjdCBhIG5ldyBpbnN0YW5jZSBvZiBhIHNwYWNlIGRlbGltaXRlZCB0ZXh0IHBhdHRlcm5cbiAgICpcbiAgICogU2luY2UgdGhpcyBjbGFzcyBtdXN0IGJlIHB1YmxpYywgd2UgY2FuJ3QgcmVseSBvbiB0aGUgdXNlciBvbmx5IGNyZWF0aW5nIGl0IHRocm91Z2hcbiAgICogdGhlIGBMb2dQYXR0ZXJuLnNwYWNlRGVsaW1pdGVkKClgIGZhY3RvcnkgZnVuY3Rpb24uIFdlIG11c3QgdGhlcmVmb3JlIHZhbGlkYXRlIHRoZVxuICAgKiBhcmd1bWVudCBpbiB0aGUgY29uc3RydWN0b3IuIFNpbmNlIHdlJ3JlIHJldHVybmluZyBhIGNvcHkgb24gZXZlcnkgbXV0YXRpb24sIGFuZCB3ZVxuICAgKiBkb24ndCB3YW50IHRvIHJlLXZhbGlkYXRlIHRoZSBzYW1lIHRoaW5ncyBvbiBldmVyeSBjb25zdHJ1Y3Rpb24sIHdlIHByb3ZpZGUgYSBsaW1pdGVkXG4gICAqIHNldCBvZiBtdXRhdG9yIGZ1bmN0aW9ucyBhbmQgb25seSB2YWxpZGF0ZSB0aGUgbmV3IGRhdGEgZXZlcnkgdGltZS5cbiAgICovXG4gIHB1YmxpYyBzdGF0aWMgY29uc3RydWN0KGNvbHVtbnM6IHN0cmluZ1tdKSB7XG4gICAgLy8gVmFsaWRhdGlvbiBoYXBwZW5zIGhlcmUgYmVjYXVzZSBhIHVzZXIgY291bGQgaW5zdGFudGlhdGUgdGhpcyBvYmplY3QgZGlyZWN0bHkgd2l0aG91dFxuICAgIC8vIGdvaW5nIHRocm91Z2ggdGhlIGZhY3RvcnlcbiAgICBmb3IgKGNvbnN0IGNvbHVtbiBvZiBjb2x1bW5zKSB7XG4gICAgICBpZiAoIXZhbGlkQ29sdW1uTmFtZShjb2x1bW4pKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgSW52YWxpZCBjb2x1bW4gbmFtZTogJHtjb2x1bW59YCk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKHN1bShjb2x1bW5zLm1hcChjID0+IGMgPT09IENPTF9FTExJUFNJUyA/IDEgOiAwKSkgPiAxKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXCJDYW4gdXNlIGF0IG1vc3Qgb25lICcuLi4nIGNvbHVtblwiKTtcbiAgICB9XG5cbiAgICByZXR1cm4gbmV3IFNwYWNlRGVsaW1pdGVkVGV4dFBhdHRlcm4oY29sdW1ucywge30pO1xuICB9XG5cbiAgLy8gVE9ETzogVGVtcG9yYXJpbHkgY2hhbmdlZCBmcm9tIHByaXZhdGUgdG8gcHJvdGVjdGVkIHRvIHVuYmxvY2sgYnVpbGQuIFdlIG5lZWQgdG8gdGhpbmtcbiAgLy8gICAgIGFib3V0IGhvdyB0byBoYW5kbGUganNpaSB0eXBlcyB3aXRoIHByaXZhdGUgY29uc3RydWN0b3JzLlxuICBwcm90ZWN0ZWQgY29uc3RydWN0b3IocHJpdmF0ZSByZWFkb25seSBjb2x1bW5zOiBzdHJpbmdbXSwgcHJpdmF0ZSByZWFkb25seSByZXN0cmljdGlvbnM6IFJlc3RyaWN0aW9uTWFwKSB7XG4gICAgLy8gUHJpdmF0ZSBjb25zdHJ1Y3RvciBzbyB3ZSB2YWxpZGF0ZSBpbiB0aGUgLmNvbnN0cnVjdCgpIGZhY3RvcnkgZnVuY3Rpb25cbiAgfVxuXG4gIC8qKlxuICAgKiBSZXN0cmljdCB3aGVyZSB0aGUgcGF0dGVybiBhcHBsaWVzXG4gICAqL1xuICBwdWJsaWMgd2hlcmVTdHJpbmcoY29sdW1uTmFtZTogc3RyaW5nLCBjb21wYXJpc29uOiBzdHJpbmcsIHZhbHVlOiBzdHJpbmcpOiBTcGFjZURlbGltaXRlZFRleHRQYXR0ZXJuIHtcbiAgICBpZiAoY29sdW1uTmFtZSA9PT0gQ09MX0VMTElQU0lTKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXCJDYW4ndCB1c2UgJy4uLicgaW4gYSByZXN0cmljdGlvblwiKTtcbiAgICB9XG4gICAgaWYgKHRoaXMuY29sdW1ucy5pbmRleE9mKGNvbHVtbk5hbWUpID09PSAtMSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBDb2x1bW4gaW4gcmVzdHJpY3Rpb25zIHRoYXQgaXMgbm90IGluIGNvbHVtbnM6ICR7Y29sdW1uTmFtZX1gKTtcbiAgICB9XG5cbiAgICBjb21wYXJpc29uID0gdmFsaWRhdGVTdHJpbmdPcGVyYXRvcihjb21wYXJpc29uKTtcblxuICAgIHJldHVybiBuZXcgU3BhY2VEZWxpbWl0ZWRUZXh0UGF0dGVybih0aGlzLmNvbHVtbnMsIHRoaXMuYWRkUmVzdHJpY3Rpb24oY29sdW1uTmFtZSwge1xuICAgICAgY29tcGFyaXNvbixcbiAgICAgIHN0cmluZ1ZhbHVlOiB2YWx1ZSxcbiAgICB9KSk7XG4gIH1cblxuICAvKipcbiAgICogUmVzdHJpY3Qgd2hlcmUgdGhlIHBhdHRlcm4gYXBwbGllc1xuICAgKi9cbiAgcHVibGljIHdoZXJlTnVtYmVyKGNvbHVtbk5hbWU6IHN0cmluZywgY29tcGFyaXNvbjogc3RyaW5nLCB2YWx1ZTogbnVtYmVyKTogU3BhY2VEZWxpbWl0ZWRUZXh0UGF0dGVybiB7XG4gICAgaWYgKGNvbHVtbk5hbWUgPT09IENPTF9FTExJUFNJUykge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFwiQ2FuJ3QgdXNlICcuLi4nIGluIGEgcmVzdHJpY3Rpb25cIik7XG4gICAgfVxuICAgIGlmICh0aGlzLmNvbHVtbnMuaW5kZXhPZihjb2x1bW5OYW1lKSA9PT0gLTEpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgQ29sdW1uIGluIHJlc3RyaWN0aW9ucyB0aGF0IGlzIG5vdCBpbiBjb2x1bW5zOiAke2NvbHVtbk5hbWV9YCk7XG4gICAgfVxuXG4gICAgY29tcGFyaXNvbiA9IHZhbGlkYXRlTnVtZXJpY2FsT3BlcmF0b3IoY29tcGFyaXNvbik7XG5cbiAgICByZXR1cm4gbmV3IFNwYWNlRGVsaW1pdGVkVGV4dFBhdHRlcm4odGhpcy5jb2x1bW5zLCB0aGlzLmFkZFJlc3RyaWN0aW9uKGNvbHVtbk5hbWUsIHtcbiAgICAgIGNvbXBhcmlzb24sXG4gICAgICBudW1iZXJWYWx1ZTogdmFsdWUsXG4gICAgfSkpO1xuICB9XG5cbiAgcHVibGljIGdldCBsb2dQYXR0ZXJuU3RyaW5nKCk6IHN0cmluZyB7XG4gICAgcmV0dXJuICdbJyArIHRoaXMuY29sdW1ucy5tYXAodGhpcy5jb2x1bW5FeHByZXNzaW9uLmJpbmQodGhpcykpLmpvaW4oJywgJykgKyAnXSc7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJuIHRoZSBjb2x1bW4gZXhwcmVzc2lvbiBmb3IgdGhlIGdpdmVuIGNvbHVtblxuICAgKi9cbiAgcHJpdmF0ZSBjb2x1bW5FeHByZXNzaW9uKGNvbHVtbjogc3RyaW5nKSB7XG4gICAgY29uc3QgcmVzdHJpY3Rpb25zID0gdGhpcy5yZXN0cmljdGlvbnNbY29sdW1uXTtcbiAgICBpZiAoIXJlc3RyaWN0aW9ucykgeyByZXR1cm4gY29sdW1uOyB9XG5cbiAgICByZXR1cm4gcmVzdHJpY3Rpb25zLm1hcChyID0+IHJlbmRlclJlc3RyaWN0aW9uKGNvbHVtbiwgcikpLmpvaW4oJyAmJiAnKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBNYWtlIGEgY29weSBvZiB0aGUgY3VycmVudCByZXN0cmljdGlvbnMgYW5kIGFkZCBvbmVcbiAgICovXG4gIHByaXZhdGUgYWRkUmVzdHJpY3Rpb24oY29sdW1uTmFtZTogc3RyaW5nLCByZXN0cmljdGlvbjogQ29sdW1uUmVzdHJpY3Rpb24pIHtcbiAgICBjb25zdCByZXQ6IFJlc3RyaWN0aW9uTWFwID0ge307XG4gICAgZm9yIChjb25zdCBrZXkgb2YgT2JqZWN0LmtleXModGhpcy5yZXN0cmljdGlvbnMpKSB7XG4gICAgICByZXRba2V5XSA9IHRoaXMucmVzdHJpY3Rpb25zW2tleV0uc2xpY2UoKTtcbiAgICB9XG4gICAgaWYgKCEoY29sdW1uTmFtZSBpbiByZXQpKSB7IHJldFtjb2x1bW5OYW1lXSA9IFtdOyB9XG4gICAgcmV0W2NvbHVtbk5hbWVdLnB1c2gocmVzdHJpY3Rpb24pO1xuICAgIHJldHVybiByZXQ7XG4gIH1cbn1cblxuZXhwb3J0IGludGVyZmFjZSBDb2x1bW5SZXN0cmljdGlvbiB7XG4gIC8qKlxuICAgKiBDb21wYXJpc29uIG9wZXJhdG9yIHRvIHVzZVxuICAgKi9cbiAgcmVhZG9ubHkgY29tcGFyaXNvbjogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBTdHJpbmcgdmFsdWUgdG8gY29tcGFyZSB0b1xuICAgKlxuICAgKiBFeGFjdGx5IG9uZSBvZiAnc3RyaW5nVmFsdWUnIGFuZCAnbnVtYmVyVmFsdWUnIG11c3QgYmUgc2V0LlxuICAgKi9cbiAgcmVhZG9ubHkgc3RyaW5nVmFsdWU/OiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIE51bWJlciB2YWx1ZSB0byBjb21wYXJlIHRvXG4gICAqXG4gICAqIEV4YWN0bHkgb25lIG9mICdzdHJpbmdWYWx1ZScgYW5kICdudW1iZXJWYWx1ZScgbXVzdCBiZSBzZXQuXG4gICAqL1xuICByZWFkb25seSBudW1iZXJWYWx1ZT86IG51bWJlcjtcbn1cblxuLyoqXG4gKiBRdW90ZSBhIHRlcm0gZm9yIHVzZSBpbiBhIHBhdHRlcm4gZXhwcmVzc2lvblxuICpcbiAqIEl0J3MgbmV2ZXIgd3JvbmcgdG8gcXVvdGUgYSBzdHJpbmcgdGVybSwgYW5kIHJlcXVpcmVkIGlmIHRoZSB0ZXJtXG4gKiBjb250YWlucyBub24tYWxwaGFudW1lcmljYWwgY2hhcmFjdGVycywgc28gd2UganVzdCBhbHdheXMgZG8gaXQuXG4gKlxuICogSW5uZXIgZG91YmxlIHF1b3RlcyBhcmUgZXNjYXBlZCB1c2luZyBhIGJhY2tzbGFzaC5cbiAqL1xuZnVuY3Rpb24gcXVvdGVUZXJtKHRlcm06IHN0cmluZyk6IHN0cmluZyB7XG4gIHJldHVybiAnXCInICsgdGVybS5yZXBsYWNlKC9cXFxcL2csICdcXFxcXFxcXCcpLnJlcGxhY2UoL1wiL2csICdcXFxcXCInKSArICdcIic7XG59XG5cbi8qKlxuICogUmV0dXJuIHdoZXRoZXIgdGhlIGdpdmVuIGNvbHVtbiBuYW1lIGlzIHZhbGlkIGluIGEgc3BhY2UtZGVsaW1pdGVkIHRhYmxlXG4gKi9cbmZ1bmN0aW9uIHZhbGlkQ29sdW1uTmFtZShjb2x1bW46IHN0cmluZykge1xuICByZXR1cm4gY29sdW1uID09PSBDT0xfRUxMSVBTSVMgfHwgL15bYS16QS1aMC05Xy1dKyQvLmV4ZWMoY29sdW1uKTtcbn1cblxuLyoqXG4gKiBWYWxpZGF0ZSBhbmQgbm9ybWFsaXplIHRoZSBzdHJpbmcgY29tcGFyaXNvbiBvcGVyYXRvclxuICpcbiAqIENvcnJlY3QgZm9yIGEgY29tbW9uIHR5cG8vY29uZnVzaW9uLCB0cmVhdCAnPT0nIGFzICc9J1xuICovXG5mdW5jdGlvbiB2YWxpZGF0ZVN0cmluZ09wZXJhdG9yKG9wZXJhdG9yOiBzdHJpbmcpIHtcbiAgaWYgKG9wZXJhdG9yID09PSAnPT0nKSB7IG9wZXJhdG9yID0gJz0nOyB9XG5cbiAgaWYgKG9wZXJhdG9yICE9PSAnPScgJiYgb3BlcmF0b3IgIT09ICchPScpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYEludmFsaWQgY29tcGFyaXNvbiBvcGVyYXRvciAoJyR7b3BlcmF0b3J9JyksIG11c3QgYmUgZWl0aGVyICc9JyBvciAnIT0nYCk7XG4gIH1cblxuICByZXR1cm4gb3BlcmF0b3I7XG59XG5cbmNvbnN0IFZBTElEX09QRVJBVE9SUyA9IFsnPScsICchPScsICc8JywgJzw9JywgJz4nLCAnPj0nXTtcblxuLyoqXG4gKiBWYWxpZGF0ZSBhbmQgbm9ybWFsaXplIG51bWVyaWNhbCBjb21wYXJpc29uIG9wZXJhdG9yc1xuICpcbiAqIENvcnJlY3QgZm9yIGEgY29tbW9uIHR5cG8vY29uZnVzaW9uLCB0cmVhdCAnPT0nIGFzICc9J1xuICovXG5mdW5jdGlvbiB2YWxpZGF0ZU51bWVyaWNhbE9wZXJhdG9yKG9wZXJhdG9yOiBzdHJpbmcpIHtcbiAgLy8gQ29ycmVjdCBmb3IgYSBjb21tb24gdHlwbywgdHJlYXQgJz09JyBhcyAnPSdcbiAgaWYgKG9wZXJhdG9yID09PSAnPT0nKSB7IG9wZXJhdG9yID0gJz0nOyB9XG5cbiAgaWYgKFZBTElEX09QRVJBVE9SUy5pbmRleE9mKG9wZXJhdG9yKSA9PT0gLTEpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYEludmFsaWQgY29tcGFyaXNvbiBvcGVyYXRvciAoJyR7b3BlcmF0b3J9JyksIG11c3QgYmUgb25lIG9mICR7VkFMSURfT1BFUkFUT1JTLmpvaW4oJywgJyl9YCk7XG4gIH1cblxuICByZXR1cm4gb3BlcmF0b3I7XG59XG5cbi8qKlxuICogUmVuZGVyIGEgdGFibGUgcmVzdHJpY3Rpb25cbiAqL1xuZnVuY3Rpb24gcmVuZGVyUmVzdHJpY3Rpb24oY29sdW1uOiBzdHJpbmcsIHJlc3RyaWN0aW9uOiBDb2x1bW5SZXN0cmljdGlvbikge1xuICBpZiAocmVzdHJpY3Rpb24ubnVtYmVyVmFsdWUgIT09IHVuZGVmaW5lZCkge1xuICAgIHJldHVybiBgJHtjb2x1bW59ICR7cmVzdHJpY3Rpb24uY29tcGFyaXNvbn0gJHtyZXN0cmljdGlvbi5udW1iZXJWYWx1ZX1gO1xuICB9IGVsc2UgaWYgKHJlc3RyaWN0aW9uLnN0cmluZ1ZhbHVlKSB7XG4gICAgcmV0dXJuIGAke2NvbHVtbn0gJHtyZXN0cmljdGlvbi5jb21wYXJpc29ufSAke3F1b3RlVGVybShyZXN0cmljdGlvbi5zdHJpbmdWYWx1ZSl9YDtcbiAgfSBlbHNlIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ0ludmFsaWQgcmVzdHJpY3Rpb24nKTtcbiAgfVxufVxuXG5mdW5jdGlvbiBzdW0oeHM6IG51bWJlcltdKTogbnVtYmVyIHtcbiAgcmV0dXJuIHhzLnJlZHVjZSgoYSwgYykgPT4gYSArIGMsIDApO1xufVxuIl19
\No newline at end of file