matrix-react-sdk
Version:
SDK for matrix.org using React
202 lines (195 loc) • 25.7 kB
JavaScript
;
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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