UNPKG

matrix-react-sdk

Version:
202 lines (195 loc) 25.7 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.getCaretOffsetAndText = getCaretOffsetAndText; exports.getRangeForSelection = getRangeForSelection; exports.walkDOMDepthFirst = walkDOMDepthFirst; var _render = require("./render"); var _offset = _interopRequireDefault(require("./offset")); /* Copyright 2019-2024 New Vector Ltd. Copyright 2019 The Matrix.org Foundation C.I.C. SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only Please see LICENSE files in the repository root for full details. */ function walkDOMDepthFirst(rootNode, enterNodeCallback, leaveNodeCallback) { let node = rootNode.firstChild; while (node && node !== rootNode) { const shouldDescend = enterNodeCallback(node); if (shouldDescend && node.firstChild) { node = node.firstChild; } else if (node.nextSibling) { node = node.nextSibling; } else { while (node && !node.nextSibling && node !== rootNode) { node = node.parentElement; if (node && node !== rootNode) { leaveNodeCallback(node); } } if (node && node !== rootNode) { node = node.nextSibling; } } } } function getCaretOffsetAndText(editor, sel) { const { offset, text } = getSelectionOffsetAndText(editor, sel.focusNode, sel.focusOffset); return { caret: offset, text }; } function tryReduceSelectionToTextNode(selectionNode, selectionOffset) { // if selectionNode is an element, the selected location comes after the selectionOffset-th child node, // which can point past any childNode, in which case, the end of selectionNode is selected. // we try to simplify this to point at a text node with the offset being // a character offset within the text node // Also see https://developer.mozilla.org/en-US/docs/Web/API/Selection while (selectionNode && selectionNode.nodeType === Node.ELEMENT_NODE) { const childNodeCount = selectionNode.childNodes.length; if (childNodeCount) { if (selectionOffset >= childNodeCount) { selectionNode = selectionNode.lastChild; if (selectionNode?.nodeType === Node.TEXT_NODE) { selectionOffset = selectionNode.textContent?.length || 0; } else { // this will select the last child node in the next iteration selectionOffset = Number.MAX_SAFE_INTEGER; } } else { selectionNode = selectionNode.childNodes[selectionOffset]; // this will select the first child node in the next iteration selectionOffset = 0; } } else { // here node won't be a text node, // but characterOffset should be 0, // this happens under some circumstances // when the editor is empty. // In this case characterOffset=0 is the right thing to do break; } } return { node: selectionNode, characterOffset: selectionOffset }; } function getSelectionOffsetAndText(editor, selectionNode, selectionOffset) { const { node, characterOffset } = tryReduceSelectionToTextNode(selectionNode, selectionOffset); const { text, offsetToNode } = getTextAndOffsetToNode(editor, node); const offset = getCaret(node, offsetToNode, characterOffset); return { offset, text }; } // gets the caret position details, ignoring and adjusting to // the ZWS if you're typing in a caret node function getCaret(node, offsetToNode, offsetWithinNode) { // if no node is selected, return an offset at the start if (!node) { return new _offset.default(0, false); } let atNodeEnd = offsetWithinNode === node.textContent?.length; if (node.nodeType === Node.TEXT_NODE && (0, _render.isCaretNode)(node.parentElement)) { const nodeValue = node.nodeValue || ""; const zwsIdx = nodeValue.indexOf(_render.CARET_NODE_CHAR); if (zwsIdx !== -1 && zwsIdx < offsetWithinNode) { offsetWithinNode -= 1; } // if typing in a caret node, you're either typing before or after the ZWS. // In both cases, you should be considered at node end because the ZWS is // not included in the text here, and once the model is updated and rerendered, // that caret node will be removed. atNodeEnd = true; } return new _offset.default(offsetToNode + offsetWithinNode, atNodeEnd); } // gets the text of the editor as a string, // and the offset in characters where the selectionNode starts in that string // all ZWS from caret nodes are filtered out function getTextAndOffsetToNode(editor, selectionNode) { let offsetToNode = 0; let foundNode = false; let text = ""; function enterNodeCallback(node) { if (!foundNode) { if (node === selectionNode) { foundNode = true; } } // usually newlines are entered as new DIV elements, // but for example while pasting in some browsers, they are still // converted to BRs, so also take these into account when they // are not the last element in the DIV. if (node instanceof HTMLElement && node.tagName === "BR" && node.nextSibling) { if (!foundNode) { offsetToNode += 1; } text += "\n"; } const nodeText = node.nodeType === Node.TEXT_NODE && getTextNodeValue(node); if (nodeText) { if (!foundNode) { offsetToNode += nodeText.length; } text += nodeText; } return true; } function leaveNodeCallback(node) { // if this is not the last DIV (which are only used as line containers atm) // we don't just check if there is a nextSibling because sometimes the caret ends up // after the last DIV and it creates a newline if you type then, // whereas you just want it to be appended to the current line if (node instanceof HTMLElement && node.tagName === "DIV" && node.nextSibling?.tagName === "DIV") { text += "\n"; if (!foundNode) { offsetToNode += 1; } } } walkDOMDepthFirst(editor, enterNodeCallback, leaveNodeCallback); return { text, offsetToNode }; } // get text value of text node, ignoring ZWS if it's a caret node function getTextNodeValue(node) { const nodeText = node.nodeValue; if (!nodeText) return ""; // filter out ZWS for caret nodes if ((0, _render.isCaretNode)(node.parentElement)) { // typed in the caret node, so there is now something more in it than the ZWS // so filter out the ZWS, and take the typed text into account if (nodeText.length !== 1) { return nodeText.replace(_render.CARET_NODE_CHAR, ""); } else { // only contains ZWS, which is ignored, so return empty string return ""; } } return nodeText; } function getRangeForSelection(editor, model, selection) { const focusOffset = getSelectionOffsetAndText(editor, selection.focusNode, selection.focusOffset).offset; const anchorOffset = getSelectionOffsetAndText(editor, selection.anchorNode, selection.anchorOffset).offset; const focusPosition = focusOffset.asPosition(model); const anchorPosition = anchorOffset.asPosition(model); return model.startRange(focusPosition, anchorPosition); } //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfcmVuZGVyIiwicmVxdWlyZSIsIl9vZmZzZXQiLCJfaW50ZXJvcFJlcXVpcmVEZWZhdWx0Iiwid2Fsa0RPTURlcHRoRmlyc3QiLCJyb290Tm9kZSIsImVudGVyTm9kZUNhbGxiYWNrIiwibGVhdmVOb2RlQ2FsbGJhY2siLCJub2RlIiwiZmlyc3RDaGlsZCIsInNob3VsZERlc2NlbmQiLCJuZXh0U2libGluZyIsInBhcmVudEVsZW1lbnQiLCJnZXRDYXJldE9mZnNldEFuZFRleHQiLCJlZGl0b3IiLCJzZWwiLCJvZmZzZXQiLCJ0ZXh0IiwiZ2V0U2VsZWN0aW9uT2Zmc2V0QW5kVGV4dCIsImZvY3VzTm9kZSIsImZvY3VzT2Zmc2V0IiwiY2FyZXQiLCJ0cnlSZWR1Y2VTZWxlY3Rpb25Ub1RleHROb2RlIiwic2VsZWN0aW9uTm9kZSIsInNlbGVjdGlvbk9mZnNldCIsIm5vZGVUeXBlIiwiTm9kZSIsIkVMRU1FTlRfTk9ERSIsImNoaWxkTm9kZUNvdW50IiwiY2hpbGROb2RlcyIsImxlbmd0aCIsImxhc3RDaGlsZCIsIlRFWFRfTk9ERSIsInRleHRDb250ZW50IiwiTnVtYmVyIiwiTUFYX1NBRkVfSU5URUdFUiIsImNoYXJhY3Rlck9mZnNldCIsIm9mZnNldFRvTm9kZSIsImdldFRleHRBbmRPZmZzZXRUb05vZGUiLCJnZXRDYXJldCIsIm9mZnNldFdpdGhpbk5vZGUiLCJEb2N1bWVudE9mZnNldCIsImF0Tm9kZUVuZCIsImlzQ2FyZXROb2RlIiwibm9kZVZhbHVlIiwiendzSWR4IiwiaW5kZXhPZiIsIkNBUkVUX05PREVfQ0hBUiIsImZvdW5kTm9kZSIsIkhUTUxFbGVtZW50IiwidGFnTmFtZSIsIm5vZGVUZXh0IiwiZ2V0VGV4dE5vZGVWYWx1ZSIsInJlcGxhY2UiLCJnZXRSYW5nZUZvclNlbGVjdGlvbiIsIm1vZGVsIiwic2VsZWN0aW9uIiwiYW5jaG9yT2Zmc2V0IiwiYW5jaG9yTm9kZSIsImZvY3VzUG9zaXRpb24iLCJhc1Bvc2l0aW9uIiwiYW5jaG9yUG9zaXRpb24iLCJzdGFydFJhbmdlIl0sInNvdXJjZXMiOlsiLi4vLi4vc3JjL2VkaXRvci9kb20udHMiXSwic291cmNlc0NvbnRlbnQiOlsiLypcbkNvcHlyaWdodCAyMDE5LTIwMjQgTmV3IFZlY3RvciBMdGQuXG5Db3B5cmlnaHQgMjAxOSBUaGUgTWF0cml4Lm9yZyBGb3VuZGF0aW9uIEMuSS5DLlxuXG5TUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogQUdQTC0zLjAtb25seSBPUiBHUEwtMy4wLW9ubHlcblBsZWFzZSBzZWUgTElDRU5TRSBmaWxlcyBpbiB0aGUgcmVwb3NpdG9yeSByb290IGZvciBmdWxsIGRldGFpbHMuXG4qL1xuXG5pbXBvcnQgeyBDQVJFVF9OT0RFX0NIQVIsIGlzQ2FyZXROb2RlIH0gZnJvbSBcIi4vcmVuZGVyXCI7XG5pbXBvcnQgRG9jdW1lbnRPZmZzZXQgZnJvbSBcIi4vb2Zmc2V0XCI7XG5pbXBvcnQgRWRpdG9yTW9kZWwgZnJvbSBcIi4vbW9kZWxcIjtcbmltcG9ydCBSYW5nZSBmcm9tIFwiLi9yYW5nZVwiO1xuXG50eXBlIFByZWRpY2F0ZSA9IChub2RlOiBOb2RlKSA9PiBib29sZWFuO1xudHlwZSBDYWxsYmFjayA9IChub2RlOiBOb2RlKSA9PiB2b2lkO1xuXG5leHBvcnQgZnVuY3Rpb24gd2Fsa0RPTURlcHRoRmlyc3Qocm9vdE5vZGU6IE5vZGUsIGVudGVyTm9kZUNhbGxiYWNrOiBQcmVkaWNhdGUsIGxlYXZlTm9kZUNhbGxiYWNrOiBDYWxsYmFjayk6IHZvaWQge1xuICAgIGxldCBub2RlID0gcm9vdE5vZGUuZmlyc3RDaGlsZDtcbiAgICB3aGlsZSAobm9kZSAmJiBub2RlICE9PSByb290Tm9kZSkge1xuICAgICAgICBjb25zdCBzaG91bGREZXNjZW5kID0gZW50ZXJOb2RlQ2FsbGJhY2sobm9kZSk7XG4gICAgICAgIGlmIChzaG91bGREZXNjZW5kICYmIG5vZGUuZmlyc3RDaGlsZCkge1xuICAgICAgICAgICAgbm9kZSA9IG5vZGUuZmlyc3RDaGlsZDtcbiAgICAgICAgfSBlbHNlIGlmIChub2RlLm5leHRTaWJsaW5nKSB7XG4gICAgICAgICAgICBub2RlID0gbm9kZS5uZXh0U2libGluZztcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHdoaWxlIChub2RlICYmICFub2RlLm5leHRTaWJsaW5nICYmIG5vZGUgIT09IHJvb3ROb2RlKSB7XG4gICAgICAgICAgICAgICAgbm9kZSA9IG5vZGUucGFyZW50RWxlbWVudDtcbiAgICAgICAgICAgICAgICBpZiAobm9kZSAmJiBub2RlICE9PSByb290Tm9kZSkge1xuICAgICAgICAgICAgICAgICAgICBsZWF2ZU5vZGVDYWxsYmFjayhub2RlKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAobm9kZSAmJiBub2RlICE9PSByb290Tm9kZSkge1xuICAgICAgICAgICAgICAgIG5vZGUgPSBub2RlLm5leHRTaWJsaW5nO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxufVxuXG5leHBvcnQgZnVuY3Rpb24gZ2V0Q2FyZXRPZmZzZXRBbmRUZXh0KFxuICAgIGVkaXRvcjogSFRNTERpdkVsZW1lbnQsXG4gICAgc2VsOiBTZWxlY3Rpb24sXG4pOiB7XG4gICAgY2FyZXQ6IERvY3VtZW50T2Zmc2V0O1xuICAgIHRleHQ6IHN0cmluZztcbn0ge1xuICAgIGNvbnN0IHsgb2Zmc2V0LCB0ZXh0IH0gPSBnZXRTZWxlY3Rpb25PZmZzZXRBbmRUZXh0KGVkaXRvciwgc2VsLmZvY3VzTm9kZSwgc2VsLmZvY3VzT2Zmc2V0KTtcbiAgICByZXR1cm4geyBjYXJldDogb2Zmc2V0LCB0ZXh0IH07XG59XG5cbmZ1bmN0aW9uIHRyeVJlZHVjZVNlbGVjdGlvblRvVGV4dE5vZGUoXG4gICAgc2VsZWN0aW9uTm9kZTogTm9kZSB8IG51bGwsXG4gICAgc2VsZWN0aW9uT2Zmc2V0OiBudW1iZXIsXG4pOiB7XG4gICAgbm9kZTogTm9kZSB8IG51bGw7XG4gICAgY2hhcmFjdGVyT2Zmc2V0OiBudW1iZXI7XG59IHtcbiAgICAvLyBpZiBzZWxlY3Rpb25Ob2RlIGlzIGFuIGVsZW1lbnQsIHRoZSBzZWxlY3RlZCBsb2NhdGlvbiBjb21lcyBhZnRlciB0aGUgc2VsZWN0aW9uT2Zmc2V0LXRoIGNoaWxkIG5vZGUsXG4gICAgLy8gd2hpY2ggY2FuIHBvaW50IHBhc3QgYW55IGNoaWxkTm9kZSwgaW4gd2hpY2ggY2FzZSwgdGhlIGVuZCBvZiBzZWxlY3Rpb25Ob2RlIGlzIHNlbGVjdGVkLlxuICAgIC8vIHdlIHRyeSB0byBzaW1wbGlmeSB0aGlzIHRvIHBvaW50IGF0IGEgdGV4dCBub2RlIHdpdGggdGhlIG9mZnNldCBiZWluZ1xuICAgIC8vIGEgY2hhcmFjdGVyIG9mZnNldCB3aXRoaW4gdGhlIHRleHQgbm9kZVxuICAgIC8vIEFsc28gc2VlIGh0dHBzOi8vZGV2ZWxvcGVyLm1vemlsbGEub3JnL2VuLVVTL2RvY3MvV2ViL0FQSS9TZWxlY3Rpb25cbiAgICB3aGlsZSAoc2VsZWN0aW9uTm9kZSAmJiBzZWxlY3Rpb25Ob2RlLm5vZGVUeXBlID09PSBOb2RlLkVMRU1FTlRfTk9ERSkge1xuICAgICAgICBjb25zdCBjaGlsZE5vZGVDb3VudCA9IHNlbGVjdGlvbk5vZGUuY2hpbGROb2Rlcy5sZW5ndGg7XG4gICAgICAgIGlmIChjaGlsZE5vZGVDb3VudCkge1xuICAgICAgICAgICAgaWYgKHNlbGVjdGlvbk9mZnNldCA+PSBjaGlsZE5vZGVDb3VudCkge1xuICAgICAgICAgICAgICAgIHNlbGVjdGlvbk5vZGUgPSBzZWxlY3Rpb25Ob2RlLmxhc3RDaGlsZDtcbiAgICAgICAgICAgICAgICBpZiAoc2VsZWN0aW9uTm9kZT8ubm9kZVR5cGUgPT09IE5vZGUuVEVYVF9OT0RFKSB7XG4gICAgICAgICAgICAgICAgICAgIHNlbGVjdGlvbk9mZnNldCA9IHNlbGVjdGlvbk5vZGUudGV4dENvbnRlbnQ/Lmxlbmd0aCB8fCAwO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIHRoaXMgd2lsbCBzZWxlY3QgdGhlIGxhc3QgY2hpbGQgbm9kZSBpbiB0aGUgbmV4dCBpdGVyYXRpb25cbiAgICAgICAgICAgICAgICAgICAgc2VsZWN0aW9uT2Zmc2V0ID0gTnVtYmVyLk1BWF9TQUZFX0lOVEVHRVI7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBzZWxlY3Rpb25Ob2RlID0gc2VsZWN0aW9uTm9kZS5jaGlsZE5vZGVzW3NlbGVjdGlvbk9mZnNldF07XG4gICAgICAgICAgICAgICAgLy8gdGhpcyB3aWxsIHNlbGVjdCB0aGUgZmlyc3QgY2hpbGQgbm9kZSBpbiB0aGUgbmV4dCBpdGVyYXRpb25cbiAgICAgICAgICAgICAgICBzZWxlY3Rpb25PZmZzZXQgPSAwO1xuICAgICAgICAgICAgfVxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgLy8gaGVyZSBub2RlIHdvbid0IGJlIGEgdGV4dCBub2RlLFxuICAgICAgICAgICAgLy8gYnV0IGNoYXJhY3Rlck9mZnNldCBzaG91bGQgYmUgMCxcbiAgICAgICAgICAgIC8vIHRoaXMgaGFwcGVucyB1bmRlciBzb21lIGNpcmN1bXN0YW5jZXNcbiAgICAgICAgICAgIC8vIHdoZW4gdGhlIGVkaXRvciBpcyBlbXB0eS5cbiAgICAgICAgICAgIC8vIEluIHRoaXMgY2FzZSBjaGFyYWN0ZXJPZmZzZXQ9MCBpcyB0aGUgcmlnaHQgdGhpbmcgdG8gZG9cbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICB9XG4gICAgfVxuICAgIHJldHVybiB7XG4gICAgICAgIG5vZGU6IHNlbGVjdGlvbk5vZGUsXG4gICAgICAgIGNoYXJhY3Rlck9mZnNldDogc2VsZWN0aW9uT2Zmc2V0LFxuICAgIH07XG59XG5cbmZ1bmN0aW9uIGdldFNlbGVjdGlvbk9mZnNldEFuZFRleHQoXG4gICAgZWRpdG9yOiBIVE1MRGl2RWxlbWVudCxcbiAgICBzZWxlY3Rpb25Ob2RlOiBOb2RlIHwgbnVsbCxcbiAgICBzZWxlY3Rpb25PZmZzZXQ6IG51bWJlcixcbik6IHtcbiAgICBvZmZzZXQ6IERvY3VtZW50T2Zmc2V0O1xuICAgIHRleHQ6IHN0cmluZztcbn0ge1xuICAgIGNvbnN0IHsgbm9kZSwgY2hhcmFjdGVyT2Zmc2V0IH0gPSB0cnlSZWR1Y2VTZWxlY3Rpb25Ub1RleHROb2RlKHNlbGVjdGlvbk5vZGUsIHNlbGVjdGlvbk9mZnNldCk7XG4gICAgY29uc3QgeyB0ZXh0LCBvZmZzZXRUb05vZGUgfSA9IGdldFRleHRBbmRPZmZzZXRUb05vZGUoZWRpdG9yLCBub2RlKTtcbiAgICBjb25zdCBvZmZzZXQgPSBnZXRDYXJldChub2RlLCBvZmZzZXRUb05vZGUsIGNoYXJhY3Rlck9mZnNldCk7XG4gICAgcmV0dXJuIHsgb2Zmc2V0LCB0ZXh0IH07XG59XG5cbi8vIGdldHMgdGhlIGNhcmV0IHBvc2l0aW9uIGRldGFpbHMsIGlnbm9yaW5nIGFuZCBhZGp1c3RpbmcgdG9cbi8vIHRoZSBaV1MgaWYgeW91J3JlIHR5cGluZyBpbiBhIGNhcmV0IG5vZGVcbmZ1bmN0aW9uIGdldENhcmV0KG5vZGU6IE5vZGUgfCBudWxsLCBvZmZzZXRUb05vZGU6IG51bWJlciwgb2Zmc2V0V2l0aGluTm9kZTogbnVtYmVyKTogRG9jdW1lbnRPZmZzZXQge1xuICAgIC8vIGlmIG5vIG5vZGUgaXMgc2VsZWN0ZWQsIHJldHVybiBhbiBvZmZzZXQgYXQgdGhlIHN0YXJ0XG4gICAgaWYgKCFub2RlKSB7XG4gICAgICAgIHJldHVybiBuZXcgRG9jdW1lbnRPZmZzZXQoMCwgZmFsc2UpO1xuICAgIH1cbiAgICBsZXQgYXROb2RlRW5kID0gb2Zmc2V0V2l0aGluTm9kZSA9PT0gbm9kZS50ZXh0Q29udGVudD8ubGVuZ3RoO1xuICAgIGlmIChub2RlLm5vZGVUeXBlID09PSBOb2RlLlRFWFRfTk9ERSAmJiBpc0NhcmV0Tm9kZShub2RlLnBhcmVudEVsZW1lbnQpKSB7XG4gICAgICAgIGNvbnN0IG5vZGVWYWx1ZSA9IG5vZGUubm9kZVZhbHVlIHx8IFwiXCI7XG4gICAgICAgIGNvbnN0IHp3c0lkeCA9IG5vZGVWYWx1ZS5pbmRleE9mKENBUkVUX05PREVfQ0hBUik7XG4gICAgICAgIGlmICh6d3NJZHggIT09IC0xICYmIHp3c0lkeCA8IG9mZnNldFdpdGhpbk5vZGUpIHtcbiAgICAgICAgICAgIG9mZnNldFdpdGhpbk5vZGUgLT0gMTtcbiAgICAgICAgfVxuICAgICAgICAvLyBpZiB0eXBpbmcgaW4gYSBjYXJldCBub2RlLCB5b3UncmUgZWl0aGVyIHR5cGluZyBiZWZvcmUgb3IgYWZ0ZXIgdGhlIFpXUy5cbiAgICAgICAgLy8gSW4gYm90aCBjYXNlcywgeW91IHNob3VsZCBiZSBjb25zaWRlcmVkIGF0IG5vZGUgZW5kIGJlY2F1c2UgdGhlIFpXUyBpc1xuICAgICAgICAvLyBub3QgaW5jbHVkZWQgaW4gdGhlIHRleHQgaGVyZSwgYW5kIG9uY2UgdGhlIG1vZGVsIGlzIHVwZGF0ZWQgYW5kIHJlcmVuZGVyZWQsXG4gICAgICAgIC8vIHRoYXQgY2FyZXQgbm9kZSB3aWxsIGJlIHJlbW92ZWQuXG4gICAgICAgIGF0Tm9kZUVuZCA9IHRydWU7XG4gICAgfVxuICAgIHJldHVybiBuZXcgRG9jdW1lbnRPZmZzZXQob2Zmc2V0VG9Ob2RlICsgb2Zmc2V0V2l0aGluTm9kZSwgYXROb2RlRW5kKTtcbn1cblxuLy8gZ2V0cyB0aGUgdGV4dCBvZiB0aGUgZWRpdG9yIGFzIGEgc3RyaW5nLFxuLy8gYW5kIHRoZSBvZmZzZXQgaW4gY2hhcmFjdGVycyB3aGVyZSB0aGUgc2VsZWN0aW9uTm9kZSBzdGFydHMgaW4gdGhhdCBzdHJpbmdcbi8vIGFsbCBaV1MgZnJvbSBjYXJldCBub2RlcyBhcmUgZmlsdGVyZWQgb3V0XG5mdW5jdGlvbiBnZXRUZXh0QW5kT2Zmc2V0VG9Ob2RlKFxuICAgIGVkaXRvcjogSFRNTERpdkVsZW1lbnQsXG4gICAgc2VsZWN0aW9uTm9kZTogTm9kZSB8IG51bGwsXG4pOiB7IG9mZnNldFRvTm9kZTogbnVtYmVyOyB0ZXh0OiBzdHJpbmcgfSB7XG4gICAgbGV0IG9mZnNldFRvTm9kZSA9IDA7XG4gICAgbGV0IGZvdW5kTm9kZSA9IGZhbHNlO1xuICAgIGxldCB0ZXh0ID0gXCJcIjtcblxuICAgIGZ1bmN0aW9uIGVudGVyTm9kZUNhbGxiYWNrKG5vZGU6IE5vZGUpOiBib29sZWFuIHtcbiAgICAgICAgaWYgKCFmb3VuZE5vZGUpIHtcbiAgICAgICAgICAgIGlmIChub2RlID09PSBzZWxlY3Rpb25Ob2RlKSB7XG4gICAgICAgICAgICAgICAgZm91bmROb2RlID0gdHJ1ZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICAvLyB1c3VhbGx5IG5ld2xpbmVzIGFyZSBlbnRlcmVkIGFzIG5ldyBESVYgZWxlbWVudHMsXG4gICAgICAgIC8vIGJ1dCBmb3IgZXhhbXBsZSB3aGlsZSBwYXN0aW5nIGluIHNvbWUgYnJvd3NlcnMsIHRoZXkgYXJlIHN0aWxsXG4gICAgICAgIC8vIGNvbnZlcnRlZCB0byBCUnMsIHNvIGFsc28gdGFrZSB0aGVzZSBpbnRvIGFjY291bnQgd2hlbiB0aGV5XG4gICAgICAgIC8vIGFyZSBub3QgdGhlIGxhc3QgZWxlbWVudCBpbiB0aGUgRElWLlxuICAgICAgICBpZiAobm9kZSBpbnN0YW5jZW9mIEhUTUxFbGVtZW50ICYmIG5vZGUudGFnTmFtZSA9PT0gXCJCUlwiICYmIG5vZGUubmV4dFNpYmxpbmcpIHtcbiAgICAgICAgICAgIGlmICghZm91bmROb2RlKSB7XG4gICAgICAgICAgICAgICAgb2Zmc2V0VG9Ob2RlICs9IDE7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB0ZXh0ICs9IFwiXFxuXCI7XG4gICAgICAgIH1cbiAgICAgICAgY29uc3Qgbm9kZVRleHQgPSBub2RlLm5vZGVUeXBlID09PSBOb2RlLlRFWFRfTk9ERSAmJiBnZXRUZXh0Tm9kZVZhbHVlKG5vZGUpO1xuICAgICAgICBpZiAobm9kZVRleHQpIHtcbiAgICAgICAgICAgIGlmICghZm91bmROb2RlKSB7XG4gICAgICAgICAgICAgICAgb2Zmc2V0VG9Ob2RlICs9IG5vZGVUZXh0Lmxlbmd0aDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHRleHQgKz0gbm9kZVRleHQ7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gbGVhdmVOb2RlQ2FsbGJhY2sobm9kZTogTm9kZSk6IHZvaWQge1xuICAgICAgICAvLyBpZiB0aGlzIGlzIG5vdCB0aGUgbGFzdCBESVYgKHdoaWNoIGFyZSBvbmx5IHVzZWQgYXMgbGluZSBjb250YWluZXJzIGF0bSlcbiAgICAgICAgLy8gd2UgZG9uJ3QganVzdCBjaGVjayBpZiB0aGVyZSBpcyBhIG5leHRTaWJsaW5nIGJlY2F1c2Ugc29tZXRpbWVzIHRoZSBjYXJldCBlbmRzIHVwXG4gICAgICAgIC8vIGFmdGVyIHRoZSBsYXN0IERJViBhbmQgaXQgY3JlYXRlcyBhIG5ld2xpbmUgaWYgeW91IHR5cGUgdGhlbixcbiAgICAgICAgLy8gd2hlcmVhcyB5b3UganVzdCB3YW50IGl0IHRvIGJlIGFwcGVuZGVkIHRvIHRoZSBjdXJyZW50IGxpbmVcbiAgICAgICAgaWYgKFxuICAgICAgICAgICAgbm9kZSBpbnN0YW5jZW9mIEhUTUxFbGVtZW50ICYmXG4gICAgICAgICAgICBub2RlLnRhZ05hbWUgPT09IFwiRElWXCIgJiZcbiAgICAgICAgICAgICg8SFRNTEVsZW1lbnQ+bm9kZS5uZXh0U2libGluZyk/LnRhZ05hbWUgPT09IFwiRElWXCJcbiAgICAgICAgKSB7XG4gICAgICAgICAgICB0ZXh0ICs9IFwiXFxuXCI7XG4gICAgICAgICAgICBpZiAoIWZvdW5kTm9kZSkge1xuICAgICAgICAgICAgICAgIG9mZnNldFRvTm9kZSArPSAxO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuXG4gICAgd2Fsa0RPTURlcHRoRmlyc3QoZWRpdG9yLCBlbnRlck5vZGVDYWxsYmFjaywgbGVhdmVOb2RlQ2FsbGJhY2spO1xuXG4gICAgcmV0dXJuIHsgdGV4dCwgb2Zmc2V0VG9Ob2RlIH07XG59XG5cbi8vIGdldCB0ZXh0IHZhbHVlIG9mIHRleHQgbm9kZSwgaWdub3JpbmcgWldTIGlmIGl0J3MgYSBjYXJldCBub2RlXG5mdW5jdGlvbiBnZXRUZXh0Tm9kZVZhbHVlKG5vZGU6IE5vZGUpOiBzdHJpbmcge1xuICAgIGNvbnN0IG5vZGVUZXh0ID0gbm9kZS5ub2RlVmFsdWU7XG4gICAgaWYgKCFub2RlVGV4dCkgcmV0dXJuIFwiXCI7XG5cbiAgICAvLyBmaWx0ZXIgb3V0IFpXUyBmb3IgY2FyZXQgbm9kZXNcbiAgICBpZiAoaXNDYXJldE5vZGUobm9kZS5wYXJlbnRFbGVtZW50KSkge1xuICAgICAgICAvLyB0eXBlZCBpbiB0aGUgY2FyZXQgbm9kZSwgc28gdGhlcmUgaXMgbm93IHNvbWV0aGluZyBtb3JlIGluIGl0IHRoYW4gdGhlIFpXU1xuICAgICAgICAvLyBzbyBmaWx0ZXIgb3V0IHRoZSBaV1MsIGFuZCB0YWtlIHRoZSB0eXBlZCB0ZXh0IGludG8gYWNjb3VudFxuICAgICAgICBpZiAobm9kZVRleHQubGVuZ3RoICE9PSAxKSB7XG4gICAgICAgICAgICByZXR1cm4gbm9kZVRleHQucmVwbGFjZShDQVJFVF9OT0RFX0NIQVIsIFwiXCIpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgLy8gb25seSBjb250YWlucyBaV1MsIHdoaWNoIGlzIGlnbm9yZWQsIHNvIHJldHVybiBlbXB0eSBzdHJpbmdcbiAgICAgICAgICAgIHJldHVybiBcIlwiO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIG5vZGVUZXh0O1xufVxuXG5leHBvcnQgZnVuY3Rpb24gZ2V0UmFuZ2VGb3JTZWxlY3Rpb24oZWRpdG9yOiBIVE1MRGl2RWxlbWVudCwgbW9kZWw6IEVkaXRvck1vZGVsLCBzZWxlY3Rpb246IFNlbGVjdGlvbik6IFJhbmdlIHtcbiAgICBjb25zdCBmb2N1c09mZnNldCA9IGdldFNlbGVjdGlvbk9mZnNldEFuZFRleHQoZWRpdG9yLCBzZWxlY3Rpb24uZm9jdXNOb2RlLCBzZWxlY3Rpb24uZm9jdXNPZmZzZXQpLm9mZnNldDtcbiAgICBjb25zdCBhbmNob3JPZmZzZXQgPSBnZXRTZWxlY3Rpb25PZmZzZXRBbmRUZXh0KGVkaXRvciwgc2VsZWN0aW9uLmFuY2hvck5vZGUsIHNlbGVjdGlvbi5hbmNob3JPZmZzZXQpLm9mZnNldDtcbiAgICBjb25zdCBmb2N1c1Bvc2l0aW9uID0gZm9jdXNPZmZzZXQuYXNQb3NpdGlvbihtb2RlbCk7XG4gICAgY29uc3QgYW5jaG9yUG9zaXRpb24gPSBhbmNob3JPZmZzZXQuYXNQb3NpdGlvbihtb2RlbCk7XG4gICAgcmV0dXJuIG1vZGVsLnN0YXJ0UmFuZ2UoZm9jdXNQb3NpdGlvbiwgYW5jaG9yUG9zaXRpb24pO1xufVxuIl0sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7QUFRQSxJQUFBQSxPQUFBLEdBQUFDLE9BQUE7QUFDQSxJQUFBQyxPQUFBLEdBQUFDLHNCQUFBLENBQUFGLE9BQUE7QUFUQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFVTyxTQUFTRyxpQkFBaUJBLENBQUNDLFFBQWMsRUFBRUMsaUJBQTRCLEVBQUVDLGlCQUEyQixFQUFRO0VBQy9HLElBQUlDLElBQUksR0FBR0gsUUFBUSxDQUFDSSxVQUFVO0VBQzlCLE9BQU9ELElBQUksSUFBSUEsSUFBSSxLQUFLSCxRQUFRLEVBQUU7SUFDOUIsTUFBTUssYUFBYSxHQUFHSixpQkFBaUIsQ0FBQ0UsSUFBSSxDQUFDO0lBQzdDLElBQUlFLGFBQWEsSUFBSUYsSUFBSSxDQUFDQyxVQUFVLEVBQUU7TUFDbENELElBQUksR0FBR0EsSUFBSSxDQUFDQyxVQUFVO0lBQzFCLENBQUMsTUFBTSxJQUFJRCxJQUFJLENBQUNHLFdBQVcsRUFBRTtNQUN6QkgsSUFBSSxHQUFHQSxJQUFJLENBQUNHLFdBQVc7SUFDM0IsQ0FBQyxNQUFNO01BQ0gsT0FBT0gsSUFBSSxJQUFJLENBQUNBLElBQUksQ0FBQ0csV0FBVyxJQUFJSCxJQUFJLEtBQUtILFFBQVEsRUFBRTtRQUNuREcs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