@openfisca/json-model
Version:
Library to handle informations extracted in JSON or YAML format from OpenFisca parameters, variables, etc
458 lines (456 loc) • 52.3 kB
JavaScript
import { accessParameterFromIds } from "../parameters.js";
import { AstTransformer } from "./visitors.js"; /// Generate an OpenFisca abstract tree from a Python Abstract syntax tree.
export class OpenfiscaAstFormulaBuilder extends AstTransformer {
cogByName = {};
globalVariableValueByName = {
ADD: {
input: {
// Dummy input
ast_class: "Name",
ctx: {
ast_class: "Load"
},
id: "openfisca_france.ADD"
},
output: {
ast_class: "built_in",
name: "ADD"
}
},
Famille: {
input: {
// Dummy input
ast_class: "Name",
ctx: {
ast_class: "Load"
},
id: "openfisca_france.Famille"
},
output: {
ast_class: "built_in",
name: "Famille"
}
},
FoyerFiscal: {
input: {
// Dummy input
ast_class: "Name",
ctx: {
ast_class: "Load"
},
id: "openfisca_france.FoyerFiscal"
},
output: {
ast_class: "built_in",
name: "FoyerFiscal"
}
},
max_: {
input: {
// Dummy input
ast_class: "Name",
ctx: {
ast_class: "Load"
},
id: "numpy.maximum"
},
output: {
ast_class: "built_in",
name: "max"
}
},
Menage: {
input: {
// Dummy input
ast_class: "Name",
ctx: {
ast_class: "Load"
},
id: "openfisca_france.Menage"
},
output: {
ast_class: "built_in",
name: "Menage"
}
},
min_: {
input: {
// Dummy input
ast_class: "Name",
ctx: {
ast_class: "Load"
},
id: "numpy.minimum"
},
output: {
ast_class: "built_in",
name: "min"
}
},
not_: {
input: {
// Dummy input
ast_class: "Name",
ctx: {
ast_class: "Load"
},
id: "numpy.logical_not"
},
output: {
ast_class: "built_in",
name: "not"
}
}
};
returnCount = 0;
/// Value of the latest return statement found in formula
returnValue = undefined;
variableValueByName = {};
constructor(variable, functionDef, entityByKey, rootParameter, variableSummaryByName) {
super();
this.variable = variable;
this.entityByKey = entityByKey;
this.rootParameter = rootParameter;
this.variableSummaryByName = variableSummaryByName;
const entityKey = variable.entity;
this.personEntityKey = Object.entries(entityByKey).filter(([, entity]) => entity.is_person).map(([key]) => key)[0];
const {
args
} = functionDef.args;
console.assert(args.length >= 2 && args.length <= 3, "Unexpected number of parameters in formula");
console.assert(args[0].arg === entityKey, `Invalid name "${args[0].arg}" for formula entity parameter`);
console.assert(entityByKey[entityKey] !== undefined, `Invalid name "${entityKey}" for formula entity parameter`);
this.variableValueByName[args[0].arg] = {
input: {
// Dummy input
ast_class: "Name",
ctx: {
ast_class: "Load"
},
id: entityKey
},
output: {
ast_class: "entity",
key: entityKey
}
};
console.assert(args[1].arg === "period", `Invalid name "${args[1].arg}" for formula period parameter`);
this.variableValueByName[args[1].arg] = {
input: {
// Dummy input
ast_class: "Name",
ctx: {
ast_class: "Load"
},
id: "period"
},
output: {
ast_class: "period"
}
};
if (args.length >= 3) {
console.assert(args[2].arg === "parameters", `Invalid name for formula parameter argunemnt: ${args[1].arg}`);
this.variableValueByName[args[2].arg] = {
input: {
// Dummy input
ast_class: "Name",
ctx: {
ast_class: "Load"
},
id: "parameters"
},
output: {
ast_class: "parameter",
ids: []
}
};
}
}
run(functionDef) {
for (const instruction of functionDef.body) {
this.transform(instruction);
}
const formula = {
ast_class: "formula",
returnValue: this.returnCount === 1 ? this.returnValue : {
input: {
ast_class: "Constant",
value: "ERROR"
},
// TODO: Replace dummy value.
output: {
ast_class: "Constant",
value: "ERROR"
},
// TODO: Replace dummy value.
error: "Formula doesn't return a value or return several values"
}
// variableValueByName: this.variableValueByName,
};
// const variableValueByNameError:{[name: string]: unknown} = {}
// const variableValueByName: {[name: string]: OpenfiscaAstNode} = {}
// for (const [name, variableValue] of Object.entries(this.variableValueByName)) {
// variableValueByName[name] = variableValue.output
// if (variableValue.error !== undefined) {
// variableValueByNameError[name] = variableValue.error
// }
// }
// if (Object.keys(variableValueByNameError).length !== 0) {
// error.variableValueByName = variableValueByNameError
// }
return formula;
}
transform_Assign(assign) {
const targets = this.reduceMapErrors(assign.targets.map(target => this.transform(target)));
const value = this.transform(assign.value);
for (const target of targets.output) {
if (target.ast_class === "Name" && target.ctx.ast_class === "Store") {
this.variableValueByName[target.id] = value;
}
}
return this.reduceErrorByKey(assign, {
...assign,
targets: targets.output,
value: value.output
}, {
targets: targets.error,
value: value.error
});
}
transform_Attribute(attribute) {
const value = this.transform(attribute.value);
const {
output: valueOutput
} = value;
switch (valueOutput.ast_class) {
case "entity":
{
const entity = this.entityByKey[valueOutput.key];
if (!entity.is_person && attribute.attr === "members") {
return this.reduceErrorByKey(attribute, {
ast_class: "entity",
key: this.personEntityKey
}, {
value: value.error
});
}
break;
}
case "instant_or_period_expression":
{
return this.reduceErrorByKey(attribute, {
ast_class: "instant_or_period_expression",
expression: {
...attribute,
value: valueOutput.expression
}
}, {
value: value.error
});
}
case "parameter_at_instant":
{
const ids = [...valueOutput.ids, attribute.attr];
const [, attrError] = accessParameterFromIds(this.rootParameter, ids);
const parameterAtInstant = {
...valueOutput,
ids
};
return this.reduceErrorByKey(attribute, parameterAtInstant, {
attr: attrError,
value: value.error
});
}
case "period":
{
return this.reduceErrorByKey(attribute, {
ast_class: "instant_or_period_expression",
expression: {
...attribute,
value: valueOutput
}
}, {
value: value.error
});
}
default:
}
return this.reduceErrorByKey(attribute, {
...attribute,
value: valueOutput
}, {
value: value.error
});
}
transform_AugAssign(augAssign) {
// Replace augmented assign (+=, /=, etc) with a normal assign.
return this.transform({
ast_class: "Assign",
targets: [augAssign.target],
value: {
ast_class: "BinOp",
left: {
...augAssign.target,
ctx: {
ast_class: "Load"
}
},
op: augAssign.op,
right: augAssign.value
}
});
}
transform_Call(call) {
const args = this.reduceMapErrors(call.args.map(arg => this.transform(arg)));
const func = this.transform(call.func);
const {
output: funcOutput
} = func;
const keywords = this.reduceMapErrors(call.keywords.map(keyword => this.transform(keyword)));
switch (funcOutput.ast_class) {
case "entity":
{
const [variableNameOutput, periodOutput, operationOutput] = args.output;
if (variableNameOutput.ast_class === "Constant") {
const variableName = variableNameOutput.value;
let cog = this.cogByName[variableName];
if (cog === undefined) {
const variableSummary = this.variableSummaryByName[variableName];
cog = this.cogByName[variableName] = {
ast_class: "cog",
entity: this.entityByKey[variableSummary.entity],
name: variableName,
periodUnit: variableSummary.definition_period
};
}
const cogCall = {
ast_class: "cog_call",
cog,
period: periodOutput
};
if (operationOutput === undefined) {
if (cog.periodUnit !== this.variable.definition_period) {
if (args.error?.[2] === undefined) {
// Add an error if one doesn't exist yet.
if (args.error === undefined) {
args.error = {};
}
;
args.error[2] = `Missing operation in cog call to convert result from ${cog.periodUnit} to ${this.variable.definition_period}`;
}
}
} else if (operationOutput.ast_class === "Constant" && ["ADD", "DIVIDE"].includes(operationOutput.value)) {
cogCall.operation = operationOutput.value;
} else if (args.error?.[2] === undefined) {
// Unexpected operation for cog call
// => Add an error if one doesn't exist yet.
if (args.error === undefined) {
args.error = {};
}
;
args.error[2] = "Unexpected operation for cog call";
}
return this.reduceErrorByKey(call, cogCall, {
args: args.error,
func: func.error,
keywords: keywords.error
});
}
break;
}
case "instant_or_period_expression":
{
return this.reduceErrorByKey(call, {
ast_class: "instant_or_period_expression",
expression: {
...call,
func: funcOutput.expression
}
}, {
args: args.error,
func: func.error,
keywords: keywords.error
});
}
case "parameter":
{
const [instantOutput] = args.output;
return this.reduceErrorByKey(call, {
ast_class: "parameter_at_instant",
ids: funcOutput.ids,
instant: instantOutput
}, {
args: args.error,
func: func.error,
keywords: keywords.error
});
}
default:
}
return this.reduceErrorByKey(call, {
...call,
args: args.output,
func: func.output,
keywords: keywords.output
}, {
args: args.error,
func: func.error,
keywords: keywords.error
});
}
transform_Name(name) {
if (name.ctx.ast_class === "Load") {
const variableValue = this.variableValueByName[name.id] ?? this.globalVariableValueByName[name.id];
return variableValue === undefined ? {
input: name,
output: name,
error: {
id: `Undefined variable: ${name.id}`
}
} : variableValue;
}
return {
input: name,
output: name
};
}
transform_Return(returnNode) {
const value = returnNode.value === undefined ? {
input: {
// Dummy input
ast_class: "Constant"
// value: undefined,
},
output: {
ast_class: "Constant"
// value: undefined
},
error: "Missing return value"
} : this.transform(returnNode.value);
this.returnCount++;
this.returnValue = value;
return this.reduceErrorByKey(returnNode, {
...returnNode,
value: value.output
}, {
value: value.error
});
}
transform_Subscript(subscript) {
const slice = this.transform(subscript.slice);
const value = this.transform(subscript.value);
return this.reduceErrorByKey(subscript, {
...subscript,
slice: slice.output,
value: value.output
}, {
slice: slice.error,
value: value.error
});
}
}
export function openfiscaAstFromFormulaPythonAst(variable, functionDef, entityByKey, rootParameter, variableSummaryByName) {
const openfiscaAstFormulaBuilder = new OpenfiscaAstFormulaBuilder(variable, functionDef, entityByKey, rootParameter, variableSummaryByName);
return openfiscaAstFormulaBuilder.run(functionDef);
}
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJhY2Nlc3NQYXJhbWV0ZXJGcm9tSWRzIiwiQXN0VHJhbnNmb3JtZXIiLCJPcGVuZmlzY2FBc3RGb3JtdWxhQnVpbGRlciIsImNvZ0J5TmFtZSIsImdsb2JhbFZhcmlhYmxlVmFsdWVCeU5hbWUiLCJBREQiLCJpbnB1dCIsImFzdF9jbGFzcyIsImN0eCIsImlkIiwib3V0cHV0IiwibmFtZSIsIkZhbWlsbGUiLCJGb3llckZpc2NhbCIsIm1heF8iLCJNZW5hZ2UiLCJtaW5fIiwibm90XyIsInJldHVybkNvdW50IiwicmV0dXJuVmFsdWUiLCJ1bmRlZmluZWQiLCJ2YXJpYWJsZVZhbHVlQnlOYW1lIiwiY29uc3RydWN0b3IiLCJ2YXJpYWJsZSIsImZ1bmN0aW9uRGVmIiwiZW50aXR5QnlLZXkiLCJyb290UGFyYW1ldGVyIiwidmFyaWFibGVTdW1tYXJ5QnlOYW1lIiwiZW50aXR5S2V5IiwiZW50aXR5IiwicGVyc29uRW50aXR5S2V5IiwiT2JqZWN0IiwiZW50cmllcyIsImZpbHRlciIsImlzX3BlcnNvbiIsIm1hcCIsImtleSIsImFyZ3MiLCJjb25zb2xlIiwiYXNzZXJ0IiwibGVuZ3RoIiwiYXJnIiwiaWRzIiwicnVuIiwiaW5zdHJ1Y3Rpb24iLCJib2R5IiwidHJhbnNmb3JtIiwiZm9ybXVsYSIsInZhbHVlIiwiZXJyb3IiLCJ0cmFuc2Zvcm1fQXNzaWduIiwiYXNzaWduIiwidGFyZ2V0cyIsInJlZHVjZU1hcEVycm9ycyIsInRhcmdldCIsInJlZHVjZUVycm9yQnlLZXkiLCJ0cmFuc2Zvcm1fQXR0cmlidXRlIiwiYXR0cmlidXRlIiwidmFsdWVPdXRwdXQiLCJhdHRyIiwiZXhwcmVzc2lvbiIsImF0dHJFcnJvciIsInBhcmFtZXRlckF0SW5zdGFudCIsInRyYW5zZm9ybV9BdWdBc3NpZ24iLCJhdWdBc3NpZ24iLCJsZWZ0Iiwib3AiLCJyaWdodCIsInRyYW5zZm9ybV9DYWxsIiwiY2FsbCIsImZ1bmMiLCJmdW5jT3V0cHV0Iiwia2V5d29yZHMiLCJrZXl3b3JkIiwidmFyaWFibGVOYW1lT3V0cHV0IiwicGVyaW9kT3V0cHV0Iiwib3BlcmF0aW9uT3V0cHV0IiwidmFyaWFibGVOYW1lIiwiY29nIiwidmFyaWFibGVTdW1tYXJ5IiwicGVyaW9kVW5pdCIsImRlZmluaXRpb25fcGVyaW9kIiwiY29nQ2FsbCIsInBlcmlvZCIsImluY2x1ZGVzIiwib3BlcmF0aW9uIiwiaW5zdGFudE91dHB1dCIsImluc3RhbnQiLCJ0cmFuc2Zvcm1fTmFtZSIsInZhcmlhYmxlVmFsdWUiLCJ0cmFuc2Zvcm1fUmV0dXJuIiwicmV0dXJuTm9kZSIsInRyYW5zZm9ybV9TdWJzY3JpcHQiLCJzdWJzY3JpcHQiLCJzbGljZSIsIm9wZW5maXNjYUFzdEZyb21Gb3JtdWxhUHl0aG9uQXN0Iiwib3BlbmZpc2NhQXN0Rm9ybXVsYUJ1aWxkZXIiXSwic291cmNlcyI6WyIuLi8uLi9zcmMvYXN0L29wZW5maXNjYS50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgdHlwZSB7IEVudGl0eUJ5S2V5IH0gZnJvbSBcIi4uL2VudGl0aWVzXCJcbmltcG9ydCB7IGFjY2Vzc1BhcmFtZXRlckZyb21JZHMsIHR5cGUgTm9kZVBhcmFtZXRlciB9IGZyb20gXCIuLi9wYXJhbWV0ZXJzXCJcbmltcG9ydCB0eXBlIHsgVmFyaWFibGUgfSBmcm9tIFwiLi4vdmFyaWFibGVzXCJcblxuaW1wb3J0IHtcbiAgT3BlbmZpc2NhQXN0Q29nQ2FsbCxcbiAgT3BlbmZpc2NhQXN0Q29nQ2FsbE9wZXJhdGlvbixcbiAgT3BlbmZpc2NhQXN0SW5zdGFudE9yUGVyaW9kRXhwcmVzc2lvbixcbiAgT3BlbmZpc2NhQXN0UGVyaW9kLFxuICBQeXRob25Bc3RDb25zdGFudCxcbiAgUHl0aG9uQXN0S2V5d29yZCxcbiAgUHl0aG9uQXN0Tm9kZSxcbiAgUHl0aG9uQXN0U3Vic2NyaXB0LFxuICB0eXBlIE9wZW5maXNjYUFzdENvZyxcbiAgdHlwZSBPcGVuZmlzY2FBc3RGb3JtdWxhLFxuICB0eXBlIE9wZW5maXNjYUFzdE5vZGUsXG4gIHR5cGUgUHl0aG9uQXN0QXNzaWduLFxuICB0eXBlIFB5dGhvbkFzdEF0dHJpYnV0ZSxcbiAgdHlwZSBQeXRob25Bc3RBdWdBc3NpZ24sXG4gIHR5cGUgUHl0aG9uQXN0QmluYXJ5T3BlcmF0b3IsXG4gIHR5cGUgUHl0aG9uQXN0Q2FsbCxcbiAgdHlwZSBQeXRob25Bc3RGdW5jdGlvbkRlZixcbiAgdHlwZSBQeXRob25Bc3ROYW1lLFxuICB0eXBlIFB5dGhvbkFzdFJldHVybixcbn0gZnJvbSBcIi4vbm9kZXNcIlxuaW1wb3J0IHsgQXN0VHJhbnNmb3JtZXIgfSBmcm9tIFwiLi92aXNpdG9yc1wiXG5cbi8vLyBHZW5lcmF0ZSBhbiBPcGVuRmlzY2EgYWJzdHJhY3QgdHJlZSBmcm9tIGEgUHl0aG9uIEFic3RyYWN0IHN5bnRheCB0cmVlLlxuZXhwb3J0IGNsYXNzIE9wZW5maXNjYUFzdEZvcm11bGFCdWlsZGVyIGV4dGVuZHMgQXN0VHJhbnNmb3JtZXI8XG4gIFB5dGhvbkFzdE5vZGUsXG4gIE9wZW5maXNjYUFzdE5vZGVcbj4ge1xuICBwdWJsaWMgcmVhZG9ubHkgY29nQnlOYW1lOiB7IFtuYW1lOiBzdHJpbmddOiBPcGVuZmlzY2FBc3RDb2cgfSA9IHt9XG4gIHB1YmxpYyByZWFkb25seSBnbG9iYWxWYXJpYWJsZVZhbHVlQnlOYW1lOiB7XG4gICAgW25hbWU6IHN0cmluZ106IHtcbiAgICAgIGlucHV0OiBQeXRob25Bc3ROb2RlXG4gICAgICBvdXRwdXQ6IE9wZW5maXNjYUFzdE5vZGVcbiAgICAgIGVycm9yPzogdW5rbm93blxuICAgIH1cbiAgfSA9IHtcbiAgICBBREQ6IHtcbiAgICAgIGlucHV0OiB7XG4gICAgICAgIC8vIER1bW15IGlucHV0XG4gICAgICAgIGFzdF9jbGFzczogXCJOYW1lXCIsXG4gICAgICAgIGN0eDogeyBhc3RfY2xhc3M6IFwiTG9hZFwiIH0sXG4gICAgICAgIGlkOiBcIm9wZW5maXNjYV9mcmFuY2UuQUREXCIsXG4gICAgICB9LFxuICAgICAgb3V0cHV0OiB7IGFzdF9jbGFzczogXCJidWlsdF9pblwiLCBuYW1lOiBcIkFERFwiIH0sXG4gICAgfSxcbiAgICBGYW1pbGxlOiB7XG4gICAgICBpbnB1dDoge1xuICAgICAgICAvLyBEdW1teSBpbnB1dFxuICAgICAgICBhc3RfY2xhc3M6IFwiTmFtZVwiLFxuICAgICAgICBjdHg6IHsgYXN0X2NsYXNzOiBcIkxvYWRcIiB9LFxuICAgICAgICBpZDogXCJvcGVuZmlzY2FfZnJhbmNlLkZhbWlsbGVcIixcbiAgICAgIH0sXG4gICAgICBvdXRwdXQ6IHsgYXN0X2NsYXNzOiBcImJ1aWx0X2luXCIsIG5hbWU6IFwiRmFtaWxsZVwiIH0sXG4gICAgfSxcbiAgICBGb3llckZpc2NhbDoge1xuICAgICAgaW5wdXQ6IHtcbiAgICAgICAgLy8gRHVtbXkgaW5wdXRcbiAgICAgICAgYXN0X2NsYXNzOiBcIk5hbWVcIixcbiAgICAgICAgY3R4OiB7IGFzdF9jbGFzczogXCJMb2FkXCIgfSxcbiAgICAgICAgaWQ6IFwib3BlbmZpc2NhX2ZyYW5jZS5Gb3llckZpc2NhbFwiLFxuICAgICAgfSxcbiAgICAgIG91dHB1dDogeyBhc3RfY2xhc3M6IFwiYnVpbHRfaW5cIiwgbmFtZTogXCJGb3llckZpc2NhbFwiIH0sXG4gICAgfSxcbiAgICBtYXhfOiB7XG4gICAgICBpbnB1dDoge1xuICAgICAgICAvLyBEdW1teSBpbnB1dFxuICAgICAgICBhc3RfY2xhc3M6IFwiTmFtZVwiLFxuICAgICAgICBjdHg6IHsgYXN0X2NsYXNzOiBcIkxvYWRcIiB9LFxuICAgICAgICBpZDogXCJudW1weS5tYXhpbXVtXCIsXG4gICAgICB9LFxuICAgICAgb3V0cHV0OiB7IGFzdF9jbGFzczogXCJidWlsdF9pblwiLCBuYW1lOiBcIm1heFwiIH0sXG4gICAgfSxcbiAgICBNZW5hZ2U6IHtcbiAgICAgIGlucHV0OiB7XG4gICAgICAgIC8vIER1bW15IGlucHV0XG4gICAgICAgIGFzdF9jbGFzczogXCJOYW1lXCIsXG4gICAgICAgIGN0eDogeyBhc3RfY2xhc3M6IFwiTG9hZFwiIH0sXG4gICAgICAgIGlkOiBcIm9wZW5maXNjYV9mcmFuY2UuTWVuYWdlXCIsXG4gICAgICB9LFxuICAgICAgb3V0cHV0OiB7IGFzdF9jbGFzczogXCJidWlsdF9pblwiLCBuYW1lOiBcIk1lbmFnZVwiIH0sXG4gICAgfSxcbiAgICBtaW5fOiB7XG4gICAgICBpbnB1dDoge1xuICAgICAgICAvLyBEdW1teSBpbnB1dFxuICAgICAgICBhc3RfY2xhc3M6IFwiTmFtZVwiLFxuICAgICAgICBjdHg6IHsgYXN0X2NsYXNzOiBcIkxvYWRcIiB9LFxuICAgICAgICBpZDogXCJudW1weS5taW5pbXVtXCIsXG4gICAgICB9LFxuICAgICAgb3V0cHV0OiB7IGFzdF9jbGFzczogXCJidWlsdF9pblwiLCBuYW1lOiBcIm1pblwiIH0sXG4gICAgfSxcbiAgICBub3RfOiB7XG4gICAgICBpbnB1dDoge1xuICAgICAgICAvLyBEdW1teSBpbnB1dFxuICAgICAgICBhc3RfY2xhc3M6IFwiTmFtZVwiLFxuICAgICAgICBjdHg6IHsgYXN0X2NsYXNzOiBcIkxvYWRcIiB9LFxuICAgICAgICBpZDogXCJudW1weS5sb2dpY2FsX25vdFwiLFxuICAgICAgfSxcbiAgICAgIG91dHB1dDogeyBhc3RfY2xhc3M6IFwiYnVpbHRfaW5cIiwgbmFtZTogXCJub3RcIiB9LFxuICAgIH0sXG4gIH1cbiAgcHVibGljIHJlYWRvbmx5IHBlcnNvbkVudGl0eUtleTogc3RyaW5nXG4gIHB1YmxpYyByZXR1cm5Db3VudCA9IDBcbiAgLy8vIFZhbHVlIG9mIHRoZSBsYXRlc3QgcmV0dXJuIHN0YXRlbWVudCBmb3VuZCBpbiBmb3JtdWxhXG4gIHB1YmxpYyByZXR1cm5WYWx1ZTpcbiAgICB8IHtcbiAgICAgICAgaW5wdXQ6IFB5dGhvbkFzdE5vZGVcbiAgICAgICAgb3V0cHV0OiBPcGVuZmlzY2FBc3ROb2RlXG4gICAgICAgIGVycm9yPzogdW5rbm93blxuICAgICAgfVxuICAgIHwgdW5kZWZpbmVkID0gdW5kZWZpbmVkXG4gIHB1YmxpYyByZWFkb25seSB2YXJpYWJsZVZhbHVlQnlOYW1lOiB7XG4gICAgW25hbWU6IHN0cmluZ106IHtcbiAgICAgIGlucHV0OiBQeXRob25Bc3ROb2RlXG4gICAgICBvdXRwdXQ6IE9wZW5maXNjYUFzdE5vZGVcbiAgICAgIGVycm9yPzogdW5rbm93blxuICAgIH1cbiAgfSA9IHt9XG5cbiAgY29uc3RydWN0b3IoXG4gICAgcHVibGljIHJlYWRvbmx5IHZhcmlhYmxlOiBWYXJpYWJsZSxcbiAgICBmdW5jdGlvbkRlZjogUHl0aG9uQXN0RnVuY3Rpb25EZWYsXG4gICAgcHVibGljIHJlYWRvbmx5IGVudGl0eUJ5S2V5OiBFbnRpdHlCeUtleSxcbiAgICBwdWJsaWMgcmVhZG9ubHkgcm9vdFBhcmFtZXRlcjogTm9kZVBhcmFtZXRlcixcbiAgICBwdWJsaWMgcmVhZG9ubHkgdmFyaWFibGVTdW1tYXJ5QnlOYW1lOiB7IFtuYW1lOiBzdHJpbmddOiBWYXJpYWJsZSB9LFxuICApIHtcbiAgICBzdXBlcigpXG5cbiAgICBjb25zdCBlbnRpdHlLZXkgPSB2YXJpYWJsZS5lbnRpdHlcbiAgICB0aGlzLnBlcnNvbkVudGl0eUtleSA9IE9iamVjdC5lbnRyaWVzKGVudGl0eUJ5S2V5KVxuICAgICAgLmZpbHRlcigoWywgZW50aXR5XSkgPT4gZW50aXR5LmlzX3BlcnNvbilcbiAgICAgIC5tYXAoKFtrZXldKSA9PiBrZXkpWzBdXG5cbiAgICBjb25zdCB7IGFyZ3MgfSA9IGZ1bmN0aW9uRGVmLmFyZ3NcbiAgICBjb25zb2xlLmFzc2VydChcbiAgICAgIGFyZ3MubGVuZ3RoID49IDIgJiYgYXJncy5sZW5ndGggPD0gMyxcbiAgICAgIFwiVW5leHBlY3RlZCBudW1iZXIgb2YgcGFyYW1ldGVycyBpbiBmb3JtdWxhXCIsXG4gICAgKVxuXG4gICAgY29uc29sZS5hc3NlcnQoXG4gICAgICBhcmdzWzBdLmFyZyA9PT0gZW50aXR5S2V5LFxuICAgICAgYEludmFsaWQgbmFtZSBcIiR7YXJnc1swXS5hcmd9XCIgZm9yIGZvcm11bGEgZW50aXR5IHBhcmFtZXRlcmAsXG4gICAgKVxuICAgIGNvbnNvbGUuYXNzZXJ0KFxuICAgICAgZW50aXR5QnlLZXlbZW50aXR5S2V5XSAhPT0gdW5kZWZpbmVkLFxuICAgICAgYEludmFsaWQgbmFtZSBcIiR7ZW50aXR5S2V5fVwiIGZvciBmb3JtdWxhIGVudGl0eSBwYXJhbWV0ZXJgLFxuICAgIClcbiAgICB0aGlzLnZhcmlhYmxlVmFsdWVCeU5hbWVbYXJnc1swXS5hcmddID0ge1xuICAgICAgaW5wdXQ6IHtcbiAgICAgICAgLy8gRHVtbXkgaW5wdXRcbiAgICAgICAgYXN0X2NsYXNzOiBcIk5hbWVcIixcbiAgICAgICAgY3R4OiB7IGFzdF9jbGFzczogXCJMb2FkXCIgfSxcbiAgICAgICAgaWQ6IGVudGl0eUtleSxcbiAgICAgIH0sXG4gICAgICBvdXRwdXQ6IHtcbiAgICAgICAgYXN0X2NsYXNzOiBcImVudGl0eVwiLFxuICAgICAgICBrZXk6IGVudGl0eUtleSxcbiAgICAgIH0sXG4gICAgfVxuXG4gICAgY29uc29sZS5hc3NlcnQoXG4gICAgICBhcmdzWzFdLmFyZyA9PT0gXCJwZXJpb2RcIixcbiAgICAgIGBJbnZhbGlkIG5hbWUgXCIke2FyZ3NbMV0uYXJnfVwiIGZvciBmb3JtdWxhIHBlcmlvZCBwYXJhbWV0ZXJgLFxuICAgIClcbiAgICB0aGlzLnZhcmlhYmxlVmFsdWVCeU5hbWVbYXJnc1sxXS5hcmddID0ge1xuICAgICAgaW5wdXQ6IHtcbiAgICAgICAgLy8gRHVtbXkgaW5wdXRcbiAgICAgICAgYXN0X2NsYXNzOiBcIk5hbWVcIixcbiAgICAgICAgY3R4OiB7IGFzdF9jbGFzczogXCJMb2FkXCIgfSxcbiAgICAgICAgaWQ6IFwicGVyaW9kXCIsXG4gICAgICB9LFxuICAgICAgb3V0cHV0OiB7IGFzdF9jbGFzczogXCJwZXJpb2RcIiB9LFxuICAgIH1cblxuICAgIGlmIChhcmdzLmxlbmd0aCA+PSAzKSB7XG4gICAgICBjb25zb2xlLmFzc2VydChcbiAgICAgICAgYXJnc1syXS5hcmcgPT09IFwicGFyYW1ldGVyc1wiLFxuICAgICAgICBgSW52YWxpZCBuYW1lIGZvciBmb3JtdWxhIHBhcmFtZXRlciBhcmd1bmVtbnQ6ICR7YXJnc1sxXS5hcmd9YCxcbiAgICAgIClcbiAgICAgIHRoaXMudmFyaWFibGVWYWx1ZUJ5TmFtZVthcmdzWzJdLmFyZ10gPSB7XG4gICAgICAgIGlucHV0OiB7XG4gICAgICAgICAgLy8gRHVtbXkgaW5wdXRcbiAgICAgICAgICBhc3RfY2xhc3M6IFwiTmFtZVwiLFxuICAgICAgICAgIGN0eDogeyBhc3RfY2xhc3M6IFwiTG9hZFwiIH0sXG4gICAgICAgICAgaWQ6IFwicGFyYW1ldGVyc1wiLFxuICAgICAgICB9LFxuICAgICAgICBvdXRwdXQ6IHtcbiAgICAgICAgICBhc3RfY2xhc3M6IFwicGFyYW1ldGVyXCIsXG4gICAgICAgICAgaWRzOiBbXSxcbiAgICAgICAgfSxcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBydW4oZnVuY3Rpb25EZWY6IFB5dGhvbkFzdEZ1bmN0aW9uRGVmKTogT3BlbmZpc2NhQXN0Rm9ybXVsYSB7XG4gICAgZm9yIChjb25zdCBpbnN0cnVjdGlvbiBvZiBmdW5jdGlvbkRlZi5ib2R5KSB7XG4gICAgICB0aGlzLnRyYW5zZm9ybShpbnN0cnVjdGlvbilcbiAgICB9XG4gICAgY29uc3QgZm9ybXVsYTogT3BlbmZpc2NhQXN0Rm9ybXVsYSA9IHtcbiAgICAgIGFzdF9jbGFzczogXCJmb3JtdWxhXCIsXG4gICAgICByZXR1cm5WYWx1ZTpcbiAgICAgICAgdGhpcy5yZXR1cm5Db3VudCA9PT0gMVxuICAgICAgICAgID8gdGhpcy5yZXR1cm5WYWx1ZSFcbiAgICAgICAgICA6IHtcbiAgICAgICAgICAgICAgaW5wdXQ6IHsgYXN0X2NsYXNzOiBcIkNvbnN0YW50XCIsIHZhbHVlOiBcIkVSUk9SXCIgfSwgLy8gVE9ETzogUmVwbGFjZSBkdW1teSB2YWx1ZS5cbiAgICAgICAgICAgICAgb3V0cHV0OiB7IGFzdF9jbGFzczogXCJDb25zdGFudFwiLCB2YWx1ZTogXCJFUlJPUlwiIH0sIC8vIFRPRE86IFJlcGxhY2UgZHVtbXkgdmFsdWUuXG4gICAgICAgICAgICAgIGVycm9yOiBcIkZvcm11bGEgZG9lc24ndCByZXR1cm4gYSB2YWx1ZSBvciByZXR1cm4gc2V2ZXJhbCB2YWx1ZXNcIixcbiAgICAgICAgICAgIH0sXG4gICAgICAvLyB2YXJpYWJsZVZhbHVlQnlOYW1lOiB0aGlzLnZhcmlhYmxlVmFsdWVCeU5hbWUsXG4gICAgfVxuXG4gICAgLy8gY29uc3QgdmFyaWFibGVWYWx1ZUJ5TmFtZUVycm9yOntbbmFtZTogc3RyaW5nXTogdW5rbm93bn0gPSB7fVxuICAgIC8vIGNvbnN0IHZhcmlhYmxlVmFsdWVCeU5hbWU6IHtbbmFtZTogc3RyaW5nXTogT3BlbmZpc2NhQXN0Tm9kZX0gPSB7fVxuICAgIC8vIGZvciAoY29uc3QgW25hbWUsIHZhcmlhYmxlVmFsdWVdIG9mIE9iamVjdC5lbnRyaWVzKHRoaXMudmFyaWFibGVWYWx1ZUJ5TmFtZSkpIHtcbiAgICAvLyAgIHZhcmlhYmxlVmFsdWVCeU5hbWVbbmFtZV0gPSB2YXJpYWJsZVZhbHVlLm91dHB1dFxuICAgIC8vICAgaWYgKHZhcmlhYmxlVmFsdWUuZXJyb3IgIT09IHVuZGVmaW5lZCkge1xuICAgIC8vICAgICB2YXJpYWJsZVZhbHVlQnlOYW1lRXJyb3JbbmFtZV0gPSB2YXJpYWJsZVZhbHVlLmVycm9yXG4gICAgLy8gICB9XG4gICAgLy8gfVxuICAgIC8vIGlmIChPYmplY3Qua2V5cyh2YXJpYWJsZVZhbHVlQnlOYW1lRXJyb3IpLmxlbmd0aCAhPT0gMCkge1xuICAgIC8vICAgZXJyb3IudmFyaWFibGVWYWx1ZUJ5TmFtZSA9IHZhcmlhYmxlVmFsdWVCeU5hbWVFcnJvclxuICAgIC8vIH1cblxuICAgIHJldHVybiBmb3JtdWxhXG4gIH1cblxuICB0cmFuc2Zvcm1fQXNzaWduKGFzc2lnbjogUHl0aG9uQXN0QXNzaWduKToge1xuICAgIGlucHV0OiBQeXRob25Bc3ROb2RlXG4gICAgb3V0cHV0OiBPcGVuZmlzY2FBc3ROb2RlXG4gICAgZXJyb3I/OiB1bmtub3duXG4gIH0ge1xuICAgIGNvbnN0IHRhcmdldHMgPSB0aGlzLnJlZHVjZU1hcEVycm9ycyhcbiAgICAgIGFzc2lnbi50YXJnZXRzLm1hcCgodGFyZ2V0KSA9PiB0aGlzLnRyYW5zZm9ybSh0YXJnZXQgYXMgUHl0aG9uQXN0Tm9kZSkpLFxuICAgIClcbiAgICBjb25zdCB2YWx1ZSA9IHRoaXMudHJhbnNmb3JtKGFzc2lnbi52YWx1ZSBhcyBQeXRob25Bc3ROb2RlKVxuICAgIGZvciAoY29uc3QgdGFyZ2V0IG9mIHRhcmdldHMub3V0cHV0KSB7XG4gICAgICBpZiAodGFyZ2V0LmFzdF9jbGFzcyA9PT0gXCJOYW1lXCIgJiYgdGFyZ2V0LmN0eC5hc3RfY2xhc3MgPT09IFwiU3RvcmVcIikge1xuICAgICAgICB0aGlzLnZhcmlhYmxlVmFsdWVCeU5hbWVbdGFyZ2V0LmlkXSA9IHZhbHVlXG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiB0aGlzLnJlZHVjZUVycm9yQnlLZXkoXG4gICAgICBhc3NpZ24sXG4gICAgICB7IC4uLmFzc2lnbiwgdGFyZ2V0czogdGFyZ2V0cy5vdXRwdXQsIHZhbHVlOiB2YWx1ZS5vdXRwdXQgfSxcbiAgICAgIHtcbiAgICAgICAgdGFyZ2V0czogdGFyZ2V0cy5lcnJvcixcbiAgICAgICAgdmFsdWU6IHZhbHVlLmVycm9yLFxuICAgICAgfSxcbiAgICApXG4gIH1cblxuICB0cmFuc2Zvcm1fQXR0cmlidXRlKGF0dHJpYnV0ZTogUHl0aG9uQXN0QXR0cmlidXRlKToge1xuICAgIGlucHV0OiBQeXRob25Bc3ROb2RlXG4gICAgb3V0cHV0OiBPcGVuZmlzY2FBc3ROb2RlXG4gICAgZXJyb3I/OiB1bmtub3duXG4gIH0ge1xuICAgIGNvbnN0IHZhbHVlID0gdGhpcy50cmFuc2Zvcm0oYXR0cmlidXRlLnZhbHVlIGFzIFB5dGhvbkFzdE5vZGUpXG4gICAgY29uc3QgeyBvdXRwdXQ6IHZhbHVlT3V0cHV0IH0gPSB2YWx1ZVxuICAgIHN3aXRjaCAodmFsdWVPdXRwdXQuYXN0X2NsYXNzKSB7XG4gICAgICBjYXNlIFwiZW50aXR5XCI6IHtcbiAgICAgICAgY29uc3QgZW50aXR5ID0gdGhpcy5lbnRpdHlCeUtleVt2YWx1ZU91dHB1dC5rZXldXG4gICAgICAgIGlmICghZW50aXR5LmlzX3BlcnNvbiAmJiBhdHRyaWJ1dGUuYXR0ciA9PT0gXCJtZW1iZXJzXCIpIHtcbiAgICAgICAgICByZXR1cm4gdGhpcy5yZWR1Y2VFcnJvckJ5S2V5KFxuICAgICAgICAgICAgYXR0cmlidXRlLFxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICBhc3RfY2xhc3M6IFwiZW50aXR5XCIsXG4gICAgICAgICAgICAgIGtleTogdGhpcy5wZXJzb25FbnRpdHlLZXksXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICB2YWx1ZTogdmFsdWUuZXJyb3IsXG4gICAgICAgICAgICB9LFxuICAgICAgICAgIClcbiAgICAgICAgfVxuICAgICAgICBicmVha1xuICAgICAgfVxuICAgICAgY2FzZSBcImluc3RhbnRfb3JfcGVyaW9kX2V4cHJlc3Npb25cIjoge1xuICAgICAgICByZXR1cm4gdGhpcy5yZWR1Y2VFcnJvckJ5S2V5KFxuICAgICAgICAgIGF0dHJpYnV0ZSxcbiAgICAgICAgICB7XG4gICAgICAgICAgICBhc3RfY2xhc3M6IFwiaW5zdGFudF9vcl9wZXJpb2RfZXhwcmVzc2lvblwiLFxuICAgICAgICAgICAgZXhwcmVzc2lvbjoge1xuICAgICAgICAgICAgICAuLi5hdHRyaWJ1dGUsXG4gICAgICAgICAgICAgIHZhbHVlOiB2YWx1ZU91dHB1dC5leHByZXNzaW9uLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICB9LFxuICAgICAgICAgIHtcbiAgICAgICAgICAgIHZhbHVlOiB2YWx1ZS5lcnJvcixcbiAgICAgICAgICB9LFxuICAgICAgICApXG4gICAgICB9XG4gICAgICBjYXNlIFwicGFyYW1ldGVyX2F0X2luc3RhbnRcIjoge1xuICAgICAgICBjb25zdCBpZHMgPSBbLi4udmFsdWVPdXRwdXQuaWRzLCBhdHRyaWJ1dGUuYXR0cl1cbiAgICAgICAgY29uc3QgWywgYXR0ckVycm9yXSA9IGFjY2Vzc1BhcmFtZXRlckZyb21JZHModGhpcy5yb290UGFyYW1ldGVyLCBpZHMpXG4gICAgICAgIGNvbnN0IHBhcmFtZXRlckF0SW5zdGFudCA9IHtcbiAgICAgICAgICAuLi52YWx1ZU91dHB1dCxcbiAgICAgICAgICBpZHMsXG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHRoaXMucmVkdWNlRXJyb3JCeUtleShhdHRyaWJ1dGUsIHBhcmFtZXRlckF0SW5zdGFudCwge1xuICAgICAgICAgIGF0dHI6IGF0dHJFcnJvcixcbiAgICAgICAgICB2YWx1ZTogdmFsdWUuZXJyb3IsXG4gICAgICAgIH0pXG4gICAgICB9XG4gICAgICBjYXNlIFwicGVyaW9kXCI6IHtcbiAgICAgICAgcmV0dXJuIHRoaXMucmVkdWNlRXJyb3JCeUtleShcbiAgICAgICAgICBhdHRyaWJ1dGUsXG4gICAgICAgICAge1xuICAgICAgICAgICAgYXN0X2NsYXNzOiBcImluc3RhbnRfb3JfcGVyaW9kX2V4cHJlc3Npb25cIixcbiAgICAgICAgICAgIGV4cHJlc3Npb246IHtcbiAgICAgICAgICAgICAgLi4uYXR0cmlidXRlLFxuICAgICAgICAgICAgICB2YWx1ZTogdmFsdWVPdXRwdXQsXG4gICAgICAgICAgICB9LFxuICAgICAgICAgIH0sXG4gICAgICAgICAge1xuICAgICAgICAgICAgdmFsdWU6IHZhbHVlLmVycm9yLFxuICAgICAgICAgIH0sXG4gICAgICAgIClcbiAgICAgIH1cbiAgICAgIGRlZmF1bHQ6XG4gICAgfVxuXG4gICAgcmV0dXJuIHRoaXMucmVkdWNlRXJyb3JCeUtleShcbiAgICAgIGF0dHJpYnV0ZSxcbiAgICAgIHsgLi4uYXR0cmlidXRlLCB2YWx1ZTogdmFsdWVPdXRwdXQgfSxcbiAgICAgIHtcbiAgICAgICAgdmFsdWU6IHZhbHVlLmVycm9yLFxuICAgICAgfSxcbiAgICApXG4gIH1cblxuICB0cmFuc2Zvcm1fQXVnQXNzaWduKGF1Z0Fzc2lnbjogUHl0aG9uQXN0QXVnQXNzaWduKToge1xuICAgIGlucHV0OiBQeXRob25Bc3ROb2RlXG4gICAgb3V0cHV0OiBPcGVuZmlzY2FBc3ROb2RlXG4gICAgZXJyb3I/OiB1bmtub3duXG4gIH0ge1xuICAgIC8vIFJlcGxhY2UgYXVnbWVudGVkIGFzc2lnbiAoKz0sIC89LCBldGMpIHdpdGggYSBub3JtYWwgYXNzaWduLlxuICAgIHJldHVybiB0aGlzLnRyYW5zZm9ybSh7XG4gICAgICBhc3RfY2xhc3M6IFwiQXNzaWduXCIsXG4gICAgICB0YXJnZXRzOiBbYXVnQXNzaWduLnRhcmdldF0sXG4gICAgICB2YWx1ZToge1xuICAgICAgICBhc3RfY2xhc3M6IFwiQmluT3BcIixcbiAgICAgICAgbGVmdDoge1xuICAgICAgICAgIC4uLmF1Z0Fzc2lnbi50YXJnZXQsXG4gICAgICAgICAgY3R4OiB7IGFzdF9jbGFzczogXCJMb2FkXCIgfSxcbiAgICAgICAgfSxcbiAgICAgICAgb3A6IGF1Z0Fzc2lnbi5vcCBhcyBQeXRob25Bc3RCaW5hcnlPcGVyYXRvcixcbiAgICAgICAgcmlnaHQ6IGF1Z0Fzc2lnbi52YWx1ZSxcbiAgICAgIH0sXG4gICAgfSlcbiAgfVxuXG4gIHRyYW5zZm9ybV9DYWxsKGNhbGw6IFB5dGhvbkFzdENhbGwpOiB7XG4gICAgaW5wdXQ6IFB5dGhvbkFzdE5vZGVcbiAgICBvdXRwdXQ6IE9wZW5maXNjYUFzdE5vZGVcbiAgICBlcnJvcj86IHVua25vd25cbiAgfSB7XG4gICAgY29uc3QgYXJncyA9IHRoaXMucmVkdWNlTWFwRXJyb3JzKFxuICAgICAgY2FsbC5hcmdzLm1hcCgoYXJnKSA9PiB0aGlzLnRyYW5zZm9ybShhcmcgYXMgUHl0aG9uQXN0Tm9kZSkpLFxuICAgIClcbiAgICBjb25zdCBmdW5jID0gdGhpcy50cmFuc2Zvcm0oY2FsbC5mdW5jIGFzIFB5dGhvbkFzdE5vZGUpXG4gICAgY29uc3QgeyBvdXRwdXQ6IGZ1bmNPdXRwdXQgfSA9IGZ1bmNcbiAgICBjb25zdCBrZXl3b3JkcyA9IHRoaXMucmVkdWNlTWFwRXJyb3JzKFxuICAgICAgY2FsbC5rZXl3b3Jkcy5tYXAoKGtleXdvcmQpID0+IHRoaXMudHJhbnNmb3JtKGtleXdvcmQgYXMgUHl0aG9uQXN0Tm9kZSkpLFxuICAgICkgYXMgeyBpbnB1dDogUHl0aG9uQXN0Tm9kZVtdOyBvdXRwdXQ6IFB5dGhvbkFzdEtleXdvcmRbXTsgZXJyb3I/OiB1bmtub3duIH1cblxuICAgIHN3aXRjaCAoZnVuY091dHB1dC5hc3RfY2xhc3MpIHtcbiAgICAgIGNhc2UgXCJlbnRpdHlcIjoge1xuICAgICAgICBjb25zdCBbdmFyaWFibGVOYW1lT3V0cHV0LCBwZXJpb2RPdXRwdXQsIG9wZXJhdGlvbk91dHB1dF0gPSBhcmdzLm91dHB1dFxuICAgICAgICBpZiAodmFyaWFibGVOYW1lT3V0cHV0LmFzdF9jbGFzcyA9PT0gXCJDb25zdGFudFwiKSB7XG4gICAgICAgICAgY29uc3QgdmFyaWFibGVOYW1lID0gdmFyaWFibGVOYW1lT3V0cHV0LnZhbHVlIGFzIHN0cmluZ1xuICAgICAgICAgIGxldCBjb2cgPSB0aGlzLmNvZ0J5TmFtZVt2YXJpYWJsZU5hbWVdXG4gICAgICAgICAgaWYgKGNvZyA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICBjb25zdCB2YXJpYWJsZVN1bW1hcnkgPSB0aGlzLnZhcmlhYmxlU3VtbWFyeUJ5TmFtZVt2YXJpYWJsZU5hbWVdXG4gICAgICAgICAgICBjb2cgPSB0aGlzLmNvZ0J5TmFtZVt2YXJpYWJsZU5hbWVdID0ge1xuICAgICAgICAgICAgICBhc3RfY2xhc3M6IFwiY29nXCIsXG4gICAgICAgICAgICAgIGVudGl0eTogdGhpcy5lbnRpdHlCeUtleVt2YXJpYWJsZVN1bW1hcnkuZW50aXR5XSxcbiAgICAgICAgICAgICAgbmFtZTogdmFyaWFibGVOYW1lLFxuICAgICAgICAgICAgICBwZXJpb2RVbml0OiB2YXJpYWJsZVN1bW1hcnkuZGVmaW5pdGlvbl9wZXJpb2QsXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICAgIGNvbnN0IGNvZ0NhbGw6IE9wZW5maXNjYUFzdENvZ0NhbGwgPSB7XG4gICAgICAgICAgICBhc3RfY2xhc3M6IFwiY29nX2NhbGxcIixcbiAgICAgICAgICAgIGNvZyxcbiAgICAgICAgICAgIHBlcmlvZDogcGVyaW9kT3V0cHV0IGFzXG4gICAgICAgICAgICAgIHwgT3BlbmZpc2NhQXN0SW5zdGFudE9yUGVyaW9kRXhwcmVzc2lvblxuICAgICAgICAgICAgICB8IE9wZW5maXNjYUFzdFBlcmlvZCxcbiAgICAgICAgICB9XG4gICAgICAgICAgaWYgKG9wZXJhdGlvbk91dHB1dCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICBpZiAoY29nLnBlcmlvZFVuaXQgIT09IHRoaXMudmFyaWFibGUuZGVmaW5pdGlvbl9wZXJpb2QpIHtcbiAgICAgICAgICAgICAgaWYgKFxuICAgICAgICAgICAgICAgIChcbiAgICAgICAgICAgICAgICAgIGFyZ3MuZXJyb3IgYXMgeyBbaW5kZXg6IG51bWJlcl06IHVua25vd24gfSB8IHVuZGVmaW5lZFxuICAgICAgICAgICAgICAgICk/LlsyXSA9PT0gdW5kZWZpbmVkXG4gICAgICAgICAgICAgICkge1xuICAgICAgICAgICAgICAgIC8vIEFkZCBhbiBlcnJvciBpZiBvbmUgZG9lc24ndCBleGlzdCB5ZXQuXG4gICAgICAgICAgICAgICAgaWYgKGFyZ3MuZXJyb3IgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgICAgICAgYXJncy5lcnJvciA9IHt9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIDsoYXJncy5lcnJvciBhcyB7IFtpbmRleDogbnVtYmVyXTogdW5rbm93biB9KVsyXSA9XG4gICAgICAgICAgICAgICAgICBgTWlzc2luZyBvcGVyYXRpb24gaW4gY29nIGNhbGwgdG8gY29udmVydCByZXN1bHQgZnJvbSAke2NvZy5wZXJpb2RVbml0fSB0byAke3RoaXMudmFyaWFibGUuZGVmaW5pdGlvbl9wZXJpb2R9YFxuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSBlbHNlIGlmIChcbiAgICAgICAgICAgIG9wZXJhdGlvbk91dHB1dC5hc3RfY2xhc3MgPT09IFwiQ29uc3RhbnRcIiAmJlxuICAgICAgICAgICAgW1wiQUREXCIsIFwiRElWSURFXCJdLmluY2x1ZGVzKG9wZXJhdGlvbk91dHB1dC52YWx1ZSBhcyBzdHJpbmcpXG4gICAgICAgICAgKSB7XG4gICAgICAgICAgICBjb2dDYWxsLm9wZXJhdGlvbiA9XG4gICAgICAgICAgICAgIG9wZXJhdGlvbk91dHB1dC52YWx1ZSBhcyBPcGVuZmlzY2FBc3RDb2dDYWxsT3BlcmF0aW9uXG4gICAgICAgICAgfSBlbHNlIGlmIChcbiAgICAgICAgICAgIChhcmdzLmVycm9yIGFzIHsgW2luZGV4OiBudW1iZXJdOiB1bmtub3duIH0gfCB1bmRlZmluZWQpPy5bMl0gPT09XG4gICAgICAgICAgICB1bmRlZmluZWRcbiAgICAgICAgICApIHtcbiAgICAgICAgICAgIC8vIFVuZXhwZWN0ZWQgb3BlcmF0aW9uIGZvciBjb2cgY2FsbFxuICAgICAgICAgICAgLy8gPT4gQWRkIGFuIGVycm9yIGlmIG9uZSBkb2Vzbid0IGV4aXN0IHlldC5cbiAgICAgICAgICAgIGlmIChhcmdzLmVycm9yID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgICAgYXJncy5lcnJvciA9IHt9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICA7KGFyZ3MuZXJyb3IgYXMgeyBbaW5kZXg6IG51bWJlcl06IHVua25vd24gfSlbMl0gPVxuICAgICAgICAgICAgICBcIlVuZXhwZWN0ZWQgb3BlcmF0aW9uIGZvciBjb2cgY2FsbFwiXG4gICAgICAgICAgfVxuICAgICAgICAgIHJldHVybiB0aGlzLnJlZHVjZUVycm9yQnlLZXkoY2FsbCwgY29nQ2FsbCwge1xuICAgICAgICAgICAgYXJnczogYXJncy5lcnJvcixcbiAgICAgICAgICAgIGZ1bmM6IGZ1bmMuZXJyb3IsXG4gICAgICAgICAgICBrZXl3b3Jkczoga2V5d29yZHMuZXJyb3IsXG4gICAgICAgICAgfSlcbiAgICAgICAgfVxuICAgICAgICBicmVha1xuICAgICAgfVxuICAgICAgY2FzZSBcImluc3RhbnRfb3JfcGVyaW9kX2V4cHJlc3Npb25cIjoge1xuICAgICAgICByZXR1cm4gdGhpcy5yZWR1Y2VFcnJvckJ5S2V5KFxuICAgICAgICAgIGNhbGwsXG4gICAgICAgICAge1xuICAgICAgICAgICAgYXN0X2NsYXNzOiBcImluc3RhbnRfb3JfcGVyaW9kX2V4cHJlc3Npb25cIixcbiAgICAgICAgICAgIGV4cHJlc3Npb246IHtcbiAgICAgICAgICAgICAgLi4uY2FsbCxcbiAgICAgICAgICAgICAgZnVuYzogZnVuY091dHB1dC5leHByZXNzaW9uLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICB9LFxuICAgICAgICAgIHtcbiAgICAgICAgICAgIGFyZ3M6IGFyZ3MuZXJyb3IsXG4gICAgICAgICAgICBmdW5jOiBmdW5jLmVycm9yLFxuICAgICAgICAgICAga2V5d29yZHM6IGtleXdvcmRzLmVycm9yLFxuICAgICAgICAgIH0sXG4gICAgICAgIClcbiAgICAgIH1cbiAgICAgIGNhc2UgXCJwYXJhbWV0ZXJcIjoge1xuICAgICAgICBjb25zdCBbaW5zdGFudE91dHB1dF0gPSBhcmdzLm91dHB1dFxuICAgICAgICByZXR1cm4gdGhpcy5yZWR1Y2VFcnJvckJ5S2V5KFxuICAgICAgICAgIGNhbGwsXG4gICAgICAgICAge1xuICAgICAgICAgICAgYXN0X2NsYXNzOiBcInBhcmFtZXRlcl9hdF9pbnN0YW50XCIsXG4gICAgICAgICAgICBpZHM6IGZ1bmNPdXRwdXQuaWRzLFxuICAgICAgICAgICAgaW5zdGFudDogaW5zdGFudE91dHB1dCxcbiAgICAgICAgICB9LFxuICAgICAgICAgIHtcbiAgICAgICAgICAgIGFyZ3M6IGFyZ3MuZXJyb3IsXG4gICAgICAgICAgICBmdW5jOiBmdW5jLmVycm9yLFxuICAgICAgICAgICAga2V5d29yZHM6IGtleXdvcmRzLmVycm9yLFxuICAgICAgICAgIH0sXG4gICAgICAgIClcbiAgICAgIH1cbiAgICAgIGRlZmF1bHQ6XG4gICAgfVxuXG4gICAgcmV0dXJuIHRoaXMucmVkdWNlRXJyb3JCeUtleShcbiAgICAgIGNhbGwsXG4gICAgICB7XG4gICAgICAgIC4uLmNhbGwsXG4gICAgICAgIGFyZ3M6IGFyZ3Mub3V0cHV0LFxuICAgICAgICBmdW5jOiBmdW5jLm91dHB1dCxcbiAgICAgICAga2V5d29yZHM6IGtleXdvcmRzLm91dHB1dCxcbiAgICAgIH0sXG4gICAgICB7XG4gICAgICAgIGFyZ3M6IGFyZ3MuZXJyb3IsXG4gICAgICAgIGZ1bmM6IGZ1bmMuZXJyb3IsXG4gICAgICAgIGtleXdvcmRzOiBrZXl3b3Jkcy5lcnJvcixcbiAgICAgIH0sXG4gICAgKVxuICB9XG5cbiAgdHJhbnNmb3JtX05hbWUobmFtZTogUHl0aG9uQXN0TmFtZSk6IHtcbiAgICBpbnB1dDogUHl0aG9uQXN0Tm9kZVxuICAgIG91dHB1dDogT3BlbmZpc2NhQXN0Tm9kZVxuICAgIGVycm9yPzogdW5rbm93blxuICB9IHtcbiAgICBpZiAobmFtZS5jdHguYXN0X2NsYXNzID09PSBcIkxvYWRcIikge1xuICAgICAgY29uc3QgdmFyaWFibGVWYWx1ZSA9XG4gICAgICAgIHRoaXMudmFyaWFibGVWYWx1ZUJ5TmFtZVtuYW1lLmlkXSA/P1xuICAgICAgICB0aGlzLmdsb2JhbFZhcmlhYmxlVmFsdWVCeU5hbWVbbmFtZS5pZF1cbiAgICAgIHJldHVybiB2YXJpYWJsZVZhbHVlID09PSB1bmRlZmluZWRcbiAgICAgICAgPyB7XG4gICAgICAgICAgICBpbnB1dDogbmFtZSxcbiAgICAgICAgICAgIG91dHB1dDogbmFtZSxcbiAgICAgICAgICAgIGVycm9yOiB7IGlkOiBgVW5kZWZpbmVkIHZhcmlhYmxlOiAke25hbWUuaWR9YCB9LFxuICAgICAgICAgIH1cbiAgICAgICAgOiB2YXJpYWJsZVZhbHVlXG4gICAgfVxuICAgIHJldHVybiB7IGlucHV0OiBuYW1lLCBvdXRwdXQ6IG5hbWUgfVxuICB9XG5cbiAgdHJhbnNmb3JtX1JldHVybihyZXR1cm5Ob2RlOiBQeXRob25Bc3RSZXR1cm4pOiB7XG4gICAgaW5wdXQ6IFB5dGhvbkFzdE5vZGVcbiAgICBvdXRwdXQ6IE9wZW5maXNjYUFzdE5vZGVcbiAgICBlcnJvcj86IHVua25vd25cbiAgfSB7XG4gICAgY29uc3QgdmFsdWUgPVxuICAgICAgcmV0dXJuTm9kZS52YWx1ZSA9PT0gdW5kZWZpbmVkXG4gICAgICAgID8ge1xuICAgICAgICAgICAgaW5wdXQ6IHtcbiAgICAgICAgICAgICAgLy8gRHVtbXkgaW5wdXRcbiAgICAgICAgICAgICAgYXN0X2NsYXNzOiBcIkNvbnN0YW50XCIsXG4gICAgICAgICAgICAgIC8vIHZhbHVlOiB1bmRlZmluZWQsXG4gICAgICAgICAgICB9IGFzIFB5dGhvbkFzdENvbnN0YW50LFxuICAgICAgICAgICAgb3V0cHV0OiB7XG4gICAgICAgICAgICAgIGFzdF9jbGFzczogXCJDb25zdGFudFwiLFxuICAgICAgICAgICAgICAvLyB2YWx1ZTogdW5kZWZpbmVkXG4gICAgICAgICAgICB9IGFzIFB5dGhvbkFzdENvbnN0YW50LFxuICAgICAgICAgICAgZXJyb3I6IFwiTWlzc2luZyByZXR1cm4gdmFsdWVcIixcbiAgICAgICAgICB9XG4gICAgICAgIDogdGhpcy50cmFuc2Zvcm0ocmV0dXJuTm9kZS52YWx1ZSBhcyBQeXRob25Bc3ROb2RlKVxuICAgIHRoaXMucmV0dXJuQ291bnQrK1xuICAgIHRoaXMucmV0dXJuVmFsdWUgPSB2YWx1ZVxuICAgIHJldHVybiB0aGlzLnJlZHVjZUVycm9yQnlLZXkoXG4gICAgICByZXR1cm5Ob2RlLFxuICAgICAgeyAuLi5yZXR1cm5Ob2RlLCB2YWx1ZTogdmFsdWUub3V0cHV0IH0sXG4gICAgICB7IHZhbHVlOiB2YWx1ZS5lcnJvciB9LFxuICAgIClcbiAgfVxuXG4gIHRyYW5zZm9ybV9TdWJzY3JpcHQoc3Vic2NyaXB0OiBQeXRob25Bc3RTdWJzY3JpcHQpOiB7XG4gICAgaW5wdXQ6IFB5dGhvbkFzdE5vZGVcbiAgICBvdXRwdXQ6IE9wZW5maXNjYUFzdE5vZGVcbiAgICBlcnJvcj86IHVua25vd25cbiAgfSB7XG4gICAgY29uc3Qgc2xpY2UgPSB0aGlzLnRyYW5zZm9ybShzdWJzY3JpcHQuc2xpY2UgYXMgUHl0aG9uQXN0Tm9kZSlcbiAgICBjb25zdCB2YWx1ZSA9IHRoaXMudHJhbnNmb3JtKHN1YnNjcmlwdC52YWx1ZSBhcyBQeXRob25Bc3ROb2RlKVxuICAgIHJldHVybiB0aGlzLnJlZHVjZUVycm9yQnlLZXkoXG4gICAgICBzdWJzY3JpcHQsXG4gICAgICB7IC4uLnN1YnNjcmlwdCwgc2xpY2U6IHNsaWNlLm91dHB1dCwgdmFsdWU6IHZhbHVlLm91dHB1dCB9LFxuICAgICAge1xuICAgICAgICBzbGljZTogc2xpY2UuZXJyb3IsXG4gICAgICAgIHZhbHVlOiB2YWx1ZS5lcnJvcixcbiAgICAgIH0sXG4gICAgKVxuICB9XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBvcGVuZmlzY2FBc3RGcm9tRm9ybXVsYVB5dGhvbkFzdChcbiAgdmFyaWFibGU6IFZhcmlhYmxlLFxuICBmdW5jdGlvbkRlZjogUHl0aG9uQXN0RnVuY3Rpb25EZWYsXG4gIGVudGl0eUJ5S2V5OiBFbnRpdHlCeUtleSxcbiAgcm9vdFBhcmFtZXRlcjogTm9kZVBhcmFtZXRlcixcbiAgdmFyaWFibGVTdW1tYXJ5QnlOYW1lOiB7IFtuYW1lOiBzdHJpbmddOiBWYXJpYWJsZSB9LFxuKTogT3BlbmZpc2NhQXN0Rm9ybXVsYSB7XG4gIGNvbnN0IG9wZW5maXNjYUFzdEZvcm11bGFCdWlsZGVyID0gbmV3IE9wZW5maXNjYUFzdEZvcm11bGFCdWlsZGVyKFxuICAgIHZhcmlhYmxlLFxuICAgIGZ1bmN0aW9uRGVmLFxuICAgIGVudGl0eUJ5S2V5LFxuICAgIHJvb3RQYXJhbWV0ZXIsXG4gICAgdmFyaWFibGVTdW1tYXJ5QnlOYW1lLFxuICApXG4gIHJldHVybiBvcGVuZmlzY2FBc3RGb3JtdWxhQnVpbGRlci5ydW4oZnVuY3Rpb25EZWYpXG59XG4iXSwibWFwcGluZ3MiOiJTQUNTQSxzQkFBc0I7QUFBQSxTQXdCdEJDLGNBQWMseUJBRXZCO0FBQ0EsT0FBTyxNQUFNQywwQkFBMEIsU0FBU0QsY0FBYyxDQUc1RDtFQUNnQkUsU0FBUyxHQUF3QyxDQUFDLENBQUM7RUFDbkRDLHlCQUF5QixHQU1yQztJQUNGQyxHQUFHLEVBQUU7TUFDSEMsS0FBSyxFQUFFO1FBQ0w7UUFDQUMsU0FBUyxFQUFFLE1BQU07UUFDakJDLEdBQUcsRUFBRTtVQUFFRCxTQUFTLEVBQUU7UUFBTyxDQUFDO1FBQzFCRSxFQUFFLEVBQUU7TUFDTixDQUFDO01BQ0RDLE1BQU0sRUFBRTtRQUFFSCxTQUFTLEVBQUUsVUFBVTtRQUFFSSxJQUFJLEVBQUU7TUFBTTtJQUMvQyxDQUFDO0lBQ0RDLE9BQU8sRUFBRTtNQUNQTixLQUFLLEVBQUU7UUFDTDtRQUNBQyxTQUFTLEVBQUUsTUFBTTtRQUNqQkMsR0FBRyxFQUFFO1VBQUVELFNBQVMsRUFBRTtRQUFPLENBQUM7UUFDMUJFLEVBQUUsRUFBRTtNQUNOLENBQUM7TUFDREMsTUFBTSxFQUFFO1FBQUVILFNBQVMsRUFBRSxVQUFVO1FBQUVJLElBQUksRUFBRTtNQUFVO0lBQ25ELENBQUM7SUFDREUsV0FBVyxFQUFFO01BQ1hQLEtBQUssRUFBRTtRQUNMO1FBQ0FDLFNBQVMsRUFBRSxNQUFNO1FBQ2pCQyxHQUFHLEVBQUU7VUFBRUQsU0FBUyxFQUFFO1FBQU8sQ0FBQztRQUMxQkUsRUFBRSxFQUFFO01BQ04sQ0FBQztNQUNEQyxNQUFNLEVBQUU7UUFBRUgsU0FBUyxFQUFFLFVBQVU7UUFBRUksSUFBSSxFQUFFO01BQWM7SUFDdkQsQ0FBQztJQUNERyxJQUFJLEVBQUU7TUFDSlIsS0FBSyxFQUFFO1FBQ0w7UUFDQUMsU0FBUyxF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