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.
- package/LICENSE +15 -0
- package/README.md +71 -0
- package/build/index.d.ts +54 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +45 -0
- package/build/src/backends/identifiers.d.ts +19 -0
- package/build/src/backends/identifiers.d.ts.map +1 -0
- package/build/src/backends/identifiers.js +93 -0
- package/build/src/backends/index.d.ts +35 -0
- package/build/src/backends/index.d.ts.map +1 -0
- package/build/src/backends/index.js +149 -0
- package/build/src/backends/java.d.ts +8 -0
- package/build/src/backends/java.d.ts.map +1 -0
- package/build/src/backends/java.js +172 -0
- package/build/src/backends/javascript.d.ts +8 -0
- package/build/src/backends/javascript.d.ts.map +1 -0
- package/build/src/backends/javascript.js +173 -0
- package/build/src/backends/php.d.ts +8 -0
- package/build/src/backends/php.d.ts.map +1 -0
- package/build/src/backends/php.js +175 -0
- package/build/src/backends/ruby.d.ts +8 -0
- package/build/src/backends/ruby.d.ts.map +1 -0
- package/build/src/backends/ruby.js +155 -0
- package/build/src/backends/scalars.d.ts +15 -0
- package/build/src/backends/scalars.d.ts.map +1 -0
- package/build/src/backends/scalars.js +138 -0
- package/build/src/backends/shared.d.ts +26 -0
- package/build/src/backends/shared.d.ts.map +1 -0
- package/build/src/backends/shared.js +424 -0
- package/build/src/backends/typescript.d.ts +8 -0
- package/build/src/backends/typescript.d.ts.map +1 -0
- package/build/src/backends/typescript.js +160 -0
- package/build/src/backends/writer.d.ts +87 -0
- package/build/src/backends/writer.d.ts.map +1 -0
- package/build/src/backends/writer.js +207 -0
- package/build/src/diagnostic.d.ts +67 -0
- package/build/src/diagnostic.d.ts.map +1 -0
- package/build/src/diagnostic.js +96 -0
- package/build/src/frontends/index.d.ts +14 -0
- package/build/src/frontends/index.d.ts.map +1 -0
- package/build/src/frontends/index.js +36 -0
- package/build/src/frontends/java.d.ts +12 -0
- package/build/src/frontends/java.d.ts.map +1 -0
- package/build/src/frontends/java.js +630 -0
- package/build/src/frontends/javascript-typescript.d.ts +19 -0
- package/build/src/frontends/javascript-typescript.d.ts.map +1 -0
- package/build/src/frontends/javascript-typescript.js +633 -0
- package/build/src/frontends/php.d.ts +12 -0
- package/build/src/frontends/php.d.ts.map +1 -0
- package/build/src/frontends/php.js +523 -0
- package/build/src/frontends/ruby.d.ts +12 -0
- package/build/src/frontends/ruby.d.ts.map +1 -0
- package/build/src/frontends/ruby.js +515 -0
- package/build/src/frontends/scalars.d.ts +19 -0
- package/build/src/frontends/scalars.d.ts.map +1 -0
- package/build/src/frontends/scalars.js +71 -0
- package/build/src/mapping.d.ts +160 -0
- package/build/src/mapping.d.ts.map +1 -0
- package/build/src/mapping.js +1120 -0
- package/build/src/semantic/location.d.ts +61 -0
- package/build/src/semantic/location.d.ts.map +1 -0
- package/build/src/semantic/location.js +142 -0
- package/build/src/semantic/operators.d.ts +16 -0
- package/build/src/semantic/operators.d.ts.map +1 -0
- package/build/src/semantic/operators.js +24 -0
- package/build/src/semantic/provenance.d.ts +74 -0
- package/build/src/semantic/provenance.d.ts.map +1 -0
- package/build/src/semantic/provenance.js +577 -0
- package/build/src/semantic/scalars.d.ts +19 -0
- package/build/src/semantic/scalars.d.ts.map +1 -0
- package/build/src/semantic/scalars.js +40 -0
- package/build/src/semantic/types.d.ts +1003 -0
- package/build/src/semantic/types.d.ts.map +1 -0
- package/build/src/semantic/types.js +279 -0
- package/build/src/semantic/validate.d.ts +60 -0
- package/build/src/semantic/validate.d.ts.map +1 -0
- package/build/src/semantic/validate.js +472 -0
- package/docs/architecture.md +39 -0
- package/docs/coding-standards.md +7 -0
- package/docs/goals.md +7 -0
- package/docs/language-support.md +69 -0
- package/docs/plans/2026-09-02-initial-toolchain.md +54 -0
- package/docs/source-maps.md +134 -0
- package/docs/testing.md +25 -0
- package/index.js +63 -0
- package/package.json +69 -0
- package/src/backends/identifiers.js +101 -0
- package/src/backends/index.js +159 -0
- package/src/backends/java.js +182 -0
- package/src/backends/javascript.js +184 -0
- package/src/backends/php.js +184 -0
- package/src/backends/ruby.js +163 -0
- package/src/backends/scalars.js +120 -0
- package/src/backends/shared.js +456 -0
- package/src/backends/typescript.js +168 -0
- package/src/backends/writer.js +224 -0
- package/src/diagnostic.js +103 -0
- package/src/frontends/index.js +36 -0
- package/src/frontends/java.js +735 -0
- package/src/frontends/javascript-typescript.js +718 -0
- package/src/frontends/php.js +593 -0
- package/src/frontends/ruby.js +622 -0
- package/src/frontends/scalars.js +77 -0
- package/src/mapping.js +1260 -0
- package/src/semantic/location.js +154 -0
- package/src/semantic/operators.js +28 -0
- package/src/semantic/provenance.js +629 -0
- package/src/semantic/scalars.js +44 -0
- package/src/semantic/types.js +319 -0
- package/src/semantic/validate.js +529 -0
- 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=
|