@mnemonica/tactica 0.1.15 → 0.2.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/README.md +165 -5
- package/lib/analyzer.d.ts +59 -2
- package/lib/analyzer.js +346 -21
- package/lib/cli.d.ts +4 -1
- package/lib/cli.js +222 -7
- package/lib/creation-graph.d.ts +131 -0
- package/lib/creation-graph.js +568 -0
- package/lib/index.d.ts +8 -2
- package/lib/index.js +11 -3
- package/lib/module-graph.d.ts +109 -0
- package/lib/module-graph.js +690 -0
- package/lib/plugins.d.ts +44 -0
- package/lib/plugins.js +27 -0
- package/lib/scopes.d.ts +113 -0
- package/lib/scopes.js +582 -0
- package/lib/topologica-analyzer.js +13 -10
- package/lib/types.d.ts +320 -0
- package/lib/types.js +1 -1
- package/lib/writer.d.ts +14 -1
- package/lib/writer.js +61 -1
- package/package.json +3 -1
package/lib/scopes.js
ADDED
|
@@ -0,0 +1,582 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.LocalScopeWalker = void 0;
|
|
37
|
+
const path = __importStar(require("path"));
|
|
38
|
+
const ts = __importStar(require("typescript"));
|
|
39
|
+
const ASSIGNMENT_OPERATORS = new Set([
|
|
40
|
+
ts.SyntaxKind.EqualsToken,
|
|
41
|
+
ts.SyntaxKind.PlusEqualsToken,
|
|
42
|
+
ts.SyntaxKind.MinusEqualsToken,
|
|
43
|
+
ts.SyntaxKind.AsteriskEqualsToken,
|
|
44
|
+
ts.SyntaxKind.AsteriskAsteriskEqualsToken,
|
|
45
|
+
ts.SyntaxKind.SlashEqualsToken,
|
|
46
|
+
ts.SyntaxKind.PercentEqualsToken,
|
|
47
|
+
ts.SyntaxKind.LessThanLessThanEqualsToken,
|
|
48
|
+
ts.SyntaxKind.GreaterThanGreaterThanEqualsToken,
|
|
49
|
+
ts.SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken,
|
|
50
|
+
ts.SyntaxKind.AmpersandEqualsToken,
|
|
51
|
+
ts.SyntaxKind.BarEqualsToken,
|
|
52
|
+
ts.SyntaxKind.CaretEqualsToken,
|
|
53
|
+
ts.SyntaxKind.AmpersandAmpersandEqualsToken,
|
|
54
|
+
ts.SyntaxKind.BarBarEqualsToken,
|
|
55
|
+
ts.SyntaxKind.QuestionQuestionEqualsToken,
|
|
56
|
+
]);
|
|
57
|
+
/**
|
|
58
|
+
* Local-scope walker (instrumentation walker plan, Phase 2).
|
|
59
|
+
*
|
|
60
|
+
* Tracks function/method/arrow scopes ONLY (decision 5: no block scopes),
|
|
61
|
+
* plus one synthetic 'module' scope per file — the plan requires module-scope
|
|
62
|
+
* instance creations to be labeled, not dropped. Variables carry isMutable
|
|
63
|
+
* (const vs let/var/parameter) and `reassignments`: each reassignment site of
|
|
64
|
+
* a mutable binding is a flow-termination point (decision 6) — downstream the
|
|
65
|
+
* walker stops following that binding there.
|
|
66
|
+
*
|
|
67
|
+
* Usage: addFile() per source file, then build(resolver) once definitions are
|
|
68
|
+
* known. findHolderScopeId(location) maps a usage location string to the
|
|
69
|
+
* innermost scope containing it (usages.json holderScopeId).
|
|
70
|
+
*/
|
|
71
|
+
class LocalScopeWalker {
|
|
72
|
+
constructor() {
|
|
73
|
+
this.scopes = new Map();
|
|
74
|
+
this.spans = new Map();
|
|
75
|
+
this.variables = new Map();
|
|
76
|
+
this.pending = [];
|
|
77
|
+
/**
|
|
78
|
+
* Arrow/function-expression node -> name it is bound to (`const f = () => …`,
|
|
79
|
+
* `{ handler: () => … }`, class properties). Program source files can be
|
|
80
|
+
* UNBOUND (no node.parent pointers), so binding names travel through this
|
|
81
|
+
* map instead of parent lookups.
|
|
82
|
+
*/
|
|
83
|
+
this.boundNames = new Map();
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Track one source file. Re-adding the same file replaces its records,
|
|
87
|
+
* so a walker may safely be reused across passes.
|
|
88
|
+
*/
|
|
89
|
+
addFile(sourceFile) {
|
|
90
|
+
const filePath = path.resolve(sourceFile.fileName);
|
|
91
|
+
this.dropFile(filePath);
|
|
92
|
+
const moduleScope = {
|
|
93
|
+
scopeId: filePath,
|
|
94
|
+
name: filePath,
|
|
95
|
+
kind: 'module',
|
|
96
|
+
filePath,
|
|
97
|
+
location: `${filePath}:1:1`,
|
|
98
|
+
};
|
|
99
|
+
this.scopes.set(moduleScope.scopeId, moduleScope);
|
|
100
|
+
const spans = [];
|
|
101
|
+
this.spans.set(filePath, spans);
|
|
102
|
+
spans.push(this.spanOf(sourceFile, sourceFile, moduleScope.scopeId));
|
|
103
|
+
const scopeStack = [moduleScope.scopeId];
|
|
104
|
+
const classStack = [];
|
|
105
|
+
this.visitNode(sourceFile, sourceFile, filePath, scopeStack, classStack, spans);
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Resolve pending typePaths and return the analysis.
|
|
109
|
+
*/
|
|
110
|
+
build(resolver) {
|
|
111
|
+
if (resolver) {
|
|
112
|
+
for (const entry of this.pending) {
|
|
113
|
+
const typePath = this.resolveVariableTypePath(entry, resolver);
|
|
114
|
+
if (typePath) {
|
|
115
|
+
entry.variable.typePath = typePath;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
const analysis = {
|
|
120
|
+
scopes: this.scopes,
|
|
121
|
+
variables: this.variables,
|
|
122
|
+
};
|
|
123
|
+
return analysis;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Map a usage location string ('abs/file.ts:line:col') to the innermost
|
|
127
|
+
* scope containing it. Module scope is the fallback, so every location
|
|
128
|
+
* inside a tracked file resolves to some scope.
|
|
129
|
+
*/
|
|
130
|
+
findHolderScopeId(location) {
|
|
131
|
+
const lastColon = location.lastIndexOf(':');
|
|
132
|
+
const prevColon = location.lastIndexOf(':', lastColon - 1);
|
|
133
|
+
if (lastColon < 0 || prevColon < 0) {
|
|
134
|
+
return undefined;
|
|
135
|
+
}
|
|
136
|
+
const filePath = path.resolve(location.slice(0, prevColon));
|
|
137
|
+
const line = Number(location.slice(prevColon + 1, lastColon));
|
|
138
|
+
const col = Number(location.slice(lastColon + 1));
|
|
139
|
+
if (!Number.isFinite(line) || !Number.isFinite(col)) {
|
|
140
|
+
return undefined;
|
|
141
|
+
}
|
|
142
|
+
const spans = this.spans.get(filePath);
|
|
143
|
+
if (!spans) {
|
|
144
|
+
return undefined;
|
|
145
|
+
}
|
|
146
|
+
let best;
|
|
147
|
+
for (const span of spans) {
|
|
148
|
+
const startsBefore = span.startLine < line || (span.startLine === line && span.startCol <= col);
|
|
149
|
+
const endsAfter = span.endLine > line || (span.endLine === line && span.endCol >= col);
|
|
150
|
+
if (!startsBefore || !endsAfter) {
|
|
151
|
+
continue;
|
|
152
|
+
}
|
|
153
|
+
// Innermost = smallest containing span
|
|
154
|
+
if (best && (best.startLine < span.startLine ||
|
|
155
|
+
(best.startLine === span.startLine && best.startCol <= span.startCol))) {
|
|
156
|
+
best = span;
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
if (!best) {
|
|
160
|
+
best = span;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
const result = best?.scopeId;
|
|
164
|
+
return result;
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Remove every record belonging to one file (re-add support).
|
|
168
|
+
*/
|
|
169
|
+
dropFile(filePath) {
|
|
170
|
+
for (const [scopeId, scope] of this.scopes) {
|
|
171
|
+
if (scope.filePath === filePath) {
|
|
172
|
+
this.scopes.delete(scopeId);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
for (const key of Array.from(this.variables.keys())) {
|
|
176
|
+
if (key.startsWith(`${filePath}#`) || key.startsWith(`${filePath}:`)) {
|
|
177
|
+
this.variables.delete(key);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
this.pending = this.pending.filter(entry => !entry.variable.declaration.startsWith(`${filePath}:`));
|
|
181
|
+
this.spans.delete(filePath);
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Attach holderScopeId to every usage whose location falls inside a
|
|
185
|
+
* tracked scope. Additive on UsageInfo; usages outside tracked files
|
|
186
|
+
* are left untouched.
|
|
187
|
+
*/
|
|
188
|
+
static attachHolderScopeIds(usages, walker) {
|
|
189
|
+
for (const usageList of usages.values()) {
|
|
190
|
+
for (const usage of usageList) {
|
|
191
|
+
const scopeId = walker.findHolderScopeId(usage.location);
|
|
192
|
+
if (scopeId) {
|
|
193
|
+
usage.holderScopeId = scopeId;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
visitNode(node, sourceFile, filePath, scopeStack, classStack, spans) {
|
|
199
|
+
const scopeKind = LocalScopeWalker.scopeKindOf(node);
|
|
200
|
+
let entered = false;
|
|
201
|
+
if (scopeKind && this.hasBody(node)) {
|
|
202
|
+
this.enterScope(node, scopeKind, sourceFile, filePath, scopeStack, classStack, spans);
|
|
203
|
+
entered = true;
|
|
204
|
+
}
|
|
205
|
+
const isClass = ts.isClassDeclaration(node) || ts.isClassExpression(node);
|
|
206
|
+
if (isClass) {
|
|
207
|
+
classStack.push(node.name?.text ?? '');
|
|
208
|
+
}
|
|
209
|
+
this.collectBoundName(node);
|
|
210
|
+
this.collectVariableDeclarationList(node, sourceFile, scopeStack);
|
|
211
|
+
this.collectReassignment(node, sourceFile, scopeStack);
|
|
212
|
+
ts.forEachChild(node, child => {
|
|
213
|
+
this.visitNode(child, sourceFile, filePath, scopeStack, classStack, spans);
|
|
214
|
+
});
|
|
215
|
+
if (isClass) {
|
|
216
|
+
classStack.pop();
|
|
217
|
+
}
|
|
218
|
+
if (entered) {
|
|
219
|
+
scopeStack.pop();
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
static scopeKindOf(node) {
|
|
223
|
+
if (ts.isMethodDeclaration(node) || ts.isGetAccessorDeclaration(node) ||
|
|
224
|
+
ts.isSetAccessorDeclaration(node) || ts.isConstructorDeclaration(node)) {
|
|
225
|
+
return 'method';
|
|
226
|
+
}
|
|
227
|
+
if (ts.isFunctionDeclaration(node) || ts.isFunctionExpression(node)) {
|
|
228
|
+
return 'function';
|
|
229
|
+
}
|
|
230
|
+
if (ts.isArrowFunction(node)) {
|
|
231
|
+
return 'arrow';
|
|
232
|
+
}
|
|
233
|
+
return undefined;
|
|
234
|
+
}
|
|
235
|
+
hasBody(node) {
|
|
236
|
+
const bodyHolder = node;
|
|
237
|
+
const result = bodyHolder.body !== undefined;
|
|
238
|
+
return result;
|
|
239
|
+
}
|
|
240
|
+
enterScope(node, kind, sourceFile, filePath, scopeStack, classStack, spans) {
|
|
241
|
+
const { line, character } = sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile));
|
|
242
|
+
const scopeId = `${filePath}:${line + 1}:${character + 1}`;
|
|
243
|
+
const parentScopeId = scopeStack[scopeStack.length - 1];
|
|
244
|
+
const scope = {
|
|
245
|
+
scopeId,
|
|
246
|
+
name: this.scopeName(node, kind, filePath, line + 1, classStack),
|
|
247
|
+
kind,
|
|
248
|
+
parentScopeId,
|
|
249
|
+
filePath,
|
|
250
|
+
location: scopeId,
|
|
251
|
+
};
|
|
252
|
+
this.scopes.set(scopeId, scope);
|
|
253
|
+
spans.push(this.spanOf(node, sourceFile, scopeId));
|
|
254
|
+
scopeStack.push(scopeId);
|
|
255
|
+
// Parameters are variables of the scope; they are reassignable, so
|
|
256
|
+
// isMutable: true — a parameter reassignment terminates the flow too
|
|
257
|
+
const fn = node;
|
|
258
|
+
for (const param of fn.parameters ?? []) {
|
|
259
|
+
if (!ts.isIdentifier(param.name)) {
|
|
260
|
+
// Skip destructured parameters (analyzer precedent)
|
|
261
|
+
continue;
|
|
262
|
+
}
|
|
263
|
+
this.recordVariable(param.name.text, param.name, sourceFile, scopeStack, {
|
|
264
|
+
isParameter: true,
|
|
265
|
+
// `this` parameters (mnemonica handlers) are never reassignable
|
|
266
|
+
isMutable: param.name.text !== 'this',
|
|
267
|
+
annotation: param.type?.getText(sourceFile),
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* Decision 8 labeling: functions by name; methods as Class.method;
|
|
273
|
+
* arrows/functions bound to a variable or property take that name;
|
|
274
|
+
* anonymous holders are labeled file:line.
|
|
275
|
+
*/
|
|
276
|
+
scopeName(node, kind, filePath, line, classStack) {
|
|
277
|
+
const named = node;
|
|
278
|
+
if (kind === 'method') {
|
|
279
|
+
const methodName = named.name ? named.name.getText() : 'anonymous';
|
|
280
|
+
const className = classStack[classStack.length - 1];
|
|
281
|
+
const ctor = ts.isConstructorDeclaration(node) ? 'constructor' : methodName;
|
|
282
|
+
const methodScopeName = className ? `${className}.${ctor}` : ctor;
|
|
283
|
+
return methodScopeName;
|
|
284
|
+
}
|
|
285
|
+
if (named.name && ts.isIdentifier(named.name)) {
|
|
286
|
+
const declaredName = named.name.text;
|
|
287
|
+
return declaredName;
|
|
288
|
+
}
|
|
289
|
+
// Bound names come from the boundNames map — program files may be
|
|
290
|
+
// unbound, so node.parent is not a reliable path to the variable name
|
|
291
|
+
const bound = this.boundNames.get(node);
|
|
292
|
+
if (bound) {
|
|
293
|
+
return bound;
|
|
294
|
+
}
|
|
295
|
+
const result = `${filePath}:${line}`;
|
|
296
|
+
return result;
|
|
297
|
+
}
|
|
298
|
+
spanOf(node, sourceFile, scopeId) {
|
|
299
|
+
const start = sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile));
|
|
300
|
+
const end = sourceFile.getLineAndCharacterOfPosition(node.getEnd());
|
|
301
|
+
const span = {
|
|
302
|
+
scopeId,
|
|
303
|
+
startLine: start.line + 1,
|
|
304
|
+
startCol: start.character + 1,
|
|
305
|
+
endLine: end.line + 1,
|
|
306
|
+
endCol: end.character + 1,
|
|
307
|
+
};
|
|
308
|
+
return span;
|
|
309
|
+
}
|
|
310
|
+
/**
|
|
311
|
+
* Record the name an arrow/function-expression is bound to, without
|
|
312
|
+
* relying on node.parent (unbound program files): `const f = () => …`,
|
|
313
|
+
* `{ handler: () => … }`, `class C { run = () => … }`.
|
|
314
|
+
*/
|
|
315
|
+
collectBoundName(node) {
|
|
316
|
+
if (ts.isVariableDeclaration(node) && ts.isIdentifier(node.name) && node.initializer &&
|
|
317
|
+
(ts.isArrowFunction(node.initializer) || ts.isFunctionExpression(node.initializer))) {
|
|
318
|
+
this.boundNames.set(node.initializer, node.name.text);
|
|
319
|
+
return;
|
|
320
|
+
}
|
|
321
|
+
if ((ts.isPropertyAssignment(node) || ts.isPropertyDeclaration(node)) &&
|
|
322
|
+
ts.isIdentifier(node.name) && node.initializer &&
|
|
323
|
+
(ts.isArrowFunction(node.initializer) || ts.isFunctionExpression(node.initializer))) {
|
|
324
|
+
this.boundNames.set(node.initializer, node.name.text);
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
collectVariableDeclarationList(node, sourceFile, scopeStack) {
|
|
328
|
+
if (!ts.isVariableDeclarationList(node)) {
|
|
329
|
+
return;
|
|
330
|
+
}
|
|
331
|
+
// Flags live on the list itself — no parent walk needed (the list's
|
|
332
|
+
// parent may be unset on unbound program files)
|
|
333
|
+
const isConst = (node.flags & ts.NodeFlags.Const) !== 0;
|
|
334
|
+
for (const decl of node.declarations) {
|
|
335
|
+
// Destructuring declarations are skipped: only plain
|
|
336
|
+
// `const/let/var x = …` has an identifier name
|
|
337
|
+
if (!ts.isIdentifier(decl.name)) {
|
|
338
|
+
continue;
|
|
339
|
+
}
|
|
340
|
+
this.recordVariable(decl.name.text, decl.name, sourceFile, scopeStack, {
|
|
341
|
+
isParameter: false,
|
|
342
|
+
isMutable: !isConst,
|
|
343
|
+
annotation: decl.type?.getText(sourceFile),
|
|
344
|
+
initializer: decl.initializer,
|
|
345
|
+
});
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
recordVariable(name, node, sourceFile, scopeStack, options) {
|
|
349
|
+
const scopeId = scopeStack[scopeStack.length - 1];
|
|
350
|
+
const { line, character } = sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile));
|
|
351
|
+
const filePath = path.resolve(sourceFile.fileName);
|
|
352
|
+
const variable = {
|
|
353
|
+
name,
|
|
354
|
+
scopeId,
|
|
355
|
+
declaration: `${filePath}:${line + 1}:${character + 1}`,
|
|
356
|
+
isParameter: options.isParameter,
|
|
357
|
+
isMutable: options.isMutable,
|
|
358
|
+
reassignments: [],
|
|
359
|
+
};
|
|
360
|
+
const inferred = options.annotation ?? (options.initializer ? LocalScopeWalker.inferInitializerKind(options.initializer) : undefined);
|
|
361
|
+
if (inferred) {
|
|
362
|
+
variable.inferredType = inferred;
|
|
363
|
+
}
|
|
364
|
+
const pendingEntry = {
|
|
365
|
+
variable,
|
|
366
|
+
scopeChain: [...scopeStack].reverse(),
|
|
367
|
+
annotation: options.annotation,
|
|
368
|
+
};
|
|
369
|
+
const { initializer } = options;
|
|
370
|
+
if (initializer && ts.isNewExpression(initializer)) {
|
|
371
|
+
const { expression } = initializer;
|
|
372
|
+
if (ts.isIdentifier(expression)) {
|
|
373
|
+
pendingEntry.newName = expression.text;
|
|
374
|
+
}
|
|
375
|
+
else if (ts.isPropertyAccessExpression(expression)) {
|
|
376
|
+
const chain = LocalScopeWalker.unwrapPropertyAccess(expression);
|
|
377
|
+
if (chain.length > 1) {
|
|
378
|
+
const [root, ...rest] = chain;
|
|
379
|
+
pendingEntry.newChainRoot = root;
|
|
380
|
+
pendingEntry.newChainRest = rest;
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
if (initializer && ts.isCallExpression(initializer)) {
|
|
385
|
+
const lookup = LocalScopeWalker.unwrapLookupCall(initializer);
|
|
386
|
+
if (lookup) {
|
|
387
|
+
pendingEntry.lookupPath = lookup.path;
|
|
388
|
+
pendingEntry.lookupReceiver = lookup.receiver;
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
this.pending.push(pendingEntry);
|
|
392
|
+
this.variables.set(`${scopeId}#${name}`, variable);
|
|
393
|
+
}
|
|
394
|
+
/**
|
|
395
|
+
* `a.b.c` → ['a', 'b', 'c'] (left-to-right); undefined-safe for
|
|
396
|
+
* non-identifier roots.
|
|
397
|
+
*/
|
|
398
|
+
static unwrapPropertyAccess(expression) {
|
|
399
|
+
const chain = [];
|
|
400
|
+
let current = expression;
|
|
401
|
+
while (ts.isPropertyAccessExpression(current)) {
|
|
402
|
+
chain.unshift(current.name.text);
|
|
403
|
+
current = current.expression;
|
|
404
|
+
}
|
|
405
|
+
if (ts.isIdentifier(current)) {
|
|
406
|
+
chain.unshift(current.text);
|
|
407
|
+
}
|
|
408
|
+
return chain;
|
|
409
|
+
}
|
|
410
|
+
/**
|
|
411
|
+
* `lookup('A.B')`, `App.lookup('A.B')`, `lookup(source, 'A.B')` → the
|
|
412
|
+
* string-literal path plus the receiver's root identifier when there is
|
|
413
|
+
* one. Only literal paths are tracked: a computed path is data the static
|
|
414
|
+
* walker cannot follow, so it is skipped (the analyzer's usage pass still
|
|
415
|
+
* records the lookup call itself).
|
|
416
|
+
*/
|
|
417
|
+
static unwrapLookupCall(call) {
|
|
418
|
+
const { expression } = call;
|
|
419
|
+
const [firstArg, secondArg] = call.arguments;
|
|
420
|
+
if (ts.isIdentifier(expression)) {
|
|
421
|
+
if (expression.text !== 'lookup') {
|
|
422
|
+
return undefined;
|
|
423
|
+
}
|
|
424
|
+
// lookup('A.B')
|
|
425
|
+
if (firstArg && ts.isStringLiteralLike(firstArg)) {
|
|
426
|
+
const result = { path: firstArg.text };
|
|
427
|
+
return result;
|
|
428
|
+
}
|
|
429
|
+
// lookup(source, 'A.B') — explicit-source form
|
|
430
|
+
if (firstArg && ts.isIdentifier(firstArg) && secondArg && ts.isStringLiteralLike(secondArg)) {
|
|
431
|
+
const result = { path: secondArg.text, receiver: firstArg.text };
|
|
432
|
+
return result;
|
|
433
|
+
}
|
|
434
|
+
return undefined;
|
|
435
|
+
}
|
|
436
|
+
if (ts.isPropertyAccessExpression(expression) && expression.name.text === 'lookup') {
|
|
437
|
+
if (!firstArg || !ts.isStringLiteralLike(firstArg)) {
|
|
438
|
+
return undefined;
|
|
439
|
+
}
|
|
440
|
+
const chain = LocalScopeWalker.unwrapPropertyAccess(expression);
|
|
441
|
+
// chain < 2 means no identifier receiver (e.g. this.lookup('A.B'))
|
|
442
|
+
if (chain.length < 2) {
|
|
443
|
+
const pathOnly = { path: firstArg.text };
|
|
444
|
+
return pathOnly;
|
|
445
|
+
}
|
|
446
|
+
const [receiver] = chain;
|
|
447
|
+
const result = { path: firstArg.text, receiver };
|
|
448
|
+
return result;
|
|
449
|
+
}
|
|
450
|
+
return undefined;
|
|
451
|
+
}
|
|
452
|
+
/**
|
|
453
|
+
* Cheap initializer classification for inferredType. Deliberately tiny:
|
|
454
|
+
* literal kinds and `new X` constructor names; everything else undefined.
|
|
455
|
+
*/
|
|
456
|
+
static inferInitializerKind(initializer) {
|
|
457
|
+
if (ts.isStringLiteralLike(initializer) || ts.isTemplateExpression(initializer)) {
|
|
458
|
+
return 'string';
|
|
459
|
+
}
|
|
460
|
+
if (ts.isNumericLiteral(initializer)) {
|
|
461
|
+
return 'number';
|
|
462
|
+
}
|
|
463
|
+
if (initializer.kind === ts.SyntaxKind.TrueKeyword || initializer.kind === ts.SyntaxKind.FalseKeyword) {
|
|
464
|
+
return 'boolean';
|
|
465
|
+
}
|
|
466
|
+
if (ts.isArrowFunction(initializer) || ts.isFunctionExpression(initializer)) {
|
|
467
|
+
return 'function';
|
|
468
|
+
}
|
|
469
|
+
if (ts.isArrayLiteralExpression(initializer)) {
|
|
470
|
+
return 'Array<unknown>';
|
|
471
|
+
}
|
|
472
|
+
if (ts.isNewExpression(initializer) && ts.isIdentifier(initializer.expression)) {
|
|
473
|
+
const result = initializer.expression.text;
|
|
474
|
+
return result;
|
|
475
|
+
}
|
|
476
|
+
return undefined;
|
|
477
|
+
}
|
|
478
|
+
/**
|
|
479
|
+
* Reassignment of a let/var/parameter binding: a flow-termination point
|
|
480
|
+
* (decision 6). Recorded on the variable so the Phase 3 walker stops
|
|
481
|
+
* following that binding there.
|
|
482
|
+
*/
|
|
483
|
+
collectReassignment(node, sourceFile, scopeStack) {
|
|
484
|
+
let target;
|
|
485
|
+
if (ts.isBinaryExpression(node) &&
|
|
486
|
+
ASSIGNMENT_OPERATORS.has(node.operatorToken.kind) &&
|
|
487
|
+
ts.isIdentifier(node.left)) {
|
|
488
|
+
target = node.left;
|
|
489
|
+
}
|
|
490
|
+
if ((ts.isPrefixUnaryExpression(node) || ts.isPostfixUnaryExpression(node)) &&
|
|
491
|
+
(node.operator === ts.SyntaxKind.PlusPlusToken || node.operator === ts.SyntaxKind.MinusMinusToken) &&
|
|
492
|
+
ts.isIdentifier(node.operand)) {
|
|
493
|
+
target = node.operand;
|
|
494
|
+
}
|
|
495
|
+
if (!target) {
|
|
496
|
+
return;
|
|
497
|
+
}
|
|
498
|
+
// Note: a declaration initializer (`let x = 5`) is a VariableDeclaration,
|
|
499
|
+
// never a BinaryExpression, so it cannot reach this path as a "reassignment"
|
|
500
|
+
const variable = this.findVariable(target.text, scopeStack);
|
|
501
|
+
if (!variable) {
|
|
502
|
+
return;
|
|
503
|
+
}
|
|
504
|
+
const filePath = path.resolve(sourceFile.fileName);
|
|
505
|
+
const { line, character } = sourceFile.getLineAndCharacterOfPosition(target.getStart(sourceFile));
|
|
506
|
+
variable.reassignments.push(`${filePath}:${line + 1}:${character + 1}`);
|
|
507
|
+
}
|
|
508
|
+
/**
|
|
509
|
+
* Find a variable by name walking the scope chain outward.
|
|
510
|
+
*/
|
|
511
|
+
findVariable(name, scopeStack) {
|
|
512
|
+
for (let i = scopeStack.length - 1; i >= 0; i--) {
|
|
513
|
+
const variable = this.variables.get(`${scopeStack[i]}#${name}`);
|
|
514
|
+
if (variable) {
|
|
515
|
+
return variable;
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
return undefined;
|
|
519
|
+
}
|
|
520
|
+
resolveVariableTypePath(entry, resolver) {
|
|
521
|
+
// `new SomeType(...)` — bare constructor name
|
|
522
|
+
if (entry.newName) {
|
|
523
|
+
const resolved = resolver.resolveByName(entry.newName);
|
|
524
|
+
if (resolved) {
|
|
525
|
+
return resolved;
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
// `new instance.Sub.Type(...)` — chain off a tracked variable's typePath
|
|
529
|
+
if (entry.newChainRoot && entry.newChainRest && entry.newChainRest.length > 0) {
|
|
530
|
+
for (const scopeId of entry.scopeChain) {
|
|
531
|
+
const rootVariable = this.variables.get(`${scopeId}#${entry.newChainRoot}`);
|
|
532
|
+
if (!rootVariable?.typePath) {
|
|
533
|
+
continue;
|
|
534
|
+
}
|
|
535
|
+
const candidate = [rootVariable.typePath, ...entry.newChainRest].join('.');
|
|
536
|
+
if (resolver.hasPath(candidate)) {
|
|
537
|
+
return candidate;
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
// `lookup('A.B')` / `receiver.lookup('A.B')` initializers
|
|
542
|
+
if (entry.lookupPath) {
|
|
543
|
+
// Receiver-relative first: `user.lookup('AdminEntity')` resolves
|
|
544
|
+
// against the receiver variable's typePath when that yields a
|
|
545
|
+
// known path (mirrors the analyzer's relative-then-root rule)
|
|
546
|
+
if (entry.lookupReceiver) {
|
|
547
|
+
for (const scopeId of entry.scopeChain) {
|
|
548
|
+
const receiverVariable = this.variables.get(`${scopeId}#${entry.lookupReceiver}`);
|
|
549
|
+
if (!receiverVariable?.typePath) {
|
|
550
|
+
continue;
|
|
551
|
+
}
|
|
552
|
+
const candidate = `${receiverVariable.typePath}.${entry.lookupPath}`;
|
|
553
|
+
if (resolver.hasPath(candidate)) {
|
|
554
|
+
return candidate;
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
if (resolver.hasPath(entry.lookupPath)) {
|
|
559
|
+
return entry.lookupPath;
|
|
560
|
+
}
|
|
561
|
+
const byName = resolver.resolveByName(entry.lookupPath);
|
|
562
|
+
if (byName) {
|
|
563
|
+
return byName;
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
// Type annotation: 'UserEntity_UserResponse' (tactica types.ts naming)
|
|
567
|
+
// → dotted path, or a bare known type name
|
|
568
|
+
if (entry.annotation) {
|
|
569
|
+
const dotted = entry.annotation.replace(/_/g, '.');
|
|
570
|
+
if (dotted.includes('.') && resolver.hasPath(dotted)) {
|
|
571
|
+
return dotted;
|
|
572
|
+
}
|
|
573
|
+
const byName = resolver.resolveByName(entry.annotation);
|
|
574
|
+
if (byName) {
|
|
575
|
+
return byName;
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
return undefined;
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
exports.LocalScopeWalker = LocalScopeWalker;
|
|
582
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2NvcGVzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL3Njb3Blcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxZQUFZLENBQUM7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUViLDJDQUE2QjtBQUM3QiwrQ0FBaUM7QUFrRGpDLE1BQU0sb0JBQW9CLEdBQUcsSUFBSSxHQUFHLENBQWdCO0lBQ25ELEVBQUUsQ0FBQyxVQUFVLENBQUMsV0FBVztJQUN6QixFQUFFLENBQUMsVUFBVSxDQUFDLGVBQWU7SUFDN0IsRUFBRSxDQUFDLFVBQVUsQ0FBQyxnQkFBZ0I7SUFDOUIsRUFBRSxDQUFDLFVBQVUsQ0FBQyxtQkFBbUI7SUFDakMsRUFBRSxDQUFDLFVBQVUsQ0FBQywyQkFBMkI7SUFDekMsRUFBRSxDQUFDLFVBQVUsQ0FBQyxnQkFBZ0I7SUFDOUIsRUFBRSxDQUFDLFVBQVUsQ0FBQyxrQkFBa0I7SUFDaEMsRUFBRSxDQUFDLFVBQVUsQ0FBQywyQkFBMkI7SUFDekMsRUFBRSxDQUFDLFVBQVUsQ0FBQyxpQ0FBaUM7SUFDL0MsRUFBRSxDQUFDLFVBQVUsQ0FBQyw0Q0FBNEM7SUFDMUQsRUFBRSxDQUFDLFVBQVUsQ0FBQyxvQkFBb0I7SUFDbEMsRUFBRSxDQUFDLFVBQVUsQ0FBQyxjQUFjO0lBQzVCLEVBQUUsQ0FBQyxVQUFVLENBQUMsZ0JBQWdCO0lBQzlCLEVBQUUsQ0FBQyxVQUFVLENBQUMsNkJBQTZCO0lBQzNDLEVBQUUsQ0FBQyxVQUFVLENBQUMsaUJBQWlCO0lBQy9CLEVBQUUsQ0FBQyxVQUFVLENBQUMsMkJBQTJCO0NBQ3pDLENBQUMsQ0FBQztBQUVIOzs7Ozs7Ozs7Ozs7O0dBYUc7QUFDSCxNQUFhLGdCQUFnQjtJQUE3QjtRQUNTLFdBQU0sR0FBRyxJQUFJLEdBQUcsRUFBcUIsQ0FBQztRQUN0QyxVQUFLLEdBQUcsSUFBSSxHQUFHLEVBQXVCLENBQUM7UUFDdkMsY0FBUyxHQUFHLElBQUksR0FBRyxF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QUFDO0NBQ0Q7QUFubEJELDRDQW1sQkMiLCJzb3VyY2VzQ29udGVudCI6WyIndXNlIHN0cmljdCc7XG5cbmltcG9ydCAqIGFzIHBhdGggZnJvbSAncGF0aCc7XG5pbXBvcnQgKiBhcyB0cyBmcm9tICd0eXBlc2NyaXB0JztcbmltcG9ydCB7XG5cdFNjb3BlQW5hbHlzaXMsIFNjb3BlSW5mbywgU2NvcGVLaW5kLCBTY29wZVZhcmlhYmxlLCBVc2FnZUluZm9cbn0gZnJvbSAnLi90eXBlcyc7XG5cbi8qKlxuICogQ29tcGlsZS10aW1lIHZpZXcgb3ZlciB0aGUgYW5hbHl6ZXIncyBkZWZpbml0aW9ucywgdXNlZCB0byBhdHRhY2ggbW5lbW9uaWNhXG4gKiB0eXBlIHBhdGhzIHRvIHZhcmlhYmxlcy4gTmFtZS1iYXNlZCBoZXVyaXN0aWNzIG9ubHkg4oCUIHRoZSBuby1nZXRUeXBlQ2hlY2tlcigpXG4gKiBwcmVjZWRlbnQgc3RheXMuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgU2NvcGVUeXBlUmVzb2x2ZXIge1xuXHQvKiogUmVzb2x2ZSBhIGJhcmUgY29uc3RydWN0b3IvdHlwZSBuYW1lIHRvIGEgbW5lbW9uaWNhIGZ1bGxQYXRoICh1bmRlZmluZWQgd2hlbiB1bmtub3duIG9yIGFtYmlndW91cykgKi9cblx0cmVzb2x2ZUJ5TmFtZShuYW1lOiBzdHJpbmcpOiBzdHJpbmcgfCB1bmRlZmluZWQ7XG5cdC8qKiBUcnVlIHdoZW4gdGhlIGRvdHRlZCBwYXRoIGlzIGEga25vd24gbW5lbW9uaWNhIHR5cGUgKi9cblx0aGFzUGF0aChmdWxsUGF0aDogc3RyaW5nKTogYm9vbGVhbjtcbn1cblxuLyoqXG4gKiBJbnRlcm5hbCBzY29wZSByZWNvcmQ6IG51bWVyaWMgc3BhbiAoMS1iYXNlZCBsaW5lL2NvbCkga2VwdCBmb3JcbiAqIGZpbmRIb2xkZXJTY29wZUlkKCkgY29udGFpbm1lbnQgbWF0Y2hpbmc7IFNjb3BlSW5mbyBpdHNlbGYgY2FycmllcyBzdHJpbmdzLlxuICovXG5pbnRlcmZhY2UgU2NvcGVTcGFuIHtcblx0c2NvcGVJZDogc3RyaW5nO1xuXHRzdGFydExpbmU6IG51bWJlcjtcblx0c3RhcnRDb2w6IG51bWJlcjtcblx0ZW5kTGluZTogbnVtYmVyO1xuXHRlbmRDb2w6IG51bWJlcjtcbn1cblxuLyoqXG4gKiBSYXcgdmFyaWFibGUgcmVjb3JkIGNvbGxlY3RlZCBkdXJpbmcgdGhlIEFTVCB3YWxrLiB0eXBlUGF0aCBpcyByZXNvbHZlZFxuICogbGF0ZXIgaW4gYnVpbGQoKSwgb25jZSBkZWZpbml0aW9ucyBhcmUga25vd24uXG4gKi9cbmludGVyZmFjZSBQZW5kaW5nVmFyaWFibGUge1xuXHR2YXJpYWJsZTogU2NvcGVWYXJpYWJsZTtcblx0LyoqIEJhcmUgY29uc3RydWN0b3IgbmFtZSBmb3IgYG5ldyBYKC4uLilgIGluaXRpYWxpemVycyAqL1xuXHRuZXdOYW1lPzogc3RyaW5nO1xuXHQvKiogUm9vdCBpZGVudGlmaWVyICsgcHJvcGVydHkgY2hhaW4gZm9yIGBuZXcgYS5iLkMoLi4uKWAgaW5pdGlhbGl6ZXJzICovXG5cdG5ld0NoYWluUm9vdD86IHN0cmluZztcblx0bmV3Q2hhaW5SZXN0Pzogc3RyaW5nW107XG5cdC8qKiBTdHJpbmctbGl0ZXJhbCBwYXRoIG9mIGEgYGxvb2t1cCgnQS5CJylgIGluaXRpYWxpemVyICovXG5cdGxvb2t1cFBhdGg/OiBzdHJpbmc7XG5cdC8qKiBSb290IGlkZW50aWZpZXIgb2YgdGhlIHJlY2VpdmVyIGZvciBgcmVjZWl2ZXIubG9va3VwKCdBLkInKWAgLyBgbG9va3VwKHNvdXJjZSwgJ0EuQicpYCAqL1xuXHRsb29rdXBSZWNlaXZlcj86IHN0cmluZztcblx0LyoqIFJhdyB0eXBlIGFubm90YXRpb24gdGV4dCAoZS5nLiAnVXNlckVudGl0eV9Vc2VyUmVzcG9uc2UnKSAqL1xuXHRhbm5vdGF0aW9uPzogc3RyaW5nO1xuXHQvKiogU2NvcGUgY2hhaW4gZnJvbSBkZWNsYXJhdGlvbiBzaXRlIG91dHdhcmQsIGZvciBjaGFpbi1yb290IGxvb2t1cCAqL1xuXHRzY29wZUNoYWluOiBzdHJpbmdbXTtcbn1cblxuY29uc3QgQVNTSUdOTUVOVF9PUEVSQVRPUlMgPSBuZXcgU2V0PHRzLlN5bnRheEtpbmQ+KFtcblx0dHMuU3ludGF4S2luZC5FcXVhbHNUb2tlbixcblx0dHMuU3ludGF4S2luZC5QbHVzRXF1YWxzVG9rZW4sXG5cdHRzLlN5bnRheEtpbmQuTWludXNFcXVhbHNUb2tlbixcblx0dHMuU3ludGF4S2luZC5Bc3Rlcmlza0VxdWFsc1Rva2VuLFxuXHR0cy5TeW50YXhLaW5kLkFzdGVyaXNrQXN0ZXJpc2tFcXVhbHNUb2tlbixcblx0dHMuU3ludGF4S2luZC5TbGFzaEVxdWFsc1Rva2VuLFxuXHR0cy5TeW50YXhLaW5kLlBlcmNlbnRFcXVhbHNUb2tlbixcblx0dHMuU3ludGF4S2luZC5MZXNzVGhhbkxlc3NUaGFuRXF1YWxzVG9rZW4sXG5cdHRzLlN5bnRheEtpbmQuR3JlYXRlclRoYW5HcmVhdGVyVGhhbkVxdWFsc1Rva2VuLFxuXHR0cy5TeW50YXhLaW5kLkdyZWF0ZXJUaGFuR3JlYXRlclRoYW5HcmVhdGVyVGhhbkVxdWFsc1Rva2VuLFxuXHR0cy5TeW50YXhLaW5kLkFtcGVyc2FuZEVxdWFsc1Rva2VuLFxuXHR0cy5TeW50YXhLaW5kLkJhckVxdWFsc1Rva2VuLFxuXHR0cy5TeW50YXhLaW5kLkNhcmV0RXF1YWxzVG9rZW4sXG5cdHRzLlN5bnRheEtpbmQuQW1wZXJzYW5kQW1wZXJzYW5kRXF1YWxzVG9rZW4sXG5cdHRzLlN5bnRheEtpbmQuQmFyQmFyRXF1YWxzVG9rZW4sXG5cdHRzLlN5bnRheEtpbmQuUXVlc3Rpb25RdWVzdGlvbkVxdWFsc1Rva2VuLFxuXSk7XG5cbi8qKlxuICogTG9jYWwtc2NvcGUgd2Fsa2VyIChpbnN0cnVtZW50YXRpb24gd2Fsa2VyIHBsYW4sIFBoYXNlIDIpLlxuICpcbiAqIFRyYWNrcyBmdW5jdGlvbi9tZXRob2QvYXJyb3cgc2NvcGVzIE9OTFkgKGRlY2lzaW9uIDU6IG5vIGJsb2NrIHNjb3BlcyksXG4gKiBwbHVzIG9uZSBzeW50aGV0aWMgJ21vZHVsZScgc2NvcGUgcGVyIGZpbGUg4oCUIHRoZSBwbGFuIHJlcXVpcmVzIG1vZHVsZS1zY29wZVxuICogaW5zdGFuY2UgY3JlYXRpb25zIHRvIGJlIGxhYmVsZWQsIG5vdCBkcm9wcGVkLiBWYXJpYWJsZXMgY2FycnkgaXNNdXRhYmxlXG4gKiAoY29uc3QgdnMgbGV0L3Zhci9wYXJhbWV0ZXIpIGFuZCBgcmVhc3NpZ25tZW50c2A6IGVhY2ggcmVhc3NpZ25tZW50IHNpdGUgb2ZcbiAqIGEgbXV0YWJsZSBiaW5kaW5nIGlzIGEgZmxvdy10ZXJtaW5hdGlvbiBwb2ludCAoZGVjaXNpb24gNikg4oCUIGRvd25zdHJlYW0gdGhlXG4gKiB3YWxrZXIgc3RvcHMgZm9sbG93aW5nIHRoYXQgYmluZGluZyB0aGVyZS5cbiAqXG4gKiBVc2FnZTogYWRkRmlsZSgpIHBlciBzb3VyY2UgZmlsZSwgdGhlbiBidWlsZChyZXNvbHZlcikgb25jZSBkZWZpbml0aW9ucyBhcmVcbiAqIGtub3duLiBmaW5kSG9sZGVyU2NvcGVJZChsb2NhdGlvbikgbWFwcyBhIHVzYWdlIGxvY2F0aW9uIHN0cmluZyB0byB0aGVcbiAqIGlubmVybW9zdCBzY29wZSBjb250YWluaW5nIGl0ICh1c2FnZXMuanNvbiBob2xkZXJTY29wZUlkKS5cbiAqL1xuZXhwb3J0IGNsYXNzIExvY2FsU2NvcGVXYWxrZXIge1xuXHRwcml2YXRlIHNjb3BlcyA9IG5ldyBNYXA8c3RyaW5nLCBTY29wZUluZm8+KCk7XG5cdHByaXZhdGUgc3BhbnMgPSBuZXcgTWFwPHN0cmluZywgU2NvcGVTcGFuW10+KCk7XG5cdHByaXZhdGUgdmFyaWFibGVzID0gbmV3IE1hcDxzdHJpbmcsIFNjb3BlVmFyaWFibGU+KCk7XG5cdHByaXZhdGUgcGVuZGluZzogUGVuZGluZ1ZhcmlhYmxlW10gPSBbXTtcblx0LyoqXG5cdCAqIEFycm93L2Z1bmN0aW9uLWV4cHJlc3Npb24gbm9kZSAtPiBuYW1lIGl0IGlzIGJvdW5kIHRvIChgY29uc3QgZiA9ICgpID0+IOKApmAsXG5cdCAqIGB7IGhhbmRsZXI6ICgpID0+IOKApiB9YCwgY2xhc3MgcHJvcGVydGllcykuIFByb2dyYW0gc291cmNlIGZpbGVzIGNhbiBiZVxuXHQgKiBVTkJPVU5EIChubyBub2RlLnBhcmVudCBwb2ludGVycyksIHNvIGJpbmRpbmcgbmFtZXMgdHJhdmVsIHRocm91Z2ggdGhpc1xuXHQgKiBtYXAgaW5zdGVhZCBvZiBwYXJlbnQgbG9va3Vwcy5cblx0ICovXG5cdHByaXZhdGUgYm91bmROYW1lcyA9IG5ldyBNYXA8dHMuTm9kZSwgc3RyaW5nPigpO1xuXG5cdC8qKlxuXHQgKiBUcmFjayBvbmUgc291cmNlIGZpbGUuIFJlLWFkZGluZyB0aGUgc2FtZSBmaWxlIHJlcGxhY2VzIGl0cyByZWNvcmRzLFxuXHQgKiBzbyBhIHdhbGtlciBtYXkgc2FmZWx5IGJlIHJldXNlZCBhY3Jvc3MgcGFzc2VzLlxuXHQgKi9cblx0YWRkRmlsZSAoc291cmNlRmlsZTogdHMuU291cmNlRmlsZSk6IHZvaWQge1xuXHRcdGNvbnN0IGZpbGVQYXRoID0gcGF0aC5yZXNvbHZlKHNvdXJjZUZpbGUuZmlsZU5hbWUpO1xuXHRcdHRoaXMuZHJvcEZpbGUoZmlsZVBhdGgpO1xuXG5cdFx0Y29uc3QgbW9kdWxlU2NvcGU6IFNjb3BlSW5mbyA9IHtcblx0XHRcdHNjb3BlSWQgIDogZmlsZVBhdGgsXG5cdFx0XHRuYW1lICAgICA6IGZpbGVQYXRoLFxuXHRcdFx0a2luZCAgICAgOiAnbW9kdWxlJyxcblx0XHRcdGZpbGVQYXRoLFxuXHRcdFx0bG9jYXRpb24gOiBgJHtmaWxlUGF0aH06MToxYCxcblx0XHR9O1xuXHRcdHRoaXMuc2NvcGVzLnNldChtb2R1bGVTY29wZS5zY29wZUlkLCBtb2R1bGVTY29wZSk7XG5cblx0XHRjb25zdCBzcGFuczogU2NvcGVTcGFuW10gPSBbXTtcblx0XHR0aGlzLnNwYW5zLnNldChmaWxlUGF0aCwgc3BhbnMpO1xuXHRcdHNwYW5zLnB1c2godGhpcy5zcGFuT2Yoc291cmNlRmlsZSwgc291cmNlRmlsZSwgbW9kdWxlU2NvcGUuc2NvcGVJZCkpO1xuXG5cdFx0Y29uc3Qgc2NvcGVTdGFjazogc3RyaW5nW10gPSBbIG1vZHVsZVNjb3BlLnNjb3BlSWQgXTtcblx0XHRjb25zdCBjbGFzc1N0YWNrOiBzdHJpbmdbXSA9IFtdO1xuXHRcdHRoaXMudmlzaXROb2RlKHNvdXJjZUZpbGUsIHNvdXJjZUZpbGUsIGZpbGVQYXRoLCBzY29wZVN0YWNrLCBjbGFzc1N0YWNrLCBzcGFucyk7XG5cdH1cblxuXHQvKipcblx0ICogUmVzb2x2ZSBwZW5kaW5nIHR5cGVQYXRocyBhbmQgcmV0dXJuIHRoZSBhbmFseXNpcy5cblx0ICovXG5cdGJ1aWxkIChyZXNvbHZlcj86IFNjb3BlVHlwZVJlc29sdmVyKTogU2NvcGVBbmFseXNpcyB7XG5cdFx0aWYgKHJlc29sdmVyKSB7XG5cdFx0XHRmb3IgKGNvbnN0IGVudHJ5IG9mIHRoaXMucGVuZGluZykge1xuXHRcdFx0XHRjb25zdCB0eXBlUGF0aCA9IHRoaXMucmVzb2x2ZVZhcmlhYmxlVHlwZVBhdGgoZW50cnksIHJlc29sdmVyKTtcblx0XHRcdFx0aWYgKHR5cGVQYXRoKSB7XG5cdFx0XHRcdFx0ZW50cnkudmFyaWFibGUudHlwZVBhdGggPSB0eXBlUGF0aDtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH1cblxuXHRcdGNvbnN0IGFuYWx5c2lzOiBTY29wZUFuYWx5c2lzID0ge1xuXHRcdFx0c2NvcGVzICAgIDogdGhpcy5zY29wZXMsXG5cdFx0XHR2YXJpYWJsZXMgOiB0aGlzLnZhcmlhYmxlcyxcblx0XHR9O1xuXHRcdHJldHVybiBhbmFseXNpcztcblx0fVxuXG5cdC8qKlxuXHQgKiBNYXAgYSB1c2FnZSBsb2NhdGlvbiBzdHJpbmcgKCdhYnMvZmlsZS50czpsaW5lOmNvbCcpIHRvIHRoZSBpbm5lcm1vc3Rcblx0ICogc2NvcGUgY29udGFpbmluZyBpdC4gTW9kdWxlIHNjb3BlIGlzIHRoZSBmYWxsYmFjaywgc28gZXZlcnkgbG9jYXRpb25cblx0ICogaW5zaWRlIGEgdHJhY2tlZCBmaWxlIHJlc29sdmVzIHRvIHNvbWUgc2NvcGUuXG5cdCAqL1xuXHRmaW5kSG9sZGVyU2NvcGVJZCAobG9jYXRpb246IHN0cmluZyk6IHN0cmluZyB8IHVuZGVmaW5lZCB7XG5cdFx0Y29uc3QgbGFzdENvbG9uID0gbG9jYXRpb24ubGFzdEluZGV4T2YoJzonKTtcblx0XHRjb25zdCBwcmV2Q29sb24gPSBsb2NhdGlvbi5sYXN0SW5kZXhPZignOicsIGxhc3RDb2xvbiAtIDEpO1xuXHRcdGlmIChsYXN0Q29sb24gPCAwIHx8IHByZXZDb2xvbiA8IDApIHtcblx0XHRcdHJldHVybiB1bmRlZmluZWQ7XG5cdFx0fVxuXHRcdGNvbnN0IGZpbGVQYXRoID0gcGF0aC5yZXNvbHZlKGxvY2F0aW9uLnNsaWNlKDAsIHByZXZDb2xvbikpO1xuXHRcdGNvbnN0IGxpbmUgPSBOdW1iZXIobG9jYXRpb24uc2xpY2UocHJldkNvbG9uICsgMSwgbGFzdENvbG9uKSk7XG5cdFx0Y29uc3QgY29sID0gTnVtYmVyKGxvY2F0aW9uLnNsaWNlKGxhc3RDb2xvbiArIDEpKTtcblx0XHRpZiAoIU51bWJlci5pc0Zpbml0ZShsaW5lKSB8fCAhTnVtYmVyLmlzRmluaXRlKGNvbCkpIHtcblx0XHRcdHJldHVybiB1bmRlZmluZWQ7XG5cdFx0fVxuXG5cdFx0Y29uc3Qgc3BhbnMgPSB0aGlzLnNwYW5zLmdldChmaWxlUGF0aCk7XG5cdFx0aWYgKCFzcGFucykge1xuXHRcdFx0cmV0dXJuIHVuZGVmaW5lZDtcblx0XHR9XG5cblx0XHRsZXQgYmVzdDogU2NvcGVTcGFuIHwgdW5kZWZpbmVkO1xuXHRcdGZvciAoY29uc3Qgc3BhbiBvZiBzcGFucykge1xuXHRcdFx0Y29uc3Qgc3RhcnRzQmVmb3JlID0gc3Bhbi5zdGFydExpbmUgPCBsaW5lIHx8IChzcGFuLnN0YXJ0TGluZSA9PT0gbGluZSAmJiBzcGFuLnN0YXJ0Q29sIDw9IGNvbCk7XG5cdFx0XHRjb25zdCBlbmRzQWZ0ZXIgPSBzcGFuLmVuZExpbmUgPiBsaW5lIHx8IChzcGFuLmVuZExpbmUgPT09IGxpbmUgJiYgc3Bhbi5lbmRDb2wgPj0gY29sKTtcblx0XHRcdGlmICghc3RhcnRzQmVmb3JlIHx8ICFlbmRzQWZ0ZXIpIHtcblx0XHRcdFx0Y29udGludWU7XG5cdFx0XHR9XG5cdFx0XHQvLyBJbm5lcm1vc3QgPSBzbWFsbGVzdCBjb250YWluaW5nIHNwYW5cblx0XHRcdGlmIChiZXN0ICYmIChiZXN0LnN0YXJ0TGluZSA8IHNwYW4uc3RhcnRMaW5lIHx8XG5cdFx0XHRcdChiZXN0LnN0YXJ0TGluZSA9PT0gc3Bhbi5zdGFydExpbmUgJiYgYmVzdC5zdGFydENvbCA8PSBzcGFuLnN0YXJ0Q29sKSkpIHtcblx0XHRcdFx0YmVzdCA9IHNwYW47XG5cdFx0XHRcdGNvbnRpbnVlO1xuXHRcdFx0fVxuXHRcdFx0aWYgKCFiZXN0KSB7XG5cdFx0XHRcdGJlc3QgPSBzcGFuO1xuXHRcdFx0fVxuXHRcdH1cblx0XHRjb25zdCByZXN1bHQgPSBiZXN0Py5zY29wZUlkO1xuXHRcdHJldHVybiByZXN1bHQ7XG5cdH1cblxuXHQvKipcblx0ICogUmVtb3ZlIGV2ZXJ5IHJlY29yZCBiZWxvbmdpbmcgdG8gb25lIGZpbGUgKHJlLWFkZCBzdXBwb3J0KS5cblx0ICovXG5cdHByaXZhdGUgZHJvcEZpbGUgKGZpbGVQYXRoOiBzdHJpbmcpOiB2b2lkIHtcblx0XHRmb3IgKGNvbnN0IFsgc2NvcGVJZCwgc2NvcGUgXSBvZiB0aGlzLnNjb3Blcykge1xuXHRcdFx0aWYgKHNjb3BlLmZpbGVQYXRoID09PSBmaWxlUGF0aCkge1xuXHRcdFx0XHR0aGlzLnNjb3Blcy5kZWxldGUoc2NvcGVJZCk7XG5cdFx0XHR9XG5cdFx0fVxuXHRcdGZvciAoY29uc3Qga2V5IG9mIEFycmF5LmZyb20odGhpcy52YXJpYWJsZXMua2V5cygpKSkge1xuXHRcdFx0aWYgKGtleS5zdGFydHNXaXRoKGAke2ZpbGVQYXRofSNgKSB8fCBrZXkuc3RhcnRzV2l0aChgJHtmaWxlUGF0aH06YCkpIHtcblx0XHRcdFx0dGhpcy52YXJpYWJsZXMuZGVsZXRlKGtleSk7XG5cdFx0XHR9XG5cdFx0fVxuXHRcdHRoaXMucGVuZGluZyA9IHRoaXMucGVuZGluZy5maWx0ZXIoZW50cnkgPT5cblx0XHRcdCFlbnRyeS52YXJpYWJsZS5kZWNsYXJhdGlvbi5zdGFydHNXaXRoKGAke2ZpbGVQYXRofTpgKSk7XG5cdFx0dGhpcy5zcGFucy5kZWxldGUoZmlsZVBhdGgpO1xuXHR9XG5cblx0LyoqXG5cdCAqIEF0dGFjaCBob2xkZXJTY29wZUlkIHRvIGV2ZXJ5IHVzYWdlIHdob3NlIGxvY2F0aW9uIGZhbGxzIGluc2lkZSBhXG5cdCAqIHRyYWNrZWQgc2NvcGUuIEFkZGl0aXZlIG9uIFVzYWdlSW5mbzsgdXNhZ2VzIG91dHNpZGUgdHJhY2tlZCBmaWxlc1xuXHQgKiBhcmUgbGVmdCB1bnRvdWNoZWQuXG5cdCAqL1xuXHRzdGF0aWMgYXR0YWNoSG9sZGVyU2NvcGVJZHMgKHVzYWdlczogTWFwPHN0cmluZywgVXNhZ2VJbmZvW10+LCB3YWxrZXI6IExvY2FsU2NvcGVXYWxrZXIpOiB2b2lkIHtcblx0XHRmb3IgKGNvbnN0IHVzYWdlTGlzdCBvZiB1c2FnZXMudmFsdWVzKCkpIHtcblx0XHRcdGZvciAoY29uc3QgdXNhZ2Ugb2YgdXNhZ2VMaXN0KSB7XG5cdFx0XHRcdGNvbnN0IHNjb3BlSWQgPSB3YWxrZXIuZmluZEhvbGRlclNjb3BlSWQodXNhZ2UubG9jYXRpb24pO1xuXHRcdFx0XHRpZiAoc2NvcGVJZCkge1xuXHRcdFx0XHRcdHVzYWdlLmhvbGRlclNjb3BlSWQgPSBzY29wZUlkO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fVxuXHR9XG5cblx0cHJpdmF0ZSB2aXNpdE5vZGUgKFxuXHRcdG5vZGU6IHRzLk5vZGUsXG5cdFx0c291cmNlRmlsZTogdHMuU291cmNlRmlsZSxcblx0XHRmaWxlUGF0aDogc3RyaW5nLFxuXHRcdHNjb3BlU3RhY2s6IHN0cmluZ1tdLFxuXHRcdGNsYXNzU3RhY2s6IHN0cmluZ1tdLFxuXHRcdHNwYW5zOiBTY29wZVNwYW5bXVxuXHQpOiB2b2lkIHtcblx0XHRjb25zdCBzY29wZUtpbmQgPSBMb2NhbFNjb3BlV2Fsa2VyLnNjb3BlS2luZE9mKG5vZGUpO1xuXHRcdGxldCBlbnRlcmVkID0gZmFsc2U7XG5cdFx0aWYgKHNjb3BlS2luZCAmJiB0aGlzLmhhc0JvZHkobm9kZSkpIHtcblx0XHRcdHRoaXMuZW50ZXJTY29wZShub2RlLCBzY29wZUtpbmQsIHNvdXJjZUZpbGUsIGZpbGVQYXRoLCBzY29wZVN0YWNrLCBjbGFzc1N0YWNrLCBzcGFucyk7XG5cdFx0XHRlbnRlcmVkID0gdHJ1ZTtcblx0XHR9XG5cblx0XHRjb25zdCBpc0NsYXNzID0gdHMuaXNDbGFzc0RlY2xhcmF0aW9uKG5vZGUpIHx8IHRzLmlzQ2xhc3NFeHByZXNzaW9uKG5vZGUpO1xuXHRcdGlmIChpc0NsYXNzKSB7XG5cdFx0XHRjbGFzc1N0YWNrLnB1c2gobm9kZS5uYW1lPy50ZXh0ID8/ICcnKTtcblx0XHR9XG5cblx0XHR0aGlzLmNvbGxlY3RCb3VuZE5hbWUobm9kZSk7XG5cdFx0dGhpcy5jb2xsZWN0VmFyaWFibGVEZWNsYXJhdGlvbkxpc3Qobm9kZSwgc291cmNlRmlsZSwgc2NvcGVTdGFjayk7XG5cdFx0dGhpcy5jb2xsZWN0UmVhc3NpZ25tZW50KG5vZGUsIHNvdXJjZUZpbGUsIHNjb3BlU3RhY2spO1xuXG5cdFx0dHMuZm9yRWFjaENoaWxkKG5vZGUsIGNoaWxkID0+IHtcblx0XHRcdHRoaXMudmlzaXROb2RlKGNoaWxkLCBzb3VyY2VGaWxlLCBmaWxlUGF0aCwgc2NvcGVTdGFjaywgY2xhc3NTdGFjaywgc3BhbnMpO1xuXHRcdH0pO1xuXG5cdFx0aWYgKGlzQ2xhc3MpIHtcblx0XHRcdGNsYXNzU3RhY2sucG9wKCk7XG5cdFx0fVxuXHRcdGlmIChlbnRlcmVkKSB7XG5cdFx0XHRzY29wZVN0YWNrLnBvcCgpO1xuXHRcdH1cblx0fVxuXG5cdHByaXZhdGUgc3RhdGljIHNjb3BlS2luZE9mIChub2RlOiB0cy5Ob2RlKTogU2NvcGVLaW5kIHwgdW5kZWZpbmVkIHtcblx0XHRpZiAodHMuaXNNZXRob2REZWNsYXJhdGlvbihub2RlKSB8fCB0cy5pc0dldEFjY2Vzc29yRGVjbGFyYXRpb24obm9kZSkgfHxcblx0XHRcdHRzLmlzU2V0QWNjZXNzb3JEZWNsYXJhdGlvbihub2RlKSB8fCB0cy5pc0NvbnN0cnVjdG9yRGVjbGFyYXRpb24obm9kZSkpIHtcblx0XHRcdHJldHVybiAnbWV0aG9kJztcblx0XHR9XG5cdFx0aWYgKHRzLmlzRnVuY3Rpb25EZWNsYXJhdGlvbihub2RlKSB8fCB0cy5pc0Z1bmN0aW9uRXhwcmVzc2lvbihub2RlKSkge1xuXHRcdFx0cmV0dXJuICdmdW5jdGlvbic7XG5cdFx0fVxuXHRcdGlmICh0cy5pc0Fycm93RnVuY3Rpb24obm9kZSkpIHtcblx0XHRcdHJldHVybiAnYXJyb3cnO1xuXHRcdH1cblx0XHRyZXR1cm4gdW5kZWZpbmVkO1xuXHR9XG5cblx0cHJpdmF0ZSBoYXNCb2R5IChub2RlOiB0cy5Ob2RlKTogYm9vbGVhbiB7XG5cdFx0Y29uc3QgYm9keUhvbGRlciA9IG5vZGUgYXMgdHMuRnVuY3Rpb25MaWtlRGVjbGFyYXRpb247XG5cdFx0Y29uc3QgcmVzdWx0ID0gYm9keUhvbGRlci5ib2R5ICE9PSB1bmRlZmluZWQ7XG5cdFx0cmV0dXJuIHJlc3VsdDtcblx0fVxuXG5cdHByaXZhdGUgZW50ZXJTY29wZSAoXG5cdFx0bm9kZTogdHMuTm9kZSxcblx0XHRraW5kOiBTY29wZUtpbmQsXG5cdFx0c291cmNlRmlsZTogdHMuU291cmNlRmlsZSxcblx0XHRmaWxlUGF0aDogc3RyaW5nLFxuXHRcdHNjb3BlU3RhY2s6IHN0cmluZ1tdLFxuXHRcdGNsYXNzU3RhY2s6IHN0cmluZ1tdLFxuXHRcdHNwYW5zOiBTY29wZVNwYW5bXVxuXHQpOiB2b2lkIHtcblx0XHRjb25zdCB7IGxpbmUsIGNoYXJhY3RlciB9ID0gc291cmNlRmlsZS5nZXRMaW5lQW5kQ2hhcmFjdGVyT2ZQb3NpdGlvbihub2RlLmdldFN0YXJ0KHNvdXJjZUZpbGUpKTtcblx0XHRjb25zdCBzY29wZUlkID0gYCR7ZmlsZVBhdGh9OiR7bGluZSArIDF9OiR7Y2hhcmFjdGVyICsgMX1gO1xuXHRcdGNvbnN0IHBhcmVudFNjb3BlSWQgPSBzY29wZVN0YWNrWyBzY29wZVN0YWNrLmxlbmd0aCAtIDEgXTtcblxuXHRcdGNvbnN0IHNjb3BlOiBTY29wZUluZm8gPSB7XG5cdFx0XHRzY29wZUlkLFxuXHRcdFx0bmFtZSAgICAgOiB0aGlzLnNjb3BlTmFtZShub2RlLCBraW5kLCBmaWxlUGF0aCwgbGluZSArIDEsIGNsYXNzU3RhY2spLFxuXHRcdFx0a2luZCxcblx0XHRcdHBhcmVudFNjb3BlSWQsXG5cdFx0XHRmaWxlUGF0aCxcblx0XHRcdGxvY2F0aW9uIDogc2NvcGVJZCxcblx0XHR9O1xuXHRcdHRoaXMuc2NvcGVzLnNldChzY29wZUlkLCBzY29wZSk7XG5cdFx0c3BhbnMucHVzaCh0aGlzLnNwYW5PZihub2RlLCBzb3VyY2VGaWxlLCBzY29wZUlkKSk7XG5cdFx0c2NvcGVTdGFjay5wdXNoKHNjb3BlSWQpO1xuXG5cdFx0Ly8gUGFyYW1ldGVycyBhcmUgdmFyaWFibGVzIG9mIHRoZSBzY29wZTsgdGhleSBhcmUgcmVhc3NpZ25hYmxlLCBzb1xuXHRcdC8vIGlzTXV0YWJsZTogdHJ1ZSDigJQgYSBwYXJhbWV0ZXIgcmVhc3NpZ25tZW50IHRlcm1pbmF0ZXMgdGhlIGZsb3cgdG9vXG5cdFx0Y29uc3QgZm4gPSBub2RlIGFzIHRzLkZ1bmN0aW9uTGlrZURlY2xhcmF0aW9uO1xuXHRcdGZvciAoY29uc3QgcGFyYW0gb2YgZm4ucGFyYW1ldGVycyA/PyBbXSkge1xuXHRcdFx0aWYgKCF0cy5pc0lkZW50aWZpZXIocGFyYW0ubmFtZSkpIHtcblx0XHRcdFx0Ly8gU2tpcCBkZXN0cnVjdHVyZWQgcGFyYW1ldGVycyAoYW5hbHl6ZXIgcHJlY2VkZW50KVxuXHRcdFx0XHRjb250aW51ZTtcblx0XHRcdH1cblx0XHRcdHRoaXMucmVjb3JkVmFyaWFibGUocGFyYW0ubmFtZS50ZXh0LCBwYXJhbS5uYW1lLCBzb3VyY2VGaWxlLCBzY29wZVN0YWNrLCB7XG5cdFx0XHRcdGlzUGFyYW1ldGVyIDogdHJ1ZSxcblx0XHRcdFx0Ly8gYHRoaXNgIHBhcmFtZXRlcnMgKG1uZW1vbmljYSBoYW5kbGVycykgYXJlIG5ldmVyIHJlYXNzaWduYWJsZVxuXHRcdFx0XHRpc011dGFibGUgICA6IHBhcmFtLm5hbWUudGV4dCAhPT0gJ3RoaXMnLFxuXHRcdFx0XHRhbm5vdGF0aW9uICA6IHBhcmFtLnR5cGU/LmdldFRleHQoc291cmNlRmlsZSksXG5cdFx0XHR9KTtcblx0XHR9XG5cdH1cblxuXHQvKipcblx0ICogRGVjaXNpb24gOCBsYWJlbGluZzogZnVuY3Rpb25zIGJ5IG5hbWU7IG1ldGhvZHMgYXMgQ2xhc3MubWV0aG9kO1xuXHQgKiBhcnJvd3MvZnVuY3Rpb25zIGJvdW5kIHRvIGEgdmFyaWFibGUgb3IgcHJvcGVydHkgdGFrZSB0aGF0IG5hbWU7XG5cdCAqIGFub255bW91cyBob2xkZXJzIGFyZSBsYWJlbGVkIGZpbGU6bGluZS5cblx0ICovXG5cdHByaXZhdGUgc2NvcGVOYW1lIChcblx0XHRub2RlOiB0cy5Ob2RlLFxuXHRcdGtpbmQ6IFNjb3BlS2luZCxcblx0XHRmaWxlUGF0aDogc3RyaW5nLFxuXHRcdGxpbmU6IG51bWJlcixcblx0XHRjbGFzc1N0YWNrOiBzdHJpbmdbXVxuXHQpOiBzdHJpbmcge1xuXHRcdGNvbnN0IG5hbWVkID0gbm9kZSBhcyB0cy5OYW1lZERlY2xhcmF0aW9uO1xuXHRcdGlmIChraW5kID09PSAnbWV0aG9kJykge1xuXHRcdFx0Y29uc3QgbWV0aG9kTmFtZSA9IG5hbWVkLm5hbWUgPyBuYW1lZC5uYW1lLmdldFRleHQoKSA6ICdhbm9ueW1vdXMnO1xuXHRcdFx0Y29uc3QgY2xhc3NOYW1lID0gY2xhc3NTdGFja1sgY2xhc3NTdGFjay5sZW5ndGggLSAxIF07XG5cdFx0XHRjb25zdCBjdG9yID0gdHMuaXNDb25zdHJ1Y3RvckRlY2xhcmF0aW9uKG5vZGUpID8gJ2NvbnN0cnVjdG9yJyA6IG1ldGhvZE5hbWU7XG5cdFx0XHRjb25zdCBtZXRob2RTY29wZU5hbWUgPSBjbGFzc05hbWUgPyBgJHtjbGFzc05hbWV9LiR7Y3Rvcn1gIDogY3Rvcjtcblx0XHRcdHJldHVybiBtZXRob2RTY29wZU5hbWU7XG5cdFx0fVxuXHRcdGlmIChuYW1lZC5uYW1lICYmIHRzLmlzSWRlbnRpZmllcihuYW1lZC5uYW1lKSkge1xuXHRcdFx0Y29uc3QgZGVjbGFyZWROYW1lID0gbmFtZWQubmFtZS50ZXh0O1xuXHRcdFx0cmV0dXJuIGRlY2xhcmVkTmFtZTtcblx0XHR9XG5cdFx0Ly8gQm91bmQgbmFtZXMgY29tZSBmcm9tIHRoZSBib3VuZE5hbWVzIG1hcCDigJQgcHJvZ3JhbSBmaWxlcyBtYXkgYmVcblx0XHQvLyB1bmJvdW5kLCBzbyBub2RlLnBhcmVudCBpcyBub3QgYSByZWxpYWJsZSBwYXRoIHRvIHRoZSB2YXJpYWJsZSBuYW1lXG5cdFx0Y29uc3QgYm91bmQgPSB0aGlzLmJvdW5kTmFtZXMuZ2V0KG5vZGUpO1xuXHRcdGlmIChib3VuZCkge1xuXHRcdFx0cmV0dXJuIGJvdW5kO1xuXHRcdH1cblx0XHRjb25zdCByZXN1bHQgPSBgJHtmaWxlUGF0aH06JHtsaW5lfWA7XG5cdFx0cmV0dXJuIHJlc3VsdDtcblx0fVxuXG5cdHByaXZhdGUgc3Bhbk9mIChcblx0XHRub2RlOiB0cy5Ob2RlLFxuXHRcdHNvdXJjZUZpbGU6IHRzLlNvdXJjZUZpbGUsXG5cdFx0c2NvcGVJZDogc3RyaW5nXG5cdCk6IFNjb3BlU3BhbiB7XG5cdFx0Y29uc3Qgc3RhcnQgPSBzb3VyY2VGaWxlLmdldExpbmVBbmRDaGFyYWN0ZXJPZlBvc2l0aW9uKG5vZGUuZ2V0U3RhcnQoc291cmNlRmlsZSkpO1xuXHRcdGNvbnN0IGVuZCA9IHNvdXJjZUZpbGUuZ2V0TGluZUFuZENoYXJhY3Rlck9mUG9zaXRpb24obm9kZS5nZXRFbmQoKSk7XG5cdFx0Y29uc3Qgc3BhbjogU2NvcGVTcGFuID0ge1xuXHRcdFx0c2NvcGVJZCxcblx0XHRcdHN0YXJ0TGluZSA6IHN0YXJ0LmxpbmUgKyAxLFxuXHRcdFx0c3RhcnRDb2wgIDogc3RhcnQuY2hhcmFjdGVyICsgMSxcblx0XHRcdGVuZExpbmUgICA6IGVuZC5saW5lICsgMSxcblx0XHRcdGVuZENvbCAgICA6IGVuZC5jaGFyYWN0ZXIgKyAxLFxuXHRcdH07XG5cdFx0cmV0dXJuIHNwYW47XG5cdH1cblxuXHQvKipcblx0ICogUmVjb3JkIHRoZSBuYW1lIGFuIGFycm93L2Z1bmN0aW9uLWV4cHJlc3Npb24gaXMgYm91bmQgdG8sIHdpdGhvdXRcblx0ICogcmVseWluZyBvbiBub2RlLnBhcmVudCAodW5ib3VuZCBwcm9ncmFtIGZpbGVzKTogYGNvbnN0IGYgPSAoKSA9PiDigKZgLFxuXHQgKiBgeyBoYW5kbGVyOiAoKSA9PiDigKYgfWAsIGBjbGFzcyBDIHsgcnVuID0gKCkgPT4g4oCmIH1gLlxuXHQgKi9cblx0cHJpdmF0ZSBjb2xsZWN0Qm91bmROYW1lIChub2RlOiB0cy5Ob2RlKTogdm9pZCB7XG5cdFx0aWYgKHRzLmlzVmFyaWFibGVEZWNsYXJhdGlvbihub2RlKSAmJiB0cy5pc0lkZW50aWZpZXIobm9kZS5uYW1lKSAmJiBub2RlLmluaXRpYWxpemVyICYmXG5cdFx0XHQodHMuaXNBcnJvd0Z1bmN0aW9uKG5vZGUuaW5pdGlhbGl6ZXIpIHx8IHRzLmlzRnVuY3Rpb25FeHByZXNzaW9uKG5vZGUuaW5pdGlhbGl6ZXIpKSkge1xuXHRcdFx0dGhpcy5ib3VuZE5hbWVzLnNldChub2RlLmluaXRpYWxpemVyLCBub2RlLm5hbWUudGV4dCk7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXHRcdGlmICgodHMuaXNQcm9wZXJ0eUFzc2lnbm1lbnQobm9kZSkgfHwgdHMuaXNQcm9wZXJ0eURlY2xhcmF0aW9uKG5vZGUpKSAmJlxuXHRcdFx0dHMuaXNJZGVudGlmaWVyKG5vZGUubmFtZSkgJiYgbm9kZS5pbml0aWFsaXplciAmJlxuXHRcdFx0KHRzLmlzQXJyb3dGdW5jdGlvbihub2RlLmluaXRpYWxpemVyKSB8fCB0cy5pc0Z1bmN0aW9uRXhwcmVzc2lvbihub2RlLmluaXRpYWxpemVyKSkpIHtcblx0XHRcdHRoaXMuYm91bmROYW1lcy5zZXQobm9kZS5pbml0aWFsaXplciwgbm9kZS5uYW1lLnRleHQpO1xuXHRcdH1cblx0fVxuXG5cdHByaXZhdGUgY29sbGVjdFZhcmlhYmxlRGVjbGFyYXRpb25MaXN0IChcblx0XHRub2RlOiB0cy5Ob2RlLFxuXHRcdHNvdXJjZUZpbGU6IHRzLlNvdXJjZUZpbGUsXG5cdFx0c2NvcGVTdGFjazogc3RyaW5nW11cblx0KTogdm9pZCB7XG5cdFx0aWYgKCF0cy5pc1ZhcmlhYmxlRGVjbGFyYXRpb25MaXN0KG5vZGUpKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXHRcdC8vIEZsYWdzIGxpdmUgb24gdGhlIGxpc3QgaXRzZWxmIOKAlCBubyBwYXJlbnQgd2FsayBuZWVkZWQgKHRoZSBsaXN0J3Ncblx0XHQvLyBwYXJlbnQgbWF5IGJlIHVuc2V0IG9uIHVuYm91bmQgcHJvZ3JhbSBmaWxlcylcblx0XHRjb25zdCBpc0NvbnN0ID0gKG5vZGUuZmxhZ3MgJiB0cy5Ob2RlRmxhZ3MuQ29uc3QpICE9PSAwO1xuXHRcdGZvciAoY29uc3QgZGVjbCBvZiBub2RlLmRlY2xhcmF0aW9ucykge1xuXHRcdFx0Ly8gRGVzdHJ1Y3R1cmluZyBkZWNsYXJhdGlvbnMgYXJlIHNraXBwZWQ6IG9ubHkgcGxhaW5cblx0XHRcdC8vIGBjb25zdC9sZXQvdmFyIHggPSDigKZgIGhhcyBhbiBpZGVudGlmaWVyIG5hbWVcblx0XHRcdGlmICghdHMuaXNJZGVudGlmaWVyKGRlY2wubmFtZSkpIHtcblx0XHRcdFx0Y29udGludWU7XG5cdFx0XHR9XG5cdFx0XHR0aGlzLnJlY29yZFZhcmlhYmxlKGRlY2wubmFtZS50ZXh0LCBkZWNsLm5hbWUsIHNvdXJjZUZpbGUsIHNjb3BlU3RhY2ssIHtcblx0XHRcdFx0aXNQYXJhbWV0ZXIgOiBmYWxzZSxcblx0XHRcdFx0aXNNdXRhYmxlICAgOiAhaXNDb25zdCxcblx0XHRcdFx0YW5ub3RhdGlvbiAgOiBkZWNsLnR5cGU/LmdldFRleHQoc291cmNlRmlsZSksXG5cdFx0XHRcdGluaXRpYWxpemVyIDogZGVjbC5pbml0aWFsaXplcixcblx0XHRcdH0pO1xuXHRcdH1cblx0fVxuXG5cdHByaXZhdGUgcmVjb3JkVmFyaWFibGUgKFxuXHRcdG5hbWU6IHN0cmluZyxcblx0XHRub2RlOiB0cy5Ob2RlLFxuXHRcdHNvdXJjZUZpbGU6IHRzLlNvdXJjZUZpbGUsXG5cdFx0c2NvcGVTdGFjazogc3RyaW5nW10sXG5cdFx0b3B0aW9uczoge1xuXHRcdFx0aXNQYXJhbWV0ZXI6IGJvb2xlYW47XG5cdFx0XHRpc011dGFibGU6IGJvb2xlYW47XG5cdFx0XHRhbm5vdGF0aW9uPzogc3RyaW5nO1xuXHRcdFx0aW5pdGlhbGl6ZXI/OiB0cy5FeHByZXNzaW9uO1xuXHRcdH1cblx0KTogdm9pZCB7XG5cdFx0Y29uc3Qgc2NvcGVJZCA9IHNjb3BlU3RhY2tbIHNjb3BlU3RhY2subGVuZ3RoIC0gMSBdO1xuXHRcdGNvbnN0IHsgbGluZSwgY2hhcmFjdGVyIH0gPSBzb3VyY2VGaWxlLmdldExpbmVBbmRDaGFyYWN0ZXJPZlBvc2l0aW9uKG5vZGUuZ2V0U3RhcnQoc291cmNlRmlsZSkpO1xuXHRcdGNvbnN0IGZpbGVQYXRoID0gcGF0aC5yZXNvbHZlKHNvdXJjZUZpbGUuZmlsZU5hbWUpO1xuXG5cdFx0Y29uc3QgdmFyaWFibGU6IFNjb3BlVmFyaWFibGUgPSB7XG5cdFx0XHRuYW1lLFxuXHRcdFx0c2NvcGVJZCxcblx0XHRcdGRlY2xhcmF0aW9uICAgOiBgJHtmaWxlUGF0aH06JHtsaW5lICsgMX06JHtjaGFyYWN0ZXIgKyAxfWAsXG5cdFx0XHRpc1BhcmFtZXRlciAgIDogb3B0aW9ucy5pc1BhcmFtZXRlcixcblx0XHRcdGlzTXV0YWJsZSAgICAgOiBvcHRpb25zLmlzTXV0YWJsZSxcblx0XHRcdHJlYXNzaWdubWVudHMgOiBbXSxcblx0XHR9O1xuXHRcdGNvbnN0IGluZmVycmVkID0gb3B0aW9ucy5hbm5vdGF0aW9uID8/IChcblx0XHRcdG9wdGlvbnMuaW5pdGlhbGl6ZXIgPyBMb2NhbFNjb3BlV2Fsa2VyLmluZmVySW5pdGlhbGl6ZXJLaW5kKG9wdGlvbnMuaW5pdGlhbGl6ZXIpIDogdW5kZWZpbmVkXG5cdFx0KTtcblx0XHRpZiAoaW5mZXJyZWQpIHtcblx0XHRcdHZhcmlhYmxlLmluZmVycmVkVHlwZSA9IGluZmVycmVkO1xuXHRcdH1cblxuXHRcdGNvbnN0IHBlbmRpbmdFbnRyeTogUGVuZGluZ1ZhcmlhYmxlID0ge1xuXHRcdFx0dmFyaWFibGUsXG5cdFx0XHRzY29wZUNoYWluIDogWyAuLi5zY29wZVN0YWNrIF0ucmV2ZXJzZSgpLFxuXHRcdFx0YW5ub3RhdGlvbiA6IG9wdGlvbnMuYW5ub3RhdGlvbixcblx0XHR9O1xuXHRcdGNvbnN0IHsgaW5pdGlhbGl6ZXIgfSA9IG9wdGlvbnM7XG5cdFx0aWYgKGluaXRpYWxpemVyICYmIHRzLmlzTmV3RXhwcmVzc2lvbihpbml0aWFsaXplcikpIHtcblx0XHRcdGNvbnN0IHsgZXhwcmVzc2lvbiB9ID0gaW5pdGlhbGl6ZXI7XG5cdFx0XHRpZiAodHMuaXNJZGVudGlmaWVyKGV4cHJlc3Npb24pKSB7XG5cdFx0XHRcdHBlbmRpbmdFbnRyeS5uZXdOYW1lID0gZXhwcmVzc2lvbi50ZXh0O1xuXHRcdFx0fSBlbHNlIGlmICh0cy5pc1Byb3BlcnR5QWNjZXNzRXhwcmVzc2lvbihleHByZXNzaW9uKSkge1xuXHRcdFx0XHRjb25zdCBjaGFpbiA9IExvY2FsU2NvcGVXYWxrZXIudW53cmFwUHJvcGVydHlBY2Nlc3MoZXhwcmVzc2lvbik7XG5cdFx0XHRcdGlmIChjaGFpbi5sZW5ndGggPiAxKSB7XG5cdFx0XHRcdFx0Y29uc3QgWyByb290LCAuLi5yZXN0IF0gPSBjaGFpbjtcblx0XHRcdFx0XHRwZW5kaW5nRW50cnkubmV3Q2hhaW5Sb290ID0gcm9vdDtcblx0XHRcdFx0XHRwZW5kaW5nRW50cnkubmV3Q2hhaW5SZXN0ID0gcmVzdDtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH1cblx0XHRpZiAoaW5pdGlhbGl6ZXIgJiYgdHMuaXNDYWxsRXhwcmVzc2lvbihpbml0aWFsaXplcikpIHtcblx0XHRcdGNvbnN0IGxvb2t1cCA9IExvY2FsU2NvcGVXYWxrZXIudW53cmFwTG9va3VwQ2FsbChpbml0aWFsaXplcik7XG5cdFx0XHRpZiAobG9va3VwKSB7XG5cdFx0XHRcdHBlbmRpbmdFbnRyeS5sb29rdXBQYXRoID0gbG9va3VwLnBhdGg7XG5cdFx0XHRcdHBlbmRpbmdFbnRyeS5sb29rdXBSZWNlaXZlciA9IGxvb2t1cC5yZWNlaXZlcjtcblx0XHRcdH1cblx0XHR9XG5cdFx0dGhpcy5wZW5kaW5nLnB1c2gocGVuZGluZ0VudHJ5KTtcblx0XHR0aGlzLnZhcmlhYmxlcy5zZXQoYCR7c2NvcGVJZH0jJHtuYW1lfWAsIHZhcmlhYmxlKTtcblx0fVxuXG5cdC8qKlxuXHQgKiBgYS5iLmNgIOKGkiBbJ2EnLCAnYicsICdjJ10gKGxlZnQtdG8tcmlnaHQpOyB1bmRlZmluZWQtc2FmZSBmb3Jcblx0ICogbm9uLWlkZW50aWZpZXIgcm9vdHMuXG5cdCAqL1xuXHRwcml2YXRlIHN0YXRpYyB1bndyYXBQcm9wZXJ0eUFjY2VzcyAoZXhwcmVzc2lvbjogdHMuUHJvcGVydHlBY2Nlc3NFeHByZXNzaW9uKTogc3RyaW5nW10ge1xuXHRcdGNvbnN0IGNoYWluOiBzdHJpbmdbXSA9IFtdO1xuXHRcdGxldCBjdXJyZW50OiB0cy5FeHByZXNzaW9uID0gZXhwcmVzc2lvbjtcblx0XHR3aGlsZSAodHMuaXNQcm9wZXJ0eUFjY2Vzc0V4cHJlc3Npb24oY3VycmVudCkpIHtcblx0XHRcdGNoYWluLnVuc2hpZnQoY3VycmVudC5uYW1lLnRleHQpO1xuXHRcdFx0Y3VycmVudCA9IGN1cnJlbnQuZXhwcmVzc2lvbjtcblx0XHR9XG5cdFx0aWYgKHRzLmlzSWRlbnRpZmllcihjdXJyZW50KSkge1xuXHRcdFx0Y2hhaW4udW5zaGlmdChjdXJyZW50LnRleHQpO1xuXHRcdH1cblx0XHRyZXR1cm4gY2hhaW47XG5cdH1cblxuXHQvKipcblx0ICogYGxvb2t1cCgnQS5CJylgLCBgQXBwLmxvb2t1cCgnQS5CJylgLCBgbG9va3VwKHNvdXJjZSwgJ0EuQicpYCDihpIgdGhlXG5cdCAqIHN0cmluZy1saXRlcmFsIHBhdGggcGx1cyB0aGUgcmVjZWl2ZXIncyByb290IGlkZW50aWZpZXIgd2hlbiB0aGVyZSBpc1xuXHQgKiBvbmUuIE9ubHkgbGl0ZXJhbCBwYXRocyBhcmUgdHJhY2tlZDogYSBjb21wdXRlZCBwYXRoIGlzIGRhdGEgdGhlIHN0YXRpY1xuXHQgKiB3YWxrZXIgY2Fubm90IGZvbGxvdywgc28gaXQgaXMgc2tpcHBlZCAodGhlIGFuYWx5emVyJ3MgdXNhZ2UgcGFzcyBzdGlsbFxuXHQgKiByZWNvcmRzIHRoZSBsb29rdXAgY2FsbCBpdHNlbGYpLlxuXHQgKi9cblx0cHJpdmF0ZSBzdGF0aWMgdW53cmFwTG9va3VwQ2FsbCAoY2FsbDogdHMuQ2FsbEV4cHJlc3Npb24pOiB7IHBhdGg6IHN0cmluZzsgcmVjZWl2ZXI/OiBzdHJpbmcgfSB8IHVuZGVmaW5lZCB7XG5cdFx0Y29uc3QgeyBleHByZXNzaW9uIH0gPSBjYWxsO1xuXHRcdGNvbnN0IFsgZmlyc3RBcmcsIHNlY29uZEFyZyBdID0gY2FsbC5hcmd1bWVudHM7XG5cblx0XHRpZiAodHMuaXNJZGVudGlmaWVyKGV4cHJlc3Npb24pKSB7XG5cdFx0XHRpZiAoZXhwcmVzc2lvbi50ZXh0ICE9PSAnbG9va3VwJykge1xuXHRcdFx0XHRyZXR1cm4gdW5kZWZpbmVkO1xuXHRcdFx0fVxuXHRcdFx0Ly8gbG9va3VwKCdBLkInKVxuXHRcdFx0aWYgKGZpcnN0QXJnICYmIHRzLmlzU3RyaW5nTGl0ZXJhbExpa2UoZmlyc3RBcmcpKSB7XG5cdFx0XHRcdGNvbnN0IHJlc3VsdCA9IHsgcGF0aCA6IGZpcnN0QXJnLnRleHQgfTtcblx0XHRcdFx0cmV0dXJuIHJlc3VsdDtcblx0XHRcdH1cblx0XHRcdC8vIGxvb2t1cChzb3VyY2UsICdBLkInKSDigJQgZXhwbGljaXQtc291cmNlIGZvcm1cblx0XHRcdGlmIChmaXJzdEFyZyAmJiB0cy5pc0lkZW50aWZpZXIoZmlyc3RBcmcpICYmIHNlY29uZEFyZyAmJiB0cy5pc1N0cmluZ0xpdGVyYWxMaWtlKHNlY29uZEFyZykpIHtcblx0XHRcdFx0Y29uc3QgcmVzdWx0ID0geyBwYXRoIDogc2Vjb25kQXJnLnRleHQsIHJlY2VpdmVyIDogZmlyc3RBcmcudGV4dCB9O1xuXHRcdFx0XHRyZXR1cm4gcmVzdWx0O1xuXHRcdFx0fVxuXHRcdFx0cmV0dXJuIHVuZGVmaW5lZDtcblx0XHR9XG5cblx0XHRpZiAodHMuaXNQcm9wZXJ0eUFjY2Vzc0V4cHJlc3Npb24oZXhwcmVzc2lvbikgJiYgZXhwcmVzc2lvbi5uYW1lLnRleHQgPT09ICdsb29rdXAnKSB7XG5cdFx0XHRpZiAoIWZpcnN0QXJnIHx8ICF0cy5pc1N0cmluZ0xpdGVyYWxMaWtlKGZpcnN0QXJnKSkge1xuXHRcdFx0XHRyZXR1cm4gdW5kZWZpbmVkO1xuXHRcdFx0fVxuXHRcdFx0Y29uc3QgY2hhaW4gPSBMb2NhbFNjb3BlV2Fsa2VyLnVud3JhcFByb3BlcnR5QWNjZXNzKGV4cHJlc3Npb24pO1xuXHRcdFx0Ly8gY2hhaW4gPCAyIG1lYW5zIG5vIGlkZW50aWZpZXIgcmVjZWl2ZXIgKGUuZy4gdGhpcy5sb29rdXAoJ0EuQicpKVxuXHRcdFx0aWYgKGNoYWluLmxlbmd0aCA8IDIpIHtcblx0XHRcdFx0Y29uc3QgcGF0aE9ubHkgPSB7IHBhdGggOiBmaXJzdEFyZy50ZXh0IH07XG5cdFx0XHRcdHJldHVybiBwYXRoT25seTtcblx0XHRcdH1cblx0XHRcdGNvbnN0IFsgcmVjZWl2ZXIgXSA9IGNoYWluO1xuXHRcdFx0Y29uc3QgcmVzdWx0ID0geyBwYXRoIDogZmlyc3RBcmcudGV4dCwgcmVjZWl2ZXIgfTtcblx0XHRcdHJldHVybiByZXN1bHQ7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIHVuZGVmaW5lZDtcblx0fVxuXG5cdC8qKlxuXHQgKiBDaGVhcCBpbml0aWFsaXplciBjbGFzc2lmaWNhdGlvbiBmb3IgaW5mZXJyZWRUeXBlLiBEZWxpYmVyYXRlbHkgdGlueTpcblx0ICogbGl0ZXJhbCBraW5kcyBhbmQgYG5ldyBYYCBjb25zdHJ1Y3RvciBuYW1lczsgZXZlcnl0aGluZyBlbHNlIHVuZGVmaW5lZC5cblx0ICovXG5cdHByaXZhdGUgc3RhdGljIGluZmVySW5pdGlhbGl6ZXJLaW5kIChpbml0aWFsaXplcjogdHMuRXhwcmVzc2lvbik6IHN0cmluZyB8IHVuZGVmaW5lZCB7XG5cdFx0aWYgKHRzLmlzU3RyaW5nTGl0ZXJhbExpa2UoaW5pdGlhbGl6ZXIpIHx8IHRzLmlzVGVtcGxhdGVFeHByZXNzaW9uKGluaXRpYWxpemVyKSkge1xuXHRcdFx0cmV0dXJuICdzdHJpbmcnO1xuXHRcdH1cblx0XHRpZiAodHMuaXNOdW1lcmljTGl0ZXJhbChpbml0aWFsaXplcikpIHtcblx0XHRcdHJldHVybiAnbnVtYmVyJztcblx0XHR9XG5cdFx0aWYgKGluaXRpYWxpemVyLmtpbmQgPT09IHRzLlN5bnRheEtpbmQuVHJ1ZUtleXdvcmQgfHwgaW5pdGlhbGl6ZXIua2luZCA9PT0gdHMuU3ludGF4S2luZC5GYWxzZUtleXdvcmQpIHtcblx0XHRcdHJldHVybiAnYm9vbGVhbic7XG5cdFx0fVxuXHRcdGlmICh0cy5pc0Fycm93RnVuY3Rpb24oaW5pdGlhbGl6ZXIpIHx8IHRzLmlzRnVuY3Rpb25FeHByZXNzaW9uKGluaXRpYWxpemVyKSkge1xuXHRcdFx0cmV0dXJuICdmdW5jdGlvbic7XG5cdFx0fVxuXHRcdGlmICh0cy5pc0FycmF5TGl0ZXJhbEV4cHJlc3Npb24oaW5pdGlhbGl6ZXIpKSB7XG5cdFx0XHRyZXR1cm4gJ0FycmF5PHVua25vd24+Jztcblx0XHR9XG5cdFx0aWYgKHRzLmlzTmV3RXhwcmVzc2lvbihpbml0aWFsaXplcikgJiYgdHMuaXNJZGVudGlmaWVyKGluaXRpYWxpemVyLmV4cHJlc3Npb24pKSB7XG5cdFx0XHRjb25zdCByZXN1bHQgPSBpbml0aWFsaXplci5leHByZXNzaW9uLnRleHQ7XG5cdFx0XHRyZXR1cm4gcmVzdWx0O1xuXHRcdH1cblx0XHRyZXR1cm4gdW5kZWZpbmVkO1xuXHR9XG5cblx0LyoqXG5cdCAqIFJlYXNzaWdubWVudCBvZiBhIGxldC92YXIvcGFyYW1ldGVyIGJpbmRpbmc6IGEgZmxvdy10ZXJtaW5hdGlvbiBwb2ludFxuXHQgKiAoZGVjaXNpb24gNikuIFJlY29yZGVkIG9uIHRoZSB2YXJpYWJsZSBzbyB0aGUgUGhhc2UgMyB3YWxrZXIgc3RvcHNcblx0ICogZm9sbG93aW5nIHRoYXQgYmluZGluZyB0aGVyZS5cblx0ICovXG5cdHByaXZhdGUgY29sbGVjdFJlYXNzaWdubWVudCAoXG5cdFx0bm9kZTogdHMuTm9kZSxcblx0XHRzb3VyY2VGaWxlOiB0cy5Tb3VyY2VGaWxlLFxuXHRcdHNjb3BlU3RhY2s6IHN0cmluZ1tdXG5cdCk6IHZvaWQge1xuXHRcdGxldCB0YXJnZXQ6IHRzLklkZW50aWZpZXIgfCB1bmRlZmluZWQ7XG5cdFx0aWYgKHRzLmlzQmluYXJ5RXhwcmVzc2lvbihub2RlKSAmJlxuXHRcdFx0QVNTSUdOTUVOVF9PUEVSQVRPUlMuaGFzKG5vZGUub3BlcmF0b3JUb2tlbi5raW5kKSAmJlxuXHRcdFx0dHMuaXNJZGVudGlmaWVyKG5vZGUubGVmdCkpIHtcblx0XHRcdHRhcmdldCA9IG5vZGUubGVmdDtcblx0XHR9XG5cdFx0aWYgKCh0cy5pc1ByZWZpeFVuYXJ5RXhwcmVzc2lvbihub2RlKSB8fCB0cy5pc1Bvc3RmaXhVbmFyeUV4cHJlc3Npb24obm9kZSkpICYmXG5cdFx0XHQobm9kZS5vcGVyYXRvciA9PT0gdHMuU3ludGF4S2luZC5QbHVzUGx1c1Rva2VuIHx8IG5vZGUub3BlcmF0b3IgPT09IHRzLlN5bnRheEtpbmQuTWludXNNaW51c1Rva2VuKSAmJlxuXHRcdFx0dHMuaXNJZGVudGlmaWVyKG5vZGUub3BlcmFuZCkpIHtcblx0XHRcdHRhcmdldCA9IG5vZGUub3BlcmFuZDtcblx0XHR9XG5cdFx0aWYgKCF0YXJnZXQpIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cdFx0Ly8gTm90ZTogYSBkZWNsYXJhdGlvbiBpbml0aWFsaXplciAoYGxldCB4ID0gNWApIGlzIGEgVmFyaWFibGVEZWNsYXJhdGlvbixcblx0XHQvLyBuZXZlciBhIEJpbmFyeUV4cHJlc3Npb24sIHNvIGl0IGNhbm5vdCByZWFjaCB0aGlzIHBhdGggYXMgYSBcInJlYXNzaWdubWVudFwiXG5cblx0XHRjb25zdCB2YXJpYWJsZSA9IHRoaXMuZmluZFZhcmlhYmxlKHRhcmdldC50ZXh0LCBzY29wZVN0YWNrKTtcblx0XHRpZiAoIXZhcmlhYmxlKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXHRcdGNvbnN0IGZpbGVQYXRoID0gcGF0aC5yZXNvbHZlKHNvdXJjZUZpbGUuZmlsZU5hbWUpO1xuXHRcdGNvbnN0IHsgbGluZSwgY2hhcmFjdGVyIH0gPSBzb3VyY2VGaWxlLmdldExpbmVBbmRDaGFyYWN0ZXJPZlBvc2l0aW9uKHRhcmdldC5nZXRTdGFydChzb3VyY2VGaWxlKSk7XG5cdFx0dmFyaWFibGUucmVhc3NpZ25tZW50cy5wdXNoKGAke2ZpbGVQYXRofToke2xpbmUgKyAxfToke2NoYXJhY3RlciArIDF9YCk7XG5cdH1cblxuXHQvKipcblx0ICogRmluZCBhIHZhcmlhYmxlIGJ5IG5hbWUgd2Fsa2luZyB0aGUgc2NvcGUgY2hhaW4gb3V0d2FyZC5cblx0ICovXG5cdHByaXZhdGUgZmluZFZhcmlhYmxlIChuYW1lOiBzdHJpbmcsIHNjb3BlU3RhY2s6IHN0cmluZ1tdKTogU2NvcGVWYXJpYWJsZSB8IHVuZGVmaW5lZCB7XG5cdFx0Zm9yIChsZXQgaSA9IHNjb3BlU3RhY2subGVuZ3RoIC0gMTsgaSA+PSAwOyBpLS0pIHtcblx0XHRcdGNvbnN0IHZhcmlhYmxlID0gdGhpcy52YXJpYWJsZXMuZ2V0KGAke3Njb3BlU3RhY2tbIGkgXX0jJHtuYW1lfWApO1xuXHRcdFx0aWYgKHZhcmlhYmxlKSB7XG5cdFx0XHRcdHJldHVybiB2YXJpYWJsZTtcblx0XHRcdH1cblx0XHR9XG5cdFx0cmV0dXJuIHVuZGVmaW5lZDtcblx0fVxuXG5cdHByaXZhdGUgcmVzb2x2ZVZhcmlhYmxlVHlwZVBhdGggKGVudHJ5OiBQZW5kaW5nVmFyaWFibGUsIHJlc29sdmVyOiBTY29wZVR5cGVSZXNvbHZlcik6IHN0cmluZyB8IHVuZGVmaW5lZCB7XG5cdFx0Ly8gYG5ldyBTb21lVHlwZSguLi4pYCDigJQgYmFyZSBjb25zdHJ1Y3RvciBuYW1lXG5cdFx0aWYgKGVudHJ5Lm5ld05hbWUpIHtcblx0XHRcdGNvbnN0IHJlc29sdmVkID0gcmVzb2x2ZXIucmVzb2x2ZUJ5TmFtZShlbnRyeS5uZXdOYW1lKTtcblx0XHRcdGlmIChyZXNvbHZlZCkge1xuXHRcdFx0XHRyZXR1cm4gcmVzb2x2ZWQ7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0Ly8gYG5ldyBpbnN0YW5jZS5TdWIuVHlwZSguLi4pYCDigJQgY2hhaW4gb2ZmIGEgdHJhY2tlZCB2YXJpYWJsZSdzIHR5cGVQYXRoXG5cdFx0aWYgKGVudHJ5Lm5ld0NoYWluUm9vdCAmJiBlbnRyeS5uZXdDaGFpblJlc3QgJiYgZW50cnkubmV3Q2hhaW5SZXN0Lmxlbmd0aCA+IDApIHtcblx0XHRcdGZvciAoY29uc3Qgc2NvcGVJZCBvZiBlbnRyeS5zY29wZUNoYWluKSB7XG5cdFx0XHRcdGNvbnN0IHJvb3RWYXJpYWJsZSA9IHRoaXMudmFyaWFibGVzLmdldChgJHtzY29wZUlkfSMke2VudHJ5Lm5ld0NoYWluUm9vdH1gKTtcblx0XHRcdFx0aWYgKCFyb290VmFyaWFibGU/LnR5cGVQYXRoKSB7XG5cdFx0XHRcdFx0Y29udGludWU7XG5cdFx0XHRcdH1cblx0XHRcdFx0Y29uc3QgY2FuZGlkYXRlID0gWyByb290VmFyaWFibGUudHlwZVBhdGgsIC4uLmVudHJ5Lm5ld0NoYWluUmVzdCBdLmpvaW4oJy4nKTtcblx0XHRcdFx0aWYgKHJlc29sdmVyLmhhc1BhdGgoY2FuZGlkYXRlKSkge1xuXHRcdFx0XHRcdHJldHVybiBjYW5kaWRhdGU7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9XG5cblx0XHQvLyBgbG9va3VwKCdBLkInKWAgLyBgcmVjZWl2ZXIubG9va3VwKCdBLkInKWAgaW5pdGlhbGl6ZXJzXG5cdFx0aWYgKGVudHJ5Lmxvb2t1cFBhdGgpIHtcblx0XHRcdC8vIFJlY2VpdmVyLXJlbGF0aXZlIGZpcnN0OiBgdXNlci5sb29rdXAoJ0FkbWluRW50aXR5JylgIHJlc29sdmVzXG5cdFx0XHQvLyBhZ2FpbnN0IHRoZSByZWNlaXZlciB2YXJpYWJsZSdzIHR5cGVQYXRoIHdoZW4gdGhhdCB5aWVsZHMgYVxuXHRcdFx0Ly8ga25vd24gcGF0aCAobWlycm9ycyB0aGUgYW5hbHl6ZXIncyByZWxhdGl2ZS10aGVuLXJvb3QgcnVsZSlcblx0XHRcdGlmIChlbnRyeS5sb29rdXBSZWNlaXZlcikge1xuXHRcdFx0XHRmb3IgKGNvbnN0IHNjb3BlSWQgb2YgZW50cnkuc2NvcGVDaGFpbikge1xuXHRcdFx0XHRcdGNvbnN0IHJlY2VpdmVyVmFyaWFibGUgPSB0aGlzLnZhcmlhYmxlcy5nZXQoYCR7c2NvcGVJZH0jJHtlbnRyeS5sb29rdXBSZWNlaXZlcn1gKTtcblx0XHRcdFx0XHRpZiAoIXJlY2VpdmVyVmFyaWFibGU/LnR5cGVQYXRoKSB7XG5cdFx0XHRcdFx0XHRjb250aW51ZTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0Y29uc3QgY2FuZGlkYXRlID0gYCR7cmVjZWl2ZXJWYXJpYWJsZS50eXBlUGF0aH0uJHtlbnRyeS5sb29rdXBQYXRofWA7XG5cdFx0XHRcdFx0aWYgKHJlc29sdmVyLmhhc1BhdGgoY2FuZGlkYXRlKSkge1xuXHRcdFx0XHRcdFx0cmV0dXJuIGNhbmRpZGF0ZTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHRcdGlmIChyZXNvbHZlci5oYXNQYXRoKGVudHJ5Lmxvb2t1cFBhdGgpKSB7XG5cdFx0XHRcdHJldHVybiBlbnRyeS5sb29rdXBQYXRoO1xuXHRcdFx0fVxuXHRcdFx0Y29uc3QgYnlOYW1lID0gcmVzb2x2ZXIucmVzb2x2ZUJ5TmFtZShlbnRyeS5sb29rdXBQYXRoKTtcblx0XHRcdGlmIChieU5hbWUpIHtcblx0XHRcdFx0cmV0dXJuIGJ5TmFtZTtcblx0XHRcdH1cblx0XHR9XG5cblx0XHQvLyBUeXBlIGFubm90YXRpb246ICdVc2VyRW50aXR5X1VzZXJSZXNwb25zZScgKHRhY3RpY2EgdHlwZXMudHMgbmFtaW5nKVxuXHRcdC8vIOKGkiBkb3R0ZWQgcGF0aCwgb3IgYSBiYXJlIGtub3duIHR5cGUgbmFtZVxuXHRcdGlmIChlbnRyeS5hbm5vdGF0aW9uKSB7XG5cdFx0XHRjb25zdCBkb3R0ZWQgPSBlbnRyeS5hbm5vdGF0aW9uLnJlcGxhY2UoL18vZywgJy4nKTtcblx0XHRcdGlmIChkb3R0ZWQuaW5jbHVkZXMoJy4nKSAmJiByZXNvbHZlci5oYXNQYXRoKGRvdHRlZCkpIHtcblx0XHRcdFx0cmV0dXJuIGRvdHRlZDtcblx0XHRcdH1cblx0XHRcdGNvbnN0IGJ5TmFtZSA9IHJlc29sdmVyLnJlc29sdmVCeU5hbWUoZW50cnkuYW5ub3RhdGlvbik7XG5cdFx0XHRpZiAoYnlOYW1lKSB7XG5cdFx0XHRcdHJldHVybiBieU5hbWU7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0cmV0dXJuIHVuZGVmaW5lZDtcblx0fVxufVxuIl19
|