semantifold 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (111) hide show
  1. package/LICENSE +15 -0
  2. package/README.md +71 -0
  3. package/build/index.d.ts +54 -0
  4. package/build/index.d.ts.map +1 -0
  5. package/build/index.js +45 -0
  6. package/build/src/backends/identifiers.d.ts +19 -0
  7. package/build/src/backends/identifiers.d.ts.map +1 -0
  8. package/build/src/backends/identifiers.js +93 -0
  9. package/build/src/backends/index.d.ts +35 -0
  10. package/build/src/backends/index.d.ts.map +1 -0
  11. package/build/src/backends/index.js +149 -0
  12. package/build/src/backends/java.d.ts +8 -0
  13. package/build/src/backends/java.d.ts.map +1 -0
  14. package/build/src/backends/java.js +172 -0
  15. package/build/src/backends/javascript.d.ts +8 -0
  16. package/build/src/backends/javascript.d.ts.map +1 -0
  17. package/build/src/backends/javascript.js +173 -0
  18. package/build/src/backends/php.d.ts +8 -0
  19. package/build/src/backends/php.d.ts.map +1 -0
  20. package/build/src/backends/php.js +175 -0
  21. package/build/src/backends/ruby.d.ts +8 -0
  22. package/build/src/backends/ruby.d.ts.map +1 -0
  23. package/build/src/backends/ruby.js +155 -0
  24. package/build/src/backends/scalars.d.ts +15 -0
  25. package/build/src/backends/scalars.d.ts.map +1 -0
  26. package/build/src/backends/scalars.js +138 -0
  27. package/build/src/backends/shared.d.ts +26 -0
  28. package/build/src/backends/shared.d.ts.map +1 -0
  29. package/build/src/backends/shared.js +424 -0
  30. package/build/src/backends/typescript.d.ts +8 -0
  31. package/build/src/backends/typescript.d.ts.map +1 -0
  32. package/build/src/backends/typescript.js +160 -0
  33. package/build/src/backends/writer.d.ts +87 -0
  34. package/build/src/backends/writer.d.ts.map +1 -0
  35. package/build/src/backends/writer.js +207 -0
  36. package/build/src/diagnostic.d.ts +67 -0
  37. package/build/src/diagnostic.d.ts.map +1 -0
  38. package/build/src/diagnostic.js +96 -0
  39. package/build/src/frontends/index.d.ts +14 -0
  40. package/build/src/frontends/index.d.ts.map +1 -0
  41. package/build/src/frontends/index.js +36 -0
  42. package/build/src/frontends/java.d.ts +12 -0
  43. package/build/src/frontends/java.d.ts.map +1 -0
  44. package/build/src/frontends/java.js +630 -0
  45. package/build/src/frontends/javascript-typescript.d.ts +19 -0
  46. package/build/src/frontends/javascript-typescript.d.ts.map +1 -0
  47. package/build/src/frontends/javascript-typescript.js +633 -0
  48. package/build/src/frontends/php.d.ts +12 -0
  49. package/build/src/frontends/php.d.ts.map +1 -0
  50. package/build/src/frontends/php.js +523 -0
  51. package/build/src/frontends/ruby.d.ts +12 -0
  52. package/build/src/frontends/ruby.d.ts.map +1 -0
  53. package/build/src/frontends/ruby.js +515 -0
  54. package/build/src/frontends/scalars.d.ts +19 -0
  55. package/build/src/frontends/scalars.d.ts.map +1 -0
  56. package/build/src/frontends/scalars.js +71 -0
  57. package/build/src/mapping.d.ts +160 -0
  58. package/build/src/mapping.d.ts.map +1 -0
  59. package/build/src/mapping.js +1120 -0
  60. package/build/src/semantic/location.d.ts +61 -0
  61. package/build/src/semantic/location.d.ts.map +1 -0
  62. package/build/src/semantic/location.js +142 -0
  63. package/build/src/semantic/operators.d.ts +16 -0
  64. package/build/src/semantic/operators.d.ts.map +1 -0
  65. package/build/src/semantic/operators.js +24 -0
  66. package/build/src/semantic/provenance.d.ts +74 -0
  67. package/build/src/semantic/provenance.d.ts.map +1 -0
  68. package/build/src/semantic/provenance.js +577 -0
  69. package/build/src/semantic/scalars.d.ts +19 -0
  70. package/build/src/semantic/scalars.d.ts.map +1 -0
  71. package/build/src/semantic/scalars.js +40 -0
  72. package/build/src/semantic/types.d.ts +1003 -0
  73. package/build/src/semantic/types.d.ts.map +1 -0
  74. package/build/src/semantic/types.js +279 -0
  75. package/build/src/semantic/validate.d.ts +60 -0
  76. package/build/src/semantic/validate.d.ts.map +1 -0
  77. package/build/src/semantic/validate.js +472 -0
  78. package/docs/architecture.md +39 -0
  79. package/docs/coding-standards.md +7 -0
  80. package/docs/goals.md +7 -0
  81. package/docs/language-support.md +69 -0
  82. package/docs/plans/2026-09-02-initial-toolchain.md +54 -0
  83. package/docs/source-maps.md +134 -0
  84. package/docs/testing.md +25 -0
  85. package/index.js +63 -0
  86. package/package.json +69 -0
  87. package/src/backends/identifiers.js +101 -0
  88. package/src/backends/index.js +159 -0
  89. package/src/backends/java.js +182 -0
  90. package/src/backends/javascript.js +184 -0
  91. package/src/backends/php.js +184 -0
  92. package/src/backends/ruby.js +163 -0
  93. package/src/backends/scalars.js +120 -0
  94. package/src/backends/shared.js +456 -0
  95. package/src/backends/typescript.js +168 -0
  96. package/src/backends/writer.js +224 -0
  97. package/src/diagnostic.js +103 -0
  98. package/src/frontends/index.js +36 -0
  99. package/src/frontends/java.js +735 -0
  100. package/src/frontends/javascript-typescript.js +718 -0
  101. package/src/frontends/php.js +593 -0
  102. package/src/frontends/ruby.js +622 -0
  103. package/src/frontends/scalars.js +77 -0
  104. package/src/mapping.js +1260 -0
  105. package/src/semantic/location.js +154 -0
  106. package/src/semantic/operators.js +28 -0
  107. package/src/semantic/provenance.js +629 -0
  108. package/src/semantic/scalars.js +44 -0
  109. package/src/semantic/types.js +319 -0
  110. package/src/semantic/validate.js +529 -0
  111. package/tsconfig.json +16 -0
