matrix-react-sdk
Version:
SDK for matrix.org using React
342 lines (279 loc) • 39.8 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.editBodyDiffToHtml = editBodyDiffToHtml;
var _react = _interopRequireDefault(require("react"));
var _classnames = _interopRequireDefault(require("classnames"));
var _diffMatchPatch = _interopRequireDefault(require("diff-match-patch"));
var _diffDom = require("diff-dom");
var _HtmlUtils = require("../HtmlUtils");
/*
Copyright 2019 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
const decodeEntities = function () {
let textarea = null;
return function (string) {
if (!textarea) {
textarea = document.createElement("textarea");
}
textarea.innerHTML = string;
return textarea.value;
};
}();
function textToHtml(text) {
const container = document.createElement("div");
container.textContent = text;
return container.innerHTML;
}
function getSanitizedHtmlBody(content) {
const opts = {
stripReplyFallback: true,
returnString: true
};
if (content.format === "org.matrix.custom.html") {
return (0, _HtmlUtils.bodyToHtml)(content, null, opts);
} else {
// convert the string to something that can be safely
// embedded in an html document, e.g. use html entities where needed
// This is also needed so that DiffDOM wouldn't interpret something
// as a tag when somebody types e.g. "</sarcasm>"
// as opposed to bodyToHtml, here we also render
// text messages with dangerouslySetInnerHTML, to unify
// the code paths and because we need html to show differences
return textToHtml((0, _HtmlUtils.bodyToHtml)(content, null, opts));
}
}
function wrapInsertion(child) {
const wrapper = document.createElement((0, _HtmlUtils.checkBlockNode)(child) ? "div" : "span");
wrapper.className = "mx_EditHistoryMessage_insertion";
wrapper.appendChild(child);
return wrapper;
}
function wrapDeletion(child) {
const wrapper = document.createElement((0, _HtmlUtils.checkBlockNode)(child) ? "div" : "span");
wrapper.className = "mx_EditHistoryMessage_deletion";
wrapper.appendChild(child);
return wrapper;
}
function findRefNodes(root, route, isAddition) {
let refNode = root;
let refParentNode;
const end = isAddition ? route.length - 1 : route.length;
for (let i = 0; i < end; ++i) {
refParentNode = refNode;
refNode = refNode.childNodes[route[i]];
}
return {
refNode,
refParentNode
};
}
function diffTreeToDOM(desc) {
if (desc.nodeName === "#text") {
return stringAsTextNode(desc.data);
} else {
const node = document.createElement(desc.nodeName);
if (desc.attributes) {
for (const [key, value] of Object.entries(desc.attributes)) {
node.setAttribute(key, value);
}
}
if (desc.childNodes) {
for (const childDesc of desc.childNodes) {
node.appendChild(diffTreeToDOM(childDesc));
}
}
return node;
}
}
function insertBefore(parent, nextSibling, child) {
if (nextSibling) {
parent.insertBefore(child, nextSibling);
} else {
parent.appendChild(child);
}
}
function isRouteOfNextSibling(route1, route2) {
// routes are arrays with indices,
// to be interpreted as a path in the dom tree
// ensure same parent
for (let i = 0; i < route1.length - 1; ++i) {
if (route1[i] !== route2[i]) {
return false;
}
} // the route2 is only affected by the diff of route1
// inserting an element if the index at the level of the
// last element of route1 being larger
// (e.g. coming behind route1 at that level)
const lastD1Idx = route1.length - 1;
return route2[lastD1Idx] >= route1[lastD1Idx];
}
function adjustRoutes(diff, remainingDiffs) {
if (diff.action === "removeTextElement" || diff.action === "removeElement") {
// as removed text is not removed from the html, but marked as deleted,
// we need to readjust indices that assume the current node has been removed.
const advance = 1;
for (const rd of remainingDiffs) {
if (isRouteOfNextSibling(diff.route, rd.route)) {
rd.route[diff.route.length - 1] += advance;
}
}
}
}
function stringAsTextNode(string) {
return document.createTextNode(decodeEntities(string));
}
function renderDifferenceInDOM(originalRootNode, diff, diffMathPatch) {
const {
refNode,
refParentNode
} = findRefNodes(originalRootNode, diff.route);
switch (diff.action) {
case "replaceElement":
{
const container = document.createElement("span");
const delNode = wrapDeletion(diffTreeToDOM(diff.oldValue));
const insNode = wrapInsertion(diffTreeToDOM(diff.newValue));
container.appendChild(delNode);
container.appendChild(insNode);
refNode.parentNode.replaceChild(container, refNode);
break;
}
case "removeTextElement":
{
const delNode = wrapDeletion(stringAsTextNode(diff.value));
refNode.parentNode.replaceChild(delNode, refNode);
break;
}
case "removeElement":
{
const delNode = wrapDeletion(diffTreeToDOM(diff.element));
refNode.parentNode.replaceChild(delNode, refNode);
break;
}
case "modifyTextElement":
{
const textDiffs = diffMathPatch.diff_main(diff.oldValue, diff.newValue);
diffMathPatch.diff_cleanupSemantic(textDiffs);
const container = document.createElement("span");
for (const [modifier, text] of textDiffs) {
let textDiffNode = stringAsTextNode(text);
if (modifier < 0) {
textDiffNode = wrapDeletion(textDiffNode);
} else if (modifier > 0) {
textDiffNode = wrapInsertion(textDiffNode);
}
container.appendChild(textDiffNode);
}
refNode.parentNode.replaceChild(container, refNode);
break;
}
case "addElement":
{
const insNode = wrapInsertion(diffTreeToDOM(diff.element));
insertBefore(refParentNode, refNode, insNode);
break;
}
case "addTextElement":
{
// XXX: sometimes diffDOM says insert a newline when there shouldn't be one
// but we must insert the node anyway so that we don't break the route child IDs.
// See https://github.com/fiduswriter/diffDOM/issues/100
const insNode = wrapInsertion(stringAsTextNode(diff.value !== "\n" ? diff.value : ""));
insertBefore(refParentNode, refNode, insNode);
break;
}
// e.g. when changing a the href of a link,
// show the link with old href as removed and with the new href as added
case "removeAttribute":
case "addAttribute":
case "modifyAttribute":
{
const delNode = wrapDeletion(refNode.cloneNode(true));
const updatedNode = refNode.cloneNode(true);
if (diff.action === "addAttribute" || diff.action === "modifyAttribute") {
updatedNode.setAttribute(diff.name, diff.newValue);
} else {
updatedNode.removeAttribute(diff.name);
}
const insNode = wrapInsertion(updatedNode);
const container = document.createElement((0, _HtmlUtils.checkBlockNode)(refNode) ? "div" : "span");
container.appendChild(delNode);
container.appendChild(insNode);
refNode.parentNode.replaceChild(container, refNode);
break;
}
default:
// Should not happen (modifyComment, ???)
console.warn("MessageDiffUtils::editBodyDiffToHtml: diff action not supported atm", diff);
}
}
function routeIsEqual(r1, r2) {
return r1.length === r2.length && !r1.some((e, i) => e !== r2[i]);
} // workaround for https://github.com/fiduswriter/diffDOM/issues/90
function filterCancelingOutDiffs(originalDiffActions) {
const diffActions = originalDiffActions.slice();
for (let i = 0; i < diffActions.length; ++i) {
const diff = diffActions[i];
if (diff.action === "removeTextElement") {
const nextDiff = diffActions[i + 1];
const cancelsOut = nextDiff && nextDiff.action === "addTextElement" && nextDiff.text === diff.text && routeIsEqual(nextDiff.route, diff.route);
if (cancelsOut) {
diffActions.splice(i, 2);
}
}
}
return diffActions;
}
/**
* Renders a message with the changes made in an edit shown visually.
* @param {object} originalContent the content for the base message
* @param {object} editContent the content for the edit message
* @return {object} a react element similar to what `bodyToHtml` returns
*/
function editBodyDiffToHtml(originalContent, editContent) {
// wrap the body in a div, DiffDOM needs a root element
const originalBody = `<div>${getSanitizedHtmlBody(originalContent)}</div>`;
const editBody = `<div>${getSanitizedHtmlBody(editContent)}</div>`;
const dd = new _diffDom.DiffDOM(); // diffActions is an array of objects with at least a `action` and `route`
// property. `action` tells us what the diff object changes, and `route` where.
// `route` is a path on the DOM tree expressed as an array of indices.
const originaldiffActions = dd.diff(originalBody, editBody); // work around https://github.com/fiduswriter/diffDOM/issues/90
const diffActions = filterCancelingOutDiffs(originaldiffActions); // for diffing text fragments
const diffMathPatch = new _diffMatchPatch.default(); // parse the base html message as a DOM tree, to which we'll apply the differences found.
// fish out the div in which we wrapped the messages above with children[0].
const originalRootNode = new DOMParser().parseFromString(originalBody, "text/html").body.children[0];
for (let i = 0; i < diffActions.length; ++i) {
const diff = diffActions[i];
renderDifferenceInDOM(originalRootNode, diff, diffMathPatch); // DiffDOM assumes in subsequent diffs route path that
// the action was applied (e.g. that a removeElement action removed the element).
// This is not the case for us. We render differences in the DOM tree, and don't apply them.
// So we need to adjust the routes of the remaining diffs to account for this.
adjustRoutes(diff, diffActions.slice(i + 1));
} // take the html out of the modified DOM tree again
const safeBody = originalRootNode.innerHTML;
const className = (0, _classnames.default)({
'mx_EventTile_body': true,
'markdown-body': true
});
return /*#__PURE__*/_react.default.createElement("span", {
key: "body",
className: className,
dangerouslySetInnerHTML: {
__html: safeBody
},
dir: "auto"
});
}
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy91dGlscy9NZXNzYWdlRGlmZlV0aWxzLmpzIl0sIm5hbWVzIjpbImRlY29kZUVudGl0aWVzIiwidGV4dGFyZWEiLCJzdHJpbmciLCJkb2N1bWVudCIsImNyZWF0ZUVsZW1lbnQiLCJpbm5lckhUTUwiLCJ2YWx1ZSIsInRleHRUb0h0bWwiLCJ0ZXh0IiwiY29udGFpbmVyIiwidGV4dENvbnRlbnQiLCJnZXRTYW5pdGl6ZWRIdG1sQm9keSIsImNvbnRlbnQiLCJvcHRzIiwic3RyaXBSZXBseUZhbGxiYWNrIiwicmV0dXJuU3RyaW5nIiwiZm9ybWF0Iiwid3JhcEluc2VydGlvbiIsImNoaWxkIiwid3JhcHBlciIsImNsYXNzTmFtZSIsImFwcGVuZENoaWxkIiwid3JhcERlbGV0aW9uIiwiZmluZFJlZk5vZGVzIiwicm9vdCIsInJvdXRlIiwiaXNBZGRpdGlvbiIsInJlZk5vZGUiLCJyZWZQYXJlbnROb2RlIiwiZW5kIiwibGVuZ3RoIiwiaSIsImNoaWxkTm9kZXMiLCJkaWZmVHJlZVRvRE9NIiwiZGVzYyIsIm5vZGVOYW1lIiwic3RyaW5nQXNUZXh0Tm9kZSIsImRhdGEiLCJub2RlIiwiYXR0cmlidXRlcyIsImtleSIsIk9iamVjdCIsImVudHJpZXMiLCJzZXRBdHRyaWJ1dGUiLCJjaGlsZERlc2MiLCJpbnNlcnRCZWZvcmUiLCJwYXJlbnQiLCJuZXh0U2libGluZyIsImlzUm91dGVPZk5leHRTaWJsaW5nIiwicm91dGUxIiwicm91dGUyIiwibGFzdEQxSWR4IiwiYWRqdXN0Um91dGVzIiwiZGlmZiIsInJlbWFpbmluZ0RpZmZzIiwiYWN0aW9uIiwiYWR2YW5jZSIsInJkIiwiY3JlYXRlVGV4dE5vZGUiLCJyZW5kZXJEaWZmZXJlbmNlSW5ET00iLCJvcmlnaW5hbFJvb3ROb2RlIiwiZGlmZk1hdGhQYXRjaCIsImRlbE5vZGUiLCJvbGRWYWx1ZSIsImluc05vZGUiLCJuZXdWYWx1ZSIsInBhcmVudE5vZGUiLCJyZXBsYWNlQ2hpbGQiLCJlbGVtZW50IiwidGV4dERpZmZzIiwiZGlmZl9tYWluIiwiZGlmZl9jbGVhbnVwU2VtYW50aWMiLCJtb2RpZmllciIsInRleHREaWZmTm9kZSIsImNsb25lTm9kZSIsInVwZGF0ZWROb2RlIiwibmFtZSIsInJlbW92ZUF0dHJpYnV0ZSIsImNvbnNvbGUiLCJ3YXJuIiwicm91dGVJc0VxdWFsIiwicjEiLCJyMiIsInNvbWUiLCJlIiwiZmlsdGVyQ2FuY2VsaW5nT3V0RGlmZnMiLCJvcmlnaW5hbERpZmZBY3Rpb25zIiwiZGlmZkFjdGlvbnMiLCJzbGljZSIsIm5leHREaWZmIiwiY2FuY2Vsc091dCIsInNwbGljZSIsImVkaXRCb2R5RGlmZlRvSHRtbCIsIm9yaWdpbmFsQ29udGVudCIsImVkaXRDb250ZW50Iiwib3JpZ2luYWxCb2R5IiwiZWRpdEJvZHkiLCJkZCIsIkRpZmZET00iLCJvcmlnaW5hbGRpZmZBY3Rpb25zIiwiRGlmZk1hdGNoUGF0Y2giLCJET01QYXJzZXIiLCJwYXJzZUZyb21TdHJpbmciLCJib2R5IiwiY2hpbGRyZW4iLCJzYWZlQm9keSIsIl9faHRtbCJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7O0FBZ0JBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQXBCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFRQSxNQUFNQSxjQUFjLEdBQUksWUFBVztBQUMvQixNQUFJQyxRQUFRLEdBQUcsSUFBZjtBQUNBLFNBQU8sVUFBU0MsTUFBVCxFQUFpQjtBQUNwQixRQUFJLENBQUNELFFBQUwsRUFBZTtBQUNYQSxNQUFBQSxRQUFRLEdBQUdFLFFBQVEsQ0FBQ0MsYUFBVCxDQUF1QixVQUF2QixDQUFYO0FBQ0g7O0FBQ0RILElBQUFBLFFBQVEsQ0FBQ0ksU0FBVCxHQUFxQkgsTUFBckI7QUFDQSxXQUFPRCxRQUFRLENBQUNLLEtBQWhCO0FBQ0gsR0FORDtBQU9ILENBVHNCLEVBQXZCOztBQVdBLFNBQVNDLFVBQVQsQ0FB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QWEsR0FBRyxJQUFJdUMsdUJBQUosRUFBdEIsQ0FaNkQsQ0FhN0Q7QUFDQTs7QUFDQSxRQUFNeEMsZ0JBQWdCLEdBQUcsSUFBSXlDLFNBQUosR0FBZ0JDLGVBQWhCLENBQWdDUCxZQUFoQyxFQUE4QyxXQUE5QyxFQUEyRFEsSUFBM0QsQ0FBZ0VDLFFBQWhFLENBQXlFLENBQXpFLENBQXpCOztBQUNBLE9BQUssSUFBSXpFLENBQUMsR0FBRyxDQUFiLEVBQWdCQSxDQUFDLEdBQUd3RCxXQUFXLENBQUN6RCxNQUFoQyxFQUF3QyxFQUFFQyxDQUExQyxFQUE2QztBQUN6QyxVQUFNc0IsSUFBSSxHQUFHa0MsV0FBVyxDQUFDeEQsQ0FBRCxDQUF4QjtBQUNBNEIsSUFBQUEscUJBQXFCLENBQUNDLGdCQUFELEVBQW1CUCxJQUFuQixFQUF5QlEsYUFBekIsQ0FBckIsQ0FGeUMsQ0FHekM7QUFDQTtBQUNBO0FBQ0E7O0FBQ0FULElBQUFBLFlBQVksQ0FBQ0MsSUFBRCxFQUFPa0MsV0FBVyxDQUFDQyxLQUFaLENBQWtCekQsQ0FBQyxHQUFHLENBQXRCLENBQVAsQ0FBWjtBQUNILEdBeEI0RCxDQXlCN0Q7OztBQUNBLFFBQU0wRSxRQUFRLEdBQUc3QyxnQkFBZ0IsQ0FBQ3ZELFNBQWxDO0FBQ0EsUUFBTWUsU0FBUyxHQUFHLHlCQUFXO0FBQ3pCLHlCQUFxQixJQURJO0FBRXpCLHFCQUFpQjtBQUZRLEdBQVgsQ0FBbEI7QUFJQSxzQkFBTztBQUFNLElBQUEsR0FBRyxFQUFDLE1BQVY7QUFBaUIsSUFBQSxTQUFTLEVBQUVBLFNBQTVCO0FBQXVDLElBQUEsdUJBQXVCLEVBQUU7QUFBRXNGLE1BQUFBLE1BQU0sRUFBRUQ7QUFBVixLQUFoRTtBQUFzRixJQUFBLEdBQUcsRUFBQztBQUExRixJQUFQO0FBQ0giLCJzb3VyY2VzQ29udGVudCI6WyIvKlxuQ29weXJpZ2h0IDIwMTkgVGhlIE1hdHJpeC5vcmcgRm91bmRhdGlvbiBDLkkuQy5cblxuTGljZW5zZWQgdW5kZXIgdGhlIEFwYWNoZSBMaWNlbnNlLCBWZXJzaW9uIDIuMCAodGhlIFwiTGljZW5zZVwiKTtcbnlvdSBtYXkgbm90IHVzZSB0aGlzIGZpbGUgZXhjZXB0IGluIGNvbXBsaWFuY2Ugd2l0aCB0aGUgTGljZW5zZS5cbllvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdFxuXG4gICAgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzL0xJQ0VOU0UtMi4wXG5cblVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvciBhZ3JlZWQgdG8gaW4gd3JpdGluZywgc29mdHdhcmVcbmRpc3RyaWJ1dGVkIHVuZGVyIHRoZSBMaWNlbnNlIGlzIGRpc3RyaWJ1dGVkIG9uIGFuIFwiQVMgSVNcIiBCQVNJUyxcbldJVEhPVVQgV0FSUkFOVElFUyBPUiBDT05ESVRJT05TIE9GIEFOWSBLSU5ELCBlaXRoZXIgZXhwcmVzcyBvciBpbXBsaWVkLlxuU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZFxubGltaXRhdGlvbnMgdW5kZXIgdGhlIExpY2Vuc2UuXG4qL1xuXG5pbXBvcnQgUmVhY3QgZnJvbSAncmVhY3QnO1xuaW1wb3J0IGNsYXNzTmFtZXMgZnJvbSAnY2xhc3NuYW1lcyc7XG5pbXBvcnQgRGlmZk1hdGNoUGF0Y2ggZnJvbSAnZGlmZi1tYXRjaC1wYXRjaCc7XG5pbXBvcnQge0RpZmZET019IGZyb20gXCJkaWZmLWRvbVwiO1xuaW1wb3J0IHsgY2hlY2tCbG9ja05vZGUsIGJvZHlUb0h0bWwgfSBmcm9tIFwiLi4vSHRtbFV0aWxzXCI7XG5cbmNvbnN0IGRlY29kZUVudGl0aWVzID0gKGZ1bmN0aW9uKCkge1xuICAgIGxldCB0ZXh0YXJlYSA9IG51bGw7XG4gICAgcmV0dXJuIGZ1bmN0aW9uKHN0cmluZykge1xuICAgICAgICBpZiAoIXRleHRhcmVhKSB7XG4gICAgICAgICAgICB0ZXh0YXJlYSA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoXCJ0ZXh0YXJlYVwiKTtcbiAgICAgICAgfVxuICAgICAgICB0ZXh0YXJlYS5pbm5lckhUTUwgPSBzdHJpbmc7XG4gICAgICAgIHJldHVybiB0ZXh0YXJlYS52YWx1ZTtcbiAgICB9O1xufSkoKTtcblxuZnVuY3Rpb24gdGV4dFRvSHRtbCh0ZXh0KSB7XG4gICAgY29uc3QgY29udGFpbmVyID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudChcImRpdlwiKTtcbiAgICBjb250YWluZXIudGV4dENvbnRlbnQgPSB0ZXh0O1xuICAgIHJldHVybiBjb250YWluZXIuaW5uZXJIVE1MO1xufVxuXG5mdW5jdGlvbiBnZXRTYW5pdGl6ZWRIdG1sQm9keShjb250ZW50KSB7XG4gICAgY29uc3Qgb3B0cyA9IHtcbiAgICAgICAgc3RyaXBSZXBseUZhbGxiYWNrOiB0cnVlLFxuICAgICAgICByZXR1cm5TdHJpbmc6IHRydWUsXG4gICAgfTtcbiAgICBpZiAoY29udGVudC5mb3JtYXQgPT09IFwib3JnLm1hdHJpeC5jdXN0b20uaHRtbFwiKSB7XG4gICAgICAgIHJldHVybiBib2R5VG9IdG1sKGNvbnRlbnQsIG51bGwsIG9wdHMpO1xuICAgIH0gZWxzZSB7XG4gICAgICAgIC8vIGNvbnZlcnQgdGhlIHN0cmluZyB0byBzb21ldGhpbmcgdGhhdCBjYW4gYmUgc2FmZWx5XG4gICAgICAgIC8vIGVtYmVkZGVkIGluIGFuIGh0bWwgZG9jdW1lbnQsIGUuZy4gdXNlIGh0bWwgZW50aXRpZXMgd2hlcmUgbmVlZGVkXG4gICAgICAgIC8vIFRoaXMgaXMgYWxzbyBuZWVkZWQgc28gdGhhdCBEaWZmRE9NIHdvdWxkbid0IGludGVycHJldCBzb21ldGhpbmdcbiAgICAgICAgLy8gYXMgYSB0YWcgd2hlbiBzb21lYm9keSB0eXBlcyBlLmcuIFwiPC9zYXJjYXNtPlwiXG5cbiAgICAgICAgLy8gYXMgb3Bwb3NlZCB0byBib2R5VG9IdG1sLCBoZXJlIHdlIGFsc28gcmVuZGVyXG4gICAgICAgIC8vIHRleHQgbWVzc2FnZXMgd2l0aCBkYW5nZXJvdXNseVNldElubmVySFRNTCwgdG8gdW5pZnlcbiAgICAgICAgLy8gdGhlIGNvZGUgcGF0aHMgYW5kIGJlY2F1c2Ugd2UgbmVlZCBodG1sIHRvIHNob3cgZGlmZmVyZW5jZXNcbiAgICAgICAgcmV0dXJuIHRleHRUb0h0bWwoYm9keVRvSHRtbChjb250ZW50LCBudWxsLCBvcHRzKSk7XG4gICAgfVxufVxuXG5mdW5jdGlvbiB3cmFwSW5zZXJ0aW9uKGNoaWxkKSB7XG4gICAgY29uc3Qgd3JhcHBlciA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoY2hlY2tCbG9ja05vZGUoY2hpbGQpID8gXCJkaXZcIiA6IFwic3BhblwiKTtcbiAgICB3cmFwcGVyLmNsYXNzTmFtZSA9IFwibXhfRWRpdEhpc3RvcnlNZXNzYWdlX2luc2VydGlvblwiO1xuICAgIHdyYXBwZXIuYXBwZW5kQ2hpbGQoY2hpbGQpO1xuICAgIHJldHVybiB3cmFwcGVyO1xufVxuXG5mdW5jdGlvbiB3cmFwRGVsZXRpb24oY2hpbGQpIHtcbiAgICBjb25zdCB3cmFwcGVyID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudChjaGVja0Jsb2NrTm9kZShjaGlsZCkgPyBcImRpdlwiIDogXCJzcGFuXCIpO1xuICAgIHdyYXBwZXIuY2xhc3NOYW1lID0gXCJteF9FZGl0SGlzdG9yeU1lc3NhZ2VfZGVsZXRpb25cIjtcbiAgICB3cmFwcGVyLmFwcGVuZENoaWxkKGNoaWxkKTtcbiAgICByZXR1cm4gd3JhcHBlcjtcbn1cblxuZnVuY3Rpb24gZmluZFJlZk5vZGVzKHJvb3QsIHJvdXRlLCBpc0FkZGl0aW9uKSB7XG4gICAgbGV0IHJlZk5vZGUgPSByb290O1xuICAgIGxldCByZWZQYXJlbnROb2RlO1xuICAgIGNvbnN0IGVuZCA9IGlzQWRkaXRpb24gPyByb3V0ZS5sZW5ndGggLSAxIDogcm91dGUubGVuZ3RoO1xuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgZW5kOyArK2kpIHtcbiAgICAgICAgcmVmUGFyZW50Tm9kZSA9IHJlZk5vZGU7XG4gICAgICAgIHJlZk5vZGUgPSByZWZOb2RlLmNoaWxkTm9kZXNbcm91dGVbaV1dO1xuICAgIH1cbiAgICByZXR1cm4ge3JlZk5vZGUsIHJlZlBhcmVudE5vZGV9O1xufVxuXG5mdW5jdGlvbiBkaWZmVHJlZVRvRE9NKGRlc2MpIHtcbiAgICBpZiAoZGVzYy5ub2RlTmFtZSA9PT0gXCIjdGV4dFwiKSB7XG4gICAgICAgIHJldHVybiBzdHJpbmdBc1RleHROb2RlKGRlc2MuZGF0YSk7XG4gICAgfSBlbHNlIHtcbiAgICAgICAgY29uc3Qgbm9kZSA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoZGVzYy5ub2RlTmFtZSk7XG4gICAgICAgIGlmIChkZXNjLmF0dHJpYnV0ZXMpIHtcbiAgICAgICAgICAgIGZvciAoY29uc3QgW2tleSwgdmFsdWVdIG9mIE9iamVjdC5lbnRyaWVzKGRlc2MuYXR0cmlidXRlcykpIHtcbiAgICAgICAgICAgICAgICBub2RlLnNldEF0dHJpYnV0ZShrZXksIHZhbHVlKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBpZiAoZGVzYy5jaGlsZE5vZGVzKSB7XG4gICAgICAgICAgICBmb3IgKGNvbnN0IGNoaWxkRGVzYyBvZiBkZXNjLmNoaWxkTm9kZXMpIHtcbiAgICAgICAgICAgICAgICBub2RlLmFwcGVuZENoaWxkKGRpZmZUcmVlVG9ET00oY2hpbGREZXNjKSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIG5vZGU7XG4gICAgfVxufVxuXG5mdW5jdGlvbiBpbnNlcnRCZWZvcmUocGFyZW50LCBuZXh0U2libGluZywgY2hpbGQpIHtcbiAgICBpZiAobmV4dFNpYmxpbmcpIHtcbiAgICAgICAgcGFyZW50Lmluc2VydEJlZm9yZShjaGlsZCwgbmV4dFNpYmxpbmcpO1xuICAgIH0gZWxzZSB7XG4gICAgICAgIHBhcmVudC5hcHBlbmRDaGlsZChjaGlsZCk7XG4gICAgfVxufVxuXG5mdW5jdGlvbiBpc1JvdXRlT2ZOZXh0U2libGluZyhyb3V0ZTEsIHJvdXRlMikge1xuICAgIC8vIHJvdXRlcyBhcmUgYXJyYXlzIHdpdGggaW5kaWNlcyxcbiAgICAvLyB0byBiZSBpbnRlcnByZXRlZCBhcyBhIHBhdGggaW4gdGhlIGRvbSB0cmVlXG5cbiAgICAvLyBlbnN1cmUgc2FtZSBwYXJlbnRcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IHJvdXRlMS5sZW5ndGggLSAxOyArK2kpIHtcbiAgICAgICAgaWYgKHJvdXRlMVtpXSAhPT0gcm91dGUyW2ldKSB7XG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIH1cbiAgICB9XG4gICAgLy8gdGhlIHJvdXRlMiBpcyBvbmx5IGFmZmVjdGVkIGJ5IHRoZSBkaWZmIG9mIHJvdXRlMVxuICAgIC8vIGluc2VydGluZyBhbiBlbGVtZW50IGlmIHRoZSBpbmRleCBhdCB0aGUgbGV2ZWwgb2YgdGhlXG4gICAgLy8gbGFzdCBlbGVtZW50IG9mIHJvdXRlMSBiZWluZyBsYXJnZXJcbiAgICAvLyAoZS5nLiBjb21pbmcgYmVoaW5kIHJvdXRlMSBhdCB0aGF0IGxldmVsKVxuICAgIGNvbnN0IGxhc3REMUlkeCA9IHJvdXRlMS5sZW5ndGggLSAxO1xuICAgIHJldHVybiByb3V0ZTJbbGFzdEQxSWR4XSA+PSByb3V0ZTFbbGFzdEQxSWR4XTtcbn1cblxuZnVuY3Rpb24gYWRqdXN0Um91dGVzKGRpZmYsIHJlbWFpbmluZ0RpZmZzKSB7XG4gICAgaWYgKGRpZmYuYWN0aW9uID09PSBcInJlbW92ZVRleHRFbGVtZW50XCIgfHwgZGlmZi5hY3Rpb24gPT09IFwicmVtb3ZlRWxlbWVudFwiKSB7XG4gICAgICAgIC8vIGFzIHJlbW92ZWQgdGV4dCBpcyBub3QgcmVtb3ZlZCBmcm9tIHRoZSBodG1sLCBidXQgbWFya2VkIGFzIGRlbGV0ZWQsXG4gICAgICAgIC8vIHdlIG5lZWQgdG8gcmVhZGp1c3QgaW5kaWNlcyB0aGF0IGFzc3VtZSB0aGUgY3VycmVudCBub2RlIGhhcyBiZWVuIHJlbW92ZWQuXG4gICAgICAgIGNvbnN0IGFkdmFuY2UgPSAxO1xuICAgICAgICBmb3IgKGNvbnN0IHJkIG9mIHJlbWFpbmluZ0RpZmZzKSB7XG4gICAgICAgICAgICBpZiAoaXNSb3V0ZU9mTmV4dFNpYmxpbmcoZGlmZi5yb3V0ZSwgcmQucm91dGUpKSB7XG4gICAgICAgICAgICAgICAgcmQucm91dGVbZGlmZi5yb3V0ZS5sZW5ndGggLSAxXSArPSBhZHZhbmNlO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxufVxuXG5mdW5jdGlvbiBzdHJpbmdBc1RleHROb2RlKHN0cmluZykge1xuICAgIHJldHVybiBkb2N1bWVudC5jcmVhdGVUZXh0Tm9kZShkZWNvZGVFbnRpdGllcyhzdHJpbmcpKTtcbn1cblxuZnVuY3Rpb24gcmVuZGVyRGlmZmVyZW5jZUluRE9NKG9yaWdpbmFsUm9vdE5vZGUsIGRpZmYsIGRpZmZNYXRoUGF0Y2gpIHtcbiAgICBjb25zdCB7cmVmTm9kZSwgcmVmUGFyZW50Tm9kZX0gPSBmaW5kUmVmTm9kZXMob3JpZ2luYWxSb290Tm9kZSwgZGlmZi5yb3V0ZSk7XG4gICAgc3dpdGNoIChkaWZmLmFjdGlvbikge1xuICAgICAgICBjYXNlIFwicmVwbGFjZUVsZW1lbnRcIjoge1xuICAgICAgICAgICAgY29uc3QgY29udGFpbmVyID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudChcInNwYW5cIik7XG4gICAgICAgICAgICBjb25zdCBkZWxOb2RlID0gd3JhcERlbGV0aW9uKGRpZmZUcmVlVG9ET00oZGlmZi5vbGRWYWx1ZSkpO1xuICAgICAgICAgICAgY29uc3QgaW5zTm9kZSA9IHdyYXBJbnNlcnRpb24oZGlmZlRyZWVUb0RPTShkaWZmLm5ld1ZhbHVlKSk7XG4gICAgICAgICAgICBjb250YWluZXIuYXBwZW5kQ2hpbGQoZGVsTm9kZSk7XG4gICAgICAgICAgICBjb250YWluZXIuYXBwZW5kQ2hpbGQoaW5zTm9kZSk7XG4gICAgICAgICAgICByZWZOb2RlLnBhcmVudE5vZGUucmVwbGFjZUNoaWxkKGNvbnRhaW5lciwgcmVmTm9kZSk7XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgfVxuICAgICAgICBjYXNlIFwicmVtb3ZlVGV4dEVsZW1lbnRcIjoge1xuICAgICAgICAgICAgY29uc3QgZGVsTm9kZSA9IHdyYXBEZWxldGlvbihzdHJpbmdBc1RleHROb2RlKGRpZmYudmFsdWUpKTtcbiAgICAgICAgICAgIHJlZk5vZGUucGFyZW50Tm9kZS5yZXBsYWNlQ2hpbGQoZGVsTm9kZSwgcmVmTm9kZSk7XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgfVxuICAgICAgICBjYXNlIFwicmVtb3ZlRWxlbWVudFwiOiB7XG4gICAgICAgICAgICBjb25zdCBkZWxOb2RlID0gd3JhcERlbGV0aW9uKGRpZmZUcmVlVG9ET00oZGlmZi5lbGVtZW50KSk7XG4gICAgICAgICAgICByZWZOb2RlLnBhcmVudE5vZGUucmVwbGFjZUNoaWxkKGRlbE5vZGUsIHJlZk5vZGUpO1xuICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgIH1cbiAgICAgICAgY2FzZSBcIm1vZGlmeVRleHRFbGVtZW50XCI6IHtcbiAgICAgICAgICAgIGNvbnN0IHRleHREaWZmcyA9IGRpZmZNYXRoUGF0Y2guZGlmZl9tYWluKGRpZmYub2xkVmFsdWUsIGRpZmYubmV3VmFsdWUpO1xuICAgICAgICAgICAgZGlmZk1hdGhQYXRjaC5kaWZmX2NsZWFudXBTZW1hbnRpYyh0ZXh0RGlmZnMpO1xuICAgICAgICAgICAgY29uc3QgY29udGFpbmVyID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudChcInNwYW5cIik7XG4gICAgICAgICAgICBmb3IgKGNvbnN0IFttb2RpZmllciwgdGV4dF0gb2YgdGV4dERpZmZzKSB7XG4gICAgICAgICAgICAgICAgbGV0IHRleHREaWZmTm9kZSA9IHN0cmluZ0FzVGV4dE5vZGUodGV4dCk7XG4gICAgICAgICAgICAgICAgaWYgKG1vZGlmaWVyIDwgMCkge1xuICAgICAgICAgICAgICAgICAgICB0ZXh0RGlmZk5vZGUgPSB3cmFwRGVsZXRpb24odGV4dERpZmZOb2RlKTtcbiAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKG1vZGlmaWVyID4gMCkge1xuICAgICAgICAgICAgICAgICAgICB0ZXh0RGlmZk5vZGUgPSB3cmFwSW5zZXJ0aW9uKHRleHREaWZmTm9kZSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGNvbnRhaW5lci5hcHBlbmRDaGlsZCh0ZXh0RGlmZk5vZGUpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmVmTm9kZS5wYXJlbnROb2RlLnJlcGxhY2VDaGlsZChjb250YWluZXIsIHJlZk5vZGUpO1xuICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgIH1cbiAgICAgICAgY2FzZSBcImFkZEVsZW1lbnRcIjoge1xuICAgICAgICAgICAgY29uc3QgaW5zTm9kZSA9IHdyYXBJbnNlcnRpb24oZGlmZlRyZWVUb0RPTShkaWZmLmVsZW1lbnQpKTtcbiAgICAgICAgICAgIGluc2VydEJlZm9yZShyZWZQYXJlbnROb2RlLCByZWZOb2RlLCBpbnNOb2RlKTtcbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICB9XG4gICAgICAgIGNhc2UgXCJhZGRUZXh0RWxlbWVudFwiOiB7XG4gICAgICAgICAgICAvLyBYWFg6IHNvbWV0aW1lcyBkaWZmRE9NIHNheXMgaW5zZXJ0IGEgbmV3bGluZSB3aGVuIHRoZXJlIHNob3VsZG4ndCBiZSBvbmVcbiAgICAgICAgICAgIC8vIGJ1dCB3ZSBtdXN0IGluc2VydCB0aGUgbm9kZSBhbnl3YXkgc28gdGhhdCB3ZSBkb24ndCBicmVhayB0aGUgcm91dGUgY2hpbGQgSURzLlxuICAgICAgICAgICAgLy8gU2VlIGh0dHBzOi8vZ2l0aHViLmNvbS9maWR1c3dyaXRlci9kaWZmRE9NL2lzc3Vlcy8xMDBcbiAgICAgICAgICAgIGNvbnN0IGluc05vZGUgPSB3cmFwSW5zZXJ0aW9uKHN0cmluZ0FzVGV4dE5vZGUoZGlmZi52YWx1ZSAhPT0gXCJcXG5cIiA/IGRpZmYudmFsdWUgOiBcIlwiKSk7XG4gICAgICAgICAgICBpbnNlcnRCZWZvcmUocmVmUGFyZW50Tm9kZSwgcmVmTm9kZSwgaW5zTm9kZSk7XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgfVxuICAgICAgICAvLyBlLmcuIHdoZW4gY2hhbmdpbmcgYSB0aGUgaHJlZiBvZiBhIGxpbmssXG4gICAgICAgIC8vIHNob3cgdGhlIGxpbmsgd2l0aCBvbGQgaHJlZiBhcyByZW1vdmVkIGFuZCB3aXRoIHRoZSBuZXcgaHJlZiBhcyBhZGRlZFxuICAgICAgICBjYXNlIFwicmVtb3ZlQXR0cmlidXRlXCI6XG4gICAgICAgIGNhc2UgXCJhZGRBdHRyaWJ1dGVcIjpcbiAgICAgICAgY2FzZSBcIm1vZGlmeUF0dHJpYnV0ZVwiOiB7XG4gICAgICAgICAgICBjb25zdCBkZWxOb2RlID0gd3JhcERlbGV0aW9uKHJlZk5vZGUuY2xvbmVOb2RlKHRydWUpKTtcbiAgICAgICAgICAgIGNvbnN0IHVwZGF0ZWROb2RlID0gcmVmTm9kZS5jbG9uZU5vZGUodHJ1ZSk7XG4gICAgICAgICAgICBpZiAoZGlmZi5hY3Rpb24gPT09IFwiYWRkQXR0cmlidXRlXCIgfHwgZGlmZi5hY3Rpb24gPT09IFwibW9kaWZ5QXR0cmlidXRlXCIpIHtcbiAgICAgICAgICAgICAgICB1cGRhdGVkTm9kZS5zZXRBdHRyaWJ1dGUoZGlmZi5uYW1lLCBkaWZmLm5ld1ZhbHVlKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgdXBkYXRlZE5vZGUucmVtb3ZlQXR0cmlidXRlKGRpZmYubmFtZSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjb25zdCBpbnNOb2RlID0gd3JhcEluc2VydGlvbih1cGRhdGVkTm9kZSk7XG4gICAgICAgICAgICBjb25zdCBjb250YWluZXIgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KGNoZWNrQmxvY2tOb2RlKHJlZk5vZGUpID8gXCJkaXZcIiA6IFwic3BhblwiKTtcbiAgICAgICAgICAgIGNvbnRhaW5lci5hcHBlbmRDaGlsZChkZWxOb2RlKTtcbiAgICAgICAgICAgIGNvbnRhaW5lci5hcHBlbmRDaGlsZChpbnNOb2RlKTtcbiAgICAgICAgICAgIHJlZk5vZGUucGFyZW50Tm9kZS5yZXBsYWNlQ2hpbGQoY29udGFpbmVyLCByZWZOb2RlKTtcbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICB9XG4gICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgICAvLyBTaG91bGQgbm90IGhhcHBlbiAobW9kaWZ5Q29tbWVudCwgPz8/KVxuICAgICAgICAgICAgY29uc29sZS53YXJuKFwiTWVzc2FnZURpZmZVdGlsczo6ZWRpdEJvZHlEaWZmVG9IdG1sOiBkaWZmIGFjdGlvbiBub3Qgc3VwcG9ydGVkIGF0bVwiLCBkaWZmKTtcbiAgICB9XG59XG5cbmZ1bmN0aW9uIHJvdXRlSXNFcXVhbChyMSwgcjIpIHtcbiAgICByZXR1cm4gcjEubGVuZ3RoID09PSByMi5sZW5ndGggJiYgIXIxLnNvbWUoKGUsIGkpID0+IGUgIT09IHIyW2ldKTtcbn1cblxuLy8gd29ya2Fyb3VuZCBmb3IgaHR0cHM6Ly9naXRodWIuY29tL2ZpZHVzd3JpdGVyL2RpZmZET00vaXNzdWVzLzkwXG5mdW5jdGlvbiBmaWx0ZXJDYW5jZWxpbmdPdXREaWZmcyhvcmlnaW5hbERpZmZBY3Rpb25zKSB7XG4gICAgY29uc3QgZGlmZkFjdGlvbnMgPSBvcmlnaW5hbERpZmZBY3Rpb25zLnNsaWNlKCk7XG5cbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IGRpZmZBY3Rpb25zLmxlbmd0aDsgKytpKSB7XG4gICAgICAgIGNvbnN0IGRpZmYgPSBkaWZmQWN0aW9uc1tpXTtcbiAgICAgICAgaWYgKGRpZmYuYWN0aW9uID09PSBcInJlbW92ZVRleHRFbGVtZW50XCIpIHtcbiAgICAgICAgICAgIGNvbnN0IG5leHREaWZmID0gZGlmZkFjdGlvbnNbaSArIDFdO1xuICAgICAgICAgICAgY29uc3QgY2FuY2Vsc091dCA9IG5leHREaWZmICYmXG4gICAgICAgICAgICAgICAgbmV4dERpZmYuYWN0aW9uID09PSBcImFkZFRleHRFbGVtZW50XCIgJiZcbiAgICAgICAgICAgICAgICBuZXh0RGlmZi50ZXh0ID09PSBkaWZmLnRleHQgJiZcbiAgICAgICAgICAgICAgICByb3V0ZUlzRXF1YWwobmV4dERpZmYucm91dGUsIGRpZmYucm91dGUpO1xuXG4gICAgICAgICAgICBpZiAoY2FuY2Vsc091dCkge1xuICAgICAgICAgICAgICAgIGRpZmZBY3Rpb25zLnNwbGljZShpLCAyKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiBkaWZmQWN0aW9ucztcbn1cblxuLyoqXG4gKiBSZW5kZXJzIGEgbWVzc2FnZSB3aXRoIHRoZSBjaGFuZ2VzIG1hZGUgaW4gYW4gZWRpdCBzaG93biB2aXN1YWxseS5cbiAqIEBwYXJhbSB7b2JqZWN0fSBvcmlnaW5hbENvbnRlbnQgdGhlIGNvbnRlbnQgZm9yIHRoZSBiYXNlIG1lc3NhZ2VcbiAqIEBwYXJhbSB7b2JqZWN0fSBlZGl0Q29udGVudCB0aGUgY29udGVudCBmb3IgdGhlIGVkaXQgbWVzc2FnZVxuICogQHJldHVybiB7b2JqZWN0fSBhIHJlYWN0IGVsZW1lbnQgc2ltaWxhciB0byB3aGF0IGBib2R5VG9IdG1sYCByZXR1cm5zXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBlZGl0Qm9keURpZmZUb0h0bWwob3JpZ2luYWxDb250ZW50LCBlZGl0Q29udGVudCkge1xuICAgIC8vIHdyYXAgdGhlIGJvZHkgaW4gYSBkaXYsIERpZmZET00gbmVlZHMgYSByb290IGVsZW1lbnRcbiAgICBjb25zdCBvcmlnaW5hbEJvZHkgPSBgPGRpdj4ke2dldFNhbml0aXplZEh0bWxCb2R5KG9yaWdpbmFsQ29udGVudCl9PC9kaXY+YDtcbiAgICBjb25zdCBlZGl0Qm9keSA9IGA8ZGl2PiR7Z2V0U2FuaXRpemVkSHRtbEJvZHkoZWRpdENvbnRlbnQpfTwvZGl2PmA7XG4gICAgY29uc3QgZGQgPSBuZXcgRGlmZkRPTSgpO1xuICAgIC8vIGRpZmZBY3Rpb25zIGlzIGFuIGFycmF5IG9mIG9iamVjdHMgd2l0aCBhdCBsZWFzdCBhIGBhY3Rpb25gIGFuZCBgcm91dGVgXG4gICAgLy8gcHJvcGVydHkuIGBhY3Rpb25gIHRlbGxzIHVzIHdoYXQgdGhlIGRpZmYgb2JqZWN0IGNoYW5nZXMsIGFuZCBgcm91dGVgIHdoZXJlLlxuICAgIC8vIGByb3V0ZWAgaXMgYSBwYXRoIG9uIHRoZSBET00gdHJlZSBleHByZXNzZWQgYXMgYW4gYXJyYXkgb2YgaW5kaWNlcy5cbiAgICBjb25zdCBvcmlnaW5hbGRpZmZBY3Rpb25zID0gZGQuZGlmZihvcmlnaW5hbEJvZHksIGVkaXRCb2R5KTtcbiAgICAvLyB3b3JrIGFyb3VuZCBodHRwczovL2dpdGh1Yi5jb20vZmlkdXN3cml0ZXIvZGlmZkRPTS9pc3N1ZXMvOTBcbiAgICBjb25zdCBkaWZmQWN0aW9ucyA9IGZpbHRlckNhbmNlbGluZ091dERpZmZzKG9yaWdpbmFsZGlmZkFjdGlvbnMpO1xuICAgIC8vIGZvciBkaWZmaW5nIHRleHQgZnJhZ21lbnRzXG4gICAgY29uc3QgZGlmZk1hdGhQYXRjaCA9IG5ldyBEaWZmTWF0Y2hQYXRjaCgpO1xuICAgIC8vIHBhcnNlIHRoZSBiYXNlIGh0bWwgbWVzc2FnZSBhcyBhIERPTSB0cmVlLCB0byB3aGljaCB3ZSdsbCBhcHBseSB0aGUgZGlmZmVyZW5jZXMgZm91bmQuXG4gICAgLy8gZmlzaCBvdXQgdGhlIGRpdiBpbiB3aGljaCB3ZSB3cmFwcGVkIHRoZSBtZXNzYWdlcyBhYm92ZSB3aXRoIGNoaWxkcmVuWzBdLlxuICAgIGNvbnN0IG9yaWdpbmFsUm9vdE5vZGUgPSBuZXcgRE9NUGFyc2VyKCkucGFyc2VGcm9tU3RyaW5nKG9yaWdpbmFsQm9keSwgXCJ0ZXh0L2h0bWxcIikuYm9keS5jaGlsZHJlblswXTtcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IGRpZmZBY3Rpb25zLmxlbmd0aDsgKytpKSB7XG4gICAgICAgIGNvbnN0IGRpZmYgPSBkaWZmQWN0aW9uc1tpXTtcbiAgICAgICAgcmVuZGVyRGlmZmVyZW5jZUluRE9NKG9yaWdpbmFsUm9vdE5vZGUsIGRpZmYsIGRpZmZNYXRoUGF0Y2gpO1xuICAgICAgICAvLyBEaWZmRE9NIGFzc3VtZXMgaW4gc3Vic2VxdWVudCBkaWZmcyByb3V0ZSBwYXRoIHRoYXRcbiAgICAgICAgLy8gdGhlIGFjdGlvbiB3YXMgYXBwbGllZCAoZS5nLiB0aGF0IGEgcmVtb3ZlRWxlbWVudCBhY3Rpb24gcmVtb3ZlZCB0aGUgZWxlbWVudCkuXG4gICAgICAgIC8vIFRoaXMgaXMgbm90IHRoZSBjYXNlIGZvciB1cy4gV2UgcmVuZGVyIGRpZmZlcmVuY2VzIGluIHRoZSBET00gdHJlZSwgYW5kIGRvbid0IGFwcGx5IHRoZW0uXG4gICAgICAgIC8vIFNvIHdlIG5lZWQgdG8gYWRqdXN0IHRoZSByb3V0ZXMgb2YgdGhlIHJlbWFpbmluZyBkaWZmcyB0byBhY2NvdW50IGZvciB0aGlzLlxuICAgICAgICBhZGp1c3RSb3V0ZXMoZGlmZiwgZGlmZkFjdGlvbnMuc2xpY2UoaSArIDEpKTtcbiAgICB9XG4gICAgLy8gdGFrZSB0aGUgaHRtbCBvdXQgb2YgdGhlIG1vZGlmaWVkIERPTSB0cmVlIGFnYWluXG4gICAgY29uc3Qgc2FmZUJvZHkgPSBvcmlnaW5hbFJvb3ROb2RlLmlubmVySFRNTDtcbiAgICBjb25zdCBjbGFzc05hbWUgPSBjbGFzc05hbWVzKHtcbiAgICAgICAgJ214X0V2ZW50VGlsZV9ib2R5JzogdHJ1ZSxcbiAgICAgICAgJ21hcmtkb3duLWJvZHknOiB0cnVlLFxuICAgIH0pO1xuICAgIHJldHVybiA8c3BhbiBrZXk9XCJib2R5XCIgY2xhc3NOYW1lPXtjbGFzc05hbWV9IGRhbmdlcm91c2x5U2V0SW5uZXJIVE1MPXt7IF9faHRtbDogc2FmZUJvZHkgfX0gZGlyPVwiYXV0b1wiIC8+O1xufVxuIl19