@the-trybe/formula-engine 1.0.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/.claude/settings.local.json +6 -0
- package/PRD_FORMULA_ENGINE.md +1863 -0
- package/README.md +382 -0
- package/dist/decimal-utils.d.ts +180 -0
- package/dist/decimal-utils.js +355 -0
- package/dist/dependency-extractor.d.ts +20 -0
- package/dist/dependency-extractor.js +103 -0
- package/dist/dependency-graph.d.ts +60 -0
- package/dist/dependency-graph.js +252 -0
- package/dist/errors.d.ts +161 -0
- package/dist/errors.js +260 -0
- package/dist/evaluator.d.ts +51 -0
- package/dist/evaluator.js +494 -0
- package/dist/formula-engine.d.ts +79 -0
- package/dist/formula-engine.js +355 -0
- package/dist/functions.d.ts +3 -0
- package/dist/functions.js +720 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +61 -0
- package/dist/lexer.d.ts +25 -0
- package/dist/lexer.js +357 -0
- package/dist/parser.d.ts +32 -0
- package/dist/parser.js +372 -0
- package/dist/types.d.ts +228 -0
- package/dist/types.js +62 -0
- package/jest.config.js +23 -0
- package/package.json +35 -0
- package/src/decimal-utils.ts +408 -0
- package/src/dependency-extractor.ts +117 -0
- package/src/dependency-graph.test.ts +238 -0
- package/src/dependency-graph.ts +288 -0
- package/src/errors.ts +296 -0
- package/src/evaluator.ts +604 -0
- package/src/formula-engine.test.ts +660 -0
- package/src/formula-engine.ts +430 -0
- package/src/functions.ts +770 -0
- package/src/index.ts +103 -0
- package/src/lexer.test.ts +288 -0
- package/src/lexer.ts +394 -0
- package/src/parser.test.ts +349 -0
- package/src/parser.ts +449 -0
- package/src/types.ts +347 -0
- package/tsconfig.json +29 -0
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { FormulaEngineConfig, FormulaDefinition, EvaluationContext, EvaluationResult, EvaluationResultSet, ValidationResult, FunctionDefinition, ASTNode, CacheStats, DependencyGraph as IDependencyGraph } from './types';
|
|
2
|
+
import { DecimalUtils, Decimal } from './decimal-utils';
|
|
3
|
+
export declare class FormulaEngine {
|
|
4
|
+
private config;
|
|
5
|
+
private parser;
|
|
6
|
+
private evaluator;
|
|
7
|
+
private dependencyExtractor;
|
|
8
|
+
private graphBuilder;
|
|
9
|
+
private decimalUtils;
|
|
10
|
+
private functions;
|
|
11
|
+
private astCache;
|
|
12
|
+
private dependencyCache;
|
|
13
|
+
private cacheHits;
|
|
14
|
+
private cacheMisses;
|
|
15
|
+
constructor(config?: FormulaEngineConfig);
|
|
16
|
+
/**
|
|
17
|
+
* Parse an expression into an AST
|
|
18
|
+
*/
|
|
19
|
+
parse(expression: string): ASTNode;
|
|
20
|
+
/**
|
|
21
|
+
* Extract variable dependencies from an expression
|
|
22
|
+
*/
|
|
23
|
+
extractDependencies(expression: string): Set<string>;
|
|
24
|
+
/**
|
|
25
|
+
* Build a dependency graph from formula definitions
|
|
26
|
+
*/
|
|
27
|
+
buildDependencyGraph(formulas: FormulaDefinition[]): IDependencyGraph;
|
|
28
|
+
/**
|
|
29
|
+
* Get the evaluation order for formulas
|
|
30
|
+
*/
|
|
31
|
+
getEvaluationOrder(formulas: FormulaDefinition[]): string[];
|
|
32
|
+
/**
|
|
33
|
+
* Validate formulas without evaluating
|
|
34
|
+
*/
|
|
35
|
+
validate(formulas: FormulaDefinition[]): ValidationResult;
|
|
36
|
+
/**
|
|
37
|
+
* Evaluate a single expression
|
|
38
|
+
*/
|
|
39
|
+
evaluate(expression: string, context: EvaluationContext): EvaluationResult;
|
|
40
|
+
/**
|
|
41
|
+
* Evaluate all formulas in dependency order
|
|
42
|
+
*/
|
|
43
|
+
evaluateAll(formulas: FormulaDefinition[], context: EvaluationContext): EvaluationResultSet;
|
|
44
|
+
/**
|
|
45
|
+
* Register a custom function
|
|
46
|
+
*/
|
|
47
|
+
registerFunction(definition: FunctionDefinition): void;
|
|
48
|
+
/**
|
|
49
|
+
* Register multiple custom functions
|
|
50
|
+
*/
|
|
51
|
+
registerFunctions(definitions: FunctionDefinition[]): void;
|
|
52
|
+
/**
|
|
53
|
+
* Get registered function names
|
|
54
|
+
*/
|
|
55
|
+
getRegisteredFunctions(): string[];
|
|
56
|
+
/**
|
|
57
|
+
* Clear the AST cache
|
|
58
|
+
*/
|
|
59
|
+
clearCache(): void;
|
|
60
|
+
/**
|
|
61
|
+
* Get cache statistics
|
|
62
|
+
*/
|
|
63
|
+
getCacheStats(): CacheStats;
|
|
64
|
+
/**
|
|
65
|
+
* Get the decimal utilities instance
|
|
66
|
+
*/
|
|
67
|
+
getDecimalUtils(): DecimalUtils;
|
|
68
|
+
/**
|
|
69
|
+
* Create a Decimal from a value
|
|
70
|
+
*/
|
|
71
|
+
createDecimal(value: string | number): Decimal;
|
|
72
|
+
private checkExpressionLength;
|
|
73
|
+
private normalizeContext;
|
|
74
|
+
private convertValue;
|
|
75
|
+
private isDecimal;
|
|
76
|
+
private applyRounding;
|
|
77
|
+
private handleError;
|
|
78
|
+
private maybeEvictCache;
|
|
79
|
+
}
|
|
@@ -0,0 +1,355 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FormulaEngine = void 0;
|
|
4
|
+
const parser_1 = require("./parser");
|
|
5
|
+
const evaluator_1 = require("./evaluator");
|
|
6
|
+
const dependency_extractor_1 = require("./dependency-extractor");
|
|
7
|
+
const dependency_graph_1 = require("./dependency-graph");
|
|
8
|
+
const decimal_utils_1 = require("./decimal-utils");
|
|
9
|
+
const functions_1 = require("./functions");
|
|
10
|
+
const errors_1 = require("./errors");
|
|
11
|
+
class FormulaEngine {
|
|
12
|
+
constructor(config) {
|
|
13
|
+
// Caches
|
|
14
|
+
this.astCache = new Map();
|
|
15
|
+
this.dependencyCache = new Map();
|
|
16
|
+
this.cacheHits = 0;
|
|
17
|
+
this.cacheMisses = 0;
|
|
18
|
+
this.config = {
|
|
19
|
+
enableCache: true,
|
|
20
|
+
maxCacheSize: 1000,
|
|
21
|
+
strictMode: true,
|
|
22
|
+
...config,
|
|
23
|
+
};
|
|
24
|
+
this.decimalUtils = new decimal_utils_1.DecimalUtils(this.config.decimal);
|
|
25
|
+
this.functions = (0, functions_1.createBuiltInFunctions)(this.decimalUtils);
|
|
26
|
+
this.parser = new parser_1.Parser();
|
|
27
|
+
this.dependencyExtractor = new dependency_extractor_1.DependencyExtractor();
|
|
28
|
+
this.graphBuilder = new dependency_graph_1.DependencyGraphBuilder();
|
|
29
|
+
this.evaluator = new evaluator_1.Evaluator(this.decimalUtils, this.functions, this.config);
|
|
30
|
+
// Register any custom functions from config
|
|
31
|
+
if (this.config.functions) {
|
|
32
|
+
for (const fn of this.config.functions) {
|
|
33
|
+
this.registerFunction(fn);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Parse an expression into an AST
|
|
39
|
+
*/
|
|
40
|
+
parse(expression) {
|
|
41
|
+
this.checkExpressionLength(expression);
|
|
42
|
+
if (this.config.enableCache) {
|
|
43
|
+
const cached = this.astCache.get(expression);
|
|
44
|
+
if (cached) {
|
|
45
|
+
this.cacheHits++;
|
|
46
|
+
return cached;
|
|
47
|
+
}
|
|
48
|
+
this.cacheMisses++;
|
|
49
|
+
}
|
|
50
|
+
const ast = this.parser.parse(expression);
|
|
51
|
+
if (this.config.enableCache) {
|
|
52
|
+
this.maybeEvictCache();
|
|
53
|
+
this.astCache.set(expression, ast);
|
|
54
|
+
}
|
|
55
|
+
return ast;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Extract variable dependencies from an expression
|
|
59
|
+
*/
|
|
60
|
+
extractDependencies(expression) {
|
|
61
|
+
if (this.config.enableCache) {
|
|
62
|
+
const cached = this.dependencyCache.get(expression);
|
|
63
|
+
if (cached) {
|
|
64
|
+
return new Set(cached);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
const deps = this.dependencyExtractor.extract(expression);
|
|
68
|
+
if (this.config.enableCache) {
|
|
69
|
+
this.dependencyCache.set(expression, new Set(deps));
|
|
70
|
+
}
|
|
71
|
+
return deps;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Build a dependency graph from formula definitions
|
|
75
|
+
*/
|
|
76
|
+
buildDependencyGraph(formulas) {
|
|
77
|
+
return this.graphBuilder.build(formulas);
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Get the evaluation order for formulas
|
|
81
|
+
*/
|
|
82
|
+
getEvaluationOrder(formulas) {
|
|
83
|
+
return this.graphBuilder.getEvaluationOrder(formulas);
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Validate formulas without evaluating
|
|
87
|
+
*/
|
|
88
|
+
validate(formulas) {
|
|
89
|
+
const errors = [];
|
|
90
|
+
const warnings = [];
|
|
91
|
+
// Check for duplicate IDs
|
|
92
|
+
const ids = new Set();
|
|
93
|
+
for (const formula of formulas) {
|
|
94
|
+
if (ids.has(formula.id)) {
|
|
95
|
+
errors.push(new errors_1.DuplicateFormulaError(formula.id));
|
|
96
|
+
}
|
|
97
|
+
ids.add(formula.id);
|
|
98
|
+
}
|
|
99
|
+
// Try to parse all expressions
|
|
100
|
+
for (const formula of formulas) {
|
|
101
|
+
try {
|
|
102
|
+
this.parse(formula.expression);
|
|
103
|
+
}
|
|
104
|
+
catch (error) {
|
|
105
|
+
if (error instanceof errors_1.FormulaEngineError) {
|
|
106
|
+
errors.push(error);
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
errors.push(new errors_1.GeneralFormulaError(String(error)));
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
// Build dependency graph and check for cycles
|
|
114
|
+
let dependencyGraph = new dependency_graph_1.DependencyGraph();
|
|
115
|
+
let evaluationOrder = [];
|
|
116
|
+
try {
|
|
117
|
+
dependencyGraph = this.buildDependencyGraph(formulas);
|
|
118
|
+
evaluationOrder = dependencyGraph.topologicalSort();
|
|
119
|
+
}
|
|
120
|
+
catch (error) {
|
|
121
|
+
if (error instanceof errors_1.FormulaEngineError) {
|
|
122
|
+
errors.push(error);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
return {
|
|
126
|
+
valid: errors.length === 0,
|
|
127
|
+
errors,
|
|
128
|
+
warnings,
|
|
129
|
+
dependencyGraph,
|
|
130
|
+
evaluationOrder,
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Evaluate a single expression
|
|
135
|
+
*/
|
|
136
|
+
evaluate(expression, context) {
|
|
137
|
+
this.checkExpressionLength(expression);
|
|
138
|
+
const normalizedContext = this.normalizeContext(context);
|
|
139
|
+
return this.evaluator.evaluate(expression, normalizedContext);
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Evaluate all formulas in dependency order
|
|
143
|
+
*/
|
|
144
|
+
evaluateAll(formulas, context) {
|
|
145
|
+
const startTime = Date.now();
|
|
146
|
+
const results = new Map();
|
|
147
|
+
const errors = [];
|
|
148
|
+
// Get evaluation order
|
|
149
|
+
let evaluationOrder;
|
|
150
|
+
try {
|
|
151
|
+
evaluationOrder = this.getEvaluationOrder(formulas);
|
|
152
|
+
}
|
|
153
|
+
catch (error) {
|
|
154
|
+
return {
|
|
155
|
+
results,
|
|
156
|
+
success: false,
|
|
157
|
+
errors: [error],
|
|
158
|
+
totalExecutionTimeMs: Date.now() - startTime,
|
|
159
|
+
evaluationOrder: [],
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
// Create a map of formulas by ID
|
|
163
|
+
const formulaMap = new Map();
|
|
164
|
+
for (const formula of formulas) {
|
|
165
|
+
formulaMap.set(formula.id, formula);
|
|
166
|
+
}
|
|
167
|
+
// Evaluate in order, merging results into context
|
|
168
|
+
const workingContext = this.normalizeContext(context);
|
|
169
|
+
for (const formulaId of evaluationOrder) {
|
|
170
|
+
const formula = formulaMap.get(formulaId);
|
|
171
|
+
if (!formula)
|
|
172
|
+
continue;
|
|
173
|
+
try {
|
|
174
|
+
const result = this.evaluator.evaluate(formula.expression, workingContext);
|
|
175
|
+
// Apply rounding if configured
|
|
176
|
+
let value = result.value;
|
|
177
|
+
if (formula.rounding && this.isDecimal(value)) {
|
|
178
|
+
value = this.applyRounding(value, formula.rounding);
|
|
179
|
+
}
|
|
180
|
+
// Handle errors based on formula config
|
|
181
|
+
if (!result.success && formula.onError) {
|
|
182
|
+
value = this.handleError(formula, result.error);
|
|
183
|
+
}
|
|
184
|
+
results.set(formulaId, {
|
|
185
|
+
...result,
|
|
186
|
+
value,
|
|
187
|
+
});
|
|
188
|
+
// Merge result into context for subsequent formulas
|
|
189
|
+
workingContext.variables[formulaId] = value;
|
|
190
|
+
if (!result.success) {
|
|
191
|
+
errors.push(result.error);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
catch (error) {
|
|
195
|
+
const evalResult = {
|
|
196
|
+
value: null,
|
|
197
|
+
success: false,
|
|
198
|
+
error: error,
|
|
199
|
+
executionTimeMs: 0,
|
|
200
|
+
accessedVariables: new Set(),
|
|
201
|
+
};
|
|
202
|
+
// Handle error based on formula config
|
|
203
|
+
if (formula.onError) {
|
|
204
|
+
evalResult.value = this.handleError(formula, error);
|
|
205
|
+
}
|
|
206
|
+
results.set(formulaId, evalResult);
|
|
207
|
+
errors.push(error);
|
|
208
|
+
// Still add to context (as null or default value) so dependent formulas can proceed
|
|
209
|
+
workingContext.variables[formulaId] = evalResult.value;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
return {
|
|
213
|
+
results,
|
|
214
|
+
success: errors.length === 0,
|
|
215
|
+
errors,
|
|
216
|
+
totalExecutionTimeMs: Date.now() - startTime,
|
|
217
|
+
evaluationOrder,
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Register a custom function
|
|
222
|
+
*/
|
|
223
|
+
registerFunction(definition) {
|
|
224
|
+
const name = definition.name.toUpperCase();
|
|
225
|
+
this.functions.set(name, definition);
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Register multiple custom functions
|
|
229
|
+
*/
|
|
230
|
+
registerFunctions(definitions) {
|
|
231
|
+
for (const definition of definitions) {
|
|
232
|
+
this.registerFunction(definition);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Get registered function names
|
|
237
|
+
*/
|
|
238
|
+
getRegisteredFunctions() {
|
|
239
|
+
return Array.from(this.functions.keys());
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Clear the AST cache
|
|
243
|
+
*/
|
|
244
|
+
clearCache() {
|
|
245
|
+
this.astCache.clear();
|
|
246
|
+
this.dependencyCache.clear();
|
|
247
|
+
this.cacheHits = 0;
|
|
248
|
+
this.cacheMisses = 0;
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Get cache statistics
|
|
252
|
+
*/
|
|
253
|
+
getCacheStats() {
|
|
254
|
+
const total = this.cacheHits + this.cacheMisses;
|
|
255
|
+
return {
|
|
256
|
+
size: this.astCache.size,
|
|
257
|
+
hits: this.cacheHits,
|
|
258
|
+
misses: this.cacheMisses,
|
|
259
|
+
hitRate: total > 0 ? this.cacheHits / total : 0,
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* Get the decimal utilities instance
|
|
264
|
+
*/
|
|
265
|
+
getDecimalUtils() {
|
|
266
|
+
return this.decimalUtils;
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* Create a Decimal from a value
|
|
270
|
+
*/
|
|
271
|
+
createDecimal(value) {
|
|
272
|
+
return this.decimalUtils.from(value);
|
|
273
|
+
}
|
|
274
|
+
// ============================================================================
|
|
275
|
+
// Private methods
|
|
276
|
+
// ============================================================================
|
|
277
|
+
checkExpressionLength(expression) {
|
|
278
|
+
const maxLength = this.config.security?.maxExpressionLength ?? 10000;
|
|
279
|
+
if (expression.length > maxLength) {
|
|
280
|
+
throw new errors_1.MaxExpressionLengthError(expression.length, maxLength);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
normalizeContext(context) {
|
|
284
|
+
// Deep copy and convert numeric values to Decimal if autoConvertFloats is enabled
|
|
285
|
+
const autoConvert = this.config.decimal?.autoConvertFloats ?? true;
|
|
286
|
+
if (!autoConvert) {
|
|
287
|
+
return { ...context };
|
|
288
|
+
}
|
|
289
|
+
const normalizedVariables = {};
|
|
290
|
+
for (const [key, value] of Object.entries(context.variables)) {
|
|
291
|
+
normalizedVariables[key] = this.convertValue(value);
|
|
292
|
+
}
|
|
293
|
+
return {
|
|
294
|
+
...context,
|
|
295
|
+
variables: normalizedVariables,
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
convertValue(value) {
|
|
299
|
+
if (typeof value === 'number' && !isNaN(value) && isFinite(value)) {
|
|
300
|
+
return this.decimalUtils.from(value);
|
|
301
|
+
}
|
|
302
|
+
if (Array.isArray(value)) {
|
|
303
|
+
return value.map(v => this.convertValue(v));
|
|
304
|
+
}
|
|
305
|
+
if (value !== null && typeof value === 'object') {
|
|
306
|
+
const converted = {};
|
|
307
|
+
for (const [k, v] of Object.entries(value)) {
|
|
308
|
+
converted[k] = this.convertValue(v);
|
|
309
|
+
}
|
|
310
|
+
return converted;
|
|
311
|
+
}
|
|
312
|
+
return value;
|
|
313
|
+
}
|
|
314
|
+
isDecimal(value) {
|
|
315
|
+
return value instanceof decimal_utils_1.Decimal;
|
|
316
|
+
}
|
|
317
|
+
applyRounding(value, config) {
|
|
318
|
+
if (config.mode === 'NONE') {
|
|
319
|
+
return value;
|
|
320
|
+
}
|
|
321
|
+
return this.decimalUtils.round(value, config.precision, config.mode);
|
|
322
|
+
}
|
|
323
|
+
handleError(formula, _error) {
|
|
324
|
+
const behavior = formula.onError;
|
|
325
|
+
if (!behavior)
|
|
326
|
+
return null;
|
|
327
|
+
switch (behavior.type) {
|
|
328
|
+
case 'NULL':
|
|
329
|
+
return null;
|
|
330
|
+
case 'ZERO':
|
|
331
|
+
return this.decimalUtils.zero();
|
|
332
|
+
case 'DEFAULT':
|
|
333
|
+
return behavior.defaultValue ?? formula.defaultValue ?? null;
|
|
334
|
+
case 'SKIP':
|
|
335
|
+
return undefined;
|
|
336
|
+
case 'THROW':
|
|
337
|
+
default:
|
|
338
|
+
throw _error;
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
maybeEvictCache() {
|
|
342
|
+
const maxSize = this.config.maxCacheSize ?? 1000;
|
|
343
|
+
if (this.astCache.size >= maxSize) {
|
|
344
|
+
// Simple FIFO eviction - remove first 10% of entries
|
|
345
|
+
const toRemove = Math.ceil(maxSize * 0.1);
|
|
346
|
+
const keys = Array.from(this.astCache.keys()).slice(0, toRemove);
|
|
347
|
+
for (const key of keys) {
|
|
348
|
+
this.astCache.delete(key);
|
|
349
|
+
this.dependencyCache.delete(key);
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
exports.FormulaEngine = FormulaEngine;
|
|
355
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZm9ybXVsYS1lbmdpbmUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvZm9ybXVsYS1lbmdpbmUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBWUEscUNBQWtDO0FBQ2xDLDJDQUF3QztBQUN4QyxpRUFBNkQ7QUFDN0QseURBQTZFO0FBQzdFLG1EQUF3RDtBQUN4RCwyQ0FBcUQ7QUFDckQscUNBS2tCO0FBRWxCLE1BQWEsYUFBYTtJQWV4QixZQUFZLE1BQTRCO1FBTnhDLFNBQVM7UUFDRCxhQUFRLEdBQXlCLElBQUksR0FBRyxFQUFFLENBQUM7UUFDM0Msb0JBQWUsR0FBNkIsSUFBSSxHQUFHLEVBQUUsQ0FBQztRQUN0RCxjQUFTLEdBQVcsQ0FBQyxDQUFDO1FBQ3RCLGdCQUFXLEdBQVcsQ0FBQyxDQUFDO1FBRzlCLElBQUksQ0FBQyxNQUFNLEdBQUc7WUFDWixXQUFXLEVBQUUsSUFBSTtZQUNqQixZQUFZLEVBQUUsSUFBSTtZQUNsQixVQUFVLEVBQUUsSUFBSTtZQUNoQixHQUFHLE1BQU07U0FDVixDQUFDO1FBRUYsSUFBSSxDQUFDLFlBQVksR0FBRyxJQUFJLDRCQUFZLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUMxRCxJQUFJLENBQUMsU0FBUyxHQUFHLElBQUEsa0NBQXNCLEVBQUMsSUFBSSxDQUFDLFlBQVksQ0FBQyxDQUFDO1FBQzNELElBQUksQ0FBQyxNQUFNLEdBQUcsSUFBSSxlQUFNLEVBQUUsQ0FBQztRQUMzQixJQUFJLENBQUMsbUJBQW1CLEdBQUcsSUFBSSwwQ0FBbUIsRUFBRSxDQUFDO1FBQ3JELElBQUksQ0FBQyxZQUFZLEdBQUcsSUFBSSx5Q0FBc0IsRUFBRSxDQUFDO1FBQ2pELElBQUksQ0FBQyxTQUFTLEdBQUcsSUFBSSxxQkFBUyxDQUFDLElBQUksQ0FBQyxZQUFZLEVBQUUsSUFBSSxDQUFDLFNBQVMsRUFBRSxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUM7UUFFL0UsNENB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WSxJQUFJLElBQUksQ0FBQztZQUMvRCxLQUFLLE1BQU07Z0JBQ1QsT0FBTyxTQUFTLENBQUM7WUFDbkIsS0FBSyxPQUFPLENBQUM7WUFDYjtnQkFDRSxNQUFNLE1BQU0sQ0FBQztRQUNqQixDQUFDO0lBQ0gsQ0FBQztJQUVPLGVBQWU7UUFDckIsTUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQyxZQUFZLElBQUksSUFBSSxDQUFDO1FBQ2pELElBQUksSUFBSSxDQUFDLFFBQVEsQ0FBQyxJQUFJLElBQUksT0FBTyxFQUFFLENBQUM7WUFDbEMscURBQXFEO1lBQ3JELE1BQU0sUUFBUSxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsT0FBTyxHQUFHLEdBQUcsQ0FBQyxDQUFDO1lBQzFDLE1BQU0sSUFBSSxHQUFHLEtBQUssQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLEVBQUUsUUFBUSxDQUFDLENBQUM7WUFDakUsS0FBSyxNQUFNLEdBQUcsSUFBSSxJQUFJLEVBQUUsQ0FBQztnQkFDdkIsSUFBSSxDQUFDLFFBQVEsQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUM7Z0JBQzFCLElBQUksQ0FBQyxlQUFlLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDO1lBQ25DLENBQUM7UUFDSCxDQUFDO0lBQ0gsQ0FBQztDQUNGO0FBcFpELHNDQW9aQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XG4gIEZvcm11bGFFbmdpbmVDb25maWcsXG4gIEZvcm11bGFEZWZpbml0aW9uLFxuICBFdmFsdWF0aW9uQ29udGV4dCxcbiAgRXZhbHVhdGlvblJlc3VsdCxcbiAgRXZhbHVhdGlvblJlc3VsdFNldCxcbiAgVmFsaWRhdGlvblJlc3VsdCxcbiAgRnVuY3Rpb25EZWZpbml0aW9uLFxuICBBU1ROb2RlLFxuICBDYWNoZVN0YXRzLFxuICBEZXBlbmRlbmN5R3JhcGggYXMgSURlcGVuZGVuY3lHcmFwaCxcbn0gZnJvbSAnLi90eXBlcyc7XG5pbXBvcnQgeyBQYXJzZXIgfSBmcm9tICcuL3BhcnNlcic7XG5pbXBvcnQgeyBFdmFsdWF0b3IgfSBmcm9tICcuL2V2YWx1YXRvcic7XG5pbXBvcnQgeyBEZXBlbmRlbmN5RXh0cmFjdG9yIH0gZnJvbSAnLi9kZXBlbmRlbmN5LWV4dHJhY3Rvcic7XG5pbXBvcnQgeyBEZXBlbmRlbmN5R3JhcGgsIERlcGVuZGVuY3lHcmFwaEJ1aWxkZXIgfSBmcm9tICcuL2RlcGVuZGVuY3ktZ3JhcGgnO1xuaW1wb3J0IHsgRGVjaW1hbFV0aWxzLCBEZWNpbWFsIH0gZnJvbSAnLi9kZWNpbWFsLXV0aWxzJztcbmltcG9ydCB7IGNyZWF0ZUJ1aWx0SW5GdW5jdGlvbnMgfSBmcm9tICcuL2Z1bmN0aW9ucyc7XG5pbXBvcnQge1xuICBGb3JtdWxhRW5naW5lRXJyb3IsXG4gIEdlbmVyYWxGb3JtdWxhRXJyb3IsXG4gIER1cGxpY2F0ZUZvcm11bGFFcnJvcixcbiAgTWF4RXhwcmVzc2lvbkxlbmd0aEVycm9yLFxufSBmcm9tICcuL2Vycm9ycyc7XG5cbmV4cG9ydCBjbGFzcyBGb3JtdWxhRW5naW5lIHtcbiAgcHJpdmF0ZSBjb25maWc6IEZvcm11bGFFbmdpbmVDb25maWc7XG4gIHByaXZhdGUgcGFyc2VyOiBQYXJzZXI7XG4gIHByaXZhdGUgZXZhbHVhdG9yOiBFdmFsdWF0b3I7XG4gIHByaXZhdGUgZGVwZW5kZW5jeUV4dHJhY3RvcjogRGVwZW5kZW5jeUV4dHJhY3RvcjtcbiAgcHJpdmF0ZSBncmFwaEJ1aWxkZXI6IERlcGVuZGVuY3lHcmFwaEJ1aWxkZXI7XG4gIHByaXZhdGUgZGVjaW1hbFV0aWxzOiBEZWNpbWFsVXRpbHM7XG4gIHByaXZhdGUgZnVuY3Rpb25zOiBNYXA8c3RyaW5nLCBGdW5jdGlvbkRlZmluaXRpb24+O1xuXG4gIC8vIENhY2hlc1xuICBwcml2YXRlIGFzdENhY2hlOiBNYXA8c3RyaW5nLCBBU1ROb2RlPiA9IG5ldyBNYXAoKTtcbiAgcHJpdmF0ZSBkZXBlbmRlbmN5Q2FjaGU6IE1hcDxzdHJpbmcsIFNldDxzdHJpbmc+PiA9IG5ldyBNYXAoKTtcbiAgcHJpdmF0ZSBjYWNoZUhpdHM6IG51bWJlciA9IDA7XG4gIHByaXZhdGUgY2FjaGVNaXNzZXM6IG51bWJlciA9IDA7XG5cbiAgY29uc3RydWN0b3IoY29uZmlnPzogRm9ybXVsYUVuZ2luZUNvbmZpZykge1xuICAgIHRoaXMuY29uZmlnID0ge1xuICAgICAgZW5hYmxlQ2FjaGU6IHRydWUsXG4gICAgICBtYXhDYWNoZVNpemU6IDEwMDAsXG4gICAgICBzdHJpY3RNb2RlOiB0cnVlLFxuICAgICAgLi4uY29uZmlnLFxuICAgIH07XG5cbiAgICB0aGlzLmRlY2ltYWxVdGlscyA9IG5ldyBEZWNpbWFsVXRpbHModGhpcy5jb25maWcuZGVjaW1hbCk7XG4gICAgdGhpcy5mdW5jdGlvbnMgPSBjcmVhdGVCdWlsdEluRnVuY3Rpb25zKHRoaXMuZGVjaW1hbFV0aWxzKTtcbiAgICB0aGlzLnBhcnNlciA9IG5ldyBQYXJzZXIoKTtcbiAgICB0aGlzLmRlcGVuZGVuY3lFeHRyYWN0b3IgPSBuZXcgRGVwZW5kZW5jeUV4dHJhY3RvcigpO1xuICAgIHRoaXMuZ3JhcGhCdWlsZGVyID0gbmV3IERlcGVuZGVuY3lHcmFwaEJ1aWxkZXIoKTtcbiAgICB0aGlzLmV2YWx1YXRvciA9IG5ldyBFdmFsdWF0b3IodGhpcy5kZWNpbWFsVXRpbHMsIHRoaXMuZnVuY3Rpb25zLCB0aGlzLmNvbmZpZyk7XG5cbiAgICAvLyBSZWdpc3RlciBhbnkgY3VzdG9tIGZ1bmN0aW9ucyBmcm9tIGNvbmZpZ1xuICAgIGlmICh0aGlzLmNvbmZpZy5mdW5jdGlvbnMpIHtcbiAgICAgIGZvciAoY29uc3QgZm4gb2YgdGhpcy5jb25maWcuZnVuY3Rpb25zKSB7XG4gICAgICAgIHRoaXMucmVnaXN0ZXJGdW5jdGlvbihmbik7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFBhcnNlIGFuIGV4cHJlc3Npb24gaW50byBhbiBBU1RcbiAgICovXG4gIHBhcnNlKGV4cHJlc3Npb246IHN0cmluZyk6IEFTVE5vZGUge1xuICAgIHRoaXMuY2hlY2tFeHByZXNzaW9uTGVuZ3RoKGV4cHJlc3Npb24pO1xuXG4gICAgaWYgKHRoaXMuY29uZmlnLmVuYWJsZUNhY2hlKSB7XG4gICAgICBjb25zdCBjYWNoZWQgPSB0aGlzLmFzdENhY2hlLmdldChleHByZXNzaW9uKTtcbiAgICAgIGlmIChjYWNoZWQpIHtcbiAgICAgICAgdGhpcy5jYWNoZUhpdHMrKztcbiAgICAgICAgcmV0dXJuIGNhY2hlZDtcbiAgICAgIH1cbiAgICAgIHRoaXMuY2FjaGVNaXNzZXMrKztcbiAgICB9XG5cbiAgICBjb25zdCBhc3QgPSB0aGlzLnBhcnNlci5wYXJzZShleHByZXNzaW9uKTtcblxuICAgIGlmICh0aGlzLmNvbmZpZy5lbmFibGVDYWNoZSkge1xuICAgICAgdGhpcy5tYXliZUV2aWN0Q2FjaGUoKTtcbiAgICAgIHRoaXMuYXN0Q2FjaGUuc2V0KGV4cHJlc3Npb24sIGFzdCk7XG4gICAgfVxuXG4gICAgcmV0dXJuIGFzdDtcbiAgfVxuXG4gIC8qKlxuICAgKiBFeHRyYWN0IHZhcmlhYmxlIGRlcGVuZGVuY2llcyBmcm9tIGFuIGV4cHJlc3Npb25cbiAgICovXG4gIGV4dHJhY3REZXBlbmRlbmNpZXMoZXhwcmVzc2lvbjogc3RyaW5nKTogU2V0PHN0cmluZz4ge1xuICAgIGlmICh0aGlzLmNvbmZpZy5lbmFibGVDYWNoZSkge1xuICAgICAgY29uc3QgY2FjaGVkID0gdGhpcy5kZXBlbmRlbmN5Q2FjaGUuZ2V0KGV4cHJlc3Npb24pO1xuICAgICAgaWYgKGNhY2hlZCkge1xuICAgICAgICByZXR1cm4gbmV3IFNldChjYWNoZWQpO1xuICAgICAgfVxuICAgIH1cblxuICAgIGNvbnN0IGRlcHMgPSB0aGlzLmRlcGVuZGVuY3lFeHRyYWN0b3IuZXh0cmFjdChleHByZXNzaW9uKTtcblxuICAgIGlmICh0aGlzLmNvbmZpZy5lbmFibGVDYWNoZSkge1xuICAgICAgdGhpcy5kZXBlbmRlbmN5Q2FjaGUuc2V0KGV4cHJlc3Npb24sIG5ldyBTZXQoZGVwcykpO1xuICAgIH1cblxuICAgIHJldHVybiBkZXBzO1xuICB9XG5cbiAgLyoqXG4gICAqIEJ1aWxkIGEgZGVwZW5kZW5jeSBncmFwaCBmcm9tIGZvcm11bGEgZGVmaW5pdGlvbnNcbiAgICovXG4gIGJ1aWxkRGVwZW5kZW5jeUdyYXBoKGZvcm11bGFzOiBGb3JtdWxhRGVmaW5pdGlvbltdKTogSURlcGVuZGVuY3lHcmFwaCB7XG4gICAgcmV0dXJuIHRoaXMuZ3JhcGhCdWlsZGVyLmJ1aWxkKGZvcm11bGFzKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXQgdGhlIGV2YWx1YXRpb24gb3JkZXIgZm9yIGZvcm11bGFzXG4gICAqL1xuICBnZXRFdmFsdWF0aW9uT3JkZXIoZm9ybXVsYXM6IEZvcm11bGFEZWZpbml0aW9uW10pOiBzdHJpbmdbXSB7XG4gICAgcmV0dXJuIHRoaXMuZ3JhcGhCdWlsZGVyLmdldEV2YWx1YXRpb25PcmRlcihmb3JtdWxhcyk7XG4gIH1cblxuICAvKipcbiAgICogVmFsaWRhdGUgZm9ybXVsYXMgd2l0aG91dCBldmFsdWF0aW5nXG4gICAqL1xuICB2YWxpZGF0ZShmb3JtdWxhczogRm9ybXVsYURlZmluaXRpb25bXSk6IFZhbGlkYXRpb25SZXN1bHQge1xuICAgIGNvbnN0IGVycm9yczogRm9ybXVsYUVuZ2luZUVycm9yW10gPSBbXTtcbiAgICBjb25zdCB3YXJuaW5nczogc3RyaW5nW10gPSBbXTtcblxuICAgIC8vIENoZWNrIGZvciBkdXBsaWNhdGUgSURzXG4gICAgY29uc3QgaWRzID0gbmV3IFNldDxzdHJpbmc+KCk7XG4gICAgZm9yIChjb25zdCBmb3JtdWxhIG9mIGZvcm11bGFzKSB7XG4gICAgICBpZiAoaWRzLmhhcyhmb3JtdWxhLmlkKSkge1xuICAgICAgICBlcnJvcnMucHVzaChuZXcgRHVwbGljYXRlRm9ybXVsYUVycm9yKGZvcm11bGEuaWQpKTtcbiAgICAgIH1cbiAgICAgIGlkcy5hZGQoZm9ybXVsYS5pZCk7XG4gICAgfVxuXG4gICAgLy8gVHJ5IHRvIHBhcnNlIGFsbCBleHByZXNzaW9uc1xuICAgIGZvciAoY29uc3QgZm9ybXVsYSBvZiBmb3JtdWxhcykge1xuICAgICAgdHJ5IHtcbiAgICAgICAgdGhpcy5wYXJzZShmb3JtdWxhLmV4cHJlc3Npb24pO1xuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgaWYgKGVycm9yIGluc3RhbmNlb2YgRm9ybXVsYUVuZ2luZUVycm9yKSB7XG4gICAgICAgICAgZXJyb3JzLnB1c2goZXJyb3IpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGVycm9ycy5wdXNoKG5ldyBHZW5lcmFsRm9ybXVsYUVycm9yKFN0cmluZyhlcnJvcikpKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cblxuICAgIC8vIEJ1aWxkIGRlcGVuZGVuY3kgZ3JhcGggYW5kIGNoZWNrIGZvciBjeWNsZXNcbiAgICBsZXQgZGVwZW5kZW5jeUdyYXBoOiBJRGVwZW5kZW5jeUdyYXBoID0gbmV3IERlcGVuZGVuY3lHcmFwaCgpO1xuICAgIGxldCBldmFsdWF0aW9uT3JkZXI6IHN0cmluZ1tdID0gW107XG5cbiAgICB0cnkge1xuICAgICAgZGVwZW5kZW5jeUdyYXBoID0gdGhpcy5idWlsZERlcGVuZGVuY3lHcmFwaChmb3JtdWxhcyk7XG4gICAgICBldmFsdWF0aW9uT3JkZXIgPSBkZXBlbmRlbmN5R3JhcGgudG9wb2xvZ2ljYWxTb3J0KCk7XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIGlmIChlcnJvciBpbnN0YW5jZW9mIEZvcm11bGFFbmdpbmVFcnJvcikge1xuICAgICAgICBlcnJvcnMucHVzaChlcnJvcik7XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIHtcbiAgICAgIHZhbGlkOiBlcnJvcnMubGVuZ3RoID09PSAwLFxuICAgICAgZXJyb3JzLFxuICAgICAgd2FybmluZ3MsXG4gICAgICBkZXBlbmRlbmN5R3JhcGgsXG4gICAgICBldmFsdWF0aW9uT3JkZXIsXG4gICAgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBFdmFsdWF0ZSBhIHNpbmdsZSBleHByZXNzaW9uXG4gICAqL1xuICBldmFsdWF0ZShleHByZXNzaW9uOiBzdHJpbmcsIGNvbnRleHQ6IEV2YWx1YXRpb25Db250ZXh0KTogRXZhbHVhdGlvblJlc3VsdCB7XG4gICAgdGhpcy5jaGVja0V4cHJlc3Npb25MZW5ndGgoZXhwcmVzc2lvbik7XG4gICAgY29uc3Qgbm9ybWFsaXplZENvbnRleHQgPSB0aGlzLm5vcm1hbGl6ZUNvbnRleHQoY29udGV4dCk7XG4gICAgcmV0dXJuIHRoaXMuZXZhbHVhdG9yLmV2YWx1YXRlKGV4cHJlc3Npb24sIG5vcm1hbGl6ZWRDb250ZXh0KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBFdmFsdWF0ZSBhbGwgZm9ybXVsYXMgaW4gZGVwZW5kZW5jeSBvcmRlclxuICAgKi9cbiAgZXZhbHVhdGVBbGwoXG4gICAgZm9ybXVsYXM6IEZvcm11bGFEZWZpbml0aW9uW10sXG4gICAgY29udGV4dDogRXZhbHVhdGlvbkNvbnRleHRcbiAgKTogRXZhbHVhdGlvblJlc3VsdFNldCB7XG4gICAgY29uc3Qgc3RhcnRUaW1lID0gRGF0ZS5ub3coKTtcbiAgICBjb25zdCByZXN1bHRzID0gbmV3IE1hcDxzdHJpbmcsIEV2YWx1YXRpb25SZXN1bHQ+KCk7XG4gICAgY29uc3QgZXJyb3JzOiBFcnJvcltdID0gW107XG5cbiAgICAvLyBHZXQgZXZhbHVhdGlvbiBvcmRlclxuICAgIGxldCBldmFsdWF0aW9uT3JkZXI6IHN0cmluZ1tdO1xuICAgIHRyeSB7XG4gICAgICBldmFsdWF0aW9uT3JkZXIgPSB0aGlzLmdldEV2YWx1YXRpb25PcmRlcihmb3JtdWxhcyk7XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIHJlc3VsdHMsXG4gICAgICAgIHN1Y2Nlc3M6IGZhbHNlLFxuICAgICAgICBlcnJvcnM6IFtlcnJvciBhcyBFcnJvcl0sXG4gICAgICAgIHRvdGFsRXhlY3V0aW9uVGltZU1zOiBEYXRlLm5vdygpIC0gc3RhcnRUaW1lLFxuICAgICAgICBldmFsdWF0aW9uT3JkZXI6IFtdLFxuICAgICAgfTtcbiAgICB9XG5cbiAgICAvLyBDcmVhdGUgYSBtYXAgb2YgZm9ybXVsYXMgYnkgSURcbiAgICBjb25zdCBmb3JtdWxhTWFwID0gbmV3IE1hcDxzdHJpbmcsIEZvcm11bGFEZWZpbml0aW9uPigpO1xuICAgIGZvciAoY29uc3QgZm9ybXVsYSBvZiBmb3JtdWxhcykge1xuICAgICAgZm9ybXVsYU1hcC5zZXQoZm9ybXVsYS5pZCwgZm9ybXVsYSk7XG4gICAgfVxuXG4gICAgLy8gRXZhbHVhdGUgaW4gb3JkZXIsIG1lcmdpbmcgcmVzdWx0cyBpbnRvIGNvbnRleHRcbiAgICBjb25zdCB3b3JraW5nQ29udGV4dDogRXZhbHVhdGlvbkNvbnRleHQgPSB0aGlzLm5vcm1hbGl6ZUNvbnRleHQoY29udGV4dCk7XG5cbiAgICBmb3IgKGNvbnN0IGZvcm11bGFJZCBvZiBldmFsdWF0aW9uT3JkZXIpIHtcbiAgICAgIGNvbnN0IGZvcm11bGEgPSBmb3JtdWxhTWFwLmdldChmb3JtdWxhSWQpO1xuICAgICAgaWYgKCFmb3JtdWxhKSBjb250aW51ZTtcblxuICAgICAgdHJ5IHtcbiAgICAgICAgY29uc3QgcmVzdWx0ID0gdGhpcy5ldmFsdWF0b3IuZXZhbHVhdGUoZm9ybXVsYS5leHByZXNzaW9uLCB3b3JraW5nQ29udGV4dCk7XG5cbiAgICAgICAgLy8gQXBwbHkgcm91bmRpbmcgaWYgY29uZmlndXJlZFxuICAgICAgICBsZXQgdmFsdWUgPSByZXN1bHQudmFsdWU7XG4gICAgICAgIGlmIChmb3JtdWxhLnJvdW5kaW5nICYmIHRoaXMuaXNEZWNpbWFsKHZhbHVlKSkge1xuICAgICAgICAgIHZhbHVlID0gdGhpcy5hcHBseVJvdW5kaW5nKHZhbHVlIGFzIERlY2ltYWwsIGZvcm11bGEucm91bmRpbmcpO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gSGFuZGxlIGVycm9ycyBiYXNlZCBvbiBmb3JtdWxhIGNvbmZpZ1xuICAgICAgICBpZiAoIXJlc3VsdC5zdWNjZXNzICYmIGZvcm11bGEub25FcnJvcikge1xuICAgICAgICAgIHZhbHVlID0gdGhpcy5oYW5kbGVFcnJvcihmb3JtdWxhLCByZXN1bHQuZXJyb3IpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmVzdWx0cy5zZXQoZm9ybXVsYUlkLCB7XG4gICAgICAgICAgLi4ucmVzdWx0LFxuICAgICAgICAgIHZhbHVlLFxuICAgICAgICB9KTtcblxuICAgICAgICAvLyBNZXJnZSByZXN1bHQgaW50byBjb250ZXh0IGZvciBzdWJzZXF1ZW50IGZvcm11bGFzXG4gICAgICAgIHdvcmtpbmdDb250ZXh0LnZhcmlhYmxlc1tmb3JtdWxhSWRdID0gdmFsdWU7XG5cbiAgICAgICAgaWYgKCFyZXN1bHQuc3VjY2Vzcykge1xuICAgICAgICAgIGVycm9ycy5wdXNoKHJlc3VsdC5lcnJvciEpO1xuICAgICAgICB9XG4gICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICBjb25zdCBldmFsUmVzdWx0OiBFdmFsdWF0aW9uUmVzdWx0ID0ge1xuICAgICAgICAgIHZhbHVlOiBudWxsLFxuICAgICAgICAgIHN1Y2Nlc3M6IGZhbHNlLFxuICAgICAgICAgIGVycm9yOiBlcnJvciBhcyBFcnJvcixcbiAgICAgICAgICBleGVjdXRpb25UaW1lTXM6IDAsXG4gICAgICAgICAgYWNjZXNzZWRWYXJpYWJsZXM6IG5ldyBTZXQoKSxcbiAgICAgICAgfTtcblxuICAgICAgICAvLyBIYW5kbGUgZXJyb3IgYmFzZWQgb24gZm9ybXVsYSBjb25maWdcbiAgICAgICAgaWYgKGZvcm11bGEub25FcnJvcikge1xuICAgICAgICAgIGV2YWxSZXN1bHQudmFsdWUgPSB0aGlzLmhhbmRsZUVycm9yKGZvcm11bGEsIGVycm9yIGFzIEVycm9yKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJlc3VsdHMuc2V0KGZvcm11bGFJZCwgZXZhbFJlc3VsdCk7XG4gICAgICAgIGVycm9ycy5wdXNoKGVycm9yIGFzIEVycm9yKTtcblxuICAgICAgICAvLyBTdGlsbCBhZGQgdG8gY29udGV4dCAoYXMgbnVsbCBvciBkZWZhdWx0IHZhbHVlKSBzbyBkZXBlbmRlbnQgZm9ybXVsYXMgY2FuIHByb2NlZWRcbiAgICAgICAgd29ya2luZ0NvbnRleHQudmFyaWFibGVzW2Zvcm11bGFJZF0gPSBldmFsUmVzdWx0LnZhbHVlO1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiB7XG4gICAgICByZXN1bHRzLFxuICAgICAgc3VjY2VzczogZXJyb3JzLmxlbmd0aCA9PT0gMCxcbiAgICAgIGVycm9ycyxcbiAgICAgIHRvdGFsRXhlY3V0aW9uVGltZU1zOiBEYXRlLm5vdygpIC0gc3RhcnRUaW1lLFxuICAgICAgZXZhbHVhdGlvbk9yZGVyLFxuICAgIH07XG4gIH1cblxuICAvKipcbiAgICogUmVnaXN0ZXIgYSBjdXN0b20gZnVuY3Rpb25cbiAgICovXG4gIHJlZ2lzdGVyRnVuY3Rpb24oZGVmaW5pdGlvbjogRnVuY3Rpb25EZWZpbml0aW9uKTogdm9pZCB7XG4gICAgY29uc3QgbmFtZSA9IGRlZmluaXRpb24ubmFtZS50b1VwcGVyQ2FzZSgpO1xuICAgIHRoaXMuZnVuY3Rpb25zLnNldChuYW1lLCBkZWZpbml0aW9uKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZWdpc3RlciBtdWx0aXBsZSBjdXN0b20gZnVuY3Rpb25zXG4gICAqL1xuICByZWdpc3RlckZ1bmN0aW9ucyhkZWZpbml0aW9uczogRnVuY3Rpb25EZWZpbml0aW9uW10pOiB2b2lkIHtcbiAgICBmb3IgKGNvbnN0IGRlZmluaXRpb24gb2YgZGVmaW5pdGlvbnMpIHtcbiAgICAgIHRoaXMucmVnaXN0ZXJGdW5jdGlvbihkZWZpbml0aW9uKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogR2V0IHJlZ2lzdGVyZWQgZnVuY3Rpb24gbmFtZXNcbiAgICovXG4gIGdldFJlZ2lzdGVyZWRGdW5jdGlvbnMoKTogc3RyaW5nW10ge1xuICAgIHJldHVybiBBcnJheS5mcm9tKHRoaXMuZnVuY3Rpb25zLmtleXMoKSk7XG4gIH1cblxuICAvKipcbiAgICogQ2xlYXIgdGhlIEFTVCBjYWNoZVxuICAgKi9cbiAgY2xlYXJDYWNoZSgpOiB2b2lkIHtcbiAgICB0aGlzLmFzdENhY2hlLmNsZWFyKCk7XG4gICAgdGhpcy5kZXBlbmRlbmN5Q2FjaGUuY2xlYXIoKTtcbiAgICB0aGlzLmNhY2hlSGl0cyA9IDA7XG4gICAgdGhpcy5jYWNoZU1pc3NlcyA9IDA7XG4gIH1cblxuICAvKipcbiAgICogR2V0IGNhY2hlIHN0YXRpc3RpY3NcbiAgICovXG4gIGdldENhY2hlU3RhdHMoKTogQ2FjaGVTdGF0cyB7XG4gICAgY29uc3QgdG90YWwgPSB0aGlzLmNhY2hlSGl0cyArIHRoaXMuY2FjaGVNaXNzZXM7XG4gICAgcmV0dXJuIHtcbiAgICAgIHNpemU6IHRoaXMuYXN0Q2FjaGUuc2l6ZSxcbiAgICAgIGhpdHM6IHRoaXMuY2FjaGVIaXRzLFxuICAgICAgbWlzc2VzOiB0aGlzLmNhY2hlTWlzc2VzLFxuICAgICAgaGl0UmF0ZTogdG90YWwgPiAwID8gdGhpcy5jYWNoZUhpdHMgLyB0b3RhbCA6IDAsXG4gICAgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXQgdGhlIGRlY2ltYWwgdXRpbGl0aWVzIGluc3RhbmNlXG4gICAqL1xuICBnZXREZWNpbWFsVXRpbHMoKTogRGVjaW1hbFV0aWxzIHtcbiAgICByZXR1cm4gdGhpcy5kZWNpbWFsVXRpbHM7XG4gIH1cblxuICAvKipcbiAgICogQ3JlYXRlIGEgRGVjaW1hbCBmcm9tIGEgdmFsdWVcbiAgICovXG4gIGNyZWF0ZURlY2ltYWwodmFsdWU6IHN0cmluZyB8IG51bWJlcik6IERlY2ltYWwge1xuICAgIHJldHVybiB0aGlzLmRlY2ltYWxVdGlscy5mcm9tKHZhbHVlKTtcbiAgfVxuXG4gIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAgLy8gUHJpdmF0ZSBtZXRob2RzXG4gIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cblxuICBwcml2YXRlIGNoZWNrRXhwcmVzc2lvbkxlbmd0aChleHByZXNzaW9uOiBzdHJpbmcpOiB2b2lkIHtcbiAgICBjb25zdCBtYXhMZW5ndGggPSB0aGlzLmNvbmZpZy5zZWN1cml0eT8ubWF4RXhwcmVzc2lvbkxlbmd0aCA/PyAxMDAwMDtcbiAgICBpZiAoZXhwcmVzc2lvbi5sZW5ndGggPiBtYXhMZW5ndGgpIHtcbiAgICAgIHRocm93IG5ldyBNYXhFeHByZXNzaW9uTGVuZ3RoRXJyb3IoZXhwcmVzc2lvbi5sZW5ndGgsIG1heExlbmd0aCk7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBub3JtYWxpemVDb250ZXh0KGNvbnRleHQ6IEV2YWx1YXRpb25Db250ZXh0KTogRXZhbHVhdGlvbkNvbnRleHQge1xuICAgIC8vIERlZXAgY29weSBhbmQgY29udmVydCBudW1lcmljIHZhbHVlcyB0byBEZWNpbWFsIGlmIGF1dG9Db252ZXJ0RmxvYXRzIGlzIGVuYWJsZWRcbiAgICBjb25zdCBhdXRvQ29udmVydCA9IHRoaXMuY29uZmlnLmRlY2ltYWw/LmF1dG9Db252ZXJ0RmxvYXRzID8/IHRydWU7XG5cbiAgICBpZiAoIWF1dG9Db252ZXJ0KSB7XG4gICAgICByZXR1cm4geyAuLi5jb250ZXh0IH07XG4gICAgfVxuXG4gICAgY29uc3Qgbm9ybWFsaXplZFZhcmlhYmxlczogUmVjb3JkPHN0cmluZywgdW5rbm93bj4gPSB7fTtcbiAgICBmb3IgKGNvbnN0IFtrZXksIHZhbHVlXSBvZiBPYmplY3QuZW50cmllcyhjb250ZXh0LnZhcmlhYmxlcykpIHtcbiAgICAgIG5vcm1hbGl6ZWRWYXJpYWJsZXNba2V5XSA9IHRoaXMuY29udmVydFZhbHVlKHZhbHVlKTtcbiAgICB9XG5cbiAgICByZXR1cm4ge1xuICAgICAgLi4uY29udGV4dCxcbiAgICAgIHZhcmlhYmxlczogbm9ybWFsaXplZFZhcmlhYmxlcyxcbiAgICB9O1xuICB9XG5cbiAgcHJpdmF0ZSBjb252ZXJ0VmFsdWUodmFsdWU6IHVua25vd24pOiB1bmtub3duIHtcbiAgICBpZiAodHlwZW9mIHZhbHVlID09PSAnbnVtYmVyJyAmJiAhaXNOYU4odmFsdWUpICYmIGlzRmluaXRlKHZhbHVlKSkge1xuICAgICAgcmV0dXJuIHRoaXMuZGVjaW1hbFV0aWxzLmZyb20odmFsdWUpO1xuICAgIH1cbiAgICBpZiAoQXJyYXkuaXNBcnJheSh2YWx1ZSkpIHtcbiAgICAgIHJldHVybiB2YWx1ZS5tYXAodiA9PiB0aGlzLmNvbnZlcnRWYWx1ZSh2KSk7XG4gICAgfVxuICAgIGlmICh2YWx1ZSAhPT0gbnVsbCAmJiB0eXBlb2YgdmFsdWUgPT09ICdvYmplY3QnKSB7XG4gICAgICBjb25zdCBjb252ZXJ0ZWQ6IFJlY29yZDxzdHJpbmcsIHVua25vd24+ID0ge307XG4gICAgICBmb3IgKGNvbnN0IFtrLCB2XSBvZiBPYmplY3QuZW50cmllcyh2YWx1ZSkpIHtcbiAgICAgICAgY29udmVydGVkW2tdID0gdGhpcy5jb252ZXJ0VmFsdWUodik7XG4gICAgICB9XG4gICAgICByZXR1cm4gY29udmVydGVkO1xuICAgIH1cbiAgICByZXR1cm4gdmFsdWU7XG4gIH1cblxuICBwcml2YXRlIGlzRGVjaW1hbCh2YWx1ZTogdW5rbm93bik6IGJvb2xlYW4ge1xuICAgIHJldHVybiB2YWx1ZSBpbnN0YW5jZW9mIERlY2ltYWw7XG4gIH1cblxuICBwcml2YXRlIGFwcGx5Um91bmRpbmcoXG4gICAgdmFsdWU6IERlY2ltYWwsXG4gICAgY29uZmlnOiB7IG1vZGU6IHN0cmluZzsgcHJlY2lzaW9uOiBudW1iZXIgfVxuICApOiBEZWNpbWFsIHtcbiAgICBpZiAoY29uZmlnLm1vZGUgPT09ICdOT05FJykge1xuICAgICAgcmV0dXJuIHZhbHVlO1xuICAgIH1cbiAgICByZXR1cm4gdGhpcy5kZWNpbWFsVXRpbHMucm91bmQodmFsdWUsIGNvbmZpZy5wcmVjaXNpb24sIGNvbmZpZy5tb2RlIGFzIGFueSk7XG4gIH1cblxuICBwcml2YXRlIGhhbmRsZUVycm9yKGZvcm11bGE6IEZvcm11bGFEZWZpbml0aW9uLCBfZXJyb3I/OiBFcnJvcik6IHVua25vd24ge1xuICAgIGNvbnN0IGJlaGF2aW9yID0gZm9ybXVsYS5vbkVycm9yO1xuICAgIGlmICghYmVoYXZpb3IpIHJldHVybiBudWxsO1xuXG4gICAgc3dpdGNoIChiZWhhdmlvci50eXBlKSB7XG4gICAgICBjYXNlICdOVUxMJzpcbiAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICBjYXNlICdaRVJPJzpcbiAgICAgICAgcmV0dXJuIHRoaXMuZGVjaW1hbFV0aWxzLnplcm8oKTtcbiAgICAgIGNhc2UgJ0RFRkFVTFQnOlxuICAgICAgICByZXR1cm4gYmVoYXZpb3IuZGVmYXVsdFZhbHVlID8/IGZvcm11bGEuZGVmYXVsdFZhbHVlID8/IG51bGw7XG4gICAgICBjYXNlICdTS0lQJzpcbiAgICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICAgIGNhc2UgJ1RIUk9XJzpcbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIHRocm93IF9lcnJvcjtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIG1heWJlRXZpY3RDYWNoZSgpOiB2b2lkIHtcbiAgICBjb25zdCBtYXhTaXplID0gdGhpcy5jb25maWcubWF4Q2FjaGVTaXplID8/IDEwMDA7XG4gICAgaWYgKHRoaXMuYXN0Q2FjaGUuc2l6ZSA+PSBtYXhTaXplKSB7XG4gICAgICAvLyBTaW1wbGUgRklGTyBldmljdGlvbiAtIHJlbW92ZSBmaXJzdCAxMCUgb2YgZW50cmllc1xuICAgICAgY29uc3QgdG9SZW1vdmUgPSBNYXRoLmNlaWwobWF4U2l6ZSAqIDAuMSk7XG4gICAgICBjb25zdCBrZXlzID0gQXJyYXkuZnJvbSh0aGlzLmFzdENhY2hlLmtleXMoKSkuc2xpY2UoMCwgdG9SZW1vdmUpO1xuICAgICAgZm9yIChjb25zdCBrZXkgb2Yga2V5cykge1xuICAgICAgICB0aGlzLmFzdENhY2hlLmRlbGV0ZShrZXkpO1xuICAgICAgICB0aGlzLmRlcGVuZGVuY3lDYWNoZS5kZWxldGUoa2V5KTtcbiAgICAgIH1cbiAgICB9XG4gIH1cbn1cbiJdfQ==
|