@wikipathways/cxml
Version:
Advanced schema-aware streaming XML parser
427 lines • 59.4 kB
JavaScript
"use strict";
// This file is part of cxml, copyright (c) 2016-2017 BusFaster Ltd.
// Released under the MIT license, see LICENSE.
Object.defineProperty(exports, "__esModule", { value: true });
var lodash_1 = require("lodash");
var Promise = require("bluebird");
var sax = require("sax");
var State_1 = require("./State");
var JS_1 = require("../importer/JS");
var xpath_1 = require("../spinoffs/xpath");
function findInMapIter(
// TODO why can't I mark this as BTree<T> instead of any?
mapIter, compare) {
var _a = mapIter.next(), value = _a.value, done = _a.done;
if (!value) {
return;
}
var itemParsed = value[0], childMap = value[1];
if (!compare(itemParsed)) {
if (done) {
return;
}
return findInMapIter(mapIter, compare);
}
else {
return childMap;
}
}
var opHandlers = {
// equal
"=": function (item, left, right) {
return item[left] === right;
},
// not equal
"!=": function (item, left, right) {
return item[left] !== right;
},
// less than
"<": function (item, left, right) {
return item[left] < right;
},
// less than or equal to
"<=": function (item, left, right) {
return item[left] < right;
},
// greater than
">": function (item, left, right) {
return item[left] > right;
},
// greater than or equal to
">=": function (item, left, right) {
return item[left] > right;
}
};
opHandlers[">"] = opHandlers[">"];
opHandlers[">="] = opHandlers[">="];
/*
opHandlers[">"]({} as HandlerInstance, "CenterX", 2);
opHandlers[">"]({} as HandlerInstance, "CenterX", "b");
opHandlers[">"]({} as HandlerInstance, "a", "b");
opHandlers[">"]({} as HandlerInstance, "CenterX", 2);
opHandlers[">"]({} as HandlerInstance, "a", 2);
opHandlers[">="]({} as HandlerInstance, 1, 2);
opHandlers[">="]({} as HandlerInstance, "a", 2);
opHandlers["="]({} as HandlerInstance, "a", 2);
//*/
function findEntry(mapIter, compare) {
var _a = mapIter.next(), value = _a.value, done = _a.done;
if (!value) {
return;
}
var itemParsed = value[0], childMap = value[1];
if (!compare(itemParsed)) {
if (done) {
return;
}
return findEntry(mapIter, compare);
}
else {
return [childMap, itemParsed];
}
}
function getAttachmentMethod(state, bTree, attachmentMethodName) {
var member = (!!state.memberRef && state.memberRef.member) ||
{};
// TODO should we use state.memberRef.safeName here?
var memberName = !!member && member.name;
var memberNamespace = !!member && !!member.namespace && member.namespace.name;
if (!memberName) {
var attachmentMethod = bTree.get(attachmentMethodName);
if (attachmentMethod) {
return attachmentMethod;
}
else {
throw new Error("getAttachmentMethod failed to find " + attachmentMethodName + " function");
}
}
var item = state.item || {};
/*{ left: string; op: keyof NonBinaryOpHandlers; right: string }
{ left: number; op: keyof BinaryOpHandlers; right: number }
| {
left: string | number;
op: keyof NonBinaryOpHandlers;
right: string | number;
}
//*/
var value = findInMapIter(bTree.entries(), function (_a) {
var axis = _a.axis, namespace = _a.namespace, name = _a.name, predicates = _a.predicates, attribute = _a.attribute;
return (["", memberNamespace].indexOf(namespace) > -1 &&
name === memberName &&
(!predicates ||
predicates.reduce(function (acc, _a) {
var left = _a.left, op = _a.op, right = _a.right;
return acc && opHandlers[op](item, left, right);
}, true)));
});
if (!value) {
// NOTE: we can end up here because there is no direct connection between
// a Parser instance's attach and _parse methods. They actually just
// connect via the rule.handler prototype. So it's possible for one
// attachment method to set something on the rule.handler prototype, meaning it
// appears to exist when we look at item._before or item._after in _parser,
// but it doesn't actually exist for this xpath when we match the
// state and bTree, level by level, up to the point where there should be
// a _before or _after.
return;
}
var parent = state.parent;
if (!!parent) {
return getAttachmentMethod(parent, value, attachmentMethodName);
}
else {
return value.get(attachmentMethodName);
}
}
var converterTbl = {
Date: function (item) {
var dateParts = item.match(/([0-9]+)-([0-9]+)-([0-9]+)(?:T([0-9]+):([0-9]+):([0-9]+)(\.[0-9]+)?)?(?:Z|([+-][0-9]+):([0-9]+))?/);
if (!dateParts)
return null;
var offsetMinutes = +(dateParts[9] || "0");
var offset = +(dateParts[8] || "0") * 60;
if (offset < 0)
offsetMinutes = -offsetMinutes;
offset += offsetMinutes;
var date = new Date(+dateParts[1], +dateParts[2] - 1, +dateParts[3], +(dateParts[4] || "0"), +(dateParts[5] || "0"), +(dateParts[6] || "0"), +(dateParts[7] || "0") * 1000);
date.setTime(date.getTime() - (offset + date.getTimezoneOffset()) * 60000);
date.cxmlTimezoneOffset = offset;
return date;
},
boolean: function (item) { return item == "true"; },
string: function (item) { return item; },
number: function (item) { return +item; }
};
function convertPrimitive(text, type) {
var converter = converterTbl[type.primitiveType];
if (converter) {
if (type.isList) {
return text
.trim()
.split(/\s+/)
.map(converter);
}
else {
return converter(text.trim());
}
}
return null;
}
var Parser = /** @class */ (function () {
function Parser(xpathNamespaceTbl) {
if (xpathNamespaceTbl === void 0) { xpathNamespaceTbl = { "": "" }; }
// TODO why do I need to use BTree<any> here?
// I should be able to use BTree<T>
this.bTree = new Map();
// TODO there is probably a better way to do this.
// It appears the context param in the parser.parser
// method may have be intended for the same purpose.
this.xpathNamespaceTbl = xpathNamespaceTbl;
}
Parser.prototype.attach = function (handler, xpath) {
var xpathNamespaceTbl = this.xpathNamespaceTbl;
var proto = handler.prototype;
var realHandler = handler.rule.handler;
var realProto = realHandler.prototype;
var customHandlerKeys = Object.keys(proto);
for (var _i = 0, customHandlerKeys_1 = customHandlerKeys; _i < customHandlerKeys_1.length; _i++) {
var customHandlerKey = customHandlerKeys_1[_i];
var timeBasedKeys = ["_before", "_after"];
if (timeBasedKeys.indexOf(customHandlerKey) === -1) {
realProto[customHandlerKey] = proto[customHandlerKey];
}
}
// TODO is this really the best way to do this?
var _before = proto._before, _after = proto._after;
if (xpath) {
if (_before || _after) {
// TODO we are mutating reversedXPathElMatchers for xpath
// expressions with attributes, such as
// "/Pathway/@GraphId"
// or
// "/Pathway/@*"
// because we need to first just match the element(s), and
// then afterwards match any attribute.
var reversedXPathElMatchers = xpath_1.parse(xpath, xpathNamespaceTbl).reverse();
var xpathAttrMatcher_1;
if (reversedXPathElMatchers[0].attribute !== null) {
xpathAttrMatcher_1 = reversedXPathElMatchers.shift();
}
var finalItem = reversedXPathElMatchers.reduce(function (parentMap, xpathElMatcher) {
var xpathElMatcherPairs = lodash_1.toPairs(xpathElMatcher);
var _a = findEntry(parentMap.entries(), function (candidateItemParsed) {
return xpathElMatcherPairs.reduce(function (isRunningMatch, _a) {
var xpathElMatcherKey = _a[0], xpathElMatcherValue = _a[1];
return (isRunningMatch &&
candidateItemParsed[xpathElMatcherKey] === xpathElMatcherValue);
}, true);
}) || [new Map(), xpathElMatcher], currentMap = _a[0], currentItemParsed = _a[1];
parentMap.set(currentItemParsed, currentMap);
return currentMap;
}, this.bTree);
if (_before) {
finalItem.set("_before", !xpathAttrMatcher_1 || xpathAttrMatcher_1.attribute === "*"
? _before
: function () {
var picked = lodash_1.pick(this, xpathAttrMatcher_1.attribute);
_before.call(picked);
});
}
if (_after) {
finalItem.set("_after", _after);
}
}
}
realHandler._custom = true;
};
Parser.prototype.parse = function (stream, output, context) {
var _this = this;
return new Promise(function (resolve, reject) {
return _this._parse(stream, output, context || JS_1.defaultContext, resolve, reject);
});
};
Parser.prototype._parse = function (stream, output, context, resolve, reject) {
var bTree = this.bTree;
var xml = sax.createStream(true, { position: true });
var rule = output.constructor.rule;
var xmlSpace = context.registerNamespace("http://www.w3.org/XML/1998/namespace");
var namespaceTbl = {
"": [rule.namespace, rule.namespace.getPrefix()],
xml: [xmlSpace, xmlSpace.getPrefix()]
};
var state = new State_1.State(null, null, rule, new rule.handler(), namespaceTbl);
var rootState = state;
var parentItem;
/** Add a new xmlns prefix recognized inside current tag and its children. */
function addNamespace(short, namespace) {
if (namespaceTbl[short] && namespaceTbl[short][0] == namespace)
return;
if (namespaceTbl == state.namespaceTbl) {
// Copy parent namespace table on first write.
namespaceTbl = {};
for (var _i = 0, _a = Object.keys(state.namespaceTbl); _i < _a.length; _i++) {
var key = _a[_i];
namespaceTbl[key] = state.namespaceTbl[key];
}
}
namespaceTbl[short] = [namespace, namespace.getPrefix()];
}
xml.on("opentag", function (node) {
var attrTbl = node.attributes;
var attr;
var nodePrefix = "";
var name = node.name;
var splitter = name.indexOf(":");
var item = null;
namespaceTbl = state.namespaceTbl;
// Read xmlns namespace prefix definitions before parsing node name.
for (var _i = 0, _a = Object.keys(attrTbl); _i < _a.length; _i++) {
var key = _a[_i];
if (key.substr(0, 5) == "xmlns") {
var nsParts = key.match(/^xmlns(:(.+))?$/);
if (nsParts) {
addNamespace(nsParts[2] || "", context.registerNamespace(attrTbl[key]));
}
}
}
// Parse node name and possible namespace prefix.
if (splitter >= 0) {
nodePrefix = name.substr(0, splitter);
name = name.substr(splitter + 1);
}
// Add internal surrogate key namespace prefix to node name.
var nodeNamespace = namespaceTbl[nodePrefix];
name = nodeNamespace[1] + name;
var child;
var rule;
if (state.rule) {
child = state.rule.childTbl[name];
if (child) {
if (child.proxy) {
rule = child.proxy.member.rule;
state = new State_1.State(state, child.proxy, rule, new rule.handler(), namespaceTbl);
}
rule = child.member.rule;
}
}
if (rule && !rule.isPlainPrimitive) {
item = new rule.handler();
// Parse all attributes.
for (var _b = 0, _c = Object.keys(attrTbl); _b < _c.length; _b++) {
var key = _c[_b];
splitter = key.indexOf(":");
if (splitter >= 0) {
var attrPrefix = key.substr(0, splitter);
if (attrPrefix == "xmlns")
continue;
var attrNamespace = namespaceTbl[attrPrefix];
if (attrNamespace) {
attr = attrNamespace[1] + key.substr(splitter + 1);
}
else {
console.warn("Namespace not found for " + key);
continue;
}
}
else {
attr = nodeNamespace[1] + key;
}
var ref = rule.attributeTbl[attr];
if (ref && ref.member.rule.isPlainPrimitive) {
item[ref.safeName] = convertPrimitive(attrTbl[key], ref.member.rule);
}
}
if (state.parent) {
Object.defineProperty(item, "_parent", {
enumerable: false,
value: state.parent.item
});
}
Object.defineProperty(item, "_name", {
enumerable: false,
value: node.name
});
}
state = new State_1.State(state, child, rule, item, namespaceTbl);
// TODO why did the previous version of this lib check
// (rule && !rule.isPlainPrimitive) before running _before?
// I'm keeping the check for now, until I figure out why.
// TODO also, why did it run '_before' prior to re-setting state
// (re-setting in the line above)?
if (rule && !rule.isPlainPrimitive) {
var thisBefore = getAttachmentMethod(state, bTree, "_before");
if (!!thisBefore) {
thisBefore.call(item);
}
}
});
xml.on("text", function (text) {
if (state.rule && state.rule.isPrimitive) {
if (!state.textList)
state.textList = [];
state.textList.push(text);
}
});
xml.on("closetag", function (name) {
var member = state.memberRef;
var obj = state.item;
var item = obj;
var text;
if (state.rule && state.rule.isPrimitive) {
text = (state.textList || []).join("").trim();
}
if (text) {
var content = convertPrimitive(text, state.rule);
if (state.rule.isPlainPrimitive) {
item = content;
}
else {
obj.content = content;
}
}
if (obj) {
var thisAfter = getAttachmentMethod(state, bTree, "_after");
if (!!thisAfter) {
thisAfter.call(obj);
}
}
state = state.parent;
if (member && member.proxy) {
if (item)
state.item[member.safeName] = item;
item = state.item;
state = state.parent;
member = member.proxy;
}
if (item) {
var parent_1 = state.item;
if (parent_1) {
if (member.max > 1) {
if (!parent_1.hasOwnProperty(member.safeName)) {
parent_1[member.safeName] = [];
}
parent_1[member.safeName].push(item);
}
else {
parent_1[member.safeName] = item;
}
}
}
});
xml.on("end", function () {
resolve(rootState.item);
});
xml.on("error", function (err) {
console.error(err);
});
if (typeof stream == "string") {
xml.write(stream);
xml.end();
}
else
stream.pipe(xml);
};
return Parser;
}());
exports.Parser = Parser;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUGFyc2VyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3BhcnNlci9QYXJzZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBLG9FQUFvRTtBQUNwRSwrQ0FBK0M7O0FBRS9DLGlDQUF1QztBQUV2QyxrQ0FBb0M7QUFDcEMseUJBQTJCO0FBTTNCLGlDQUFnQztBQUNoQyxxQ0FBZ0Q7QUFDaEQsMkNBQXNEO0FBMkJ0RCxTQUFTLGFBQWE7QUFDcEIseURBQXlEO0FBQ3pELE9BQW9DLEVBQ3BDLE9BQW1DO0lBRTdCLElBQUEsbUJBQWdDLEVBQTlCLGdCQUFLLEVBQUUsY0FBdUIsQ0FBQztJQUN2QyxJQUFJLENBQUMsS0FBSyxFQUFFO1FBQ1YsT0FBTztLQUNSO0lBQ00sSUFBQSxxQkFBVSxFQUFFLG1CQUFRLENBQVU7SUFDckMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxVQUFVLENBQUMsRUFBRTtRQUN4QixJQUFJLElBQUksRUFBRTtZQUNSLE9BQU87U0FDUjtRQUNELE9BQU8sYUFBYSxDQUFJLE9BQU8sRUFBRSxPQUFPLENBQUMsQ0FBQztLQUMzQztTQUFNO1FBQ0wsT0FBTyxRQUFRLENBQUM7S0FDakI7QUFDSCxDQUFDO0FBc0JELElBQUksVUFBVSxHQUFHO0lBQ2YsUUFBUTtJQUNSLEdBQUcsRUFBRSxVQUFTLElBQUksRUFBRSxJQUFJLEVBQUUsS0FBSztRQUM3QixPQUFPLElBQUksQ0FBQyxJQUFJLENBQUMsS0FBSyxLQUFLLENBQUM7SUFDOUIsQ0FBQztJQUNELFlBQVk7SUFDWixJQUFJLEVBQUUsVUFBUyxJQUFJLEVBQUUsSUFBSSxFQUFFLEtBQUs7UUFDOUIsT0FBTyxJQUFJLENBQUMsSUFBSSxDQUFDLEtBQUssS0FBSyxDQUFDO0lBQzlCLENBQUM7SUFDRCxZQUFZO0lBQ1osTUFBTSxFQUFFLFVBQVMsSUFBSSxFQUFFLElBQUksRUFBRSxLQUFLO1FBQ2hDLE9BQU8sSUFBSSxDQUFDLElBQUksQ0FBQyxHQUFHLEtBQUss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QUFDLENBQUM7UUFFSCxHQUFHLENBQUMsRUFBRSxDQUFDLE9BQU8sRUFBRSxVQUFTLEdBQVU7WUFDakMsT0FBTyxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUNyQixDQUFDLENBQUMsQ0FBQztRQUVILElBQUksT0FBTyxNQUFNLElBQUksUUFBUSxFQUFFO1lBQzdCLEdBQUcsQ0FBQyxLQUFLLENBQUMsTUFBZ0IsQ0FBQyxDQUFDO1lBQzVCLEdBQUcsQ0FBQyxHQUFHLEVBQUUsQ0FBQztTQUNYOztZQUFPLE1BQTBCLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBQy9DLENBQUM7SUFDSCxhQUFDO0FBQUQsQ0FBQyxBQTFWRCxJQTBWQztBQTFWWSx3QkFBTSIsInNvdXJjZXNDb250ZW50IjpbIi8vIFRoaXMgZmlsZSBpcyBwYXJ0IG9mIGN4bWwsIGNvcHlyaWdodCAoYykgMjAxNi0yMDE3IEJ1c0Zhc3RlciBMdGQuXG4vLyBSZWxlYXNlZCB1bmRlciB0aGUgTUlUIGxpY2Vuc2UsIHNlZSBMSUNFTlNFLlxuXG5pbXBvcnQgeyBwaWNrLCB0b1BhaXJzIH0gZnJvbSBcImxvZGFzaFwiO1xuaW1wb3J0ICogYXMgc3RyZWFtIGZyb20gXCJzdHJlYW1cIjtcbmltcG9ydCAqIGFzIFByb21pc2UgZnJvbSBcImJsdWViaXJkXCI7XG5pbXBvcnQgKiBhcyBzYXggZnJvbSBcInNheFwiO1xuXG5pbXBvcnQgeyBDb250ZXh0IH0gZnJvbSBcIi4uL3htbC9Db250ZXh0XCI7XG5pbXBvcnQgeyBOYW1lc3BhY2UgfSBmcm9tIFwiLi4veG1sL05hbWVzcGFjZVwiO1xuaW1wb3J0IHsgUnVsZSwgUnVsZUNsYXNzLCBIYW5kbGVySW5zdGFuY2UgfSBmcm9tIFwiLi9SdWxlXCI7XG5pbXBvcnQgeyBNZW1iZXJSZWYgfSBmcm9tIFwiLi4veG1sL01lbWJlclJlZlwiO1xuaW1wb3J0IHsgU3RhdGUgfSBmcm9tIFwiLi9TdGF0ZVwiO1xuaW1wb3J0IHsgZGVmYXVsdENvbnRleHQgfSBmcm9tIFwiLi4vaW1wb3J0ZXIvSlNcIjtcbmltcG9ydCB7IHBhcnNlLCBJdGVtUGFyc2VkIH0gZnJvbSBcIi4uL3NwaW5vZmZzL3hwYXRoXCI7XG5cbmV4cG9ydCB0eXBlIEl0ZW1QYXJzZWRLZXkgPSBrZXlvZiBJdGVtUGFyc2VkO1xuZXhwb3J0IHR5cGUgSXRlbVBhcnNlZFZhbHVlID0gSXRlbVBhcnNlZFtJdGVtUGFyc2VkS2V5XTtcblxuLy8gVE9ETyBjYW4gdGhpcyB0eXBlIGRlZmluaXRpb24gYmUgaW1wcm92ZWQ/XG4vKlxue1xuXHR4cGF0aEVsTWF0Y2hlcihvYmopOiB7XG4gXHQgIF9iZWZvcmU6IEZ1bmN0aW9uLFxuIFx0ICBfYWZ0ZXI6IEZ1bmN0aW9uLFxuXHRcdHhwYXRoRWxNYXRjaGVyKG9iaik6IHtcblx0XHRcdF9iZWZvcmU6IEZ1bmN0aW9uLFxuXHRcdFx0X2FmdGVyOiBGdW5jdGlvbixcblx0XHR9KE1hcCksXG5cdH0oTWFwKVxufShNYXApXG4vLyovXG5leHBvcnQgdHlwZSBBdHRhY2htZW50TWV0aG9kTmFtZXMgPSBcIl9hZnRlclwiIHwgXCJfYmVmb3JlXCI7XG5leHBvcnQgdHlwZSBCVHJlZUZpbmFsID0gTWFwPEF0dGFjaG1lbnRNZXRob2ROYW1lcywgRnVuY3Rpb24+O1xuZXhwb3J0IHR5cGUgQlRyZWVJbnRlcm1lZGlhdGU8VD4gPSBNYXA8SXRlbVBhcnNlZCwgVCB8IEJUcmVlRmluYWw+O1xuZXhwb3J0IHR5cGUgQlRyZWU8VD4gPSBCVHJlZUludGVybWVkaWF0ZTxUPiAmIEJUcmVlRmluYWw7XG5cbmV4cG9ydCBpbnRlcmZhY2UgQ3htbERhdGUgZXh0ZW5kcyBEYXRlIHtcbiAgY3htbFRpbWV6b25lT2Zmc2V0OiBudW1iZXI7XG59XG5cbmZ1bmN0aW9uIGZpbmRJbk1hcEl0ZXI8VD4oXG4gIC8vIFRPRE8gd2h5IGNhbid0IEkgbWFyayB0aGlzIGFzIEJUcmVlPFQ+IGluc3RlYWQgb2YgYW55P1xuICBtYXBJdGVyOiBJdGVyYXRvcjxbSXRlbVBhcnNlZCwgYW55XT4sXG4gIGNvbXBhcmU6ICh4OiBJdGVtUGFyc2VkKSA9PiBib29sZWFuXG4pOiBCVHJlZTxUPiB7XG4gIGNvbnN0IHsgdmFsdWUsIGRvbmUgfSA9IG1hcEl0ZXIubmV4dCgpO1xuICBpZiAoIXZhbHVlKSB7XG4gICAgcmV0dXJuO1xuICB9XG4gIGNvbnN0IFtpdGVtUGFyc2VkLCBjaGlsZE1hcF0gPSB2YWx1ZTtcbiAgaWYgKCFjb21wYXJlKGl0ZW1QYXJzZWQpKSB7XG4gICAgaWYgKGRvbmUpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgcmV0dXJuIGZpbmRJbk1hcEl0ZXI8VD4obWFwSXRlciwgY29tcGFyZSk7XG4gIH0gZWxzZSB7XG4gICAgcmV0dXJuIGNoaWxkTWFwO1xuICB9XG59XG5cbmV4cG9ydCB0eXBlIE5vbkJpbmFyeU9wVG9SaWdodHMgPSB7IFtLIGluIFwiPVwiIHwgXCIhPVwiXTogc3RyaW5nIHwgbnVtYmVyIH07XG5leHBvcnQgdHlwZSBCaW5hcnlPcFRvUmlnaHRzID0ge1xuICBbSyBpbiBcIiZsdDtcIiB8IFwiJmx0Oz1cIiB8IFwiJmd0O1wiIHwgXCI+XCIgfCBcIiZndDs9XCIgfCBcIj49XCJdOiBudW1iZXJcbn07XG4vLyBUT0RPIGxvb2sgYXQgbW92aW5nIHNvbWUgb2YgdGhlc2UgdHlwZSBkZWZpbml0aW9ucyBpbnRvIHhwYXRoLnRzXG5leHBvcnQgdHlwZSBPcFRvUmlnaHRzID0gTm9uQmluYXJ5T3BUb1JpZ2h0cyAmIEJpbmFyeU9wVG9SaWdodHM7XG5leHBvcnQgdHlwZSBPcEhhbmRsZXJJbnB1dEdlbmVyaWM8VCwgSyBleHRlbmRzIGtleW9mIFQ+ID0ge1xuICBsZWZ0OiBzdHJpbmc7XG4gIG9wOiBLO1xuICByaWdodDogVFtLXTtcbn07XG5leHBvcnQgdHlwZSBPcEhhbmRsZXJJbnB1dCA9IE9wSGFuZGxlcklucHV0R2VuZXJpYzxcbiAgT3BUb1JpZ2h0cyxcbiAga2V5b2YgT3BUb1JpZ2h0c1xuPjtcbmV4cG9ydCB0eXBlIE9wSGFuZGxlcnNHZW5lcmljPFQsIEsgZXh0ZW5kcyBrZXlvZiBUPiA9IHtcbiAgW0s6IHN0cmluZ106IChpdGVtOiBIYW5kbGVySW5zdGFuY2UsIGxlZnQ6IHN0cmluZywgcmlnaHQ6IFRbS10pID0+IGJvb2xlYW47XG59O1xuZXhwb3J0IHR5cGUgT3BIYW5kbGVycyA9IE9wSGFuZGxlcnNHZW5lcmljPE9wVG9SaWdodHMsIGtleW9mIE9wVG9SaWdodHM+O1xuXG5sZXQgb3BIYW5kbGVycyA9IHtcbiAgLy8gZXF1YWxcbiAgXCI9XCI6IGZ1bmN0aW9uKGl0ZW0sIGxlZnQsIHJpZ2h0KSB7XG4gICAgcmV0dXJuIGl0ZW1bbGVmdF0gPT09IHJpZ2h0O1xuICB9LFxuICAvLyBub3QgZXF1YWxcbiAgXCIhPVwiOiBmdW5jdGlvbihpdGVtLCBsZWZ0LCByaWdodCkge1xuICAgIHJldHVybiBpdGVtW2xlZnRdICE9PSByaWdodDtcbiAgfSxcbiAgLy8gbGVzcyB0aGFuXG4gIFwiJmx0O1wiOiBmdW5jdGlvbihpdGVtLCBsZWZ0LCByaWdodCkge1xuICAgIHJldHVybiBpdGVtW2xlZnRdIDwgcmlnaHQ7XG4gIH0sXG4gIC8vIGxlc3MgdGhhbiBvciBlcXVhbCB0b1xuICBcIiZsdDs9XCI6IGZ1bmN0aW9uKGl0ZW0sIGxlZnQsIHJpZ2h0KSB7XG4gICAgcmV0dXJuIGl0ZW1bbGVmdF0gPCByaWdodDtcbiAgfSxcbiAgLy8gZ3JlYXRlciB0aGFuXG4gIFwiJmd0O1wiOiBmdW5jdGlvbihpdGVtLCBsZWZ0LCByaWdodCkge1xuICAgIHJldHVybiBpdGVtW2xlZnRdID4gcmlnaHQ7XG4gIH0sXG4gIC8vIGdyZWF0ZXIgdGhhbiBvciBlcXVhbCB0b1xuICBcIiZndDs9XCI6IGZ1bmN0aW9uKGl0ZW0sIGxlZnQsIHJpZ2h0KSB7XG4gICAgcmV0dXJuIGl0ZW1bbGVmdF0gPiByaWdodDtcbiAgfVxufSBhcyBPcEhhbmRsZXJzO1xuXG5vcEhhbmRsZXJzW1wiPlwiXSA9IG9wSGFuZGxlcnNbXCImZ3Q7XCJdO1xub3BIYW5kbGVyc1tcIj49XCJdID0gb3BIYW5kbGVyc1tcIiZndDs9XCJdO1xuXG4vKlxub3BIYW5kbGVyc1tcIiZndDtcIl0oe30gYXMgSGFuZGxlckluc3RhbmNlLCBcIkNlbnRlclhcIiwgMik7XG5vcEhhbmRsZXJzW1wiJmd0O1wiXSh7fSBhcyBIYW5kbGVySW5zdGFuY2UsIFwiQ2VudGVyWFwiLCBcImJcIik7XG5vcEhhbmRsZXJzW1wiJmd0O1wiXSh7fSBhcyBIYW5kbGVySW5zdGFuY2UsIFwiYVwiLCBcImJcIik7XG5vcEhhbmRsZXJzW1wiPlwiXSh7fSBhcyBIYW5kbGVySW5zdGFuY2UsIFwiQ2VudGVyWFwiLCAyKTtcbm9wSGFuZGxlcnNbXCI+XCJdKHt9IGFzIEhhbmRsZXJJbnN0YW5jZSwgXCJhXCIsIDIpO1xub3BIYW5kbGVyc1tcIj49XCJdKHt9IGFzIEhhbmRsZXJJbnN0YW5jZSwgMSwgMik7XG5vcEhhbmRsZXJzW1wiPj1cIl0oe30gYXMgSGFuZGxlckluc3RhbmNlLCBcImFcIiwgMik7XG5vcEhhbmRsZXJzW1wiPVwiXSh7fSBhcyBIYW5kbGVySW5zdGFuY2UsIFwiYVwiLCAyKTtcbi8vKi9cblxuZnVuY3Rpb24gZmluZEVudHJ5PFQ+KFxuICBtYXBJdGVyOiBJdGVyYXRvcjxbSXRlbVBhcnNlZCwgQlRyZWU8VD5dPixcbiAgY29tcGFyZTogKHg6IEl0ZW1QYXJzZWQpID0+IGJvb2xlYW5cbik6IFtCVHJlZTxUPiwgSXRlbVBhcnNlZF0ge1xuICBjb25zdCB7IHZhbHVlLCBkb25lIH0gPSBtYXBJdGVyLm5leHQoKTtcbiAgaWYgKCF2YWx1ZSkge1xuICAgIHJldHVybjtcbiAgfVxuICBjb25zdCBbaXRlbVBhcnNlZCwgY2hpbGRNYXBdID0gdmFsdWU7XG4gIGlmICghY29tcGFyZShpdGVtUGFyc2VkKSkge1xuICAgIGlmIChkb25lKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIHJldHVybiBmaW5kRW50cnkobWFwSXRlciwgY29tcGFyZSk7XG4gIH0gZWxzZSB7XG4gICAgcmV0dXJuIFtjaGlsZE1hcCwgaXRlbVBhcnNlZF07XG4gIH1cbn1cblxuZnVuY3Rpb24gZ2V0QXR0YWNobWVudE1ldGhvZDxUPihcbiAgc3RhdGU6IFN0YXRlLFxuICBiVHJlZTogQlRyZWU8VD4sXG4gIGF0dGFjaG1lbnRNZXRob2ROYW1lOiBBdHRhY2htZW50TWV0aG9kTmFtZXNcbik6IEZ1bmN0aW9uIHtcbiAgY29uc3QgbWVtYmVyID1cbiAgICAoISFzdGF0ZS5tZW1iZXJSZWYgJiYgc3RhdGUubWVtYmVyUmVmLm1lbWJlcikgfHxcbiAgICAoe30gYXMgdHlwZW9mIE1lbWJlclJlZi5wcm90b3R5cGUubWVtYmVyKTtcbiAgLy8gVE9ETyBzaG91bGQgd2UgdXNlIHN0YXRlLm1lbWJlclJlZi5zYWZlTmFtZSBoZXJlP1xuICBjb25zdCBtZW1iZXJOYW1lID0gISFtZW1iZXIgJiYgbWVtYmVyLm5hbWU7XG4gIGNvbnN0IG1lbWJlck5hbWVzcGFjZSA9XG4gICAgISFtZW1iZXIgJiYgISFtZW1iZXIubmFtZXNwYWNlICYmIG1lbWJlci5uYW1lc3BhY2UubmFtZTtcblxuICBpZiAoIW1lbWJlck5hbWUpIHtcbiAgICBjb25zdCBhdHRhY2htZW50TWV0aG9kID0gYlRyZWUuZ2V0KGF0dGFjaG1lbnRNZXRob2ROYW1lKTtcbiAgICBpZiAoYXR0YWNobWVudE1ldGhvZCkge1xuICAgICAgcmV0dXJuIGF0dGFjaG1lbnRNZXRob2Q7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgYGdldEF0dGFjaG1lbnRNZXRob2QgZmFpbGVkIHRvIGZpbmQgJHthdHRhY2htZW50TWV0aG9kTmFtZX0gZnVuY3Rpb25gXG4gICAgICApO1xuICAgIH1cbiAgfVxuICBjb25zdCBpdGVtID0gc3RhdGUuaXRlbSB8fCAoe30gYXMgSGFuZGxlckluc3RhbmNlKTtcblxuICAvKnsgbGVmdDogc3RyaW5nOyBvcDoga2V5b2YgTm9uQmluYXJ5T3BIYW5kbGVyczsgcmlnaHQ6IHN0cmluZyB9XG4gICAgICAgICAgICB7IGxlZnQ6IG51bWJlcjsgb3A6IGtleW9mIEJpbmFyeU9wSGFuZGxlcnM7IHJpZ2h0OiBudW1iZXIgfVxuICAgICAgICAgICAgfCB7XG4gICAgICAgICAgICAgICAgbGVmdDogc3RyaW5nIHwgbnVtYmVyO1xuICAgICAgICAgICAgICAgIG9wOiBrZXlvZiBOb25CaW5hcnlPcEhhbmRsZXJzO1xuICAgICAgICAgICAgICAgIHJpZ2h0OiBzdHJpbmcgfCBudW1iZXI7XG4gICAgICAgICAgICAgIH1cblx0XHRcdFx0XHRcdFx0Ly8qL1xuXG4gIGNvbnN0IHZhbHVlID0gZmluZEluTWFwSXRlcihiVHJlZS5lbnRyaWVzKCksIGZ1bmN0aW9uKHtcbiAgICBheGlzLFxuICAgIG5hbWVzcGFjZSxcbiAgICBuYW1lLFxuICAgIHByZWRpY2F0ZXMsXG4gICAgYXR0cmlidXRlXG4gIH06IEl0ZW1QYXJzZWQpIHtcbiAgICByZXR1cm4gKFxuICAgICAgW1wiXCIsIG1lbWJlck5hbWVzcGFjZV0uaW5kZXhPZihuYW1lc3BhY2UpID4gLTEgJiZcbiAgICAgIG5hbWUgPT09IG1lbWJlck5hbWUgJiZcbiAgICAgICghcHJlZGljYXRlcyB8fFxuICAgICAgICBwcmVkaWNhdGVzLnJlZHVjZShmdW5jdGlvbihhY2MsIHsgbGVmdCwgb3AsIHJpZ2h0IH06IE9wSGFuZGxlcklucHV0KSB7XG4gICAgICAgICAgcmV0dXJuIGFjYyAmJiBvcEhhbmRsZXJzW29wXShpdGVtLCBsZWZ0LCByaWdodCk7XG4gICAgICAgIH0sIHRydWUpKVxuICAgICk7XG4gIH0pO1xuXG4gIGlmICghdmFsdWUpIHtcbiAgICAvLyBOT1RFOiB3ZSBjYW4gZW5kIHVwIGhlcmUgYmVjYXVzZSB0aGVyZSBpcyBubyBkaXJlY3QgY29ubmVjdGlvbiBiZXR3ZWVuXG4gICAgLy8gYSBQYXJzZXIgaW5zdGFuY2UncyBhdHRhY2ggYW5kIF9wYXJzZSBtZXRob2RzLiBUaGV5IGFjdHVhbGx5IGp1c3RcbiAgICAvLyBjb25uZWN0IHZpYSB0aGUgcnVsZS5oYW5kbGVyIHByb3RvdHlwZS4gU28gaXQncyBwb3NzaWJsZSBmb3Igb25lXG4gICAgLy8gYXR0YWNobWVudCBtZXRob2QgdG8gc2V0IHNvbWV0aGluZyBvbiB0aGUgcnVsZS5oYW5kbGVyIHByb3RvdHlwZSwgbWVhbmluZyBpdFxuICAgIC8vIGFwcGVhcnMgdG8gZXhpc3Qgd2hlbiB3ZSBsb29rIGF0IGl0ZW0uX2JlZm9yZSBvciBpdGVtLl9hZnRlciBpbiBfcGFyc2VyLFxuICAgIC8vIGJ1dCBpdCBkb2Vzbid0IGFjdHVhbGx5IGV4aXN0IGZvciB0aGlzIHhwYXRoIHdoZW4gd2UgbWF0Y2ggdGhlXG4gICAgLy8gc3RhdGUgYW5kIGJUcmVlLCBsZXZlbCBieSBsZXZlbCwgdXAgdG8gdGhlIHBvaW50IHdoZXJlIHRoZXJlIHNob3VsZCBiZVxuICAgIC8vIGEgX2JlZm9yZSBvciBfYWZ0ZXIuXG4gICAgcmV0dXJuO1xuICB9XG5cbiAgY29uc3QgcGFyZW50ID0gc3RhdGUucGFyZW50O1xuICBpZiAoISFwYXJlbnQpIHtcbiAgICByZXR1cm4gZ2V0QXR0YWNobWVudE1ldGhvZChwYXJlbnQsIHZhbHVlLCBhdHRhY2htZW50TWV0aG9kTmFtZSk7XG4gIH0gZWxzZSB7XG4gICAgcmV0dXJuIHZhbHVlLmdldChhdHRhY2htZW50TWV0aG9kTmFtZSk7XG4gIH1cbn1cblxuY29uc3QgY29udmVydGVyVGJsOiB7IFt0eXBlOiBzdHJpbmddOiAoaXRlbTogc3RyaW5nKSA9PiBhbnkgfSA9IHtcbiAgRGF0ZTogKGl0ZW06IHN0cmluZykgPT4ge1xuICAgIGNvbnN0IGRhdGVQYXJ0cyA9IGl0ZW0ubWF0Y2goXG4gICAgICAvKFswLTldKyktKFswLTldKyktKFswLTldKykoPzpUKFswLTldKyk6KFswLTldKyk6KFswLTldKykoXFwuWzAtOV0rKT8pPyg/Olp8KFsrLV1bMC05XSspOihbMC05XSspKT8vXG4gICAgKTtcblxuICAgIGlmICghZGF0ZVBhcnRzKSByZXR1cm4gbnVsbDtcblxuICAgIGxldCBvZmZzZXRNaW51dGVzID0gKyhkYXRlUGFydHNbOV0gfHwgXCIwXCIpO1xuICAgIGxldCBvZmZzZXQgPSArKGRhdGVQYXJ0c1s4XSB8fCBcIjBcIikgKiA2MDtcblxuICAgIGlmIChvZmZzZXQgPCAwKSBvZmZzZXRNaW51dGVzID0gLW9mZnNldE1pbnV0ZXM7XG5cbiAgICBvZmZzZXQgKz0gb2Zmc2V0TWludXRlcztcblxuICAgIGNvbnN0IGRhdGUgPSBuZXcgRGF0ZShcbiAgICAgICtkYXRlUGFydHNbMV0sXG4gICAgICArZGF0ZVBhcnRzWzJdIC0gMSxcbiAgICAgICtkYXRlUGFydHNbM10sXG4gICAgICArKGRhdGVQYXJ0c1s0XSB8fCBcIjBcIiksXG4gICAgICArKGRhdGVQYXJ0c1s1XSB8fCBcIjBcIiksXG4gICAgICArKGRhdGVQYXJ0c1s2XSB8fCBcIjBcIiksXG4gICAgICArKGRhdGVQYXJ0c1s3XSB8fCBcIjBcIikgKiAxMDAwXG4gICAgKSBhcyBDeG1sRGF0ZTtcblxuICAgIGRhdGUuc2V0VGltZShkYXRlLmdldFRpbWUoKSAtIChvZmZzZXQgKyBkYXRlLmdldFRpbWV6b25lT2Zmc2V0KCkpICogNjAwMDApO1xuICAgIGRhdGUuY3htbFRpbWV6b25lT2Zmc2V0ID0gb2Zmc2V0O1xuXG4gICAgcmV0dXJuIGRhdGU7XG4gIH0sXG4gIGJvb2xlYW46IChpdGVtOiBzdHJpbmcpID0+IGl0ZW0gPT0gXCJ0cnVlXCIsXG4gIHN0cmluZzogKGl0ZW06IHN0cmluZykgPT4gaXRlbSxcbiAgbnVtYmVyOiAoaXRlbTogc3RyaW5nKSA9PiAraXRlbVxufTtcblxuZnVuY3Rpb24gY29udmVydFByaW1pdGl2ZSh0ZXh0OiBzdHJpbmcsIHR5cGU6IFJ1bGUpIHtcbiAgY29uc3QgY29udmVydGVyID0gY29udmVydGVyVGJsW3R5cGUucHJpbWl0aXZlVHlwZV07XG5cbiAgaWYgKGNvbnZlcnRlcikge1xuICAgIGlmICh0eXBlLmlzTGlzdCkge1xuICAgICAgcmV0dXJuIHRleHRcbiAgICAgICAgLnRyaW0oKVxuICAgICAgICAuc3BsaXQoL1xccysvKVxuICAgICAgICAubWFwKGNvbnZlcnRlcik7XG4gICAgfSBlbHNlIHtcbiAgICAgIHJldHVybiBjb252ZXJ0ZXIodGV4dC50cmltKCkpO1xuICAgIH1cbiAgfVxuXG4gIHJldHVybiBudWxsO1xufVxuXG5leHBvcnQgY2xhc3MgUGFyc2VyPFQ+IHtcbiAgeHBhdGhOYW1lc3BhY2VUYmw6IFJlY29yZDxzdHJpbmcsIHN0cmluZz47XG4gIGNvbnN0cnVjdG9yKHhwYXRoTmFtZXNwYWNlVGJsOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+ID0geyBcIlwiOiBcIlwiIH0pIHtcbiAgICAvLyBUT0RPIHRoZXJlIGlzIHByb2JhYmx5IGEgYmV0dGVyIHdheSB0byBkbyB0aGlzLlxuICAgIC8vIEl0IGFwcGVhcnMgdGhlIGNvbnRleHQgcGFyYW0gaW4gdGhlIHBhcnNlci5wYXJzZXJcbiAgICAvLyBtZXRob2QgbWF5IGhhdmUgYmUgaW50ZW5kZWQgZm9yIHRoZSBzYW1lIHB1cnBvc2UuXG4gICAgdGhpcy54cGF0aE5hbWVzcGFjZVRibCA9IHhwYXRoTmFtZXNwYWNlVGJsO1xuICB9XG4gIC8vIFRPRE8gd2h5IGRvIEkgbmVlZCB0byB1c2UgQlRyZWU8YW55PiBoZXJlP1xuICAvLyBJIHNob3VsZCBiZSBhYmxlIHRvIHVzZSBCVHJlZTxUPlxuICBiVHJlZTogQlRyZWU8YW55PiAmIEJUcmVlPFQ+ID0gbmV3IE1hcCgpO1xuICBhdHRhY2g8Q3VzdG9tSGFuZGxlciBleHRlbmRzIEhhbmRsZXJJbnN0YW5jZT4oXG4gICAgaGFuZGxlcjoge1xuICAgICAgbmV3ICgpOiBDdXN0b21IYW5kbGVyO1xuICAgIH0sXG4gICAgeHBhdGg6IHN0cmluZ1xuICApIHtcbiAgICBjb25zdCB7IHhwYXRoTmFtZXNwYWNlVGJsIH0gPSB0aGlzO1xuICAgIGNvbnN0IHByb3RvID0gaGFuZGxlci5wcm90b3R5cGUgYXMgQ3VzdG9tSGFuZGxlcjtcbiAgICBjb25zdCByZWFsSGFuZGxlciA9IChoYW5kbGVyIGFzIFJ1bGVDbGFzcykucnVsZS5oYW5kbGVyO1xuICAgIGNvbnN0IHJlYWxQcm90byA9IHJlYWxIYW5kbGVyLnByb3RvdHlwZSBhcyBDdXN0b21IYW5kbGVyO1xuXG4gICAgdHlwZSBDdXN0b21IYW5kbGVyS2V5ID0ga2V5b2YgQ3VzdG9tSGFuZGxlcjtcbiAgICBjb25zdCBjdXN0b21IYW5kbGVyS2V5czogQ3VzdG9tSGFuZGxlcktleVtdID0gT2JqZWN0LmtleXMocHJvdG8pO1xuXG4gICAgZm9yIChjb25zdCBjdXN0b21IYW5kbGVyS2V5IG9mIGN1c3RvbUhhbmRsZXJLZXlzKSB7XG4gICAgICBjb25zdCB0aW1lQmFzZWRLZXlzOiBDdXN0b21IYW5kbGVyS2V5W10gPSBbXCJfYmVmb3JlXCIsIFwiX2FmdGVyXCJdO1xuICAgICAgaWYgKHRpbWVCYXNlZEtleXMuaW5kZXhPZihjdXN0b21IYW5kbGVyS2V5KSA9PT0gLTEpIHtcbiAgICAgICAgcmVhbFByb3RvW2N1c3RvbUhhbmRsZXJLZXldID0gcHJvdG9bY3VzdG9tSGFuZGxlcktleV07XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gVE9ETyBpcyB0aGlzIHJlYWxseSB0aGUgYmVzdCB3YXkgdG8gZG8gdGhpcz9cbiAgICBjb25zdCB7IF9iZWZvcmUsIF9hZnRlciB9ID0gcHJvdG87XG4gICAgaWYgKHhwYXRoKSB7XG4gICAgICBpZiAoX2JlZm9yZSB8fCBfYWZ0ZXIpIHtcbiAgICAgICAgLy8gVE9ETyB3ZSBhcmUgbXV0YXRpbmcgcmV2ZXJzZWRYUGF0aEVsTWF0Y2hlcnMgZm9yIHhwYXRoXG4gICAgICAgIC8vIGV4cHJlc3Npb25zIHdpdGggYXR0cmlidXRlcywgc3VjaCBhc1xuICAgICAgICAvLyBcIi9QYXRod2F5L0BHcmFwaElkXCJcbiAgICAgICAgLy8gb3JcbiAgICAgICAgLy8gXCIvUGF0aHdheS9AKlwiXG4gICAgICAgIC8vIGJlY2F1c2Ugd2UgbmVlZCB0byBmaXJzdCBqdXN0IG1hdGNoIHRoZSBlbGVtZW50KHMpLCBhbmRcbiAgICAgICAgLy8gdGhlbiBhZnRlcndhcmRzIG1hdGNoIGFueSBhdHRyaWJ1dGUuXG4gICAgICAgIGxldCByZXZlcnNlZFhQYXRoRWxNYXRjaGVycyA9IHBhcnNlKHhwYXRoLCB4cGF0aE5hbWVzcGFjZVRibCkucmV2ZXJzZSgpO1xuICAgICAgICBsZXQgeHBhdGhBdHRyTWF0Y2hlcjogeyBhdHRyaWJ1dGU6IHN0cmluZyB9O1xuICAgICAgICBpZiAocmV2ZXJzZWRYUGF0aEVsTWF0Y2hlcnNbMF0uYXR0cmlidXRlICE9PSBudWxsKSB7XG4gICAgICAgICAgeHBhdGhBdHRyTWF0Y2hlciA9IHJldmVyc2VkWFBhdGhFbE1hdGNoZXJzLnNoaWZ0KCk7XG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgZmluYWxJdGVtID0gcmV2ZXJzZWRYUGF0aEVsTWF0Y2hlcnMucmVkdWNlKGZ1bmN0aW9uKFxuICAgICAgICAgIHBhcmVudE1hcCxcbiAgICAgICAgICB4cGF0aEVsTWF0Y2hlcjogSXRlbVBhcnNlZFxuICAgICAgICApIHtcbiAgICAgICAgICBjb25zdCB4cGF0aEVsTWF0Y2hlclBhaXJzID0gdG9QYWlycyh4cGF0aEVsTWF0Y2hlcik7XG4gICAgICAgICAgbGV0IFtjdXJyZW50TWFwLCBjdXJyZW50SXRlbVBhcnNlZF06IFtcbiAgICAgICAgICAgIEJUcmVlPFQ+LFxuICAgICAgICAgICAgSXRlbVBhcnNlZFxuICAgICAgICAgIF0gPSBmaW5kRW50cnkocGFyZW50TWFwLmVudHJpZXMoKSwgZnVuY3Rpb24oY2FuZGlkYXRlSXRlbVBhcnNlZCkge1xuICAgICAgICAgICAgcmV0dXJuIHhwYXRoRWxNYXRjaGVyUGFpcnMucmVkdWNlKGZ1bmN0aW9uKFxuICAgICAgICAgICAgICBpc1J1bm5pbmdNYXRjaDogYm9vbGVhbixcbiAgICAgICAgICAgICAgW3hwYXRoRWxNYXRjaGVyS2V5LCB4cGF0aEVsTWF0Y2hlclZhbHVlXTogW1xuICAgICAgICAgICAgICAgIEl0ZW1QYXJzZWRLZXksXG4gICAgICAgICAgICAgICAgSXRlbVBhcnNlZFZhbHVlXG4gICAgICAgICAgICAgIF1cbiAgICAgICAgICAgICkge1xuICAgICAgICAgICAgICByZXR1cm4gKFxuICAgICAgICAgICAgICAgIGlzUnVubmluZ01hdGNoICYmXG4gICAgICAgICAgICAgICAgY2FuZGlkYXRlSXRlbVBhcnNlZFt4cGF0aEVsTWF0Y2hlcktleV0gPT09IHhwYXRoRWxNYXRjaGVyVmFsdWVcbiAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB0cnVlKTtcbiAgICAgICAgICB9KSB8fCBbbmV3IE1hcCgpLCB4cGF0aEVsTWF0Y2hlcl07XG4gICAgICAgICAgcGFyZW50TWFwLnNldChjdXJyZW50SXRlbVBhcnNlZCwgY3VycmVudE1hcCk7XG4gICAgICAgICAgcmV0dXJuIGN1cnJlbnRNYXA7XG4gICAgICAgIH0sXG4gICAgICAgIHRoaXMuYlRyZWUpO1xuXG4gICAgICAgIGlmIChfYmVmb3JlKSB7XG4gICAgICAgICAgZmluYWxJdGVtLnNldChcbiAgICAgICAgICAgIFwiX2JlZm9yZVwiLFxuICAgICAgICAgICAgIXhwYXRoQXR0ck1hdGNoZXIgfHwgeHBhdGhBdHRyTWF0Y2hlci5hdHRyaWJ1dGUgPT09IFwiKlwiXG4gICAgICAgICAgICAgID8gX2JlZm9yZVxuICAgICAgICAgICAgICA6IGZ1bmN0aW9uKHRoaXM6IE1hcDxzdHJpbmcsIHN0cmluZyB8IG51bWJlciB8IGJvb2xlYW4gfCBcIlwiPikge1xuICAgICAgICAgICAgICAgICAgY29uc3QgcGlja2VkID0gcGljayh0aGlzLCB4cGF0aEF0dHJNYXRjaGVyLmF0dHJpYnV0ZSk7XG4gICAgICAgICAgICAgICAgICBfYmVmb3JlLmNhbGwocGlja2VkKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoX2FmdGVyKSB7XG4gICAgICAgICAgZmluYWxJdGVtLnNldChcIl9hZnRlclwiLCBfYWZ0ZXIpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmVhbEhhbmRsZXIuX2N1c3RvbSA9IHRydWU7XG4gIH1cblxuICBwYXJzZTxPdXRwdXQgZXh0ZW5kcyBIYW5kbGVySW5zdGFuY2U+KFxuICAgIHN0cmVhbTogc3RyaW5nIHwgc3RyZWFtLlJlYWRhYmxlIHwgTm9kZUpTLlJlYWRhYmxlU3RyZWFtLFxuICAgIG91dHB1dDogT3V0cHV0LFxuICAgIGN