@grnsft/if-core
Version:
If core utilities.
298 lines • 42.5 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.validateArithmeticExpression = exports.evaluateSimpleArithmeticExpression = exports.isValidArithmeticExpression = exports.evaluateConfig = exports.evaluateInput = exports.evaluateArithmeticOutput = exports.getParameterFromArithmeticExpression = void 0;
const errors_1 = require("./errors");
const { InputValidationError, WrongArithmeticExpressionError, ZeroDivisionArithmeticOperationError, } = errors_1.ERRORS;
/**
* Parses an arithmetic parameter string by identifying and extracting
* operands and variables from the input string. This function handles
* arithmetic symbols, numeric values, and string literals, and returns
* a list of trimmed and sanitized operands for further processing.
*/
const parseArithmeticParameter = (arithmeticParameter) => {
const stringWithArithmeticSymbols = /(\s*[\+\-\*/&]\s*)|(\b\d+\b)|("[^"]+"|'[^']+')|(\b\w[\w-]*\b)/;
const operands = arithmeticParameter
.replace('=', '')
.trim()
.split(stringWithArithmeticSymbols)
.filter(Boolean)
.map(s => s.trim().replace(/^['"](.*)['"]$/, '$1'));
return [...operands];
};
/**
* Extracts a parameter from an arithmetic expression.
*/
const getParameterFromArithmeticExpression = (arithmeticParameter) => {
const regex = /["']?([a-zA-Z]+(?:[-_/][a-zA-Z]+)*)["']?/;
const regexForNumbers = /^=?[0-9+\-*/\s]+$/;
const match = regex.exec(arithmeticParameter) ||
regexForNumbers.exec(arithmeticParameter);
if (regexForNumbers.exec(arithmeticParameter)) {
const evaluatedValue = eval(arithmeticParameter.toString().replace('=', ''));
if (!isNaN(evaluatedValue) && isFinite(evaluatedValue)) {
return evaluatedValue;
}
}
if (typeof arithmeticParameter === 'string' && match !== null) {
return match[1];
}
return arithmeticParameter;
};
exports.getParameterFromArithmeticExpression = getParameterFromArithmeticExpression;
/**
* Evaluates an arithmetic expression provided as a string and returns the result.
* The function first checks if the `outputParameter` contains an assignment ('=') and extracts the parameter
* from the expression. If found, the expression is transformed by replacing the assignment and the parameter
* with the `calculatedResult`, and then evaluated using `eval`. The result is returned as an object.
* If no assignment is found, the function returns the original `outputParameter` with the `calculatedResult`.
*/
const evaluateArithmeticOutput = (outputParameter, output) => {
const checkedOutputParameter = (0, exports.getParameterFromArithmeticExpression)(outputParameter);
const isValidExpression = (0, exports.isValidArithmeticExpression)(outputParameter);
const valueFromOutput = output[outputParameter];
if (typeof outputParameter === 'string' &&
outputParameter.includes('=') &&
checkedOutputParameter &&
isValidExpression) {
const transformedOutputParameter = outputParameter
.replace('=', '')
.replace(`${checkedOutputParameter}`, valueFromOutput.toString())
.replace(/['"]/g, '');
const result = evaluateExpression(transformedOutputParameter);
delete output[outputParameter];
return {
...output,
[checkedOutputParameter]: result,
};
}
else if (outputParameter !== checkedOutputParameter) {
throw new WrongArithmeticExpressionError(`The output parameter \`${outputParameter}\` contains an invalid arithmetic expression. It should start with \`=\` and include the symbols \`*\`, \`+\`, \`-\` and \`/\`.`);
}
return output;
};
exports.evaluateArithmeticOutput = evaluateArithmeticOutput;
/**
* Evaluates and updates the input by replacing its properties
* with the results of arithmetic expressions.
*/
const evaluateInput = (input) => {
const evaluatedInput = Object.assign({}, input);
Object.entries(input).forEach(([parameter, value]) => {
evaluatedInput[parameter] = evaluateArithmeticExpression(value, parameter, [], evaluatedInput);
});
return evaluatedInput;
};
exports.evaluateInput = evaluateInput;
/**
* Evaluates and updates the config by replacing its properties
* with the results of arithmetic expressions.
*/
const evaluateConfig = (options) => {
const { config, input, parametersToEvaluate } = options;
const evaluatedConfig = Object.assign({}, config);
Object.keys(evaluatedConfig).forEach(parameter => {
if (parametersToEvaluate.includes(parameter)) {
(0, exports.validateArithmeticExpression)(parameter, evaluatedConfig[parameter]);
evaluatedConfig[parameter] = evaluateArithmeticExpression(evaluatedConfig[parameter], parameter, parametersToEvaluate, input);
}
});
return evaluatedConfig;
};
exports.evaluateConfig = evaluateConfig;
/**
* Checks if the provided parameter is a valid arithmetic expression.
* The function uses a regular expression to validate arithmetic expressions
* that consist of numbers, alphanumeric strings, or quoted strings,
* separated by arithmetic operators (+, -, *, /). The expression can contain
* whitespace and support basic arithmetic operations.
*/
const isValidArithmeticExpression = (parameter) => {
const arithmeticExpression = /^\s*(\d+(\.\d+)?|["']?[a-zA-Z0-9-_]+["']?)(\s*[-+*/]\s*(\d+(\.\d+)?|["']?[a-zA-Z0-9-_]+["']?))*\s*$/;
const checkedParameter = (0, exports.getParameterFromArithmeticExpression)(parameter);
return !!(parameter !== checkedParameter &&
parameter.replace('=', '').match(arithmeticExpression));
};
exports.isValidArithmeticExpression = isValidArithmeticExpression;
/**
* Evaluates an arithmetic expression by validating it first,
* then either returning the original expression or evaluating its value.
*
* The function performs the following:
* 1. Checks if the paramenter is `timestamp`, returns the value.
* 2. Checks if the expression is valid based on the provided parameters.
* 3. If valid, it returns the original expression.
* 4. If the expression is a basic arithmetic operation, it evaluates the expression.
* 5. If not, it proceeds to evaluate more complex expressions.
*/
const evaluateArithmeticExpression = (expression, parameter, parametersToEvaluate, input) => {
if (parameter === 'timestamp') {
return input[parameter];
}
if (isNotArithmeticExpression(expression)) {
return expression;
}
const strippedEqualExpression = expression.replace('=', '');
if (isBasicArithmetic(strippedEqualExpression)) {
return evaluateExpression(strippedEqualExpression);
}
return evaluateComplexExpression(expression, parameter, parametersToEvaluate, input);
};
/**
* Checks if the given expression is not an arithmetic expression.
*/
const isNotArithmeticExpression = (expression) => typeof expression !== 'string' ||
(!expression.includes('=') && !containsOnlyNumbersAndOperators(expression));
/**
* Utility function to check if a string contains only numbers and basic math operators.
*/
const containsOnlyNumbersAndOperators = (expression) => {
const numberAndMathSymbolsRegex = /^\s*\d+(\.\d+)?(\s*[-+*/]\s*\d+(\.\d+)?)*\s*$/;
return numberAndMathSymbolsRegex.test(expression);
};
/**
* Checks if the provided expression is a basic arithmetic expression.
*/
const isBasicArithmetic = (expression) => typeof expression === 'string' && containsOnlyNumbersAndOperators(expression);
/**
* Evaluates a complex arithmetic expression by parsing it into operands,
* validating whether each operand is a number or an operator, and evaluating
* any parameters within the expression. The resulting valid operands are
* joined together and evaluated using `eval`.
*/
const evaluateComplexExpression = (expression, parameterValue, parametersToEvaluate, input) => {
const operands = parseArithmeticParameter(expression);
const params = [];
operands.forEach(operand => {
// Check if the operand is a number
if (operand && !isNaN(Number(operand))) {
params.push(operand);
}
else if (isOperandOperator(operand, expression)) {
params.push(operand);
}
else {
const evaluatedOperand = evaluateOperand({
parameter: operand,
expression,
parameterValue,
parametersToEvaluate,
input,
});
params.push(evaluatedOperand);
}
});
return evaluateExpression(params.join(''));
};
/**
* Checks if a given operand is a valid arithmetic operator within an expression.
* Throws an error if the operand is not one of the allowed arithmetic operators: *, +, -, or /.
*/
const isOperandOperator = (operand, expression) => {
if (operand.length === 1 && !/[\+\-\*/]/.test(operand)) {
throw new WrongArithmeticExpressionError(`The operator in \`${expression}\` should be one of these arithmetic operators: *, +, - or /.`);
}
else if (operand.length === 1) {
return true;
}
return false;
};
/**
* Evaluates the value of a given parameter from the input.
* If the parameter's value is an arithmetic expression, it evaluates the expression.
* Otherwise, it returns the parameter's value directly.
*/
const evaluateOperand = (operandOptions) => {
const { parameter, expression, parametersToEvaluate, input } = operandOptions;
if (!(parameter in input)) {
throw new InputValidationError(`${parameter} is missing from the input array or has nullish value.`);
}
// Checks if the parameter in the input array has number value.
if (isNaN(Number(input[parameter]))) {
throw new InputValidationError(`The value of the \`${parameter}\` parameter in the input array is not a number.`);
}
const isExpression = (0, exports.isValidArithmeticExpression)(expression);
if (isExpression) {
return evaluateArithmeticExpression(input[parameter], parameter, [...parametersToEvaluate, parameter], input);
}
return input[parameter];
};
/**
* Evaluates a simple arithmetic expression if the input is a valid expression.
* It checks if the input string follows a pattern for simple arithmetic
* operations (numbers with operators like *, /, +, -) between them.
*/
const evaluateSimpleArithmeticExpression = (parameter) => {
const simpleExpressionRegex = /^\d+(\.\d+)?([+\-*/]\d+(\.\d+)?)*$/;
return typeof parameter === 'string' &&
parameter.replace('=', '').match(simpleExpressionRegex)
? evaluateExpression(parameter.replace('=', ''))
: parameter;
};
exports.evaluateSimpleArithmeticExpression = evaluateSimpleArithmeticExpression;
/**
* Validates whether a given value is a valid arithmetic expression.
*
* If the value is a string, it first removes any equal signs and checks if it
* is a valid arithmetic expression using the `isValidArithmeticExpression` helper.
* If valid, it attempts to evaluate the expression and ensures the result is numeric.
* In case of an invalid format, it calls `validateExpressionFormat`.
* The function returns true if the value is valid or numeric.
*/
const validateArithmeticExpression = (parameterName, value, type) => {
if (typeof value === 'string') {
const sanitizedValue = value.replace('=', '');
if ((0, exports.isValidArithmeticExpression)(sanitizedValue)) {
const evaluatedParam = evaluateExpression(sanitizedValue) || value;
if (!isNaN(Number(evaluatedParam))) {
return evaluatedParam;
}
}
validateExpressionFormat(parameterName, value);
if (type === 'number') {
const numberMatch = sanitizedValue.match(/[-+]?[0-9]*\.?[0-9]+/g);
return numberMatch ? parseFloat(numberMatch[0]) : value;
}
}
return value;
};
exports.validateArithmeticExpression = validateArithmeticExpression;
/**
* Helper function to evaluate the arithmetic expression.
*/
const evaluateExpression = (expression) => {
try {
const evaluatedValue = eval(expression);
if (evaluatedValue === Infinity) {
throw new ZeroDivisionArithmeticOperationError(`The input expression contains a division by zero: \`${expression}\`.`);
}
if (isNaN(evaluatedValue)) {
return undefined;
}
return evaluatedValue;
}
catch (error) {
if (error instanceof ZeroDivisionArithmeticOperationError) {
throw error;
}
return undefined;
}
};
/**
* Validates whether the provided string value is a valid arithmetic expression based on its format.
*
* Checks if the expression contains an `=` sign and ensures that
* the part of the string following the equal sign is a valid arithmetic expression.
*
* - If the string starts with `=`, the remaining part should be a valid arithmetic expression.
* - If it doesn't start with `=`, the entire string should not resemble a valid arithmetic expression.
*
* Throws an `InputValidationError` error if the format or content of the arithmetic expression is invalid.
*/
const validateExpressionFormat = (parameterName, value) => {
const hasEqualSign = value.includes('=');
const isValid = (0, exports.isValidArithmeticExpression)(value.replace('=', ''));
if ((hasEqualSign && !isValid) || (!hasEqualSign && isValid)) {
throw new InputValidationError(`The \`${parameterName}\` contains an invalid arithmetic expression. It should start with \`=\` and include the symbols \`*\`, \`+\`, \`-\` and \`/\`.`);
}
};
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXJpdGhtZXRpYy1oZWxwZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvdXRpbHMvYXJpdGhtZXRpYy1oZWxwZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBRUEscUNBQWdDO0FBRWhDLE1BQU0sRUFDSixvQkFBb0IsRUFDcEIsOEJBQThCLEVBQzlCLG9DQUFvQyxHQUNyQyxHQUFHLGVBQU0sQ0FBQztBQUVYOzs7OztHQUtHO0FBQ0gsTUFBTSx3QkFBd0IsR0FBRyxDQUFDLG1CQUEyQixFQUFFLEVBQUU7SUFDL0QsTUFBTSwyQkFBMkIsR0FDL0IsK0RBQStELENBQUM7SUFFbEUsTUFBTSxRQUFRLEdBQUcsbUJBQW1CO1NBQ2pDLE9BQU8sQ0FBQyxHQUFHLEVBQUUsRUFBRSxDQUFDO1NBQ2hCLElBQUksRUFBRTtTQUNOLEtBQUssQ0FBQywyQkFBMkIsQ0FBQztTQUNsQyxNQUFNLENBQUMsT0FBTyxDQUFDO1NBQ2YsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLElBQUksRUFBRSxDQUFDLE9BQU8sQ0FBQyxnQkFBZ0IsRUFBRSxJQUFJLENBQUMsQ0FBQyxDQUFDO0lBRXRELE9BQU8sQ0FBQyxHQUFHLFFBQVEsQ0FBQyxDQUFDO0FBQ3ZCLENBQUMsQ0FBQztBQUVGOztHQUVHO0FBQ0ksTUFBTSxvQ0FBb0MsR0FBRyxDQUNsRCxtQkFBMkIsRUFDM0IsRUFBRTtJQUNGLE1BQU0sS0FBSyxHQUFHLDBDQUEwQyxDQUFDO0lBQ3pELE1BQU0sZUFBZSxHQUFHLG1CQUFtQixDQUFDO0lBRTVDLE1BQU0sS0FBSyxHQUNULEtBQUssQ0FBQyxJQUFJLENBQUMsbUJBQW1CLENBQUM7UUFDL0IsZUFBZSxDQUFDLElBQUksQ0FBQyxtQkFBbUIsQ0FBQyxDQUFDO0lBRTVDLElBQUksZUFBZSxDQUFDLElBQUksQ0FBQyxtQkFBbUIsQ0FBQyxFQUFFLENBQUM7UUFDOUMsTUFBTSxjQUFjLEdBQUcsSUFBSSxDQUN6Qixt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b0NBQW9DLENBQzVDLHVEQUF1RCxVQUFVLEtBQUssQ0FDdkUsQ0FBQztRQUNKLENBQUM7UUFDRCxJQUFJLEtBQUssQ0FBQyxjQUFjLENBQUMsRUFBRSxDQUFDO1lBQzFCLE9BQU8sU0FBUyxDQUFDO1FBQ25CLENBQUM7UUFFRCxPQUFPLGNBQWMsQ0FBQztJQUN4QixDQUFDO0lBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztRQUNmLElBQUksS0FBSyxZQUFZLG9DQUFvQyxFQUFFLENBQUM7WUFDMUQsTUFBTSxLQUFLLENBQUM7UUFDZCxDQUFDO1FBRUQsT0FBTyxTQUFTLENBQUM7SUFDbkIsQ0FBQztBQUNILENBQUMsQ0FBQztBQUVGOzs7Ozs7Ozs7O0dBVUc7QUFDSCxNQUFNLHdCQUF3QixHQUFHLENBQUMsYUFBcUIsRUFBRSxLQUFhLEVBQUUsRUFBRTtJQUN4RSxNQUFNLFlBQVksR0FBRyxLQUFLLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBQ3pDLE1BQU0sT0FBTyxHQUFHLElBQUEsbUNBQTJCLEVBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxHQUFHLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQztJQUVwRSxJQUFJLENBQUMsWUFBWSxJQUFJLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDLFlBQVksSUFBSSxPQUFPLENBQUMsRUFBRSxDQUFDO1FBQzdELE1BQU0sSUFBSSxvQkFBb0IsQ0FDNUIsU0FBUyxhQUFhLGlJQUFpSSxDQUN4SixDQUFDO0lBQ0osQ0FBQztBQUNILENBQUMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7UGx1Z2luUGFyYW1zLCBBcml0aG1ldGljUGFyYW1ldGVyc30gZnJvbSAnLi4vdHlwZXMnO1xuXG5pbXBvcnQge0VSUk9SU30gZnJvbSAnLi9lcnJvcnMnO1xuXG5jb25zdCB7XG4gIElucHV0VmFsaWRhdGlvbkVycm9yLFxuICBXcm9uZ0FyaXRobWV0aWNFeHByZXNzaW9uRXJyb3IsXG4gIFplcm9EaXZpc2lvbkFyaXRobWV0aWNPcGVyYXRpb25FcnJvcixcbn0gPSBFUlJPUlM7XG5cbi8qKlxuICogUGFyc2VzIGFuIGFyaXRobWV0aWMgcGFyYW1ldGVyIHN0cmluZyBieSBpZGVudGlmeWluZyBhbmQgZXh0cmFjdGluZ1xuICogb3BlcmFuZHMgYW5kIHZhcmlhYmxlcyBmcm9tIHRoZSBpbnB1dCBzdHJpbmcuIFRoaXMgZnVuY3Rpb24gaGFuZGxlc1xuICogYXJpdGhtZXRpYyBzeW1ib2xzLCBudW1lcmljIHZhbHVlcywgYW5kIHN0cmluZyBsaXRlcmFscywgYW5kIHJldHVybnNcbiAqIGEgbGlzdCBvZiB0cmltbWVkIGFuZCBzYW5pdGl6ZWQgb3BlcmFuZHMgZm9yIGZ1cnRoZXIgcHJvY2Vzc2luZy5cbiAqL1xuY29uc3QgcGFyc2VBcml0aG1ldGljUGFyYW1ldGVyID0gKGFyaXRobWV0aWNQYXJhbWV0ZXI6IHN0cmluZykgPT4ge1xuICBjb25zdCBzdHJpbmdXaXRoQXJpdGhtZXRpY1N5bWJvbHMgPVxuICAgIC8oXFxzKltcXCtcXC1cXCovJl1cXHMqKXwoXFxiXFxkK1xcYil8KFwiW15cIl0rXCJ8J1teJ10rJyl8KFxcYlxcd1tcXHctXSpcXGIpLztcblxuICBjb25zdCBvcGVyYW5kcyA9IGFyaXRobWV0aWNQYXJhbWV0ZXJcbiAgICAucmVwbGFjZSgnPScsICcnKVxuICAgIC50cmltKClcbiAgICAuc3BsaXQoc3RyaW5nV2l0aEFyaXRobWV0aWNTeW1ib2xzKVxuICAgIC5maWx0ZXIoQm9vbGVhbilcbiAgICAubWFwKHMgPT4gcy50cmltKCkucmVwbGFjZSgvXlsnXCJdKC4qKVsnXCJdJC8sICckMScpKTtcblxuICByZXR1cm4gWy4uLm9wZXJhbmRzXTtcbn07XG5cbi8qKlxuICogRXh0cmFjdHMgYSBwYXJhbWV0ZXIgZnJvbSBhbiBhcml0aG1ldGljIGV4cHJlc3Npb24uXG4gKi9cbmV4cG9ydCBjb25zdCBnZXRQYXJhbWV0ZXJGcm9tQXJpdGhtZXRpY0V4cHJlc3Npb24gPSAoXG4gIGFyaXRobWV0aWNQYXJhbWV0ZXI6IHN0cmluZ1xuKSA9PiB7XG4gIGNvbnN0IHJlZ2V4ID0gL1tcIiddPyhbYS16QS1aXSsoPzpbLV8vXVthLXpBLVpdKykqKVtcIiddPy87XG4gIGNvbnN0IHJlZ2V4Rm9yTnVtYmVycyA9IC9ePT9bMC05K1xcLSovXFxzXSskLztcblxuICBjb25zdCBtYXRjaCA9XG4gICAgcmVnZXguZXhlYyhhcml0aG1ldGljUGFyYW1ldGVyKSB8fFxuICAgIHJlZ2V4Rm9yTnVtYmVycy5leGVjKGFyaXRobWV0aWNQYXJhbWV0ZXIpO1xuXG4gIGlmIChyZWdleEZvck51bWJlcnMuZXhlYyhhcml0aG1ldGljUGFyYW1ldGVyKSkge1xuICAgIGNvbnN0IGV2YWx1YXRlZFZhbHVlID0gZXZhbChcbiAgICAgIGFyaXRobWV0aWNQYXJhbWV0ZXIudG9TdHJpbmcoKS5yZXBsYWNlKCc9JywgJycpXG4gICAgKTtcblxuICAgIGlmICghaXNOYU4oZXZhbHVhdGVkVmFsdWUpICYmIGlzRmluaXRlKGV2YWx1YXRlZFZhbHVlKSkge1xuICAgICAgcmV0dXJuIGV2YWx1YXRlZFZhbHVlO1xuICAgIH1cbiAgfVxuXG4gIGlmICh0eXBlb2YgYXJpdGhtZXRpY1BhcmFtZXRlciA9PT0gJ3N0cmluZycgJiYgbWF0Y2ggIT09IG51bGwpIHtcbiAgICByZXR1cm4gbWF0Y2hbMV07XG4gIH1cblxuICByZXR1cm4gYXJpdGhtZXRpY1BhcmFtZXRlcjtcbn07XG5cbi8qKlxuICogRXZhbHVhdGVzIGFuIGFyaXRobWV0aWMgZXhwcmVzc2lvbiBwcm92aWRlZCBhcyBhIHN0cmluZyBhbmQgcmV0dXJucyB0aGUgcmVzdWx0LlxuICogVGhlIGZ1bmN0aW9uIGZpcnN0IGNoZWNrcyBpZiB0aGUgYG91dHB1dFBhcmFtZXRlcmAgY29udGFpbnMgYW4gYXNzaWdubWVudCAoJz0nKSBhbmQgZXh0cmFjdHMgdGhlIHBhcmFtZXRlclxuICogZnJvbSB0aGUgZXhwcmVzc2lvbi4gSWYgZm91bmQsIHRoZSBleHByZXNzaW9uIGlzIHRyYW5zZm9ybWVkIGJ5IHJlcGxhY2luZyB0aGUgYXNzaWdubWVudCBhbmQgdGhlIHBhcmFtZXRlclxuICogd2l0aCB0aGUgYGNhbGN1bGF0ZWRSZXN1bHRgLCBhbmQgdGhlbiBldmFsdWF0ZWQgdXNpbmcgYGV2YWxgLiBUaGUgcmVzdWx0IGlzIHJldHVybmVkIGFzIGFuIG9iamVjdC5cbiAqIElmIG5vIGFzc2lnbm1lbnQgaXMgZm91bmQsIHRoZSBmdW5jdGlvbiByZXR1cm5zIHRoZSBvcmlnaW5hbCBgb3V0cHV0UGFyYW1ldGVyYCB3aXRoIHRoZSBgY2FsY3VsYXRlZFJlc3VsdGAuXG4gKi9cbmV4cG9ydCBjb25zdCBldmFsdWF0ZUFyaXRobWV0aWNPdXRwdXQgPSAoXG4gIG91dHB1dFBhcmFtZXRlcjogc3RyaW5nLFxuICBvdXRwdXQ6IFBsdWdpblBhcmFtc1xuKSA9PiB7XG4gIGNvbnN0IGNoZWNrZWRPdXRwdXRQYXJhbWV0ZXIgPVxuICAgIGdldFBhcmFtZXRlckZyb21Bcml0aG1ldGljRXhwcmVzc2lvbihvdXRwdXRQYXJhbWV0ZXIpO1xuICBjb25zdCBpc1ZhbGlkRXhwcmVzc2lvbiA9IGlzVmFsaWRBcml0aG1ldGljRXhwcmVzc2lvbihvdXRwdXRQYXJhbWV0ZXIpO1xuICBjb25zdCB2YWx1ZUZyb21PdXRwdXQgPSBvdXRwdXRbb3V0cHV0UGFyYW1ldGVyXTtcblxuICBpZiAoXG4gICAgdHlwZW9mIG91dHB1dFBhcmFtZXRlciA9PT0gJ3N0cmluZycgJiZcbiAgICBvdXRwdXRQYXJhbWV0ZXIuaW5jbHVkZXMoJz0nKSAmJlxuICAgIGNoZWNrZWRPdXRwdXRQYXJhbWV0ZXIgJiZcbiAgICBpc1ZhbGlkRXhwcmVzc2lvblxuICApIHtcbiAgICBjb25zdCB0cmFuc2Zvcm1lZE91dHB1dFBhcmFtZXRlciA9IG91dHB1dFBhcmFtZXRlclxuICAgICAgLnJlcGxhY2UoJz0nLCAnJylcbiAgICAgIC5yZXBsYWNlKGAke2NoZWNrZWRPdXRwdXRQYXJhbWV0ZXJ9YCwgdmFsdWVGcm9tT3V0cHV0LnRvU3RyaW5nKCkpXG4gICAgICAucmVwbGFjZSgvWydcIl0vZywgJycpO1xuXG4gICAgY29uc3QgcmVzdWx0ID0gZXZhbHVhdGVFeHByZXNzaW9uKHRyYW5zZm9ybWVkT3V0cHV0UGFyYW1ldGVyKTtcbiAgICBkZWxldGUgb3V0cHV0W291dHB1dFBhcmFtZXRlcl07XG5cbiAgICByZXR1cm4ge1xuICAgICAgLi4ub3V0cHV0LFxuICAgICAgW2NoZWNrZWRPdXRwdXRQYXJhbWV0ZXJdOiByZXN1bHQsXG4gICAgfTtcbiAgfSBlbHNlIGlmIChvdXRwdXRQYXJhbWV0ZXIgIT09IGNoZWNrZWRPdXRwdXRQYXJhbWV0ZXIpIHtcbiAgICB0aHJvdyBuZXcgV3JvbmdBcml0aG1ldGljRXhwcmVzc2lvbkVycm9yKFxuICAgICAgYFRoZSBvdXRwdXQgcGFyYW1ldGVyIFxcYCR7b3V0cHV0UGFyYW1ldGVyfVxcYCBjb250YWlucyBhbiBpbnZhbGlkIGFyaXRobWV0aWMgZXhwcmVzc2lvbi4gSXQgc2hvdWxkIHN0YXJ0IHdpdGggXFxgPVxcYCBhbmQgaW5jbHVkZSB0aGUgc3ltYm9scyBcXGAqXFxgLCBcXGArXFxgLCBcXGAtXFxgIGFuZCBcXGAvXFxgLmBcbiAgICApO1xuICB9XG5cbiAgcmV0dXJuIG91dHB1dDtcbn07XG5cbi8qKlxuICogRXZhbHVhdGVzIGFuZCB1cGRhdGVzIHRoZSBpbnB1dCBieSByZXBsYWNpbmcgaXRzIHByb3BlcnRpZXNcbiAqIHdpdGggdGhlIHJlc3VsdHMgb2YgYXJpdGhtZXRpYyBleHByZXNzaW9ucy5cbiAqL1xuZXhwb3J0IGNvbnN0IGV2YWx1YXRlSW5wdXQgPSAoaW5wdXQ6IFBsdWdpblBhcmFtcykgPT4ge1xuICBjb25zdCBldmFsdWF0ZWRJbnB1dCA9IE9iamVjdC5hc3NpZ24oe30sIGlucHV0KTtcblxuICBPYmplY3QuZW50cmllcyhpbnB1dCkuZm9yRWFjaCgoW3BhcmFtZXRlciwgdmFsdWVdKSA9PiB7XG4gICAgZXZhbHVhdGVkSW5wdXRbcGFyYW1ldGVyXSA9IGV2YWx1YXRlQXJpdGhtZXRpY0V4cHJlc3Npb24oXG4gICAgICB2YWx1ZSxcbiAgICAgIHBhcmFtZXRlcixcbiAgICAgIFtdLFxuICAgICAgZXZhbHVhdGVkSW5wdXRcbiAgICApO1xuICB9KTtcblxuICByZXR1cm4gZXZhbHVhdGVkSW5wdXQ7XG59O1xuXG4vKipcbiAqIEV2YWx1YXRlcyBhbmQgdXBkYXRlcyB0aGUgY29uZmlnIGJ5IHJlcGxhY2luZyBpdHMgcHJvcGVydGllc1xuICogd2l0aCB0aGUgcmVzdWx0cyBvZiBhcml0aG1ldGljIGV4cHJlc3Npb25zLlxuICovXG5leHBvcnQgY29uc3QgZXZhbHVhdGVDb25maWcgPSAob3B0aW9uczogQXJpdGhtZXRpY1BhcmFtZXRlcnMpID0+IHtcbiAgY29uc3Qge2NvbmZpZywgaW5wdXQsIHBhcmFtZXRlcnNUb0V2YWx1YXRlfSA9IG9wdGlvbnM7XG4gIGNvbnN0IGV2YWx1YXRlZENvbmZpZyA9IE9iamVjdC5hc3NpZ24oe30sIGNvbmZpZyk7XG5cbiAgT2JqZWN0LmtleXMoZXZhbHVhdGVkQ29uZmlnKS5mb3JFYWNoKHBhcmFtZXRlciA9PiB7XG4gICAgaWYgKHBhcmFtZXRlcnNUb0V2YWx1YXRlLmluY2x1ZGVzKHBhcmFtZXRlcikpIHtcbiAgICAgIHZhbGlkYXRlQXJpdGhtZXRpY0V4cHJlc3Npb24ocGFyYW1ldGVyLCBldmFsdWF0ZWRDb25maWdbcGFyYW1ldGVyXSk7XG5cbiAgICAgIGV2YWx1YXRlZENvbmZpZ1twYXJhbWV0ZXJdID0gZXZhbHVhdGVBcml0aG1ldGljRXhwcmVzc2lvbihcbiAgICAgICAgZXZhbHVhdGVkQ29uZmlnW3BhcmFtZXRlcl0sXG4gICAgICAgIHBhcmFtZXRlcixcbiAgICAgICAgcGFyYW1ldGVyc1RvRXZhbHVhdGUsXG4gICAgICAgIGlucHV0XG4gICAgICApO1xuICAgIH1cbiAgfSk7XG5cbiAgcmV0dXJuIGV2YWx1YXRlZENvbmZpZztcbn07XG5cbi8qKlxuICogQ2hlY2tzIGlmIHRoZSBwcm92aWRlZCBwYXJhbWV0ZXIgaXMgYSB2YWxpZCBhcml0aG1ldGljIGV4cHJlc3Npb24uXG4gKiBUaGUgZnVuY3Rpb24gdXNlcyBhIHJlZ3VsYXIgZXhwcmVzc2lvbiB0byB2YWxpZGF0ZSBhcml0aG1ldGljIGV4cHJlc3Npb25zXG4gKiB0aGF0IGNvbnNpc3Qgb2YgbnVtYmVycywgYWxwaGFudW1lcmljIHN0cmluZ3MsIG9yIHF1b3RlZCBzdHJpbmdzLFxuICogc2VwYXJhdGVkIGJ5IGFyaXRobWV0aWMgb3BlcmF0b3JzICgrLCAtLCAqLCAvKS4gVGhlIGV4cHJlc3Npb24gY2FuIGNvbnRhaW5cbiAqIHdoaXRlc3BhY2UgYW5kIHN1cHBvcnQgYmFzaWMgYXJpdGhtZXRpYyBvcGVyYXRpb25zLlxuICovXG5leHBvcnQgY29uc3QgaXNWYWxpZEFyaXRobWV0aWNFeHByZXNzaW9uID0gKHBhcmFtZXRlcjogc3RyaW5nKSA9PiB7XG4gIGNvbnN0IGFyaXRobWV0aWNFeHByZXNzaW9uID1cbiAgICAvXlxccyooXFxkKyhcXC5cXGQrKT98W1wiJ10/W2EtekEtWjAtOS1fXStbXCInXT8pKFxccypbLSsqL11cXHMqKFxcZCsoXFwuXFxkKyk/fFtcIiddP1thLXpBLVowLTktX10rW1wiJ10/KSkqXFxzKiQvO1xuICBjb25zdCBjaGVja2VkUGFyYW1ldGVyID0gZ2V0UGFyYW1ldGVyRnJvbUFyaXRobWV0aWNFeHByZXNzaW9uKHBhcmFtZXRlcik7XG5cbiAgcmV0dXJuICEhKFxuICAgIHBhcmFtZXRlciAhPT0gY2hlY2tlZFBhcmFtZXRlciAmJlxuICAgIHBhcmFtZXRlci5yZXBsYWNlKCc9JywgJycpLm1hdGNoKGFyaXRobWV0aWNFeHByZXNzaW9uKVxuICApO1xufTtcblxuLyoqXG4gKiBFdmFsdWF0ZXMgYW4gYXJpdGhtZXRpYyBleHByZXNzaW9uIGJ5IHZhbGlkYXRpbmcgaXQgZmlyc3QsXG4gKiB0aGVuIGVpdGhlciByZXR1cm5pbmcgdGhlIG9yaWdpbmFsIGV4cHJlc3Npb24gb3IgZXZhbHVhdGluZyBpdHMgdmFsdWUuXG4gKlxuICogVGhlIGZ1bmN0aW9uIHBlcmZvcm1zIHRoZSBmb2xsb3dpbmc6XG4gKiAxLiBDaGVja3MgaWYgdGhlIHBhcmFtZW50ZXIgaXMgYHRpbWVzdGFtcGAsIHJldHVybnMgdGhlIHZhbHVlLlxuICogMi4gQ2hlY2tzIGlmIHRoZSBleHByZXNzaW9uIGlzIHZhbGlkIGJhc2VkIG9uIHRoZSBwcm92aWRlZCBwYXJhbWV0ZXJzLlxuICogMy4gSWYgdmFsaWQsIGl0IHJldHVybnMgdGhlIG9yaWdpbmFsIGV4cHJlc3Npb24uXG4gKiA0LiBJZiB0aGUgZXhwcmVzc2lvbiBpcyBhIGJhc2ljIGFyaXRobWV0aWMgb3BlcmF0aW9uLCBpdCBldmFsdWF0ZXMgdGhlIGV4cHJlc3Npb24uXG4gKiA1LiBJZiBub3QsIGl0IHByb2NlZWRzIHRvIGV2YWx1YXRlIG1vcmUgY29tcGxleCBleHByZXNzaW9ucy5cbiAqL1xuY29uc3QgZXZhbHVhdGVBcml0aG1ldGljRXhwcmVzc2lvbiA9IChcbiAgZXhwcmVzc2lvbjogc3RyaW5nLFxuICBwYXJhbWV0ZXI6IHN0cmluZyxcbiAgcGFyYW1ldGVyc1RvRXZhbHVhdGU6IHN0cmluZ1tdLFxuICBpbnB1dDogUGx1Z2luUGFyYW1zXG4pID0+IHtcbiAgaWYgKHBhcmFtZXRlciA9PT0gJ3RpbWVzdGFtcCcpIHtcbiAgICByZXR1cm4gaW5wdXRbcGFyYW1ldGVyXTtcbiAgfVxuXG4gIGlmIChpc05vdEFyaXRobWV0aWNFeHByZXNzaW9uKGV4cHJlc3Npb24pKSB7XG4gICAgcmV0dXJuIGV4cHJlc3Npb247XG4gIH1cblxuICBjb25zdCBzdHJpcHBlZEVxdWFsRXhwcmVzc2lvbiA9IGV4cHJlc3Npb24ucmVwbGFjZSgnPScsICcnKTtcblxuICBpZiAoaXNCYXNpY0FyaXRobWV0aWMoc3RyaXBwZWRFcXVhbEV4cHJlc3Npb24pKSB7XG4gICAgcmV0dXJuIGV2YWx1YXRlRXhwcmVzc2lvbihzdHJpcHBlZEVxdWFsRXhwcmVzc2lvbik7XG4gIH1cblxuICByZXR1cm4gZXZhbHVhdGVDb21wbGV4RXhwcmVzc2lvbihcbiAgICBleHByZXNzaW9uLFxuICAgIHBhcmFtZXRlcixcbiAgICBwYXJhbWV0ZXJzVG9FdmFsdWF0ZSxcbiAgICBpbnB1dFxuICApO1xufTtcblxuLyoqXG4gKiBDaGVja3MgaWYgdGhlIGdpdmVuIGV4cHJlc3Npb24gaXMgbm90IGFuIGFyaXRobWV0aWMgZXhwcmVzc2lvbi5cbiAqL1xuY29uc3QgaXNOb3RBcml0aG1ldGljRXhwcmVzc2lvbiA9IChleHByZXNzaW9uOiBzdHJpbmcpID0+XG4gIHR5cGVvZiBleHByZXNzaW9uICE9PSAnc3RyaW5nJyB8fFxuICAoIWV4cHJlc3Npb24uaW5jbHVkZXMoJz0nKSAmJiAhY29udGFpbnNPbmx5TnVtYmVyc0FuZE9wZXJhdG9ycyhleHByZXNzaW9uKSk7XG5cbi8qKlxuICogVXRpbGl0eSBmdW5jdGlvbiB0byBjaGVjayBpZiBhIHN0cmluZyBjb250YWlucyBvbmx5IG51bWJlcnMgYW5kIGJhc2ljIG1hdGggb3BlcmF0b3JzLlxuICovXG5jb25zdCBjb250YWluc09ubHlOdW1iZXJzQW5kT3BlcmF0b3JzID0gKGV4cHJlc3Npb246IHN0cmluZyk6IGJvb2xlYW4gPT4ge1xuICBjb25zdCBudW1iZXJBbmRNYXRoU3ltYm9sc1JlZ2V4ID1cbiAgICAvXlxccypcXGQrKFxcLlxcZCspPyhcXHMqWy0rKi9dXFxzKlxcZCsoXFwuXFxkKyk/KSpcXHMqJC87XG5cbiAgcmV0dXJuIG51bWJlckFuZE1hdGhTeW1ib2xzUmVnZXgudGVzdChleHByZXNzaW9uKTtcbn07XG5cbi8qKlxuICogQ2hlY2tzIGlmIHRoZSBwcm92aWRlZCBleHByZXNzaW9uIGlzIGEgYmFzaWMgYXJpdGhtZXRpYyBleHByZXNzaW9uLlxuICovXG5jb25zdCBpc0Jhc2ljQXJpdGhtZXRpYyA9IChleHByZXNzaW9uOiBzdHJpbmcpOiBib29sZWFuID0+XG4gIHR5cGVvZiBleHByZXNzaW9uID09PSAnc3RyaW5nJyAmJiBjb250YWluc09ubHlOdW1iZXJzQW5kT3BlcmF0b3JzKGV4cHJlc3Npb24pO1xuXG4vKipcbiAqIEV2YWx1YXRlcyBhIGNvbXBsZXggYXJpdGhtZXRpYyBleHByZXNzaW9uIGJ5IHBhcnNpbmcgaXQgaW50byBvcGVyYW5kcyxcbiAqIHZhbGlkYXRpbmcgd2hldGhlciBlYWNoIG9wZXJhbmQgaXMgYSBudW1iZXIgb3IgYW4gb3BlcmF0b3IsIGFuZCBldmFsdWF0aW5nXG4gKiBhbnkgcGFyYW1ldGVycyB3aXRoaW4gdGhlIGV4cHJlc3Npb24uIFRoZSByZXN1bHRpbmcgdmFsaWQgb3BlcmFuZHMgYXJlXG4gKiBqb2luZWQgdG9nZXRoZXIgYW5kIGV2YWx1YXRlZCB1c2luZyBgZXZhbGAuXG4gKi9cbmNvbnN0IGV2YWx1YXRlQ29tcGxleEV4cHJlc3Npb24gPSAoXG4gIGV4cHJlc3Npb246IHN0cmluZyxcbiAgcGFyYW1ldGVyVmFsdWU6IHN0cmluZyxcbiAgcGFyYW1ldGVyc1RvRXZhbHVhdGU6IHN0cmluZ1tdLFxuICBpbnB1dDogUGx1Z2luUGFyYW1zXG4pID0+IHtcbiAgY29uc3Qgb3BlcmFuZHMgPSBwYXJzZUFyaXRobWV0aWNQYXJhbWV0ZXIoZXhwcmVzc2lvbik7XG4gIGNvbnN0IHBhcmFtczogc3RyaW5nW10gPSBbXTtcblxuICBvcGVyYW5kcy5mb3JFYWNoKG9wZXJhbmQgPT4ge1xuICAgIC8vIENoZWNrIGlmIHRoZSBvcGVyYW5kIGlzIGEgbnVtYmVyXG4gICAgaWYgKG9wZXJhbmQgJiYgIWlzTmFOKE51bWJlcihvcGVyYW5kKSkpIHtcbiAgICAgIHBhcmFtcy5wdXNoKG9wZXJhbmQpO1xuICAgIH0gZWxzZSBpZiAoaXNPcGVyYW5kT3BlcmF0b3Iob3BlcmFuZCwgZXhwcmVzc2lvbikpIHtcbiAgICAgIHBhcmFtcy5wdXNoKG9wZXJhbmQpO1xuICAgIH0gZWxzZSB7XG4gICAgICBjb25zdCBldmFsdWF0ZWRPcGVyYW5kID0gZXZhbHVhdGVPcGVyYW5kKHtcbiAgICAgICAgcGFyYW1ldGVyOiBvcGVyYW5kLFxuICAgICAgICBleHByZXNzaW9uLFxuICAgICAgICBwYXJhbWV0ZXJWYWx1ZSxcbiAgICAgICAgcGFyYW1ldGVyc1RvRXZhbHVhdGUsXG4gICAgICAgIGlucHV0LFxuICAgICAgfSk7XG5cbiAgICAgIHBhcmFtcy5wdXNoKGV2YWx1YXRlZE9wZXJhbmQpO1xuICAgIH1cbiAgfSk7XG5cbiAgcmV0dXJuIGV2YWx1YXRlRXhwcmVzc2lvbihwYXJhbXMuam9pbignJykpO1xufTtcblxuLyoqXG4gKiBDaGVja3MgaWYgYSBnaXZlbiBvcGVyYW5kIGlzIGEgdmFsaWQgYXJpdGhtZXRpYyBvcGVyYXRvciB3aXRoaW4gYW4gZXhwcmVzc2lvbi5cbiAqIFRocm93cyBhbiBlcnJvciBpZiB0aGUgb3BlcmFuZCBpcyBub3Qgb25lIG9mIHRoZSBhbGxvd2VkIGFyaXRobWV0aWMgb3BlcmF0b3JzOiAqLCArLCAtLCBvciAvLlxuICovXG5jb25zdCBpc09wZXJhbmRPcGVyYXRvciA9IChvcGVyYW5kOiBzdHJpbmcsIGV4cHJlc3Npb246IHN0cmluZykgPT4ge1xuICBpZiAob3BlcmFuZC5sZW5ndGggPT09IDEgJiYgIS9bXFwrXFwtXFwqL10vLnRlc3Qob3BlcmFuZCkpIHtcbiAgICB0aHJvdyBuZXcgV3JvbmdBcml0aG1ldGljRXhwcmVzc2lvbkVycm9yKFxuICAgICAgYFRoZSBvcGVyYXRvciBpbiBcXGAke2V4cHJlc3Npb259XFxgIHNob3VsZCBiZSBvbmUgb2YgdGhlc2UgYXJpdGhtZXRpYyBvcGVyYXRvcnM6ICosICssIC0gb3IgLy5gXG4gICAgKTtcbiAgfSBlbHNlIGlmIChvcGVyYW5kLmxlbmd0aCA9PT0gMSkge1xuICAgIHJldHVybiB0cnVlO1xuICB9XG5cbiAgcmV0dXJuIGZhbHNlO1xufTtcblxuLyoqXG4gKiBFdmFsdWF0ZXMgdGhlIHZhbHVlIG9mIGEgZ2l2ZW4gcGFyYW1ldGVyIGZyb20gdGhlIGlucHV0LlxuICogSWYgdGhlIHBhcmFtZXRlcidzIHZhbHVlIGlzIGFuIGFyaXRobWV0aWMgZXhwcmVzc2lvbiwgaXQgZXZhbHVhdGVzIHRoZSBleHByZXNzaW9uLlxuICogT3RoZXJ3aXNlLCBpdCByZXR1cm5zIHRoZSBwYXJhbWV0ZXIncyB2YWx1ZSBkaXJlY3RseS5cbiAqL1xuY29uc3QgZXZhbHVhdGVPcGVyYW5kID0gKG9wZXJhbmRPcHRpb25zOiB7XG4gIHBhcmFtZXRlcjogc3RyaW5nO1xuICBleHByZXNzaW9uOiBzdHJpbmc7XG4gIHBhcmFtZXRlclZhbHVlOiBzdHJpbmc7XG4gIHBhcmFtZXRlcnNUb0V2YWx1YXRlOiBzdHJpbmdbXTtcbiAgaW5wdXQ6IFBsdWdpblBhcmFtcztcbn0pID0+IHtcbiAgY29uc3Qge3BhcmFtZXRlciwgZXhwcmVzc2lvbiwgcGFyYW1ldGVyc1RvRXZhbHVhdGUsIGlucHV0fSA9IG9wZXJhbmRPcHRpb25zO1xuXG4gIGlmICghKHBhcmFtZXRlciBpbiBpbnB1dCkpIHtcbiAgICB0aHJvdyBuZXcgSW5wdXRWYWxpZGF0aW9uRXJyb3IoXG4gICAgICBgJHtwYXJhbWV0ZXJ9IGlzIG1pc3NpbmcgZnJvbSB0aGUgaW5wdXQgYXJyYXkgb3IgaGFzIG51bGxpc2ggdmFsdWUuYFxuICAgICk7XG4gIH1cblxuICAvLyBDaGVja3MgaWYgdGhlIHBhcmFtZXRlciBpbiB0aGUgaW5wdXQgYXJyYXkgaGFzIG51bWJlciB2YWx1ZS5cbiAgaWYgKGlzTmFOKE51bWJlcihpbnB1dFtwYXJhbWV0ZXJdKSkpIHtcbiAgICB0aHJvdyBuZXcgSW5wdXRWYWxpZGF0aW9uRXJyb3IoXG4gICAgICBgVGhlIHZhbHVlIG9mIHRoZSBcXGAke3BhcmFtZXRlcn1cXGAgcGFyYW1ldGVyIGluIHRoZSBpbnB1dCBhcnJheSBpcyBub3QgYSBudW1iZXIuYFxuICAgICk7XG4gIH1cblxuICBjb25zdCBpc0V4cHJlc3Npb24gPSBpc1ZhbGlkQXJpdGhtZXRpY0V4cHJlc3Npb24oZXhwcmVzc2lvbik7XG5cbiAgaWYgKGlzRXhwcmVzc2lvbikge1xuICAgIHJldHVybiBldmFsdWF0ZUFyaXRobWV0aWNFeHByZXNzaW9uKFxuICAgICAgaW5wdXRbcGFyYW1ldGVyXSxcbiAgICAgIHBhcmFtZXRlcixcbiAgICAgIFsuLi5wYXJhbWV0ZXJzVG9FdmFsdWF0ZSwgcGFyYW1ldGVyXSxcbiAgICAgIGlucHV0XG4gICAgKTtcbiAgfVxuXG4gIHJldHVybiBpbnB1dFtwYXJhbWV0ZXJdO1xufTtcblxuLyoqXG4gKiBFdmFsdWF0ZXMgYSBzaW1wbGUgYXJpdGhtZXRpYyBleHByZXNzaW9uIGlmIHRoZSBpbnB1dCBpcyBhIHZhbGlkIGV4cHJlc3Npb24uXG4gKiBJdCBjaGVja3MgaWYgdGhlIGlucHV0IHN0cmluZyBmb2xsb3dzIGEgcGF0dGVybiBmb3Igc2ltcGxlIGFyaXRobWV0aWNcbiAqIG9wZXJhdGlvbnMgKG51bWJlcnMgd2l0aCBvcGVyYXRvcnMgbGlrZSAqLCAvLCArLCAtKSBiZXR3ZWVuIHRoZW0uXG4gKi9cbmV4cG9ydCBjb25zdCBldmFsdWF0ZVNpbXBsZUFyaXRobWV0aWNFeHByZXNzaW9uID0gKHBhcmFtZXRlcjogc3RyaW5nKSA9PiB7XG4gIGNvbnN0IHNpbXBsZUV4cHJlc3Npb25SZWdleCA9IC9eXFxkKyhcXC5cXGQrKT8oWytcXC0qL11cXGQrKFxcLlxcZCspPykqJC87XG5cbiAgcmV0dXJuIHR5cGVvZiBwYXJhbWV0ZXIgPT09ICdzdHJpbmcnICYmXG4gICAgcGFyYW1ldGVyLnJlcGxhY2UoJz0nLCAnJykubWF0Y2goc2ltcGxlRXhwcmVzc2lvblJlZ2V4KVxuICAgID8gZXZhbHVhdGVFeHByZXNzaW9uKHBhcmFtZXRlci5yZXBsYWNlKCc9JywgJycpKVxuICAgIDogcGFyYW1ldGVyO1xufTtcblxuLyoqXG4gKiBWYWxpZGF0ZXMgd2hldGhlciBhIGdpdmVuIHZhbHVlIGlzIGEgdmFsaWQgYXJpdGhtZXRpYyBleHByZXNzaW9uLlxuICpcbiAqIElmIHRoZSB2YWx1ZSBpcyBhIHN0cmluZywgaXQgZmlyc3QgcmVtb3ZlcyBhbnkgZXF1YWwgc2lnbnMgYW5kIGNoZWNrcyBpZiBpdFxuICogaXMgYSB2YWxpZCBhcml0aG1ldGljIGV4cHJlc3Npb24gdXNpbmcgdGhlIGBpc1ZhbGlkQXJpdGhtZXRpY0V4cHJlc3Npb25gIGhlbHBlci5cbiAqIElmIHZhbGlkLCBpdCBhdHRlbXB0cyB0byBldmFsdWF0ZSB0aGUgZXhwcmVzc2lvbiBhbmQgZW5zdXJlcyB0aGUgcmVzdWx0IGlzIG51bWVyaWMuXG4gKiBJbiBjYXNlIG9mIGFuIGludmFsaWQgZm9ybWF0LCBpdCBjYWxscyBgdmFsaWRhdGVFeHByZXNzaW9uRm9ybWF0YC5cbiAqIFRoZSBmdW5jdGlvbiByZXR1cm5zIHRydWUgaWYgdGhlIHZhbHVlIGlzIHZhbGlkIG9yIG51bWVyaWMuXG4gKi9cbmV4cG9ydCBjb25zdCB2YWxpZGF0ZUFyaXRobWV0aWNFeHByZXNzaW9uID0gKFxuICBwYXJhbWV0ZXJOYW1lOiBzdHJpbmcsXG4gIHZhbHVlOiBhbnksXG4gIHR5cGU/OiBhbnlcbikgPT4ge1xuICBpZiAodHlwZW9mIHZhbHVlID09PSAnc3RyaW5nJykge1xuICAgIGNvbnN0IHNhbml0aXplZFZhbHVlID0gdmFsdWUucmVwbGFjZSgnPScsICcnKTtcblxuICAgIGlmIChpc1ZhbGlkQXJpdGhtZXRpY0V4cHJlc3Npb24oc2FuaXRpemVkVmFsdWUpKSB7XG4gICAgICBjb25zdCBldmFsdWF0ZWRQYXJhbSA9IGV2YWx1YXRlRXhwcmVzc2lvbihzYW5pdGl6ZWRWYWx1ZSkgfHwgdmFsdWU7XG5cbiAgICAgIGlmICghaXNOYU4oTnVtYmVyKGV2YWx1YXRlZFBhcmFtKSkpIHtcbiAgICAgICAgcmV0dXJuIGV2YWx1YXRlZFBhcmFtO1xuICAgICAgfVxuICAgIH1cblxuICAgIHZhbGlkYXRlRXhwcmVzc2lvbkZvcm1hdChwYXJhbWV0ZXJOYW1lLCB2YWx1ZSk7XG5cbiAgICBpZiAodHlwZSA9PT0gJ251bWJlcicpIHtcbiAgICAgIGNvbnN0IG51bWJlck1hdGNoID0gc2FuaXRpemVkVmFsdWUubWF0Y2goL1stK10/WzAtOV0qXFwuP1swLTldKy9nKTtcblxuICAgICAgcmV0dXJuIG51bWJlck1hdGNoID8gcGFyc2VGbG9hdChudW1iZXJNYXRjaFswXSkgOiB2YWx1ZTtcbiAgICB9XG4gIH1cblxuICByZXR1cm4gdmFsdWU7XG59O1xuXG4vKipcbiAqIEhlbHBlciBmdW5jdGlvbiB0byBldmFsdWF0ZSB0aGUgYXJpdGhtZXRpYyBleHByZXNzaW9uLlxuICovXG5jb25zdCBldmFsdWF0ZUV4cHJlc3Npb24gPSAoZXhwcmVzc2lvbjogc3RyaW5nKSA9PiB7XG4gIHRyeSB7XG4gICAgY29uc3QgZXZhbHVhdGVkVmFsdWUgPSBldmFsKGV4cHJlc3Npb24pO1xuICAgIGlmIChldmFsdWF0ZWRWYWx1ZSA9PT0gSW5maW5pdHkpIHtcbiAgICAgIHRocm93IG5ldyBaZXJvRGl2aXNpb25Bcml0aG1ldGljT3BlcmF0aW9uRXJyb3IoXG4gICAgICAgIGBUaGUgaW5wdXQgZXhwcmVzc2lvbiBjb250YWlucyBhIGRpdmlzaW9uIGJ5IHplcm86IFxcYCR7ZXhwcmVzc2lvbn1cXGAuYFxuICAgICAgKTtcbiAgICB9XG4gICAgaWYgKGlzTmFOKGV2YWx1YXRlZFZhbHVlKSkge1xuICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICB9XG5cbiAgICByZXR1cm4gZXZhbHVhdGVkVmFsdWU7XG4gIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgaWYgKGVycm9yIGluc3RhbmNlb2YgWmVyb0RpdmlzaW9uQXJpdGhtZXRpY09wZXJhdGlvbkVycm9yKSB7XG4gICAgICB0aHJvdyBlcnJvcjtcbiAgICB9XG5cbiAgICByZXR1cm4gdW5kZWZpbmVkO1xuICB9XG59O1xuXG4vKipcbiAqIFZhbGlkYXRlcyB3aGV0aGVyIHRoZSBwcm92aWRlZCBzdHJpbmcgdmFsdWUgaXMgYSB2YWxpZCBhcml0aG1ldGljIGV4cHJlc3Npb24gYmFzZWQgb24gaXRzIGZvcm1hdC5cbiAqXG4gKiBDaGVja3MgaWYgdGhlIGV4cHJlc3Npb24gY29udGFpbnMgYW4gYD1gIHNpZ24gYW5kIGVuc3VyZXMgdGhhdFxuICogdGhlIHBhcnQgb2YgdGhlIHN0cmluZyBmb2xsb3dpbmcgdGhlIGVxdWFsIHNpZ24gaXMgYSB2YWxpZCBhcml0aG1ldGljIGV4cHJlc3Npb24uXG4gKlxuICogLSBJZiB0aGUgc3RyaW5nIHN0YXJ0cyB3aXRoIGA9YCwgdGhlIHJlbWFpbmluZyBwYXJ0IHNob3VsZCBiZSBhIHZhbGlkIGFyaXRobWV0aWMgZXhwcmVzc2lvbi5cbiAqIC0gSWYgaXQgZG9lc24ndCBzdGFydCB3aXRoIGA9YCwgdGhlIGVudGlyZSBzdHJpbmcgc2hvdWxkIG5vdCByZXNlbWJsZSBhIHZhbGlkIGFyaXRobWV0aWMgZXhwcmVzc2lvbi5cbiAqXG4gKiBUaHJvd3MgYW4gYElucHV0VmFsaWRhdGlvbkVycm9yYCBlcnJvciBpZiB0aGUgZm9ybWF0IG9yIGNvbnRlbnQgb2YgdGhlIGFyaXRobWV0aWMgZXhwcmVzc2lvbiBpcyBpbnZhbGlkLlxuICovXG5jb25zdCB2YWxpZGF0ZUV4cHJlc3Npb25Gb3JtYXQgPSAocGFyYW1ldGVyTmFtZTogc3RyaW5nLCB2YWx1ZTogc3RyaW5nKSA9PiB7XG4gIGNvbnN0IGhhc0VxdWFsU2lnbiA9IHZhbHVlLmluY2x1ZGVzKCc9Jyk7XG4gIGNvbnN0IGlzVmFsaWQgPSBpc1ZhbGlkQXJpdGhtZXRpY0V4cHJlc3Npb24odmFsdWUucmVwbGFjZSgnPScsICcnKSk7XG5cbiAgaWYgKChoYXNFcXVhbFNpZ24gJiYgIWlzVmFsaWQpIHx8ICghaGFzRXF1YWxTaWduICYmIGlzVmFsaWQpKSB7XG4gICAgdGhyb3cgbmV3IElucHV0VmFsaWRhdGlvbkVycm9yKFxuICAgICAgYFRoZSBcXGAke3BhcmFtZXRlck5hbWV9XFxgIGNvbnRhaW5zIGFuIGludmFsaWQgYXJpdGhtZXRpYyBleHByZXNzaW9uLiBJdCBzaG91bGQgc3RhcnQgd2l0aCBcXGA9XFxgIGFuZCBpbmNsdWRlIHRoZSBzeW1ib2xzIFxcYCpcXGAsIFxcYCtcXGAsIFxcYC1cXGAgYW5kIFxcYC9cXGAuYFxuICAgICk7XG4gIH1cbn07XG4iXX0=