UNPKG

matrix-react-sdk

Version:
378 lines (362 loc) 50 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); require("./@types/commonmark"); var commonmark = _interopRequireWildcard(require("commonmark")); var _lodash = require("lodash"); var _logger = require("matrix-js-sdk/src/logger"); var _linkifyMatrix = require("./linkify-matrix"); function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); } function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; } /* Copyright 2024 New Vector Ltd. Copyright 2021 The Matrix.org Foundation C.I.C. Copyright 2016 OpenMarket Ltd SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only Please see LICENSE files in the repository root for full details. */ // import better types than @types/commonmark const ALLOWED_HTML_TAGS = ["sub", "sup", "del", "s", "u", "br", "br/"]; // These types of node are definitely text const TEXT_NODES = ["text", "softbreak", "linebreak", "paragraph", "document"]; function isAllowedHtmlTag(node) { if (!node.literal) { return false; } if (node.literal.match('^<((div|span) data-mx-maths="[^"]*"|/(div|span))>$') != null) { return true; } // Regex won't work for tags with attrs, but the tags we allow // shouldn't really have any anyway. const matches = /^<\/?(.*)>$/.exec(node.literal); if (matches && matches.length == 2) { const tag = matches[1]; return ALLOWED_HTML_TAGS.indexOf(tag) > -1; } return false; } /* * Returns true if the parse output containing the node * comprises multiple block level elements (ie. lines), * or false if it is only a single line. */ function isMultiLine(node) { let par = node; while (par.parent) { par = par.parent; } return par.firstChild != par.lastChild; } function getTextUntilEndOrLinebreak(node) { let currentNode = node; let text = ""; while (currentNode && currentNode.type !== "softbreak" && currentNode.type !== "linebreak") { const { literal, type } = currentNode; if (type === "text" && literal) { let n = 0; let char = literal[n]; while (char !== " " && char !== null && n <= literal.length) { if (char === " ") { break; } if (char) { text += char; } n += 1; char = literal[n]; } if (char === " ") { break; } } currentNode = currentNode.next; } return text; } const formattingChangesByNodeType = { emph: "_", strong: "__" }; /** * Returns the literal of a node an all child nodes. */ const innerNodeLiteral = node => { let literal = ""; const walker = node.walker(); let step; while (step = walker.next()) { const currentNode = step.node; const currentNodeLiteral = currentNode.literal; if (step.entering && currentNode.type === "text" && currentNodeLiteral) { literal += currentNodeLiteral; } } return literal; }; const emptyItemWithNoSiblings = node => { return !node.prev && !node.next && !node.firstChild; }; /** * Class that wraps commonmark, adding the ability to see whether * a given message actually uses any markdown syntax or whether * it's plain text. */ class Markdown { constructor(input) { (0, _defineProperty2.default)(this, "input", void 0); (0, _defineProperty2.default)(this, "parsed", void 0); this.input = input; const parser = new commonmark.Parser(); this.parsed = parser.parse(this.input); this.parsed = this.repairLinks(this.parsed); } /** * This method is modifying the parsed AST in such a way that links are always * properly linkified instead of sometimes being wrongly emphasised in case * if you were to write a link like the example below: * https://my_weird-link_domain.domain.com * ^ this link would be parsed to something like this: * <a href="https://my">https://my</a><b>weird-link</b><a href="https://domain.domain.com">domain.domain.com</a> * This method makes it so the link gets properly modified to a version where it is * not emphasised until it actually ends. * See: https://github.com/vector-im/element-web/issues/4674 * @param parsed */ repairLinks(parsed) { const walker = parsed.walker(); let event = null; let text = ""; let isInPara = false; let previousNode = null; let shouldUnlinkFormattingNode = false; while (event = walker.next()) { const { node } = event; if (node.type === "paragraph") { if (event.entering) { isInPara = true; } else { isInPara = false; } } if (isInPara) { // Clear saved string when line ends if (node.type === "softbreak" || node.type === "linebreak" || // Also start calculating the text from the beginning on any spaces node.type === "text" && node.literal === " ") { text = ""; continue; } // Break up text nodes on spaces, so that we don't shoot past them without resetting if (node.type === "text" && node.literal) { const [thisPart, ...nextParts] = node.literal.split(/( )/); node.literal = thisPart; text += thisPart; // Add the remaining parts as siblings nextParts.reverse().forEach(part => { if (part) { const nextNode = new commonmark.Node("text"); nextNode.literal = part; node.insertAfter(nextNode); // Make the iterator aware of the newly inserted node walker.resumeAt(nextNode, true); } }); } // We should not do this if previous node was not a textnode, as we can't combine it then. if ((node.type === "emph" || node.type === "strong") && previousNode?.type === "text") { if (event.entering) { const foundLinks = _linkifyMatrix.linkify.find(text); for (const { value } of foundLinks) { if (node?.firstChild?.literal) { /** * NOTE: This technically should unlink the emph node and create LINK nodes instead, adding all the next elements as siblings * but this solution seems to work well and is hopefully slightly easier to understand too */ const format = formattingChangesByNodeType[node.type]; const nonEmphasizedText = `${format}${innerNodeLiteral(node)}${format}`; const f = getTextUntilEndOrLinebreak(node); const newText = value + nonEmphasizedText + f; const newLinks = _linkifyMatrix.linkify.find(newText); // Should always find only one link here, if it finds more it means that the algorithm is broken if (newLinks.length === 1) { const emphasisTextNode = new commonmark.Node("text"); emphasisTextNode.literal = nonEmphasizedText; previousNode.insertAfter(emphasisTextNode); node.firstChild.literal = ""; event = node.walker().next(); if (event) { // Remove `em` opening and closing nodes node.unlink(); previousNode.insertAfter(event.node); shouldUnlinkFormattingNode = true; } } else { _logger.logger.error("Markdown links escaping found too many links for following text: ", text); _logger.logger.error("Markdown links escaping found too many links for modified text: ", newText); } } } } else { if (shouldUnlinkFormattingNode) { node.unlink(); shouldUnlinkFormattingNode = false; } } } } previousNode = node; } return parsed; } isPlainText() { const walker = this.parsed.walker(); let ev; while (ev = walker.next()) { const node = ev.node; if (TEXT_NODES.indexOf(node.type) > -1) { // definitely text continue; } else if (node.type == "list" || node.type == "item") { // Special handling for inputs like `+`, `*`, `-` and `2021.` which // would otherwise be treated as a list of a single empty item. // See https://github.com/vector-im/element-web/issues/7631 if (node.type == "list" && node.firstChild && emptyItemWithNoSiblings(node.firstChild)) { // A list with a single empty item is treated as plain text. continue; } if (node.type == "item" && emptyItemWithNoSiblings(node)) { // An empty list item with no sibling items is treated as plain text. continue; } // Everything else is actual lists and therefore not plaintext. return false; } else if (node.type == "html_inline" || node.type == "html_block") { // if it's an allowed html tag, we need to render it and therefore // we will need to use HTML. If it's not allowed, it's not HTML since // we'll just be treating it as text. if (isAllowedHtmlTag(node)) { return false; } } else { return false; } } return true; } toHTML({ externalLinks = false } = {}) { const renderer = new commonmark.HtmlRenderer({ safe: false, // Set soft breaks to hard HTML breaks: commonmark // puts softbreaks in for multiple lines in a blockquote, // so if these are just newline characters then the // block quote ends up all on one line // (https://github.com/vector-im/element-web/issues/3154) softbreak: "<br />" }); // Trying to strip out the wrapping <p/> causes a lot more complication // than it's worth, i think. For instance, this code will go and strip // out any <p/> tag (no matter where it is in the tree) which doesn't // contain \n's. // On the flip side, <p/>s are quite opionated and restricted on where // you can nest them. // // Let's try sending with <p/>s anyway for now, though. const realParagraph = renderer.paragraph; renderer.paragraph = function (node, entering) { // If there is only one top level node, just return the // bare text: it's a single line of text and so should be // 'inline', rather than unnecessarily wrapped in its own // p tag. If, however, we have multiple nodes, each gets // its own p tag to keep them as separate paragraphs. // However, if it's a blockquote, adds a p tag anyway // in order to avoid deviation to commonmark and unexpected // results when parsing the formatted HTML. if (node.parent?.type === "block_quote" || isMultiLine(node)) { realParagraph.call(this, node, entering); } }; renderer.link = function (node, entering) { const attrs = this.attrs(node); if (entering && node.destination) { attrs.push(["href", this.esc(node.destination)]); if (node.title) { attrs.push(["title", this.esc(node.title)]); } // Modified link behaviour to treat them all as external and // thus opening in a new tab. if (externalLinks) { attrs.push(["target", "_blank"]); attrs.push(["rel", "noreferrer noopener"]); } this.tag("a", attrs); } else { this.tag("/a"); } }; renderer.html_inline = function (node) { if (node.literal) { if (isAllowedHtmlTag(node)) { this.lit(node.literal); } else { this.lit((0, _lodash.escape)(node.literal)); } } }; renderer.html_block = function (node) { /* // as with `paragraph`, we only insert line breaks // if there are multiple lines in the markdown. const isMultiLine = is_multi_line(node); if (isMultiLine) this.cr(); */ renderer.html_inline(node); /* if (isMultiLine) this.cr(); */ }; return renderer.render(this.parsed); } /* * Render the markdown message to plain text. That is, essentially * just remove any backslashes escaping what would otherwise be * markdown syntax * (to fix https://github.com/vector-im/element-web/issues/2870). * * N.B. this does **NOT** render arbitrary MD to plain text - only MD * which has no formatting. Otherwise it emits HTML(!). */ toPlaintext() { const renderer = new commonmark.HtmlRenderer({ safe: false }); renderer.paragraph = function (node, entering) { // as with toHTML, only append lines to paragraphs if there are // multiple paragraphs if (isMultiLine(node)) { if (!entering && node.next) { this.lit("\n\n"); } } }; renderer.html_block = function (node) { if (node.literal) this.lit(node.literal); if (isMultiLine(node) && node.next) this.lit("\n\n"); }; return renderer.render(this.parsed); } } exports.default = Markdown; //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJyZXF1aXJlIiwiY29tbW9ubWFyayIsIl9pbnRlcm9wUmVxdWlyZVdpbGRjYXJkIiwiX2xvZGFzaCIsIl9sb2dnZXIiLCJfbGlua2lmeU1hdHJpeCIsIl9nZXRSZXF1aXJlV2lsZGNhcmRDYWNoZSIsImUiLCJXZWFrTWFwIiwiciIsInQiLCJfX2VzTW9kdWxlIiwiZGVmYXVsdCIsImhhcyIsImdldCIsIm4iLCJfX3Byb3RvX18iLCJhIiwiT2JqZWN0IiwiZGVmaW5lUHJvcGVydHkiLCJnZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3IiLCJ1IiwiaGFzT3duUHJvcGVydHkiLCJjYWxsIiwiaSIsInNldCIsIkFMTE9XRURfSFRNTF9UQUdTIiwiVEVYVF9OT0RFUyIsImlzQWxsb3dlZEh0bWxUYWciLCJub2RlIiwibGl0ZXJhbCIsIm1hdGNoIiwibWF0Y2hlcyIsImV4ZWMiLCJsZW5ndGgiLCJ0YWciLCJpbmRleE9mIiwiaXNNdWx0aUxpbmUiLCJwYXIiLCJwYXJlbnQiLCJmaXJzdENoaWxkIiwibGFzdENoaWxkIiwiZ2V0VGV4dFVudGlsRW5kT3JMaW5lYnJlYWsiLCJjdXJyZW50Tm9kZSIsInRleHQiLCJ0eXBlIiwiY2hhciIsIm5leHQiLCJmb3JtYXR0aW5nQ2hhbmdlc0J5Tm9kZVR5cGUiLCJlbXBoIiwic3Ryb25nIiwiaW5uZXJOb2RlTGl0ZXJhbCIsIndhbGtlciIsInN0ZXAiLCJjdXJyZW50Tm9kZUxpdGVyYWwiLCJlbnRlcmluZyIsImVtcHR5SXRlbVdpdGhOb1NpYmxpbmdzIiwicHJldiIsIk1hcmtkb3duIiwiY29uc3RydWN0b3IiLCJpbnB1dCIsIl9kZWZpbmVQcm9wZXJ0eTIiLCJwYXJzZXIiLCJQYXJzZXIiLCJwYXJzZWQiLCJwYXJzZSIsInJlcGFpckxpbmtzIiwiZXZlbnQiLCJpc0luUGFyYSIsInByZXZpb3VzTm9kZSIsInNob3VsZFVubGlua0Zvcm1hdHRpbmdOb2RlIiwidGhpc1BhcnQiLCJuZXh0UGFydHMiLCJzcGxpdCIsInJldmVyc2UiLCJmb3JFYWNoIiwicGFydCIsIm5leHROb2RlIiwiTm9kZSIsImluc2VydEFmdGVyIiwicmVzdW1lQXQiLCJmb3VuZExpbmtzIiwibGlua2lmeSIsImZpbmQiLCJ2YWx1ZSIsImZvcm1hdCIsIm5vbkVtcGhhc2l6ZWRUZXh0IiwiZiIsIm5ld1RleHQiLCJuZXdMaW5rcyIsImVtcGhhc2lzVGV4dE5vZGUiLCJ1bmxpbmsiLCJsb2dnZXIiLCJlcnJvciIsImlzUGxhaW5UZXh0IiwiZXYiLCJ0b0hUTUwiLCJleHRlcm5hbExpbmtzIiwicmVuZGVyZXIiLCJIdG1sUmVuZGVyZXIiLCJzYWZlIiwic29mdGJyZWFrIiwicmVhbFBhcmFncmFwaCIsInBhcmFncmFwaCIsImxpbmsiLCJhdHRycyIsImRlc3RpbmF0aW9uIiwicHVzaCIsImVzYyIsInRpdGxlIiwiaHRtbF9pbmxpbmUiLCJsaXQiLCJlc2NhcGUiLCJodG1sX2Jsb2NrIiwicmVuZGVyIiwidG9QbGFpbnRleHQiLCJleHBvcnRzIl0sInNvdXJjZXMiOlsiLi4vc3JjL01hcmtkb3duLnRzIl0sInNvdXJjZXNDb250ZW50IjpbIi8qXG5Db3B5cmlnaHQgMjAyNCBOZXcgVmVjdG9yIEx0ZC5cbkNvcHlyaWdodCAyMDIxIFRoZSBNYXRyaXgub3JnIEZvdW5kYXRpb24gQy5JLkMuXG5Db3B5cmlnaHQgMjAxNiBPcGVuTWFya2V0IEx0ZFxuXG5TUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogQUdQTC0zLjAtb25seSBPUiBHUEwtMy4wLW9ubHlcblBsZWFzZSBzZWUgTElDRU5TRSBmaWxlcyBpbiB0aGUgcmVwb3NpdG9yeSByb290IGZvciBmdWxsIGRldGFpbHMuXG4qL1xuXG5pbXBvcnQgXCIuL0B0eXBlcy9jb21tb25tYXJrXCI7IC8vIGltcG9ydCBiZXR0ZXIgdHlwZXMgdGhhbiBAdHlwZXMvY29tbW9ubWFya1xuaW1wb3J0ICogYXMgY29tbW9ubWFyayBmcm9tIFwiY29tbW9ubWFya1wiO1xuaW1wb3J0IHsgZXNjYXBlIH0gZnJvbSBcImxvZGFzaFwiO1xuaW1wb3J0IHsgbG9nZ2VyIH0gZnJvbSBcIm1hdHJpeC1qcy1zZGsvc3JjL2xvZ2dlclwiO1xuXG5pbXBvcnQgeyBsaW5raWZ5IH0gZnJvbSBcIi4vbGlua2lmeS1tYXRyaXhcIjtcblxuY29uc3QgQUxMT1dFRF9IVE1MX1RBR1MgPSBbXCJzdWJcIiwgXCJzdXBcIiwgXCJkZWxcIiwgXCJzXCIsIFwidVwiLCBcImJyXCIsIFwiYnIvXCJdO1xuXG4vLyBUaGVzZSB0eXBlcyBvZiBub2RlIGFyZSBkZWZpbml0ZWx5IHRleHRcbmNvbnN0IFRFWFRfTk9ERVMgPSBbXCJ0ZXh0XCIsIFwic29mdGJyZWFrXCIsIFwibGluZWJyZWFrXCIsIFwicGFyYWdyYXBoXCIsIFwiZG9jdW1lbnRcIl07XG5cbmZ1bmN0aW9uIGlzQWxsb3dlZEh0bWxUYWcobm9kZTogY29tbW9ubWFyay5Ob2RlKTogYm9vbGVhbiB7XG4gICAgaWYgKCFub2RlLmxpdGVyYWwpIHtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cblxuICAgIGlmIChub2RlLmxpdGVyYWwubWF0Y2goJ148KChkaXZ8c3BhbikgZGF0YS1teC1tYXRocz1cIlteXCJdKlwifC8oZGl2fHNwYW4pKT4kJykgIT0gbnVsbCkge1xuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG5cbiAgICAvLyBSZWdleCB3b24ndCB3b3JrIGZvciB0YWdzIHdpdGggYXR0cnMsIGJ1dCB0aGUgdGFncyB3ZSBhbGxvd1xuICAgIC8vIHNob3VsZG4ndCByZWFsbHkgaGF2ZSBhbnkgYW55d2F5LlxuICAgIGNvbnN0IG1hdGNoZXMgPSAvXjxcXC8/KC4qKT4kLy5leGVjKG5vZGUubGl0ZXJhbCk7XG4gICAgaWYgKG1hdGNoZXMgJiYgbWF0Y2hlcy5sZW5ndGggPT0gMikge1xuICAgICAgICBjb25zdCB0YWcgPSBtYXRjaGVzWzFdO1xuICAgICAgICByZXR1cm4gQUxMT1dFRF9IVE1MX1RBR1MuaW5kZXhPZih0YWcpID4gLTE7XG4gICAgfVxuXG4gICAgcmV0dXJuIGZhbHNlO1xufVxuXG4vKlxuICogUmV0dXJucyB0cnVlIGlmIHRoZSBwYXJzZSBvdXRwdXQgY29udGFpbmluZyB0aGUgbm9kZVxuICogY29tcHJpc2VzIG11bHRpcGxlIGJsb2NrIGxldmVsIGVsZW1lbnRzIChpZS4gbGluZXMpLFxuICogb3IgZmFsc2UgaWYgaXQgaXMgb25seSBhIHNpbmdsZSBsaW5lLlxuICovXG5mdW5jdGlvbiBpc011bHRpTGluZShub2RlOiBjb21tb25tYXJrLk5vZGUpOiBib29sZWFuIHtcbiAgICBsZXQgcGFyID0gbm9kZTtcbiAgICB3aGlsZSAocGFyLnBhcmVudCkge1xuICAgICAgICBwYXIgPSBwYXIucGFyZW50O1xuICAgIH1cbiAgICByZXR1cm4gcGFyLmZpcnN0Q2hpbGQgIT0gcGFyLmxhc3RDaGlsZDtcbn1cblxuZnVuY3Rpb24gZ2V0VGV4dFVudGlsRW5kT3JMaW5lYnJlYWsobm9kZTogY29tbW9ubWFyay5Ob2RlKTogc3RyaW5nIHtcbiAgICBsZXQgY3VycmVudE5vZGU6IGNvbW1vbm1hcmsuTm9kZSB8IG51bGwgPSBub2RlO1xuICAgIGxldCB0ZXh0ID0gXCJcIjtcbiAgICB3aGlsZSAoY3VycmVudE5vZGUgJiYgY3VycmVudE5vZGUudHlwZSAhPT0gXCJzb2Z0YnJlYWtcIiAmJiBjdXJyZW50Tm9kZS50eXBlICE9PSBcImxpbmVicmVha1wiKSB7XG4gICAgICAgIGNvbnN0IHsgbGl0ZXJhbCwgdHlwZSB9ID0gY3VycmVudE5vZGU7XG4gICAgICAgIGlmICh0eXBlID09PSBcInRleHRcIiAmJiBsaXRlcmFsKSB7XG4gICAgICAgICAgICBsZXQgbiA9IDA7XG4gICAgICAgICAgICBsZXQgY2hhciA9IGxpdGVyYWxbbl07XG4gICAgICAgICAgICB3aGlsZSAoY2hhciAhPT0gXCIgXCIgJiYgY2hhciAhPT0gbnVsbCAmJiBuIDw9IGxpdGVyYWwubGVuZ3RoKSB7XG4gICAgICAgICAgICAgICAgaWYgKGNoYXIgPT09IFwiIFwiKSB7XG4gICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBpZiAoY2hhcikge1xuICAgICAgICAgICAgICAgICAgICB0ZXh0ICs9IGNoYXI7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIG4gKz0gMTtcbiAgICAgICAgICAgICAgICBjaGFyID0gbGl0ZXJhbFtuXTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmIChjaGFyID09PSBcIiBcIikge1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGN1cnJlbnROb2RlID0gY3VycmVudE5vZGUubmV4dDtcbiAgICB9XG4gICAgcmV0dXJuIHRleHQ7XG59XG5cbmNvbnN0IGZvcm1hdHRpbmdDaGFuZ2VzQnlOb2RlVHlwZSA9IHtcbiAgICBlbXBoOiBcIl9cIixcbiAgICBzdHJvbmc6IFwiX19cIixcbn07XG5cbi8qKlxuICogUmV0dXJucyB0aGUgbGl0ZXJhbCBvZiBhIG5vZGUgYW4gYWxsIGNoaWxkIG5vZGVzLlxuICovXG5jb25zdCBpbm5lck5vZGVMaXRlcmFsID0gKG5vZGU6IGNvbW1vbm1hcmsuTm9kZSk6IHN0cmluZyA9PiB7XG4gICAgbGV0IGxpdGVyYWwgPSBcIlwiO1xuXG4gICAgY29uc3Qgd2Fsa2VyID0gbm9kZS53YWxrZXIoKTtcbiAgICBsZXQgc3RlcDogY29tbW9ubWFyay5Ob2RlV2Fsa2luZ1N0ZXAgfCBudWxsO1xuXG4gICAgd2hpbGUgKChzdGVwID0gd2Fsa2VyLm5leHQoKSkpIHtcbiAgICAgICAgY29uc3QgY3VycmVudE5vZGUgPSBzdGVwLm5vZGU7XG4gICAgICAgIGNvbnN0IGN1cnJlbnROb2RlTGl0ZXJhbCA9IGN1cnJlbnROb2RlLmxpdGVyYWw7XG4gICAgICAgIGlmIChzdGVwLmVudGVyaW5nICYmIGN1cnJlbnROb2RlLnR5cGUgPT09IFwidGV4dFwiICYmIGN1cnJlbnROb2RlTGl0ZXJhbCkge1xuICAgICAgICAgICAgbGl0ZXJhbCArPSBjdXJyZW50Tm9kZUxpdGVyYWw7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gbGl0ZXJhbDtcbn07XG5cbmNvbnN0IGVtcHR5SXRlbVdpdGhOb1NpYmxpbmdzID0gKG5vZGU6IGNvbW1vbm1hcmsuTm9kZSk6IGJvb2xlYW4gPT4ge1xuICAgIHJldHVybiAhbm9kZS5wcmV2ICYmICFub2RlLm5leHQgJiYgIW5vZGUuZmlyc3RDaGlsZDtcbn07XG5cbi8qKlxuICogQ2xhc3MgdGhhdCB3cmFwcyBjb21tb25tYXJrLCBhZGRpbmcgdGhlIGFiaWxpdHkgdG8gc2VlIHdoZXRoZXJcbiAqIGEgZ2l2ZW4gbWVzc2FnZSBhY3R1YWxseSB1c2VzIGFueSBtYXJrZG93biBzeW50YXggb3Igd2hldGhlclxuICogaXQncyBwbGFpbiB0ZXh0LlxuICovXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBNYXJrZG93biB7XG4gICAgcHJpdmF0ZSBpbnB1dDogc3RyaW5nO1xuICAgIHByaXZhdGUgcGFyc2VkOiBjb21tb25tYXJrLk5vZGU7XG5cbiAgICBwdWJsaWMgY29uc3RydWN0b3IoaW5wdXQ6IHN0cmluZykge1xuICAgICAgICB0aGlzLmlucHV0ID0gaW5wdXQ7XG5cbiAgICAgICAgY29uc3QgcGFyc2VyID0gbmV3IGNvbW1vbm1hcmsuUGFyc2VyKCk7XG4gICAgICAgIHRoaXMucGFyc2VkID0gcGFyc2VyLnBhcnNlKHRoaXMuaW5wdXQpO1xuICAgICAgICB0aGlzLnBhcnNlZCA9IHRoaXMucmVwYWlyTGlua3ModGhpcy5wYXJzZWQpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFRoaXMgbWV0aG9kIGlzIG1vZGlmeWluZyB0aGUgcGFyc2VkIEFTVCBpbiBzdWNoIGEgd2F5IHRoYXQgbGlua3MgYXJlIGFsd2F5c1xuICAgICAqIHByb3Blcmx5IGxpbmtpZmllZCBpbnN0ZWFkIG9mIHNvbWV0aW1lcyBiZWluZyB3cm9uZ2x5IGVtcGhhc2lzZWQgaW4gY2FzZVxuICAgICAqIGlmIHlvdSB3ZXJlIHRvIHdyaXRlIGEgbGluayBsaWtlIHRoZSBleGFtcGxlIGJlbG93OlxuICAgICAqIGh0dHBzOi8vbXlfd2VpcmQtbGlua19kb21haW4uZG9tYWluLmNvbVxuICAgICAqIF4gdGhpcyBsaW5rIHdvdWxkIGJlIHBhcnNlZCB0byBzb21ldGhpbmcgbGlrZSB0aGlzOlxuICAgICAqIDxhIGhyZWY9XCJodHRwczovL215XCI+aHR0cHM6Ly9teTwvYT48Yj53ZWlyZC1saW5rPC9iPjxhIGhyZWY9XCJodHRwczovL2RvbWFpbi5kb21haW4uY29tXCI+ZG9tYWluLmRvbWFpbi5jb208L2E+XG4gICAgICogVGhpcyBtZXRob2QgbWFrZXMgaXQgc28gdGhlIGxpbmsgZ2V0cyBwcm9wZXJseSBtb2RpZmllZCB0byBhIHZlcnNpb24gd2hlcmUgaXQgaXNcbiAgICAgKiBub3QgZW1waGFzaXNlZCB1bnRpbCBpdCBhY3R1YWxseSBlbmRzLlxuICAgICAqIFNlZTogaHR0cHM6Ly9naXRodWIuY29tL3ZlY3Rvci1pbS9lbGVtZW50LXdlYi9pc3N1ZXMvNDY3NFxuICAgICAqIEBwYXJhbSBwYXJzZWRcbiAgICAgKi9cbiAgICBwcml2YXRlIHJlcGFpckxpbmtzKHBhcnNlZDogY29tbW9ubWFyay5Ob2RlKTogY29tbW9ubWFyay5Ob2RlIHtcbiAgICAgICAgY29uc3Qgd2Fsa2VyID0gcGFyc2VkLndhbGtlcigpO1xuICAgICAgICBsZXQgZXZlbnQ6IGNvbW1vbm1hcmsuTm9kZVdhbGtpbmdTdGVwIHwgbnVsbCA9IG51bGw7XG4gICAgICAgIGxldCB0ZXh0ID0gXCJcIjtcbiAgICAgICAgbGV0IGlzSW5QYXJhID0gZmFsc2U7XG4gICAgICAgIGxldCBwcmV2aW91c05vZGU6IGNvbW1vbm1hcmsuTm9kZSB8IG51bGwgPSBudWxsO1xuICAgICAgICBsZXQgc2hvdWxkVW5saW5rRm9ybWF0dGluZ05vZGUgPSBmYWxzZTtcbiAgICAgICAgd2hpbGUgKChldmVudCA9IHdhbGtlci5uZXh0KCkpKSB7XG4gICAgICAgICAgICBjb25zdCB7IG5vZGUgfSA9IGV2ZW50O1xuICAgICAgICAgICAgaWYgKG5vZGUudHlwZSA9PT0gXCJwYXJhZ3JhcGhcIikge1xuICAgICAgICAgICAgICAgIGlmIChldmVudC5lbnRlcmluZykge1xuICAgICAgICAgICAgICAgICAgICBpc0luUGFyYSA9IHRydWU7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgaXNJblBhcmEgPSBmYWxzZTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoaXNJblBhcmEpIHtcbiAgICAgICAgICAgICAgICAvLyBDbGVhciBzYXZlZCBzdHJpbmcgd2hlbiBsaW5lIGVuZHNcbiAgICAgICAgICAgICAgICBpZiAoXG4gICAgICAgICAgICAgICAgICAgIG5vZGUudHlwZSA9PT0gXCJzb2Z0YnJlYWtcIiB8fFxuICAgICAgICAgICAgICAgICAgICBub2RlLnR5cGUgPT09IFwibGluZWJyZWFrXCIgfHxcbiAgICAgICAgICAgICAgICAgICAgLy8gQWxzbyBzdGFydCBjYWxjdWxhdGluZyB0aGUgdGV4dCBmcm9tIHRoZSBiZWdpbm5pbmcgb24gYW55IHNwYWNlc1xuICAgICAgICAgICAgICAgICAgICAobm9kZS50eXBlID09PSBcInRleHRcIiAmJiBub2RlLmxpdGVyYWwgPT09IFwiIFwiKVxuICAgICAgICAgICAgICAgICkge1xuICAgICAgICAgICAgICAgICAgICB0ZXh0ID0gXCJcIjtcbiAgICAgICAgICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgLy8gQnJlYWsgdXAgdGV4dCBub2RlcyBvbiBzcGFjZXMsIHNvIHRoYXQgd2UgZG9uJ3Qgc2hvb3QgcGFzdCB0aGVtIHdpdGhvdXQgcmVzZXR0aW5nXG4gICAgICAgICAgICAgICAgaWYgKG5vZGUudHlwZSA9PT0gXCJ0ZXh0XCIgJiYgbm9kZS5saXRlcmFsKSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IFt0aGlzUGFydCwgLi4ubmV4dFBhcnRzXSA9IG5vZGUubGl0ZXJhbC5zcGxpdCgvKCApLyk7XG4gICAgICAgICAgICAgICAgICAgIG5vZGUubGl0ZXJhbCA9IHRoaXNQYXJ0O1xuICAgICAgICAgICAgICAgICAgICB0ZXh0ICs9IHRoaXNQYXJ0O1xuXG4gICAgICAgICAgICAgICAgICAgIC8vIEFkZCB0aGUgcmVtYWluaW5nIHBhcnRzIGFzIHNpYmxpbmdzXG4gICAgICAgICAgICAgICAgICAgIG5leHRQYXJ0cy5yZXZlcnNlKCkuZm9yRWFjaCgocGFydCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHBhcnQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBuZXh0Tm9kZSA9IG5ldyBjb21tb25tYXJrLk5vZGUoXCJ0ZXh0XCIpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5leHROb2RlLmxpdGVyYWwgPSBwYXJ0O1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5vZGUuaW5zZXJ0QWZ0ZXIobmV4dE5vZGUpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIE1ha2UgdGhlIGl0ZXJhdG9yIGF3YXJlIG9mIHRoZSBuZXdseSBpbnNlcnRlZCBub2RlXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgd2Fsa2VyLnJlc3VtZUF0KG5leHROb2RlLCB0cnVlKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgLy8gV2Ugc2hvdWxkIG5vdCBkbyB0aGlzIGlmIHByZXZpb3VzIG5vZGUgd2FzIG5vdCBhIHRleHRub2RlLCBhcyB3ZSBjYW4ndCBjb21iaW5lIGl0IHRoZW4uXG4gICAgICAgICAgICAgICAgaWYgKChub2RlLnR5cGUgPT09IFwiZW1waFwiIHx8IG5vZGUudHlwZSA9PT0gXCJzdHJvbmdcIikgJiYgcHJldmlvdXNOb2RlPy50eXBlID09PSBcInRleHRcIikge1xuICAgICAgICAgICAgICAgICAgICBpZiAoZXZlbnQuZW50ZXJpbmcpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IGZvdW5kTGlua3MgPSBsaW5raWZ5LmZpbmQodGV4dCk7XG4gICAgICAgICAgICAgICAgICAgICAgICBmb3IgKGNvbnN0IHsgdmFsdWUgfSBvZiBmb3VuZExpbmtzKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKG5vZGU/LmZpcnN0Q2hpbGQ/LmxpdGVyYWwpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLyoqXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAqIE5PVEU6IFRoaXMgdGVjaG5pY2FsbHkgc2hvdWxkIHVubGluayB0aGUgZW1waCBub2RlIGFuZCBjcmVhdGUgTElOSyBub2RlcyBpbnN0ZWFkLCBhZGRpbmcgYWxsIHRoZSBuZXh0IGVsZW1lbnRzIGFzIHNpYmxpbmdzXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAqIGJ1dCB0aGlzIHNvbHV0aW9uIHNlZW1zIHRvIHdvcmsgd2VsbCBhbmQgaXMgaG9wZWZ1bGx5IHNsaWdodGx5IGVhc2llciB0byB1bmRlcnN0YW5kIHRvb1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKi9cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgZm9ybWF0ID0gZm9ybWF0dGluZ0NoYW5nZXNCeU5vZGVUeXBlW25vZGUudHlwZV07XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IG5vbkVtcGhhc2l6ZWRUZXh0ID0gYCR7Zm9ybWF0fSR7aW5uZXJOb2RlTGl0ZXJhbChub2RlKX0ke2Zvcm1hdH1gO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBmID0gZ2V0VGV4dFVudGlsRW5kT3JMaW5lYnJlYWsobm9kZSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IG5ld1RleHQgPSB2YWx1ZSArIG5vbkVtcGhhc2l6ZWRUZXh0ICsgZjtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgbmV3TGlua3MgPSBsaW5raWZ5LmZpbmQobmV3VGV4dCk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIFNob3VsZCBhbHdheXMgZmluZCBvbmx5IG9uZSBsaW5rIGhlcmUsIGlmIGl0IGZpbmRzIG1vcmUgaXQgbWVhbnMgdGhhdCB0aGUgYWxnb3JpdGhtIGlzIGJyb2tlblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAobmV3TGlua3MubGVuZ3RoID09PSAxKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBlbXBoYXNpc1RleHROb2RlID0gbmV3IGNvbW1vbm1hcmsuTm9kZShcInRleHRcIik7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbXBoYXNpc1RleHROb2RlLmxpdGVyYWwgPSBub25FbXBoYXNpemVkVGV4dDtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByZXZpb3VzTm9kZS5pbnNlcnRBZnRlcihlbXBoYXNpc1RleHROb2RlKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5vZGUuZmlyc3RDaGlsZC5saXRlcmFsID0gXCJcIjtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV2ZW50ID0gbm9kZS53YWxrZXIoKS5uZXh0KCk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoZXZlbnQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBSZW1vdmUgYGVtYCBvcGVuaW5nIGFuZCBjbG9zaW5nIG5vZGVzXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbm9kZS51bmxpbmsoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcmV2aW91c05vZGUuaW5zZXJ0QWZ0ZXIoZXZlbnQubm9kZSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2hvdWxkVW5saW5rRm9ybWF0dGluZ05vZGUgPSB0cnVlO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9nZ2VyLmVycm9yKFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFwiTWFya2Rvd24gbGlua3MgZXNjYXBpbmcgZm91bmQgdG9vIG1hbnkgbGlua3MgZm9yIGZvbGxvd2luZyB0ZXh0OiBcIixcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0ZXh0LFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvZ2dlci5lcnJvcihcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcIk1hcmtkb3duIGxpbmtzIGVzY2FwaW5nIGZvdW5kIHRvbyBtYW55IGxpbmtzIGZvciBtb2RpZmllZCB0ZXh0OiBcIixcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuZXdUZXh0LFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChzaG91bGRVbmxpbmtGb3JtYXR0aW5nTm9kZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5vZGUudW5saW5rKCk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgc2hvdWxkVW5saW5rRm9ybWF0dGluZ05vZGUgPSBmYWxzZTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHByZXZpb3VzTm9kZSA9IG5vZGU7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHBhcnNlZDtcbiAgICB9XG5cbiAgICBwdWJsaWMgaXNQbGFpblRleHQoKTogYm9vbGVhbiB7XG4gICAgICAgIGNvbnN0IHdhbGtlciA9IHRoaXMucGFyc2VkLndhbGtlcigpO1xuICAgICAgICBsZXQgZXY6IGNvbW1vbm1hcmsuTm9kZVdhbGtpbmdTdGVwIHwgbnVsbDtcblxuICAgICAgICB3aGlsZSAoKGV2ID0gd2Fsa2VyLm5leHQoKSkpIHtcbiAgICAgICAgICAgIGNvbnN0IG5vZGUgPSBldi5ub2RlO1xuXG4gICAgICAgICAgICBpZiAoVEVYVF9OT0RFUy5pbmRleE9mKG5vZGUudHlwZSkgPiAtMSkge1xuICAgICAgICAgICAgICAgIC8vIGRlZmluaXRlbHkgdGV4dFxuICAgICAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICAgICAgfSBlbHNlIGlmIChub2RlLnR5cGUgPT0gXCJsaXN0XCIgfHwgbm9kZS50eXBlID09IFwiaXRlbVwiKSB7XG4gICAgICAgICAgICAgICAgLy8gU3BlY2lhbCBoYW5kbGluZyBmb3IgaW5wdXRzIGxpa2UgYCtgLCBgKmAsIGAtYCBhbmQgYDIwMjEuYCB3aGljaFxuICAgICAgICAgICAgICAgIC8vIHdvdWxkIG90aGVyd2lzZSBiZSB0cmVhdGVkIGFzIGEgbGlzdCBvZiBhIHNpbmdsZSBlbXB0eSBpdGVtLlxuICAgICAgICAgICAgICAgIC8vIFNlZSBodHRwczovL2dpdGh1Yi5jb20vdmVjdG9yLWltL2VsZW1lbnQtd2ViL2lzc3Vlcy83NjMxXG4gICAgICAgICAgICAgICAgaWYgKG5vZGUudHlwZSA9PSBcImxpc3RcIiAmJiBub2RlLmZpcnN0Q2hpbGQgJiYgZW1wdHlJdGVtV2l0aE5vU2libGluZ3Mobm9kZS5maXJzdENoaWxkKSkge1xuICAgICAgICAgICAgICAgICAgICAvLyBBIGxpc3Qgd2l0aCBhIHNpbmdsZSBlbXB0eSBpdGVtIGlzIHRyZWF0ZWQgYXMgcGxhaW4gdGV4dC5cbiAgICAgICAgICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgaWYgKG5vZGUudHlwZSA9PSBcIml0ZW1cIiAmJiBlbXB0eUl0ZW1XaXRoTm9TaWJsaW5ncyhub2RlKSkge1xuICAgICAgICAgICAgICAgICAgICAvLyBBbiBlbXB0eSBsaXN0IGl0ZW0gd2l0aCBubyBzaWJsaW5nIGl0ZW1zIGlzIHRyZWF0ZWQgYXMgcGxhaW4gdGV4dC5cbiAgICAgICAgICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgLy8gRXZlcnl0aGluZyBlbHNlIGlzIGFjdHVhbCBsaXN0cyBhbmQgdGhlcmVmb3JlIG5vdCBwbGFpbnRleHQuXG4gICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgICAgfSBlbHNlIGlmIChub2RlLnR5cGUgPT0gXCJodG1sX2lubGluZVwiIHx8IG5vZGUudHlwZSA9PSBcImh0bWxfYmxvY2tcIikge1xuICAgICAgICAgICAgICAgIC8vIGlmIGl0J3MgYW4gYWxsb3dlZCBodG1sIHRhZywgd2UgbmVlZCB0byByZW5kZXIgaXQgYW5kIHRoZXJlZm9yZVxuICAgICAgICAgICAgICAgIC8vIHdlIHdpbGwgbmVlZCB0byB1c2UgSFRNTC4gSWYgaXQncyBub3QgYWxsb3dlZCwgaXQncyBub3QgSFRNTCBzaW5jZVxuICAgICAgICAgICAgICAgIC8vIHdlJ2xsIGp1c3QgYmUgdHJlYXRpbmcgaXQgYXMgdGV4dC5cbiAgICAgICAgICAgICAgICBpZiAoaXNBbGxvd2VkSHRtbFRhZyhub2RlKSkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuXG4gICAgcHVibGljIHRvSFRNTCh7IGV4dGVybmFsTGlua3MgPSBmYWxzZSB9ID0ge30pOiBzdHJpbmcge1xuICAgICAgICBjb25zdCByZW5kZXJlciA9IG5ldyBjb21tb25tYXJrLkh0bWxSZW5kZXJlcih7XG4gICAgICAgICAgICBzYWZlOiBmYWxzZSxcblxuICAgICAgICAgICAgLy8gU2V0IHNvZnQgYnJlYWtzIHRvIGhhcmQgSFRNTCBicmVha3M6IGNvbW1vbm1hcmtcbiAgICAgICAgICAgIC8vIHB1dHMgc29mdGJyZWFrcyBpbiBmb3IgbXVsdGlwbGUgbGluZXMgaW4gYSBibG9ja3F1b3RlLFxuICAgICAgICAgICAgLy8gc28gaWYgdGhlc2UgYXJlIGp1c3QgbmV3bGluZSBjaGFyYWN0ZXJzIHRoZW4gdGhlXG4gICAgICAgICAgICAvLyBibG9jayBxdW90ZSBlbmRzIHVwIGFsbCBvbiBvbmUgbGluZVxuICAgICAgICAgICAgLy8gKGh0dHBzOi8vZ2l0aHViLmNvbS92ZWN0b3ItaW0vZWxlbWVudC13ZWIvaXNzdWVzLzMxNTQpXG4gICAgICAgICAgICBzb2Z0YnJlYWs6IFwiPGJyIC8+XCIsXG4gICAgICAgIH0pO1xuXG4gICAgICAgIC8vIFRyeWluZyB0byBzdHJpcCBvdXQgdGhlIHdyYXBwaW5nIDxwLz4gY2F1c2VzIGEgbG90IG1vcmUgY29tcGxpY2F0aW9uXG4gICAgICAgIC8vIHRoYW4gaXQncyB3b3J0aCwgaSB0aGluay4gIEZvciBpbnN0YW5jZSwgdGhpcyBjb2RlIHdpbGwgZ28gYW5kIHN0cmlwXG4gICAgICAgIC8vIG91dCBhbnkgPHAvPiB0YWcgKG5vIG1hdHRlciB3aGVyZSBpdCBpcyBpbiB0aGUgdHJlZSkgd2hpY2ggZG9lc24ndFxuICAgICAgICAvLyBjb250YWluIFxcbidzLlxuICAgICAgICAvLyBPbiB0aGUgZmxpcCBzaWRlLCA8cC8+cyBhcmUgcXVpdGUgb3Bpb25hdGVkIGFuZCByZXN0cmljdGVkIG9uIHdoZXJlXG4gICAgICAgIC8vIHlvdSBjYW4gbmVzdCB0aGVtLlxuICAgICAgICAvL1xuICAgICAgICAvLyBMZXQncyB0cnkgc2VuZGluZyB3aXRoIDxwLz5zIGFueXdheSBmb3Igbm93LCB0aG91Z2guXG4gICAgICAgIGNvbnN0IHJlYWxQYXJhZ3JhcGggPSByZW5kZXJlci5wYXJhZ3JhcGg7XG4gICAgICAgIHJlbmRlcmVyLnBhcmFncmFwaCA9IGZ1bmN0aW9uIChub2RlOiBjb21tb25tYXJrLk5vZGUsIGVudGVyaW5nOiBib29sZWFuKSB7XG4gICAgICAgICAgICAvLyBJZiB0aGVyZSBpcyBvbmx5IG9uZSB0b3AgbGV2ZWwgbm9kZSwganVzdCByZXR1cm4gdGhlXG4gICAgICAgICAgICAvLyBiYXJlIHRleHQ6IGl0J3MgYSBzaW5nbGUgbGluZSBvZiB0ZXh0IGFuZCBzbyBzaG91bGQgYmVcbiAgICAgICAgICAgIC8vICdpbmxpbmUnLCByYXRoZXIgdGhhbiB1bm5lY2Vzc2FyaWx5IHdyYXBwZWQgaW4gaXRzIG93blxuICAgICAgICAgICAgLy8gcCB0YWcuIElmLCBob3dldmVyLCB3ZSBoYXZlIG11bHRpcGxlIG5vZGVzLCBlYWNoIGdldHNcbiAgICAgICAgICAgIC8vIGl0cyBvd24gcCB0YWcgdG8ga2VlcCB0aGVtIGFzIHNlcGFyYXRlIHBhcmFncmFwaHMuXG4gICAgICAgICAgICAvLyBIb3dldmVyLCBpZiBpdCdzIGEgYmxvY2txdW90ZSwgYWRkcyBhIHAgdGFnIGFueXdheVxuICAgICAgICAgICAgLy8gaW4gb3JkZXIgdG8gYXZvaWQgZGV2aWF0aW9uIHRvIGNvbW1vbm1hcmsgYW5kIHVuZXhwZWN0ZWRcbiAgICAgICAgICAgIC8vIHJlc3VsdHMgd2hlbiBwYXJzaW5nIHRoZSBmb3JtYXR0ZWQgSFRNTC5cbiAgICAgICAgICAgIGlmIChub2RlLnBhcmVudD8udHlwZSA9PT0gXCJibG9ja19xdW90ZVwiIHx8IGlzTXVsdGlMaW5lKG5vZGUpKSB7XG4gICAgICAgICAgICAgICAgcmVhbFBhcmFncmFwaC5jYWxsKHRoaXMsIG5vZGUsIGVudGVyaW5nKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfTtcblxuICAgICAgICByZW5kZXJlci5saW5rID0gZnVuY3Rpb24gKG5vZGUsIGVudGVyaW5nKSB7XG4gICAgICAgICAgICBjb25zdCBhdHRycyA9IHRoaXMuYXR0cnMobm9kZSk7XG4gICAgICAgICAgICBpZiAoZW50ZXJpbmcgJiYgbm9kZS5kZXN0aW5hdGlvbikge1xuICAgICAgICAgICAgICAgIGF0dHJzLnB1c2goW1wiaHJlZlwiLCB0aGlzLmVzYyhub2RlLmRlc3RpbmF0aW9uKV0pO1xuICAgICAgICAgICAgICAgIGlmIChub2RlLnRpdGxlKSB7XG4gICAgICAgICAgICAgICAgICAgIGF0dHJzLnB1c2goW1widGl0bGVcIiwgdGhpcy5lc2Mobm9kZS50aXRsZSldKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgLy8gTW9kaWZpZWQgbGluayBiZWhhdmlvdXIgdG8gdHJlYXQgdGhlbSBhbGwgYXMgZXh0ZXJuYWwgYW5kXG4gICAgICAgICAgICAgICAgLy8gdGh1cyBvcGVuaW5nIGluIGEgbmV3IHRhYi5cbiAgICAgICAgICAgICAgICBpZiAoZXh0ZXJuYWxMaW5rcykge1xuICAgICAgICAgICAgICAgICAgICBhdHRycy5wdXNoKFtcInRhcmdldFwiLCBcIl9ibGFua1wiXSk7XG4gICAgICAgICAgICAgICAgICAgIGF0dHJzLnB1c2goW1wicmVsXCIsIFwibm9yZWZlcnJlciBub29wZW5lclwiXSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHRoaXMudGFnKFwiYVwiLCBhdHRycyk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHRoaXMudGFnKFwiL2FcIik7XG4gICAgICAgICAgICB9XG4gICAgICAgIH07XG5cbiAgICAgICAgcmVuZGVyZXIuaHRtbF9pbmxpbmUgPSBmdW5jdGlvbiAobm9kZTogY29tbW9ubWFyay5Ob2RlKSB7XG4gICAgICAgICAgICBpZiAobm9kZS5saXRlcmFsKSB7XG4gICAgICAgICAgICAgICAgaWYgKGlzQWxsb3dlZEh0bWxUYWcobm9kZSkpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5saXQobm9kZS5saXRlcmFsKTtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmxpdChlc2NhcGUobm9kZS5saXRlcmFsKSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9O1xuXG4gICAgICAgIHJlbmRlcmVyLmh0bWxfYmxvY2sgPSBmdW5jdGlvbiAobm9kZTogY29tbW9ubWFyay5Ob2RlKSB7XG4gICAgICAgICAgICAvKlxuICAgICAgICAgICAgLy8gYXMgd2l0aCBgcGFyYWdyYXBoYCwgd2Ugb25seSBpbnNlcnQgbGluZSBicmVha3NcbiAgICAgICAgICAgIC8vIGlmIHRoZXJlIGFyZSBtdWx0aXBsZSBsaW5lcyBpbiB0aGUgbWFya2Rvd24uXG4gICAgICAgICAgICBjb25zdCBpc011bHRpTGluZSA9IGlzX211bHRpX2xpbmUobm9kZSk7XG4gICAgICAgICAgICBpZiAoaXNNdWx0aUxpbmUpIHRoaXMuY3IoKTtcbiAgICAgICAgICAgICovXG4gICAgICAgICAgICByZW5kZXJlci5odG1sX2lubGluZShub2RlKTtcbiAgICAgICAgICAgIC8qXG4gICAgICAgICAgICBpZiAoaXNNdWx0aUxpbmUpIHRoaXMuY3IoKTtcbiAgICAgICAgICAgICovXG4gICAgICAgIH07XG5cbiAgICAgICAgcmV0dXJuIHJlbmRlcmVyLnJlbmRlcih0aGlzLnBhcnNlZCk7XG4gICAgfVxuXG4gICAgLypcbiAgICAgKiBSZW5kZXIgdGhlIG1hcmtkb3duIG1lc3NhZ2UgdG8gcGxhaW4gdGV4dC4gVGhhdCBpcywgZXNzZW50aWFsbHlcbiAgICAgKiBqdXN0IHJlbW92ZSBhbnkgYmFja3NsYXNoZXMgZXNjYXBpbmcgd2hhdCB3b3VsZCBvdGhlcndpc2UgYmVcbiAgICAgKiBtYXJrZG93biBzeW50YXhcbiAgICAgKiAodG8gZml4IGh0dHBzOi8vZ2l0aHViLmNvbS92ZWN0b3ItaW0vZWxlbWVudC13ZWIvaXNzdWVzLzI4NzApLlxuICAgICAqXG4gICAgICogTi5CLiB0aGlzIGRvZXMgKipOT1QqKiByZW5kZXIgYXJiaXRyYXJ5IE1EIHRvIHBsYWluIHRleHQgLSBvbmx5IE1EXG4gICAgICogd2hpY2ggaGFzIG5vIGZvcm1hdHRpbmcuICBPdGhlcndpc2UgaXQgZW1pdHMgSFRNTCghKS5cbiAgICAgKi9cbiAgICBwdWJsaWMgdG9QbGFpbnRleHQoKTogc3RyaW5nIHtcbiAgICAgICAgY29uc3QgcmVuZGVyZXIgPSBuZXcgY29tbW9ubWFyay5IdG1sUmVuZGVyZXIoeyBzYWZlOiBmYWxzZSB9KTtcblxuICAgICAgICByZW5kZXJlci5wYXJhZ3JhcGggPSBmdW5jdGlvbiAobm9kZTogY29tbW9ubWFyay5Ob2RlLCBlbnRlcmluZzogYm9vbGVhbikge1xuICAgICAgICAgICAgLy8gYXMgd2l0aCB0b0hUTUwsIG9ubHkgYXBwZW5kIGxpbmVzIHRvIHBhcmFncmFwaHMgaWYgdGhlcmUgYXJlXG4gICAgICAgICAgICAvLyBtdWx0aXBsZSBwYXJhZ3JhcGhzXG4gICAgICAgICAgICBpZiAoaXNNdWx0aUxpbmUobm9kZSkpIHtcbiAgICAgICAgICAgICAgICBpZiAoIWVudGVyaW5nICYmIG5vZGUubmV4dCkge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmxpdChcIlxcblxcblwiKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH07XG5cbiAgICAgICAgcmVuZGVyZXIuaHRtbF9ibG9jayA9IGZ1bmN0aW9uIChub2RlOiBjb21tb25tYXJrLk5vZGUpIHtcbiAgICAgICAgICAgIGlmIChub2RlLmxpdGVyYWwpIHRoaXMubGl0KG5vZGUubGl0ZXJhbCk7XG4gICAgICAgICAgICBpZiAoaXNNdWx0aUxpbmUobm9kZSkgJiYgbm9kZS5uZXh0KSB0aGlzLmxpdChcIlxcblxcblwiKTtcbiAgICAgICAgfTtcblxuICAgICAgICByZXR1cm4gcmVuZGVyZXIucmVuZGVyKHRoaXMucGFyc2VkKTtcbiAgICB9XG59XG4iXSwibWFwcGluZ3MiOiI7Ozs7Ozs7O0FBU0FBLE9BQUE7QUFDQSxJQUFBQyxVQUFBLEdBQUFDLHVCQUFBLENBQUFGLE9BQUE7QUFDQSxJQUFBRyxPQUFBLEdBQUFILE9BQUE7QUFDQSxJQUFBSSxPQUFBLEdBQUFKLE9BQUE7QUFFQSxJQUFBSyxjQUFBLEdBQUFMLE9BQUE7QUFBMkMsU0FBQU0seUJBQUFDLENBQUEsNkJBQUFDLE9BQUEsbUJBQUFDLENBQUEsT0FBQUQsT0FBQSxJQUFBRSxDQUFBLE9BQUFGLE9BQUEsWUFBQUYsd0JBQUEsWUFBQUEsQ0FBQUMsQ0FBQSxXQUFBQSxDQUFBLEdBQUFHLENBQUEsR0FBQUQsQ0FBQSxLQUFBRixDQUFBO0FBQUEsU0FBQUwsd0JBQUFLLENBQUEsRUFBQUUsQ0FBQSxTQUFBQSxDQUFBLElBQUFGLENBQUEsSUFBQUEsQ0FBQSxDQUFBSSxVQUFBLFNBQUFKLENBQUEsZUFBQUEsQ0FBQSx1QkFBQUEsQ0FBQSx5QkFBQUEsQ0FBQSxXQUFBSyxPQUFBLEVBQUFMLENBQUEsUUFBQUcsQ0FBQSxHQUFBSix3QkFBQSxDQUFBRyxDQUFBLE9BQUFDLENBQUEsSUFBQUEsQ0FBQSxDQUFBRyxHQUFBLENBQUFOLENBQUEsVUFBQUcsQ0FBQSxDQUFBSSxHQUFBLENBQUFQLENBQUEsT0FBQVEsQ0FBQSxLQUFB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