@@ -0,0 +1,633 @@
1
+ // @ts-check
2
+ import { parse as parseBabel } from "@babel/parser";
3
+ import { parse as parseComment } from "comment-parser";
4
+ import { missingType, parseFailure, unsupportedSyntax } from "../diagnostic.js";
5
+ import { locationFromOffsets, moduleLocation } from "../semantic/location.js";
6
+ import { withAdaptedOperation } from "../semantic/operators.js";
7
+ import { withParserRanges } from "../semantic/provenance.js";
8
+ import { hasOnlyUnicodeScalars } from "../semantic/scalars.js";
9
+ import { requireSourceScalarType } from "./scalars.js";
10
+ /** @typedef {NonNullable<import("@babel/parser").ParseResult<import("@babel/types").File>["tokens"]>[number]} BabelToken */
11
+ /** @typedef {{byStart: Map<number, BabelToken>, tokens: BabelToken[]}} BabelTokenIndex */
12
+ /** @type {WeakMap<object, BabelTokenIndex>} */
13
+ const nodeTokens = new WeakMap();
14
+ const babelBinaryOperations = new Map([
15
+ ["+", "Add"],
16
+ ["-", "Subtract"],
17
+ ["*", "Multiply"],
18
+ ["===", "Equal"],
19
+ ["!==", "NotEqual"],
20
+ ["<", "LessThan"],
21
+ ["<=", "LessThanOrEqual"],
22
+ [">", "GreaterThan"],
23
+ [">=", "GreaterThanOrEqual"]
24
+ ]);
25
+ /**
26
+ * Returns a source location for a Babel node.
27
+ * @param {import("@babel/types").Node} node - Babel node.
28
+ * @param {string} filename - Source filename.
29
+ * @param {string} source - Complete source.
30
+ * @returns {import("../semantic/types.js").SourceLocation} Normalized location.
31
+ */
32
+ function nodeLocation(node, filename, source) {
33
+ if (typeof node.start != "number" || typeof node.end != "number") {
34
+ throw new Error(`Babel omitted source offsets for ${node.type}.`);
35
+ }
36
+ return locationFromOffsets(filename, source, node.start, node.end);
37
+ }
38
+ /**
39
+ * Returns the identifier spelling rather than a trailing TypeScript annotation.
40
+ * @param {import("@babel/types").Identifier} node - Parser identifier.
41
+ * @param {string} filename - Source filename.
42
+ * @param {string} source - Complete source.
43
+ * @returns {import("../semantic/types.js").SourceLocation} Identifier location.
44
+ */
45
+ function identifierLocation(node, filename, source) {
46
+ if (typeof node.start != "number")
47
+ throw new Error("Babel omitted an identifier start offset.");
48
+ const token = nodeTokens.get(node)?.byStart.get(node.start);
49
+ if (!token || token.type.label != "name")
50
+ throw new Error(`Babel omitted the identifier token for '${node.name}'.`);
51
+ return locationFromOffsets(filename, source, token.start, token.end);
52
+ }
53
+ /**
54
+ * Locates one Babel token within parser-node boundaries.
55
+ * @param {import("@babel/types").Node} owner - Token-owning parser node.
56
+ * @param {string} value - Exact token spelling.
57
+ * @param {number} startOffset - Inclusive boundary.
58
+ * @param {number} endOffset - Exclusive boundary.
59
+ * @param {string} filename - Source filename.
60
+ * @param {string} source - Complete source.
61
+ * @returns {import("../semantic/types.js").SourceLocation} Exact token location.
62
+ */
63
+ function tokenLocation(owner, value, startOffset, endOffset, filename, source) {
64
+ const tokens = nodeTokens.get(owner)?.tokens ?? [];
65
+ let low = 0;
66
+ let high = tokens.length;
67
+ while (low < high) {
68
+ const middle = Math.floor((low + high) / 2);
69
+ if (tokens[middle].start < startOffset)
70
+ low = middle + 1;
71
+ else
72
+ high = middle;
73
+ }
74
+ let token;
75
+ for (let index = low; index < tokens.length && tokens[index].start < endOffset; index++) {
76
+ const candidate = tokens[index];
77
+ if (candidate.end <= endOffset && (candidate.value == value || candidate.type.label == value)) {
78
+ token = candidate;
79
+ break;
80
+ }
81
+ }
82
+ if (!token)
83
+ throw new Error(`Babel omitted token '${value}' between ${startOffset} and ${endOffset}.`);
84
+ return locationFromOffsets(filename, source, token.start, token.end);
85
+ }
86
+ /**
87
+ * Locates a comment-parser token inside a Babel-owned doc comment.
88
+ * @param {import("@babel/types").CommentBlock} comment - Babel doc comment.
89
+ * @param {import("comment-parser").Spec} tag - Parsed doc tag.
90
+ * @param {"name" | "type"} field - Token field.
91
+ * @param {string} filename - Source filename.
92
+ * @param {string} source - Complete source.
93
+ * @returns {import("../semantic/types.js").SourceLocation} Exact token location.
94
+ */
95
+ function commentTagLocation(comment, tag, field, filename, source) {
96
+ const line = tag.source[0];
97
+ if (typeof comment.start != "number" || !line)
98
+ throw new Error(`Comment parser omitted the @${tag.tag} source token.`);
99
+ let lineStart = comment.start;
100
+ for (let lineNumber = 0; lineNumber < line.number; lineNumber++) {
101
+ while (lineStart < source.length && source[lineStart] != "\r" && source[lineStart] != "\n")
102
+ lineStart++;
103
+ if (source[lineStart] == "\r" && source[lineStart + 1] == "\n")
104
+ lineStart += 2;
105
+ else
106
+ lineStart++;
107
+ }
108
+ const orderedFields = ["start", "delimiter", "postDelimiter", "tag", "postTag", "type", "postType", "name"];
109
+ const fieldIndex = orderedFields.indexOf(field);
110
+ const start = lineStart + orderedFields.slice(0, fieldIndex).reduce((length, key) => length + line.tokens[ /** @type {keyof typeof line.tokens} */(key)].length, 0);
111
+ const token = line.tokens[field];
112
+ return locationFromOffsets(filename, source, start, start + token.length);
113
+ }
114
+ /**
115
+ * Converts a supported Babel expression.
116
+ * @param {import("@babel/types").Expression} node - Babel expression.
117
+ * @param {"javascript" | "typescript"} language - Frontend language.
118
+ * @param {string} filename - Source filename.
119
+ * @param {string} source - Complete source.
120
+ * @returns {import("../semantic/types.js").Expression} Semantic expression.
121
+ */
122
+ function convertExpression(node, language, filename, source) {
123
+ const location = nodeLocation(node, filename, source);
124
+ if (node.type == "Identifier") {
125
+ return withParserRanges({ kind: /** @type {const} */ ("IdentifierExpression"), location, name: node.name }, {
126
+ name: identifierLocation(node, filename, source)
127
+ });
128
+ }
129
+ if (node.type == "NumericLiteral") {
130
+ if (!Number.isSafeInteger(node.value))
131
+ return unsupportedSyntax(language, "non-safe integer literal", location);
132
+ return withParserRanges({ kind: /** @type {const} */ ("IntegerLiteral"), location, value: node.value }, { literal: location });
133
+ }
134
+ if (node.type == "BooleanLiteral") {
135
+ if (typeof node.value != "boolean")
136
+ return unsupportedSyntax(language, "invalid boolean literal value", location);
137
+ return withParserRanges({ kind: /** @type {const} */ ("BooleanLiteral"), location, value: node.value }, { literal: location });
138
+ }
139
+ if (node.type == "StringLiteral") {
140
+ if (typeof node.value != "string" || !hasOnlyUnicodeScalars(node.value)) {
141
+ return unsupportedSyntax(language, "invalid Unicode string literal", location);
142
+ }
143
+ return withParserRanges({ kind: /** @type {const} */ ("StringLiteral"), location, value: node.value }, { literal: location });
144
+ }
145
+ if (node.type == "TemplateLiteral") {
146
+ if (node.expressions.length > 0)
147
+ return unsupportedSyntax(language, "interpolated string", location);
148
+ const quasi = node.quasis[0];
149
+ if (typeof quasi.value.cooked != "string" || !hasOnlyUnicodeScalars(quasi.value.cooked)) {
150
+ return unsupportedSyntax(language, "invalid Unicode string literal", location);
151
+ }
152
+ return withParserRanges({ kind: /** @type {const} */ ("StringLiteral"), location, value: quasi.value.cooked }, { literal: location });
153
+ }
154
+ if (node.type == "UnaryExpression" && ["!", "-"].includes(node.operator)) {
155
+ const operand = convertExpression(node.argument, language, filename, source);
156
+ const semantic = withAdaptedOperation(withParserRanges({
157
+ kind: "UnaryExpression",
158
+ location,
159
+ operand
160
+ }, {
161
+ operator: tokenLocation(node, node.operator, node.start ?? 0, node.argument.start ?? node.end ?? source.length, filename, source)
162
+ }), node.operator == "!" ? "Not" : "Negate");
163
+ return /** @type {import("../semantic/types.js").Expression} */ ( /** @type {unknown} */(semantic));
164
+ }
165
+ if (node.type == "LogicalExpression" && ["&&", "||"].includes(node.operator)) {
166
+ const semantic = withAdaptedOperation(withParserRanges({
167
+ kind: "BinaryExpression",
168
+ left: convertExpression(node.left, language, filename, source),
169
+ location,
170
+ right: convertExpression(node.right, language, filename, source)
171
+ }, {
172
+ operator: tokenLocation(node, node.operator, node.left.end ?? node.start ?? 0, node.right.start ?? node.end ?? source.length, filename, source)
173
+ }), node.operator == "&&" ? "And" : "Or");
174
+ return /** @type {import("../semantic/types.js").Expression} */ ( /** @type {unknown} */(semantic));
175
+ }
176
+ if (node.type == "BinaryExpression" && babelBinaryOperations.has(node.operator)) {
177
+ if (node.left.type == "PrivateName")
178
+ unsupportedSyntax(language, node.left.type, location);
179
+ const left = convertExpression(node.left, language, filename, source);
180
+ const right = convertExpression(node.right, language, filename, source);
181
+ const semantic = withAdaptedOperation(withParserRanges({
182
+ kind: "BinaryExpression",
183
+ left,
184
+ location,
185
+ right
186
+ }, {
187
+ operator: tokenLocation(node, node.operator, node.left.end ?? node.start ?? 0, node.right.start ?? node.end ?? source.length, filename, source)
188
+ }), /** @type {import("../semantic/operators.js").AdaptedOperation} */ (babelBinaryOperations.get(node.operator)));
189
+ return /** @type {import("../semantic/types.js").Expression} */ ( /** @type {unknown} */(semantic));
190
+ }
191
+ if (node.type == "BinaryExpression" && ["==", "!="].includes(node.operator)) {
192
+ return unsupportedSyntax(language, `coercive equality ${node.operator}`, location);
193
+ }
194
+ if (node.type == "CallExpression" && node.callee.type == "Identifier") {
195
+ const arguments_ = node.arguments.map((argument) => {
196
+ if (argument.type == "SpreadElement" || argument.type == "ArgumentPlaceholder") {
197
+ return unsupportedSyntax(language, argument.type, nodeLocation(argument, filename, source));
198
+ }
199
+ return convertExpression(argument, language, filename, source);
200
+ });
201
+ return withParserRanges({ arguments: arguments_, callee: node.callee.name, kind: /** @type {const} */ ("CallExpression"), location }, {
202
+ callee: identifierLocation(node.callee, filename, source)
203
+ });
204
+ }
205
+ return unsupportedSyntax(language, node.type, location);
206
+ }
207
+ /**
208
+ * Converts a supported return statement.
209
+ * @param {import("@babel/types").Statement} node - Babel statement.
210
+ * @param {"javascript" | "typescript"} language - Frontend language.
211
+ * @param {string} filename - Source filename.
212
+ * @param {string} source - Complete source.
213
+ * @returns {import("../semantic/types.js").ReturnStatement} Semantic return.
214
+ */
215
+ function convertReturn(node, language, filename, source) {
216
+ const location = nodeLocation(node, filename, source);
217
+ if (node.type != "ReturnStatement" || !node.argument)
218
+ return unsupportedSyntax(language, node.type, location);
219
+ return { expression: convertExpression(node.argument, language, filename, source), kind: "ReturnStatement", location };
220
+ }
221
+ /**
222
+ * Converts one supported local declaration or assignment.
223
+ * @param {import("@babel/types").Statement} node - Babel statement.
224
+ * @param {"javascript" | "typescript"} language - Frontend language.
225
+ * @param {string} filename - Source filename.
226
+ * @param {string} source - Complete source.
227
+ * @returns {import("../semantic/types.js").LocalStatement} Semantic local statement.
228
+ */
229
+ function convertLocalStatement(node, language, filename, source) {
230
+ const location = nodeLocation(node, filename, source);
231
+ if (node.type == "VariableDeclaration") {
232
+ if (!["let", "const"].includes(node.kind) || node.declarations.length != 1) {
233
+ return unsupportedSyntax(language, `${node.kind} declaration`, location);
234
+ }
235
+ const declarator = node.declarations[0];
236
+ const declaratorLocation = nodeLocation(declarator, filename, source);
237
+ if (declarator.id.type != "Identifier")
238
+ return unsupportedSyntax(language, declarator.id.type, declaratorLocation);
239
+ if (!declarator.init)
240
+ return unsupportedSyntax(language, "uninitialized declaration", declaratorLocation);
241
+ const type = language == "typescript"
242
+ ? convertTypeScriptType(declarator.id.typeAnnotation, `Local '${declarator.id.name}'`, declaratorLocation, filename, source)
243
+ : localJavaScriptType(node, declarator.id.name, filename, source);
244
+ return withParserRanges({
245
+ initializer: convertExpression(declarator.init, language, filename, source),
246
+ kind: "LocalDeclaration",
247
+ location,
248
+ mutable: node.kind == "let",
249
+ name: declarator.id.name,
250
+ type
251
+ }, {
252
+ name: identifierLocation(declarator.id, filename, source),
253
+ operator: tokenLocation(declarator, "=", declarator.id.end ?? declarator.start ?? 0, declarator.init.start ?? declarator.end ?? source.length, filename, source)
254
+ });
255
+ }
256
+ if (node.type == "ExpressionStatement" && node.expression.type == "AssignmentExpression") {
257
+ const assignment = node.expression;
258
+ const targetLocation = nodeLocation(assignment.left, filename, source);
259
+ if (assignment.operator != "=")
260
+ return unsupportedSyntax(language, `assignment ${assignment.operator}`, location);
261
+ if (assignment.left.type != "Identifier")
262
+ return unsupportedSyntax(language, assignment.left.type, targetLocation);
263
+ const target = withParserRanges({ kind: /** @type {const} */ ("IdentifierExpression"), location: targetLocation, name: assignment.left.name }, {
264
+ name: identifierLocation(assignment.left, filename, source)
265
+ });
266
+ return withParserRanges({
267
+ expression: convertExpression(assignment.right, language, filename, source),
268
+ kind: "AssignmentStatement",
269
+ location,
270
+ target
271
+ }, {
272
+ operator: tokenLocation(assignment, "=", assignment.left.end ?? assignment.start ?? 0, assignment.right.start ?? assignment.end ?? source.length, filename, source)
273
+ });
274
+ }
275
+ return unsupportedSyntax(language, node.type, location);
276
+ }
277
+ /**
278
+ * Reads an immediately associated JavaScript local `@type` tag.
279
+ * @param {import("@babel/types").VariableDeclaration} node - Local declaration.
280
+ * @param {string} name - Local name.
281
+ * @param {string} filename - Source filename.
282
+ * @param {string} source - Complete source.
283
+ * @returns {import("../semantic/types.js").TypeReference} Semantic type.
284
+ */
285
+ function localJavaScriptType(node, name, filename, source) {
286
+ const comment = node.leadingComments?.at(-1);
287
+ const location = nodeLocation(node, filename, source);
288
+ if (!comment || comment.type != "CommentBlock" || !comment.value.startsWith("*")) {
289
+ return missingType("javascript", `Local '${name}'`, location);
290
+ }
291
+ const gap = source.slice(comment.end ?? 0, node.start ?? 0);
292
+ if (!/^\s*$/u.test(gap) || (gap.match(/\n/gu)?.length ?? 0) > 1) {
293
+ return missingType("javascript", `Local '${name}'`, location);
294
+ }
295
+ const block = parseComment(`/*${comment.value}*/`)[0];
296
+ const tags = block?.tags.filter((tag) => tag.tag == "type") ?? [];
297
+ const tag = tags.length == 1 ? tags[0] : undefined;
298
+ return convertType(tag?.type, "javascript", `Local '${name}'`, location, tag ? commentTagLocation(comment, tag, "type", filename, source) : location);
299
+ }
300
+ /**
301
+ * Converts one exhaustive Babel statement.
302
+ * @param {import("@babel/types").Statement} node - Babel statement.
303
+ * @param {"javascript" | "typescript"} language - Frontend language.
304
+ * @param {string} filename - Source filename.
305
+ * @param {string} source - Complete source.
306
+ * @param {boolean} canonicalZeroRequired - Whether generated scalar output may contain signed zero.
307
+ * @returns {import("../semantic/types.js").Statement} Semantic statement.
308
+ */
309
+ function convertStatement(node, language, filename, source, canonicalZeroRequired) {
310
+ if (node.type == "ReturnStatement")
311
+ return convertReturn(node, language, filename, source);
312
+ if (node.type == "IfStatement")
313
+ return convertIf(node, language, filename, source, canonicalZeroRequired);
314
+ if (node.type == "VariableDeclaration" || node.type == "ExpressionStatement" && node.expression.type == "AssignmentExpression") {
315
+ return convertLocalStatement(node, language, filename, source);
316
+ }
317
+ if (node.type == "ExpressionStatement")
318
+ return convertPrint(node, language, filename, source, canonicalZeroRequired);
319
+ return unsupportedSyntax(language, node.type, nodeLocation(node, filename, source));
320
+ }
321
+ /**
322
+ * Converts one Babel block or normalized single-statement body.
323
+ * @param {import("@babel/types").BlockStatement | import("@babel/types").Statement[]} input - Parser block or statements.
324
+ * @param {"javascript" | "typescript"} language - Frontend language.
325
+ * @param {string} filename - Source filename.
326
+ * @param {string} source - Complete source.
327
+ * @param {boolean} canonicalZeroRequired - Whether generated scalar output may contain signed zero.
328
+ * @param {import("../semantic/types.js").SourceLocation} [location] - Location for a statement-array block.
329
+ * @returns {import("../semantic/types.js").Block} Semantic block.
330
+ */
331
+ function convertBlock(input, language, filename, source, canonicalZeroRequired, location) {
332
+ const statements = Array.isArray(input) ? input : input.body;
333
+ const directives = Array.isArray(input) ? [] : input.directives;
334
+ const blockLocation = location ?? nodeLocation(/** @type {import("@babel/types").BlockStatement} */ (input), filename, source);
335
+ if (directives.length > 0) {
336
+ return unsupportedSyntax(language, "directive", nodeLocation(directives[0], filename, source));
337
+ }
338
+ return {
339
+ kind: "Block",
340
+ location: blockLocation,
341
+ statements: statements.map((statement) => convertStatement(statement, language, filename, source, canonicalZeroRequired))
342
+ };
343
+ }
344
+ /**
345
+ * Reads JavaScript JSDoc types from a function.
346
+ * @param {import("@babel/types").FunctionDeclaration} node - Babel function node.
347
+ * @param {string} filename - Source filename.
348
+ * @param {string} source - Complete source.
349
+ * @returns {{parameters: Map<string, {location: import("../semantic/types.js").SourceLocation, sourceType: string}>, returnType: {location: import("../semantic/types.js").SourceLocation, sourceType: string} | undefined}} Parsed types.
350
+ */
351
+ function jsdocTypes(node, filename, source) {
352
+ const comment = node.leadingComments?.find((candidate) => candidate.type == "CommentBlock" && candidate.value.startsWith("*"));
353
+ if (!comment)
354
+ missingType("javascript", `Function '${node.id?.name ?? "anonymous"}'`, nodeLocation(node, filename, source));
355
+ const commentBlock = /** @type {import("@babel/types").CommentBlock} */ (comment);
356
+ const block = parseComment(`/*${commentBlock.value}*/`)[0];
357
+ const parameters = new Map(block.tags.filter((tag) => tag.tag == "param").map((tag) => [tag.name, {
358
+ location: commentTagLocation(commentBlock, tag, "type", filename, source),
359
+ sourceType: tag.type
360
+ }]));
361
+ const returnTag = block.tags.find((tag) => tag.tag == "returns" || tag.tag == "return");
362
+ return {
363
+ parameters,
364
+ returnType: returnTag ? { location: commentTagLocation(commentBlock, returnTag, "type", filename, source), sourceType: returnTag.type } : undefined
365
+ };
366
+ }
367
+ /**
368
+ * Requires a supported JavaScript JSDoc scalar type spelling.
369
+ * @param {string | undefined} sourceType - Source-language type.
370
+ * @param {"javascript" | "typescript"} language - Frontend language.
371
+ * @param {string} subject - Typed subject.
372
+ * @param {import("../semantic/types.js").SourceLocation} location - Source location.
373
+ * @param {import("../semantic/types.js").SourceLocation} [typeLocation] - Exact type token location.
374
+ * @returns {import("../semantic/types.js").TypeReference} Semantic type.
375
+ */
376
+ function convertType(sourceType, language, subject, location, typeLocation = location) {
377
+ return requireSourceScalarType(language, sourceType, subject, location, typeLocation);
378
+ }
379
+ /**
380
+ * Converts one exact TypeScript scalar keyword annotation.
381
+ * @param {import("@babel/types").TypeAnnotation | import("@babel/types").TSTypeAnnotation | import("@babel/types").Noop | null | undefined} annotation - Type annotation.
382
+ * @param {string} subject - Typed subject.
383
+ * @param {import("../semantic/types.js").SourceLocation} ownerLocation - Owning declaration location.
384
+ * @param {string} filename - Source filename.
385
+ * @param {string} source - Complete source.
386
+ * @returns {import("../semantic/types.js").TypeReference} Semantic scalar type.
387
+ */
388
+ function convertTypeScriptType(annotation, subject, ownerLocation, filename, source) {
389
+ if (!annotation)
390
+ return missingType("typescript", subject, ownerLocation);
391
+ if (annotation.type != "TSTypeAnnotation") {
392
+ return unsupportedSyntax("typescript", "unsupported scalar type", nodeLocation(annotation, filename, source));
393
+ }
394
+ const typeNode = annotation.typeAnnotation;
395
+ const sourceType = typeNode.type == "TSNumberKeyword"
396
+ ? "number"
397
+ : typeNode.type == "TSBooleanKeyword"
398
+ ? "boolean"
399
+ : typeNode.type == "TSStringKeyword" ? "string" : undefined;
400
+ if (!sourceType) {
401
+ return unsupportedSyntax("typescript", "unsupported scalar type", nodeLocation(typeNode, filename, source));
402
+ }
403
+ return requireSourceScalarType("typescript", sourceType, subject, ownerLocation, nodeLocation(typeNode, filename, source));
404
+ }
405
+ /**
406
+ * Converts a supported function declaration.
407
+ * @param {import("@babel/types").FunctionDeclaration} node - Babel function.
408
+ * @param {"javascript" | "typescript"} language - Frontend language.
409
+ * @param {string} filename - Source filename.
410
+ * @param {string} source - Complete source.
411
+ * @param {boolean} canonicalZeroRequired - Whether generated scalar output may contain signed zero.
412
+ * @returns {import("../semantic/types.js").FunctionDeclaration} Semantic function.
413
+ */
414
+ function convertFunction(node, language, filename, source, canonicalZeroRequired) {
415
+ const location = nodeLocation(node, filename, source);
416
+ if (!node.id)
417
+ return unsupportedSyntax(language, "anonymous function", location);
418
+ if (node.async)
419
+ return unsupportedSyntax(language, "async function", location);
420
+ if (node.generator)
421
+ return unsupportedSyntax(language, "generator function", location);
422
+ const documentedTypes = language == "javascript" ? jsdocTypes(node, filename, source) : undefined;
423
+ const parameters = node.params.map((parameter) => {
424
+ const parameterLocation = nodeLocation(parameter, filename, source);
425
+ if (parameter.type != "Identifier")
426
+ return unsupportedSyntax(language, parameter.type, parameterLocation);
427
+ const documentedType = documentedTypes?.parameters.get(parameter.name);
428
+ const type = language == "javascript"
429
+ ? convertType(documentedType?.sourceType, language, `Parameter '${parameter.name}'`, parameterLocation, documentedType?.location)
430
+ : convertTypeScriptType(parameter.typeAnnotation, `Parameter '${parameter.name}'`, parameterLocation, filename, source);
431
+ return withParserRanges({
432
+ kind: /** @type {const} */ ("Parameter"),
433
+ location: parameterLocation,
434
+ name: parameter.name,
435
+ type
436
+ }, { name: identifierLocation(parameter, filename, source) });
437
+ });
438
+ const returnAnnotation = node.returnType;
439
+ const returnType = language == "javascript"
440
+ ? convertType(documentedTypes?.returnType?.sourceType, language, `Function '${node.id.name}' return`, location, documentedTypes?.returnType?.location)
441
+ : convertTypeScriptType(returnAnnotation, `Function '${node.id.name}' return`, location, filename, source);
442
+ const body = convertBlock(node.body, language, filename, source, canonicalZeroRequired);
443
+ return withParserRanges({
444
+ body,
445
+ kind: "FunctionDeclaration",
446
+ location,
447
+ name: node.id.name,
448
+ parameters,
449
+ returnType
450
+ }, { name: identifierLocation(node.id, filename, source) });
451
+ }
452
+ /**
453
+ * Converts the existing exact if/else terminal shape.
454
+ * @param {import("@babel/types").IfStatement} node - Babel if statement.
455
+ * @param {"javascript" | "typescript"} language - Frontend language.
456
+ * @param {string} filename - Source filename.
457
+ * @param {string} source - Complete source.
458
+ * @param {boolean} canonicalZeroRequired - Whether generated scalar output may contain signed zero.
459
+ * @returns {import("../semantic/types.js").IfStatement} Semantic branch.
460
+ */
461
+ function convertIf(node, language, filename, source, canonicalZeroRequired) {
462
+ const location = nodeLocation(node, filename, source);
463
+ const consequent = node.consequent.type == "BlockStatement"
464
+ ? convertBlock(node.consequent, language, filename, source, canonicalZeroRequired)
465
+ : convertBlock([node.consequent], language, filename, source, canonicalZeroRequired, nodeLocation(node.consequent, filename, source));
466
+ const alternate = node.alternate
467
+ ? node.alternate.type == "BlockStatement"
468
+ ? convertBlock(node.alternate, language, filename, source, canonicalZeroRequired)
469
+ : convertBlock([node.alternate], language, filename, source, canonicalZeroRequired, nodeLocation(node.alternate, filename, source))
470
+ : undefined;
471
+ return {
472
+ ...(alternate ? { alternate } : {}),
473
+ condition: convertExpression(node.test, language, filename, source),
474
+ consequent,
475
+ kind: "IfStatement",
476
+ location
477
+ };
478
+ }
479
+ /**
480
+ * Reports whether Babel parsed an operation that makes generated JavaScript-family scalar output require zero canonicalization.
481
+ * @param {unknown} value - Babel parser subtree.
482
+ * @param {WeakSet<object>} [visited] - Cycle protection.
483
+ * @returns {boolean} Whether the subtree contains integer negation or multiplication syntax.
484
+ */
485
+ function parserTreeRequiresCanonicalZero(value, visited = new WeakSet()) {
486
+ if (!value || typeof value != "object")
487
+ return false;
488
+ if (visited.has(value))
489
+ return false;
490
+ visited.add(value);
491
+ if (Reflect.get(value, "type") == "UnaryExpression" && Reflect.get(value, "operator") == "-")
492
+ return true;
493
+ if (Reflect.get(value, "type") == "BinaryExpression" && Reflect.get(value, "operator") == "*")
494
+ return true;
495
+ return Object.entries(value).some(([key, child]) => !["extra", "innerComments", "leadingComments", "loc", "trailingComments"].includes(key) &&
496
+ (Array.isArray(child)
497
+ ? child.some((item) => parserTreeRequiresCanonicalZero(item, visited))
498
+ : parserTreeRequiresCanonicalZero(child, visited)));
499
+ }
500
+ /**
501
+ * Recognizes the parser-owned receiver parentheses emitted only for canonical integer output.
502
+ * @param {import("@babel/types").Expression | import("@babel/types").Super} receiver - Qualified-call receiver.
503
+ * @param {import("@babel/types").CallExpression} call - Outer `toString` call.
504
+ * @returns {boolean} Whether the receiver has the generated wrapper shape.
505
+ */
506
+ function hasCanonicalZeroReceiverWrapper(receiver, call) {
507
+ const extra = Reflect.get(receiver, "extra");
508
+ const expressionParentheses = ["BinaryExpression", "LogicalExpression", "UnaryExpression"].includes(receiver.type) ? 1 : 0;
509
+ const wrapperParentheses = expressionParentheses + 1;
510
+ const property = call.callee.type == "MemberExpression" ? call.callee.property : undefined;
511
+ return Boolean(extra) && typeof extra == "object" && Reflect.get(extra, "parenthesized") === true &&
512
+ Reflect.get(extra, "parenStart") === call.start && typeof call.start == "number" && typeof call.end == "number" &&
513
+ typeof receiver.start == "number" && typeof receiver.end == "number" && property?.type == "Identifier" &&
514
+ typeof property.start == "number" && typeof property.end == "number" && call.callee.start === call.start &&
515
+ receiver.start == call.start + wrapperParentheses && property.start == receiver.end + wrapperParentheses + 1 &&
516
+ property.end == property.start + "toString".length && call.end == property.end + 2;
517
+ }
518
+ /**
519
+ * Converts a console.log entry-point call.
520
+ * @param {import("@babel/types").Statement} node - Babel statement.
521
+ * @param {"javascript" | "typescript"} language - Frontend language.
522
+ * @param {string} filename - Source filename.
523
+ * @param {string} source - Complete source.
524
+ * @param {boolean} canonicalZeroRequired - Whether this parsed module contains a sign-producing integer operation.
525
+ * @returns {import("../semantic/types.js").PrintStatement} Print statement.
526
+ */
527
+ function convertPrint(node, language, filename, source, canonicalZeroRequired) {
528
+ const location = nodeLocation(node, filename, source);
529
+ if (node.type != "ExpressionStatement" || node.expression.type != "CallExpression") {
530
+ return unsupportedSyntax(language, node.type, location);
531
+ }
532
+ const call = node.expression;
533
+ const callee = call.callee;
534
+ if (callee.type != "MemberExpression" || callee.computed || callee.object.type != "Identifier" ||
535
+ callee.object.name != "console" || callee.property.type != "Identifier" || callee.property.name != "log" ||
536
+ call.arguments.length != 1) {
537
+ return unsupportedSyntax(language, "entry-point expression", location);
538
+ }
539
+ let argument = call.arguments[0];
540
+ if (argument.type == "SpreadElement" || argument.type == "ArgumentPlaceholder") {
541
+ return unsupportedSyntax(language, argument.type, nodeLocation(argument, filename, source));
542
+ }
543
+ if (argument.type == "CallExpression" && argument.callee.type == "MemberExpression" && !argument.callee.computed &&
544
+ !argument.callee.optional && argument.callee.object.type != "Super" && argument.callee.property.type == "Identifier" &&
545
+ argument.callee.property.name == "toString" && !argument.optional && !argument.typeArguments &&
546
+ !argument.typeParameters && argument.arguments.length == 0) {
547
+ if (!canonicalZeroRequired || !hasCanonicalZeroReceiverWrapper(argument.callee.object, argument)) {
548
+ return unsupportedSyntax(language, "entry-point qualified call", nodeLocation(argument.callee.property, filename, source));
549
+ }
550
+ argument = argument.callee.object;
551
+ }
552
+ return { expression: convertExpression(argument, language, filename, source), kind: "PrintStatement", location };
553
+ }
554
+ /**
555
+ * Parses JavaScript or TypeScript into the shared semantic module.
556
+ * @param {object} input - Parser input.
557
+ * @param {string} input.filename - Source filename.
558
+ * @param {"javascript" | "typescript"} input.language - Frontend language.
559
+ * @param {string} input.source - Source text.
560
+ * @returns {import("../semantic/types.js").SemanticModule} Semantic module.
561
+ */
562
+ export function parseJavaScriptTypeScript({ filename, language, source }) {
563
+ const file = parseBabelSource({ filename, language, source });
564
+ const tokens = file.tokens ?? [];
565
+ const tokenIndex = { byStart: new Map(tokens.map((token) => [token.start, token])), tokens };
566
+ const canonicalZeroRequired = parserTreeRequiresCanonicalZero(file.program);
567
+ rememberTokens(file, tokenIndex);
568
+ if (file.program.directives.length > 0) {
569
+ return unsupportedSyntax(language, "top-level directive", nodeLocation(file.program.directives[0], filename, source));
570
+ }
571
+ const functions = file.program.body.filter((node) => node.type == "FunctionDeclaration")
572
+ .map((node) => convertFunction(node, language, filename, source, canonicalZeroRequired));
573
+ const entryNodes = file.program.body.filter((node) => node.type != "FunctionDeclaration");
574
+ const location = moduleLocation(filename, source);
575
+ if (functions.length == 0)
576
+ return unsupportedSyntax(language, "module without a function", location);
577
+ const entryLocation = entryNodes.length == 0 ? location : locationFromOffsets(filename, source, entryNodes[0].start ?? 0, entryNodes.at(-1)?.end ?? source.length);
578
+ const entryBlock = convertBlock(entryNodes, language, filename, source, canonicalZeroRequired, entryLocation);
579
+ return {
580
+ entryPoint: {
581
+ body: entryBlock,
582
+ kind: "EntryPoint",
583
+ location: entryLocation
584
+ },
585
+ functions,
586
+ kind: "Module",
587
+ location
588
+ };
589
+ }
590
+ /**
591
+ * Invokes Babel and normalizes syntax failures.
592
+ * @param {object} input - Parser input.
593
+ * @param {string} input.filename - Source filename.
594
+ * @param {"javascript" | "typescript"} input.language - Frontend language.
595
+ * @param {string} input.source - Source text.
596
+ * @returns {import("@babel/parser").ParseResult<import("@babel/types").File>} Babel file.
597
+ */
598
+ function parseBabelSource({ filename, language, source }) {
599
+ try {
600
+ return parseBabel(source, {
601
+ plugins: language == "typescript" ? ["typescript"] : [],
602
+ sourceFilename: filename,
603
+ sourceType: "script",
604
+ tokens: true
605
+ });
606
+ }
607
+ catch (error) {
608
+ return parseFailure(language, error);
609
+ }
610
+ }
611
+ /**
612
+ * Associates Babel nodes with their parser token stream without leaking it into semantic values.
613
+ * @param {object} value - Current parser value.
614
+ * @param {BabelTokenIndex} tokens - Indexed parser tokens.
615
+ * @param {WeakSet<object>} [visited] - Cycle protection.
616
+ * @returns {void}
617
+ */
618
+ function rememberTokens(value, tokens, visited = new WeakSet()) {
619
+ if (visited.has(value))
620
+ return;
621
+ visited.add(value);
622
+ nodeTokens.set(value, tokens);
623
+ for (const child of Object.values(value)) {
624
+ if (Array.isArray(child)) {
625
+ for (const item of child)
626
+ if (item && typeof item == "object")
627
+ rememberTokens(item, tokens, visited);
628
+ }
629
+ else if (child && typeof child == "object")
630
+ rememberTokens(child, tokens, visited);
631
+ }
632
+ }
633
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiamF2YXNjcmlwdC10eXBlc2NyaXB0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2Zyb250ZW5kcy9qYXZhc2NyaXB0LXR5cGVzY3JpcHQuanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsWUFBWTtBQUVaLE9BQU8sRUFBQyxLQUFLLElBQUksVUFBVSxFQUFDLE1BQU0sZUFBZSxDQUFBO0FBQ2pELE9BQU8sRUFBQyxLQUFLLElBQUksWUFBWSxFQUFDLE1BQU0sZ0JBQWdCLENBQUE7QUFDcEQsT0FBTyxFQUFDLFdBQVcsRUFBRSxZQUFZLEVBQUUsaUJBQWlCLEVBQUMsTUFBTSxrQkFBa0IsQ0FBQTtBQUM3RSxPQUFPLEVBQUMsbUJBQW1CLEVBQUUsY0FBYyxFQUFDLE1BQU0seUJBQXlCLENBQUE7QUFDM0UsT0FBTyxFQUFDLG9CQUFvQixFQUFDLE1BQU0sMEJBQTBCLENBQUE7QUFDN0QsT0FBTyxFQUFDLGdCQUFnQixFQUFDLE1BQU0sMkJBQTJCLENBQUE7QUFDMUQsT0FBTyxFQUFDLHFCQUFxQixFQUFDLE1BQU0sd0JBQXdCLENBQUE7QUFDNUQsT0FBTyxFQUFDLHVCQUF1QixFQUFDLE1BQU0sY0FBYyxDQUFBO0FBRXBELDRIQUE0SDtBQUM1SCwwRkFBMEY7QUFFMUYsK0NBQStDO0FBQy9DLE1BQU0sVUFBVSxHQUFHLElBQUksT0FBTyxFQUFFLENBQUE7QUFDaEMsTUFBTSxxQkFBcUIsR0FBRyxJQUFJLEdBQUcsQ0FBQztJQUNwQyxDQUFDLEdBQUcsRUFBRSxLQUFLLENBQUM7SUFDWixDQUFDLEdBQUcsRUFBRSxVQUFVLENBQUM7SUFDakIsQ0FBQyxHQUFHLEVBQUUsVUFBVSxDQUFDO0lBQ2pCLENBQUMsS0FBSyxFQUFFLE9BQU8sQ0FBQztJQUNoQixDQUFDLEtBQUssRUFBRSxVQUFVLENBQUM7SUFDbkIsQ0FBQyxHQUFHLEVBQUUsVUFBVSxDQUFDO0lBQ2pCLENBQUMsSUFBSSxFQUFFLGlCQUFpQixDQUFDO0lBQ3pC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QUFDSCxTQUFTLGNBQWMsQ0FBQyxLQUFLLEVBQUUsTUFBTSxFQUFFLE9BQU8sR0FBRyxJQUFJLE9BQU8sRUFBRTtJQUM1RCxJQUFJLE9BQU8sQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDO1FBQUUsT0FBTTtJQUU5QixPQUFPLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxDQUFBO0lBQ2xCLFVBQVUsQ0FBQyxHQUFHLENBQUMsS0FBSyxFQUFFLE1BQU0sQ0FBQyxDQUFBO0lBRTdCLEtBQUssTUFBTSxLQUFLLElBQUksTUFBTSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDO1FBQ3pDLElBQUksS0FBSyxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDO1lBQ3pCLEtBQUssTUFBTSxJQUFJLElBQUksS0FBSztnQkFBRSxJQUFJLElBQUksSUFBSSxPQUFPLElBQUksSUFBSSxRQUFRO29CQUFFLGNBQWMsQ0FBQyxJQUFJLEVBQUUsTUFBTSxFQUFFLE9BQU8sQ0FBQyxDQUFBO1FBQ3RHLENBQUM7YUFBTSxJQUFJLEtBQUssSUFBSSxPQUFPLEtBQUssSUFBSSxRQUFRO1lBQUUsY0FBYyxDQUFDLEtBQUssRUFBRSxNQUFNLEVBQUUsT0FBTyxDQUFDLENBQUE7SUFDdEYsQ0FBQztBQUNILENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBAdHMtY2hlY2tcblxuaW1wb3J0IHtwYXJzZSBhcyBwYXJzZUJhYmVsfSBmcm9tIFwiQGJhYmVsL3BhcnNlclwiXG5pbXBvcnQge3BhcnNlIGFzIHBhcnNlQ29tbWVudH0gZnJvbSBcImNvbW1lbnQtcGFyc2VyXCJcbmltcG9ydCB7bWlzc2luZ1R5cGUsIHBhcnNlRmFpbHVyZSwgdW5zdXBwb3J0ZWRTeW50YXh9IGZyb20gXCIuLi9kaWFnbm9zdGljLmpzXCJcbmltcG9ydCB7bG9jYXRpb25Gcm9tT2Zmc2V0cywgbW9kdWxlTG9jYXRpb259IGZyb20gXCIuLi9zZW1hbnRpYy9sb2NhdGlvbi5qc1wiXG5pbXBvcnQge3dpdGhBZGFwdGVkT3BlcmF0aW9ufSBmcm9tIFwiLi4vc2VtYW50aWMvb3BlcmF0b3JzLmpzXCJcbmltcG9ydCB7d2l0aFBhcnNlclJhbmdlc30gZnJvbSBcIi4uL3NlbWFudGljL3Byb3ZlbmFuY2UuanNcIlxuaW1wb3J0IHtoYXNPbmx5VW5pY29kZVNjYWxhcnN9IGZyb20gXCIuLi9zZW1hbnRpYy9zY2FsYXJzLmpzXCJcbmltcG9ydCB7cmVxdWlyZVNvdXJjZVNjYWxhclR5cGV9IGZyb20gXCIuL3NjYWxhcnMuanNcIlxuXG4vKiogQHR5cGVkZWYge05vbk51bGxhYmxlPGltcG9ydChcIkBiYWJlbC9wYXJzZXJcIikuUGFyc2VSZXN1bHQ8aW1wb3J0KFwiQGJhYmVsL3R5cGVzXCIpLkZpbGU+W1widG9rZW5zXCJdPltudW1iZXJdfSBCYWJlbFRva2VuICovXG4vKiogQHR5cGVkZWYge3tieVN0YXJ0OiBNYXA8bnVtYmVyLCBCYWJlbFRva2VuPiwgdG9rZW5zOiBCYWJlbFRva2VuW119fSBCYWJlbFRva2VuSW5kZXggKi9cblxuLyoqIEB0eXBlIHtXZWFrTWFwPG9iamVjdCwgQmFiZWxUb2tlbkluZGV4Pn0gKi9cbmNvbnN0IG5vZGVUb2tlbnMgPSBuZXcgV2Vha01hcCgpXG5jb25zdCBiYWJlbEJpbmFyeU9wZXJhdGlvbnMgPSBuZXcgTWFwKFtcbiAgW1wiK1wiLCBcIkFkZFwiXSxcbiAgW1wiLVwiLCBcIlN1YnRyYWN0XCJdLFxuICBbXCIqXCIsIFwiTXVsdGlwbHlcIl0sXG4gIFtcIj09PVwiLCBcIkVxdWFsXCJdLFxuICBbXCIhPT1cIiwgXCJOb3RFcXVhbFwiXSxcbiAgW1wiPFwiLCBcIkxlc3NUaGFuXCJdLFxuICBbXCI8PVwiLCBcIkxlc3NUaGFuT3JFcXVhbFwiXSxcbiAgW1wiPlwiLCBcIkdyZWF0ZXJUaGFuXCJdLFxuICBbXCI+PVwiLCBcIkdyZWF0ZXJUaGFuT3JFcXVhbFwiXVxuXSlcblxuLyoqXG4gKiBSZXR1cm5zIGEgc291cmNlIGxvY2F0aW9uIGZvciBhIEJhYmVsIG5vZGUuXG4gKiBAcGFyYW0ge2ltcG9ydChcIkBiYWJlbC90eXBlc1wiKS5Ob2RlfSBub2RlIC0gQmFiZWwgbm9kZS5cbiAqIEBwYXJhbSB7c3RyaW5nfSBmaWxlbmFtZSAtIFNvdXJjZSBmaWxlbmFtZS5cbiAqIEBwYXJhbSB7c3RyaW5nfSBzb3VyY2UgLSBDb21wbGV0ZSBzb3VyY2UuXG4gKiBAcmV0dXJucyB7aW1wb3J0KFwiLi4vc2VtYW50aWMvdHlwZXMuanNcIikuU291cmNlTG9jYXRpb259IE5vcm1hbGl6ZWQgbG9jYXRpb24uXG4gKi9cbmZ1bmN0aW9uIG5vZGVMb2NhdGlvbihub2RlLCBmaWxlbmFtZSwgc291cmNlKSB7XG4gIGlmICh0eXBlb2Ygbm9kZS5zdGFydCAhPSBcIm51bWJlclwiIHx8IHR5cGVvZiBub2RlLmVuZCAhPSBcIm51bWJlclwiKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBCYWJlbCBvbWl0dGVkIHNvdXJjZSBvZmZzZXRzIGZvciAke25vZGUudHlwZX0uYClcbiAgfVxuXG4gIHJldHVybiBsb2NhdGlvbkZyb21PZmZzZXRzKGZpbGVuYW1lLCBzb3VyY2UsIG5vZGUuc3RhcnQsIG5vZGUuZW5kKVxufVxuXG4vKipcbiAqIFJldHVybnMgdGhlIGlkZW50aWZpZXIgc3BlbGxpbmcgcmF0aGVyIHRoYW4gYSB0cmFpbGluZyBUeXBlU2NyaXB0IGFubm90YXRpb24uXG4gKiBAcGFyYW0ge2ltcG9ydChcIkBiYWJlbC90eXBlc1wiKS5JZGVudGlmaWVyfSBub2RlIC0gUGFyc2VyIGlkZW50aWZpZXIuXG4gKiBAcGFyYW0ge3N0cmluZ30gZmlsZW5hbWUgLSBTb3VyY2UgZmlsZW5hbWUuXG4gKiBAcGFyYW0ge3N0cmluZ30gc291cmNlIC0gQ29tcGxldGUgc291cmNlLlxuICogQHJldHVybnMge2ltcG9ydChcIi4uL3NlbWFudGljL3R5cGVzLmpzXCIpLlNvdXJjZUxvY2F0aW9ufSBJZGVudGlmaWVyIGxvY2F0aW9uLlxuICovXG5mdW5jdGlvbiBpZGVudGlmaWVyTG9jYXRpb24obm9kZSwgZmlsZW5hbWUsIHNvdXJjZSkge1xuICBpZiAodHlwZW9mIG5vZGUuc3RhcnQgIT0gXCJudW1iZXJcIikgdGhyb3cgbmV3IEVycm9yKFwiQmFiZWwgb21pdHRlZCBhbiBpZGVudGlmaWVyIHN0YXJ0IG9mZnNldC5cIilcbiAgY29uc3QgdG9rZW4gPSBub2RlVG9rZW5zLmdldChub2RlKT8uYnlTdGFydC5nZXQobm9kZS5zdGFydClcblxuICBpZiAoIXRva2VuIHx8IHRva2VuLnR5cGUubGFiZWwgIT0gXCJuYW1lXCIpIHRocm93IG5ldyBFcnJvcihgQmFiZWwgb21pdHRlZCB0aGUgaWRlbnRpZmllciB0b2tlbiBmb3IgJyR7bm9kZS5uYW1lfScuYClcblxuICByZXR1cm4gbG9jYXRpb25Gcm9tT2Zmc2V0cyhmaWxlbmFtZSwgc291cmNlLCB0b2tlbi5zdGFydCwgdG9rZW4uZW5kKVxufVxuXG4vKipcbiAqIExvY2F0ZXMgb25lIEJhYmVsIHRva2VuIHdpdGhpbiBwYXJzZXItbm9kZSBib3VuZGFyaWVzLlxuICogQHBhcmFtIHtpbXBvcnQoXCJAYmFiZWwvdHlwZXNcIikuTm9kZX0gb3duZXIgLSBUb2tlbi1vd25pbmcgcGFyc2VyIG5vZGUuXG4gKiBAcGFyYW0ge3N0cmluZ30gdmFsdWUgLSBFeGFjdCB0b2tlbiBzcGVsbGluZy5cbiAqIEBwYXJhbSB7bnVtYmVyfSBzdGFydE9mZnNldCAtIEluY2x1c2l2ZSBib3VuZGFyeS5cbiAqIEBwYXJhbSB7bnVtYmVyfSBlbmRPZmZzZXQgLSBFeGNsdXNpdmUgYm91bmRhcnkuXG4gKiBAcGFyYW0ge3N0cmluZ30gZmlsZW5hbWUgLSBTb3VyY2UgZmlsZW5hbWUuXG4gKiBAcGFyYW0ge3N0cmluZ30gc291cmNlIC0gQ29tcGxldGUgc291cmNlLlxuICogQHJldHVybnMge2ltcG9ydChcIi4uL3NlbWFudGljL3R5cGVzLmpzXCIpLlNvdXJjZUxvY2F0aW9ufSBFeGFjdCB0b2tlbiBsb2NhdGlvbi5cbiAqL1xuZnVuY3Rpb24gdG9rZW5Mb2NhdGlvbihvd25lciwgdmFsdWUsIHN0YXJ0T2Zmc2V0LCBlbmRPZmZzZXQsIGZpbGVuYW1lLCBzb3VyY2UpIHtcbiAgY29uc3QgdG9rZW5zID0gbm9kZVRva2Vucy5nZXQob3duZXIpPy50b2tlbnMgPz8gW11cbiAgbGV0IGxvdyA9IDBcbiAgbGV0IGhpZ2ggPSB0b2tlbnMubGVuZ3RoXG5cbiAgd2hpbGUgKGxvdyA8IGhpZ2gpIHtcbiAgICBjb25zdCBtaWRkbGUgPSBNYXRoLmZsb29yKChsb3cgKyBoaWdoKSAvIDIpXG5cbiAgICBpZiAodG9rZW5zW21pZGRsZV0uc3RhcnQgPCBzdGFydE9mZnNldCkgbG93ID0gbWlkZGxlICsgMVxuICAgIGVsc2UgaGlnaCA9IG1pZGRsZVxuICB9XG4gIGxldCB0b2tlblxuXG4gIGZvciAobGV0IGluZGV4ID0gbG93OyBpbmRleCA8IHRva2Vucy5sZW5ndGggJiYgdG9rZW5zW2luZGV4XS5zdGFydCA8IGVuZE9mZnNldDsgaW5kZXgrKykge1xuICAgIGNvbnN0IGNhbmRpZGF0ZSA9IHRva2Vuc1tpbmRleF1cblxuICAgIGlmIChjYW5kaWRhdGUuZW5kIDw9IGVuZE9mZnNldCAmJiAoY2FuZGlkYXRlLnZhbHVlID09IHZhbHVlIHx8IGNhbmRpZGF0ZS50eXBlLmxhYmVsID09IHZhbHVlKSkge1xuICAgICAgdG9rZW4gPSBjYW5kaWRhdGVcbiAgICAgIGJyZWFrXG4gICAgfVxuICB9XG5cbiAgaWYgKCF0b2tlbikgdGhyb3cgbmV3IEVycm9yKGBCYWJlbCBvbWl0dGVkIHRva2VuICcke3ZhbHVlfScgYmV0d2VlbiAke3N0YXJ0T2Zmc2V0fSBhbmQgJHtlbmRPZmZzZXR9LmApXG5cbiAgcmV0dXJuIGxvY2F0aW9uRnJvbU9mZnNldHMoZmlsZW5hbWUsIHNvdXJjZSwgdG9rZW4uc3RhcnQsIHRva2VuLmVuZClcbn1cblxuLyoqXG4gKiBMb2NhdGVzIGEgY29tbWVudC1wYXJzZXIgdG9rZW4gaW5zaWRlIGEgQmFiZWwtb3duZWQgZG9jIGNvbW1lbnQuXG4gKiBAcGFyYW0ge2ltcG9ydChcIkBiYWJlbC90eXBlc1wiKS5Db21tZW50QmxvY2t9IGNvbW1lbnQgLSBCYWJlbCBkb2MgY29tbWVudC5cbiAqIEBwYXJhbSB7aW1wb3J0KFwiY29tbWVudC1wYXJzZXJcIikuU3BlY30gdGFnIC0gUGFyc2VkIGRvYyB0YWcuXG4gKiBAcGFyYW0ge1wibmFtZVwiIHwgXCJ0eXBlXCJ9IGZpZWxkIC0gVG9rZW4gZmllbGQuXG4gKiBAcGFyYW0ge3N0cmluZ30gZmlsZW5hbWUgLSBTb3VyY2UgZmlsZW5hbWUuXG4gKiBAcGFyYW0ge3N0cmluZ30gc291cmNlIC0gQ29tcGxldGUgc291cmNlLlxuICogQHJldHVybnMge2ltcG9ydChcIi4uL3NlbWFudGljL3R5cGVzLmpzXCIpLlNvdXJjZUxvY2F0aW9ufSBFeGFjdCB0b2tlbiBsb2NhdGlvbi5cbiAqL1xuZnVuY3Rpb24gY29tbWVudFRhZ0xvY2F0aW9uKGNvbW1lbnQsIHRhZywgZmllbGQsIGZpbGVuYW1lLCBzb3VyY2UpIHtcbiAgY29uc3QgbGluZSA9IHRhZy5zb3VyY2VbMF1cblxuICBpZiAodHlwZW9mIGNvbW1lbnQuc3RhcnQgIT0gXCJudW1iZXJcIiB8fCAhbGluZSkgdGhyb3cgbmV3IEVycm9yKGBDb21tZW50IHBhcnNlciBvbWl0dGVkIHRoZSBAJHt0YWcudGFnfSBzb3VyY2UgdG9rZW4uYClcblxuICBsZXQgbGluZVN0YXJ0ID0gY29tbWVudC5zdGFydFxuXG4gIGZvciAobGV0IGxpbmVOdW1iZXIgPSAwOyBsaW5lTnVtYmVyIDwgbGluZS5udW1iZXI7IGxpbmVOdW1iZXIrKykge1xuICAgIHdoaWxlIChsaW5lU3RhcnQgPCBzb3VyY2UubGVuZ3RoICYmIHNvdXJjZVtsaW5lU3RhcnRdICE9IFwiXFxyXCIgJiYgc291cmNlW2xpbmVTdGFydF0gIT0gXCJcXG5cIikgbGluZVN0YXJ0KytcbiAgICBpZiAoc291cmNlW2xpbmVTdGFydF0gPT0gXCJcXHJcIiAmJiBzb3VyY2VbbGluZVN0YXJ0ICsgMV0gPT0gXCJcXG5cIikgbGluZVN0YXJ0ICs9IDJcbiAgICBlbHNlIGxpbmVTdGFydCsrXG4gIH1cblxuICBjb25zdCBvcmRlcmVkRmllbGRzID0gW1wic3RhcnRcIiwgXCJkZWxpbWl0ZXJcIiwgXCJwb3N0RGVsaW1pdGVyXCIsIFwidGFnXCIsIFwicG9zdFRhZ1wiLCBcInR5cGVcIiwgXCJwb3N0VHlwZVwiLCBcIm5hbWVcIl1cbiAgY29uc3QgZmllbGRJbmRleCA9IG9yZGVyZWRGaWVsZHMuaW5kZXhPZihmaWVsZClcbiAgY29uc3Qgc3RhcnQgPSBsaW5lU3RhcnQgKyBvcmRlcmVkRmllbGRzLnNsaWNlKDAsIGZpZWxkSW5kZXgpLnJlZHVjZSgobGVuZ3RoLCBrZXkpID0+XG4gICAgbGVuZ3RoICsgbGluZS50b2tlbnNbLyoqIEB0eXBlIHtrZXlvZiB0eXBlb2YgbGluZS50b2tlbnN9ICovIChrZXkpXS5sZW5ndGgsIDApXG4gIGNvbnN0IHRva2VuID0gbGluZS50b2tlbnNbZmllbGRdXG5cbiAgcmV0dXJuIGxvY2F0aW9uRnJvbU9mZnNldHMoZmlsZW5hbWUsIHNvdXJjZSwgc3RhcnQsIHN0YXJ0ICsgdG9rZW4ubGVuZ3RoKVxufVxuXG4vKipcbiAqIENvbnZlcnRzIGEgc3VwcG9ydGVkIEJhYmVsIGV4cHJlc3Npb24uXG4gKiBAcGFyYW0ge2ltcG9ydChcIkBiYWJlbC90eXBlc1wiKS5FeHByZXNzaW9ufSBub2RlIC0gQmFiZWwgZXhwcmVzc2lvbi5cbiAqIEBwYXJhbSB7XCJqYXZhc2NyaXB0XCIgfCBcInR5cGVzY3JpcHRcIn0gbGFuZ3VhZ2UgLSBGcm9udGVuZCBsYW5ndWFnZS5cbiAqIEBwYXJhbSB7c3RyaW5nfSBmaWxlbmFtZSAtIFNvdXJjZSBmaWxlbmFtZS5cbiAqIEBwYXJhbSB7c3RyaW5nfSBzb3VyY2UgLSBDb21wbGV0ZSBzb3VyY2UuXG4gKiBAcmV0dXJucyB7aW1wb3J0KFwiLi4vc2VtYW50aWMvdHlwZXMuanNcIikuRXhwcmVzc2lvbn0gU2VtYW50aWMgZXhwcmVzc2lvbi5cbiAqL1xuZnVuY3Rpb24gY29udmVydEV4cHJlc3Npb24obm9kZSwgbGFuZ3VhZ2UsIGZpbGVuYW1lLCBzb3VyY2UpIHtcbiAgY29uc3QgbG9jYXRpb24gPSBub2RlTG9jYXRpb24obm9kZSwgZmlsZW5hbWUsIHNvdXJjZSlcblxuICBpZiAobm9kZS50eXBlID09IFwiSWRlbnRpZmllclwiKSB7XG4gICAgcmV0dXJuIHdpdGhQYXJzZXJSYW5nZXMoe2tpbmQ6IC8qKiBAdHlwZSB7Y29uc3R9ICovIChcIklkZW50aWZpZXJFeHByZXNzaW9uXCIpLCBsb2NhdGlvbiwgbmFtZTogbm9kZS5uYW1lfSwge1xuICAgICAgbmFtZTogaWRlbnRpZmllckxvY2F0aW9uKG5vZGUsIGZpbGVuYW1lLCBzb3VyY2UpXG4gICAgfSlcbiAgfVxuXG4gIGlmIChub2RlLnR5cGUgPT0gXCJOdW1lcmljTGl0ZXJhbFwiKSB7XG4gICAgaWYgKCFOdW1iZXIuaXNTYWZlSW50ZWdlcihub2RlLnZhbHVlKSkgcmV0dXJuIHVuc3VwcG9ydGVkU3ludGF4KGxhbmd1YWdlLCBcIm5vbi1zYWZlIGludGVnZXIgbGl0ZXJhbFwiLCBsb2NhdGlvbilcblxuICAgIHJldHVybiB3aXRoUGFyc2VyUmFuZ2VzKHtraW5kOiAvKiogQHR5cGUge2NvbnN0fSAqLyAoXCJJbnRlZ2VyTGl0ZXJhbFwiKSwgbG9jYXRpb24sIHZhbHVlOiBub2RlLnZhbHVlfSwge2xpdGVyYWw6IGxvY2F0aW9ufSlcbiAgfVxuXG4gIGlmIChub2RlLnR5cGUgPT0gXCJCb29sZWFuTGl0ZXJhbFwiKSB7XG4gICAgaWYgKHR5cGVvZiBub2RlLnZhbHVlICE9IFwiYm9vbGVhblwiKSByZXR1cm4gdW5zdXBwb3J0ZWRTeW50YXgobGFuZ3VhZ2UsIFwiaW52YWxpZCBib29sZWFuIGxpdGVyYWwgdmFsdWVcIiwgbG9jYXRpb24pXG5cbiAgICByZXR1cm4gd2l0aFBhcnNlclJhbmdlcyh7a2luZDogLyoqIEB0eXBlIHtjb25zdH0gKi8gKFwiQm9vbGVhbkxpdGVyYWxcIiksIGxvY2F0aW9uLCB2YWx1ZTogbm9kZS52YWx1ZX0sIHtsaXRlcmFsOiBsb2NhdGlvbn0pXG4gIH1cblxuICBpZiAobm9kZS50eXBlID09IFwiU3RyaW5nTGl0ZXJhbFwiKSB7XG4gICAgaWYgKHR5cGVvZiBub2RlLnZhbHVlICE9IFwic3RyaW5nXCIgfHwgIWhhc09ubHlVbmljb2RlU2NhbGFycyhub2RlLnZhbHVlKSkge1xuICAgICAgcmV0dXJuIHVuc3VwcG9ydGVkU3ludGF4KGxhbmd1YWdlLCBcImludmFsaWQgVW5pY29kZSBzdHJpbmcgbGl0ZXJhbFwiLCBsb2NhdGlvbilcbiAgICB9XG5cbiAgICByZXR1cm4gd2l0aFBhcnNlclJhbmdlcyh7a2luZDogLyoqIEB0eXBlIHtjb25zdH0gKi8gKFwiU3RyaW5nTGl0ZXJhbFwiKSwgbG9jYXRpb24sIHZhbHVlOiBub2RlLnZhbHVlfSwge2xpdGVyYWw6IGxvY2F0aW9ufSlcbiAgfVxuXG4gIGlmIChub2RlLnR5cGUgPT0gXCJUZW1wbGF0ZUxpdGVyYWxcIikge1xuICAgIGlmIChub2RlLmV4cHJlc3Npb25zLmxlbmd0aCA+IDApIHJldHVybiB1bnN1cHBvcnRlZFN5bnRheChsYW5ndWFnZSwgXCJpbnRlcnBvbGF0ZWQgc3RyaW5nXCIsIGxvY2F0aW9uKVxuXG4gICAgY29uc3QgcXVhc2kgPSBub2RlLnF1YXNpc1swXVxuXG4gICAgaWYgKHR5cGVvZiBxdWFzaS52YWx1ZS5jb29rZWQgIT0gXCJzdHJpbmdcIiB8fCAhaGFzT25seVVuaWNvZGVTY2FsYXJzKHF1YXNpLnZhbHVlLmNvb2tlZCkpIHtcbiAgICAgIHJldHVybiB1bnN1cHBvcnRlZFN5bnRheChsYW5ndWFnZSwgXCJpbnZhbGlkIFVuaWNvZGUgc3RyaW5nIGxpdGVyYWxcIiwgbG9jYXRpb24pXG4gICAgfVxuXG4gICAgcmV0dXJuIHdpdGhQYXJzZXJSYW5nZXMoe2tpbmQ6IC8qKiBAdHlwZSB7Y29uc3R9ICovIChcIlN0cmluZ0xpdGVyYWxcIiksIGxvY2F0aW9uLCB2YWx1ZTogcXVhc2kudmFsdWUuY29va2VkfSwge2xpdGVyYWw6IGxvY2F0aW9ufSlcbiAgfVxuXG4gIGlmIChub2RlLnR5cGUgPT0gXCJVbmFyeUV4cHJlc3Npb25cIiAmJiBbXCIhXCIsIFwiLVwiXS5pbmNsdWRlcyhub2RlLm9wZXJhdG9yKSkge1xuICAgIGNvbnN0IG9wZXJhbmQgPSBjb252ZXJ0RXhwcmVzc2lvbihub2RlLmFyZ3VtZW50LCBsYW5ndWFnZSwgZmlsZW5hbWUsIHNvdXJjZSlcbiAgICBjb25zdCBzZW1hbnRpYyA9IHdpdGhBZGFwdGVkT3BlcmF0aW9uKHdpdGhQYXJzZXJSYW5nZXMoe1xuICAgICAga2luZDogXCJVbmFyeUV4cHJlc3Npb25cIixcbiAgICAgIGxvY2F0aW9uLFxuICAgICAgb3BlcmFuZFxuICAgIH0sIHtcbiAgICAgIG9wZXJhdG9yOiB0b2tlbkxvY2F0aW9uKG5vZGUsIG5vZGUub3BlcmF0b3IsIG5vZGUuc3RhcnQgPz8gMCwgbm9kZS5hcmd1bWVudC5zdGFydCA/PyBub2RlLmVuZCA/PyBzb3VyY2UubGVuZ3RoLCBmaWxlbmFtZSwgc291cmNlKVxuICAgIH0pLCBub2RlLm9wZXJhdG9yID09IFwiIVwiID8gXCJOb3RcIiA6IFwiTmVnYXRlXCIpXG5cbiAgICByZXR1cm4gLyoqIEB0eXBlIHtpbXBvcnQoXCIuLi9zZW1hbnRpYy90eXBlcy5qc1wiKS5FeHByZXNzaW9ufSAqLyAoLyoqIEB0eXBlIHt1bmtub3dufSAqLyAoc2VtYW50aWMpKVxuICB9XG5cbiAgaWYgKG5vZGUudHlwZSA9PSBcIkxvZ2ljYWxFeHByZXNzaW9uXCIgJiYgW1wiJiZcIiwgXCJ8fFwiXS5pbmNsdWRlcyhub2RlLm9wZXJhdG9yKSkge1xuICAgIGNvbnN0IHNlbWFudGljID0gd2l0aEFkYXB0ZWRPcGVyYXRpb24od2l0aFBhcnNlclJhbmdlcyh7XG4gICAgICBraW5kOiBcIkJpbmFyeUV4cHJlc3Npb25cIixcbiAgICAgIGxlZnQ6IGNvbnZlcnRFeHByZXNzaW9uKG5vZGUubGVmdCwgbGFuZ3VhZ2UsIGZpbGVuYW1lLCBzb3VyY2UpLFxuICAgICAgbG9jYXRpb24sXG4gICAgICByaWdodDogY29udmVydEV4cHJlc3Npb24obm9kZS5yaWdodCwgbGFuZ3VhZ2UsIGZpbGVuYW1lLCBzb3VyY2UpXG4gICAgfSwge1xuICAgICAgb3BlcmF0b3I6IHRva2VuTG9jYXRpb24obm9kZSwgbm9kZS5vcGVyYXRvciwgbm9kZS5sZWZ0LmVuZCA/PyBub2RlLnN0YXJ0ID8/IDAsIG5vZGUucmlnaHQuc3RhcnQgPz8gbm9kZS5lbmQgPz8gc291cmNlLmxlbmd0aCwgZmlsZW5hbWUsIHNvdXJjZSlcbiAgICB9KSwgbm9kZS5vcGVyYXRvciA9PSBcIiYmXCIgPyBcIkFuZFwiIDogXCJPclwiKVxuXG4gICAgcmV0dXJuIC8qKiBAdHlwZSB7aW1wb3J0KFwiLi4vc2VtYW50aWMvdHlwZXMuanNcIikuRXhwcmVzc2lvbn0gKi8gKC8qKiBAdHlwZSB7dW5rbm93bn0gKi8gKHNlbWFudGljKSlcbiAgfVxuXG4gIGlmIChub2RlLnR5cGUgPT0gXCJCaW5hcnlFeHByZXNzaW9uXCIgJiYgYmFiZWxCaW5hcnlPcGVyYXRpb25zLmhhcyhub2RlLm9wZXJhdG9yKSkge1xuICAgIGlmIChub2RlLmxlZnQudHlwZSA9PSBcIlByaXZhdGVOYW1lXCIpIHVuc3VwcG9ydGVkU3ludGF4KGxhbmd1YWdlLCBub2RlLmxlZnQudHlwZSwgbG9jYXRpb24pXG5cbiAgICBjb25zdCBsZWZ0ID0gY29udmVydEV4cHJlc3Npb24obm9kZS5sZWZ0LCBsYW5ndWFnZSwgZmlsZW5hbWUsIHNvdXJjZSlcbiAgICBjb25zdCByaWdodCA9IGNvbnZlcnRFeHByZXNzaW9uKG5vZGUucmlnaHQsIGxhbmd1YWdlLCBmaWxlbmFtZSwgc291cmNlKVxuXG4gICAgY29uc3Qgc2VtYW50aWMgPSB3aXRoQWRhcHRlZE9wZXJhdGlvbih3aXRoUGFyc2VyUmFuZ2VzKHtcbiAgICAgIGtpbmQ6IFwiQmluYXJ5RXhwcmVzc2lvblwiLFxuICAgICAgbGVmdCxcbiAgICAgIGxvY2F0aW9uLFxuICAgICAgcmlnaHRcbiAgICB9LCB7XG4gICAgICBvcGVyYXRvcjogdG9rZW5Mb2NhdGlvbihub2RlLCBub2RlLm9wZXJhdG9yLCBub2RlLmxlZnQuZW5kID8/IG5vZGUuc3RhcnQgPz8gMCwgbm9kZS5yaWdodC5zdGFydCA/PyBub2RlLmVuZCA/PyBzb3VyY2UubGVuZ3RoLCBmaWxlbmFtZSwgc291cmNlKVxuICAgIH0pLCAvKiogQHR5cGUge2ltcG9ydChcIi4uL3NlbWFudGljL29wZXJhdG9ycy5qc1wiKS5BZGFwdGVkT3BlcmF0aW9ufSAqLyAoYmFiZWxCaW5hcnlPcGVyYXRpb25zLmdldChub2RlLm9wZXJhdG9yKSkpXG5cbiAgICByZXR1cm4gLyoqIEB0eXBlIHtpbXBvcnQoXCIuLi9zZW1hbnRpYy90eXBlcy5qc1wiKS5FeHByZXNzaW9ufSAqLyAoLyoqIEB0eXBlIHt1bmtub3dufSAqLyAoc2VtYW50aWMpKVxuICB9XG5cbiAgaWYgKG5vZGUudHlwZSA9PSBcIkJpbmFyeUV4cHJlc3Npb25cIiAmJiBbXCI9PVwiLCBcIiE9XCJdLmluY2x1ZGVzKG5vZGUub3BlcmF0b3IpKSB7XG4gICAgcmV0dXJuIHVuc3VwcG9ydGVkU3ludGF4KGxhbmd1YWdlLCBgY29lcmNpdmUgZXF1YWxpdHkgJHtub2RlLm9wZXJhdG9yfWAsIGxvY2F0aW9uKVxuICB9XG5cbiAgaWYgKG5vZGUudHlwZSA9PSBcIkNhbGxFeHByZXNzaW9uXCIgJiYgbm9kZS5jYWxsZWUudHlwZSA9PSBcIklkZW50aWZpZXJcIikge1xuICAgIGNvbnN0IGFyZ3VtZW50c18gPSBub2RlLmFyZ3VtZW50cy5tYXAoKGFyZ3VtZW50KSA9PiB7XG4gICAgICBpZiAoYXJndW1lbnQudHlwZSA9PSBcIlNwcmVhZEVsZW1lbnRcIiB8fCBhcmd1bWVudC50eXBlID09IFwiQXJndW1lbnRQbGFjZWhvbGRlclwiKSB7XG4gICAgICAgIHJldHVybiB1bnN1cHBvcnRlZFN5bnRheChsYW5ndWFnZSwgYXJndW1lbnQudHlwZSwgbm9kZUxvY2F0aW9uKGFyZ3VtZW50LCBmaWxlbmFtZSwgc291cmNlKSlcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIGNvbnZlcnRFeHByZXNzaW9uKGFyZ3VtZW50LCBsYW5ndWFnZSwgZmlsZW5hbWUsIHNvdXJjZSlcbiAgICB9KVxuXG4gICAgcmV0dXJuIHdpdGhQYXJzZXJSYW5nZXMoe2FyZ3VtZW50czogYXJndW1lbnRzXywgY2FsbGVlOiBub2RlLmNhbGxlZS5uYW1lLCBraW5kOiAvKiogQHR5cGUge2NvbnN0fSAqLyAoXCJDYWxsRXhwcmVzc2lvblwiKSwgbG9jYXRpb259LCB7XG4gICAgICBjYWxsZWU6IGlkZW50aWZpZXJMb2NhdGlvbihub2RlLmNhbGxlZSwgZmlsZW5hbWUsIHNvdXJjZSlcbiAgICB9KVxuICB9XG5cbiAgcmV0dXJuIHVuc3VwcG9ydGVkU3ludGF4KGxhbmd1YWdlLCBub2RlLnR5cGUsIGxvY2F0aW9uKVxufVxuXG4vKipcbiAqIENvbnZlcnRzIGEgc3VwcG9ydGVkIHJldHVybiBzdGF0ZW1lbnQuXG4gKiBAcGFyYW0ge2ltcG9ydChcIkBiYWJlbC90eXBlc1wiKS5TdGF0ZW1lbnR9IG5vZGUgLSBCYWJlbCBzdGF0ZW1lbnQuXG4gKiBAcGFyYW0ge1wiamF2YXNjcmlwdFwiIHwgXCJ0eXBlc2NyaXB0XCJ9IGxhbmd1YWdlIC0gRnJvbnRlbmQgbGFuZ3VhZ2UuXG4gKiBAcGFyYW0ge3N0cmluZ30gZmlsZW5hbWUgLSBTb3VyY2UgZmlsZW5hbWUuXG4gKiBAcGFyYW0ge3N0cmluZ30gc291cmNlIC0gQ29tcGxldGUgc291cmNlLlxuICogQHJldHVybnMge2ltcG9ydChcIi4uL3NlbWFudGljL3R5cGVzLmpzXCIpLlJldHVyblN0YXRlbWVudH0gU2VtYW50aWMgcmV0dXJuLlxuICovXG5mdW5jdGlvbiBjb252ZXJ0UmV0dXJuKG5vZGUsIGxhbmd1YWdlLCBmaWxlbmFtZSwgc291cmNlKSB7XG4gIGNvbnN0IGxvY2F0aW9uID0gbm9kZUxvY2F0aW9uKG5vZGUsIGZpbGVuYW1lLCBzb3VyY2UpXG5cbiAgaWYgKG5vZGUudHlwZSAhPSBcIlJldHVyblN0YXRlbWVudFwiIHx8ICFub2RlLmFyZ3VtZW50KSByZXR1cm4gdW5zdXBwb3J0ZWRTeW50YXgobGFuZ3VhZ2UsIG5vZGUudHlwZSwgbG9jYXRpb24pXG5cbiAgcmV0dXJuIHtleHByZXNzaW9uOiBjb252ZXJ0RXhwcmVzc2lvbihub2RlLmFyZ3VtZW50LCBsYW5ndWFnZSwgZmlsZW5hbWUsIHNvdXJjZSksIGtpbmQ6IFwiUmV0dXJuU3RhdGVtZW50XCIsIGxvY2F0aW9ufVxufVxuXG4vKipcbiAqIENvbnZlcnRzIG9uZSBzdXBwb3J0ZWQgbG9jYWwgZGVjbGFyYXRpb24gb3IgYXNzaWdubWVudC5cbiAqIEBwYXJhbSB7aW1wb3J0KFwiQGJhYmVsL3R5cGVzXCIpLlN0YXRlbWVudH0gbm9kZSAtIEJhYmVsIHN0YXRlbWVudC5cbiAqIEBwYXJhbSB7XCJqYXZhc2NyaXB0XCIgfCBcInR5cGVzY3JpcHRcIn0gbGFuZ3VhZ2UgLSBGcm9udGVuZCBsYW5ndWFnZS5cbiAqIEBwYXJhbSB7c3RyaW5nfSBmaWxlbmFtZSAtIFNvdXJjZSBmaWxlbmFtZS5cbiAqIEBwYXJhbSB7c3RyaW5nfSBzb3VyY2UgLSBDb21wbGV0ZSBzb3VyY2UuXG4gKiBAcmV0dXJucyB7aW1wb3J0KFwiLi4vc2VtYW50aWMvdHlwZXMuanNcIikuTG9jYWxTdGF0ZW1lbnR9IFNlbWFudGljIGxvY2FsIHN0YXRlbWVudC5cbiAqL1xuZnVuY3Rpb24gY29udmVydExvY2FsU3RhdGVtZW50KG5vZGUsIGxhbmd1YWdlLCBmaWxlbmFtZSwgc291cmNlKSB7XG4gIGNvbnN0IGxvY2F0aW9uID0gbm9kZUxvY2F0aW9uKG5vZGUsIGZpbGVuYW1lLCBzb3VyY2UpXG5cbiAgaWYgKG5vZGUudHlwZSA9PSBcIlZhcmlhYmxlRGVjbGFyYXRpb25cIikge1xuICAgIGlmICghW1wibGV0XCIsIFwiY29uc3RcIl0uaW5jbHVkZXMobm9kZS5raW5kKSB8fCBub2RlLmRlY2xhcmF0aW9ucy5sZW5ndGggIT0gMSkge1xuICAgICAgcmV0dXJuIHVuc3VwcG9ydGVkU3ludGF4KGxhbmd1YWdlLCBgJHtub2RlLmtpbmR9IGRlY2xhcmF0aW9uYCwgbG9jYXRpb24pXG4gICAgfVxuXG4gICAgY29uc3QgZGVjbGFyYXRvciA9IG5vZGUuZGVjbGFyYXRpb25zWzBdXG4gICAgY29uc3QgZGVjbGFyYXRvckxvY2F0aW9uID0gbm9kZUxvY2F0aW9uKGRlY2xhcmF0b3IsIGZpbGVuYW1lLCBzb3VyY2UpXG5cbiAgICBpZiAoZGVjbGFyYXRvci5pZC50eXBlICE9IFwiSWRlbnRpZmllclwiKSByZXR1cm4gdW5zdXBwb3J0ZWRTeW50YXgobGFuZ3VhZ2UsIGRlY2xhcmF0b3IuaWQudHlwZSwgZGVjbGFyYXRvckxvY2F0aW9uKVxuICAgIGlmICghZGVjbGFyYXRvci5pbml0KSByZXR1cm4gdW5zdXBwb3J0ZWRTeW50YXgobGFuZ3VhZ2UsIFwidW5pbml0aWFsaXplZCBkZWNsYXJhdGlvblwiLCBkZWNsYXJhdG9yTG9jYXRpb24pXG5cbiAgICBjb25zdCB0eXBlID0gbGFuZ3VhZ2UgPT0gXCJ0eXBlc2NyaXB0XCJcbiAgICAgID8gY29udmVydFR5cGVTY3JpcHRUeXBlKGRlY2xhcmF0b3IuaWQudHlwZUFubm90YXRpb24sIGBMb2NhbCAnJHtkZWNsYXJhdG9yLmlkLm5hbWV9J2AsIGRlY2xhcmF0b3JMb2NhdGlvbiwgZmlsZW5hbWUsIHNvdXJjZSlcbiAgICAgIDogbG9jYWxKYXZhU2NyaXB0VHlwZShub2RlLCBkZWNsYXJhdG9yLmlkLm5hbWUsIGZpbGVuYW1lLCBzb3VyY2UpXG5cbiAgICByZXR1cm4gd2l0aFBhcnNlclJhbmdlcyh7XG4gICAgICBpbml0aWFsaXplcjogY29udmVydEV4cHJlc3Npb24oZGVjbGFyYXRvci5pbml0LCBsYW5ndWFnZSwgZmlsZW5hbWUsIHNvdXJjZSksXG4gICAgICBraW5kOiBcIkxvY2FsRGVjbGFyYXRpb25cIixcbiAgICAgIGxvY2F0aW9uLFxuICAgICAgbXV0YWJsZTogbm9kZS5raW5kID09IFwibGV0XCIsXG4gICAgICBuYW1lOiBkZWNsYXJhdG9yLmlkLm5hbWUsXG4gICAgICB0eXBlXG4gICAgfSwge1xuICAgICAgbmFtZTogaWRlbnRpZmllckxvY2F0aW9uKGRlY2xhcmF0b3IuaWQsIGZpbGVuYW1lLCBzb3VyY2UpLFxuICAgICAgb3BlcmF0b3I6IHRva2VuTG9jYXRpb24oZGVjbGFyYXRvciwgXCI9XCIsIGRlY2xhcmF0b3IuaWQuZW5kID8/IGRlY2xhcmF0b3Iuc3RhcnQgPz8gMCwgZGVjbGFyYXRvci5pbml0LnN0YXJ0ID8/IGRlY2xhcmF0b3IuZW5kID8/IHNvdXJjZS5sZW5ndGgsIGZpbGVuYW1lLCBzb3VyY2UpXG4gICAgfSlcbiAgfVxuXG4gIGlmIChub2RlLnR5cGUgPT0gXCJFeHByZXNzaW9uU3RhdGVtZW50XCIgJiYgbm9kZS5leHByZXNzaW9uLnR5cGUgPT0gXCJBc3NpZ25tZW50RXhwcmVzc2lvblwiKSB7XG4gICAgY29uc3QgYXNzaWdubWVudCA9IG5vZGUuZXhwcmVzc2lvblxuICAgIGNvbnN0IHRhcmdldExvY2F0aW9uID0gbm9kZUxvY2F0aW9uKGFzc2lnbm1lbnQubGVmdCwgZmlsZW5hbWUsIHNvdXJjZSlcblxuICAgIGlmIChhc3NpZ25tZW50Lm9wZXJhdG9yICE9IFwiPVwiKSByZXR1cm4gdW5zdXBwb3J0ZWRTeW50YXgobGFuZ3VhZ2UsIGBhc3NpZ25tZW50ICR7YXNzaWdubWVudC5vcGVyYXRvcn1gLCBsb2NhdGlvbilcbiAgICBpZiAoYXNzaWdubWVudC5sZWZ0LnR5cGUgIT0gXCJJZGVudGlmaWVyXCIpIHJldHVybiB1bnN1cHBvcnRlZFN5bnRheChsYW5ndWFnZSwgYXNzaWdubWVudC5sZWZ0LnR5cGUsIHRhcmdldExvY2F0aW9uKVxuXG4gICAgY29uc3QgdGFyZ2V0ID0gd2l0aFBhcnNlclJhbmdlcyh7a2luZDogLyoqIEB0eXBlIHtjb25zdH0gKi8gKFwiSWRlbnRpZmllckV4cHJlc3Npb25cIiksIGxvY2F0aW9uOiB0YXJnZXRMb2NhdGlvbiwgbmFtZTogYXNzaWdubWVudC5sZWZ0Lm5hbWV9LCB7XG4gICAgICBuYW1lOiBpZGVudGlmaWVyTG9jYXRpb24oYXNzaWdubWVudC5sZWZ0LCBmaWxlbmFtZSwgc291cmNlKVxuICAgIH0pXG5cbiAgICByZXR1cm4gd2l0aFBhcnNlclJhbmdlcyh7XG4gICAgICBleHByZXNzaW9uOiBjb252ZXJ0RXhwcmVzc2lvbihhc3NpZ25tZW50LnJpZ2h0LCBsYW5ndWFnZSwgZmlsZW5hbWUsIHNvdXJjZSksXG4gICAgICBraW5kOiBcIkFzc2lnbm1lbnRTdGF0ZW1lbnRcIixcbiAgICAgIGxvY2F0aW9uLFxuICAgICAgdGFyZ2V0XG4gICAgfSwge1xuICAgICAgb3BlcmF0b3I6IHRva2VuTG9jYXRpb24oYXNzaWdubWVudCwgXCI9XCIsIGFzc2lnbm1lbnQubGVmdC5lbmQgPz8gYXNzaWdubWVudC5zdGFydCA/PyAwLCBhc3NpZ25tZW50LnJpZ2h0LnN0YXJ0ID8/IGFzc2lnbm1lbnQuZW5kID8/IHNvdXJjZS5sZW5ndGgsIGZpbGVuYW1lLCBzb3VyY2UpXG4gICAgfSlcbiAgfVxuXG4gIHJldHVybiB1bnN1cHBvcnRlZFN5bnRheChsYW5ndWFnZSwgbm9kZS50eXBlLCBsb2NhdGlvbilcbn1cblxuLyoqXG4gKiBSZWFkcyBhbiBpbW1lZGlhdGVseSBhc3NvY2lhdGVkIEphdmFTY3JpcHQgbG9jYWwgYEB0eXBlYCB0YWcuXG4gKiBAcGFyYW0ge2ltcG9ydChcIkBiYWJlbC90eXBlc1wiKS5WYXJpYWJsZURlY2xhcmF0aW9ufSBub2RlIC0gTG9jYWwgZGVjbGFyYXRpb24uXG4gKiBAcGFyYW0ge3N0cmluZ30gbmFtZSAtIExvY2FsIG5hbWUuXG4gKiBAcGFyYW0ge3N0cmluZ30gZmlsZW5hbWUgLSBTb3VyY2UgZmlsZW5hbWUuXG4gKiBAcGFyYW0ge3N0cmluZ30gc291cmNlIC0gQ29tcGxldGUgc291cmNlLlxuICogQHJldHVybnMge2ltcG9ydChcIi4uL3NlbWFudGljL3R5cGVzLmpzXCIpLlR5cGVSZWZlcmVuY2V9IFNlbWFudGljIHR5cGUuXG4gKi9cbmZ1bmN0aW9uIGxvY2FsSmF2YVNjcmlwdFR5cGUobm9kZSwgbmFtZSwgZmlsZW5hbWUsIHNvdXJjZSkge1xuICBjb25zdCBjb21tZW50ID0gbm9kZS5sZWFkaW5nQ29tbWVudHM/LmF0KC0xKVxuICBjb25zdCBsb2NhdGlvbiA9IG5vZGVMb2NhdGlvbihub2RlLCBmaWxlbmFtZSwgc291cmNlKVxuXG4gIGlmICghY29tbWVudCB8fCBjb21tZW50LnR5cGUgIT0gXCJDb21tZW50QmxvY2tcIiB8fCAhY29tbWVudC52YWx1ZS5zdGFydHNXaXRoKFwiKlwiKSkge1xuICAgIHJldHVybiBtaXNzaW5nVHlwZShcImphdmFzY3JpcHRcIiwgYExvY2FsICcke25hbWV9J2AsIGxvY2F0aW9uKVxuICB9XG5cbiAgY29uc3QgZ2FwID0gc291cmNlLnNsaWNlKGNvbW1lbnQuZW5kID8/IDAsIG5vZGUuc3RhcnQgPz8gMClcblxuICBpZiAoIS9eXFxzKiQvdS50ZXN0KGdhcCkgfHwgKGdhcC5tYXRjaCgvXFxuL2d1KT8ubGVuZ3RoID8/IDApID4gMSkge1xuICAgIHJldHVybiBtaXNzaW5nVHlwZShcImphdmFzY3JpcHRcIiwgYExvY2FsICcke25hbWV9J2AsIGxvY2F0aW9uKVxuICB9XG5cbiAgY29uc3QgYmxvY2sgPSBwYXJzZUNvbW1lbnQoYC8qJHtjb21tZW50LnZhbHVlfSovYClbMF1cbiAgY29uc3QgdGFncyA9IGJsb2NrPy50YWdzLmZpbHRlcigodGFnKSA9PiB0YWcudGFnID09IFwidHlwZVwiKSA/PyBbXVxuXG4gIGNvbnN0IHRhZyA9IHRhZ3MubGVuZ3RoID09IDEgPyB0YWdzWzBdIDogdW5kZWZpbmVkXG5cbiAgcmV0dXJuIGNvbnZlcnRUeXBlKFxuICAgIHRhZz8udHlwZSxcbiAgICBcImphdmFzY3JpcHRcIixcbiAgICBgTG9jYWwgJyR7bmFtZX0nYCxcbiAgICBsb2NhdGlvbixcbiAgICB0YWcgPyBjb21tZW50VGFnTG9jYXRpb24oY29tbWVudCwgdGFnLCBcInR5cGVcIiwgZmlsZW5hbWUsIHNvdXJjZSkgOiBsb2NhdGlvblxuICApXG59XG5cbi8qKlxuICogQ29udmVydHMgb25lIGV4aGF1c3RpdmUgQmFiZWwgc3RhdGVtZW50LlxuICogQHBhcmFtIHtpbXBvcnQoXCJAYmFiZWwvdHlwZXNcIikuU3RhdGVtZW50fSBub2RlIC0gQmFiZWwgc3RhdGVtZW50LlxuICogQHBhcmFtIHtcImphdmFzY3JpcHRcIiB8IFwidHlwZXNjcmlwdFwifSBsYW5ndWFnZSAtIEZyb250ZW5kIGxhbmd1YWdlLlxuICogQHBhcmFtIHtzdHJpbmd9IGZpbGVuYW1lIC0gU291cmNlIGZpbGVuYW1lLlxuICogQHBhcmFtIHtzdHJpbmd9IHNvdXJjZSAtIENvbXBsZXRlIHNvdXJjZS5cbiAqIEBwYXJhbSB7Ym9vbGVhbn0gY2Fub25pY2FsWmVyb1JlcXVpcmVkIC0gV2hldGhlciBnZW5lcmF0ZWQgc2NhbGFyIG91dHB1dCBtYXkgY29udGFpbiBzaWduZWQgemVyby5cbiAqIEByZXR1cm5zIHtpbXBvcnQoXCIuLi9zZW1hbnRpYy90eXBlcy5qc1wiKS5TdGF0ZW1lbnR9IFNlbWFudGljIHN0YXRlbWVudC5cbiAqL1xuZnVuY3Rpb24gY29udmVydFN0YXRlbWVudChub2RlLCBsYW5ndWFnZSwgZmlsZW5hbWUsIHNvdXJjZSwgY2Fub25pY2FsWmVyb1JlcXVpcmVkKSB7XG4gIGlmIChub2RlLnR5cGUgPT0gXCJSZXR1cm5TdGF0ZW1lbnRcIikgcmV0dXJuIGNvbnZlcnRSZXR1cm4obm9kZSwgbGFuZ3VhZ2UsIGZpbGVuYW1lLCBzb3VyY2UpXG4gIGlmIChub2RlLnR5cGUgPT0gXCJJZlN0YXRlbWVudFwiKSByZXR1cm4gY29udmVydElmKG5vZGUsIGxhbmd1YWdlLCBmaWxlbmFtZSwgc291cmNlLCBjYW5vbmljYWxaZXJvUmVxdWlyZWQpXG4gIGlmIChub2RlLnR5cGUgPT0gXCJWYXJpYWJsZURlY2xhcmF0aW9uXCIgfHwgbm9kZS50eXBlID09IFwiRXhwcmVzc2lvblN0YXRlbWVudFwiICYmIG5vZGUuZXhwcmVzc2lvbi50eXBlID09IFwiQXNzaWdubWVudEV4cHJlc3Npb25cIikge1xuICAgIHJldHVybiBjb252ZXJ0TG9jYWxTdGF0ZW1lbnQobm9kZSwgbGFuZ3VhZ2UsIGZpbGVuYW1lLCBzb3VyY2UpXG4gIH1cbiAgaWYgKG5vZGUudHlwZSA9PSBcIkV4cHJlc3Npb25TdGF0ZW1lbnRcIikgcmV0dXJuIGNvbnZlcnRQcmludChub2RlLCBsYW5ndWFnZSwgZmlsZW5hbWUsIHNvdXJjZSwgY2Fub25pY2FsWmVyb1JlcXVpcmVkKVxuXG4gIHJldHVybiB1bnN1cHBvcnRlZFN5bnRheChsYW5ndWFnZSwgbm9kZS50eXBlLCBub2RlTG9jYXRpb24obm9kZSwgZmlsZW5hbWUsIHNvdXJjZSkpXG59XG5cbi8qKlxuICogQ29udmVydHMgb25lIEJhYmVsIGJsb2NrIG9yIG5vcm1hbGl6ZWQgc2luZ2xlLXN0YXRlbWVudCBib2R5LlxuICogQHBhcmFtIHtpbXBvcnQoXCJAYmFiZWwvdHlwZXNcIikuQmxvY2tTdGF0ZW1lbnQgfCBpbXBvcnQoXCJAYmFiZWwvdHlwZXNcIikuU3RhdGVtZW50W119IGlucHV0IC0gUGFyc2VyIGJsb2NrIG9yIHN0YXRlbWVudHMuXG4gKiBAcGFyYW0ge1wiamF2YXNjcmlwdFwiIHwgXCJ0eXBlc2NyaXB0XCJ9IGxhbmd1YWdlIC0gRnJvbnRlbmQgbGFuZ3VhZ2UuXG4gKiBAcGFyYW0ge3N0cmluZ30gZmlsZW5hbWUgLSBTb3VyY2UgZmlsZW5hbWUuXG4gKiBAcGFyYW0ge3N0cmluZ30gc291cmNlIC0gQ29tcGxldGUgc291cmNlLlxuICogQHBhcmFtIHtib29sZWFufSBjYW5vbmljYWxaZXJvUmVxdWlyZWQgLSBXaGV0aGVyIGdlbmVyYXRlZCBzY2FsYXIgb3V0cHV0IG1heSBjb250YWluIHNpZ25lZCB6ZXJvLlxuICogQHBhcmFtIHtpbXBvcnQoXCIuLi9zZW1hbnRpYy90eXBlcy5qc1wiKS5Tb3VyY2VMb2NhdGlvbn0gW2xvY2F0aW9uXSAtIExvY2F0aW9uIGZvciBhIHN0YXRlbWVudC1hcnJheSBibG9jay5cbiAqIEByZXR1cm5zIHtpbXBvcnQoXCIuLi9zZW1hbnRpYy90eXBlcy5qc1wiKS5CbG9ja30gU2VtYW50aWMgYmxvY2suXG4gKi9cbmZ1bmN0aW9uIGNvbnZlcnRCbG9jayhpbnB1dCwgbGFuZ3VhZ2UsIGZpbGVuYW1lLCBzb3VyY2UsIGNhbm9uaWNhbFplcm9SZXF1aXJlZCwgbG9jYXRpb24pIHtcbiAgY29uc3Qgc3RhdGVtZW50cyA9IEFycmF5LmlzQXJyYXkoaW5wdXQpID8gaW5wdXQgOiBpbnB1dC5ib2R5XG4gIGNvbnN0IGRpcmVjdGl2ZXMgPSBBcnJheS5pc0FycmF5KGlucHV0KSA/IFtdIDogaW5wdXQuZGlyZWN0aXZlc1xuICBjb25zdCBibG9ja0xvY2F0aW9uID0gbG9jYXRpb24gPz8gbm9kZUxvY2F0aW9uKC8qKiBAdHlwZSB7aW1wb3J0KFwiQGJhYmVsL3R5cGVzXCIpLkJsb2NrU3RhdGVtZW50fSAqLyAoaW5wdXQpLCBmaWxlbmFtZSwgc291cmNlKVxuXG4gIGlmIChkaXJlY3RpdmVzLmxlbmd0aCA+IDApIHtcbiAgICByZXR1cm4gdW5zdXBwb3J0ZWRTeW50YXgobGFuZ3VhZ2UsIFwiZGlyZWN0aXZlXCIsIG5vZGVMb2NhdGlvbihkaXJlY3RpdmVzWzBdLCBmaWxlbmFtZSwgc291cmNlKSlcbiAgfVxuXG4gIHJldHVybiB7XG4gICAga2luZDogXCJCbG9ja1wiLFxuICAgIGxvY2F0aW9uOiBibG9ja0xvY2F0aW9uLFxuICAgIHN0YXRlbWVudHM6IHN0YXRlbWVudHMubWFwKChzdGF0ZW1lbnQpID0+IGNvbnZlcnRTdGF0ZW1lbnQoc3RhdGVtZW50LCBsYW5ndWFnZSwgZmlsZW5hbWUsIHNvdXJjZSwgY2Fub25pY2FsWmVyb1JlcXVpcmVkKSlcbiAgfVxufVxuXG4vKipcbiAqIFJlYWRzIEphdmFTY3JpcHQgSlNEb2MgdHlwZXMgZnJvbSBhIGZ1bmN0aW9uLlxuICogQHBhcmFtIHtpbXBvcnQoXCJAYmFiZWwvdHlwZXNcIikuRnVuY3Rpb25EZWNsYXJhdGlvbn0gbm9kZSAtIEJhYmVsIGZ1bmN0aW9uIG5vZGUuXG4gKiBAcGFyYW0ge3N0cmluZ30gZmlsZW5hbWUgLSBTb3VyY2UgZmlsZW5hbWUuXG4gKiBAcGFyYW0ge3N0cmluZ30gc291cmNlIC0gQ29tcGxldGUgc291cmNlLlxuICogQHJldHVybnMge3twYXJhbWV0ZXJzOiBNYXA8c3RyaW5nLCB7bG9jYXRpb246IGltcG9ydChcIi4uL3NlbWFudGljL3R5cGVzLmpzXCIpLlNvdXJjZUxvY2F0aW9uLCBzb3VyY2VUeXBlOiBzdHJpbmd9PiwgcmV0dXJuVHlwZToge2xvY2F0aW9uOiBpbXBvcnQoXCIuLi9zZW1hbnRpYy90eXBlcy5qc1wiKS5Tb3VyY2VMb2NhdGlvbiwgc291cmNlVHlwZTogc3RyaW5nfSB8IHVuZGVmaW5lZH19IFBhcnNlZCB0eXBlcy5cbiAqL1xuZnVuY3Rpb24ganNkb2NUeXBlcyhub2RlLCBmaWxlbmFtZSwgc291cmNlKSB7XG4gIGNvbnN0IGNvbW1lbnQgPSBub2RlLmxlYWRpbmdDb21tZW50cz8uZmluZCgoY2FuZGlkYXRlKSA9PiBjYW5kaWRhdGUudHlwZSA9PSBcIkNvbW1lbnRCbG9ja1wiICYmIGNhbmRpZGF0ZS52YWx1ZS5zdGFydHNXaXRoKFwiKlwiKSlcblxuICBpZiAoIWNvbW1lbnQpIG1pc3NpbmdUeXBlKFwiamF2YXNjcmlwdFwiLCBgRnVuY3Rpb24gJyR7bm9kZS5pZD8ubmFtZSA/PyBcImFub255bW91c1wifSdgLCBub2RlTG9jYXRpb24obm9kZSwgZmlsZW5hbWUsIHNvdXJjZSkpXG5cbiAgY29uc3QgY29tbWVudEJsb2NrID0gLyoqIEB0eXBlIHtpbXBvcnQoXCJAYmFiZWwvdHlwZXNcIikuQ29tbWVudEJsb2NrfSAqLyAoY29tbWVudClcbiAgY29uc3QgYmxvY2sgPSBwYXJzZUNvbW1lbnQoYC8qJHtjb21tZW50QmxvY2sudmFsdWV9Ki9gKVswXVxuICBjb25zdCBwYXJhbWV0ZXJzID0gbmV3IE1hcChibG9jay50YWdzLmZpbHRlcigodGFnKSA9PiB0YWcudGFnID09IFwicGFyYW1cIikubWFwKCh0YWcpID0+IFt0YWcubmFtZSwge1xuICAgIGxvY2F0aW9uOiBjb21tZW50VGFnTG9jYXRpb24oY29tbWVudEJsb2NrLCB0YWcsIFwidHlwZVwiLCBmaWxlbmFtZSwgc291cmNlKSxcbiAgICBzb3VyY2VUeXBlOiB0YWcudHlwZVxuICB9XSkpXG4gIGNvbnN0IHJldHVyblRhZyA9IGJsb2NrLnRhZ3MuZmluZCgodGFnKSA9PiB0YWcudGFnID09IFwicmV0dXJuc1wiIHx8IHRhZy50YWcgPT0gXCJyZXR1cm5cIilcblxuICByZXR1cm4ge1xuICAgIHBhcmFtZXRlcnMsXG4gICAgcmV0dXJuVHlwZTogcmV0dXJuVGFnID8ge2xvY2F0aW9uOiBjb21tZW50VGFnTG9jYXRpb24oY29tbWVudEJsb2NrLCByZXR1cm5UYWcsIFwidHlwZVwiLCBmaWxlbmFtZSwgc291cmNlKSwgc291cmNlVHlwZTogcmV0dXJuVGFnLnR5cGV9IDogdW5kZWZpbmVkXG4gIH1cbn1cblxuLyoqXG4gKiBSZXF1aXJlcyBhIHN1cHBvcnRlZCBKYXZhU2NyaXB0IEpTRG9jIHNjYWxhciB0eXBlIHNwZWxsaW5nLlxuICogQHBhcmFtIHtzdHJpbmcgfCB1bmRlZmluZWR9IHNvdXJjZVR5cGUgLSBTb3VyY2UtbGFuZ3VhZ2UgdHlwZS5cbiAqIEBwYXJhbSB7XCJqYXZhc2NyaXB0XCIgfCBcInR5cGVzY3JpcHRcIn0gbGFuZ3VhZ2UgLSBGcm9udGVuZCBsYW5ndWFnZS5cbiAqIEBwYXJhbSB7c3RyaW5nfSBzdWJqZWN0IC0gVHlwZWQgc3ViamVjdC5cbiAqIEBwYXJhbSB7aW1wb3J0KFwiLi4vc2VtYW50aWMvdHlwZXMuanNcIikuU291cmNlTG9jYXRpb259IGxvY2F0aW9uIC0gU291cmNlIGxvY2F0aW9uLlxuICogQHBhcmFtIHtpbXBvcnQoXCIuLi9zZW1hbnRpYy90eXBlcy5qc1wiKS5Tb3VyY2VMb2NhdGlvbn0gW3R5cGVMb2NhdGlvbl0gLSBFeGFjdCB0eXBlIHRva2VuIGxvY2F0aW9uLlxuICogQHJldHVybnMge2ltcG9ydChcIi4uL3NlbWFudGljL3R5cGVzLmpzXCIpLlR5cGVSZWZlcmVuY2V9IFNlbWFudGljIHR5cGUuXG4gKi9cbmZ1bmN0aW9uIGNvbnZlcnRUeXBlKHNvdXJjZVR5cGUsIGxhbmd1YWdlLCBzdWJqZWN0LCBsb2NhdGlvbiwgdHlwZUxvY2F0aW9uID0gbG9jYXRpb24pIHtcbiAgcmV0dXJuIHJlcXVpcmVTb3VyY2VTY2FsYXJUeXBlKGxhbmd1YWdlLCBzb3VyY2VUeXBlLCBzdWJqZWN0LCBsb2NhdGlvbiwgdHlwZUxvY2F0aW9uKVxufVxuXG4vKipcbiAqIENvbnZlcnRzIG9uZSBleGFjdCBUeXBlU2NyaXB0IHNjYWxhciBrZXl3b3JkIGFubm90YXRpb24uXG4gKiBAcGFyYW0ge2ltcG9ydChcIkBiYWJlbC90eXBlc1wiKS5UeXBlQW5ub3RhdGlvbiB8IGltcG9ydChcIkBiYWJlbC90eXBlc1wiKS5UU1R5cGVBbm5vdGF0aW9uIHwgaW1wb3J0KFwiQGJhYmVsL3R5cGVzXCIpLk5vb3AgfCBudWxsIHwgdW5kZWZpbmVkfSBhbm5vdGF0aW9uIC0gVHlwZSBhbm5vdGF0aW9uLlxuICogQHBhcmFtIHtzdHJpbmd9IHN1YmplY3QgLSBUeXBlZCBzdWJqZWN0LlxuICogQHBhcmFtIHtpbXBvcnQoXCIuLi9zZW1hbnRpYy90eXBlcy5qc1wiKS5Tb3VyY2VMb2NhdGlvbn0gb3duZXJMb2NhdGlvbiAtIE93bmluZyBkZWNsYXJhdGlvbiBsb2NhdGlvbi5cbiAqIEBwYXJhbSB7c3RyaW5nfSBmaWxlbmFtZSAtIFNvdXJjZSBmaWxlbmFtZS5cbiAqIEBwYXJhbSB7c3RyaW5nfSBzb3VyY2UgLSBDb21wbGV0ZSBzb3VyY2UuXG4gKiBAcmV0dXJucyB7aW1wb3J0KFwiLi4vc2VtYW50aWMvdHlwZXMuanNcIikuVHlwZVJlZmVyZW5jZX0gU2VtYW50aWMgc2NhbGFyIHR5cGUuXG4gKi9cbmZ1bmN0aW9uIGNvbnZlcnRUeXBlU2NyaXB0VHlwZShhbm5vdGF0aW9uLCBzdWJqZWN0LCBvd25lckxvY2F0aW9uLCBmaWxlbmFtZSwgc291cmNlKSB7XG4gIGlmICghYW5ub3RhdGlvbikgcmV0dXJuIG1pc3NpbmdUeXBlKFwidHlwZXNjcmlwdFwiLCBzdWJqZWN0LCBvd25lckxvY2F0aW9uKVxuICBpZiAoYW5ub3RhdGlvbi50eXBlICE9IFwiVFNUeXBlQW5ub3RhdGlvblwiKSB7XG4gICAgcmV0dXJuIHVuc3VwcG9ydGVkU3ludGF4KFwidHlwZXNjcmlwdFwiLCBcInVuc3VwcG9ydGVkIHNjYWxhciB0eXBlXCIsIG5vZGVMb2NhdGlvbihhbm5vdGF0aW9uLCBmaWxlbmFtZSwgc291cmNlKSlcbiAgfVxuXG4gIGNvbnN0IHR5cGVOb2RlID0gYW5ub3RhdGlvbi50eXBlQW5ub3RhdGlvblxuICBjb25zdCBzb3VyY2VUeXBlID0gdHlwZU5vZGUudHlwZSA9PSBcIlRTTnVtYmVyS2V5d29yZFwiXG4gICAgPyBcIm51bWJlclwiXG4gICAgOiB0eXBlTm9kZS50eXBlID09IFwiVFNCb29sZWFuS2V5d29yZFwiXG4gICAgICA/IFwiYm9vbGVhblwiXG4gICAgICA6IHR5cGVOb2RlLnR5cGUgPT0gXCJUU1N0cmluZ0tleXdvcmRcIiA/IFwic3RyaW5nXCIgOiB1bmRlZmluZWRcblxuICBpZiAoIXNvdXJjZVR5cGUpIHtcbiAgICByZXR1cm4gdW5zdXBwb3J0ZWRTeW50YXgoXCJ0eXBlc2NyaXB0XCIsIFwidW5zdXBwb3J0ZWQgc2NhbGFyIHR5cGVcIiwgbm9kZUxvY2F0aW9uKHR5cGVOb2RlLCBmaWxlbmFtZSwgc291cmNlKSlcbiAgfVxuXG4gIHJldHVybiByZXF1aXJlU291cmNlU2NhbGFyVHlwZShcInR5cGVzY3JpcHRcIiwgc291cmNlVHlwZSwgc3ViamVjdCwgb3duZXJMb2NhdGlvbiwgbm9kZUxvY2F0aW9uKHR5cGVOb2RlLCBmaWxlbmFtZSwgc291cmNlKSlcbn1cblxuLyoqXG4gKiBDb252ZXJ0cyBhIHN1cHBvcnRlZCBmdW5jdGlvbiBkZWNsYXJhdGlvbi5cbiAqIEBwYXJhbSB7aW1wb3J0KFwiQGJhYmVsL3R5cGVzXCIpLkZ1bmN0aW9uRGVjbGFyYXRpb259IG5vZGUgLSBCYWJlbCBmdW5jdGlvbi5cbiAqIEBwYXJhbSB7XCJqYXZhc2NyaXB0XCIgfCBcInR5cGVzY3JpcHRcIn0gbGFuZ3VhZ2UgLSBGcm9udGVuZCBsYW5ndWFnZS5cbiAqIEBwYXJhbSB7c3RyaW5nfSBmaWxlbmFtZSAtIFNvdXJjZSBmaWxlbmFtZS5cbiAqIEBwYXJhbSB7c3RyaW5nfSBzb3VyY2UgLSBDb21wbGV0ZSBzb3VyY2UuXG4gKiBAcGFyYW0ge2Jvb2xlYW59IGNhbm9uaWNhbFplcm9SZXF1aXJlZCAtIFdoZXRoZXIgZ2VuZXJhdGVkIHNjYWxhciBvdXRwdXQgbWF5IGNvbnRhaW4gc2lnbmVkIHplcm8uXG4gKiBAcmV0dXJucyB7aW1wb3J0KFwiLi4vc2VtYW50aWMvdHlwZXMuanNcIikuRnVuY3Rpb25EZWNsYXJhdGlvbn0gU2VtYW50aWMgZnVuY3Rpb24uXG4gKi9cbmZ1bmN0aW9uIGNvbnZlcnRGdW5jdGlvbihub2RlLCBsYW5ndWFnZSwgZmlsZW5hbWUsIHNvdXJjZSwgY2Fub25pY2FsWmVyb1JlcXVpcmVkKSB7XG4gIGNvbnN0IGxvY2F0aW9uID0gbm9kZUxvY2F0aW9uKG5vZGUsIGZpbGVuYW1lLCBzb3VyY2UpXG5cbiAgaWYgKCFub2RlLmlkKSByZXR1cm4gdW5zdXBwb3J0ZWRTeW50YXgobGFuZ3VhZ2UsIFwiYW5vbnltb3VzIGZ1bmN0aW9uXCIsIGxvY2F0aW9uKVxuICBpZiAobm9kZS5hc3luYykgcmV0dXJuIHVuc3VwcG9ydGVkU3ludGF4KGxhbmd1YWdlLCBcImFzeW5jIGZ1bmN0aW9uXCIsIGxvY2F0aW9uKVxuICBpZiAobm9kZS5nZW5lcmF0b3IpIHJldHVybiB1bnN1cHBvcnRlZFN5bnRheChsYW5ndWFnZSwgXCJnZW5lcmF0b3IgZnVuY3Rpb25cIiwgbG9jYXRpb24pXG5cbiAgY29uc3QgZG9jdW1lbnRlZFR5cGVzID0gbGFuZ3VhZ2UgPT0gXCJqYXZhc2NyaXB0XCIgPyBqc2RvY1R5cGVzKG5vZGUsIGZpbGVuYW1lLCBzb3VyY2UpIDogdW5kZWZpbmVkXG4gIGNvbnN0IHBhcmFtZXRlcnMgPSBub2RlLnBhcmFtcy5tYXAoKHBhcmFtZXRlcikgPT4ge1xuICAgIGNvbnN0IHBhcmFtZXRlckxvY2F0aW9uID0gbm9kZUxvY2F0aW9uKHBhcmFtZXRlciwgZmlsZW5hbWUsIHNvdXJjZSlcblxuICAgIGlmIChwYXJhbWV0ZXIudHlwZSAhPSBcIklkZW50aWZpZXJcIikgcmV0dXJuIHVuc3VwcG9ydGVkU3ludGF4KGxhbmd1YWdlLCBwYXJhbWV0ZXIudHlwZSwgcGFyYW1ldGVyTG9jYXRpb24pXG5cbiAgICBjb25zdCBkb2N1bWVudGVkVHlwZSA9IGRvY3VtZW50ZWRUeXBlcz8ucGFyYW1ldGVycy5nZXQocGFyYW1ldGVyLm5hbWUpXG4gICAgY29uc3QgdHlwZSA9IGxhbmd1YWdlID09IFwiamF2YXNjcmlwdFwiXG4gICAgICA/IGNvbnZlcnRUeXBlKGRvY3VtZW50ZWRUeXBlPy5zb3VyY2VUeXBlLCBsYW5ndWFnZSwgYFBhcmFtZXRlciAnJHtwYXJhbWV0ZXIubmFtZX0nYCwgcGFyYW1ldGVyTG9jYXRpb24sIGRvY3VtZW50ZWRUeXBlPy5sb2NhdGlvbilcbiAgICAgIDogY29udmVydFR5cGVTY3JpcHRUeXBlKHBhcmFtZXRlci50eXBlQW5ub3RhdGlvbiwgYFBhcmFtZXRlciAnJHtwYXJhbWV0ZXIubmFtZX0nYCwgcGFyYW1ldGVyTG9jYXRpb24sIGZpbGVuYW1lLCBzb3VyY2UpXG5cbiAgICByZXR1cm4gd2l0aFBhcnNlclJhbmdlcyh7XG4gICAgICBraW5kOiAvKiogQHR5cGUge2NvbnN0fSAqLyAoXCJQYXJhbWV0ZXJcIiksXG4gICAgICBsb2NhdGlvbjogcGFyYW1ldGVyTG9jYXRpb24sXG4gICAgICBuYW1lOiBwYXJhbWV0ZXIubmFtZSxcbiAgICAgIHR5cGVcbiAgICB9LCB7bmFtZTogaWRlbnRpZmllckxvY2F0aW9uKHBhcmFtZXRlciwgZmlsZW5hbWUsIHNvdXJjZSl9KVxuICB9KVxuICBjb25zdCByZXR1cm5Bbm5vdGF0aW9uID0gbm9kZS5yZXR1cm5UeXBlXG4gIGNvbnN0IHJldHVyblR5cGUgPSBsYW5ndWFnZSA9PSBcImphdmFzY3JpcHRcIlxuICAgID8gY29udmVydFR5cGUoZG9jdW1lbnRlZFR5cGVzPy5yZXR1cm5UeXBlPy5zb3VyY2VUeXBlLCBsYW5ndWFnZSwgYEZ1bmN0aW9uICcke25vZGUuaWQubmFtZX0nIHJldHVybmAsIGxvY2F0aW9uLCBkb2N1bWVudGVkVHlwZXM/LnJldHVyblR5cGU/LmxvY2F0aW9uKVxuICAgIDogY29udmVydFR5cGVTY3JpcHRUeXBlKHJldHVybkFubm90YXRpb24sIGBGdW5jdGlvbiAnJHtub2RlLmlkLm5hbWV9JyByZXR1cm5gLCBsb2NhdGlvbiwgZmlsZW5hbWUsIHNvdXJjZSlcbiAgY29uc3QgYm9keSA9IGNvbnZlcnRCbG9jayhub2RlLmJvZHksIGxhbmd1YWdlLCBmaWxlbmFtZSwgc291cmNlLCBjYW5vbmljYWxaZXJvUmVxdWlyZWQpXG5cbiAgcmV0dXJuIHdpdGhQYXJzZXJSYW5nZXMoe1xuICAgIGJvZHksXG4gICAga2luZDogXCJGdW5jdGlvbkRlY2xhcmF0aW9uXCIsXG4gICAgbG9jYXRpb24sXG4gICAgbmFtZTogbm9kZS5pZC5uYW1lLFxuICAgIHBhcmFtZXRlcnMsXG4gICAgcmV0dXJuVHlwZVxuICB9LCB7bmFtZTogaWRlbnRpZmllckxvY2F0aW9uKG5vZGUuaWQsIGZpbGVuYW1lLCBzb3VyY2UpfSlcbn1cblxuLyoqXG4gKiBDb252ZXJ0cyB0aGUgZXhpc3RpbmcgZXhhY3QgaWYvZWxzZSB0ZXJtaW5hbCBzaGFwZS5cbiAqIEBwYXJhbSB7aW1wb3J0KFwiQGJhYmVsL3R5cGVzXCIpLklmU3RhdGVtZW50fSBub2RlIC0gQmFiZWwgaWYgc3RhdGVtZW50LlxuICogQHBhcmFtIHtcImphdmFzY3JpcHRcIiB8IFwidHlwZXNjcmlwdFwifSBsYW5ndWFnZSAtIEZyb250ZW5kIGxhbmd1YWdlLlxuICogQHBhcmFtIHtzdHJpbmd9IGZpbGVuYW1lIC0gU291cmNlIGZpbGVuYW1lLlxuICogQHBhcmFtIHtzdHJpbmd9IHNvdXJjZSAtIENvbXBsZXRlIHNvdXJjZS5cbiAqIEBwYXJhbSB7Ym9vbGVhbn0gY2Fub25pY2FsWmVyb1JlcXVpcmVkIC0gV2hldGhlciBnZW5lcmF0ZWQgc2NhbGFyIG91dHB1dCBtYXkgY29udGFpbiBzaWduZWQgemVyby5cbiAqIEByZXR1cm5zIHtpbXBvcnQoXCIuLi9zZW1hbnRpYy90eXBlcy5qc1wiKS5JZlN0YXRlbWVudH0gU2VtYW50aWMgYnJhbmNoLlxuICovXG5mdW5jdGlvbiBjb252ZXJ0SWYobm9kZSwgbGFuZ3VhZ2UsIGZpbGVuYW1lLCBzb3VyY2UsIGNhbm9uaWNhbFplcm9SZXF1aXJlZCkge1xuICBjb25zdCBsb2NhdGlvbiA9IG5vZGVMb2NhdGlvbihub2RlLCBmaWxlbmFtZSwgc291cmNlKVxuICBjb25zdCBjb25zZXF1ZW50ID0gbm9kZS5jb25zZXF1ZW50LnR5cGUgPT0gXCJCbG9ja1N0YXRlbWVudFwiXG4gICAgPyBjb252ZXJ0QmxvY2sobm9kZS5jb25zZXF1ZW50LCBsYW5ndWFnZSwgZmlsZW5hbWUsIHNvdXJjZSwgY2Fub25pY2FsWmVyb1JlcXVpcmVkKVxuICAgIDogY29udmVydEJsb2NrKFtub2RlLmNvbnNlcXVlbnRdLCBsYW5ndWFnZSwgZmlsZW5hbWUsIHNvdXJjZSwgY2Fub25pY2FsWmVyb1JlcXVpcmVkLCBub2RlTG9jYXRpb24obm9kZS5jb25zZXF1ZW50LCBmaWxlbmFtZSwgc291cmNlKSlcbiAgY29uc3QgYWx0ZXJuYXRlID0gbm9kZS5hbHRlcm5hdGVcbiAgICA/IG5vZGUuYWx0ZXJuYXRlLnR5cGUgPT0gXCJCbG9ja1N0YXRlbWVudFwiXG4gICAgICA/IGNvbnZlcnRCbG9jayhub2RlLmFsdGVybmF0ZSwgbGFuZ3VhZ2UsIGZpbGVuYW1lLCBzb3VyY2UsIGNhbm9uaWNhbFplcm9SZXF1aXJlZClcbiAgICAgIDogY29udmVydEJsb2NrKFtub2RlLmFsdGVybmF0ZV0sIGxhbmd1YWdlLCBmaWxlbmFtZSwgc291cmNlLCBjYW5vbmljYWxaZXJvUmVxdWlyZWQsIG5vZGVMb2NhdGlvbihub2RlLmFsdGVybmF0ZSwgZmlsZW5hbWUsIHNvdXJjZSkpXG4gICAgOiB1bmRlZmluZWRcblxuICByZXR1cm4ge1xuICAgIC4uLihhbHRlcm5hdGUgPyB7YWx0ZXJuYXRlfSA6IHt9KSxcbiAgICBjb25kaXRpb246IGNvbnZlcnRFeHByZXNzaW9uKG5vZGUudGVzdCwgbGFuZ3VhZ2UsIGZpbGVuYW1lLCBzb3VyY2UpLFxuICAgIGNvbnNlcXVlbnQsXG4gICAga2luZDogXCJJZlN0YXRlbWVudFwiLFxuICAgIGxvY2F0aW9uXG4gIH1cbn1cblxuLyoqXG4gKiBSZXBvcnRzIHdoZXRoZXIgQmFiZWwgcGFyc2VkIGFuIG9wZXJhdGlvbiB0aGF0IG1ha2VzIGdlbmVyYXRlZCBKYXZhU2NyaXB0LWZhbWlseSBzY2FsYXIgb3V0cHV0IHJlcXVpcmUgemVybyBjYW5vbmljYWxpemF0aW9uLlxuICogQHBhcmFtIHt1bmtub3dufSB2YWx1ZSAtIEJhYmVsIHBhcnNlciBzdWJ0cmVlLlxuICogQHBhcmFtIHtXZWFrU2V0PG9iamVjdD59IFt2aXNpdGVkXSAtIEN5Y2xlIHByb3RlY3Rpb24uXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gV2hldGhlciB0aGUgc3VidHJlZSBjb250YWlucyBpbnRlZ2VyIG5lZ2F0aW9uIG9yIG11bHRpcGxpY2F0aW9uIHN5bnRheC5cbiAqL1xuZnVuY3Rpb24gcGFyc2VyVHJlZVJlcXVpcmVzQ2Fub25pY2FsWmVybyh2YWx1ZSwgdmlzaXRlZCA9IG5ldyBXZWFrU2V0KCkpIHtcbiAgaWYgKCF2YWx1ZSB8fCB0eXBlb2YgdmFsdWUgIT0gXCJvYmplY3RcIikgcmV0dXJuIGZhbHNlXG4gIGlmICh2aXNpdGVkLmhhcyh2YWx1ZSkpIHJldHVybiBmYWxzZVxuXG4gIHZpc2l0ZWQuYWRkKHZhbHVlKVxuICBpZiAoUmVmbGVjdC5nZXQodmFsdWUsIFwidHlwZVwiKSA9PSBcIlVuYXJ5RXhwcmVzc2lvblwiICYmIFJlZmxlY3QuZ2V0KHZhbHVlLCBcIm9wZXJhdG9yXCIpID09IFwiLVwiKSByZXR1cm4gdHJ1ZVxuICBpZiAoUmVmbGVjdC5nZXQodmFsdWUsIFwidHlwZVwiKSA9PSBcIkJpbmFyeUV4cHJlc3Npb25cIiAmJiBSZWZsZWN0LmdldCh2YWx1ZSwgXCJvcGVyYXRvclwiKSA9PSBcIipcIikgcmV0dXJuIHRydWVcblxuICByZXR1cm4gT2JqZWN0LmVudHJpZXModmFsdWUpLnNvbWUoKFtrZXksIGNoaWxkXSkgPT5cbiAgICAhW1wiZXh0cmFcIiwgXCJpbm5lckNvbW1lbnRzXCIsIFwibGVhZGluZ0NvbW1lbnRzXCIsIFwibG9jXCIsIFwidHJhaWxpbmdDb21tZW50c1wiXS5pbmNsdWRlcyhrZXkpICYmXG4gICAgKEFycmF5LmlzQXJyYXkoY2hpbGQpXG4gICAgICA/IGNoaWxkLnNvbWUoKGl0ZW0pID0+IHBhcnNlclRyZWVSZXF1aXJlc0Nhbm9uaWNhbFplcm8oaXRlbSwgdmlzaXRlZCkpXG4gICAgICA6IHBhcnNlclRyZWVSZXF1aXJlc0Nhbm9uaWNhbFplcm8oY2hpbGQsIHZpc2l0ZWQpKSlcbn1cblxuLyoqXG4gKiBSZWNvZ25pemVzIHRoZSBwYXJzZXItb3duZWQgcmVjZWl2ZXIgcGFyZW50aGVzZXMgZW1pdHRlZCBvbmx5IGZvciBjYW5vbmljYWwgaW50ZWdlciBvdXRwdXQuXG4gKiBAcGFyYW0ge2ltcG9ydChcIkBiYWJlbC90eXBlc1wiKS5FeHByZXNzaW9uIHwgaW1wb3J0KFwiQGJhYmVsL3R5cGVzXCIpLlN1cGVyfSByZWNlaXZlciAtIFF1YWxpZmllZC1jYWxsIHJlY2VpdmVyLlxuICogQHBhcmFtIHtpbXBvcnQoXCJAYmFiZWwvdHlwZXNcIikuQ2FsbEV4cHJlc3Npb259IGNhbGwgLSBPdXRlciBgdG9TdHJpbmdgIGNhbGwuXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gV2hldGhlciB0aGUgcmVjZWl2ZXIgaGFzIHRoZSBnZW5lcmF0ZWQgd3JhcHBlciBzaGFwZS5cbiAqL1xuZnVuY3Rpb24gaGFzQ2Fub25pY2FsWmVyb1JlY2VpdmVyV3JhcHBlcihyZWNlaXZlciwgY2FsbCkge1xuICBjb25zdCBleHRyYSA9IFJlZmxlY3QuZ2V0KHJlY2VpdmVyLCBcImV4dHJhXCIpXG4gIGNvbnN0IGV4cHJlc3Npb25QYXJlbnRoZXNlcyA9IFtcIkJpbmFyeUV4cHJlc3Npb25cIiwgXCJMb2dpY2FsRXhwcmVzc2lvblwiLCBcIlVuYXJ5RXhwcmVzc2lvblwiXS5pbmNsdWRlcyhyZWNlaXZlci50eXBlKSA/IDEgOiAwXG4gIGNvbnN0IHdyYXBwZXJQYXJlbnRoZXNlcyA9IGV4cHJlc3Npb25QYXJlbnRoZXNlcyArIDFcbiAgY29uc3QgcHJvcGVydHkgPSBjYWxsLmNhbGxlZS50eXBlID09IFwiTWVtYmVyRXhwcmVzc2lvblwiID8gY2FsbC5jYWxsZWUucHJvcGVydHkgOiB1bmRlZmluZWRcblxuICByZXR1cm4gQm9vbGVhbihleHRyYSkgJiYgdHlwZW9mIGV4dHJhID09IFwib2JqZWN0XCIgJiYgUmVmbGVjdC5nZXQoZXh0cmEsIFwicGFyZW50aGVzaXplZFwiKSA9PT0gdHJ1ZSAmJlxuICAgIFJlZmxlY3QuZ2V0KGV4dHJhLCBcInBhcmVuU3RhcnRcIikgPT09IGNhbGwuc3RhcnQgJiYgdHlwZW9mIGNhbGwuc3RhcnQgPT0gXCJudW1iZXJcIiAmJiB0eXBlb2YgY2FsbC5lbmQgPT0gXCJudW1iZXJcIiAmJlxuICAgIHR5cGVvZiByZWNlaXZlci5zdGFydCA9PSBcIm51bWJlclwiICYmIHR5cGVvZiByZWNlaXZlci5lbmQgPT0gXCJudW1iZXJcIiAmJiBwcm9wZXJ0eT8udHlwZSA9PSBcIklkZW50aWZpZXJcIiAmJlxuICAgIHR5cGVvZiBwcm9wZXJ0eS5zdGFydCA9PSBcIm51bWJlclwiICYmIHR5cGVvZiBwcm9wZXJ0eS5lbmQgPT0gXCJudW1iZXJcIiAmJiBjYWxsLmNhbGxlZS5zdGFydCA9PT0gY2FsbC5zdGFydCAmJlxuICAgIHJlY2VpdmVyLnN0YXJ0ID09IGNhbGwuc3RhcnQgKyB3cmFwcGVyUGFyZW50aGVzZXMgJiYgcHJvcGVydHkuc3RhcnQgPT0gcmVjZWl2ZXIuZW5kICsgd3JhcHBlclBhcmVudGhlc2VzICsgMSAmJlxuICAgIHByb3BlcnR5LmVuZCA9PSBwcm9wZXJ0eS5zdGFydCArIFwidG9TdHJpbmdcIi5sZW5ndGggJiYgY2FsbC5lbmQgPT0gcHJvcGVydHkuZW5kICsgMlxufVxuXG4vKipcbiAqIENvbnZlcnRzIGEgY29uc29sZS5sb2cgZW50cnktcG9pbnQgY2FsbC5cbiAqIEBwYXJhbSB7aW1wb3J0KFwiQGJhYmVsL3R5cGVzXCIpLlN0YXRlbWVudH0gbm9kZSAtIEJhYmVsIHN0YXRlbWVudC5cbiAqIEBwYXJhbSB7XCJqYXZhc2NyaXB0XCIgfCBcInR5cGVzY3JpcHRcIn0gbGFuZ3VhZ2UgLSBGcm9udGVuZCBsYW5ndWFnZS5cbiAqIEBwYXJhbSB7c3RyaW5nfSBmaWxlbmFtZSAtIFNvdXJjZSBmaWxlbmFtZS5cbiAqIEBwYXJhbSB7c3RyaW5nfSBzb3VyY2UgLSBDb21wbGV0ZSBzb3VyY2UuXG4gKiBAcGFyYW0ge2Jvb2xlYW59IGNhbm9uaWNhbFplcm9SZXF1aXJlZCAtIFdoZXRoZXIgdGhpcyBwYXJzZWQgbW9kdWxlIGNvbnRhaW5zIGEgc2lnbi1wcm9kdWNpbmcgaW50ZWdlciBvcGVyYXRpb24uXG4gKiBAcmV0dXJucyB7aW1wb3J0KFwiLi4vc2VtYW50aWMvdHlwZXMuanNcIikuUHJpbnRTdGF0ZW1lbnR9IFByaW50IHN0YXRlbWVudC5cbiAqL1xuZnVuY3Rpb24gY29udmVydFByaW50KG5vZGUsIGxhbmd1YWdlLCBmaWxlbmFtZSwgc291cmNlLCBjYW5vbmljYWxaZXJvUmVxdWlyZWQpIHtcbiAgY29uc3QgbG9jYXRpb24gPSBub2RlTG9jYXRpb24obm9kZSwgZmlsZW5hbWUsIHNvdXJjZSlcblxuICBpZiAobm9kZS50eXBlICE9IFwiRXhwcmVzc2lvblN0YXRlbWVudFwiIHx8IG5vZGUuZXhwcmVzc2lvbi50eXBlICE9IFwiQ2FsbEV4cHJlc3Npb25cIikge1xuICAgIHJldHVybiB1bnN1cHBvcnRlZFN5bnRheChsYW5ndWFnZSwgbm9kZS50eXBlLCBsb2NhdGlvbilcbiAgfVxuXG4gIGNvbnN0IGNhbGwgPSBub2RlLmV4cHJlc3Npb25cbiAgY29uc3QgY2FsbGVlID0gY2FsbC5jYWxsZWVcblxuICBpZiAoY2FsbGVlLnR5cGUgIT0gXCJNZW1iZXJFeHByZXNzaW9uXCIgfHwgY2FsbGVlLmNvbXB1dGVkIHx8IGNhbGxlZS5vYmplY3QudHlwZSAhPSBcIklkZW50aWZpZXJcIiB8fFxuICAgIGNhbGxlZS5vYmplY3QubmFtZSAhPSBcImNvbnNvbGVcIiB8fCBjYWxsZWUucHJvcGVydHkudHlwZSAhPSBcIklkZW50aWZpZXJcIiB8fCBjYWxsZWUucHJvcGVydHkubmFtZSAhPSBcImxvZ1wiIHx8XG4gICAgY2FsbC5hcmd1bWVudHMubGVuZ3RoICE9IDEpIHtcbiAgICByZXR1cm4gdW5zdXBwb3J0ZWRTeW50YXgobGFuZ3VhZ2UsIFwiZW50cnktcG9pbnQgZXhwcmVzc2lvblwiLCBsb2NhdGlvbilcbiAgfVxuXG4gIGxldCBhcmd1bWVudCA9IGNhbGwuYXJndW1lbnRzWzBdXG5cbiAgaWYgKGFyZ3VtZW50LnR5cGUgPT0gXCJTcHJlYWRFbGVtZW50XCIgfHwgYXJndW1lbnQudHlwZSA9PSBcIkFyZ3VtZW50UGxhY2Vob2xkZXJcIikge1xuICAgIHJldHVybiB1bnN1cHBvcnRlZFN5bnRheChsYW5ndWFnZSwgYXJndW1lbnQudHlwZSwgbm9kZUxvY2F0aW9uKGFyZ3VtZW50LCBmaWxlbmFtZSwgc291cmNlKSlcbiAgfVxuXG4gIGlmIChhcmd1bWVudC50eXBlID09IFwiQ2FsbEV4cHJlc3Npb25cIiAmJiBhcmd1bWVudC5jYWxsZWUudHlwZSA9PSBcIk1lbWJlckV4cHJlc3Npb25cIiAmJiAhYXJndW1lbnQuY2FsbGVlLmNvbXB1dGVkICYmXG4gICAgIWFyZ3VtZW50LmNhbGxlZS5vcHRpb25hbCAmJiBhcmd1bWVudC5jYWxsZWUub2JqZWN0LnR5cGUgIT0gXCJTdXBlclwiICYmIGFyZ3VtZW50LmNhbGxlZS5wcm9wZXJ0eS50eXBlID09IFwiSWRlbnRpZmllclwiICYmXG4gICAgYXJndW1lbnQuY2FsbGVlLnByb3BlcnR5Lm5hbWUgPT0gXCJ0b1N0cmluZ1wiICYmICFhcmd1bWVudC5vcHRpb25hbCAmJiAhYXJndW1lbnQudHlwZUFyZ3VtZW50cyAmJlxuICAgICFhcmd1bWVudC50eXBlUGFyYW1ldGVycyAmJiBhcmd1bWVudC5hcmd1bWVudHMubGVuZ3RoID09IDApIHtcbiAgICBpZiAoIWNhbm9uaWNhbFplcm9SZXF1aXJlZCB8fCAhaGFzQ2Fub25pY2FsWmVyb1JlY2VpdmVyV3JhcHBlcihhcmd1bWVudC5jYWxsZWUub2JqZWN0LCBhcmd1bWVudCkpIHtcbiAgICAgIHJldHVybiB1bnN1cHBvcnRlZFN5bnRheChsYW5ndWFnZSwgXCJlbnRyeS1wb2ludCBxdWFsaWZpZWQgY2FsbFwiLCBub2RlTG9jYXRpb24oYXJndW1lbnQuY2FsbGVlLnByb3BlcnR5LCBmaWxlbmFtZSwgc291cmNlKSlcbiAgICB9XG4gICAgYXJndW1lbnQgPSBhcmd1bWVudC5jYWxsZWUub2JqZWN0XG4gIH1cblxuICByZXR1cm4ge2V4cHJlc3Npb246IGNvbnZlcnRFeHByZXNzaW9uKGFyZ3VtZW50LCBsYW5ndWFnZSwgZmlsZW5hbWUsIHNvdXJjZSksIGtpbmQ6IFwiUHJpbnRTdGF0ZW1lbnRcIiwgbG9jYXRpb259XG59XG5cbi8qKlxuICogUGFyc2VzIEphdmFTY3JpcHQgb3IgVHlwZVNjcmlwdCBpbnRvIHRoZSBzaGFyZWQgc2VtYW50aWMgbW9kdWxlLlxuICogQHBhcmFtIHtvYmplY3R9IGlucHV0IC0gUGFyc2VyIGlucHV0LlxuICogQHBhcmFtIHtzdHJpbmd9IGlucHV0LmZpbGVuYW1lIC0gU291cmNlIGZpbGVuYW1lLlxuICogQHBhcmFtIHtcImphdmFzY3JpcHRcIiB8IFwidHlwZXNjcmlwdFwifSBpbnB1dC5sYW5ndWFnZSAtIEZyb250ZW5kIGxhbmd1YWdlLlxuICogQHBhcmFtIHtzdHJpbmd9IGlucHV0LnNvdXJjZSAtIFNvdXJjZSB0ZXh0LlxuICogQHJldHVybnMge2ltcG9ydChcIi4uL3NlbWFudGljL3R5cGVzLmpzXCIpLlNlbWFudGljTW9kdWxlfSBTZW1hbnRpYyBtb2R1bGUuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBwYXJzZUphdmFTY3JpcHRUeXBlU2NyaXB0KHtmaWxlbmFtZSwgbGFuZ3VhZ2UsIHNvdXJjZX0pIHtcbiAgY29uc3QgZmlsZSA9IHBhcnNlQmFiZWxTb3VyY2Uoe2ZpbGVuYW1lLCBsYW5ndWFnZSwgc291cmNlfSlcbiAgY29uc3QgdG9rZW5zID0gZmlsZS50b2tlbnMgPz8gW11cbiAgY29uc3QgdG9rZW5JbmRleCA9IHtieVN0YXJ0OiBuZXcgTWFwKHRva2Vucy5tYXAoKHRva2VuKSA9PiBbdG9rZW4uc3RhcnQsIHRva2VuXSkpLCB0b2tlbnN9XG4gIGNvbnN0IGNhbm9uaWNhbFplcm9SZXF1aXJlZCA9IHBhcnNlclRyZWVSZXF1aXJlc0Nhbm9uaWNhbFplcm8oZmlsZS5wcm9ncmFtKVxuXG4gIHJlbWVtYmVyVG9rZW5zKGZpbGUsIHRva2VuSW5kZXgpXG4gIGlmIChmaWxlLnByb2dyYW0uZGlyZWN0aXZlcy5sZW5ndGggPiAwKSB7XG4gICAgcmV0dXJuIHVuc3VwcG9ydGVkU3ludGF4KGxhbmd1YWdlLCBcInRvcC1sZXZlbCBkaXJlY3RpdmVcIiwgbm9kZUxvY2F0aW9uKGZpbGUucHJvZ3JhbS5kaXJlY3RpdmVzWzBdLCBmaWxlbmFtZSwgc291cmNlKSlcbiAgfVxuICBjb25zdCBmdW5jdGlvbnMgPSBmaWxlLnByb2dyYW0uYm9keS5maWx0ZXIoKG5vZGUpID0+IG5vZGUudHlwZSA9PSBcIkZ1bmN0aW9uRGVjbGFyYXRpb25cIilcbiAgICAubWFwKChub2RlKSA9PiBjb252ZXJ0RnVuY3Rpb24obm9kZSwgbGFuZ3VhZ2UsIGZpbGVuYW1lLCBzb3VyY2UsIGNhbm9uaWNhbFplcm9SZXF1aXJlZCkpXG4gIGNvbnN0IGVudHJ5Tm9kZXMgPSBmaWxlLnByb2dyYW0uYm9keS5maWx0ZXIoKG5vZGUpID0+IG5vZGUudHlwZSAhPSBcIkZ1bmN0aW9uRGVjbGFyYXRpb25cIilcbiAgY29uc3QgbG9jYXRpb24gPSBtb2R1bGVMb2NhdGlvbihmaWxlbmFtZSwgc291cmNlKVxuXG4gIGlmIChmdW5jdGlvbnMubGVuZ3RoID09IDApIHJldHVybiB1bnN1cHBvcnRlZFN5bnRheChsYW5ndWFnZSwgXCJtb2R1bGUgd2l0aG91dCBhIGZ1bmN0aW9uXCIsIGxvY2F0aW9uKVxuICBjb25zdCBlbnRyeUxvY2F0aW9uID0gZW50cnlOb2Rlcy5sZW5ndGggPT0gMCA/IGxvY2F0aW9uIDogbG9jYXRpb25Gcm9tT2Zmc2V0cyhcbiAgICBmaWxlbmFtZSxcbiAgICBzb3VyY2UsXG4gICAgZW50cnlOb2Rlc1swXS5zdGFydCA/PyAwLFxuICAgIGVudHJ5Tm9kZXMuYXQoLTEpPy5lbmQgPz8gc291cmNlLmxlbmd0aFxuICApXG4gIGNvbnN0IGVudHJ5QmxvY2sgPSBjb252ZXJ0QmxvY2soZW50cnlOb2RlcywgbGFuZ3VhZ2UsIGZpbGVuYW1lLCBzb3VyY2UsIGNhbm9uaWNhbFplcm9SZXF1aXJlZCwgZW50cnlMb2NhdGlvbilcblxuICByZXR1cm4ge1xuICAgIGVudHJ5UG9pbnQ6IHtcbiAgICAgIGJvZHk6IGVudHJ5QmxvY2ssXG4gICAgICBraW5kOiBcIkVudHJ5UG9pbnRcIixcbiAgICAgIGxvY2F0aW9uOiBlbnRyeUxvY2F0aW9uXG4gICAgfSxcbiAgICBmdW5jdGlvbnMsXG4gICAga2luZDogXCJNb2R1bGVcIixcbiAgICBsb2NhdGlvblxuICB9XG59XG5cbi8qKlxuICogSW52b2tlcyBCYWJlbCBhbmQgbm9ybWFsaXplcyBzeW50YXggZmFpbHVyZXMuXG4gKiBAcGFyYW0ge29iamVjdH0gaW5wdXQgLSBQYXJzZXIgaW5wdXQuXG4gKiBAcGFyYW0ge3N0cmluZ30gaW5wdXQuZmlsZW5hbWUgLSBTb3VyY2UgZmlsZW5hbWUuXG4gKiBAcGFyYW0ge1wiamF2YXNjcmlwdFwiIHwgXCJ0eXBlc2NyaXB0XCJ9IGlucHV0Lmxhbmd1YWdlIC0gRnJvbnRlbmQgbGFuZ3VhZ2UuXG4gKiBAcGFyYW0ge3N0cmluZ30gaW5wdXQuc291cmNlIC0gU291cmNlIHRleHQuXG4gKiBAcmV0dXJucyB7aW1wb3J0KFwiQGJhYmVsL3BhcnNlclwiKS5QYXJzZVJlc3VsdDxpbXBvcnQoXCJAYmFiZWwvdHlwZXNcIikuRmlsZT59IEJhYmVsIGZpbGUuXG4gKi9cbmZ1bmN0aW9uIHBhcnNlQmFiZWxTb3VyY2Uoe2ZpbGVuYW1lLCBsYW5ndWFnZSwgc291cmNlfSkge1xuICB0cnkge1xuICAgIHJldHVybiBwYXJzZUJhYmVsKHNvdXJjZSwge1xuICAgICAgcGx1Z2luczogbGFuZ3VhZ2UgPT0gXCJ0eXBlc2NyaXB0XCIgPyBbXCJ0eXBlc2NyaXB0XCJdIDogW10sXG4gICAgICBzb3VyY2VGaWxlbmFtZTogZmlsZW5hbWUsXG4gICAgICBzb3VyY2VUeXBlOiBcInNjcmlwdFwiLFxuICAgICAgdG9rZW5zOiB0cnVlXG4gICAgfSlcbiAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICByZXR1cm4gcGFyc2VGYWlsdXJlKGxhbmd1YWdlLCBlcnJvcilcbiAgfVxufVxuXG4vKipcbiAqIEFzc29jaWF0ZXMgQmFiZWwgbm9kZXMgd2l0aCB0aGVpciBwYXJzZXIgdG9rZW4gc3RyZWFtIHdpdGhvdXQgbGVha2luZyBpdCBpbnRvIHNlbWFudGljIHZhbHVlcy5cbiAqIEBwYXJhbSB7b2JqZWN0fSB2YWx1ZSAtIEN1cnJlbnQgcGFyc2VyIHZhbHVlLlxuICogQHBhcmFtIHtCYWJlbFRva2VuSW5kZXh9IHRva2VucyAtIEluZGV4ZWQgcGFyc2VyIHRva2Vucy5cbiAqIEBwYXJhbSB7V2Vha1NldDxvYmplY3Q+fSBbdmlzaXRlZF0gLSBDeWNsZSBwcm90ZWN0aW9uLlxuICogQHJldHVybnMge3ZvaWR9XG4gKi9cbmZ1bmN0aW9uIHJlbWVtYmVyVG9rZW5zKHZhbHVlLCB0b2tlbnMsIHZpc2l0ZWQgPSBuZXcgV2Vha1NldCgpKSB7XG4gIGlmICh2aXNpdGVkLmhhcyh2YWx1ZSkpIHJldHVyblxuXG4gIHZpc2l0ZWQuYWRkKHZhbHVlKVxuICBub2RlVG9rZW5zLnNldCh2YWx1ZSwgdG9rZW5zKVxuXG4gIGZvciAoY29uc3QgY2hpbGQgb2YgT2JqZWN0LnZhbHVlcyh2YWx1ZSkpIHtcbiAgICBpZiAoQXJyYXkuaXNBcnJheShjaGlsZCkpIHtcbiAgICAgIGZvciAoY29uc3QgaXRlbSBvZiBjaGlsZCkgaWYgKGl0ZW0gJiYgdHlwZW9mIGl0ZW0gPT0gXCJvYmplY3RcIikgcmVtZW1iZXJUb2tlbnMoaXRlbSwgdG9rZW5zLCB2aXNpdGVkKVxuICAgIH0gZWxzZSBpZiAoY2hpbGQgJiYgdHlwZW9mIGNoaWxkID09IFwib2JqZWN0XCIpIHJlbWVtYmVyVG9rZW5zKGNoaWxkLCB0b2tlbnMsIHZpc2l0ZWQpXG4gIH1cbn1cbiJdfQ==