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,515 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
import { AndNode, CallNode, DefNode, ElseNode, FalseNode, IfNode, IntegerNode, InterpolatedStringNode, LocalVariableReadNode, LocalVariableWriteNode, OrNode, ParenthesesNode, ProgramNode, RequiredParameterNode, ReturnNode, StatementsNode, StringNode, TrueNode, loadPrism } from "@ruby/prism";
|
|
3
|
+
import { missingType, SemantifoldDiagnostic, unsupportedSyntax } from "../diagnostic.js";
|
|
4
|
+
import { locationFromOffsets, moduleLocation, utf8ByteOffsetToUtf16Offset } from "../semantic/location.js";
|
|
5
|
+
import { withAdaptedOperation } from "../semantic/operators.js";
|
|
6
|
+
import { withParserRanges } from "../semantic/provenance.js";
|
|
7
|
+
import { hasOnlyUnicodeScalars } from "../semantic/scalars.js";
|
|
8
|
+
import { requireSourceScalarType } from "./scalars.js";
|
|
9
|
+
const parsePrism = await loadPrism();
|
|
10
|
+
const rubyBinaryOperations = new Map([
|
|
11
|
+
["+", "Add"],
|
|
12
|
+
["-", "Subtract"],
|
|
13
|
+
["*", "Multiply"],
|
|
14
|
+
["==", "Equal"],
|
|
15
|
+
["!=", "NotEqual"],
|
|
16
|
+
["<", "LessThan"],
|
|
17
|
+
["<=", "LessThanOrEqual"],
|
|
18
|
+
[">", "GreaterThan"],
|
|
19
|
+
[">=", "GreaterThanOrEqual"]
|
|
20
|
+
]);
|
|
21
|
+
/**
|
|
22
|
+
* Returns a normalized Prism node location.
|
|
23
|
+
* @param {{location: import("@ruby/prism").Location}} node - Prism node.
|
|
24
|
+
* @param {string} filename - Source filename.
|
|
25
|
+
* @param {string} source - Complete source.
|
|
26
|
+
* @returns {import("../semantic/types.js").SourceLocation} Source location.
|
|
27
|
+
*/
|
|
28
|
+
function nodeLocation(node, filename, source) {
|
|
29
|
+
return prismLocation(node.location, filename, source);
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Converts a Prism location into a normalized source location.
|
|
33
|
+
* @param {import("@ruby/prism").Location} location - Prism location.
|
|
34
|
+
* @param {string} filename - Source filename.
|
|
35
|
+
* @param {string} source - Complete source.
|
|
36
|
+
* @returns {import("../semantic/types.js").SourceLocation} Source location.
|
|
37
|
+
*/
|
|
38
|
+
function prismLocation(location, filename, source) {
|
|
39
|
+
return locationFromOffsets(filename, source, utf8ByteOffsetToUtf16Offset(source, location.startOffset), utf8ByteOffsetToUtf16Offset(source, location.startOffset + location.length));
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Slices JavaScript source using Prism's UTF-8 byte offsets.
|
|
43
|
+
* @param {string} source - Complete source.
|
|
44
|
+
* @param {number} startOffset - Inclusive Prism byte offset.
|
|
45
|
+
* @param {number} endOffset - Exclusive Prism byte offset.
|
|
46
|
+
* @returns {string} Source text in the byte range.
|
|
47
|
+
*/
|
|
48
|
+
function slicePrismSource(source, startOffset, endOffset) {
|
|
49
|
+
return source.slice(utf8ByteOffsetToUtf16Offset(source, startOffset), utf8ByteOffsetToUtf16Offset(source, endOffset));
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Converts a supported Prism expression.
|
|
53
|
+
* @param {import("@ruby/prism").Node} node - Prism node.
|
|
54
|
+
* @param {string} filename - Source filename.
|
|
55
|
+
* @param {string} source - Complete source.
|
|
56
|
+
* @returns {import("../semantic/types.js").Expression} Semantic expression.
|
|
57
|
+
*/
|
|
58
|
+
function convertExpression(node, filename, source) {
|
|
59
|
+
const location = nodeLocation(node, filename, source);
|
|
60
|
+
if (node instanceof ParenthesesNode && node.body instanceof StatementsNode && node.body.body.length == 1) {
|
|
61
|
+
return convertExpression(node.body.body[0], filename, source);
|
|
62
|
+
}
|
|
63
|
+
if (node instanceof LocalVariableReadNode) {
|
|
64
|
+
return withParserRanges({ kind: /** @type {const} */ ("IdentifierExpression"), location, name: node.name }, { name: location });
|
|
65
|
+
}
|
|
66
|
+
if (node instanceof IntegerNode) {
|
|
67
|
+
if (!Number.isSafeInteger(node.value))
|
|
68
|
+
return unsupportedSyntax("ruby", "non-safe integer literal", location);
|
|
69
|
+
return withParserRanges({ kind: /** @type {const} */ ("IntegerLiteral"), location, value: node.value }, { literal: location });
|
|
70
|
+
}
|
|
71
|
+
if (node instanceof TrueNode || node instanceof FalseNode) {
|
|
72
|
+
return withParserRanges({ kind: /** @type {const} */ ("BooleanLiteral"), location, value: node instanceof TrueNode }, { literal: location });
|
|
73
|
+
}
|
|
74
|
+
if (node instanceof StringNode) {
|
|
75
|
+
const decoded = node.unescaped;
|
|
76
|
+
if (!decoded.validEncoding || decoded.encoding != "utf-8" || node.isForcedBinaryEncoding() ||
|
|
77
|
+
!hasOnlyUnicodeScalars(decoded.value)) {
|
|
78
|
+
return unsupportedSyntax("ruby", "invalid Unicode string literal", location);
|
|
79
|
+
}
|
|
80
|
+
return withParserRanges({ kind: /** @type {const} */ ("StringLiteral"), location, value: decoded.value }, { literal: location });
|
|
81
|
+
}
|
|
82
|
+
if (node instanceof InterpolatedStringNode)
|
|
83
|
+
return unsupportedSyntax("ruby", "interpolated string", location);
|
|
84
|
+
if (node instanceof CallNode && node.receiver && node.name == "!") {
|
|
85
|
+
const operatorLocation = prismLocation(node.messageLoc ?? node.location, filename, source);
|
|
86
|
+
if (node.callOperatorLoc)
|
|
87
|
+
return unsupportedSyntax("ruby", "qualified boolean not", operatorLocation);
|
|
88
|
+
if (node.messageLoc?.length != 1) {
|
|
89
|
+
return unsupportedSyntax("ruby", "precedence-sensitive boolean not", operatorLocation);
|
|
90
|
+
}
|
|
91
|
+
if (node.arguments_)
|
|
92
|
+
return unsupportedSyntax("ruby", "boolean not argument list", operatorLocation);
|
|
93
|
+
const semantic = withAdaptedOperation(withParserRanges({
|
|
94
|
+
kind: "UnaryExpression",
|
|
95
|
+
location,
|
|
96
|
+
operand: convertExpression(node.receiver, filename, source)
|
|
97
|
+
}, { operator: operatorLocation }), "Not");
|
|
98
|
+
return /** @type {import("../semantic/types.js").Expression} */ ( /** @type {unknown} */(semantic));
|
|
99
|
+
}
|
|
100
|
+
if (node instanceof CallNode && node.receiver && node.name == "-@") {
|
|
101
|
+
const operatorLocation = prismLocation(node.messageLoc ?? node.location, filename, source);
|
|
102
|
+
if (node.callOperatorLoc)
|
|
103
|
+
return unsupportedSyntax("ruby", "qualified integer negation", operatorLocation);
|
|
104
|
+
if (node.arguments_)
|
|
105
|
+
return unsupportedSyntax("ruby", "integer negation argument list", operatorLocation);
|
|
106
|
+
const semantic = withAdaptedOperation(withParserRanges({
|
|
107
|
+
kind: "UnaryExpression",
|
|
108
|
+
location,
|
|
109
|
+
operand: convertExpression(node.receiver, filename, source)
|
|
110
|
+
}, { operator: operatorLocation }), "Negate");
|
|
111
|
+
return /** @type {import("../semantic/types.js").Expression} */ ( /** @type {unknown} */(semantic));
|
|
112
|
+
}
|
|
113
|
+
if (node instanceof AndNode || node instanceof OrNode) {
|
|
114
|
+
const operatorLocation = prismLocation(node.operatorLoc, filename, source);
|
|
115
|
+
const sourceOperator = source.slice(operatorLocation.start.offset, operatorLocation.end.offset);
|
|
116
|
+
if (sourceOperator != "&&" && sourceOperator != "||") {
|
|
117
|
+
return unsupportedSyntax("ruby", `precedence-sensitive boolean ${sourceOperator}`, location);
|
|
118
|
+
}
|
|
119
|
+
const semantic = withAdaptedOperation(withParserRanges({
|
|
120
|
+
kind: "BinaryExpression",
|
|
121
|
+
left: convertExpression(node.left, filename, source),
|
|
122
|
+
location,
|
|
123
|
+
right: convertExpression(node.right, filename, source)
|
|
124
|
+
}, { operator: operatorLocation }), node instanceof AndNode ? "And" : "Or");
|
|
125
|
+
return /** @type {import("../semantic/types.js").Expression} */ ( /** @type {unknown} */(semantic));
|
|
126
|
+
}
|
|
127
|
+
if (node instanceof CallNode && node.receiver && rubyBinaryOperations.has(node.name) && node.callOperatorLoc &&
|
|
128
|
+
node.arguments_?.arguments_.length == 1) {
|
|
129
|
+
return unsupportedSyntax("ruby", `qualified binary operator ${node.name}`, prismLocation(node.messageLoc ?? node.location, filename, source));
|
|
130
|
+
}
|
|
131
|
+
if (node instanceof CallNode && node.receiver && rubyBinaryOperations.has(node.name) && node.arguments_?.arguments_.length == 1) {
|
|
132
|
+
const semantic = withAdaptedOperation(withParserRanges({
|
|
133
|
+
kind: "BinaryExpression",
|
|
134
|
+
left: convertExpression(node.receiver, filename, source),
|
|
135
|
+
location,
|
|
136
|
+
right: convertExpression(node.arguments_.arguments_[0], filename, source)
|
|
137
|
+
}, { operator: prismLocation(node.messageLoc ?? node.location, filename, source) }), /** @type {import("../semantic/operators.js").AdaptedOperation} */ (rubyBinaryOperations.get(node.name)));
|
|
138
|
+
return /** @type {import("../semantic/types.js").Expression} */ ( /** @type {unknown} */(semantic));
|
|
139
|
+
}
|
|
140
|
+
if (node instanceof CallNode && !node.receiver) {
|
|
141
|
+
return withParserRanges({
|
|
142
|
+
arguments: (node.arguments_?.arguments_ ?? []).map((argument) => convertExpression(argument, filename, source)),
|
|
143
|
+
callee: node.name,
|
|
144
|
+
kind: "CallExpression",
|
|
145
|
+
location
|
|
146
|
+
}, { callee: prismLocation(node.messageLoc ?? node.location, filename, source) });
|
|
147
|
+
}
|
|
148
|
+
return unsupportedSyntax("ruby", node.constructor.name, location);
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Converts one explicit Ruby return.
|
|
152
|
+
* @param {import("@ruby/prism").Node} node - Prism node.
|
|
153
|
+
* @param {string} filename - Source filename.
|
|
154
|
+
* @param {string} source - Complete source.
|
|
155
|
+
* @returns {import("../semantic/types.js").ReturnStatement} Semantic return.
|
|
156
|
+
*/
|
|
157
|
+
function convertReturn(node, filename, source) {
|
|
158
|
+
const location = nodeLocation(node, filename, source);
|
|
159
|
+
if (!(node instanceof ReturnNode) || node.arguments_?.arguments_.length != 1) {
|
|
160
|
+
return unsupportedSyntax("ruby", node.constructor.name, location);
|
|
161
|
+
}
|
|
162
|
+
return {
|
|
163
|
+
expression: convertExpression(node.arguments_.arguments_[0], filename, source),
|
|
164
|
+
kind: "ReturnStatement",
|
|
165
|
+
location
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Reads Prism-owned RBS-style type comments directly preceding a definition.
|
|
170
|
+
* @param {import("@ruby/prism/src/deserialize.js").Comment[]} comments - Prism comments.
|
|
171
|
+
* @param {{location: import("@ruby/prism").Location}} node - Comment owner.
|
|
172
|
+
* @param {string} filename - Source filename.
|
|
173
|
+
* @param {string} source - Complete source.
|
|
174
|
+
* @returns {{parameters: Map<string, {location: import("../semantic/types.js").SourceLocation, sourceType: string}>, returnType: {location: import("../semantic/types.js").SourceLocation, sourceType: string} | undefined}} Declared types.
|
|
175
|
+
*/
|
|
176
|
+
function typeComments(comments, node, filename, source) {
|
|
177
|
+
const preceding = associatedComments(comments, node, source);
|
|
178
|
+
const parameterTypes = new Map();
|
|
179
|
+
/** @type {{location: import("../semantic/types.js").SourceLocation, sourceType: string} | undefined} */
|
|
180
|
+
let returnType;
|
|
181
|
+
for (const comment of preceding) {
|
|
182
|
+
const words = commentTokens(comment, filename, source);
|
|
183
|
+
if (words[0]?.text == "@param" && words.length == 3) {
|
|
184
|
+
parameterTypes.set(words[1].text, { location: words[2].location, sourceType: words[2].text });
|
|
185
|
+
}
|
|
186
|
+
if (words[0]?.text == "@return" && words.length == 2) {
|
|
187
|
+
returnType = { location: words[1].location, sourceType: words[1].text };
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
return { parameters: parameterTypes, returnType };
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Lexes whitespace-separated metadata tokens inside a Prism-owned Ruby comment.
|
|
194
|
+
* @param {import("@ruby/prism/src/deserialize.js").Comment} comment - Prism comment token.
|
|
195
|
+
* @param {string} filename - Source filename.
|
|
196
|
+
* @param {string} source - Complete source.
|
|
197
|
+
* @returns {{location: import("../semantic/types.js").SourceLocation, text: string}[]} Metadata tokens.
|
|
198
|
+
*/
|
|
199
|
+
function commentTokens(comment, filename, source) {
|
|
200
|
+
const start = utf8ByteOffsetToUtf16Offset(source, comment.location.startOffset);
|
|
201
|
+
const end = utf8ByteOffsetToUtf16Offset(source, comment.location.startOffset + comment.location.length);
|
|
202
|
+
const tokens = [];
|
|
203
|
+
let offset = start + 1;
|
|
204
|
+
while (offset < end) {
|
|
205
|
+
while (offset < end && isRubyMetadataWhitespace(source[offset]))
|
|
206
|
+
offset++;
|
|
207
|
+
const tokenStart = offset;
|
|
208
|
+
while (offset < end && !isRubyMetadataWhitespace(source[offset]))
|
|
209
|
+
offset++;
|
|
210
|
+
if (tokenStart < offset) {
|
|
211
|
+
tokens.push({ location: locationFromOffsets(filename, source, tokenStart, offset), text: source.slice(tokenStart, offset) });
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
return tokens;
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Checks one Ruby metadata separator.
|
|
218
|
+
* @param {string} character - Source character.
|
|
219
|
+
* @returns {boolean} Whether it separates metadata tokens.
|
|
220
|
+
*/
|
|
221
|
+
function isRubyMetadataWhitespace(character) {
|
|
222
|
+
return character == " " || character == "\t" || character == "\r" || character == "\n";
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* Selects only the contiguous comment block immediately before a definition.
|
|
226
|
+
* @param {import("@ruby/prism/src/deserialize.js").Comment[]} comments - Prism comments.
|
|
227
|
+
* @param {{location: import("@ruby/prism").Location}} node - Comment owner.
|
|
228
|
+
* @param {string} source - Complete source.
|
|
229
|
+
* @returns {import("@ruby/prism/src/deserialize.js").Comment[]} Associated comments.
|
|
230
|
+
*/
|
|
231
|
+
function associatedComments(comments, node, source) {
|
|
232
|
+
const preceding = comments.filter((comment) => comment.location.startOffset < node.location.startOffset)
|
|
233
|
+
.sort((left, right) => left.location.startOffset - right.location.startOffset);
|
|
234
|
+
const associated = [];
|
|
235
|
+
let boundary = node.location.startOffset;
|
|
236
|
+
for (let index = preceding.length - 1; index >= 0; index--) {
|
|
237
|
+
const comment = preceding[index];
|
|
238
|
+
const endOffset = comment.location.startOffset + comment.location.length;
|
|
239
|
+
const gap = slicePrismSource(source, endOffset, boundary);
|
|
240
|
+
if (!isImmediateCommentGap(gap))
|
|
241
|
+
break;
|
|
242
|
+
associated.unshift(comment);
|
|
243
|
+
boundary = comment.location.startOffset;
|
|
244
|
+
}
|
|
245
|
+
return associated;
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Reads one exact Ruby local type carrier and immutability marker.
|
|
249
|
+
* @param {import("@ruby/prism/src/deserialize.js").Comment[]} comments - Prism comments.
|
|
250
|
+
* @param {LocalVariableWriteNode} node - Local write.
|
|
251
|
+
* @param {string} filename - Source filename.
|
|
252
|
+
* @param {string} source - Complete source.
|
|
253
|
+
* @returns {{immutable: boolean, type: import("../semantic/types.js").TypeReference} | undefined} Metadata when present.
|
|
254
|
+
*/
|
|
255
|
+
function localMetadata(comments, node, filename, source) {
|
|
256
|
+
const associated = associatedComments(comments, node, source);
|
|
257
|
+
const metadata = associated.map((comment) => commentTokens(comment, filename, source));
|
|
258
|
+
const typeMetadata = metadata.filter(([token]) => token?.text == "@type");
|
|
259
|
+
const immutableMetadata = metadata.filter(([token]) => token?.text == "@semantifold-immutable");
|
|
260
|
+
const profileMetadata = metadata.filter(([token]) => {
|
|
261
|
+
return token?.text.startsWith("@type") || token?.text.startsWith("@semantifold-immutable");
|
|
262
|
+
});
|
|
263
|
+
if (profileMetadata.length == 0)
|
|
264
|
+
return undefined;
|
|
265
|
+
const location = nodeLocation(node, filename, source);
|
|
266
|
+
if (typeMetadata.length != 1 || typeMetadata[0].length != 2 ||
|
|
267
|
+
immutableMetadata.length > 1 || immutableMetadata.some((tokens) => tokens.length != 1) ||
|
|
268
|
+
profileMetadata.length != typeMetadata.length + immutableMetadata.length) {
|
|
269
|
+
return unsupportedSyntax("ruby", "malformed local type metadata", location);
|
|
270
|
+
}
|
|
271
|
+
return {
|
|
272
|
+
immutable: immutableMetadata.length == 1,
|
|
273
|
+
type: convertType(typeMetadata[0][1].text, `Local '${node.name}'`, location, typeMetadata[0][1].location)
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* Converts one Ruby local declaration or assignment.
|
|
278
|
+
* @param {import("@ruby/prism").Node} node - Prism node.
|
|
279
|
+
* @param {import("@ruby/prism/src/deserialize.js").Comment[]} comments - Prism comments.
|
|
280
|
+
* @param {Set<string>} visible - Names visible during adaptation.
|
|
281
|
+
* @param {string} filename - Source filename.
|
|
282
|
+
* @param {string} source - Complete source.
|
|
283
|
+
* @returns {import("../semantic/types.js").LocalStatement} Semantic local statement.
|
|
284
|
+
*/
|
|
285
|
+
function convertLocalStatement(node, comments, visible, filename, source) {
|
|
286
|
+
const location = nodeLocation(node, filename, source);
|
|
287
|
+
if (!(node instanceof LocalVariableWriteNode))
|
|
288
|
+
return unsupportedSyntax("ruby", node.constructor.name, location);
|
|
289
|
+
const metadata = localMetadata(comments, node, filename, source);
|
|
290
|
+
if (metadata) {
|
|
291
|
+
visible.add(node.name);
|
|
292
|
+
return withParserRanges({
|
|
293
|
+
initializer: convertExpression(node.value, filename, source),
|
|
294
|
+
kind: "LocalDeclaration",
|
|
295
|
+
location,
|
|
296
|
+
mutable: !metadata.immutable,
|
|
297
|
+
name: node.name,
|
|
298
|
+
type: metadata.type
|
|
299
|
+
}, { name: prismLocation(node.nameLoc, filename, source), operator: prismLocation(node.operatorLoc, filename, source) });
|
|
300
|
+
}
|
|
301
|
+
if (!visible.has(node.name))
|
|
302
|
+
return missingType("ruby", `Local '${node.name}'`, location);
|
|
303
|
+
const targetLocation = prismLocation(node.nameLoc, filename, source);
|
|
304
|
+
const target = withParserRanges({ kind: /** @type {const} */ ("IdentifierExpression"), location: targetLocation, name: node.name }, {
|
|
305
|
+
name: targetLocation
|
|
306
|
+
});
|
|
307
|
+
return withParserRanges({
|
|
308
|
+
expression: convertExpression(node.value, filename, source),
|
|
309
|
+
kind: "AssignmentStatement",
|
|
310
|
+
location,
|
|
311
|
+
target
|
|
312
|
+
}, { operator: prismLocation(node.operatorLoc, filename, source) });
|
|
313
|
+
}
|
|
314
|
+
/**
|
|
315
|
+
* Converts one exhaustive Prism statement.
|
|
316
|
+
* @param {import("@ruby/prism").Node} node - Prism statement.
|
|
317
|
+
* @param {import("@ruby/prism/src/deserialize.js").Comment[]} comments - Prism comments.
|
|
318
|
+
* @param {Set<string>} visible - Names visible during adaptation.
|
|
319
|
+
* @param {string} filename - Source filename.
|
|
320
|
+
* @param {string} source - Complete source.
|
|
321
|
+
* @returns {import("../semantic/types.js").Statement} Semantic statement.
|
|
322
|
+
*/
|
|
323
|
+
function convertStatement(node, comments, visible, filename, source) {
|
|
324
|
+
if (node instanceof ReturnNode)
|
|
325
|
+
return convertReturn(node, filename, source);
|
|
326
|
+
if (node instanceof IfNode)
|
|
327
|
+
return convertIf(node, comments, visible, filename, source);
|
|
328
|
+
if (node instanceof LocalVariableWriteNode)
|
|
329
|
+
return convertLocalStatement(node, comments, visible, filename, source);
|
|
330
|
+
if (node instanceof CallNode)
|
|
331
|
+
return convertPrint(node, filename, source);
|
|
332
|
+
return unsupportedSyntax("ruby", node.constructor.name, nodeLocation(node, filename, source));
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* Converts one ordered Prism statement list.
|
|
336
|
+
* @param {StatementsNode | null} node - Prism statements, or an empty source block.
|
|
337
|
+
* @param {import("@ruby/prism/src/deserialize.js").Comment[]} comments - Prism comments.
|
|
338
|
+
* @param {Set<string>} visible - Names visible on block entry.
|
|
339
|
+
* @param {string} filename - Source filename.
|
|
340
|
+
* @param {string} source - Complete source.
|
|
341
|
+
* @param {import("../semantic/types.js").SourceLocation} fallbackLocation - Empty block location.
|
|
342
|
+
* @returns {import("../semantic/types.js").Block} Semantic block.
|
|
343
|
+
*/
|
|
344
|
+
function convertBlock(node, comments, visible, filename, source, fallbackLocation) {
|
|
345
|
+
return {
|
|
346
|
+
kind: "Block",
|
|
347
|
+
location: node ? nodeLocation(node, filename, source) : fallbackLocation,
|
|
348
|
+
statements: node ? node.body.map((statement) => convertStatement(statement, comments, visible, filename, source)) : []
|
|
349
|
+
};
|
|
350
|
+
}
|
|
351
|
+
/**
|
|
352
|
+
* Checks that a comment and its owner are separated by at most one newline.
|
|
353
|
+
* @param {string} gap - Source between the comment and following item.
|
|
354
|
+
* @returns {boolean} Whether the gap is immediate whitespace.
|
|
355
|
+
*/
|
|
356
|
+
function isImmediateCommentGap(gap) {
|
|
357
|
+
let newlines = 0;
|
|
358
|
+
for (const character of gap) {
|
|
359
|
+
if (character == "\n") {
|
|
360
|
+
newlines++;
|
|
361
|
+
}
|
|
362
|
+
else if (character != " " && character != "\t" && character != "\r") {
|
|
363
|
+
return false;
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
return newlines <= 1;
|
|
367
|
+
}
|
|
368
|
+
/**
|
|
369
|
+
* Requires an exact supported Ruby scalar spelling.
|
|
370
|
+
* @param {string | undefined} sourceType - Ruby type comment value.
|
|
371
|
+
* @param {string} subject - Typed subject.
|
|
372
|
+
* @param {import("../semantic/types.js").SourceLocation} location - Source location.
|
|
373
|
+
* @param {import("../semantic/types.js").SourceLocation} [typeLocation] - Exact type comment token location.
|
|
374
|
+
* @returns {import("../semantic/types.js").TypeReference} Semantic type.
|
|
375
|
+
*/
|
|
376
|
+
function convertType(sourceType, subject, location, typeLocation = location) {
|
|
377
|
+
return requireSourceScalarType("ruby", sourceType, subject, location, typeLocation);
|
|
378
|
+
}
|
|
379
|
+
/**
|
|
380
|
+
* Converts a Ruby definition.
|
|
381
|
+
* @param {DefNode} node - Prism definition.
|
|
382
|
+
* @param {import("@ruby/prism/src/deserialize.js").Comment[]} comments - Prism comments.
|
|
383
|
+
* @param {string} filename - Source filename.
|
|
384
|
+
* @param {string} source - Complete source.
|
|
385
|
+
* @returns {import("../semantic/types.js").FunctionDeclaration} Semantic function.
|
|
386
|
+
*/
|
|
387
|
+
function convertFunction(node, comments, filename, source) {
|
|
388
|
+
const location = nodeLocation(node, filename, source);
|
|
389
|
+
if (!node.parameters || node.parameters.optionals.length > 0 || node.parameters.rest || node.parameters.posts.length > 0 ||
|
|
390
|
+
node.parameters.keywords.length > 0 || node.parameters.keywordRest || node.parameters.block ||
|
|
391
|
+
node.parameters.requireds.some((parameter) => !(parameter instanceof RequiredParameterNode))) {
|
|
392
|
+
return unsupportedSyntax("ruby", "parameters", location);
|
|
393
|
+
}
|
|
394
|
+
const declaredTypes = typeComments(comments, node, filename, source);
|
|
395
|
+
const parameters = node.parameters.requireds.map((parameter) => {
|
|
396
|
+
if (!(parameter instanceof RequiredParameterNode))
|
|
397
|
+
return unsupportedSyntax("ruby", parameter.constructor.name, location);
|
|
398
|
+
const parameterLocation = nodeLocation(parameter, filename, source);
|
|
399
|
+
const declaredType = declaredTypes.parameters.get(parameter.name);
|
|
400
|
+
return withParserRanges({
|
|
401
|
+
kind: /** @type {const} */ ("Parameter"),
|
|
402
|
+
location: parameterLocation,
|
|
403
|
+
name: parameter.name,
|
|
404
|
+
type: convertType(declaredType?.sourceType, `Parameter '${parameter.name}'`, parameterLocation, declaredType?.location)
|
|
405
|
+
}, { name: parameterLocation });
|
|
406
|
+
});
|
|
407
|
+
const visible = new Set(parameters.map((parameter) => parameter.name));
|
|
408
|
+
const body = convertBlock(node.body instanceof StatementsNode ? node.body : null, comments, visible, filename, source, location);
|
|
409
|
+
return withParserRanges({
|
|
410
|
+
body,
|
|
411
|
+
kind: "FunctionDeclaration",
|
|
412
|
+
location,
|
|
413
|
+
name: node.name,
|
|
414
|
+
parameters,
|
|
415
|
+
returnType: convertType(declaredTypes.returnType?.sourceType, `Function '${node.name}' return`, location, declaredTypes.returnType?.location)
|
|
416
|
+
}, { name: prismLocation(node.nameLoc, filename, source) });
|
|
417
|
+
}
|
|
418
|
+
/**
|
|
419
|
+
* Converts the existing Ruby if/else terminal with restricted branch prefixes.
|
|
420
|
+
* @param {IfNode} node - Prism if node.
|
|
421
|
+
* @param {import("@ruby/prism/src/deserialize.js").Comment[]} comments - Prism comments.
|
|
422
|
+
* @param {Set<string>} visible - Enclosing visible names.
|
|
423
|
+
* @param {string} filename - Source filename.
|
|
424
|
+
* @param {string} source - Complete source.
|
|
425
|
+
* @returns {import("../semantic/types.js").IfStatement} Semantic branch.
|
|
426
|
+
*/
|
|
427
|
+
function convertIf(node, comments, visible, filename, source) {
|
|
428
|
+
const location = nodeLocation(node, filename, source);
|
|
429
|
+
if (!node.ifKeywordLoc || node.ifKeywordLoc.startOffset != node.location.startOffset) {
|
|
430
|
+
return unsupportedSyntax("ruby", "modifier conditional", node.ifKeywordLoc
|
|
431
|
+
? prismLocation(node.ifKeywordLoc, filename, source)
|
|
432
|
+
: location);
|
|
433
|
+
}
|
|
434
|
+
const consequentVisible = new Set(visible);
|
|
435
|
+
let alternate;
|
|
436
|
+
if (node.subsequent) {
|
|
437
|
+
const alternateVisible = new Set(visible);
|
|
438
|
+
if (node.subsequent instanceof ElseNode) {
|
|
439
|
+
alternate = convertBlock(node.subsequent.statements, comments, alternateVisible, filename, source, nodeLocation(node.subsequent, filename, source));
|
|
440
|
+
}
|
|
441
|
+
else if (node.subsequent instanceof IfNode) {
|
|
442
|
+
alternate = {
|
|
443
|
+
kind: /** @type {const} */ ("Block"),
|
|
444
|
+
location: nodeLocation(node.subsequent, filename, source),
|
|
445
|
+
statements: [convertIf(node.subsequent, comments, alternateVisible, filename, source)]
|
|
446
|
+
};
|
|
447
|
+
}
|
|
448
|
+
else
|
|
449
|
+
return unsupportedSyntax("ruby", node.subsequent.constructor.name, nodeLocation(node.subsequent, filename, source));
|
|
450
|
+
}
|
|
451
|
+
return {
|
|
452
|
+
...(alternate ? { alternate } : {}),
|
|
453
|
+
condition: convertExpression(node.predicate, filename, source),
|
|
454
|
+
consequent: convertBlock(node.statements, comments, consequentVisible, filename, source, location),
|
|
455
|
+
kind: "IfStatement",
|
|
456
|
+
location
|
|
457
|
+
};
|
|
458
|
+
}
|
|
459
|
+
/**
|
|
460
|
+
* Converts the supported Ruby puts entry point.
|
|
461
|
+
* @param {import("@ruby/prism").Node} node - Prism node.
|
|
462
|
+
* @param {string} filename - Source filename.
|
|
463
|
+
* @param {string} source - Complete source.
|
|
464
|
+
* @returns {import("../semantic/types.js").PrintStatement} Print statement.
|
|
465
|
+
*/
|
|
466
|
+
function convertPrint(node, filename, source) {
|
|
467
|
+
const location = nodeLocation(node, filename, source);
|
|
468
|
+
if (!(node instanceof CallNode) || node.receiver || node.name != "puts" || node.arguments_?.arguments_.length != 1) {
|
|
469
|
+
return unsupportedSyntax("ruby", node.constructor.name, location);
|
|
470
|
+
}
|
|
471
|
+
return { expression: convertExpression(node.arguments_.arguments_[0], filename, source), kind: "PrintStatement", location };
|
|
472
|
+
}
|
|
473
|
+
/**
|
|
474
|
+
* Parses Ruby into the shared semantic module.
|
|
475
|
+
* @param {object} input - Parser input.
|
|
476
|
+
* @param {string} input.filename - Source filename.
|
|
477
|
+
* @param {string} input.source - Source text.
|
|
478
|
+
* @returns {import("../semantic/types.js").SemanticModule} Semantic module.
|
|
479
|
+
*/
|
|
480
|
+
export function parseRuby({ filename, source }) {
|
|
481
|
+
const result = parsePrism(source, { filepath: filename });
|
|
482
|
+
if (result.errors.length > 0) {
|
|
483
|
+
const error = result.errors[0];
|
|
484
|
+
const location = locationFromOffsets(filename, source, error.location.startOffset, error.location.startOffset + error.location.length);
|
|
485
|
+
throw new SemantifoldDiagnostic({ code: "PARSE_ERROR", language: "ruby", location, message: error.message });
|
|
486
|
+
}
|
|
487
|
+
if (!(result.value instanceof ProgramNode))
|
|
488
|
+
throw new Error("Prism returned a non-program root.");
|
|
489
|
+
const body = result.value.statements.body;
|
|
490
|
+
const functions = body.filter((node) => node instanceof DefNode)
|
|
491
|
+
.map((node) => convertFunction(node, result.comments, filename, source));
|
|
492
|
+
const entryNodes = body.filter((node) => !(node instanceof DefNode));
|
|
493
|
+
const location = moduleLocation(filename, source);
|
|
494
|
+
if (functions.length == 0)
|
|
495
|
+
return unsupportedSyntax("ruby", "module without a function", location);
|
|
496
|
+
const firstEntry = entryNodes[0];
|
|
497
|
+
const entryLocation = firstEntry ? locationFromOffsets(filename, source, utf8ByteOffsetToUtf16Offset(source, firstEntry.location.startOffset), utf8ByteOffsetToUtf16Offset(source, (entryNodes.at(-1)?.location.startOffset ?? 0) + (entryNodes.at(-1)?.location.length ?? 0))) : location;
|
|
498
|
+
const entryVisible = new Set();
|
|
499
|
+
const entryBlock = {
|
|
500
|
+
kind: /** @type {const} */ ("Block"),
|
|
501
|
+
location: entryLocation,
|
|
502
|
+
statements: entryNodes.map((statement) => convertStatement(statement, result.comments, entryVisible, filename, source))
|
|
503
|
+
};
|
|
504
|
+
return {
|
|
505
|
+
entryPoint: {
|
|
506
|
+
body: entryBlock,
|
|
507
|
+
kind: "EntryPoint",
|
|
508
|
+
location: entryLocation
|
|
509
|
+
},
|
|
510
|
+
functions,
|
|
511
|
+
kind: "Module",
|
|
512
|
+
location
|
|
513
|
+
};
|
|
514
|
+
}
|
|
515
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicnVieS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9mcm9udGVuZHMvcnVieS5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxZQUFZO0FBRVosT0FBTyxFQUNMLE9BQU8sRUFDUCxRQUFRLEVBQ1IsT0FBTyxFQUNQLFFBQVEsRUFDUixTQUFTLEVBQ1QsTUFBTSxFQUNOLFdBQVcsRUFDWCxzQkFBc0IsRUFDdEIscUJBQXFCLEVBQ3JCLHNCQUFzQixFQUN0QixNQUFNLEVBQ04sZUFBZSxFQUNmLFdBQVcsRUFDWCxxQkFBcUIsRUFDckIsVUFBVSxFQUNWLGNBQWMsRUFDZCxVQUFVLEVBQ1YsUUFBUSxFQUNSLFNBQVMsRUFDVixNQUFNLGFBQWEsQ0FBQTtBQUNwQixPQUFPLEVBQUMsV0FBVyxFQUFFLHFCQUFxQixFQUFFLGlCQUFpQixFQUFDLE1BQU0sa0JBQWtCLENBQUE7QUFDdEYsT0FBTyxFQUFDLG1CQUFtQixFQUFFLGNBQWMsRUFBRSwyQkFBMkIsRUFBQyxNQUFNLHlCQUF5QixDQUFBO0FBQ3hHLE9BQU8sRUFBQyxvQkFBb0IsRUFBQyxNQUFNLDBCQUEwQixDQUFBO0FBQzdELE9BQU8sRUFBQyxnQkFBZ0IsRUFBQyxNQUFNLDJCQUEyQixDQUFBO0FBQzFELE9BQU8sRUFBQyxxQkFBcUIsRUFBQyxNQUFNLHdCQUF3QixDQUFBO0FBQzVELE9BQU8sRUFBQyx1QkFBdUIsRUFBQyxNQUFNLGNBQWMsQ0FBQTtBQUNwRCxNQUFNLFVBQVUsR0FBRyxNQUFNLFNBQVMsRUFBRSxDQUFBO0FBQ3BDLE1BQU0sb0JBQW9CLEdBQUcsSUFBSSxHQUFHLENBQUM7SUFDbkMsQ0FBQyxHQUFHLEVBQUUsS0FBSyxDQUFDO0lBQ1osQ0FBQyxHQUFHLEVBQUUsVUFBVSxDQUFDO0lBQ2pCLENBQUMsR0FBRyxFQUFFLFVBQVUsQ0FBQztJQUNqQixDQUFDLElBQUksRUFBRSxPQUFPLENBQUM7SUFDZixDQUFDLElBQUksRUFBRSxVQUFVLENBQUM7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SUFBSSxDQUFDLENBQUMsQ0FDM0YsQ0FDRixDQUFDLENBQUMsQ0FBQyxRQUFRLENBQUE7SUFDWixNQUFNLFlBQVksR0FBRyxJQUFJLEdBQUcsRUFBRSxDQUFBO0lBQzlCLE1BQU0sVUFBVSxHQUFHO1FBQ2pCLElBQUksRUFBRSxvQkFBb0IsQ0FBQyxDQUFDLE9BQU8sQ0FBQztRQUNwQyxRQUFRLEVBQUUsYUFBYTtRQUN2QixVQUFVLEVBQUUsVUFBVSxDQUFDLEdBQUcsQ0FBQyxDQUFDLFNBQVMsRUFBRSxFQUFFLENBQUMsZ0JBQWdCLENBQUMsU0FBUyxFQUFFLE1BQU0sQ0FBQyxRQUFRLEVBQUUsWUFBWSxFQUFFLFFBQVEsRUFBRSxNQUFNLENBQUMsQ0FBQztLQUN4SCxDQUFBO0lBRUQsT0FBTztRQUNMLFVBQVUsRUFBRTtZQUNWLElBQUksRUFBRSxVQUFVO1lBQ2hCLElBQUksRUFBRSxZQUFZO1lBQ2xCLFFBQVEsRUFBRSxhQUFhO1NBQ3hCO1FBQ0QsU0FBUztRQUNULElBQUksRUFBRSxRQUFRO1FBQ2QsUUFBUTtLQUNULENBQUE7QUFDSCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQHRzLWNoZWNrXG5cbmltcG9ydCB7XG4gIEFuZE5vZGUsXG4gIENhbGxOb2RlLFxuICBEZWZOb2RlLFxuICBFbHNlTm9kZSxcbiAgRmFsc2VOb2RlLFxuICBJZk5vZGUsXG4gIEludGVnZXJOb2RlLFxuICBJbnRlcnBvbGF0ZWRTdHJpbmdOb2RlLFxuICBMb2NhbFZhcmlhYmxlUmVhZE5vZGUsXG4gIExvY2FsVmFyaWFibGVXcml0ZU5vZGUsXG4gIE9yTm9kZSxcbiAgUGFyZW50aGVzZXNOb2RlLFxuICBQcm9ncmFtTm9kZSxcbiAgUmVxdWlyZWRQYXJhbWV0ZXJOb2RlLFxuICBSZXR1cm5Ob2RlLFxuICBTdGF0ZW1lbnRzTm9kZSxcbiAgU3RyaW5nTm9kZSxcbiAgVHJ1ZU5vZGUsXG4gIGxvYWRQcmlzbVxufSBmcm9tIFwiQHJ1YnkvcHJpc21cIlxuaW1wb3J0IHttaXNzaW5nVHlwZSwgU2VtYW50aWZvbGREaWFnbm9zdGljLCB1bnN1cHBvcnRlZFN5bnRheH0gZnJvbSBcIi4uL2RpYWdub3N0aWMuanNcIlxuaW1wb3J0IHtsb2NhdGlvbkZyb21PZmZzZXRzLCBtb2R1bGVMb2NhdGlvbiwgdXRmOEJ5dGVPZmZzZXRUb1V0ZjE2T2Zmc2V0fSBmcm9tIFwiLi4vc2VtYW50aWMvbG9jYXRpb24uanNcIlxuaW1wb3J0IHt3aXRoQWRhcHRlZE9wZXJhdGlvbn0gZnJvbSBcIi4uL3NlbWFudGljL29wZXJhdG9ycy5qc1wiXG5pbXBvcnQge3dpdGhQYXJzZXJSYW5nZXN9IGZyb20gXCIuLi9zZW1hbnRpYy9wcm92ZW5hbmNlLmpzXCJcbmltcG9ydCB7aGFzT25seVVuaWNvZGVTY2FsYXJzfSBmcm9tIFwiLi4vc2VtYW50aWMvc2NhbGFycy5qc1wiXG5pbXBvcnQge3JlcXVpcmVTb3VyY2VTY2FsYXJUeXBlfSBmcm9tIFwiLi9zY2FsYXJzLmpzXCJcbmNvbnN0IHBhcnNlUHJpc20gPSBhd2FpdCBsb2FkUHJpc20oKVxuY29uc3QgcnVieUJpbmFyeU9wZXJhdGlvbnMgPSBuZXcgTWFwKFtcbiAgW1wiK1wiLCBcIkFkZFwiXSxcbiAgW1wiLVwiLCBcIlN1YnRyYWN0XCJdLFxuICBbXCIqXCIsIFwiTXVsdGlwbHlcIl0sXG4gIFtcIj09XCIsIFwiRXF1YWxcIl0sXG4gIFtcIiE9XCIsIFwiTm90RXF1YWxcIl0sXG4gIFtcIjxcIiwgXCJMZXNzVGhhblwiXSxcbiAgW1wiPD1cIiwgXCJMZXNzVGhhbk9yRXF1YWxcIl0sXG4gIFtcIj5cIiwgXCJHcmVhdGVyVGhhblwiXSxcbiAgW1wiPj1cIiwgXCJHcmVhdGVyVGhhbk9yRXF1YWxcIl1cbl0pXG5cbi8qKlxuICogUmV0dXJucyBhIG5vcm1hbGl6ZWQgUHJpc20gbm9kZSBsb2NhdGlvbi5cbiAqIEBwYXJhbSB7e2xvY2F0aW9uOiBpbXBvcnQoXCJAcnVieS9wcmlzbVwiKS5Mb2NhdGlvbn19IG5vZGUgLSBQcmlzbSBub2RlLlxuICogQHBhcmFtIHtzdHJpbmd9IGZpbGVuYW1lIC0gU291cmNlIGZpbGVuYW1lLlxuICogQHBhcmFtIHtzdHJpbmd9IHNvdXJjZSAtIENvbXBsZXRlIHNvdXJjZS5cbiAqIEByZXR1cm5zIHtpbXBvcnQoXCIuLi9zZW1hbnRpYy90eXBlcy5qc1wiKS5Tb3VyY2VMb2NhdGlvbn0gU291cmNlIGxvY2F0aW9uLlxuICovXG5mdW5jdGlvbiBub2RlTG9jYXRpb24obm9kZSwgZmlsZW5hbWUsIHNvdXJjZSkge1xuICByZXR1cm4gcHJpc21Mb2NhdGlvbihub2RlLmxvY2F0aW9uLCBmaWxlbmFtZSwgc291cmNlKVxufVxuXG4vKipcbiAqIENvbnZlcnRzIGEgUHJpc20gbG9jYXRpb24gaW50byBhIG5vcm1hbGl6ZWQgc291cmNlIGxvY2F0aW9uLlxuICogQHBhcmFtIHtpbXBvcnQoXCJAcnVieS9wcmlzbVwiKS5Mb2NhdGlvbn0gbG9jYXRpb24gLSBQcmlzbSBsb2NhdGlvbi5cbiAqIEBwYXJhbSB7c3RyaW5nfSBmaWxlbmFtZSAtIFNvdXJjZSBmaWxlbmFtZS5cbiAqIEBwYXJhbSB7c3RyaW5nfSBzb3VyY2UgLSBDb21wbGV0ZSBzb3VyY2UuXG4gKiBAcmV0dXJucyB7aW1wb3J0KFwiLi4vc2VtYW50aWMvdHlwZXMuanNcIikuU291cmNlTG9jYXRpb259IFNvdXJjZSBsb2NhdGlvbi5cbiAqL1xuZnVuY3Rpb24gcHJpc21Mb2NhdGlvbihsb2NhdGlvbiwgZmlsZW5hbWUsIHNvdXJjZSkge1xuICByZXR1cm4gbG9jYXRpb25Gcm9tT2Zmc2V0cyhcbiAgICBmaWxlbmFtZSxcbiAgICBzb3VyY2UsXG4gICAgdXRmOEJ5dGVPZmZzZXRUb1V0ZjE2T2Zmc2V0KHNvdXJjZSwgbG9jYXRpb24uc3RhcnRPZmZzZXQpLFxuICAgIHV0ZjhCeXRlT2Zmc2V0VG9VdGYxNk9mZnNldChzb3VyY2UsIGxvY2F0aW9uLnN0YXJ0T2Zmc2V0ICsgbG9jYXRpb24ubGVuZ3RoKVxuICApXG59XG5cbi8qKlxuICogU2xpY2VzIEphdmFTY3JpcHQgc291cmNlIHVzaW5nIFByaXNtJ3MgVVRGLTggYnl0ZSBvZmZzZXRzLlxuICogQHBhcmFtIHtzdHJpbmd9IHNvdXJjZSAtIENvbXBsZXRlIHNvdXJjZS5cbiAqIEBwYXJhbSB7bnVtYmVyfSBzdGFydE9mZnNldCAtIEluY2x1c2l2ZSBQcmlzbSBieXRlIG9mZnNldC5cbiAqIEBwYXJhbSB7bnVtYmVyfSBlbmRPZmZzZXQgLSBFeGNsdXNpdmUgUHJpc20gYnl0ZSBvZmZzZXQuXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBTb3VyY2UgdGV4dCBpbiB0aGUgYnl0ZSByYW5nZS5cbiAqL1xuZnVuY3Rpb24gc2xpY2VQcmlzbVNvdXJjZShzb3VyY2UsIHN0YXJ0T2Zmc2V0LCBlbmRPZmZzZXQpIHtcbiAgcmV0dXJuIHNvdXJjZS5zbGljZShcbiAgICB1dGY4Qnl0ZU9mZnNldFRvVXRmMTZPZmZzZXQoc291cmNlLCBzdGFydE9mZnNldCksXG4gICAgdXRmOEJ5dGVPZmZzZXRUb1V0ZjE2T2Zmc2V0KHNvdXJjZSwgZW5kT2Zmc2V0KVxuICApXG59XG5cbi8qKlxuICogQ29udmVydHMgYSBzdXBwb3J0ZWQgUHJpc20gZXhwcmVzc2lvbi5cbiAqIEBwYXJhbSB7aW1wb3J0KFwiQHJ1YnkvcHJpc21cIikuTm9kZX0gbm9kZSAtIFByaXNtIG5vZGUuXG4gKiBAcGFyYW0ge3N0cmluZ30gZmlsZW5hbWUgLSBTb3VyY2UgZmlsZW5hbWUuXG4gKiBAcGFyYW0ge3N0cmluZ30gc291cmNlIC0gQ29tcGxldGUgc291cmNlLlxuICogQHJldHVybnMge2ltcG9ydChcIi4uL3NlbWFudGljL3R5cGVzLmpzXCIpLkV4cHJlc3Npb259IFNlbWFudGljIGV4cHJlc3Npb24uXG4gKi9cbmZ1bmN0aW9uIGNvbnZlcnRFeHByZXNzaW9uKG5vZGUsIGZpbGVuYW1lLCBzb3VyY2UpIHtcbiAgY29uc3QgbG9jYXRpb24gPSBub2RlTG9jYXRpb24obm9kZSwgZmlsZW5hbWUsIHNvdXJjZSlcblxuICBpZiAobm9kZSBpbnN0YW5jZW9mIFBhcmVudGhlc2VzTm9kZSAmJiBub2RlLmJvZHkgaW5zdGFuY2VvZiBTdGF0ZW1lbnRzTm9kZSAmJiBub2RlLmJvZHkuYm9keS5sZW5ndGggPT0gMSkge1xuICAgIHJldHVybiBjb252ZXJ0RXhwcmVzc2lvbihub2RlLmJvZHkuYm9keVswXSwgZmlsZW5hbWUsIHNvdXJjZSlcbiAgfVxuXG4gIGlmIChub2RlIGluc3RhbmNlb2YgTG9jYWxWYXJpYWJsZVJlYWROb2RlKSB7XG4gICAgcmV0dXJuIHdpdGhQYXJzZXJSYW5nZXMoe2tpbmQ6IC8qKiBAdHlwZSB7Y29uc3R9ICovIChcIklkZW50aWZpZXJFeHByZXNzaW9uXCIpLCBsb2NhdGlvbiwgbmFtZTogbm9kZS5uYW1lfSwge25hbWU6IGxvY2F0aW9ufSlcbiAgfVxuXG4gIGlmIChub2RlIGluc3RhbmNlb2YgSW50ZWdlck5vZGUpIHtcbiAgICBpZiAoIU51bWJlci5pc1NhZmVJbnRlZ2VyKG5vZGUudmFsdWUpKSByZXR1cm4gdW5zdXBwb3J0ZWRTeW50YXgoXCJydWJ5XCIsIFwibm9uLXNhZmUgaW50ZWdlciBsaXRlcmFsXCIsIGxvY2F0aW9uKVxuXG4gICAgcmV0dXJuIHdpdGhQYXJzZXJSYW5nZXMoe2tpbmQ6IC8qKiBAdHlwZSB7Y29uc3R9ICovIChcIkludGVnZXJMaXRlcmFsXCIpLCBsb2NhdGlvbiwgdmFsdWU6IG5vZGUudmFsdWV9LCB7bGl0ZXJhbDogbG9jYXRpb259KVxuICB9XG5cbiAgaWYgKG5vZGUgaW5zdGFuY2VvZiBUcnVlTm9kZSB8fCBub2RlIGluc3RhbmNlb2YgRmFsc2VOb2RlKSB7XG4gICAgcmV0dXJuIHdpdGhQYXJzZXJSYW5nZXMoe2tpbmQ6IC8qKiBAdHlwZSB7Y29uc3R9ICovIChcIkJvb2xlYW5MaXRlcmFsXCIpLCBsb2NhdGlvbiwgdmFsdWU6IG5vZGUgaW5zdGFuY2VvZiBUcnVlTm9kZX0sIHtsaXRlcmFsOiBsb2NhdGlvbn0pXG4gIH1cblxuICBpZiAobm9kZSBpbnN0YW5jZW9mIFN0cmluZ05vZGUpIHtcbiAgICBjb25zdCBkZWNvZGVkID0gbm9kZS51bmVzY2FwZWRcblxuICAgIGlmICghZGVjb2RlZC52YWxpZEVuY29kaW5nIHx8IGRlY29kZWQuZW5jb2RpbmcgIT0gXCJ1dGYtOFwiIHx8IG5vZGUuaXNGb3JjZWRCaW5hcnlFbmNvZGluZygpIHx8XG4gICAgICAhaGFzT25seVVuaWNvZGVTY2FsYXJzKGRlY29kZWQudmFsdWUpKSB7XG4gICAgICByZXR1cm4gdW5zdXBwb3J0ZWRTeW50YXgoXCJydWJ5XCIsIFwiaW52YWxpZCBVbmljb2RlIHN0cmluZyBsaXRlcmFsXCIsIGxvY2F0aW9uKVxuICAgIH1cblxuICAgIHJldHVybiB3aXRoUGFyc2VyUmFuZ2VzKHtraW5kOiAvKiogQHR5cGUge2NvbnN0fSAqLyAoXCJTdHJpbmdMaXRlcmFsXCIpLCBsb2NhdGlvbiwgdmFsdWU6IGRlY29kZWQudmFsdWV9LCB7bGl0ZXJhbDogbG9jYXRpb259KVxuICB9XG5cbiAgaWYgKG5vZGUgaW5zdGFuY2VvZiBJbnRlcnBvbGF0ZWRTdHJpbmdOb2RlKSByZXR1cm4gdW5zdXBwb3J0ZWRTeW50YXgoXCJydWJ5XCIsIFwiaW50ZXJwb2xhdGVkIHN0cmluZ1wiLCBsb2NhdGlvbilcblxuICBpZiAobm9kZSBpbnN0YW5jZW9mIENhbGxOb2RlICYmIG5vZGUucmVjZWl2ZXIgJiYgbm9kZS5uYW1lID09IFwiIVwiKSB7XG4gICAgY29uc3Qgb3BlcmF0b3JMb2NhdGlvbiA9IHByaXNtTG9jYXRpb24obm9kZS5tZXNzYWdlTG9jID8/IG5vZGUubG9jYXRpb24sIGZpbGVuYW1lLCBzb3VyY2UpXG5cbiAgICBpZiAobm9kZS5jYWxsT3BlcmF0b3JMb2MpIHJldHVybiB1bnN1cHBvcnRlZFN5bnRheChcInJ1YnlcIiwgXCJxdWFsaWZpZWQgYm9vbGVhbiBub3RcIiwgb3BlcmF0b3JMb2NhdGlvbilcbiAgICBpZiAobm9kZS5tZXNzYWdlTG9jPy5sZW5ndGggIT0gMSkge1xuICAgICAgcmV0dXJuIHVuc3VwcG9ydGVkU3ludGF4KFwicnVieVwiLCBcInByZWNlZGVuY2Utc2Vuc2l0aXZlIGJvb2xlYW4gbm90XCIsIG9wZXJhdG9yTG9jYXRpb24pXG4gICAgfVxuICAgIGlmIChub2RlLmFyZ3VtZW50c18pIHJldHVybiB1bnN1cHBvcnRlZFN5bnRheChcInJ1YnlcIiwgXCJib29sZWFuIG5vdCBhcmd1bWVudCBsaXN0XCIsIG9wZXJhdG9yTG9jYXRpb24pXG5cbiAgICBjb25zdCBzZW1hbnRpYyA9IHdpdGhBZGFwdGVkT3BlcmF0aW9uKHdpdGhQYXJzZXJSYW5nZXMoe1xuICAgICAga2luZDogXCJVbmFyeUV4cHJlc3Npb25cIixcbiAgICAgIGxvY2F0aW9uLFxuICAgICAgb3BlcmFuZDogY29udmVydEV4cHJlc3Npb24obm9kZS5yZWNlaXZlciwgZmlsZW5hbWUsIHNvdXJjZSlcbiAgICB9LCB7b3BlcmF0b3I6IG9wZXJhdG9yTG9jYXRpb259KSwgXCJOb3RcIilcblxuICAgIHJldHVybiAvKiogQHR5cGUge2ltcG9ydChcIi4uL3NlbWFudGljL3R5cGVzLmpzXCIpLkV4cHJlc3Npb259ICovICgvKiogQHR5cGUge3Vua25vd259ICovIChzZW1hbnRpYykpXG4gIH1cblxuICBpZiAobm9kZSBpbnN0YW5jZW9mIENhbGxOb2RlICYmIG5vZGUucmVjZWl2ZXIgJiYgbm9kZS5uYW1lID09IFwiLUBcIikge1xuICAgIGNvbnN0IG9wZXJhdG9yTG9jYXRpb24gPSBwcmlzbUxvY2F0aW9uKG5vZGUubWVzc2FnZUxvYyA/PyBub2RlLmxvY2F0aW9uLCBmaWxlbmFtZSwgc291cmNlKVxuXG4gICAgaWYgKG5vZGUuY2FsbE9wZXJhdG9yTG9jKSByZXR1cm4gdW5zdXBwb3J0ZWRTeW50YXgoXCJydWJ5XCIsIFwicXVhbGlmaWVkIGludGVnZXIgbmVnYXRpb25cIiwgb3BlcmF0b3JMb2NhdGlvbilcbiAgICBpZiAobm9kZS5hcmd1bWVudHNfKSByZXR1cm4gdW5zdXBwb3J0ZWRTeW50YXgoXCJydWJ5XCIsIFwiaW50ZWdlciBuZWdhdGlvbiBhcmd1bWVudCBsaXN0XCIsIG9wZXJhdG9yTG9jYXRpb24pXG5cbiAgICBjb25zdCBzZW1hbnRpYyA9IHdpdGhBZGFwdGVkT3BlcmF0aW9uKHdpdGhQYXJzZXJSYW5nZXMoe1xuICAgICAga2luZDogXCJVbmFyeUV4cHJlc3Npb25cIixcbiAgICAgIGxvY2F0aW9uLFxuICAgICAgb3BlcmFuZDogY29udmVydEV4cHJlc3Npb24obm9kZS5yZWNlaXZlciwgZmlsZW5hbWUsIHNvdXJjZSlcbiAgICB9LCB7b3BlcmF0b3I6IG9wZXJhdG9yTG9jYXRpb259KSwgXCJOZWdhdGVcIilcblxuICAgIHJldHVybiAvKiogQHR5cGUge2ltcG9ydChcIi4uL3NlbWFudGljL3R5cGVzLmpzXCIpLkV4cHJlc3Npb259ICovICgvKiogQHR5cGUge3Vua25vd259ICovIChzZW1hbnRpYykpXG4gIH1cblxuICBpZiAobm9kZSBpbnN0YW5jZW9mIEFuZE5vZGUgfHwgbm9kZSBpbnN0YW5jZW9mIE9yTm9kZSkge1xuICAgIGNvbnN0IG9wZXJhdG9yTG9jYXRpb24gPSBwcmlzbUxvY2F0aW9uKG5vZGUub3BlcmF0b3JMb2MsIGZpbGVuYW1lLCBzb3VyY2UpXG4gICAgY29uc3Qgc291cmNlT3BlcmF0b3IgPSBzb3VyY2Uuc2xpY2Uob3BlcmF0b3JMb2NhdGlvbi5zdGFydC5vZmZzZXQsIG9wZXJhdG9yTG9jYXRpb24uZW5kLm9mZnNldClcblxuICAgIGlmIChzb3VyY2VPcGVyYXRvciAhPSBcIiYmXCIgJiYgc291cmNlT3BlcmF0b3IgIT0gXCJ8fFwiKSB7XG4gICAgICByZXR1cm4gdW5zdXBwb3J0ZWRTeW50YXgoXCJydWJ5XCIsIGBwcmVjZWRlbmNlLXNlbnNpdGl2ZSBib29sZWFuICR7c291cmNlT3BlcmF0b3J9YCwgbG9jYXRpb24pXG4gICAgfVxuXG4gICAgY29uc3Qgc2VtYW50aWMgPSB3aXRoQWRhcHRlZE9wZXJhdGlvbih3aXRoUGFyc2VyUmFuZ2VzKHtcbiAgICAgIGtpbmQ6IFwiQmluYXJ5RXhwcmVzc2lvblwiLFxuICAgICAgbGVmdDogY29udmVydEV4cHJlc3Npb24obm9kZS5sZWZ0LCBmaWxlbmFtZSwgc291cmNlKSxcbiAgICAgIGxvY2F0aW9uLFxuICAgICAgcmlnaHQ6IGNvbnZlcnRFeHByZXNzaW9uKG5vZGUucmlnaHQsIGZpbGVuYW1lLCBzb3VyY2UpXG4gICAgfSwge29wZXJhdG9yOiBvcGVyYXRvckxvY2F0aW9ufSksIG5vZGUgaW5zdGFuY2VvZiBBbmROb2RlID8gXCJBbmRcIiA6IFwiT3JcIilcblxuICAgIHJldHVybiAvKiogQHR5cGUge2ltcG9ydChcIi4uL3NlbWFudGljL3R5cGVzLmpzXCIpLkV4cHJlc3Npb259ICovICgvKiogQHR5cGUge3Vua25vd259ICovIChzZW1hbnRpYykpXG4gIH1cblxuICBpZiAobm9kZSBpbnN0YW5jZW9mIENhbGxOb2RlICYmIG5vZGUucmVjZWl2ZXIgJiYgcnVieUJpbmFyeU9wZXJhdGlvbnMuaGFzKG5vZGUubmFtZSkgJiYgbm9kZS5jYWxsT3BlcmF0b3JMb2MgJiZcbiAgICBub2RlLmFyZ3VtZW50c18/LmFyZ3VtZW50c18ubGVuZ3RoID09IDEpIHtcbiAgICByZXR1cm4gdW5zdXBwb3J0ZWRTeW50YXgoXG4gICAgICBcInJ1YnlcIixcbiAgICAgIGBxdWFsaWZpZWQgYmluYXJ5IG9wZXJhdG9yICR7bm9kZS5uYW1lfWAsXG4gICAgICBwcmlzbUxvY2F0aW9uKG5vZGUubWVzc2FnZUxvYyA/PyBub2RlLmxvY2F0aW9uLCBmaWxlbmFtZSwgc291cmNlKVxuICAgIClcbiAgfVxuXG4gIGlmIChub2RlIGluc3RhbmNlb2YgQ2FsbE5vZGUgJiYgbm9kZS5yZWNlaXZlciAmJiBydWJ5QmluYXJ5T3BlcmF0aW9ucy5oYXMobm9kZS5uYW1lKSAmJiBub2RlLmFyZ3VtZW50c18/LmFyZ3VtZW50c18ubGVuZ3RoID09IDEpIHtcbiAgICBjb25zdCBzZW1hbnRpYyA9IHdpdGhBZGFwdGVkT3BlcmF0aW9uKHdpdGhQYXJzZXJSYW5nZXMoe1xuICAgICAga2luZDogXCJCaW5hcnlFeHByZXNzaW9uXCIsXG4gICAgICBsZWZ0OiBjb252ZXJ0RXhwcmVzc2lvbihub2RlLnJlY2VpdmVyLCBmaWxlbmFtZSwgc291cmNlKSxcbiAgICAgIGxvY2F0aW9uLFxuICAgICAgcmlnaHQ6IGNvbnZlcnRFeHByZXNzaW9uKG5vZGUuYXJndW1lbnRzXy5hcmd1bWVudHNfWzBdLCBmaWxlbmFtZSwgc291cmNlKVxuICAgIH0sIHtvcGVyYXRvcjogcHJpc21Mb2NhdGlvbihub2RlLm1lc3NhZ2VMb2MgPz8gbm9kZS5sb2NhdGlvbiwgZmlsZW5hbWUsIHNvdXJjZSl9KSwgLyoqIEB0eXBlIHtpbXBvcnQoXCIuLi9zZW1hbnRpYy9vcGVyYXRvcnMuanNcIikuQWRhcHRlZE9wZXJhdGlvbn0gKi8gKHJ1YnlCaW5hcnlPcGVyYXRpb25zLmdldChub2RlLm5hbWUpKSlcblxuICAgIHJldHVybiAvKiogQHR5cGUge2ltcG9ydChcIi4uL3NlbWFudGljL3R5cGVzLmpzXCIpLkV4cHJlc3Npb259ICovICgvKiogQHR5cGUge3Vua25vd259ICovIChzZW1hbnRpYykpXG4gIH1cblxuICBpZiAobm9kZSBpbnN0YW5jZW9mIENhbGxOb2RlICYmICFub2RlLnJlY2VpdmVyKSB7XG4gICAgcmV0dXJuIHdpdGhQYXJzZXJSYW5nZXMoe1xuICAgICAgYXJndW1lbnRzOiAobm9kZS5hcmd1bWVudHNfPy5hcmd1bWVudHNfID8/IFtdKS5tYXAoKGFyZ3VtZW50KSA9PiBjb252ZXJ0RXhwcmVzc2lvbihhcmd1bWVudCwgZmlsZW5hbWUsIHNvdXJjZSkpLFxuICAgICAgY2FsbGVlOiBub2RlLm5hbWUsXG4gICAgICBraW5kOiBcIkNhbGxFeHByZXNzaW9uXCIsXG4gICAgICBsb2NhdGlvblxuICAgIH0sIHtjYWxsZWU6IHByaXNtTG9jYXRpb24obm9kZS5tZXNzYWdlTG9jID8/IG5vZGUubG9jYXRpb24sIGZpbGVuYW1lLCBzb3VyY2UpfSlcbiAgfVxuXG4gIHJldHVybiB1bnN1cHBvcnRlZFN5bnRheChcInJ1YnlcIiwgbm9kZS5jb25zdHJ1Y3Rvci5uYW1lLCBsb2NhdGlvbilcbn1cblxuLyoqXG4gKiBDb252ZXJ0cyBvbmUgZXhwbGljaXQgUnVieSByZXR1cm4uXG4gKiBAcGFyYW0ge2ltcG9ydChcIkBydWJ5L3ByaXNtXCIpLk5vZGV9IG5vZGUgLSBQcmlzbSBub2RlLlxuICogQHBhcmFtIHtzdHJpbmd9IGZpbGVuYW1lIC0gU291cmNlIGZpbGVuYW1lLlxuICogQHBhcmFtIHtzdHJpbmd9IHNvdXJjZSAtIENvbXBsZXRlIHNvdXJjZS5cbiAqIEByZXR1cm5zIHtpbXBvcnQoXCIuLi9zZW1hbnRpYy90eXBlcy5qc1wiKS5SZXR1cm5TdGF0ZW1lbnR9IFNlbWFudGljIHJldHVybi5cbiAqL1xuZnVuY3Rpb24gY29udmVydFJldHVybihub2RlLCBmaWxlbmFtZSwgc291cmNlKSB7XG4gIGNvbnN0IGxvY2F0aW9uID0gbm9kZUxvY2F0aW9uKG5vZGUsIGZpbGVuYW1lLCBzb3VyY2UpXG5cbiAgaWYgKCEobm9kZSBpbnN0YW5jZW9mIFJldHVybk5vZGUpIHx8IG5vZGUuYXJndW1lbnRzXz8uYXJndW1lbnRzXy5sZW5ndGggIT0gMSkge1xuICAgIHJldHVybiB1bnN1cHBvcnRlZFN5bnRheChcInJ1YnlcIiwgbm9kZS5jb25zdHJ1Y3Rvci5uYW1lLCBsb2NhdGlvbilcbiAgfVxuXG4gIHJldHVybiB7XG4gICAgZXhwcmVzc2lvbjogY29udmVydEV4cHJlc3Npb24obm9kZS5hcmd1bWVudHNfLmFyZ3VtZW50c19bMF0sIGZpbGVuYW1lLCBzb3VyY2UpLFxuICAgIGtpbmQ6IFwiUmV0dXJuU3RhdGVtZW50XCIsXG4gICAgbG9jYXRpb25cbiAgfVxufVxuXG4vKipcbiAqIFJlYWRzIFByaXNtLW93bmVkIFJCUy1zdHlsZSB0eXBlIGNvbW1lbnRzIGRpcmVjdGx5IHByZWNlZGluZyBhIGRlZmluaXRpb24uXG4gKiBAcGFyYW0ge2ltcG9ydChcIkBydWJ5L3ByaXNtL3NyYy9kZXNlcmlhbGl6ZS5qc1wiKS5Db21tZW50W119IGNvbW1lbnRzIC0gUHJpc20gY29tbWVudHMuXG4gKiBAcGFyYW0ge3tsb2NhdGlvbjogaW1wb3J0KFwiQHJ1YnkvcHJpc21cIikuTG9jYXRpb259fSBub2RlIC0gQ29tbWVudCBvd25lci5cbiAqIEBwYXJhbSB7c3RyaW5nfSBmaWxlbmFtZSAtIFNvdXJjZSBmaWxlbmFtZS5cbiAqIEBwYXJhbSB7c3RyaW5nfSBzb3VyY2UgLSBDb21wbGV0ZSBzb3VyY2UuXG4gKiBAcmV0dXJucyB7e3BhcmFtZXRlcnM6IE1hcDxzdHJpbmcsIHtsb2NhdGlvbjogaW1wb3J0KFwiLi4vc2VtYW50aWMvdHlwZXMuanNcIikuU291cmNlTG9jYXRpb24sIHNvdXJjZVR5cGU6IHN0cmluZ30+LCByZXR1cm5UeXBlOiB7bG9jYXRpb246IGltcG9ydChcIi4uL3NlbWFudGljL3R5cGVzLmpzXCIpLlNvdXJjZUxvY2F0aW9uLCBzb3VyY2VUeXBlOiBzdHJpbmd9IHwgdW5kZWZpbmVkfX0gRGVjbGFyZWQgdHlwZXMuXG4gKi9cbmZ1bmN0aW9uIHR5cGVDb21tZW50cyhjb21tZW50cywgbm9kZSwgZmlsZW5hbWUsIHNvdXJjZSkge1xuICBjb25zdCBwcmVjZWRpbmcgPSBhc3NvY2lhdGVkQ29tbWVudHMoY29tbWVudHMsIG5vZGUsIHNvdXJjZSlcbiAgY29uc3QgcGFyYW1ldGVyVHlwZXMgPSBuZXcgTWFwKClcbiAgLyoqIEB0eXBlIHt7bG9jYXRpb246IGltcG9ydChcIi4uL3NlbWFudGljL3R5cGVzLmpzXCIpLlNvdXJjZUxvY2F0aW9uLCBzb3VyY2VUeXBlOiBzdHJpbmd9IHwgdW5kZWZpbmVkfSAqL1xuICBsZXQgcmV0dXJuVHlwZVxuXG4gIGZvciAoY29uc3QgY29tbWVudCBvZiBwcmVjZWRpbmcpIHtcbiAgICBjb25zdCB3b3JkcyA9IGNvbW1lbnRUb2tlbnMoY29tbWVudCwgZmlsZW5hbWUsIHNvdXJjZSlcblxuICAgIGlmICh3b3Jkc1swXT8udGV4dCA9PSBcIkBwYXJhbVwiICYmIHdvcmRzLmxlbmd0aCA9PSAzKSB7XG4gICAgICBwYXJhbWV0ZXJUeXBlcy5zZXQod29yZHNbMV0udGV4dCwge2xvY2F0aW9uOiB3b3Jkc1syXS5sb2NhdGlvbiwgc291cmNlVHlwZTogd29yZHNbMl0udGV4dH0pXG4gICAgfVxuICAgIGlmICh3b3Jkc1swXT8udGV4dCA9PSBcIkByZXR1cm5cIiAmJiB3b3Jkcy5sZW5ndGggPT0gMikge1xuICAgICAgcmV0dXJuVHlwZSA9IHtsb2NhdGlvbjogd29yZHNbMV0ubG9jYXRpb24sIHNvdXJjZVR5cGU6IHdvcmRzWzFdLnRleHR9XG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIHtwYXJhbWV0ZXJzOiBwYXJhbWV0ZXJUeXBlcywgcmV0dXJuVHlwZX1cbn1cblxuLyoqXG4gKiBMZXhlcyB3aGl0ZXNwYWNlLXNlcGFyYXRlZCBtZXRhZGF0YSB0b2tlbnMgaW5zaWRlIGEgUHJpc20tb3duZWQgUnVieSBjb21tZW50LlxuICogQHBhcmFtIHtpbXBvcnQoXCJAcnVieS9wcmlzbS9zcmMvZGVzZXJpYWxpemUuanNcIikuQ29tbWVudH0gY29tbWVudCAtIFByaXNtIGNvbW1lbnQgdG9rZW4uXG4gKiBAcGFyYW0ge3N0cmluZ30gZmlsZW5hbWUgLSBTb3VyY2UgZmlsZW5hbWUuXG4gKiBAcGFyYW0ge3N0cmluZ30gc291cmNlIC0gQ29tcGxldGUgc291cmNlLlxuICogQHJldHVybnMge3tsb2NhdGlvbjogaW1wb3J0KFwiLi4vc2VtYW50aWMvdHlwZXMuanNcIikuU291cmNlTG9jYXRpb24sIHRleHQ6IHN0cmluZ31bXX0gTWV0YWRhdGEgdG9rZW5zLlxuICovXG5mdW5jdGlvbiBjb21tZW50VG9rZW5zKGNvbW1lbnQsIGZpbGVuYW1lLCBzb3VyY2UpIHtcbiAgY29uc3Qgc3RhcnQgPSB1dGY4Qnl0ZU9mZnNldFRvVXRmMTZPZmZzZXQoc291cmNlLCBjb21tZW50LmxvY2F0aW9uLnN0YXJ0T2Zmc2V0KVxuICBjb25zdCBlbmQgPSB1dGY4Qnl0ZU9mZnNldFRvVXRmMTZPZmZzZXQoc291cmNlLCBjb21tZW50LmxvY2F0aW9uLnN0YXJ0T2Zmc2V0ICsgY29tbWVudC5sb2NhdGlvbi5sZW5ndGgpXG4gIGNvbnN0IHRva2VucyA9IFtdXG4gIGxldCBvZmZzZXQgPSBzdGFydCArIDFcblxuICB3aGlsZSAob2Zmc2V0IDwgZW5kKSB7XG4gICAgd2hpbGUgKG9mZnNldCA8IGVuZCAmJiBpc1J1YnlNZXRhZGF0YVdoaXRlc3BhY2Uoc291cmNlW29mZnNldF0pKSBvZmZzZXQrK1xuICAgIGNvbnN0IHRva2VuU3RhcnQgPSBvZmZzZXRcblxuICAgIHdoaWxlIChvZmZzZXQgPCBlbmQgJiYgIWlzUnVieU1ldGFkYXRhV2hpdGVzcGFjZShzb3VyY2Vbb2Zmc2V0XSkpIG9mZnNldCsrXG4gICAgaWYgKHRva2VuU3RhcnQgPCBvZmZzZXQpIHtcbiAgICAgIHRva2Vucy5wdXNoKHtsb2NhdGlvbjogbG9jYXRpb25Gcm9tT2Zmc2V0cyhmaWxlbmFtZSwgc291cmNlLCB0b2tlblN0YXJ0LCBvZmZzZXQpLCB0ZXh0OiBzb3VyY2Uuc2xpY2UodG9rZW5TdGFydCwgb2Zmc2V0KX0pXG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIHRva2Vuc1xufVxuXG4vKipcbiAqIENoZWNrcyBvbmUgUnVieSBtZXRhZGF0YSBzZXBhcmF0b3IuXG4gKiBAcGFyYW0ge3N0cmluZ30gY2hhcmFjdGVyIC0gU291cmNlIGNoYXJhY3Rlci5cbiAqIEByZXR1cm5zIHtib29sZWFufSBXaGV0aGVyIGl0IHNlcGFyYXRlcyBtZXRhZGF0YSB0b2tlbnMuXG4gKi9cbmZ1bmN0aW9uIGlzUnVieU1ldGFkYXRhV2hpdGVzcGFjZShjaGFyYWN0ZXIpIHtcbiAgcmV0dXJuIGNoYXJhY3RlciA9PSBcIiBcIiB8fCBjaGFyYWN0ZXIgPT0gXCJcXHRcIiB8fCBjaGFyYWN0ZXIgPT0gXCJcXHJcIiB8fCBjaGFyYWN0ZXIgPT0gXCJcXG5cIlxufVxuXG4vKipcbiAqIFNlbGVjdHMgb25seSB0aGUgY29udGlndW91cyBjb21tZW50IGJsb2NrIGltbWVkaWF0ZWx5IGJlZm9yZSBhIGRlZmluaXRpb24uXG4gKiBAcGFyYW0ge2ltcG9ydChcIkBydWJ5L3ByaXNtL3NyYy9kZXNlcmlhbGl6ZS5qc1wiKS5Db21tZW50W119IGNvbW1lbnRzIC0gUHJpc20gY29tbWVudHMuXG4gKiBAcGFyYW0ge3tsb2NhdGlvbjogaW1wb3J0KFwiQHJ1YnkvcHJpc21cIikuTG9jYXRpb259fSBub2RlIC0gQ29tbWVudCBvd25lci5cbiAqIEBwYXJhbSB7c3RyaW5nfSBzb3VyY2UgLSBDb21wbGV0ZSBzb3VyY2UuXG4gKiBAcmV0dXJucyB7aW1wb3J0KFwiQHJ1YnkvcHJpc20vc3JjL2Rlc2VyaWFsaXplLmpzXCIpLkNvbW1lbnRbXX0gQXNzb2NpYXRlZCBjb21tZW50cy5cbiAqL1xuZnVuY3Rpb24gYXNzb2NpYXRlZENvbW1lbnRzKGNvbW1lbnRzLCBub2RlLCBzb3VyY2UpIHtcbiAgY29uc3QgcHJlY2VkaW5nID0gY29tbWVudHMuZmlsdGVyKChjb21tZW50KSA9PiBjb21tZW50LmxvY2F0aW9uLnN0YXJ0T2Zmc2V0IDwgbm9kZS5sb2NhdGlvbi5zdGFydE9mZnNldClcbiAgICAuc29ydCgobGVmdCwgcmlnaHQpID0+IGxlZnQubG9jYXRpb24uc3RhcnRPZmZzZXQgLSByaWdodC5sb2NhdGlvbi5zdGFydE9mZnNldClcbiAgY29uc3QgYXNzb2NpYXRlZCA9IFtdXG4gIGxldCBib3VuZGFyeSA9IG5vZGUubG9jYXRpb24uc3RhcnRPZmZzZXRcblxuICBmb3IgKGxldCBpbmRleCA9IHByZWNlZGluZy5sZW5ndGggLSAxOyBpbmRleCA+PSAwOyBpbmRleC0tKSB7XG4gICAgY29uc3QgY29tbWVudCA9IHByZWNlZGluZ1tpbmRleF1cbiAgICBjb25zdCBlbmRPZmZzZXQgPSBjb21tZW50LmxvY2F0aW9uLnN0YXJ0T2Zmc2V0ICsgY29tbWVudC5sb2NhdGlvbi5sZW5ndGhcbiAgICBjb25zdCBnYXAgPSBzbGljZVByaXNtU291cmNlKHNvdXJjZSwgZW5kT2Zmc2V0LCBib3VuZGFyeSlcblxuICAgIGlmICghaXNJbW1lZGlhdGVDb21tZW50R2FwKGdhcCkpIGJyZWFrXG5cbiAgICBhc3NvY2lhdGVkLnVuc2hpZnQoY29tbWVudClcbiAgICBib3VuZGFyeSA9IGNvbW1lbnQubG9jYXRpb24uc3RhcnRPZmZzZXRcbiAgfVxuXG4gIHJldHVybiBhc3NvY2lhdGVkXG59XG5cbi8qKlxuICogUmVhZHMgb25lIGV4YWN0IFJ1YnkgbG9jYWwgdHlwZSBjYXJyaWVyIGFuZCBpbW11dGFiaWxpdHkgbWFya2VyLlxuICogQHBhcmFtIHtpbXBvcnQoXCJAcnVieS9wcmlzbS9zcmMvZGVzZXJpYWxpemUuanNcIikuQ29tbWVudFtdfSBjb21tZW50cyAtIFByaXNtIGNvbW1lbnRzLlxuICogQHBhcmFtIHtMb2NhbFZhcmlhYmxlV3JpdGVOb2RlfSBub2RlIC0gTG9jYWwgd3JpdGUuXG4gKiBAcGFyYW0ge3N0cmluZ30gZmlsZW5hbWUgLSBTb3VyY2UgZmlsZW5hbWUuXG4gKiBAcGFyYW0ge3N0cmluZ30gc291cmNlIC0gQ29tcGxldGUgc291cmNlLlxuICogQHJldHVybnMge3tpbW11dGFibGU6IGJvb2xlYW4sIHR5cGU6IGltcG9ydChcIi4uL3NlbWFudGljL3R5cGVzLmpzXCIpLlR5cGVSZWZlcmVuY2V9IHwgdW5kZWZpbmVkfSBNZXRhZGF0YSB3aGVuIHByZXNlbnQuXG4gKi9cbmZ1bmN0aW9uIGxvY2FsTWV0YWRhdGEoY29tbWVudHMsIG5vZGUsIGZpbGVuYW1lLCBzb3VyY2UpIHtcbiAgY29uc3QgYXNzb2NpYXRlZCA9IGFzc29jaWF0ZWRDb21tZW50cyhjb21tZW50cywgbm9kZSwgc291cmNlKVxuICBjb25zdCBtZXRhZGF0YSA9IGFzc29jaWF0ZWQubWFwKChjb21tZW50KSA9PiBjb21tZW50VG9rZW5zKGNvbW1lbnQsIGZpbGVuYW1lLCBzb3VyY2UpKVxuICBjb25zdCB0eXBlTWV0YWRhdGEgPSBtZXRhZGF0YS5maWx0ZXIoKFt0b2tlbl0pID0+IHRva2VuPy50ZXh0ID09IFwiQHR5cGVcIilcbiAgY29uc3QgaW1tdXRhYmxlTWV0YWRhdGEgPSBtZXRhZGF0YS5maWx0ZXIoKFt0b2tlbl0pID0+IHRva2VuPy50ZXh0ID09IFwiQHNlbWFudGlmb2xkLWltbXV0YWJsZVwiKVxuICBjb25zdCBwcm9maWxlTWV0YWRhdGEgPSBtZXRhZGF0YS5maWx0ZXIoKFt0b2tlbl0pID0+IHtcbiAgICByZXR1cm4gdG9rZW4/LnRleHQuc3RhcnRzV2l0aChcIkB0eXBlXCIpIHx8IHRva2VuPy50ZXh0LnN0YXJ0c1dpdGgoXCJAc2VtYW50aWZvbGQtaW1tdXRhYmxlXCIpXG4gIH0pXG5cbiAgaWYgKHByb2ZpbGVNZXRhZGF0YS5sZW5ndGggPT0gMCkgcmV0dXJuIHVuZGVmaW5lZFxuXG4gIGNvbnN0IGxvY2F0aW9uID0gbm9kZUxvY2F0aW9uKG5vZGUsIGZpbGVuYW1lLCBzb3VyY2UpXG5cbiAgaWYgKHR5cGVNZXRhZGF0YS5sZW5ndGggIT0gMSB8fCB0eXBlTWV0YWRhdGFbMF0ubGVuZ3RoICE9IDIgfHxcbiAgICBpbW11dGFibGVNZXRhZGF0YS5sZW5ndGggPiAxIHx8IGltbXV0YWJsZU1ldGFkYXRhLnNvbWUoKHRva2VucykgPT4gdG9rZW5zLmxlbmd0aCAhPSAxKSB8fFxuICAgIHByb2ZpbGVNZXRhZGF0YS5sZW5ndGggIT0gdHlwZU1ldGFkYXRhLmxlbmd0aCArIGltbXV0YWJsZU1ldGFkYXRhLmxlbmd0aCkge1xuICAgIHJldHVybiB1bnN1cHBvcnRlZFN5bnRheChcInJ1YnlcIiwgXCJtYWxmb3JtZWQgbG9jYWwgdHlwZSBtZXRhZGF0YVwiLCBsb2NhdGlvbilcbiAgfVxuXG4gIHJldHVybiB7XG4gICAgaW1tdXRhYmxlOiBpbW11dGFibGVNZXRhZGF0YS5sZW5ndGggPT0gMSxcbiAgICB0eXBlOiBjb252ZXJ0VHlwZSh0eXBlTWV0YWRhdGFbMF1bMV0udGV4dCwgYExvY2FsICcke25vZGUubmFtZX0nYCwgbG9jYXRpb24sIHR5cGVNZXRhZGF0YVswXVsxXS5sb2NhdGlvbilcbiAgfVxufVxuXG4vKipcbiAqIENvbnZlcnRzIG9uZSBSdWJ5IGxvY2FsIGRlY2xhcmF0aW9uIG9yIGFzc2lnbm1lbnQuXG4gKiBAcGFyYW0ge2ltcG9ydChcIkBydWJ5L3ByaXNtXCIpLk5vZGV9IG5vZGUgLSBQcmlzbSBub2RlLlxuICogQHBhcmFtIHtpbXBvcnQoXCJAcnVieS9wcmlzbS9zcmMvZGVzZXJpYWxpemUuanNcIikuQ29tbWVudFtdfSBjb21tZW50cyAtIFByaXNtIGNvbW1lbnRzLlxuICogQHBhcmFtIHtTZXQ8c3RyaW5nPn0gdmlzaWJsZSAtIE5hbWVzIHZpc2libGUgZHVyaW5nIGFkYXB0YXRpb24uXG4gKiBAcGFyYW0ge3N0cmluZ30gZmlsZW5hbWUgLSBTb3VyY2UgZmlsZW5hbWUuXG4gKiBAcGFyYW0ge3N0cmluZ30gc291cmNlIC0gQ29tcGxldGUgc291cmNlLlxuICogQHJldHVybnMge2ltcG9ydChcIi4uL3NlbWFudGljL3R5cGVzLmpzXCIpLkxvY2FsU3RhdGVtZW50fSBTZW1hbnRpYyBsb2NhbCBzdGF0ZW1lbnQuXG4gKi9cbmZ1bmN0aW9uIGNvbnZlcnRMb2NhbFN0YXRlbWVudChub2RlLCBjb21tZW50cywgdmlzaWJsZSwgZmlsZW5hbWUsIHNvdXJjZSkge1xuICBjb25zdCBsb2NhdGlvbiA9IG5vZGVMb2NhdGlvbihub2RlLCBmaWxlbmFtZSwgc291cmNlKVxuXG4gIGlmICghKG5vZGUgaW5zdGFuY2VvZiBMb2NhbFZhcmlhYmxlV3JpdGVOb2RlKSkgcmV0dXJuIHVuc3VwcG9ydGVkU3ludGF4KFwicnVieVwiLCBub2RlLmNvbnN0cnVjdG9yLm5hbWUsIGxvY2F0aW9uKVxuXG4gIGNvbnN0IG1ldGFkYXRhID0gbG9jYWxNZXRhZGF0YShjb21tZW50cywgbm9kZSwgZmlsZW5hbWUsIHNvdXJjZSlcblxuICBpZiAobWV0YWRhdGEpIHtcbiAgICB2aXNpYmxlLmFkZChub2RlLm5hbWUpXG4gICAgcmV0dXJuIHdpdGhQYXJzZXJSYW5nZXMoe1xuICAgICAgaW5pdGlhbGl6ZXI6IGNvbnZlcnRFeHByZXNzaW9uKG5vZGUudmFsdWUsIGZpbGVuYW1lLCBzb3VyY2UpLFxuICAgICAga2luZDogXCJMb2NhbERlY2xhcmF0aW9uXCIsXG4gICAgICBsb2NhdGlvbixcbiAgICAgIG11dGFibGU6ICFtZXRhZGF0YS5pbW11dGFibGUsXG4gICAgICBuYW1lOiBub2RlLm5hbWUsXG4gICAgICB0eXBlOiBtZXRhZGF0YS50eXBlXG4gICAgfSwge25hbWU6IHByaXNtTG9jYXRpb24obm9kZS5uYW1lTG9jLCBmaWxlbmFtZSwgc291cmNlKSwgb3BlcmF0b3I6IHByaXNtTG9jYXRpb24obm9kZS5vcGVyYXRvckxvYywgZmlsZW5hbWUsIHNvdXJjZSl9KVxuICB9XG5cbiAgaWYgKCF2aXNpYmxlLmhhcyhub2RlLm5hbWUpKSByZXR1cm4gbWlzc2luZ1R5cGUoXCJydWJ5XCIsIGBMb2NhbCAnJHtub2RlLm5hbWV9J2AsIGxvY2F0aW9uKVxuXG4gIGNvbnN0IHRhcmdldExvY2F0aW9uID0gcHJpc21Mb2NhdGlvbihub2RlLm5hbWVMb2MsIGZpbGVuYW1lLCBzb3VyY2UpXG4gIGNvbnN0IHRhcmdldCA9IHdpdGhQYXJzZXJSYW5nZXMoe2tpbmQ6IC8qKiBAdHlwZSB7Y29uc3R9ICovIChcIklkZW50aWZpZXJFeHByZXNzaW9uXCIpLCBsb2NhdGlvbjogdGFyZ2V0TG9jYXRpb24sIG5hbWU6IG5vZGUubmFtZX0sIHtcbiAgICBuYW1lOiB0YXJnZXRMb2NhdGlvblxuICB9KVxuXG4gIHJldHVybiB3aXRoUGFyc2VyUmFuZ2VzKHtcbiAgICBleHByZXNzaW9uOiBjb252ZXJ0RXhwcmVzc2lvbihub2RlLnZhbHVlLCBmaWxlbmFtZSwgc291cmNlKSxcbiAgICBraW5kOiBcIkFzc2lnbm1lbnRTdGF0ZW1lbnRcIixcbiAgICBsb2NhdGlvbixcbiAgICB0YXJnZXRcbiAgfSwge29wZXJhdG9yOiBwcmlzbUxvY2F0aW9uKG5vZGUub3BlcmF0b3JMb2MsIGZpbGVuYW1lLCBzb3VyY2UpfSlcbn1cblxuLyoqXG4gKiBDb252ZXJ0cyBvbmUgZXhoYXVzdGl2ZSBQcmlzbSBzdGF0ZW1lbnQuXG4gKiBAcGFyYW0ge2ltcG9ydChcIkBydWJ5L3ByaXNtXCIpLk5vZGV9IG5vZGUgLSBQcmlzbSBzdGF0ZW1lbnQuXG4gKiBAcGFyYW0ge2ltcG9ydChcIkBydWJ5L3ByaXNtL3NyYy9kZXNlcmlhbGl6ZS5qc1wiKS5Db21tZW50W119IGNvbW1lbnRzIC0gUHJpc20gY29tbWVudHMuXG4gKiBAcGFyYW0ge1NldDxzdHJpbmc+fSB2aXNpYmxlIC0gTmFtZXMgdmlzaWJsZSBkdXJpbmcgYWRhcHRhdGlvbi5cbiAqIEBwYXJhbSB7c3RyaW5nfSBmaWxlbmFtZSAtIFNvdXJjZSBmaWxlbmFtZS5cbiAqIEBwYXJhbSB7c3RyaW5nfSBzb3VyY2UgLSBDb21wbGV0ZSBzb3VyY2UuXG4gKiBAcmV0dXJucyB7aW1wb3J0KFwiLi4vc2VtYW50aWMvdHlwZXMuanNcIikuU3RhdGVtZW50fSBTZW1hbnRpYyBzdGF0ZW1lbnQuXG4gKi9cbmZ1bmN0aW9uIGNvbnZlcnRTdGF0ZW1lbnQobm9kZSwgY29tbWVudHMsIHZpc2libGUsIGZpbGVuYW1lLCBzb3VyY2UpIHtcbiAgaWYgKG5vZGUgaW5zdGFuY2VvZiBSZXR1cm5Ob2RlKSByZXR1cm4gY29udmVydFJldHVybihub2RlLCBmaWxlbmFtZSwgc291cmNlKVxuICBpZiAobm9kZSBpbnN0YW5jZW9mIElmTm9kZSkgcmV0dXJuIGNvbnZlcnRJZihub2RlLCBjb21tZW50cywgdmlzaWJsZSwgZmlsZW5hbWUsIHNvdXJjZSlcbiAgaWYgKG5vZGUgaW5zdGFuY2VvZiBMb2NhbFZhcmlhYmxlV3JpdGVOb2RlKSByZXR1cm4gY29udmVydExvY2FsU3RhdGVtZW50KG5vZGUsIGNvbW1lbnRzLCB2aXNpYmxlLCBmaWxlbmFtZSwgc291cmNlKVxuICBpZiAobm9kZSBpbnN0YW5jZW9mIENhbGxOb2RlKSByZXR1cm4gY29udmVydFByaW50KG5vZGUsIGZpbGVuYW1lLCBzb3VyY2UpXG5cbiAgcmV0dXJuIHVuc3VwcG9ydGVkU3ludGF4KFwicnVieVwiLCBub2RlLmNvbnN0cnVjdG9yLm5hbWUsIG5vZGVMb2NhdGlvbihub2RlLCBmaWxlbmFtZSwgc291cmNlKSlcbn1cblxuLyoqXG4gKiBDb252ZXJ0cyBvbmUgb3JkZXJlZCBQcmlzbSBzdGF0ZW1lbnQgbGlzdC5cbiAqIEBwYXJhbSB7U3RhdGVtZW50c05vZGUgfCBudWxsfSBub2RlIC0gUHJpc20gc3RhdGVtZW50cywgb3IgYW4gZW1wdHkgc291cmNlIGJsb2NrLlxuICogQHBhcmFtIHtpbXBvcnQoXCJAcnVieS9wcmlzbS9zcmMvZGVzZXJpYWxpemUuanNcIikuQ29tbWVudFtdfSBjb21tZW50cyAtIFByaXNtIGNvbW1lbnRzLlxuICogQHBhcmFtIHtTZXQ8c3RyaW5nPn0gdmlzaWJsZSAtIE5hbWVzIHZpc2libGUgb24gYmxvY2sgZW50cnkuXG4gKiBAcGFyYW0ge3N0cmluZ30gZmlsZW5hbWUgLSBTb3VyY2UgZmlsZW5hbWUuXG4gKiBAcGFyYW0ge3N0cmluZ30gc291cmNlIC0gQ29tcGxldGUgc291cmNlLlxuICogQHBhcmFtIHtpbXBvcnQoXCIuLi9zZW1hbnRpYy90eXBlcy5qc1wiKS5Tb3VyY2VMb2NhdGlvbn0gZmFsbGJhY2tMb2NhdGlvbiAtIEVtcHR5IGJsb2NrIGxvY2F0aW9uLlxuICogQHJldHVybnMge2ltcG9ydChcIi4uL3NlbWFudGljL3R5cGVzLmpzXCIpLkJsb2NrfSBTZW1hbnRpYyBibG9jay5cbiAqL1xuZnVuY3Rpb24gY29udmVydEJsb2NrKG5vZGUsIGNvbW1lbnRzLCB2aXNpYmxlLCBmaWxlbmFtZSwgc291cmNlLCBmYWxsYmFja0xvY2F0aW9uKSB7XG4gIHJldHVybiB7XG4gICAga2luZDogXCJCbG9ja1wiLFxuICAgIGxvY2F0aW9uOiBub2RlID8gbm9kZUxvY2F0aW9uKG5vZGUsIGZpbGVuYW1lLCBzb3VyY2UpIDogZmFsbGJhY2tMb2NhdGlvbixcbiAgICBzdGF0ZW1lbnRzOiBub2RlID8gbm9kZS5ib2R5Lm1hcCgoc3RhdGVtZW50KSA9PiBjb252ZXJ0U3RhdGVtZW50KHN0YXRlbWVudCwgY29tbWVudHMsIHZpc2libGUsIGZpbGVuYW1lLCBzb3VyY2UpKSA6IFtdXG4gIH1cbn1cblxuLyoqXG4gKiBDaGVja3MgdGhhdCBhIGNvbW1lbnQgYW5kIGl0cyBvd25lciBhcmUgc2VwYXJhdGVkIGJ5IGF0IG1vc3Qgb25lIG5ld2xpbmUuXG4gKiBAcGFyYW0ge3N0cmluZ30gZ2FwIC0gU291cmNlIGJldHdlZW4gdGhlIGNvbW1lbnQgYW5kIGZvbGxvd2luZyBpdGVtLlxuICogQHJldHVybnMge2Jvb2xlYW59IFdoZXRoZXIgdGhlIGdhcCBpcyBpbW1lZGlhdGUgd2hpdGVzcGFjZS5cbiAqL1xuZnVuY3Rpb24gaXNJbW1lZGlhdGVDb21tZW50R2FwKGdhcCkge1xuICBsZXQgbmV3bGluZXMgPSAwXG5cbiAgZm9yIChjb25zdCBjaGFyYWN0ZXIgb2YgZ2FwKSB7XG4gICAgaWYgKGNoYXJhY3RlciA9PSBcIlxcblwiKSB7XG4gICAgICBuZXdsaW5lcysrXG4gICAgfSBlbHNlIGlmIChjaGFyYWN0ZXIgIT0gXCIgXCIgJiYgY2hhcmFjdGVyICE9IFwiXFx0XCIgJiYgY2hhcmFjdGVyICE9IFwiXFxyXCIpIHtcbiAgICAgIHJldHVybiBmYWxzZVxuICAgIH1cbiAgfVxuXG4gIHJldHVybiBuZXdsaW5lcyA8PSAxXG59XG5cbi8qKlxuICogUmVxdWlyZXMgYW4gZXhhY3Qgc3VwcG9ydGVkIFJ1Ynkgc2NhbGFyIHNwZWxsaW5nLlxuICogQHBhcmFtIHtzdHJpbmcgfCB1bmRlZmluZWR9IHNvdXJjZVR5cGUgLSBSdWJ5IHR5cGUgY29tbWVudCB2YWx1ZS5cbiAqIEBwYXJhbSB7c3RyaW5nfSBzdWJqZWN0IC0gVHlwZWQgc3ViamVjdC5cbiAqIEBwYXJhbSB7aW1wb3J0KFwiLi4vc2VtYW50aWMvdHlwZXMuanNcIikuU291cmNlTG9jYXRpb259IGxvY2F0aW9uIC0gU291cmNlIGxvY2F0aW9uLlxuICogQHBhcmFtIHtpbXBvcnQoXCIuLi9zZW1hbnRpYy90eXBlcy5qc1wiKS5Tb3VyY2VMb2NhdGlvbn0gW3R5cGVMb2NhdGlvbl0gLSBFeGFjdCB0eXBlIGNvbW1lbnQgdG9rZW4gbG9jYXRpb24uXG4gKiBAcmV0dXJucyB7aW1wb3J0KFwiLi4vc2VtYW50aWMvdHlwZXMuanNcIikuVHlwZVJlZmVyZW5jZX0gU2VtYW50aWMgdHlwZS5cbiAqL1xuZnVuY3Rpb24gY29udmVydFR5cGUoc291cmNlVHlwZSwgc3ViamVjdCwgbG9jYXRpb24sIHR5cGVMb2NhdGlvbiA9IGxvY2F0aW9uKSB7XG4gIHJldHVybiByZXF1aXJlU291cmNlU2NhbGFyVHlwZShcInJ1YnlcIiwgc291cmNlVHlwZSwgc3ViamVjdCwgbG9jYXRpb24sIHR5cGVMb2NhdGlvbilcbn1cblxuLyoqXG4gKiBDb252ZXJ0cyBhIFJ1YnkgZGVmaW5pdGlvbi5cbiAqIEBwYXJhbSB7RGVmTm9kZX0gbm9kZSAtIFByaXNtIGRlZmluaXRpb24uXG4gKiBAcGFyYW0ge2ltcG9ydChcIkBydWJ5L3ByaXNtL3NyYy9kZXNlcmlhbGl6ZS5qc1wiKS5Db21tZW50W119IGNvbW1lbnRzIC0gUHJpc20gY29tbWVudHMuXG4gKiBAcGFyYW0ge3N0cmluZ30gZmlsZW5hbWUgLSBTb3VyY2UgZmlsZW5hbWUuXG4gKiBAcGFyYW0ge3N0cmluZ30gc291cmNlIC0gQ29tcGxldGUgc291cmNlLlxuICogQHJldHVybnMge2ltcG9ydChcIi4uL3NlbWFudGljL3R5cGVzLmpzXCIpLkZ1bmN0aW9uRGVjbGFyYXRpb259IFNlbWFudGljIGZ1bmN0aW9uLlxuICovXG5mdW5jdGlvbiBjb252ZXJ0RnVuY3Rpb24obm9kZSwgY29tbWVudHMsIGZpbGVuYW1lLCBzb3VyY2UpIHtcbiAgY29uc3QgbG9jYXRpb24gPSBub2RlTG9jYXRpb24obm9kZSwgZmlsZW5hbWUsIHNvdXJjZSlcblxuICBpZiAoIW5vZGUucGFyYW1ldGVycyB8fCBub2RlLnBhcmFtZXRlcnMub3B0aW9uYWxzLmxlbmd0aCA+IDAgfHwgbm9kZS5wYXJhbWV0ZXJzLnJlc3QgfHwgbm9kZS5wYXJhbWV0ZXJzLnBvc3RzLmxlbmd0aCA+IDAgfHxcbiAgICBub2RlLnBhcmFtZXRlcnMua2V5d29yZHMubGVuZ3RoID4gMCB8fCBub2RlLnBhcmFtZXRlcnMua2V5d29yZFJlc3QgfHwgbm9kZS5wYXJhbWV0ZXJzLmJsb2NrIHx8XG4gICAgbm9kZS5wYXJhbWV0ZXJzLnJlcXVpcmVkcy5zb21lKChwYXJhbWV0ZXIpID0+ICEocGFyYW1ldGVyIGluc3RhbmNlb2YgUmVxdWlyZWRQYXJhbWV0ZXJOb2RlKSkpIHtcbiAgICByZXR1cm4gdW5zdXBwb3J0ZWRTeW50YXgoXCJydWJ5XCIsIFwicGFyYW1ldGVyc1wiLCBsb2NhdGlvbilcbiAgfVxuXG4gIGNvbnN0IGRlY2xhcmVkVHlwZXMgPSB0eXBlQ29tbWVudHMoY29tbWVudHMsIG5vZGUsIGZpbGVuYW1lLCBzb3VyY2UpXG4gIGNvbnN0IHBhcmFtZXRlcnMgPSBub2RlLnBhcmFtZXRlcnMucmVxdWlyZWRzLm1hcCgocGFyYW1ldGVyKSA9PiB7XG4gICAgaWYgKCEocGFyYW1ldGVyIGluc3RhbmNlb2YgUmVxdWlyZWRQYXJhbWV0ZXJOb2RlKSkgcmV0dXJuIHVuc3VwcG9ydGVkU3ludGF4KFwicnVieVwiLCBwYXJhbWV0ZXIuY29uc3RydWN0b3IubmFtZSwgbG9jYXRpb24pXG5cbiAgICBjb25zdCBwYXJhbWV0ZXJMb2NhdGlvbiA9IG5vZGVMb2NhdGlvbihwYXJhbWV0ZXIsIGZpbGVuYW1lLCBzb3VyY2UpXG5cbiAgICBjb25zdCBkZWNsYXJlZFR5cGUgPSBkZWNsYXJlZFR5cGVzLnBhcmFtZXRlcnMuZ2V0KHBhcmFtZXRlci5uYW1lKVxuXG4gICAgcmV0dXJuIHdpdGhQYXJzZXJSYW5nZXMoe1xuICAgICAga2luZDogLyoqIEB0eXBlIHtjb25zdH0gKi8gKFwiUGFyYW1ldGVyXCIpLFxuICAgICAgbG9jYXRpb246IHBhcmFtZXRlckxvY2F0aW9uLFxuICAgICAgbmFtZTogcGFyYW1ldGVyLm5hbWUsXG4gICAgICB0eXBlOiBjb252ZXJ0VHlwZShkZWNsYXJlZFR5cGU/LnNvdXJjZVR5cGUsIGBQYXJhbWV0ZXIgJyR7cGFyYW1ldGVyLm5hbWV9J2AsIHBhcmFtZXRlckxvY2F0aW9uLCBkZWNsYXJlZFR5cGU/LmxvY2F0aW9uKVxuICAgIH0sIHtuYW1lOiBwYXJhbWV0ZXJMb2NhdGlvbn0pXG4gIH0pXG4gIGNvbnN0IHZpc2libGUgPSBuZXcgU2V0KHBhcmFtZXRlcnMubWFwKChwYXJhbWV0ZXIpID0+IHBhcmFtZXRlci5uYW1lKSlcbiAgY29uc3QgYm9keSA9IGNvbnZlcnRCbG9jayhub2RlLmJvZHkgaW5zdGFuY2VvZiBTdGF0ZW1lbnRzTm9kZSA/IG5vZGUuYm9keSA6IG51bGwsIGNvbW1lbnRzLCB2aXNpYmxlLCBmaWxlbmFtZSwgc291cmNlLCBsb2NhdGlvbilcblxuICByZXR1cm4gd2l0aFBhcnNlclJhbmdlcyh7XG4gICAgYm9keSxcbiAgICBraW5kOiBcIkZ1bmN0aW9uRGVjbGFyYXRpb25cIixcbiAgICBsb2NhdGlvbixcbiAgICBuYW1lOiBub2RlLm5hbWUsXG4gICAgcGFyYW1ldGVycyxcbiAgICByZXR1cm5UeXBlOiBjb252ZXJ0VHlwZShkZWNsYXJlZFR5cGVzLnJldHVyblR5cGU/LnNvdXJjZVR5cGUsIGBGdW5jdGlvbiAnJHtub2RlLm5hbWV9JyByZXR1cm5gLCBsb2NhdGlvbiwgZGVjbGFyZWRUeXBlcy5yZXR1cm5UeXBlPy5sb2NhdGlvbilcbiAgfSwge25hbWU6IHByaXNtTG9jYXRpb24obm9kZS5uYW1lTG9jLCBmaWxlbmFtZSwgc291cmNlKX0pXG59XG5cbi8qKlxuICogQ29udmVydHMgdGhlIGV4aXN0aW5nIFJ1YnkgaWYvZWxzZSB0ZXJtaW5hbCB3aXRoIHJlc3RyaWN0ZWQgYnJhbmNoIHByZWZpeGVzLlxuICogQHBhcmFtIHtJZk5vZGV9IG5vZGUgLSBQcmlzbSBpZiBub2RlLlxuICogQHBhcmFtIHtpbXBvcnQoXCJAcnVieS9wcmlzbS9zcmMvZGVzZXJpYWxpemUuanNcIikuQ29tbWVudFtdfSBjb21tZW50cyAtIFByaXNtIGNvbW1lbnRzLlxuICogQHBhcmFtIHtTZXQ8c3RyaW5nPn0gdmlzaWJsZSAtIEVuY2xvc2luZyB2aXNpYmxlIG5hbWVzLlxuICogQHBhcmFtIHtzdHJpbmd9IGZpbGVuYW1lIC0gU291cmNlIGZpbGVuYW1lLlxuICogQHBhcmFtIHtzdHJpbmd9IHNvdXJjZSAtIENvbXBsZXRlIHNvdXJjZS5cbiAqIEByZXR1cm5zIHtpbXBvcnQoXCIuLi9zZW1hbnRpYy90eXBlcy5qc1wiKS5JZlN0YXRlbWVudH0gU2VtYW50aWMgYnJhbmNoLlxuICovXG5mdW5jdGlvbiBjb252ZXJ0SWYobm9kZSwgY29tbWVudHMsIHZpc2libGUsIGZpbGVuYW1lLCBzb3VyY2UpIHtcbiAgY29uc3QgbG9jYXRpb24gPSBub2RlTG9jYXRpb24obm9kZSwgZmlsZW5hbWUsIHNvdXJjZSlcblxuICBpZiAoIW5vZGUuaWZLZXl3b3JkTG9jIHx8IG5vZGUuaWZLZXl3b3JkTG9jLnN0YXJ0T2Zmc2V0ICE9IG5vZGUubG9jYXRpb24uc3RhcnRPZmZzZXQpIHtcbiAgICByZXR1cm4gdW5zdXBwb3J0ZWRTeW50YXgoXCJydWJ5XCIsIFwibW9kaWZpZXIgY29uZGl0aW9uYWxcIiwgbm9kZS5pZktleXdvcmRMb2NcbiAgICAgID8gcHJpc21Mb2NhdGlvbihub2RlLmlmS2V5d29yZExvYywgZmlsZW5hbWUsIHNvdXJjZSlcbiAgICAgIDogbG9jYXRpb24pXG4gIH1cblxuICBjb25zdCBjb25zZXF1ZW50VmlzaWJsZSA9IG5ldyBTZXQodmlzaWJsZSlcbiAgbGV0IGFsdGVybmF0ZVxuXG4gIGlmIChub2RlLnN1YnNlcXVlbnQpIHtcbiAgICBjb25zdCBhbHRlcm5hdGVWaXNpYmxlID0gbmV3IFNldCh2aXNpYmxlKVxuXG4gICAgaWYgKG5vZGUuc3Vic2VxdWVudCBpbnN0YW5jZW9mIEVsc2VOb2RlKSB7XG4gICAgICBhbHRlcm5hdGUgPSBjb252ZXJ0QmxvY2sobm9kZS5zdWJzZXF1ZW50LnN0YXRlbWVudHMsIGNvbW1lbnRzLCBhbHRlcm5hdGVWaXNpYmxlLCBmaWxlbmFtZSwgc291cmNlLFxuICAgICAgICBub2RlTG9jYXRpb24obm9kZS5zdWJzZXF1ZW50LCBmaWxlbmFtZSwgc291cmNlKSlcbiAgICB9IGVsc2UgaWYgKG5vZGUuc3Vic2VxdWVudCBpbnN0YW5jZW9mIElmTm9kZSkge1xuICAgICAgYWx0ZXJuYXRlID0ge1xuICAgICAgICBraW5kOiAvKiogQHR5cGUge2NvbnN0fSAqLyAoXCJCbG9ja1wiKSxcbiAgICAgICAgbG9jYXRpb246IG5vZGVMb2NhdGlvbihub2RlLnN1YnNlcXVlbnQsIGZpbGVuYW1lLCBzb3VyY2UpLFxuICAgICAgICBzdGF0ZW1lbnRzOiBbY29udmVydElmKG5vZGUuc3Vic2VxdWVudCwgY29tbWVudHMsIGFsdGVybmF0ZVZpc2libGUsIGZpbGVuYW1lLCBzb3VyY2UpXVxuICAgICAgfVxuICAgIH0gZWxzZSByZXR1cm4gdW5zdXBwb3J0ZWRTeW50YXgoXCJydWJ5XCIsIG5vZGUuc3Vic2VxdWVudC5jb25zdHJ1Y3Rvci5uYW1lLCBub2RlTG9jYXRpb24obm9kZS5zdWJzZXF1ZW50LCBmaWxlbmFtZSwgc291cmNlKSlcbiAgfVxuXG4gIHJldHVybiB7XG4gICAgLi4uKGFsdGVybmF0ZSA/IHthbHRlcm5hdGV9IDoge30pLFxuICAgIGNvbmRpdGlvbjogY29udmVydEV4cHJlc3Npb24obm9kZS5wcmVkaWNhdGUsIGZpbGVuYW1lLCBzb3VyY2UpLFxuICAgIGNvbnNlcXVlbnQ6IGNvbnZlcnRCbG9jayhub2RlLnN0YXRlbWVudHMsIGNvbW1lbnRzLCBjb25zZXF1ZW50VmlzaWJsZSwgZmlsZW5hbWUsIHNvdXJjZSwgbG9jYXRpb24pLFxuICAgIGtpbmQ6IFwiSWZTdGF0ZW1lbnRcIixcbiAgICBsb2NhdGlvblxuICB9XG59XG5cbi8qKlxuICogQ29udmVydHMgdGhlIHN1cHBvcnRlZCBSdWJ5IHB1dHMgZW50cnkgcG9pbnQuXG4gKiBAcGFyYW0ge2ltcG9ydChcIkBydWJ5L3ByaXNtXCIpLk5vZGV9IG5vZGUgLSBQcmlzbSBub2RlLlxuICogQHBhcmFtIHtzdHJpbmd9IGZpbGVuYW1lIC0gU291cmNlIGZpbGVuYW1lLlxuICogQHBhcmFtIHtzdHJpbmd9IHNvdXJjZSAtIENvbXBsZXRlIHNvdXJjZS5cbiAqIEByZXR1cm5zIHtpbXBvcnQoXCIuLi9zZW1hbnRpYy90eXBlcy5qc1wiKS5QcmludFN0YXRlbWVudH0gUHJpbnQgc3RhdGVtZW50LlxuICovXG5mdW5jdGlvbiBjb252ZXJ0UHJpbnQobm9kZSwgZmlsZW5hbWUsIHNvdXJjZSkge1xuICBjb25zdCBsb2NhdGlvbiA9IG5vZGVMb2NhdGlvbihub2RlLCBmaWxlbmFtZSwgc291cmNlKVxuXG4gIGlmICghKG5vZGUgaW5zdGFuY2VvZiBDYWxsTm9kZSkgfHwgbm9kZS5yZWNlaXZlciB8fCBub2RlLm5hbWUgIT0gXCJwdXRzXCIgfHwgbm9kZS5hcmd1bWVudHNfPy5hcmd1bWVudHNfLmxlbmd0aCAhPSAxKSB7XG4gICAgcmV0dXJuIHVuc3VwcG9ydGVkU3ludGF4KFwicnVieVwiLCBub2RlLmNvbnN0cnVjdG9yLm5hbWUsIGxvY2F0aW9uKVxuICB9XG5cbiAgcmV0dXJuIHtleHByZXNzaW9uOiBjb252ZXJ0RXhwcmVzc2lvbihub2RlLmFyZ3VtZW50c18uYXJndW1lbnRzX1swXSwgZmlsZW5hbWUsIHNvdXJjZSksIGtpbmQ6IFwiUHJpbnRTdGF0ZW1lbnRcIiwgbG9jYXRpb259XG59XG5cbi8qKlxuICogUGFyc2VzIFJ1YnkgaW50byB0aGUgc2hhcmVkIHNlbWFudGljIG1vZHVsZS5cbiAqIEBwYXJhbSB7b2JqZWN0fSBpbnB1dCAtIFBhcnNlciBpbnB1dC5cbiAqIEBwYXJhbSB7c3RyaW5nfSBpbnB1dC5maWxlbmFtZSAtIFNvdXJjZSBmaWxlbmFtZS5cbiAqIEBwYXJhbSB7c3RyaW5nfSBpbnB1dC5zb3VyY2UgLSBTb3VyY2UgdGV4dC5cbiAqIEByZXR1cm5zIHtpbXBvcnQoXCIuLi9zZW1hbnRpYy90eXBlcy5qc1wiKS5TZW1hbnRpY01vZHVsZX0gU2VtYW50aWMgbW9kdWxlLlxuICovXG5leHBvcnQgZnVuY3Rpb24gcGFyc2VSdWJ5KHtmaWxlbmFtZSwgc291cmNlfSkge1xuICBjb25zdCByZXN1bHQgPSBwYXJzZVByaXNtKHNvdXJjZSwge2ZpbGVwYXRoOiBmaWxlbmFtZX0pXG5cbiAgaWYgKHJlc3VsdC5lcnJvcnMubGVuZ3RoID4gMCkge1xuICAgIGNvbnN0IGVycm9yID0gcmVzdWx0LmVycm9yc1swXVxuICAgIGNvbnN0IGxvY2F0aW9uID0gbG9jYXRpb25Gcm9tT2Zmc2V0cyhmaWxlbmFtZSwgc291cmNlLCBlcnJvci5sb2NhdGlvbi5zdGFydE9mZnNldCwgZXJyb3IubG9jYXRpb24uc3RhcnRPZmZzZXQgKyBlcnJvci5sb2NhdGlvbi5sZW5ndGgpXG5cbiAgICB0aHJvdyBuZXcgU2VtYW50aWZvbGREaWFnbm9zdGljKHtjb2RlOiBcIlBBUlNFX0VSUk9SXCIsIGxhbmd1YWdlOiBcInJ1YnlcIiwgbG9jYXRpb24sIG1lc3NhZ2U6IGVycm9yLm1lc3NhZ2V9KVxuICB9XG5cbiAgaWYgKCEocmVzdWx0LnZhbHVlIGluc3RhbmNlb2YgUHJvZ3JhbU5vZGUpKSB0aHJvdyBuZXcgRXJyb3IoXCJQcmlzbSByZXR1cm5lZCBhIG5vbi1wcm9ncmFtIHJvb3QuXCIpXG5cbiAgY29uc3QgYm9keSA9IHJlc3VsdC52YWx1ZS5zdGF0ZW1lbnRzLmJvZHlcbiAgY29uc3QgZnVuY3Rpb25zID0gYm9keS5maWx0ZXIoKG5vZGUpID0+IG5vZGUgaW5zdGFuY2VvZiBEZWZOb2RlKVxuICAgIC5tYXAoKG5vZGUpID0+IGNvbnZlcnRGdW5jdGlvbihub2RlLCByZXN1bHQuY29tbWVudHMsIGZpbGVuYW1lLCBzb3VyY2UpKVxuICBjb25zdCBlbnRyeU5vZGVzID0gYm9keS5maWx0ZXIoKG5vZGUpID0+ICEobm9kZSBpbnN0YW5jZW9mIERlZk5vZGUpKVxuICBjb25zdCBsb2NhdGlvbiA9IG1vZHVsZUxvY2F0aW9uKGZpbGVuYW1lLCBzb3VyY2UpXG5cbiAgaWYgKGZ1bmN0aW9ucy5sZW5ndGggPT0gMCkgcmV0dXJuIHVuc3VwcG9ydGVkU3ludGF4KFwicnVieVwiLCBcIm1vZHVsZSB3aXRob3V0IGEgZnVuY3Rpb25cIiwgbG9jYXRpb24pXG4gIGNvbnN0IGZpcnN0RW50cnkgPSBlbnRyeU5vZGVzWzBdXG4gIGNvbnN0IGVudHJ5TG9jYXRpb24gPSBmaXJzdEVudHJ5ID8gbG9jYXRpb25Gcm9tT2Zmc2V0cyhcbiAgICBmaWxlbmFtZSxcbiAgICBzb3VyY2UsXG4gICAgdXRmOEJ5dGVPZmZzZXRUb1V0ZjE2T2Zmc2V0KHNvdXJjZSwgZmlyc3RFbnRyeS5sb2NhdGlvbi5zdGFydE9mZnNldCksXG4gICAgdXRmOEJ5dGVPZmZzZXRUb1V0ZjE2T2Zmc2V0KFxuICAgICAgc291cmNlLFxuICAgICAgKGVudHJ5Tm9kZXMuYXQoLTEpPy5sb2NhdGlvbi5zdGFydE9mZnNldCA/PyAwKSArIChlbnRyeU5vZGVzLmF0KC0xKT8ubG9jYXRpb24ubGVuZ3RoID8/IDApXG4gICAgKVxuICApIDogbG9jYXRpb25cbiAgY29uc3QgZW50cnlWaXNpYmxlID0gbmV3IFNldCgpXG4gIGNvbnN0IGVudHJ5QmxvY2sgPSB7XG4gICAga2luZDogLyoqIEB0eXBlIHtjb25zdH0gKi8gKFwiQmxvY2tcIiksXG4gICAgbG9jYXRpb246IGVudHJ5TG9jYXRpb24sXG4gICAgc3RhdGVtZW50czogZW50cnlOb2Rlcy5tYXAoKHN0YXRlbWVudCkgPT4gY29udmVydFN0YXRlbWVudChzdGF0ZW1lbnQsIHJlc3VsdC5jb21tZW50cywgZW50cnlWaXNpYmxlLCBmaWxlbmFtZSwgc291cmNlKSlcbiAgfVxuXG4gIHJldHVybiB7XG4gICAgZW50cnlQb2ludDoge1xuICAgICAgYm9keTogZW50cnlCbG9jayxcbiAgICAgIGtpbmQ6IFwiRW50cnlQb2ludFwiLFxuICAgICAgbG9jYXRpb246IGVudHJ5TG9jYXRpb25cbiAgICB9LFxuICAgIGZ1bmN0aW9ucyxcbiAgICBraW5kOiBcIk1vZHVsZVwiLFxuICAgIGxvY2F0aW9uXG4gIH1cbn1cbiJdfQ==
|