UNPKG

@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
/// 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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