@openfisca/json-model
Version:
Library to handle informations extracted in JSON or YAML format from OpenFisca parameters, variables, etc
158 lines (155 loc) • 30.7 kB
JavaScript
import { auditArray, auditBoolean, auditChain, auditCleanArray, auditDateIso8601String, auditFunction, auditKeyValueDictionary, auditOptions, auditRequire, auditString, auditSwitch, auditTrimString, auditUnique } from "@auditors/core";
import { auditReferencesByDate } from "./references.js";
const auditCustomization = parametersNames => (audit, dataUnknown) => {
if (dataUnknown == null) {
return [dataUnknown, null];
}
if (typeof dataUnknown !== "object") {
return audit.unexpectedType(dataUnknown, "object");
}
const data = {
...dataUnknown
};
const errors = {};
const remainingKeys = new Set(Object.keys(data));
auditDecompositionCoreContent(audit, data, errors, remainingKeys);
audit.attribute(data, "input", true, errors, remainingKeys, auditBoolean, auditFunction(value => value || undefined) // Delete false.
);
audit.attribute(data, "linked_other_variables", true, errors, remainingKeys, auditCleanArray(auditTrimString), auditUnique);
audit.attribute(data, "main_parameters", true, errors, remainingKeys, auditCleanArray(auditTrimString, auditOptions(parametersNames)), auditUnique);
audit.attribute(data, "variables", true, errors, remainingKeys, auditCleanArray(auditTrimString), auditUnique);
return audit.reduceRemaining(data, errors, remainingKeys);
};
export const auditCustomizationByName = parametersNames => auditKeyValueDictionary(auditTrimString, [auditCustomization(parametersNames), auditRequire]);
export function auditDecomposition(audit, dataUnknown) {
if (dataUnknown == null) {
return [dataUnknown, null];
}
if (typeof dataUnknown !== "object") {
return audit.unexpectedType(dataUnknown, "object");
}
const data = {
...dataUnknown
};
const errors = {};
const remainingKeys = new Set(Object.keys(data));
auditDecompositionCoreContent(audit, data, errors, remainingKeys);
audit.attribute(data, "label", true, errors, remainingKeys, auditRequire);
return audit.reduceRemaining(data, errors, remainingKeys);
}
export const auditDecompositionByName = auditKeyValueDictionary(auditTrimString, [auditDecomposition, auditRequire]);
function auditDecompositionCoreContent(audit, data, errors, remainingKeys) {
audit.attribute(data, "children", false,
// Don't delete nullish children (nullish means null after a JSON.parse).
errors, remainingKeys, auditCleanArray(auditDecompositionReference));
audit.attribute(data, "description", true, errors, remainingKeys, auditReferencesByDate);
// Note: `"hidden": false` is not the same as `undefined`.
audit.attribute(data, "hidden", true, errors, remainingKeys, auditBoolean);
for (const key of ["label", "short_label"]) {
audit.attribute(data, key, true, errors, remainingKeys, auditTrimString);
}
audit.attribute(data, "last_value_still_valid_on", true, errors, remainingKeys, auditDateIso8601String);
for (const key of ["obsolete", "virtual"]) {
audit.attribute(data, key, true, errors, remainingKeys, auditBoolean, auditFunction(value => value || undefined) // Delete false.
);
}
audit.attribute(data, "options", true, errors, remainingKeys, auditSwitch([auditArray(), auditCleanArray(auditDecompositionOptions)], [auditDecompositionOptions, auditFunction(options => [options])]));
audit.attribute(data, "reference", true, errors, remainingKeys, auditReferencesByDate);
}
export function auditDecompositionOptions(audit, dataUnknown) {
if (dataUnknown == null) {
return [dataUnknown, null];
}
if (typeof dataUnknown !== "object") {
return audit.unexpectedType(dataUnknown, "object");
}
const data = {
...dataUnknown
};
const errors = {};
const remainingKeys = new Set(Object.keys(data));
audit.attribute(data, "waterfall", true, errors, remainingKeys, auditSwitch([auditArray(), auditCleanArray(auditTrimString), auditUnique], [auditTrimString, auditFunction(name => [name])])
// TODO: Test existence of waterfall names.
);
if (errors.waterfall === undefined) {
if (data.waterfall === undefined) {
// Variables options
for (const key of ["else", "then"]) {
audit.attribute(data, key, true, errors, remainingKeys, auditVariablesCustomization);
}
for (const variableName of remainingKeys) {
const [validVariableName, variableNameError] = auditChain(auditTrimString,
// TODO: Test existence of variable name.
auditRequire)(audit, variableName);
if (variableNameError === null) {
audit.attribute(data, variableName, true, errors, remainingKeys, auditSwitch([auditArray(auditBoolean), auditCleanArray(auditBoolean), auditUnique], [auditArray(auditString), auditCleanArray(auditTrimString), auditUnique], [auditBoolean, auditFunction(value => [value])], [auditTrimString, auditFunction(value => [value])]),
// TODO: Test existence of variable value.
auditRequire);
if (errors[variableName] === undefined && validVariableName !== variableName) {
data[validVariableName] = data[variableName];
delete data[variableName];
}
}
}
} else {
// Waterfall options
for (const key of ["else", "then"]) {
audit.attribute(data, key, true, errors, remainingKeys, auditWaterfallCustomization);
}
}
}
return audit.reduceRemaining(data, errors, remainingKeys);
}
export function auditDecompositionReference(audit, dataUnknown) {
if (dataUnknown == null) {
return [dataUnknown, null];
}
if (typeof dataUnknown !== "object") {
return audit.unexpectedType(dataUnknown, "object");
}
const data = {
...dataUnknown
};
const errors = {};
const remainingKeys = new Set(Object.keys(data));
audit.attribute(data, "name", true, errors, remainingKeys, auditTrimString, auditRequire);
audit.attribute(data, "negate", true, errors, remainingKeys, auditBoolean, auditFunction(value => value || undefined) // Replace false with undefined.
);
return audit.reduceRemaining(data, errors, remainingKeys);
}
export function auditVariablesCustomization(audit, dataUnknown) {
if (dataUnknown == null) {
return [dataUnknown, null];
}
if (typeof dataUnknown !== "object") {
return audit.unexpectedType(dataUnknown, "object");
}
const data = {
...dataUnknown
};
const errors = {};
const remainingKeys = new Set(Object.keys(data));
// Note: `"hidden": false` is not the same as `undefined`.
audit.attribute(data, "hidden", true, errors, remainingKeys, auditBoolean);
return audit.reduceRemaining(data, errors, remainingKeys);
}
export function auditWaterfallCustomization(audit, dataUnknown) {
if (dataUnknown == null) {
return [dataUnknown, null];
}
if (typeof dataUnknown !== "object") {
return audit.unexpectedType(dataUnknown, "object");
}
const data = {
...dataUnknown
};
const errors = {};
const remainingKeys = new Set(Object.keys(data));
audit.attribute(data, "children", false,
// Don't delete nullish children (nullish means null after a JSON.parse).
errors, remainingKeys, auditCleanArray(auditDecompositionReference));
// Note: `"hidden": false` is not the same as `undefined`.
audit.attribute(data, "hidden", true, errors, remainingKeys, auditBoolean);
return audit.reduceRemaining(data, errors, remainingKeys);
}
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJhdWRpdEFycmF5IiwiYXVkaXRCb29sZWFuIiwiYXVkaXRDaGFpbiIsImF1ZGl0Q2xlYW5BcnJheSIsImF1ZGl0RGF0ZUlzbzg2MDFTdHJpbmciLCJhdWRpdEZ1bmN0aW9uIiwiYXVkaXRLZXlWYWx1ZURpY3Rpb25hcnkiLCJhdWRpdE9wdGlvbnMiLCJhdWRpdFJlcXVpcmUiLCJhdWRpdFN0cmluZyIsImF1ZGl0U3dpdGNoIiwiYXVkaXRUcmltU3RyaW5nIiwiYXVkaXRVbmlxdWUiLCJhdWRpdFJlZmVyZW5jZXNCeURhdGUiLCJhdWRpdEN1c3RvbWl6YXRpb24iLCJwYXJhbWV0ZXJzTmFtZXMiLCJhdWRpdCIsImRhdGFVbmtub3duIiwidW5leHBlY3RlZFR5cGUiLCJkYXRhIiwiZXJyb3JzIiwicmVtYWluaW5nS2V5cyIsIlNldCIsIk9iamVjdCIsImtleXMiLCJhdWRpdERlY29tcG9zaXRpb25Db3JlQ29udGVudCIsImF0dHJpYnV0ZSIsInZhbHVlIiwidW5kZWZpbmVkIiwicmVkdWNlUmVtYWluaW5nIiwiYXVkaXRDdXN0b21pemF0aW9uQnlOYW1lIiwiYXVkaXREZWNvbXBvc2l0aW9uIiwiYXVkaXREZWNvbXBvc2l0aW9uQnlOYW1lIiwiYXVkaXREZWNvbXBvc2l0aW9uUmVmZXJlbmNlIiwia2V5IiwiYXVkaXREZWNvbXBvc2l0aW9uT3B0aW9ucyIsIm9wdGlvbnMiLCJuYW1lIiwid2F0ZXJmYWxsIiwiYXVkaXRWYXJpYWJsZXNDdXN0b21pemF0aW9uIiwidmFyaWFibGVOYW1lIiwidmFsaWRWYXJpYWJsZU5hbWUiLCJ2YXJpYWJsZU5hbWVFcnJvciIsImF1ZGl0V2F0ZXJmYWxsQ3VzdG9taXphdGlvbiJdLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9hdWRpdG9ycy9kZWNvbXBvc2l0aW9ucy50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgdHlwZSB7IEF1ZGl0LCBBdWRpdG9yIH0gZnJvbSBcIkBhdWRpdG9ycy9jb3JlXCJcbmltcG9ydCB7XG4gIGF1ZGl0QXJyYXksXG4gIGF1ZGl0Qm9vbGVhbixcbiAgYXVkaXRDaGFpbixcbiAgYXVkaXRDbGVhbkFycmF5LFxuICBhdWRpdERhdGVJc284NjAxU3RyaW5nLFxuICBhdWRpdEZ1bmN0aW9uLFxuICBhdWRpdEtleVZhbHVlRGljdGlvbmFyeSxcbiAgYXVkaXRPcHRpb25zLFxuICBhdWRpdFJlcXVpcmUsXG4gIGF1ZGl0U3RyaW5nLFxuICBhdWRpdFN3aXRjaCxcbiAgYXVkaXRUcmltU3RyaW5nLFxuICBhdWRpdFVuaXF1ZSxcbn0gZnJvbSBcIkBhdWRpdG9ycy9jb3JlXCJcblxuaW1wb3J0IHsgYXVkaXRSZWZlcmVuY2VzQnlEYXRlIH0gZnJvbSBcIi4vcmVmZXJlbmNlc1wiXG5cbmNvbnN0IGF1ZGl0Q3VzdG9taXphdGlvbiA9XG4gIChwYXJhbWV0ZXJzTmFtZXM6IHN0cmluZ1tdKTogQXVkaXRvciA9PlxuICAoYXVkaXQ6IEF1ZGl0LCBkYXRhVW5rbm93bjogdW5rbm93bik6IFt1bmtub3duLCB1bmtub3duXSA9PiB7XG4gICAgaWYgKGRhdGFVbmtub3duID09IG51bGwpIHtcbiAgICAgIHJldHVybiBbZGF0YVVua25vd24sIG51bGxdXG4gICAgfVxuICAgIGlmICh0eXBlb2YgZGF0YVVua25vd24gIT09IFwib2JqZWN0XCIpIHtcbiAgICAgIHJldHVybiBhdWRpdC51bmV4cGVjdGVkVHlwZShkYXRhVW5rbm93biwgXCJvYmplY3RcIilcbiAgICB9XG5cbiAgICBjb25zdCBkYXRhOiB7IFtrZXk6IHN0cmluZ106IHVua25vd24gfSA9IHsgLi4uZGF0YVVua25vd24gfVxuICAgIGNvbnN0IGVycm9yczogeyBba2V5OiBzdHJpbmddOiB1bmtub3duIH0gPSB7fVxuICAgIGNvbnN0IHJlbWFpbmluZ0tleXMgPSBuZXcgU2V0KE9iamVjdC5rZXlzKGRhdGEpKVxuXG4gICAgYXVkaXREZWNvbXBvc2l0aW9uQ29yZUNvbnRlbnQoYXVkaXQsIGRhdGEsIGVycm9ycywgcmVtYWluaW5nS2V5cylcblxuICAgIGF1ZGl0LmF0dHJpYnV0ZShcbiAgICAgIGRhdGEsXG4gICAgICBcImlucHV0XCIsXG4gICAgICB0cnVlLFxuICAgICAgZXJyb3JzLFxuICAgICAgcmVtYWluaW5nS2V5cyxcbiAgICAgIGF1ZGl0Qm9vbGVhbixcbiAgICAgIGF1ZGl0RnVuY3Rpb24oKHZhbHVlKSA9PiB2YWx1ZSB8fCB1bmRlZmluZWQpLCAvLyBEZWxldGUgZmFsc2UuXG4gICAgKVxuICAgIGF1ZGl0LmF0dHJpYnV0ZShcbiAgICAgIGRhdGEsXG4gICAgICBcImxpbmtlZF9vdGhlcl92YXJpYWJsZXNcIixcbiAgICAgIHRydWUsXG4gICAgICBlcnJvcnMsXG4gICAgICByZW1haW5pbmdLZXlzLFxuICAgICAgYXVkaXRDbGVhbkFycmF5KGF1ZGl0VHJpbVN0cmluZyksXG4gICAgICBhdWRpdFVuaXF1ZSxcbiAgICApXG4gICAgYXVkaXQuYXR0cmlidXRlKFxuICAgICAgZGF0YSxcbiAgICAgIFwibWFpbl9wYXJhbWV0ZXJzXCIsXG4gICAgICB0cnVlLFxuICAgICAgZXJyb3JzLFxuICAgICAgcmVtYWluaW5nS2V5cyxcbiAgICAgIGF1ZGl0Q2xlYW5BcnJheShhdWRpdFRyaW1TdHJpbmcsIGF1ZGl0T3B0aW9ucyhwYXJhbWV0ZXJzTmFtZXMpKSxcbiAgICAgIGF1ZGl0VW5pcXVlLFxuICAgIClcbiAgICBhdWRpdC5hdHRyaWJ1dGUoXG4gICAgICBkYXRhLFxuICAgICAgXCJ2YXJpYWJsZXNcIixcbiAgICAgIHRydWUsXG4gICAgICBlcnJvcnMsXG4gICAgICByZW1haW5pbmdLZXlzLFxuICAgICAgYXVkaXRDbGVhbkFycmF5KGF1ZGl0VHJpbVN0cmluZyksXG4gICAgICBhdWRpdFVuaXF1ZSxcbiAgICApXG5cbiAgICByZXR1cm4gYXVkaXQucmVkdWNlUmVtYWluaW5nKGRhdGEsIGVycm9ycywgcmVtYWluaW5nS2V5cylcbiAgfVxuXG5leHBvcnQgY29uc3QgYXVkaXRDdXN0b21pemF0aW9uQnlOYW1lID0gKHBhcmFtZXRlcnNOYW1lczogc3RyaW5nW10pID0+XG4gIGF1ZGl0S2V5VmFsdWVEaWN0aW9uYXJ5KGF1ZGl0VHJpbVN0cmluZywgW1xuICAgIGF1ZGl0Q3VzdG9taXphdGlvbihwYXJhbWV0ZXJzTmFtZXMpLFxuICAgIGF1ZGl0UmVxdWlyZSxcbiAgXSlcblxuZXhwb3J0IGZ1bmN0aW9uIGF1ZGl0RGVjb21wb3NpdGlvbihcbiAgYXVkaXQ6IEF1ZGl0LFxuICBkYXRhVW5rbm93bjogdW5rbm93bixcbik6IFt1bmtub3duLCB1bmtub3duXSB7XG4gIGlmIChkYXRhVW5rbm93biA9PSBudWxsKSB7XG4gICAgcmV0dXJuIFtkYXRhVW5rbm93biwgbnVsbF1cbiAgfVxuICBpZiAodHlwZW9mIGRhdGFVbmtub3duICE9PSBcIm9iamVjdFwiKSB7XG4gICAgcmV0dXJuIGF1ZGl0LnVuZXhwZWN0ZWRUeXBlKGRhdGFVbmtub3duLCBcIm9iamVjdFwiKVxuICB9XG5cbiAgY29uc3QgZGF0YTogeyBba2V5OiBzdHJpbmddOiB1bmtub3duIH0gPSB7IC4uLmRhdGFVbmtub3duIH1cbiAgY29uc3QgZXJyb3JzOiB7IFtrZXk6IHN0cmluZ106IHVua25vd24gfSA9IHt9XG4gIGNvbnN0IHJlbWFpbmluZ0tleXMgPSBuZXcgU2V0KE9iamVjdC5rZXlzKGRhdGEpKVxuXG4gIGF1ZGl0RGVjb21wb3NpdGlvbkNvcmVDb250ZW50KGF1ZGl0LCBkYXRhLCBlcnJvcnMsIHJlbWFpbmluZ0tleXMpXG5cbiAgYXVkaXQuYXR0cmlidXRlKGRhdGEsIFwibGFiZWxcIiwgdHJ1ZSwgZXJyb3JzLCByZW1haW5pbmdLZXlzLCBhdWRpdFJlcXVpcmUpXG5cbiAgcmV0dXJuIGF1ZGl0LnJlZHVjZVJlbWFpbmluZyhkYXRhLCBlcnJvcnMsIHJlbWFpbmluZ0tleXMpXG59XG5cbmV4cG9ydCBjb25zdCBhdWRpdERlY29tcG9zaXRpb25CeU5hbWUgPSBhdWRpdEtleVZhbHVlRGljdGlvbmFyeShcbiAgYXVkaXRUcmltU3RyaW5nLFxuICBbYXVkaXREZWNvbXBvc2l0aW9uLCBhdWRpdFJlcXVpcmVdLFxuKVxuXG5mdW5jdGlvbiBhdWRpdERlY29tcG9zaXRpb25Db3JlQ29udGVudChcbiAgYXVkaXQ6IEF1ZGl0LFxuICBkYXRhOiB7IFtrZXk6IHN0cmluZ106IHVua25vd24gfSxcbiAgZXJyb3JzOiB7IFtrZXk6IHN0cmluZ106IHVua25vd24gfSxcbiAgcmVtYWluaW5nS2V5czogU2V0PHN0cmluZz4sXG4pOiB2b2lkIHtcbiAgYXVkaXQuYXR0cmlidXRlKFxuICAgIGRhdGEsXG4gICAgXCJjaGlsZHJlblwiLFxuICAgIGZhbHNlLCAvLyBEb24ndCBkZWxldGUgbnVsbGlzaCBjaGlsZHJlbiAobnVsbGlzaCBtZWFucyBudWxsIGFmdGVyIGEgSlNPTi5wYXJzZSkuXG4gICAgZXJyb3JzLFxuICAgIHJlbWFpbmluZ0tleXMsXG4gICAgYXVkaXRDbGVhbkFycmF5KGF1ZGl0RGVjb21wb3NpdGlvblJlZmVyZW5jZSksXG4gIClcbiAgYXVkaXQuYXR0cmlidXRlKFxuICAgIGRhdGEsXG4gICAgXCJkZXNjcmlwdGlvblwiLFxuICAgIHRydWUsXG4gICAgZXJyb3JzLFxuICAgIHJlbWFpbmluZ0tleXMsXG4gICAgYXVkaXRSZWZlcmVuY2VzQnlEYXRlLFxuICApXG4gIC8vIE5vdGU6IGBcImhpZGRlblwiOiBmYWxzZWAgaXMgbm90IHRoZSBzYW1lIGFzIGB1bmRlZmluZWRgLlxuICBhdWRpdC5hdHRyaWJ1dGUoZGF0YSwgXCJoaWRkZW5cIiwgdHJ1ZSwgZXJyb3JzLCByZW1haW5pbmdLZXlzLCBhdWRpdEJvb2xlYW4pXG4gIGZvciAoY29uc3Qga2V5IG9mIFtcImxhYmVsXCIsIFwic2hvcnRfbGFiZWxcIl0pIHtcbiAgICBhdWRpdC5hdHRyaWJ1dGUoZGF0YSwga2V5LCB0cnVlLCBlcnJvcnMsIHJlbWFpbmluZ0tleXMsIGF1ZGl0VHJpbVN0cmluZylcbiAgfVxuICBhdWRpdC5hdHRyaWJ1dGUoXG4gICAgZGF0YSxcbiAgICBcImxhc3RfdmFsdWVfc3RpbGxfdmFsaWRfb25cIixcbiAgICB0cnVlLFxuICAgIGVycm9ycyxcbiAgICByZW1haW5pbmdLZXlzLFxuICAgIGF1ZGl0RGF0ZUlzbzg2MDFTdHJpbmcsXG4gIClcbiAgZm9yIChjb25zdCBrZXkgb2YgW1wib2Jzb2xldGVcIiwgXCJ2aXJ0dWFsXCJdKSB7XG4gICAgYXVkaXQuYXR0cmlidXRlKFxuICAgICAgZGF0YSxcbiAgICAgIGtleSxcbiAgICAgIHRydWUsXG4gICAgICBlcnJvcnMsXG4gICAgICByZW1haW5pbmdLZXlzLFxuICAgICAgYXVkaXRCb29sZWFuLFxuICAgICAgYXVkaXRGdW5jdGlvbigodmFsdWUpID0+IHZhbHVlIHx8IHVuZGVmaW5lZCksIC8vIERlbGV0ZSBmYWxzZS5cbiAgICApXG4gIH1cbiAgYXVkaXQuYXR0cmlidXRlKFxuICAgIGRhdGEsXG4gICAgXCJvcHRpb25zXCIsXG4gICAgdHJ1ZSxcbiAgICBlcnJvcnMsXG4gICAgcmVtYWluaW5nS2V5cyxcbiAgICBhdWRpdFN3aXRjaChcbiAgICAgIFthdWRpdEFycmF5KCksIGF1ZGl0Q2xlYW5BcnJheShhdWRpdERlY29tcG9zaXRpb25PcHRpb25zKV0sXG4gICAgICBbYXVkaXREZWNvbXBvc2l0aW9uT3B0aW9ucywgYXVkaXRGdW5jdGlvbigob3B0aW9ucykgPT4gW29wdGlvbnNdKV0sXG4gICAgKSxcbiAgKVxuICBhdWRpdC5hdHRyaWJ1dGUoXG4gICAgZGF0YSxcbiAgICBcInJlZmVyZW5jZVwiLFxuICAgIHRydWUsXG4gICAgZXJyb3JzLFxuICAgIHJlbWFpbmluZ0tleXMsXG4gICAgYXVkaXRSZWZlcmVuY2VzQnlEYXRlLFxuICApXG59XG5cbmV4cG9ydCBmdW5jdGlvbiBhdWRpdERlY29tcG9zaXRpb25PcHRpb25zKFxuICBhdWRpdDogQXVkaXQsXG4gIGRhdGFVbmtub3duOiB1bmtub3duLFxuKTogW3Vua25vd24sIHVua25vd25dIHtcbiAgaWYgKGRhdGFVbmtub3duID09IG51bGwpIHtcbiAgICByZXR1cm4gW2RhdGFVbmtub3duLCBudWxsXVxuICB9XG4gIGlmICh0eXBlb2YgZGF0YVVua25vd24gIT09IFwib2JqZWN0XCIpIHtcbiAgICByZXR1cm4gYXVkaXQudW5leHBlY3RlZFR5cGUoZGF0YVVua25vd24sIFwib2JqZWN0XCIpXG4gIH1cblxuICBjb25zdCBkYXRhOiB7IFtrZXk6IHN0cmluZ106IHVua25vd24gfSA9IHsgLi4uZGF0YVVua25vd24gfVxuICBjb25zdCBlcnJvcnM6IHsgW2tleTogc3RyaW5nXTogdW5rbm93biB9ID0ge31cbiAgY29uc3QgcmVtYWluaW5nS2V5cyA9IG5ldyBTZXQoT2JqZWN0LmtleXMoZGF0YSkpXG5cbiAgYXVkaXQuYXR0cmlidXRlKFxuICAgIGRhdGEsXG4gICAgXCJ3YXRlcmZhbGxcIixcbiAgICB0cnVlLFxuICAgIGVycm9ycyxcbiAgICByZW1haW5pbmdLZXlzLFxuICAgIGF1ZGl0U3dpdGNoKFxuICAgICAgW2F1ZGl0QXJyYXkoKSwgYXVkaXRDbGVhbkFycmF5KGF1ZGl0VHJpbVN0cmluZyksIGF1ZGl0VW5pcXVlXSxcbiAgICAgIFthdWRpdFRyaW1TdHJpbmcsIGF1ZGl0RnVuY3Rpb24oKG5hbWUpID0+IFtuYW1lXSldLFxuICAgICksXG4gICAgLy8gVE9ETzogVGVzdCBleGlzdGVuY2Ugb2Ygd2F0ZXJmYWxsIG5hbWVzLlxuICApXG5cbiAgaWYgKGVycm9ycy53YXRlcmZhbGwgPT09IHVuZGVmaW5lZCkge1xuICAgIGlmIChkYXRhLndhdGVyZmFsbCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAvLyBWYXJpYWJsZXMgb3B0aW9uc1xuXG4gICAgICBmb3IgKGNvbnN0IGtleSBvZiBbXCJlbHNlXCIsIFwidGhlblwiXSkge1xuICAgICAgICBhdWRpdC5hdHRyaWJ1dGUoXG4gICAgICAgICAgZGF0YSxcbiAgICAgICAgICBrZXksXG4gICAgICAgICAgdHJ1ZSxcbiAgICAgICAgICBlcnJvcnMsXG4gICAgICAgICAgcmVtYWluaW5nS2V5cyxcbiAgICAgICAgICBhdWRpdFZhcmlhYmxlc0N1c3RvbWl6YXRpb24sXG4gICAgICAgIClcbiAgICAgIH1cblxuICAgICAgZm9yIChjb25zdCB2YXJpYWJsZU5hbWUgb2YgcmVtYWluaW5nS2V5cykge1xuICAgICAgICBjb25zdCBbdmFsaWRWYXJpYWJsZU5hbWUsIHZhcmlhYmxlTmFtZUVycm9yXSA9IGF1ZGl0Q2hhaW4oXG4gICAgICAgICAgYXVkaXRUcmltU3RyaW5nLFxuICAgICAgICAgIC8vIFRPRE86IFRlc3QgZXhpc3RlbmNlIG9mIHZhcmlhYmxlIG5hbWUuXG4gICAgICAgICAgYXVkaXRSZXF1aXJlLFxuICAgICAgICApKGF1ZGl0LCB2YXJpYWJsZU5hbWUpXG4gICAgICAgIGlmICh2YXJpYWJsZU5hbWVFcnJvciA9PT0gbnVsbCkge1xuICAgICAgICAgIGF1ZGl0LmF0dHJpYnV0ZShcbiAgICAgICAgICAgIGRhdGEsXG4gICAgICAgICAgICB2YXJpYWJsZU5hbWUsXG4gICAgICAgICAgICB0cnVlLFxuICAgICAgICAgICAgZXJyb3JzLFxuICAgICAgICAgICAgcmVtYWluaW5nS2V5cyxcbiAgICAgICAgICAgIGF1ZGl0U3dpdGNoKFxuICAgICAgICAgICAgICBbXG4gICAgICAgICAgICAgICAgYXVkaXRBcnJheShhdWRpdEJvb2xlYW4pLFxuICAgICAgICAgICAgICAgIGF1ZGl0Q2xlYW5BcnJheShhdWRpdEJvb2xlYW4pLFxuICAgICAgICAgICAgICAgIGF1ZGl0VW5pcXVlLFxuICAgICAgICAgICAgICBdLFxuICAgICAgICAgICAgICBbXG4gICAgICAgICAgICAgICAgYXVkaXRBcnJheShhdWRpdFN0cmluZyksXG4gICAgICAgICAgICAgICAgYXVkaXRDbGVhbkFycmF5KGF1ZGl0VHJpbVN0cmluZyksXG4gICAgICAgICAgICAgICAgYXVkaXRVbmlxdWUsXG4gICAgICAgICAgICAgIF0sXG4gICAgICAgICAgICAgIFthdWRpdEJvb2xlYW4sIGF1ZGl0RnVuY3Rpb24oKHZhbHVlKSA9PiBbdmFsdWVdKV0sXG4gICAgICAgICAgICAgIFthdWRpdFRyaW1TdHJpbmcsIGF1ZGl0RnVuY3Rpb24oKHZhbHVlKSA9PiBbdmFsdWVdKV0sXG4gICAgICAgICAgICApLFxuICAgICAgICAgICAgLy8gVE9ETzogVGVzdCBleGlzdGVuY2Ugb2YgdmFyaWFibGUgdmFsdWUuXG4gICAgICAgICAgICBhdWRpdFJlcXVpcmUsXG4gICAgICAgICAgKVxuICAgICAgICAgIGlmIChcbiAgICAgICAgICAgIGVycm9yc1t2YXJpYWJsZU5hbWVdID09PSB1bmRlZmluZWQgJiZcbiAgICAgICAgICAgIHZhbGlkVmFyaWFibGVOYW1lICE9PSB2YXJpYWJsZU5hbWVcbiAgICAgICAgICApIHtcbiAgICAgICAgICAgIGRhdGFbdmFsaWRWYXJpYWJsZU5hbWVdID0gZGF0YVt2YXJpYWJsZU5hbWVdXG4gICAgICAgICAgICBkZWxldGUgZGF0YVt2YXJpYWJsZU5hbWVdXG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIC8vIFdhdGVyZmFsbCBvcHRpb25zXG5cbiAgICAgIGZvciAoY29uc3Qga2V5IG9mIFtcImVsc2VcIiwgXCJ0aGVuXCJdKSB7XG4gICAgICAgIGF1ZGl0LmF0dHJpYnV0ZShcbiAgICAgICAgICBkYXRhLFxuICAgICAgICAgIGtleSxcbiAgICAgICAgICB0cnVlLFxuICAgICAgICAgIGVycm9ycyxcbiAgICAgICAgICByZW1haW5pbmdLZXlzLFxuICAgICAgICAgIGF1ZGl0V2F0ZXJmYWxsQ3VzdG9taXphdGlvbixcbiAgICAgICAgKVxuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIHJldHVybiBhdWRpdC5yZWR1Y2VSZW1haW5pbmcoZGF0YSwgZXJyb3JzLCByZW1haW5pbmdLZXlzKVxufVxuXG5leHBvcnQgZnVuY3Rpb24gYXVkaXREZWNvbXBvc2l0aW9uUmVmZXJlbmNlKFxuICBhdWRpdDogQXVkaXQsXG4gIGRhdGFVbmtub3duOiB1bmtub3duLFxuKTogW3Vua25vd24sIHVua25vd25dIHtcbiAgaWYgKGRhdGFVbmtub3duID09IG51bGwpIHtcbiAgICByZXR1cm4gW2RhdGFVbmtub3duLCBudWxsXVxuICB9XG4gIGlmICh0eXBlb2YgZGF0YVVua25vd24gIT09IFwib2JqZWN0XCIpIHtcbiAgICByZXR1cm4gYXVkaXQudW5leHBlY3RlZFR5cGUoZGF0YVVua25vd24sIFwib2JqZWN0XCIpXG4gIH1cblxuICBjb25zdCBkYXRhOiB7IFtrZXk6IHN0cmluZ106IHVua25vd24gfSA9IHsgLi4uZGF0YVVua25vd24gfVxuICBjb25zdCBlcnJvcnM6IHsgW2tleTogc3RyaW5nXTogdW5rbm93biB9ID0ge31cbiAgY29uc3QgcmVtYWluaW5nS2V5cyA9IG5ldyBTZXQoT2JqZWN0LmtleXMoZGF0YSkpXG5cbiAgYXVkaXQuYXR0cmlidXRlKFxuICAgIGRhdGEsXG4gICAgXCJuYW1lXCIsXG4gICAgdHJ1ZSxcbiAgICBlcnJvcnMsXG4gICAgcmVtYWluaW5nS2V5cyxcbiAgICBhdWRpdFRyaW1TdHJpbmcsXG4gICAgYXVkaXRSZXF1aXJlLFxuICApXG4gIGF1ZGl0LmF0dHJpYnV0ZShcbiAgICBkYXRhLFxuICAgIFwibmVnYXRlXCIsXG4gICAgdHJ1ZSxcbiAgICBlcnJvcnMsXG4gICAgcmVtYWluaW5nS2V5cyxcbiAgICBhdWRpdEJvb2xlYW4sXG4gICAgYXVkaXRGdW5jdGlvbigodmFsdWUpID0+IHZhbHVlIHx8IHVuZGVmaW5lZCksIC8vIFJlcGxhY2UgZmFsc2Ugd2l0aCB1bmRlZmluZWQuXG4gIClcblxuICByZXR1cm4gYXVkaXQucmVkdWNlUmVtYWluaW5nKGRhdGEsIGVycm9ycywgcmVtYWluaW5nS2V5cylcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGF1ZGl0VmFyaWFibGVzQ3VzdG9taXphdGlvbihcbiAgYXVkaXQ6IEF1ZGl0LFxuICBkYXRhVW5rbm93bjogdW5rbm93bixcbik6IFt1bmtub3duLCB1bmtub3duXSB7XG4gIGlmIChkYXRhVW5rbm93biA9PSBudWxsKSB7XG4gICAgcmV0dXJuIFtkYXRhVW5rbm93biwgbnVsbF1cbiAgfVxuICBpZiAodHlwZW9mIGRhdGFVbmtub3duICE9PSBcIm9iamVjdFwiKSB7XG4gICAgcmV0dXJuIGF1ZGl0LnVuZXhwZWN0ZWRUeXBlKGRhdGFVbmtub3duLCBcIm9iamVjdFwiKVxuICB9XG5cbiAgY29uc3QgZGF0YTogeyBba2V5OiBzdHJpbmddOiB1bmtub3duIH0gPSB7IC4uLmRhdGFVbmtub3duIH1cbiAgY29uc3QgZXJyb3JzOiB7IFtrZXk6IHN0cmluZ106IHVua25vd24gfSA9IHt9XG4gIGNvbnN0IHJlbWFpbmluZ0tleXMgPSBuZXcgU2V0KE9iamVjdC5rZXlzKGRhdGEpKVxuXG4gIC8vIE5vdGU6IGBcImhpZGRlblwiOiBmYWxzZWAgaXMgbm90IHRoZSBzYW1lIGFzIGB1bmRlZmluZWRgLlxuICBhdWRpdC5hdHRyaWJ1dGUoZGF0YSwgXCJoaWRkZW5cIiwgdHJ1ZSwgZXJyb3JzLCByZW1haW5pbmdLZXlzLCBhdWRpdEJvb2xlYW4pXG5cbiAgcmV0dXJuIGF1ZGl0LnJlZHVjZVJlbWFpbmluZyhkYXRhLCBlcnJvcnMsIHJlbWFpbmluZ0tleXMpXG59XG5cbmV4cG9ydCBmdW5jdGlvbiBhdWRpdFdhdGVyZmFsbEN1c3RvbWl6YXRpb24oXG4gIGF1ZGl0OiBBdWRpdCxcbiAgZGF0YVVua25vd246IHVua25vd24sXG4pOiBbdW5rbm93biwgdW5rbm93bl0ge1xuICBpZiAoZGF0YVVua25vd24gPT0gbnVsbCkge1xuICAgIHJldHVybiBbZGF0YVVua25vd24sIG51bGxdXG4gIH1cbiAgaWYgKHR5cGVvZiBkYXRhVW5rbm93biAhPT0gXCJvYmplY3RcIikge1xuICAgIHJldHVybiBhdWRpdC51bmV4cGVjdGVkVHlwZShkYXRhVW5rbm93biwgXCJvYmplY3RcIilcbiAgfVxuXG4gIGNvbnN0IGRhdGE6IHsgW2tleTogc3RyaW5nXTogdW5rbm93biB9ID0geyAuLi5kYXRhVW5rbm93biB9XG4gIGNvbnN0IGVycm9yczogeyBba2V5OiBzdHJpbmddOiB1bmtub3duIH0gPSB7fVxuICBjb25zdCByZW1haW5pbmdLZXlzID0gbmV3IFNldChPYmplY3Qua2V5cyhkYXRhKSlcblxuICBhdWRpdC5hdHRyaWJ1dGUoXG4gICAgZGF0YSxcbiAgICBcImNoaWxkcmVuXCIsXG4gICAgZmFsc2UsIC8vIERvbid0IGRlbGV0ZSBudWxsaXNoIGNoaWxkcmVuIChudWxsaXNoIG1lYW5zIG51bGwgYWZ0ZXIgYSBKU09OLnBhcnNlKS5cbiAgICBlcnJvcnMsXG4gICAgcmVtYWluaW5nS2V5cyxcbiAgICBhdWRpdENsZWFuQXJyYXkoYXVkaXREZWNvbXBvc2l0aW9uUmVmZXJlbmNlKSxcbiAgKVxuICAvLyBOb3RlOiBgXCJoaWRkZW5cIjogZmFsc2VgIGlzIG5vdCB0aGUgc2FtZSBhcyBgdW5kZWZpbmVkYC5cbiAgYXVkaXQuYXR0cmlidXRlKGRhdGEsIFwiaGlkZGVuXCIsIHRydWUsIGVycm9ycywgcmVtYWluaW5nS2V5cywgYXVkaXRCb29sZWFuKVxuXG4gIHJldHVybiBhdWRpdC5yZWR1Y2VSZW1haW5pbmcoZGF0YSwgZXJyb3JzLCByZW1haW5pbmdLZXlzKVxufVxuIl0sIm1hcHBpbmdzIjoiQUFDQSxTQUNFQSxVQUFVLEVBQ1ZDLFlBQVksRUFDWkMsVUFBVSxFQUNWQyxlQUFlLEVBQ2ZDLHNCQUFzQixFQUN0QkMsYUFBYSxFQUNiQyx1QkFBdUIsRUFDdkJDLFlBQVksRUFDWkMsWUFBWSxFQUNaQyxXQUFXLEVBQ1hDLFdBQVcsRUFDWEMsZUFBZSxFQUNmQyxXQUFXLFFBQ04sZ0JBQWdCO0FBQUEsU0FFZEMscUJBQXFCO0FBRTlCLE1BQU1DLGtCQUFrQixHQUNyQkMsZUFBeUIsSUFDMUIsQ0FBQ0MsS0FBWSxFQUFFQyxXQUFvQixLQUF5QjtFQUMxRCxJQUFJQSxXQUFXLElBQUksSUFBSSxFQUFFO0lBQ3ZCLE9BQU8sQ0FBQ0EsV0FBVyxFQUFFLElBQUksQ0FBQztFQUM1QjtFQUNBLElBQUksT0FBT0EsV0FBVyxLQUFLLFFBQVEsRUFBRTtJQUNuQyxPQUFPRCxLQUFLLENBQUNFLGNBQWMsQ0FB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