UNPKG

@openfisca/json-model

Version:

Library to handle informations extracted in JSON or YAML format from OpenFisca parameters, variables, etc

350 lines 53.1 kB
import { accessParameterFromIds, ParameterClass } from "../parameters.js"; import { Period } from "../periods.js"; import { evaluateOpenfiscaAstInstantOrPeriod } from "./periods.js"; import { AstTransformer } from "./visitors.js"; class XlsxFormulaGenerator extends AstTransformer { constructor(variable, period, rootParameter, variableSummaryByName) { super(); this.variable = variable; this.period = period; this.rootParameter = rootParameter; this.variableSummaryByName = variableSummaryByName; } transform_Attribute(attribute) { const value = this.transform(attribute.value); return this.reduceErrorByKey(attribute, `${value.output}.${attribute.attr}`, { value: value.error }); } transform_BinOp(binOp) { const left = this.transform(binOp.left); const right = this.transform(binOp.right); switch (binOp.op.ast_class) { case "Add": return this.reduceErrorByKey(binOp, `${left.output} + ${right.output}`, { left: left.error, right: right.error }); case "BitAnd": return this.reduceErrorByKey(binOp, `AND(${left.output},${right.output})`, { left: left.error, right: right.error }); case "BitOr": return this.reduceErrorByKey(binOp, `OR(${left.output},${right.output})`, { left: left.error, right: right.error }); case "Div": return this.reduceErrorByKey(binOp, `${left.output} / ${right.output}`, { left: left.error, right: right.error }); case "Mult": return this.reduceErrorByKey(binOp, `${left.output} * ${right.output}`, { left: left.error, right: right.error }); case "Sub": return this.reduceErrorByKey(binOp, `${left.output} / ${right.output}`, { left: left.error, right: right.error }); default: assertNever("binary operator", binOp.op); } } transform_built_in(builtIn) { return { input: builtIn, output: builtIn.name }; } transform_Call(call) { const { args, func, keywords } = call; const argsTransformed = this.reduceMapErrors(args.map(arg => this.transform(arg))); const funcTransformed = this.transform(func); const keywordsTransformed = this.reduceMapErrors(keywords.map(keyword => this.transform(keyword))); if (argsTransformed.error === undefined && funcTransformed.error === undefined && keywordsTransformed.error === undefined) { switch (func.ast_class) { case "Attribute": { const attribute = func; const { attr, value } = attribute; if (value.ast_class === "entity") { const entity = value; switch (attr) { case "nb_persons": { if (args.length === 0 && keywords.length === 0) { // To find the number of persons in entity, count the number of ":" in column "membres" of entity. // See https://learn.microsoft.com/en-us/office/troubleshoot/excel/formulas-to-count-occurrences-in-excel const membersRange = `FORMULATEXT(membres_${entity.key})`; return { input: call, output: `(LEN(${membersRange})-LEN(SUBSTITUTE(${membersRange},":",""))+1)/2` }; } else { return { input: call, output: JSON.stringify(call), error: `Unexpected arguments in method "${attr}" of entity expression` }; } } case "sum": { if (args.length === 1 && keywords.length === 0) { const cogCall = this.transform(args[0]); const membersRange = `REPLACE(FORMULATEXT(membres_${entity.key}),0,1,"")`; return this.reduceErrorByKey(call, `SUM(INDIRECT(${membersRange}) ${cogCall.output})`, cogCall.error === undefined ? {} : { func: { args: { 0: cogCall.error } } }); } else { return { input: call, output: JSON.stringify(call), error: `Unexpected arguments in method "${attr}" of entity expression` }; } } default: return { input: call, output: JSON.stringify(call), error: `Unknown entity method "${attr}" in entity expression` }; } } else { return { input: call, output: JSON.stringify(call), error: `Unknown object "${value}" for method "${attr}" in entity expression` }; } } default: } } return this.reduceErrorByKey(call, `${funcTransformed.output}(${[...argsTransformed.output, ...keywordsTransformed.output].join(", ")})`, { args: argsTransformed.error, func: funcTransformed.error, keywords: keywordsTransformed.error }); } transform_cog_call(cogCall) { const { cog } = cogCall; const period = this.transform(cogCall.period); let output; let operationError = undefined; if (cogCall.operation === undefined) { output = `${cog.name}_${String(period.output).replace(/-/g, "_")}`; } else if (cogCall.operation === "ADD" && cog.periodUnit === "month" && this.variable.definition_period === "year") { const monthlyOutputs = []; for (let month = 1; month <= 12; month++) { monthlyOutputs.push(`${cog.name}_${period.output}_${month.toString().padStart(2, "0")}`); } output = monthlyOutputs.join(" * "); } else if (cogCall.operation === "DIVIDE" && cog.periodUnit === "year" && this.variable.definition_period === "month") { const monthlyOutputs = []; for (let month = 1; month <= 12; month++) { monthlyOutputs.push(`${cog.name}_${String(period.output).split("-")[0]} / 12`); } output = monthlyOutputs.join("*"); } else { operationError = `Unable to convert ${cog.name} with a definition period of ${cog.periodUnit} to ${period.output}`; output = `${cog.name}_${String(period.output).replace(/-/g, "_")}`; } return this.reduceErrorByKey(cogCall, output, { operation: operationError, period: period.error }); } transform_Compare(compare) { const left = this.transform(compare.left); const operators = compare.ops.map(operator => transformPythonAstComparisonOperator(operator)); const comparators = this.reduceMapErrors(compare.comparators.map(comparator => this.transform(comparator))); const fragments = [left.output]; for (const [index, operator] of operators.entries()) { fragments.push(operator, comparators.output[index]); } return this.reduceErrorByKey(compare, fragments.join(""), { left: left.error, comparators: comparators.error }); } transform_Constant(constant) { return { input: constant, output: JSON.stringify(constant.value) }; } transform_entity(entity) { return { input: entity, output: entity.key }; } transform_instant_or_period_expression(instantOrPeriodExpression) { const expression = evaluateOpenfiscaAstInstantOrPeriod(instantOrPeriodExpression.expression, this.period); return this.reduceErrorByKey(instantOrPeriodExpression, expression.output, { expression: expression.error }); } transform_keyword(keyword) { const value = this.transform(keyword.value); if (keyword.arg === undefined) { return { input: keyword, output: `**${value.output}`, error: "Can't handle yet keyword argument without name" }; } return this.reduceErrorByKey(keyword, `${keyword.arg}=${value.output}`, { arg: keyword.arg === undefined ? "Can't handle yet keyword argument without name" : undefined, value: value.error }); } transform_parameter_at_instant(parameterAtInstant) { const instant = this.transform(parameterAtInstant.instant); const instantString = String(instant.output instanceof Period ? instant.output.start : instant.output); if (instant.error !== undefined) { return this.reduceErrorByKey(parameterAtInstant, [`parameters(${instantString})`, ...parameterAtInstant.ids].join("."), { instant: instant.error }); } const [parameter, parameterError] = accessParameterFromIds(this.rootParameter, parameterAtInstant.ids); if (parameterError !== null) { return this.reduceErrorByKey(parameterAtInstant, [`parameters(${instantString})`, ...parameterAtInstant.ids].join("."), { parameter: parameterError }); } switch (parameter.class) { case ParameterClass.Node: { return this.reduceErrorByKey(parameterAtInstant, [`parameters(${instantString})`, ...parameterAtInstant.ids].join("."), { parameter: "Parameter is a node instead of a leaf (ie scale or value)" }); } case ParameterClass.Scale: { return this.reduceErrorByKey(parameterAtInstant, [`parameters(${instantString})`, ...parameterAtInstant.ids].join("."), { parameter: "Scale parameter can't be used directly in formula" }); } case ParameterClass.Value: { const valueAtInstant = Object.entries(parameter.values).sort(([instant1], [instant2]) => instant2.localeCompare(instant1)).find(([instant1]) => instant1 <= instantString)?.[1]; if (valueAtInstant === undefined) { return this.reduceErrorByKey(parameterAtInstant, [`parameters(${instant.output})`, ...parameterAtInstant.ids].join("."), { parameter: `Parameter has no value at instant ${instant.output}` }); } const value = valueAtInstant.value; if (value === null) { return this.reduceErrorByKey(parameterAtInstant, "null", { parameter: `Value of parameter is null at instant ${instant.output}` }); } return { input: parameterAtInstant, output: value.toString() }; } default: assertNever("parameter class", parameter); } } transform_period(period) { return { input: period, output: this.period }; } transform_Subscript(subscript) { const slice = this.transform(subscript.slice); const value = this.transform(subscript.value); return this.reduceErrorByKey(subscript, `${value.output}[${slice.output}]`, { value: value.error }); } transform_UnaryOp(unaryOp) { const operand = this.transform(unaryOp.operand); const operator = transformPythonAstUnaryOperator(unaryOp.op); return this.reduceErrorByKey(unaryOp, `${operator}${operand.output}`, { operand: operand.error }); } transformGenericOutputByKey(input, outputByKey, _errorByKey) { return { input, output: JSON.stringify(outputByKey), error: `Missing XLSX transformer for ${input.ast_class}` }; } } function assertNever(type, value) { throw new Error(`Unexpected ${type}: ${JSON.stringify(value)}`); } function transformPythonAstComparisonOperator(op) { switch (op.ast_class) { case "Eq": return " == "; case "Gt": return " > "; case "GtE": return " >= "; case "In": return " in "; case "Is": return " === "; case "IsNot": return " !== "; case "Lt": return " < "; case "LtE": return " <= "; case "NotEq": return " != "; case "NotIn": return " not in "; default: assertNever("binary operator", op); } } function transformPythonAstUnaryOperator(op) { switch (op.ast_class) { case "Invert": return "~"; case "Not": return "not "; case "UAdd": return "+"; case "USub": return "-"; default: assertNever("unary operator", op); } } export function xlsxFormulaFromOpenfiscaAst(variable, node, period, rootParameter, variableSummaryByName) { const xlsxFormulaGenerator = new XlsxFormulaGenerator(variable, period, rootParameter, variableSummaryByName); const result = xlsxFormulaGenerator.transform(node); return typeof result.output === "string" ? result : { ...result, output: String(result.output) }; } //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJhY2Nlc3NQYXJhbWV0ZXJGcm9tSWRzIiwiUGFyYW1ldGVyQ2xhc3MiLCJQZXJpb2QiLCJldmFsdWF0ZU9wZW5maXNjYUFzdEluc3RhbnRPclBlcmlvZCIsIkFzdFRyYW5zZm9ybWVyIiwiWGxzeEZvcm11bGFHZW5lcmF0b3IiLCJjb25zdHJ1Y3RvciIsInZhcmlhYmxlIiwicGVyaW9kIiwicm9vdFBhcmFtZXRlciIsInZhcmlhYmxlU3VtbWFyeUJ5TmFtZSIsInRyYW5zZm9ybV9BdHRyaWJ1dGUiLCJhdHRyaWJ1dGUiLCJ2YWx1ZSIsInRyYW5zZm9ybSIsInJlZHVjZUVycm9yQnlLZXkiLCJvdXRwdXQiLCJhdHRyIiwiZXJyb3IiLCJ0cmFuc2Zvcm1fQmluT3AiLCJiaW5PcCIsImxlZnQiLCJyaWdodCIsIm9wIiwiYXN0X2NsYXNzIiwiYXNzZXJ0TmV2ZXIiLCJ0cmFuc2Zvcm1fYnVpbHRfaW4iLCJidWlsdEluIiwiaW5wdXQiLCJuYW1lIiwidHJhbnNmb3JtX0NhbGwiLCJjYWxsIiwiYXJncyIsImZ1bmMiLCJrZXl3b3JkcyIsImFyZ3NUcmFuc2Zvcm1lZCIsInJlZHVjZU1hcEVycm9ycyIsIm1hcCIsImFyZyIsImZ1bmNUcmFuc2Zvcm1lZCIsImtleXdvcmRzVHJhbnNmb3JtZWQiLCJrZXl3b3JkIiwidW5kZWZpbmVkIiwiZW50aXR5IiwibGVuZ3RoIiwibWVtYmVyc1JhbmdlIiwia2V5IiwiSlNPTiIsInN0cmluZ2lmeSIsImNvZ0NhbGwiLCJqb2luIiwidHJhbnNmb3JtX2NvZ19jYWxsIiwiY29nIiwib3BlcmF0aW9uRXJyb3IiLCJvcGVyYXRpb24iLCJTdHJpbmciLCJyZXBsYWNlIiwicGVyaW9kVW5pdCIsImRlZmluaXRpb25fcGVyaW9kIiwibW9udGhseU91dHB1dHMiLCJtb250aCIsInB1c2giLCJ0b1N0cmluZyIsInBhZFN0YXJ0Iiwic3BsaXQiLCJ0cmFuc2Zvcm1fQ29tcGFyZSIsImNvbXBhcmUiLCJvcGVyYXRvcnMiLCJvcHMiLCJvcGVyYXRvciIsInRyYW5zZm9ybVB5dGhvbkFzdENvbXBhcmlzb25PcGVyYXRvciIsImNvbXBhcmF0b3JzIiwiY29tcGFyYXRvciIsImZyYWdtZW50cyIsImluZGV4IiwiZW50cmllcyIsInRyYW5zZm9ybV9Db25zdGFudCIsImNvbnN0YW50IiwidHJhbnNmb3JtX2VudGl0eSIsInRyYW5zZm9ybV9pbnN0YW50X29yX3BlcmlvZF9leHByZXNzaW9uIiwiaW5zdGFudE9yUGVyaW9kRXhwcmVzc2lvbiIsImV4cHJlc3Npb24iLCJ0cmFuc2Zvcm1fa2V5d29yZCIsInRyYW5zZm9ybV9wYXJhbWV0ZXJfYXRfaW5zdGFudCIsInBhcmFtZXRlckF0SW5zdGFudCIsImluc3RhbnQiLCJpbnN0YW50U3RyaW5nIiwic3RhcnQiLCJpZHMiLCJwYXJhbWV0ZXIiLCJwYXJhbWV0ZXJFcnJvciIsImNsYXNzIiwiTm9kZSIsIlNjYWxlIiwiVmFsdWUiLCJ2YWx1ZUF0SW5zdGFudCIsIk9iamVjdCIsInZhbHVlcyIsInNvcnQiLCJpbnN0YW50MSIsImluc3RhbnQyIiwibG9jYWxlQ29tcGFyZSIsImZpbmQiLCJ0cmFuc2Zvcm1fcGVyaW9kIiwidHJhbnNmb3JtX1N1YnNjcmlwdCIsInN1YnNjcmlwdCIsInNsaWNlIiwidHJhbnNmb3JtX1VuYXJ5T3AiLCJ1bmFyeU9wIiwib3BlcmFuZCIsInRyYW5zZm9ybVB5dGhvbkFzdFVuYXJ5T3BlcmF0b3IiLCJ0cmFuc2Zvcm1HZW5lcmljT3V0cHV0QnlLZXkiLCJvdXRwdXRCeUtleSIsIl9lcnJvckJ5S2V5IiwidHlwZSIsIkVycm9yIiwieGxzeEZvcm11bGFGcm9tT3BlbmZpc2NhQXN0Iiwibm9kZSIsInhsc3hGb3JtdWxhR2VuZXJhdG9yIiwicmVzdWx0Il0sInNvdXJjZXMiOlsiLi4vLi4vc3JjL2FzdC9zcHJlYWRzaGVldHMudHMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcbiAgYWNjZXNzUGFyYW1ldGVyRnJvbUlkcyxcbiAgUGFyYW1ldGVyQ2xhc3MsXG4gIHR5cGUgTm9kZVBhcmFtZXRlcixcbn0gZnJvbSBcIi4uL3BhcmFtZXRlcnNcIlxuaW1wb3J0IHsgUGVyaW9kIH0gZnJvbSBcIi4uL3BlcmlvZHNcIlxuaW1wb3J0IHR5cGUgeyBWYXJpYWJsZSB9IGZyb20gXCIuLi92YXJpYWJsZXNcIlxuXG5pbXBvcnQgdHlwZSB7XG4gIE9wZW5maXNjYUFzdEJ1aWx0SW4sXG4gIE9wZW5maXNjYUFzdENvZ0NhbGwsXG4gIE9wZW5maXNjYUFzdEVudGl0eSxcbiAgT3BlbmZpc2NhQXN0SW5zdGFudE9yUGVyaW9kRXhwcmVzc2lvbixcbiAgT3BlbmZpc2NhQXN0Tm9kZSxcbiAgT3BlbmZpc2NhQXN0UGFyYW1ldGVyQXRJbnN0YW50LFxuICBPcGVuZmlzY2FBc3RQZXJpb2QsXG4gIFB5dGhvbkFzdEF0dHJpYnV0ZSxcbiAgUHl0aG9uQXN0QmluT3AsXG4gIFB5dGhvbkFzdENhbGwsXG4gIFB5dGhvbkFzdENvbXBhcmUsXG4gIFB5dGhvbkFzdENvbXBhcmlzb25PcGVyYXRvcixcbiAgUHl0aG9uQXN0Q29uc3RhbnQsXG4gIFB5dGhvbkFzdEtleXdvcmQsXG4gIFB5dGhvbkFzdFN1YnNjcmlwdCxcbiAgUHl0aG9uQXN0VW5hcnlPcCxcbiAgUHl0aG9uQXN0VW5hcnlPcGVyYXRvcixcbn0gZnJvbSBcIi4vbm9kZXNcIlxuaW1wb3J0IHsgZXZhbHVhdGVPcGVuZmlzY2FBc3RJbnN0YW50T3JQZXJpb2QgfSBmcm9tIFwiLi9wZXJpb2RzXCJcbmltcG9ydCB7IEFzdFRyYW5zZm9ybWVyIH0gZnJvbSBcIi4vdmlzaXRvcnNcIlxuXG5jbGFzcyBYbHN4Rm9ybXVsYUdlbmVyYXRvciBleHRlbmRzIEFzdFRyYW5zZm9ybWVyPE9wZW5maXNjYUFzdE5vZGUsIHVua25vd24+IHtcbiAgY29uc3RydWN0b3IoXG4gICAgcHVibGljIHJlYWRvbmx5IHZhcmlhYmxlOiBWYXJpYWJsZSxcbiAgICBwdWJsaWMgcmVhZG9ubHkgcGVyaW9kOiBQZXJpb2QsXG4gICAgcHVibGljIHJlYWRvbmx5IHJvb3RQYXJhbWV0ZXI6IE5vZGVQYXJhbWV0ZXIsXG4gICAgcHVibGljIHJlYWRvbmx5IHZhcmlhYmxlU3VtbWFyeUJ5TmFtZTogeyBbbmFtZTogc3RyaW5nXTogVmFyaWFibGUgfSxcbiAgKSB7XG4gICAgc3VwZXIoKVxuICB9XG5cbiAgdHJhbnNmb3JtX0F0dHJpYnV0ZShhdHRyaWJ1dGU6IFB5dGhvbkFzdEF0dHJpYnV0ZSk6IHtcbiAgICBpbnB1dDogT3BlbmZpc2NhQXN0Tm9kZVxuICAgIG91dHB1dDogdW5rbm93blxuICAgIGVycm9yPzogdW5rbm93blxuICB9IHtcbiAgICBjb25zdCB2YWx1ZSA9IHRoaXMudHJhbnNmb3JtKGF0dHJpYnV0ZS52YWx1ZSlcbiAgICByZXR1cm4gdGhpcy5yZWR1Y2VFcnJvckJ5S2V5KFxuICAgICAgYXR0cmlidXRlLFxuICAgICAgYCR7dmFsdWUub3V0cHV0fS4ke2F0dHJpYnV0ZS5hdHRyfWAsXG4gICAgICB7XG4gICAgICAgIHZhbHVlOiB2YWx1ZS5lcnJvcixcbiAgICAgIH0sXG4gICAgKVxuICB9XG5cbiAgdHJhbnNmb3JtX0Jpbk9wKGJpbk9wOiBQeXRob25Bc3RCaW5PcCk6IHtcbiAgICBpbnB1dDogT3BlbmZpc2NhQXN0Tm9kZVxuICAgIG91dHB1dDogdW5rbm93blxuICAgIGVycm9yPzogdW5rbm93blxuICB9IHtcbiAgICBjb25zdCBsZWZ0ID0gdGhpcy50cmFuc2Zvcm0oYmluT3AubGVmdClcbiAgICBjb25zdCByaWdodCA9IHRoaXMudHJhbnNmb3JtKGJpbk9wLnJpZ2h0KVxuICAgIHN3aXRjaCAoYmluT3Aub3AuYXN0X2NsYXNzKSB7XG4gICAgICBjYXNlIFwiQWRkXCI6XG4gICAgICAgIHJldHVybiB0aGlzLnJlZHVjZUVycm9yQnlLZXkoXG4gICAgICAgICAgYmluT3AsXG4gICAgICAgICAgYCR7bGVmdC5vdXRwdXR9ICsgJHtyaWdodC5vdXRwdXR9YCxcbiAgICAgICAgICB7IGxlZnQ6IGxlZnQuZXJyb3IsIHJpZ2h0OiByaWdodC5lcnJvciB9LFxuICAgICAgICApXG4gICAgICBjYXNlIFwiQml0QW5kXCI6XG4gICAgICAgIHJldHVybiB0aGlzLnJlZHVjZUVycm9yQnlLZXkoXG4gICAgICAgICAgYmluT3AsXG4gICAgICAgICAgYEFORCgke2xlZnQub3V0cHV0fSwke3JpZ2h0Lm91dHB1dH0pYCxcbiAgICAgICAgICB7IGxlZnQ6IGxlZnQuZXJyb3IsIHJpZ2h0OiByaWdodC5lcnJvciB9LFxuICAgICAgICApXG4gICAgICBjYXNlIFwiQml0T3JcIjpcbiAgICAgICAgcmV0dXJuIHRoaXMucmVkdWNlRXJyb3JCeUtleShcbiAgICAgICAgICBiaW5PcCxcbiAgICAgICAgICBgT1IoJHtsZWZ0Lm91dHB1dH0sJHtyaWdodC5vdXRwdXR9KWAsXG4gICAgICAgICAgeyBsZWZ0OiBsZWZ0LmVycm9yLCByaWdodDogcmlnaHQuZXJyb3IgfSxcbiAgICAgICAgKVxuICAgICAgY2FzZSBcIkRpdlwiOlxuICAgICAgICByZXR1cm4gdGhpcy5yZWR1Y2VFcnJvckJ5S2V5KFxuICAgICAgICAgIGJpbk9wLFxuICAgICAgICAgIGAke2xlZnQub3V0cHV0fSAvICR7cmlnaHQub3V0cHV0fWAsXG4gICAgICAgICAgeyBsZWZ0OiBsZWZ0LmVycm9yLCByaWdodDogcmlnaHQuZXJyb3IgfSxcbiAgICAgICAgKVxuICAgICAgY2FzZSBcIk11bHRcIjpcbiAgICAgICAgcmV0dXJuIHRoaXMucmVkdWNlRXJyb3JCeUtleShcbiAgICAgICAgICBiaW5PcCxcbiAgICAgICAgICBgJHtsZWZ0Lm91dHB1dH0gKiAke3JpZ2h0Lm91dHB1dH1gLFxuICAgICAgICAgIHsgbGVmdDogbGVmdC5lcnJvciwgcmlnaHQ6IHJpZ2h0LmVycm9yIH0sXG4gICAgICAgIClcbiAgICAgIGNhc2UgXCJTdWJcIjpcbiAgICAgICAgcmV0dXJuIHRoaXMucmVkdWNlRXJyb3JCeUtleShcbiAgICAgICAgICBiaW5PcCxcbiAgICAgICAgICBgJHtsZWZ0Lm91dHB1dH0gLyAke3JpZ2h0Lm91dHB1dH1gLFxuICAgICAgICAgIHsgbGVmdDogbGVmdC5lcnJvciwgcmlnaHQ6IHJpZ2h0LmVycm9yIH0sXG4gICAgICAgIClcbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIGFzc2VydE5ldmVyKFwiYmluYXJ5IG9wZXJhdG9yXCIsIGJpbk9wLm9wKVxuICAgIH1cbiAgfVxuXG4gIHRyYW5zZm9ybV9idWlsdF9pbihidWlsdEluOiBPcGVuZmlzY2FBc3RCdWlsdEluKToge1xuICAgIGlucHV0OiBPcGVuZmlzY2FBc3ROb2RlXG4gICAgb3V0cHV0OiB1bmtub3duXG4gICAgZXJyb3I/OiB1bmtub3duXG4gIH0ge1xuICAgIHJldHVybiB7IGlucHV0OiBidWlsdEluLCBvdXRwdXQ6IGJ1aWx0SW4ubmFtZSB9XG4gIH1cblxuICB0cmFuc2Zvcm1fQ2FsbChjYWxsOiBQeXRob25Bc3RDYWxsKToge1xuICAgIGlucHV0OiBPcGVuZmlzY2FBc3ROb2RlXG4gICAgb3V0cHV0OiB1bmtub3duXG4gICAgZXJyb3I/OiB1bmtub3duXG4gIH0ge1xuICAgIGNvbnN0IHsgYXJncywgZnVuYywga2V5d29yZHMgfSA9IGNhbGxcblxuICAgIGNvbnN0IGFyZ3NUcmFuc2Zvcm1lZCA9IHRoaXMucmVkdWNlTWFwRXJyb3JzKFxuICAgICAgYXJncy5tYXAoKGFyZykgPT4gdGhpcy50cmFuc2Zvcm0oYXJnKSksXG4gICAgKVxuICAgIGNvbnN0IGZ1bmNUcmFuc2Zvcm1lZCA9IHRoaXMudHJhbnNmb3JtKGZ1bmMpXG4gICAgY29uc3Qga2V5d29yZHNUcmFuc2Zvcm1lZCA9IHRoaXMucmVkdWNlTWFwRXJyb3JzKFxuICAgICAga2V5d29yZHMubWFwKChrZXl3b3JkKSA9PiB0aGlzLnRyYW5zZm9ybShrZXl3b3JkKSksXG4gICAgKVxuXG4gICAgaWYgKFxuICAgICAgYXJnc1RyYW5zZm9ybWVkLmVycm9yID09PSB1bmRlZmluZWQgJiZcbiAgICAgIGZ1bmNUcmFuc2Zvcm1lZC5lcnJvciA9PT0gdW5kZWZpbmVkICYmXG4gICAgICBrZXl3b3Jkc1RyYW5zZm9ybWVkLmVycm9yID09PSB1bmRlZmluZWRcbiAgICApIHtcbiAgICAgIHN3aXRjaCAoZnVuYy5hc3RfY2xhc3MpIHtcbiAgICAgICAgY2FzZSBcIkF0dHJpYnV0ZVwiOiB7XG4gICAgICAgICAgY29uc3QgYXR0cmlidXRlID0gZnVuY1xuICAgICAgICAgIGNvbnN0IHsgYXR0ciwgdmFsdWUgfSA9IGF0dHJpYnV0ZVxuICAgICAgICAgIGlmICh2YWx1ZS5hc3RfY2xhc3MgPT09IFwiZW50aXR5XCIpIHtcbiAgICAgICAgICAgIGNvbnN0IGVudGl0eSA9IHZhbHVlXG4gICAgICAgICAgICBzd2l0Y2ggKGF0dHIpIHtcbiAgICAgICAgICAgICAgY2FzZSBcIm5iX3BlcnNvbnNcIjoge1xuICAgICAgICAgICAgICAgIGlmIChhcmdzLmxlbmd0aCA9PT0gMCAmJiBrZXl3b3Jkcy5sZW5ndGggPT09IDApIHtcbiAgICAgICAgICAgICAgICAgIC8vIFRvIGZpbmQgdGhlIG51bWJlciBvZiBwZXJzb25zIGluIGVudGl0eSwgY291bnQgdGhlIG51bWJlciBvZiBcIjpcIiBpbiBjb2x1bW4gXCJtZW1icmVzXCIgb2YgZW50aXR5LlxuICAgICAgICAgICAgICAgICAgLy8gU2VlIGh0dHBzOi8vbGVhcm4ubWljcm9zb2Z0LmNvbS9lbi11cy9vZmZpY2UvdHJvdWJsZXNob290L2V4Y2VsL2Zvcm11bGFzLXRvLWNvdW50LW9jY3VycmVuY2VzLWluLWV4Y2VsXG4gICAgICAgICAgICAgICAgICBjb25zdCBtZW1iZXJzUmFuZ2UgPSBgRk9STVVMQVRFWFQobWVtYnJlc18ke2VudGl0eS5rZXl9KWBcbiAgICAgICAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgICAgIGlucHV0OiBjYWxsLFxuICAgICAgICAgICAgICAgICAgICBvdXRwdXQ6IGAoTEVOKCR7bWVtYmVyc1JhbmdlfSktTEVOKFNVQlNUSVRVVEUoJHttZW1iZXJzUmFuZ2V9LFwiOlwiLFwiXCIpKSsxKS8yYCxcbiAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgICAgICAgaW5wdXQ6IGNhbGwsXG4gICAgICAgICAgICAgICAgICAgIG91dHB1dDogSlNPTi5zdHJpbmdpZnkoY2FsbCksXG4gICAgICAgICAgICAgICAgICAgIGVycm9yOiBgVW5leHBlY3RlZCBhcmd1bWVudHMgaW4gbWV0aG9kIFwiJHthdHRyfVwiIG9mIGVudGl0eSBleHByZXNzaW9uYCxcbiAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgY2FzZSBcInN1bVwiOiB7XG4gICAgICAgICAgICAgICAgaWYgKGFyZ3MubGVuZ3RoID09PSAxICYmIGtleXdvcmRzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICAgICAgICAgICAgY29uc3QgY29nQ2FsbCA9IHRoaXMudHJhbnNmb3JtKGFyZ3NbMF0pXG4gICAgICAgICAgICAgICAgICBjb25zdCBtZW1iZXJzUmFuZ2UgPSBgUkVQTEFDRShGT1JNVUxBVEVYVChtZW1icmVzXyR7ZW50aXR5LmtleX0pLDAsMSxcIlwiKWBcbiAgICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLnJlZHVjZUVycm9yQnlLZXkoXG4gICAgICAgICAgICAgICAgICAgIGNhbGwsXG4gICAgICAgICAgICAgICAgICAgIGBTVU0oSU5ESVJFQ1QoJHttZW1iZXJzUmFuZ2V9KSAke2NvZ0NhbGwub3V0cHV0fSlgLFxuICAgICAgICAgICAgICAgICAgICBjb2dDYWxsLmVycm9yID09PSB1bmRlZmluZWRcbiAgICAgICAgICAgICAgICAgICAgICA/IHt9XG4gICAgICAgICAgICAgICAgICAgICAgOiB7IGZ1bmM6IHsgYXJnczogeyAwOiBjb2dDYWxsLmVycm9yIH0gfSB9LFxuICAgICAgICAgICAgICAgICAgKVxuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICAgICAgICBpbnB1dDogY2FsbCxcbiAgICAgICAgICAgICAgICAgICAgb3V0cHV0OiBKU09OLnN0cmluZ2lmeShjYWxsKSxcbiAgICAgICAgICAgICAgICAgICAgZXJyb3I6IGBVbmV4cGVjdGVkIGFyZ3VtZW50cyBpbiBtZXRob2QgXCIke2F0dHJ9XCIgb2YgZW50aXR5IGV4cHJlc3Npb25gLFxuICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgICBpbnB1dDogY2FsbCxcbiAgICAgICAgICAgICAgICAgIG91dHB1dDogSlNPTi5zdHJpbmdpZnkoY2FsbCksXG4gICAgICAgICAgICAgICAgICBlcnJvcjogYFVua25vd24gZW50aXR5IG1ldGhvZCBcIiR7YXR0cn1cIiBpbiBlbnRpdHkgZXhwcmVzc2lvbmAsXG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICBpbnB1dDogY2FsbCxcbiAgICAgICAgICAgICAgb3V0cHV0OiBKU09OLnN0cmluZ2lmeShjYWxsKSxcbiAgICAgICAgICAgICAgZXJyb3I6IGBVbmtub3duIG9iamVjdCBcIiR7dmFsdWV9XCIgZm9yIG1ldGhvZCBcIiR7YXR0cn1cIiBpbiBlbnRpdHkgZXhwcmVzc2lvbmAsXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGRlZmF1bHQ6XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIHRoaXMucmVkdWNlRXJyb3JCeUtleShcbiAgICAgIGNhbGwsXG4gICAgICBgJHtmdW5jVHJhbnNmb3JtZWQub3V0cHV0fSgke1tcbiAgICAgICAgLi4uYXJnc1RyYW5zZm9ybWVkLm91dHB1dCxcbiAgICAgICAgLi4ua2V5d29yZHNUcmFuc2Zvcm1lZC5vdXRwdXQsXG4gICAgICBdLmpvaW4oXCIsIFwiKX0pYCxcbiAgICAgIHtcbiAgICAgICAgYXJnczogYXJnc1RyYW5zZm9ybWVkLmVycm9yLFxuICAgICAgICBmdW5jOiBmdW5jVHJhbnNmb3JtZWQuZXJyb3IsXG4gICAgICAgIGtleXdvcmRzOiBrZXl3b3Jkc1RyYW5zZm9ybWVkLmVycm9yLFxuICAgICAgfSxcbiAgICApXG4gIH1cblxuICB0cmFuc2Zvcm1fY29nX2NhbGwoY29nQ2FsbDogT3BlbmZpc2NhQXN0Q29nQ2FsbCk6IHtcbiAgICBpbnB1dDogT3BlbmZpc2NhQXN0Tm9kZVxuICAgIG91dHB1dDogdW5rbm93blxuICAgIGVycm9yPzogdW5rbm93blxuICB9IHtcbiAgICBjb25zdCB7IGNvZyB9ID0gY29nQ2FsbFxuICAgIGNvbnN0IHBlcmlvZCA9IHRoaXMudHJhbnNmb3JtKGNvZ0NhbGwucGVyaW9kKVxuICAgIGxldCBvdXRwdXQ6IHN0cmluZ1xuICAgIGxldCBvcGVyYXRpb25FcnJvcjogc3RyaW5nIHwgdW5kZWZpbmVkID0gdW5kZWZpbmVkXG4gICAgaWYgKGNvZ0NhbGwub3BlcmF0aW9uID09PSB1bmRlZmluZWQpIHtcbiAgICAgIG91dHB1dCA9IGAke2NvZy5uYW1lfV8ke1N0cmluZyhwZXJpb2Qub3V0cHV0KS5yZXBsYWNlKC8tL2csIFwiX1wiKX1gXG4gICAgfSBlbHNlIGlmIChcbiAgICAgIGNvZ0NhbGwub3BlcmF0aW9uID09PSBcIkFERFwiICYmXG4gICAgICBjb2cucGVyaW9kVW5pdCA9PT0gXCJtb250aFwiICYmXG4gICAgICB0aGlzLnZhcmlhYmxlLmRlZmluaXRpb25fcGVyaW9kID09PSBcInllYXJcIlxuICAgICkge1xuICAgICAgY29uc3QgbW9udGhseU91dHB1dHM6IHN0cmluZ1tdID0gW11cbiAgICAgIGZvciAobGV0IG1vbnRoID0gMTsgbW9udGggPD0gMTI7IG1vbnRoKyspIHtcbiAgICAgICAgbW9udGhseU91dHB1dHMucHVzaChcbiAgICAgICAgICBgJHtjb2cubmFtZX1fJHtwZXJpb2Qub3V0cHV0fV8ke21vbnRoLnRvU3RyaW5nKCkucGFkU3RhcnQoMiwgXCIwXCIpfWAsXG4gICAgICAgIClcbiAgICAgIH1cbiAgICAgIG91dHB1dCA9IG1vbnRobHlPdXRwdXRzLmpvaW4oXCIgKiBcIilcbiAgICB9IGVsc2UgaWYgKFxuICAgICAgY29nQ2FsbC5vcGVyYXRpb24gPT09IFwiRElWSURFXCIgJiZcbiAgICAgIGNvZy5wZXJpb2RVbml0ID09PSBcInllYXJcIiAmJlxuICAgICAgdGhpcy52YXJpYWJsZS5kZWZpbml0aW9uX3BlcmlvZCA9PT0gXCJtb250aFwiXG4gICAgKSB7XG4gICAgICBjb25zdCBtb250aGx5T3V0cHV0czogc3RyaW5nW10gPSBbXVxuICAgICAgZm9yIChsZXQgbW9udGggPSAxOyBtb250aCA8PSAxMjsgbW9udGgrKykge1xuICAgICAgICBtb250aGx5T3V0cHV0cy5wdXNoKFxuICAgICAgICAgIGAke2NvZy5uYW1lfV8ke1N0cmluZyhwZXJpb2Qub3V0cHV0KS5zcGxpdChcIi1cIilbMF19IC8gMTJgLFxuICAgICAgICApXG4gICAgICB9XG4gICAgICBvdXRwdXQgPSBtb250aGx5T3V0cHV0cy5qb2luKFwiKlwiKVxuICAgIH0gZWxzZSB7XG4gICAgICBvcGVyYXRpb25FcnJvciA9IGBVbmFibGUgdG8gY29udmVydCAke2NvZy5uYW1lfSB3aXRoIGEgZGVmaW5pdGlvbiBwZXJpb2Qgb2YgJHtjb2cucGVyaW9kVW5pdH0gdG8gJHtwZXJpb2Qub3V0cHV0fWBcbiAgICAgIG91dHB1dCA9IGAke2NvZy5uYW1lfV8ke1N0cmluZyhwZXJpb2Qub3V0cHV0KS5yZXBsYWNlKC8tL2csIFwiX1wiKX1gXG4gICAgfVxuICAgIHJldHVybiB0aGlzLnJlZHVjZUVycm9yQnlLZXkoY29nQ2FsbCwgb3V0cHV0LCB7XG4gICAgICBvcGVyYXRpb246IG9wZXJhdGlvbkVycm9yLFxuICAgICAgcGVyaW9kOiBwZXJpb2QuZXJyb3IsXG4gICAgfSlcbiAgfVxuXG4gIHRyYW5zZm9ybV9Db21wYXJlKGNvbXBhcmU6IFB5dGhvbkFzdENvbXBhcmUpOiB7XG4gICAgaW5wdXQ6IE9wZW5maXNjYUFzdE5vZGVcbiAgICBvdXRwdXQ6IHVua25vd25cbiAgICBlcnJvcj86IHVua25vd25cbiAgfSB7XG4gICAgY29uc3QgbGVmdCA9IHRoaXMudHJhbnNmb3JtKGNvbXBhcmUubGVmdClcbiAgICBjb25zdCBvcGVyYXRvcnMgPSBjb21wYXJlLm9wcy5tYXAoKG9wZXJhdG9yKSA9PlxuICAgICAgdHJhbnNmb3JtUHl0aG9uQXN0Q29tcGFyaXNvbk9wZXJhdG9yKG9wZXJhdG9yKSxcbiAgICApXG4gICAgY29uc3QgY29tcGFyYXRvcnMgPSB0aGlzLnJlZHVjZU1hcEVycm9ycyhcbiAgICAgIGNvbXBhcmUuY29tcGFyYXRvcnMubWFwKChjb21wYXJhdG9yKSA9PiB0aGlzLnRyYW5zZm9ybShjb21wYXJhdG9yKSksXG4gICAgKVxuICAgIGNvbnN0IGZyYWdtZW50cyA9IFtsZWZ0Lm91dHB1dF1cbiAgICBmb3IgKGNvbnN0IFtpbmRleCwgb3BlcmF0b3JdIG9mIG9wZXJhdG9ycy5lbnRyaWVzKCkpIHtcbiAgICAgIGZyYWdtZW50cy5wdXNoKG9wZXJhdG9yLCBjb21wYXJhdG9ycy5vdXRwdXRbaW5kZXhdKVxuICAgIH1cbiAgICByZXR1cm4gdGhpcy5yZWR1Y2VFcnJvckJ5S2V5KGNvbXBhcmUsIGZyYWdtZW50cy5qb2luKFwiXCIpLCB7XG4gICAgICBsZWZ0OiBsZWZ0LmVycm9yLFxuICAgICAgY29tcGFyYXRvcnM6IGNvbXBhcmF0b3JzLmVycm9yLFxuICAgIH0pXG4gIH1cblxuICB0cmFuc2Zvcm1fQ29uc3RhbnQoY29uc3RhbnQ6IFB5dGhvbkFzdENvbnN0YW50KToge1xuICAgIGlucHV0OiBPcGVuZmlzY2FBc3ROb2RlXG4gICAgb3V0cHV0OiB1bmtub3duXG4gICAgZXJyb3I/OiB1bmtub3duXG4gIH0ge1xuICAgIHJldHVybiB7IGlucHV0OiBjb25zdGFudCwgb3V0cHV0OiBKU09OLnN0cmluZ2lmeShjb25zdGFudC52YWx1ZSkgfVxuICB9XG5cbiAgdHJhbnNmb3JtX2VudGl0eShlbnRpdHk6IE9wZW5maXNjYUFzdEVudGl0eSk6IHtcbiAgICBpbnB1dDogT3BlbmZpc2NhQXN0Tm9kZVxuICAgIG91dHB1dDogdW5rbm93blxuICAgIGVycm9yPzogdW5rbm93blxuICB9IHtcbiAgICByZXR1cm4geyBpbnB1dDogZW50aXR5LCBvdXRwdXQ6IGVudGl0eS5rZXkgfVxuICB9XG5cbiAgdHJhbnNmb3JtX2luc3RhbnRfb3JfcGVyaW9kX2V4cHJlc3Npb24oXG4gICAgaW5zdGFudE9yUGVyaW9kRXhwcmVzc2lvbjogT3BlbmZpc2NhQXN0SW5zdGFudE9yUGVyaW9kRXhwcmVzc2lvbixcbiAgKToge1xuICAgIGlucHV0OiBPcGVuZmlzY2FBc3ROb2RlXG4gICAgb3V0cHV0OiB1bmtub3duXG4gICAgZXJyb3I/OiB1bmtub3duXG4gIH0ge1xuICAgIGNvbnN0IGV4cHJlc3Npb24gPSBldmFsdWF0ZU9wZW5maXNjYUFzdEluc3RhbnRPclBlcmlvZChcbiAgICAgIGluc3RhbnRPclBlcmlvZEV4cHJlc3Npb24uZXhwcmVzc2lvbixcbiAgICAgIHRoaXMucGVyaW9kLFxuICAgIClcbiAgICByZXR1cm4gdGhpcy5yZWR1Y2VFcnJvckJ5S2V5KGluc3RhbnRPclBlcmlvZEV4cHJlc3Npb24sIGV4cHJlc3Npb24ub3V0cHV0LCB7XG4gICAgICBleHByZXNzaW9uOiBleHByZXNzaW9uLmVycm9yLFxuICAgIH0pXG4gIH1cblxuICB0cmFuc2Zvcm1fa2V5d29yZChrZXl3b3JkOiBQeXRob25Bc3RLZXl3b3JkKToge1xuICAgIGlucHV0OiBPcGVuZmlzY2FBc3ROb2RlXG4gICAgb3V0cHV0OiB1bmtub3duXG4gICAgZXJyb3I/OiB1bmtub3duXG4gIH0ge1xuICAgIGNvbnN0IHZhbHVlID0gdGhpcy50cmFuc2Zvcm0oa2V5d29yZC52YWx1ZSlcbiAgICBpZiAoa2V5d29yZC5hcmcgPT09IHVuZGVmaW5lZCkge1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgaW5wdXQ6IGtleXdvcmQsXG4gICAgICAgIG91dHB1dDogYCoqJHt2YWx1ZS5vdXRwdXR9YCxcbiAgICAgICAgZXJyb3I6IFwiQ2FuJ3QgaGFuZGxlIHlldCBrZXl3b3JkIGFyZ3VtZW50IHdpdGhvdXQgbmFtZVwiLFxuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gdGhpcy5yZWR1Y2VFcnJvckJ5S2V5KGtleXdvcmQsIGAke2tleXdvcmQuYXJnfT0ke3ZhbHVlLm91dHB1dH1gLCB7XG4gICAgICBhcmc6XG4gICAgICAgIGtleXdvcmQuYXJnID09PSB1bmRlZmluZWRcbiAgICAgICAgICA/IFwiQ2FuJ3QgaGFuZGxlIHlldCBrZXl3b3JkIGFyZ3VtZW50IHdpdGhvdXQgbmFtZVwiXG4gICAgICAgICAgOiB1bmRlZmluZWQsXG4gICAgICB2YWx1ZTogdmFsdWUuZXJyb3IsXG4gICAgfSlcbiAgfVxuXG4gIHRyYW5zZm9ybV9wYXJhbWV0ZXJfYXRfaW5zdGFudChcbiAgICBwYXJhbWV0ZXJBdEluc3RhbnQ6IE9wZW5maXNjYUFzdFBhcmFtZXRlckF0SW5zdGFudCxcbiAgKToge1xuICAgIGlucHV0OiBPcGVuZmlzY2FBc3ROb2RlXG4gICAgb3V0cHV0OiB1bmtub3duXG4gICAgZXJyb3I/OiB1bmtub3duXG4gIH0ge1xuICAgIGNvbnN0IGluc3RhbnQgPSB0aGlzLnRyYW5zZm9ybShwYXJhbWV0ZXJBdEluc3RhbnQuaW5zdGFudClcbiAgICBjb25zdCBpbnN0YW50U3RyaW5nID0gU3RyaW5nKFxuICAgICAgaW5zdGFudC5vdXRwdXQgaW5zdGFuY2VvZiBQZXJpb2QgPyBpbnN0YW50Lm91dHB1dC5zdGFydCA6IGluc3RhbnQub3V0cHV0LFxuICAgIClcbiAgICBpZiAoaW5zdGFudC5lcnJvciAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICByZXR1cm4gdGhpcy5yZWR1Y2VFcnJvckJ5S2V5KFxuICAgICAgICBwYXJhbWV0ZXJBdEluc3RhbnQsXG4gICAgICAgIFtgcGFyYW1ldGVycygke2luc3RhbnRTdHJpbmd9KWAsIC4uLnBhcmFtZXRlckF0SW5zdGFudC5pZHNdLmpvaW4oXCIuXCIpLFxuICAgICAgICB7IGluc3RhbnQ6IGluc3RhbnQuZXJyb3IgfSxcbiAgICAgIClcbiAgICB9XG4gICAgY29uc3QgW3BhcmFtZXRlciwgcGFyYW1ldGVyRXJyb3JdID0gYWNjZXNzUGFyYW1ldGVyRnJvbUlkcyhcbiAgICAgIHRoaXMucm9vdFBhcmFtZXRlcixcbiAgICAgIHBhcmFtZXRlckF0SW5zdGFudC5pZHMsXG4gICAgKVxuICAgIGlmIChwYXJhbWV0ZXJFcnJvciAhPT0gbnVsbCkge1xuICAgICAgcmV0dXJuIHRoaXMucmVkdWNlRXJyb3JCeUtleShcbiAgICAgICAgcGFyYW1ldGVyQXRJbnN0YW50LFxuICAgICAgICBbYHBhcmFtZXRlcnMoJHtpbnN0YW50U3RyaW5nfSlgLCAuLi5wYXJhbWV0ZXJBdEluc3RhbnQuaWRzXS5qb2luKFwiLlwiKSxcbiAgICAgICAge1xuICAgICAgICAgIHBhcmFtZXRlcjogcGFyYW1ldGVyRXJyb3IsXG4gICAgICAgIH0sXG4gICAgICApXG4gICAgfVxuICAgIHN3aXRjaCAocGFyYW1ldGVyLmNsYXNzKSB7XG4gICAgICBjYXNlIFBhcmFtZXRlckNsYXNzLk5vZGU6IHtcbiAgICAgICAgcmV0dXJuIHRoaXMucmVkdWNlRXJyb3JCeUtleShcbiAgICAgICAgICBwYXJhbWV0ZXJBdEluc3RhbnQsXG4gICAgICAgICAgW2BwYXJhbWV0ZXJzKCR7aW5zdGFudFN0cmluZ30pYCwgLi4ucGFyYW1ldGVyQXRJbnN0YW50Lmlkc10uam9pbihcIi5cIiksXG4gICAgICAgICAge1xuICAgICAgICAgICAgcGFyYW1ldGVyOlxuICAgICAgICAgICAgICBcIlBhcmFtZXRlciBpcyBhIG5vZGUgaW5zdGVhZCBvZiBhIGxlYWYgKGllIHNjYWxlIG9yIHZhbHVlKVwiLFxuICAgICAgICAgIH0sXG4gICAgICAgIClcbiAgICAgIH1cbiAgICAgIGNhc2UgUGFyYW1ldGVyQ2xhc3MuU2NhbGU6IHtcbiAgICAgICAgcmV0dXJuIHRoaXMucmVkdWNlRXJyb3JCeUtleShcbiAgICAgICAgICBwYXJhbWV0ZXJBdEluc3RhbnQsXG4gICAgICAgICAgW2BwYXJhbWV0ZXJzKCR7aW5zdGFudFN0cmluZ30pYCwgLi4ucGFyYW1ldGVyQXRJbnN0YW50Lmlkc10uam9pbihcIi5cIiksXG4gICAgICAgICAge1xuICAgICAgICAgICAgcGFyYW1ldGVyOiBcIlNjYWxlIHBhcmFtZXRlciBjYW4ndCBiZSB1c2VkIGRpcmVjdGx5IGluIGZvcm11bGFcIixcbiAgICAgICAgICB9LFxuICAgICAgICApXG4gICAgICB9XG4gICAgICBjYXNlIFBhcmFtZXRlckNsYXNzLlZhbHVlOiB7XG4gICAgICAgIGNvbnN0IHZhbHVlQXRJbnN0YW50ID0gT2JqZWN0LmVudHJpZXMocGFyYW1ldGVyLnZhbHVlcylcbiAgICAgICAgICAuc29ydCgoW2luc3RhbnQxXSwgW2luc3RhbnQyXSkgPT4gaW5zdGFudDIubG9jYWxlQ29tcGFyZShpbnN0YW50MSkpXG4gICAgICAgICAgLmZpbmQoKFtpbnN0YW50MV0pID0+IGluc3RhbnQxIDw9IGluc3RhbnRTdHJpbmcpPy5bMV1cbiAgICAgICAgaWYgKHZhbHVlQXRJbnN0YW50ID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICByZXR1cm4gdGhpcy5yZWR1Y2VFcnJvckJ5S2V5KFxuICAgICAgICAgICAgcGFyYW1ldGVyQXRJbnN0YW50LFxuICAgICAgICAgICAgW2BwYXJhbWV0ZXJzKCR7aW5zdGFudC5vdXRwdXR9KWAsIC4uLnBhcmFtZXRlckF0SW5zdGFudC5pZHNdLmpvaW4oXG4gICAgICAgICAgICAgIFwiLlwiLFxuICAgICAgICAgICAgKSxcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgcGFyYW1ldGVyOiBgUGFyYW1ldGVyIGhhcyBubyB2YWx1ZSBhdCBpbnN0YW50ICR7aW5zdGFudC5vdXRwdXR9YCxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgKVxuICAgICAgICB9XG4gICAgICAgIGNvbnN0IHZhbHVlID0gdmFsdWVBdEluc3RhbnQudmFsdWVcbiAgICAgICAgaWYgKHZhbHVlID09PSBudWxsKSB7XG4gICAgICAgICAgcmV0dXJuIHRoaXMucmVkdWNlRXJyb3JCeUtleShwYXJhbWV0ZXJBdEluc3RhbnQsIFwibnVsbFwiLCB7XG4gICAgICAgICAgICBwYXJhbWV0ZXI6IGBWYWx1ZSBvZiBwYXJhbWV0ZXIgaXMgbnVsbCBhdCBpbnN0YW50ICR7aW5zdGFudC5vdXRwdXR9YCxcbiAgICAgICAgICB9KVxuICAgICAgICB9XG4gICAgICAgIHJldHVybiB7IGlucHV0OiBwYXJhbWV0ZXJBdEluc3RhbnQsIG91dHB1dDogdmFsdWUudG9TdHJpbmcoKSB9XG4gICAgICB9XG4gICAgICBkZWZhdWx0OlxuICAgICAgICBhc3NlcnROZXZlcihcInBhcmFtZXRlciBjbGFzc1wiLCBwYXJhbWV0ZXIpXG4gICAgfVxuICB9XG5cbiAgdHJhbnNmb3JtX3BlcmlvZChwZXJpb2Q6IE9wZW5maXNjYUFzdFBlcmlvZCk6IHtcbiAgICBpbnB1dDogT3BlbmZpc2NhQXN0Tm9kZVxuICAgIG91dHB1dDogdW5rbm93blxuICAgIGVycm9yPzogdW5rbm93blxuICB9IHtcbiAgICByZXR1cm4geyBpbnB1dDogcGVyaW9kLCBvdXRwdXQ6IHRoaXMucGVyaW9kIH1cbiAgfVxuXG4gIHRyYW5zZm9ybV9TdWJzY3JpcHQoc3Vic2NyaXB0OiBQeXRob25Bc3RTdWJzY3JpcHQpOiB7XG4gICAgaW5wdXQ6IE9wZW5maXNjYUFzdE5vZGVcbiAgICBvdXRwdXQ6IHVua25vd25cbiAgICBlcnJvcj86IHVua25vd25cbiAgfSB7XG4gICAgY29uc3Qgc2xpY2UgPSB0aGlzLnRyYW5zZm9ybShzdWJzY3JpcHQuc2xpY2UpXG4gICAgY29uc3QgdmFsdWUgPSB0aGlzLnRyYW5zZm9ybShzdWJzY3JpcHQudmFsdWUpXG4gICAgcmV0dXJuIHRoaXMucmVkdWNlRXJyb3JCeUtleShcbiAgICAgIHN1YnNjcmlwdCxcbiAgICAgIGAke3ZhbHVlLm91dHB1dH1bJHtzbGljZS5vdXRwdXR9XWAsXG4gICAgICB7XG4gICAgICAgIHZhbHVlOiB2YWx1ZS5lcnJvcixcbiAgICAgIH0sXG4gICAgKVxuICB9XG5cbiAgdHJhbnNmb3JtX1VuYXJ5T3AodW5hcnlPcDogUHl0aG9uQXN0VW5hcnlPcCk6IHtcbiAgICBpbnB1dDogT3BlbmZpc2NhQXN0Tm9kZVxuICAgIG91dHB1dDogdW5rbm93blxuICAgIGVycm9yPzogdW5rbm93blxuICB9IHtcbiAgICBjb25zdCBvcGVyYW5kID0gdGhpcy50cmFuc2Zvcm0odW5hcnlPcC5vcGVyYW5kKVxuICAgIGNvbnN0IG9wZXJhdG9yID0gdHJhbnNmb3JtUHl0aG9uQXN0VW5hcnlPcGVyYXRvcih1bmFyeU9wLm9wKVxuICAgIHJldHVybiB0aGlzLnJlZHVjZUVycm9yQnlLZXkodW5hcnlPcCwgYCR7b3BlcmF0b3J9JHtvcGVyYW5kLm91dHB1dH1gLCB7XG4gICAgICBvcGVyYW5kOiBvcGVyYW5kLmVycm9yLFxuICAgIH0pXG4gIH1cblxuICB0cmFuc2Zvcm1HZW5lcmljT3V0cHV0QnlLZXkoXG4gICAgaW5wdXQ6IE9wZW5maXNjYUFzdE5vZGUsXG4gICAgb3V0cHV0QnlLZXk6IHtcbiAgICAgIFtrZXk6IHN0cmluZ106IHVua25vd25cbiAgICB9LFxuICAgIF9lcnJvckJ5S2V5OiB7XG4gICAgICBba2V5OiBzdHJpbmddOiB1bmtub3duXG4gICAgfSxcbiAgKTogeyBpbnB1dDogT3BlbmZpc2NhQXN0Tm9kZTsgb3V0cHV0OiB1bmtub3duOyBlcnJvcj86IHVua25vd24gfSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIGlucHV0LFxuICAgICAgb3V0cHV0OiBKU09OLnN0cmluZ2lmeShvdXRwdXRCeUtleSksXG4gICAgICBlcnJvcjogYE1pc3NpbmcgWExTWCB0cmFuc2Zvcm1lciBmb3IgJHtpbnB1dC5hc3RfY2xhc3N9YCxcbiAgICB9XG4gIH1cbn1cblxuZnVuY3Rpb24gYXNzZXJ0TmV2ZXIodHlwZTogc3RyaW5nLCB2YWx1ZTogbmV2ZXIpOiBuZXZlciB7XG4gIHRocm93IG5ldyBFcnJvcihgVW5leHBlY3RlZCAke3R5cGV9OiAke0pTT04uc3RyaW5naWZ5KHZhbHVlKX1gKVxufVxuXG5mdW5jdGlvbiB0cmFuc2Zvcm1QeXRob25Bc3RDb21wYXJpc29uT3BlcmF0b3IoXG4gIG9wOiBQeXRob25Bc3RDb21wYXJpc29uT3BlcmF0b3IsXG4pOiBzdHJpbmcge1xuICBzd2l0Y2ggKG9wLmFzdF9jbGFzcykge1xuICAgIGNhc2UgXCJFcVwiOlxuICAgICAgcmV0dXJuIFwiID09IFwiXG4gICAgY2FzZSBcIkd0XCI6XG4gICAgICByZXR1cm4gXCIgPiBcIlxuICAgIGNhc2UgXCJHdEVcIjpcbiAgICAgIHJldHVybiBcIiA+PSBcIlxuICAgIGNhc2UgXCJJblwiOlxuICAgICAgcmV0dXJuIFwiIGluIFwiXG4gICAgY2FzZSBcIklzXCI6XG4gICAgICByZXR1cm4gXCIgPT09IFwiXG4gICAgY2FzZSBcIklzTm90XCI6XG4gICAgICByZXR1cm4gXCIgIT09IFwiXG4gICAgY2FzZSBcIkx0XCI6XG4gICAgICByZXR1cm4gXCIgPCBcIlxuICAgIGNhc2UgXCJMdEVcIjpcbiAgICAgIHJldHVybiBcIiA8PSBcIlxuICAgIGNhc2UgXCJOb3RFcVwiOlxuICAgICAgcmV0dXJuIFwiICE9IFwiXG4gICAgY2FzZSBcIk5vdEluXCI6XG4gICAgICByZXR1cm4gXCIgbm90IGluIFwiXG4gICAgZGVmYXVsdDpcbiAgICAgIGFzc2VydE5ldmVyKFwiYmluYXJ5IG9wZXJhdG9yXCIsIG9wKVxuICB9XG59XG5cbmZ1bmN0aW9uIHRyYW5zZm9ybVB5dGhvbkFzdFVuYXJ5T3BlcmF0b3Iob3A6IFB5dGhvbkFzdFVuYXJ5T3BlcmF0b3IpOiBzdHJpbmcge1xuICBzd2l0Y2ggKG9wLmFzdF9jbGFzcykge1xuICAgIGNhc2UgXCJJbnZlcnRcIjpcbiAgICAgIHJldHVybiBcIn5cIlxuICAgIGNhc2UgXCJOb3RcIjpcbiAgICAgIHJldHVybiBcIm5vdCBcIlxuICAgIGNhc2UgXCJVQWRkXCI6XG4gICAgICByZXR1cm4gXCIrXCJcbiAgICBjYXNlIFwiVVN1YlwiOlxuICAgICAgcmV0dXJuIFwiLVwiXG4gICAgZGVmYXVsdDpcbiAgICAgIGFzc2VydE5ldmVyKFwidW5hcnkgb3BlcmF0b3JcIiwgb3ApXG4gIH1cbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHhsc3hGb3JtdWxhRnJvbU9wZW5maXNjYUFzdChcbiAgdmFyaWFibGU6IFZhcmlhYmxlLFxuICBub2RlOiBPcGVuZmlzY2FBc3ROb2RlLFxuICBwZXJpb2Q6IFBlcmlvZCxcbiAgcm9vdFBhcmFtZXRlcjogTm9kZVBhcmFtZXRlcixcbiAgdmFyaWFibGVTdW1tYXJ5QnlOYW1lOiB7IFtuYW1lOiBzdHJpbmddOiBWYXJpYWJsZSB9LFxuKToge1xuICBpbnB1dDogT3BlbmZpc2NhQXN0Tm9kZVxuICBvdXRwdXQ6IHN0cmluZ1xuICBlcnJvcj86IHVua25vd25cbn0ge1xuICBjb25zdCB4bHN4Rm9ybXVsYUdlbmVyYXRvciA9IG5ldyBYbHN4Rm9ybXVsYUdlbmVyYXRvcihcbiAgICB2YXJpYWJsZSxcbiAgICBwZXJpb2QsXG4gICAgcm9vdFBhcmFtZXRlcixcbiAgICB2YXJpYWJsZVN1bW1hcnlCeU5hbWUsXG4gIClcbiAgY29uc3QgcmVzdWx0ID0geGxzeEZvcm11bGFHZW5lcmF0b3IudHJhbnNmb3JtKG5vZGUpXG4gIHJldHVybiB0eXBlb2YgcmVzdWx0Lm91dHB1dCA9PT0gXCJzdHJpbmdcIlxuICAgID8gKHJlc3VsdCBhcyB7XG4gICAgICAgIGlucHV0OiBPcGVuZmlzY2FBc3ROb2RlXG4gICAgICAgIG91dHB1dDogc3RyaW5nXG4gICAgICAgIGVycm9yPzogdW5rbm93blxuICAgICAgfSlcbiAgICA6IHtcbiAgICAgICAgLi4ucmVzdWx0LFxuICAg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