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,523 @@
1
+ // @ts-check
2
+ import PhpParser from "php-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
+ const parser = new PhpParser.Engine({
11
+ ast: { withPositions: true },
12
+ parser: { extractDoc: true, suppressErrors: false }
13
+ });
14
+ /** @type {string | undefined} */
15
+ let cachedTokenSource;
16
+ /** @type {{end: number, start: number, text: string}[]} */
17
+ let cachedTokenRanges = [];
18
+ const phpBinaryOperations = new Map([
19
+ ["+", "PhpAdd"],
20
+ ["-", "Subtract"],
21
+ ["*", "Multiply"],
22
+ ["&&", "And"],
23
+ ["||", "Or"],
24
+ ["===", "Equal"],
25
+ ["!==", "NotEqual"],
26
+ ["<", "LessThan"],
27
+ ["<=", "LessThanOrEqual"],
28
+ [">", "GreaterThan"],
29
+ [">=", "GreaterThanOrEqual"],
30
+ [".", "StringConcat"]
31
+ ]);
32
+ /**
33
+ * Returns a normalized PHP node location.
34
+ * @param {import("php-parser").Node} node - PHP parser node.
35
+ * @param {string} filename - Source filename.
36
+ * @param {string} source - Complete source.
37
+ * @returns {import("../semantic/types.js").SourceLocation} Source location.
38
+ */
39
+ function nodeLocation(node, filename, source) {
40
+ if (!node.loc)
41
+ throw new Error(`PHP parser omitted source location for ${node.kind}.`);
42
+ return locationFromOffsets(filename, source, node.loc.start.offset, node.loc.end.offset);
43
+ }
44
+ /**
45
+ * Locates a comment-parser token inside a PHP parser-owned doc comment.
46
+ * @param {import("php-parser").CommentBlock} comment - PHP doc comment.
47
+ * @param {import("comment-parser").Spec} tag - Parsed doc tag.
48
+ * @param {"name" | "type"} field - Token field.
49
+ * @param {string} filename - Source filename.
50
+ * @param {string} source - Complete source.
51
+ * @returns {import("../semantic/types.js").SourceLocation} Exact token location.
52
+ */
53
+ function commentTagLocation(comment, tag, field, filename, source) {
54
+ const line = tag.source[0];
55
+ if (!comment.loc || !line)
56
+ throw new Error(`Comment parser omitted the @${tag.tag} source token.`);
57
+ let lineStart = comment.loc.start.offset;
58
+ for (let lineNumber = 0; lineNumber < line.number; lineNumber++) {
59
+ while (lineStart < source.length && source[lineStart] != "\r" && source[lineStart] != "\n")
60
+ lineStart++;
61
+ if (source[lineStart] == "\r" && source[lineStart + 1] == "\n")
62
+ lineStart += 2;
63
+ else
64
+ lineStart++;
65
+ }
66
+ const orderedFields = ["start", "delimiter", "postDelimiter", "tag", "postTag", "name", "postName", "type"];
67
+ const fieldIndex = orderedFields.indexOf(field);
68
+ const start = lineStart + orderedFields.slice(0, fieldIndex).reduce((length, key) => length + line.tokens[ /** @type {keyof typeof line.tokens} */(key)].length, 0);
69
+ const value = line.tokens[field];
70
+ return locationFromOffsets(filename, source, start, start + value.length);
71
+ }
72
+ /**
73
+ * Finds one parser token between parser-owned node boundaries.
74
+ * @param {string} tokenText - Exact token text.
75
+ * @param {number} startOffset - Inclusive search boundary.
76
+ * @param {number} endOffset - Exclusive search boundary.
77
+ * @param {string} filename - Source filename.
78
+ * @param {string} source - Complete source.
79
+ * @returns {import("../semantic/types.js").SourceLocation} Token location.
80
+ */
81
+ function tokenLocation(tokenText, startOffset, endOffset, filename, source) {
82
+ if (cachedTokenSource != source) {
83
+ let offset = 0;
84
+ cachedTokenRanges = parser.tokenGetAll(source).map((token) => {
85
+ const text = typeof token == "string" ? token : token[1];
86
+ const range = { end: offset + text.length, start: offset, text };
87
+ offset = range.end;
88
+ return range;
89
+ });
90
+ cachedTokenSource = source;
91
+ }
92
+ const token = cachedTokenRanges.find((candidate) => candidate.text == tokenText && candidate.start >= startOffset &&
93
+ candidate.end <= endOffset);
94
+ if (token)
95
+ return locationFromOffsets(filename, source, token.start, token.end);
96
+ throw new Error(`PHP parser omitted token '${tokenText}' between ${startOffset} and ${endOffset}.`);
97
+ }
98
+ /**
99
+ * Converts a supported PHP expression.
100
+ * @param {import("php-parser").Expression} node - PHP expression.
101
+ * @param {string} filename - Source filename.
102
+ * @param {string} source - Complete source.
103
+ * @returns {import("../semantic/types.js").Expression} Semantic expression.
104
+ */
105
+ function convertExpression(node, filename, source) {
106
+ const location = nodeLocation(node, filename, source);
107
+ if (node.kind == "variable") {
108
+ const variable = /** @type {import("php-parser").Variable} */ (node);
109
+ if (typeof variable.name != "string")
110
+ return unsupportedSyntax("php", "dynamic variable", location);
111
+ return withParserRanges({ kind: /** @type {const} */ ("IdentifierExpression"), location, name: variable.name }, { name: location });
112
+ }
113
+ if (node.kind == "number") {
114
+ const literal = /** @type {import("php-parser").Number} */ (node);
115
+ const value = Number(literal.value);
116
+ if (!Number.isSafeInteger(value))
117
+ return unsupportedSyntax("php", "non-safe integer literal", location);
118
+ return withParserRanges({ kind: /** @type {const} */ ("IntegerLiteral"), location, value }, { literal: location });
119
+ }
120
+ if (node.kind == "boolean") {
121
+ const literal = /** @type {import("php-parser").Boolean} */ (node);
122
+ if (typeof literal.value != "boolean")
123
+ return unsupportedSyntax("php", "invalid boolean literal value", location);
124
+ return withParserRanges({ kind: /** @type {const} */ ("BooleanLiteral"), location, value: literal.value }, { literal: location });
125
+ }
126
+ if (node.kind == "string") {
127
+ const literal = /** @type {import("php-parser").String} */ (node);
128
+ if (typeof literal.raw == "string" && literal.raw.startsWith("<<<")) {
129
+ const detail = literal.raw.startsWith("<<<'") ? "nowdoc string" : "heredoc string";
130
+ return unsupportedSyntax("php", detail, location);
131
+ }
132
+ if (typeof literal.raw == "string" && ["b\"", "B\"", "b'", "B'"].some((prefix) => literal.raw.startsWith(prefix))) {
133
+ return unsupportedSyntax("php", "binary string literal", location);
134
+ }
135
+ if (typeof literal.value != "string" || !hasOnlyUnicodeScalars(literal.value)) {
136
+ return unsupportedSyntax("php", "invalid Unicode string literal", location);
137
+ }
138
+ return withParserRanges({ kind: /** @type {const} */ ("StringLiteral"), location, value: literal.value }, { literal: location });
139
+ }
140
+ if (node.kind == "encapsed") {
141
+ const literal = /** @type {import("php-parser").Encapsed} */ (node);
142
+ const detail = literal.type == "string" ? "interpolated string" : `${literal.type} string`;
143
+ return unsupportedSyntax("php", detail, location);
144
+ }
145
+ if (node.kind == "nowdoc")
146
+ return unsupportedSyntax("php", "nowdoc string", location);
147
+ if (node.kind == "unary") {
148
+ const unary = /** @type {import("php-parser").Unary} */ (node);
149
+ if (!["!", "-"].includes(unary.type))
150
+ return unsupportedSyntax("php", `unary ${unary.type}`, location);
151
+ const semantic = withAdaptedOperation(withParserRanges({
152
+ kind: "UnaryExpression",
153
+ location,
154
+ operand: convertExpression(unary.what, filename, source)
155
+ }, {
156
+ operator: tokenLocation(unary.type, unary.loc?.start.offset ?? 0, unary.what.loc?.start.offset ?? unary.loc?.end.offset ?? source.length, filename, source)
157
+ }), unary.type == "!" ? "Not" : "Negate");
158
+ return /** @type {import("../semantic/types.js").Expression} */ ( /** @type {unknown} */(semantic));
159
+ }
160
+ if (node.kind == "bin") {
161
+ const binary = /** @type {import("php-parser").Bin} */ (node);
162
+ if (["==", "!="].includes(binary.type))
163
+ return unsupportedSyntax("php", `coercive equality ${binary.type}`, location);
164
+ if (["and", "or"].includes(binary.type))
165
+ return unsupportedSyntax("php", `precedence-sensitive boolean ${binary.type}`, location);
166
+ if (!phpBinaryOperations.has(binary.type))
167
+ return unsupportedSyntax("php", `binary ${binary.type}`, location);
168
+ const semantic = withAdaptedOperation({
169
+ kind: /** @type {const} */ ("BinaryExpression"),
170
+ left: convertExpression(binary.left, filename, source),
171
+ location,
172
+ right: convertExpression(binary.right, filename, source)
173
+ }, /** @type {import("../semantic/operators.js").AdaptedOperation} */ (phpBinaryOperations.get(binary.type)));
174
+ return /** @type {import("../semantic/types.js").Expression} */ ( /** @type {unknown} */(withParserRanges(semantic, {
175
+ operator: tokenLocation(binary.type, binary.left.loc?.end.offset ?? 0, binary.right.loc?.start.offset ?? source.length, filename, source)
176
+ })));
177
+ }
178
+ if (node.kind == "call") {
179
+ const call = /** @type {import("php-parser").Call} */ (node);
180
+ if (call.what.kind != "name" && call.what.kind != "identifier") {
181
+ return unsupportedSyntax("php", "dynamic call", location);
182
+ }
183
+ const callee = /** @type {import("php-parser").Name | import("php-parser").Identifier} */ (call.what).name;
184
+ return withParserRanges({
185
+ arguments: call.arguments.map((argument) => convertExpression(argument, filename, source)),
186
+ callee,
187
+ kind: "CallExpression",
188
+ location
189
+ }, { callee: nodeLocation(call.what, filename, source) });
190
+ }
191
+ return unsupportedSyntax("php", node.kind, location);
192
+ }
193
+ /**
194
+ * Converts one explicit PHP return.
195
+ * @param {import("php-parser").Node} node - PHP node.
196
+ * @param {string} filename - Source filename.
197
+ * @param {string} source - Complete source.
198
+ * @returns {import("../semantic/types.js").ReturnStatement} Semantic return.
199
+ */
200
+ function convertReturn(node, filename, source) {
201
+ const location = nodeLocation(node, filename, source);
202
+ if (node.kind != "return")
203
+ return unsupportedSyntax("php", node.kind, location);
204
+ const returnNode = /** @type {import("php-parser").Return} */ (node);
205
+ if (!returnNode.expr)
206
+ return unsupportedSyntax("php", "empty return", location);
207
+ return { expression: convertExpression(returnNode.expr, filename, source), kind: "ReturnStatement", location };
208
+ }
209
+ /**
210
+ * Reads one exact PHP local `@var` carrier and immutability marker.
211
+ * @param {import("php-parser").Node} node - Assignment-owning statement.
212
+ * @param {string} name - Local name.
213
+ * @param {string} filename - Source filename.
214
+ * @param {string} source - Complete source.
215
+ * @returns {{immutable: boolean, type: import("../semantic/types.js").TypeReference} | undefined} Metadata when present.
216
+ */
217
+ function localMetadata(node, name, filename, source) {
218
+ const comments = node.leadingComments ?? [];
219
+ const comment = comments.at(-1);
220
+ if (!comment || comment.kind != "commentblock" || !comment.loc || !node.loc)
221
+ return undefined;
222
+ const gap = source.slice(comment.loc.end.offset, node.loc.start.offset);
223
+ if (!/^\s*$/u.test(gap) || (gap.match(/\n/gu)?.length ?? 0) > 1)
224
+ return undefined;
225
+ const block = parseComment(comment.value)[0];
226
+ const tags = block?.tags ?? [];
227
+ const variables = tags.filter((tag) => tag.tag == "var");
228
+ const immutable = tags.filter((tag) => tag.tag == "semantifold-immutable");
229
+ const location = nodeLocation(node, filename, source);
230
+ if (variables.length == 0 && immutable.length == 0)
231
+ return undefined;
232
+ const exactVariable = variables.length == 1 && variables[0].type == "" && variables[0].description == `$${name}`;
233
+ const exactImmutable = immutable.length <= 1 && immutable.every((tag) => tag.name == "" && tag.type == "" && tag.description == "");
234
+ const knownTags = tags.every((tag) => tag.tag == "var" || tag.tag == "semantifold-immutable");
235
+ if (!exactVariable || !exactImmutable || !knownTags) {
236
+ return unsupportedSyntax("php", "malformed local type metadata", location);
237
+ }
238
+ return {
239
+ immutable: immutable.length == 1,
240
+ type: requireSourceScalarType("php", variables[0].name, `Local '${name}'`, location, commentTagLocation(comment, variables[0], "name", filename, source))
241
+ };
242
+ }
243
+ /**
244
+ * Converts one PHP local declaration or assignment.
245
+ * @param {import("php-parser").Node} node - PHP statement.
246
+ * @param {Set<string>} visible - Names visible during adaptation.
247
+ * @param {string} filename - Source filename.
248
+ * @param {string} source - Complete source.
249
+ * @returns {import("../semantic/types.js").LocalStatement} Semantic local statement.
250
+ */
251
+ function convertLocalStatement(node, visible, filename, source) {
252
+ const location = nodeLocation(node, filename, source);
253
+ if (node.kind != "expressionstatement")
254
+ return unsupportedSyntax("php", node.kind, location);
255
+ const expression = /** @type {import("php-parser").ExpressionStatement} */ (node).expression;
256
+ if (expression.kind != "assign")
257
+ return unsupportedSyntax("php", expression.kind, nodeLocation(expression, filename, source));
258
+ const assignment = /** @type {import("php-parser").Assign} */ (expression);
259
+ if (assignment.operator != "=")
260
+ return unsupportedSyntax("php", `assignment ${assignment.operator}`, location);
261
+ if (assignment.left.kind != "variable")
262
+ return unsupportedSyntax("php", assignment.left.kind, nodeLocation(assignment.left, filename, source));
263
+ const variable = /** @type {import("php-parser").Variable} */ (assignment.left);
264
+ const targetLocation = nodeLocation(variable, filename, source);
265
+ if (typeof variable.name != "string" || variable.curly)
266
+ return unsupportedSyntax("php", "dynamic variable", targetLocation);
267
+ const metadata = localMetadata(node, variable.name, filename, source);
268
+ if (metadata) {
269
+ visible.add(variable.name);
270
+ return withParserRanges({
271
+ initializer: convertExpression(assignment.right, filename, source),
272
+ kind: "LocalDeclaration",
273
+ location,
274
+ mutable: !metadata.immutable,
275
+ name: variable.name,
276
+ type: metadata.type
277
+ }, {
278
+ name: targetLocation,
279
+ operator: tokenLocation("=", assignment.left.loc?.end.offset ?? 0, assignment.right.loc?.start.offset ?? source.length, filename, source)
280
+ });
281
+ }
282
+ if (!visible.has(variable.name))
283
+ return missingType("php", `Local '${variable.name}'`, location);
284
+ const target = withParserRanges({ kind: /** @type {const} */ ("IdentifierExpression"), location: targetLocation, name: variable.name }, {
285
+ name: targetLocation
286
+ });
287
+ return withParserRanges({
288
+ expression: convertExpression(assignment.right, filename, source),
289
+ kind: "AssignmentStatement",
290
+ location,
291
+ target
292
+ }, {
293
+ operator: tokenLocation("=", assignment.left.loc?.end.offset ?? 0, assignment.right.loc?.start.offset ?? source.length, filename, source)
294
+ });
295
+ }
296
+ /**
297
+ * Converts one exhaustive PHP statement.
298
+ * @param {import("php-parser").Node} node - PHP statement.
299
+ * @param {Set<string>} visible - Names visible during adaptation.
300
+ * @param {string} filename - Source filename.
301
+ * @param {string} source - Complete source.
302
+ * @returns {import("../semantic/types.js").Statement} Semantic statement.
303
+ */
304
+ function convertStatement(node, visible, filename, source) {
305
+ if (node.kind == "return")
306
+ return convertReturn(node, filename, source);
307
+ if (node.kind == "if")
308
+ return convertIf(/** @type {import("php-parser").If} */ (node), visible, filename, source);
309
+ if (node.kind == "echo")
310
+ return convertPrint(/** @type {import("php-parser").Echo} */ (node), filename, source);
311
+ if (node.kind == "expressionstatement")
312
+ return convertLocalStatement(node, visible, filename, source);
313
+ return unsupportedSyntax("php", node.kind, nodeLocation(node, filename, source));
314
+ }
315
+ /**
316
+ * Converts an ordered PHP block with its own adaptation scope.
317
+ * @param {import("php-parser").Block} node - PHP parser block.
318
+ * @param {Set<string>} visible - Names visible on block entry.
319
+ * @param {string} filename - Source filename.
320
+ * @param {string} source - Complete source.
321
+ * @returns {import("../semantic/types.js").Block} Semantic block.
322
+ */
323
+ function convertBlock(node, visible, filename, source) {
324
+ return {
325
+ kind: "Block",
326
+ location: nodeLocation(node, filename, source),
327
+ statements: node.children.map((statement) => convertStatement(statement, visible, filename, source))
328
+ };
329
+ }
330
+ /**
331
+ * Requires an exact PHP scalar declaration type.
332
+ * @param {import("php-parser").Node | null} sourceType - PHP type node.
333
+ * @param {string} subject - Typed subject.
334
+ * @param {import("../semantic/types.js").SourceLocation} location - Source location.
335
+ * @param {string} filename - Source filename.
336
+ * @param {string} source - Complete source.
337
+ * @returns {import("../semantic/types.js").TypeReference} Semantic type.
338
+ */
339
+ function convertType(sourceType, subject, location, filename, source) {
340
+ if (!sourceType)
341
+ return requireSourceScalarType("php", undefined, subject, location);
342
+ if (sourceType.kind != "typereference" && sourceType.kind != "name" && sourceType.kind != "identifier") {
343
+ return unsupportedSyntax("php", "unsupported scalar type", nodeLocation(sourceType, filename, source));
344
+ }
345
+ const typeName = /** @type {import("php-parser").TypeReference | import("php-parser").Name | import("php-parser").Identifier} */ (sourceType).name;
346
+ return requireSourceScalarType("php", typeName, subject, location, nodeLocation(sourceType, filename, source));
347
+ }
348
+ /**
349
+ * Converts a PHP function.
350
+ * @param {import("php-parser").Function} node - PHP function node.
351
+ * @param {string} filename - Source filename.
352
+ * @param {string} source - Complete source.
353
+ * @returns {import("../semantic/types.js").FunctionDeclaration} Semantic function.
354
+ */
355
+ function convertFunction(node, filename, source) {
356
+ const location = nodeLocation(node, filename, source);
357
+ const name = typeof node.name == "string" ? node.name : node.name.name;
358
+ if (!node.body) {
359
+ return unsupportedSyntax("php", "function body", location);
360
+ }
361
+ const parameters = node.arguments.map((parameter) => {
362
+ const parameterLocation = nodeLocation(parameter, filename, source);
363
+ const parameterName = typeof parameter.name == "string" ? parameter.name : parameter.name.name;
364
+ if (parameter.nullable)
365
+ return unsupportedSyntax("php", "unsupported scalar type", parameterLocation);
366
+ const parameterNode = typeof parameter.name == "string" ? parameter : parameter.name;
367
+ const semanticParameter = {
368
+ kind: /** @type {const} */ ("Parameter"),
369
+ location: parameterLocation,
370
+ name: parameterName,
371
+ type: convertType(parameter.type, `Parameter '${parameterName}'`, parameterLocation, filename, source)
372
+ };
373
+ return withParserRanges(semanticParameter, { name: nodeLocation(parameterNode, filename, source) });
374
+ });
375
+ if (node.nullable)
376
+ return unsupportedSyntax("php", "unsupported scalar type", location);
377
+ const visible = new Set(parameters.map((parameter) => parameter.name));
378
+ const body = convertBlock(node.body, visible, filename, source);
379
+ const nameNode = typeof node.name == "string" ? node : node.name;
380
+ return withParserRanges({
381
+ body,
382
+ kind: "FunctionDeclaration",
383
+ location,
384
+ name,
385
+ parameters,
386
+ returnType: convertType(node.type, `Function '${name}' return`, location, filename, source)
387
+ }, { name: nodeLocation(nameNode, filename, source) });
388
+ }
389
+ /**
390
+ * Converts the existing PHP if/else terminal with restricted branch prefixes.
391
+ * @param {import("php-parser").If} node - PHP if node.
392
+ * @param {Set<string>} visible - Enclosing visible names.
393
+ * @param {string} filename - Source filename.
394
+ * @param {string} source - Complete source.
395
+ * @returns {import("../semantic/types.js").IfStatement} Semantic branch.
396
+ */
397
+ function convertIf(node, visible, filename, source) {
398
+ const location = nodeLocation(node, filename, source);
399
+ if (node.shortForm)
400
+ return unsupportedSyntax("php", "alternative if syntax", location);
401
+ if (node.body.kind != "block")
402
+ return unsupportedSyntax("php", "if without block consequent", location);
403
+ const consequentVisible = new Set(visible);
404
+ let alternate;
405
+ if (node.alternate) {
406
+ const alternateVisible = new Set(visible);
407
+ if (node.alternate.kind == "block") {
408
+ alternate = convertBlock(/** @type {import("php-parser").Block} */ (node.alternate), alternateVisible, filename, source);
409
+ }
410
+ else if (node.alternate.kind == "if") {
411
+ const nested = /** @type {import("php-parser").If} */ (node.alternate);
412
+ alternate = {
413
+ kind: /** @type {const} */ ("Block"),
414
+ location: nodeLocation(nested, filename, source),
415
+ statements: [convertIf(nested, alternateVisible, filename, source)]
416
+ };
417
+ }
418
+ else
419
+ return unsupportedSyntax("php", `if alternate ${node.alternate.kind}`, nodeLocation(node.alternate, filename, source));
420
+ }
421
+ return {
422
+ ...(alternate ? { alternate } : {}),
423
+ condition: convertExpression(node.test, filename, source),
424
+ consequent: convertBlock(node.body, consequentVisible, filename, source),
425
+ kind: "IfStatement",
426
+ location
427
+ };
428
+ }
429
+ /**
430
+ * Converts a PHP echo entry point.
431
+ * @param {import("php-parser").Echo} node - PHP echo node.
432
+ * @param {string} filename - Source filename.
433
+ * @param {string} source - Complete source.
434
+ * @returns {import("../semantic/types.js").PrintStatement} Print statement.
435
+ */
436
+ function convertPrint(node, filename, source) {
437
+ const location = nodeLocation(node, filename, source);
438
+ if (node.expressions.length != 2 || node.expressions[1].kind != "name" ||
439
+ /** @type {import("php-parser").Name} */ (node.expressions[1]).name != "PHP_EOL") {
440
+ return unsupportedSyntax("php", "echo without one expression and PHP_EOL", location);
441
+ }
442
+ return { expression: convertExpression(node.expressions[0], filename, source), kind: "PrintStatement", location };
443
+ }
444
+ /**
445
+ * Parses PHP into the shared semantic module.
446
+ * @param {object} input - Parser input.
447
+ * @param {string} input.filename - Source filename.
448
+ * @param {string} input.source - Source text.
449
+ * @returns {import("../semantic/types.js").SemanticModule} Semantic module.
450
+ */
451
+ export function parsePhp({ filename, source }) {
452
+ const program = parsePhpProgram(filename, source);
453
+ validateDeclareNodes(program.children, filename, source);
454
+ const functions = program.children.filter((node) => node.kind == "function")
455
+ .map((node) => convertFunction(/** @type {import("php-parser").Function} */ (node), filename, source));
456
+ const executableNodes = program.children.filter((node) => node.kind != "function" && node.kind != "declare" && node.kind != "noop");
457
+ const location = moduleLocation(filename, source);
458
+ if (functions.length == 0)
459
+ return unsupportedSyntax("php", "module without a function", location);
460
+ const first = executableNodes[0];
461
+ const last = executableNodes.at(-1) ?? first;
462
+ const entryLocation = first
463
+ ? locationFromOffsets(filename, source, first.loc?.start.offset ?? 0, last?.loc?.end.offset ?? source.length)
464
+ : location;
465
+ const entryVisible = new Set();
466
+ const entryBlock = {
467
+ kind: /** @type {const} */ ("Block"),
468
+ location: entryLocation,
469
+ statements: executableNodes.map((node) => convertStatement(node, entryVisible, filename, source))
470
+ };
471
+ return {
472
+ entryPoint: {
473
+ body: entryBlock,
474
+ kind: "EntryPoint",
475
+ location: entryLocation
476
+ },
477
+ functions,
478
+ kind: "Module",
479
+ location
480
+ };
481
+ }
482
+ /**
483
+ * Accepts only an optional single `declare(strict_types=1)` directive.
484
+ * @param {import("php-parser").Node[]} nodes - Top-level PHP nodes.
485
+ * @param {string} filename - Source filename.
486
+ * @param {string} source - Complete source.
487
+ * @returns {void}
488
+ */
489
+ function validateDeclareNodes(nodes, filename, source) {
490
+ const declarations = nodes.filter((node) => node.kind == "declare");
491
+ if (declarations.length > 1) {
492
+ unsupportedSyntax("php", "multiple declare directives", nodeLocation(declarations[1], filename, source));
493
+ }
494
+ for (const declarationNode of declarations) {
495
+ const declaration = /** @type {import("php-parser").Declare} */ (declarationNode);
496
+ const directive = declaration.directives[0];
497
+ const key = directive?.key;
498
+ const value = directive?.value;
499
+ const numericValue = value && typeof value == "object" && value.kind == "number"
500
+ ? /** @type {import("php-parser").Number} */ (value)
501
+ : undefined;
502
+ const valueIsOne = numericValue?.loc && source.slice(numericValue.loc.start.offset, numericValue.loc.end.offset) == "1";
503
+ const valid = declaration.mode == "none" && declaration.children.length == 0 && declaration.directives.length == 1 &&
504
+ key.kind == "identifier" && key.name == "strict_types" && valueIsOne;
505
+ if (!valid)
506
+ unsupportedSyntax("php", "declare other than strict_types=1", nodeLocation(declaration, filename, source));
507
+ }
508
+ }
509
+ /**
510
+ * Invokes php-parser and normalizes syntax failures.
511
+ * @param {string} filename - Source filename.
512
+ * @param {string} source - Source text.
513
+ * @returns {import("php-parser").Program} PHP program.
514
+ */
515
+ function parsePhpProgram(filename, source) {
516
+ try {
517
+ return parser.parseCode(source, filename);
518
+ }
519
+ catch (error) {
520
+ return parseFailure("php", error);
521
+ }
522
+ }
523
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGhwLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2Zyb250ZW5kcy9waHAuanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsWUFBWTtBQUVaLE9BQU8sU0FBUyxNQUFNLFlBQVksQ0FBQTtBQUNsQyxPQUFPLEVBQUMsS0FBSyxJQUFJLFlBQVksRUFBQyxNQUFNLGdCQUFnQixDQUFBO0FBQ3BELE9BQU8sRUFBQyxXQUFXLEVBQUUsWUFBWSxFQUFFLGlCQUFpQixFQUFDLE1BQU0sa0JBQWtCLENBQUE7QUFDN0UsT0FBTyxFQUFDLG1CQUFtQixFQUFFLGNBQWMsRUFBQyxNQUFNLHlCQUF5QixDQUFBO0FBQzNFLE9BQU8sRUFBQyxvQkFBb0IsRUFBQyxNQUFNLDBCQUEwQixDQUFBO0FBQzdELE9BQU8sRUFBQyxnQkFBZ0IsRUFBQyxNQUFNLDJCQUEyQixDQUFBO0FBQzFELE9BQU8sRUFBQyxxQkFBcUIsRUFBQyxNQUFNLHdCQUF3QixDQUFBO0FBQzVELE9BQU8sRUFBQyx1QkFBdUIsRUFBQyxNQUFNLGNBQWMsQ0FBQTtBQUNwRCxNQUFNLE1BQU0sR0FBRyxJQUFJLFNBQVMsQ0FBQyxNQUFNLENBQUM7SUFDbEMsR0FBRyxFQUFFLEVBQUMsYUFBYSxFQUFFLElBQUksRUFBQztJQUMxQixNQUFNLEVBQUUsRUFBQyxVQUFVLEVBQUUsSUFBSSxFQUFFLGNBQWMsRUFBRSxLQUFLLEVBQUM7Q0FDbEQsQ0FBQyxDQUFBO0FBQ0YsaUNBQWlDO0FBQ2pDLElBQUksaUJBQWlCLENBQUE7QUFDckIsMkRBQTJEO0FBQzNELElBQUksaUJBQWlCLEdBQUcsRUFBRSxDQUFBO0FBQzFCLE1BQU0sbUJBQW1CLEdBQUcsSUFBSSxHQUFHLENBQUM7SUFDbEMsQ0FBQyxHQUFHLEVBQUUsUUFBUSxDQUFDO0lBQ2YsQ0FBQyxHQUFHLEVBQUUsVUFBVSxDQUFDO0lBQ2pCLENBQUMsR0FBRyxFQUFFLFVBQVUsQ0FBQztJQUNqQixDQUFDLElBQUksRUFBRSxL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QUMsQ0FBQyxDQUFBO0lBQzVDLE1BQU0sSUFBSSxHQUFHLEtBQUssRUFBRSxJQUFJLElBQUksRUFBRSxDQUFBO0lBQzlCLE1BQU0sU0FBUyxHQUFHLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQyxHQUFHLEVBQUUsRUFBRSxDQUFDLEdBQUcsQ0FBQyxHQUFHLElBQUksS0FBSyxDQUFDLENBQUE7SUFDeEQsTUFBTSxTQUFTLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDLEdBQUcsRUFBRSxFQUFFLENBQUMsR0FBRyxDQUFDLEdBQUcsSUFBSSx1QkFBdUIsQ0FBQyxDQUFBO0lBQzFFLE1BQU0sUUFBUSxHQUFHLFlBQVksQ0FBQyxJQUFJLEVBQUUsUUFBUSxFQUFFLE1BQU0sQ0FBQyxDQUFBO0lBRXJELElBQUksU0FBUyxDQUFDLE1BQU0sSUFBSSxDQUFDLElBQUksU0FBUyxDQUFDLE1BQU0sSUFBSSxDQUFDO1FBQUUsT0FBTyxTQUFTLENBQUE7SUFFcEUsTUFBTSxhQUFhLEdBQUcsU0FBUyxDQUFDLE1BQU0sSUFBSSxDQUFDLElBQUksU0FBUyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksSUFBSSxFQUFFLElBQUksU0FBUyxDQUFDLENBQUMsQ0FBQyxDQUFDLFdBQVcsSUFBSSxJQUFJLElBQUksRUFBRSxDQUFBO0lBQ2hILE1BQU0sY0FBYyxHQUFHLFNBQVMsQ0FBQyxNQUFNLElBQUksQ0FBQyxJQUFJLFNBQVMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxHQUFHLEVBQUUsRUFBRSxDQUFDLEdBQUcsQ0FBQyxJQUFJLElBQUksRUFBRSxJQUFJLEdBQUcsQ0FBQyxJQUFJLElBQUksRUFBRSxJQUFJLEdBQUcsQ0FBQyxXQUFXLElBQUksRUFBRSxDQUFDLENBQUE7SUFDbkksTUFBTSxTQUFTLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLEdBQUcsRUFBRSxFQUFFLENBQUMsR0FBRyxDQUFDLEdBQUcsSUFBSSxLQUFLLElBQUksR0FBRyxDQUFDLEdBQUcsSUFBSSx1QkFBdUIsQ0FBQyxDQUFBO0lBRTdG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S0FBSyxFQUFFLEtBQUssQ0FBQyxDQUFBO0lBQ25DLENBQUM7QUFDSCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQHRzLWNoZWNrXG5cbmltcG9ydCBQaHBQYXJzZXIgZnJvbSBcInBocC1wYXJzZXJcIlxuaW1wb3J0IHtwYXJzZSBhcyBwYXJzZUNvbW1lbnR9IGZyb20gXCJjb21tZW50LXBhcnNlclwiXG5pbXBvcnQge21pc3NpbmdUeXBlLCBwYXJzZUZhaWx1cmUsIHVuc3VwcG9ydGVkU3ludGF4fSBmcm9tIFwiLi4vZGlhZ25vc3RpYy5qc1wiXG5pbXBvcnQge2xvY2F0aW9uRnJvbU9mZnNldHMsIG1vZHVsZUxvY2F0aW9ufSBmcm9tIFwiLi4vc2VtYW50aWMvbG9jYXRpb24uanNcIlxuaW1wb3J0IHt3aXRoQWRhcHRlZE9wZXJhdGlvbn0gZnJvbSBcIi4uL3NlbWFudGljL29wZXJhdG9ycy5qc1wiXG5pbXBvcnQge3dpdGhQYXJzZXJSYW5nZXN9IGZyb20gXCIuLi9zZW1hbnRpYy9wcm92ZW5hbmNlLmpzXCJcbmltcG9ydCB7aGFzT25seVVuaWNvZGVTY2FsYXJzfSBmcm9tIFwiLi4vc2VtYW50aWMvc2NhbGFycy5qc1wiXG5pbXBvcnQge3JlcXVpcmVTb3VyY2VTY2FsYXJUeXBlfSBmcm9tIFwiLi9zY2FsYXJzLmpzXCJcbmNvbnN0IHBhcnNlciA9IG5ldyBQaHBQYXJzZXIuRW5naW5lKHtcbiAgYXN0OiB7d2l0aFBvc2l0aW9uczogdHJ1ZX0sXG4gIHBhcnNlcjoge2V4dHJhY3REb2M6IHRydWUsIHN1cHByZXNzRXJyb3JzOiBmYWxzZX1cbn0pXG4vKiogQHR5cGUge3N0cmluZyB8IHVuZGVmaW5lZH0gKi9cbmxldCBjYWNoZWRUb2tlblNvdXJjZVxuLyoqIEB0eXBlIHt7ZW5kOiBudW1iZXIsIHN0YXJ0OiBudW1iZXIsIHRleHQ6IHN0cmluZ31bXX0gKi9cbmxldCBjYWNoZWRUb2tlblJhbmdlcyA9IFtdXG5jb25zdCBwaHBCaW5hcnlPcGVyYXRpb25zID0gbmV3IE1hcChbXG4gIFtcIitcIiwgXCJQaHBBZGRcIl0sXG4gIFtcIi1cIiwgXCJTdWJ0cmFjdFwiXSxcbiAgW1wiKlwiLCBcIk11bHRpcGx5XCJdLFxuICBbXCImJlwiLCBcIkFuZFwiXSxcbiAgW1wifHxcIiwgXCJPclwiXSxcbiAgW1wiPT09XCIsIFwiRXF1YWxcIl0sXG4gIFtcIiE9PVwiLCBcIk5vdEVxdWFsXCJdLFxuICBbXCI8XCIsIFwiTGVzc1RoYW5cIl0sXG4gIFtcIjw9XCIsIFwiTGVzc1RoYW5PckVxdWFsXCJdLFxuICBbXCI+XCIsIFwiR3JlYXRlclRoYW5cIl0sXG4gIFtcIj49XCIsIFwiR3JlYXRlclRoYW5PckVxdWFsXCJdLFxuICBbXCIuXCIsIFwiU3RyaW5nQ29uY2F0XCJdXG5dKVxuXG4vKipcbiAqIFJldHVybnMgYSBub3JtYWxpemVkIFBIUCBub2RlIGxvY2F0aW9uLlxuICogQHBhcmFtIHtpbXBvcnQoXCJwaHAtcGFyc2VyXCIpLk5vZGV9IG5vZGUgLSBQSFAgcGFyc2VyIG5vZGUuXG4gKiBAcGFyYW0ge3N0cmluZ30gZmlsZW5hbWUgLSBTb3VyY2UgZmlsZW5hbWUuXG4gKiBAcGFyYW0ge3N0cmluZ30gc291cmNlIC0gQ29tcGxldGUgc291cmNlLlxuICogQHJldHVybnMge2ltcG9ydChcIi4uL3NlbWFudGljL3R5cGVzLmpzXCIpLlNvdXJjZUxvY2F0aW9ufSBTb3VyY2UgbG9jYXRpb24uXG4gKi9cbmZ1bmN0aW9uIG5vZGVMb2NhdGlvbihub2RlLCBmaWxlbmFtZSwgc291cmNlKSB7XG4gIGlmICghbm9kZS5sb2MpIHRocm93IG5ldyBFcnJvcihgUEhQIHBhcnNlciBvbWl0dGVkIHNvdXJjZSBsb2NhdGlvbiBmb3IgJHtub2RlLmtpbmR9LmApXG5cbiAgcmV0dXJuIGxvY2F0aW9uRnJvbU9mZnNldHMoZmlsZW5hbWUsIHNvdXJjZSwgbm9kZS5sb2Muc3RhcnQub2Zmc2V0LCBub2RlLmxvYy5lbmQub2Zmc2V0KVxufVxuXG4vKipcbiAqIExvY2F0ZXMgYSBjb21tZW50LXBhcnNlciB0b2tlbiBpbnNpZGUgYSBQSFAgcGFyc2VyLW93bmVkIGRvYyBjb21tZW50LlxuICogQHBhcmFtIHtpbXBvcnQoXCJwaHAtcGFyc2VyXCIpLkNvbW1lbnRCbG9ja30gY29tbWVudCAtIFBIUCBkb2MgY29tbWVudC5cbiAqIEBwYXJhbSB7aW1wb3J0KFwiY29tbWVudC1wYXJzZXJcIikuU3BlY30gdGFnIC0gUGFyc2VkIGRvYyB0YWcuXG4gKiBAcGFyYW0ge1wibmFtZVwiIHwgXCJ0eXBlXCJ9IGZpZWxkIC0gVG9rZW4gZmllbGQuXG4gKiBAcGFyYW0ge3N0cmluZ30gZmlsZW5hbWUgLSBTb3VyY2UgZmlsZW5hbWUuXG4gKiBAcGFyYW0ge3N0cmluZ30gc291cmNlIC0gQ29tcGxldGUgc291cmNlLlxuICogQHJldHVybnMge2ltcG9ydChcIi4uL3NlbWFudGljL3R5cGVzLmpzXCIpLlNvdXJjZUxvY2F0aW9ufSBFeGFjdCB0b2tlbiBsb2NhdGlvbi5cbiAqL1xuZnVuY3Rpb24gY29tbWVudFRhZ0xvY2F0aW9uKGNvbW1lbnQsIHRhZywgZmllbGQsIGZpbGVuYW1lLCBzb3VyY2UpIHtcbiAgY29uc3QgbGluZSA9IHRhZy5zb3VyY2VbMF1cblxuICBpZiAoIWNvbW1lbnQubG9jIHx8ICFsaW5lKSB0aHJvdyBuZXcgRXJyb3IoYENvbW1lbnQgcGFyc2VyIG9taXR0ZWQgdGhlIEAke3RhZy50YWd9IHNvdXJjZSB0b2tlbi5gKVxuXG4gIGxldCBsaW5lU3RhcnQgPSBjb21tZW50LmxvYy5zdGFydC5vZmZzZXRcblxuICBmb3IgKGxldCBsaW5lTnVtYmVyID0gMDsgbGluZU51bWJlciA8IGxpbmUubnVtYmVyOyBsaW5lTnVtYmVyKyspIHtcbiAgICB3aGlsZSAobGluZVN0YXJ0IDwgc291cmNlLmxlbmd0aCAmJiBzb3VyY2VbbGluZVN0YXJ0XSAhPSBcIlxcclwiICYmIHNvdXJjZVtsaW5lU3RhcnRdICE9IFwiXFxuXCIpIGxpbmVTdGFydCsrXG4gICAgaWYgKHNvdXJjZVtsaW5lU3RhcnRdID09IFwiXFxyXCIgJiYgc291cmNlW2xpbmVTdGFydCArIDFdID09IFwiXFxuXCIpIGxpbmVTdGFydCArPSAyXG4gICAgZWxzZSBsaW5lU3RhcnQrK1xuICB9XG5cbiAgY29uc3Qgb3JkZXJlZEZpZWxkcyA9IFtcInN0YXJ0XCIsIFwiZGVsaW1pdGVyXCIsIFwicG9zdERlbGltaXRlclwiLCBcInRhZ1wiLCBcInBvc3RUYWdcIiwgXCJuYW1lXCIsIFwicG9zdE5hbWVcIiwgXCJ0eXBlXCJdXG4gIGNvbnN0IGZpZWxkSW5kZXggPSBvcmRlcmVkRmllbGRzLmluZGV4T2YoZmllbGQpXG4gIGNvbnN0IHN0YXJ0ID0gbGluZVN0YXJ0ICsgb3JkZXJlZEZpZWxkcy5zbGljZSgwLCBmaWVsZEluZGV4KS5yZWR1Y2UoKGxlbmd0aCwga2V5KSA9PlxuICAgIGxlbmd0aCArIGxpbmUudG9rZW5zWy8qKiBAdHlwZSB7a2V5b2YgdHlwZW9mIGxpbmUudG9rZW5zfSAqLyAoa2V5KV0ubGVuZ3RoLCAwKVxuICBjb25zdCB2YWx1ZSA9IGxpbmUudG9rZW5zW2ZpZWxkXVxuXG4gIHJldHVybiBsb2NhdGlvbkZyb21PZmZzZXRzKGZpbGVuYW1lLCBzb3VyY2UsIHN0YXJ0LCBzdGFydCArIHZhbHVlLmxlbmd0aClcbn1cblxuLyoqXG4gKiBGaW5kcyBvbmUgcGFyc2VyIHRva2VuIGJldHdlZW4gcGFyc2VyLW93bmVkIG5vZGUgYm91bmRhcmllcy5cbiAqIEBwYXJhbSB7c3RyaW5nfSB0b2tlblRleHQgLSBFeGFjdCB0b2tlbiB0ZXh0LlxuICogQHBhcmFtIHtudW1iZXJ9IHN0YXJ0T2Zmc2V0IC0gSW5jbHVzaXZlIHNlYXJjaCBib3VuZGFyeS5cbiAqIEBwYXJhbSB7bnVtYmVyfSBlbmRPZmZzZXQgLSBFeGNsdXNpdmUgc2VhcmNoIGJvdW5kYXJ5LlxuICogQHBhcmFtIHtzdHJpbmd9IGZpbGVuYW1lIC0gU291cmNlIGZpbGVuYW1lLlxuICogQHBhcmFtIHtzdHJpbmd9IHNvdXJjZSAtIENvbXBsZXRlIHNvdXJjZS5cbiAqIEByZXR1cm5zIHtpbXBvcnQoXCIuLi9zZW1hbnRpYy90eXBlcy5qc1wiKS5Tb3VyY2VMb2NhdGlvbn0gVG9rZW4gbG9jYXRpb24uXG4gKi9cbmZ1bmN0aW9uIHRva2VuTG9jYXRpb24odG9rZW5UZXh0LCBzdGFydE9mZnNldCwgZW5kT2Zmc2V0LCBmaWxlbmFtZSwgc291cmNlKSB7XG4gIGlmIChjYWNoZWRUb2tlblNvdXJjZSAhPSBzb3VyY2UpIHtcbiAgICBsZXQgb2Zmc2V0ID0gMFxuXG4gICAgY2FjaGVkVG9rZW5SYW5nZXMgPSBwYXJzZXIudG9rZW5HZXRBbGwoc291cmNlKS5tYXAoKHRva2VuKSA9PiB7XG4gICAgICBjb25zdCB0ZXh0ID0gdHlwZW9mIHRva2VuID09IFwic3RyaW5nXCIgPyB0b2tlbiA6IHRva2VuWzFdXG4gICAgICBjb25zdCByYW5nZSA9IHtlbmQ6IG9mZnNldCArIHRleHQubGVuZ3RoLCBzdGFydDogb2Zmc2V0LCB0ZXh0fVxuXG4gICAgICBvZmZzZXQgPSByYW5nZS5lbmRcblxuICAgICAgcmV0dXJuIHJhbmdlXG4gICAgfSlcbiAgICBjYWNoZWRUb2tlblNvdXJjZSA9IHNvdXJjZVxuICB9XG5cbiAgY29uc3QgdG9rZW4gPSBjYWNoZWRUb2tlblJhbmdlcy5maW5kKChjYW5kaWRhdGUpID0+IGNhbmRpZGF0ZS50ZXh0ID09IHRva2VuVGV4dCAmJiBjYW5kaWRhdGUuc3RhcnQgPj0gc3RhcnRPZmZzZXQgJiZcbiAgICBjYW5kaWRhdGUuZW5kIDw9IGVuZE9mZnNldClcblxuICBpZiAodG9rZW4pIHJldHVybiBsb2NhdGlvbkZyb21PZmZzZXRzKGZpbGVuYW1lLCBzb3VyY2UsIHRva2VuLnN0YXJ0LCB0b2tlbi5lbmQpXG5cbiAgdGhyb3cgbmV3IEVycm9yKGBQSFAgcGFyc2VyIG9taXR0ZWQgdG9rZW4gJyR7dG9rZW5UZXh0fScgYmV0d2VlbiAke3N0YXJ0T2Zmc2V0fSBhbmQgJHtlbmRPZmZzZXR9LmApXG59XG5cbi8qKlxuICogQ29udmVydHMgYSBzdXBwb3J0ZWQgUEhQIGV4cHJlc3Npb24uXG4gKiBAcGFyYW0ge2ltcG9ydChcInBocC1wYXJzZXJcIikuRXhwcmVzc2lvbn0gbm9kZSAtIFBIUCBleHByZXNzaW9uLlxuICogQHBhcmFtIHtzdHJpbmd9IGZpbGVuYW1lIC0gU291cmNlIGZpbGVuYW1lLlxuICogQHBhcmFtIHtzdHJpbmd9IHNvdXJjZSAtIENvbXBsZXRlIHNvdXJjZS5cbiAqIEByZXR1cm5zIHtpbXBvcnQoXCIuLi9zZW1hbnRpYy90eXBlcy5qc1wiKS5FeHByZXNzaW9ufSBTZW1hbnRpYyBleHByZXNzaW9uLlxuICovXG5mdW5jdGlvbiBjb252ZXJ0RXhwcmVzc2lvbihub2RlLCBmaWxlbmFtZSwgc291cmNlKSB7XG4gIGNvbnN0IGxvY2F0aW9uID0gbm9kZUxvY2F0aW9uKG5vZGUsIGZpbGVuYW1lLCBzb3VyY2UpXG5cbiAgaWYgKG5vZGUua2luZCA9PSBcInZhcmlhYmxlXCIpIHtcbiAgICBjb25zdCB2YXJpYWJsZSA9IC8qKiBAdHlwZSB7aW1wb3J0KFwicGhwLXBhcnNlclwiKS5WYXJpYWJsZX0gKi8gKG5vZGUpXG5cbiAgICBpZiAodHlwZW9mIHZhcmlhYmxlLm5hbWUgIT0gXCJzdHJpbmdcIikgcmV0dXJuIHVuc3VwcG9ydGVkU3ludGF4KFwicGhwXCIsIFwiZHluYW1pYyB2YXJpYWJsZVwiLCBsb2NhdGlvbilcblxuICAgIHJldHVybiB3aXRoUGFyc2VyUmFuZ2VzKHtraW5kOiAvKiogQHR5cGUge2NvbnN0fSAqLyAoXCJJZGVudGlmaWVyRXhwcmVzc2lvblwiKSwgbG9jYXRpb24sIG5hbWU6IHZhcmlhYmxlLm5hbWV9LCB7bmFtZTogbG9jYXRpb259KVxuICB9XG5cbiAgaWYgKG5vZGUua2luZCA9PSBcIm51bWJlclwiKSB7XG4gICAgY29uc3QgbGl0ZXJhbCA9IC8qKiBAdHlwZSB7aW1wb3J0KFwicGhwLXBhcnNlclwiKS5OdW1iZXJ9ICovIChub2RlKVxuICAgIGNvbnN0IHZhbHVlID0gTnVtYmVyKGxpdGVyYWwudmFsdWUpXG5cbiAgICBpZiAoIU51bWJlci5pc1NhZmVJbnRlZ2VyKHZhbHVlKSkgcmV0dXJuIHVuc3VwcG9ydGVkU3ludGF4KFwicGhwXCIsIFwibm9uLXNhZmUgaW50ZWdlciBsaXRlcmFsXCIsIGxvY2F0aW9uKVxuXG4gICAgcmV0dXJuIHdpdGhQYXJzZXJSYW5nZXMoe2tpbmQ6IC8qKiBAdHlwZSB7Y29uc3R9ICovIChcIkludGVnZXJMaXRlcmFsXCIpLCBsb2NhdGlvbiwgdmFsdWV9LCB7bGl0ZXJhbDogbG9jYXRpb259KVxuICB9XG5cbiAgaWYgKG5vZGUua2luZCA9PSBcImJvb2xlYW5cIikge1xuICAgIGNvbnN0IGxpdGVyYWwgPSAvKiogQHR5cGUge2ltcG9ydChcInBocC1wYXJzZXJcIikuQm9vbGVhbn0gKi8gKG5vZGUpXG5cbiAgICBpZiAodHlwZW9mIGxpdGVyYWwudmFsdWUgIT0gXCJib29sZWFuXCIpIHJldHVybiB1bnN1cHBvcnRlZFN5bnRheChcInBocFwiLCBcImludmFsaWQgYm9vbGVhbiBsaXRlcmFsIHZhbHVlXCIsIGxvY2F0aW9uKVxuXG4gICAgcmV0dXJuIHdpdGhQYXJzZXJSYW5nZXMoe2tpbmQ6IC8qKiBAdHlwZSB7Y29uc3R9ICovIChcIkJvb2xlYW5MaXRlcmFsXCIpLCBsb2NhdGlvbiwgdmFsdWU6IGxpdGVyYWwudmFsdWV9LCB7bGl0ZXJhbDogbG9jYXRpb259KVxuICB9XG5cbiAgaWYgKG5vZGUua2luZCA9PSBcInN0cmluZ1wiKSB7XG4gICAgY29uc3QgbGl0ZXJhbCA9IC8qKiBAdHlwZSB7aW1wb3J0KFwicGhwLXBhcnNlclwiKS5TdHJpbmd9ICovIChub2RlKVxuXG4gICAgaWYgKHR5cGVvZiBsaXRlcmFsLnJhdyA9PSBcInN0cmluZ1wiICYmIGxpdGVyYWwucmF3LnN0YXJ0c1dpdGgoXCI8PDxcIikpIHtcbiAgICAgIGNvbnN0IGRldGFpbCA9IGxpdGVyYWwucmF3LnN0YXJ0c1dpdGgoXCI8PDwnXCIpID8gXCJub3dkb2Mgc3RyaW5nXCIgOiBcImhlcmVkb2Mgc3RyaW5nXCJcblxuICAgICAgcmV0dXJuIHVuc3VwcG9ydGVkU3ludGF4KFwicGhwXCIsIGRldGFpbCwgbG9jYXRpb24pXG4gICAgfVxuICAgIGlmICh0eXBlb2YgbGl0ZXJhbC5yYXcgPT0gXCJzdHJpbmdcIiAmJiBbXCJiXFxcIlwiLCBcIkJcXFwiXCIsIFwiYidcIiwgXCJCJ1wiXS5zb21lKChwcmVmaXgpID0+IGxpdGVyYWwucmF3LnN0YXJ0c1dpdGgocHJlZml4KSkpIHtcbiAgICAgIHJldHVybiB1bnN1cHBvcnRlZFN5bnRheChcInBocFwiLCBcImJpbmFyeSBzdHJpbmcgbGl0ZXJhbFwiLCBsb2NhdGlvbilcbiAgICB9XG4gICAgaWYgKHR5cGVvZiBsaXRlcmFsLnZhbHVlICE9IFwic3RyaW5nXCIgfHwgIWhhc09ubHlVbmljb2RlU2NhbGFycyhsaXRlcmFsLnZhbHVlKSkge1xuICAgICAgcmV0dXJuIHVuc3VwcG9ydGVkU3ludGF4KFwicGhwXCIsIFwiaW52YWxpZCBVbmljb2RlIHN0cmluZyBsaXRlcmFsXCIsIGxvY2F0aW9uKVxuICAgIH1cblxuICAgIHJldHVybiB3aXRoUGFyc2VyUmFuZ2VzKHtraW5kOiAvKiogQHR5cGUge2NvbnN0fSAqLyAoXCJTdHJpbmdMaXRlcmFsXCIpLCBsb2NhdGlvbiwgdmFsdWU6IGxpdGVyYWwudmFsdWV9LCB7bGl0ZXJhbDogbG9jYXRpb259KVxuICB9XG5cbiAgaWYgKG5vZGUua2luZCA9PSBcImVuY2Fwc2VkXCIpIHtcbiAgICBjb25zdCBsaXRlcmFsID0gLyoqIEB0eXBlIHtpbXBvcnQoXCJwaHAtcGFyc2VyXCIpLkVuY2Fwc2VkfSAqLyAobm9kZSlcbiAgICBjb25zdCBkZXRhaWwgPSBsaXRlcmFsLnR5cGUgPT0gXCJzdHJpbmdcIiA/IFwiaW50ZXJwb2xhdGVkIHN0cmluZ1wiIDogYCR7bGl0ZXJhbC50eXBlfSBzdHJpbmdgXG5cbiAgICByZXR1cm4gdW5zdXBwb3J0ZWRTeW50YXgoXCJwaHBcIiwgZGV0YWlsLCBsb2NhdGlvbilcbiAgfVxuXG4gIGlmIChub2RlLmtpbmQgPT0gXCJub3dkb2NcIikgcmV0dXJuIHVuc3VwcG9ydGVkU3ludGF4KFwicGhwXCIsIFwibm93ZG9jIHN0cmluZ1wiLCBsb2NhdGlvbilcblxuICBpZiAobm9kZS5raW5kID09IFwidW5hcnlcIikge1xuICAgIGNvbnN0IHVuYXJ5ID0gLyoqIEB0eXBlIHtpbXBvcnQoXCJwaHAtcGFyc2VyXCIpLlVuYXJ5fSAqLyAobm9kZSlcblxuICAgIGlmICghW1wiIVwiLCBcIi1cIl0uaW5jbHVkZXModW5hcnkudHlwZSkpIHJldHVybiB1bnN1cHBvcnRlZFN5bnRheChcInBocFwiLCBgdW5hcnkgJHt1bmFyeS50eXBlfWAsIGxvY2F0aW9uKVxuXG4gICAgY29uc3Qgc2VtYW50aWMgPSB3aXRoQWRhcHRlZE9wZXJhdGlvbih3aXRoUGFyc2VyUmFuZ2VzKHtcbiAgICAgIGtpbmQ6IFwiVW5hcnlFeHByZXNzaW9uXCIsXG4gICAgICBsb2NhdGlvbixcbiAgICAgIG9wZXJhbmQ6IGNvbnZlcnRFeHByZXNzaW9uKHVuYXJ5LndoYXQsIGZpbGVuYW1lLCBzb3VyY2UpXG4gICAgfSwge1xuICAgICAgb3BlcmF0b3I6IHRva2VuTG9jYXRpb24odW5hcnkudHlwZSwgdW5hcnkubG9jPy5zdGFydC5vZmZzZXQgPz8gMCwgdW5hcnkud2hhdC5sb2M/LnN0YXJ0Lm9mZnNldCA/PyB1bmFyeS5sb2M/LmVuZC5vZmZzZXQgPz8gc291cmNlLmxlbmd0aCwgZmlsZW5hbWUsIHNvdXJjZSlcbiAgICB9KSwgdW5hcnkudHlwZSA9PSBcIiFcIiA/IFwiTm90XCIgOiBcIk5lZ2F0ZVwiKVxuXG4gICAgcmV0dXJuIC8qKiBAdHlwZSB7aW1wb3J0KFwiLi4vc2VtYW50aWMvdHlwZXMuanNcIikuRXhwcmVzc2lvbn0gKi8gKC8qKiBAdHlwZSB7dW5rbm93bn0gKi8gKHNlbWFudGljKSlcbiAgfVxuXG4gIGlmIChub2RlLmtpbmQgPT0gXCJiaW5cIikge1xuICAgIGNvbnN0IGJpbmFyeSA9IC8qKiBAdHlwZSB7aW1wb3J0KFwicGhwLXBhcnNlclwiKS5CaW59ICovIChub2RlKVxuICAgIGlmIChbXCI9PVwiLCBcIiE9XCJdLmluY2x1ZGVzKGJpbmFyeS50eXBlKSkgcmV0dXJuIHVuc3VwcG9ydGVkU3ludGF4KFwicGhwXCIsIGBjb2VyY2l2ZSBlcXVhbGl0eSAke2JpbmFyeS50eXBlfWAsIGxvY2F0aW9uKVxuICAgIGlmIChbXCJhbmRcIiwgXCJvclwiXS5pbmNsdWRlcyhiaW5hcnkudHlwZSkpIHJldHVybiB1bnN1cHBvcnRlZFN5bnRheChcInBocFwiLCBgcHJlY2VkZW5jZS1zZW5zaXRpdmUgYm9vbGVhbiAke2JpbmFyeS50eXBlfWAsIGxvY2F0aW9uKVxuICAgIGlmICghcGhwQmluYXJ5T3BlcmF0aW9ucy5oYXMoYmluYXJ5LnR5cGUpKSByZXR1cm4gdW5zdXBwb3J0ZWRTeW50YXgoXCJwaHBcIiwgYGJpbmFyeSAke2JpbmFyeS50eXBlfWAsIGxvY2F0aW9uKVxuXG4gICAgY29uc3Qgc2VtYW50aWMgPSB3aXRoQWRhcHRlZE9wZXJhdGlvbih7XG4gICAgICBraW5kOiAvKiogQHR5cGUge2NvbnN0fSAqLyAoXCJCaW5hcnlFeHByZXNzaW9uXCIpLFxuICAgICAgbGVmdDogY29udmVydEV4cHJlc3Npb24oYmluYXJ5LmxlZnQsIGZpbGVuYW1lLCBzb3VyY2UpLFxuICAgICAgbG9jYXRpb24sXG4gICAgICByaWdodDogY29udmVydEV4cHJlc3Npb24oYmluYXJ5LnJpZ2h0LCBmaWxlbmFtZSwgc291cmNlKVxuICAgIH0sIC8qKiBAdHlwZSB7aW1wb3J0KFwiLi4vc2VtYW50aWMvb3BlcmF0b3JzLmpzXCIpLkFkYXB0ZWRPcGVyYXRpb259ICovIChwaHBCaW5hcnlPcGVyYXRpb25zLmdldChiaW5hcnkudHlwZSkpKVxuXG4gICAgcmV0dXJuIC8qKiBAdHlwZSB7aW1wb3J0KFwiLi4vc2VtYW50aWMvdHlwZXMuanNcIikuRXhwcmVzc2lvbn0gKi8gKC8qKiBAdHlwZSB7dW5rbm93bn0gKi8gKHdpdGhQYXJzZXJSYW5nZXMoc2VtYW50aWMsIHtcbiAgICAgIG9wZXJhdG9yOiB0b2tlbkxvY2F0aW9uKGJpbmFyeS50eXBlLCBiaW5hcnkubGVmdC5sb2M/LmVuZC5vZmZzZXQgPz8gMCwgYmluYXJ5LnJpZ2h0LmxvYz8uc3RhcnQub2Zmc2V0ID8/IHNvdXJjZS5sZW5ndGgsIGZpbGVuYW1lLCBzb3VyY2UpXG4gICAgfSkpKVxuICB9XG5cbiAgaWYgKG5vZGUua2luZCA9PSBcImNhbGxcIikge1xuICAgIGNvbnN0IGNhbGwgPSAvKiogQHR5cGUge2ltcG9ydChcInBocC1wYXJzZXJcIikuQ2FsbH0gKi8gKG5vZGUpXG5cbiAgICBpZiAoY2FsbC53aGF0LmtpbmQgIT0gXCJuYW1lXCIgJiYgY2FsbC53aGF0LmtpbmQgIT0gXCJpZGVudGlmaWVyXCIpIHtcbiAgICAgIHJldHVybiB1bnN1cHBvcnRlZFN5bnRheChcInBocFwiLCBcImR5bmFtaWMgY2FsbFwiLCBsb2NhdGlvbilcbiAgICB9XG5cbiAgICBjb25zdCBjYWxsZWUgPSAvKiogQHR5cGUge2ltcG9ydChcInBocC1wYXJzZXJcIikuTmFtZSB8IGltcG9ydChcInBocC1wYXJzZXJcIikuSWRlbnRpZmllcn0gKi8gKGNhbGwud2hhdCkubmFtZVxuXG4gICAgcmV0dXJuIHdpdGhQYXJzZXJSYW5nZXMoe1xuICAgICAgYXJndW1lbnRzOiBjYWxsLmFyZ3VtZW50cy5tYXAoKGFyZ3VtZW50KSA9PiBjb252ZXJ0RXhwcmVzc2lvbihhcmd1bWVudCwgZmlsZW5hbWUsIHNvdXJjZSkpLFxuICAgICAgY2FsbGVlLFxuICAgICAga2luZDogXCJDYWxsRXhwcmVzc2lvblwiLFxuICAgICAgbG9jYXRpb25cbiAgICB9LCB7Y2FsbGVlOiBub2RlTG9jYXRpb24oY2FsbC53aGF0LCBmaWxlbmFtZSwgc291cmNlKX0pXG4gIH1cblxuICByZXR1cm4gdW5zdXBwb3J0ZWRTeW50YXgoXCJwaHBcIiwgbm9kZS5raW5kLCBsb2NhdGlvbilcbn1cblxuLyoqXG4gKiBDb252ZXJ0cyBvbmUgZXhwbGljaXQgUEhQIHJldHVybi5cbiAqIEBwYXJhbSB7aW1wb3J0KFwicGhwLXBhcnNlclwiKS5Ob2RlfSBub2RlIC0gUEhQIG5vZGUuXG4gKiBAcGFyYW0ge3N0cmluZ30gZmlsZW5hbWUgLSBTb3VyY2UgZmlsZW5hbWUuXG4gKiBAcGFyYW0ge3N0cmluZ30gc291cmNlIC0gQ29tcGxldGUgc291cmNlLlxuICogQHJldHVybnMge2ltcG9ydChcIi4uL3NlbWFudGljL3R5cGVzLmpzXCIpLlJldHVyblN0YXRlbWVudH0gU2VtYW50aWMgcmV0dXJuLlxuICovXG5mdW5jdGlvbiBjb252ZXJ0UmV0dXJuKG5vZGUsIGZpbGVuYW1lLCBzb3VyY2UpIHtcbiAgY29uc3QgbG9jYXRpb24gPSBub2RlTG9jYXRpb24obm9kZSwgZmlsZW5hbWUsIHNvdXJjZSlcblxuICBpZiAobm9kZS5raW5kICE9IFwicmV0dXJuXCIpIHJldHVybiB1bnN1cHBvcnRlZFN5bnRheChcInBocFwiLCBub2RlLmtpbmQsIGxvY2F0aW9uKVxuXG4gIGNvbnN0IHJldHVybk5vZGUgPSAvKiogQHR5cGUge2ltcG9ydChcInBocC1wYXJzZXJcIikuUmV0dXJufSAqLyAobm9kZSlcblxuICBpZiAoIXJldHVybk5vZGUuZXhwcikgcmV0dXJuIHVuc3VwcG9ydGVkU3ludGF4KFwicGhwXCIsIFwiZW1wdHkgcmV0dXJuXCIsIGxvY2F0aW9uKVxuXG4gIHJldHVybiB7ZXhwcmVzc2lvbjogY29udmVydEV4cHJlc3Npb24ocmV0dXJuTm9kZS5leHByLCBmaWxlbmFtZSwgc291cmNlKSwga2luZDogXCJSZXR1cm5TdGF0ZW1lbnRcIiwgbG9jYXRpb259XG59XG5cbi8qKlxuICogUmVhZHMgb25lIGV4YWN0IFBIUCBsb2NhbCBgQHZhcmAgY2FycmllciBhbmQgaW1tdXRhYmlsaXR5IG1hcmtlci5cbiAqIEBwYXJhbSB7aW1wb3J0KFwicGhwLXBhcnNlclwiKS5Ob2RlfSBub2RlIC0gQXNzaWdubWVudC1vd25pbmcgc3RhdGVtZW50LlxuICogQHBhcmFtIHtzdHJpbmd9IG5hbWUgLSBMb2NhbCBuYW1lLlxuICogQHBhcmFtIHtzdHJpbmd9IGZpbGVuYW1lIC0gU291cmNlIGZpbGVuYW1lLlxuICogQHBhcmFtIHtzdHJpbmd9IHNvdXJjZSAtIENvbXBsZXRlIHNvdXJjZS5cbiAqIEByZXR1cm5zIHt7aW1tdXRhYmxlOiBib29sZWFuLCB0eXBlOiBpbXBvcnQoXCIuLi9zZW1hbnRpYy90eXBlcy5qc1wiKS5UeXBlUmVmZXJlbmNlfSB8IHVuZGVmaW5lZH0gTWV0YWRhdGEgd2hlbiBwcmVzZW50LlxuICovXG5mdW5jdGlvbiBsb2NhbE1ldGFkYXRhKG5vZGUsIG5hbWUsIGZpbGVuYW1lLCBzb3VyY2UpIHtcbiAgY29uc3QgY29tbWVudHMgPSBub2RlLmxlYWRpbmdDb21tZW50cyA/PyBbXVxuICBjb25zdCBjb21tZW50ID0gY29tbWVudHMuYXQoLTEpXG5cbiAgaWYgKCFjb21tZW50IHx8IGNvbW1lbnQua2luZCAhPSBcImNvbW1lbnRibG9ja1wiIHx8ICFjb21tZW50LmxvYyB8fCAhbm9kZS5sb2MpIHJldHVybiB1bmRlZmluZWRcblxuICBjb25zdCBnYXAgPSBzb3VyY2Uuc2xpY2UoY29tbWVudC5sb2MuZW5kLm9mZnNldCwgbm9kZS5sb2Muc3RhcnQub2Zmc2V0KVxuXG4gIGlmICghL15cXHMqJC91LnRlc3QoZ2FwKSB8fCAoZ2FwLm1hdGNoKC9cXG4vZ3UpPy5sZW5ndGggPz8gMCkgPiAxKSByZXR1cm4gdW5kZWZpbmVkXG5cbiAgY29uc3QgYmxvY2sgPSBwYXJzZUNvbW1lbnQoY29tbWVudC52YWx1ZSlbMF1cbiAgY29uc3QgdGFncyA9IGJsb2NrPy50YWdzID8/IFtdXG4gIGNvbnN0IHZhcmlhYmxlcyA9IHRhZ3MuZmlsdGVyKCh0YWcpID0+IHRhZy50YWcgPT0gXCJ2YXJcIilcbiAgY29uc3QgaW1tdXRhYmxlID0gdGFncy5maWx0ZXIoKHRhZykgPT4gdGFnLnRhZyA9PSBcInNlbWFudGlmb2xkLWltbXV0YWJsZVwiKVxuICBjb25zdCBsb2NhdGlvbiA9IG5vZGVMb2NhdGlvbihub2RlLCBmaWxlbmFtZSwgc291cmNlKVxuXG4gIGlmICh2YXJpYWJsZXMubGVuZ3RoID09IDAgJiYgaW1tdXRhYmxlLmxlbmd0aCA9PSAwKSByZXR1cm4gdW5kZWZpbmVkXG5cbiAgY29uc3QgZXhhY3RWYXJpYWJsZSA9IHZhcmlhYmxlcy5sZW5ndGggPT0gMSAmJiB2YXJpYWJsZXNbMF0udHlwZSA9PSBcIlwiICYmIHZhcmlhYmxlc1swXS5kZXNjcmlwdGlvbiA9PSBgJCR7bmFtZX1gXG4gIGNvbnN0IGV4YWN0SW1tdXRhYmxlID0gaW1tdXRhYmxlLmxlbmd0aCA8PSAxICYmIGltbXV0YWJsZS5ldmVyeSgodGFnKSA9PiB0YWcubmFtZSA9PSBcIlwiICYmIHRhZy50eXBlID09IFwiXCIgJiYgdGFnLmRlc2NyaXB0aW9uID09IFwiXCIpXG4gIGNvbnN0IGtub3duVGFncyA9IHRhZ3MuZXZlcnkoKHRhZykgPT4gdGFnLnRhZyA9PSBcInZhclwiIHx8IHRhZy50YWcgPT0gXCJzZW1hbnRpZm9sZC1pbW11dGFibGVcIilcblxuICBpZiAoIWV4YWN0VmFyaWFibGUgfHwgIWV4YWN0SW1tdXRhYmxlIHx8ICFrbm93blRhZ3MpIHtcbiAgICByZXR1cm4gdW5zdXBwb3J0ZWRTeW50YXgoXCJwaHBcIiwgXCJtYWxmb3JtZWQgbG9jYWwgdHlwZSBtZXRhZGF0YVwiLCBsb2NhdGlvbilcbiAgfVxuXG4gIHJldHVybiB7XG4gICAgaW1tdXRhYmxlOiBpbW11dGFibGUubGVuZ3RoID09IDEsXG4gICAgdHlwZTogcmVxdWlyZVNvdXJjZVNjYWxhclR5cGUoXG4gICAgICBcInBocFwiLFxuICAgICAgdmFyaWFibGVzWzBdLm5hbWUsXG4gICAgICBgTG9jYWwgJyR7bmFtZX0nYCxcbiAgICAgIGxvY2F0aW9uLFxuICAgICAgY29tbWVudFRhZ0xvY2F0aW9uKGNvbW1lbnQsIHZhcmlhYmxlc1swXSwgXCJuYW1lXCIsIGZpbGVuYW1lLCBzb3VyY2UpXG4gICAgKVxuICB9XG59XG5cbi8qKlxuICogQ29udmVydHMgb25lIFBIUCBsb2NhbCBkZWNsYXJhdGlvbiBvciBhc3NpZ25tZW50LlxuICogQHBhcmFtIHtpbXBvcnQoXCJwaHAtcGFyc2VyXCIpLk5vZGV9IG5vZGUgLSBQSFAgc3RhdGVtZW50LlxuICogQHBhcmFtIHtTZXQ8c3RyaW5nPn0gdmlzaWJsZSAtIE5hbWVzIHZpc2libGUgZHVyaW5nIGFkYXB0YXRpb24uXG4gKiBAcGFyYW0ge3N0cmluZ30gZmlsZW5hbWUgLSBTb3VyY2UgZmlsZW5hbWUuXG4gKiBAcGFyYW0ge3N0cmluZ30gc291cmNlIC0gQ29tcGxldGUgc291cmNlLlxuICogQHJldHVybnMge2ltcG9ydChcIi4uL3NlbWFudGljL3R5cGVzLmpzXCIpLkxvY2FsU3RhdGVtZW50fSBTZW1hbnRpYyBsb2NhbCBzdGF0ZW1lbnQuXG4gKi9cbmZ1bmN0aW9uIGNvbnZlcnRMb2NhbFN0YXRlbWVudChub2RlLCB2aXNpYmxlLCBmaWxlbmFtZSwgc291cmNlKSB7XG4gIGNvbnN0IGxvY2F0aW9uID0gbm9kZUxvY2F0aW9uKG5vZGUsIGZpbGVuYW1lLCBzb3VyY2UpXG5cbiAgaWYgKG5vZGUua2luZCAhPSBcImV4cHJlc3Npb25zdGF0ZW1lbnRcIikgcmV0dXJuIHVuc3VwcG9ydGVkU3ludGF4KFwicGhwXCIsIG5vZGUua2luZCwgbG9jYXRpb24pXG5cbiAgY29uc3QgZXhwcmVzc2lvbiA9IC8qKiBAdHlwZSB7aW1wb3J0KFwicGhwLXBhcnNlclwiKS5FeHByZXNzaW9uU3RhdGVtZW50fSAqLyAobm9kZSkuZXhwcmVzc2lvblxuXG4gIGlmIChleHByZXNzaW9uLmtpbmQgIT0gXCJhc3NpZ25cIikgcmV0dXJuIHVuc3VwcG9ydGVkU3ludGF4KFwicGhwXCIsIGV4cHJlc3Npb24ua2luZCwgbm9kZUxvY2F0aW9uKGV4cHJlc3Npb24sIGZpbGVuYW1lLCBzb3VyY2UpKVxuXG4gIGNvbnN0IGFzc2lnbm1lbnQgPSAvKiogQHR5cGUge2ltcG9ydChcInBocC1wYXJzZXJcIikuQXNzaWdufSAqLyAoZXhwcmVzc2lvbilcblxuICBpZiAoYXNzaWdubWVudC5vcGVyYXRvciAhPSBcIj1cIikgcmV0dXJuIHVuc3VwcG9ydGVkU3ludGF4KFwicGhwXCIsIGBhc3NpZ25tZW50ICR7YXNzaWdubWVudC5vcGVyYXRvcn1gLCBsb2NhdGlvbilcbiAgaWYgKGFzc2lnbm1lbnQubGVmdC5raW5kICE9IFwidmFyaWFibGVcIikgcmV0dXJuIHVuc3VwcG9ydGVkU3ludGF4KFwicGhwXCIsIGFzc2lnbm1lbnQubGVmdC5raW5kLCBub2RlTG9jYXRpb24oYXNzaWdubWVudC5sZWZ0LCBmaWxlbmFtZSwgc291cmNlKSlcblxuICBjb25zdCB2YXJpYWJsZSA9IC8qKiBAdHlwZSB7aW1wb3J0KFwicGhwLXBhcnNlclwiKS5WYXJpYWJsZX0gKi8gKGFzc2lnbm1lbnQubGVmdClcbiAgY29uc3QgdGFyZ2V0TG9jYXRpb24gPSBub2RlTG9jYXRpb24odmFyaWFibGUsIGZpbGVuYW1lLCBzb3VyY2UpXG5cbiAgaWYgKHR5cGVvZiB2YXJpYWJsZS5uYW1lICE9IFwic3RyaW5nXCIgfHwgdmFyaWFibGUuY3VybHkpIHJldHVybiB1bnN1cHBvcnRlZFN5bnRheChcInBocFwiLCBcImR5bmFtaWMgdmFyaWFibGVcIiwgdGFyZ2V0TG9jYXRpb24pXG5cbiAgY29uc3QgbWV0YWRhdGEgPSBsb2NhbE1ldGFkYXRhKG5vZGUsIHZhcmlhYmxlLm5hbWUsIGZpbGVuYW1lLCBzb3VyY2UpXG5cbiAgaWYgKG1ldGFkYXRhKSB7XG4gICAgdmlzaWJsZS5hZGQodmFyaWFibGUubmFtZSlcbiAgICByZXR1cm4gd2l0aFBhcnNlclJhbmdlcyh7XG4gICAgICBpbml0aWFsaXplcjogY29udmVydEV4cHJlc3Npb24oYXNzaWdubWVudC5yaWdodCwgZmlsZW5hbWUsIHNvdXJjZSksXG4gICAgICBraW5kOiBcIkxvY2FsRGVjbGFyYXRpb25cIixcbiAgICAgIGxvY2F0aW9uLFxuICAgICAgbXV0YWJsZTogIW1ldGFkYXRhLmltbXV0YWJsZSxcbiAgICAgIG5hbWU6IHZhcmlhYmxlLm5hbWUsXG4gICAgICB0eXBlOiBtZXRhZGF0YS50eXBlXG4gICAgfSwge1xuICAgICAgbmFtZTogdGFyZ2V0TG9jYXRpb24sXG4gICAgICBvcGVyYXRvcjogdG9rZW5Mb2NhdGlvbihcIj1cIiwgYXNzaWdubWVudC5sZWZ0LmxvYz8uZW5kLm9mZnNldCA/PyAwLCBhc3NpZ25tZW50LnJpZ2h0LmxvYz8uc3RhcnQub2Zmc2V0ID8/IHNvdXJjZS5sZW5ndGgsIGZpbGVuYW1lLCBzb3VyY2UpXG4gICAgfSlcbiAgfVxuXG4gIGlmICghdmlzaWJsZS5oYXModmFyaWFibGUubmFtZSkpIHJldHVybiBtaXNzaW5nVHlwZShcInBocFwiLCBgTG9jYWwgJyR7dmFyaWFibGUubmFtZX0nYCwgbG9jYXRpb24pXG5cbiAgY29uc3QgdGFyZ2V0ID0gd2l0aFBhcnNlclJhbmdlcyh7a2luZDogLyoqIEB0eXBlIHtjb25zdH0gKi8gKFwiSWRlbnRpZmllckV4cHJlc3Npb25cIiksIGxvY2F0aW9uOiB0YXJnZXRMb2NhdGlvbiwgbmFtZTogdmFyaWFibGUubmFtZX0sIHtcbiAgICBuYW1lOiB0YXJnZXRMb2NhdGlvblxuICB9KVxuXG4gIHJldHVybiB3aXRoUGFyc2VyUmFuZ2VzKHtcbiAgICBleHByZXNzaW9uOiBjb252ZXJ0RXhwcmVzc2lvbihhc3NpZ25tZW50LnJpZ2h0LCBmaWxlbmFtZSwgc291cmNlKSxcbiAgICBraW5kOiBcIkFzc2lnbm1lbnRTdGF0ZW1lbnRcIixcbiAgICBsb2NhdGlvbixcbiAgICB0YXJnZXRcbiAgfSwge1xuICAgIG9wZXJhdG9yOiB0b2tlbkxvY2F0aW9uKFwiPVwiLCBhc3NpZ25tZW50LmxlZnQubG9jPy5lbmQub2Zmc2V0ID8/IDAsIGFzc2lnbm1lbnQucmlnaHQubG9jPy5zdGFydC5vZmZzZXQgPz8gc291cmNlLmxlbmd0aCwgZmlsZW5hbWUsIHNvdXJjZSlcbiAgfSlcbn1cblxuLyoqXG4gKiBDb252ZXJ0cyBvbmUgZXhoYXVzdGl2ZSBQSFAgc3RhdGVtZW50LlxuICogQHBhcmFtIHtpbXBvcnQoXCJwaHAtcGFyc2VyXCIpLk5vZGV9IG5vZGUgLSBQSFAgc3RhdGVtZW50LlxuICogQHBhcmFtIHtTZXQ8c3RyaW5nPn0gdmlzaWJsZSAtIE5hbWVzIHZpc2libGUgZHVyaW5nIGFkYXB0YXRpb24uXG4gKiBAcGFyYW0ge3N0cmluZ30gZmlsZW5hbWUgLSBTb3VyY2UgZmlsZW5hbWUuXG4gKiBAcGFyYW0ge3N0cmluZ30gc291cmNlIC0gQ29tcGxldGUgc291cmNlLlxuICogQHJldHVybnMge2ltcG9ydChcIi4uL3NlbWFudGljL3R5cGVzLmpzXCIpLlN0YXRlbWVudH0gU2VtYW50aWMgc3RhdGVtZW50LlxuICovXG5mdW5jdGlvbiBjb252ZXJ0U3RhdGVtZW50KG5vZGUsIHZpc2libGUsIGZpbGVuYW1lLCBzb3VyY2UpIHtcbiAgaWYgKG5vZGUua2luZCA9PSBcInJldHVyblwiKSByZXR1cm4gY29udmVydFJldHVybihub2RlLCBmaWxlbmFtZSwgc291cmNlKVxuICBpZiAobm9kZS5raW5kID09IFwiaWZcIikgcmV0dXJuIGNvbnZlcnRJZigvKiogQHR5cGUge2ltcG9ydChcInBocC1wYXJzZXJcIikuSWZ9ICovIChub2RlKSwgdmlzaWJsZSwgZmlsZW5hbWUsIHNvdXJjZSlcbiAgaWYgKG5vZGUua2luZCA9PSBcImVjaG9cIikgcmV0dXJuIGNvbnZlcnRQcmludCgvKiogQHR5cGUge2ltcG9ydChcInBocC1wYXJzZXJcIikuRWNob30gKi8gKG5vZGUpLCBmaWxlbmFtZSwgc291cmNlKVxuICBpZiAobm9kZS5raW5kID09IFwiZXhwcmVzc2lvbnN0YXRlbWVudFwiKSByZXR1cm4gY29udmVydExvY2FsU3RhdGVtZW50KG5vZGUsIHZpc2libGUsIGZpbGVuYW1lLCBzb3VyY2UpXG5cbiAgcmV0dXJuIHVuc3VwcG9ydGVkU3ludGF4KFwicGhwXCIsIG5vZGUua2luZCwgbm9kZUxvY2F0aW9uKG5vZGUsIGZpbGVuYW1lLCBzb3VyY2UpKVxufVxuXG4vKipcbiAqIENvbnZlcnRzIGFuIG9yZGVyZWQgUEhQIGJsb2NrIHdpdGggaXRzIG93biBhZGFwdGF0aW9uIHNjb3BlLlxuICogQHBhcmFtIHtpbXBvcnQoXCJwaHAtcGFyc2VyXCIpLkJsb2NrfSBub2RlIC0gUEhQIHBhcnNlciBibG9jay5cbiAqIEBwYXJhbSB7U2V0PHN0cmluZz59IHZpc2libGUgLSBOYW1lcyB2aXNpYmxlIG9uIGJsb2NrIGVudHJ5LlxuICogQHBhcmFtIHtzdHJpbmd9IGZpbGVuYW1lIC0gU291cmNlIGZpbGVuYW1lLlxuICogQHBhcmFtIHtzdHJpbmd9IHNvdXJjZSAtIENvbXBsZXRlIHNvdXJjZS5cbiAqIEByZXR1cm5zIHtpbXBvcnQoXCIuLi9zZW1hbnRpYy90eXBlcy5qc1wiKS5CbG9ja30gU2VtYW50aWMgYmxvY2suXG4gKi9cbmZ1bmN0aW9uIGNvbnZlcnRCbG9jayhub2RlLCB2aXNpYmxlLCBmaWxlbmFtZSwgc291cmNlKSB7XG4gIHJldHVybiB7XG4gICAga2luZDogXCJCbG9ja1wiLFxuICAgIGxvY2F0aW9uOiBub2RlTG9jYXRpb24obm9kZSwgZmlsZW5hbWUsIHNvdXJjZSksXG4gICAgc3RhdGVtZW50czogbm9kZS5jaGlsZHJlbi5tYXAoKHN0YXRlbWVudCkgPT4gY29udmVydFN0YXRlbWVudChzdGF0ZW1lbnQsIHZpc2libGUsIGZpbGVuYW1lLCBzb3VyY2UpKVxuICB9XG59XG5cbi8qKlxuICogUmVxdWlyZXMgYW4gZXhhY3QgUEhQIHNjYWxhciBkZWNsYXJhdGlvbiB0eXBlLlxuICogQHBhcmFtIHtpbXBvcnQoXCJwaHAtcGFyc2VyXCIpLk5vZGUgfCBudWxsfSBzb3VyY2VUeXBlIC0gUEhQIHR5cGUgbm9kZS5cbiAqIEBwYXJhbSB7c3RyaW5nfSBzdWJqZWN0IC0gVHlwZWQgc3ViamVjdC5cbiAqIEBwYXJhbSB7aW1wb3J0KFwiLi4vc2VtYW50aWMvdHlwZXMuanNcIikuU291cmNlTG9jYXRpb259IGxvY2F0aW9uIC0gU291cmNlIGxvY2F0aW9uLlxuICogQHBhcmFtIHtzdHJpbmd9IGZpbGVuYW1lIC0gU291cmNlIGZpbGVuYW1lLlxuICogQHBhcmFtIHtzdHJpbmd9IHNvdXJjZSAtIENvbXBsZXRlIHNvdXJjZS5cbiAqIEByZXR1cm5zIHtpbXBvcnQoXCIuLi9zZW1hbnRpYy90eXBlcy5qc1wiKS5UeXBlUmVmZXJlbmNlfSBTZW1hbnRpYyB0eXBlLlxuICovXG5mdW5jdGlvbiBjb252ZXJ0VHlwZShzb3VyY2VUeXBlLCBzdWJqZWN0LCBsb2NhdGlvbiwgZmlsZW5hbWUsIHNvdXJjZSkge1xuICBpZiAoIXNvdXJjZVR5cGUpIHJldHVybiByZXF1aXJlU291cmNlU2NhbGFyVHlwZShcInBocFwiLCB1bmRlZmluZWQsIHN1YmplY3QsIGxvY2F0aW9uKVxuICBpZiAoc291cmNlVHlwZS5raW5kICE9IFwidHlwZXJlZmVyZW5jZVwiICYmIHNvdXJjZVR5cGUua2luZCAhPSBcIm5hbWVcIiAmJiBzb3VyY2VUeXBlLmtpbmQgIT0gXCJpZGVudGlmaWVyXCIpIHtcbiAgICByZXR1cm4gdW5zdXBwb3J0ZWRTeW50YXgoXCJwaHBcIiwgXCJ1bnN1cHBvcnRlZCBzY2FsYXIgdHlwZVwiLCBub2RlTG9jYXRpb24oc291cmNlVHlwZSwgZmlsZW5hbWUsIHNvdXJjZSkpXG4gIH1cblxuICBjb25zdCB0eXBlTmFtZSA9IC8qKiBAdHlwZSB7aW1wb3J0KFwicGhwLXBhcnNlclwiKS5UeXBlUmVmZXJlbmNlIHwgaW1wb3J0KFwicGhwLXBhcnNlclwiKS5OYW1lIHwgaW1wb3J0KFwicGhwLXBhcnNlclwiKS5JZGVudGlmaWVyfSAqLyAoc291cmNlVHlwZSkubmFtZVxuXG4gIHJldHVybiByZXF1aXJlU291cmNlU2NhbGFyVHlwZShcInBocFwiLCB0eXBlTmFtZSwgc3ViamVjdCwgbG9jYXRpb24sIG5vZGVMb2NhdGlvbihzb3VyY2VUeXBlLCBmaWxlbmFtZSwgc291cmNlKSlcbn1cblxuLyoqXG4gKiBDb252ZXJ0cyBhIFBIUCBmdW5jdGlvbi5cbiAqIEBwYXJhbSB7aW1wb3J0KFwicGhwLXBhcnNlclwiKS5GdW5jdGlvbn0gbm9kZSAtIFBIUCBmdW5jdGlvbiBub2RlLlxuICogQHBhcmFtIHtzdHJpbmd9IGZpbGVuYW1lIC0gU291cmNlIGZpbGVuYW1lLlxuICogQHBhcmFtIHtzdHJpbmd9IHNvdXJjZSAtIENvbXBsZXRlIHNvdXJjZS5cbiAqIEByZXR1cm5zIHtpbXBvcnQoXCIuLi9zZW1hbnRpYy90eXBlcy5qc1wiKS5GdW5jdGlvbkRlY2xhcmF0aW9ufSBTZW1hbnRpYyBmdW5jdGlvbi5cbiAqL1xuZnVuY3Rpb24gY29udmVydEZ1bmN0aW9uKG5vZGUsIGZpbGVuYW1lLCBzb3VyY2UpIHtcbiAgY29uc3QgbG9jYXRpb24gPSBub2RlTG9jYXRpb24obm9kZSwgZmlsZW5hbWUsIHNvdXJjZSlcbiAgY29uc3QgbmFtZSA9IHR5cGVvZiBub2RlLm5hbWUgPT0gXCJzdHJpbmdcIiA/IG5vZGUubmFtZSA6IG5vZGUubmFtZS5uYW1lXG5cbiAgaWYgKCFub2RlLmJvZHkpIHtcbiAgICByZXR1cm4gdW5zdXBwb3J0ZWRTeW50YXgoXCJwaHBcIiwgXCJmdW5jdGlvbiBib2R5XCIsIGxvY2F0aW9uKVxuICB9XG5cbiAgY29uc3QgcGFyYW1ldGVycyA9IG5vZGUuYXJndW1lbnRzLm1hcCgocGFyYW1ldGVyKSA9PiB7XG4gICAgY29uc3QgcGFyYW1ldGVyTG9jYXRpb24gPSBub2RlTG9jYXRpb24ocGFyYW1ldGVyLCBmaWxlbmFtZSwgc291cmNlKVxuICAgIGNvbnN0IHBhcmFtZXRlck5hbWUgPSB0eXBlb2YgcGFyYW1ldGVyLm5hbWUgPT0gXCJzdHJpbmdcIiA/IHBhcmFtZXRlci5uYW1lIDogcGFyYW1ldGVyLm5hbWUubmFtZVxuXG4gICAgaWYgKHBhcmFtZXRlci5udWxsYWJsZSkgcmV0dXJuIHVuc3VwcG9ydGVkU3ludGF4KFwicGhwXCIsIFwidW5zdXBwb3J0ZWQgc2NhbGFyIHR5cGVcIiwgcGFyYW1ldGVyTG9jYXRpb24pXG5cbiAgICBjb25zdCBwYXJhbWV0ZXJOb2RlID0gdHlwZW9mIHBhcmFtZXRlci5uYW1lID09IFwic3RyaW5nXCIgPyBwYXJhbWV0ZXIgOiBwYXJhbWV0ZXIubmFtZVxuICAgIGNvbnN0IHNlbWFudGljUGFyYW1ldGVyID0ge1xuICAgICAga2luZDogLyoqIEB0eXBlIHtjb25zdH0gKi8gKFwiUGFyYW1ldGVyXCIpLFxuICAgICAgbG9jYXRpb246IHBhcmFtZXRlckxvY2F0aW9uLFxuICAgICAgbmFtZTogcGFyYW1ldGVyTmFtZSxcbiAgICAgIHR5cGU6IGNvbnZlcnRUeXBlKHBhcmFtZXRlci50eXBlLCBgUGFyYW1ldGVyICcke3BhcmFtZXRlck5hbWV9J2AsIHBhcmFtZXRlckxvY2F0aW9uLCBmaWxlbmFtZSwgc291cmNlKVxuICAgIH1cblxuICAgIHJldHVybiB3aXRoUGFyc2VyUmFuZ2VzKHNlbWFudGljUGFyYW1ldGVyLCB7bmFtZTogbm9kZUxvY2F0aW9uKHBhcmFtZXRlck5vZGUsIGZpbGVuYW1lLCBzb3VyY2UpfSlcbiAgfSlcbiAgaWYgKG5vZGUubnVsbGFibGUpIHJldHVybiB1bnN1cHBvcnRlZFN5bnRheChcInBocFwiLCBcInVuc3VwcG9ydGVkIHNjYWxhciB0eXBlXCIsIGxvY2F0aW9uKVxuICBjb25zdCB2aXNpYmxlID0gbmV3IFNldChwYXJhbWV0ZXJzLm1hcCgocGFyYW1ldGVyKSA9PiBwYXJhbWV0ZXIubmFtZSkpXG4gIGNvbnN0IGJvZHkgPSBjb252ZXJ0QmxvY2sobm9kZS5ib2R5LCB2aXNpYmxlLCBmaWxlbmFtZSwgc291cmNlKVxuXG4gIGNvbnN0IG5hbWVOb2RlID0gdHlwZW9mIG5vZGUubmFtZSA9PSBcInN0cmluZ1wiID8gbm9kZSA6IG5vZGUubmFtZVxuXG4gIHJldHVybiB3aXRoUGFyc2VyUmFuZ2VzKHtcbiAgICBib2R5LFxuICAgIGtpbmQ6IFwiRnVuY3Rpb25EZWNsYXJhdGlvblwiLFxuICAgIGxvY2F0aW9uLFxuICAgIG5hbWUsXG4gICAgcGFyYW1ldGVycyxcbiAgICByZXR1cm5UeXBlOiBjb252ZXJ0VHlwZShub2RlLnR5cGUsIGBGdW5jdGlvbiAnJHtuYW1lfScgcmV0dXJuYCwgbG9jYXRpb24sIGZpbGVuYW1lLCBzb3VyY2UpXG4gIH0sIHtuYW1lOiBub2RlTG9jYXRpb24obmFtZU5vZGUsIGZpbGVuYW1lLCBzb3VyY2UpfSlcbn1cblxuLyoqXG4gKiBDb252ZXJ0cyB0aGUgZXhpc3RpbmcgUEhQIGlmL2Vsc2UgdGVybWluYWwgd2l0aCByZXN0cmljdGVkIGJyYW5jaCBwcmVmaXhlcy5cbiAqIEBwYXJhbSB7aW1wb3J0KFwicGhwLXBhcnNlclwiKS5JZn0gbm9kZSAtIFBIUCBpZiBub2RlLlxuICogQHBhcmFtIHtTZXQ8c3RyaW5nPn0gdmlzaWJsZSAtIEVuY2xvc2luZyB2aXNpYmxlIG5hbWVzLlxuICogQHBhcmFtIHtzdHJpbmd9IGZpbGVuYW1lIC0gU291cmNlIGZpbGVuYW1lLlxuICogQHBhcmFtIHtzdHJpbmd9IHNvdXJjZSAtIENvbXBsZXRlIHNvdXJjZS5cbiAqIEByZXR1cm5zIHtpbXBvcnQoXCIuLi9zZW1hbnRpYy90eXBlcy5qc1wiKS5JZlN0YXRlbWVudH0gU2VtYW50aWMgYnJhbmNoLlxuICovXG5mdW5jdGlvbiBjb252ZXJ0SWYobm9kZSwgdmlzaWJsZSwgZmlsZW5hbWUsIHNvdXJjZSkge1xuICBjb25zdCBsb2NhdGlvbiA9IG5vZGVMb2NhdGlvbihub2RlLCBmaWxlbmFtZSwgc291cmNlKVxuXG4gIGlmIChub2RlLnNob3J0Rm9ybSkgcmV0dXJuIHVuc3VwcG9ydGVkU3ludGF4KFwicGhwXCIsIFwiYWx0ZXJuYXRpdmUgaWYgc3ludGF4XCIsIGxvY2F0aW9uKVxuICBpZiAobm9kZS5ib2R5LmtpbmQgIT0gXCJibG9ja1wiKSByZXR1cm4gdW5zdXBwb3J0ZWRTeW50YXgoXCJwaHBcIiwgXCJpZiB3aXRob3V0IGJsb2NrIGNvbnNlcXVlbnRcIiwgbG9jYXRpb24pXG5cbiAgY29uc3QgY29uc2VxdWVudFZpc2libGUgPSBuZXcgU2V0KHZpc2libGUpXG4gIGxldCBhbHRlcm5hdGVcblxuICBpZiAobm9kZS5hbHRlcm5hdGUpIHtcbiAgICBjb25zdCBhbHRlcm5hdGVWaXNpYmxlID0gbmV3IFNldCh2aXNpYmxlKVxuXG4gICAgaWYgKG5vZGUuYWx0ZXJuYXRlLmtpbmQgPT0gXCJibG9ja1wiKSB7XG4gICAgICBhbHRlcm5hdGUgPSBjb252ZXJ0QmxvY2soLyoqIEB0eXBlIHtpbXBvcnQoXCJwaHAtcGFyc2VyXCIpLkJsb2NrfSAqLyAobm9kZS5hbHRlcm5hdGUpLCBhbHRlcm5hdGVWaXNpYmxlLCBmaWxlbmFtZSwgc291cmNlKVxuICAgIH0gZWxzZSBpZiAobm9kZS5hbHRlcm5hdGUua2luZCA9PSBcImlmXCIpIHtcbiAgICAgIGNvbnN0IG5lc3RlZCA9IC8qKiBAdHlwZSB7aW1wb3J0KFwicGhwLXBhcnNlclwiKS5JZn0gKi8gKG5vZGUuYWx0ZXJuYXRlKVxuXG4gICAgICBhbHRlcm5hdGUgPSB7XG4gICAgICAgIGtpbmQ6IC8qKiBAdHlwZSB7Y29uc3R9ICovIChcIkJsb2NrXCIpLFxuICAgICAgICBsb2NhdGlvbjogbm9kZUxvY2F0aW9uKG5lc3RlZCwgZmlsZW5hbWUsIHNvdXJjZSksXG4gICAgICAgIHN0YXRlbWVudHM6IFtjb252ZXJ0SWYobmVzdGVkLCBhbHRlcm5hdGVWaXNpYmxlLCBmaWxlbmFtZSwgc291cmNlKV1cbiAgICAgIH1cbiAgICB9IGVsc2UgcmV0dXJuIHVuc3VwcG9ydGVkU3ludGF4KFwicGhwXCIsIGBpZiBhbHRlcm5hdGUgJHtub2RlLmFsdGVybmF0ZS5raW5kfWAsIG5vZGVMb2NhdGlvbihub2RlLmFsdGVybmF0ZSwgZmlsZW5hbWUsIHNvdXJjZSkpXG4gIH1cblxuICByZXR1cm4ge1xuICAgIC4uLihhbHRlcm5hdGUgPyB7YWx0ZXJuYXRlfSA6IHt9KSxcbiAgICBjb25kaXRpb246IGNvbnZlcnRFeHByZXNzaW9uKG5vZGUudGVzdCwgZmlsZW5hbWUsIHNvdXJjZSksXG4gICAgY29uc2VxdWVudDogY29udmVydEJsb2NrKG5vZGUuYm9keSwgY29uc2VxdWVudFZpc2libGUsIGZpbGVuYW1lLCBzb3VyY2UpLFxuICAgIGtpbmQ6IFwiSWZTdGF0ZW1lbnRcIixcbiAgICBsb2NhdGlvblxuICB9XG59XG5cbi8qKlxuICogQ29udmVydHMgYSBQSFAgZWNobyBlbnRyeSBwb2ludC5cbiAqIEBwYXJhbSB7aW1wb3J0KFwicGhwLXBhcnNlclwiKS5FY2hvfSBub2RlIC0gUEhQIGVjaG8gbm9kZS5cbiAqIEBwYXJhbSB7c3RyaW5nfSBmaWxlbmFtZSAtIFNvdXJjZSBmaWxlbmFtZS5cbiAqIEBwYXJhbSB7c3RyaW5nfSBzb3VyY2UgLSBDb21wbGV0ZSBzb3VyY2UuXG4gKiBAcmV0dXJucyB7aW1wb3J0KFwiLi4vc2VtYW50aWMvdHlwZXMuanNcIikuUHJpbnRTdGF0ZW1lbnR9IFByaW50IHN0YXRlbWVudC5cbiAqL1xuZnVuY3Rpb24gY29udmVydFByaW50KG5vZGUsIGZpbGVuYW1lLCBzb3VyY2UpIHtcbiAgY29uc3QgbG9jYXRpb24gPSBub2RlTG9jYXRpb24obm9kZSwgZmlsZW5hbWUsIHNvdXJjZSlcblxuICBpZiAobm9kZS5leHByZXNzaW9ucy5sZW5ndGggIT0gMiB8fCBub2RlLmV4cHJlc3Npb25zWzFdLmtpbmQgIT0gXCJuYW1lXCIgfHxcbiAgICAvKiogQHR5cGUge2ltcG9ydChcInBocC1wYXJzZXJcIikuTmFtZX0gKi8gKG5vZGUuZXhwcmVzc2lvbnNbMV0pLm5hbWUgIT0gXCJQSFBfRU9MXCIpIHtcbiAgICByZXR1cm4gdW5zdXBwb3J0ZWRTeW50YXgoXCJwaHBcIiwgXCJlY2hvIHdpdGhvdXQgb25lIGV4cHJlc3Npb24gYW5kIFBIUF9FT0xcIiwgbG9jYXRpb24pXG4gIH1cblxuICByZXR1cm4ge2V4cHJlc3Npb246IGNvbnZlcnRFeHByZXNzaW9uKG5vZGUuZXhwcmVzc2lvbnNbMF0sIGZpbGVuYW1lLCBzb3VyY2UpLCBraW5kOiBcIlByaW50U3RhdGVtZW50XCIsIGxvY2F0aW9ufVxufVxuXG4vKipcbiAqIFBhcnNlcyBQSFAgaW50byB0aGUgc2hhcmVkIHNlbWFudGljIG1vZHVsZS5cbiAqIEBwYXJhbSB7b2JqZWN0fSBpbnB1dCAtIFBhcnNlciBpbnB1dC5cbiAqIEBwYXJhbSB7c3RyaW5nfSBpbnB1dC5maWxlbmFtZSAtIFNvdXJjZSBmaWxlbmFtZS5cbiAqIEBwYXJhbSB7c3RyaW5nfSBpbnB1dC5zb3VyY2UgLSBTb3VyY2UgdGV4dC5cbiAqIEByZXR1cm5zIHtpbXBvcnQoXCIuLi9zZW1hbnRpYy90eXBlcy5qc1wiKS5TZW1hbnRpY01vZHVsZX0gU2VtYW50aWMgbW9kdWxlLlxuICovXG5leHBvcnQgZnVuY3Rpb24gcGFyc2VQaHAoe2ZpbGVuYW1lLCBzb3VyY2V9KSB7XG4gIGNvbnN0IHByb2dyYW0gPSBwYXJzZVBocFByb2dyYW0oZmlsZW5hbWUsIHNvdXJjZSlcbiAgdmFsaWRhdGVEZWNsYXJlTm9kZXMocHJvZ3JhbS5jaGlsZHJlbiwgZmlsZW5hbWUsIHNvdXJjZSlcbiAgY29uc3QgZnVuY3Rpb25zID0gcHJvZ3JhbS5jaGlsZHJlbi5maWx0ZXIoKG5vZGUpID0+IG5vZGUua2luZCA9PSBcImZ1bmN0aW9uXCIpXG4gICAgLm1hcCgobm9kZSkgPT4gY29udmVydEZ1bmN0aW9uKC8qKiBAdHlwZSB7aW1wb3J0KFwicGhwLXBhcnNlclwiKS5GdW5jdGlvbn0gKi8gKG5vZGUpLCBmaWxlbmFtZSwgc291cmNlKSlcbiAgY29uc3QgZXhlY3V0YWJsZU5vZGVzID0gcHJvZ3JhbS5jaGlsZHJlbi5maWx0ZXIoKG5vZGUpID0+IG5vZGUua2luZCAhPSBcImZ1bmN0aW9uXCIgJiYgbm9kZS5raW5kICE9IFwiZGVjbGFyZVwiICYmIG5vZGUua2luZCAhPSBcIm5vb3BcIilcbiAgY29uc3QgbG9jYXRpb24gPSBtb2R1bGVMb2NhdGlvbihmaWxlbmFtZSwgc291cmNlKVxuXG4gIGlmIChmdW5jdGlvbnMubGVuZ3RoID09IDApIHJldHVybiB1bnN1cHBvcnRlZFN5bnRheChcInBocFwiLCBcIm1vZHVsZSB3aXRob3V0IGEgZnVuY3Rpb25cIiwgbG9jYXRpb24pXG4gIGNvbnN0IGZpcnN0ID0gZXhlY3V0YWJsZU5vZGVzWzBdXG4gIGNvbnN0IGxhc3QgPSBleGVjdXRhYmxlTm9kZXMuYXQoLTEpID8/IGZpcnN0XG4gIGNvbnN0IGVudHJ5TG9jYXRpb24gPSBmaXJzdFxuICAgID8gbG9jYXRpb25Gcm9tT2Zmc2V0cyhmaWxlbmFtZSwgc291cmNlLCBmaXJzdC5sb2M/LnN0YXJ0Lm9mZnNldCA/PyAwLCBsYXN0Py5sb2M/LmVuZC5vZmZzZXQgPz8gc291cmNlLmxlbmd0aClcbiAgICA6IGxvY2F0aW9uXG4gIGNvbnN0IGVudHJ5VmlzaWJsZSA9IG5ldyBTZXQoKVxuICBjb25zdCBlbnRyeUJsb2NrID0ge1xuICAgIGtpbmQ6IC8qKiBAdHlwZSB7Y29uc3R9ICovIChcIkJsb2NrXCIpLFxuICAgIGxvY2F0aW9uOiBlbnRyeUxvY2F0aW9uLFxuICAgIHN0YXRlbWVudHM6IGV4ZWN1dGFibGVOb2Rlcy5tYXAoKG5vZGUpID0+IGNvbnZlcnRTdGF0ZW1lbnQobm9kZSwgZW50cnlWaXNpYmxlLCBmaWxlbmFtZSwgc291cmNlKSlcbiAgfVxuXG4gIHJldHVybiB7XG4gICAgZW50cnlQb2ludDoge1xuICAgICAgYm9keTogZW50cnlCbG9jayxcbiAgICAgIGtpbmQ6IFwiRW50cnlQb2ludFwiLFxuICAgICAgbG9jYXRpb246IGVudHJ5TG9jYXRpb25cbiAgICB9LFxuICAgIGZ1bmN0aW9ucyxcbiAgICBraW5kOiBcIk1vZHVsZVwiLFxuICAgIGxvY2F0aW9uXG4gIH1cbn1cblxuLyoqXG4gKiBBY2NlcHRzIG9ubHkgYW4gb3B0aW9uYWwgc2luZ2xlIGBkZWNsYXJlKHN0cmljdF90eXBlcz0xKWAgZGlyZWN0aXZlLlxuICogQHBhcmFtIHtpbXBvcnQoXCJwaHAtcGFyc2VyXCIpLk5vZGVbXX0gbm9kZXMgLSBUb3AtbGV2ZWwgUEhQIG5vZGVzLlxuICogQHBhcmFtIHtzdHJpbmd9IGZpbGVuYW1lIC0gU291cmNlIGZpbGVuYW1lLlxuICogQHBhcmFtIHtzdHJpbmd9IHNvdXJjZSAtIENvbXBsZXRlIHNvdXJjZS5cbiAqIEByZXR1cm5zIHt2b2lkfVxuICovXG5mdW5jdGlvbiB2YWxpZGF0ZURlY2xhcmVOb2Rlcyhub2RlcywgZmlsZW5hbWUsIHNvdXJjZSkge1xuICBjb25zdCBkZWNsYXJhdGlvbnMgPSBub2Rlcy5maWx0ZXIoKG5vZGUpID0+IG5vZGUua2luZCA9PSBcImRlY2xhcmVcIilcblxuICBpZiAoZGVjbGFyYXRpb25zLmxlbmd0aCA+IDEpIHtcbiAgICB1bnN1cHBvcnRlZFN5bnRheChcInBocFwiLCBcIm11bHRpcGxlIGRlY2xhcmUgZGlyZWN0aXZlc1wiLCBub2RlTG9jYXRpb24oZGVjbGFyYXRpb25zWzFdLCBmaWxlbmFtZSwgc291cmNlKSlcbiAgfVxuXG4gIGZvciAoY29uc3QgZGVjbGFyYXRpb25Ob2RlIG9mIGRlY2xhcmF0aW9ucykge1xuICAgIGNvbnN0IGRlY2xhcmF0aW9uID0gLyoqIEB0eXBlIHtpbXBvcnQoXCJwaHAtcGFyc2VyXCIpLkRlY2xhcmV9ICovIChkZWNsYXJhdGlvbk5vZGUpXG4gICAgY29uc3QgZGlyZWN0aXZlID0gZGVjbGFyYXRpb24uZGlyZWN0aXZlc1swXVxuICAgIGNvbnN0IGtleSA9IGRpcmVjdGl2ZT8ua2V5XG4gICAgY29uc3QgdmFsdWUgPSBkaXJlY3RpdmU/LnZhbHVlXG4gICAgY29uc3QgbnVtZXJpY1ZhbHVlID0gdmFsdWUgJiYgdHlwZW9mIHZhbHVlID09IFwib2JqZWN0XCIgJiYgdmFsdWUua2luZCA9PSBcIm51bWJlclwiXG4gICAgICA/IC8qKiBAdHlwZSB7aW1wb3J0KFwicGhwLXBhcnNlclwiKS5OdW1iZXJ9ICovICh2YWx1ZSlcbiAgICAgIDogdW5kZWZpbmVkXG4gICAgY29uc3QgdmFsdWVJc09uZSA9IG51bWVyaWNWYWx1ZT8ubG9jICYmIHNvdXJjZS5zbGljZShudW1lcmljVmFsdWUubG9jLnN0YXJ0Lm9mZnNldCwgbnVtZXJpY1ZhbHVlLmxvYy5lbmQub2Zmc2V0KSA9PSBcIjFcIlxuICAgIGNvbnN0IHZhbGlkID0gZGVjbGFyYXRpb24ubW9kZSA9PSBcIm5vbmVcIiAmJiBkZWNsYXJhdGlvbi5jaGlsZHJlbi5sZW5ndGggPT0gMCAmJiBkZWNsYXJhdGlvbi5kaXJlY3RpdmVzLmxlbmd0aCA9PSAxICYmXG4gICAgICBrZXkua2luZCA9PSBcImlkZW50aWZpZXJcIiAmJiBrZXkubmFtZSA9PSBcInN0cmljdF90eXBlc1wiICYmIHZhbHVlSXNPbmVcblxuICAgIGlmICghdmFsaWQpIHVuc3VwcG9ydGVkU3ludGF4KFwicGhwXCIsIFwiZGVjbGFyZSBvdGhlciB0aGFuIHN0cmljdF90eXBlcz0xXCIsIG5vZGVMb2NhdGlvbihkZWNsYXJhdGlvbiwgZmlsZW5hbWUsIHNvdXJjZSkpXG4gIH1cbn1cblxuLyoqXG4gKiBJbnZva2VzIHBocC1wYXJzZXIgYW5kIG5vcm1hbGl6ZXMgc3ludGF4IGZhaWx1cmVzLlxuICogQHBhcmFtIHtzdHJpbmd9IGZpbGVuYW1lIC0gU291cmNlIGZpbGVuYW1lLlxuICogQHBhcmFtIHtzdHJpbmd9IHNvdXJjZSAtIFNvdXJjZSB0ZXh0LlxuICogQHJldHVybnMge2ltcG9ydChcInBocC1wYXJzZXJcIikuUHJvZ3JhbX0gUEhQIHByb2dyYW0uXG4gKi9cbmZ1bmN0aW9uIHBhcnNlUGhwUHJvZ3JhbShmaWxlbmFtZSwgc291cmNlKSB7XG4gIHRyeSB7XG4gICAgcmV0dXJuIHBhcnNlci5wYXJzZUNvZGUoc291cmNlLCBmaWxlbmFtZSlcbiAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICByZXR1cm4gcGFyc2VGYWlsdXJlKFwicGhwXCIsIGVycm9yKVxuICB9XG59XG4iXX0=