@openfisca/json-model
Version:
Library to handle informations extracted in JSON or YAML format from OpenFisca parameters, variables, etc
384 lines (379 loc) • 61.7 kB
JavaScript
/// Structure and functions of editable parameters
/// Note: raw parameters have no structure.
export let ParameterClass = /*#__PURE__*/function (ParameterClass) {
ParameterClass["Node"] = "Node";
ParameterClass["Scale"] = "Scale";
ParameterClass["Value"] = "Value";
return ParameterClass;
}({});
export let ScaleType = /*#__PURE__*/function (ScaleType) {
ScaleType["LinearAverageRate"] = "linear_average_rate";
ScaleType["MarginalAmount"] = "marginal_amount";
ScaleType["MarginalRate"] = "marginal_rate";
ScaleType["SingleAmount"] = "single_amount";
return ScaleType;
}({});
export let ValueType = /*#__PURE__*/function (ValueType) {
ValueType["Boolean"] = "boolean";
ValueType["Number"] = "number";
ValueType["StringArray"] = "string_array";
ValueType["StringByString"] = "string_by_string";
return ValueType;
}({});
export function accessParameterFromIds(parameter, ids) {
for (const id of ids) {
if (parameter.class !== ParameterClass.Node) {
return [parameter, `Can't access to child "${id}" in parameter ${parameter.name}, because it is not a node`];
}
const child = parameter.children?.[id];
if (child === undefined) {
return [parameter, `Parameter ${parameter.name} has no child named "${id}"`];
}
parameter = child;
}
return [parameter, null];
}
/// Convert a dictionary of brackets by instant to a list of brackets
/// containing amounts, bases, rates & thresholds by instant.
export function bracketsFromScaleByInstant(scaleByInstant) {
const brackets = [];
for (const key of ["amount", "base", "rate", "threshold"]) {
let latestValue = undefined;
for (const [instant, scaleAtInstant] of Object.entries(scaleByInstant).sort(([instant1], [instant2]) => instant1.localeCompare(instant2))) {
for (const [bracketIndex, bracketAtInstant] of scaleAtInstant.entries()) {
if (brackets.length <= bracketIndex) {
brackets.push({});
}
const value = bracketAtInstant[key];
if (value !== undefined) {
const bracket = brackets[bracketIndex];
let valueByInstant = bracket[key];
if (valueByInstant === undefined) {
valueByInstant = bracket[key] = {};
}
if (value === "expected") {
if (value !== latestValue) {
latestValue = valueByInstant[instant] = value;
}
} else if (latestValue === undefined || latestValue === "expected" || value.value !== latestValue.value) {
latestValue = valueByInstant[instant] = value;
} else if (value.reference !== undefined) {
let latestReferences = latestValue.reference;
if (latestReferences === undefined) {
latestReferences = latestValue.reference = [];
}
for (const reference of value.reference) {
if (!latestReferences.some(latestReference => latestReference.href === reference.href && latestReference.title === reference.title)) {
latestReferences.push(reference);
}
}
}
}
}
}
}
return brackets;
}
export function improveParameter(parameter, parent = undefined, ids = []) {
const id = ids[ids.length - 1];
if (id !== undefined) {
parameter.id = id;
}
if (parameter.name === undefined) {
parameter.name = ids.join(".");
}
if (parent != null) {
parameter.parent = parent;
}
const title = parameter.short_label ?? parameter.description ?? id?.replace(/_/g, " ").replace(/^\w/, c => c.toUpperCase());
if (title !== undefined) {
parameter.title = title;
}
parameter.titles = (title === undefined ? parent?.titles ?? [] : [...(parent?.titles ?? []), title]).filter(Boolean);
switch (parameter.class) {
case ParameterClass.Node:
if (parameter.children !== undefined) {
for (const [childId, child] of Object.entries(parameter.children)) {
improveParameter(child, parameter, [...ids, childId]);
}
}
break;
default:
}
}
export function isAmountScaleParameter(parameter) {
return [ScaleType.MarginalAmount, ScaleType.SingleAmount].includes(parameter.type);
}
export function isRateScaleParameter(parameter) {
return ![ScaleType.MarginalAmount, ScaleType.SingleAmount].includes(parameter.type);
}
export function isVectorialNodeParameter(node) {
if (node.children === undefined || Object.keys(node.children).length <= 1) {
return false;
}
const children = Object.values(node.children);
if (children.some(child => child.class !== ParameterClass.Value)) {
return false;
}
const commonType = children[0].type;
if (children.some(child => child.type !== commonType)) {
return false;
}
const commonFilePath = children[0].file_path;
if (children.some(child => child.file_path !== commonFilePath)) {
return false;
}
return true;
}
export function* iterParameterAncestors(parameter) {
if (parameter == null || !parameter.id) {
return;
}
yield* iterParameterAncestors(parameter.parent);
yield parameter;
}
function mergeDuplicateParameters(existingParameter, parameter) {
if (existingParameter.class === ParameterClass.Node) {
const existingChidren = existingParameter.children;
for (const child of Object.values(parameter.children)) {
const existingChild = existingChidren[child.id ?? ""];
if (existingChild === undefined) {
existingChidren[child.id ?? ""] = child;
child.parent = existingParameter;
} else {
mergeDuplicateParameters(existingChild, child);
}
}
}
}
export function mergeParameters(parameters) {
const rootParameterById = {};
for (const parameter of parameters) {
// Create a copy of the parameters tree, containing only this parameter.
let rootParameter = {
...parameter
};
for (let ancestor = rootParameter.parent; ancestor !== undefined && ancestor.id; rootParameter = ancestor, ancestor = rootParameter.parent) {
ancestor = {
...ancestor,
children: {
[rootParameter.id]: rootParameter
}
};
rootParameter.parent = ancestor;
}
// Merge this simplified parameters tree with the others.
const existingRootParameter = rootParameterById[rootParameter.id ?? ""];
if (existingRootParameter === undefined) {
rootParameterById[rootParameter.id ?? ""] = rootParameter;
} else {
mergeDuplicateParameters(existingRootParameter, rootParameter);
}
}
return rootParameterById;
}
export function mergeReferences(references1, references2) {
if (references1 == null) {
return references2 ?? undefined;
}
if (references2 == null) {
return references1 ?? undefined;
}
const references = [...references1];
for (const reference2 of references2) {
let found = false;
if (reference2.href !== undefined) {
const index = references.findIndex(reference => reference.href === reference2.href);
if (index >= 0) {
found = true;
let reference = references[index];
let changed = false;
if (reference.note === undefined && reference2.note !== undefined) {
if (!changed) {
changed = true;
reference = references[index] = {
...reference
};
}
reference.note = reference2.note;
}
if (reference.title === undefined && reference2.title !== undefined) {
if (!changed) {
changed = true;
reference = references[index] = {
...reference
};
}
reference.title = reference2.title;
}
}
} else if (reference2.title !== undefined) {
const index = references.findIndex(reference => reference.title === reference2.title);
if (index >= 0) {
found = true;
let reference = references[index];
if (reference.note === undefined && reference2.note !== undefined) {
reference = references[index] = {
...reference
};
reference.note = reference2.note;
}
}
} else {
// assert.notStrictEqual(reference2.note, undefined)
const index = references.findIndex(reference => reference.note === reference2.note);
if (index >= 0) {
found = true;
}
}
if (!found) {
references.push(reference2);
}
}
return references;
}
export function newParameterRepositoryUrl(metadata, parameter) {
if (parameter.file_path === undefined) {
return undefined;
}
const packageName = parameter.file_path.split("/")[0];
for (const packageMetadata of metadata.packages) {
if (packageMetadata.name === packageName) {
return `${packageMetadata.repository_url}/blob/${packageMetadata.version}/${parameter.file_path}`;
}
}
return undefined;
}
export function parameterLastReviewOrChange(parameter) {
switch (parameter.class) {
case ParameterClass.Node:
return parameter.last_value_still_valid_on;
case ParameterClass.Scale:
{
const latestInstant = [parameter.last_value_still_valid_on, ...Object.keys(scaleByInstantFromBrackets(parameter.brackets))].filter(instant => instant !== undefined).sort((instant1, instant2) => instant2.localeCompare(instant1))[0];
return latestInstant;
}
case ParameterClass.Value:
{
const latestInstant = [parameter.last_value_still_valid_on, ...Object.keys(parameter.values)].filter(instant => instant !== undefined).sort((instant1, instant2) => instant2.localeCompare(instant1))[0];
return latestInstant;
}
}
}
export function parameterWithoutChildren(parameter) {
if (parameter.class === ParameterClass.Node) {
parameter = {
...parameter
};
delete parameter.children;
}
return parameter;
}
/// Apply changes of a reform to (root) parameter.
export function patchParameter(parameter, patch) {
if (Object.keys(patch).length === 0) {
return parameter;
}
const patchedParameter = {
...parameter
};
for (const [key, value] of Object.entries(patch)) {
if (value === null) {
delete patchedParameter[key];
} else if (patchedParameter[key] === undefined) {
;
patchedParameter[key] = value;
} else if (key === "children") {
const patchedChildren = patchedParameter.children = {
...patchedParameter.children
};
for (const [childId, childPatch] of Object.entries(value)) {
if (childPatch === null) {
delete patchedChildren[childId];
} else if (patchedChildren[childId] === undefined) {
patchedChildren[childId] = childPatch;
} else {
patchedChildren[childId] = patchParameter(patchedChildren[childId], childPatch);
}
}
} else {
;
patchedParameter[key] = value;
}
}
return patchedParameter;
}
/// Convert a list of brackets containing amounts, bases, rates & thresholds by instant
/// to a dictionary of brackets by instant.
/// For heuristic, see function `build_api_scale` of
/// https://github.com/openfisca/openfisca-core/blob/master/openfisca_web_api/loader/parameters.py
export function scaleByInstantFromBrackets(brackets) {
const instants = new Set();
for (const bracket of brackets) {
for (const instant of Object.keys(bracket.amount ?? {})) {
instants.add(instant);
}
for (const instant of Object.keys(bracket.base ?? {})) {
instants.add(instant);
}
for (const instant of Object.keys(bracket.rate ?? {})) {
instants.add(instant);
}
for (const instant of Object.keys(bracket.threshold)) {
instants.add(instant);
}
}
const scaleAtInstantByInstant = {};
for (const instant of instants) {
const scaleAtInstant = [];
for (const bracket of brackets) {
const bracketAtInstant = {};
for (const key of ["amount", "base", "rate", "threshold"]) {
const valueByInstant = bracket?.[key];
if (valueByInstant === undefined) {
continue;
}
let bestInstant = undefined;
for (const valueInstant of Object.keys(valueByInstant)) {
if ((bestInstant === undefined || bestInstant.localeCompare(valueInstant) < 0) && valueInstant.localeCompare(instant) <= 0) {
bestInstant = valueInstant;
}
}
if (bestInstant === undefined) {
continue;
}
bracketAtInstant[key] = valueByInstant[bestInstant];
}
if (Object.keys(bracketAtInstant).length === 0 || Object.values(bracketAtInstant).every(value => value !== "expected" && value.value === null)) {
continue;
}
scaleAtInstant.push(bracketAtInstant);
}
if (scaleAtInstant.length > 0) {
scaleAtInstantByInstant[instant] = scaleAtInstant;
}
}
return scaleAtInstantByInstant;
}
export function scaleParameterUsesBase(parameter) {
return isRateScaleParameter(parameter) && parameter.brackets.some(bracket => bracket.base !== undefined);
}
export function* walkParameters(parameter, depthFirst = false) {
if (!depthFirst && parameter.class !== ParameterClass.Node) {
yield parameter;
}
switch (parameter.class) {
case ParameterClass.Node:
if (parameter.children !== undefined) {
for (const child of Object.values(parameter.children)) {
yield* walkParameters(child, depthFirst);
}
}
break;
default:
}
if (depthFirst && parameter.class !== ParameterClass.Node) {
yield parameter;
}
}
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJQYXJhbWV0ZXJDbGFzcyIsIlNjYWxlVHlwZSIsIlZhbHVlVHlwZSIsImFjY2Vzc1BhcmFtZXRlckZyb21JZHMiLCJwYXJhbWV0ZXIiLCJpZHMiLCJpZCIsImNsYXNzIiwiTm9kZSIsIm5hbWUiLCJjaGlsZCIsImNoaWxkcmVuIiwidW5kZWZpbmVkIiwiYnJhY2tldHNGcm9tU2NhbGVCeUluc3RhbnQiLCJzY2FsZUJ5SW5zdGFudCIsImJyYWNrZXRzIiwia2V5IiwibGF0ZXN0VmFsdWUiLCJpbnN0YW50Iiwic2NhbGVBdEluc3RhbnQiLCJPYmplY3QiLCJlbnRyaWVzIiwic29ydCIsImluc3RhbnQxIiwiaW5zdGFudDIiLCJsb2NhbGVDb21wYXJlIiwiYnJhY2tldEluZGV4IiwiYnJhY2tldEF0SW5zdGFudCIsImxlbmd0aCIsInB1c2giLCJ2YWx1ZSIsImJyYWNrZXQiLCJ2YWx1ZUJ5SW5zdGFudCIsInJlZmVyZW5jZSIsImxhdGVzdFJlZmVyZW5jZXMiLCJzb21lIiwibGF0ZXN0UmVmZXJlbmNlIiwiaHJlZiIsInRpdGxlIiwiaW1wcm92ZVBhcmFtZXRlciIsInBhcmVudCIsImpvaW4iLCJzaG9ydF9sYWJlbCIsImRlc2NyaXB0aW9uIiwicmVwbGFjZSIsImMiLCJ0b1VwcGVyQ2FzZSIsInRpdGxlcyIsImZpbHRlciIsIkJvb2xlYW4iLCJjaGlsZElkIiwiaXNBbW91bnRTY2FsZVBhcmFtZXRlciIsIk1hcmdpbmFsQW1vdW50IiwiU2luZ2xlQW1vdW50IiwiaW5jbHVkZXMiLCJ0eXBlIiwiaXNSYXRlU2NhbGVQYXJhbWV0ZXIiLCJpc1ZlY3RvcmlhbE5vZGVQYXJhbWV0ZXIiLCJub2RlIiwia2V5cyIsInZhbHVlcyIsIlZhbHVlIiwiY29tbW9uVHlwZSIsImNvbW1vbkZpbGVQYXRoIiwiZmlsZV9wYXRoIiwiaXRlclBhcmFtZXRlckFuY2VzdG9ycyIsIm1lcmdlRHVwbGljYXRlUGFyYW1ldGVycyIsImV4aXN0aW5nUGFyYW1ldGVyIiwiZXhpc3RpbmdDaGlkcmVuIiwiZXhpc3RpbmdDaGlsZCIsIm1lcmdlUGFyYW1ldGVycyIsInBhcmFtZXRlcnMiLCJyb290UGFyYW1ldGVyQnlJZCIsInJvb3RQYXJhbWV0ZXIiLCJhbmNlc3RvciIsImV4aXN0aW5nUm9vdFBhcmFtZXRlciIsIm1lcmdlUmVmZXJlbmNlcyIsInJlZmVyZW5jZXMxIiwicmVmZXJlbmNlczIiLCJyZWZlcmVuY2VzIiwicmVmZXJlbmNlMiIsImZvdW5kIiwiaW5kZXgiLCJmaW5kSW5kZXgiLCJjaGFuZ2VkIiwibm90ZSIsIm5ld1BhcmFtZXRlclJlcG9zaXRvcnlVcmwiLCJtZXRhZGF0YSIsInBhY2thZ2VOYW1lIiwic3BsaXQiLCJwYWNrYWdlTWV0YWRhdGEiLCJwYWNrYWdlcyIsInJlcG9zaXRvcnlfdXJsIiwidmVyc2lvbiIsInBhcmFtZXRlckxhc3RSZXZpZXdPckNoYW5nZSIsImxhc3RfdmFsdWVfc3RpbGxfdmFsaWRfb24iLCJTY2FsZSIsImxhdGVzdEluc3RhbnQiLCJzY2FsZUJ5SW5zdGFudEZyb21CcmFja2V0cyIsInBhcmFtZXRlcldpdGhvdXRDaGlsZHJlbiIsInBhdGNoUGFyYW1ldGVyIiwicGF0Y2giLCJwYXRjaGVkUGFyYW1ldGVyIiwicGF0Y2hlZENoaWxkcmVuIiwiY2hpbGRQYXRjaCIsImluc3RhbnRzIiwiU2V0IiwiYW1vdW50IiwiYWRkIiwiYmFzZSIsInJhdGUiLCJ0aHJlc2hvbGQiLCJzY2FsZUF0SW5zdGFudEJ5SW5zdGFudCIsImJlc3RJbnN0YW50IiwidmFsdWVJbnN0YW50IiwiZXZlcnkiLCJzY2FsZVBhcmFtZXRlclVzZXNCYXNlIiwid2Fsa1BhcmFtZXRlcnMiLCJkZXB0aEZpcnN0Il0sInNvdXJjZXMiOlsiLi4vc3JjL3BhcmFtZXRlcnMudHMiXSwic291cmNlc0NvbnRlbnQiOlsiLy8vIFN0cnVjdHVyZSBhbmQgZnVuY3Rpb25zIG9mIGVkaXRhYmxlIHBhcmFtZXRlcnNcbi8vLyBOb3RlOiByYXcgcGFyYW1ldGVycyBoYXZlIG5vIHN0cnVjdHVyZS5cblxuaW1wb3J0IHR5cGUgeyBNZXRhZGF0YSB9IGZyb20gXCIuL21ldGFkYXRhXCJcbmltcG9ydCB0eXBlIHsgUmVmZXJlbmNlLCBSZWZlcmVuY2VzQnlJbnN0YW50IH0gZnJvbSBcIi4vcmVmZXJlbmNlc1wiXG5cbmV4cG9ydCBpbnRlcmZhY2UgQW1vdW50QnJhY2tldCBleHRlbmRzIEJyYWNrZXRCYXNlIHtcbiAgYW1vdW50OiB7IFtpbnN0YW50OiBzdHJpbmddOiBOdW1iZXJWYWx1ZSB8IFwiZXhwZWN0ZWRcIiB9XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgQW1vdW50QnJhY2tldEF0SW5zdGFudCBleHRlbmRzIEJyYWNrZXRBdEluc3RhbnRCYXNlIHtcbiAgYW1vdW50OiBOdW1iZXJWYWx1ZSB8IFwiZXhwZWN0ZWRcIlxufVxuXG5leHBvcnQgaW50ZXJmYWNlIEJvb2xlYW5QYXJhbWV0ZXIgZXh0ZW5kcyBWYWx1ZVBhcmFtZXRlckJhc2Uge1xuICB0eXBlOiBWYWx1ZVR5cGUuQm9vbGVhblxuICB2YWx1ZXM6IHsgW2luc3RhbnQ6IHN0cmluZ106IE1heWJlQm9vbGVhblZhbHVlIHwgXCJleHBlY3RlZFwiIH1cbn1cblxuZXhwb3J0IGludGVyZmFjZSBCb29sZWFuVmFsdWUgZXh0ZW5kcyBWYWx1ZUJhc2Uge1xuICB2YWx1ZTogYm9vbGVhblxufVxuXG5leHBvcnQgdHlwZSBCcmFja2V0ID0gQW1vdW50QnJhY2tldCB8IFJhdGVCcmFja2V0XG5cbmV4cG9ydCB0eXBlIEJyYWNrZXRBdEluc3RhbnQgPSBBbW91bnRCcmFja2V0QXRJbnN0YW50IHwgUmF0ZUJyYWNrZXRBdEluc3RhbnRcblxuZXhwb3J0IGludGVyZmFjZSBCcmFja2V0QXRJbnN0YW50QmFzZSB7XG4gIHRocmVzaG9sZDogTWF5YmVOdW1iZXJWYWx1ZSB8IFwiZXhwZWN0ZWRcIlxufVxuXG5leHBvcnQgaW50ZXJmYWNlIEJyYWNrZXRCYXNlIHtcbiAgdGhyZXNob2xkOiB7IFtpbnN0YW50OiBzdHJpbmddOiBNYXliZU51bWJlclZhbHVlIHwgXCJleHBlY3RlZFwiIH1cbn1cblxuZXhwb3J0IHR5cGUgQnJhY2tldFZhbHVlQXRJbnN0YW50ID0gTWF5YmVOdW1iZXJWYWx1ZSB8IE51bWJlclZhbHVlIHwgXCJleHBlY3RlZFwiXG5cbmV4cG9ydCBpbnRlcmZhY2UgTGluZWFyQXZlcmFnZVJhdGVTY2FsZVBhcmFtZXRlciBleHRlbmRzIFNjYWxlUGFyYW1ldGVyQmFzZSB7XG4gIGJyYWNrZXRzOiBSYXRlQnJhY2tldFtdXG4gIHJhdGVfdW5pdD86IHN0cmluZ1xuICB0eXBlOiBTY2FsZVR5cGUuTGluZWFyQXZlcmFnZVJhdGVcbn1cblxuZXhwb3J0IGludGVyZmFjZSBNYXJnaW5hbEFtb3VudFNjYWxlUGFyYW1ldGVyIGV4dGVuZHMgU2NhbGVQYXJhbWV0ZXJCYXNlIHtcbiAgYW1vdW50X3VuaXQ/OiBzdHJpbmdcbiAgYnJhY2tldHM6IEFtb3VudEJyYWNrZXRbXVxuICB0eXBlOiBTY2FsZVR5cGUuTWFyZ2luYWxBbW91bnRcbn1cblxuZXhwb3J0IGludGVyZmFjZSBNYXJnaW5hbFJhdGVTY2FsZVBhcmFtZXRlciBleHRlbmRzIFNjYWxlUGFyYW1ldGVyQmFzZSB7XG4gIGJyYWNrZXRzOiBSYXRlQnJhY2tldFtdXG4gIHJhdGVfdW5pdD86IHN0cmluZ1xuICB0eXBlOiBTY2FsZVR5cGUuTWFyZ2luYWxSYXRlXG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgTWF5YmVCb29sZWFuVmFsdWUgZXh0ZW5kcyBWYWx1ZUJhc2Uge1xuICB2YWx1ZTogYm9vbGVhbiB8IG51bGxcbn1cblxuZXhwb3J0IGludGVyZmFjZSBNYXliZU51bWJlclZhbHVlIGV4dGVuZHMgVmFsdWVCYXNlIHtcbiAgdmFsdWU6IG51bWJlciB8IG51bGxcbn1cblxuZXhwb3J0IGludGVyZmFjZSBNYXliZVN0cmluZ0FycmF5VmFsdWUgZXh0ZW5kcyBWYWx1ZUJhc2Uge1xuICB2YWx1ZTogQXJyYXk8c3RyaW5nIHwgbnVsbD4gfCBudWxsXG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgTWF5YmVTdHJpbmdCeVN0cmluZ1ZhbHVlIGV4dGVuZHMgVmFsdWVCYXNlIHtcbiAgdmFsdWU6IHsgW2tleTogc3RyaW5nXTogc3RyaW5nIHwgbnVsbCB9IHwgbnVsbFxufVxuXG5leHBvcnQgaW50ZXJmYWNlIE5vZGVQYXJhbWV0ZXIgZXh0ZW5kcyBQYXJhbWV0ZXJCYXNlIHtcbiAgLy8gQ2hpbGRyZW4gYXJlIHByZXNlbnQgaW4gZXZlcnkgUGFyYW1ldGVyTm9kZSwgYnV0IGFyZSByZW1vdmVkIGZyb20gYW5jZXN0b3JzLlxuICBjaGlsZHJlbj86IHsgW2lkOiBzdHJpbmddOiBQYXJhbWV0ZXIgfVxuICBjbGFzczogUGFyYW1ldGVyQ2xhc3MuTm9kZVxuICBvcmRlcj86IHN0cmluZ1tdXG4gIHVuaXQ/OiBzdHJpbmdcbn1cblxuZXhwb3J0IGludGVyZmFjZSBOdW1iZXJWYWx1ZSBleHRlbmRzIFZhbHVlQmFzZSB7XG4gIHZhbHVlOiBudW1iZXJcbn1cblxuZXhwb3J0IGludGVyZmFjZSBOdW1iZXJQYXJhbWV0ZXIgZXh0ZW5kcyBWYWx1ZVBhcmFtZXRlckJhc2Uge1xuICB0eXBlOiBWYWx1ZVR5cGUuTnVtYmVyXG4gIHZhbHVlczogeyBbaW5zdGFudDogc3RyaW5nXTogTWF5YmVOdW1iZXJWYWx1ZSB8IFwiZXhwZWN0ZWRcIiB9XG59XG5cbmV4cG9ydCB0eXBlIE9mZmljaWFsSm91cm5hbERhdGVzQnlJbnN0YW50ID0geyBbaW5zdGFudDogc3RyaW5nXTogc3RyaW5nIHwgbnVsbCB9XG5cbmV4cG9ydCB0eXBlIFBhcmFtZXRlciA9IE5vZGVQYXJhbWV0ZXIgfCBTY2FsZVBhcmFtZXRlciB8IFZhbHVlUGFyYW1ldGVyXG5cbmV4cG9ydCBpbnRlcmZhY2UgUGFyYW1ldGVyQmFzZSB7XG4gIGNsYXNzOiBQYXJhbWV0ZXJDbGFzc1xuICBkZXNjcmlwdGlvbj86IHN0cmluZ1xuICBsYWJlbF9lbj86IHN0cmluZ1xuICBkb2N1bWVudGF0aW9uPzogc3RyaW5nXG4gIGRvY3VtZW50YXRpb25fc3RhcnQ/OiBib29sZWFuXG4gIGZpbGVfcGF0aD86IHN0cmluZ1xuICBpZD86IHN0cmluZyAvLyBHZW5lcmF0ZWQgYXR0cmlidXRlIChsYXN0IHBhcnQgb2YgbmFtZSlcbiAgLy8vIE5hbWUgb2YgcGFyYW1ldGVyIHRoYXQgaXMgdXNlZCB0byBhdXRvbWF0aWNhbGx5IHJldmFsdWF0ZSB0aGlzIHBhcmFtZXRlciB3aXRoIGluZmxhdGlvblxuICBpbmZsYXRvcj86IHN0cmluZ1xuICBpbmZsYXRvcl9yZWZlcmVuY2U/OiBSZWZlcmVuY2VzQnlJbnN0YW50XG4gIGxhc3RfdmFsdWVfc3RpbGxfdmFsaWRfb24/OiBzdHJpbmdcbiAgbmFtZT86IHN0cmluZ1xuICBub3Rlcz86IFJlZmVyZW5jZXNCeUluc3RhbnRcbiAgb2ZmaWNpYWxfam91cm5hbF9kYXRlPzogT2ZmaWNpYWxKb3VybmFsRGF0ZXNCeUluc3RhbnRcbiAgcGFyZW50PzogTm9kZVBhcmFtZXRlciAvLyBHZW5lcmF0ZWQgYXR0cmlidXRlXG4gIHJlZmVyZW5jZT86IFJlZmVyZW5jZXNCeUluc3RhbnRcbiAgcmVmZXJyaW5nX3ZhcmlhYmxlcz86IHN0cmluZ1tdXG4gIHNob3J0X2xhYmVsPzogc3RyaW5nXG4gIHNob3J0X2xhYmVsX2VuPzogc3RyaW5nXG4gIHRpdGxlPzogc3RyaW5nIC8vIEdlbmVyYXRlZCBhdHRyaWJ1dGUgY29uc3RydWN0ZWQgdXNpbmcgc2hvcnRfbGFiZWwgb3IgZGVzY3JpcHRpb24gb3IgbmFtZVxuICB0aXRsZXM/OiBzdHJpbmdbXSAvLyBHZW5lcmF0ZWQgYXR0cmlidXRlIGFnZ3JlZ2F0aW5nIHRoZSB0aXRsZXMgb2YgZXZlcnkgYW5jZXN0b3JzXG59XG5cbmV4cG9ydCBlbnVtIFBhcmFtZXRlckNsYXNzIHtcbiAgTm9kZSA9IFwiTm9kZVwiLFxuICBTY2FsZSA9IFwiU2NhbGVcIixcbiAgVmFsdWUgPSBcIlZhbHVlXCIsXG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgUGFyYW1ldGVyV2l0aEFuY2VzdG9ycyB7XG4gIHBhcmFtZXRlcjogUGFyYW1ldGVyXG4gIGFuY2VzdG9yczogTm9kZVBhcmFtZXRlcltdXG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgUmF0ZUJyYWNrZXQgZXh0ZW5kcyBCcmFja2V0QmFzZSB7XG4gIGJhc2U/OiB7IFtpbnN0YW50OiBzdHJpbmddOiBOdW1iZXJWYWx1ZSB8IFwiZXhwZWN0ZWRcIiB9XG4gIHJhdGU6IHsgW2luc3RhbnQ6IHN0cmluZ106IE1heWJlTnVtYmVyVmFsdWUgfCBcImV4cGVjdGVkXCIgfVxufVxuXG5leHBvcnQgaW50ZXJmYWNlIFJhdGVCcmFja2V0QXRJbnN0YW50IGV4dGVuZHMgQnJhY2tldEF0SW5zdGFudEJhc2Uge1xuICBiYXNlPzogTnVtYmVyVmFsdWUgfCBcImV4cGVjdGVkXCJcbiAgcmF0ZTogTWF5YmVOdW1iZXJWYWx1ZSB8IFwiZXhwZWN0ZWRcIlxufVxuXG5leHBvcnQgdHlwZSBTY2FsZUF0SW5zdGFudCA9IEJyYWNrZXRBdEluc3RhbnRbXVxuXG5leHBvcnQgdHlwZSBTY2FsZVBhcmFtZXRlciA9XG4gIHwgTGluZWFyQXZlcmFnZVJhdGVTY2FsZVBhcmFtZXRlclxuICB8IE1hcmdpbmFsQW1vdW50U2NhbGVQYXJhbWV0ZXJcbiAgfCBNYXJnaW5hbFJhdGVTY2FsZVBhcmFtZXRlclxuICB8IFNpbmdsZUFtb3VudFNjYWxlUGFyYW1ldGVyXG5cbmV4cG9ydCBpbnRlcmZhY2UgU2NhbGVQYXJhbWV0ZXJCYXNlIGV4dGVuZHMgUGFyYW1ldGVyQmFzZSB7XG4gIGJyYWNrZXRzOiBBbW91bnRCcmFja2V0W10gfCBSYXRlQnJhY2tldFtdXG4gIGNsYXNzOiBQYXJhbWV0ZXJDbGFzcy5TY2FsZVxuICBpcHBfY3N2X2lkPzogc3RyaW5nIHwgeyBbYnJhY2tldE5hbWU6IHN0cmluZ106IHN0cmluZyB9XG4gIHRocmVzaG9sZF91bml0Pzogc3RyaW5nXG4gIHR5cGU6IFNjYWxlVHlwZVxufVxuXG5leHBvcnQgZW51bSBTY2FsZVR5cGUge1xuICBMaW5lYXJBdmVyYWdlUmF0ZSA9IFwibGluZWFyX2F2ZXJhZ2VfcmF0ZVwiLFxuICBNYXJnaW5hbEFtb3VudCA9IFwibWFyZ2luYWxfYW1vdW50XCIsXG4gIE1hcmdpbmFsUmF0ZSA9IFwibWFyZ2luYWxfcmF0ZVwiLFxuICBTaW5nbGVBbW91bnQgPSBcInNpbmdsZV9hbW91bnRcIixcbn1cblxuZXhwb3J0IGludGVyZmFjZSBTaW5nbGVBbW91bnRTY2FsZVBhcmFtZXRlciBleHRlbmRzIFNjYWxlUGFyYW1ldGVyQmFzZSB7XG4gIGFtb3VudF91bml0Pzogc3RyaW5nXG4gIGJyYWNrZXRzOiBBbW91bnRCcmFja2V0W11cbiAgdHlwZTogU2NhbGVUeXBlLlNpbmdsZUFtb3VudFxufVxuXG5leHBvcnQgaW50ZXJmYWNlIFN0cmluZ0FycmF5UGFyYW1ldGVyIGV4dGVuZHMgVmFsdWVQYXJhbWV0ZXJCYXNlIHtcbiAgdHlwZTogVmFsdWVUeXBlLlN0cmluZ0FycmF5XG4gIHZhbHVlczogeyBbaW5zdGFudDogc3RyaW5nXTogTWF5YmVTdHJpbmdBcnJheVZhbHVlIH1cbn1cblxuZXhwb3J0IGludGVyZmFjZSBTdHJpbmdCeVN0cmluZ1BhcmFtZXRlciBleHRlbmRzIFZhbHVlUGFyYW1ldGVyQmFzZSB7XG4gIHR5cGU6IFZhbHVlVHlwZS5TdHJpbmdCeVN0cmluZ1xuICB2YWx1ZXM6IHsgW2luc3RhbnQ6IHN0cmluZ106IE1heWJlU3RyaW5nQnlTdHJpbmdWYWx1ZSB9XG59XG5cbmV4cG9ydCB0eXBlIFZhbHVlQXRJbnN0YW50ID1cbiAgfCBCb29sZWFuVmFsdWVcbiAgfCBNYXliZUJvb2xlYW5WYWx1ZVxuICB8IE1heWJlTnVtYmVyVmFsdWVcbiAgfCBNYXliZVN0cmluZ0FycmF5VmFsdWVcbiAgfCBNYXliZVN0cmluZ0J5U3RyaW5nVmFsdWVcbiAgfCBOdW1iZXJWYWx1ZVxuICB8IFwiZXhwZWN0ZWRcIlxuXG5leHBvcnQgaW50ZXJmYWNlIFZhbHVlQmFzZSB7XG4gIHJlZmVyZW5jZT86IFJlZmVyZW5jZVtdXG4gIHVuaXQ/OiBzdHJpbmcgLy8gTm90ZTogQSBicmFja2V0IHZhbHVlIGhhcyBubyB1bml0LlxuICB2YWx1ZT86IHVua25vd25cbn1cblxuZXhwb3J0IHR5cGUgVmFsdWVQYXJhbWV0ZXIgPVxuICB8IEJvb2xlYW5QYXJhbWV0ZXJcbiAgfCBOdW1iZXJQYXJhbWV0ZXJcbiAgfCBTdHJpbmdBcnJheVBhcmFtZXRlclxuICB8IFN0cmluZ0J5U3RyaW5nUGFyYW1ldGVyXG5cbmV4cG9ydCBpbnRlcmZhY2UgVmFsdWVQYXJhbWV0ZXJCYXNlIGV4dGVuZHMgUGFyYW1ldGVyQmFzZSB7XG4gIGNsYXNzOiBQYXJhbWV0ZXJDbGFzcy5WYWx1ZVxuICBpcHBfY3N2X2lkPzogc3RyaW5nXG4gIHR5cGU6IFZhbHVlVHlwZVxuICB1bml0Pzogc3RyaW5nXG4gIHZhbHVlczogeyBbaW5zdGFudDogc3RyaW5nXTogVmFsdWVBdEluc3RhbnQgfVxufVxuXG5leHBvcnQgZW51bSBWYWx1ZVR5cGUge1xuICBCb29sZWFuID0gXCJib29sZWFuXCIsXG4gIE51bWJlciA9IFwibnVtYmVyXCIsXG4gIFN0cmluZ0FycmF5ID0gXCJzdHJpbmdfYXJyYXlcIixcbiAgU3RyaW5nQnlTdHJpbmcgPSBcInN0cmluZ19ieV9zdHJpbmdcIixcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGFjY2Vzc1BhcmFtZXRlckZyb21JZHMoXG4gIHBhcmFtZXRlcjogUGFyYW1ldGVyLFxuICBpZHM6IHN0cmluZ1tdLFxuKTogW1BhcmFtZXRlciwgdW5rbm93bl0ge1xuICBmb3IgKGNvbnN0IGlkIG9mIGlkcykge1xuICAgIGlmIChwYXJhbWV0ZXIuY2xhc3MgIT09IFBhcmFtZXRlckNsYXNzLk5vZGUpIHtcbiAgICAgIHJldHVybiBbXG4gICAgICAgIHBhcmFtZXRlcixcbiAgICAgICAgYENhbid0IGFjY2VzcyB0byBjaGlsZCBcIiR7aWR9XCIgaW4gcGFyYW1ldGVyICR7cGFyYW1ldGVyLm5hbWV9LCBiZWNhdXNlIGl0IGlzIG5vdCBhIG5vZGVgLFxuICAgICAgXVxuICAgIH1cbiAgICBjb25zdCBjaGlsZCA9IHBhcmFtZXRlci5jaGlsZHJlbj8uW2lkXVxuICAgIGlmIChjaGlsZCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICByZXR1cm4gW1xuICAgICAgICBwYXJhbWV0ZXIsXG4gICAgICAgIGBQYXJhbWV0ZXIgJHtwYXJhbWV0ZXIubmFtZX0gaGFzIG5vIGNoaWxkIG5hbWVkIFwiJHtpZH1cImAsXG4gICAgICBdXG4gICAgfVxuICAgIHBhcmFtZXRlciA9IGNoaWxkXG4gIH1cbiAgcmV0dXJuIFtwYXJhbWV0ZXIsIG51bGxdXG59XG5cbi8vLyBDb252ZXJ0IGEgZGljdGlvbmFyeSBvZiBicmFja2V0cyBieSBpbnN0YW50IHRvIGEgbGlzdCBvZiBicmFja2V0c1xuLy8vIGNvbnRhaW5pbmcgYW1vdW50cywgYmFzZXMsIHJhdGVzICYgdGhyZXNob2xkcyBieSBpbnN0YW50LlxuZXhwb3J0IGZ1bmN0aW9uIGJyYWNrZXRzRnJvbVNjYWxlQnlJbnN0YW50KHNjYWxlQnlJbnN0YW50OiB7XG4gIFtpbnN0YW50OiBzdHJpbmddOiBTY2FsZUF0SW5zdGFudFxufSk6IEFtb3VudEJyYWNrZXRbXSB8IFJhdGVCcmFja2V0W10ge1xuICBjb25zdCBicmFja2V0czogUGFydGlhbDxCcmFja2V0PltdID0gW11cbiAgZm9yIChjb25zdCBrZXkgb2YgW1wiYW1vdW50XCIsIFwiYmFzZVwiLCBcInJhdGVcIiwgXCJ0aHJlc2hvbGRcIl0pIHtcbiAgICBsZXQgbGF0ZXN0VmFsdWU6IE1heWJlTnVtYmVyVmFsdWUgfCBcImV4cGVjdGVkXCIgfCB1bmRlZmluZWQgPSB1bmRlZmluZWRcbiAgICBmb3IgKGNvbnN0IFtpbnN0YW50LCBzY2FsZUF0SW5zdGFudF0gb2YgT2JqZWN0LmVudHJpZXMoc2NhbGVCeUluc3RhbnQpLnNvcnQoXG4gICAgICAoW2luc3RhbnQxXSwgW2luc3RhbnQyXSkgPT4gaW5zdGFudDEubG9jYWxlQ29tcGFyZShpbnN0YW50MiksXG4gICAgKSkge1xuICAgICAgZm9yIChjb25zdCBbYnJhY2tldEluZGV4LCBicmFja2V0QXRJbnN0YW50XSBvZiBzY2FsZUF0SW5zdGFudC5lbnRyaWVzKCkpIHtcbiAgICAgICAgaWYgKGJyYWNrZXRzLmxlbmd0aCA8PSBicmFja2V0SW5kZXgpIHtcbiAgICAgICAgICBicmFja2V0cy5wdXNoKHt9KVxuICAgICAgICB9XG4gICAgICAgIGNvbnN0IHZhbHVlID0gYnJhY2tldEF0SW5zdGFudFtrZXkgYXMga2V5b2YgQnJhY2tldEF0SW5zdGFudF1cbiAgICAgICAgaWYgKHZhbHVlICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICBjb25zdCBicmFja2V0ID0gYnJhY2tldHNbYnJhY2tldEluZGV4XVxuICAgICAgICAgIGxldCB2YWx1ZUJ5SW5zdGFudCA9IGJyYWNrZXRba2V5IGFzIGtleW9mIEJyYWNrZXRdXG4gICAgICAgICAgaWYgKHZhbHVlQnlJbnN0YW50ID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgIHZhbHVlQnlJbnN0YW50ID0gYnJhY2tldFtrZXkgYXMga2V5b2YgQnJhY2tldF0gPSB7fVxuICAgICAgICAgIH1cbiAgICAgICAgICBpZiAodmFsdWUgPT09IFwiZXhwZWN0ZWRcIikge1xuICAgICAgICAgICAgaWYgKHZhbHVlICE9PSBsYXRlc3RWYWx1ZSkge1xuICAgICAgICAgICAgICBsYXRlc3RWYWx1ZSA9IHZhbHVlQnlJbnN0YW50W2luc3RhbnRdID0gdmFsdWVcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9IGVsc2UgaWYgKFxuICAgICAgICAgICAgbGF0ZXN0VmFsdWUgPT09IHVuZGVmaW5lZCB8fFxuICAgICAgICAgICAgbGF0ZXN0VmFsdWUgPT09IFwiZXhwZWN0ZWRcIiB8fFxuICAgICAgICAgICAgdmFsdWUudmFsdWUgIT09IGxhdGVzdFZhbHVlLnZhbHVlXG4gICAgICAgICAgKSB7XG4gICAgICAgICAgICBsYXRlc3RWYWx1ZSA9IHZhbHVlQnlJbnN0YW50W2luc3RhbnRdID0gdmFsdWVcbiAgICAgICAgICB9IGVsc2UgaWYgKHZhbHVlLnJlZmVyZW5jZSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICBsZXQgbGF0ZXN0UmVmZXJlbmNlcyA9IGxhdGVzdFZhbHVlLnJlZmVyZW5jZVxuICAgICAgICAgICAgaWYgKGxhdGVzdFJlZmVyZW5jZXMgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgICBsYXRlc3RSZWZlcmVuY2VzID0gbGF0ZXN0VmFsdWUucmVmZXJlbmNlID0gW11cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGZvciAoY29uc3QgcmVmZXJlbmNlIG9mIHZhbHVlLnJlZmVyZW5jZSkge1xuICAgICAgICAgICAgICBpZiAoXG4gICAgICAgICAgICAgICAgIWxhdGVzdFJlZmVyZW5jZXMuc29tZShcbiAgICAgICAgICAgICAgICAgIChsYXRlc3RSZWZlcmVuY2UpID0+XG4gICAgICAgICAgICAgICAgICAgIGxhdGVzdFJlZmVyZW5jZS5ocmVmID09PSByZWZlcmVuY2UuaHJlZiAmJlxuICAgICAgICAgICAgICAgICAgICBsYXRlc3RSZWZlcmVuY2UudGl0bGUgPT09IHJlZmVyZW5jZS50aXRsZSxcbiAgICAgICAgICAgICAgICApXG4gICAgICAgICAgICAgICkge1xuICAgICAgICAgICAgICAgIGxhdGVzdFJlZmVyZW5jZXMucHVzaChyZWZlcmVuY2UpXG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gIH1cbiAgcmV0dXJuIGJyYWNrZXRzIGFzIEFtb3VudEJyYWNrZXRbXSB8IFJhdGVCcmFja2V0W11cbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGltcHJvdmVQYXJhbWV0ZXIoXG4gIHBhcmFtZXRlcjogUGFyYW1ldGVyLFxuICBwYXJlbnQ6IE5vZGVQYXJhbWV0ZXIgfCB1bmRlZmluZWQgfCBudWxsID0gdW5kZWZpbmVkLFxuICBpZHM6IHN0cmluZ1tdID0gW10sXG4pOiB2b2lkIHtcbiAgY29uc3QgaWQgPSBpZHNbaWRzLmxlbmd0aCAtIDFdXG4gIGlmIChpZCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgcGFyYW1ldGVyLmlkID0gaWRcbiAgfVxuICBpZiAocGFyYW1ldGVyLm5hbWUgPT09IHVuZGVmaW5lZCkge1xuICAgIHBhcmFtZXRlci5uYW1lID0gaWRzLmpvaW4oXCIuXCIpXG4gIH1cbiAgaWYgKHBhcmVudCAhPSBudWxsKSB7XG4gICAgcGFyYW1ldGVyLnBhcmVudCA9IHBhcmVudFxuICB9XG4gIGNvbnN0IHRpdGxlID1cbiAgICBwYXJhbWV0ZXIuc2hvcnRfbGFiZWwgPz9cbiAgICBwYXJhbWV0ZXIuZGVzY3JpcHRpb24gPz9cbiAgICBpZD8ucmVwbGFjZSgvXy9nLCBcIiBcIikucmVwbGFjZSgvXlxcdy8sIChjKSA9PiBjLnRvVXBwZXJDYXNlKCkpXG4gIGlmICh0aXRsZSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgcGFyYW1ldGVyLnRpdGxlID0gdGl0bGVcbiAgfVxuICBwYXJhbWV0ZXIudGl0bGVzID0gKFxuICAgIHRpdGxlID09PSB1bmRlZmluZWRcbiAgICAgID8gKHBhcmVudD8udGl0bGVzID8/IFtdKVxuICAgICAgOiBbLi4uKHBhcmVudD8udGl0bGVzID8/IFtdKSwgdGl0bGVdXG4gICkuZmlsdGVyKEJvb2xlYW4pXG5cbiAgc3dpdGNoIChwYXJhbWV0ZXIuY2xhc3MpIHtcbiAgICBjYXNlIFBhcmFtZXRlckNsYXNzLk5vZGU6XG4gICAgICBpZiAocGFyYW1ldGVyLmNoaWxkcmVuICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgZm9yIChjb25zdCBbY2hpbGRJZCwgY2hpbGRdIG9mIE9iamVjdC5lbnRyaWVzKHBhcmFtZXRlci5jaGlsZHJlbikpIHtcbiAgICAgICAgICBpbXByb3ZlUGFyYW1ldGVyKGNoaWxkLCBwYXJhbWV0ZXIsIFsuLi5pZHMsIGNoaWxkSWRdKVxuICAgICAgICB9XG4gICAgICB9XG4gICAgICBicmVha1xuICAgIGRlZmF1bHQ6XG4gIH1cbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGlzQW1vdW50U2NhbGVQYXJhbWV0ZXIocGFyYW1ldGVyOiBTY2FsZVBhcmFtZXRlcikge1xuICByZXR1cm4gW1NjYWxlVHlwZS5NYXJnaW5hbEFtb3VudCwgU2NhbGVUeXBlLlNpbmdsZUFtb3VudF0uaW5jbHVkZXMoXG4gICAgcGFyYW1ldGVyLnR5cGUsXG4gIClcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGlzUmF0ZVNjYWxlUGFyYW1ldGVyKHBhcmFtZXRlcjogU2NhbGVQYXJhbWV0ZXIpIHtcbiAgcmV0dXJuICFbU2NhbGVUeXBlLk1hcmdpbmFsQW1vdW50LCBTY2FsZVR5cGUuU2luZ2xlQW1vdW50XS5pbmNsdWRlcyhcbiAgICBwYXJhbWV0ZXIudHlwZSxcbiAgKVxufVxuXG5leHBvcnQgZnVuY3Rpb24gaXNWZWN0b3JpYWxOb2RlUGFyYW1ldGVyKG5vZGU6IE5vZGVQYXJhbWV0ZXIpOiBib29sZWFuIHtcbiAgaWYgKG5vZGUuY2hpbGRyZW4gPT09IHVuZGVmaW5lZCB8fCBPYmplY3Qua2V5cyhub2RlLmNoaWxkcmVuKS5sZW5ndGggPD0gMSkge1xuICAgIHJldHVybiBmYWxzZVxuICB9XG4gIGNvbnN0IGNoaWxkcmVuID0gT2JqZWN0LnZhbHVlcyhub2RlLmNoaWxkcmVuKSBhcyBWYWx1ZVBhcmFtZXRlcltdXG4gIGlmIChjaGlsZHJlbi5zb21lKChjaGlsZCkgPT4gY2hpbGQuY2xhc3MgIT09IFBhcmFtZXRlckNsYXNzLlZhbHVlKSkge1xuICAgIHJldHVybiBmYWxzZVxuICB9XG4gIGNvbnN0IGNvbW1vblR5cGUgPSBjaGlsZHJlblswXS50eXBlXG4gIGlmIChjaGlsZHJlbi5zb21lKChjaGlsZCkgPT4gY2hpbGQudHlwZSAhPT0gY29tbW9uVHlwZSkpIHtcbiAgICByZXR1cm4gZmFsc2VcbiAgfVxuICBjb25zdCBjb21tb25GaWxlUGF0aCA9IGNoaWxkcmVuWzBdLmZpbGVfcGF0aFxuICBpZiAoY2hpbGRyZW4uc29tZSgoY2hpbGQpID0+IGNoaWxkLmZpbGVfcGF0aCAhPT0gY29tbW9uRmlsZVBhdGgpKSB7XG4gICAgcmV0dXJuIGZhbHNlXG4gIH1cbiAgcmV0dXJuIHRydWVcbn1cblxuZXhwb3J0IGZ1bmN0aW9uKiBpdGVyUGFyYW1ldGVyQW5jZXN0b3JzKFxuICBwYXJhbWV0ZXI/OiBQYXJhbWV0ZXIgfCB1bmRlZmluZWQgfCBudWxsLFxuKTogR2VuZXJhdG9yPFBhcmFtZXRlciwgdm9pZCwgdW5rbm93bj4ge1xuICBpZiAocGFyYW1ldGVyID09IG51bGwgfHwgIXBhcmFtZXRlci5pZCkge1xuICAgIHJldHVyblxuICB9XG4gIHlpZWxkKiBpdGVyUGFyYW1ldGVyQW5jZXN0b3JzKHBhcmFtZXRlci5wYXJlbnQpXG4gIHlpZWxkIHBhcmFtZXRlclxufVxuXG5mdW5jdGlvbiBtZXJnZUR1cGxpY2F0ZVBhcmFtZXRlcnMoXG4gIGV4aXN0aW5nUGFyYW1ldGVyOiBQYXJhbWV0ZXIsXG4gIHBhcmFtZXRlcjogUGFyYW1ldGVyLFxuKTogdm9pZCB7XG4gIGlmIChleGlzdGluZ1BhcmFtZXRlci5jbGFzcyA9PT0gUGFyYW1ldGVyQ2xhc3MuTm9kZSkge1xuICAgIGNvbnN0IGV4aXN0aW5nQ2hpZHJlbiA9IGV4aXN0aW5nUGFyYW1ldGVyLmNoaWxkcmVuIGFzIHtcbiAgICAgIFtpZDogc3RyaW5nXTogUGFyYW1ldGVyXG4gICAgfVxuICAgIGZvciAoY29uc3QgY2hpbGQgb2YgT2JqZWN0LnZhbHVlcyhcbiAgICAgIChwYXJhbWV0ZXIgYXMgTm9kZVBhcmFtZXRlcikuY2hpbGRyZW4gYXMge1xuICAgICAgICBbaWQ6IHN0cmluZ106IFBhcmFtZXRlclxuICAgICAgfSxcbiAgICApKSB7XG4gICAgICBjb25zdCBleGlzdGluZ0NoaWxkID0gZXhpc3RpbmdDaGlkcmVuW2NoaWxkLmlkID8/IFwiXCJdXG4gICAgICBpZiAoZXhpc3RpbmdDaGlsZCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIGV4aXN0aW5nQ2hpZHJlbltjaGlsZC5pZCA/PyBcIlwiXSA9IGNoaWxkXG4gICAgICAgIGNoaWxkLnBhcmVudCA9IGV4aXN0aW5nUGFyYW1ldGVyXG4gICAgICB9IGVsc2Uge1xuICAgICAgICBtZXJnZUR1cGxpY2F0ZVBhcmFtZXRlcnMoZXhpc3RpbmdDaGlsZCwgY2hpbGQpXG4gICAgICB9XG4gICAgfVxuICB9XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBtZXJnZVBhcmFtZXRlcnMocGFyYW1ldGVyczogUGFyYW1ldGVyW10pOiB7XG4gIFtpZDogc3RyaW5nXTogUGFyYW1ldGVyXG59IHtcbiAgY29uc3Qgcm9vdFBhcmFtZXRlckJ5SWQ6IHsgW2lkOiBzdHJpbmddOiBQYXJhbWV0ZXIgfSA9IHt9XG4gIGZvciAoY29uc3QgcGFyYW1ldGVyIG9mIHBhcmFtZXRlcnMpIHtcbiAgICAvLyBDcmVhdGUgYSBjb3B5IG9mIHRoZSBwYXJhbWV0ZXJzIHRyZWUsIGNvbnRhaW5pbmcgb25seSB0aGlzIHBhcmFtZXRlci5cbiAgICBsZXQgcm9vdFBhcmFtZXRlciA9IHsgLi4ucGFyYW1ldGVyIH1cbiAgICBmb3IgKFxuICAgICAgbGV0IGFuY2VzdG9yOiBOb2RlUGFyYW1ldGVyIHwgdW5kZWZpbmVkID0gcm9vdFBhcmFtZXRlci5wYXJlbnQ7XG4gICAgICBhbmNlc3RvciAhPT0gdW5kZWZpbmVkICYmIGFuY2VzdG9yLmlkO1xuICAgICAgcm9vdFBhcmFtZXRlciA9IGFuY2VzdG9yISwgYW5jZXN0b3IgPSByb290UGFyYW1ldGVyLnBhcmVudFxuICAgICkge1xuICAgICAgYW5jZXN0b3IgPSB7XG4gICAgICAgIC4uLmFuY2VzdG9yLFxuICAgICAgICBjaGlsZHJlbjogeyBbcm9vdFBhcmFtZXRlci5pZCFdOiByb290UGFyYW1ldGVyIH0sXG4gICAgICB9XG4gICAgICByb290UGFyYW1ldGVyLnBhcmVudCA9IGFuY2VzdG9yXG4gICAgfVxuXG4gICAgLy8gTWVyZ2UgdGhpcyBzaW1wbGlmaWVkIHBhcmFtZXRlcnMgdHJlZSB3aXRoIHRoZSBvdGhlcnMuXG4gICAgY29uc3QgZXhpc3RpbmdSb290UGFyYW1ldGVyID0gcm9vdFBhcmFtZXRlckJ5SWRbcm9vdFBhcmFtZXRlci5pZCA/PyBcIlwiXVxuICAgIGlmIChleGlzdGluZ1Jvb3RQYXJhbWV0ZXIgPT09IHVuZGVmaW5lZCkge1xuICAgICAgcm9vdFBhcmFtZXRlckJ5SWRbcm9vdFBhcmFtZXRlci5pZCA/PyBcIlwiXSA9IHJvb3RQYXJhbWV0ZXJcbiAgICB9IGVsc2Uge1xuICAgICAgbWVyZ2VEdXBsaWNhdGVQYXJhbWV0ZXJzKGV4aXN0aW5nUm9vdFBhcmFtZXRlciwgcm9vdFBhcmFtZXRlcilcbiAgICB9XG4gIH1cbiAgcmV0dXJuIHJvb3RQYXJhbWV0ZXJCeUlkXG59XG5cbmV4cG9ydCBmdW5jdGlvbiBtZXJnZVJlZmVyZW5jZXMoXG4gIHJlZmVyZW5jZXMxOiBSZWZlcmVuY2VbXSB8IHVuZGVmaW5lZCB8IG51bGwsXG4gIHJlZmVyZW5jZXMyOiBSZWZlcmVuY2VbXSB8IHVuZGVmaW5lZCB8IG51bGwsXG4pOiBSZWZlcmVuY2VbXSB8IHVuZGVmaW5lZCB7XG4gIGlmIChyZWZlcmVuY2VzMSA9PSBudWxsKSB7XG4gICAgcmV0dXJuIHJlZmVyZW5jZXMyID8/IHVuZGVmaW5lZFxuICB9XG4gIGlmIChyZWZlcmVuY2VzMiA9PSBudWxsKSB7XG4gICAgcmV0dXJuIHJlZmVyZW5jZXMxID8/IHVuZGVmaW5lZFxuICB9XG4gIGNvbnN0IHJlZmVyZW5jZXMgPSBbLi4ucmVmZXJlbmNlczFdXG4gIGZvciAoY29uc3QgcmVmZXJlbmNlMiBvZiByZWZlcmVuY2VzMikge1xuICAgIGxldCBmb3VuZCA9IGZhbHNlXG4gICAgaWYgKHJlZmVyZW5jZTIuaHJlZiAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICBjb25zdCBpbmRleCA9IHJlZmVyZW5jZXMuZmluZEluZGV4KFxuICAgICAgICAocmVmZXJlbmNlKSA9PiByZWZlcmVuY2UuaHJlZiA9PT0gcmVmZXJlbmNlMi5ocmVmLFxuICAgICAgKVxuICAgICAgaWYgKGluZGV4ID49IDApIHtcbiAgICAgICAgZm91bmQgPSB0cnVlXG4gICAgICAgIGxldCByZWZlcmVuY2UgPSByZWZlcmVuY2VzW2luZGV4XVxuICAgICAgICBsZXQgY2hhbmdlZCA9IGZhbHNlXG4gICAgICAgIGlmIChyZWZlcmVuY2Uubm90ZSA9PT0gdW5kZWZpbmVkICYmIHJlZmVyZW5jZTIubm90ZSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgaWYgKCFjaGFuZ2VkKSB7XG4gICAgICAgICAgICBjaGFuZ2VkID0gdHJ1ZVxuICAgICAgICAgICAgcmVmZXJlbmNlID0gcmVmZXJlbmNlc1tpbmRleF0gPSB7IC4uLnJlZmVyZW5jZSB9XG4gICAgICAgICAgfVxuICAgICAgICAgIHJlZmVyZW5jZS5ub3RlID0gcmVmZXJlbmNlMi5ub3RlXG4gICAgICAgIH1cbiAgICAgICAgaWYgKHJlZmVyZW5jZS50aXRsZSA9PT0gdW5kZWZpbmVkICYmIHJlZmVyZW5jZTIudGl0bGUgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgIGlmICghY2hhbmdlZCkge1xuICAgICAgICAgICAgY2hhbmdlZCA9IHRydWVcbiAgICAgICAgICAgIHJlZmVyZW5jZSA9IHJlZmVyZW5jZXNbaW5kZXhdID0geyAuLi5yZWZlcmVuY2UgfVxuICAgICAgICAgIH1cbiAgICAgICAgICByZWZlcmVuY2UudGl0bGUgPSByZWZlcmVuY2UyLnRpdGxlXG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9IGVsc2UgaWYgKHJlZmVyZW5jZTIudGl0bGUgIT09IHVuZGVmaW5lZCkge1xuICAgICAgY29uc3QgaW5kZXggPSByZWZlcmVuY2VzLmZpbmRJbmRleChcbiAgICAgICAgKHJlZmVyZW5jZSkgPT4gcmVmZXJlbmNlLnRpdGxlID09PSByZWZlcmVuY2UyLnRpdGxlLFxuICAgICAgKVxuICAgICAgaWYgKGluZGV4ID49IDApIHtcbiAgICAgICAgZm91bmQgPSB0cnVlXG4gICAgICAgIGxldCByZWZlcmVuY2UgPSByZWZlcmVuY2VzW2luZGV4XVxuICAgICAgICBpZiAocmVmZXJlbmNlLm5vdGUgPT09IHVuZGVmaW5lZCAmJiByZWZlcmVuY2UyLm5vdGUgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgIHJlZmVyZW5jZSA9IHJlZmVyZW5jZXNbaW5kZXhdID0geyAuLi5yZWZlcmVuY2UgfVxuICAgICAgICAgIHJlZmVyZW5jZS5ub3RlID0gcmVmZXJlbmNlMi5ub3RlXG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgLy8gYXNzZXJ0Lm5vdFN0cmljdEVxdWFsKHJlZmVyZW5jZTIubm90ZSwgdW5kZWZpbmVkKVxuICAgICAgY29uc3QgaW5kZXggPSByZWZlcmVuY2VzLmZpbmRJbmRleChcbiAgICAgICAgKHJlZmVyZW5jZSkgPT4gcmVmZXJlbmNlLm5vdGUgPT09IHJlZmVyZW5jZTIubm90ZSxcbiAgICAgIClcbiAgICAgIGlmIChpbmRleCA+PSAwKSB7XG4gICAgICAgIGZvdW5kID0gdHJ1ZVxuICAgICAgfVxuICAgIH1cbiAgICBpZiAoIWZvdW5kKSB7XG4gICAgICByZWZlcmVuY2VzLnB1c2gocmVmZXJlbmNlMilcbiAgICB9XG4gIH1cbiAgcmV0dXJuIHJlZmVyZW5jZXNcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIG5ld1BhcmFtZXRlclJlcG9zaXRvcnlVcmwoXG4gIG1ldGFkYXRhOiBNZXRhZGF0YSxcbiAgcGFyYW1ldGVyOiBQYXJhbWV0ZXIsXG4pOiBzdHJpbmcgfCB1bmRlZmluZWQge1xuICBpZiAocGFyYW1ldGVyLmZpbGVfcGF0aCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgcmV0dXJuIHVuZGVmaW5lZFxuICB9XG4gIGNvbnN0IHBhY2thZ2VOYW1lID0gcGFyYW1ldGVyLmZpbGVfcGF0aC5zcGxpdChcIi9cIilbMF1cbiAgZm9yIChjb25zdCBwYWNrYWdlTWV0YWRhdGEgb2YgbWV0YWRhdGEucGFja2FnZXMpIHtcbiAgICBpZiAocGFja2FnZU1ldGFkYXRhLm5hbWUgPT09IHBhY2thZ2VOYW1lKSB7XG4gICAgICByZXR1cm4gYCR7cGFja2FnZU1ldGFkYXRhLnJlcG9zaXRvcnlfdXJsfS9ibG9iLyR7cGFja2FnZU1ldGFkYXRhLnZlcnNpb259LyR7cGFyYW1ldGVyLmZpbGVfcGF0aH1gXG4gICAgfVxuICB9XG4gIHJldHVybiB1bmRlZmluZWRcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHBhcmFtZXRlckxhc3RSZXZpZXdPckNoYW5nZShcbiAgcGFyYW1ldGVyOiBQYXJhbWV0ZXIsXG4pOiBzdHJpbmcgfCB1bmRlZmluZWQge1xuICBzd2l0Y2ggKHBhcmFtZXRlci5jbGFzcykge1xuICAgIGNhc2UgUGFyYW1ldGVyQ2xhc3MuTm9kZTpcbiAgICAgIHJldHVybiBwYXJhbWV0ZXIubGFzdF92YWx1ZV9zdGlsbF92YWxpZF9vblxuXG4gICAgY2FzZSBQYXJhbWV0ZXJDbGFzcy5TY2FsZToge1xuICAgICAgY29uc3QgbGF0ZXN0SW5zdGFudCA9IFtcbiAgICAgICAgcGFyYW1ldGVyLmxhc3RfdmFsdWVfc3RpbGxfdmFsaWRfb24sXG4gICAgICAgIC4uLk9iamVjdC5rZXlzKHNjYWxlQnlJbnN0YW50RnJvbUJyYWNrZXRzKHBhcmFtZXRlci5icmFja2V0cykpLFxuICAgICAgXVxuICAgICAgICAuZmlsdGVyKChpbnN0YW50KSA9PiBpbnN0YW50ICE9PSB1bmRlZmluZWQpXG4gICAgICAgIC5zb3J0KChpbnN0YW50MSwgaW5zdGFudDIpID0+IGluc3RhbnQyIS5sb2NhbGVDb21wYXJlKGluc3RhbnQxISkpWzBdXG4gICAgICByZXR1cm4gbGF0ZXN0SW5zdGFudFxuICAgIH1cblxuICAgIGNhc2UgUGFyYW1ldGVyQ2xhc3MuVmFsdWU6IHtcbiAgICAgIGNvbnN0IGxhdGVzdEluc3RhbnQgPSBbXG4gICAgICAgIHBhcmFtZXRlci5sYXN0X3ZhbHVlX3N0aWxsX3ZhbGlkX29uLFxuICAgICAgICAuLi5PYmplY3Qua2V5cyhwYXJhbWV0ZXIudmFsdWVzKSxcbiAgICAgIF1cbiAgICAgICAgLmZpbHRlcigoaW5zdGFudCkgPT4gaW5zdGFudCAhPT0gdW5kZWZpbmVkKVxuICAgICAgICAuc29ydCgoaW5zdGFudDEsIGluc3RhbnQyKSA9PiBpbnN0YW50MiEubG9jYWxlQ29tcGFyZShpbnN0YW50MSEpKVswXVxuICAgICAgcmV0dXJuIGxhdGVzdEluc3RhbnRcbiAgICB9XG4gIH1cbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHBhcmFtZXRlcldpdGhvdXRDaGlsZHJlbihwYXJhbWV0ZXI6IFBhcmFtZXRlcik6IFBhcmFtZXRlciB7XG4gIGlmIChwYXJhbWV0ZXIuY2xhc3MgPT09IFBhcmFtZXRlckNsYXNzLk5vZGUpIHtcbiAgICBwYXJhbWV0ZXIgPSB7IC4uLnBhcmFtZXRlciB9XG4gICAgZGVsZXRlIHBhcmFtZXRlci5jaGlsZHJlblxuICB9XG4gIHJldHVybiBwYXJhbWV0ZXJcbn1cblxuLy8vIEFwcGx5IGNoYW5nZXMgb2YgYSByZWZvcm0gdG8gKHJvb3QpIHBhcmFtZXRlci5cbmV4cG9ydCBmdW5jdGlvbiBwYXRjaFBhcmFtZXRlcjxQYXJhbWV0ZXJUeXBlIGV4dGVuZHMgUGFyYW1ldGVyPihcbiAgcGFyYW1ldGVyOiBQYXJhbWV0ZXJUeXBlLFxuICBwYXRjaDogeyBba2V5OiBzdHJpbmddOiB1bmtub3duIH0sXG4pOiBQYXJhbWV0ZXJUeXBlIHtcbiAgaWYgKE9iamVjdC5rZXlzKHBhdGNoKS5sZW5ndGggPT09IDApIHtcbiAgICByZXR1cm4gcGFyYW1ldGVyXG4gIH1cbiAgY29uc3QgcGF0Y2hlZFBhcmFtZXRlciA9IHsgLi4ucGFyYW1ldGVyIH1cbiAgZm9yIChjb25zdCBba2V5LCB2YWx1ZV0gb2YgT2JqZWN0LmVudHJpZXMocGF0Y2gpKSB7XG4gICAgaWYgKHZhbHVlID09PSBudWxsKSB7XG4gICAgICBkZWxldGUgKHBhdGNoZWRQYXJhbWV0ZXIgYXMgdW5rbm93biBhcyB7IFtrZXk6IHN0cmluZ106IHVua25vd24gfSlba2V5XVxuICAgIH0gZWxzZSBpZiAoXG4gICAgICAocGF0Y2hlZFBhcmFtZXRlciBhcyB1bmtub3duIGFzIHsgW2tleTogc3RyaW5nXTogdW5rbm93biB9KVtrZXldID09PVxuICAgICAgdW5kZWZpbmVkXG4gICAgKSB7XG4gICAgICA7KHBhdGNoZWRQYXJhbWV0ZXIgYXMgdW5rbm93biBhcyB7IFtrZXk6IHN0cmluZ106IHVua25vd24gfSlba2V5XSA9IHZhbHVlXG4gICAgfSBlbHNlIGlmIChrZXkgPT09IFwiY2hpbGRyZW5cIikge1xuICAgICAgY29uc3QgcGF0Y2hlZENoaWxkcmVuID0gKChwYXRjaGVkUGFyYW1ldGVyIGFzIE5vZGVQYXJhbWV0ZXIpLmNoaWxkcmVuID0ge1xuICAgICAgICAuLi4ocGF0Y2hlZFBhcmFtZXRlciBhcyBOb2RlUGFyYW1ldGVyKS5jaGlsZHJlbixcbiAgICAgIH0pXG4gICAgICBmb3IgKGNvbnN0IFtjaGlsZElkLCBjaGlsZFBhdGNoXSBvZiBPYmplY3QuZW50cmllcyhcbiAgICAgICAgdmFsdWUgYXMgeyBbY2hpbGRJZDogc3RyaW5nXTogdW5rbm93biB9LFxuICAgICAgKSkge1xuICAgICAgICBpZiAoY2hpbGRQYXRjaCA9PT0gbnVsbCkge1xuICAgICAgICAgIGRlbGV0ZSBwYXRjaGVkQ2hpbGRyZW5bY2hpbGRJZF1cbiAgICAgICAgfSBlbHNlIGlmIChwYXRjaGVkQ2hpbGRyZW5bY2hpbGRJZF0gPT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgIHBhdGNoZWRDaGlsZHJlbltjaGlsZElkXSA9IGNoaWxkUGF0Y2ggYXMgUGFyYW1ldGVyXG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgcGF0Y2hlZENoaWxkcmVuW2NoaWxkSWRdID0gcGF0Y2hQYXJhbWV0ZXIoXG4gICAgICAgICAgICBwYXRjaGVkQ2hpbGRyZW5bY2hpbGRJZF0sXG4gICAgICAgICAgICBjaGlsZFBhdGNoIGFzIHsgW2tleTogc3RyaW5nXTogdW5rbm93biB9LFxuICAgICAgICAgIClcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICA7KHBhdGNoZWRQYXJhbWV0ZXIgYXMgdW5rbm93biBhcyB7IFtrZXk6IHN0cmluZ106IHVua25vd24gfSlba2V5XSA9IHZhbHVlXG4gICAgfVxuICB9XG4gIHJldHVybiBwYXRjaGVkUGFyYW1ldGVyXG59XG5cbi8vLyBDb252ZXJ0IGEgbGlzdCBvZiBicmFja2V0cyBjb250YWluaW5nIGFtb3VudHMsIGJhc2VzLCByYXRlcyAmIHRocmVzaG9sZHMgYnkgaW5zdGFudFxuLy8vIHRvIGEgZGljdGlvbmFyeSBvZiBicmFja2V0cyBieSBpbnN0YW50LlxuLy8vIEZvciBoZXVyaXN0aWMsIHNlZSBmdW5jdGlvbiBgYnVpbGRfYXBpX3NjYWxlYCBvZlxuLy8vIGh0dHBzOi8vZ2l0aHViLmNvbS9vcGVuZmlzY2Evb3BlbmZpc2NhLWNvcmUvYmxvYi9tYXN0ZXIvb3BlbmZpc2NhX3dlYl9hcGkvbG9hZGVyL3BhcmFtZXRlcnMucHlcbmV4cG9ydCBmdW5jdGlvbiBzY2FsZUJ5SW5zdGFudEZyb21CcmFja2V0cyhicmFja2V0czogQnJhY2tldFtdKToge1xuICBbaW5zdGFudDogc3RyaW5nXTogU2NhbGVBdEluc3RhbnRcbn0ge1xuICBjb25zdCBpbnN0YW50cyA9IG5ldyBTZXQ8c3RyaW5nPigpXG4gIGZvciAoY29uc3QgYnJhY2tldCBvZiBicmFja2V0cykge1xuICAgIGZvciAoY29uc3QgaW5zdGFudCBvZiBPYmplY3Qua2V5cyhcbiAgICAgIChicmFja2V0IGFzIEFtb3VudEJyYWNrZXQpLmFtb3VudCA/PyB7fSxcbiAgICApKSB7XG4gICAgICBpbnN0YW50cy5hZGQoaW5zdGFudClcbiAgICB9XG4gICAgZm9yIChjb25zdCBpbnN0YW50IG9mIE9iamVjdC5rZXlzKChicmFja2V0IGFzIFJhdGVCcmFja2V0KS5iYXNlID8/IHt9KSkge1xuICAgICAgaW5zdGFudHMuYWRkKGluc3RhbnQpXG4gICAgfVxuICAgIGZvciAoY29uc3QgaW5zdGFudCBvZiBPYmplY3Qua2V5cygoYnJhY2tldCBhcyBSYXRlQnJhY2tldCkucmF0ZSA/PyB7fSkpIHtcbiAgICAgIGluc3RhbnRzLmFkZChpbnN0YW50KVxuICAgIH1cbiAgICBmb3IgKGNvbnN0IGluc3RhbnQgb2YgT2JqZWN0LmtleXMoYnJhY2tldC50aHJlc2hvbGQpKSB7XG4gICAgICBpbnN0YW50cy5hZGQoaW5zdGFudClcbiAgICB9XG4gIH1cblxuICBjb25zdCBzY2FsZUF0SW5zdGFudEJ5SW5zdGFudDoge1xuICAgIFtpbnN0YW50OiBzdHJpbmddOiBTY2FsZUF0SW5zdGFudFxuICB9ID0ge31cbiAgZm9yIChjb25zdCBpbnN0YW50IG9mIGluc3RhbnRzKSB7XG4gICAgY29uc3Qgc2NhbGVBdEluc3RhbnQ6IFNjYWxlQXRJbnN0YW50ID0gW11cbiAgICBmb3IgKGNvbnN0IGJyYWNrZXQgb2YgYnJhY2tldHMpIHtcbiAgICAgIGNvbnN0IGJyYWNrZXRBdEluc3RhbnQgPSB7fSBhcyB7IFtrZXk6IHN0cmluZ106IHVua25vd24gfVxuICAgICAgZm9yIChjb25zdCBrZXkgb2YgW1wiYW1vdW50XCIsIFwiYmFzZVwiLCBcInJhdGVcIiwgXCJ0aHJlc2hvbGRcIl0pIHtcbiAgICAgICAgY29uc3QgdmFsdWVCeUluc3RhbnQgPSAoXG4gICAgICAgICAgYnJhY2tldCBhcyB1bmtub3duIGFzIHtcbiAgICAgICAgICAgIFtrZXk6IHN0cmluZ106IHsgW2luc3RhbnQ6IHN0cmluZ106IHVua25vd24gfVxuICAgICAgICAgIH1cbiAgICAgICAgKT8uW2tleV1cbiAgICAgICAgaWYgKHZhbHVlQnlJbnN0YW50ID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICBjb250aW51ZVxuICAgICAgICB9XG4gICAgICAgIGxldCBiZXN0SW5zdGFudDogc3RyaW5nIHwgdW5kZWZpbmVkID0gdW5kZWZpbmVkXG4gICAgICAgIGZvciAoY29uc3QgdmFsdWVJbnN0YW50IG9mIE9iamVjdC5rZXlzKHZhbHVlQnlJbnN0YW50KSkge1xuICAgICAgICAgIGlmIChcbiAgICAgICAgICAgIChiZXN0SW5zdGFudCA9PT0gdW5kZWZpbmVkIHx8XG4gICAgICAgICAgICAgIGJlc3RJbnN0YW50LmxvY2FsZUNvbXBhcmUodmFsdWVJbnN0YW50KSA8IDApICYmXG4gICAgICAgICAgICB2YWx1ZUluc3RhbnQubG9jYWxlQ29tcGFyZShpbnN0YW50KSA8PSAwXG4gICAgICAgICAgKSB7XG4gICAgICAgICAgICBiZXN0SW5zdGFudCA9IHZhbHVlSW5zdGFudFxuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBpZiAoYmVzdEluc3RhbnQgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgIGNvbnRpbnVlXG4gICAgICAgIH1cbiAgICAgICAgYnJhY2tldEF0SW5zdGFudFtrZXldID0gdmFsdWVCeUluc3RhbnRbYmVzdEluc3RhbnRdXG4gICAgICB9XG4gICAgICBpZiAoXG4gICAgICAgIE9iamVjdC5rZXlzKGJyYWNrZXRBdEluc3RhbnQpLmxlbmd0aCA9PT0gMCB8fFxuICAgICAgICBPYmplY3QudmFsdWVzKGJyYWNrZXRBdEluc3RhbnQpLmV2ZXJ5KFxuICAgICAgICAgICh2YWx1ZSkgPT5cbiAgICAgICAgICAgIHZhbHVlICE9PSBcImV4cGVjdGVkXCIgJiZcbiAgICAgICAgICAgICh2YWx1ZSBhcyB7IHZhbHVlPzogdW5rbm93biB9KS52YWx1ZSA9PT0gbnVsbCxcbiAgICAgICAgKVxuICAgICAgKSB7XG4gICAgICAgIGNvbnRpbnVlXG4gICAgICB9XG4gICAgICBzY2FsZUF0SW5zdGFudC5wdXNoKGJyYWNrZXRBdEluc3RhbnQgYXMgdW5rbm93biBhcyBCcmFja2V0QXRJbnN0YW50KVxuICAgIH1cbiAgICBpZiAoc2NhbGVBdEluc3RhbnQubGVuZ3RoID4gMCkge1xuICAgICAgc2NhbGVBdEluc3RhbnRCeUluc3RhbnRbaW5zdGFudF0gPSBzY2FsZUF0SW5zdGFudFxuICAgIH1cbiAgfVxuICByZXR1cm4gc2NhbGVBdEluc3RhbnRCeUluc3RhbnRcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHNjYWxlUGFyYW1ldGVyVXNlc0Jhc2UocGFyYW1ldGVyOiBTY2FsZVBhcmFtZXRlcik6IGJvb2xlYW4ge1xuICByZXR1cm4gKFxuICAgIGlzUmF0ZVNjYWxlUGFyYW1ldGVyKHBhcmFtZXRlcikgJiZcbiAgICAocGFyYW1ldGVyLmJyYWNrZXRzIGFzIFJhdGVCcmFja2V0W10pLnNvbWUoXG4gICAgICAoYnJhY2tldDogUmF0ZUJyYWNrZXQpID0+IGJyYWNrZXQuYmFzZSAhPT0gdW5kZWZpbmVkLFxuICAgIClcbiAgKVxufVxuXG5leHBvcnQgZnVuY3Rpb24qIHdhbGtQYXJhbWV0ZXJzKFxuICBwYXJhbWV0ZXI6IFBhcmFtZXRlcixcbiAgZGVwdGhGaXJzdCA9IGZhbHNlLFxuKTogR2VuZXJhdG9yPFBhcmFtZXRlciwgdm9pZCwgdW5rbm93bj4ge1xuICBpZiAoIWRlcHRoRmlyc3QgJiYgcGFyYW1ldGVyLmNsYXNzICE9PSBQYXJhbWV0ZXJDbGFzcy5Ob2RlKSB7XG4gICAgeWllbGQgcGFyYW1ldGVyXG4gIH1cbiAgc3dpdGNoIChwYXJhbWV0ZXIuY2xhc3MpIHtcbiAgICBjYXNlIFBhcmFtZXRlckNsYXNzLk5vZGU6XG4gICAgICBpZiAocGFyYW1ldGVyLmNoaWxkcmVuICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgZm9yIChjb25zdCBjaGlsZCBvZiBPYmplY3QudmFsdWVzKHBhcmFtZXRlci5jaGlsZHJlbikpIHtcbiAgICAgICAgICB5aWVsZCogd2Fsa1BhcmFtZXRlcnMoY2hpbGQsIGRlcHRoRmlyc3QpXG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIGJyZWFrXG4gICAgZGVmYXVsdDpcbiAgfVxuICBpZiAoZGVwdGhGaXJzdCAmJiBwYXJhbWV0ZXIuY2xhc3MgIT09IFBhcmFtZXRlckNsYXNzLk5vZGUpIHtcbiAgICB5aWVsZCBwYXJhbWV0ZXJcbiAgfVxufVxuIl0sIm1hcHBpbmdzIjoiQUFBQTtBQUNBOztBQW1IQSxXQUFZQSxjQUFjLDBCQUFkQSxjQUFjO0VBQWRBLGNBQWM7RUFBZEEsY0FBYztFQUFkQSxjQUFjO0VBQUEsT0FBZEEsY0FBYztBQUFBO0FBcUMxQixXQUFZQyxTQUFTLDBCQUFUQSxTQUFTO0VBQVRBLFNBQVM7RUFBVEEs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