25 lines
622 KiB
JavaScript
25 lines
622 KiB
JavaScript
"use strict";
|
|
/*
|
|
* ATTENTION: An "eval-source-map" devtool has been used.
|
|
* This devtool is neither made for production nor for readable output files.
|
|
* It uses "eval()" calls to create a separate source file with attached SourceMaps in the browser devtools.
|
|
* If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
|
|
* or disable the default devtool with "devtool: false".
|
|
* If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
|
|
*/
|
|
exports.id = "vendor-chunks/prosemirror-view";
|
|
exports.ids = ["vendor-chunks/prosemirror-view"];
|
|
exports.modules = {
|
|
|
|
/***/ "(ssr)/./node_modules/prosemirror-view/dist/index.js":
|
|
/*!*****************************************************!*\
|
|
!*** ./node_modules/prosemirror-view/dist/index.js ***!
|
|
\*****************************************************/
|
|
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
|
|
|
|
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ Decoration: () => (/* binding */ Decoration),\n/* harmony export */ DecorationSet: () => (/* binding */ DecorationSet),\n/* harmony export */ EditorView: () => (/* binding */ EditorView),\n/* harmony export */ __endComposition: () => (/* binding */ __endComposition),\n/* harmony export */ __parseFromClipboard: () => (/* binding */ __parseFromClipboard)\n/* harmony export */ });\n/* harmony import */ var prosemirror_state__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! prosemirror-state */ \"(ssr)/./node_modules/prosemirror-state/dist/index.js\");\n/* harmony import */ var prosemirror_model__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! prosemirror-model */ \"(ssr)/./node_modules/prosemirror-model/dist/index.js\");\n/* harmony import */ var prosemirror_transform__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! prosemirror-transform */ \"(ssr)/./node_modules/prosemirror-transform/dist/index.js\");\n\n\n\n\nconst domIndex = function (node) {\n for (var index = 0;; index++) {\n node = node.previousSibling;\n if (!node)\n return index;\n }\n};\nconst parentNode = function (node) {\n let parent = node.assignedSlot || node.parentNode;\n return parent && parent.nodeType == 11 ? parent.host : parent;\n};\nlet reusedRange = null;\n// Note that this will always return the same range, because DOM range\n// objects are every expensive, and keep slowing down subsequent DOM\n// updates, for some reason.\nconst textRange = function (node, from, to) {\n let range = reusedRange || (reusedRange = document.createRange());\n range.setEnd(node, to == null ? node.nodeValue.length : to);\n range.setStart(node, from || 0);\n return range;\n};\nconst clearReusedRange = function () {\n reusedRange = null;\n};\n// Scans forward and backward through DOM positions equivalent to the\n// given one to see if the two are in the same place (i.e. after a\n// text node vs at the end of that text node)\nconst isEquivalentPosition = function (node, off, targetNode, targetOff) {\n return targetNode && (scanFor(node, off, targetNode, targetOff, -1) ||\n scanFor(node, off, targetNode, targetOff, 1));\n};\nconst atomElements = /^(img|br|input|textarea|hr)$/i;\nfunction scanFor(node, off, targetNode, targetOff, dir) {\n var _a;\n for (;;) {\n if (node == targetNode && off == targetOff)\n return true;\n if (off == (dir < 0 ? 0 : nodeSize(node))) {\n let parent = node.parentNode;\n if (!parent || parent.nodeType != 1 || hasBlockDesc(node) || atomElements.test(node.nodeName) ||\n node.contentEditable == \"false\")\n return false;\n off = domIndex(node) + (dir < 0 ? 0 : 1);\n node = parent;\n }\n else if (node.nodeType == 1) {\n let child = node.childNodes[off + (dir < 0 ? -1 : 0)];\n if (child.nodeType == 1 && child.contentEditable == \"false\") {\n if ((_a = child.pmViewDesc) === null || _a === void 0 ? void 0 : _a.ignoreForSelection)\n off += dir;\n else\n return false;\n }\n else {\n node = child;\n off = dir < 0 ? nodeSize(node) : 0;\n }\n }\n else {\n return false;\n }\n }\n}\nfunction nodeSize(node) {\n return node.nodeType == 3 ? node.nodeValue.length : node.childNodes.length;\n}\nfunction textNodeBefore$1(node, offset) {\n for (;;) {\n if (node.nodeType == 3 && offset)\n return node;\n if (node.nodeType == 1 && offset > 0) {\n if (node.contentEditable == \"false\")\n return null;\n node = node.childNodes[offset - 1];\n offset = nodeSize(node);\n }\n else if (node.parentNode && !hasBlockDesc(node)) {\n offset = domIndex(node);\n node = node.parentNode;\n }\n else {\n return null;\n }\n }\n}\nfunction textNodeAfter$1(node, offset) {\n for (;;) {\n if (node.nodeType == 3 && offset < node.nodeValue.length)\n return node;\n if (node.nodeType == 1 && offset < node.childNodes.length) {\n if (node.contentEditable == \"false\")\n return null;\n node = node.childNodes[offset];\n offset = 0;\n }\n else if (node.parentNode && !hasBlockDesc(node)) {\n offset = domIndex(node) + 1;\n node = node.parentNode;\n }\n else {\n return null;\n }\n }\n}\nfunction isOnEdge(node, offset, parent) {\n for (let atStart = offset == 0, atEnd = offset == nodeSize(node); atStart || atEnd;) {\n if (node == parent)\n return true;\n let index = domIndex(node);\n node = node.parentNode;\n if (!node)\n return false;\n atStart = atStart && index == 0;\n atEnd = atEnd && index == nodeSize(node);\n }\n}\nfunction hasBlockDesc(dom) {\n let desc;\n for (let cur = dom; cur; cur = cur.parentNode)\n if (desc = cur.pmViewDesc)\n break;\n return desc && desc.node && desc.node.isBlock && (desc.dom == dom || desc.contentDOM == dom);\n}\n// Work around Chrome issue https://bugs.chromium.org/p/chromium/issues/detail?id=447523\n// (isCollapsed inappropriately returns true in shadow dom)\nconst selectionCollapsed = function (domSel) {\n return domSel.focusNode && isEquivalentPosition(domSel.focusNode, domSel.focusOffset, domSel.anchorNode, domSel.anchorOffset);\n};\nfunction keyEvent(keyCode, key) {\n let event = document.createEvent(\"Event\");\n event.initEvent(\"keydown\", true, true);\n event.keyCode = keyCode;\n event.key = event.code = key;\n return event;\n}\nfunction deepActiveElement(doc) {\n let elt = doc.activeElement;\n while (elt && elt.shadowRoot)\n elt = elt.shadowRoot.activeElement;\n return elt;\n}\nfunction caretFromPoint(doc, x, y) {\n if (doc.caretPositionFromPoint) {\n try { // Firefox throws for this call in hard-to-predict circumstances (#994)\n let pos = doc.caretPositionFromPoint(x, y);\n // Clip the offset, because Chrome will return a text offset\n // into <input> nodes, which can't be treated as a regular DOM\n // offset\n if (pos)\n return { node: pos.offsetNode, offset: Math.min(nodeSize(pos.offsetNode), pos.offset) };\n }\n catch (_) { }\n }\n if (doc.caretRangeFromPoint) {\n let range = doc.caretRangeFromPoint(x, y);\n if (range)\n return { node: range.startContainer, offset: Math.min(nodeSize(range.startContainer), range.startOffset) };\n }\n}\n\nconst nav = typeof navigator != \"undefined\" ? navigator : null;\nconst doc = typeof document != \"undefined\" ? document : null;\nconst agent = (nav && nav.userAgent) || \"\";\nconst ie_edge = /Edge\\/(\\d+)/.exec(agent);\nconst ie_upto10 = /MSIE \\d/.exec(agent);\nconst ie_11up = /Trident\\/(?:[7-9]|\\d{2,})\\..*rv:(\\d+)/.exec(agent);\nconst ie = !!(ie_upto10 || ie_11up || ie_edge);\nconst ie_version = ie_upto10 ? document.documentMode : ie_11up ? +ie_11up[1] : ie_edge ? +ie_edge[1] : 0;\nconst gecko = !ie && /gecko\\/(\\d+)/i.test(agent);\ngecko && +(/Firefox\\/(\\d+)/.exec(agent) || [0, 0])[1];\nconst _chrome = !ie && /Chrome\\/(\\d+)/.exec(agent);\nconst chrome = !!_chrome;\nconst chrome_version = _chrome ? +_chrome[1] : 0;\nconst safari = !ie && !!nav && /Apple Computer/.test(nav.vendor);\n// Is true for both iOS and iPadOS for convenience\nconst ios = safari && (/Mobile\\/\\w+/.test(agent) || !!nav && nav.maxTouchPoints > 2);\nconst mac = ios || (nav ? /Mac/.test(nav.platform) : false);\nconst windows = nav ? /Win/.test(nav.platform) : false;\nconst android = /Android \\d/.test(agent);\nconst webkit = !!doc && \"webkitFontSmoothing\" in doc.documentElement.style;\nconst webkit_version = webkit ? +(/\\bAppleWebKit\\/(\\d+)/.exec(navigator.userAgent) || [0, 0])[1] : 0;\n\nfunction windowRect(doc) {\n let vp = doc.defaultView && doc.defaultView.visualViewport;\n if (vp)\n return {\n left: 0, right: vp.width,\n top: 0, bottom: vp.height\n };\n return { left: 0, right: doc.documentElement.clientWidth,\n top: 0, bottom: doc.documentElement.clientHeight };\n}\nfunction getSide(value, side) {\n return typeof value == \"number\" ? value : value[side];\n}\nfunction clientRect(node) {\n let rect = node.getBoundingClientRect();\n // Adjust for elements with style \"transform: scale()\"\n let scaleX = (rect.width / node.offsetWidth) || 1;\n let scaleY = (rect.height / node.offsetHeight) || 1;\n // Make sure scrollbar width isn't included in the rectangle\n return { left: rect.left, right: rect.left + node.clientWidth * scaleX,\n top: rect.top, bottom: rect.top + node.clientHeight * scaleY };\n}\nfunction scrollRectIntoView(view, rect, startDOM) {\n let scrollThreshold = view.someProp(\"scrollThreshold\") || 0, scrollMargin = view.someProp(\"scrollMargin\") || 5;\n let doc = view.dom.ownerDocument;\n for (let parent = startDOM || view.dom;;) {\n if (!parent)\n break;\n if (parent.nodeType != 1) {\n parent = parentNode(parent);\n continue;\n }\n let elt = parent;\n let atTop = elt == doc.body;\n let bounding = atTop ? windowRect(doc) : clientRect(elt);\n let moveX = 0, moveY = 0;\n if (rect.top < bounding.top + getSide(scrollThreshold, \"top\"))\n moveY = -(bounding.top - rect.top + getSide(scrollMargin, \"top\"));\n else if (rect.bottom > bounding.bottom - getSide(scrollThreshold, \"bottom\"))\n moveY = rect.bottom - rect.top > bounding.bottom - bounding.top\n ? rect.top + getSide(scrollMargin, \"top\") - bounding.top\n : rect.bottom - bounding.bottom + getSide(scrollMargin, \"bottom\");\n if (rect.left < bounding.left + getSide(scrollThreshold, \"left\"))\n moveX = -(bounding.left - rect.left + getSide(scrollMargin, \"left\"));\n else if (rect.right > bounding.right - getSide(scrollThreshold, \"right\"))\n moveX = rect.right - bounding.right + getSide(scrollMargin, \"right\");\n if (moveX || moveY) {\n if (atTop) {\n doc.defaultView.scrollBy(moveX, moveY);\n }\n else {\n let startX = elt.scrollLeft, startY = elt.scrollTop;\n if (moveY)\n elt.scrollTop += moveY;\n if (moveX)\n elt.scrollLeft += moveX;\n let dX = elt.scrollLeft - startX, dY = elt.scrollTop - startY;\n rect = { left: rect.left - dX, top: rect.top - dY, right: rect.right - dX, bottom: rect.bottom - dY };\n }\n }\n let pos = atTop ? \"fixed\" : getComputedStyle(parent).position;\n if (/^(fixed|sticky)$/.test(pos))\n break;\n parent = pos == \"absolute\" ? parent.offsetParent : parentNode(parent);\n }\n}\n// Store the scroll position of the editor's parent nodes, along with\n// the top position of an element near the top of the editor, which\n// will be used to make sure the visible viewport remains stable even\n// when the size of the content above changes.\nfunction storeScrollPos(view) {\n let rect = view.dom.getBoundingClientRect(), startY = Math.max(0, rect.top);\n let refDOM, refTop;\n for (let x = (rect.left + rect.right) / 2, y = startY + 1; y < Math.min(innerHeight, rect.bottom); y += 5) {\n let dom = view.root.elementFromPoint(x, y);\n if (!dom || dom == view.dom || !view.dom.contains(dom))\n continue;\n let localRect = dom.getBoundingClientRect();\n if (localRect.top >= startY - 20) {\n refDOM = dom;\n refTop = localRect.top;\n break;\n }\n }\n return { refDOM: refDOM, refTop: refTop, stack: scrollStack(view.dom) };\n}\nfunction scrollStack(dom) {\n let stack = [], doc = dom.ownerDocument;\n for (let cur = dom; cur; cur = parentNode(cur)) {\n stack.push({ dom: cur, top: cur.scrollTop, left: cur.scrollLeft });\n if (dom == doc)\n break;\n }\n return stack;\n}\n// Reset the scroll position of the editor's parent nodes to that what\n// it was before, when storeScrollPos was called.\nfunction resetScrollPos({ refDOM, refTop, stack }) {\n let newRefTop = refDOM ? refDOM.getBoundingClientRect().top : 0;\n restoreScrollStack(stack, newRefTop == 0 ? 0 : newRefTop - refTop);\n}\nfunction restoreScrollStack(stack, dTop) {\n for (let i = 0; i < stack.length; i++) {\n let { dom, top, left } = stack[i];\n if (dom.scrollTop != top + dTop)\n dom.scrollTop = top + dTop;\n if (dom.scrollLeft != left)\n dom.scrollLeft = left;\n }\n}\nlet preventScrollSupported = null;\n// Feature-detects support for .focus({preventScroll: true}), and uses\n// a fallback kludge when not supported.\nfunction focusPreventScroll(dom) {\n if (dom.setActive)\n return dom.setActive(); // in IE\n if (preventScrollSupported)\n return dom.focus(preventScrollSupported);\n let stored = scrollStack(dom);\n dom.focus(preventScrollSupported == null ? {\n get preventScroll() {\n preventScrollSupported = { preventScroll: true };\n return true;\n }\n } : undefined);\n if (!preventScrollSupported) {\n preventScrollSupported = false;\n restoreScrollStack(stored, 0);\n }\n}\nfunction findOffsetInNode(node, coords) {\n let closest, dxClosest = 2e8, coordsClosest, offset = 0;\n let rowBot = coords.top, rowTop = coords.top;\n let firstBelow, coordsBelow;\n for (let child = node.firstChild, childIndex = 0; child; child = child.nextSibling, childIndex++) {\n let rects;\n if (child.nodeType == 1)\n rects = child.getClientRects();\n else if (child.nodeType == 3)\n rects = textRange(child).getClientRects();\n else\n continue;\n for (let i = 0; i < rects.length; i++) {\n let rect = rects[i];\n if (rect.top <= rowBot && rect.bottom >= rowTop) {\n rowBot = Math.max(rect.bottom, rowBot);\n rowTop = Math.min(rect.top, rowTop);\n let dx = rect.left > coords.left ? rect.left - coords.left\n : rect.right < coords.left ? coords.left - rect.right : 0;\n if (dx < dxClosest) {\n closest = child;\n dxClosest = dx;\n coordsClosest = dx && closest.nodeType == 3 ? {\n left: rect.right < coords.left ? rect.right : rect.left,\n top: coords.top\n } : coords;\n if (child.nodeType == 1 && dx)\n offset = childIndex + (coords.left >= (rect.left + rect.right) / 2 ? 1 : 0);\n continue;\n }\n }\n else if (rect.top > coords.top && !firstBelow && rect.left <= coords.left && rect.right >= coords.left) {\n firstBelow = child;\n coordsBelow = { left: Math.max(rect.left, Math.min(rect.right, coords.left)), top: rect.top };\n }\n if (!closest && (coords.left >= rect.right && coords.top >= rect.top ||\n coords.left >= rect.left && coords.top >= rect.bottom))\n offset = childIndex + 1;\n }\n }\n if (!closest && firstBelow) {\n closest = firstBelow;\n coordsClosest = coordsBelow;\n dxClosest = 0;\n }\n if (closest && closest.nodeType == 3)\n return findOffsetInText(closest, coordsClosest);\n if (!closest || (dxClosest && closest.nodeType == 1))\n return { node, offset };\n return findOffsetInNode(closest, coordsClosest);\n}\nfunction findOffsetInText(node, coords) {\n let len = node.nodeValue.length;\n let range = document.createRange(), result;\n for (let i = 0; i < len; i++) {\n range.setEnd(node, i + 1);\n range.setStart(node, i);\n let rect = singleRect(range, 1);\n if (rect.top == rect.bottom)\n continue;\n if (inRect(coords, rect)) {\n result = { node, offset: i + (coords.left >= (rect.left + rect.right) / 2 ? 1 : 0) };\n break;\n }\n }\n range.detach();\n return result || { node, offset: 0 };\n}\nfunction inRect(coords, rect) {\n return coords.left >= rect.left - 1 && coords.left <= rect.right + 1 &&\n coords.top >= rect.top - 1 && coords.top <= rect.bottom + 1;\n}\nfunction targetKludge(dom, coords) {\n let parent = dom.parentNode;\n if (parent && /^li$/i.test(parent.nodeName) && coords.left < dom.getBoundingClientRect().left)\n return parent;\n return dom;\n}\nfunction posFromElement(view, elt, coords) {\n let { node, offset } = findOffsetInNode(elt, coords), bias = -1;\n if (node.nodeType == 1 && !node.firstChild) {\n let rect = node.getBoundingClientRect();\n bias = rect.left != rect.right && coords.left > (rect.left + rect.right) / 2 ? 1 : -1;\n }\n return view.docView.posFromDOM(node, offset, bias);\n}\nfunction posFromCaret(view, node, offset, coords) {\n // Browser (in caretPosition/RangeFromPoint) will agressively\n // normalize towards nearby inline nodes. Since we are interested in\n // positions between block nodes too, we first walk up the hierarchy\n // of nodes to see if there are block nodes that the coordinates\n // fall outside of. If so, we take the position before/after that\n // block. If not, we call `posFromDOM` on the raw node/offset.\n let outsideBlock = -1;\n for (let cur = node, sawBlock = false;;) {\n if (cur == view.dom)\n break;\n let desc = view.docView.nearestDesc(cur, true), rect;\n if (!desc)\n return null;\n if (desc.dom.nodeType == 1 && (desc.node.isBlock && desc.parent || !desc.contentDOM) &&\n // Ignore elements with zero-size bounding rectangles\n ((rect = desc.dom.getBoundingClientRect()).width || rect.height)) {\n if (desc.node.isBlock && desc.parent && !/^T(R|BODY|HEAD|FOOT)$/.test(desc.dom.nodeName)) {\n // Only apply the horizontal test to the innermost block. Vertical for any parent.\n if (!sawBlock && rect.left > coords.left || rect.top > coords.top)\n outsideBlock = desc.posBefore;\n else if (!sawBlock && rect.right < coords.left || rect.bottom < coords.top)\n outsideBlock = desc.posAfter;\n sawBlock = true;\n }\n if (!desc.contentDOM && outsideBlock < 0 && !desc.node.isText) {\n // If we are inside a leaf, return the side of the leaf closer to the coords\n let before = desc.node.isBlock ? coords.top < (rect.top + rect.bottom) / 2\n : coords.left < (rect.left + rect.right) / 2;\n return before ? desc.posBefore : desc.posAfter;\n }\n }\n cur = desc.dom.parentNode;\n }\n return outsideBlock > -1 ? outsideBlock : view.docView.posFromDOM(node, offset, -1);\n}\nfunction elementFromPoint(element, coords, box) {\n let len = element.childNodes.length;\n if (len && box.top < box.bottom) {\n for (let startI = Math.max(0, Math.min(len - 1, Math.floor(len * (coords.top - box.top) / (box.bottom - box.top)) - 2)), i = startI;;) {\n let child = element.childNodes[i];\n if (child.nodeType == 1) {\n let rects = child.getClientRects();\n for (let j = 0; j < rects.length; j++) {\n let rect = rects[j];\n if (inRect(coords, rect))\n return elementFromPoint(child, coords, rect);\n }\n }\n if ((i = (i + 1) % len) == startI)\n break;\n }\n }\n return element;\n}\n// Given an x,y position on the editor, get the position in the document.\nfunction posAtCoords(view, coords) {\n let doc = view.dom.ownerDocument, node, offset = 0;\n let caret = caretFromPoint(doc, coords.left, coords.top);\n if (caret)\n ({ node, offset } = caret);\n let elt = (view.root.elementFromPoint ? view.root : doc)\n .elementFromPoint(coords.left, coords.top);\n let pos;\n if (!elt || !view.dom.contains(elt.nodeType != 1 ? elt.parentNode : elt)) {\n let box = view.dom.getBoundingClientRect();\n if (!inRect(coords, box))\n return null;\n elt = elementFromPoint(view.dom, coords, box);\n if (!elt)\n return null;\n }\n // Safari's caretRangeFromPoint returns nonsense when on a draggable element\n if (safari) {\n for (let p = elt; node && p; p = parentNode(p))\n if (p.draggable)\n node = undefined;\n }\n elt = targetKludge(elt, coords);\n if (node) {\n if (gecko && node.nodeType == 1) {\n // Firefox will sometimes return offsets into <input> nodes, which\n // have no actual children, from caretPositionFromPoint (#953)\n offset = Math.min(offset, node.childNodes.length);\n // It'll also move the returned position before image nodes,\n // even if those are behind it.\n if (offset < node.childNodes.length) {\n let next = node.childNodes[offset], box;\n if (next.nodeName == \"IMG\" && (box = next.getBoundingClientRect()).right <= coords.left &&\n box.bottom > coords.top)\n offset++;\n }\n }\n let prev;\n // When clicking above the right side of an uneditable node, Chrome will report a cursor position after that node.\n if (webkit && offset && node.nodeType == 1 && (prev = node.childNodes[offset - 1]).nodeType == 1 &&\n prev.contentEditable == \"false\" && prev.getBoundingClientRect().top >= coords.top)\n offset--;\n // Suspiciously specific kludge to work around caret*FromPoint\n // never returning a position at the end of the document\n if (node == view.dom && offset == node.childNodes.length - 1 && node.lastChild.nodeType == 1 &&\n coords.top > node.lastChild.getBoundingClientRect().bottom)\n pos = view.state.doc.content.size;\n // Ignore positions directly after a BR, since caret*FromPoint\n // 'round up' positions that would be more accurately placed\n // before the BR node.\n else if (offset == 0 || node.nodeType != 1 || node.childNodes[offset - 1].nodeName != \"BR\")\n pos = posFromCaret(view, node, offset, coords);\n }\n if (pos == null)\n pos = posFromElement(view, elt, coords);\n let desc = view.docView.nearestDesc(elt, true);\n return { pos, inside: desc ? desc.posAtStart - desc.border : -1 };\n}\nfunction nonZero(rect) {\n return rect.top < rect.bottom || rect.left < rect.right;\n}\nfunction singleRect(target, bias) {\n let rects = target.getClientRects();\n if (rects.length) {\n let first = rects[bias < 0 ? 0 : rects.length - 1];\n if (nonZero(first))\n return first;\n }\n return Array.prototype.find.call(rects, nonZero) || target.getBoundingClientRect();\n}\nconst BIDI = /[\\u0590-\\u05f4\\u0600-\\u06ff\\u0700-\\u08ac]/;\n// Given a position in the document model, get a bounding box of the\n// character at that position, relative to the window.\nfunction coordsAtPos(view, pos, side) {\n let { node, offset, atom } = view.docView.domFromPos(pos, side < 0 ? -1 : 1);\n let supportEmptyRange = webkit || gecko;\n if (node.nodeType == 3) {\n // These browsers support querying empty text ranges. Prefer that in\n // bidi context or when at the end of a node.\n if (supportEmptyRange && (BIDI.test(node.nodeValue) || (side < 0 ? !offset : offset == node.nodeValue.length))) {\n let rect = singleRect(textRange(node, offset, offset), side);\n // Firefox returns bad results (the position before the space)\n // when querying a position directly after line-broken\n // whitespace. Detect this situation and and kludge around it\n if (gecko && offset && /\\s/.test(node.nodeValue[offset - 1]) && offset < node.nodeValue.length) {\n let rectBefore = singleRect(textRange(node, offset - 1, offset - 1), -1);\n if (rectBefore.top == rect.top) {\n let rectAfter = singleRect(textRange(node, offset, offset + 1), -1);\n if (rectAfter.top != rect.top)\n return flattenV(rectAfter, rectAfter.left < rectBefore.left);\n }\n }\n return rect;\n }\n else {\n let from = offset, to = offset, takeSide = side < 0 ? 1 : -1;\n if (side < 0 && !offset) {\n to++;\n takeSide = -1;\n }\n else if (side >= 0 && offset == node.nodeValue.length) {\n from--;\n takeSide = 1;\n }\n else if (side < 0) {\n from--;\n }\n else {\n to++;\n }\n return flattenV(singleRect(textRange(node, from, to), takeSide), takeSide < 0);\n }\n }\n let $dom = view.state.doc.resolve(pos - (atom || 0));\n // Return a horizontal line in block context\n if (!$dom.parent.inlineContent) {\n if (atom == null && offset && (side < 0 || offset == nodeSize(node))) {\n let before = node.childNodes[offset - 1];\n if (before.nodeType == 1)\n return flattenH(before.getBoundingClientRect(), false);\n }\n if (atom == null && offset < nodeSize(node)) {\n let after = node.childNodes[offset];\n if (after.nodeType == 1)\n return flattenH(after.getBoundingClientRect(), true);\n }\n return flattenH(node.getBoundingClientRect(), side >= 0);\n }\n // Inline, not in text node (this is not Bidi-safe)\n if (atom == null && offset && (side < 0 || offset == nodeSize(node))) {\n let before = node.childNodes[offset - 1];\n let target = before.nodeType == 3 ? textRange(before, nodeSize(before) - (supportEmptyRange ? 0 : 1))\n // BR nodes tend to only return the rectangle before them.\n // Only use them if they are the last element in their parent\n : before.nodeType == 1 && (before.nodeName != \"BR\" || !before.nextSibling) ? before : null;\n if (target)\n return flattenV(singleRect(target, 1), false);\n }\n if (atom == null && offset < nodeSize(node)) {\n let after = node.childNodes[offset];\n while (after.pmViewDesc && after.pmViewDesc.ignoreForCoords)\n after = after.nextSibling;\n let target = !after ? null : after.nodeType == 3 ? textRange(after, 0, (supportEmptyRange ? 0 : 1))\n : after.nodeType == 1 ? after : null;\n if (target)\n return flattenV(singleRect(target, -1), true);\n }\n // All else failed, just try to get a rectangle for the target node\n return flattenV(singleRect(node.nodeType == 3 ? textRange(node) : node, -side), side >= 0);\n}\nfunction flattenV(rect, left) {\n if (rect.width == 0)\n return rect;\n let x = left ? rect.left : rect.right;\n return { top: rect.top, bottom: rect.bottom, left: x, right: x };\n}\nfunction flattenH(rect, top) {\n if (rect.height == 0)\n return rect;\n let y = top ? rect.top : rect.bottom;\n return { top: y, bottom: y, left: rect.left, right: rect.right };\n}\nfunction withFlushedState(view, state, f) {\n let viewState = view.state, active = view.root.activeElement;\n if (viewState != state)\n view.updateState(state);\n if (active != view.dom)\n view.focus();\n try {\n return f();\n }\n finally {\n if (viewState != state)\n view.updateState(viewState);\n if (active != view.dom && active)\n active.focus();\n }\n}\n// Whether vertical position motion in a given direction\n// from a position would leave a text block.\nfunction endOfTextblockVertical(view, state, dir) {\n let sel = state.selection;\n let $pos = dir == \"up\" ? sel.$from : sel.$to;\n return withFlushedState(view, state, () => {\n let { node: dom } = view.docView.domFromPos($pos.pos, dir == \"up\" ? -1 : 1);\n for (;;) {\n let nearest = view.docView.nearestDesc(dom, true);\n if (!nearest)\n break;\n if (nearest.node.isBlock) {\n dom = nearest.contentDOM || nearest.dom;\n break;\n }\n dom = nearest.dom.parentNode;\n }\n let coords = coordsAtPos(view, $pos.pos, 1);\n for (let child = dom.firstChild; child; child = child.nextSibling) {\n let boxes;\n if (child.nodeType == 1)\n boxes = child.getClientRects();\n else if (child.nodeType == 3)\n boxes = textRange(child, 0, child.nodeValue.length).getClientRects();\n else\n continue;\n for (let i = 0; i < boxes.length; i++) {\n let box = boxes[i];\n if (box.bottom > box.top + 1 &&\n (dir == \"up\" ? coords.top - box.top > (box.bottom - coords.top) * 2\n : box.bottom - coords.bottom > (coords.bottom - box.top) * 2))\n return false;\n }\n }\n return true;\n });\n}\nconst maybeRTL = /[\\u0590-\\u08ac]/;\nfunction endOfTextblockHorizontal(view, state, dir) {\n let { $head } = state.selection;\n if (!$head.parent.isTextblock)\n return false;\n let offset = $head.parentOffset, atStart = !offset, atEnd = offset == $head.parent.content.size;\n let sel = view.domSelection();\n if (!sel)\n return $head.pos == $head.start() || $head.pos == $head.end();\n // If the textblock is all LTR, or the browser doesn't support\n // Selection.modify (Edge), fall back to a primitive approach\n if (!maybeRTL.test($head.parent.textContent) || !sel.modify)\n return dir == \"left\" || dir == \"backward\" ? atStart : atEnd;\n return withFlushedState(view, state, () => {\n // This is a huge hack, but appears to be the best we can\n // currently do: use `Selection.modify` to move the selection by\n // one character, and see if that moves the cursor out of the\n // textblock (or doesn't move it at all, when at the start/end of\n // the document).\n let { focusNode: oldNode, focusOffset: oldOff, anchorNode, anchorOffset } = view.domSelectionRange();\n let oldBidiLevel = sel.caretBidiLevel // Only for Firefox\n ;\n sel.modify(\"move\", dir, \"character\");\n let parentDOM = $head.depth ? view.docView.domAfterPos($head.before()) : view.dom;\n let { focusNode: newNode, focusOffset: newOff } = view.domSelectionRange();\n let result = newNode && !parentDOM.contains(newNode.nodeType == 1 ? newNode : newNode.parentNode) ||\n (oldNode == newNode && oldOff == newOff);\n // Restore the previous selection\n try {\n sel.collapse(anchorNode, anchorOffset);\n if (oldNode && (oldNode != anchorNode || oldOff != anchorOffset) && sel.extend)\n sel.extend(oldNode, oldOff);\n }\n catch (_) { }\n if (oldBidiLevel != null)\n sel.caretBidiLevel = oldBidiLevel;\n return result;\n });\n}\nlet cachedState = null;\nlet cachedDir = null;\nlet cachedResult = false;\nfunction endOfTextblock(view, state, dir) {\n if (cachedState == state && cachedDir == dir)\n return cachedResult;\n cachedState = state;\n cachedDir = dir;\n return cachedResult = dir == \"up\" || dir == \"down\"\n ? endOfTextblockVertical(view, state, dir)\n : endOfTextblockHorizontal(view, state, dir);\n}\n\n// View descriptions are data structures that describe the DOM that is\n// used to represent the editor's content. They are used for:\n//\n// - Incremental redrawing when the document changes\n//\n// - Figuring out what part of the document a given DOM position\n// corresponds to\n//\n// - Wiring in custom implementations of the editing interface for a\n// given node\n//\n// They form a doubly-linked mutable tree, starting at `view.docView`.\nconst NOT_DIRTY = 0, CHILD_DIRTY = 1, CONTENT_DIRTY = 2, NODE_DIRTY = 3;\n// Superclass for the various kinds of descriptions. Defines their\n// basic structure and shared methods.\nclass ViewDesc {\n constructor(parent, children, dom, \n // This is the node that holds the child views. It may be null for\n // descs that don't have children.\n contentDOM) {\n this.parent = parent;\n this.children = children;\n this.dom = dom;\n this.contentDOM = contentDOM;\n this.dirty = NOT_DIRTY;\n // An expando property on the DOM node provides a link back to its\n // description.\n dom.pmViewDesc = this;\n }\n // Used to check whether a given description corresponds to a\n // widget/mark/node.\n matchesWidget(widget) { return false; }\n matchesMark(mark) { return false; }\n matchesNode(node, outerDeco, innerDeco) { return false; }\n matchesHack(nodeName) { return false; }\n // When parsing in-editor content (in domchange.js), we allow\n // descriptions to determine the parse rules that should be used to\n // parse them.\n parseRule() { return null; }\n // Used by the editor's event handler to ignore events that come\n // from certain descs.\n stopEvent(event) { return false; }\n // The size of the content represented by this desc.\n get size() {\n let size = 0;\n for (let i = 0; i < this.children.length; i++)\n size += this.children[i].size;\n return size;\n }\n // For block nodes, this represents the space taken up by their\n // start/end tokens.\n get border() { return 0; }\n destroy() {\n this.parent = undefined;\n if (this.dom.pmViewDesc == this)\n this.dom.pmViewDesc = undefined;\n for (let i = 0; i < this.children.length; i++)\n this.children[i].destroy();\n }\n posBeforeChild(child) {\n for (let i = 0, pos = this.posAtStart;; i++) {\n let cur = this.children[i];\n if (cur == child)\n return pos;\n pos += cur.size;\n }\n }\n get posBefore() {\n return this.parent.posBeforeChild(this);\n }\n get posAtStart() {\n return this.parent ? this.parent.posBeforeChild(this) + this.border : 0;\n }\n get posAfter() {\n return this.posBefore + this.size;\n }\n get posAtEnd() {\n return this.posAtStart + this.size - 2 * this.border;\n }\n localPosFromDOM(dom, offset, bias) {\n // If the DOM position is in the content, use the child desc after\n // it to figure out a position.\n if (this.contentDOM && this.contentDOM.contains(dom.nodeType == 1 ? dom : dom.parentNode)) {\n if (bias < 0) {\n let domBefore, desc;\n if (dom == this.contentDOM) {\n domBefore = dom.childNodes[offset - 1];\n }\n else {\n while (dom.parentNode != this.contentDOM)\n dom = dom.parentNode;\n domBefore = dom.previousSibling;\n }\n while (domBefore && !((desc = domBefore.pmViewDesc) && desc.parent == this))\n domBefore = domBefore.previousSibling;\n return domBefore ? this.posBeforeChild(desc) + desc.size : this.posAtStart;\n }\n else {\n let domAfter, desc;\n if (dom == this.contentDOM) {\n domAfter = dom.childNodes[offset];\n }\n else {\n while (dom.parentNode != this.contentDOM)\n dom = dom.parentNode;\n domAfter = dom.nextSibling;\n }\n while (domAfter && !((desc = domAfter.pmViewDesc) && desc.parent == this))\n domAfter = domAfter.nextSibling;\n return domAfter ? this.posBeforeChild(desc) : this.posAtEnd;\n }\n }\n // Otherwise, use various heuristics, falling back on the bias\n // parameter, to determine whether to return the position at the\n // start or at the end of this view desc.\n let atEnd;\n if (dom == this.dom && this.contentDOM) {\n atEnd = offset > domIndex(this.contentDOM);\n }\n else if (this.contentDOM && this.contentDOM != this.dom && this.dom.contains(this.contentDOM)) {\n atEnd = dom.compareDocumentPosition(this.contentDOM) & 2;\n }\n else if (this.dom.firstChild) {\n if (offset == 0)\n for (let search = dom;; search = search.parentNode) {\n if (search == this.dom) {\n atEnd = false;\n break;\n }\n if (search.previousSibling)\n break;\n }\n if (atEnd == null && offset == dom.childNodes.length)\n for (let search = dom;; search = search.parentNode) {\n if (search == this.dom) {\n atEnd = true;\n break;\n }\n if (search.nextSibling)\n break;\n }\n }\n return (atEnd == null ? bias > 0 : atEnd) ? this.posAtEnd : this.posAtStart;\n }\n nearestDesc(dom, onlyNodes = false) {\n for (let first = true, cur = dom; cur; cur = cur.parentNode) {\n let desc = this.getDesc(cur), nodeDOM;\n if (desc && (!onlyNodes || desc.node)) {\n // If dom is outside of this desc's nodeDOM, don't count it.\n if (first && (nodeDOM = desc.nodeDOM) &&\n !(nodeDOM.nodeType == 1 ? nodeDOM.contains(dom.nodeType == 1 ? dom : dom.parentNode) : nodeDOM == dom))\n first = false;\n else\n return desc;\n }\n }\n }\n getDesc(dom) {\n let desc = dom.pmViewDesc;\n for (let cur = desc; cur; cur = cur.parent)\n if (cur == this)\n return desc;\n }\n posFromDOM(dom, offset, bias) {\n for (let scan = dom; scan; scan = scan.parentNode) {\n let desc = this.getDesc(scan);\n if (desc)\n return desc.localPosFromDOM(dom, offset, bias);\n }\n return -1;\n }\n // Find the desc for the node after the given pos, if any. (When a\n // parent node overrode rendering, there might not be one.)\n descAt(pos) {\n for (let i = 0, offset = 0; i < this.children.length; i++) {\n let child = this.children[i], end = offset + child.size;\n if (offset == pos && end != offset) {\n while (!child.border && child.children.length) {\n for (let i = 0; i < child.children.length; i++) {\n let inner = child.children[i];\n if (inner.size) {\n child = inner;\n break;\n }\n }\n }\n return child;\n }\n if (pos < end)\n return child.descAt(pos - offset - child.border);\n offset = end;\n }\n }\n domFromPos(pos, side) {\n if (!this.contentDOM)\n return { node: this.dom, offset: 0, atom: pos + 1 };\n // First find the position in the child array\n let i = 0, offset = 0;\n for (let curPos = 0; i < this.children.length; i++) {\n let child = this.children[i], end = curPos + child.size;\n if (end > pos || child instanceof TrailingHackViewDesc) {\n offset = pos - curPos;\n break;\n }\n curPos = end;\n }\n // If this points into the middle of a child, call through\n if (offset)\n return this.children[i].domFromPos(offset - this.children[i].border, side);\n // Go back if there were any zero-length widgets with side >= 0 before this point\n for (let prev; i && !(prev = this.children[i - 1]).size && prev instanceof WidgetViewDesc && prev.side >= 0; i--) { }\n // Scan towards the first useable node\n if (side <= 0) {\n let prev, enter = true;\n for (;; i--, enter = false) {\n prev = i ? this.children[i - 1] : null;\n if (!prev || prev.dom.parentNode == this.contentDOM)\n break;\n }\n if (prev && side && enter && !prev.border && !prev.domAtom)\n return prev.domFromPos(prev.size, side);\n return { node: this.contentDOM, offset: prev ? domIndex(prev.dom) + 1 : 0 };\n }\n else {\n let next, enter = true;\n for (;; i++, enter = false) {\n next = i < this.children.length ? this.children[i] : null;\n if (!next || next.dom.parentNode == this.contentDOM)\n break;\n }\n if (next && enter && !next.border && !next.domAtom)\n return next.domFromPos(0, side);\n return { node: this.contentDOM, offset: next ? domIndex(next.dom) : this.contentDOM.childNodes.length };\n }\n }\n // Used to find a DOM range in a single parent for a given changed\n // range.\n parseRange(from, to, base = 0) {\n if (this.children.length == 0)\n return { node: this.contentDOM, from, to, fromOffset: 0, toOffset: this.contentDOM.childNodes.length };\n let fromOffset = -1, toOffset = -1;\n for (let offset = base, i = 0;; i++) {\n let child = this.children[i], end = offset + child.size;\n if (fromOffset == -1 && from <= end) {\n let childBase = offset + child.border;\n // FIXME maybe descend mark views to parse a narrower range?\n if (from >= childBase && to <= end - child.border && child.node &&\n child.contentDOM && this.contentDOM.contains(child.contentDOM))\n return child.parseRange(from, to, childBase);\n from = offset;\n for (let j = i; j > 0; j--) {\n let prev = this.children[j - 1];\n if (prev.size && prev.dom.parentNode == this.contentDOM && !prev.emptyChildAt(1)) {\n fromOffset = domIndex(prev.dom) + 1;\n break;\n }\n from -= prev.size;\n }\n if (fromOffset == -1)\n fromOffset = 0;\n }\n if (fromOffset > -1 && (end > to || i == this.children.length - 1)) {\n to = end;\n for (let j = i + 1; j < this.children.length; j++) {\n let next = this.children[j];\n if (next.size && next.dom.parentNode == this.contentDOM && !next.emptyChildAt(-1)) {\n toOffset = domIndex(next.dom);\n break;\n }\n to += next.size;\n }\n if (toOffset == -1)\n toOffset = this.contentDOM.childNodes.length;\n break;\n }\n offset = end;\n }\n return { node: this.contentDOM, from, to, fromOffset, toOffset };\n }\n emptyChildAt(side) {\n if (this.border || !this.contentDOM || !this.children.length)\n return false;\n let child = this.children[side < 0 ? 0 : this.children.length - 1];\n return child.size == 0 || child.emptyChildAt(side);\n }\n domAfterPos(pos) {\n let { node, offset } = this.domFromPos(pos, 0);\n if (node.nodeType != 1 || offset == node.childNodes.length)\n throw new RangeError(\"No node after pos \" + pos);\n return node.childNodes[offset];\n }\n // View descs are responsible for setting any selection that falls\n // entirely inside of them, so that custom implementations can do\n // custom things with the selection. Note that this falls apart when\n // a selection starts in such a node and ends in another, in which\n // case we just use whatever domFromPos produces as a best effort.\n setSelection(anchor, head, view, force = false) {\n // If the selection falls entirely in a child, give it to that child\n let from = Math.min(anchor, head), to = Math.max(anchor, head);\n for (let i = 0, offset = 0; i < this.children.length; i++) {\n let child = this.children[i], end = offset + child.size;\n if (from > offset && to < end)\n return child.setSelection(anchor - offset - child.border, head - offset - child.border, view, force);\n offset = end;\n }\n let anchorDOM = this.domFromPos(anchor, anchor ? -1 : 1);\n let headDOM = head == anchor ? anchorDOM : this.domFromPos(head, head ? -1 : 1);\n let domSel = view.root.getSelection();\n let selRange = view.domSelectionRange();\n let brKludge = false;\n // On Firefox, using Selection.collapse to put the cursor after a\n // BR node for some reason doesn't always work (#1073). On Safari,\n // the cursor sometimes inexplicable visually lags behind its\n // reported position in such situations (#1092).\n if ((gecko || safari) && anchor == head) {\n let { node, offset } = anchorDOM;\n if (node.nodeType == 3) {\n brKludge = !!(offset && node.nodeValue[offset - 1] == \"\\n\");\n // Issue #1128\n if (brKludge && offset == node.nodeValue.length) {\n for (let scan = node, after; scan; scan = scan.parentNode) {\n if (after = scan.nextSibling) {\n if (after.nodeName == \"BR\")\n anchorDOM = headDOM = { node: after.parentNode, offset: domIndex(after) + 1 };\n break;\n }\n let desc = scan.pmViewDesc;\n if (desc && desc.node && desc.node.isBlock)\n break;\n }\n }\n }\n else {\n let prev = node.childNodes[offset - 1];\n brKludge = prev && (prev.nodeName == \"BR\" || prev.contentEditable == \"false\");\n }\n }\n // Firefox can act strangely when the selection is in front of an\n // uneditable node. See #1163 and https://bugzilla.mozilla.org/show_bug.cgi?id=1709536\n if (gecko && selRange.focusNode && selRange.focusNode != headDOM.node && selRange.focusNode.nodeType == 1) {\n let after = selRange.focusNode.childNodes[selRange.focusOffset];\n if (after && after.contentEditable == \"false\")\n force = true;\n }\n if (!(force || brKludge && safari) &&\n isEquivalentPosition(anchorDOM.node, anchorDOM.offset, selRange.anchorNode, selRange.anchorOffset) &&\n isEquivalentPosition(headDOM.node, headDOM.offset, selRange.focusNode, selRange.focusOffset))\n return;\n // Selection.extend can be used to create an 'inverted' selection\n // (one where the focus is before the anchor), but not all\n // browsers support it yet.\n let domSelExtended = false;\n if ((domSel.extend || anchor == head) && !(brKludge && gecko)) {\n domSel.collapse(anchorDOM.node, anchorDOM.offset);\n try {\n if (anchor != head)\n domSel.extend(headDOM.node, headDOM.offset);\n domSelExtended = true;\n }\n catch (_) {\n // In some cases with Chrome the selection is empty after calling\n // collapse, even when it should be valid. This appears to be a bug, but\n // it is difficult to isolate. If this happens fallback to the old path\n // without using extend.\n // Similarly, this could crash on Safari if the editor is hidden, and\n // there was no selection.\n }\n }\n if (!domSelExtended) {\n if (anchor > head) {\n let tmp = anchorDOM;\n anchorDOM = headDOM;\n headDOM = tmp;\n }\n let range = document.createRange();\n range.setEnd(headDOM.node, headDOM.offset);\n range.setStart(anchorDOM.node, anchorDOM.offset);\n domSel.removeAllRanges();\n domSel.addRange(range);\n }\n }\n ignoreMutation(mutation) {\n return !this.contentDOM && mutation.type != \"selection\";\n }\n get contentLost() {\n return this.contentDOM && this.contentDOM != this.dom && !this.dom.contains(this.contentDOM);\n }\n // Remove a subtree of the element tree that has been touched\n // by a DOM change, so that the next update will redraw it.\n markDirty(from, to) {\n for (let offset = 0, i = 0; i < this.children.length; i++) {\n let child = this.children[i], end = offset + child.size;\n if (offset == end ? from <= end && to >= offset : from < end && to > offset) {\n let startInside = offset + child.border, endInside = end - child.border;\n if (from >= startInside && to <= endInside) {\n this.dirty = from == offset || to == end ? CONTENT_DIRTY : CHILD_DIRTY;\n if (from == startInside && to == endInside &&\n (child.contentLost || child.dom.parentNode != this.contentDOM))\n child.dirty = NODE_DIRTY;\n else\n child.markDirty(from - startInside, to - startInside);\n return;\n }\n else {\n child.dirty = child.dom == child.contentDOM && child.dom.parentNode == this.contentDOM && !child.children.length\n ? CONTENT_DIRTY : NODE_DIRTY;\n }\n }\n offset = end;\n }\n this.dirty = CONTENT_DIRTY;\n }\n markParentsDirty() {\n let level = 1;\n for (let node = this.parent; node; node = node.parent, level++) {\n let dirty = level == 1 ? CONTENT_DIRTY : CHILD_DIRTY;\n if (node.dirty < dirty)\n node.dirty = dirty;\n }\n }\n get domAtom() { return false; }\n get ignoreForCoords() { return false; }\n get ignoreForSelection() { return false; }\n isText(text) { return false; }\n}\n// A widget desc represents a widget decoration, which is a DOM node\n// drawn between the document nodes.\nclass WidgetViewDesc extends ViewDesc {\n constructor(parent, widget, view, pos) {\n let self, dom = widget.type.toDOM;\n if (typeof dom == \"function\")\n dom = dom(view, () => {\n if (!self)\n return pos;\n if (self.parent)\n return self.parent.posBeforeChild(self);\n });\n if (!widget.type.spec.raw) {\n if (dom.nodeType != 1) {\n let wrap = document.createElement(\"span\");\n wrap.appendChild(dom);\n dom = wrap;\n }\n dom.contentEditable = \"false\";\n dom.classList.add(\"ProseMirror-widget\");\n }\n super(parent, [], dom, null);\n this.widget = widget;\n this.widget = widget;\n self = this;\n }\n matchesWidget(widget) {\n return this.dirty == NOT_DIRTY && widget.type.eq(this.widget.type);\n }\n parseRule() { return { ignore: true }; }\n stopEvent(event) {\n let stop = this.widget.spec.stopEvent;\n return stop ? stop(event) : false;\n }\n ignoreMutation(mutation) {\n return mutation.type != \"selection\" || this.widget.spec.ignoreSelection;\n }\n destroy() {\n this.widget.type.destroy(this.dom);\n super.destroy();\n }\n get domAtom() { return true; }\n get ignoreForSelection() { return !!this.widget.type.spec.relaxedSide; }\n get side() { return this.widget.type.side; }\n}\nclass CompositionViewDesc extends ViewDesc {\n constructor(parent, dom, textDOM, text) {\n super(parent, [], dom, null);\n this.textDOM = textDOM;\n this.text = text;\n }\n get size() { return this.text.length; }\n localPosFromDOM(dom, offset) {\n if (dom != this.textDOM)\n return this.posAtStart + (offset ? this.size : 0);\n return this.posAtStart + offset;\n }\n domFromPos(pos) {\n return { node: this.textDOM, offset: pos };\n }\n ignoreMutation(mut) {\n return mut.type === 'characterData' && mut.target.nodeValue == mut.oldValue;\n }\n}\n// A mark desc represents a mark. May have multiple children,\n// depending on how the mark is split. Note that marks are drawn using\n// a fixed nesting order, for simplicity and predictability, so in\n// some cases they will be split more often than would appear\n// necessary.\nclass MarkViewDesc extends ViewDesc {\n constructor(parent, mark, dom, contentDOM, spec) {\n super(parent, [], dom, contentDOM);\n this.mark = mark;\n this.spec = spec;\n }\n static create(parent, mark, inline, view) {\n let custom = view.nodeViews[mark.type.name];\n let spec = custom && custom(mark, view, inline);\n if (!spec || !spec.dom)\n spec = prosemirror_model__WEBPACK_IMPORTED_MODULE_0__.DOMSerializer.renderSpec(document, mark.type.spec.toDOM(mark, inline), null, mark.attrs);\n return new MarkViewDesc(parent, mark, spec.dom, spec.contentDOM || spec.dom, spec);\n }\n parseRule() {\n if ((this.dirty & NODE_DIRTY) || this.mark.type.spec.reparseInView)\n return null;\n return { mark: this.mark.type.name, attrs: this.mark.attrs, contentElement: this.contentDOM };\n }\n matchesMark(mark) { return this.dirty != NODE_DIRTY && this.mark.eq(mark); }\n markDirty(from, to) {\n super.markDirty(from, to);\n // Move dirty info to nearest node view\n if (this.dirty != NOT_DIRTY) {\n let parent = this.parent;\n while (!parent.node)\n parent = parent.parent;\n if (parent.dirty < this.dirty)\n parent.dirty = this.dirty;\n this.dirty = NOT_DIRTY;\n }\n }\n slice(from, to, view) {\n let copy = MarkViewDesc.create(this.parent, this.mark, true, view);\n let nodes = this.children, size = this.size;\n if (to < size)\n nodes = replaceNodes(nodes, to, size, view);\n if (from > 0)\n nodes = replaceNodes(nodes, 0, from, view);\n for (let i = 0; i < nodes.length; i++)\n nodes[i].parent = copy;\n copy.children = nodes;\n return copy;\n }\n ignoreMutation(mutation) {\n return this.spec.ignoreMutation ? this.spec.ignoreMutation(mutation) : super.ignoreMutation(mutation);\n }\n destroy() {\n if (this.spec.destroy)\n this.spec.destroy();\n super.destroy();\n }\n}\n// Node view descs are the main, most common type of view desc, and\n// correspond to an actual node in the document. Unlike mark descs,\n// they populate their child array themselves.\nclass NodeViewDesc extends ViewDesc {\n constructor(parent, node, outerDeco, innerDeco, dom, contentDOM, nodeDOM, view, pos) {\n super(parent, [], dom, contentDOM);\n this.node = node;\n this.outerDeco = outerDeco;\n this.innerDeco = innerDeco;\n this.nodeDOM = nodeDOM;\n }\n // By default, a node is rendered using the `toDOM` method from the\n // node type spec. But client code can use the `nodeViews` spec to\n // supply a custom node view, which can influence various aspects of\n // the way the node works.\n //\n // (Using subclassing for this was intentionally decided against,\n // since it'd require exposing a whole slew of finicky\n // implementation details to the user code that they probably will\n // never need.)\n static create(parent, node, outerDeco, innerDeco, view, pos) {\n let custom = view.nodeViews[node.type.name], descObj;\n let spec = custom && custom(node, view, () => {\n // (This is a function that allows the custom view to find its\n // own position)\n if (!descObj)\n return pos;\n if (descObj.parent)\n return descObj.parent.posBeforeChild(descObj);\n }, outerDeco, innerDeco);\n let dom = spec && spec.dom, contentDOM = spec && spec.contentDOM;\n if (node.isText) {\n if (!dom)\n dom = document.createTextNode(node.text);\n else if (dom.nodeType != 3)\n throw new RangeError(\"Text must be rendered as a DOM text node\");\n }\n else if (!dom) {\n let spec = prosemirror_model__WEBPACK_IMPORTED_MODULE_0__.DOMSerializer.renderSpec(document, node.type.spec.toDOM(node), null, node.attrs);\n ({ dom, contentDOM } = spec);\n }\n if (!contentDOM && !node.isText && dom.nodeName != \"BR\") { // Chrome gets confused by <br contenteditable=false>\n if (!dom.hasAttribute(\"contenteditable\"))\n dom.contentEditable = \"false\";\n if (node.type.spec.draggable)\n dom.draggable = true;\n }\n let nodeDOM = dom;\n dom = applyOuterDeco(dom, outerDeco, node);\n if (spec)\n return descObj = new CustomNodeViewDesc(parent, node, outerDeco, innerDeco, dom, contentDOM || null, nodeDOM, spec, view, pos + 1);\n else if (node.isText)\n return new TextViewDesc(parent, node, outerDeco, innerDeco, dom, nodeDOM, view);\n else\n return new NodeViewDesc(parent, node, outerDeco, innerDeco, dom, contentDOM || null, nodeDOM, view, pos + 1);\n }\n parseRule() {\n // Experimental kludge to allow opt-in re-parsing of nodes\n if (this.node.type.spec.reparseInView)\n return null;\n // FIXME the assumption that this can always return the current\n // attrs means that if the user somehow manages to change the\n // attrs in the dom, that won't be picked up. Not entirely sure\n // whether this is a problem\n let rule = { node: this.node.type.name, attrs: this.node.attrs };\n if (this.node.type.whitespace == \"pre\")\n rule.preserveWhitespace = \"full\";\n if (!this.contentDOM) {\n rule.getContent = () => this.node.content;\n }\n else if (!this.contentLost) {\n rule.contentElement = this.contentDOM;\n }\n else {\n // Chrome likes to randomly recreate parent nodes when\n // backspacing things. When that happens, this tries to find the\n // new parent.\n for (let i = this.children.length - 1; i >= 0; i--) {\n let child = this.children[i];\n if (this.dom.contains(child.dom.parentNode)) {\n rule.contentElement = child.dom.parentNode;\n break;\n }\n }\n if (!rule.contentElement)\n rule.getContent = () => prosemirror_model__WEBPACK_IMPORTED_MODULE_0__.Fragment.empty;\n }\n return rule;\n }\n matchesNode(node, outerDeco, innerDeco) {\n return this.dirty == NOT_DIRTY && node.eq(this.node) &&\n sameOuterDeco(outerDeco, this.outerDeco) && innerDeco.eq(this.innerDeco);\n }\n get size() { return this.node.nodeSize; }\n get border() { return this.node.isLeaf ? 0 : 1; }\n // Syncs `this.children` to match `this.node.content` and the local\n // decorations, possibly introducing nesting for marks. Then, in a\n // separate step, syncs the DOM inside `this.contentDOM` to\n // `this.children`.\n updateChildren(view, pos) {\n let inline = this.node.inlineContent, off = pos;\n let composition = view.composing ? this.localCompositionInfo(view, pos) : null;\n let localComposition = composition && composition.pos > -1 ? composition : null;\n let compositionInChild = composition && composition.pos < 0;\n let updater = new ViewTreeUpdater(this, localComposition && localComposition.node, view);\n iterDeco(this.node, this.innerDeco, (widget, i, insideNode) => {\n if (widget.spec.marks)\n updater.syncToMarks(widget.spec.marks, inline, view, i);\n else if (widget.type.side >= 0 && !insideNode)\n updater.syncToMarks(i == this.node.childCount ? prosemirror_model__WEBPACK_IMPORTED_MODULE_0__.Mark.none : this.node.child(i).marks, inline, view, i);\n // If the next node is a desc matching this widget, reuse it,\n // otherwise insert the widget as a new view desc.\n updater.placeWidget(widget, view, off);\n }, (child, outerDeco, innerDeco, i) => {\n // Make sure the wrapping mark descs match the node's marks.\n updater.syncToMarks(child.marks, inline, view, i);\n // Try several strategies for drawing this node\n let compIndex;\n if (updater.findNodeMatch(child, outerDeco, innerDeco, i)) ;\n else if (compositionInChild && view.state.selection.from > off &&\n view.state.selection.to < off + child.nodeSize &&\n (compIndex = updater.findIndexWithChild(composition.node)) > -1 &&\n updater.updateNodeAt(child, outerDeco, innerDeco, compIndex, view)) ;\n else if (updater.updateNextNode(child, outerDeco, innerDeco, view, i, off)) ;\n else {\n // Add it as a new view\n updater.addNode(child, outerDeco, innerDeco, view, off);\n }\n off += child.nodeSize;\n });\n // Drop all remaining descs after the current position.\n updater.syncToMarks([], inline, view, 0);\n if (this.node.isTextblock)\n updater.addTextblockHacks();\n updater.destroyRest();\n // Sync the DOM if anything changed\n if (updater.changed || this.dirty == CONTENT_DIRTY) {\n // May have to protect focused DOM from being changed if a composition is active\n if (localComposition)\n this.protectLocalComposition(view, localComposition);\n renderDescs(this.contentDOM, this.children, view);\n if (ios)\n iosHacks(this.dom);\n }\n }\n localCompositionInfo(view, pos) {\n // Only do something if both the selection and a focused text node\n // are inside of this node\n let { from, to } = view.state.selection;\n if (!(view.state.selection instanceof prosemirror_state__WEBPACK_IMPORTED_MODULE_1__.TextSelection) || from < pos || to > pos + this.node.content.size)\n return null;\n let textNode = view.input.compositionNode;\n if (!textNode || !this.dom.contains(textNode.parentNode))\n return null;\n if (this.node.inlineContent) {\n // Find the text in the focused node in the node, stop if it's not\n // there (may have been modified through other means, in which\n // case it should overwritten)\n let text = textNode.nodeValue;\n let textPos = findTextInFragment(this.node.content, text, from - pos, to - pos);\n return textPos < 0 ? null : { node: textNode, pos: textPos, text };\n }\n else {\n return { node: textNode, pos: -1, text: \"\" };\n }\n }\n protectLocalComposition(view, { node, pos, text }) {\n // The node is already part of a local view desc, leave it there\n if (this.getDesc(node))\n return;\n // Create a composition view for the orphaned nodes\n let topNode = node;\n for (;; topNode = topNode.parentNode) {\n if (topNode.parentNode == this.contentDOM)\n break;\n while (topNode.previousSibling)\n topNode.parentNode.removeChild(topNode.previousSibling);\n while (topNode.nextSibling)\n topNode.parentNode.removeChild(topNode.nextSibling);\n if (topNode.pmViewDesc)\n topNode.pmViewDesc = undefined;\n }\n let desc = new CompositionViewDesc(this, topNode, node, text);\n view.input.compositionNodes.push(desc);\n // Patch up this.children to contain the composition view\n this.children = replaceNodes(this.children, pos, pos + text.length, view, desc);\n }\n // If this desc must be updated to match the given node decoration,\n // do so and return true.\n update(node, outerDeco, innerDeco, view) {\n if (this.dirty == NODE_DIRTY ||\n !node.sameMarkup(this.node))\n return false;\n this.updateInner(node, outerDeco, innerDeco, view);\n return true;\n }\n updateInner(node, outerDeco, innerDeco, view) {\n this.updateOuterDeco(outerDeco);\n this.node = node;\n this.innerDeco = innerDeco;\n if (this.contentDOM)\n this.updateChildren(view, this.posAtStart);\n this.dirty = NOT_DIRTY;\n }\n updateOuterDeco(outerDeco) {\n if (sameOuterDeco(outerDeco, this.outerDeco))\n return;\n let needsWrap = this.nodeDOM.nodeType != 1;\n let oldDOM = this.dom;\n this.dom = patchOuterDeco(this.dom, this.nodeDOM, computeOuterDeco(this.outerDeco, this.node, needsWrap), computeOuterDeco(outerDeco, this.node, needsWrap));\n if (this.dom != oldDOM) {\n oldDOM.pmViewDesc = undefined;\n this.dom.pmViewDesc = this;\n }\n this.outerDeco = outerDeco;\n }\n // Mark this node as being the selected node.\n selectNode() {\n if (this.nodeDOM.nodeType == 1) {\n this.nodeDOM.classList.add(\"ProseMirror-selectednode\");\n if (this.contentDOM || !this.node.type.spec.draggable)\n this.nodeDOM.draggable = true;\n }\n }\n // Remove selected node marking from this node.\n deselectNode() {\n if (this.nodeDOM.nodeType == 1) {\n this.nodeDOM.classList.remove(\"ProseMirror-selectednode\");\n if (this.contentDOM || !this.node.type.spec.draggable)\n this.nodeDOM.removeAttribute(\"draggable\");\n }\n }\n get domAtom() { return this.node.isAtom; }\n}\n// Create a view desc for the top-level document node, to be exported\n// and used by the view class.\nfunction docViewDesc(doc, outerDeco, innerDeco, dom, view) {\n applyOuterDeco(dom, outerDeco, doc);\n let docView = new NodeViewDesc(undefined, doc, outerDeco, innerDeco, dom, dom, dom, view, 0);\n if (docView.contentDOM)\n docView.updateChildren(view, 0);\n return docView;\n}\nclass TextViewDesc extends NodeViewDesc {\n constructor(parent, node, outerDeco, innerDeco, dom, nodeDOM, view) {\n super(parent, node, outerDeco, innerDeco, dom, null, nodeDOM, view, 0);\n }\n parseRule() {\n let skip = this.nodeDOM.parentNode;\n while (skip && skip != this.dom && !skip.pmIsDeco)\n skip = skip.parentNode;\n return { skip: (skip || true) };\n }\n update(node, outerDeco, innerDeco, view) {\n if (this.dirty == NODE_DIRTY || (this.dirty != NOT_DIRTY && !this.inParent()) ||\n !node.sameMarkup(this.node))\n return false;\n this.updateOuterDeco(outerDeco);\n if ((this.dirty != NOT_DIRTY || node.text != this.node.text) && node.text != this.nodeDOM.nodeValue) {\n this.nodeDOM.nodeValue = node.text;\n if (view.trackWrites == this.nodeDOM)\n view.trackWrites = null;\n }\n this.node = node;\n this.dirty = NOT_DIRTY;\n return true;\n }\n inParent() {\n let parentDOM = this.parent.contentDOM;\n for (let n = this.nodeDOM; n; n = n.parentNode)\n if (n == parentDOM)\n return true;\n return false;\n }\n domFromPos(pos) {\n return { node: this.nodeDOM, offset: pos };\n }\n localPosFromDOM(dom, offset, bias) {\n if (dom == this.nodeDOM)\n return this.posAtStart + Math.min(offset, this.node.text.length);\n return super.localPosFromDOM(dom, offset, bias);\n }\n ignoreMutation(mutation) {\n return mutation.type != \"characterData\" && mutation.type != \"selection\";\n }\n slice(from, to, view) {\n let node = this.node.cut(from, to), dom = document.createTextNode(node.text);\n return new TextViewDesc(this.parent, node, this.outerDeco, this.innerDeco, dom, dom, view);\n }\n markDirty(from, to) {\n super.markDirty(from, to);\n if (this.dom != this.nodeDOM && (from == 0 || to == this.nodeDOM.nodeValue.length))\n this.dirty = NODE_DIRTY;\n }\n get domAtom() { return false; }\n isText(text) { return this.node.text == text; }\n}\n// A dummy desc used to tag trailing BR or IMG nodes created to work\n// around contentEditable terribleness.\nclass TrailingHackViewDesc extends ViewDesc {\n parseRule() { return { ignore: true }; }\n matchesHack(nodeName) { return this.dirty == NOT_DIRTY && this.dom.nodeName == nodeName; }\n get domAtom() { return true; }\n get ignoreForCoords() { return this.dom.nodeName == \"IMG\"; }\n}\n// A separate subclass is used for customized node views, so that the\n// extra checks only have to be made for nodes that are actually\n// customized.\nclass CustomNodeViewDesc extends NodeViewDesc {\n constructor(parent, node, outerDeco, innerDeco, dom, contentDOM, nodeDOM, spec, view, pos) {\n super(parent, node, outerDeco, innerDeco, dom, contentDOM, nodeDOM, view, pos);\n this.spec = spec;\n }\n // A custom `update` method gets to decide whether the update goes\n // through. If it does, and there's a `contentDOM` node, our logic\n // updates the children.\n update(node, outerDeco, innerDeco, view) {\n if (this.dirty == NODE_DIRTY)\n return false;\n if (this.spec.update && (this.node.type == node.type || this.spec.multiType)) {\n let result = this.spec.update(node, outerDeco, innerDeco);\n if (result)\n this.updateInner(node, outerDeco, innerDeco, view);\n return result;\n }\n else if (!this.contentDOM && !node.isLeaf) {\n return false;\n }\n else {\n return super.update(node, outerDeco, innerDeco, view);\n }\n }\n selectNode() {\n this.spec.selectNode ? this.spec.selectNode() : super.selectNode();\n }\n deselectNode() {\n this.spec.deselectNode ? this.spec.deselectNode() : super.deselectNode();\n }\n setSelection(anchor, head, view, force) {\n this.spec.setSelection ? this.spec.setSelection(anchor, head, view.root)\n : super.setSelection(anchor, head, view, force);\n }\n destroy() {\n if (this.spec.destroy)\n this.spec.destroy();\n super.destroy();\n }\n stopEvent(event) {\n return this.spec.stopEvent ? this.spec.stopEvent(event) : false;\n }\n ignoreMutation(mutation) {\n return this.spec.ignoreMutation ? this.spec.ignoreMutation(mutation) : super.ignoreMutation(mutation);\n }\n}\n// Sync the content of the given DOM node with the nodes associated\n// with the given array of view descs, recursing into mark descs\n// because this should sync the subtree for a whole node at a time.\nfunction renderDescs(parentDOM, descs, view) {\n let dom = parentDOM.firstChild, written = false;\n for (let i = 0; i < descs.length; i++) {\n let desc = descs[i], childDOM = desc.dom;\n if (childDOM.parentNode == parentDOM) {\n while (childDOM != dom) {\n dom = rm(dom);\n written = true;\n }\n dom = dom.nextSibling;\n }\n else {\n written = true;\n parentDOM.insertBefore(childDOM, dom);\n }\n if (desc instanceof MarkViewDesc) {\n let pos = dom ? dom.previousSibling : parentDOM.lastChild;\n renderDescs(desc.contentDOM, desc.children, view);\n dom = pos ? pos.nextSibling : parentDOM.firstChild;\n }\n }\n while (dom) {\n dom = rm(dom);\n written = true;\n }\n if (written && view.trackWrites == parentDOM)\n view.trackWrites = null;\n}\nconst OuterDecoLevel = function (nodeName) {\n if (nodeName)\n this.nodeName = nodeName;\n};\nOuterDecoLevel.prototype = Object.create(null);\nconst noDeco = [new OuterDecoLevel];\nfunction computeOuterDeco(outerDeco, node, needsWrap) {\n if (outerDeco.length == 0)\n return noDeco;\n let top = needsWrap ? noDeco[0] : new OuterDecoLevel, result = [top];\n for (let i = 0; i < outerDeco.length; i++) {\n let attrs = outerDeco[i].type.attrs;\n if (!attrs)\n continue;\n if (attrs.nodeName)\n result.push(top = new OuterDecoLevel(attrs.nodeName));\n for (let name in attrs) {\n let val = attrs[name];\n if (val == null)\n continue;\n if (needsWrap && result.length == 1)\n result.push(top = new OuterDecoLevel(node.isInline ? \"span\" : \"div\"));\n if (name == \"class\")\n top.class = (top.class ? top.class + \" \" : \"\") + val;\n else if (name == \"style\")\n top.style = (top.style ? top.style + \";\" : \"\") + val;\n else if (name != \"nodeName\")\n top[name] = val;\n }\n }\n return result;\n}\nfunction patchOuterDeco(outerDOM, nodeDOM, prevComputed, curComputed) {\n // Shortcut for trivial case\n if (prevComputed == noDeco && curComputed == noDeco)\n return nodeDOM;\n let curDOM = nodeDOM;\n for (let i = 0; i < curComputed.length; i++) {\n let deco = curComputed[i], prev = prevComputed[i];\n if (i) {\n let parent;\n if (prev && prev.nodeName == deco.nodeName && curDOM != outerDOM &&\n (parent = curDOM.parentNode) && parent.nodeName.toLowerCase() == deco.nodeName) {\n curDOM = parent;\n }\n else {\n parent = document.createElement(deco.nodeName);\n parent.pmIsDeco = true;\n parent.appendChild(curDOM);\n prev = noDeco[0];\n curDOM = parent;\n }\n }\n patchAttributes(curDOM, prev || noDeco[0], deco);\n }\n return curDOM;\n}\nfunction patchAttributes(dom, prev, cur) {\n for (let name in prev)\n if (name != \"class\" && name != \"style\" && name != \"nodeName\" && !(name in cur))\n dom.removeAttribute(name);\n for (let name in cur)\n if (name != \"class\" && name != \"style\" && name != \"nodeName\" && cur[name] != prev[name])\n dom.setAttribute(name, cur[name]);\n if (prev.class != cur.class) {\n let prevList = prev.class ? prev.class.split(\" \").filter(Boolean) : [];\n let curList = cur.class ? cur.class.split(\" \").filter(Boolean) : [];\n for (let i = 0; i < prevList.length; i++)\n if (curList.indexOf(prevList[i]) == -1)\n dom.classList.remove(prevList[i]);\n for (let i = 0; i < curList.length; i++)\n if (prevList.indexOf(curList[i]) == -1)\n dom.classList.add(curList[i]);\n if (dom.classList.length == 0)\n dom.removeAttribute(\"class\");\n }\n if (prev.style != cur.style) {\n if (prev.style) {\n let prop = /\\s*([\\w\\-\\xa1-\\uffff]+)\\s*:(?:\"(?:\\\\.|[^\"])*\"|'(?:\\\\.|[^'])*'|\\(.*?\\)|[^;])*/g, m;\n while (m = prop.exec(prev.style))\n dom.style.removeProperty(m[1]);\n }\n if (cur.style)\n dom.style.cssText += cur.style;\n }\n}\nfunction applyOuterDeco(dom, deco, node) {\n return patchOuterDeco(dom, dom, noDeco, computeOuterDeco(deco, node, dom.nodeType != 1));\n}\nfunction sameOuterDeco(a, b) {\n if (a.length != b.length)\n return false;\n for (let i = 0; i < a.length; i++)\n if (!a[i].type.eq(b[i].type))\n return false;\n return true;\n}\n// Remove a DOM node and return its next sibling.\nfunction rm(dom) {\n let next = dom.nextSibling;\n dom.parentNode.removeChild(dom);\n return next;\n}\n// Helper class for incrementally updating a tree of mark descs and\n// the widget and node descs inside of them.\nclass ViewTreeUpdater {\n constructor(top, lock, view) {\n this.lock = lock;\n this.view = view;\n // Index into `this.top`'s child array, represents the current\n // update position.\n this.index = 0;\n // When entering a mark, the current top and index are pushed\n // onto this.\n this.stack = [];\n // Tracks whether anything was changed\n this.changed = false;\n this.top = top;\n this.preMatch = preMatch(top.node.content, top);\n }\n // Destroy and remove the children between the given indices in\n // `this.top`.\n destroyBetween(start, end) {\n if (start == end)\n return;\n for (let i = start; i < end; i++)\n this.top.children[i].destroy();\n this.top.children.splice(start, end - start);\n this.changed = true;\n }\n // Destroy all remaining children in `this.top`.\n destroyRest() {\n this.destroyBetween(this.index, this.top.children.length);\n }\n // Sync the current stack of mark descs with the given array of\n // marks, reusing existing mark descs when possible.\n syncToMarks(marks, inline, view, parentIndex) {\n let keep = 0, depth = this.stack.length >> 1;\n let maxKeep = Math.min(depth, marks.length);\n while (keep < maxKeep &&\n (keep == depth - 1 ? this.top : this.stack[(keep + 1) << 1])\n .matchesMark(marks[keep]) && marks[keep].type.spec.spanning !== false)\n keep++;\n while (keep < depth) {\n this.destroyRest();\n this.top.dirty = NOT_DIRTY;\n this.index = this.stack.pop();\n this.top = this.stack.pop();\n depth--;\n }\n while (depth < marks.length) {\n this.stack.push(this.top, this.index + 1);\n let found = -1, scanTo = this.top.children.length;\n if (parentIndex < this.preMatch.index)\n scanTo = Math.min(this.index + 3, scanTo);\n for (let i = this.index; i < scanTo; i++) {\n let next = this.top.children[i];\n if (next.matchesMark(marks[depth]) && !this.isLocked(next.dom)) {\n found = i;\n break;\n }\n }\n if (found > -1) {\n if (found > this.index) {\n this.changed = true;\n this.destroyBetween(this.index, found);\n }\n this.top = this.top.children[this.index];\n }\n else {\n let markDesc = MarkViewDesc.create(this.top, marks[depth], inline, view);\n this.top.children.splice(this.index, 0, markDesc);\n this.top = markDesc;\n this.changed = true;\n }\n this.index = 0;\n depth++;\n }\n }\n // Try to find a node desc matching the given data. Skip over it and\n // return true when successful.\n findNodeMatch(node, outerDeco, innerDeco, index) {\n let found = -1, targetDesc;\n if (index >= this.preMatch.index &&\n (targetDesc = this.preMatch.matches[index - this.preMatch.index]).parent == this.top &&\n targetDesc.matchesNode(node, outerDeco, innerDeco)) {\n found = this.top.children.indexOf(targetDesc, this.index);\n }\n else {\n for (let i = this.index, e = Math.min(this.top.children.length, i + 5); i < e; i++) {\n let child = this.top.children[i];\n if (child.matchesNode(node, outerDeco, innerDeco) && !this.preMatch.matched.has(child)) {\n found = i;\n break;\n }\n }\n }\n if (found < 0)\n return false;\n this.destroyBetween(this.index, found);\n this.index++;\n return true;\n }\n updateNodeAt(node, outerDeco, innerDeco, index, view) {\n let child = this.top.children[index];\n if (child.dirty == NODE_DIRTY && child.dom == child.contentDOM)\n child.dirty = CONTENT_DIRTY;\n if (!child.update(node, outerDeco, innerDeco, view))\n return false;\n this.destroyBetween(this.index, index);\n this.index++;\n return true;\n }\n findIndexWithChild(domNode) {\n for (;;) {\n let parent = domNode.parentNode;\n if (!parent)\n return -1;\n if (parent == this.top.contentDOM) {\n let desc = domNode.pmViewDesc;\n if (desc)\n for (let i = this.index; i < this.top.children.length; i++) {\n if (this.top.children[i] == desc)\n return i;\n }\n return -1;\n }\n domNode = parent;\n }\n }\n // Try to update the next node, if any, to the given data. Checks\n // pre-matches to avoid overwriting nodes that could still be used.\n updateNextNode(node, outerDeco, innerDeco, view, index, pos) {\n for (let i = this.index; i < this.top.children.length; i++) {\n let next = this.top.children[i];\n if (next instanceof NodeViewDesc) {\n let preMatch = this.preMatch.matched.get(next);\n if (preMatch != null && preMatch != index)\n return false;\n let nextDOM = next.dom, updated;\n // Can't update if nextDOM is or contains this.lock, except if\n // it's a text node whose content already matches the new text\n // and whose decorations match the new ones.\n let locked = this.isLocked(nextDOM) &&\n !(node.isText && next.node && next.node.isText && next.nodeDOM.nodeValue == node.text &&\n next.dirty != NODE_DIRTY && sameOuterDeco(outerDeco, next.outerDeco));\n if (!locked && next.update(node, outerDeco, innerDeco, view)) {\n this.destroyBetween(this.index, i);\n if (next.dom != nextDOM)\n this.changed = true;\n this.index++;\n return true;\n }\n else if (!locked && (updated = this.recreateWrapper(next, node, outerDeco, innerDeco, view, pos))) {\n this.destroyBetween(this.index, i);\n this.top.children[this.index] = updated;\n if (updated.contentDOM) {\n updated.dirty = CONTENT_DIRTY;\n updated.updateChildren(view, pos + 1);\n updated.dirty = NOT_DIRTY;\n }\n this.changed = true;\n this.index++;\n return true;\n }\n break;\n }\n }\n return false;\n }\n // When a node with content is replaced by a different node with\n // identical content, move over its children.\n recreateWrapper(next, node, outerDeco, innerDeco, view, pos) {\n if (next.dirty || node.isAtom || !next.children.length ||\n !next.node.content.eq(node.content) ||\n !sameOuterDeco(outerDeco, next.outerDeco) || !innerDeco.eq(next.innerDeco))\n return null;\n let wrapper = NodeViewDesc.create(this.top, node, outerDeco, innerDeco, view, pos);\n if (wrapper.contentDOM) {\n wrapper.children = next.children;\n next.children = [];\n for (let ch of wrapper.children)\n ch.parent = wrapper;\n }\n next.destroy();\n return wrapper;\n }\n // Insert the node as a newly created node desc.\n addNode(node, outerDeco, innerDeco, view, pos) {\n let desc = NodeViewDesc.create(this.top, node, outerDeco, innerDeco, view, pos);\n if (desc.contentDOM)\n desc.updateChildren(view, pos + 1);\n this.top.children.splice(this.index++, 0, desc);\n this.changed = true;\n }\n placeWidget(widget, view, pos) {\n let next = this.index < this.top.children.length ? this.top.children[this.index] : null;\n if (next && next.matchesWidget(widget) &&\n (widget == next.widget || !next.widget.type.toDOM.parentNode)) {\n this.index++;\n }\n else {\n let desc = new WidgetViewDesc(this.top, widget, view, pos);\n this.top.children.splice(this.index++, 0, desc);\n this.changed = true;\n }\n }\n // Make sure a textblock looks and behaves correctly in\n // contentEditable.\n addTextblockHacks() {\n let lastChild = this.top.children[this.index - 1], parent = this.top;\n while (lastChild instanceof MarkViewDesc) {\n parent = lastChild;\n lastChild = parent.children[parent.children.length - 1];\n }\n if (!lastChild || // Empty textblock\n !(lastChild instanceof TextViewDesc) ||\n /\\n$/.test(lastChild.node.text) ||\n (this.view.requiresGeckoHackNode && /\\s$/.test(lastChild.node.text))) {\n // Avoid bugs in Safari's cursor drawing (#1165) and Chrome's mouse selection (#1152)\n if ((safari || chrome) && lastChild && lastChild.dom.contentEditable == \"false\")\n this.addHackNode(\"IMG\", parent);\n this.addHackNode(\"BR\", this.top);\n }\n }\n addHackNode(nodeName, parent) {\n if (parent == this.top && this.index < parent.children.length && parent.children[this.index].matchesHack(nodeName)) {\n this.index++;\n }\n else {\n let dom = document.createElement(nodeName);\n if (nodeName == \"IMG\") {\n dom.className = \"ProseMirror-separator\";\n dom.alt = \"\";\n }\n if (nodeName == \"BR\")\n dom.className = \"ProseMirror-trailingBreak\";\n let hack = new TrailingHackViewDesc(this.top, [], dom, null);\n if (parent != this.top)\n parent.children.push(hack);\n else\n parent.children.splice(this.index++, 0, hack);\n this.changed = true;\n }\n }\n isLocked(node) {\n return this.lock && (node == this.lock || node.nodeType == 1 && node.contains(this.lock.parentNode));\n }\n}\n// Iterate from the end of the fragment and array of descs to find\n// directly matching ones, in order to avoid overeagerly reusing those\n// for other nodes.\nfunction preMatch(frag, parentDesc) {\n let curDesc = parentDesc, descI = curDesc.children.length;\n let fI = frag.childCount, matched = new Map, matches = [];\n outer: while (fI > 0) {\n let desc;\n for (;;) {\n if (descI) {\n let next = curDesc.children[descI - 1];\n if (next instanceof MarkViewDesc) {\n curDesc = next;\n descI = next.children.length;\n }\n else {\n desc = next;\n descI--;\n break;\n }\n }\n else if (curDesc == parentDesc) {\n break outer;\n }\n else {\n descI = curDesc.parent.children.indexOf(curDesc);\n curDesc = curDesc.parent;\n }\n }\n let node = desc.node;\n if (!node)\n continue;\n if (node != frag.child(fI - 1))\n break;\n --fI;\n matched.set(desc, fI);\n matches.push(desc);\n }\n return { index: fI, matched, matches: matches.reverse() };\n}\nfunction compareSide(a, b) {\n return a.type.side - b.type.side;\n}\n// This function abstracts iterating over the nodes and decorations in\n// a fragment. Calls `onNode` for each node, with its local and child\n// decorations. Splits text nodes when there is a decoration starting\n// or ending inside of them. Calls `onWidget` for each widget.\nfunction iterDeco(parent, deco, onWidget, onNode) {\n let locals = deco.locals(parent), offset = 0;\n // Simple, cheap variant for when there are no local decorations\n if (locals.length == 0) {\n for (let i = 0; i < parent.childCount; i++) {\n let child = parent.child(i);\n onNode(child, locals, deco.forChild(offset, child), i);\n offset += child.nodeSize;\n }\n return;\n }\n let decoIndex = 0, active = [], restNode = null;\n for (let parentIndex = 0;;) {\n let widget, widgets;\n while (decoIndex < locals.length && locals[decoIndex].to == offset) {\n let next = locals[decoIndex++];\n if (next.widget) {\n if (!widget)\n widget = next;\n else\n (widgets || (widgets = [widget])).push(next);\n }\n }\n if (widget) {\n if (widgets) {\n widgets.sort(compareSide);\n for (let i = 0; i < widgets.length; i++)\n onWidget(widgets[i], parentIndex, !!restNode);\n }\n else {\n onWidget(widget, parentIndex, !!restNode);\n }\n }\n let child, index;\n if (restNode) {\n index = -1;\n child = restNode;\n restNode = null;\n }\n else if (parentIndex < parent.childCount) {\n index = parentIndex;\n child = parent.child(parentIndex++);\n }\n else {\n break;\n }\n for (let i = 0; i < active.length; i++)\n if (active[i].to <= offset)\n active.splice(i--, 1);\n while (decoIndex < locals.length && locals[decoIndex].from <= offset && locals[decoIndex].to > offset)\n active.push(locals[decoIndex++]);\n let end = offset + child.nodeSize;\n if (child.isText) {\n let cutAt = end;\n if (decoIndex < locals.length && locals[decoIndex].from < cutAt)\n cutAt = locals[decoIndex].from;\n for (let i = 0; i < active.length; i++)\n if (active[i].to < cutAt)\n cutAt = active[i].to;\n if (cutAt < end) {\n restNode = child.cut(cutAt - offset);\n child = child.cut(0, cutAt - offset);\n end = cutAt;\n index = -1;\n }\n }\n else {\n while (decoIndex < locals.length && locals[decoIndex].to < end)\n decoIndex++;\n }\n let outerDeco = child.isInline && !child.isLeaf ? active.filter(d => !d.inline) : active.slice();\n onNode(child, outerDeco, deco.forChild(offset, child), index);\n offset = end;\n }\n}\n// List markers in Mobile Safari will mysteriously disappear\n// sometimes. This works around that.\nfunction iosHacks(dom) {\n if (dom.nodeName == \"UL\" || dom.nodeName == \"OL\") {\n let oldCSS = dom.style.cssText;\n dom.style.cssText = oldCSS + \"; list-style: square !important\";\n window.getComputedStyle(dom).listStyle;\n dom.style.cssText = oldCSS;\n }\n}\n// Find a piece of text in an inline fragment, overlapping from-to\nfunction findTextInFragment(frag, text, from, to) {\n for (let i = 0, pos = 0; i < frag.childCount && pos <= to;) {\n let child = frag.child(i++), childStart = pos;\n pos += child.nodeSize;\n if (!child.isText)\n continue;\n let str = child.text;\n while (i < frag.childCount) {\n let next = frag.child(i++);\n pos += next.nodeSize;\n if (!next.isText)\n break;\n str += next.text;\n }\n if (pos >= from) {\n if (pos >= to && str.slice(to - text.length - childStart, to - childStart) == text)\n return to - text.length;\n let found = childStart < to ? str.lastIndexOf(text, to - childStart - 1) : -1;\n if (found >= 0 && found + text.length + childStart >= from)\n return childStart + found;\n if (from == to && str.length >= (to + text.length) - childStart &&\n str.slice(to - childStart, to - childStart + text.length) == text)\n return to;\n }\n }\n return -1;\n}\n// Replace range from-to in an array of view descs with replacement\n// (may be null to just delete). This goes very much against the grain\n// of the rest of this code, which tends to create nodes with the\n// right shape in one go, rather than messing with them after\n// creation, but is necessary in the composition hack.\nfunction replaceNodes(nodes, from, to, view, replacement) {\n let result = [];\n for (let i = 0, off = 0; i < nodes.length; i++) {\n let child = nodes[i], start = off, end = off += child.size;\n if (start >= to || end <= from) {\n result.push(child);\n }\n else {\n if (start < from)\n result.push(child.slice(0, from - start, view));\n if (replacement) {\n result.push(replacement);\n replacement = undefined;\n }\n if (end > to)\n result.push(child.slice(to - start, child.size, view));\n }\n }\n return result;\n}\n\nfunction selectionFromDOM(view, origin = null) {\n let domSel = view.domSelectionRange(), doc = view.state.doc;\n if (!domSel.focusNode)\n return null;\n let nearestDesc = view.docView.nearestDesc(domSel.focusNode), inWidget = nearestDesc && nearestDesc.size == 0;\n let head = view.docView.posFromDOM(domSel.focusNode, domSel.focusOffset, 1);\n if (head < 0)\n return null;\n let $head = doc.resolve(head), anchor, selection;\n if (selectionCollapsed(domSel)) {\n anchor = head;\n while (nearestDesc && !nearestDesc.node)\n nearestDesc = nearestDesc.parent;\n let nearestDescNode = nearestDesc.node;\n if (nearestDesc && nearestDescNode.isAtom && prosemirror_state__WEBPACK_IMPORTED_MODULE_1__.NodeSelection.isSelectable(nearestDescNode) && nearestDesc.parent\n && !(nearestDescNode.isInline && isOnEdge(domSel.focusNode, domSel.focusOffset, nearestDesc.dom))) {\n let pos = nearestDesc.posBefore;\n selection = new prosemirror_state__WEBPACK_IMPORTED_MODULE_1__.NodeSelection(head == pos ? $head : doc.resolve(pos));\n }\n }\n else {\n if (domSel instanceof view.dom.ownerDocument.defaultView.Selection && domSel.rangeCount > 1) {\n let min = head, max = head;\n for (let i = 0; i < domSel.rangeCount; i++) {\n let range = domSel.getRangeAt(i);\n min = Math.min(min, view.docView.posFromDOM(range.startContainer, range.startOffset, 1));\n max = Math.max(max, view.docView.posFromDOM(range.endContainer, range.endOffset, -1));\n }\n if (min < 0)\n return null;\n [anchor, head] = max == view.state.selection.anchor ? [max, min] : [min, max];\n $head = doc.resolve(head);\n }\n else {\n anchor = view.docView.posFromDOM(domSel.anchorNode, domSel.anchorOffset, 1);\n }\n if (anchor < 0)\n return null;\n }\n let $anchor = doc.resolve(anchor);\n if (!selection) {\n let bias = origin == \"pointer\" || (view.state.selection.head < $head.pos && !inWidget) ? 1 : -1;\n selection = selectionBetween(view, $anchor, $head, bias);\n }\n return selection;\n}\nfunction editorOwnsSelection(view) {\n return view.editable ? view.hasFocus() :\n hasSelection(view) && document.activeElement && document.activeElement.contains(view.dom);\n}\nfunction selectionToDOM(view, force = false) {\n let sel = view.state.selection;\n syncNodeSelection(view, sel);\n if (!editorOwnsSelection(view))\n return;\n // The delayed drag selection causes issues with Cell Selections\n // in Safari. And the drag selection delay is to workarond issues\n // which only present in Chrome.\n if (!force && view.input.mouseDown && view.input.mouseDown.allowDefault && chrome) {\n let domSel = view.domSelectionRange(), curSel = view.domObserver.currentSelection;\n if (domSel.anchorNode && curSel.anchorNode &&\n isEquivalentPosition(domSel.anchorNode, domSel.anchorOffset, curSel.anchorNode, curSel.anchorOffset)) {\n view.input.mouseDown.delayedSelectionSync = true;\n view.domObserver.setCurSelection();\n return;\n }\n }\n view.domObserver.disconnectSelection();\n if (view.cursorWrapper) {\n selectCursorWrapper(view);\n }\n else {\n let { anchor, head } = sel, resetEditableFrom, resetEditableTo;\n if (brokenSelectBetweenUneditable && !(sel instanceof prosemirror_state__WEBPACK_IMPORTED_MODULE_1__.TextSelection)) {\n if (!sel.$from.parent.inlineContent)\n resetEditableFrom = temporarilyEditableNear(view, sel.from);\n if (!sel.empty && !sel.$from.parent.inlineContent)\n resetEditableTo = temporarilyEditableNear(view, sel.to);\n }\n view.docView.setSelection(anchor, head, view, force);\n if (brokenSelectBetweenUneditable) {\n if (resetEditableFrom)\n resetEditable(resetEditableFrom);\n if (resetEditableTo)\n resetEditable(resetEditableTo);\n }\n if (sel.visible) {\n view.dom.classList.remove(\"ProseMirror-hideselection\");\n }\n else {\n view.dom.classList.add(\"ProseMirror-hideselection\");\n if (\"onselectionchange\" in document)\n removeClassOnSelectionChange(view);\n }\n }\n view.domObserver.setCurSelection();\n view.domObserver.connectSelection();\n}\n// Kludge to work around Webkit not allowing a selection to start/end\n// between non-editable block nodes. We briefly make something\n// editable, set the selection, then set it uneditable again.\nconst brokenSelectBetweenUneditable = safari || chrome && chrome_version < 63;\nfunction temporarilyEditableNear(view, pos) {\n let { node, offset } = view.docView.domFromPos(pos, 0);\n let after = offset < node.childNodes.length ? node.childNodes[offset] : null;\n let before = offset ? node.childNodes[offset - 1] : null;\n if (safari && after && after.contentEditable == \"false\")\n return setEditable(after);\n if ((!after || after.contentEditable == \"false\") &&\n (!before || before.contentEditable == \"false\")) {\n if (after)\n return setEditable(after);\n else if (before)\n return setEditable(before);\n }\n}\nfunction setEditable(element) {\n element.contentEditable = \"true\";\n if (safari && element.draggable) {\n element.draggable = false;\n element.wasDraggable = true;\n }\n return element;\n}\nfunction resetEditable(element) {\n element.contentEditable = \"false\";\n if (element.wasDraggable) {\n element.draggable = true;\n element.wasDraggable = null;\n }\n}\nfunction removeClassOnSelectionChange(view) {\n let doc = view.dom.ownerDocument;\n doc.removeEventListener(\"selectionchange\", view.input.hideSelectionGuard);\n let domSel = view.domSelectionRange();\n let node = domSel.anchorNode, offset = domSel.anchorOffset;\n doc.addEventListener(\"selectionchange\", view.input.hideSelectionGuard = () => {\n if (domSel.anchorNode != node || domSel.anchorOffset != offset) {\n doc.removeEventListener(\"selectionchange\", view.input.hideSelectionGuard);\n setTimeout(() => {\n if (!editorOwnsSelection(view) || view.state.selection.visible)\n view.dom.classList.remove(\"ProseMirror-hideselection\");\n }, 20);\n }\n });\n}\nfunction selectCursorWrapper(view) {\n let domSel = view.domSelection();\n if (!domSel)\n return;\n let node = view.cursorWrapper.dom, img = node.nodeName == \"IMG\";\n if (img)\n domSel.collapse(node.parentNode, domIndex(node) + 1);\n else\n domSel.collapse(node, 0);\n // Kludge to kill 'control selection' in IE11 when selecting an\n // invisible cursor wrapper, since that would result in those weird\n // resize handles and a selection that considers the absolutely\n // positioned wrapper, rather than the root editable node, the\n // focused element.\n if (!img && !view.state.selection.visible && ie && ie_version <= 11) {\n node.disabled = true;\n node.disabled = false;\n }\n}\nfunction syncNodeSelection(view, sel) {\n if (sel instanceof prosemirror_state__WEBPACK_IMPORTED_MODULE_1__.NodeSelection) {\n let desc = view.docView.descAt(sel.from);\n if (desc != view.lastSelectedViewDesc) {\n clearNodeSelection(view);\n if (desc)\n desc.selectNode();\n view.lastSelectedViewDesc = desc;\n }\n }\n else {\n clearNodeSelection(view);\n }\n}\n// Clear all DOM statefulness of the last node selection.\nfunction clearNodeSelection(view) {\n if (view.lastSelectedViewDesc) {\n if (view.lastSelectedViewDesc.parent)\n view.lastSelectedViewDesc.deselectNode();\n view.lastSelectedViewDesc = undefined;\n }\n}\nfunction selectionBetween(view, $anchor, $head, bias) {\n return view.someProp(\"createSelectionBetween\", f => f(view, $anchor, $head))\n || prosemirror_state__WEBPACK_IMPORTED_MODULE_1__.TextSelection.between($anchor, $head, bias);\n}\nfunction hasFocusAndSelection(view) {\n if (view.editable && !view.hasFocus())\n return false;\n return hasSelection(view);\n}\nfunction hasSelection(view) {\n let sel = view.domSelectionRange();\n if (!sel.anchorNode)\n return false;\n try {\n // Firefox will raise 'permission denied' errors when accessing\n // properties of `sel.anchorNode` when it's in a generated CSS\n // element.\n return view.dom.contains(sel.anchorNode.nodeType == 3 ? sel.anchorNode.parentNode : sel.anchorNode) &&\n (view.editable || view.dom.contains(sel.focusNode.nodeType == 3 ? sel.focusNode.parentNode : sel.focusNode));\n }\n catch (_) {\n return false;\n }\n}\nfunction anchorInRightPlace(view) {\n let anchorDOM = view.docView.domFromPos(view.state.selection.anchor, 0);\n let domSel = view.domSelectionRange();\n return isEquivalentPosition(anchorDOM.node, anchorDOM.offset, domSel.anchorNode, domSel.anchorOffset);\n}\n\nfunction moveSelectionBlock(state, dir) {\n let { $anchor, $head } = state.selection;\n let $side = dir > 0 ? $anchor.max($head) : $anchor.min($head);\n let $start = !$side.parent.inlineContent ? $side : $side.depth ? state.doc.resolve(dir > 0 ? $side.after() : $side.before()) : null;\n return $start && prosemirror_state__WEBPACK_IMPORTED_MODULE_1__.Selection.findFrom($start, dir);\n}\nfunction apply(view, sel) {\n view.dispatch(view.state.tr.setSelection(sel).scrollIntoView());\n return true;\n}\nfunction selectHorizontally(view, dir, mods) {\n let sel = view.state.selection;\n if (sel instanceof prosemirror_state__WEBPACK_IMPORTED_MODULE_1__.TextSelection) {\n if (mods.indexOf(\"s\") > -1) {\n let { $head } = sel, node = $head.textOffset ? null : dir < 0 ? $head.nodeBefore : $head.nodeAfter;\n if (!node || node.isText || !node.isLeaf)\n return false;\n let $newHead = view.state.doc.resolve($head.pos + node.nodeSize * (dir < 0 ? -1 : 1));\n return apply(view, new prosemirror_state__WEBPACK_IMPORTED_MODULE_1__.TextSelection(sel.$anchor, $newHead));\n }\n else if (!sel.empty) {\n return false;\n }\n else if (view.endOfTextblock(dir > 0 ? \"forward\" : \"backward\")) {\n let next = moveSelectionBlock(view.state, dir);\n if (next && (next instanceof prosemirror_state__WEBPACK_IMPORTED_MODULE_1__.NodeSelection))\n return apply(view, next);\n return false;\n }\n else if (!(mac && mods.indexOf(\"m\") > -1)) {\n let $head = sel.$head, node = $head.textOffset ? null : dir < 0 ? $head.nodeBefore : $head.nodeAfter, desc;\n if (!node || node.isText)\n return false;\n let nodePos = dir < 0 ? $head.pos - node.nodeSize : $head.pos;\n if (!(node.isAtom || (desc = view.docView.descAt(nodePos)) && !desc.contentDOM))\n return false;\n if (prosemirror_state__WEBPACK_IMPORTED_MODULE_1__.NodeSelection.isSelectable(node)) {\n return apply(view, new prosemirror_state__WEBPACK_IMPORTED_MODULE_1__.NodeSelection(dir < 0 ? view.state.doc.resolve($head.pos - node.nodeSize) : $head));\n }\n else if (webkit) {\n // Chrome and Safari will introduce extra pointless cursor\n // positions around inline uneditable nodes, so we have to\n // take over and move the cursor past them (#937)\n return apply(view, new prosemirror_state__WEBPACK_IMPORTED_MODULE_1__.TextSelection(view.state.doc.resolve(dir < 0 ? nodePos : nodePos + node.nodeSize)));\n }\n else {\n return false;\n }\n }\n }\n else if (sel instanceof prosemirror_state__WEBPACK_IMPORTED_MODULE_1__.NodeSelection && sel.node.isInline) {\n return apply(view, new prosemirror_state__WEBPACK_IMPORTED_MODULE_1__.TextSelection(dir > 0 ? sel.$to : sel.$from));\n }\n else {\n let next = moveSelectionBlock(view.state, dir);\n if (next)\n return apply(view, next);\n return false;\n }\n}\nfunction nodeLen(node) {\n return node.nodeType == 3 ? node.nodeValue.length : node.childNodes.length;\n}\nfunction isIgnorable(dom, dir) {\n let desc = dom.pmViewDesc;\n return desc && desc.size == 0 && (dir < 0 || dom.nextSibling || dom.nodeName != \"BR\");\n}\nfunction skipIgnoredNodes(view, dir) {\n return dir < 0 ? skipIgnoredNodesBefore(view) : skipIgnoredNodesAfter(view);\n}\n// Make sure the cursor isn't directly after one or more ignored\n// nodes, which will confuse the browser's cursor motion logic.\nfunction skipIgnoredNodesBefore(view) {\n let sel = view.domSelectionRange();\n let node = sel.focusNode, offset = sel.focusOffset;\n if (!node)\n return;\n let moveNode, moveOffset, force = false;\n // Gecko will do odd things when the selection is directly in front\n // of a non-editable node, so in that case, move it into the next\n // node if possible. Issue prosemirror/prosemirror#832.\n if (gecko && node.nodeType == 1 && offset < nodeLen(node) && isIgnorable(node.childNodes[offset], -1))\n force = true;\n for (;;) {\n if (offset > 0) {\n if (node.nodeType != 1) {\n break;\n }\n else {\n let before = node.childNodes[offset - 1];\n if (isIgnorable(before, -1)) {\n moveNode = node;\n moveOffset = --offset;\n }\n else if (before.nodeType == 3) {\n node = before;\n offset = node.nodeValue.length;\n }\n else\n break;\n }\n }\n else if (isBlockNode(node)) {\n break;\n }\n else {\n let prev = node.previousSibling;\n while (prev && isIgnorable(prev, -1)) {\n moveNode = node.parentNode;\n moveOffset = domIndex(prev);\n prev = prev.previousSibling;\n }\n if (!prev) {\n node = node.parentNode;\n if (node == view.dom)\n break;\n offset = 0;\n }\n else {\n node = prev;\n offset = nodeLen(node);\n }\n }\n }\n if (force)\n setSelFocus(view, node, offset);\n else if (moveNode)\n setSelFocus(view, moveNode, moveOffset);\n}\n// Make sure the cursor isn't directly before one or more ignored\n// nodes.\nfunction skipIgnoredNodesAfter(view) {\n let sel = view.domSelectionRange();\n let node = sel.focusNode, offset = sel.focusOffset;\n if (!node)\n return;\n let len = nodeLen(node);\n let moveNode, moveOffset;\n for (;;) {\n if (offset < len) {\n if (node.nodeType != 1)\n break;\n let after = node.childNodes[offset];\n if (isIgnorable(after, 1)) {\n moveNode = node;\n moveOffset = ++offset;\n }\n else\n break;\n }\n else if (isBlockNode(node)) {\n break;\n }\n else {\n let next = node.nextSibling;\n while (next && isIgnorable(next, 1)) {\n moveNode = next.parentNode;\n moveOffset = domIndex(next) + 1;\n next = next.nextSibling;\n }\n if (!next) {\n node = node.parentNode;\n if (node == view.dom)\n break;\n offset = len = 0;\n }\n else {\n node = next;\n offset = 0;\n len = nodeLen(node);\n }\n }\n }\n if (moveNode)\n setSelFocus(view, moveNode, moveOffset);\n}\nfunction isBlockNode(dom) {\n let desc = dom.pmViewDesc;\n return desc && desc.node && desc.node.isBlock;\n}\nfunction textNodeAfter(node, offset) {\n while (node && offset == node.childNodes.length && !hasBlockDesc(node)) {\n offset = domIndex(node) + 1;\n node = node.parentNode;\n }\n while (node && offset < node.childNodes.length) {\n let next = node.childNodes[offset];\n if (next.nodeType == 3)\n return next;\n if (next.nodeType == 1 && next.contentEditable == \"false\")\n break;\n node = next;\n offset = 0;\n }\n}\nfunction textNodeBefore(node, offset) {\n while (node && !offset && !hasBlockDesc(node)) {\n offset = domIndex(node);\n node = node.parentNode;\n }\n while (node && offset) {\n let next = node.childNodes[offset - 1];\n if (next.nodeType == 3)\n return next;\n if (next.nodeType == 1 && next.contentEditable == \"false\")\n break;\n node = next;\n offset = node.childNodes.length;\n }\n}\nfunction setSelFocus(view, node, offset) {\n if (node.nodeType != 3) {\n let before, after;\n if (after = textNodeAfter(node, offset)) {\n node = after;\n offset = 0;\n }\n else if (before = textNodeBefore(node, offset)) {\n node = before;\n offset = before.nodeValue.length;\n }\n }\n let sel = view.domSelection();\n if (!sel)\n return;\n if (selectionCollapsed(sel)) {\n let range = document.createRange();\n range.setEnd(node, offset);\n range.setStart(node, offset);\n sel.removeAllRanges();\n sel.addRange(range);\n }\n else if (sel.extend) {\n sel.extend(node, offset);\n }\n view.domObserver.setCurSelection();\n let { state } = view;\n // If no state update ends up happening, reset the selection.\n setTimeout(() => {\n if (view.state == state)\n selectionToDOM(view);\n }, 50);\n}\nfunction findDirection(view, pos) {\n let $pos = view.state.doc.resolve(pos);\n if (!(chrome || windows) && $pos.parent.inlineContent) {\n let coords = view.coordsAtPos(pos);\n if (pos > $pos.start()) {\n let before = view.coordsAtPos(pos - 1);\n let mid = (before.top + before.bottom) / 2;\n if (mid > coords.top && mid < coords.bottom && Math.abs(before.left - coords.left) > 1)\n return before.left < coords.left ? \"ltr\" : \"rtl\";\n }\n if (pos < $pos.end()) {\n let after = view.coordsAtPos(pos + 1);\n let mid = (after.top + after.bottom) / 2;\n if (mid > coords.top && mid < coords.bottom && Math.abs(after.left - coords.left) > 1)\n return after.left > coords.left ? \"ltr\" : \"rtl\";\n }\n }\n let computed = getComputedStyle(view.dom).direction;\n return computed == \"rtl\" ? \"rtl\" : \"ltr\";\n}\n// Check whether vertical selection motion would involve node\n// selections. If so, apply it (if not, the result is left to the\n// browser)\nfunction selectVertically(view, dir, mods) {\n let sel = view.state.selection;\n if (sel instanceof prosemirror_state__WEBPACK_IMPORTED_MODULE_1__.TextSelection && !sel.empty || mods.indexOf(\"s\") > -1)\n return false;\n if (mac && mods.indexOf(\"m\") > -1)\n return false;\n let { $from, $to } = sel;\n if (!$from.parent.inlineContent || view.endOfTextblock(dir < 0 ? \"up\" : \"down\")) {\n let next = moveSelectionBlock(view.state, dir);\n if (next && (next instanceof prosemirror_state__WEBPACK_IMPORTED_MODULE_1__.NodeSelection))\n return apply(view, next);\n }\n if (!$from.parent.inlineContent) {\n let side = dir < 0 ? $from : $to;\n let beyond = sel instanceof prosemirror_state__WEBPACK_IMPORTED_MODULE_1__.AllSelection ? prosemirror_state__WEBPACK_IMPORTED_MODULE_1__.Selection.near(side, dir) : prosemirror_state__WEBPACK_IMPORTED_MODULE_1__.Selection.findFrom(side, dir);\n return beyond ? apply(view, beyond) : false;\n }\n return false;\n}\nfunction stopNativeHorizontalDelete(view, dir) {\n if (!(view.state.selection instanceof prosemirror_state__WEBPACK_IMPORTED_MODULE_1__.TextSelection))\n return true;\n let { $head, $anchor, empty } = view.state.selection;\n if (!$head.sameParent($anchor))\n return true;\n if (!empty)\n return false;\n if (view.endOfTextblock(dir > 0 ? \"forward\" : \"backward\"))\n return true;\n let nextNode = !$head.textOffset && (dir < 0 ? $head.nodeBefore : $head.nodeAfter);\n if (nextNode && !nextNode.isText) {\n let tr = view.state.tr;\n if (dir < 0)\n tr.delete($head.pos - nextNode.nodeSize, $head.pos);\n else\n tr.delete($head.pos, $head.pos + nextNode.nodeSize);\n view.dispatch(tr);\n return true;\n }\n return false;\n}\nfunction switchEditable(view, node, state) {\n view.domObserver.stop();\n node.contentEditable = state;\n view.domObserver.start();\n}\n// Issue #867 / #1090 / https://bugs.chromium.org/p/chromium/issues/detail?id=903821\n// In which Safari (and at some point in the past, Chrome) does really\n// wrong things when the down arrow is pressed when the cursor is\n// directly at the start of a textblock and has an uneditable node\n// after it\nfunction safariDownArrowBug(view) {\n if (!safari || view.state.selection.$head.parentOffset > 0)\n return false;\n let { focusNode, focusOffset } = view.domSelectionRange();\n if (focusNode && focusNode.nodeType == 1 && focusOffset == 0 &&\n focusNode.firstChild && focusNode.firstChild.contentEditable == \"false\") {\n let child = focusNode.firstChild;\n switchEditable(view, child, \"true\");\n setTimeout(() => switchEditable(view, child, \"false\"), 20);\n }\n return false;\n}\n// A backdrop key mapping used to make sure we always suppress keys\n// that have a dangerous default effect, even if the commands they are\n// bound to return false, and to make sure that cursor-motion keys\n// find a cursor (as opposed to a node selection) when pressed. For\n// cursor-motion keys, the code in the handlers also takes care of\n// block selections.\nfunction getMods(event) {\n let result = \"\";\n if (event.ctrlKey)\n result += \"c\";\n if (event.metaKey)\n result += \"m\";\n if (event.altKey)\n result += \"a\";\n if (event.shiftKey)\n result += \"s\";\n return result;\n}\nfunction captureKeyDown(view, event) {\n let code = event.keyCode, mods = getMods(event);\n if (code == 8 || (mac && code == 72 && mods == \"c\")) { // Backspace, Ctrl-h on Mac\n return stopNativeHorizontalDelete(view, -1) || skipIgnoredNodes(view, -1);\n }\n else if ((code == 46 && !event.shiftKey) || (mac && code == 68 && mods == \"c\")) { // Delete, Ctrl-d on Mac\n return stopNativeHorizontalDelete(view, 1) || skipIgnoredNodes(view, 1);\n }\n else if (code == 13 || code == 27) { // Enter, Esc\n return true;\n }\n else if (code == 37 || (mac && code == 66 && mods == \"c\")) { // Left arrow, Ctrl-b on Mac\n let dir = code == 37 ? (findDirection(view, view.state.selection.from) == \"ltr\" ? -1 : 1) : -1;\n return selectHorizontally(view, dir, mods) || skipIgnoredNodes(view, dir);\n }\n else if (code == 39 || (mac && code == 70 && mods == \"c\")) { // Right arrow, Ctrl-f on Mac\n let dir = code == 39 ? (findDirection(view, view.state.selection.from) == \"ltr\" ? 1 : -1) : 1;\n return selectHorizontally(view, dir, mods) || skipIgnoredNodes(view, dir);\n }\n else if (code == 38 || (mac && code == 80 && mods == \"c\")) { // Up arrow, Ctrl-p on Mac\n return selectVertically(view, -1, mods) || skipIgnoredNodes(view, -1);\n }\n else if (code == 40 || (mac && code == 78 && mods == \"c\")) { // Down arrow, Ctrl-n on Mac\n return safariDownArrowBug(view) || selectVertically(view, 1, mods) || skipIgnoredNodes(view, 1);\n }\n else if (mods == (mac ? \"m\" : \"c\") &&\n (code == 66 || code == 73 || code == 89 || code == 90)) { // Mod-[biyz]\n return true;\n }\n return false;\n}\n\nfunction serializeForClipboard(view, slice) {\n view.someProp(\"transformCopied\", f => { slice = f(slice, view); });\n let context = [], { content, openStart, openEnd } = slice;\n while (openStart > 1 && openEnd > 1 && content.childCount == 1 && content.firstChild.childCount == 1) {\n openStart--;\n openEnd--;\n let node = content.firstChild;\n context.push(node.type.name, node.attrs != node.type.defaultAttrs ? node.attrs : null);\n content = node.content;\n }\n let serializer = view.someProp(\"clipboardSerializer\") || prosemirror_model__WEBPACK_IMPORTED_MODULE_0__.DOMSerializer.fromSchema(view.state.schema);\n let doc = detachedDoc(), wrap = doc.createElement(\"div\");\n wrap.appendChild(serializer.serializeFragment(content, { document: doc }));\n let firstChild = wrap.firstChild, needsWrap, wrappers = 0;\n while (firstChild && firstChild.nodeType == 1 && (needsWrap = wrapMap[firstChild.nodeName.toLowerCase()])) {\n for (let i = needsWrap.length - 1; i >= 0; i--) {\n let wrapper = doc.createElement(needsWrap[i]);\n while (wrap.firstChild)\n wrapper.appendChild(wrap.firstChild);\n wrap.appendChild(wrapper);\n wrappers++;\n }\n firstChild = wrap.firstChild;\n }\n if (firstChild && firstChild.nodeType == 1)\n firstChild.setAttribute(\"data-pm-slice\", `${openStart} ${openEnd}${wrappers ? ` -${wrappers}` : \"\"} ${JSON.stringify(context)}`);\n let text = view.someProp(\"clipboardTextSerializer\", f => f(slice, view)) ||\n slice.content.textBetween(0, slice.content.size, \"\\n\\n\");\n return { dom: wrap, text, slice };\n}\n// Read a slice of content from the clipboard (or drop data).\nfunction parseFromClipboard(view, text, html, plainText, $context) {\n let inCode = $context.parent.type.spec.code;\n let dom, slice;\n if (!html && !text)\n return null;\n let asText = !!text && (plainText || inCode || !html);\n if (asText) {\n view.someProp(\"transformPastedText\", f => { text = f(text, inCode || plainText, view); });\n if (inCode) {\n slice = new prosemirror_model__WEBPACK_IMPORTED_MODULE_0__.Slice(prosemirror_model__WEBPACK_IMPORTED_MODULE_0__.Fragment.from(view.state.schema.text(text.replace(/\\r\\n?/g, \"\\n\"))), 0, 0);\n view.someProp(\"transformPasted\", f => { slice = f(slice, view, true); });\n return slice;\n }\n let parsed = view.someProp(\"clipboardTextParser\", f => f(text, $context, plainText, view));\n if (parsed) {\n slice = parsed;\n }\n else {\n let marks = $context.marks();\n let { schema } = view.state, serializer = prosemirror_model__WEBPACK_IMPORTED_MODULE_0__.DOMSerializer.fromSchema(schema);\n dom = document.createElement(\"div\");\n text.split(/(?:\\r\\n?|\\n)+/).forEach(block => {\n let p = dom.appendChild(document.createElement(\"p\"));\n if (block)\n p.appendChild(serializer.serializeNode(schema.text(block, marks)));\n });\n }\n }\n else {\n view.someProp(\"transformPastedHTML\", f => { html = f(html, view); });\n dom = readHTML(html);\n if (webkit)\n restoreReplacedSpaces(dom);\n }\n let contextNode = dom && dom.querySelector(\"[data-pm-slice]\");\n let sliceData = contextNode && /^(\\d+) (\\d+)(?: -(\\d+))? (.*)/.exec(contextNode.getAttribute(\"data-pm-slice\") || \"\");\n if (sliceData && sliceData[3])\n for (let i = +sliceData[3]; i > 0; i--) {\n let child = dom.firstChild;\n while (child && child.nodeType != 1)\n child = child.nextSibling;\n if (!child)\n break;\n dom = child;\n }\n if (!slice) {\n let parser = view.someProp(\"clipboardParser\") || view.someProp(\"domParser\") || prosemirror_model__WEBPACK_IMPORTED_MODULE_0__.DOMParser.fromSchema(view.state.schema);\n slice = parser.parseSlice(dom, {\n preserveWhitespace: !!(asText || sliceData),\n context: $context,\n ruleFromNode(dom) {\n if (dom.nodeName == \"BR\" && !dom.nextSibling &&\n dom.parentNode && !inlineParents.test(dom.parentNode.nodeName))\n return { ignore: true };\n return null;\n }\n });\n }\n if (sliceData) {\n slice = addContext(closeSlice(slice, +sliceData[1], +sliceData[2]), sliceData[4]);\n }\n else { // HTML wasn't created by ProseMirror. Make sure top-level siblings are coherent\n slice = prosemirror_model__WEBPACK_IMPORTED_MODULE_0__.Slice.maxOpen(normalizeSiblings(slice.content, $context), true);\n if (slice.openStart || slice.openEnd) {\n let openStart = 0, openEnd = 0;\n for (let node = slice.content.firstChild; openStart < slice.openStart && !node.type.spec.isolating; openStart++, node = node.firstChild) { }\n for (let node = slice.content.lastChild; openEnd < slice.openEnd && !node.type.spec.isolating; openEnd++, node = node.lastChild) { }\n slice = closeSlice(slice, openStart, openEnd);\n }\n }\n view.someProp(\"transformPasted\", f => { slice = f(slice, view, asText); });\n return slice;\n}\nconst inlineParents = /^(a|abbr|acronym|b|cite|code|del|em|i|ins|kbd|label|output|q|ruby|s|samp|span|strong|sub|sup|time|u|tt|var)$/i;\n// Takes a slice parsed with parseSlice, which means there hasn't been\n// any content-expression checking done on the top nodes, tries to\n// find a parent node in the current context that might fit the nodes,\n// and if successful, rebuilds the slice so that it fits into that parent.\n//\n// This addresses the problem that Transform.replace expects a\n// coherent slice, and will fail to place a set of siblings that don't\n// fit anywhere in the schema.\nfunction normalizeSiblings(fragment, $context) {\n if (fragment.childCount < 2)\n return fragment;\n for (let d = $context.depth; d >= 0; d--) {\n let parent = $context.node(d);\n let match = parent.contentMatchAt($context.index(d));\n let lastWrap, result = [];\n fragment.forEach(node => {\n if (!result)\n return;\n let wrap = match.findWrapping(node.type), inLast;\n if (!wrap)\n return result = null;\n if (inLast = result.length && lastWrap.length && addToSibling(wrap, lastWrap, node, result[result.length - 1], 0)) {\n result[result.length - 1] = inLast;\n }\n else {\n if (result.length)\n result[result.length - 1] = closeRight(result[result.length - 1], lastWrap.length);\n let wrapped = withWrappers(node, wrap);\n result.push(wrapped);\n match = match.matchType(wrapped.type);\n lastWrap = wrap;\n }\n });\n if (result)\n return prosemirror_model__WEBPACK_IMPORTED_MODULE_0__.Fragment.from(result);\n }\n return fragment;\n}\nfunction withWrappers(node, wrap, from = 0) {\n for (let i = wrap.length - 1; i >= from; i--)\n node = wrap[i].create(null, prosemirror_model__WEBPACK_IMPORTED_MODULE_0__.Fragment.from(node));\n return node;\n}\n// Used to group adjacent nodes wrapped in similar parents by\n// normalizeSiblings into the same parent node\nfunction addToSibling(wrap, lastWrap, node, sibling, depth) {\n if (depth < wrap.length && depth < lastWrap.length && wrap[depth] == lastWrap[depth]) {\n let inner = addToSibling(wrap, lastWrap, node, sibling.lastChild, depth + 1);\n if (inner)\n return sibling.copy(sibling.content.replaceChild(sibling.childCount - 1, inner));\n let match = sibling.contentMatchAt(sibling.childCount);\n if (match.matchType(depth == wrap.length - 1 ? node.type : wrap[depth + 1]))\n return sibling.copy(sibling.content.append(prosemirror_model__WEBPACK_IMPORTED_MODULE_0__.Fragment.from(withWrappers(node, wrap, depth + 1))));\n }\n}\nfunction closeRight(node, depth) {\n if (depth == 0)\n return node;\n let fragment = node.content.replaceChild(node.childCount - 1, closeRight(node.lastChild, depth - 1));\n let fill = node.contentMatchAt(node.childCount).fillBefore(prosemirror_model__WEBPACK_IMPORTED_MODULE_0__.Fragment.empty, true);\n return node.copy(fragment.append(fill));\n}\nfunction closeRange(fragment, side, from, to, depth, openEnd) {\n let node = side < 0 ? fragment.firstChild : fragment.lastChild, inner = node.content;\n if (fragment.childCount > 1)\n openEnd = 0;\n if (depth < to - 1)\n inner = closeRange(inner, side, from, to, depth + 1, openEnd);\n if (depth >= from)\n inner = side < 0 ? node.contentMatchAt(0).fillBefore(inner, openEnd <= depth).append(inner)\n : inner.append(node.contentMatchAt(node.childCount).fillBefore(prosemirror_model__WEBPACK_IMPORTED_MODULE_0__.Fragment.empty, true));\n return fragment.replaceChild(side < 0 ? 0 : fragment.childCount - 1, node.copy(inner));\n}\nfunction closeSlice(slice, openStart, openEnd) {\n if (openStart < slice.openStart)\n slice = new prosemirror_model__WEBPACK_IMPORTED_MODULE_0__.Slice(closeRange(slice.content, -1, openStart, slice.openStart, 0, slice.openEnd), openStart, slice.openEnd);\n if (openEnd < slice.openEnd)\n slice = new prosemirror_model__WEBPACK_IMPORTED_MODULE_0__.Slice(closeRange(slice.content, 1, openEnd, slice.openEnd, 0, 0), slice.openStart, openEnd);\n return slice;\n}\n// Trick from jQuery -- some elements must be wrapped in other\n// elements for innerHTML to work. I.e. if you do `div.innerHTML =\n// \"<td>..</td>\"` the table cells are ignored.\nconst wrapMap = {\n thead: [\"table\"],\n tbody: [\"table\"],\n tfoot: [\"table\"],\n caption: [\"table\"],\n colgroup: [\"table\"],\n col: [\"table\", \"colgroup\"],\n tr: [\"table\", \"tbody\"],\n td: [\"table\", \"tbody\", \"tr\"],\n th: [\"table\", \"tbody\", \"tr\"]\n};\nlet _detachedDoc = null;\nfunction detachedDoc() {\n return _detachedDoc || (_detachedDoc = document.implementation.createHTMLDocument(\"title\"));\n}\nlet _policy = null;\nfunction maybeWrapTrusted(html) {\n let trustedTypes = window.trustedTypes;\n if (!trustedTypes)\n return html;\n // With the require-trusted-types-for CSP, Chrome will block\n // innerHTML, even on a detached document. This wraps the string in\n // a way that makes the browser allow us to use its parser again.\n if (!_policy)\n _policy = trustedTypes.defaultPolicy || trustedTypes.createPolicy(\"ProseMirrorClipboard\", { createHTML: (s) => s });\n return _policy.createHTML(html);\n}\nfunction readHTML(html) {\n let metas = /^(\\s*<meta [^>]*>)*/.exec(html);\n if (metas)\n html = html.slice(metas[0].length);\n let elt = detachedDoc().createElement(\"div\");\n let firstTag = /<([a-z][^>\\s]+)/i.exec(html), wrap;\n if (wrap = firstTag && wrapMap[firstTag[1].toLowerCase()])\n html = wrap.map(n => \"<\" + n + \">\").join(\"\") + html + wrap.map(n => \"</\" + n + \">\").reverse().join(\"\");\n elt.innerHTML = maybeWrapTrusted(html);\n if (wrap)\n for (let i = 0; i < wrap.length; i++)\n elt = elt.querySelector(wrap[i]) || elt;\n return elt;\n}\n// Webkit browsers do some hard-to-predict replacement of regular\n// spaces with non-breaking spaces when putting content on the\n// clipboard. This tries to convert such non-breaking spaces (which\n// will be wrapped in a plain span on Chrome, a span with class\n// Apple-converted-space on Safari) back to regular spaces.\nfunction restoreReplacedSpaces(dom) {\n let nodes = dom.querySelectorAll(chrome ? \"span:not([class]):not([style])\" : \"span.Apple-converted-space\");\n for (let i = 0; i < nodes.length; i++) {\n let node = nodes[i];\n if (node.childNodes.length == 1 && node.textContent == \"\\u00a0\" && node.parentNode)\n node.parentNode.replaceChild(dom.ownerDocument.createTextNode(\" \"), node);\n }\n}\nfunction addContext(slice, context) {\n if (!slice.size)\n return slice;\n let schema = slice.content.firstChild.type.schema, array;\n try {\n array = JSON.parse(context);\n }\n catch (e) {\n return slice;\n }\n let { content, openStart, openEnd } = slice;\n for (let i = array.length - 2; i >= 0; i -= 2) {\n let type = schema.nodes[array[i]];\n if (!type || type.hasRequiredAttrs())\n break;\n content = prosemirror_model__WEBPACK_IMPORTED_MODULE_0__.Fragment.from(type.create(array[i + 1], content));\n openStart++;\n openEnd++;\n }\n return new prosemirror_model__WEBPACK_IMPORTED_MODULE_0__.Slice(content, openStart, openEnd);\n}\n\n// A collection of DOM events that occur within the editor, and callback functions\n// to invoke when the event fires.\nconst handlers = {};\nconst editHandlers = {};\nconst passiveHandlers = { touchstart: true, touchmove: true };\nclass InputState {\n constructor() {\n this.shiftKey = false;\n this.mouseDown = null;\n this.lastKeyCode = null;\n this.lastKeyCodeTime = 0;\n this.lastClick = { time: 0, x: 0, y: 0, type: \"\", button: 0 };\n this.lastSelectionOrigin = null;\n this.lastSelectionTime = 0;\n this.lastIOSEnter = 0;\n this.lastIOSEnterFallbackTimeout = -1;\n this.lastFocus = 0;\n this.lastTouch = 0;\n this.lastChromeDelete = 0;\n this.composing = false;\n this.compositionNode = null;\n this.composingTimeout = -1;\n this.compositionNodes = [];\n this.compositionEndedAt = -2e8;\n this.compositionID = 1;\n this.badSafariComposition = false;\n // Set to a composition ID when there are pending changes at compositionend\n this.compositionPendingChanges = 0;\n this.domChangeCount = 0;\n this.eventHandlers = Object.create(null);\n this.hideSelectionGuard = null;\n }\n}\nfunction initInput(view) {\n for (let event in handlers) {\n let handler = handlers[event];\n view.dom.addEventListener(event, view.input.eventHandlers[event] = (event) => {\n if (eventBelongsToView(view, event) && !runCustomHandler(view, event) &&\n (view.editable || !(event.type in editHandlers)))\n handler(view, event);\n }, passiveHandlers[event] ? { passive: true } : undefined);\n }\n // On Safari, for reasons beyond my understanding, adding an input\n // event handler makes an issue where the composition vanishes when\n // you press enter go away.\n if (safari)\n view.dom.addEventListener(\"input\", () => null);\n ensureListeners(view);\n}\nfunction setSelectionOrigin(view, origin) {\n view.input.lastSelectionOrigin = origin;\n view.input.lastSelectionTime = Date.now();\n}\nfunction destroyInput(view) {\n view.domObserver.stop();\n for (let type in view.input.eventHandlers)\n view.dom.removeEventListener(type, view.input.eventHandlers[type]);\n clearTimeout(view.input.composingTimeout);\n clearTimeout(view.input.lastIOSEnterFallbackTimeout);\n}\nfunction ensureListeners(view) {\n view.someProp(\"handleDOMEvents\", currentHandlers => {\n for (let type in currentHandlers)\n if (!view.input.eventHandlers[type])\n view.dom.addEventListener(type, view.input.eventHandlers[type] = event => runCustomHandler(view, event));\n });\n}\nfunction runCustomHandler(view, event) {\n return view.someProp(\"handleDOMEvents\", handlers => {\n let handler = handlers[event.type];\n return handler ? handler(view, event) || event.defaultPrevented : false;\n });\n}\nfunction eventBelongsToView(view, event) {\n if (!event.bubbles)\n return true;\n if (event.defaultPrevented)\n return false;\n for (let node = event.target; node != view.dom; node = node.parentNode)\n if (!node || node.nodeType == 11 ||\n (node.pmViewDesc && node.pmViewDesc.stopEvent(event)))\n return false;\n return true;\n}\nfunction dispatchEvent(view, event) {\n if (!runCustomHandler(view, event) && handlers[event.type] &&\n (view.editable || !(event.type in editHandlers)))\n handlers[event.type](view, event);\n}\neditHandlers.keydown = (view, _event) => {\n let event = _event;\n view.input.shiftKey = event.keyCode == 16 || event.shiftKey;\n if (inOrNearComposition(view, event))\n return;\n view.input.lastKeyCode = event.keyCode;\n view.input.lastKeyCodeTime = Date.now();\n // Suppress enter key events on Chrome Android, because those tend\n // to be part of a confused sequence of composition events fired,\n // and handling them eagerly tends to corrupt the input.\n if (android && chrome && event.keyCode == 13)\n return;\n if (event.keyCode != 229)\n view.domObserver.forceFlush();\n // On iOS, if we preventDefault enter key presses, the virtual\n // keyboard gets confused. So the hack here is to set a flag that\n // makes the DOM change code recognize that what just happens should\n // be replaced by whatever the Enter key handlers do.\n if (ios && event.keyCode == 13 && !event.ctrlKey && !event.altKey && !event.metaKey) {\n let now = Date.now();\n view.input.lastIOSEnter = now;\n view.input.lastIOSEnterFallbackTimeout = setTimeout(() => {\n if (view.input.lastIOSEnter == now) {\n view.someProp(\"handleKeyDown\", f => f(view, keyEvent(13, \"Enter\")));\n view.input.lastIOSEnter = 0;\n }\n }, 200);\n }\n else if (view.someProp(\"handleKeyDown\", f => f(view, event)) || captureKeyDown(view, event)) {\n event.preventDefault();\n }\n else {\n setSelectionOrigin(view, \"key\");\n }\n};\neditHandlers.keyup = (view, event) => {\n if (event.keyCode == 16)\n view.input.shiftKey = false;\n};\neditHandlers.keypress = (view, _event) => {\n let event = _event;\n if (inOrNearComposition(view, event) || !event.charCode ||\n event.ctrlKey && !event.altKey || mac && event.metaKey)\n return;\n if (view.someProp(\"handleKeyPress\", f => f(view, event))) {\n event.preventDefault();\n return;\n }\n let sel = view.state.selection;\n if (!(sel instanceof prosemirror_state__WEBPACK_IMPORTED_MODULE_1__.TextSelection) || !sel.$from.sameParent(sel.$to)) {\n let text = String.fromCharCode(event.charCode);\n let deflt = () => view.state.tr.insertText(text).scrollIntoView();\n if (!/[\\r\\n]/.test(text) && !view.someProp(\"handleTextInput\", f => f(view, sel.$from.pos, sel.$to.pos, text, deflt)))\n view.dispatch(deflt());\n event.preventDefault();\n }\n};\nfunction eventCoords(event) { return { left: event.clientX, top: event.clientY }; }\nfunction isNear(event, click) {\n let dx = click.x - event.clientX, dy = click.y - event.clientY;\n return dx * dx + dy * dy < 100;\n}\nfunction runHandlerOnContext(view, propName, pos, inside, event) {\n if (inside == -1)\n return false;\n let $pos = view.state.doc.resolve(inside);\n for (let i = $pos.depth + 1; i > 0; i--) {\n if (view.someProp(propName, f => i > $pos.depth ? f(view, pos, $pos.nodeAfter, $pos.before(i), event, true)\n : f(view, pos, $pos.node(i), $pos.before(i), event, false)))\n return true;\n }\n return false;\n}\nfunction updateSelection(view, selection, origin) {\n if (!view.focused)\n view.focus();\n if (view.state.selection.eq(selection))\n return;\n let tr = view.state.tr.setSelection(selection);\n if (origin == \"pointer\")\n tr.setMeta(\"pointer\", true);\n view.dispatch(tr);\n}\nfunction selectClickedLeaf(view, inside) {\n if (inside == -1)\n return false;\n let $pos = view.state.doc.resolve(inside), node = $pos.nodeAfter;\n if (node && node.isAtom && prosemirror_state__WEBPACK_IMPORTED_MODULE_1__.NodeSelection.isSelectable(node)) {\n updateSelection(view, new prosemirror_state__WEBPACK_IMPORTED_MODULE_1__.NodeSelection($pos), \"pointer\");\n return true;\n }\n return false;\n}\nfunction selectClickedNode(view, inside) {\n if (inside == -1)\n return false;\n let sel = view.state.selection, selectedNode, selectAt;\n if (sel instanceof prosemirror_state__WEBPACK_IMPORTED_MODULE_1__.NodeSelection)\n selectedNode = sel.node;\n let $pos = view.state.doc.resolve(inside);\n for (let i = $pos.depth + 1; i > 0; i--) {\n let node = i > $pos.depth ? $pos.nodeAfter : $pos.node(i);\n if (prosemirror_state__WEBPACK_IMPORTED_MODULE_1__.NodeSelection.isSelectable(node)) {\n if (selectedNode && sel.$from.depth > 0 &&\n i >= sel.$from.depth && $pos.before(sel.$from.depth + 1) == sel.$from.pos)\n selectAt = $pos.before(sel.$from.depth);\n else\n selectAt = $pos.before(i);\n break;\n }\n }\n if (selectAt != null) {\n updateSelection(view, prosemirror_state__WEBPACK_IMPORTED_MODULE_1__.NodeSelection.create(view.state.doc, selectAt), \"pointer\");\n return true;\n }\n else {\n return false;\n }\n}\nfunction handleSingleClick(view, pos, inside, event, selectNode) {\n return runHandlerOnContext(view, \"handleClickOn\", pos, inside, event) ||\n view.someProp(\"handleClick\", f => f(view, pos, event)) ||\n (selectNode ? selectClickedNode(view, inside) : selectClickedLeaf(view, inside));\n}\nfunction handleDoubleClick(view, pos, inside, event) {\n return runHandlerOnContext(view, \"handleDoubleClickOn\", pos, inside, event) ||\n view.someProp(\"handleDoubleClick\", f => f(view, pos, event));\n}\nfunction handleTripleClick(view, pos, inside, event) {\n return runHandlerOnContext(view, \"handleTripleClickOn\", pos, inside, event) ||\n view.someProp(\"handleTripleClick\", f => f(view, pos, event)) ||\n defaultTripleClick(view, inside, event);\n}\nfunction defaultTripleClick(view, inside, event) {\n if (event.button != 0)\n return false;\n let doc = view.state.doc;\n if (inside == -1) {\n if (doc.inlineContent) {\n updateSelection(view, prosemirror_state__WEBPACK_IMPORTED_MODULE_1__.TextSelection.create(doc, 0, doc.content.size), \"pointer\");\n return true;\n }\n return false;\n }\n let $pos = doc.resolve(inside);\n for (let i = $pos.depth + 1; i > 0; i--) {\n let node = i > $pos.depth ? $pos.nodeAfter : $pos.node(i);\n let nodePos = $pos.before(i);\n if (node.inlineContent)\n updateSelection(view, prosemirror_state__WEBPACK_IMPORTED_MODULE_1__.TextSelection.create(doc, nodePos + 1, nodePos + 1 + node.content.size), \"pointer\");\n else if (prosemirror_state__WEBPACK_IMPORTED_MODULE_1__.NodeSelection.isSelectable(node))\n updateSelection(view, prosemirror_state__WEBPACK_IMPORTED_MODULE_1__.NodeSelection.create(doc, nodePos), \"pointer\");\n else\n continue;\n return true;\n }\n}\nfunction forceDOMFlush(view) {\n return endComposition(view);\n}\nconst selectNodeModifier = mac ? \"metaKey\" : \"ctrlKey\";\nhandlers.mousedown = (view, _event) => {\n let event = _event;\n view.input.shiftKey = event.shiftKey;\n let flushed = forceDOMFlush(view);\n let now = Date.now(), type = \"singleClick\";\n if (now - view.input.lastClick.time < 500 && isNear(event, view.input.lastClick) && !event[selectNodeModifier] &&\n view.input.lastClick.button == event.button) {\n if (view.input.lastClick.type == \"singleClick\")\n type = \"doubleClick\";\n else if (view.input.lastClick.type == \"doubleClick\")\n type = \"tripleClick\";\n }\n view.input.lastClick = { time: now, x: event.clientX, y: event.clientY, type, button: event.button };\n let pos = view.posAtCoords(eventCoords(event));\n if (!pos)\n return;\n if (type == \"singleClick\") {\n if (view.input.mouseDown)\n view.input.mouseDown.done();\n view.input.mouseDown = new MouseDown(view, pos, event, !!flushed);\n }\n else if ((type == \"doubleClick\" ? handleDoubleClick : handleTripleClick)(view, pos.pos, pos.inside, event)) {\n event.preventDefault();\n }\n else {\n setSelectionOrigin(view, \"pointer\");\n }\n};\nclass MouseDown {\n constructor(view, pos, event, flushed) {\n this.view = view;\n this.pos = pos;\n this.event = event;\n this.flushed = flushed;\n this.delayedSelectionSync = false;\n this.mightDrag = null;\n this.startDoc = view.state.doc;\n this.selectNode = !!event[selectNodeModifier];\n this.allowDefault = event.shiftKey;\n let targetNode, targetPos;\n if (pos.inside > -1) {\n targetNode = view.state.doc.nodeAt(pos.inside);\n targetPos = pos.inside;\n }\n else {\n let $pos = view.state.doc.resolve(pos.pos);\n targetNode = $pos.parent;\n targetPos = $pos.depth ? $pos.before() : 0;\n }\n const target = flushed ? null : event.target;\n const targetDesc = target ? view.docView.nearestDesc(target, true) : null;\n this.target = targetDesc && targetDesc.nodeDOM.nodeType == 1 ? targetDesc.nodeDOM : null;\n let { selection } = view.state;\n if (event.button == 0 &&\n targetNode.type.spec.draggable && targetNode.type.spec.selectable !== false ||\n selection instanceof prosemirror_state__WEBPACK_IMPORTED_MODULE_1__.NodeSelection && selection.from <= targetPos && selection.to > targetPos)\n this.mightDrag = {\n node: targetNode,\n pos: targetPos,\n addAttr: !!(this.target && !this.target.draggable),\n setUneditable: !!(this.target && gecko && !this.target.hasAttribute(\"contentEditable\"))\n };\n if (this.target && this.mightDrag && (this.mightDrag.addAttr || this.mightDrag.setUneditable)) {\n this.view.domObserver.stop();\n if (this.mightDrag.addAttr)\n this.target.draggable = true;\n if (this.mightDrag.setUneditable)\n setTimeout(() => {\n if (this.view.input.mouseDown == this)\n this.target.setAttribute(\"contentEditable\", \"false\");\n }, 20);\n this.view.domObserver.start();\n }\n view.root.addEventListener(\"mouseup\", this.up = this.up.bind(this));\n view.root.addEventListener(\"mousemove\", this.move = this.move.bind(this));\n setSelectionOrigin(view, \"pointer\");\n }\n done() {\n this.view.root.removeEventListener(\"mouseup\", this.up);\n this.view.root.removeEventListener(\"mousemove\", this.move);\n if (this.mightDrag && this.target) {\n this.view.domObserver.stop();\n if (this.mightDrag.addAttr)\n this.target.removeAttribute(\"draggable\");\n if (this.mightDrag.setUneditable)\n this.target.removeAttribute(\"contentEditable\");\n this.view.domObserver.start();\n }\n if (this.delayedSelectionSync)\n setTimeout(() => selectionToDOM(this.view));\n this.view.input.mouseDown = null;\n }\n up(event) {\n this.done();\n if (!this.view.dom.contains(event.target))\n return;\n let pos = this.pos;\n if (this.view.state.doc != this.startDoc)\n pos = this.view.posAtCoords(eventCoords(event));\n this.updateAllowDefault(event);\n if (this.allowDefault || !pos) {\n setSelectionOrigin(this.view, \"pointer\");\n }\n else if (handleSingleClick(this.view, pos.pos, pos.inside, event, this.selectNode)) {\n event.preventDefault();\n }\n else if (event.button == 0 &&\n (this.flushed ||\n // Safari ignores clicks on draggable elements\n (safari && this.mightDrag && !this.mightDrag.node.isAtom) ||\n // Chrome will sometimes treat a node selection as a\n // cursor, but still report that the node is selected\n // when asked through getSelection. You'll then get a\n // situation where clicking at the point where that\n // (hidden) cursor is doesn't change the selection, and\n // thus doesn't get a reaction from ProseMirror. This\n // works around that.\n (chrome && !this.view.state.selection.visible &&\n Math.min(Math.abs(pos.pos - this.view.state.selection.from), Math.abs(pos.pos - this.view.state.selection.to)) <= 2))) {\n updateSelection(this.view, prosemirror_state__WEBPACK_IMPORTED_MODULE_1__.Selection.near(this.view.state.doc.resolve(pos.pos)), \"pointer\");\n event.preventDefault();\n }\n else {\n setSelectionOrigin(this.view, \"pointer\");\n }\n }\n move(event) {\n this.updateAllowDefault(event);\n setSelectionOrigin(this.view, \"pointer\");\n if (event.buttons == 0)\n this.done();\n }\n updateAllowDefault(event) {\n if (!this.allowDefault && (Math.abs(this.event.x - event.clientX) > 4 ||\n Math.abs(this.event.y - event.clientY) > 4))\n this.allowDefault = true;\n }\n}\nhandlers.touchstart = view => {\n view.input.lastTouch = Date.now();\n forceDOMFlush(view);\n setSelectionOrigin(view, \"pointer\");\n};\nhandlers.touchmove = view => {\n view.input.lastTouch = Date.now();\n setSelectionOrigin(view, \"pointer\");\n};\nhandlers.contextmenu = view => forceDOMFlush(view);\nfunction inOrNearComposition(view, event) {\n if (view.composing)\n return true;\n // See https://www.stum.de/2016/06/24/handling-ime-events-in-javascript/.\n // On Japanese input method editors (IMEs), the Enter key is used to confirm character\n // selection. On Safari, when Enter is pressed, compositionend and keydown events are\n // emitted. The keydown event triggers newline insertion, which we don't want.\n // This method returns true if the keydown event should be ignored.\n // We only ignore it once, as pressing Enter a second time *should* insert a newline.\n // Furthermore, the keydown event timestamp must be close to the compositionEndedAt timestamp.\n // This guards against the case where compositionend is triggered without the keyboard\n // (e.g. character confirmation may be done with the mouse), and keydown is triggered\n // afterwards- we wouldn't want to ignore the keydown event in this case.\n if (safari && Math.abs(event.timeStamp - view.input.compositionEndedAt) < 500) {\n view.input.compositionEndedAt = -2e8;\n return true;\n }\n return false;\n}\n// Drop active composition after 5 seconds of inactivity on Android\nconst timeoutComposition = android ? 5000 : -1;\neditHandlers.compositionstart = editHandlers.compositionupdate = view => {\n if (!view.composing) {\n view.domObserver.flush();\n let { state } = view, $pos = state.selection.$to;\n if (state.selection instanceof prosemirror_state__WEBPACK_IMPORTED_MODULE_1__.TextSelection &&\n (state.storedMarks ||\n (!$pos.textOffset && $pos.parentOffset && $pos.nodeBefore.marks.some(m => m.type.spec.inclusive === false)) ||\n chrome && windows && selectionBeforeUneditable(view))) { // Issue #1500\n // Need to wrap the cursor in mark nodes different from the ones in the DOM context\n view.markCursor = view.state.storedMarks || $pos.marks();\n endComposition(view, true);\n view.markCursor = null;\n }\n else {\n endComposition(view, !state.selection.empty);\n // In firefox, if the cursor is after but outside a marked node,\n // the inserted text won't inherit the marks. So this moves it\n // inside if necessary.\n if (gecko && state.selection.empty && $pos.parentOffset && !$pos.textOffset && $pos.nodeBefore.marks.length) {\n let sel = view.domSelectionRange();\n for (let node = sel.focusNode, offset = sel.focusOffset; node && node.nodeType == 1 && offset != 0;) {\n let before = offset < 0 ? node.lastChild : node.childNodes[offset - 1];\n if (!before)\n break;\n if (before.nodeType == 3) {\n let sel = view.domSelection();\n if (sel)\n sel.collapse(before, before.nodeValue.length);\n break;\n }\n else {\n node = before;\n offset = -1;\n }\n }\n }\n }\n view.input.composing = true;\n }\n scheduleComposeEnd(view, timeoutComposition);\n};\nfunction selectionBeforeUneditable(view) {\n let { focusNode, focusOffset } = view.domSelectionRange();\n if (!focusNode || focusNode.nodeType != 1 || focusOffset >= focusNode.childNodes.length)\n return false;\n let next = focusNode.childNodes[focusOffset];\n return next.nodeType == 1 && next.contentEditable == \"false\";\n}\neditHandlers.compositionend = (view, event) => {\n if (view.composing) {\n view.input.composing = false;\n view.input.compositionEndedAt = event.timeStamp;\n view.input.compositionPendingChanges = view.domObserver.pendingRecords().length ? view.input.compositionID : 0;\n view.input.compositionNode = null;\n if (view.input.badSafariComposition)\n view.domObserver.forceFlush();\n else if (view.input.compositionPendingChanges)\n Promise.resolve().then(() => view.domObserver.flush());\n view.input.compositionID++;\n scheduleComposeEnd(view, 20);\n }\n};\nfunction scheduleComposeEnd(view, delay) {\n clearTimeout(view.input.composingTimeout);\n if (delay > -1)\n view.input.composingTimeout = setTimeout(() => endComposition(view), delay);\n}\nfunction clearComposition(view) {\n if (view.composing) {\n view.input.composing = false;\n view.input.compositionEndedAt = timestampFromCustomEvent();\n }\n while (view.input.compositionNodes.length > 0)\n view.input.compositionNodes.pop().markParentsDirty();\n}\nfunction findCompositionNode(view) {\n let sel = view.domSelectionRange();\n if (!sel.focusNode)\n return null;\n let textBefore = textNodeBefore$1(sel.focusNode, sel.focusOffset);\n let textAfter = textNodeAfter$1(sel.focusNode, sel.focusOffset);\n if (textBefore && textAfter && textBefore != textAfter) {\n let descAfter = textAfter.pmViewDesc, lastChanged = view.domObserver.lastChangedTextNode;\n if (textBefore == lastChanged || textAfter == lastChanged)\n return lastChanged;\n if (!descAfter || !descAfter.isText(textAfter.nodeValue)) {\n return textAfter;\n }\n else if (view.input.compositionNode == textAfter) {\n let descBefore = textBefore.pmViewDesc;\n if (!(!descBefore || !descBefore.isText(textBefore.nodeValue)))\n return textAfter;\n }\n }\n return textBefore || textAfter;\n}\nfunction timestampFromCustomEvent() {\n let event = document.createEvent(\"Event\");\n event.initEvent(\"event\", true, true);\n return event.timeStamp;\n}\n/**\n@internal\n*/\nfunction endComposition(view, restarting = false) {\n if (android && view.domObserver.flushingSoon >= 0)\n return;\n view.domObserver.forceFlush();\n clearComposition(view);\n if (restarting || view.docView && view.docView.dirty) {\n let sel = selectionFromDOM(view), cur = view.state.selection;\n if (sel && !sel.eq(cur))\n view.dispatch(view.state.tr.setSelection(sel));\n else if ((view.markCursor || restarting) && !cur.$from.node(cur.$from.sharedDepth(cur.to)).inlineContent)\n view.dispatch(view.state.tr.deleteSelection());\n else\n view.updateState(view.state);\n return true;\n }\n return false;\n}\nfunction captureCopy(view, dom) {\n // The extra wrapper is somehow necessary on IE/Edge to prevent the\n // content from being mangled when it is put onto the clipboard\n if (!view.dom.parentNode)\n return;\n let wrap = view.dom.parentNode.appendChild(document.createElement(\"div\"));\n wrap.appendChild(dom);\n wrap.style.cssText = \"position: fixed; left: -10000px; top: 10px\";\n let sel = getSelection(), range = document.createRange();\n range.selectNodeContents(dom);\n // Done because IE will fire a selectionchange moving the selection\n // to its start when removeAllRanges is called and the editor still\n // has focus (which will mess up the editor's selection state).\n view.dom.blur();\n sel.removeAllRanges();\n sel.addRange(range);\n setTimeout(() => {\n if (wrap.parentNode)\n wrap.parentNode.removeChild(wrap);\n view.focus();\n }, 50);\n}\n// This is very crude, but unfortunately both these browsers _pretend_\n// that they have a clipboard API—all the objects and methods are\n// there, they just don't work, and they are hard to test.\nconst brokenClipboardAPI = (ie && ie_version < 15) ||\n (ios && webkit_version < 604);\nhandlers.copy = editHandlers.cut = (view, _event) => {\n let event = _event;\n let sel = view.state.selection, cut = event.type == \"cut\";\n if (sel.empty)\n return;\n // IE and Edge's clipboard interface is completely broken\n let data = brokenClipboardAPI ? null : event.clipboardData;\n let slice = sel.content(), { dom, text } = serializeForClipboard(view, slice);\n if (data) {\n event.preventDefault();\n data.clearData();\n data.setData(\"text/html\", dom.innerHTML);\n data.setData(\"text/plain\", text);\n }\n else {\n captureCopy(view, dom);\n }\n if (cut)\n view.dispatch(view.state.tr.deleteSelection().scrollIntoView().setMeta(\"uiEvent\", \"cut\"));\n};\nfunction sliceSingleNode(slice) {\n return slice.openStart == 0 && slice.openEnd == 0 && slice.content.childCount == 1 ? slice.content.firstChild : null;\n}\nfunction capturePaste(view, event) {\n if (!view.dom.parentNode)\n return;\n let plainText = view.input.shiftKey || view.state.selection.$from.parent.type.spec.code;\n let target = view.dom.parentNode.appendChild(document.createElement(plainText ? \"textarea\" : \"div\"));\n if (!plainText)\n target.contentEditable = \"true\";\n target.style.cssText = \"position: fixed; left: -10000px; top: 10px\";\n target.focus();\n let plain = view.input.shiftKey && view.input.lastKeyCode != 45;\n setTimeout(() => {\n view.focus();\n if (target.parentNode)\n target.parentNode.removeChild(target);\n if (plainText)\n doPaste(view, target.value, null, plain, event);\n else\n doPaste(view, target.textContent, target.innerHTML, plain, event);\n }, 50);\n}\nfunction doPaste(view, text, html, preferPlain, event) {\n let slice = parseFromClipboard(view, text, html, preferPlain, view.state.selection.$from);\n if (view.someProp(\"handlePaste\", f => f(view, event, slice || prosemirror_model__WEBPACK_IMPORTED_MODULE_0__.Slice.empty)))\n return true;\n if (!slice)\n return false;\n let singleNode = sliceSingleNode(slice);\n let tr = singleNode\n ? view.state.tr.replaceSelectionWith(singleNode, preferPlain)\n : view.state.tr.replaceSelection(slice);\n view.dispatch(tr.scrollIntoView().setMeta(\"paste\", true).setMeta(\"uiEvent\", \"paste\"));\n return true;\n}\nfunction getText(clipboardData) {\n let text = clipboardData.getData(\"text/plain\") || clipboardData.getData(\"Text\");\n if (text)\n return text;\n let uris = clipboardData.getData(\"text/uri-list\");\n return uris ? uris.replace(/\\r?\\n/g, \" \") : \"\";\n}\neditHandlers.paste = (view, _event) => {\n let event = _event;\n // Handling paste from JavaScript during composition is very poorly\n // handled by browsers, so as a dodgy but preferable kludge, we just\n // let the browser do its native thing there, except on Android,\n // where the editor is almost always composing.\n if (view.composing && !android)\n return;\n let data = brokenClipboardAPI ? null : event.clipboardData;\n let plain = view.input.shiftKey && view.input.lastKeyCode != 45;\n if (data && doPaste(view, getText(data), data.getData(\"text/html\"), plain, event))\n event.preventDefault();\n else\n capturePaste(view, event);\n};\nclass Dragging {\n constructor(slice, move, node) {\n this.slice = slice;\n this.move = move;\n this.node = node;\n }\n}\nconst dragCopyModifier = mac ? \"altKey\" : \"ctrlKey\";\nfunction dragMoves(view, event) {\n let moves = view.someProp(\"dragCopies\", test => !test(event));\n return moves != null ? moves : !event[dragCopyModifier];\n}\nhandlers.dragstart = (view, _event) => {\n let event = _event;\n let mouseDown = view.input.mouseDown;\n if (mouseDown)\n mouseDown.done();\n if (!event.dataTransfer)\n return;\n let sel = view.state.selection;\n let pos = sel.empty ? null : view.posAtCoords(eventCoords(event));\n let node;\n if (pos && pos.pos >= sel.from && pos.pos <= (sel instanceof prosemirror_state__WEBPACK_IMPORTED_MODULE_1__.NodeSelection ? sel.to - 1 : sel.to)) ;\n else if (mouseDown && mouseDown.mightDrag) {\n node = prosemirror_state__WEBPACK_IMPORTED_MODULE_1__.NodeSelection.create(view.state.doc, mouseDown.mightDrag.pos);\n }\n else if (event.target && event.target.nodeType == 1) {\n let desc = view.docView.nearestDesc(event.target, true);\n if (desc && desc.node.type.spec.draggable && desc != view.docView)\n node = prosemirror_state__WEBPACK_IMPORTED_MODULE_1__.NodeSelection.create(view.state.doc, desc.posBefore);\n }\n let draggedSlice = (node || view.state.selection).content();\n let { dom, text, slice } = serializeForClipboard(view, draggedSlice);\n // Pre-120 Chrome versions clear files when calling `clearData` (#1472)\n if (!event.dataTransfer.files.length || !chrome || chrome_version > 120)\n event.dataTransfer.clearData();\n event.dataTransfer.setData(brokenClipboardAPI ? \"Text\" : \"text/html\", dom.innerHTML);\n // See https://github.com/ProseMirror/prosemirror/issues/1156\n event.dataTransfer.effectAllowed = \"copyMove\";\n if (!brokenClipboardAPI)\n event.dataTransfer.setData(\"text/plain\", text);\n view.dragging = new Dragging(slice, dragMoves(view, event), node);\n};\nhandlers.dragend = view => {\n let dragging = view.dragging;\n window.setTimeout(() => {\n if (view.dragging == dragging)\n view.dragging = null;\n }, 50);\n};\neditHandlers.dragover = editHandlers.dragenter = (_, e) => e.preventDefault();\neditHandlers.drop = (view, event) => {\n try {\n handleDrop(view, event, view.dragging);\n }\n finally {\n view.dragging = null;\n }\n};\nfunction handleDrop(view, event, dragging) {\n if (!event.dataTransfer)\n return;\n let eventPos = view.posAtCoords(eventCoords(event));\n if (!eventPos)\n return;\n let $mouse = view.state.doc.resolve(eventPos.pos);\n let slice = dragging && dragging.slice;\n if (slice) {\n view.someProp(\"transformPasted\", f => { slice = f(slice, view, false); });\n }\n else {\n slice = parseFromClipboard(view, getText(event.dataTransfer), brokenClipboardAPI ? null : event.dataTransfer.getData(\"text/html\"), false, $mouse);\n }\n let move = !!(dragging && dragMoves(view, event));\n if (view.someProp(\"handleDrop\", f => f(view, event, slice || prosemirror_model__WEBPACK_IMPORTED_MODULE_0__.Slice.empty, move))) {\n event.preventDefault();\n return;\n }\n if (!slice)\n return;\n event.preventDefault();\n let insertPos = slice ? (0,prosemirror_transform__WEBPACK_IMPORTED_MODULE_2__.dropPoint)(view.state.doc, $mouse.pos, slice) : $mouse.pos;\n if (insertPos == null)\n insertPos = $mouse.pos;\n let tr = view.state.tr;\n if (move) {\n let { node } = dragging;\n if (node)\n node.replace(tr);\n else\n tr.deleteSelection();\n }\n let pos = tr.mapping.map(insertPos);\n let isNode = slice.openStart == 0 && slice.openEnd == 0 && slice.content.childCount == 1;\n let beforeInsert = tr.doc;\n if (isNode)\n tr.replaceRangeWith(pos, pos, slice.content.firstChild);\n else\n tr.replaceRange(pos, pos, slice);\n if (tr.doc.eq(beforeInsert))\n return;\n let $pos = tr.doc.resolve(pos);\n if (isNode && prosemirror_state__WEBPACK_IMPORTED_MODULE_1__.NodeSelection.isSelectable(slice.content.firstChild) &&\n $pos.nodeAfter && $pos.nodeAfter.sameMarkup(slice.content.firstChild)) {\n tr.setSelection(new prosemirror_state__WEBPACK_IMPORTED_MODULE_1__.NodeSelection($pos));\n }\n else {\n let end = tr.mapping.map(insertPos);\n tr.mapping.maps[tr.mapping.maps.length - 1].forEach((_from, _to, _newFrom, newTo) => end = newTo);\n tr.setSelection(selectionBetween(view, $pos, tr.doc.resolve(end)));\n }\n view.focus();\n view.dispatch(tr.setMeta(\"uiEvent\", \"drop\"));\n}\nhandlers.focus = view => {\n view.input.lastFocus = Date.now();\n if (!view.focused) {\n view.domObserver.stop();\n view.dom.classList.add(\"ProseMirror-focused\");\n view.domObserver.start();\n view.focused = true;\n setTimeout(() => {\n if (view.docView && view.hasFocus() && !view.domObserver.currentSelection.eq(view.domSelectionRange()))\n selectionToDOM(view);\n }, 20);\n }\n};\nhandlers.blur = (view, _event) => {\n let event = _event;\n if (view.focused) {\n view.domObserver.stop();\n view.dom.classList.remove(\"ProseMirror-focused\");\n view.domObserver.start();\n if (event.relatedTarget && view.dom.contains(event.relatedTarget))\n view.domObserver.currentSelection.clear();\n view.focused = false;\n }\n};\nhandlers.beforeinput = (view, _event) => {\n let event = _event;\n // We should probably do more with beforeinput events, but support\n // is so spotty that I'm still waiting to see where they are going.\n // Very specific hack to deal with backspace sometimes failing on\n // Chrome Android when after an uneditable node.\n if (chrome && android && event.inputType == \"deleteContentBackward\") {\n view.domObserver.flushSoon();\n let { domChangeCount } = view.input;\n setTimeout(() => {\n if (view.input.domChangeCount != domChangeCount)\n return; // Event already had some effect\n // This bug tends to close the virtual keyboard, so we refocus\n view.dom.blur();\n view.focus();\n if (view.someProp(\"handleKeyDown\", f => f(view, keyEvent(8, \"Backspace\"))))\n return;\n let { $cursor } = view.state.selection;\n // Crude approximation of backspace behavior when no command handled it\n if ($cursor && $cursor.pos > 0)\n view.dispatch(view.state.tr.delete($cursor.pos - 1, $cursor.pos).scrollIntoView());\n }, 50);\n }\n};\n// Make sure all handlers get registered\nfor (let prop in editHandlers)\n handlers[prop] = editHandlers[prop];\n\nfunction compareObjs(a, b) {\n if (a == b)\n return true;\n for (let p in a)\n if (a[p] !== b[p])\n return false;\n for (let p in b)\n if (!(p in a))\n return false;\n return true;\n}\nclass WidgetType {\n constructor(toDOM, spec) {\n this.toDOM = toDOM;\n this.spec = spec || noSpec;\n this.side = this.spec.side || 0;\n }\n map(mapping, span, offset, oldOffset) {\n let { pos, deleted } = mapping.mapResult(span.from + oldOffset, this.side < 0 ? -1 : 1);\n return deleted ? null : new Decoration(pos - offset, pos - offset, this);\n }\n valid() { return true; }\n eq(other) {\n return this == other ||\n (other instanceof WidgetType &&\n (this.spec.key && this.spec.key == other.spec.key ||\n this.toDOM == other.toDOM && compareObjs(this.spec, other.spec)));\n }\n destroy(node) {\n if (this.spec.destroy)\n this.spec.destroy(node);\n }\n}\nclass InlineType {\n constructor(attrs, spec) {\n this.attrs = attrs;\n this.spec = spec || noSpec;\n }\n map(mapping, span, offset, oldOffset) {\n let from = mapping.map(span.from + oldOffset, this.spec.inclusiveStart ? -1 : 1) - offset;\n let to = mapping.map(span.to + oldOffset, this.spec.inclusiveEnd ? 1 : -1) - offset;\n return from >= to ? null : new Decoration(from, to, this);\n }\n valid(_, span) { return span.from < span.to; }\n eq(other) {\n return this == other ||\n (other instanceof InlineType && compareObjs(this.attrs, other.attrs) &&\n compareObjs(this.spec, other.spec));\n }\n static is(span) { return span.type instanceof InlineType; }\n destroy() { }\n}\nclass NodeType {\n constructor(attrs, spec) {\n this.attrs = attrs;\n this.spec = spec || noSpec;\n }\n map(mapping, span, offset, oldOffset) {\n let from = mapping.mapResult(span.from + oldOffset, 1);\n if (from.deleted)\n return null;\n let to = mapping.mapResult(span.to + oldOffset, -1);\n if (to.deleted || to.pos <= from.pos)\n return null;\n return new Decoration(from.pos - offset, to.pos - offset, this);\n }\n valid(node, span) {\n let { index, offset } = node.content.findIndex(span.from), child;\n return offset == span.from && !(child = node.child(index)).isText && offset + child.nodeSize == span.to;\n }\n eq(other) {\n return this == other ||\n (other instanceof NodeType && compareObjs(this.attrs, other.attrs) &&\n compareObjs(this.spec, other.spec));\n }\n destroy() { }\n}\n/**\nDecoration objects can be provided to the view through the\n[`decorations` prop](https://prosemirror.net/docs/ref/#view.EditorProps.decorations). They come in\nseveral variants—see the static members of this class for details.\n*/\nclass Decoration {\n /**\n @internal\n */\n constructor(\n /**\n The start position of the decoration.\n */\n from, \n /**\n The end position. Will be the same as `from` for [widget\n decorations](https://prosemirror.net/docs/ref/#view.Decoration^widget).\n */\n to, \n /**\n @internal\n */\n type) {\n this.from = from;\n this.to = to;\n this.type = type;\n }\n /**\n @internal\n */\n copy(from, to) {\n return new Decoration(from, to, this.type);\n }\n /**\n @internal\n */\n eq(other, offset = 0) {\n return this.type.eq(other.type) && this.from + offset == other.from && this.to + offset == other.to;\n }\n /**\n @internal\n */\n map(mapping, offset, oldOffset) {\n return this.type.map(mapping, this, offset, oldOffset);\n }\n /**\n Creates a widget decoration, which is a DOM node that's shown in\n the document at the given position. It is recommended that you\n delay rendering the widget by passing a function that will be\n called when the widget is actually drawn in a view, but you can\n also directly pass a DOM node. `getPos` can be used to find the\n widget's current document position.\n */\n static widget(pos, toDOM, spec) {\n return new Decoration(pos, pos, new WidgetType(toDOM, spec));\n }\n /**\n Creates an inline decoration, which adds the given attributes to\n each inline node between `from` and `to`.\n */\n static inline(from, to, attrs, spec) {\n return new Decoration(from, to, new InlineType(attrs, spec));\n }\n /**\n Creates a node decoration. `from` and `to` should point precisely\n before and after a node in the document. That node, and only that\n node, will receive the given attributes.\n */\n static node(from, to, attrs, spec) {\n return new Decoration(from, to, new NodeType(attrs, spec));\n }\n /**\n The spec provided when creating this decoration. Can be useful\n if you've stored extra information in that object.\n */\n get spec() { return this.type.spec; }\n /**\n @internal\n */\n get inline() { return this.type instanceof InlineType; }\n /**\n @internal\n */\n get widget() { return this.type instanceof WidgetType; }\n}\nconst none = [], noSpec = {};\n/**\nA collection of [decorations](https://prosemirror.net/docs/ref/#view.Decoration), organized in such\na way that the drawing algorithm can efficiently use and compare\nthem. This is a persistent data structure—it is not modified,\nupdates create a new value.\n*/\nclass DecorationSet {\n /**\n @internal\n */\n constructor(local, children) {\n this.local = local.length ? local : none;\n this.children = children.length ? children : none;\n }\n /**\n Create a set of decorations, using the structure of the given\n document. This will consume (modify) the `decorations` array, so\n you must make a copy if you want need to preserve that.\n */\n static create(doc, decorations) {\n return decorations.length ? buildTree(decorations, doc, 0, noSpec) : empty;\n }\n /**\n Find all decorations in this set which touch the given range\n (including decorations that start or end directly at the\n boundaries) and match the given predicate on their spec. When\n `start` and `end` are omitted, all decorations in the set are\n considered. When `predicate` isn't given, all decorations are\n assumed to match.\n */\n find(start, end, predicate) {\n let result = [];\n this.findInner(start == null ? 0 : start, end == null ? 1e9 : end, result, 0, predicate);\n return result;\n }\n findInner(start, end, result, offset, predicate) {\n for (let i = 0; i < this.local.length; i++) {\n let span = this.local[i];\n if (span.from <= end && span.to >= start && (!predicate || predicate(span.spec)))\n result.push(span.copy(span.from + offset, span.to + offset));\n }\n for (let i = 0; i < this.children.length; i += 3) {\n if (this.children[i] < end && this.children[i + 1] > start) {\n let childOff = this.children[i] + 1;\n this.children[i + 2].findInner(start - childOff, end - childOff, result, offset + childOff, predicate);\n }\n }\n }\n /**\n Map the set of decorations in response to a change in the\n document.\n */\n map(mapping, doc, options) {\n if (this == empty || mapping.maps.length == 0)\n return this;\n return this.mapInner(mapping, doc, 0, 0, options || noSpec);\n }\n /**\n @internal\n */\n mapInner(mapping, node, offset, oldOffset, options) {\n let newLocal;\n for (let i = 0; i < this.local.length; i++) {\n let mapped = this.local[i].map(mapping, offset, oldOffset);\n if (mapped && mapped.type.valid(node, mapped))\n (newLocal || (newLocal = [])).push(mapped);\n else if (options.onRemove)\n options.onRemove(this.local[i].spec);\n }\n if (this.children.length)\n return mapChildren(this.children, newLocal || [], mapping, node, offset, oldOffset, options);\n else\n return newLocal ? new DecorationSet(newLocal.sort(byPos), none) : empty;\n }\n /**\n Add the given array of decorations to the ones in the set,\n producing a new set. Consumes the `decorations` array. Needs\n access to the current document to create the appropriate tree\n structure.\n */\n add(doc, decorations) {\n if (!decorations.length)\n return this;\n if (this == empty)\n return DecorationSet.create(doc, decorations);\n return this.addInner(doc, decorations, 0);\n }\n addInner(doc, decorations, offset) {\n let children, childIndex = 0;\n doc.forEach((childNode, childOffset) => {\n let baseOffset = childOffset + offset, found;\n if (!(found = takeSpansForNode(decorations, childNode, baseOffset)))\n return;\n if (!children)\n children = this.children.slice();\n while (childIndex < children.length && children[childIndex] < childOffset)\n childIndex += 3;\n if (children[childIndex] == childOffset)\n children[childIndex + 2] = children[childIndex + 2].addInner(childNode, found, baseOffset + 1);\n else\n children.splice(childIndex, 0, childOffset, childOffset + childNode.nodeSize, buildTree(found, childNode, baseOffset + 1, noSpec));\n childIndex += 3;\n });\n let local = moveSpans(childIndex ? withoutNulls(decorations) : decorations, -offset);\n for (let i = 0; i < local.length; i++)\n if (!local[i].type.valid(doc, local[i]))\n local.splice(i--, 1);\n return new DecorationSet(local.length ? this.local.concat(local).sort(byPos) : this.local, children || this.children);\n }\n /**\n Create a new set that contains the decorations in this set, minus\n the ones in the given array.\n */\n remove(decorations) {\n if (decorations.length == 0 || this == empty)\n return this;\n return this.removeInner(decorations, 0);\n }\n removeInner(decorations, offset) {\n let children = this.children, local = this.local;\n for (let i = 0; i < children.length; i += 3) {\n let found;\n let from = children[i] + offset, to = children[i + 1] + offset;\n for (let j = 0, span; j < decorations.length; j++)\n if (span = decorations[j]) {\n if (span.from > from && span.to < to) {\n decorations[j] = null;\n (found || (found = [])).push(span);\n }\n }\n if (!found)\n continue;\n if (children == this.children)\n children = this.children.slice();\n let removed = children[i + 2].removeInner(found, from + 1);\n if (removed != empty) {\n children[i + 2] = removed;\n }\n else {\n children.splice(i, 3);\n i -= 3;\n }\n }\n if (local.length)\n for (let i = 0, span; i < decorations.length; i++)\n if (span = decorations[i]) {\n for (let j = 0; j < local.length; j++)\n if (local[j].eq(span, offset)) {\n if (local == this.local)\n local = this.local.slice();\n local.splice(j--, 1);\n }\n }\n if (children == this.children && local == this.local)\n return this;\n return local.length || children.length ? new DecorationSet(local, children) : empty;\n }\n forChild(offset, node) {\n if (this == empty)\n return this;\n if (node.isLeaf)\n return DecorationSet.empty;\n let child, local;\n for (let i = 0; i < this.children.length; i += 3)\n if (this.children[i] >= offset) {\n if (this.children[i] == offset)\n child = this.children[i + 2];\n break;\n }\n let start = offset + 1, end = start + node.content.size;\n for (let i = 0; i < this.local.length; i++) {\n let dec = this.local[i];\n if (dec.from < end && dec.to > start && (dec.type instanceof InlineType)) {\n let from = Math.max(start, dec.from) - start, to = Math.min(end, dec.to) - start;\n if (from < to)\n (local || (local = [])).push(dec.copy(from, to));\n }\n }\n if (local) {\n let localSet = new DecorationSet(local.sort(byPos), none);\n return child ? new DecorationGroup([localSet, child]) : localSet;\n }\n return child || empty;\n }\n /**\n @internal\n */\n eq(other) {\n if (this == other)\n return true;\n if (!(other instanceof DecorationSet) ||\n this.local.length != other.local.length ||\n this.children.length != other.children.length)\n return false;\n for (let i = 0; i < this.local.length; i++)\n if (!this.local[i].eq(other.local[i]))\n return false;\n for (let i = 0; i < this.children.length; i += 3)\n if (this.children[i] != other.children[i] ||\n this.children[i + 1] != other.children[i + 1] ||\n !this.children[i + 2].eq(other.children[i + 2]))\n return false;\n return true;\n }\n /**\n @internal\n */\n locals(node) {\n return removeOverlap(this.localsInner(node));\n }\n /**\n @internal\n */\n localsInner(node) {\n if (this == empty)\n return none;\n if (node.inlineContent || !this.local.some(InlineType.is))\n return this.local;\n let result = [];\n for (let i = 0; i < this.local.length; i++) {\n if (!(this.local[i].type instanceof InlineType))\n result.push(this.local[i]);\n }\n return result;\n }\n forEachSet(f) { f(this); }\n}\n/**\nThe empty set of decorations.\n*/\nDecorationSet.empty = new DecorationSet([], []);\n/**\n@internal\n*/\nDecorationSet.removeOverlap = removeOverlap;\nconst empty = DecorationSet.empty;\n// An abstraction that allows the code dealing with decorations to\n// treat multiple DecorationSet objects as if it were a single object\n// with (a subset of) the same interface.\nclass DecorationGroup {\n constructor(members) {\n this.members = members;\n }\n map(mapping, doc) {\n const mappedDecos = this.members.map(member => member.map(mapping, doc, noSpec));\n return DecorationGroup.from(mappedDecos);\n }\n forChild(offset, child) {\n if (child.isLeaf)\n return DecorationSet.empty;\n let found = [];\n for (let i = 0; i < this.members.length; i++) {\n let result = this.members[i].forChild(offset, child);\n if (result == empty)\n continue;\n if (result instanceof DecorationGroup)\n found = found.concat(result.members);\n else\n found.push(result);\n }\n return DecorationGroup.from(found);\n }\n eq(other) {\n if (!(other instanceof DecorationGroup) ||\n other.members.length != this.members.length)\n return false;\n for (let i = 0; i < this.members.length; i++)\n if (!this.members[i].eq(other.members[i]))\n return false;\n return true;\n }\n locals(node) {\n let result, sorted = true;\n for (let i = 0; i < this.members.length; i++) {\n let locals = this.members[i].localsInner(node);\n if (!locals.length)\n continue;\n if (!result) {\n result = locals;\n }\n else {\n if (sorted) {\n result = result.slice();\n sorted = false;\n }\n for (let j = 0; j < locals.length; j++)\n result.push(locals[j]);\n }\n }\n return result ? removeOverlap(sorted ? result : result.sort(byPos)) : none;\n }\n // Create a group for the given array of decoration sets, or return\n // a single set when possible.\n static from(members) {\n switch (members.length) {\n case 0: return empty;\n case 1: return members[0];\n default: return new DecorationGroup(members.every(m => m instanceof DecorationSet) ? members :\n members.reduce((r, m) => r.concat(m instanceof DecorationSet ? m : m.members), []));\n }\n }\n forEachSet(f) {\n for (let i = 0; i < this.members.length; i++)\n this.members[i].forEachSet(f);\n }\n}\nfunction mapChildren(oldChildren, newLocal, mapping, node, offset, oldOffset, options) {\n let children = oldChildren.slice();\n // Mark the children that are directly touched by changes, and\n // move those that are after the changes.\n for (let i = 0, baseOffset = oldOffset; i < mapping.maps.length; i++) {\n let moved = 0;\n mapping.maps[i].forEach((oldStart, oldEnd, newStart, newEnd) => {\n let dSize = (newEnd - newStart) - (oldEnd - oldStart);\n for (let i = 0; i < children.length; i += 3) {\n let end = children[i + 1];\n if (end < 0 || oldStart > end + baseOffset - moved)\n continue;\n let start = children[i] + baseOffset - moved;\n if (oldEnd >= start) {\n children[i + 1] = oldStart <= start ? -2 : -1;\n }\n else if (oldStart >= baseOffset && dSize) {\n children[i] += dSize;\n children[i + 1] += dSize;\n }\n }\n moved += dSize;\n });\n baseOffset = mapping.maps[i].map(baseOffset, -1);\n }\n // Find the child nodes that still correspond to a single node,\n // recursively call mapInner on them and update their positions.\n let mustRebuild = false;\n for (let i = 0; i < children.length; i += 3)\n if (children[i + 1] < 0) { // Touched nodes\n if (children[i + 1] == -2) {\n mustRebuild = true;\n children[i + 1] = -1;\n continue;\n }\n let from = mapping.map(oldChildren[i] + oldOffset), fromLocal = from - offset;\n if (fromLocal < 0 || fromLocal >= node.content.size) {\n mustRebuild = true;\n continue;\n }\n // Must read oldChildren because children was tagged with -1\n let to = mapping.map(oldChildren[i + 1] + oldOffset, -1), toLocal = to - offset;\n let { index, offset: childOffset } = node.content.findIndex(fromLocal);\n let childNode = node.maybeChild(index);\n if (childNode && childOffset == fromLocal && childOffset + childNode.nodeSize == toLocal) {\n let mapped = children[i + 2]\n .mapInner(mapping, childNode, from + 1, oldChildren[i] + oldOffset + 1, options);\n if (mapped != empty) {\n children[i] = fromLocal;\n children[i + 1] = toLocal;\n children[i + 2] = mapped;\n }\n else {\n children[i + 1] = -2;\n mustRebuild = true;\n }\n }\n else {\n mustRebuild = true;\n }\n }\n // Remaining children must be collected and rebuilt into the appropriate structure\n if (mustRebuild) {\n let decorations = mapAndGatherRemainingDecorations(children, oldChildren, newLocal, mapping, offset, oldOffset, options);\n let built = buildTree(decorations, node, 0, options);\n newLocal = built.local;\n for (let i = 0; i < children.length; i += 3)\n if (children[i + 1] < 0) {\n children.splice(i, 3);\n i -= 3;\n }\n for (let i = 0, j = 0; i < built.children.length; i += 3) {\n let from = built.children[i];\n while (j < children.length && children[j] < from)\n j += 3;\n children.splice(j, 0, built.children[i], built.children[i + 1], built.children[i + 2]);\n }\n }\n return new DecorationSet(newLocal.sort(byPos), children);\n}\nfunction moveSpans(spans, offset) {\n if (!offset || !spans.length)\n return spans;\n let result = [];\n for (let i = 0; i < spans.length; i++) {\n let span = spans[i];\n result.push(new Decoration(span.from + offset, span.to + offset, span.type));\n }\n return result;\n}\nfunction mapAndGatherRemainingDecorations(children, oldChildren, decorations, mapping, offset, oldOffset, options) {\n // Gather all decorations from the remaining marked children\n function gather(set, oldOffset) {\n for (let i = 0; i < set.local.length; i++) {\n let mapped = set.local[i].map(mapping, offset, oldOffset);\n if (mapped)\n decorations.push(mapped);\n else if (options.onRemove)\n options.onRemove(set.local[i].spec);\n }\n for (let i = 0; i < set.children.length; i += 3)\n gather(set.children[i + 2], set.children[i] + oldOffset + 1);\n }\n for (let i = 0; i < children.length; i += 3)\n if (children[i + 1] == -1)\n gather(children[i + 2], oldChildren[i] + oldOffset + 1);\n return decorations;\n}\nfunction takeSpansForNode(spans, node, offset) {\n if (node.isLeaf)\n return null;\n let end = offset + node.nodeSize, found = null;\n for (let i = 0, span; i < spans.length; i++) {\n if ((span = spans[i]) && span.from > offset && span.to < end) {\n (found || (found = [])).push(span);\n spans[i] = null;\n }\n }\n return found;\n}\nfunction withoutNulls(array) {\n let result = [];\n for (let i = 0; i < array.length; i++)\n if (array[i] != null)\n result.push(array[i]);\n return result;\n}\n// Build up a tree that corresponds to a set of decorations. `offset`\n// is a base offset that should be subtracted from the `from` and `to`\n// positions in the spans (so that we don't have to allocate new spans\n// for recursive calls).\nfunction buildTree(spans, node, offset, options) {\n let children = [], hasNulls = false;\n node.forEach((childNode, localStart) => {\n let found = takeSpansForNode(spans, childNode, localStart + offset);\n if (found) {\n hasNulls = true;\n let subtree = buildTree(found, childNode, offset + localStart + 1, options);\n if (subtree != empty)\n children.push(localStart, localStart + childNode.nodeSize, subtree);\n }\n });\n let locals = moveSpans(hasNulls ? withoutNulls(spans) : spans, -offset).sort(byPos);\n for (let i = 0; i < locals.length; i++)\n if (!locals[i].type.valid(node, locals[i])) {\n if (options.onRemove)\n options.onRemove(locals[i].spec);\n locals.splice(i--, 1);\n }\n return locals.length || children.length ? new DecorationSet(locals, children) : empty;\n}\n// Used to sort decorations so that ones with a low start position\n// come first, and within a set with the same start position, those\n// with an smaller end position come first.\nfunction byPos(a, b) {\n return a.from - b.from || a.to - b.to;\n}\n// Scan a sorted array of decorations for partially overlapping spans,\n// and split those so that only fully overlapping spans are left (to\n// make subsequent rendering easier). Will return the input array if\n// no partially overlapping spans are found (the common case).\nfunction removeOverlap(spans) {\n let working = spans;\n for (let i = 0; i < working.length - 1; i++) {\n let span = working[i];\n if (span.from != span.to)\n for (let j = i + 1; j < working.length; j++) {\n let next = working[j];\n if (next.from == span.from) {\n if (next.to != span.to) {\n if (working == spans)\n working = spans.slice();\n // Followed by a partially overlapping larger span. Split that\n // span.\n working[j] = next.copy(next.from, span.to);\n insertAhead(working, j + 1, next.copy(span.to, next.to));\n }\n continue;\n }\n else {\n if (next.from < span.to) {\n if (working == spans)\n working = spans.slice();\n // The end of this one overlaps with a subsequent span. Split\n // this one.\n working[i] = span.copy(span.from, next.from);\n insertAhead(working, j, span.copy(next.from, span.to));\n }\n break;\n }\n }\n }\n return working;\n}\nfunction insertAhead(array, i, deco) {\n while (i < array.length && byPos(deco, array[i]) > 0)\n i++;\n array.splice(i, 0, deco);\n}\n// Get the decorations associated with the current props of a view.\nfunction viewDecorations(view) {\n let found = [];\n view.someProp(\"decorations\", f => {\n let result = f(view.state);\n if (result && result != empty)\n found.push(result);\n });\n if (view.cursorWrapper)\n found.push(DecorationSet.create(view.state.doc, [view.cursorWrapper.deco]));\n return DecorationGroup.from(found);\n}\n\nconst observeOptions = {\n childList: true,\n characterData: true,\n characterDataOldValue: true,\n attributes: true,\n attributeOldValue: true,\n subtree: true\n};\n// IE11 has very broken mutation observers, so we also listen to DOMCharacterDataModified\nconst useCharData = ie && ie_version <= 11;\nclass SelectionState {\n constructor() {\n this.anchorNode = null;\n this.anchorOffset = 0;\n this.focusNode = null;\n this.focusOffset = 0;\n }\n set(sel) {\n this.anchorNode = sel.anchorNode;\n this.anchorOffset = sel.anchorOffset;\n this.focusNode = sel.focusNode;\n this.focusOffset = sel.focusOffset;\n }\n clear() {\n this.anchorNode = this.focusNode = null;\n }\n eq(sel) {\n return sel.anchorNode == this.anchorNode && sel.anchorOffset == this.anchorOffset &&\n sel.focusNode == this.focusNode && sel.focusOffset == this.focusOffset;\n }\n}\nclass DOMObserver {\n constructor(view, handleDOMChange) {\n this.view = view;\n this.handleDOMChange = handleDOMChange;\n this.queue = [];\n this.flushingSoon = -1;\n this.observer = null;\n this.currentSelection = new SelectionState;\n this.onCharData = null;\n this.suppressingSelectionUpdates = false;\n this.lastChangedTextNode = null;\n this.observer = window.MutationObserver &&\n new window.MutationObserver(mutations => {\n for (let i = 0; i < mutations.length; i++)\n this.queue.push(mutations[i]);\n if (ie && ie_version <= 11 && mutations.some(m => m.type == \"childList\" && m.removedNodes.length ||\n m.type == \"characterData\" && m.oldValue.length > m.target.nodeValue.length)) {\n // IE11 will sometimes (on backspacing out a single character\n // text node after a BR node) call the observer callback\n // before actually updating the DOM, which will cause\n // ProseMirror to miss the change (see #930)\n this.flushSoon();\n }\n else if (safari && view.composing && mutations.some(m => m.type == \"childList\" && m.target.nodeName == \"TR\")) {\n // Safari does weird stuff when finishing a composition in a\n // table cell, which tends to involve inserting inappropriate\n // nodes in the table row.\n view.input.badSafariComposition = true;\n this.flushSoon();\n }\n else {\n this.flush();\n }\n });\n if (useCharData) {\n this.onCharData = e => {\n this.queue.push({ target: e.target, type: \"characterData\", oldValue: e.prevValue });\n this.flushSoon();\n };\n }\n this.onSelectionChange = this.onSelectionChange.bind(this);\n }\n flushSoon() {\n if (this.flushingSoon < 0)\n this.flushingSoon = window.setTimeout(() => { this.flushingSoon = -1; this.flush(); }, 20);\n }\n forceFlush() {\n if (this.flushingSoon > -1) {\n window.clearTimeout(this.flushingSoon);\n this.flushingSoon = -1;\n this.flush();\n }\n }\n start() {\n if (this.observer) {\n this.observer.takeRecords();\n this.observer.observe(this.view.dom, observeOptions);\n }\n if (this.onCharData)\n this.view.dom.addEventListener(\"DOMCharacterDataModified\", this.onCharData);\n this.connectSelection();\n }\n stop() {\n if (this.observer) {\n let take = this.observer.takeRecords();\n if (take.length) {\n for (let i = 0; i < take.length; i++)\n this.queue.push(take[i]);\n window.setTimeout(() => this.flush(), 20);\n }\n this.observer.disconnect();\n }\n if (this.onCharData)\n this.view.dom.removeEventListener(\"DOMCharacterDataModified\", this.onCharData);\n this.disconnectSelection();\n }\n connectSelection() {\n this.view.dom.ownerDocument.addEventListener(\"selectionchange\", this.onSelectionChange);\n }\n disconnectSelection() {\n this.view.dom.ownerDocument.removeEventListener(\"selectionchange\", this.onSelectionChange);\n }\n suppressSelectionUpdates() {\n this.suppressingSelectionUpdates = true;\n setTimeout(() => this.suppressingSelectionUpdates = false, 50);\n }\n onSelectionChange() {\n if (!hasFocusAndSelection(this.view))\n return;\n if (this.suppressingSelectionUpdates)\n return selectionToDOM(this.view);\n // Deletions on IE11 fire their events in the wrong order, giving\n // us a selection change event before the DOM changes are\n // reported.\n if (ie && ie_version <= 11 && !this.view.state.selection.empty) {\n let sel = this.view.domSelectionRange();\n // Selection.isCollapsed isn't reliable on IE\n if (sel.focusNode && isEquivalentPosition(sel.focusNode, sel.focusOffset, sel.anchorNode, sel.anchorOffset))\n return this.flushSoon();\n }\n this.flush();\n }\n setCurSelection() {\n this.currentSelection.set(this.view.domSelectionRange());\n }\n ignoreSelectionChange(sel) {\n if (!sel.focusNode)\n return true;\n let ancestors = new Set, container;\n for (let scan = sel.focusNode; scan; scan = parentNode(scan))\n ancestors.add(scan);\n for (let scan = sel.anchorNode; scan; scan = parentNode(scan))\n if (ancestors.has(scan)) {\n container = scan;\n break;\n }\n let desc = container && this.view.docView.nearestDesc(container);\n if (desc && desc.ignoreMutation({\n type: \"selection\",\n target: container.nodeType == 3 ? container.parentNode : container\n })) {\n this.setCurSelection();\n return true;\n }\n }\n pendingRecords() {\n if (this.observer)\n for (let mut of this.observer.takeRecords())\n this.queue.push(mut);\n return this.queue;\n }\n flush() {\n let { view } = this;\n if (!view.docView || this.flushingSoon > -1)\n return;\n let mutations = this.pendingRecords();\n if (mutations.length)\n this.queue = [];\n let sel = view.domSelectionRange();\n let newSel = !this.suppressingSelectionUpdates && !this.currentSelection.eq(sel) && hasFocusAndSelection(view) && !this.ignoreSelectionChange(sel);\n let from = -1, to = -1, typeOver = false, added = [];\n if (view.editable) {\n for (let i = 0; i < mutations.length; i++) {\n let result = this.registerMutation(mutations[i], added);\n if (result) {\n from = from < 0 ? result.from : Math.min(result.from, from);\n to = to < 0 ? result.to : Math.max(result.to, to);\n if (result.typeOver)\n typeOver = true;\n }\n }\n }\n if (added.some(n => n.nodeName == \"BR\") && (view.input.lastKeyCode == 8 || view.input.lastKeyCode == 46)) {\n // Browsers sometimes insert a bogus break node if you\n // backspace out the last bit of text before an inline-flex node (#1552)\n for (let node of added)\n if (node.nodeName == \"BR\" && node.parentNode) {\n let after = node.nextSibling;\n if (after && after.nodeType == 1 && after.contentEditable == \"false\")\n node.parentNode.removeChild(node);\n }\n }\n else if (gecko && added.length) {\n let brs = added.filter(n => n.nodeName == \"BR\");\n if (brs.length == 2) {\n let [a, b] = brs;\n if (a.parentNode && a.parentNode.parentNode == b.parentNode)\n b.remove();\n else\n a.remove();\n }\n else {\n let { focusNode } = this.currentSelection;\n for (let br of brs) {\n let parent = br.parentNode;\n if (parent && parent.nodeName == \"LI\" && (!focusNode || blockParent(view, focusNode) != parent))\n br.remove();\n }\n }\n }\n let readSel = null;\n // If it looks like the browser has reset the selection to the\n // start of the document after focus, restore the selection from\n // the state\n if (from < 0 && newSel && view.input.lastFocus > Date.now() - 200 &&\n Math.max(view.input.lastTouch, view.input.lastClick.time) < Date.now() - 300 &&\n selectionCollapsed(sel) && (readSel = selectionFromDOM(view)) &&\n readSel.eq(prosemirror_state__WEBPACK_IMPORTED_MODULE_1__.Selection.near(view.state.doc.resolve(0), 1))) {\n view.input.lastFocus = 0;\n selectionToDOM(view);\n this.currentSelection.set(sel);\n view.scrollToSelection();\n }\n else if (from > -1 || newSel) {\n if (from > -1) {\n view.docView.markDirty(from, to);\n checkCSS(view);\n }\n if (view.input.badSafariComposition) {\n view.input.badSafariComposition = false;\n fixUpBadSafariComposition(view, added);\n }\n this.handleDOMChange(from, to, typeOver, added);\n if (view.docView && view.docView.dirty)\n view.updateState(view.state);\n else if (!this.currentSelection.eq(sel))\n selectionToDOM(view);\n this.currentSelection.set(sel);\n }\n }\n registerMutation(mut, added) {\n // Ignore mutations inside nodes that were already noted as inserted\n if (added.indexOf(mut.target) > -1)\n return null;\n let desc = this.view.docView.nearestDesc(mut.target);\n if (mut.type == \"attributes\" &&\n (desc == this.view.docView || mut.attributeName == \"contenteditable\" ||\n // Firefox sometimes fires spurious events for null/empty styles\n (mut.attributeName == \"style\" && !mut.oldValue && !mut.target.getAttribute(\"style\"))))\n return null;\n if (!desc || desc.ignoreMutation(mut))\n return null;\n if (mut.type == \"childList\") {\n for (let i = 0; i < mut.addedNodes.length; i++) {\n let node = mut.addedNodes[i];\n added.push(node);\n if (node.nodeType == 3)\n this.lastChangedTextNode = node;\n }\n if (desc.contentDOM && desc.contentDOM != desc.dom && !desc.contentDOM.contains(mut.target))\n return { from: desc.posBefore, to: desc.posAfter };\n let prev = mut.previousSibling, next = mut.nextSibling;\n if (ie && ie_version <= 11 && mut.addedNodes.length) {\n // IE11 gives us incorrect next/prev siblings for some\n // insertions, so if there are added nodes, recompute those\n for (let i = 0; i < mut.addedNodes.length; i++) {\n let { previousSibling, nextSibling } = mut.addedNodes[i];\n if (!previousSibling || Array.prototype.indexOf.call(mut.addedNodes, previousSibling) < 0)\n prev = previousSibling;\n if (!nextSibling || Array.prototype.indexOf.call(mut.addedNodes, nextSibling) < 0)\n next = nextSibling;\n }\n }\n let fromOffset = prev && prev.parentNode == mut.target\n ? domIndex(prev) + 1 : 0;\n let from = desc.localPosFromDOM(mut.target, fromOffset, -1);\n let toOffset = next && next.parentNode == mut.target\n ? domIndex(next) : mut.target.childNodes.length;\n let to = desc.localPosFromDOM(mut.target, toOffset, 1);\n return { from, to };\n }\n else if (mut.type == \"attributes\") {\n return { from: desc.posAtStart - desc.border, to: desc.posAtEnd + desc.border };\n }\n else { // \"characterData\"\n this.lastChangedTextNode = mut.target;\n return {\n from: desc.posAtStart,\n to: desc.posAtEnd,\n // An event was generated for a text change that didn't change\n // any text. Mark the dom change to fall back to assuming the\n // selection was typed over with an identical value if it can't\n // find another change.\n typeOver: mut.target.nodeValue == mut.oldValue\n };\n }\n }\n}\nlet cssChecked = new WeakMap();\nlet cssCheckWarned = false;\nfunction checkCSS(view) {\n if (cssChecked.has(view))\n return;\n cssChecked.set(view, null);\n if (['normal', 'nowrap', 'pre-line'].indexOf(getComputedStyle(view.dom).whiteSpace) !== -1) {\n view.requiresGeckoHackNode = gecko;\n if (cssCheckWarned)\n return;\n console[\"warn\"](\"ProseMirror expects the CSS white-space property to be set, preferably to 'pre-wrap'. It is recommended to load style/prosemirror.css from the prosemirror-view package.\");\n cssCheckWarned = true;\n }\n}\nfunction rangeToSelectionRange(view, range) {\n let anchorNode = range.startContainer, anchorOffset = range.startOffset;\n let focusNode = range.endContainer, focusOffset = range.endOffset;\n let currentAnchor = view.domAtPos(view.state.selection.anchor);\n // Since such a range doesn't distinguish between anchor and head,\n // use a heuristic that flips it around if its end matches the\n // current anchor.\n if (isEquivalentPosition(currentAnchor.node, currentAnchor.offset, focusNode, focusOffset))\n [anchorNode, anchorOffset, focusNode, focusOffset] = [focusNode, focusOffset, anchorNode, anchorOffset];\n return { anchorNode, anchorOffset, focusNode, focusOffset };\n}\n// Used to work around a Safari Selection/shadow DOM bug\n// Based on https://github.com/codemirror/dev/issues/414 fix\nfunction safariShadowSelectionRange(view, selection) {\n if (selection.getComposedRanges) {\n let range = selection.getComposedRanges(view.root)[0];\n if (range)\n return rangeToSelectionRange(view, range);\n }\n let found;\n function read(event) {\n event.preventDefault();\n event.stopImmediatePropagation();\n found = event.getTargetRanges()[0];\n }\n // Because Safari (at least in 2018-2022) doesn't provide regular\n // access to the selection inside a shadowRoot, we have to perform a\n // ridiculous hack to get at it—using `execCommand` to trigger a\n // `beforeInput` event so that we can read the target range from the\n // event.\n view.dom.addEventListener(\"beforeinput\", read, true);\n document.execCommand(\"indent\");\n view.dom.removeEventListener(\"beforeinput\", read, true);\n return found ? rangeToSelectionRange(view, found) : null;\n}\nfunction blockParent(view, node) {\n for (let p = node.parentNode; p && p != view.dom; p = p.parentNode) {\n let desc = view.docView.nearestDesc(p, true);\n if (desc && desc.node.isBlock)\n return p;\n }\n return null;\n}\n// Kludge for a Safari bug where, on ending a composition in an\n// otherwise empty table cell, it randomly moves the composed text\n// into the table row around that cell, greatly confusing everything\n// (#188).\nfunction fixUpBadSafariComposition(view, addedNodes) {\n var _a;\n let { focusNode, focusOffset } = view.domSelectionRange();\n for (let node of addedNodes) {\n if (((_a = node.parentNode) === null || _a === void 0 ? void 0 : _a.nodeName) == \"TR\") {\n let nextCell = node.nextSibling;\n while (nextCell && (nextCell.nodeName != \"TD\" && nextCell.nodeName != \"TH\"))\n nextCell = nextCell.nextSibling;\n if (nextCell) {\n let parent = nextCell;\n for (;;) {\n let first = parent.firstChild;\n if (!first || first.nodeType != 1 || first.contentEditable == \"false\" ||\n /^(BR|IMG)$/.test(first.nodeName))\n break;\n parent = first;\n }\n parent.insertBefore(node, parent.firstChild);\n if (focusNode == node)\n view.domSelection().collapse(node, focusOffset);\n }\n else {\n node.parentNode.removeChild(node);\n }\n }\n }\n}\n\n// Note that all referencing and parsing is done with the\n// start-of-operation selection and document, since that's the one\n// that the DOM represents. If any changes came in in the meantime,\n// the modification is mapped over those before it is applied, in\n// readDOMChange.\nfunction parseBetween(view, from_, to_) {\n let { node: parent, fromOffset, toOffset, from, to } = view.docView.parseRange(from_, to_);\n let domSel = view.domSelectionRange();\n let find;\n let anchor = domSel.anchorNode;\n if (anchor && view.dom.contains(anchor.nodeType == 1 ? anchor : anchor.parentNode)) {\n find = [{ node: anchor, offset: domSel.anchorOffset }];\n if (!selectionCollapsed(domSel))\n find.push({ node: domSel.focusNode, offset: domSel.focusOffset });\n }\n // Work around issue in Chrome where backspacing sometimes replaces\n // the deleted content with a random BR node (issues #799, #831)\n if (chrome && view.input.lastKeyCode === 8) {\n for (let off = toOffset; off > fromOffset; off--) {\n let node = parent.childNodes[off - 1], desc = node.pmViewDesc;\n if (node.nodeName == \"BR\" && !desc) {\n toOffset = off;\n break;\n }\n if (!desc || desc.size)\n break;\n }\n }\n let startDoc = view.state.doc;\n let parser = view.someProp(\"domParser\") || prosemirror_model__WEBPACK_IMPORTED_MODULE_0__.DOMParser.fromSchema(view.state.schema);\n let $from = startDoc.resolve(from);\n let sel = null, doc = parser.parse(parent, {\n topNode: $from.parent,\n topMatch: $from.parent.contentMatchAt($from.index()),\n topOpen: true,\n from: fromOffset,\n to: toOffset,\n preserveWhitespace: $from.parent.type.whitespace == \"pre\" ? \"full\" : true,\n findPositions: find,\n ruleFromNode,\n context: $from\n });\n if (find && find[0].pos != null) {\n let anchor = find[0].pos, head = find[1] && find[1].pos;\n if (head == null)\n head = anchor;\n sel = { anchor: anchor + from, head: head + from };\n }\n return { doc, sel, from, to };\n}\nfunction ruleFromNode(dom) {\n let desc = dom.pmViewDesc;\n if (desc) {\n return desc.parseRule();\n }\n else if (dom.nodeName == \"BR\" && dom.parentNode) {\n // Safari replaces the list item or table cell with a BR\n // directly in the list node (?!) if you delete the last\n // character in a list item or table cell (#708, #862)\n if (safari && /^(ul|ol)$/i.test(dom.parentNode.nodeName)) {\n let skip = document.createElement(\"div\");\n skip.appendChild(document.createElement(\"li\"));\n return { skip };\n }\n else if (dom.parentNode.lastChild == dom || safari && /^(tr|table)$/i.test(dom.parentNode.nodeName)) {\n return { ignore: true };\n }\n }\n else if (dom.nodeName == \"IMG\" && dom.getAttribute(\"mark-placeholder\")) {\n return { ignore: true };\n }\n return null;\n}\nconst isInline = /^(a|abbr|acronym|b|bd[io]|big|br|button|cite|code|data(list)?|del|dfn|em|i|img|ins|kbd|label|map|mark|meter|output|q|ruby|s|samp|small|span|strong|su[bp]|time|u|tt|var)$/i;\nfunction readDOMChange(view, from, to, typeOver, addedNodes) {\n let compositionID = view.input.compositionPendingChanges || (view.composing ? view.input.compositionID : 0);\n view.input.compositionPendingChanges = 0;\n if (from < 0) {\n let origin = view.input.lastSelectionTime > Date.now() - 50 ? view.input.lastSelectionOrigin : null;\n let newSel = selectionFromDOM(view, origin);\n if (newSel && !view.state.selection.eq(newSel)) {\n if (chrome && android &&\n view.input.lastKeyCode === 13 && Date.now() - 100 < view.input.lastKeyCodeTime &&\n view.someProp(\"handleKeyDown\", f => f(view, keyEvent(13, \"Enter\"))))\n return;\n let tr = view.state.tr.setSelection(newSel);\n if (origin == \"pointer\")\n tr.setMeta(\"pointer\", true);\n else if (origin == \"key\")\n tr.scrollIntoView();\n if (compositionID)\n tr.setMeta(\"composition\", compositionID);\n view.dispatch(tr);\n }\n return;\n }\n let $before = view.state.doc.resolve(from);\n let shared = $before.sharedDepth(to);\n from = $before.before(shared + 1);\n to = view.state.doc.resolve(to).after(shared + 1);\n let sel = view.state.selection;\n let parse = parseBetween(view, from, to);\n let doc = view.state.doc, compare = doc.slice(parse.from, parse.to);\n let preferredPos, preferredSide;\n // Prefer anchoring to end when Backspace is pressed\n if (view.input.lastKeyCode === 8 && Date.now() - 100 < view.input.lastKeyCodeTime) {\n preferredPos = view.state.selection.to;\n preferredSide = \"end\";\n }\n else {\n preferredPos = view.state.selection.from;\n preferredSide = \"start\";\n }\n view.input.lastKeyCode = null;\n let change = findDiff(compare.content, parse.doc.content, parse.from, preferredPos, preferredSide);\n if (change)\n view.input.domChangeCount++;\n if ((ios && view.input.lastIOSEnter > Date.now() - 225 || android) &&\n addedNodes.some(n => n.nodeType == 1 && !isInline.test(n.nodeName)) &&\n (!change || change.endA >= change.endB) &&\n view.someProp(\"handleKeyDown\", f => f(view, keyEvent(13, \"Enter\")))) {\n view.input.lastIOSEnter = 0;\n return;\n }\n if (!change) {\n if (typeOver && sel instanceof prosemirror_state__WEBPACK_IMPORTED_MODULE_1__.TextSelection && !sel.empty && sel.$head.sameParent(sel.$anchor) &&\n !view.composing && !(parse.sel && parse.sel.anchor != parse.sel.head)) {\n change = { start: sel.from, endA: sel.to, endB: sel.to };\n }\n else {\n if (parse.sel) {\n let sel = resolveSelection(view, view.state.doc, parse.sel);\n if (sel && !sel.eq(view.state.selection)) {\n let tr = view.state.tr.setSelection(sel);\n if (compositionID)\n tr.setMeta(\"composition\", compositionID);\n view.dispatch(tr);\n }\n }\n return;\n }\n }\n // Handle the case where overwriting a selection by typing matches\n // the start or end of the selected content, creating a change\n // that's smaller than what was actually overwritten.\n if (view.state.selection.from < view.state.selection.to &&\n change.start == change.endB &&\n view.state.selection instanceof prosemirror_state__WEBPACK_IMPORTED_MODULE_1__.TextSelection) {\n if (change.start > view.state.selection.from && change.start <= view.state.selection.from + 2 &&\n view.state.selection.from >= parse.from) {\n change.start = view.state.selection.from;\n }\n else if (change.endA < view.state.selection.to && change.endA >= view.state.selection.to - 2 &&\n view.state.selection.to <= parse.to) {\n change.endB += (view.state.selection.to - change.endA);\n change.endA = view.state.selection.to;\n }\n }\n // IE11 will insert a non-breaking space _ahead_ of the space after\n // the cursor space when adding a space before another space. When\n // that happened, adjust the change to cover the space instead.\n if (ie && ie_version <= 11 && change.endB == change.start + 1 &&\n change.endA == change.start && change.start > parse.from &&\n parse.doc.textBetween(change.start - parse.from - 1, change.start - parse.from + 1) == \" \\u00a0\") {\n change.start--;\n change.endA--;\n change.endB--;\n }\n let $from = parse.doc.resolveNoCache(change.start - parse.from);\n let $to = parse.doc.resolveNoCache(change.endB - parse.from);\n let $fromA = doc.resolve(change.start);\n let inlineChange = $from.sameParent($to) && $from.parent.inlineContent && $fromA.end() >= change.endA;\n // If this looks like the effect of pressing Enter (or was recorded\n // as being an iOS enter press), just dispatch an Enter key instead.\n if (((ios && view.input.lastIOSEnter > Date.now() - 225 &&\n (!inlineChange || addedNodes.some(n => n.nodeName == \"DIV\" || n.nodeName == \"P\"))) ||\n (!inlineChange && $from.pos < parse.doc.content.size &&\n (!$from.sameParent($to) || !$from.parent.inlineContent) &&\n $from.pos < $to.pos && !/\\S/.test(parse.doc.textBetween($from.pos, $to.pos, \"\", \"\")))) &&\n view.someProp(\"handleKeyDown\", f => f(view, keyEvent(13, \"Enter\")))) {\n view.input.lastIOSEnter = 0;\n return;\n }\n // Same for backspace\n if (view.state.selection.anchor > change.start &&\n looksLikeBackspace(doc, change.start, change.endA, $from, $to) &&\n view.someProp(\"handleKeyDown\", f => f(view, keyEvent(8, \"Backspace\")))) {\n if (android && chrome)\n view.domObserver.suppressSelectionUpdates(); // #820\n return;\n }\n // Chrome will occasionally, during composition, delete the\n // entire composition and then immediately insert it again. This is\n // used to detect that situation.\n if (chrome && change.endB == change.start)\n view.input.lastChromeDelete = Date.now();\n // This tries to detect Android virtual keyboard\n // enter-and-pick-suggestion action. That sometimes (see issue\n // #1059) first fires a DOM mutation, before moving the selection to\n // the newly created block. And then, because ProseMirror cleans up\n // the DOM selection, it gives up moving the selection entirely,\n // leaving the cursor in the wrong place. When that happens, we drop\n // the new paragraph from the initial change, and fire a simulated\n // enter key afterwards.\n if (android && !inlineChange && $from.start() != $to.start() && $to.parentOffset == 0 && $from.depth == $to.depth &&\n parse.sel && parse.sel.anchor == parse.sel.head && parse.sel.head == change.endA) {\n change.endB -= 2;\n $to = parse.doc.resolveNoCache(change.endB - parse.from);\n setTimeout(() => {\n view.someProp(\"handleKeyDown\", function (f) { return f(view, keyEvent(13, \"Enter\")); });\n }, 20);\n }\n let chFrom = change.start, chTo = change.endA;\n let mkTr = (base) => {\n let tr = base || view.state.tr.replace(chFrom, chTo, parse.doc.slice(change.start - parse.from, change.endB - parse.from));\n if (parse.sel) {\n let sel = resolveSelection(view, tr.doc, parse.sel);\n // Chrome will sometimes, during composition, report the\n // selection in the wrong place. If it looks like that is\n // happening, don't update the selection.\n // Edge just doesn't move the cursor forward when you start typing\n // in an empty block or between br nodes.\n if (sel && !(chrome && view.composing && sel.empty &&\n (change.start != change.endB || view.input.lastChromeDelete < Date.now() - 100) &&\n (sel.head == chFrom || sel.head == tr.mapping.map(chTo) - 1) ||\n ie && sel.empty && sel.head == chFrom))\n tr.setSelection(sel);\n }\n if (compositionID)\n tr.setMeta(\"composition\", compositionID);\n return tr.scrollIntoView();\n };\n let markChange;\n if (inlineChange) {\n if ($from.pos == $to.pos) { // Deletion\n // IE11 sometimes weirdly moves the DOM selection around after\n // backspacing out the first element in a textblock\n if (ie && ie_version <= 11 && $from.parentOffset == 0) {\n view.domObserver.suppressSelectionUpdates();\n setTimeout(() => selectionToDOM(view), 20);\n }\n let tr = mkTr(view.state.tr.delete(chFrom, chTo));\n let marks = doc.resolve(change.start).marksAcross(doc.resolve(change.endA));\n if (marks)\n tr.ensureMarks(marks);\n view.dispatch(tr);\n }\n else if ( // Adding or removing a mark\n change.endA == change.endB &&\n (markChange = isMarkChange($from.parent.content.cut($from.parentOffset, $to.parentOffset), $fromA.parent.content.cut($fromA.parentOffset, change.endA - $fromA.start())))) {\n let tr = mkTr(view.state.tr);\n if (markChange.type == \"add\")\n tr.addMark(chFrom, chTo, markChange.mark);\n else\n tr.removeMark(chFrom, chTo, markChange.mark);\n view.dispatch(tr);\n }\n else if ($from.parent.child($from.index()).isText && $from.index() == $to.index() - ($to.textOffset ? 0 : 1)) {\n // Both positions in the same text node -- simply insert text\n let text = $from.parent.textBetween($from.parentOffset, $to.parentOffset);\n let deflt = () => mkTr(view.state.tr.insertText(text, chFrom, chTo));\n if (!view.someProp(\"handleTextInput\", f => f(view, chFrom, chTo, text, deflt)))\n view.dispatch(deflt());\n }\n else {\n view.dispatch(mkTr());\n }\n }\n else {\n view.dispatch(mkTr());\n }\n}\nfunction resolveSelection(view, doc, parsedSel) {\n if (Math.max(parsedSel.anchor, parsedSel.head) > doc.content.size)\n return null;\n return selectionBetween(view, doc.resolve(parsedSel.anchor), doc.resolve(parsedSel.head));\n}\n// Given two same-length, non-empty fragments of inline content,\n// determine whether the first could be created from the second by\n// removing or adding a single mark type.\nfunction isMarkChange(cur, prev) {\n let curMarks = cur.firstChild.marks, prevMarks = prev.firstChild.marks;\n let added = curMarks, removed = prevMarks, type, mark, update;\n for (let i = 0; i < prevMarks.length; i++)\n added = prevMarks[i].removeFromSet(added);\n for (let i = 0; i < curMarks.length; i++)\n removed = curMarks[i].removeFromSet(removed);\n if (added.length == 1 && removed.length == 0) {\n mark = added[0];\n type = \"add\";\n update = (node) => node.mark(mark.addToSet(node.marks));\n }\n else if (added.length == 0 && removed.length == 1) {\n mark = removed[0];\n type = \"remove\";\n update = (node) => node.mark(mark.removeFromSet(node.marks));\n }\n else {\n return null;\n }\n let updated = [];\n for (let i = 0; i < prev.childCount; i++)\n updated.push(update(prev.child(i)));\n if (prosemirror_model__WEBPACK_IMPORTED_MODULE_0__.Fragment.from(updated).eq(cur))\n return { mark, type };\n}\nfunction looksLikeBackspace(old, start, end, $newStart, $newEnd) {\n if ( // The content must have shrunk\n end - start <= $newEnd.pos - $newStart.pos ||\n // newEnd must point directly at or after the end of the block that newStart points into\n skipClosingAndOpening($newStart, true, false) < $newEnd.pos)\n return false;\n let $start = old.resolve(start);\n // Handle the case where, rather than joining blocks, the change just removed an entire block\n if (!$newStart.parent.isTextblock) {\n let after = $start.nodeAfter;\n return after != null && end == start + after.nodeSize;\n }\n // Start must be at the end of a block\n if ($start.parentOffset < $start.parent.content.size || !$start.parent.isTextblock)\n return false;\n let $next = old.resolve(skipClosingAndOpening($start, true, true));\n // The next textblock must start before end and end near it\n if (!$next.parent.isTextblock || $next.pos > end ||\n skipClosingAndOpening($next, true, false) < end)\n return false;\n // The fragments after the join point must match\n return $newStart.parent.content.cut($newStart.parentOffset).eq($next.parent.content);\n}\nfunction skipClosingAndOpening($pos, fromEnd, mayOpen) {\n let depth = $pos.depth, end = fromEnd ? $pos.end() : $pos.pos;\n while (depth > 0 && (fromEnd || $pos.indexAfter(depth) == $pos.node(depth).childCount)) {\n depth--;\n end++;\n fromEnd = false;\n }\n if (mayOpen) {\n let next = $pos.node(depth).maybeChild($pos.indexAfter(depth));\n while (next && !next.isLeaf) {\n next = next.firstChild;\n end++;\n }\n }\n return end;\n}\nfunction findDiff(a, b, pos, preferredPos, preferredSide) {\n let start = a.findDiffStart(b, pos);\n if (start == null)\n return null;\n let { a: endA, b: endB } = a.findDiffEnd(b, pos + a.size, pos + b.size);\n if (preferredSide == \"end\") {\n let adjust = Math.max(0, start - Math.min(endA, endB));\n preferredPos -= endA + adjust - start;\n }\n if (endA < start && a.size < b.size) {\n let move = preferredPos <= start && preferredPos >= endA ? start - preferredPos : 0;\n start -= move;\n if (start && start < b.size && isSurrogatePair(b.textBetween(start - 1, start + 1)))\n start += move ? 1 : -1;\n endB = start + (endB - endA);\n endA = start;\n }\n else if (endB < start) {\n let move = preferredPos <= start && preferredPos >= endB ? start - preferredPos : 0;\n start -= move;\n if (start && start < a.size && isSurrogatePair(a.textBetween(start - 1, start + 1)))\n start += move ? 1 : -1;\n endA = start + (endA - endB);\n endB = start;\n }\n return { start, endA, endB };\n}\nfunction isSurrogatePair(str) {\n if (str.length != 2)\n return false;\n let a = str.charCodeAt(0), b = str.charCodeAt(1);\n return a >= 0xDC00 && a <= 0xDFFF && b >= 0xD800 && b <= 0xDBFF;\n}\n\n/**\n@internal\n*/\nconst __parseFromClipboard = parseFromClipboard;\n/**\n@internal\n*/\nconst __endComposition = endComposition;\n/**\nAn editor view manages the DOM structure that represents an\neditable document. Its state and behavior are determined by its\n[props](https://prosemirror.net/docs/ref/#view.DirectEditorProps).\n*/\nclass EditorView {\n /**\n Create a view. `place` may be a DOM node that the editor should\n be appended to, a function that will place it into the document,\n or an object whose `mount` property holds the node to use as the\n document container. If it is `null`, the editor will not be\n added to the document.\n */\n constructor(place, props) {\n this._root = null;\n /**\n @internal\n */\n this.focused = false;\n /**\n Kludge used to work around a Chrome bug @internal\n */\n this.trackWrites = null;\n this.mounted = false;\n /**\n @internal\n */\n this.markCursor = null;\n /**\n @internal\n */\n this.cursorWrapper = null;\n /**\n @internal\n */\n this.lastSelectedViewDesc = undefined;\n /**\n @internal\n */\n this.input = new InputState;\n this.prevDirectPlugins = [];\n this.pluginViews = [];\n /**\n Holds `true` when a hack node is needed in Firefox to prevent the\n [space is eaten issue](https://github.com/ProseMirror/prosemirror/issues/651)\n @internal\n */\n this.requiresGeckoHackNode = false;\n /**\n When editor content is being dragged, this object contains\n information about the dragged slice and whether it is being\n copied or moved. At any other time, it is null.\n */\n this.dragging = null;\n this._props = props;\n this.state = props.state;\n this.directPlugins = props.plugins || [];\n this.directPlugins.forEach(checkStateComponent);\n this.dispatch = this.dispatch.bind(this);\n this.dom = (place && place.mount) || document.createElement(\"div\");\n if (place) {\n if (place.appendChild)\n place.appendChild(this.dom);\n else if (typeof place == \"function\")\n place(this.dom);\n else if (place.mount)\n this.mounted = true;\n }\n this.editable = getEditable(this);\n updateCursorWrapper(this);\n this.nodeViews = buildNodeViews(this);\n this.docView = docViewDesc(this.state.doc, computeDocDeco(this), viewDecorations(this), this.dom, this);\n this.domObserver = new DOMObserver(this, (from, to, typeOver, added) => readDOMChange(this, from, to, typeOver, added));\n this.domObserver.start();\n initInput(this);\n this.updatePluginViews();\n }\n /**\n Holds `true` when a\n [composition](https://w3c.github.io/uievents/#events-compositionevents)\n is active.\n */\n get composing() { return this.input.composing; }\n /**\n The view's current [props](https://prosemirror.net/docs/ref/#view.EditorProps).\n */\n get props() {\n if (this._props.state != this.state) {\n let prev = this._props;\n this._props = {};\n for (let name in prev)\n this._props[name] = prev[name];\n this._props.state = this.state;\n }\n return this._props;\n }\n /**\n Update the view's props. Will immediately cause an update to\n the DOM.\n */\n update(props) {\n if (props.handleDOMEvents != this._props.handleDOMEvents)\n ensureListeners(this);\n let prevProps = this._props;\n this._props = props;\n if (props.plugins) {\n props.plugins.forEach(checkStateComponent);\n this.directPlugins = props.plugins;\n }\n this.updateStateInner(props.state, prevProps);\n }\n /**\n Update the view by updating existing props object with the object\n given as argument. Equivalent to `view.update(Object.assign({},\n view.props, props))`.\n */\n setProps(props) {\n let updated = {};\n for (let name in this._props)\n updated[name] = this._props[name];\n updated.state = this.state;\n for (let name in props)\n updated[name] = props[name];\n this.update(updated);\n }\n /**\n Update the editor's `state` prop, without touching any of the\n other props.\n */\n updateState(state) {\n this.updateStateInner(state, this._props);\n }\n updateStateInner(state, prevProps) {\n var _a;\n let prev = this.state, redraw = false, updateSel = false;\n // When stored marks are added, stop composition, so that they can\n // be displayed.\n if (state.storedMarks && this.composing) {\n clearComposition(this);\n updateSel = true;\n }\n this.state = state;\n let pluginsChanged = prev.plugins != state.plugins || this._props.plugins != prevProps.plugins;\n if (pluginsChanged || this._props.plugins != prevProps.plugins || this._props.nodeViews != prevProps.nodeViews) {\n let nodeViews = buildNodeViews(this);\n if (changedNodeViews(nodeViews, this.nodeViews)) {\n this.nodeViews = nodeViews;\n redraw = true;\n }\n }\n if (pluginsChanged || prevProps.handleDOMEvents != this._props.handleDOMEvents) {\n ensureListeners(this);\n }\n this.editable = getEditable(this);\n updateCursorWrapper(this);\n let innerDeco = viewDecorations(this), outerDeco = computeDocDeco(this);\n let scroll = prev.plugins != state.plugins && !prev.doc.eq(state.doc) ? \"reset\"\n : state.scrollToSelection > prev.scrollToSelection ? \"to selection\" : \"preserve\";\n let updateDoc = redraw || !this.docView.matchesNode(state.doc, outerDeco, innerDeco);\n if (updateDoc || !state.selection.eq(prev.selection))\n updateSel = true;\n let oldScrollPos = scroll == \"preserve\" && updateSel && this.dom.style.overflowAnchor == null && storeScrollPos(this);\n if (updateSel) {\n this.domObserver.stop();\n // Work around an issue in Chrome, IE, and Edge where changing\n // the DOM around an active selection puts it into a broken\n // state where the thing the user sees differs from the\n // selection reported by the Selection object (#710, #973,\n // #1011, #1013, #1035).\n let forceSelUpdate = updateDoc && (ie || chrome) && !this.composing &&\n !prev.selection.empty && !state.selection.empty && selectionContextChanged(prev.selection, state.selection);\n if (updateDoc) {\n // If the node that the selection points into is written to,\n // Chrome sometimes starts misreporting the selection, so this\n // tracks that and forces a selection reset when our update\n // did write to the node.\n let chromeKludge = chrome ? (this.trackWrites = this.domSelectionRange().focusNode) : null;\n if (this.composing)\n this.input.compositionNode = findCompositionNode(this);\n if (redraw || !this.docView.update(state.doc, outerDeco, innerDeco, this)) {\n this.docView.updateOuterDeco(outerDeco);\n this.docView.destroy();\n this.docView = docViewDesc(state.doc, outerDeco, innerDeco, this.dom, this);\n }\n if (chromeKludge && (!this.trackWrites || !this.dom.contains(this.trackWrites)))\n forceSelUpdate = true;\n }\n // Work around for an issue where an update arriving right between\n // a DOM selection change and the \"selectionchange\" event for it\n // can cause a spurious DOM selection update, disrupting mouse\n // drag selection.\n if (forceSelUpdate ||\n !(this.input.mouseDown && this.domObserver.currentSelection.eq(this.domSelectionRange()) &&\n anchorInRightPlace(this))) {\n selectionToDOM(this, forceSelUpdate);\n }\n else {\n syncNodeSelection(this, state.selection);\n this.domObserver.setCurSelection();\n }\n this.domObserver.start();\n }\n this.updatePluginViews(prev);\n if (((_a = this.dragging) === null || _a === void 0 ? void 0 : _a.node) && !prev.doc.eq(state.doc))\n this.updateDraggedNode(this.dragging, prev);\n if (scroll == \"reset\") {\n this.dom.scrollTop = 0;\n }\n else if (scroll == \"to selection\") {\n this.scrollToSelection();\n }\n else if (oldScrollPos) {\n resetScrollPos(oldScrollPos);\n }\n }\n /**\n @internal\n */\n scrollToSelection() {\n let startDOM = this.domSelectionRange().focusNode;\n if (!startDOM || !this.dom.contains(startDOM.nodeType == 1 ? startDOM : startDOM.parentNode)) ;\n else if (this.someProp(\"handleScrollToSelection\", f => f(this))) ;\n else if (this.state.selection instanceof prosemirror_state__WEBPACK_IMPORTED_MODULE_1__.NodeSelection) {\n let target = this.docView.domAfterPos(this.state.selection.from);\n if (target.nodeType == 1)\n scrollRectIntoView(this, target.getBoundingClientRect(), startDOM);\n }\n else {\n scrollRectIntoView(this, this.coordsAtPos(this.state.selection.head, 1), startDOM);\n }\n }\n destroyPluginViews() {\n let view;\n while (view = this.pluginViews.pop())\n if (view.destroy)\n view.destroy();\n }\n updatePluginViews(prevState) {\n if (!prevState || prevState.plugins != this.state.plugins || this.directPlugins != this.prevDirectPlugins) {\n this.prevDirectPlugins = this.directPlugins;\n this.destroyPluginViews();\n for (let i = 0; i < this.directPlugins.length; i++) {\n let plugin = this.directPlugins[i];\n if (plugin.spec.view)\n this.pluginViews.push(plugin.spec.view(this));\n }\n for (let i = 0; i < this.state.plugins.length; i++) {\n let plugin = this.state.plugins[i];\n if (plugin.spec.view)\n this.pluginViews.push(plugin.spec.view(this));\n }\n }\n else {\n for (let i = 0; i < this.pluginViews.length; i++) {\n let pluginView = this.pluginViews[i];\n if (pluginView.update)\n pluginView.update(this, prevState);\n }\n }\n }\n updateDraggedNode(dragging, prev) {\n let sel = dragging.node, found = -1;\n if (this.state.doc.nodeAt(sel.from) == sel.node) {\n found = sel.from;\n }\n else {\n let movedPos = sel.from + (this.state.doc.content.size - prev.doc.content.size);\n let moved = movedPos > 0 && this.state.doc.nodeAt(movedPos);\n if (moved == sel.node)\n found = movedPos;\n }\n this.dragging = new Dragging(dragging.slice, dragging.move, found < 0 ? undefined : prosemirror_state__WEBPACK_IMPORTED_MODULE_1__.NodeSelection.create(this.state.doc, found));\n }\n someProp(propName, f) {\n let prop = this._props && this._props[propName], value;\n if (prop != null && (value = f ? f(prop) : prop))\n return value;\n for (let i = 0; i < this.directPlugins.length; i++) {\n let prop = this.directPlugins[i].props[propName];\n if (prop != null && (value = f ? f(prop) : prop))\n return value;\n }\n let plugins = this.state.plugins;\n if (plugins)\n for (let i = 0; i < plugins.length; i++) {\n let prop = plugins[i].props[propName];\n if (prop != null && (value = f ? f(prop) : prop))\n return value;\n }\n }\n /**\n Query whether the view has focus.\n */\n hasFocus() {\n // Work around IE not handling focus correctly if resize handles are shown.\n // If the cursor is inside an element with resize handles, activeElement\n // will be that element instead of this.dom.\n if (ie) {\n // If activeElement is within this.dom, and there are no other elements\n // setting `contenteditable` to false in between, treat it as focused.\n let node = this.root.activeElement;\n if (node == this.dom)\n return true;\n if (!node || !this.dom.contains(node))\n return false;\n while (node && this.dom != node && this.dom.contains(node)) {\n if (node.contentEditable == 'false')\n return false;\n node = node.parentElement;\n }\n return true;\n }\n return this.root.activeElement == this.dom;\n }\n /**\n Focus the editor.\n */\n focus() {\n this.domObserver.stop();\n if (this.editable)\n focusPreventScroll(this.dom);\n selectionToDOM(this);\n this.domObserver.start();\n }\n /**\n Get the document root in which the editor exists. This will\n usually be the top-level `document`, but might be a [shadow\n DOM](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Shadow_DOM)\n root if the editor is inside one.\n */\n get root() {\n let cached = this._root;\n if (cached == null)\n for (let search = this.dom.parentNode; search; search = search.parentNode) {\n if (search.nodeType == 9 || (search.nodeType == 11 && search.host)) {\n if (!search.getSelection)\n Object.getPrototypeOf(search).getSelection = () => search.ownerDocument.getSelection();\n return this._root = search;\n }\n }\n return cached || document;\n }\n /**\n When an existing editor view is moved to a new document or\n shadow tree, call this to make it recompute its root.\n */\n updateRoot() {\n this._root = null;\n }\n /**\n Given a pair of viewport coordinates, return the document\n position that corresponds to them. May return null if the given\n coordinates aren't inside of the editor. When an object is\n returned, its `pos` property is the position nearest to the\n coordinates, and its `inside` property holds the position of the\n inner node that the position falls inside of, or -1 if it is at\n the top level, not in any node.\n */\n posAtCoords(coords) {\n return posAtCoords(this, coords);\n }\n /**\n Returns the viewport rectangle at a given document position.\n `left` and `right` will be the same number, as this returns a\n flat cursor-ish rectangle. If the position is between two things\n that aren't directly adjacent, `side` determines which element\n is used. When < 0, the element before the position is used,\n otherwise the element after.\n */\n coordsAtPos(pos, side = 1) {\n return coordsAtPos(this, pos, side);\n }\n /**\n Find the DOM position that corresponds to the given document\n position. When `side` is negative, find the position as close as\n possible to the content before the position. When positive,\n prefer positions close to the content after the position. When\n zero, prefer as shallow a position as possible.\n \n Note that you should **not** mutate the editor's internal DOM,\n only inspect it (and even that is usually not necessary).\n */\n domAtPos(pos, side = 0) {\n return this.docView.domFromPos(pos, side);\n }\n /**\n Find the DOM node that represents the document node after the\n given position. May return `null` when the position doesn't point\n in front of a node or if the node is inside an opaque node view.\n \n This is intended to be able to call things like\n `getBoundingClientRect` on that DOM node. Do **not** mutate the\n editor DOM directly, or add styling this way, since that will be\n immediately overriden by the editor as it redraws the node.\n */\n nodeDOM(pos) {\n let desc = this.docView.descAt(pos);\n return desc ? desc.nodeDOM : null;\n }\n /**\n Find the document position that corresponds to a given DOM\n position. (Whenever possible, it is preferable to inspect the\n document structure directly, rather than poking around in the\n DOM, but sometimes—for example when interpreting an event\n target—you don't have a choice.)\n \n The `bias` parameter can be used to influence which side of a DOM\n node to use when the position is inside a leaf node.\n */\n posAtDOM(node, offset, bias = -1) {\n let pos = this.docView.posFromDOM(node, offset, bias);\n if (pos == null)\n throw new RangeError(\"DOM position not inside the editor\");\n return pos;\n }\n /**\n Find out whether the selection is at the end of a textblock when\n moving in a given direction. When, for example, given `\"left\"`,\n it will return true if moving left from the current cursor\n position would leave that position's parent textblock. Will apply\n to the view's current state by default, but it is possible to\n pass a different state.\n */\n endOfTextblock(dir, state) {\n return endOfTextblock(this, state || this.state, dir);\n }\n /**\n Run the editor's paste logic with the given HTML string. The\n `event`, if given, will be passed to the\n [`handlePaste`](https://prosemirror.net/docs/ref/#view.EditorProps.handlePaste) hook.\n */\n pasteHTML(html, event) {\n return doPaste(this, \"\", html, false, event || new ClipboardEvent(\"paste\"));\n }\n /**\n Run the editor's paste logic with the given plain-text input.\n */\n pasteText(text, event) {\n return doPaste(this, text, null, true, event || new ClipboardEvent(\"paste\"));\n }\n /**\n Serialize the given slice as it would be if it was copied from\n this editor. Returns a DOM element that contains a\n representation of the slice as its children, a textual\n representation, and the transformed slice (which can be\n different from the given input due to hooks like\n [`transformCopied`](https://prosemirror.net/docs/ref/#view.EditorProps.transformCopied)).\n */\n serializeForClipboard(slice) {\n return serializeForClipboard(this, slice);\n }\n /**\n Removes the editor from the DOM and destroys all [node\n views](https://prosemirror.net/docs/ref/#view.NodeView).\n */\n destroy() {\n if (!this.docView)\n return;\n destroyInput(this);\n this.destroyPluginViews();\n if (this.mounted) {\n this.docView.update(this.state.doc, [], viewDecorations(this), this);\n this.dom.textContent = \"\";\n }\n else if (this.dom.parentNode) {\n this.dom.parentNode.removeChild(this.dom);\n }\n this.docView.destroy();\n this.docView = null;\n clearReusedRange();\n }\n /**\n This is true when the view has been\n [destroyed](https://prosemirror.net/docs/ref/#view.EditorView.destroy) (and thus should not be\n used anymore).\n */\n get isDestroyed() {\n return this.docView == null;\n }\n /**\n Used for testing.\n */\n dispatchEvent(event) {\n return dispatchEvent(this, event);\n }\n /**\n @internal\n */\n domSelectionRange() {\n let sel = this.domSelection();\n if (!sel)\n return { focusNode: null, focusOffset: 0, anchorNode: null, anchorOffset: 0 };\n return safari && this.root.nodeType === 11 &&\n deepActiveElement(this.dom.ownerDocument) == this.dom && safariShadowSelectionRange(this, sel) || sel;\n }\n /**\n @internal\n */\n domSelection() {\n return this.root.getSelection();\n }\n}\nEditorView.prototype.dispatch = function (tr) {\n let dispatchTransaction = this._props.dispatchTransaction;\n if (dispatchTransaction)\n dispatchTransaction.call(this, tr);\n else\n this.updateState(this.state.apply(tr));\n};\nfunction computeDocDeco(view) {\n let attrs = Object.create(null);\n attrs.class = \"ProseMirror\";\n attrs.contenteditable = String(view.editable);\n view.someProp(\"attributes\", value => {\n if (typeof value == \"function\")\n value = value(view.state);\n if (value)\n for (let attr in value) {\n if (attr == \"class\")\n attrs.class += \" \" + value[attr];\n else if (attr == \"style\")\n attrs.style = (attrs.style ? attrs.style + \";\" : \"\") + value[attr];\n else if (!attrs[attr] && attr != \"contenteditable\" && attr != \"nodeName\")\n attrs[attr] = String(value[attr]);\n }\n });\n if (!attrs.translate)\n attrs.translate = \"no\";\n return [Decoration.node(0, view.state.doc.content.size, attrs)];\n}\nfunction updateCursorWrapper(view) {\n if (view.markCursor) {\n let dom = document.createElement(\"img\");\n dom.className = \"ProseMirror-separator\";\n dom.setAttribute(\"mark-placeholder\", \"true\");\n dom.setAttribute(\"alt\", \"\");\n view.cursorWrapper = { dom, deco: Decoration.widget(view.state.selection.from, dom, { raw: true, marks: view.markCursor }) };\n }\n else {\n view.cursorWrapper = null;\n }\n}\nfunction getEditable(view) {\n return !view.someProp(\"editable\", value => value(view.state) === false);\n}\nfunction selectionContextChanged(sel1, sel2) {\n let depth = Math.min(sel1.$anchor.sharedDepth(sel1.head), sel2.$anchor.sharedDepth(sel2.head));\n return sel1.$anchor.start(depth) != sel2.$anchor.start(depth);\n}\nfunction buildNodeViews(view) {\n let result = Object.create(null);\n function add(obj) {\n for (let prop in obj)\n if (!Object.prototype.hasOwnProperty.call(result, prop))\n result[prop] = obj[prop];\n }\n view.someProp(\"nodeViews\", add);\n view.someProp(\"markViews\", add);\n return result;\n}\nfunction changedNodeViews(a, b) {\n let nA = 0, nB = 0;\n for (let prop in a) {\n if (a[prop] != b[prop])\n return true;\n nA++;\n }\n for (let _ in b)\n nB++;\n return nA != nB;\n}\nfunction checkStateComponent(plugin) {\n if (plugin.spec.state || plugin.spec.filterTransaction || plugin.spec.appendTransaction)\n throw new RangeError(\"Plugins passed directly to the view must not have a state component\");\n}\n\n\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiKHNzcikvLi9ub2RlX21vZHVsZXMvcHJvc2VtaXJyb3Itdmlldy9kaXN0L2luZGV4LmpzIiwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7O0FBQTBGO0FBQ047QUFDbEM7O0FBRWxEO0FBQ0EseUJBQXlCO0FBQ3pCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxXQUFXO0FBQ1g7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFdBQVc7QUFDWDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxXQUFXO0FBQ1g7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esc0VBQXNFLGlCQUFpQjtBQUN2RjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSx3QkFBd0IsS0FBSztBQUM3QjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxjQUFjO0FBQ2Q7QUFD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QUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFdBQVcsZUFBZTtBQUMxQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLDBCQUEwQixXQUFXO0FBQ3JDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxVQUFVLHFCQUFxQjtBQUMvQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWE7QUFDYjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNi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QUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGVBQWU7QUFDZjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSw2Q0FBNkMsOEJBQThCO0FBQzNFO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxpQ0FBaUMsOEJBQThCO0FBQy9EO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGVBQWU7QUFDZjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHdCQUF3Qix1QkFBdUI7QUFDL0M7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSw4QkFBOEI7QUFDOUI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxnQ0FBZ0Msb0JBQW9CO0FBQ3BEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esd0JBQXdCLG1CQUFtQjtBQUMzQztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSw0QkFBNEIsbUJBQW1CO0FBQy9DO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSx3Q0FBd0M7QUFDeEM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsNkJBQTZCLGlDQUFpQztBQUM5RDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsNkJBQTZCLGtCQUFrQjtBQUMvQztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxxREFBcUQsNERBQWE7QUFDbEU7QUFDQTtBQUNBLDRCQUE0Qiw0REFBYTtBQUN6QztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsNEJBQTRCLHVCQUF1QjtBQUNuRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxjQUFjLGVBQWU7QUFDN0IsOERBQThELDREQUFhO0FBQzNFO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxVQUFVLGVBQWU7QUFDekI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWE7QUFDYjtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSx1QkFBdUIsNERBQWE7QUFDcEM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxXQUFXLDREQUFhO0FBQ3hCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxVQUFVLGlCQUFpQjtBQUMzQjtBQUNBO0FBQ0EscUJBQXFCLHdEQUFTO0FBQzlCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsdUJBQXVCLDREQUFhO0FBQ3BDO0FBQ0Esa0JBQWtCLFFBQVE7QUFDMUI7QUFDQTtBQUNBO0FBQ0EsbUNBQW1DLDREQUFhO0FBQ2hEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHlDQUF5Qyw0REFBYTtBQUN0RDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGdCQUFnQiw0REFBYTtBQUM3Qix1Q0FBdUMsNERBQWE7QUFDcEQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHVDQUF1Qyw0REFBYTtBQUNwRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSw0QkFBNEIsNERBQWE7QUFDekMsK0JBQStCLDREQUFhO0FBQzVDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsV0FBVztBQUNYO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFdBQVc7QUFDWDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFVBQVUsUUFBUTtBQUNsQjtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7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Q0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsMkNBQTJDLGdCQUFnQjtBQUMzRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxpQ0FBaUMsWUFBWTtBQUM3QztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLDZDQUE2QyxnQkFBZ0I7QUFDN0Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0Esa0VBQWtFLG9EQUFLO0FBQ3ZFO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7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QkFBaUI7QUFDakI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFVBQVUsbUJBQW1CO0FBQzdCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esc0JBQXNCO0FBQ3RCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGtFQUFrRTtBQUNsRTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxpREFBaUQsNERBQWE7QUFDOUQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsNEJBQTRCLCtCQUErQjtBQUMzRDtBQUNBO0FBQ0E7QUFDQTtBQUNBLDRCQUE0QiwrQkFBK0I7QUFDM0Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsNEJBQTRCLDZCQUE2QjtBQUN6RDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsNEZBQTRGLDREQUFhO0FBQ3pHO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSx3QkFBd0IsK0JBQStCO0FBQ3ZEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLDRCQUE0QixvQkFBb0I7QUFDaEQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsbURBQW1ELFFBQVE7QUFDM0Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxxQkFBcUI7QUFDckI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGlFQUFpRTtBQUNqRTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSwrQkFBK0IsK0RBQStELG1DQUFtQztBQUNqSTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUV5RiIsInNvdXJjZXMiOlsiRTpcXEdJVFxcbXZwXFxuYXNoZWwtZnJvbnRlbmRcXG5vZGVfbW9kdWxlc1xccHJvc2VtaXJyb3Itdmlld1xcZGlzdFxcaW5kZXguanMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgVGV4dFNlbGVjdGlvbiwgTm9kZVNlbGVjdGlvbiwgQWxsU2VsZWN0aW9uLCBTZWxlY3Rpb24gfSBmcm9tICdwcm9zZW1pcnJvci1zdGF0ZSc7XG5pbXBvcnQgeyBET01TZXJpYWxpemVyLCBGcmFnbWVudCwgTWFyaywgU2xpY2UsIERPTVBhcnNlciB9IGZyb20gJ3Byb3NlbWlycm9yLW1vZGVsJztcbmltcG9ydCB7IGRyb3BQb2ludCB9IGZyb20gJ3Byb3NlbWlycm9yLXRyYW5zZm9ybSc7XG5cbmNvbnN0IGRvbUluZGV4ID0gZnVuY3Rpb24gKG5vZGUpIHtcbiAgICBmb3IgKHZhciBpbmRleCA9IDA7OyBpbmRleCsrKSB7XG4gICAgICAgIG5vZGUgPSBub2RlLnByZXZpb3VzU2libGluZztcbiAgICAgICAgaWYgKCFub2RlKVxuICAgICAgICAgICAgcmV0dXJuIGluZGV4O1xuICAgIH1cbn07XG5jb25zdCBwYXJlbnROb2RlID0gZnVuY3Rpb24gKG5vZGUpIHtcbiAgICBsZXQgcGFyZW50ID0gbm9kZS5hc3NpZ25lZFNsb3QgfHwgbm9kZS5wYXJlbnROb2RlO1xuICAgIHJldHVybiBwYXJlbnQgJiYgcGFyZW50Lm5vZGVUeXBlID09IDExID8gcGFyZW50Lmhvc3QgOiBwYXJlbnQ7XG59O1xubGV0IHJldXNlZFJhbmdlID0gbnVsbDtcbi8vIE5vdGUgdGhhdCB0aGlzIHdpbGwgYWx3YXlzIHJldHVybiB0aGUgc2FtZSByYW5nZSwgYmVjYXVzZSBET00gcmFuZ2Vcbi8vIG9iamVjdHMgYXJlIGV2ZXJ5IGV4cGVuc2l2ZSwgYW5kIGtlZXAgc2xvd2luZyBkb3duIHN1YnNlcXVlbnQgRE9NXG4vLyB1cGRhdGVzLCBmb3Igc29tZSByZWFzb24uXG5jb25zdCB0ZXh0UmFuZ2UgPSBmdW5jdGlvbiAobm9kZSwgZnJvbSwgdG8pIHtcbiAgICBsZXQgcmFuZ2UgPSByZXVzZWRSYW5nZSB8fCAocmV1c2VkUmFuZ2UgPSBkb2N1bWVudC5jcmVhdGVSYW5nZSgpKTtcbiAgICByYW5nZS5zZXRFbmQobm9kZSwgdG8gPT0gbnVsbCA/IG5vZGUubm9kZVZhbHVlLmxlbmd0aCA6IHRvKTtcbiAgICByYW5nZS5zZXRTdGFydChub2RlLCBmcm9tIHx8IDApO1xuICAgIHJldHVybiByYW5nZTtcbn07XG5jb25zdCBjbGVhclJldXNlZFJhbmdlID0gZnVuY3Rpb24gKCkge1xuICAgIHJldXNlZFJhbmdlID0gbnVsbDtcbn07XG4vLyBTY2FucyBmb3J3YXJkIGFuZCBiYWNrd2FyZCB0aHJvdWdoIERPTSBwb3NpdGlvbnMgZXF1aXZhbGVudCB0byB0aGVcbi8vIGdpdmVuIG9uZSB0byBzZWUgaWYgdGhlIHR3byBhcmUgaW4gdGhlIHNhbWUgcGxhY2UgKGkuZS4gYWZ0ZXIgYVxuLy8gdGV4dCBub2RlIHZzIGF0IHRoZSBlbmQgb2YgdGhhdCB0ZXh0IG5vZGUpXG5jb25zdCBpc0VxdWl2YWxlbnRQb3NpdGlvbiA9IGZ1bmN0aW9uIChub2RlLCBvZmYsIHRhcmdldE5vZGUsIHRhcmdldE9mZikge1xuICAgIHJldHVybiB0YXJnZXROb2RlICYmIChzY2FuRm9yKG5vZGUsIG9mZiwgdGFyZ2V0Tm9kZSwgdGFyZ2V0T2ZmLCAtMSkgfHxcbiAgICAgICAgc2NhbkZvcihub2RlLCBvZmYsIHRhcmdldE5vZGUsIHRhcmdldE9mZiwgMSkpO1xufTtcbmNvbnN0IGF0b21FbGVtZW50cyA9IC9eKGltZ3xicnxpbnB1dHx0ZXh0YXJlYXxocikkL2k7XG5mdW5jdGlvbiBzY2FuRm9yKG5vZGUsIG9mZiwgdGFyZ2V0Tm9kZSwgdGFyZ2V0T2ZmLCBkaXIpIHtcbiAgICB2YXIgX2E7XG4gICAgZm9yICg7Oykge1xuICAgICAgICBpZiAobm9kZSA9PSB0YXJnZXROb2RlICYmIG9mZiA9PSB0YXJnZXRPZmYpXG4gICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgaWYgKG9mZiA9PSAoZGlyIDwgMCA/IDAgOiBub2RlU2l6ZShub2RlKSkpIHtcbiAgICAgICAgICAgIGxldCBwYXJlbnQgPSBub2RlLnBhcmVudE5vZGU7XG4gICAgICAgICAgICBpZiAoIXBhcmVudCB8fCBwYXJlbnQubm9kZVR5cGUgIT0gMSB8fCBoYXNCbG9ja0Rlc2Mobm9kZSkgfHwgYXRvbUVsZW1lbnRzLnRlc3Qobm9kZS5ub2RlTmFtZSkgfHxcbiAgICAgICAgICAgICAgICBub2RlLmNvbnRlbnRFZGl0YWJsZSA9PSBcImZhbHNlXCIpXG4gICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgICAgb2ZmID0gZG9tSW5kZXgobm9kZSkgKyAoZGlyIDwgMCA/IDAgOiAxKTtcbiAgICAgICAgICAgIG5vZGUgPSBwYXJlbnQ7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAobm9kZS5ub2RlVHlwZSA9PSAxKSB7XG4gICAgICAgICAgICBsZXQgY2hpbGQgPSBub2RlLmNoaWxkTm9kZXNbb2ZmICsgKGRpciA8IDAgPyAtMSA6IDApXTtcbiAgICAgICAgICAgIGlmIChjaGlsZC5ub2RlVHlwZSA9PSAxICYmIGNoaWxkLmNvbnRlbnRFZGl0YWJsZSA9PSBcImZhbHNlXCIpIHtcbiAgICAgICAgICAgICAgICBpZiAoKF9hID0gY2hpbGQucG1WaWV3RGVzYykgPT09IG51bGwgfHwgX2EgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9hLmlnbm9yZUZvclNlbGVjdGlvbilcbiAgICAgICAgICAgICAgICAgICAgb2ZmICs9IGRpcjtcbiAgICAgICAgICAgICAgICBlbHNlXG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgIG5vZGUgPSBjaGlsZDtcbiAgICAgICAgICAgICAgICBvZmYgPSBkaXIgPCAwID8gbm9kZVNpemUobm9kZSkgOiAwO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG4gICAgfVxufVxuZnVuY3Rpb24gbm9kZVNpemUobm9kZSkge1xuICAgIHJldHVybiBub2RlLm5vZGVUeXBlID09IDMgPyBub2RlLm5vZGVWYWx1ZS5sZW5ndGggOiBub2RlLmNoaWxkTm9kZXMubGVuZ3RoO1xufVxuZnVuY3Rpb24gdGV4dE5vZGVCZWZvcmUkMShub2RlLCBvZmZzZXQpIHtcbiAgICBmb3IgKDs7KSB7XG4gICAgICAgIGlmIChub2RlLm5vZGVUeXBlID09IDMgJiYgb2Zmc2V0KVxuICAgICAgICAgICAgcmV0dXJuIG5vZGU7XG4gICAgICAgIGlmIChub2RlLm5vZGVUeXBlID09IDEgJiYgb2Zmc2V0ID4gMCkge1xuICAgICAgICAgICAgaWYgKG5vZGUuY29udGVudEVkaXRhYmxlID09IFwiZmFsc2VcIilcbiAgICAgICAgICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgICAgICAgIG5vZGUgPSBub2RlLmNoaWxkTm9kZXNbb2Zmc2V0IC0gMV07XG4gICAgICAgICAgICBvZmZzZXQgPSBub2RlU2l6ZShub2RlKTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIGlmIChub2RlLnBhcmVudE5vZGUgJiYgIWhhc0Jsb2NrRGVzYyhub2RlKSkge1xuICAgICAgICAgICAgb2Zmc2V0ID0gZG9tSW5kZXgobm9kZSk7XG4gICAgICAgICAgICBub2RlID0gbm9kZS5wYXJlbnROb2RlO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgIH1cbiAgICB9XG59XG5mdW5jdGlvbiB0ZXh0Tm9kZUFmdGVyJDEobm9kZSwgb2Zmc2V0KSB7XG4gICAgZm9yICg7Oykge1xuICAgICAgICBpZiAobm9kZS5ub2RlVHlwZSA9PSAzICYmIG9mZnNldCA8IG5vZGUubm9kZVZhbHVlLmxlbmd0aClcbiAgICAgICAgICAgIHJldHVybiBub2RlO1xuICAgICAgICBpZiAobm9kZS5ub2RlVHlwZSA9PSAxICYmIG9mZnNldCA8IG5vZGUuY2hpbGROb2Rlcy5sZW5ndGgpIHtcbiAgICAgICAgICAgIGlmIChub2RlLmNvbnRlbnRFZGl0YWJsZSA9PSBcImZhbHNlXCIpXG4gICAgICAgICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgICAgICBub2RlID0gbm9kZS5jaGlsZE5vZGVzW29mZnNldF07XG4gICAgICAgICAgICBvZmZzZXQgPSAwO1xuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYgKG5vZGUucGFyZW50Tm9kZSAmJiAhaGFzQmxvY2tEZXNjKG5vZGUpKSB7XG4gICAgICAgICAgICBvZmZzZXQgPSBkb21JbmRleChub2RlKSArIDE7XG4gICAgICAgICAgICBub2RlID0gbm9kZS5wYXJlbnROb2RlO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgIH1cbiAgICB9XG59XG5mdW5jdGlvbiBpc09uRWRnZShub2RlLCBvZmZzZXQsIHBhcmVudCkge1xuICAgIGZvciAobGV0IGF0U3RhcnQgPSBvZmZzZXQgPT0gMCwgYXRFbmQgPSBvZmZzZXQgPT0gbm9kZVNpemUobm9kZSk7IGF0U3RhcnQgfHwgYXRFbmQ7KSB7XG4gICAgICAgIGlmIChub2RlID09IHBhcmVudClcbiAgICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICBsZXQgaW5kZXggPSBkb21JbmRleChub2RlKTtcbiAgICAgICAgbm9kZSA9IG5vZGUucGFyZW50Tm9kZTtcbiAgICAgICAgaWYgKCFub2RlKVxuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICBhdFN0YXJ0ID0gYXRTdGFydCAmJiBpbmRleCA9PSAwO1xuICAgICAgICBhdEVuZCA9IGF0RW5kICYmIGluZGV4ID09IG5vZGVTaXplKG5vZGUpO1xuICAgIH1cbn1cbmZ1bmN0aW9uIGhhc0Jsb2NrRGVzYyhkb20pIHtcbiAgICBsZXQgZGVzYztcbiAgICBmb3IgKGxldCBjdXIgPSBkb207IGN1cjsgY3VyID0gY3VyLnBhcmVudE5vZGUpXG4gICAgICAgIGlmIChkZXNjID0gY3VyLnBtVmlld0Rlc2MpXG4gICAgICAgICAgICBicmVhaztcbiAgICByZXR1cm4gZGVzYyAmJiBkZXNjLm5vZGUgJiYgZGVzYy5ub2RlLmlzQmxvY2sgJiYgKGRlc2MuZG9tID09IGRvbSB8fCBkZXNjLmNvbnRlbnRET00gPT0gZG9tKTtcbn1cbi8vIFdvcmsgYXJvdW5kIENocm9tZSBpc3N1ZSBodHRwczovL2J1Z3MuY2hyb21pdW0ub3JnL3AvY2hyb21pdW0vaXNzdWVzL2RldGFpbD9pZD00NDc1MjNcbi8vIChpc0NvbGxhcHNlZCBpbmFwcHJvcHJpYXRlbHkgcmV0dXJucyB0cnVlIGluIHNoYWRvdyBkb20pXG5jb25zdCBzZWxlY3Rpb25Db2xsYXBzZWQgPSBmdW5jdGlvbiAoZG9tU2VsKSB7XG4gICAgcmV0dXJuIGRvbVNlbC5mb2N1c05vZGUgJiYgaXNFcXVpdmFsZW50UG9zaXRpb24oZG9tU2VsLmZvY3VzTm9kZSwgZG9tU2VsLmZvY3VzT2Zmc2V0LCBkb21TZWwuYW5jaG9yTm9kZSwgZG9tU2VsLmFuY2hvck9mZnNldCk7XG59O1xuZnVuY3Rpb24ga2V5RXZlbnQoa2V5Q29kZSwga2V5KSB7XG4gICAgbGV0IGV2ZW50ID0gZG9jdW1lbnQuY3JlYXRlRXZlbnQoXCJFdmVudFwiKTtcbiAgICBldmVudC5pbml0RXZlbnQoXCJrZXlkb3duXCIsIHRydWUsIHRydWUpO1xuICAgIGV2ZW50LmtleUNvZGUgPSBrZXlDb2RlO1xuICAgIGV2ZW50LmtleSA9IGV2ZW50LmNvZGUgPSBrZXk7XG4gICAgcmV0dXJuIGV2ZW50O1xufVxuZnVuY3Rpb24gZGVlcEFjdGl2ZUVsZW1lbnQoZG9jKSB7XG4gICAgbGV0IGVsdCA9IGRvYy5hY3RpdmVFbGVtZW50O1xuICAgIHdoaWxlIChlbHQgJiYgZWx0LnNoYWRvd1Jvb3QpXG4gICAgICAgIGVsdCA9IGVsdC5zaGFkb3dSb290LmFjdGl2ZUVsZW1lbnQ7XG4gICAgcmV0dXJuIGVsdDtcbn1cbmZ1bmN0aW9uIGNhcmV0RnJvbVBvaW50KGRvYywgeCwgeSkge1xuICAgIGlmIChkb2MuY2FyZXRQb3NpdGlvbkZyb21Qb2ludCkge1xuICAgICAgICB0cnkgeyAvLyBGaXJlZm94IHRocm93cyBmb3IgdGhpcyBjYWxsIGluIGhhcmQtdG8tcHJlZGljdCBjaXJjdW1zdGFuY2VzICgjOTk0KVxuICAgICAgICAgICAgbGV0IHBvcyA9IGRvYy5jYXJldFBvc2l0aW9uRnJvbVBvaW50KHgsIHkpO1xuICAgICAgICAgICAgLy8gQ2xpcCB0aGUgb2Zmc2V0LCBiZWNhdXNlIENocm9tZSB3aWxsIHJldHVybiBhIHRleHQgb2Zmc2V0XG4gICAgICAgICAgICAvLyBpbnRvIDxpbnB1dD4gbm9kZXMsIHdoaWNoIGNhbid0IGJlIHRyZWF0ZWQgYXMgYSByZWd1bGFyIERPTVxuICAgICAgICAgICAgLy8gb2Zmc2V0XG4gICAgICAgICAgICBpZiAocG9zKVxuICAgICAgICAgICAgICAgIHJldHVybiB7IG5vZGU6IHBvcy5vZmZzZXROb2RlLCBvZmZzZXQ6IE1hdGgubWluKG5vZGVTaXplKHBvcy5vZmZzZXROb2RlKSwgcG9zLm9mZnNldCkgfTtcbiAgICAgICAgfVxuICAgICAgICBjYXRjaCAoXykgeyB9XG4gICAgfVxuICAgIGlmIChkb2MuY2FyZXRSYW5nZUZyb21Qb2ludCkge1xuICAgICAgICBsZXQgcmFuZ2UgPSBkb2MuY2FyZXRSYW5nZUZyb21Qb2ludCh4LCB5KTtcbiAgICAgICAgaWYgKHJhbmdlKVxuICAgICAgICAgICAgcmV0dXJuIHsgbm9kZTogcmFuZ2Uuc3RhcnRDb250YWluZXIsIG9mZnNldDogTWF0aC5taW4obm9kZVNpemUocmFuZ2Uuc3RhcnRDb250YWluZXIpLCByYW5nZS5zdGFydE9mZnNldCkgfTtcbiAgICB9XG59XG5cbmNvbnN0IG5hdiA9IHR5cGVvZiBuYXZpZ2F0b3IgIT0gXCJ1bmRlZmluZWRcIiA/IG5hdmlnYXRvciA6IG51bGw7XG5jb25zdCBkb2MgPSB0eXBlb2YgZG9jdW1lbnQgIT0gXCJ1bmRlZmluZWRcIiA/IGRvY3VtZW50IDogbnVsbDtcbmNvbnN0IGFnZW50ID0gKG5hdiAmJiBuYXYudXNlckFnZW50KSB8fCBcIlwiO1xuY29uc3QgaWVfZWRnZSA9IC9FZGdlXFwvKFxcZCspLy5leGVjKGFnZW50KTtcbmNvbnN0IGllX3VwdG8xMCA9IC9NU0lFIFxcZC8uZXhlYyhhZ2VudCk7XG5jb25zdCBpZV8xMXVwID0gL1RyaWRlbnRcXC8oPzpbNy05XXxcXGR7Mix9KVxcLi4qcnY6KFxcZCspLy5leGVjKGFnZW50KTtcbmNvbnN0IGllID0gISEoaWVfdXB0bzEwIHx8IGllXzExdXAgfHwgaWVfZWRnZSk7XG5jb25zdCBpZV92ZXJzaW9uID0gaWVfdXB0bzEwID8gZG9jdW1lbnQuZG9jdW1lbnRNb2RlIDogaWVfMTF1cCA/ICtpZV8xMXVwWzFdIDogaWVfZWRnZSA/ICtpZV9lZGdlWzFdIDogMDtcbmNvbnN0IGdlY2tvID0gIWllICYmIC9nZWNrb1xcLyhcXGQrKS9pLnRlc3QoYWdlbnQpO1xuZ2Vja28gJiYgKygvRmlyZWZveFxcLyhcXGQrKS8uZXhlYyhhZ2VudCkgfHwgWzAsIDBdKVsxXTtcbmNvbnN0IF9jaHJvbWUgPSAhaWUgJiYgL0Nocm9tZVxcLyhcXGQrKS8uZXhlYyhhZ2VudCk7XG5jb25zdCBjaHJvbWUgPSAhIV9jaHJvbWU7XG5jb25zdCBjaHJvbWVfdmVyc2lvbiA9IF9jaHJvbWUgPyArX2Nocm9tZVsxXSA6IDA7XG5jb25zdCBzYWZhcmkgPSAhaWUgJiYgISFuYXYgJiYgL0FwcGxlIENvbXB1dGVyLy50ZXN0KG5hdi52ZW5kb3IpO1xuLy8gSXMgdHJ1ZSBmb3IgYm90aCBpT1MgYW5kIGlQYWRPUyBmb3IgY29udmVuaWVuY2VcbmNvbnN0IGlvcyA9IHNhZmFyaSAmJiAoL01vYmlsZVxcL1xcdysvLnRlc3QoYWdlbnQpIHx8ICEhbmF2ICYmIG5hdi5tYXhUb3VjaFBvaW50cyA+IDIpO1xuY29uc3QgbWFjID0gaW9zIHx8IChuYXYgPyAvTWFjLy50ZXN0KG5hdi5wbGF0Zm9ybSkgOiBmYWxzZSk7XG5jb25zdCB3aW5kb3dzID0gbmF2ID8gL1dpbi8udGVzdChuYXYucGxhdGZvcm0pIDogZmFsc2U7XG5jb25zdCBhbmRyb2lkID0gL0FuZHJvaWQgXFxkLy50ZXN0KGFnZW50KTtcbmNvbnN0IHdlYmtpdCA9ICEhZG9jICYmIFwid2Via2l0Rm9udFNtb290aGluZ1wiIGluIGRvYy5kb2N1bWVudEVsZW1lbnQuc3R5bGU7XG5jb25zdCB3ZWJraXRfdmVyc2lvbiA9IHdlYmtpdCA/ICsoL1xcYkFwcGxlV2ViS2l0XFwvKFxcZCspLy5leGVjKG5hdmlnYXRvci51c2VyQWdlbnQpIHx8IFswLCAwXSlbMV0gOiAwO1xuXG5mdW5jdGlvbiB3aW5kb3dSZWN0KGRvYykge1xuICAgIGxldCB2cCA9IGRvYy5kZWZhdWx0VmlldyAmJiBkb2MuZGVmYXVsdFZpZXcudmlzdWFsVmlld3BvcnQ7XG4gICAgaWYgKHZwKVxuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgbGVmdDogMCwgcmlnaHQ6IHZwLndpZHRoLFxuICAgICAgICAgICAgdG9wOiAwLCBib3R0b206IHZwLmhlaWdodFxuICAgICAgICB9O1xuICAgIHJldHVybiB7IGxlZnQ6IDAsIHJpZ2h0OiBkb2MuZG9jdW1lbnRFbGVtZW50LmNsaWVudFdpZHRoLFxuICAgICAgICB0b3A6IDAsIGJvdHRvbTogZG9jLmRvY3VtZW50RWxlbWVudC5jbGllbnRIZWlnaHQgfTtcbn1cbmZ1bmN0aW9uIGdldFNpZGUodmFsdWUsIHNpZGUpIHtcbiAgICByZXR1cm4gdHlwZW9mIHZhbHVlID09IFwibnVtYmVyXCIgPyB2YWx1ZSA6IHZhbHVlW3NpZGVdO1xufVxuZnVuY3Rpb24gY2xpZW50UmVjdChub2RlKSB7XG4gICAgbGV0IHJlY3QgPSBub2RlLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xuICAgIC8vIEFkanVzdCBmb3IgZWxlbWVudHMgd2l0aCBzdHlsZSBcInRyYW5zZm9ybTogc2NhbGUoKVwiXG4gICAgbGV0IHNjYWxlWCA9IChyZWN0LndpZHRoIC8gbm9kZS5vZmZzZXRXaWR0aCkgfHwgMTtcbiAgICBsZXQgc2NhbGVZID0gKHJlY3QuaGVpZ2h0IC8gbm9kZS5vZmZzZXRIZWlnaHQpIHx8IDE7XG4gICAgLy8gTWFrZSBzdXJlIHNjcm9sbGJhciB3aWR0aCBpc24ndCBpbmNsdWRlZCBpbiB0aGUgcmVjdGFuZ2xlXG4gICAgcmV0dXJuIHsgbGVmdDogcmVjdC5sZWZ0LCByaWdodDogcmVjdC5sZWZ0ICsgbm9kZS5jbGllbnRXaWR0aCAqIHNjYWxlWCxcbiAgICAgICAgdG9wOiByZWN0LnRvcCwgYm90dG9tOiByZWN0LnRvcCArIG5vZGUuY2xpZW50SGVpZ2h0ICogc2NhbGVZIH07XG59XG5mdW5jdGlvbiBzY3JvbGxSZWN0SW50b1ZpZXcodmlldywgcmVjdCwgc3RhcnRET00pIHtcbiAgICBsZXQgc2Nyb2xsVGhyZXNob2xkID0gdmlldy5zb21lUHJvcChcInNjcm9sbFRocmVzaG9sZFwiKSB8fCAwLCBzY3JvbGxNYXJnaW4gPSB2aWV3LnNvbWVQcm9wKFwic2Nyb2xsTWFyZ2luXCIpIHx8IDU7XG4gICAgbGV0IGRvYyA9IHZpZXcuZG9tLm93bmVyRG9jdW1lbnQ7XG4gICAgZm9yIChsZXQgcGFyZW50ID0gc3RhcnRET00gfHwgdmlldy5kb207Oykge1xuICAgICAgICBpZiAoIXBhcmVudClcbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICBpZiAocGFyZW50Lm5vZGVUeXBlICE9IDEpIHtcbiAgICAgICAgICAgIHBhcmVudCA9IHBhcmVudE5vZGUocGFyZW50KTtcbiAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG4gICAgICAgIGxldCBlbHQgPSBwYXJlbnQ7XG4gICAgICAgIGxldCBhdFRvcCA9IGVsdCA9PSBkb2MuYm9keTtcbiAgICAgICAgbGV0IGJvdW5kaW5nID0gYXRUb3AgPyB3aW5kb3dSZWN0KGRvYykgOiBjbGllbnRSZWN0KGVsdCk7XG4gICAgICAgIGxldCBtb3ZlWCA9IDAsIG1vdmVZID0gMDtcbiAgICAgICAgaWYgKHJlY3QudG9wIDwgYm91bmRpbmcudG9wICsgZ2V0U2lkZShzY3JvbGxUaHJlc2hvbGQsIFwidG9wXCIpKVxuICAgICAgICAgICAgbW92ZVkgPSAtKGJvdW5kaW5nLnRvcCAtIHJlY3QudG9wICsgZ2V0U2lkZShzY3JvbGxNYXJnaW4sIFwidG9wXCIpKTtcbiAgICAgICAgZWxzZSBpZiAocmVjdC5ib3R0b20gPiBib3VuZGluZy5ib3R0b20gLSBnZXRTaWRlKHNjcm9sbFRocmVzaG9sZCwgXCJib3R0b21cIikpXG4gICAgICAgICAgICBtb3ZlWSA9IHJlY3QuYm90dG9tIC0gcmVjdC50b3AgPiBib3VuZGluZy5ib3R0b20gLSBib3VuZGluZy50b3BcbiAgICAgICAgICAgICAgICA/IHJlY3QudG9wICsgZ2V0U2lkZShzY3JvbGxNYXJnaW4sIFwidG9wXCIpIC0gYm91bmRpbmcudG9wXG4gICAgICAgICAgICAgICAgOiByZWN0LmJvdHRvbSAtIGJvdW5kaW5nLmJvdHRvbSArIGdldFNpZGUoc2Nyb2xsTWFyZ2luLCBcImJvdHRvbVwiKTtcbiAgICAgICAgaWYgKHJlY3QubGVmdCA8IGJvdW5kaW5nLmxlZnQgKyBnZXRTaWRlKHNjcm9sbFRocmVzaG9sZCwgXCJsZWZ0XCIpKVxuICAgICAgICAgICAgbW92ZVggPSAtKGJvdW5kaW5nLmxlZnQgLSByZWN0LmxlZnQgKyBnZXRTaWRlKHNjcm9sbE1hcmdpbiwgXCJsZWZ0XCIpKTtcbiAgICAgICAgZWxzZSBpZiAocmVjdC5yaWdodCA+IGJvdW5kaW5nLnJpZ2h0IC0gZ2V0U2lkZShzY3JvbGxUaHJlc2hvbGQsIFwicmlnaHRcIikpXG4gICAgICAgICAgICBtb3ZlWCA9IHJlY3QucmlnaHQgLSBib3VuZGluZy5yaWdodCArIGdldFNpZGUoc2Nyb2xsTWFyZ2luLCBcInJpZ2h0XCIpO1xuICAgICAgICBpZiAobW92ZVggfHwgbW92ZVkpIHtcbiAgICAgICAgICAgIGlmIChhdFRvcCkge1xuICAgICAgICAgICAgICAgIGRvYy5kZWZhdWx0Vmlldy5zY3JvbGxCeShtb3ZlWCwgbW92ZVkpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgbGV0IHN0YXJ0WCA9IGVsdC5zY3JvbGxMZWZ0LCBzdGFydFkgPSBlbHQuc2Nyb2xsVG9wO1xuICAgICAgICAgICAgICAgIGlmIChtb3ZlWSlcbiAgICAgICAgICAgICAgICAgICAgZWx0LnNjcm9sbFRvcCArPSBtb3ZlWTtcbiAgICAgICAgICAgICAgICBpZiAobW92ZVgpXG4gICAgICAgICAgICAgICAgICAgIGVsdC5zY3JvbGxMZWZ0ICs9IG1vdmVYO1xuICAgICAgICAgICAgICAgIGxldCBkWCA9IGVsdC5zY3JvbGxMZWZ0IC0gc3RhcnRYLCBkWSA9IGVsdC5zY3JvbGxUb3AgLSBzdGFydFk7XG4gICAgICAgICAgICAgICAgcmVjdCA9IHsgbGVmdDogcmVjdC5sZWZ0IC0gZFgsIHRvcDogcmVjdC50b3AgLSBkWSwgcmlnaHQ6IHJlY3QucmlnaHQgLSBkWCwgYm90dG9tOiByZWN0LmJvdHRvbSAtIGRZIH07XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgbGV0IHBvcyA9IGF0VG9wID8gXCJmaXhlZFwiIDogZ2V0Q29tcHV0ZWRTdHlsZShwYXJlbnQpLnBvc2l0aW9uO1xuICAgICAgICBpZiAoL14oZml4ZWR8c3RpY2t5KSQvLnRlc3QocG9zKSlcbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICBwYXJlbnQgPSBwb3MgPT0gXCJhYnNvbHV0ZVwiID8gcGFyZW50Lm9mZnNldFBhcmVudCA6IHBhcmVudE5vZGUocGFyZW50KTtcbiAgICB9XG59XG4vLyBTdG9yZSB0aGUgc2Nyb2xsIHBvc2l0aW9uIG9mIHRoZSBlZGl0b3IncyBwYXJlbnQgbm9kZXMsIGFsb25nIHdpdGhcbi8vIHRoZSB0b3AgcG9zaXRpb24gb2YgYW4gZWxlbWVudCBuZWFyIHRoZSB0b3Agb2YgdGhlIGVkaXRvciwgd2hpY2hcbi8vIHdpbGwgYmUgdXNlZCB0byBtYWtlIHN1cmUgdGhlIHZpc2libGUgdmlld3BvcnQgcmVtYWlucyBzdGFibGUgZXZlblxuLy8gd2hlbiB0aGUgc2l6ZSBvZiB0aGUgY29udGVudCBhYm92ZSBjaGFuZ2VzLlxuZnVuY3Rpb24gc3RvcmVTY3JvbGxQb3Modmlldykge1xuICAgIGxldCByZWN0ID0gdmlldy5kb20uZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCksIHN0YXJ0WSA9IE1hdGgubWF4KDAsIHJlY3QudG9wKTtcbiAgICBsZXQgcmVmRE9NLCByZWZUb3A7XG4gICAgZm9yIChsZXQgeCA9IChyZWN0LmxlZnQgKyByZWN0LnJpZ2h0KSAvIDIsIHkgPSBzdGFydFkgKyAxOyB5IDwgTWF0aC5taW4oaW5uZXJIZWlnaHQsIHJlY3QuYm90dG9tKTsgeSArPSA1KSB7XG4gICAgICAgIGxldCBkb20gPSB2aWV3LnJvb3QuZWxlbWVudEZyb21Qb2ludCh4LCB5KTtcbiAgICAgICAgaWYgKCFkb20gfHwgZG9tID09IHZpZXcuZG9tIHx8ICF2aWV3LmRvbS5jb250YWlucyhkb20pKVxuICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgIGxldCBsb2NhbFJlY3QgPSBkb20uZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XG4gICAgICAgIGlmIChsb2NhbFJlY3QudG9wID49IHN0YXJ0WSAtIDIwKSB7XG4gICAgICAgICAgICByZWZET00gPSBkb207XG4gICAgICAgICAgICByZWZUb3AgPSBsb2NhbFJlY3QudG9wO1xuICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIHsgcmVmRE9NOiByZWZET00sIHJlZlRvcDogcmVmVG9wLCBzdGFjazogc2Nyb2xsU3RhY2sodmlldy5kb20pIH07XG59XG5mdW5jdGlvbiBzY3JvbGxTdGFjayhkb20pIHtcbiAgICBsZXQgc3RhY2sgPSBbXSwgZG9jID0gZG9tLm93bmVyRG9jdW1lbnQ7XG4gICAgZm9yIChsZXQgY3VyID0gZG9tOyBjdXI7IGN1ciA9IHBhcmVudE5vZGUoY3VyKSkge1xuICAgICAgICBzdGFjay5wdXNoKHsgZG9tOiBjdXIsIHRvcDogY3VyLnNjcm9sbFRvcCwgbGVmdDogY3VyLnNjcm9sbExlZnQgfSk7XG4gICAgICAgIGlmIChkb20gPT0gZG9jKVxuICAgICAgICAgICAgYnJlYWs7XG4gICAgfVxuICAgIHJldHVybiBzdGFjaztcbn1cbi8vIFJlc2V0IHRoZSBzY3JvbGwgcG9zaXRpb24gb2YgdGhlIGVkaXRvcidzIHBhcmVudCBub2RlcyB0byB0aGF0IHdoYXRcbi8vIGl0IHdhcyBiZWZvcmUsIHdoZW4gc3RvcmVTY3JvbGxQb3Mgd2FzIGNhbGxlZC5cbmZ1bmN0aW9uIHJlc2V0U2Nyb2xsUG9zKHsgcmVmRE9NLCByZWZUb3AsIHN0YWNrIH0pIHtcbiAgICBsZXQgbmV3UmVmVG9wID0gcmVmRE9NID8gcmVmRE9NLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpLnRvcCA6IDA7XG4gICAgcmVzdG9yZVNjcm9sbFN0YWNrKHN0YWNrLCBuZXdSZWZUb3AgPT0gMCA/IDAgOiBuZXdSZWZUb3AgLSByZWZUb3ApO1xufVxuZnVuY3Rpb24gcmVzdG9yZVNjcm9sbFN0YWNrKHN0YWNrLCBkVG9wKSB7XG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBzdGFjay5sZW5ndGg7IGkrKykge1xuICAgICAgICBsZXQgeyBkb20sIHRvcCwgbGVmdCB9ID0gc3RhY2tbaV07XG4gICAgICAgIGlmIChkb20uc2Nyb2xsVG9wICE9IHRvcCArIGRUb3ApXG4gICAgICAgICAgICBkb20uc2Nyb2xsVG9wID0gdG9wICsgZFRvcDtcbiAgICAgICAgaWYgKGRvbS5zY3JvbGxMZWZ0ICE9IGxlZnQpXG4gICAgICAgICAgICBkb20uc2Nyb2xsTGVmdCA9IGxlZnQ7XG4gICAgfVxufVxubGV0IHByZXZlbnRTY3JvbGxTdXBwb3J0ZWQgPSBudWxsO1xuLy8gRmVhdHVyZS1kZXRlY3RzIHN1cHBvcnQgZm9yIC5mb2N1cyh7cHJldmVudFNjcm9sbDogdHJ1ZX0pLCBhbmQgdXNlc1xuLy8gYSBmYWxsYmFjayBrbHVkZ2Ugd2hlbiBub3Qgc3VwcG9ydGVkLlxuZnVuY3Rpb24gZm9jdXNQcmV2ZW50U2Nyb2xsKGRvbSkge1xuICAgIGlmIChkb20uc2V0QWN0aXZlKVxuICAgICAgICByZXR1cm4gZG9tLnNldEFjdGl2ZSgpOyAvLyBpbiBJRVxuICAgIGlmIChwcmV2ZW50U2Nyb2xsU3VwcG9ydGVkKVxuICAgICAgICByZXR1cm4gZG9tLmZvY3VzKHByZXZlbnRTY3JvbGxTdXBwb3J0ZWQpO1xuICAgIGxldCBzdG9yZWQgPSBzY3JvbGxTdGFjayhkb20pO1xuICAgIGRvbS5mb2N1cyhwcmV2ZW50U2Nyb2xsU3VwcG9ydGVkID09IG51bGwgPyB7XG4gICAgICAgIGdldCBwcmV2ZW50U2Nyb2xsKCkge1xuICAgICAgICAgICAgcHJldmVudFNjcm9sbFN1cHBvcnRlZCA9IHsgcHJldmVudFNjcm9sbDogdHJ1ZSB9O1xuICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgIH1cbiAgICB9IDogdW5kZWZpbmVkKTtcbiAgICBpZiAoIXByZXZlbnRTY3JvbGxTdXBwb3J0ZWQpIHtcbiAgICAgICAgcHJldmVudFNjcm9sbFN1cHBvcnRlZCA9IGZhbHNlO1xuICAgICAgICByZXN0b3JlU2Nyb2xsU3RhY2soc3RvcmVkLCAwKTtcbiAgICB9XG59XG5mdW5jdGlvbiBmaW5kT2Zmc2V0SW5Ob2RlKG5vZGUsIGNvb3Jkcykge1xuICAgIGxldCBjbG9zZXN0LCBkeENsb3Nlc3QgPSAyZTgsIGNvb3Jkc0Nsb3Nlc3QsIG9mZnNldCA9IDA7XG4gICAgbGV0IHJvd0JvdCA9IGNvb3Jkcy50b3AsIHJvd1RvcCA9IGNvb3Jkcy50b3A7XG4gICAgbGV0IGZpcnN0QmVsb3csIGNvb3Jkc0JlbG93O1xuICAgIGZvciAobGV0IGNoaWxkID0gbm9kZS5maXJzdENoaWxkLCBjaGlsZEluZGV4ID0gMDsgY2hpbGQ7IGNoaWxkID0gY2hpbGQubmV4dFNpYmxpbmcsIGNoaWxkSW5kZXgrKykge1xuICAgICAgICBsZXQgcmVjdHM7XG4gICAgICAgIGlmIChjaGlsZC5ub2RlVHlwZSA9PSAxKVxuICAgICAgICAgICAgcmVjdHMgPSBjaGlsZC5nZXRDbGllbnRSZWN0cygpO1xuICAgICAgICBlbHNlIGlmIChjaGlsZC5ub2RlVHlwZSA9PSAzKVxuICAgICAgICAgICAgcmVjdHMgPSB0ZXh0UmFuZ2UoY2hpbGQpLmdldENsaWVudFJlY3RzKCk7XG4gICAgICAgIGVsc2VcbiAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHJlY3RzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICBsZXQgcmVjdCA9IHJlY3RzW2ldO1xuICAgICAgICAgICAgaWYgKHJlY3QudG9wIDw9IHJvd0JvdCAmJiByZWN0LmJvdHRvbSA+PSByb3dUb3ApIHtcbiAgICAgICAgICAgICAgICByb3dCb3QgPSBNYXRoLm1heChyZWN0LmJvdHRvbSwgcm93Qm90KTtcbiAgICAgICAgICAgICAgICByb3dUb3AgPSBNYXRoLm1pbihyZWN0LnRvcCwgcm93VG9wKTtcbiAgICAgICAgICAgICAgICBsZXQgZHggPSByZWN0LmxlZnQgPiBjb29yZHMubGVmdCA/IHJlY3QubGVmdCAtIGNvb3Jkcy5sZWZ0XG4gICAgICAgICAgICAgICAgICAgIDogcmVjdC5yaWdodCA8IGNvb3Jkcy5sZWZ0ID8gY29vcmRzLmxlZnQgLSByZWN0LnJpZ2h0IDogMDtcbiAgICAgICAgICAgICAgICBpZiAoZHggPCBkeENsb3Nlc3QpIHtcbiAgICAgICAgICAgICAgICAgICAgY2xvc2VzdCA9IGNoaWxkO1xuICAgICAgICAgICAgICAgICAgICBkeENsb3Nlc3QgPSBkeDtcbiAgICAgICAgICAgICAgICAgICAgY29vcmRzQ2xvc2VzdCA9IGR4ICYmIGNsb3Nlc3Qubm9kZVR5cGUgPT0gMyA/IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGxlZnQ6IHJlY3QucmlnaHQgPCBjb29yZHMubGVmdCA/IHJlY3QucmlnaHQgOiByZWN0LmxlZnQsXG4gICAgICAgICAgICAgICAgICAgICAgICB0b3A6IGNvb3Jkcy50b3BcbiAgICAgICAgICAgICAgICAgICAgfSA6IGNvb3JkcztcbiAgICAgICAgICAgICAgICAgICAgaWYgKGNoaWxkLm5vZGVUeXBlID09IDEgJiYgZHgpXG4gICAgICAgICAgICAgICAgICAgICAgICBvZmZzZXQgPSBjaGlsZEluZGV4ICsgKGNvb3Jkcy5sZWZ0ID49IChyZWN0LmxlZnQgKyByZWN0LnJpZ2h0KSAvIDIgPyAxIDogMCk7XG4gICAgICAgICAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2UgaWYgKHJlY3QudG9wID4gY29vcmRzLnRvcCAmJiAhZmlyc3RCZWxvdyAmJiByZWN0LmxlZnQgPD0gY29vcmRzLmxlZnQgJiYgcmVjdC5yaWdodCA+PSBjb29yZHMubGVmdCkge1xuICAgICAgICAgICAgICAgIGZpcnN0QmVsb3cgPSBjaGlsZDtcbiAgICAgICAgICAgICAgICBjb29yZHNCZWxvdyA9IHsgbGVmdDogTWF0aC5tYXgocmVjdC5sZWZ0LCBNYXRoLm1pbihyZWN0LnJpZ2h0LCBjb29yZHMubGVmdCkpLCB0b3A6IHJlY3QudG9wIH07XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoIWNsb3Nlc3QgJiYgKGNvb3Jkcy5sZWZ0ID49IHJlY3QucmlnaHQgJiYgY29vcmRzLnRvcCA+PSByZWN0LnRvcCB8fFxuICAgICAgICAgICAgICAgIGNvb3Jkcy5sZWZ0ID49IHJlY3QubGVmdCAmJiBjb29yZHMudG9wID49IHJlY3QuYm90dG9tKSlcbiAgICAgICAgICAgICAgICBvZmZzZXQgPSBjaGlsZEluZGV4ICsgMTtcbiAgICAgICAgfVxuICAgIH1cbiAgICBpZiAoIWNsb3Nlc3QgJiYgZmlyc3RCZWxvdykge1xuICAgICAgICBjbG9zZXN0ID0gZmlyc3RCZWxvdztcbiAgICAgICAgY29vcmRzQ2xvc2VzdCA9IGNvb3Jkc0JlbG93O1xuICAgICAgICBkeENsb3Nlc3QgPSAwO1xuICAgIH1cbiAgICBpZiAoY2xvc2VzdCAmJiBjbG9zZXN0Lm5vZGVUeXBlID09IDMpXG4gICAgICAgIHJldHVybiBmaW5kT2Zmc2V0SW5UZXh0KGNsb3Nlc3QsIGNvb3Jkc0Nsb3Nlc3QpO1xuICAgIGlmICghY2xvc2VzdCB8fCAoZHhDbG9zZXN0ICYmIGNsb3Nlc3Qubm9kZVR5cGUgPT0gMSkpXG4gICAgICAgIHJldHVybiB7IG5vZGUsIG9mZnNldCB9O1xuICAgIHJldHVybiBmaW5kT2Zmc2V0SW5Ob2RlKGNsb3Nlc3QsIGNvb3Jkc0Nsb3Nlc3QpO1xufVxuZnVuY3Rpb24gZmluZE9mZnNldEluVGV4dChub2RlLCBjb29yZHMpIHtcbiAgICBsZXQgbGVuID0gbm9kZS5ub2RlVmFsdWUubGVuZ3RoO1xuICAgIGxldCByYW5nZSA9IGRvY3VtZW50LmNyZWF0ZVJhbmdlKCksIHJlc3VsdDtcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IGxlbjsgaSsrKSB7XG4gICAgICAgIHJhbmdlLnNldEVuZChub2RlLCBpICsgMSk7XG4gICAgICAgIHJhbmdlLnNldFN0YXJ0KG5vZGUsIGkpO1xuICAgICAgICBsZXQgcmVjdCA9IHNpbmdsZVJlY3QocmFuZ2UsIDEpO1xuICAgICAgICBpZiAocmVjdC50b3AgPT0gcmVjdC5ib3R0b20pXG4gICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgaWYgKGluUmVjdChjb29yZHMsIHJlY3QpKSB7XG4gICAgICAgICAgICByZXN1bHQgPSB7IG5vZGUsIG9mZnNldDogaSArIChjb29yZHMubGVmdCA+PSAocmVjdC5sZWZ0ICsgcmVjdC5yaWdodCkgLyAyID8gMSA6IDApIH07XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgfVxuICAgIH1cbiAgICByYW5nZS5kZXRhY2goKTtcbiAgICByZXR1cm4gcmVzdWx0IHx8IHsgbm9kZSwgb2Zmc2V0OiAwIH07XG59XG5mdW5jdGlvbiBpblJlY3QoY29vcmRzLCByZWN0KSB7XG4gICAgcmV0dXJuIGNvb3Jkcy5sZWZ0ID49IHJlY3QubGVmdCAtIDEgJiYgY29vcmRzLmxlZnQgPD0gcmVjdC5yaWdodCArIDEgJiZcbiAgICAgICAgY29vcmRzLnRvcCA+PSByZWN0LnRvcCAtIDEgJiYgY29vcmRzLnRvcCA8PSByZWN0LmJvdHRvbSArIDE7XG59XG5mdW5jdGlvbiB0YXJnZXRLbHVkZ2UoZG9tLCBjb29yZHMpIHtcbiAgICBsZXQgcGFyZW50ID0gZG9tLnBhcmVudE5vZGU7XG4gICAgaWYgKHBhcmVudCAmJiAvXmxpJC9pLnRlc3QocGFyZW50Lm5vZGVOYW1lKSAmJiBjb29yZHMubGVmdCA8IGRvbS5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKS5sZWZ0KVxuICAgICAgICByZXR1cm4gcGFyZW50O1xuICAgIHJldHVybiBkb207XG59XG5mdW5jdGlvbiBwb3NGcm9tRWxlbWVudCh2aWV3LCBlbHQsIGNvb3Jkcykge1xuICAgIGxldCB7IG5vZGUsIG9mZnNldCB9ID0gZmluZE9mZnNldEluTm9kZShlbHQsIGNvb3JkcyksIGJpYXMgPSAtMTtcbiAgICBpZiAobm9kZS5ub2RlVHlwZSA9PSAxICYmICFub2RlLmZpcnN0Q2hpbGQpIHtcbiAgICAgICAgbGV0IHJlY3QgPSBub2RlLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xuICAgICAgICBiaWFzID0gcmVjdC5sZWZ0ICE9IHJlY3QucmlnaHQgJiYgY29vcmRzLmxlZnQgPiAocmVjdC5sZWZ0ICsgcmVjdC5yaWdodCkgLyAyID8gMSA6IC0xO1xuICAgIH1cbiAgICByZXR1cm4gdmlldy5kb2NWaWV3LnBvc0Zyb21ET00obm9kZSwgb2Zmc2V0LCBiaWFzKTtcbn1cbmZ1bmN0aW9uIHBvc0Zyb21DYXJldCh2aWV3LCBub2RlLCBvZmZzZXQsIGNvb3Jkcykge1xuICAgIC8vIEJyb3dzZXIgKGluIGNhcmV0UG9zaXRpb24vUmFuZ2VGcm9tUG9pbnQpIHdpbGwgYWdyZXNzaXZlbHlcbiAgICAvLyBub3JtYWxpemUgdG93YXJkcyBuZWFyYnkgaW5saW5lIG5vZGVzLiBTaW5jZSB3ZSBhcmUgaW50ZXJlc3RlZCBpblxuICAgIC8vIHBvc2l0aW9ucyBiZXR3ZWVuIGJsb2NrIG5vZGVzIHRvbywgd2UgZmlyc3Qgd2FsayB1cCB0aGUgaGllcmFyY2h5XG4gICAgLy8gb2Ygbm9kZXMgdG8gc2VlIGlmIHRoZXJlIGFyZSBibG9jayBub2RlcyB0aGF0IHRoZSBjb29yZGluYXRlc1xuICAgIC8vIGZhbGwgb3V0c2lkZSBvZi4gSWYgc28sIHdlIHRha2UgdGhlIHBvc2l0aW9uIGJlZm9yZS9hZnRlciB0aGF0XG4gICAgLy8gYmxvY2suIElmIG5vdCwgd2UgY2FsbCBgcG9zRnJvbURPTWAgb24gdGhlIHJhdyBub2RlL29mZnNldC5cbiAgICBsZXQgb3V0c2lkZUJsb2NrID0gLTE7XG4gICAgZm9yIChsZXQgY3VyID0gbm9kZSwgc2F3QmxvY2sgPSBmYWxzZTs7KSB7XG4gICAgICAgIGlmIChjdXIgPT0gdmlldy5kb20pXG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgbGV0IGRlc2MgPSB2aWV3LmRvY1ZpZXcubmVhcmVzdERlc2MoY3VyLCB0cnVlKSwgcmVjdDtcbiAgICAgICAgaWYgKCFkZXNjKVxuICAgICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgIGlmIChkZXNjLmRvbS5ub2RlVHlwZSA9PSAxICYmIChkZXNjLm5vZGUuaXNCbG9jayAmJiBkZXNjLnBhcmVudCB8fCAhZGVzYy5jb250ZW50RE9NKSAmJlxuICAgICAgICAgICAgLy8gSWdub3JlIGVsZW1lbnRzIHdpdGggemVyby1zaXplIGJvdW5kaW5nIHJlY3RhbmdsZXNcbiAgICAgICAgICAgICgocmVjdCA9IGRlc2MuZG9tLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpKS53aWR0aCB8fCByZWN0LmhlaWdodCkpIHtcbiAgICAgICAgICAgIGlmIChkZXNjLm5vZGUuaXNCbG9jayAmJiBkZXNjLnBhcmVudCAmJiAhL15UKFJ8Qk9EWXxIRUFEfEZPT1QpJC8udGVzdChkZXNjLmRvbS5ub2RlTmFtZSkpIHtcbiAgICAgICAgICAgICAgICAvLyBPbmx5IGFwcGx5IHRoZSBob3Jpem9udGFsIHRlc3QgdG8gdGhlIGlubmVybW9zdCBibG9jay4gVmVydGljYWwgZm9yIGFueSBwYXJlbnQuXG4gICAgICAgICAgICAgICAgaWYgKCFzYXdCbG9jayAmJiByZWN0LmxlZnQgPiBjb29yZHMubGVmdCB8fCByZWN0LnRvcCA+IGNvb3Jkcy50b3ApXG4gICAgICAgICAgICAgICAgICAgIG91dHNpZGVCbG9jayA9IGRlc2MucG9zQmVmb3JlO1xuICAgICAgICAgICAgICAgIGVsc2UgaWYgKCFzYXdCbG9jayAmJiByZWN0LnJpZ2h0IDwgY29vcmRzLmxlZnQgfHwgcmVjdC5ib3R0b20gPCBjb29yZHMudG9wKVxuICAgICAgICAgICAgICAgICAgICBvdXRzaWRlQmxvY2sgPSBkZXNjLnBvc0FmdGVyO1xuICAgICAgICAgICAgICAgIHNhd0Jsb2NrID0gdHJ1ZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmICghZGVzYy5jb250ZW50RE9NICYmIG91dHNpZGVCbG9jayA8IDAgJiYgIWRlc2Mubm9kZS5pc1RleHQpIHtcbiAgICAgICAgICAgICAgICAvLyBJZiB3ZSBhcmUgaW5zaWRlIGEgbGVhZiwgcmV0dXJuIHRoZSBzaWRlIG9mIHRoZSBsZWFmIGNsb3NlciB0byB0aGUgY29vcmRzXG4gICAgICAgICAgICAgICAgbGV0IGJlZm9yZSA9IGRlc2Mubm9kZS5pc0Jsb2NrID8gY29vcmRzLnRvcCA8IChyZWN0LnRvcCArIHJlY3QuYm90dG9tKSAvIDJcbiAgICAgICAgICAgICAgICAgICAgOiBjb29yZHMubGVmdCA8IChyZWN0LmxlZnQgKyByZWN0LnJpZ2h0KSAvIDI7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGJlZm9yZSA/IGRlc2MucG9zQmVmb3JlIDogZGVzYy5wb3NBZnRlcjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBjdXIgPSBkZXNjLmRvbS5wYXJlbnROb2RlO1xuICAgIH1cbiAgICByZXR1cm4gb3V0c2lkZUJsb2NrID4gLTEgPyBvdXRzaWRlQmxvY2sgOiB2aWV3LmRvY1ZpZXcucG9zRnJvbURPTShub2RlLCBvZmZzZXQsIC0xKTtcbn1cbmZ1bmN0aW9uIGVsZW1lbnRGcm9tUG9pbnQoZWxlbWVudCwgY29vcmRzLCBib3gpIHtcbiAgICBsZXQgbGVuID0gZWxlbWVudC5jaGlsZE5vZGVzLmxlbmd0aDtcbiAgICBpZiAobGVuICYmIGJveC50b3AgPCBib3guYm90dG9tKSB7XG4gICAgICAgIGZvciAobGV0IHN0YXJ0SSA9IE1hdGgubWF4KDAsIE1hdGgubWluKGxlbiAtIDEsIE1hdGguZmxvb3IobGVuICogKGNvb3Jkcy50b3AgLSBib3gudG9wKSAvIChib3guYm90dG9tIC0gYm94LnRvcCkpIC0gMikpLCBpID0gc3RhcnRJOzspIHtcbiAgICAgICAgICAgIGxldCBjaGlsZCA9IGVsZW1lbnQuY2hpbGROb2Rlc1tpXTtcbiAgICAgICAgICAgIGlmIChjaGlsZC5ub2RlVHlwZSA9PSAxKSB7XG4gICAgICAgICAgICAgICAgbGV0IHJlY3RzID0gY2hpbGQuZ2V0Q2xpZW50UmVjdHMoKTtcbiAgICAgICAgICAgICAgICBmb3IgKGxldCBqID0gMDsgaiA8IHJlY3RzLmxlbmd0aDsgaisrKSB7XG4gICAgICAgICAgICAgICAgICAgIGxldCByZWN0ID0gcmVjdHNbal07XG4gICAgICAgICAgICAgICAgICAgIGlmIChpblJlY3QoY29vcmRzLCByZWN0KSlcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBlbGVtZW50RnJvbVBvaW50KGNoaWxkLCBjb29yZHMsIHJlY3QpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmICgoaSA9IChpICsgMSkgJSBsZW4pID09IHN0YXJ0SSlcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gZWxlbWVudDtcbn1cbi8vIEdpdmVuIGFuIHgseSBwb3NpdGlvbiBvbiB0aGUgZWRpdG9yLCBnZXQgdGhlIHBvc2l0aW9uIGluIHRoZSBkb2N1bWVudC5cbmZ1bmN0aW9uIHBvc0F0Q29vcmRzKHZpZXcsIGNvb3Jkcykge1xuICAgIGxldCBkb2MgPSB2aWV3LmRvbS5vd25lckRvY3VtZW50LCBub2RlLCBvZmZzZXQgPSAwO1xuICAgIGxldCBjYXJldCA9IGNhcmV0RnJvbVBvaW50KGRvYywgY29vcmRzLmxlZnQsIGNvb3Jkcy50b3ApO1xuICAgIGlmIChjYXJldClcbiAgICAgICAgKHsgbm9kZSwgb2Zmc2V0IH0gPSBjYXJldCk7XG4gICAgbGV0IGVsdCA9ICh2aWV3LnJvb3QuZWxlbWVudEZyb21Qb2ludCA/IHZpZXcucm9vdCA6IGRvYylcbiAgICAgICAgLmVsZW1lbnRGcm9tUG9pbnQoY29vcmRzLmxlZnQsIGNvb3Jkcy50b3ApO1xuICAgIGxldCBwb3M7XG4gICAgaWYgKCFlbHQgfHwgIXZpZXcuZG9tLmNvbnRhaW5zKGVsdC5ub2RlVHlwZSAhPSAxID8gZWx0LnBhcmVudE5vZGUgOiBlbHQpKSB7XG4gICAgICAgIGxldCBib3ggPSB2aWV3LmRvbS5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtcbiAgICAgICAgaWYgKCFpblJlY3QoY29vcmRzLCBib3gpKVxuICAgICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgIGVsdCA9IGVsZW1lbnRGcm9tUG9pbnQodmlldy5kb20sIGNvb3JkcywgYm94KTtcbiAgICAgICAgaWYgKCFlbHQpXG4gICAgICAgICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG4gICAgLy8gU2FmYXJpJ3MgY2FyZXRSYW5nZUZyb21Qb2ludCByZXR1cm5zIG5vbnNlbnNlIHdoZW4gb24gYSBkcmFnZ2FibGUgZWxlbWVudFxuICAgIGlmIChzYWZhcmkpIHtcbiAgICAgICAgZm9yIChsZXQgcCA9IGVsdDsgbm9kZSAmJiBwOyBwID0gcGFyZW50Tm9kZShwKSlcbiAgICAgICAgICAgIGlmIChwLmRyYWdnYWJsZSlcbiAgICAgICAgICAgICAgICBub2RlID0gdW5kZWZpbmVkO1xuICAgIH1cbiAgICBlbHQgPSB0YXJnZXRLbHVkZ2UoZWx0LCBjb29yZHMpO1xuICAgIGlmIChub2RlKSB7XG4gICAgICAgIGlmIChnZWNrbyAmJiBub2RlLm5vZGVUeXBlID09IDEpIHtcbiAgICAgICAgICAgIC8vIEZpcmVmb3ggd2lsbCBzb21ldGltZXMgcmV0dXJuIG9mZnNldHMgaW50byA8aW5wdXQ+IG5vZGVzLCB3aGljaFxuICAgICAgICAgICAgLy8gaGF2ZSBubyBhY3R1YWwgY2hpbGRyZW4sIGZyb20gY2FyZXRQb3NpdGlvbkZyb21Qb2ludCAoIzk1MylcbiAgICAgICAgICAgIG9mZnNldCA9IE1hdGgubWluKG9mZnNldCwgbm9kZS5jaGlsZE5vZGVzLmxlbmd0aCk7XG4gICAgICAgICAgICAvLyBJdCdsbCBhbHNvIG1vdmUgdGhlIHJldHVybmVkIHBvc2l0aW9uIGJlZm9yZSBpbWFnZSBub2RlcyxcbiAgICAgICAgICAgIC8vIGV2ZW4gaWYgdGhvc2UgYXJlIGJlaGluZCBpdC5cbiAgICAgICAgICAgIGlmIChvZmZzZXQgPCBub2RlLmNoaWxkTm9kZXMubGVuZ3RoKSB7XG4gICAgICAgICAgICAgICAgbGV0IG5leHQgPSBub2RlLmNoaWxkTm9kZXNbb2Zmc2V0XSwgYm94O1xuICAgICAgICAgICAgICAgIGlmIChuZXh0Lm5vZGVOYW1lID09IFwiSU1HXCIgJiYgKGJveCA9IG5leHQuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCkpLnJpZ2h0IDw9IGNvb3Jkcy5sZWZ0ICYmXG4gICAgICAgICAgICAgICAgICAgIGJveC5ib3R0b20gPiBjb29yZHMudG9wKVxuICAgICAgICAgICAgICAgICAgICBvZmZzZXQrKztcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBsZXQgcHJldjtcbiAgICAgICAgLy8gV2hlbiBjbGlja2luZyBhYm92ZSB0aGUgcmlnaHQgc2lkZSBvZiBhbiB1bmVkaXRhYmxlIG5vZGUsIENocm9tZSB3aWxsIHJlcG9ydCBhIGN1cnNvciBwb3NpdGlvbiBhZnRlciB0aGF0IG5vZGUuXG4gICAgICAgIGlmICh3ZWJraXQgJiYgb2Zmc2V0ICYmIG5vZGUubm9kZVR5cGUgPT0gMSAmJiAocHJldiA9IG5vZGUuY2hpbGROb2Rlc1tvZmZzZXQgLSAxXSkubm9kZVR5cGUgPT0gMSAmJlxuICAgICAgICAgICAgcHJldi5jb250ZW50RWRpdGFibGUgPT0gXCJmYWxzZVwiICYmIHByZXYuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCkudG9wID49IGNvb3Jkcy50b3ApXG4gICAgICAgICAgICBvZmZzZXQtLTtcbiAgICAgICAgLy8gU3VzcGljaW91c2x5IHNwZWNpZmljIGtsdWRnZSB0byB3b3JrIGFyb3VuZCBjYXJldCpGcm9tUG9pbnRcbiAgICAgICAgLy8gbmV2ZXIgcmV0dXJuaW5nIGEgcG9zaXRpb24gYXQgdGhlIGVuZCBvZiB0aGUgZG9jdW1lbnRcbiAgICAgICAgaWYgKG5vZGUgPT0gdmlldy5kb20gJiYgb2Zmc2V0ID09IG5vZGUuY2hpbGROb2Rlcy5sZW5ndGggLSAxICYmIG5vZGUubGFzdENoaWxkLm5vZGVUeXBlID09IDEgJiZcbiAgICAgICAgICAgIGNvb3Jkcy50b3AgPiBub2RlLmxhc3RDaGlsZC5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKS5ib3R0b20pXG4gICAgICAgICAgICBwb3MgPSB2aWV3LnN0YXRlLmRvYy5jb250ZW50LnNpemU7XG4gICAgICAgIC8vIElnbm9yZSBwb3NpdGlvbnMgZGlyZWN0bHkgYWZ0ZXIgYSBCUiwgc2luY2UgY2FyZXQqRnJvbVBvaW50XG4gICAgICAgIC8vICdyb3VuZCB1cCcgcG9zaXRpb25zIHRoYXQgd291bGQgYmUgbW9yZSBhY2N1cmF0ZWx5IHBsYWNlZFxuICAgICAgICAvLyBiZWZvcmUgdGhlIEJSIG5vZGUuXG4gICAgICAgIGVsc2UgaWYgKG9mZnNldCA9PSAwIHx8IG5vZGUubm9kZVR5cGUgIT0gMSB8fCBub2RlLmNoaWxkTm9kZXNbb2Zmc2V0IC0gMV0ubm9kZU5hbWUgIT0gXCJCUlwiKVxuICAgICAgICAgICAgcG9zID0gcG9zRnJvbUNhcmV0KHZpZXcsIG5vZGUsIG9mZnNldCwgY29vcmRzKTtcbiAgICB9XG4gICAgaWYgKHBvcyA9PSBudWxsKVxuICAgICAgICBwb3MgPSBwb3NGcm9tRWxlbWVudCh2aWV3LCBlbHQsIGNvb3Jkcyk7XG4gICAgbGV0IGRlc2MgPSB2aWV3LmRvY1ZpZXcubmVhcmVzdERlc2MoZWx0LCB0cnVlKTtcbiAgICByZXR1cm4geyBwb3MsIGluc2lkZTogZGVzYyA/IGRlc2MucG9zQXRTdGFydCAtIGRlc2MuYm9yZGVyIDogLTEgfTtcbn1cbmZ1bmN0aW9uIG5vblplcm8ocmVjdCkge1xuICAgIHJldHVybiByZWN0LnRvcCA8IHJlY3QuYm90dG9tIHx8IHJlY3QubGVmdCA8IHJlY3QucmlnaHQ7XG59XG5mdW5jdGlvbiBzaW5nbGVSZWN0KHRhcmdldCwgYmlhcykge1xuICAgIGxldCByZWN0cyA9IHRhcmdldC5nZXRDbGllbnRSZWN0cygpO1xuICAgIGlmIChyZWN0cy5sZW5ndGgpIHtcbiAgICAgICAgbGV0IGZpcnN0ID0gcmVjdHNbYmlhcyA8IDAgPyAwIDogcmVjdHMubGVuZ3RoIC0gMV07XG4gICAgICAgIGlmIChub25aZXJvKGZpcnN0KSlcbiAgICAgICAgICAgIHJldHVybiBmaXJzdDtcbiAgICB9XG4gICAgcmV0dXJuIEFycmF5LnByb3RvdHlwZS5maW5kLmNhbGwocmVjdHMsIG5vblplcm8pIHx8IHRhcmdldC5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtcbn1cbmNvbnN0IEJJREkgPSAvW1xcdTA1OTAtXFx1MDVmNFxcdTA2MDAtXFx1MDZmZlxcdTA3MDAtXFx1MDhhY10vO1xuLy8gR2l2ZW4gYSBwb3NpdGlvbiBpbiB0aGUgZG9jdW1lbnQgbW9kZWwsIGdldCBhIGJvdW5kaW5nIGJveCBvZiB0aGVcbi8vIGNoYXJhY3RlciBhdCB0aGF0IHBvc2l0aW9uLCByZWxhdGl2ZSB0byB0aGUgd2luZG93LlxuZnVuY3Rpb24gY29vcmRzQXRQb3ModmlldywgcG9zLCBzaWRlKSB7XG4gICAgbGV0IHsgbm9kZSwgb2Zmc2V0LCBhdG9tIH0gPSB2aWV3LmRvY1ZpZXcuZG9tRnJvbVBvcyhwb3MsIHNpZGUgPCAwID8gLTEgOiAxKTtcbiAgICBsZXQgc3VwcG9ydEVtcHR5UmFuZ2UgPSB3ZWJraXQgfHwgZ2Vja287XG4gICAgaWYgKG5vZGUubm9kZVR5cGUgPT0gMykge1xuICAgICAgICAvLyBUaGVzZSBicm93c2VycyBzdXBwb3J0IHF1ZXJ5aW5nIGVtcHR5IHRleHQgcmFuZ2VzLiBQcmVmZXIgdGhhdCBpblxuICAgICAgICAvLyBiaWRpIGNvbnRleHQgb3Igd2hlbiBhdCB0aGUgZW5kIG9mIGEgbm9kZS5cbiAgICAgICAgaWYgKHN1cHBvcnRFbXB0eVJhbmdlICYmIChCSURJLnRlc3Qobm9kZS5ub2RlVmFsdWUpIHx8IChzaWRlIDwgMCA/ICFvZmZzZXQgOiBvZmZzZXQgPT0gbm9kZS5ub2RlVmFsdWUubGVuZ3RoKSkpIHtcbiAgICAgICAgICAgIGxldCByZWN0ID0gc2luZ2xlUmVjdCh0ZXh0UmFuZ2Uobm9kZSwgb2Zmc2V0LCBvZmZzZXQpLCBzaWRlKTtcbiAgICAgICAgICAgIC8vIEZpcmVmb3ggcmV0dXJucyBiYWQgcmVzdWx0cyAodGhlIHBvc2l0aW9uIGJlZm9yZSB0aGUgc3BhY2UpXG4gICAgICAgICAgICAvLyB3aGVuIHF1ZXJ5aW5nIGEgcG9zaXRpb24gZGlyZWN0bHkgYWZ0ZXIgbGluZS1icm9rZW5cbiAgICAgICAgICAgIC8vIHdoaXRlc3BhY2UuIERldGVjdCB0aGlzIHNpdHVhdGlvbiBhbmQgYW5kIGtsdWRnZSBhcm91bmQgaXRcbiAgICAgICAgICAgIGlmIChnZWNrbyAmJiBvZmZzZXQgJiYgL1xccy8udGVzdChub2RlLm5vZGVWYWx1ZVtvZmZzZXQgLSAxXSkgJiYgb2Zmc2V0IDwgbm9kZS5ub2RlVmFsdWUubGVuZ3RoKSB7XG4gICAgICAgICAgICAgICAgbGV0IHJlY3RCZWZvcmUgPSBzaW5nbGVSZWN0KHRleHRSYW5nZShub2RlLCBvZmZzZXQgLSAxLCBvZmZzZXQgLSAxKSwgLTEpO1xuICAgICAgICAgICAgICAgIGlmIChyZWN0QmVmb3JlLnRvcCA9PSByZWN0LnRvcCkge1xuICAgICAgICAgICAgICAgICAgICBsZXQgcmVjdEFmdGVyID0gc2luZ2xlUmVjdCh0ZXh0UmFuZ2Uobm9kZSwgb2Zmc2V0LCBvZmZzZXQgKyAxKSwgLTEpO1xuICAgICAgICAgICAgICAgICAgICBpZiAocmVjdEFmdGVyLnRvcCAhPSByZWN0LnRvcClcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBmbGF0dGVuVihyZWN0QWZ0ZXIsIHJlY3RBZnRlci5sZWZ0IDwgcmVjdEJlZm9yZS5sZWZ0KTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gcmVjdDtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIGxldCBmcm9tID0gb2Zmc2V0LCB0byA9IG9mZnNldCwgdGFrZVNpZGUgPSBzaWRlIDwgMCA/IDEgOiAtMTtcbiAgICAgICAgICAgIGlmIChzaWRlIDwgMCAmJiAhb2Zmc2V0KSB7XG4gICAgICAgICAgICAgICAgdG8rKztcbiAgICAgICAgICAgICAgICB0YWtlU2lkZSA9IC0xO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSBpZiAoc2lkZSA+PSAwICYmIG9mZnNldCA9PSBub2RlLm5vZGVWYWx1ZS5sZW5ndGgpIHtcbiAgICAgICAgICAgICAgICBmcm9tLS07XG4gICAgICAgICAgICAgICAgdGFrZVNpZGUgPSAxO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSBpZiAoc2lkZSA8IDApIHtcbiAgICAgICAgICAgICAgICBmcm9tLS07XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICB0bysrO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIGZsYXR0ZW5WKHNpbmdsZVJlY3QodGV4dFJhbmdlKG5vZGUsIGZyb20sIHRvKSwgdGFrZVNpZGUpLCB0YWtlU2lkZSA8IDApO1xuICAgICAgICB9XG4gICAgfVxuICAgIGxldCAkZG9tID0gdmlldy5zdGF0ZS5kb2MucmVzb2x2ZShwb3MgLSAoYXRvbSB8fCAwKSk7XG4gICAgLy8gUmV0dXJuIGEgaG9yaXpvbnRhbCBsaW5lIGluIGJsb2NrIGNvbnRleHRcbiAgICBpZiAoISRkb20ucGFyZW50LmlubGluZUNvbnRlbnQpIHtcbiAgICAgICAgaWYgKGF0b20gPT0gbnVsbCAmJiBvZmZzZXQgJiYgKHNpZGUgPCAwIHx8IG9mZnNldCA9PSBub2RlU2l6ZShub2RlKSkpIHtcbiAgICAgICAgICAgIGxldCBiZWZvcmUgPSBub2RlLmNoaWxkTm9kZXNbb2Zmc2V0IC0gMV07XG4gICAgICAgICAgICBpZiAoYmVmb3JlLm5vZGVUeXBlID09IDEpXG4gICAgICAgICAgICAgICAgcmV0dXJuIGZsYXR0ZW5IKGJlZm9yZS5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKSwgZmFsc2UpO1xuICAgICAgICB9XG4gICAgICAgIGlmIChhdG9tID09IG51bGwgJiYgb2Zmc2V0IDwgbm9kZVNpemUobm9kZSkpIHtcbiAgICAgICAgICAgIGxldCBhZnRlciA9IG5vZGUuY2hpbGROb2Rlc1tvZmZzZXRdO1xuICAgICAgICAgICAgaWYgKGFmdGVyLm5vZGVUeXBlID09IDEpXG4gICAgICAgICAgICAgICAgcmV0dXJuIGZsYXR0ZW5IKGFmdGVyLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpLCB0cnVlKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gZmxhdHRlbkgobm9kZS5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKSwgc2lkZSA+PSAwKTtcbiAgICB9XG4gICAgLy8gSW5saW5lLCBub3QgaW4gdGV4dCBub2RlICh0aGlzIGlzIG5vdCBCaWRpLXNhZmUpXG4gICAgaWYgKGF0b20gPT0gbnVsbCAmJiBvZmZzZXQgJiYgKHNpZGUgPCAwIHx8IG9mZnNldCA9PSBub2RlU2l6ZShub2RlKSkpIHtcbiAgICAgICAgbGV0IGJlZm9yZSA9IG5vZGUuY2hpbGROb2Rlc1tvZmZzZXQgLSAxXTtcbiAgICAgICAgbGV0IHRhcmdldCA9IGJlZm9yZS5ub2RlVHlwZSA9PSAzID8gdGV4dFJhbmdlKGJlZm9yZSwgbm9kZVNpemUoYmVmb3JlKSAtIChzdXBwb3J0RW1wdHlSYW5nZSA/IDAgOiAxKSlcbiAgICAgICAgICAgIC8vIEJSIG5vZGVzIHRlbmQgdG8gb25seSByZXR1cm4gdGhlIHJlY3RhbmdsZSBiZWZvcmUgdGhlbS5cbiAgICAgICAgICAgIC8vIE9ubHkgdXNlIHRoZW0gaWYgdGhleSBhcmUgdGhlIGxhc3QgZWxlbWVudCBpbiB0aGVpciBwYXJlbnRcbiAgICAgICAgICAgIDogYmVmb3JlLm5vZGVUeXBlID09IDEgJiYgKGJlZm9yZS5ub2RlTmFtZSAhPSBcIkJSXCIgfHwgIWJlZm9yZS5uZXh0U2libGluZykgPyBiZWZvcmUgOiBudWxsO1xuICAgICAgICBpZiAodGFyZ2V0KVxuICAgICAgICAgICAgcmV0dXJuIGZsYXR0ZW5WKHNpbmdsZVJlY3QodGFyZ2V0LCAxKSwgZmFsc2UpO1xuICAgIH1cbiAgICBpZiAoYXRvbSA9PSBudWxsICYmIG9mZnNldCA8IG5vZGVTaXplKG5vZGUpKSB7XG4gICAgICAgIGxldCBhZnRlciA9IG5vZGUuY2hpbGROb2Rlc1tvZmZzZXRdO1xuICAgICAgICB3aGlsZSAoYWZ0ZXIucG1WaWV3RGVzYyAmJiBhZnRlci5wbVZpZXdEZXNjLmlnbm9yZUZvckNvb3JkcylcbiAgICAgICAgICAgIGFmdGVyID0gYWZ0ZXIubmV4dFNpYmxpbmc7XG4gICAgICAgIGxldCB0YXJnZXQgPSAhYWZ0ZXIgPyBudWxsIDogYWZ0ZXIubm9kZVR5cGUgPT0gMyA/IHRleHRSYW5nZShhZnRlciwgMCwgKHN1cHBvcnRFbXB0eVJhbmdlID8gMCA6IDEpKVxuICAgICAgICAgICAgOiBhZnRlci5ub2RlVHlwZSA9PSAxID8gYWZ0ZXIgOiBudWxsO1xuICAgICAgICBpZiAodGFyZ2V0KVxuICAgICAgICAgICAgcmV0dXJuIGZsYXR0ZW5WKHNpbmdsZVJlY3QodGFyZ2V0LCAtMSksIHRydWUpO1xuICAgIH1cbiAgICAvLyBBbGwgZWxzZSBmYWlsZWQsIGp1c3QgdHJ5IHRvIGdldCBhIHJlY3RhbmdsZSBmb3IgdGhlIHRhcmdldCBub2RlXG4gICAgcmV0dXJuIGZsYXR0ZW5WKHNpbmdsZVJlY3Qobm9kZS5ub2RlVHlwZSA9PSAzID8gdGV4dFJhbmdlKG5vZGUpIDogbm9kZSwgLXNpZGUpLCBzaWRlID49IDApO1xufVxuZnVuY3Rpb24gZmxhdHRlblYocmVjdCwgbGVmdCkge1xuICAgIGlmIChyZWN0LndpZHRoID09IDApXG4gICAgICAgIHJldHVybiByZWN0O1xuICAgIGxldCB4ID0gbGVmdCA/IHJlY3QubGVmdCA6IHJlY3QucmlnaHQ7XG4gICAgcmV0dXJuIHsgdG9wOiByZWN0LnRvcCwgYm90dG9tOiByZWN0LmJvdHRvbSwgbGVmdDogeCwgcmlnaHQ6IHggfTtcbn1cbmZ1bmN0aW9uIGZsYXR0ZW5IKHJlY3QsIHRvcCkge1xuICAgIGlmIChyZWN0LmhlaWdodCA9PSAwKVxuICAgICAgICByZXR1cm4gcmVjdDtcbiAgICBsZXQgeSA9IHRvcCA/IHJlY3QudG9wIDogcmVjdC5ib3R0b207XG4gICAgcmV0dXJuIHsgdG9wOiB5LCBib3R0b206IHksIGxlZnQ6IHJlY3QubGVmdCwgcmlnaHQ6IHJlY3QucmlnaHQgfTtcbn1cbmZ1bmN0aW9uIHdpdGhGbHVzaGVkU3RhdGUodmlldywgc3RhdGUsIGYpIHtcbiAgICBsZXQgdmlld1N0YXRlID0gdmlldy5zdGF0ZSwgYWN0aXZlID0gdmlldy5yb290LmFjdGl2ZUVsZW1lbnQ7XG4gICAgaWYgKHZpZXdTdGF0ZSAhPSBzdGF0ZSlcbiAgICAgICAgdmlldy51cGRhdGVTdGF0ZShzdGF0ZSk7XG4gICAgaWYgKGFjdGl2ZSAhPSB2aWV3LmRvbSlcbiAgICAgICAgdmlldy5mb2N1cygpO1xuICAgIHRyeSB7XG4gICAgICAgIHJldHVybiBmKCk7XG4gICAgfVxuICAgIGZpbmFsbHkge1xuICAgICAgICBpZiAodmlld1N0YXRlICE9IHN0YXRlKVxuICAgICAgICAgICAgdmlldy51cGRhdGVTdGF0ZSh2aWV3U3RhdGUpO1xuICAgICAgICBpZiAoYWN0aXZlICE9IHZpZXcuZG9tICYmIGFjdGl2ZSlcbiAgICAgICAgICAgIGFjdGl2ZS5mb2N1cygpO1xuICAgIH1cbn1cbi8vIFdoZXRoZXIgdmVydGljYWwgcG9zaXRpb24gbW90aW9uIGluIGEgZ2l2ZW4gZGlyZWN0aW9uXG4vLyBmcm9tIGEgcG9zaXRpb24gd291bGQgbGVhdmUgYSB0ZXh0IGJsb2NrLlxuZnVuY3Rpb24gZW5kT2ZUZXh0YmxvY2tWZXJ0aWNhbCh2aWV3LCBzdGF0ZSwgZGlyKSB7XG4gICAgbGV0IHNlbCA9IHN0YXRlLnNlbGVjdGlvbjtcbiAgICBsZXQgJHBvcyA9IGRpciA9PSBcInVwXCIgPyBzZWwuJGZyb20gOiBzZWwuJHRvO1xuICAgIHJldHVybiB3aXRoRmx1c2hlZFN0YXRlKHZpZXcsIHN0YXRlLCAoKSA9PiB7XG4gICAgICAgIGxldCB7IG5vZGU6IGRvbSB9ID0gdmlldy5kb2NWaWV3LmRvbUZyb21Qb3MoJHBvcy5wb3MsIGRpciA9PSBcInVwXCIgPyAtMSA6IDEpO1xuICAgICAgICBmb3IgKDs7KSB7XG4gICAgICAgICAgICBsZXQgbmVhcmVzdCA9IHZpZXcuZG9jVmlldy5uZWFyZXN0RGVzYyhkb20sIHRydWUpO1xuICAgICAgICAgICAgaWYgKCFuZWFyZXN0KVxuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgaWYgKG5lYXJlc3Qubm9kZS5pc0Jsb2NrKSB7XG4gICAgICAgICAgICAgICAgZG9tID0gbmVhcmVzdC5jb250ZW50RE9NIHx8IG5lYXJlc3QuZG9tO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZG9tID0gbmVhcmVzdC5kb20ucGFyZW50Tm9kZTtcbiAgICAgICAgfVxuICAgICAgICBsZXQgY29vcmRzID0gY29vcmRzQXRQb3ModmlldywgJHBvcy5wb3MsIDEpO1xuICAgICAgICBmb3IgKGxldCBjaGlsZCA9IGRvbS5maXJzdENoaWxkOyBjaGlsZDsgY2hpbGQgPSBjaGlsZC5uZXh0U2libGluZykge1xuICAgICAgICAgICAgbGV0IGJveGVzO1xuICAgICAgICAgICAgaWYgKGNoaWxkLm5vZGVUeXBlID09IDEpXG4gICAgICAgICAgICAgICAgYm94ZXMgPSBjaGlsZC5nZXRDbGllbnRSZWN0cygpO1xuICAgICAgICAgICAgZWxzZSBpZiAoY2hpbGQubm9kZVR5cGUgPT0gMylcbiAgICAgICAgICAgICAgICBib3hlcyA9IHRleHRSYW5nZShjaGlsZCwgMCwgY2hpbGQubm9kZVZhbHVlLmxlbmd0aCkuZ2V0Q2xpZW50UmVjdHMoKTtcbiAgICAgICAgICAgIGVsc2VcbiAgICAgICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgYm94ZXMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgICAgICBsZXQgYm94ID0gYm94ZXNbaV07XG4gICAgICAgICAgICAgICAgaWYgKGJveC5ib3R0b20gPiBib3gudG9wICsgMSAmJlxuICAgICAgICAgICAgICAgICAgICAoZGlyID09IFwidXBcIiA/IGNvb3Jkcy50b3AgLSBib3gudG9wID4gKGJveC5ib3R0b20gLSBjb29yZHMudG9wKSAqIDJcbiAgICAgICAgICAgICAgICAgICAgICAgIDogYm94LmJvdHRvbSAtIGNvb3Jkcy5ib3R0b20gPiAoY29vcmRzLmJvdHRvbSAtIGJveC50b3ApICogMikpXG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9KTtcbn1cbmNvbnN0IG1heWJlUlRMID0gL1tcXHUwNTkwLVxcdTA4YWNdLztcbmZ1bmN0aW9uIGVuZE9mVGV4dGJsb2NrSG9yaXpvbnRhbCh2aWV3LCBzdGF0ZSwgZGlyKSB7XG4gICAgbGV0IHsgJGhlYWQgfSA9IHN0YXRlLnNlbGVjdGlvbjtcbiAgICBpZiAoISRoZWFkLnBhcmVudC5pc1RleHRibG9jaylcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIGxldCBvZmZzZXQgPSAkaGVhZC5wYXJlbnRPZmZzZXQsIGF0U3RhcnQgPSAhb2Zmc2V0LCBhdEVuZCA9IG9mZnNldCA9PSAkaGVhZC5wYXJlbnQuY29udGVudC5zaXplO1xuICAgIGxldCBzZWwgPSB2aWV3LmRvbVNlbGVjdGlvbigpO1xuICAgIGlmICghc2VsKVxuICAgICAgICByZXR1cm4gJGhlYWQucG9zID09ICRoZWFkLnN0YXJ0KCkgfHwgJGhlYWQucG9zID09ICRoZWFkLmVuZCgpO1xuICAgIC8vIElmIHRoZSB0ZXh0YmxvY2sgaXMgYWxsIExUUiwgb3IgdGhlIGJyb3dzZXIgZG9lc24ndCBzdXBwb3J0XG4gICAgLy8gU2VsZWN0aW9uLm1vZGlmeSAoRWRnZSksIGZhbGwgYmFjayB0byBhIHByaW1pdGl2ZSBhcHByb2FjaFxuICAgIGlmICghbWF5YmVSVEwudGVzdCgkaGVhZC5wYXJlbnQudGV4dENvbnRlbnQpIHx8ICFzZWwubW9kaWZ5KVxuICAgICAgICByZXR1cm4gZGlyID09IFwibGVmdFwiIHx8IGRpciA9PSBcImJhY2t3YXJkXCIgPyBhdFN0YXJ0IDogYXRFbmQ7XG4gICAgcmV0dXJuIHdpdGhGbHVzaGVkU3RhdGUodmlldywgc3RhdGUsICgpID0+IHtcbiAgICAgICAgLy8gVGhpcyBpcyBhIGh1Z2UgaGFjaywgYnV0IGFwcGVhcnMgdG8gYmUgdGhlIGJlc3Qgd2UgY2FuXG4gICAgICAgIC8vIGN1cnJlbnRseSBkbzogdXNlIGBTZWxlY3Rpb24ubW9kaWZ5YCB0byBtb3ZlIHRoZSBzZWxlY3Rpb24gYnlcbiAgICAgICAgLy8gb25lIGNoYXJhY3RlciwgYW5kIHNlZSBpZiB0aGF0IG1vdmVzIHRoZSBjdXJzb3Igb3V0IG9mIHRoZVxuICAgICAgICAvLyB0ZXh0YmxvY2sgKG9yIGRvZXNuJ3QgbW92ZSBpdCBhdCBhbGwsIHdoZW4gYXQgdGhlIHN0YXJ0L2VuZCBvZlxuICAgICAgICAvLyB0aGUgZG9jdW1lbnQpLlxuICAgICAgICBsZXQgeyBmb2N1c05vZGU6IG9sZE5vZGUsIGZvY3VzT2Zmc2V0OiBvbGRPZmYsIGFuY2hvck5vZGUsIGFuY2hvck9mZnNldCB9ID0gdmlldy5kb21TZWxlY3Rpb25SYW5nZSgpO1xuICAgICAgICBsZXQgb2xkQmlkaUxldmVsID0gc2VsLmNhcmV0QmlkaUxldmVsIC8vIE9ubHkgZm9yIEZpcmVmb3hcbiAgICAgICAgO1xuICAgICAgICBzZWwubW9kaWZ5KFwibW92ZVwiLCBkaXIsIFwiY2hhcmFjdGVyXCIpO1xuICAgICAgICBsZXQgcGFyZW50RE9NID0gJGhlYWQuZGVwdGggPyB2aWV3LmRvY1ZpZXcuZG9tQWZ0ZXJQb3MoJGhlYWQuYmVmb3JlKCkpIDogdmlldy5kb207XG4gICAgICAgIGxldCB7IGZvY3VzTm9kZTogbmV3Tm9kZSwgZm9jdXNPZmZzZXQ6IG5ld09mZiB9ID0gdmlldy5kb21TZWxlY3Rpb25SYW5nZSgpO1xuICAgICAgICBsZXQgcmVzdWx0ID0gbmV3Tm9kZSAmJiAhcGFyZW50RE9NLmNvbnRhaW5zKG5ld05vZGUubm9kZVR5cGUgPT0gMSA/IG5ld05vZGUgOiBuZXdOb2RlLnBhcmVudE5vZGUpIHx8XG4gICAgICAgICAgICAob2xkTm9kZSA9PSBuZXdOb2RlICYmIG9sZE9mZiA9PSBuZXdPZmYpO1xuICAgICAgICAvLyBSZXN0b3JlIHRoZSBwcmV2aW91cyBzZWxlY3Rpb25cbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIHNlbC5jb2xsYXBzZShhbmNob3JOb2RlLCBhbmNob3JPZmZzZXQpO1xuICAgICAgICAgICAgaWYgKG9sZE5vZGUgJiYgKG9sZE5vZGUgIT0gYW5jaG9yTm9kZSB8fCBvbGRPZmYgIT0gYW5jaG9yT2Zmc2V0KSAmJiBzZWwuZXh0ZW5kKVxuICAgICAgICAgICAgICAgIHNlbC5leHRlbmQob2xkTm9kZSwgb2xkT2ZmKTtcbiAgICAgICAgfVxuICAgICAgICBjYXRjaCAoXykgeyB9XG4gICAgICAgIGlmIChvbGRCaWRpTGV2ZWwgIT0gbnVsbClcbiAgICAgICAgICAgIHNlbC5jYXJldEJpZGlMZXZlbCA9IG9sZEJpZGlMZXZlbDtcbiAgICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICB9KTtcbn1cbmxldCBjYWNoZWRTdGF0ZSA9IG51bGw7XG5sZXQgY2FjaGVkRGlyID0gbnVsbDtcbmxldCBjYWNoZWRSZXN1bHQgPSBmYWxzZTtcbmZ1bmN0aW9uIGVuZE9mVGV4dGJsb2NrKHZpZXcsIHN0YXRlLCBkaXIpIHtcbiAgICBpZiAoY2FjaGVkU3RhdGUgPT0gc3RhdGUgJiYgY2FjaGVkRGlyID09IGRpcilcbiAgICAgICAgcmV0dXJuIGNhY2hlZFJlc3VsdDtcbiAgICBjYWNoZWRTdGF0ZSA9IHN0YXRlO1xuICAgIGNhY2hlZERpciA9IGRpcjtcbiAgICByZXR1cm4gY2FjaGVkUmVzdWx0ID0gZGlyID09IFwidXBcIiB8fCBkaXIgPT0gXCJkb3duXCJcbiAgICAgICAgPyBlbmRPZlRleHRibG9ja1ZlcnRpY2FsKHZpZXcsIHN0YXRlLCBkaXIpXG4gICAgICAgIDogZW5kT2ZUZXh0YmxvY2tIb3Jpem9udGFsKHZpZXcsIHN0YXRlLCBkaXIpO1xufVxuXG4vLyBWaWV3IGRlc2NyaXB0aW9ucyBhcmUgZGF0YSBzdHJ1Y3R1cmVzIHRoYXQgZGVzY3JpYmUgdGhlIERPTSB0aGF0IGlzXG4vLyB1c2VkIHRvIHJlcHJlc2VudCB0aGUgZWRpdG9yJ3MgY29udGVudC4gVGhleSBhcmUgdXNlZCBmb3I6XG4vL1xuLy8gLSBJbmNyZW1lbnRhbCByZWRyYXdpbmcgd2hlbiB0aGUgZG9jdW1lbnQgY2hhbmdlc1xuLy9cbi8vIC0gRmlndXJpbmcgb3V0IHdoYXQgcGFydCBvZiB0aGUgZG9jdW1lbnQgYSBnaXZlbiBET00gcG9zaXRpb25cbi8vICAgY29ycmVzcG9uZHMgdG9cbi8vXG4vLyAtIFdpcmluZyBpbiBjdXN0b20gaW1wbGVtZW50YXRpb25zIG9mIHRoZSBlZGl0aW5nIGludGVyZmFjZSBmb3IgYVxuLy8gICBnaXZlbiBub2RlXG4vL1xuLy8gVGhleSBmb3JtIGEgZG91Ymx5LWxpbmtlZCBtdXRhYmxlIHRyZWUsIHN0YXJ0aW5nIGF0IGB2aWV3LmRvY1ZpZXdgLlxuY29uc3QgTk9UX0RJUlRZID0gMCwgQ0hJTERfRElSVFkgPSAxLCBDT05URU5UX0RJUlRZID0gMiwgTk9ERV9ESVJUWSA9IDM7XG4vLyBTdXBlcmNsYXNzIGZvciB0aGUgdmFyaW91cyBraW5kcyBvZiBkZXNjcmlwdGlvbnMuIERlZmluZXMgdGhlaXJcbi8vIGJhc2ljIHN0cnVjdHVyZSBhbmQgc2hhcmVkIG1ldGhvZHMuXG5jbGFzcyBWaWV3RGVzYyB7XG4gICAgY29uc3RydWN0b3IocGFyZW50LCBjaGlsZHJlbiwgZG9tLCBcbiAgICAvLyBUaGlzIGlzIHRoZSBub2RlIHRoYXQgaG9sZHMgdGhlIGNoaWxkIHZpZXdzLiBJdCBtYXkgYmUgbnVsbCBmb3JcbiAgICAvLyBkZXNjcyB0aGF0IGRvbid0IGhhdmUgY2hpbGRyZW4uXG4gICAgY29udGVudERPTSkge1xuICAgICAgICB0aGlzLnBhcmVudCA9IHBhcmVudDtcbiAgICAgICAgdGhpcy5jaGlsZHJlbiA9IGNoaWxkcmVuO1xuICAgICAgICB0aGlzLmRvbSA9IGRvbTtcbiAgICAgICAgdGhpcy5jb250ZW50RE9NID0gY29udGVudERPTTtcbiAgICAgICAgdGhpcy5kaXJ0eSA9IE5PVF9ESVJUWTtcbiAgICAgICAgLy8gQW4gZXhwYW5kbyBwcm9wZXJ0eSBvbiB0aGUgRE9NIG5vZGUgcHJvdmlkZXMgYSBsaW5rIGJhY2sgdG8gaXRzXG4gICAgICAgIC8vIGRlc2NyaXB0aW9uLlxuICAgICAgICBkb20ucG1WaWV3RGVzYyA9IHRoaXM7XG4gICAgfVxuICAgIC8vIFVzZWQgdG8gY2hlY2sgd2hldGhlciBhIGdpdmVuIGRlc2NyaXB0aW9uIGNvcnJlc3BvbmRzIHRvIGFcbiAgICAvLyB3aWRnZXQvbWFyay9ub2RlLlxuICAgIG1hdGNoZXNXaWRnZXQod2lkZ2V0KSB7IHJldHVybiBmYWxzZTsgfVxuICAgIG1hdGNoZXNNYXJrKG1hcmspIHsgcmV0dXJuIGZhbHNlOyB9XG4gICAgbWF0Y2hlc05vZGUobm9kZSwgb3V0ZXJEZWNvLCBpbm5lckRlY28pIHsgcmV0dXJuIGZhbHNlOyB9XG4gICAgbWF0Y2hlc0hhY2sobm9kZU5hbWUpIHsgcmV0dXJuIGZhbHNlOyB9XG4gICAgLy8gV2hlbiBwYXJzaW5nIGluLWVkaXRvciBjb250ZW50IChpbiBkb21jaGFuZ2UuanMpLCB3ZSBhbGxvd1xuICAgIC8vIGRlc2NyaXB0aW9ucyB0byBkZXRlcm1pbmUgdGhlIHBhcnNlIHJ1bGVzIHRoYXQgc2hvdWxkIGJlIHVzZWQgdG9cbiAgICAvLyBwYXJzZSB0aGVtLlxuICAgIHBhcnNlUnVsZSgpIHsgcmV0dXJuIG51bGw7IH1cbiAgICAvLyBVc2VkIGJ5IHRoZSBlZGl0b3IncyBldmVudCBoYW5kbGVyIHRvIGlnbm9yZSBldmVudHMgdGhhdCBjb21lXG4gICAgLy8gZnJvbSBjZXJ0YWluIGRlc2NzLlxuICAgIHN0b3BFdmVudChldmVudCkgeyByZXR1cm4gZmFsc2U7IH1cbiAgICAvLyBUaGUgc2l6ZSBvZiB0aGUgY29udGVudCByZXByZXNlbnRlZCBieSB0aGlzIGRlc2MuXG4gICAgZ2V0IHNpemUoKSB7XG4gICAgICAgIGxldCBzaXplID0gMDtcbiAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCB0aGlzLmNoaWxkcmVuLmxlbmd0aDsgaSsrKVxuICAgICAgICAgICAgc2l6ZSArPSB0aGlzLmNoaWxkcmVuW2ldLnNpemU7XG4gICAgICAgIHJldHVybiBzaXplO1xuICAgIH1cbiAgICAvLyBGb3IgYmxvY2sgbm9kZXMsIHRoaXMgcmVwcmVzZW50cyB0aGUgc3BhY2UgdGFrZW4gdXAgYnkgdGhlaXJcbiAgICAvLyBzdGFydC9lbmQgdG9rZW5zLlxuICAgIGdldCBib3JkZXIoKSB7IHJldHVybiAwOyB9XG4gICAgZGVzdHJveSgpIHtcbiAgICAgICAgdGhpcy5wYXJlbnQgPSB1bmRlZmluZWQ7XG4gICAgICAgIGlmICh0aGlzLmRvbS5wbVZpZXdEZXNjID09IHRoaXMpXG4gICAgICAgICAgICB0aGlzLmRvbS5wbVZpZXdEZXNjID0gdW5kZWZpbmVkO1xuICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMuY2hpbGRyZW4ubGVuZ3RoOyBpKyspXG4gICAgICAgICAgICB0aGlzLmNoaWxkcmVuW2ldLmRlc3Ryb3koKTtcbiAgICB9XG4gICAgcG9zQmVmb3JlQ2hpbGQoY2hpbGQpIHtcbiAgICAgICAgZm9yIChsZXQgaSA9IDAsIHBvcyA9IHRoaXMucG9zQXRTdGFydDs7IGkrKykge1xuICAgICAgICAgICAgbGV0IGN1ciA9IHRoaXMuY2hpbGRyZW5baV07XG4gICAgICAgICAgICBpZiAoY3VyID09IGNoaWxkKVxuICAgICAgICAgICAgICAgIHJldHVybiBwb3M7XG4gICAgICAgICAgICBwb3MgKz0gY3VyLnNpemU7XG4gICAgICAgIH1cbiAgICB9XG4gICAgZ2V0IHBvc0JlZm9yZSgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMucGFyZW50LnBvc0JlZm9yZUNoaWxkKHRoaXMpO1xuICAgIH1cbiAgICBnZXQgcG9zQXRTdGFydCgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMucGFyZW50ID8gdGhpcy5wYXJlbnQucG9zQmVmb3JlQ2hpbGQodGhpcykgKyB0aGlzLmJvcmRlciA6IDA7XG4gICAgfVxuICAgIGdldCBwb3NBZnRlcigpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMucG9zQmVmb3JlICsgdGhpcy5zaXplO1xuICAgIH1cbiAgICBnZXQgcG9zQXRFbmQoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLnBvc0F0U3RhcnQgKyB0aGlzLnNpemUgLSAyICogdGhpcy5ib3JkZXI7XG4gICAgfVxuICAgIGxvY2FsUG9zRnJvbURPTShkb20sIG9mZnNldCwgYmlhcykge1xuICAgICAgICAvLyBJZiB0aGUgRE9NIHBvc2l0aW9uIGlzIGluIHRoZSBjb250ZW50LCB1c2UgdGhlIGNoaWxkIGRlc2MgYWZ0ZXJcbiAgICAgICAgLy8gaXQgdG8gZmlndXJlIG91dCBhIHBvc2l0aW9uLlxuICAgICAgICBpZiAodGhpcy5jb250ZW50RE9NICYmIHRoaXMuY29udGVudERPTS5jb250YWlucyhkb20ubm9kZVR5cGUgPT0gMSA/IGRvbSA6IGRvbS5wYXJlbnROb2RlKSkge1xuICAgICAgICAgICAgaWYgKGJpYXMgPCAwKSB7XG4gICAgICAgICAgICAgICAgbGV0IGRvbUJlZm9yZSwgZGVzYztcbiAgICAgICAgICAgICAgICBpZiAoZG9tID09IHRoaXMuY29udGVudERPTSkge1xuICAgICAgICAgICAgICAgICAgICBkb21CZWZvcmUgPSBkb20uY2hpbGROb2Rlc1tvZmZzZXQgLSAxXTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIHdoaWxlIChkb20ucGFyZW50Tm9kZSAhPSB0aGlzLmNvbnRlbnRET00pXG4gICAgICAgICAgICAgICAgICAgICAgICBkb20gPSBkb20ucGFyZW50Tm9kZTtcbiAgICAgICAgICAgICAgICAgICAgZG9tQmVmb3JlID0gZG9tLnByZXZpb3VzU2libGluZztcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgd2hpbGUgKGRvbUJlZm9yZSAmJiAhKChkZXNjID0gZG9tQmVmb3JlLnBtVmlld0Rlc2MpICYmIGRlc2MucGFyZW50ID09IHRoaXMpKVxuICAgICAgICAgICAgICAgICAgICBkb21CZWZvcmUgPSBkb21CZWZvcmUucHJldmlvdXNTaWJsaW5nO1xuICAgICAgICAgICAgICAgIHJldHVybiBkb21CZWZvcmUgPyB0aGlzLnBvc0JlZm9yZUNoaWxkKGRlc2MpICsgZGVzYy5zaXplIDogdGhpcy5wb3NBdFN0YXJ0O1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgbGV0IGRvbUFmdGVyLCBkZXNjO1xuICAgICAgICAgICAgICAgIGlmIChkb20gPT0gdGhpcy5jb250ZW50RE9NKSB7XG4gICAgICAgICAgICAgICAgICAgIGRvbUFmdGVyID0gZG9tLmNoaWxkTm9kZXNbb2Zmc2V0XTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIHdoaWxlIChkb20ucGFyZW50Tm9kZSAhPSB0aGlzLmNvbnRlbnRET00pXG4gICAgICAgICAgICAgICAgICAgICAgICBkb20gPSBkb20ucGFyZW50Tm9kZTtcbiAgICAgICAgICAgICAgICAgICAgZG9tQWZ0ZXIgPSBkb20ubmV4dFNpYmxpbmc7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHdoaWxlIChkb21BZnRlciAmJiAhKChkZXNjID0gZG9tQWZ0ZXIucG1WaWV3RGVzYykgJiYgZGVzYy5wYXJlbnQgPT0gdGhpcykpXG4gICAgICAgICAgICAgICAgICAgIGRvbUFmdGVyID0gZG9tQWZ0ZXIubmV4dFNpYmxpbmc7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGRvbUFmdGVyID8gdGhpcy5wb3NCZWZvcmVDaGlsZChkZXNjKSA6IHRoaXMucG9zQXRFbmQ7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgLy8gT3RoZXJ3aXNlLCB1c2UgdmFyaW91cyBoZXVyaXN0aWNzLCBmYWxsaW5nIGJhY2sgb24gdGhlIGJpYXNcbiAgICAgICAgLy8gcGFyYW1ldGVyLCB0byBkZXRlcm1pbmUgd2hldGhlciB0byByZXR1cm4gdGhlIHBvc2l0aW9uIGF0IHRoZVxuICAgICAgICAvLyBzdGFydCBvciBhdCB0aGUgZW5kIG9mIHRoaXMgdmlldyBkZXNjLlxuICAgICAgICBsZXQgYXRFbmQ7XG4gICAgICAgIGlmIChkb20gPT0gdGhpcy5kb20gJiYgdGhpcy5jb250ZW50RE9NKSB7XG4gICAgICAgICAgICBhdEVuZCA9IG9mZnNldCA+IGRvbUluZGV4KHRoaXMuY29udGVudERPTSk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAodGhpcy5jb250ZW50RE9NICYmIHRoaXMuY29udGVudERPTSAhPSB0aGlzLmRvbSAmJiB0aGlzLmRvbS5jb250YWlucyh0aGlzLmNvbnRlbnRET00pKSB7XG4gICAgICAgICAgICBhdEVuZCA9IGRvbS5jb21wYXJlRG9jdW1lbnRQb3NpdGlvbih0aGlzLmNvbnRlbnRET00pICYgMjtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIGlmICh0aGlzLmRvbS5maXJzdENoaWxkKSB7XG4gICAgICAgICAgICBpZiAob2Zmc2V0ID09IDApXG4gICAgICAgICAgICAgICAgZm9yIChsZXQgc2VhcmNoID0gZG9tOzsgc2VhcmNoID0gc2VhcmNoLnBhcmVudE5vZGUpIHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKHNlYXJjaCA9PSB0aGlzLmRvbSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgYXRFbmQgPSBmYWxzZTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIGlmIChzZWFyY2gucHJldmlvdXNTaWJsaW5nKVxuICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKGF0RW5kID09IG51bGwgJiYgb2Zmc2V0ID09IGRvbS5jaGlsZE5vZGVzLmxlbmd0aClcbiAgICAgICAgICAgICAgICBmb3IgKGxldCBzZWFyY2ggPSBkb207OyBzZWFyY2ggPSBzZWFyY2gucGFyZW50Tm9kZSkge1xuICAgICAgICAgICAgICAgICAgICBpZiAoc2VhcmNoID09IHRoaXMuZG9tKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBhdEVuZCA9IHRydWU7XG4gICAgICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBpZiAoc2VhcmNoLm5leHRTaWJsaW5nKVxuICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHJldHVybiAoYXRFbmQgPT0gbnVsbCA/IGJpYXMgPiAwIDogYXRFbmQpID8gdGhpcy5wb3NBdEVuZCA6IHRoaXMucG9zQXRTdGFydDtcbiAgICB9XG4gICAgbmVhcmVzdERlc2MoZG9tLCBvbmx5Tm9kZXMgPSBmYWxzZSkge1xuICAgICAgICBmb3IgKGxldCBmaXJzdCA9IHRydWUsIGN1ciA9IGRvbTsgY3VyOyBjdXIgPSBjdXIucGFyZW50Tm9kZSkge1xuICAgICAgICAgICAgbGV0IGRlc2MgPSB0aGlzLmdldERlc2MoY3VyKSwgbm9kZURPTTtcbiAgICAgICAgICAgIGlmIChkZXNjICYmICghb25seU5vZGVzIHx8IGRlc2Mubm9kZSkpIHtcbiAgICAgICAgICAgICAgICAvLyBJZiBkb20gaXMgb3V0c2lkZSBvZiB0aGlzIGRlc2MncyBub2RlRE9NLCBkb24ndCBjb3VudCBpdC5cbiAgICAgICAgICAgICAgICBpZiAoZmlyc3QgJiYgKG5vZGVET00gPSBkZXNjLm5vZGVET00pICYmXG4gICAgICAgICAgICAgICAgICAgICEobm9kZURPTS5ub2RlVHlwZSA9PSAxID8gbm9kZURPTS5jb250YWlucyhkb20ubm9kZVR5cGUgPT0gMSA/IGRvbSA6IGRvbS5wYXJlbnROb2RlKSA6IG5vZGVET00gPT0gZG9tKSlcbiAgICAgICAgICAgICAgICAgICAgZmlyc3QgPSBmYWxzZTtcbiAgICAgICAgICAgICAgICBlbHNlXG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBkZXNjO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuICAgIGdldERlc2MoZG9tKSB7XG4gICAgICAgIGxldCBkZXNjID0gZG9tLnBtVmlld0Rlc2M7XG4gICAgICAgIGZvciAobGV0IGN1ciA9IGRlc2M7IGN1cjsgY3VyID0gY3VyLnBhcmVudClcbiAgICAgICAgICAgIGlmIChjdXIgPT0gdGhpcylcbiAgICAgICAgICAgICAgICByZXR1cm4gZGVzYztcbiAgICB9XG4gICAgcG9zRnJvbURPTShkb20sIG9mZnNldCwgYmlhcykge1xuICAgICAgICBmb3IgKGxldCBzY2FuID0gZG9tOyBzY2FuOyBzY2FuID0gc2Nhbi5wYXJlbnROb2RlKSB7XG4gICAgICAgICAgICBsZXQgZGVzYyA9IHRoaXMuZ2V0RGVzYyhzY2FuKTtcbiAgICAgICAgICAgIGlmIChkZXNjKVxuICAgICAgICAgICAgICAgIHJldHVybiBkZXNjLmxvY2FsUG9zRnJvbURPTShkb20sIG9mZnNldCwgYmlhcyk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIC0xO1xuICAgIH1cbiAgICAvLyBGaW5kIHRoZSBkZXNjIGZvciB0aGUgbm9kZSBhZnRlciB0aGUgZ2l2ZW4gcG9zLCBpZiBhbnkuIChXaGVuIGFcbiAgICAvLyBwYXJlbnQgbm9kZSBvdmVycm9kZSByZW5kZXJpbmcsIHRoZXJlIG1pZ2h0IG5vdCBiZSBvbmUuKVxuICAgIGRlc2NBdChwb3MpIHtcbiAgICAgICAgZm9yIChsZXQgaSA9IDAsIG9mZnNldCA9IDA7IGkgPCB0aGlzLmNoaWxkcmVuLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICBsZXQgY2hpbGQgPSB0aGlzLmNoaWxkcmVuW2ldLCBlbmQgPSBvZmZzZXQgKyBjaGlsZC5zaXplO1xuICAgICAgICAgICAgaWYgKG9mZnNldCA9PSBwb3MgJiYgZW5kICE9IG9mZnNldCkge1xuICAgICAgICAgICAgICAgIHdoaWxlICghY2hpbGQuYm9yZGVyICYmIGNoaWxkLmNoaWxkcmVuLmxlbmd0aCkge1xuICAgICAgICAgICAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IGNoaWxkLmNoaWxkcmVuLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBsZXQgaW5uZXIgPSBjaGlsZC5jaGlsZHJlbltpXTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChpbm5lci5zaXplKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY2hpbGQgPSBpbm5lcjtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICByZXR1cm4gY2hpbGQ7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAocG9zIDwgZW5kKVxuICAgICAgICAgICAgICAgIHJldHVybiBjaGlsZC5kZXNjQXQocG9zIC0gb2Zmc2V0IC0gY2hpbGQuYm9yZGVyKTtcbiAgICAgICAgICAgIG9mZnNldCA9IGVuZDtcbiAgICAgICAgfVxuICAgIH1cbiAgICBkb21Gcm9tUG9zKHBvcywgc2lkZSkge1xuICAgICAgICBpZiAoIXRoaXMuY29udGVudERPTSlcbiAgICAgICAgICAgIHJldHVybiB7IG5vZGU6IHRoaXMuZG9tLCBvZmZzZXQ6IDAsIGF0b206IHBvcyArIDEgfTtcbiAgICAgICAgLy8gRmlyc3QgZmluZCB0aGUgcG9zaXRpb24gaW4gdGhlIGNoaWxkIGFycmF5XG4gICAgICAgIGxldCBpID0gMCwgb2Zmc2V0ID0gMDtcbiAgICAgICAgZm9yIChsZXQgY3VyUG9zID0gMDsgaSA8IHRoaXMuY2hpbGRyZW4ubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgIGxldCBjaGlsZCA9IHRoaXMuY2hpbGRyZW5baV0sIGVuZCA9IGN1clBvcyArIGNoaWxkLnNpemU7XG4gICAgICAgICAgICBpZiAoZW5kID4gcG9zIHx8IGNoaWxkIGluc3RhbmNlb2YgVHJhaWxpbmdIYWNrVmlld0Rlc2MpIHtcbiAgICAgICAgICAgICAgICBvZmZzZXQgPSBwb3MgLSBjdXJQb3M7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjdXJQb3MgPSBlbmQ7XG4gICAgICAgIH1cbiAgICAgICAgLy8gSWYgdGhpcyBwb2ludHMgaW50byB0aGUgbWlkZGxlIG9mIGEgY2hpbGQsIGNhbGwgdGhyb3VnaFxuICAgICAgICBpZiAob2Zmc2V0KVxuICAgICAgICAgICAgcmV0dXJuIHRoaXMuY2hpbGRyZW5baV0uZG9tRnJvbVBvcyhvZmZzZXQgLSB0aGlzLmNoaWxkcmVuW2ldLmJvcmRlciwgc2lkZSk7XG4gICAgICAgIC8vIEdvIGJhY2sgaWYgdGhlcmUgd2VyZSBhbnkgemVyby1sZW5ndGggd2lkZ2V0cyB3aXRoIHNpZGUgPj0gMCBiZWZvcmUgdGhpcyBwb2ludFxuICAgICAgICBmb3IgKGxldCBwcmV2OyBpICYmICEocHJldiA9IHRoaXMuY2hpbGRyZW5baSAtIDFdKS5zaXplICYmIHByZXYgaW5zdGFuY2VvZiBXaWRnZXRWaWV3RGVzYyAmJiBwcmV2LnNpZGUgPj0gMDsgaS0tKSB7IH1cbiAgICAgICAgLy8gU2NhbiB0b3dhcmRzIHRoZSBmaXJzdCB1c2VhYmxlIG5vZGVcbiAgICAgICAgaWYgKHNpZGUgPD0gMCkge1xuICAgICAgICAgICAgbGV0IHByZXYsIGVudGVyID0gdHJ1ZTtcbiAgICAgICAgICAgIGZvciAoOzsgaS0tLCBlbnRlciA9IGZhbHNlKSB7XG4gICAgICAgICAgICAgICAgcHJldiA9IGkgPyB0aGlzLmNoaWxkcmVuW2kgLSAxXSA6IG51bGw7XG4gICAgICAgICAgICAgICAgaWYgKCFwcmV2IHx8IHByZXYuZG9tLnBhcmVudE5vZGUgPT0gdGhpcy5jb250ZW50RE9NKVxuICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmIChwcmV2ICYmIHNpZGUgJiYgZW50ZXIgJiYgIXByZXYuYm9yZGVyICYmICFwcmV2LmRvbUF0b20pXG4gICAgICAgICAgICAgICAgcmV0dXJuIHByZXYuZG9tRnJvbVBvcyhwcmV2LnNpemUsIHNpZGUpO1xuICAgICAgICAgICAgcmV0dXJuIHsgbm9kZTogdGhpcy5jb250ZW50RE9NLCBvZmZzZXQ6IHByZXYgPyBkb21JbmRleChwcmV2LmRvbSkgKyAxIDogMCB9O1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgbGV0IG5leHQsIGVudGVyID0gdHJ1ZTtcbiAgICAgICAgICAgIGZvciAoOzsgaSsrLCBlbnRlciA9IGZhbHNlKSB7XG4gICAgICAgICAgICAgICAgbmV4dCA9IGkgPCB0aGlzLmNoaWxkcmVuLmxlbmd0aCA/IHRoaXMuY2hpbGRyZW5baV0gOiBudWxsO1xuICAgICAgICAgICAgICAgIGlmICghbmV4dCB8fCBuZXh0LmRvbS5wYXJlbnROb2RlID09IHRoaXMuY29udGVudERPTSlcbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAobmV4dCAmJiBlbnRlciAmJiAhbmV4dC5ib3JkZXIgJiYgIW5leHQuZG9tQXRvbSlcbiAgICAgICAgICAgICAgICByZXR1cm4gbmV4dC5kb21Gcm9tUG9zKDAsIHNpZGUpO1xuICAgICAgICAgICAgcmV0dXJuIHsgbm9kZTogdGhpcy5jb250ZW50RE9NLCBvZmZzZXQ6IG5leHQgPyBkb21JbmRleChuZXh0LmRvbSkgOiB0aGlzLmNvbnRlbnRET00uY2hpbGROb2Rlcy5sZW5ndGggfTtcbiAgICAgICAgfVxuICAgIH1cbiAgICAvLyBVc2VkIHRvIGZpbmQgYSBET00gcmFuZ2UgaW4gYSBzaW5nbGUgcGFyZW50IGZvciBhIGdpdmVuIGNoYW5nZWRcbiAgICAvLyByYW5nZS5cbiAgICBwYXJzZVJhbmdlKGZyb20sIHRvLCBiYXNlID0gMCkge1xuICAgICAgICBpZiAodGhpcy5jaGlsZHJlbi5sZW5ndGggPT0gMClcbiAgICAgICAgICAgIHJldHVybiB7IG5vZGU6IHRoaXMuY29udGVudERPTSwgZnJvbSwgdG8sIGZyb21PZmZzZXQ6IDAsIHRvT2Zmc2V0OiB0aGlzLmNvbnRlbnRET00uY2hpbGROb2Rlcy5sZW5ndGggfTtcbiAgICAgICAgbGV0IGZyb21PZmZzZXQgPSAtMSwgdG9PZmZzZXQgPSAtMTtcbiAgICAgICAgZm9yIChsZXQgb2Zmc2V0ID0gYmFzZSwgaSA9IDA7OyBpKyspIHtcbiAgICAgICAgICAgIGxldCBjaGlsZCA9IHRoaXMuY2hpbGRyZW5baV0sIGVuZCA9IG9mZnNldCArIGNoaWxkLnNpemU7XG4gICAgICAgICAgICBpZiAoZnJvbU9mZnNldCA9PSAtMSAmJiBmcm9tIDw9IGVuZCkge1xuICAgICAgICAgICAgICAgIGxldCBjaGlsZEJhc2UgPSBvZmZzZXQgKyBjaGlsZC5ib3JkZXI7XG4gICAgICAgICAgICAgICAgLy8gRklYTUUgbWF5YmUgZGVzY2VuZCBtYXJrIHZpZXdzIHRvIHBhcnNlIGEgbmFycm93ZXIgcmFuZ2U/XG4gICAgICAgICAgICAgICAgaWYgKGZyb20gPj0gY2hpbGRCYXNlICYmIHRvIDw9IGVuZCAtIGNoaWxkLmJvcmRlciAmJiBjaGlsZC5ub2RlICYmXG4gICAgICAgICAgICAgICAgICAgIGNoaWxkLmNvbnRlbnRET00gJiYgdGhpcy5jb250ZW50RE9NLmNvbnRhaW5zKGNoaWxkLmNvbnRlbnRET00pKVxuICAgICAgICAgICAgICAgICAgICByZXR1cm4gY2hpbGQucGFyc2VSYW5nZShmcm9tLCB0bywgY2hpbGRCYXNlKTtcbiAgICAgICAgICAgICAgICBmcm9tID0gb2Zmc2V0O1xuICAgICAgICAgICAgICAgIGZvciAobGV0IGogPSBpOyBqID4gMDsgai0tKSB7XG4gICAgICAgICAgICAgICAgICAgIGxldCBwcmV2ID0gdGhpcy5jaGlsZHJlbltqIC0gMV07XG4gICAgICAgICAgICAgICAgICAgIGlmIChwcmV2LnNpemUgJiYgcHJldi5kb20ucGFyZW50Tm9kZSA9PSB0aGlzLmNvbnRlbnRET00gJiYgIXByZXYuZW1wdHlDaGlsZEF0KDEpKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBmcm9tT2Zmc2V0ID0gZG9tSW5kZXgocHJldi5kb20pICsgMTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIGZyb20gLT0gcHJldi5zaXplO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBpZiAoZnJvbU9mZnNldCA9PSAtMSlcbiAgICAgICAgICAgICAgICAgICAgZnJvbU9mZnNldCA9IDA7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoZnJvbU9mZnNldCA+IC0xICYmIChlbmQgPiB0byB8fCBpID09IHRoaXMuY2hpbGRyZW4ubGVuZ3RoIC0gMSkpIHtcbiAgICAgICAgICAgICAgICB0byA9IGVuZDtcbiAgICAgICAgICAgICAgICBmb3IgKGxldCBqID0gaSArIDE7IGogPCB0aGlzLmNoaWxkcmVuLmxlbmd0aDsgaisrKSB7XG4gICAgICAgICAgICAgICAgICAgIGxldCBuZXh0ID0gdGhpcy5jaGlsZHJlbltqXTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKG5leHQuc2l6ZSAmJiBuZXh0LmRvbS5wYXJlbnROb2RlID09IHRoaXMuY29udGVudERPTSAmJiAhbmV4dC5lbXB0eUNoaWxkQXQoLTEpKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB0b09mZnNldCA9IGRvbUluZGV4KG5leHQuZG9tKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIHRvICs9IG5leHQuc2l6ZTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgaWYgKHRvT2Zmc2V0ID09IC0xKVxuICAgICAgICAgICAgICAgICAgICB0b09mZnNldCA9IHRoaXMuY29udGVudERPTS5jaGlsZE5vZGVzLmxlbmd0aDtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIG9mZnNldCA9IGVuZDtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4geyBub2RlOiB0aGlzLmNvbnRlbnRET00sIGZyb20sIHRvLCBmcm9tT2Zmc2V0LCB0b09mZnNldCB9O1xuICAgIH1cbiAgICBlbXB0eUNoaWxkQXQoc2lkZSkge1xuICAgICAgICBpZiAodGhpcy5ib3JkZXIgfHwgIXRoaXMuY29udGVudERPTSB8fCAhdGhpcy5jaGlsZHJlbi5sZW5ndGgpXG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIGxldCBjaGlsZCA9IHRoaXMuY2hpbGRyZW5bc2lkZSA8IDAgPyAwIDogdGhpcy5jaGlsZHJlbi5sZW5ndGggLSAxXTtcbiAgICAgICAgcmV0dXJuIGNoaWxkLnNpemUgPT0gMCB8fCBjaGlsZC5lbXB0eUNoaWxkQXQoc2lkZSk7XG4gICAgfVxuICAgIGRvbUFmdGVyUG9zKHBvcykge1xuICAgICAgICBsZXQgeyBub2RlLCBvZmZzZXQgfSA9IHRoaXMuZG9tRnJvbVBvcyhwb3MsIDApO1xuICAgICAgICBpZiAobm9kZS5ub2RlVHlwZSAhPSAxIHx8IG9mZnNldCA9PSBub2RlLmNoaWxkTm9kZXMubGVuZ3RoKVxuICAgICAgICAgICAgdGhyb3cgbmV3IFJhbmdlRXJyb3IoXCJObyBub2RlIGFmdGVyIHBvcyBcIiArIHBvcyk7XG4gICAgICAgIHJldHVybiBub2RlLmNoaWxkTm9kZXNbb2Zmc2V0XTtcbiAgICB9XG4gICAgLy8gVmlldyBkZXNjcyBhcmUgcmVzcG9uc2libGUgZm9yIHNldHRpbmcgYW55IHNlbGVjdGlvbiB0aGF0IGZhbGxzXG4gICAgLy8gZW50aXJlbHkgaW5zaWRlIG9mIHRoZW0sIHNvIHRoYXQgY3VzdG9tIGltcGxlbWVudGF0aW9ucyBjYW4gZG9cbiAgICAvLyBjdXN0b20gdGhpbmdzIHdpdGggdGhlIHNlbGVjdGlvbi4gTm90ZSB0aGF0IHRoaXMgZmFsbHMgYXBhcnQgd2hlblxuICAgIC8vIGEgc2VsZWN0aW9uIHN0YXJ0cyBpbiBzdWNoIGEgbm9kZSBhbmQgZW5kcyBpbiBhbm90aGVyLCBpbiB3aGljaFxuICAgIC8vIGNhc2Ugd2UganVzdCB1c2Ugd2hhdGV2ZXIgZG9tRnJvbVBvcyBwcm9kdWNlcyBhcyBhIGJlc3QgZWZmb3J0LlxuICAgIHNldFNlbGVjdGlvbihhbmNob3IsIGhlYWQsIHZpZXcsIGZvcmNlID0gZmFsc2UpIHtcbiAgICAgICAgLy8gSWYgdGhlIHNlbGVjdGlvbiBmYWxscyBlbnRpcmVseSBpbiBhIGNoaWxkLCBnaXZlIGl0IHRvIHRoYXQgY2hpbGRcbiAgICAgICAgbGV0IGZyb20gPSBNYXRoLm1pbihhbmNob3IsIGhlYWQpLCB0byA9IE1hdGgubWF4KGFuY2hvciwgaGVhZCk7XG4gICAgICAgIGZvciAobGV0IGkgPSAwLCBvZmZzZXQgPSAwOyBpIDwgdGhpcy5jaGlsZHJlbi5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgbGV0IGNoaWxkID0gdGhpcy5jaGlsZHJlbltpXSwgZW5kID0gb2Zmc2V0ICsgY2hpbGQuc2l6ZTtcbiAgICAgICAgICAgIGlmIChmcm9tID4gb2Zmc2V0ICYmIHRvIDwgZW5kKVxuICAgICAgICAgICAgICAgIHJldHVybiBjaGlsZC5zZXRTZWxlY3Rpb24oYW5jaG9yIC0gb2Zmc2V0IC0gY2hpbGQuYm9yZGVyLCBoZWFkIC0gb2Zmc2V0IC0gY2hpbGQuYm9yZGVyLCB2aWV3LCBmb3JjZSk7XG4gICAgICAgICAgICBvZmZzZXQgPSBlbmQ7XG4gICAgICAgIH1cbiAgICAgICAgbGV0IGFuY2hvckRPTSA9IHRoaXMuZG9tRnJvbVBvcyhhbmNob3IsIGFuY2hvciA/IC0xIDogMSk7XG4gICAgICAgIGxldCBoZWFkRE9NID0gaGVhZCA9PSBhbmNob3IgPyBhbmNob3JET00gOiB0aGlzLmRvbUZyb21Qb3MoaGVhZCwgaGVhZCA/IC0xIDogMSk7XG4gICAgICAgIGxldCBkb21TZWwgPSB2aWV3LnJvb3QuZ2V0U2VsZWN0aW9uKCk7XG4gICAgICAgIGxldCBzZWxSYW5nZSA9IHZpZXcuZG9tU2VsZWN0aW9uUmFuZ2UoKTtcbiAgICAgICAgbGV0IGJyS2x1ZGdlID0gZmFsc2U7XG4gICAgICAgIC8vIE9uIEZpcmVmb3gsIHVzaW5nIFNlbGVjdGlvbi5jb2xsYXBzZSB0byBwdXQgdGhlIGN1cnNvciBhZnRlciBhXG4gICAgICAgIC8vIEJSIG5vZGUgZm9yIHNvbWUgcmVhc29uIGRvZXNuJ3QgYWx3YXlzIHdvcmsgKCMxMDczKS4gT24gU2FmYXJpLFxuICAgICAgICAvLyB0aGUgY3Vyc29yIHNvbWV0aW1lcyBpbmV4cGxpY2FibGUgdmlzdWFsbHkgbGFncyBiZWhpbmQgaXRzXG4gICAgICAgIC8vIHJlcG9ydGVkIHBvc2l0aW9uIGluIHN1Y2ggc2l0dWF0aW9ucyAoIzEwOTIpLlxuICAgICAgICBpZiAoKGdlY2tvIHx8IHNhZmFyaSkgJiYgYW5jaG9yID09IGhlYWQpIHtcbiAgICAgICAgICAgIGxldCB7IG5vZGUsIG9mZnNldCB9ID0gYW5jaG9yRE9NO1xuICAgICAgICAgICAgaWYgKG5vZGUubm9kZVR5cGUgPT0gMykge1xuICAgICAgICAgICAgICAgIGJyS2x1ZGdlID0gISEob2Zmc2V0ICYmIG5vZGUubm9kZVZhbHVlW29mZnNldCAtIDFdID09IFwiXFxuXCIpO1xuICAgICAgICAgICAgICAgIC8vIElzc3VlICMxMTI4XG4gICAgICAgICAgICAgICAgaWYgKGJyS2x1ZGdlICYmIG9mZnNldCA9PSBub2RlLm5vZGVWYWx1ZS5sZW5ndGgpIHtcbiAgICAgICAgICAgICAgICAgICAgZm9yIChsZXQgc2NhbiA9IG5vZGUsIGFmdGVyOyBzY2FuOyBzY2FuID0gc2Nhbi5wYXJlbnROb2RlKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoYWZ0ZXIgPSBzY2FuLm5leHRTaWJsaW5nKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGFmdGVyLm5vZGVOYW1lID09IFwiQlJcIilcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYW5jaG9yRE9NID0gaGVhZERPTSA9IHsgbm9kZTogYWZ0ZXIucGFyZW50Tm9kZSwgb2Zmc2V0OiBkb21JbmRleChhZnRlcikgKyAxIH07XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICBsZXQgZGVzYyA9IHNjYW4ucG1WaWV3RGVzYztcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChkZXNjICYmIGRlc2Mubm9kZSAmJiBkZXNjLm5vZGUuaXNCbG9jaylcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgIGxldCBwcmV2ID0gbm9kZS5jaGlsZE5vZGVzW29mZnNldCAtIDFdO1xuICAgICAgICAgICAgICAgIGJyS2x1ZGdlID0gcHJldiAmJiAocHJldi5ub2RlTmFtZSA9PSBcIkJSXCIgfHwgcHJldi5jb250ZW50RWRpdGFibGUgPT0gXCJmYWxzZVwiKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICAvLyBGaXJlZm94IGNhbiBhY3Qgc3RyYW5nZWx5IHdoZW4gdGhlIHNlbGVjdGlvbiBpcyBpbiBmcm9udCBvZiBhblxuICAgICAgICAvLyB1bmVkaXRhYmxlIG5vZGUuIFNlZSAjMTE2MyBhbmQgaHR0cHM6Ly9idWd6aWxsYS5tb3ppbGxhLm9yZy9zaG93X2J1Zy5jZ2k/aWQ9MTcwOTUzNlxuICAgICAgICBpZiAoZ2Vja28gJiYgc2VsUmFuZ2UuZm9jdXNOb2RlICYmIHNlbFJhbmdlLmZvY3VzTm9kZSAhPSBoZWFkRE9NLm5vZGUgJiYgc2VsUmFuZ2UuZm9jdXNOb2RlLm5vZGVUeXBlID09IDEpIHtcbiAgICAgICAgICAgIGxldCBhZnRlciA9IHNlbFJhbmdlLmZvY3VzTm9kZS5jaGlsZE5vZGVzW3NlbFJhbmdlLmZvY3VzT2Zmc2V0XTtcbiAgICAgICAgICAgIGlmIChhZnRlciAmJiBhZnRlci5jb250ZW50RWRpdGFibGUgPT0gXCJmYWxzZVwiKVxuICAgICAgICAgICAgICAgIGZvcmNlID0gdHJ1ZTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoIShmb3JjZSB8fCBicktsdWRnZSAmJiBzYWZhcmkpICYmXG4gICAgICAgICAgICBpc0VxdWl2YWxlbnRQb3NpdGlvbihhbmNob3JET00ubm9kZSwgYW5jaG9yRE9NLm9mZnNldCwgc2VsUmFuZ2UuYW5jaG9yTm9kZSwgc2VsUmFuZ2UuYW5jaG9yT2Zmc2V0KSAmJlxuICAgICAgICAgICAgaXNFcXVpdmFsZW50UG9zaXRpb24oaGVhZERPTS5ub2RlLCBoZWFkRE9NLm9mZnNldCwgc2VsUmFuZ2UuZm9jdXNOb2RlLCBzZWxSYW5nZS5mb2N1c09mZnNldCkpXG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIC8vIFNlbGVjdGlvbi5leHRlbmQgY2FuIGJlIHVzZWQgdG8gY3JlYXRlIGFuICdpbnZlcnRlZCcgc2VsZWN0aW9uXG4gICAgICAgIC8vIChvbmUgd2hlcmUgdGhlIGZvY3VzIGlzIGJlZm9yZSB0aGUgYW5jaG9yKSwgYnV0IG5vdCBhbGxcbiAgICAgICAgLy8gYnJvd3NlcnMgc3VwcG9ydCBpdCB5ZXQuXG4gICAgICAgIGxldCBkb21TZWxFeHRlbmRlZCA9IGZhbHNlO1xuICAgICAgICBpZiAoKGRvbVNlbC5leHRlbmQgfHwgYW5jaG9yID09IGhlYWQpICYmICEoYnJLbHVkZ2UgJiYgZ2Vja28pKSB7XG4gICAgICAgICAgICBkb21TZWwuY29sbGFwc2UoYW5jaG9yRE9NLm5vZGUsIGFuY2hvckRPTS5vZmZzZXQpO1xuICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICBpZiAoYW5jaG9yICE9IGhlYWQpXG4gICAgICAgICAgICAgICAgICAgIGRvbVNlbC5leHRlbmQoaGVhZERPTS5ub2RlLCBoZWFkRE9NLm9mZnNldCk7XG4gICAgICAgICAgICAgICAgZG9tU2VsRXh0ZW5kZWQgPSB0cnVlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgY2F0Y2ggKF8pIHtcbiAgICAgICAgICAgICAgICAvLyBJbiBzb21lIGNhc2VzIHdpdGggQ2hyb21lIHRoZSBzZWxlY3Rpb24gaXMgZW1wdHkgYWZ0ZXIgY2FsbGluZ1xuICAgICAgICAgICAgICAgIC8vIGNvbGxhcHNlLCBldmVuIHdoZW4gaXQgc2hvdWxkIGJlIHZhbGlkLiBUaGlzIGFwcGVhcnMgdG8gYmUgYSBidWcsIGJ1dFxuICAgICAgICAgICAgICAgIC8vIGl0IGlzIGRpZmZpY3VsdCB0byBpc29sYXRlLiBJZiB0aGlzIGhhcHBlbnMgZmFsbGJhY2sgdG8gdGhlIG9sZCBwYXRoXG4gICAgICAgICAgICAgICAgLy8gd2l0aG91dCB1c2luZyBleHRlbmQuXG4gICAgICAgICAgICAgICAgLy8gU2ltaWxhcmx5LCB0aGlzIGNvdWxkIGNyYXNoIG9uIFNhZmFyaSBpZiB0aGUgZWRpdG9yIGlzIGhpZGRlbiwgYW5kXG4gICAgICAgICAgICAgICAgLy8gdGhlcmUgd2FzIG5vIHNlbGVjdGlvbi5cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBpZiAoIWRvbVNlbEV4dGVuZGVkKSB7XG4gICAgICAgICAgICBpZiAoYW5jaG9yID4gaGVhZCkge1xuICAgICAgICAgICAgICAgIGxldCB0bXAgPSBhbmNob3JET007XG4gICAgICAgICAgICAgICAgYW5jaG9yRE9NID0gaGVhZERPTTtcbiAgICAgICAgICAgICAgICBoZWFkRE9NID0gdG1wO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgbGV0IHJhbmdlID0gZG9jdW1lbnQuY3JlYXRlUmFuZ2UoKTtcbiAgICAgICAgICAgIHJhbmdlLnNldEVuZChoZWFkRE9NLm5vZGUsIGhlYWRET00ub2Zmc2V0KTtcbiAgICAgICAgICAgIHJhbmdlLnNldFN0YXJ0KGFuY2hvckRPTS5ub2RlLCBhbmNob3JET00ub2Zmc2V0KTtcbiAgICAgICAgICAgIGRvbVNlbC5yZW1vdmVBbGxSYW5nZXMoKTtcbiAgICAgICAgICAgIGRvbVNlbC5hZGRSYW5nZShyYW5nZSk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgaWdub3JlTXV0YXRpb24obXV0YXRpb24pIHtcbiAgICAgICAgcmV0dXJuICF0aGlzLmNvbnRlbnRET00gJiYgbXV0YXRpb24udHlwZSAhPSBcInNlbGVjdGlvblwiO1xuICAgIH1cbiAgICBnZXQgY29udGVudExvc3QoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmNvbnRlbnRET00gJiYgdGhpcy5jb250ZW50RE9NICE9IHRoaXMuZG9tICYmICF0aGlzLmRvbS5jb250YWlucyh0aGlzLmNvbnRlbnRET00pO1xuICAgIH1cbiAgICAvLyBSZW1vdmUgYSBzdWJ0cmVlIG9mIHRoZSBlbGVtZW50IHRyZWUgdGhhdCBoYXMgYmVlbiB0b3VjaGVkXG4gICAgLy8gYnkgYSBET00gY2hhbmdlLCBzbyB0aGF0IHRoZSBuZXh0IHVwZGF0ZSB3aWxsIHJlZHJhdyBpdC5cbiAgICBtYXJrRGlydHkoZnJvbSwgdG8pIHtcbiAgICAgICAgZm9yIChsZXQgb2Zmc2V0ID0gMCwgaSA9IDA7IGkgPCB0aGlzLmNoaWxkcmVuLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICBsZXQgY2hpbGQgPSB0aGlzLmNoaWxkcmVuW2ldLCBlbmQgPSBvZmZzZXQgKyBjaGlsZC5zaXplO1xuICAgICAgICAgICAgaWYgKG9mZnNldCA9PSBlbmQgPyBmcm9tIDw9IGVuZCAmJiB0byA+PSBvZmZzZXQgOiBmcm9tIDwgZW5kICYmIHRvID4gb2Zmc2V0KSB7XG4gICAgICAgICAgICAgICAgbGV0IHN0YXJ0SW5zaWRlID0gb2Zmc2V0ICsgY2hpbGQuYm9yZGVyLCBlbmRJbnNpZGUgPSBlbmQgLSBjaGlsZC5ib3JkZXI7XG4gICAgICAgICAgICAgICAgaWYgKGZyb20gPj0gc3RhcnRJbnNpZGUgJiYgdG8gPD0gZW5kSW5zaWRlKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuZGlydHkgPSBmcm9tID09IG9mZnNldCB8fCB0byA9PSBlbmQgPyBDT05URU5UX0RJUlRZIDogQ0hJTERfRElSVFk7XG4gICAgICAgICAgICAgICAgICAgIGlmIChmcm9tID09IHN0YXJ0SW5zaWRlICYmIHRvID09IGVuZEluc2lkZSAmJlxuICAgICAgICAgICAgICAgICAgICAgICAgKGNoaWxkLmNvbnRlbnRMb3N0IHx8IGNoaWxkLmRvbS5wYXJlbnROb2RlICE9IHRoaXMuY29udGVudERPTSkpXG4gICAgICAgICAgICAgICAgICAgICAgICBjaGlsZC5kaXJ0eSA9IE5PREVfRElSVFk7XG4gICAgICAgICAgICAgICAgICAgIGVsc2VcbiAgICAgICAgICAgICAgICAgICAgICAgIGNoaWxkLm1hcmtEaXJ0eShmcm9tIC0gc3RhcnRJbnNpZGUsIHRvIC0gc3RhcnRJbnNpZGUpO1xuICAgICAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICBjaGlsZC5kaXJ0eSA9IGNoaWxkLmRvbSA9PSBjaGlsZC5jb250ZW50RE9NICYmIGNoaWxkLmRvbS5wYXJlbnROb2RlID09IHRoaXMuY29udGVudERPTSAmJiAhY2hpbGQuY2hpbGRyZW4ubGVuZ3RoXG4gICAgICAgICAgICAgICAgICAgICAgICA/IENPTlRFTlRfRElSVFkgOiBOT0RFX0RJUlRZO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIG9mZnNldCA9IGVuZDtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLmRpcnR5ID0gQ09OVEVOVF9ESVJUWTtcbiAgICB9XG4gICAgbWFya1BhcmVudHNEaXJ0eSgpIHtcbiAgICAgICAgbGV0IGxldmVsID0gMTtcbiAgICAgICAgZm9yIChsZXQgbm9kZSA9IHRoaXMucGFyZW50OyBub2RlOyBub2RlID0gbm9kZS5wYXJlbnQsIGxldmVsKyspIHtcbiAgICAgICAgICAgIGxldCBkaXJ0eSA9IGxldmVsID09IDEgPyBDT05URU5UX0RJUlRZIDogQ0hJTERfRElSVFk7XG4gICAgICAgICAgICBpZiAobm9kZS5kaXJ0eSA8IGRpcnR5KVxuICAgICAgICAgICAgICAgIG5vZGUuZGlydHkgPSBkaXJ0eTtcbiAgICAgICAgfVxuICAgIH1cbiAgICBnZXQgZG9tQXRvbSgpIHsgcmV0dXJuIGZhbHNlOyB9XG4gICAgZ2V0IGlnbm9yZUZvckNvb3JkcygpIHsgcmV0dXJuIGZhbHNlOyB9XG4gICAgZ2V0IGlnbm9yZUZvclNlbGVjdGlvbigpIHsgcmV0dXJuIGZhbHNlOyB9XG4gICAgaXNUZXh0KHRleHQpIHsgcmV0dXJuIGZhbHNlOyB9XG59XG4vLyBBIHdpZGdldCBkZXNjIHJlcHJlc2VudHMgYSB3aWRnZXQgZGVjb3JhdGlvbiwgd2hpY2ggaXMgYSBET00gbm9kZVxuLy8gZHJhd24gYmV0d2VlbiB0aGUgZG9jdW1lbnQgbm9kZXMuXG5jbGFzcyBXaWRnZXRWaWV3RGVzYyBleHRlbmRzIFZpZXdEZXNjIHtcbiAgICBjb25zdHJ1Y3RvcihwYXJlbnQsIHdpZGdldCwgdmlldywgcG9zKSB7XG4gICAgICAgIGxldCBzZWxmLCBkb20gPSB3aWRnZXQudHlwZS50b0RPTTtcbiAgICAgICAgaWYgKHR5cGVvZiBkb20gPT0gXCJmdW5jdGlvblwiKVxuICAgICAgICAgICAgZG9tID0gZG9tKHZpZXcsICgpID0+IHtcbiAgICAgICAgICAgICAgICBpZiAoIXNlbGYpXG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBwb3M7XG4gICAgICAgICAgICAgICAgaWYgKHNlbGYucGFyZW50KVxuICAgICAgICAgICAgICAgICAgICByZXR1cm4gc2VsZi5wYXJlbnQucG9zQmVmb3JlQ2hpbGQoc2VsZik7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgaWYgKCF3aWRnZXQudHlwZS5zcGVjLnJhdykge1xuICAgICAgICAgICAgaWYgKGRvbS5ub2RlVHlwZSAhPSAxKSB7XG4gICAgICAgICAgICAgICAgbGV0IHdyYXAgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KFwic3BhblwiKTtcbiAgICAgICAgICAgICAgICB3cmFwLmFwcGVuZENoaWxkKGRvbSk7XG4gICAgICAgICAgICAgICAgZG9tID0gd3JhcDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGRvbS5jb250ZW50RWRpdGFibGUgPSBcImZhbHNlXCI7XG4gICAgICAgICAgICBkb20uY2xhc3NMaXN0LmFkZChcIlByb3NlTWlycm9yLXdpZGdldFwiKTtcbiAgICAgICAgfVxuICAgICAgICBzdXBlcihwYXJlbnQsIFtdLCBkb20sIG51bGwpO1xuICAgICAgICB0aGlzLndpZGdldCA9IHdpZGdldDtcbiAgICAgICAgdGhpcy53aWRnZXQgPSB3aWRnZXQ7XG4gICAgICAgIHNlbGYgPSB0aGlzO1xuICAgIH1cbiAgICBtYXRjaGVzV2lkZ2V0KHdpZGdldCkge1xuICAgICAgICByZXR1cm4gdGhpcy5kaXJ0eSA9PSBOT1RfRElSVFkgJiYgd2lkZ2V0LnR5cGUuZXEodGhpcy53aWRnZXQudHlwZSk7XG4gICAgfVxuICAgIHBhcnNlUnVsZSgpIHsgcmV0dXJuIHsgaWdub3JlOiB0cnVlIH07IH1cbiAgICBzdG9wRXZlbnQoZXZlbnQpIHtcbiAgICAgICAgbGV0IHN0b3AgPSB0aGlzLndpZGdldC5zcGVjLnN0b3BFdmVudDtcbiAgICAgICAgcmV0dXJuIHN0b3AgPyBzdG9wKGV2ZW50KSA6IGZhbHNlO1xuICAgIH1cbiAgICBpZ25vcmVNdXRhdGlvbihtdXRhdGlvbikge1xuICAgICAgICByZXR1cm4gbXV0YXRpb24udHlwZSAhPSBcInNlbGVjdGlvblwiIHx8IHRoaXMud2lkZ2V0LnNwZWMuaWdub3JlU2VsZWN0aW9uO1xuICAgIH1cbiAgICBkZXN0cm95KCkge1xuICAgICAgICB0aGlzLndpZGdldC50eXBlLmRlc3Ryb3kodGhpcy5kb20pO1xuICAgICAgICBzdXBlci5kZXN0cm95KCk7XG4gICAgfVxuICAgIGdldCBkb21BdG9tKCkgeyByZXR1cm4gdHJ1ZTsgfVxuICAgIGdldCBpZ25vcmVGb3JTZWxlY3Rpb24oKSB7IHJldHVybiAhIXRoaXMud2lkZ2V0LnR5cGUuc3BlYy5yZWxheGVkU2lkZTsgfVxuICAgIGdldCBzaWRlKCkgeyByZXR1cm4gdGhpcy53aWRnZXQudHlwZS5zaWRlOyB9XG59XG5jbGFzcyBDb21wb3NpdGlvblZpZXdEZXNjIGV4dGVuZHMgVmlld0Rlc2Mge1xuICAgIGNvbnN0cnVjdG9yKHBhcmVudCwgZG9tLCB0ZXh0RE9NLCB0ZXh0KSB7XG4gICAgICAgIHN1cGVyKHBhcmVudCwgW10sIGRvbSwgbnVsbCk7XG4gICAgICAgIHRoaXMudGV4dERPTSA9IHRleHRET007XG4gICAgICAgIHRoaXMudGV4dCA9IHRleHQ7XG4gICAgfVxuICAgIGdldCBzaXplKCkgeyByZXR1cm4gdGhpcy50ZXh0Lmxlbmd0aDsgfVxuICAgIGxvY2FsUG9zRnJvbURPTShkb20sIG9mZnNldCkge1xuICAgICAgICBpZiAoZG9tICE9IHRoaXMudGV4dERPTSlcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnBvc0F0U3RhcnQgKyAob2Zmc2V0ID8gdGhpcy5zaXplIDogMCk7XG4gICAgICAgIHJldHVybiB0aGlzLnBvc0F0U3RhcnQgKyBvZmZzZXQ7XG4gICAgfVxuICAgIGRvbUZyb21Qb3MocG9zKSB7XG4gICAgICAgIHJldHVybiB7IG5vZGU6IHRoaXMudGV4dERPTSwgb2Zmc2V0OiBwb3MgfTtcbiAgICB9XG4gICAgaWdub3JlTXV0YXRpb24obXV0KSB7XG4gICAgICAgIHJldHVybiBtdXQudHlwZSA9PT0gJ2NoYXJhY3RlckRhdGEnICYmIG11dC50YXJnZXQubm9kZVZhbHVlID09IG11dC5vbGRWYWx1ZTtcbiAgICB9XG59XG4vLyBBIG1hcmsgZGVzYyByZXByZXNlbnRzIGEgbWFyay4gTWF5IGhhdmUgbXVsdGlwbGUgY2hpbGRyZW4sXG4vLyBkZXBlbmRpbmcgb24gaG93IHRoZSBtYXJrIGlzIHNwbGl0LiBOb3RlIHRoYXQgbWFya3MgYXJlIGRyYXduIHVzaW5nXG4vLyBhIGZpeGVkIG5lc3Rpbmcgb3JkZXIsIGZvciBzaW1wbGljaXR5IGFuZCBwcmVkaWN0YWJpbGl0eSwgc28gaW5cbi8vIHNvbWUgY2FzZXMgdGhleSB3aWxsIGJlIHNwbGl0IG1vcmUgb2Z0ZW4gdGhhbiB3b3VsZCBhcHBlYXJcbi8vIG5lY2Vzc2FyeS5cbmNsYXNzIE1hcmtWaWV3RGVzYyBleHRlbmRzIFZpZXdEZXNjIHtcbiAgICBjb25zdHJ1Y3RvcihwYXJlbnQsIG1hcmssIGRvbSwgY29udGVudERPTSwgc3BlYykge1xuICAgICAgICBzdXBlcihwYXJlbnQsIFtdLCBkb20sIGNvbnRlbnRET00pO1xuICAgICAgICB0aGlzLm1hcmsgPSBtYXJrO1xuICAgICAgICB0aGlzLnNwZWMgPSBzcGVjO1xuICAgIH1cbiAgICBzdGF0aWMgY3JlYXRlKHBhcmVudCwgbWFyaywgaW5saW5lLCB2aWV3KSB7XG4gICAgICAgIGxldCBjdXN0b20gPSB2aWV3Lm5vZGVWaWV3c1ttYXJrLnR5cGUubmFtZV07XG4gICAgICAgIGxldCBzcGVjID0gY3VzdG9tICYmIGN1c3RvbShtYXJrLCB2aWV3LCBpbmxpbmUpO1xuICAgICAgICBpZiAoIXNwZWMgfHwgIXNwZWMuZG9tKVxuICAgICAgICAgICAgc3BlYyA9IERPTVNlcmlhbGl6ZXIucmVuZGVyU3BlYyhkb2N1bWVudCwgbWFyay50eXBlLnNwZWMudG9ET00obWFyaywgaW5saW5lKSwgbnVsbCwgbWFyay5hdHRycyk7XG4gICAgICAgIHJldHVybiBuZXcgTWFya1ZpZXdEZXNjKHBhcmVudCwgbWFyaywgc3BlYy5kb20sIHNwZWMuY29udGVudERPTSB8fCBzcGVjLmRvbSwgc3BlYyk7XG4gICAgfVxuICAgIHBhcnNlUnVsZSgpIHtcbiAgICAgICAgaWYgKCh0aGlzLmRpcnR5ICYgTk9ERV9ESVJUWSkgfHwgdGhpcy5tYXJrLnR5cGUuc3BlYy5yZXBhcnNlSW5WaWV3KVxuICAgICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgIHJldHVybiB7IG1hcms6IHRoaXMubWFyay50eXBlLm5hbWUsIGF0dHJzOiB0aGlzLm1hcmsuYXR0cnMsIGNvbnRlbnRFbGVtZW50OiB0aGlzLmNvbnRlbnRET00gfTtcbiAgICB9XG4gICAgbWF0Y2hlc01hcmsobWFyaykgeyByZXR1cm4gdGhpcy5kaXJ0eSAhPSBOT0RFX0RJUlRZICYmIHRoaXMubWFyay5lcShtYXJrKTsgfVxuICAgIG1hcmtEaXJ0eShmcm9tLCB0bykge1xuICAgICAgICBzdXBlci5tYXJrRGlydHkoZnJvbSwgdG8pO1xuICAgICAgICAvLyBNb3ZlIGRpcnR5IGluZm8gdG8gbmVhcmVzdCBub2RlIHZpZXdcbiAgICAgICAgaWYgKHRoaXMuZGlydHkgIT0gTk9UX0RJUlRZKSB7XG4gICAgICAgICAgICBsZXQgcGFyZW50ID0gdGhpcy5wYXJlbnQ7XG4gICAgICAgICAgICB3aGlsZSAoIXBhcmVudC5ub2RlKVxuICAgICAgICAgICAgICAgIHBhcmVudCA9IHBhcmVudC5wYXJlbnQ7XG4gICAgICAgICAgICBpZiAocGFyZW50LmRpcnR5IDwgdGhpcy5kaXJ0eSlcbiAgICAgICAgICAgICAgICBwYXJlbnQuZGlydHkgPSB0aGlzLmRpcnR5O1xuICAgICAgICAgICAgdGhpcy5kaXJ0eSA9IE5PVF9ESVJUWTtcbiAgICAgICAgfVxuICAgIH1cbiAgICBzbGljZShmcm9tLCB0bywgdmlldykge1xuICAgICAgICBsZXQgY29weSA9IE1hcmtWaWV3RGVzYy5jcmVhdGUodGhpcy5wYXJlbnQsIHRoaXMubWFyaywgdHJ1ZSwgdmlldyk7XG4gICAgICAgIGxldCBub2RlcyA9IHRoaXMuY2hpbGRyZW4sIHNpemUgPSB0aGlzLnNpemU7XG4gICAgICAgIGlmICh0byA8IHNpemUpXG4gICAgICAgICAgICBub2RlcyA9IHJlcGxhY2VOb2Rlcyhub2RlcywgdG8sIHNpemUsIHZpZXcpO1xuICAgICAgICBpZiAoZnJvbSA+IDApXG4gICAgICAgICAgICBub2RlcyA9IHJlcGxhY2VOb2Rlcyhub2RlcywgMCwgZnJvbSwgdmlldyk7XG4gICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgbm9kZXMubGVuZ3RoOyBpKyspXG4gICAgICAgICAgICBub2Rlc1tpXS5wYXJlbnQgPSBjb3B5O1xuICAgICAgICBjb3B5LmNoaWxkcmVuID0gbm9kZXM7XG4gICAgICAgIHJldHVybiBjb3B5O1xuICAgIH1cbiAgICBpZ25vcmVNdXRhdGlvbihtdXRhdGlvbikge1xuICAgICAgICByZXR1cm4gdGhpcy5zcGVjLmlnbm9yZU11dGF0aW9uID8gdGhpcy5zcGVjLmlnbm9yZU11dGF0aW9uKG11dGF0aW9uKSA6IHN1cGVyLmlnbm9yZU11dGF0aW9uKG11dGF0aW9uKTtcbiAgICB9XG4gICAgZGVzdHJveSgpIHtcbiAgICAgICAgaWYgKHRoaXMuc3BlYy5kZXN0cm95KVxuICAgICAgICAgICAgdGhpcy5zcGVjLmRlc3Ryb3koKTtcbiAgICAgICAgc3VwZXIuZGVzdHJveSgpO1xuICAgIH1cbn1cbi8vIE5vZGUgdmlldyBkZXNjcyBhcmUgdGhlIG1haW4sIG1vc3QgY29tbW9uIHR5cGUgb2YgdmlldyBkZXNjLCBhbmRcbi8vIGNvcnJlc3BvbmQgdG8gYW4gYWN0dWFsIG5vZGUgaW4gdGhlIGRvY3VtZW50LiBVbmxpa2UgbWFyayBkZXNjcyxcbi8vIHRoZXkgcG9wdWxhdGUgdGhlaXIgY2hpbGQgYXJyYXkgdGhlbXNlbHZlcy5cbmNsYXNzIE5vZGVWaWV3RGVzYyBleHRlbmRzIFZpZXdEZXNjIHtcbiAgICBjb25zdHJ1Y3RvcihwYXJlbnQsIG5vZGUsIG91dGVyRGVjbywgaW5uZXJEZWNvLCBkb20sIGNvbnRlbnRET00sIG5vZGVET00sIHZpZXcsIHBvcykge1xuICAgICAgICBzdXBlcihwYXJlbnQsIFtdLCBkb20sIGNvbnRlbnRET00pO1xuICAgICAgICB0aGlzLm5vZGUgPSBub2RlO1xuICAgICAgICB0aGlzLm91dGVyRGVjbyA9IG91dGVyRGVjbztcbiAgICAgICAgdGhpcy5pbm5lckRlY28gPSBpbm5lckRlY287XG4gICAgICAgIHRoaXMubm9kZURPTSA9IG5vZGVET007XG4gICAgfVxuICAgIC8vIEJ5IGRlZmF1bHQsIGEgbm9kZSBpcyByZW5kZXJlZCB1c2luZyB0aGUgYHRvRE9NYCBtZXRob2QgZnJvbSB0aGVcbiAgICAvLyBub2RlIHR5cGUgc3BlYy4gQnV0IGNsaWVudCBjb2RlIGNhbiB1c2UgdGhlIGBub2RlVmlld3NgIHNwZWMgdG9cbiAgICAvLyBzdXBwbHkgYSBjdXN0b20gbm9kZSB2aWV3LCB3aGljaCBjYW4gaW5mbHVlbmNlIHZhcmlvdXMgYXNwZWN0cyBvZlxuICAgIC8vIHRoZSB3YXkgdGhlIG5vZGUgd29ya3MuXG4gICAgLy9cbiAgICAvLyAoVXNpbmcgc3ViY2xhc3NpbmcgZm9yIHRoaXMgd2FzIGludGVudGlvbmFsbHkgZGVjaWRlZCBhZ2FpbnN0LFxuICAgIC8vIHNpbmNlIGl0J2QgcmVxdWlyZSBleHBvc2luZyBhIHdob2xlIHNsZXcgb2YgZmluaWNreVxuICAgIC8vIGltcGxlbWVudGF0aW9uIGRldGFpbHMgdG8gdGhlIHVzZXIgY29kZSB0aGF0IHRoZXkgcHJvYmFibHkgd2lsbFxuICAgIC8vIG5ldmVyIG5lZWQuKVxuICAgIHN0YXRpYyBjcmVhdGUocGFyZW50LCBub2RlLCBvdXRlckRlY28sIGlubmVyRGVjbywgdmlldywgcG9zKSB7XG4gICAgICAgIGxldCBjdXN0b20gPSB2aWV3Lm5vZGVWaWV3c1tub2RlLnR5cGUubmFtZV0sIGRlc2NPYmo7XG4gICAgICAgIGxldCBzcGVjID0gY3VzdG9tICYmIGN1c3RvbShub2RlLCB2aWV3LCAoKSA9PiB7XG4gICAgICAgICAgICAvLyAoVGhpcyBpcyBhIGZ1bmN0aW9uIHRoYXQgYWxsb3dzIHRoZSBjdXN0b20gdmlldyB0byBmaW5kIGl0c1xuICAgICAgICAgICAgLy8gb3duIHBvc2l0aW9uKVxuICAgICAgICAgICAgaWYgKCFkZXNjT2JqKVxuICAgICAgICAgICAgICAgIHJldHVybiBwb3M7XG4gICAgICAgICAgICBpZiAoZGVzY09iai5wYXJlbnQpXG4gICAgICAgICAgICAgICAgcmV0dXJuIGRlc2NPYmoucGFyZW50LnBvc0JlZm9yZUNoaWxkKGRlc2NPYmopO1xuICAgICAgICB9LCBvdXRlckRlY28sIGlubmVyRGVjbyk7XG4gICAgICAgIGxldCBkb20gPSBzcGVjICYmIHNwZWMuZG9tLCBjb250ZW50RE9NID0gc3BlYyAmJiBzcGVjLmNvbnRlbnRET007XG4gICAgICAgIGlmIChub2RlLmlzVGV4dCkge1xuICAgICAgICAgICAgaWYgKCFkb20pXG4gICAgICAgICAgICAgICAgZG9tID0gZG9jdW1lbnQuY3JlYXRlVGV4dE5vZGUobm9kZS50ZXh0KTtcbiAgICAgICAgICAgIGVsc2UgaWYgKGRvbS5ub2RlVHlwZSAhPSAzKVxuICAgICAgICAgICAgICAgIHRocm93IG5ldyBSYW5nZUVycm9yKFwiVGV4dCBtdXN0IGJlIHJlbmRlcmVkIGFzIGEgRE9NIHRleHQgbm9kZVwiKTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIGlmICghZG9tKSB7XG4gICAgICAgICAgICBsZXQgc3BlYyA9IERPTVNlcmlhbGl6ZXIucmVuZGVyU3BlYyhkb2N1bWVudCwgbm9kZS50eXBlLnNwZWMudG9ET00obm9kZSksIG51bGwsIG5vZGUuYXR0cnMpO1xuICAgICAgICAgICAgKHsgZG9tLCBjb250ZW50RE9NIH0gPSBzcGVjKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoIWNvbnRlbnRET00gJiYgIW5vZGUuaXNUZXh0ICYmIGRvbS5ub2RlTmFtZSAhPSBcIkJSXCIpIHsgLy8gQ2hyb21lIGdldHMgY29uZnVzZWQgYnkgPGJyIGNvbnRlbnRlZGl0YWJsZT1mYWxzZT5cbiAgICAgICAgICAgIGlmICghZG9tLmhhc0F0dHJpYnV0ZShcImNvbnRlbnRlZGl0YWJsZVwiKSlcbiAgICAgICAgICAgICAgICBkb20uY29udGVudEVkaXRhYmxlID0gXCJmYWxzZVwiO1xuICAgICAgICAgICAgaWYgKG5vZGUudHlwZS5zcGVjLmRyYWdnYWJsZSlcbiAgICAgICAgICAgICAgICBkb20uZHJhZ2dhYmxlID0gdHJ1ZTtcbiAgICAgICAgfVxuICAgICAgICBsZXQgbm9kZURPTSA9IGRvbTtcbiAgICAgICAgZG9tID0gYXBwbHlPdXRlckRlY28oZG9tLCBvdXRlckRlY28sIG5vZGUpO1xuICAgICAgICBpZiAoc3BlYylcbiAgICAgICAgICAgIHJldHVybiBkZXNjT2JqID0gbmV3IEN1c3RvbU5vZGVWaWV3RGVzYyhwYXJlbnQsIG5vZGUsIG91dGVyRGVjbywgaW5uZXJEZWNvLCBkb20sIGNvbnRlbnRET00gfHwgbnVsbCwgbm9kZURPTSwgc3BlYywgdmlldywgcG9zICsgMSk7XG4gICAgICAgIGVsc2UgaWYgKG5vZGUuaXNUZXh0KVxuICAgICAgICAgICAgcmV0dXJuIG5ldyBUZXh0Vmlld0Rlc2MocGFyZW50LCBub2RlLCBvdXRlckRlY28sIGlubmVyRGVjbywgZG9tLCBub2RlRE9NLCB2aWV3KTtcbiAgICAgICAgZWxzZVxuICAgICAgICAgICAgcmV0dXJuIG5ldyBOb2RlVmlld0Rlc2MocGFyZW50LCBub2RlLCBvdXRlckRlY28sIGlubmVyRGVjbywgZG9tLCBjb250ZW50RE9NIHx8IG51bGwsIG5vZGVET00sIHZpZXcsIHBvcyArIDEpO1xuICAgIH1cbiAgICBwYXJzZVJ1bGUoKSB7XG4gICAgICAgIC8vIEV4cGVyaW1lbnRhbCBrbHVkZ2UgdG8gYWxsb3cgb3B0LWluIHJlLXBhcnNpbmcgb2Ygbm9kZXNcbiAgICAgICAgaWYgKHRoaXMubm9kZS50eXBlLnNwZWMucmVwYXJzZUluVmlldylcbiAgICAgICAgICAgIHJldHVybiBudWxsO1xuICAgICAgICAvLyBGSVhNRSB0aGUgYXNzdW1wdGlvbiB0aGF0IHRoaXMgY2FuIGFsd2F5cyByZXR1cm4gdGhlIGN1cnJlbnRcbiAgICAgICAgLy8gYXR0cnMgbWVhbnMgdGhhdCBpZiB0aGUgdXNlciBzb21laG93IG1hbmFnZXMgdG8gY2hhbmdlIHRoZVxuICAgICAgICAvLyBhdHRycyBpbiB0aGUgZG9tLCB0aGF0IHdvbid0IGJlIHBpY2tlZCB1cC4gTm90IGVudGlyZWx5IHN1cmVcbiAgICAgICAgLy8gd2hldGhlciB0aGlzIGlzIGEgcHJvYmxlbVxuICAgICAgICBsZXQgcnVsZSA9IHsgbm9kZTogdGhpcy5ub2RlLnR5cGUubmFtZSwgYXR0cnM6IHRoaXMubm9kZS5hdHRycyB9O1xuICAgICAgICBpZiAodGhpcy5ub2RlLnR5cGUud2hpdGVzcGFjZSA9PSBcInByZVwiKVxuICAgICAgICAgICAgcnVsZS5wcmVzZXJ2ZVdoaXRlc3BhY2UgPSBcImZ1bGxcIjtcbiAgICAgICAgaWYgKCF0aGlzLmNvbnRlbnRET00pIHtcbiAgICAgICAgICAgIHJ1bGUuZ2V0Q29udGVudCA9ICgpID0+IHRoaXMubm9kZS5jb250ZW50O1xuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYgKCF0aGlzLmNvbnRlbnRMb3N0KSB7XG4gICAgICAgICAgICBydWxlLmNvbnRlbnRFbGVtZW50ID0gdGhpcy5jb250ZW50RE9NO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgLy8gQ2hyb21lIGxpa2VzIHRvIHJhbmRvbWx5IHJlY3JlYXRlIHBhcmVudCBub2RlcyB3aGVuXG4gICAgICAgICAgICAvLyBiYWNrc3BhY2luZyB0aGluZ3MuIFdoZW4gdGhhdCBoYXBwZW5zLCB0aGlzIHRyaWVzIHRvIGZpbmQgdGhlXG4gICAgICAgICAgICAvLyBuZXcgcGFyZW50LlxuICAgICAgICAgICAgZm9yIChsZXQgaSA9IHRoaXMuY2hpbGRyZW4ubGVuZ3RoIC0gMTsgaSA+PSAwOyBpLS0pIHtcbiAgICAgICAgICAgICAgICBsZXQgY2hpbGQgPSB0aGlzLmNoaWxkcmVuW2ldO1xuICAgICAgICAgICAgICAgIGlmICh0aGlzLmRvbS5jb250YWlucyhjaGlsZC5kb20ucGFyZW50Tm9kZSkpIHtcbiAgICAgICAgICAgICAgICAgICAgcnVsZS5jb250ZW50RWxlbWVudCA9IGNoaWxkLmRvbS5wYXJlbnROb2RlO1xuICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoIXJ1bGUuY29udGVudEVsZW1lbnQpXG4gICAgICAgICAgICAgICAgcnVsZS5nZXRDb250ZW50ID0gKCkgPT4gRnJhZ21lbnQuZW1wdHk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHJ1bGU7XG4gICAgfVxuICAgIG1hdGNoZXNOb2RlKG5vZGUsIG91dGVyRGVjbywgaW5uZXJEZWNvKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmRpcnR5ID09IE5PVF9ESVJUWSAmJiBub2RlLmVxKHRoaXMubm9kZSkgJiZcbiAgICAgICAgICAgIHNhbWVPdXRlckRlY28ob3V0ZXJEZWNvLCB0aGlzLm91dGVyRGVjbykgJiYgaW5uZXJEZWNvLmVxKHRoaXMuaW5uZXJEZWNvKTtcbiAgICB9XG4gICAgZ2V0IHNpemUoKSB7IHJldHVybiB0aGlzLm5vZGUubm9kZVNpemU7IH1cbiAgICBnZXQgYm9yZGVyKCkgeyByZXR1cm4gdGhpcy5ub2RlLmlzTGVhZiA/IDAgOiAxOyB9XG4gICAgLy8gU3luY3MgYHRoaXMuY2hpbGRyZW5gIHRvIG1hdGNoIGB0aGlzLm5vZGUuY29udGVudGAgYW5kIHRoZSBsb2NhbFxuICAgIC8vIGRlY29yYXRpb25zLCBwb3NzaWJseSBpbnRyb2R1Y2luZyBuZXN0aW5nIGZvciBtYXJrcy4gVGhlbiwgaW4gYVxuICAgIC8vIHNlcGFyYXRlIHN0ZXAsIHN5bmNzIHRoZSBET00gaW5zaWRlIGB0aGlzLmNvbnRlbnRET01gIHRvXG4gICAgLy8gYHRoaXMuY2hpbGRyZW5gLlxuICAgIHVwZGF0ZUNoaWxkcmVuKHZpZXcsIHBvcykge1xuICAgICAgICBsZXQgaW5saW5lID0gdGhpcy5ub2RlLmlubGluZUNvbnRlbnQsIG9mZiA9IHBvcztcbiAgICAgICAgbGV0IGNvbXBvc2l0aW9uID0gdmlldy5jb21wb3NpbmcgPyB0aGlzLmxvY2FsQ29tcG9zaXRpb25JbmZvKHZpZXcsIHBvcykgOiBudWxsO1xuICAgICAgICBsZXQgbG9jYWxDb21wb3NpdGlvbiA9IGNvbXBvc2l0aW9uICYmIGNvbXBvc2l0aW9uLnBvcyA+IC0xID8gY29tcG9zaXRpb24gOiBudWxsO1xuICAgICAgICBsZXQgY29tcG9zaXRpb25JbkNoaWxkID0gY29tcG9zaXRpb24gJiYgY29tcG9zaXRpb24ucG9zIDwgMDtcbiAgICAgICAgbGV0IHVwZGF0ZXIgPSBuZXcgVmlld1RyZWVVcGRhdGVyKHRoaXMsIGxvY2FsQ29tcG9zaXRpb24gJiYgbG9jYWxDb21wb3NpdGlvbi5ub2RlLCB2aWV3KTtcbiAgICAgICAgaXRlckRlY28odGhpcy5ub2RlLCB0aGlzLmlubmVyRGVjbywgKHdpZGdldCwgaSwgaW5zaWRlTm9kZSkgPT4ge1xuICAgICAgICAgICAgaWYgKHdpZGdldC5zcGVjLm1hcmtzKVxuICAgICAgICAgICAgICAgIHVwZGF0ZXIuc3luY1RvTWFya3Mod2lkZ2V0LnNwZWMubWFya3MsIGlubGluZSwgdmlldywgaSk7XG4gICAgICAgICAgICBlbHNlIGlmICh3aWRnZXQudHlwZS5zaWRlID49IDAgJiYgIWluc2lkZU5vZGUpXG4gICAgICAgICAgICAgICAgdXBkYXRlci5zeW5jVG9NYXJrcyhpID09IHRoaXMubm9kZS5jaGlsZENvdW50ID8gTWFyay5ub25lIDogdGhpcy5ub2RlLmNoaWxkKGkpLm1hcmtzLCBpbmxpbmUsIHZpZXcsIGkpO1xuICAgICAgICAgICAgLy8gSWYgdGhlIG5leHQgbm9kZSBpcyBhIGRlc2MgbWF0Y2hpbmcgdGhpcyB3aWRnZXQsIHJldXNlIGl0LFxuICAgICAgICAgICAgLy8gb3RoZXJ3aXNlIGluc2VydCB0aGUgd2lkZ2V0IGFzIGEgbmV3IHZpZXcgZGVzYy5cbiAgICAgICAgICAgIHVwZGF0ZXIucGxhY2VXaWRnZXQod2lkZ2V0LCB2aWV3LCBvZmYpO1xuICAgICAgICB9LCAoY2hpbGQsIG91dGVyRGVjbywgaW5uZXJEZWNvLCBpKSA9PiB7XG4gICAgICAgICAgICAvLyBNYWtlIHN1cmUgdGhlIHdyYXBwaW5nIG1hcmsgZGVzY3MgbWF0Y2ggdGhlIG5vZGUncyBtYXJrcy5cbiAgICAgICAgICAgIHVwZGF0ZXIuc3luY1RvTWFya3MoY2hpbGQubWFya3MsIGlubGluZSwgdmlldywgaSk7XG4gICAgICAgICAgICAvLyBUcnkgc2V2ZXJhbCBzdHJhdGVnaWVzIGZvciBkcmF3aW5nIHRoaXMgbm9kZVxuICAgICAgICAgICAgbGV0IGNvbXBJbmRleDtcbiAgICAgICAgICAgIGlmICh1cGRhdGVyLmZpbmROb2RlTWF0Y2goY2hpbGQsIG91dGVyRGVjbywgaW5uZXJEZWNvLCBpKSkgO1xuICAgICAgICAgICAgZWxzZSBpZiAoY29tcG9zaXRpb25JbkNoaWxkICYmIHZpZXcuc3RhdGUuc2VsZWN0aW9uLmZyb20gPiBvZmYgJiZcbiAgICAgICAgICAgICAgICB2aWV3LnN0YXRlLnNlbGVjdGlvbi50byA8IG9mZiArIGNoaWxkLm5vZGVTaXplICYmXG4gICAgICAgICAgICAgICAgKGNvbXBJbmRleCA9IHVwZGF0ZXIuZmluZEluZGV4V2l0aENoaWxkKGNvbXBvc2l0aW9uLm5vZGUpKSA+IC0xICYmXG4gICAgICAgICAgICAgICAgdXBkYXRlci51cGRhdGVOb2RlQXQoY2hpbGQsIG91dGVyRGVjbywgaW5uZXJEZWNvLCBjb21wSW5kZXgsIHZpZXcpKSA7XG4gICAgICAgICAgICBlbHNlIGlmICh1cGRhdGVyLnVwZGF0ZU5leHROb2RlKGNoaWxkLCBvdXRlckRlY28sIGlubmVyRGVjbywgdmlldywgaSwgb2ZmKSkgO1xuICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgLy8gQWRkIGl0IGFzIGEgbmV3IHZpZXdcbiAgICAgICAgICAgICAgICB1cGRhdGVyLmFkZE5vZGUoY2hpbGQsIG91dGVyRGVjbywgaW5uZXJEZWNvLCB2aWV3LCBvZmYpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgb2ZmICs9IGNoaWxkLm5vZGVTaXplO1xuICAgICAgICB9KTtcbiAgICAgICAgLy8gRHJvcCBhbGwgcmVtYWluaW5nIGRlc2NzIGFmdGVyIHRoZSBjdXJyZW50IHBvc2l0aW9uLlxuICAgICAgICB1cGRhdGVyLnN5bmNUb01hcmtzKFtdLCBpbmxpbmUsIHZpZXcsIDApO1xuICAgICAgICBpZiAodGhpcy5ub2RlLmlzVGV4dGJsb2NrKVxuICAgICAgICAgICAgdXBkYXRlci5hZGRUZXh0YmxvY2tIYWNrcygpO1xuICAgICAgICB1cGRhdGVyLmRlc3Ryb3lSZXN0KCk7XG4gICAgICAgIC8vIFN5bmMgdGhlIERPTSBpZiBhbnl0aGluZyBjaGFuZ2VkXG4gICAgICAgIGlmICh1cGRhdGVyLmNoYW5nZWQgfHwgdGhpcy5kaXJ0eSA9PSBDT05URU5UX0RJUlRZKSB7XG4gICAgICAgICAgICAvLyBNYXkgaGF2ZSB0byBwcm90ZWN0IGZvY3VzZWQgRE9NIGZyb20gYmVpbmcgY2hhbmdlZCBpZiBhIGNvbXBvc2l0aW9uIGlzIGFjdGl2ZVxuICAgICAgICAgICAgaWYgKGxvY2FsQ29tcG9zaXRpb24pXG4gICAgICAgICAgICAgICAgdGhpcy5wcm90ZWN0TG9jYWxDb21wb3NpdGlvbih2aWV3LCBsb2NhbENvbXBvc2l0aW9uKTtcbiAgICAgICAgICAgIHJlbmRlckRlc2NzKHRoaXMuY29udGVudERPTSwgdGhpcy5jaGlsZHJlbiwgdmlldyk7XG4gICAgICAgICAgICBpZiAoaW9zKVxuICAgICAgICAgICAgICAgIGlvc0hhY2tzKHRoaXMuZG9tKTtcbiAgICAgICAgfVxuICAgIH1cbiAgICBsb2NhbENvbXBvc2l0aW9uSW5mbyh2aWV3LCBwb3MpIHtcbiAgICAgICAgLy8gT25seSBkbyBzb21ldGhpbmcgaWYgYm90aCB0aGUgc2VsZWN0aW9uIGFuZCBhIGZvY3VzZWQgdGV4dCBub2RlXG4gICAgICAgIC8vIGFyZSBpbnNpZGUgb2YgdGhpcyBub2RlXG4gICAgICAgIGxldCB7IGZyb20sIHRvIH0gPSB2aWV3LnN0YXRlLnNlbGVjdGlvbjtcbiAgICAgICAgaWYgKCEodmlldy5zdGF0ZS5zZWxlY3Rpb24gaW5zdGFuY2VvZiBUZXh0U2VsZWN0aW9uKSB8fCBmcm9tIDwgcG9zIHx8IHRvID4gcG9zICsgdGhpcy5ub2RlLmNvbnRlbnQuc2l6ZSlcbiAgICAgICAgICAgIHJldHVybiBudWxsO1xuICAgICAgICBsZXQgdGV4dE5vZGUgPSB2aWV3LmlucHV0LmNvbXBvc2l0aW9uTm9kZTtcbiAgICAgICAgaWYgKCF0ZXh0Tm9kZSB8fCAhdGhpcy5kb20uY29udGFpbnModGV4dE5vZGUucGFyZW50Tm9kZSkpXG4gICAgICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgICAgaWYgKHRoaXMubm9kZS5pbmxpbmVDb250ZW50KSB7XG4gICAgICAgICAgICAvLyBGaW5kIHRoZSB0ZXh0IGluIHRoZSBmb2N1c2VkIG5vZGUgaW4gdGhlIG5vZGUsIHN0b3AgaWYgaXQncyBub3RcbiAgICAgICAgICAgIC8vIHRoZXJlIChtYXkgaGF2ZSBiZWVuIG1vZGlmaWVkIHRocm91Z2ggb3RoZXIgbWVhbnMsIGluIHdoaWNoXG4gICAgICAgICAgICAvLyBjYXNlIGl0IHNob3VsZCBvdmVyd3JpdHRlbilcbiAgICAgICAgICAgIGxldCB0ZXh0ID0gdGV4dE5vZGUubm9kZVZhbHVlO1xuICAgICAgICAgICAgbGV0IHRleHRQb3MgPSBmaW5kVGV4dEluRnJhZ21lbnQodGhpcy5ub2RlLmNvbnRlbnQsIHRleHQsIGZyb20gLSBwb3MsIHRvIC0gcG9zKTtcbiAgICAgICAgICAgIHJldHVybiB0ZXh0UG9zIDwgMCA/IG51bGwgOiB7IG5vZGU6IHRleHROb2RlLCBwb3M6IHRleHRQb3MsIHRleHQgfTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIHJldHVybiB7IG5vZGU6IHRleHROb2RlLCBwb3M6IC0xLCB0ZXh0OiBcIlwiIH07XG4gICAgICAgIH1cbiAgICB9XG4gICAgcHJvdGVjdExvY2FsQ29tcG9zaXRpb24odmlldywgeyBub2RlLCBwb3MsIHRleHQgfSkge1xuICAgICAgICAvLyBUaGUgbm9kZSBpcyBhbHJlYWR5IHBhcnQgb2YgYSBsb2NhbCB2aWV3IGRlc2MsIGxlYXZlIGl0IHRoZXJlXG4gICAgICAgIGlmICh0aGlzLmdldERlc2Mobm9kZSkpXG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIC8vIENyZWF0ZSBhIGNvbXBvc2l0aW9uIHZpZXcgZm9yIHRoZSBvcnBoYW5lZCBub2Rlc1xuICAgICAgICBsZXQgdG9wTm9kZSA9IG5vZGU7XG4gICAgICAgIGZvciAoOzsgdG9wTm9kZSA9IHRvcE5vZGUucGFyZW50Tm9kZSkge1xuICAgICAgICAgICAgaWYgKHRvcE5vZGUucGFyZW50Tm9kZSA9PSB0aGlzLmNvbnRlbnRET00pXG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICB3aGlsZSAodG9wTm9kZS5wcmV2aW91c1NpYmxpbmcpXG4gICAgICAgICAgICAgICAgdG9wTm9kZS5wYXJlbnROb2RlLnJlbW92ZUNoaWxkKHRvcE5vZGUucHJldmlvdXNTaWJsaW5nKTtcbiAgICAgICAgICAgIHdoaWxlICh0b3BOb2RlLm5leHRTaWJsaW5nKVxuICAgICAgICAgICAgICAgIHRvcE5vZGUucGFyZW50Tm9kZS5yZW1vdmVDaGlsZCh0b3BOb2RlLm5leHRTaWJsaW5nKTtcbiAgICAgICAgICAgIGlmICh0b3BOb2RlLnBtVmlld0Rlc2MpXG4gICAgICAgICAgICAgICAgdG9wTm9kZS5wbVZpZXdEZXNjID0gdW5kZWZpbmVkO1xuICAgICAgICB9XG4gICAgICAgIGxldCBkZXNjID0gbmV3IENvbXBvc2l0aW9uVmlld0Rlc2ModGhpcywgdG9wTm9kZSwgbm9kZSwgdGV4dCk7XG4gICAgICAgIHZpZXcuaW5wdXQuY29tcG9zaXRpb25Ob2Rlcy5wdXNoKGRlc2MpO1xuICAgICAgICAvLyBQYXRjaCB1cCB0aGlzLmNoaWxkcmVuIHRvIGNvbnRhaW4gdGhlIGNvbXBvc2l0aW9uIHZpZXdcbiAgICAgICAgdGhpcy5jaGlsZHJlbiA9IHJlcGxhY2VOb2Rlcyh0aGlzLmNoaWxkcmVuLCBwb3MsIHBvcyArIHRleHQubGVuZ3RoLCB2aWV3LCBkZXNjKTtcbiAgICB9XG4gICAgLy8gSWYgdGhpcyBkZXNjIG11c3QgYmUgdXBkYXRlZCB0byBtYXRjaCB0aGUgZ2l2ZW4gbm9kZSBkZWNvcmF0aW9uLFxuICAgIC8vIGRvIHNvIGFuZCByZXR1cm4gdHJ1ZS5cbiAgICB1cGRhdGUobm9kZSwgb3V0ZXJEZWNvLCBpbm5lckRlY28sIHZpZXcpIHtcbiAgICAgICAgaWYgKHRoaXMuZGlydHkgPT0gTk9ERV9ESVJUWSB8fFxuICAgICAgICAgICAgIW5vZGUuc2FtZU1hcmt1cCh0aGlzLm5vZGUpKVxuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB0aGlzLnVwZGF0ZUlubmVyKG5vZGUsIG91dGVyRGVjbywgaW5uZXJEZWNvLCB2aWV3KTtcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuICAgIHVwZGF0ZUlubmVyKG5vZGUsIG91dGVyRGVjbywgaW5uZXJEZWNvLCB2aWV3KSB7XG4gICAgICAgIHRoaXMudXBkYXRlT3V0ZXJEZWNvKG91dGVyRGVjbyk7XG4gICAgICAgIHRoaXMubm9kZSA9IG5vZGU7XG4gICAgICAgIHRoaXMuaW5uZXJEZWNvID0gaW5uZXJEZWNvO1xuICAgICAgICBpZiAodGhpcy5jb250ZW50RE9NKVxuICAgICAgICAgICAgdGhpcy51cGRhdGVDaGlsZHJlbih2aWV3LCB0aGlzLnBvc0F0U3RhcnQpO1xuICAgICAgICB0aGlzLmRpcnR5ID0gTk9UX0RJUlRZO1xuICAgIH1cbiAgICB1cGRhdGVPdXRlckRlY28ob3V0ZXJEZWNvKSB7XG4gICAgICAgIGlmIChzYW1lT3V0ZXJEZWNvKG91dGVyRGVjbywgdGhpcy5vdXRlckRlY28pKVxuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICBsZXQgbmVlZHNXcmFwID0gdGhpcy5ub2RlRE9NLm5vZGVUeXBlICE9IDE7XG4gICAgICAgIGxldCBvbGRET00gPSB0aGlzLmRvbTtcbiAgICAgICAgdGhpcy5kb20gPSBwYXRjaE91dGVyRGVjbyh0aGlzLmRvbSwgdGhpcy5ub2RlRE9NLCBjb21wdXRlT3V0ZXJEZWNvKHRoaXMub3V0ZXJEZWNvLCB0aGlzLm5vZGUsIG5lZWRzV3JhcCksIGNvbXB1dGVPdXRlckRlY28ob3V0ZXJEZWNvLCB0aGlzLm5vZGUsIG5lZWRzV3JhcCkpO1xuICAgICAgICBpZiAodGhpcy5kb20gIT0gb2xkRE9NKSB7XG4gICAgICAgICAgICBvbGRET00ucG1WaWV3RGVzYyA9IHVuZGVmaW5lZDtcbiAgICAgICAgICAgIHRoaXMuZG9tLnBtVmlld0Rlc2MgPSB0aGlzO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMub3V0ZXJEZWNvID0gb3V0ZXJEZWNvO1xuICAgIH1cbiAgICAvLyBNYXJrIHRoaXMgbm9kZSBhcyBiZWluZyB0aGUgc2VsZWN0ZWQgbm9kZS5cbiAgICBzZWxlY3ROb2RlKCkge1xuICAgICAgICBpZiAodGhpcy5ub2RlRE9NLm5vZGVUeXBlID09IDEpIHtcbiAgICAgICAgICAgIHRoaXMubm9kZURPTS5jbGFzc0xpc3QuYWRkKFwiUHJvc2VNaXJyb3Itc2VsZWN0ZWRub2RlXCIpO1xuICAgICAgICAgICAgaWYgKHRoaXMuY29udGVudERPTSB8fCAhdGhpcy5ub2RlLnR5cGUuc3BlYy5kcmFnZ2FibGUpXG4gICAgICAgICAgICAgICAgdGhpcy5ub2RlRE9NLmRyYWdnYWJsZSA9IHRydWU7XG4gICAgICAgIH1cbiAgICB9XG4gICAgLy8gUmVtb3ZlIHNlbGVjdGVkIG5vZGUgbWFya2luZyBmcm9tIHRoaXMgbm9kZS5cbiAgICBkZXNlbGVjdE5vZGUoKSB7XG4gICAgICAgIGlmICh0aGlzLm5vZGVET00ubm9kZVR5cGUgPT0gMSkge1xuICAgICAgICAgICAgdGhpcy5ub2RlRE9NLmNsYXNzTGlzdC5yZW1vdmUoXCJQcm9zZU1pcnJvci1zZWxlY3RlZG5vZGVcIik7XG4gICAgICAgICAgICBpZiAodGhpcy5jb250ZW50RE9NIHx8ICF0aGlzLm5vZGUudHlwZS5zcGVjLmRyYWdnYWJsZSlcbiAgICAgICAgICAgICAgICB0aGlzLm5vZGVET00ucmVtb3ZlQXR0cmlidXRlKFwiZHJhZ2dhYmxlXCIpO1xuICAgICAgICB9XG4gICAgfVxuICAgIGdldCBkb21BdG9tKCkgeyByZXR1cm4gdGhpcy5ub2RlLmlzQXRvbTsgfVxufVxuLy8gQ3JlYXRlIGEgdmlldyBkZXNjIGZvciB0aGUgdG9wLWxldmVsIGRvY3VtZW50IG5vZGUsIHRvIGJlIGV4cG9ydGVkXG4vLyBhbmQgdXNlZCBieSB0aGUgdmlldyBjbGFzcy5cbmZ1bmN0aW9uIGRvY1ZpZXdEZXNjKGRvYywgb3V0ZXJEZWNvLCBpbm5lckRlY28sIGRvbSwgdmlldykge1xuICAgIGFwcGx5T3V0ZXJEZWNvKGRvbSwgb3V0ZXJEZWNvLCBkb2MpO1xuICAgIGxldCBkb2NWaWV3ID0gbmV3IE5vZGVWaWV3RGVzYyh1bmRlZmluZWQsIGRvYywgb3V0ZXJEZWNvLCBpbm5lckRlY28sIGRvbSwgZG9tLCBkb20sIHZpZXcsIDApO1xuICAgIGlmIChkb2NWaWV3LmNvbnRlbnRET00pXG4gICAgICAgIGRvY1ZpZXcudXBkYXRlQ2hpbGRyZW4odmlldywgMCk7XG4gICAgcmV0dXJuIGRvY1ZpZXc7XG59XG5jbGFzcyBUZXh0Vmlld0Rlc2MgZXh0ZW5kcyBOb2RlVmlld0Rlc2Mge1xuICAgIGNvbnN0cnVjdG9yKHBhcmVudCwgbm9kZSwgb3V0ZXJEZWNvLCBpbm5lckRlY28sIGRvbSwgbm9kZURPTSwgdmlldykge1xuICAgICAgICBzdXBlcihwYXJlbnQsIG5vZGUsIG91dGVyRGVjbywgaW5uZXJEZWNvLCBkb20sIG51bGwsIG5vZGVET00sIHZpZXcsIDApO1xuICAgIH1cbiAgICBwYXJzZVJ1bGUoKSB7XG4gICAgICAgIGxldCBza2lwID0gdGhpcy5ub2RlRE9NLnBhcmVudE5vZGU7XG4gICAgICAgIHdoaWxlIChza2lwICYmIHNraXAgIT0gdGhpcy5kb20gJiYgIXNraXAucG1Jc0RlY28pXG4gICAgICAgICAgICBza2lwID0gc2tpcC5wYXJlbnROb2RlO1xuICAgICAgICByZXR1cm4geyBza2lwOiAoc2tpcCB8fCB0cnVlKSB9O1xuICAgIH1cbiAgICB1cGRhdGUobm9kZSwgb3V0ZXJEZWNvLCBpbm5lckRlY28sIHZpZXcpIHtcbiAgICAgICAgaWYgKHRoaXMuZGlydHkgPT0gTk9ERV9ESVJUWSB8fCAodGhpcy5kaXJ0eSAhPSBOT1RfRElSVFkgJiYgIXRoaXMuaW5QYXJlbnQoKSkgfHxcbiAgICAgICAgICAgICFub2RlLnNhbWVNYXJrdXAodGhpcy5ub2RlKSlcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgdGhpcy51cGRhdGVPdXRlckRlY28ob3V0ZXJEZWNvKTtcbiAgICAgICAgaWYgKCh0aGlzLmRpcnR5ICE9IE5PVF9ESVJUWSB8fCBub2RlLnRleHQgIT0gdGhpcy5ub2RlLnRleHQpICYmIG5vZGUudGV4dCAhPSB0aGlzLm5vZGVET00ubm9kZVZhbHVlKSB7XG4gICAgICAgICAgICB0aGlzLm5vZGVET00ubm9kZVZhbHVlID0gbm9kZS50ZXh0O1xuICAgICAgICAgICAgaWYgKHZpZXcudHJhY2tXcml0ZXMgPT0gdGhpcy5ub2RlRE9NKVxuICAgICAgICAgICAgICAgIHZpZXcudHJhY2tXcml0ZXMgPSBudWxsO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMubm9kZSA9IG5vZGU7XG4gICAgICAgIHRoaXMuZGlydHkgPSBOT1RfRElSVFk7XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cbiAgICBpblBhcmVudCgpIHtcbiAgICAgICAgbGV0IHBhcmVudERPTSA9IHRoaXMucGFyZW50LmNvbnRlbnRET007XG4gICAgICAgIGZvciAobGV0IG4gPSB0aGlzLm5vZGVET007IG47IG4gPSBuLnBhcmVudE5vZGUpXG4gICAgICAgICAgICBpZiAobiA9PSBwYXJlbnRET00pXG4gICAgICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgZG9tRnJvbVBvcyhwb3MpIHtcbiAgICAgICAgcmV0dXJuIHsgbm9kZTogdGhpcy5ub2RlRE9NLCBvZmZzZXQ6IHBvcyB9O1xuICAgIH1cbiAgICBsb2NhbFBvc0Zyb21ET00oZG9tLCBvZmZzZXQsIGJpYXMpIHtcbiAgICAgICAgaWYgKGRvbSA9PSB0aGlzLm5vZGVET00pXG4gICAgICAgICAgICByZXR1cm4gdGhpcy5wb3NBdFN0YXJ0ICsgTWF0aC5taW4ob2Zmc2V0LCB0aGlzLm5vZGUudGV4dC5sZW5ndGgpO1xuICAgICAgICByZXR1cm4gc3VwZXIubG9jYWxQb3NGcm9tRE9NKGRvbSwgb2Zmc2V0LCBiaWFzKTtcbiAgICB9XG4gICAgaWdub3JlTXV0YXRpb24obXV0YXRpb24pIHtcbiAgICAgICAgcmV0dXJuIG11dGF0aW9uLnR5cGUgIT0gXCJjaGFyYWN0ZXJEYXRhXCIgJiYgbXV0YXRpb24udHlwZSAhPSBcInNlbGVjdGlvblwiO1xuICAgIH1cbiAgICBzbGljZShmcm9tLCB0bywgdmlldykge1xuICAgICAgICBsZXQgbm9kZSA9IHRoaXMubm9kZS5jdXQoZnJvbSwgdG8pLCBkb20gPSBkb2N1bWVudC5jcmVhdGVUZXh0Tm9kZShub2RlLnRleHQpO1xuICAgICAgICByZXR1cm4gbmV3IFRleHRWaWV3RGVzYyh0aGlzLnBhcmVudCwgbm9kZSwgdGhpcy5vdXRlckRlY28sIHRoaXMuaW5uZXJEZWNvLCBkb20sIGRvbSwgdmlldyk7XG4gICAgfVxuICAgIG1hcmtEaXJ0eShmcm9tLCB0bykge1xuICAgICAgICBzdXBlci5tYXJrRGlydHkoZnJvbSwgdG8pO1xuICAgICAgICBpZiAodGhpcy5kb20gIT0gdGhpcy5ub2RlRE9NICYmIChmcm9tID09IDAgfHwgdG8gPT0gdGhpcy5ub2RlRE9NLm5vZGVWYWx1ZS5sZW5ndGgpKVxuICAgICAgICAgICAgdGhpcy5kaXJ0eSA9IE5PREVfRElSVFk7XG4gICAgfVxuICAgIGdldCBkb21BdG9tKCkgeyByZXR1cm4gZmFsc2U7IH1cbiAgICBpc1RleHQodGV4dCkgeyByZXR1cm4gdGhpcy5ub2RlLnRleHQgPT0gdGV4dDsgfVxufVxuLy8gQSBkdW1teSBkZXNjIHVzZWQgdG8gdGFnIHRyYWlsaW5nIEJSIG9yIElNRyBub2RlcyBjcmVhdGVkIHRvIHdvcmtcbi8vIGFyb3VuZCBjb250ZW50RWRpdGFibGUgdGVycmlibGVuZXNzLlxuY2xhc3MgVHJhaWxpbmdIYWNrVmlld0Rlc2MgZXh0ZW5kcyBWaWV3RGVzYyB7XG4gICAgcGFyc2VSdWxlKCkgeyByZXR1cm4geyBpZ25vcmU6IHRydWUgfTsgfVxuICAgIG1hdGNoZXNIYWNrKG5vZGVOYW1lKSB7IHJldHVybiB0aGlzLmRpcnR5ID09IE5PVF9ESVJUWSAmJiB0aGlzLmRvbS5ub2RlTmFtZSA9PSBub2RlTmFtZTsgfVxuICAgIGdldCBkb21BdG9tKCkgeyByZXR1cm4gdHJ1ZTsgfVxuICAgIGdldCBpZ25vcmVGb3JDb29yZHMoKSB7IHJldHVybiB0aGlzLmRvbS5ub2RlTmFtZSA9PSBcIklNR1wiOyB9XG59XG4vLyBBIHNlcGFyYXRlIHN1YmNsYXNzIGlzIHVzZWQgZm9yIGN1c3RvbWl6ZWQgbm9kZSB2aWV3cywgc28gdGhhdCB0aGVcbi8vIGV4dHJhIGNoZWNrcyBvbmx5IGhhdmUgdG8gYmUgbWFkZSBmb3Igbm9kZXMgdGhhdCBhcmUgYWN0dWFsbHlcbi8vIGN1c3RvbWl6ZWQuXG5jbGFzcyBDdXN0b21Ob2RlVmlld0Rlc2MgZXh0ZW5kcyBOb2RlVmlld0Rlc2Mge1xuICAgIGNvbnN0cnVjdG9yKHBhcmVudCwgbm9kZSwgb3V0ZXJEZWNvLCBpbm5lckRlY28sIGRvbSwgY29udGVudERPTSwgbm9kZURPTSwgc3BlYywgdmlldywgcG9zKSB7XG4gICAgICAgIHN1cGVyKHBhcmVudCwgbm9kZSwgb3V0ZXJEZWNvLCBpbm5lckRlY28sIGRvbSwgY29udGVudERPTSwgbm9kZURPTSwgdmlldywgcG9zKTtcbiAgICAgICAgdGhpcy5zcGVjID0gc3BlYztcbiAgICB9XG4gICAgLy8gQSBjdXN0b20gYHVwZGF0ZWAgbWV0aG9kIGdldHMgdG8gZGVjaWRlIHdoZXRoZXIgdGhlIHVwZGF0ZSBnb2VzXG4gICAgLy8gdGhyb3VnaC4gSWYgaXQgZG9lcywgYW5kIHRoZXJlJ3MgYSBgY29udGVudERPTWAgbm9kZSwgb3VyIGxvZ2ljXG4gICAgLy8gdXBkYXRlcyB0aGUgY2hpbGRyZW4uXG4gICAgdXBkYXRlKG5vZGUsIG91dGVyRGVjbywgaW5uZXJEZWNvLCB2aWV3KSB7XG4gICAgICAgIGlmICh0aGlzLmRpcnR5ID09IE5PREVfRElSVFkpXG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIGlmICh0aGlzLnNwZWMudXBkYXRlICYmICh0aGlzLm5vZGUudHlwZSA9PSBub2RlLnR5cGUgfHwgdGhpcy5zcGVjLm11bHRpVHlwZSkpIHtcbiAgICAgICAgICAgIGxldCByZXN1bHQgPSB0aGlzLnNwZWMudXBkYXRlKG5vZGUsIG91dGVyRGVjbywgaW5uZXJEZWNvKTtcbiAgICAgICAgICAgIGlmIChyZXN1bHQpXG4gICAgICAgICAgICAgICAgdGhpcy51cGRhdGVJbm5lcihub2RlLCBvdXRlckRlY28sIGlubmVyRGVjbywgdmlldyk7XG4gICAgICAgICAgICByZXR1cm4gcmVzdWx0O1xuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYgKCF0aGlzLmNvbnRlbnRET00gJiYgIW5vZGUuaXNMZWFmKSB7XG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICByZXR1cm4gc3VwZXIudXBkYXRlKG5vZGUsIG91dGVyRGVjbywgaW5uZXJEZWNvLCB2aWV3KTtcbiAgICAgICAgfVxuICAgIH1cbiAgICBzZWxlY3ROb2RlKCkge1xuICAgICAgICB0aGlzLnNwZWMuc2VsZWN0Tm9kZSA/IHRoaXMuc3BlYy5zZWxlY3ROb2RlKCkgOiBzdXBlci5zZWxlY3ROb2RlKCk7XG4gICAgfVxuICAgIGRlc2VsZWN0Tm9kZSgpIHtcbiAgICAgICAgdGhpcy5zcGVjLmRlc2VsZWN0Tm9kZSA/IHRoaXMuc3BlYy5kZXNlbGVjdE5vZGUoKSA6IHN1cGVyLmRlc2VsZWN0Tm9kZSgpO1xuICAgIH1cbiAgICBzZXRTZWxlY3Rpb24oYW5jaG9yLCBoZWFkLCB2aWV3LCBmb3JjZSkge1xuICAgICAgICB0aGlzLnNwZWMuc2V0U2VsZWN0aW9uID8gdGhpcy5zcGVjLnNldFNlbGVjdGlvbihhbmNob3IsIGhlYWQsIHZpZXcucm9vdClcbiAgICAgICAgICAgIDogc3VwZXIuc2V0U2VsZWN0aW9uKGFuY2hvciwgaGVhZCwgdmlldywgZm9yY2UpO1xuICAgIH1cbiAgICBkZXN0cm95KCkge1xuICAgICAgICBpZiAodGhpcy5zcGVjLmRlc3Ryb3kpXG4gICAgICAgICAgICB0aGlzLnNwZWMuZGVzdHJveSgpO1xuICAgICAgICBzdXBlci5kZXN0cm95KCk7XG4gICAgfVxuICAgIHN0b3BFdmVudChldmVudCkge1xuICAgICAgICByZXR1cm4gdGhpcy5zcGVjLnN0b3BFdmVudCA/IHRoaXMuc3BlYy5zdG9wRXZlbnQoZXZlbnQpIDogZmFsc2U7XG4gICAgfVxuICAgIGlnbm9yZU11dGF0aW9uKG11dGF0aW9uKSB7XG4gICAgICAgIHJldHVybiB0aGlzLnNwZWMuaWdub3JlTXV0YXRpb24gPyB0aGlzLnNwZWMuaWdub3JlTXV0YXRpb24obXV0YXRpb24pIDogc3VwZXIuaWdub3JlTXV0YXRpb24obXV0YXRpb24pO1xuICAgIH1cbn1cbi8vIFN5bmMgdGhlIGNvbnRlbnQgb2YgdGhlIGdpdmVuIERPTSBub2RlIHdpdGggdGhlIG5vZGVzIGFzc29jaWF0ZWRcbi8vIHdpdGggdGhlIGdpdmVuIGFycmF5IG9mIHZpZXcgZGVzY3MsIHJlY3Vyc2luZyBpbnRvIG1hcmsgZGVzY3Ncbi8vIGJlY2F1c2UgdGhpcyBzaG91bGQgc3luYyB0aGUgc3VidHJlZSBmb3IgYSB3aG9sZSBub2RlIGF0IGEgdGltZS5cbmZ1bmN0aW9uIHJlbmRlckRlc2NzKHBhcmVudERPTSwgZGVzY3MsIHZpZXcpIHtcbiAgICBsZXQgZG9tID0gcGFyZW50RE9NLmZpcnN0Q2hpbGQsIHdyaXR0ZW4gPSBmYWxzZTtcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IGRlc2NzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIGxldCBkZXNjID0gZGVzY3NbaV0sIGNoaWxkRE9NID0gZGVzYy5kb207XG4gICAgICAgIGlmIChjaGlsZERPTS5wYXJlbnROb2RlID09IHBhcmVudERPTSkge1xuICAgICAgICAgICAgd2hpbGUgKGNoaWxkRE9NICE9IGRvbSkge1xuICAgICAgICAgICAgICAgIGRvbSA9IHJtKGRvbSk7XG4gICAgICAgICAgICAgICAgd3JpdHRlbiA9IHRydWU7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBkb20gPSBkb20ubmV4dFNpYmxpbmc7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICB3cml0dGVuID0gdHJ1ZTtcbiAgICAgICAgICAgIHBhcmVudERPTS5pbnNlcnRCZWZvcmUoY2hpbGRET00sIGRvbSk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGRlc2MgaW5zdGFuY2VvZiBNYXJrVmlld0Rlc2MpIHtcbiAgICAgICAgICAgIGxldCBwb3MgPSBkb20gPyBkb20ucHJldmlvdXNTaWJsaW5nIDogcGFyZW50RE9NLmxhc3RDaGlsZDtcbiAgICAgICAgICAgIHJlbmRlckRlc2NzKGRlc2MuY29udGVudERPTSwgZGVzYy5jaGlsZHJlbiwgdmlldyk7XG4gICAgICAgICAgICBkb20gPSBwb3MgPyBwb3MubmV4dFNpYmxpbmcgOiBwYXJlbnRET00uZmlyc3RDaGlsZDtcbiAgICAgICAgfVxuICAgIH1cbiAgICB3aGlsZSAoZG9tKSB7XG4gICAgICAgIGRvbSA9IHJtKGRvbSk7XG4gICAgICAgIHdyaXR0ZW4gPSB0cnVlO1xuICAgIH1cbiAgICBpZiAod3JpdHRlbiAmJiB2aWV3LnRyYWNrV3JpdGVzID09IHBhcmVudERPTSlcbiAgICAgICAgdmlldy50cmFja1dyaXRlcyA9IG51bGw7XG59XG5jb25zdCBPdXRlckRlY29MZXZlbCA9IGZ1bmN0aW9uIChub2RlTmFtZSkge1xuICAgIGlmIChub2RlTmFtZSlcbiAgICAgICAgdGhpcy5ub2RlTmFtZSA9IG5vZGVOYW1lO1xufTtcbk91dGVyRGVjb0xldmVsLnByb3RvdHlwZSA9IE9iamVjdC5jcmVhdGUobnVsbCk7XG5jb25zdCBub0RlY28gPSBbbmV3IE91dGVyRGVjb0xldmVsXTtcbmZ1bmN0aW9uIGNvbXB1dGVPdXRlckRlY28ob3V0ZXJEZWNvLCBub2RlLCBuZWVkc1dyYXApIHtcbiAgICBpZiAob3V0ZXJEZWNvLmxlbmd0aCA9PSAwKVxuICAgICAgICByZXR1cm4gbm9EZWNvO1xuICAgIGxldCB0b3AgPSBuZWVkc1dyYXAgPyBub0RlY29bMF0gOiBuZXcgT3V0ZXJEZWNvTGV2ZWwsIHJlc3VsdCA9IFt0b3BdO1xuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgb3V0ZXJEZWNvLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIGxldCBhdHRycyA9IG91dGVyRGVjb1tpXS50eXBlLmF0dHJzO1xuICAgICAgICBpZiAoIWF0dHJzKVxuICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgIGlmIChhdHRycy5ub2RlTmFtZSlcbiAgICAgICAgICAgIHJlc3VsdC5wdXNoKHRvcCA9IG5ldyBPdXRlckRlY29MZXZlbChhdHRycy5ub2RlTmFtZSkpO1xuICAgICAgICBmb3IgKGxldCBuYW1lIGluIGF0dHJzKSB7XG4gICAgICAgICAgICBsZXQgdmFsID0gYXR0cnNbbmFtZV07XG4gICAgICAgICAgICBpZiAodmFsID09IG51bGwpXG4gICAgICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgICAgICBpZiAobmVlZHNXcmFwICYmIHJlc3VsdC5sZW5ndGggPT0gMSlcbiAgICAgICAgICAgICAgICByZXN1bHQucHVzaCh0b3AgPSBuZXcgT3V0ZXJEZWNvTGV2ZWwobm9kZS5pc0lubGluZSA/IFwic3BhblwiIDogXCJkaXZcIikpO1xuICAgICAgICAgICAgaWYgKG5hbWUgPT0gXCJjbGFzc1wiKVxuICAgICAgICAgICAgICAgIHRvcC5jbGFzcyA9ICh0b3AuY2xhc3MgPyB0b3AuY2xhc3MgKyBcIiBcIiA6IFwiXCIpICsgdmFsO1xuICAgICAgICAgICAgZWxzZSBpZiAobmFtZSA9PSBcInN0eWxlXCIpXG4gICAgICAgICAgICAgICAgdG9wLnN0eWxlID0gKHRvcC5zdHlsZSA/IHRvcC5zdHlsZSArIFwiO1wiIDogXCJcIikgKyB2YWw7XG4gICAgICAgICAgICBlbHNlIGlmIChuYW1lICE9IFwibm9kZU5hbWVcIilcbiAgICAgICAgICAgICAgICB0b3BbbmFtZV0gPSB2YWw7XG4gICAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIHJlc3VsdDtcbn1cbmZ1bmN0aW9uIHBhdGNoT3V0ZXJEZWNvKG91dGVyRE9NLCBub2RlRE9NLCBwcmV2Q29tcHV0ZWQsIGN1ckNvbXB1dGVkKSB7XG4gICAgLy8gU2hvcnRjdXQgZm9yIHRyaXZpYWwgY2FzZVxuICAgIGlmIChwcmV2Q29tcHV0ZWQgPT0gbm9EZWNvICYmIGN1ckNvbXB1dGVkID09IG5vRGVjbylcbiAgICAgICAgcmV0dXJuIG5vZGVET007XG4gICAgbGV0IGN1ckRPTSA9IG5vZGVET007XG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBjdXJDb21wdXRlZC5sZW5ndGg7IGkrKykge1xuICAgICAgICBsZXQgZGVjbyA9IGN1ckNvbXB1dGVkW2ldLCBwcmV2ID0gcHJldkNvbXB1dGVkW2ldO1xuICAgICAgICBpZiAoaSkge1xuICAgICAgICAgICAgbGV0IHBhcmVudDtcbiAgICAgICAgICAgIGlmIChwcmV2ICYmIHByZXYubm9kZU5hbWUgPT0gZGVjby5ub2RlTmFtZSAmJiBjdXJET00gIT0gb3V0ZXJET00gJiZcbiAgICAgICAgICAgICAgICAocGFyZW50ID0gY3VyRE9NLnBhcmVudE5vZGUpICYmIHBhcmVudC5ub2RlTmFtZS50b0xvd2VyQ2FzZSgpID09IGRlY28ubm9kZU5hbWUpIHtcbiAgICAgICAgICAgICAgICBjdXJET00gPSBwYXJlbnQ7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICBwYXJlbnQgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KGRlY28ubm9kZU5hbWUpO1xuICAgICAgICAgICAgICAgIHBhcmVudC5wbUlzRGVjbyA9IHRydWU7XG4gICAgICAgICAgICAgICAgcGFyZW50LmFwcGVuZENoaWxkKGN1ckRPTSk7XG4gICAgICAgICAgICAgICAgcHJldiA9IG5vRGVjb1swXTtcbiAgICAgICAgICAgICAgICBjdXJET00gPSBwYXJlbnQ7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgcGF0Y2hBdHRyaWJ1dGVzKGN1ckRPTSwgcHJldiB8fCBub0RlY29bMF0sIGRlY28pO1xuICAgIH1cbiAgICByZXR1cm4gY3VyRE9NO1xufVxuZnVuY3Rpb24gcGF0Y2hBdHRyaWJ1dGVzKGRvbSwgcHJldiwgY3VyKSB7XG4gICAgZm9yIChsZXQgbmFtZSBpbiBwcmV2KVxuICAgICAgICBpZiAobmFtZSAhPSBcImNsYXNzXCIgJiYgbmFtZSAhPSBcInN0eWxlXCIgJiYgbmFtZSAhPSBcIm5vZGVOYW1lXCIgJiYgIShuYW1lIGluIGN1cikpXG4gICAgICAgICAgICBkb20ucmVtb3ZlQXR0cmlidXRlKG5hbWUpO1xuICAgIGZvciAobGV0IG5hbWUgaW4gY3VyKVxuICAgICAgICBpZiAobmFtZSAhPSBcImNsYXNzXCIgJiYgbmFtZSAhPSBcInN0eWxlXCIgJiYgbmFtZSAhPSBcIm5vZGVOYW1lXCIgJiYgY3VyW25hbWVdICE9IHByZXZbbmFtZV0pXG4gICAgICAgICAgICBkb20uc2V0QXR0cmlidXRlKG5hbWUsIGN1cltuYW1lXSk7XG4gICAgaWYgKHByZXYuY2xhc3MgIT0gY3VyLmNsYXNzKSB7XG4gICAgICAgIGxldCBwcmV2TGlzdCA9IHByZXYuY2xhc3MgPyBwcmV2LmNsYXNzLnNwbGl0KFwiIFwiKS5maWx0ZXIoQm9vbGVhbikgOiBbXTtcbiAgICAgICAgbGV0IGN1ckxpc3QgPSBjdXIuY2xhc3MgPyBjdXIuY2xhc3Muc3BsaXQoXCIgXCIpLmZpbHRlcihCb29sZWFuKSA6IFtdO1xuICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHByZXZMaXN0Lmxlbmd0aDsgaSsrKVxuICAgICAgICAgICAgaWYgKGN1ckxpc3QuaW5kZXhPZihwcmV2TGlzdFtpXSkgPT0gLTEpXG4gICAgICAgICAgICAgICAgZG9tLmNsYXNzTGlzdC5yZW1vdmUocHJldkxpc3RbaV0pO1xuICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IGN1ckxpc3QubGVuZ3RoOyBpKyspXG4gICAgICAgICAgICBpZiAocHJldkxpc3QuaW5kZXhPZihjdXJMaXN0W2ldKSA9PSAtMSlcbiAgICAgICAgICAgICAgICBkb20uY2xhc3NMaXN0LmFkZChjdXJMaXN0W2ldKTtcbiAgICAgICAgaWYgKGRvbS5jbGFzc0xpc3QubGVuZ3RoID09IDApXG4gICAgICAgICAgICBkb20ucmVtb3ZlQXR0cmlidXRlKFwiY2xhc3NcIik7XG4gICAgfVxuICAgIGlmIChwcmV2LnN0eWxlICE9IGN1ci5zdHlsZSkge1xuICAgICAgICBpZiAocHJldi5zdHlsZSkge1xuICAgICAgICAgICAgbGV0IHByb3AgPSAvXFxzKihbXFx3XFwtXFx4YTEtXFx1ZmZmZl0rKVxccyo6KD86XCIoPzpcXFxcLnxbXlwiXSkqXCJ8Jyg/OlxcXFwufFteJ10pKid8XFwoLio/XFwpfFteO10pKi9nLCBtO1xuICAgICAgICAgICAgd2hpbGUgKG0gPSBwcm9wLmV4ZWMocHJldi5zdHlsZSkpXG4gICAgICAgICAgICAgICAgZG9tLnN0eWxlLnJlbW92ZVByb3BlcnR5KG1bMV0pO1xuICAgICAgICB9XG4gICAgICAgIGlmIChjdXIuc3R5bGUpXG4gICAgICAgICAgICBkb20uc3R5bGUuY3NzVGV4dCArPSBjdXIuc3R5bGU7XG4gICAgfVxufVxuZnVuY3Rpb24gYXBwbHlPdXRlckRlY28oZG9tLCBkZWNvLCBub2RlKSB7XG4gICAgcmV0dXJuIHBhdGNoT3V0ZXJEZWNvKGRvbSwgZG9tLCBub0RlY28sIGNvbXB1dGVPdXRlckRlY28oZGVjbywgbm9kZSwgZG9tLm5vZGVUeXBlICE9IDEpKTtcbn1cbmZ1bmN0aW9uIHNhbWVPdXRlckRlY28oYSwgYikge1xuICAgIGlmIChhLmxlbmd0aCAhPSBiLmxlbmd0aClcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgYS5sZW5ndGg7IGkrKylcbiAgICAgICAgaWYgKCFhW2ldLnR5cGUuZXEoYltpXS50eXBlKSlcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICByZXR1cm4gdHJ1ZTtcbn1cbi8vIFJlbW92ZSBhIERPTSBub2RlIGFuZCByZXR1cm4gaXRzIG5leHQgc2libGluZy5cbmZ1bmN0aW9uIHJtKGRvbSkge1xuICAgIGxldCBuZXh0ID0gZG9tLm5leHRTaWJsaW5nO1xuICAgIGRvbS5wYXJlbnROb2RlLnJlbW92ZUNoaWxkKGRvbSk7XG4gICAgcmV0dXJuIG5leHQ7XG59XG4vLyBIZWxwZXIgY2xhc3MgZm9yIGluY3JlbWVudGFsbHkgdXBkYXRpbmcgYSB0cmVlIG9mIG1hcmsgZGVzY3MgYW5kXG4vLyB0aGUgd2lkZ2V0IGFuZCBub2RlIGRlc2NzIGluc2lkZSBvZiB0aGVtLlxuY2xhc3MgVmlld1RyZWVVcGRhdGVyIHtcbiAgICBjb25zdHJ1Y3Rvcih0b3AsIGxvY2ssIHZpZXcpIHtcbiAgICAgICAgdGhpcy5sb2NrID0gbG9jaztcbiAgICAgICAgdGhpcy52aWV3ID0gdmlldztcbiAgICAgICAgLy8gSW5kZXggaW50byBgdGhpcy50b3BgJ3MgY2hpbGQgYXJyYXksIHJlcHJlc2VudHMgdGhlIGN1cnJlbnRcbiAgICAgICAgLy8gdXBkYXRlIHBvc2l0aW9uLlxuICAgICAgICB0aGlzLmluZGV4ID0gMDtcbiAgICAgICAgLy8gV2hlbiBlbnRlcmluZyBhIG1hcmssIHRoZSBjdXJyZW50IHRvcCBhbmQgaW5kZXggYXJlIHB1c2hlZFxuICAgICAgICAvLyBvbnRvIHRoaXMuXG4gICAgICAgIHRoaXMuc3RhY2sgPSBbXTtcbiAgICAgICAgLy8gVHJhY2tzIHdoZXRoZXIgYW55dGhpbmcgd2FzIGNoYW5nZWRcbiAgICAgICAgdGhpcy5jaGFuZ2VkID0gZmFsc2U7XG4gICAgICAgIHRoaXMudG9wID0gdG9wO1xuICAgICAgICB0aGlzLnByZU1hdGNoID0gcHJlTWF0Y2godG9wLm5vZGUuY29udGVudCwgdG9wKTtcbiAgICB9XG4gICAgLy8gRGVzdHJveSBhbmQgcmVtb3ZlIHRoZSBjaGlsZHJlbiBiZXR3ZWVuIHRoZSBnaXZlbiBpbmRpY2VzIGluXG4gICAgLy8gYHRoaXMudG9wYC5cbiAgICBkZXN0cm95QmV0d2VlbihzdGFydCwgZW5kKSB7XG4gICAgICAgIGlmIChzdGFydCA9PSBlbmQpXG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIGZvciAobGV0IGkgPSBzdGFydDsgaSA8IGVuZDsgaSsrKVxuICAgICAgICAgICAgdGhpcy50b3AuY2hpbGRyZW5baV0uZGVzdHJveSgpO1xuICAgICAgICB0aGlzLnRvcC5jaGlsZHJlbi5zcGxpY2Uoc3RhcnQsIGVuZCAtIHN0YXJ0KTtcbiAgICAgICAgdGhpcy5jaGFuZ2VkID0gdHJ1ZTtcbiAgICB9XG4gICAgLy8gRGVzdHJveSBhbGwgcmVtYWluaW5nIGNoaWxkcmVuIGluIGB0aGlzLnRvcGAuXG4gICAgZGVzdHJveVJlc3QoKSB7XG4gICAgICAgIHRoaXMuZGVzdHJveUJldHdlZW4odGhpcy5pbmRleCwgdGhpcy50b3AuY2hpbGRyZW4ubGVuZ3RoKTtcbiAgICB9XG4gICAgLy8gU3luYyB0aGUgY3VycmVudCBzdGFjayBvZiBtYXJrIGRlc2NzIHdpdGggdGhlIGdpdmVuIGFycmF5IG9mXG4gICAgLy8gbWFya3MsIHJldXNpbmcgZXhpc3RpbmcgbWFyayBkZXNjcyB3aGVuIHBvc3NpYmxlLlxuICAgIHN5bmNUb01hcmtzKG1hcmtzLCBpbmxpbmUsIHZpZXcsIHBhcmVudEluZGV4KSB7XG4gICAgICAgIGxldCBrZWVwID0gMCwgZGVwdGggPSB0aGlzLnN0YWNrLmxlbmd0aCA+PiAxO1xuICAgICAgICBsZXQgbWF4S2VlcCA9IE1hdGgubWluKGRlcHRoLCBtYXJrcy5sZW5ndGgpO1xuICAgICAgICB3aGlsZSAoa2VlcCA8IG1heEtlZXAgJiZcbiAgICAgICAgICAgIChrZWVwID09IGRlcHRoIC0gMSA/IHRoaXMudG9wIDogdGhpcy5zdGFja1soa2VlcCArIDEpIDw8IDFdKVxuICAgICAgICAgICAgICAgIC5tYXRjaGVzTWFyayhtYXJrc1trZWVwXSkgJiYgbWFya3Nba2VlcF0udHlwZS5zcGVjLnNwYW5uaW5nICE9PSBmYWxzZSlcbiAgICAgICAgICAgIGtlZXArKztcbiAgICAgICAgd2hpbGUgKGtlZXAgPCBkZXB0aCkge1xuICAgICAgICAgICAgdGhpcy5kZXN0cm95UmVzdCgpO1xuICAgICAgICAgICAgdGhpcy50b3AuZGlydHkgPSBOT1RfRElSVFk7XG4gICAgICAgICAgICB0aGlzLmluZGV4ID0gdGhpcy5zdGFjay5wb3AoKTtcbiAgICAgICAgICAgIHRoaXMudG9wID0gdGhpcy5zdGFjay5wb3AoKTtcbiAgICAgICAgICAgIGRlcHRoLS07XG4gICAgICAgIH1cbiAgICAgICAgd2hpbGUgKGRlcHRoIDwgbWFya3MubGVuZ3RoKSB7XG4gICAgICAgICAgICB0aGlzLnN0YWNrLnB1c2godGhpcy50b3AsIHRoaXMuaW5kZXggKyAxKTtcbiAgICAgICAgICAgIGxldCBmb3VuZCA9IC0xLCBzY2FuVG8gPSB0aGlzLnRvcC5jaGlsZHJlbi5sZW5ndGg7XG4gICAgICAgICAgICBpZiAocGFyZW50SW5kZXggPCB0aGlzLnByZU1hdGNoLmluZGV4KVxuICAgICAgICAgICAgICAgIHNjYW5UbyA9IE1hdGgubWluKHRoaXMuaW5kZXggKyAzLCBzY2FuVG8pO1xuICAgICAgICAgICAgZm9yIChsZXQgaSA9IHRoaXMuaW5kZXg7IGkgPCBzY2FuVG87IGkrKykge1xuICAgICAgICAgICAgICAgIGxldCBuZXh0ID0gdGhpcy50b3AuY2hpbGRyZW5baV07XG4gICAgICAgICAgICAgICAgaWYgKG5leHQubWF0Y2hlc01hcmsobWFya3NbZGVwdGhdKSAmJiAhdGhpcy5pc0xvY2tlZChuZXh0LmRvbSkpIHtcbiAgICAgICAgICAgICAgICAgICAgZm91bmQgPSBpO1xuICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoZm91bmQgPiAtMSkge1xuICAgICAgICAgICAgICAgIGlmIChmb3VuZCA+IHRoaXMuaW5kZXgpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5jaGFuZ2VkID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5kZXN0cm95QmV0d2Vlbih0aGlzLmluZGV4LCBmb3VuZCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHRoaXMudG9wID0gdGhpcy50b3AuY2hpbGRyZW5bdGhpcy5pbmRleF07XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICBsZXQgbWFya0Rlc2MgPSBNYXJrVmlld0Rlc2MuY3JlYXRlKHRoaXMudG9wLCBtYXJrc1tkZXB0aF0sIGlubGluZSwgdmlldyk7XG4gICAgICAgICAgICAgICAgdGhpcy50b3AuY2hpbGRyZW4uc3BsaWNlKHRoaXMuaW5kZXgsIDAsIG1hcmtEZXNjKTtcbiAgICAgICAgICAgICAgICB0aGlzLnRvcCA9IG1hcmtEZXNjO1xuICAgICAgICAgICAgICAgIHRoaXMuY2hhbmdlZCA9IHRydWU7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB0aGlzLmluZGV4ID0gMDtcbiAgICAgICAgICAgIGRlcHRoKys7XG4gICAgICAgIH1cbiAgICB9XG4gICAgLy8gVHJ5IHRvIGZpbmQgYSBub2RlIGRlc2MgbWF0Y2hpbmcgdGhlIGdpdmVuIGRhdGEuIFNraXAgb3ZlciBpdCBhbmRcbiAgICAvLyByZXR1cm4gdHJ1ZSB3aGVuIHN1Y2Nlc3NmdWwuXG4gICAgZmluZE5vZGVNYXRjaChub2RlLCBvdXRlckRlY28sIGlubmVyRGVjbywgaW5kZXgpIHtcbiAgICAgICAgbGV0IGZvdW5kID0gLTEsIHRhcmdldERlc2M7XG4gICAgICAgIGlmIChpbmRleCA+PSB0aGlzLnByZU1hdGNoLmluZGV4ICYmXG4gICAgICAgICAgICAodGFyZ2V0RGVzYyA9IHRoaXMucHJlTWF0Y2gubWF0Y2hlc1tpbmRleCAtIHRoaXMucHJlTWF0Y2guaW5kZXhdKS5wYXJlbnQgPT0gdGhpcy50b3AgJiZcbiAgICAgICAgICAgIHRhcmdldERlc2MubWF0Y2hlc05vZGUobm9kZSwgb3V0ZXJEZWNvLCBpbm5lckRlY28pKSB7XG4gICAgICAgICAgICBmb3VuZCA9IHRoaXMudG9wLmNoaWxkcmVuLmluZGV4T2YodGFyZ2V0RGVzYywgdGhpcy5pbmRleCk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICBmb3IgKGxldCBpID0gdGhpcy5pbmRleCwgZSA9IE1hdGgubWluKHRoaXMudG9wLmNoaWxkcmVuLmxlbmd0aCwgaSArIDUpOyBpIDwgZTsgaSsrKSB7XG4gICAgICAgICAgICAgICAgbGV0IGNoaWxkID0gdGhpcy50b3AuY2hpbGRyZW5baV07XG4gICAgICAgICAgICAgICAgaWYgKGNoaWxkLm1hdGNoZXNOb2RlKG5vZGUsIG91dGVyRGVjbywgaW5uZXJEZWNvKSAmJiAhdGhpcy5wcmVNYXRjaC5tYXRjaGVkLmhhcyhjaGlsZCkpIHtcbiAgICAgICAgICAgICAgICAgICAgZm91bmQgPSBpO1xuICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGZvdW5kIDwgMClcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgdGhpcy5kZXN0cm95QmV0d2Vlbih0aGlzLmluZGV4LCBmb3VuZCk7XG4gICAgICAgIHRoaXMuaW5kZXgrKztcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuICAgIHVwZGF0ZU5vZGVBdChub2RlLCBvdXRlckRlY28sIGlubmVyRGVjbywgaW5kZXgsIHZpZXcpIHtcbiAgICAgICAgbGV0IGNoaWxkID0gdGhpcy50b3AuY2hpbGRyZW5baW5kZXhdO1xuICAgICAgICBpZiAoY2hpbGQuZGlydHkgPT0gTk9ERV9ESVJUWSAmJiBjaGlsZC5kb20gPT0gY2hpbGQuY29udGVudERPTSlcbiAgICAgICAgICAgIGNoaWxkLmRpcnR5ID0gQ09OVEVOVF9ESVJUWTtcbiAgICAgICAgaWYgKCFjaGlsZC51cGRhdGUobm9kZSwgb3V0ZXJEZWNvLCBpbm5lckRlY28sIHZpZXcpKVxuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB0aGlzLmRlc3Ryb3lCZXR3ZWVuKHRoaXMuaW5kZXgsIGluZGV4KTtcbiAgICAgICAgdGhpcy5pbmRleCsrO1xuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG4gICAgZmluZEluZGV4V2l0aENoaWxkKGRvbU5vZGUpIHtcbiAgICAgICAgZm9yICg7Oykge1xuICAgICAgICAgICAgbGV0IHBhcmVudCA9IGRvbU5vZGUucGFyZW50Tm9kZTtcbiAgICAgICAgICAgIGlmICghcGFyZW50KVxuICAgICAgICAgICAgICAgIHJldHVybiAtMTtcbiAgICAgICAgICAgIGlmIChwYXJlbnQgPT0gdGhpcy50b3AuY29udGVudERPTSkge1xuICAgICAgICAgICAgICAgIGxldCBkZXNjID0gZG9tTm9kZS5wbVZpZXdEZXNjO1xuICAgICAgICAgICAgICAgIGlmIChkZXNjKVxuICAgICAgICAgICAgICAgICAgICBmb3IgKGxldCBpID0gdGhpcy5pbmRleDsgaSA8IHRoaXMudG9wLmNoaWxkcmVuLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAodGhpcy50b3AuY2hpbGRyZW5baV0gPT0gZGVzYylcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gaTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHJldHVybiAtMTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGRvbU5vZGUgPSBwYXJlbnQ7XG4gICAgICAgIH1cbiAgICB9XG4gICAgLy8gVHJ5IHRvIHVwZGF0ZSB0aGUgbmV4dCBub2RlLCBpZiBhbnksIHRvIHRoZSBnaXZlbiBkYXRhLiBDaGVja3NcbiAgICAvLyBwcmUtbWF0Y2hlcyB0byBhdm9pZCBvdmVyd3JpdGluZyBub2RlcyB0aGF0IGNvdWxkIHN0aWxsIGJlIHVzZWQuXG4gICAgdXBkYXRlTmV4dE5vZGUobm9kZSwgb3V0ZXJEZWNvLCBpbm5lckRlY28sIHZpZXcsIGluZGV4LCBwb3MpIHtcbiAgICAgICAgZm9yIChsZXQgaSA9IHRoaXMuaW5kZXg7IGkgPCB0aGlzLnRvcC5jaGlsZHJlbi5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgbGV0IG5leHQgPSB0aGlzLnRvcC5jaGlsZHJlbltpXTtcbiAgICAgICAgICAgIGlmIChuZXh0IGluc3RhbmNlb2YgTm9kZVZpZXdEZXNjKSB7XG4gICAgICAgICAgICAgICAgbGV0IHByZU1hdGNoID0gdGhpcy5wcmVNYXRjaC5tYXRjaGVkLmdldChuZXh0KTtcbiAgICAgICAgICAgICAgICBpZiAocHJlTWF0Y2ggIT0gbnVsbCAmJiBwcmVNYXRjaCAhPSBpbmRleClcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgICAgICAgIGxldCBuZXh0RE9NID0gbmV4dC5kb20sIHVwZGF0ZWQ7XG4gICAgICAgICAgICAgICAgLy8gQ2FuJ3QgdXBkYXRlIGlmIG5leHRET00gaXMgb3IgY29udGFpbnMgdGhpcy5sb2NrLCBleGNlcHQgaWZcbiAgICAgICAgICAgICAgICAvLyBpdCdzIGEgdGV4dCBub2RlIHdob3NlIGNvbnRlbnQgYWxyZWFkeSBtYXRjaGVzIHRoZSBuZXcgdGV4dFxuICAgICAgICAgICAgICAgIC8vIGFuZCB3aG9zZSBkZWNvcmF0aW9ucyBtYXRjaCB0aGUgbmV3IG9uZXMuXG4gICAgICAgICAgICAgICAgbGV0IGxvY2tlZCA9IHRoaXMuaXNMb2NrZWQobmV4dERPTSkgJiZcbiAgICAgICAgICAgICAgICAgICAgIShub2RlLmlzVGV4dCAmJiBuZXh0Lm5vZGUgJiYgbmV4dC5ub2RlLmlzVGV4dCAmJiBuZXh0Lm5vZGVET00ubm9kZVZhbHVlID09IG5vZGUudGV4dCAmJlxuICAgICAgICAgICAgICAgICAgICAgICAgbmV4dC5kaXJ0eSAhPSBOT0RFX0RJUlRZICYmIHNhbWVPdXRlckRlY28ob3V0ZXJEZWNvLCBuZXh0Lm91dGVyRGVjbykpO1xuICAgICAgICAgICAgICAgIGlmICghbG9ja2VkICYmIG5leHQudXBkYXRlKG5vZGUsIG91dGVyRGVjbywgaW5uZXJEZWNvLCB2aWV3KSkge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmRlc3Ryb3lCZXR3ZWVuKHRoaXMuaW5kZXgsIGkpO1xuICAgICAgICAgICAgICAgICAgICBpZiAobmV4dC5kb20gIT0gbmV4dERPTSlcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuY2hhbmdlZCA9IHRydWU7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuaW5kZXgrKztcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGVsc2UgaWYgKCFsb2NrZWQgJiYgKHVwZGF0ZWQgPSB0aGlzLnJlY3JlYXRlV3JhcHBlcihuZXh0LCBub2RlLCBvdXRlckRlY28sIGlubmVyRGVjbywgdmlldywgcG9zKSkpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5kZXN0cm95QmV0d2Vlbih0aGlzLmluZGV4LCBpKTtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy50b3AuY2hpbGRyZW5bdGhpcy5pbmRleF0gPSB1cGRhdGVkO1xuICAgICAgICAgICAgICAgICAgICBpZiAodXBkYXRlZC5jb250ZW50RE9NKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB1cGRhdGVkLmRpcnR5ID0gQ09OVEVOVF9ESVJUWTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHVwZGF0ZWQudXBkYXRlQ2hpbGRyZW4odmlldywgcG9zICsgMSk7XG4gICAgICAgICAgICAgICAgICAgICAgICB1cGRhdGVkLmRpcnR5ID0gTk9UX0RJUlRZO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuY2hhbmdlZCA9IHRydWU7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuaW5kZXgrKztcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgLy8gV2hlbiBhIG5vZGUgd2l0aCBjb250ZW50IGlzIHJlcGxhY2VkIGJ5IGEgZGlmZmVyZW50IG5vZGUgd2l0aFxuICAgIC8vIGlkZW50aWNhbCBjb250ZW50LCBtb3ZlIG92ZXIgaXRzIGNoaWxkcmVuLlxuICAgIHJlY3JlYXRlV3JhcHBlcihuZXh0LCBub2RlLCBvdXRlckRlY28sIGlubmVyRGVjbywgdmlldywgcG9zKSB7XG4gICAgICAgIGlmIChuZXh0LmRpcnR5IHx8IG5vZGUuaXNBdG9tIHx8ICFuZXh0LmNoaWxkcmVuLmxlbmd0aCB8fFxuICAgICAgICAgICAgIW5leHQubm9kZS5jb250ZW50LmVxKG5vZGUuY29udGVudCkgfHxcbiAgICAgICAgICAgICFzYW1lT3V0ZXJEZWNvKG91dGVyRGVjbywgbmV4dC5vdXRlckRlY28pIHx8ICFpbm5lckRlY28uZXEobmV4dC5pbm5lckRlY28pKVxuICAgICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgIGxldCB3cmFwcGVyID0gTm9kZVZpZXdEZXNjLmNyZWF0ZSh0aGlzLnRvcCwgbm9kZSwgb3V0ZXJEZWNvLCBpbm5lckRlY28sIHZpZXcsIHBvcyk7XG4gICAgICAgIGlmICh3cmFwcGVyLmNvbnRlbnRET00pIHtcbiAgICAgICAgICAgIHdyYXBwZXIuY2hpbGRyZW4gPSBuZXh0LmNoaWxkcmVuO1xuICAgICAgICAgICAgbmV4dC5jaGlsZHJlbiA9IFtdO1xuICAgICAgICAgICAgZm9yIChsZXQgY2ggb2Ygd3JhcHBlci5jaGlsZHJlbilcbiAgICAgICAgICAgICAgICBjaC5wYXJlbnQgPSB3cmFwcGVyO1xuICAgICAgICB9XG4gICAgICAgIG5leHQuZGVzdHJveSgpO1xuICAgICAgICByZXR1cm4gd3JhcHBlcjtcbiAgICB9XG4gICAgLy8gSW5zZXJ0IHRoZSBub2RlIGFzIGEgbmV3bHkgY3JlYXRlZCBub2RlIGRlc2MuXG4gICAgYWRkTm9kZShub2RlLCBvdXRlckRlY28sIGlubmVyRGVjbywgdmlldywgcG9zKSB7XG4gICAgICAgIGxldCBkZXNjID0gTm9kZVZpZXdEZXNjLmNyZWF0ZSh0aGlzLnRvcCwgbm9kZSwgb3V0ZXJEZWNvLCBpbm5lckRlY28sIHZpZXcsIHBvcyk7XG4gICAgICAgIGlmIChkZXNjLmNvbnRlbnRET00pXG4gICAgICAgICAgICBkZXNjLnVwZGF0ZUNoaWxkcmVuKHZpZXcsIHBvcyArIDEpO1xuICAgICAgICB0aGlzLnRvcC5jaGlsZHJlbi5zcGxpY2UodGhpcy5pbmRleCsrLCAwLCBkZXNjKTtcbiAgICAgICAgdGhpcy5jaGFuZ2VkID0gdHJ1ZTtcbiAgICB9XG4gICAgcGxhY2VXaWRnZXQod2lkZ2V0LCB2aWV3LCBwb3MpIHtcbiAgICAgICAgbGV0IG5leHQgPSB0aGlzLmluZGV4IDwgdGhpcy50b3AuY2hpbGRyZW4ubGVuZ3RoID8gdGhpcy50b3AuY2hpbGRyZW5bdGhpcy5pbmRleF0gOiBudWxsO1xuICAgICAgICBpZiAobmV4dCAmJiBuZXh0Lm1hdGNoZXNXaWRnZXQod2lkZ2V0KSAmJlxuICAgICAgICAgICAgKHdpZGdldCA9PSBuZXh0LndpZGdldCB8fCAhbmV4dC53aWRnZXQudHlwZS50b0RPTS5wYXJlbnROb2RlKSkge1xuICAgICAgICAgICAgdGhpcy5pbmRleCsrO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgbGV0IGRlc2MgPSBuZXcgV2lkZ2V0Vmlld0Rlc2ModGhpcy50b3AsIHdpZGdldCwgdmlldywgcG9zKTtcbiAgICAgICAgICAgIHRoaXMudG9wLmNoaWxkcmVuLnNwbGljZSh0aGlzLmluZGV4KyssIDAsIGRlc2MpO1xuICAgICAgICAgICAgdGhpcy5jaGFuZ2VkID0gdHJ1ZTtcbiAgICAgICAgfVxuICAgIH1cbiAgICAvLyBNYWtlIHN1cmUgYSB0ZXh0YmxvY2sgbG9va3MgYW5kIGJlaGF2ZXMgY29ycmVjdGx5IGluXG4gICAgLy8gY29udGVudEVkaXRhYmxlLlxuICAgIGFkZFRleHRibG9ja0hhY2tzKCkge1xuICAgICAgICBsZXQgbGFzdENoaWxkID0gdGhpcy50b3AuY2hpbGRyZW5bdGhpcy5pbmRleCAtIDFdLCBwYXJlbnQgPSB0aGlzLnRvcDtcbiAgICAgICAgd2hpbGUgKGxhc3RDaGlsZCBpbnN0YW5jZW9mIE1hcmtWaWV3RGVzYykge1xuICAgICAgICAgICAgcGFyZW50ID0gbGFzdENoaWxkO1xuICAgICAgICAgICAgbGFzdENoaWxkID0gcGFyZW50LmNoaWxkcmVuW3BhcmVudC5jaGlsZHJlbi5sZW5ndGggLSAxXTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoIWxhc3RDaGlsZCB8fCAvLyBFbXB0eSB0ZXh0YmxvY2tcbiAgICAgICAgICAgICEobGFzdENoaWxkIGluc3RhbmNlb2YgVGV4dFZpZXdEZXNjKSB8fFxuICAgICAgICAgICAgL1xcbiQvLnRlc3QobGFzdENoaWxkLm5vZGUudGV4dCkgfHxcbiAgICAgICAgICAgICh0aGlzLnZpZXcucmVxdWlyZXNHZWNrb0hhY2tOb2RlICYmIC9cXHMkLy50ZXN0KGxhc3RDaGlsZC5ub2RlLnRleHQpKSkge1xuICAgICAgICAgICAgLy8gQXZvaWQgYnVncyBpbiBTYWZhcmkncyBjdXJzb3IgZHJhd2luZyAoIzExNjUpIGFuZCBDaHJvbWUncyBtb3VzZSBzZWxlY3Rpb24gKCMxMTUyKVxuICAgICAgICAgICAgaWYgKChzYWZhcmkgfHwgY2hyb21lKSAmJiBsYXN0Q2hpbGQgJiYgbGFzdENoaWxkLmRvbS5jb250ZW50RWRpdGFibGUgPT0gXCJmYWxzZVwiKVxuICAgICAgICAgICAgICAgIHRoaXMuYWRkSGFja05vZGUoXCJJTUdcIiwgcGFyZW50KTtcbiAgICAgICAgICAgIHRoaXMuYWRkSGFja05vZGUoXCJCUlwiLCB0aGlzLnRvcCk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgYWRkSGFja05vZGUobm9kZU5hbWUsIHBhcmVudCkge1xuICAgICAgICBpZiAocGFyZW50ID09IHRoaXMudG9wICYmIHRoaXMuaW5kZXggPCBwYXJlbnQuY2hpbGRyZW4ubGVuZ3RoICYmIHBhcmVudC5jaGlsZHJlblt0aGlzLmluZGV4XS5tYXRjaGVzSGFjayhub2RlTmFtZSkpIHtcbiAgICAgICAgICAgIHRoaXMuaW5kZXgrKztcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIGxldCBkb20gPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KG5vZGVOYW1lKTtcbiAgICAgICAgICAgIGlmIChub2RlTmFtZSA9PSBcIklNR1wiKSB7XG4gICAgICAgICAgICAgICAgZG9tLmNsYXNzTmFtZSA9IFwiUHJvc2VNaXJyb3Itc2VwYXJhdG9yXCI7XG4gICAgICAgICAgICAgICAgZG9tLmFsdCA9IFwiXCI7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAobm9kZU5hbWUgPT0gXCJCUlwiKVxuICAgICAgICAgICAgICAgIGRvbS5jbGFzc05hbWUgPSBcIlByb3NlTWlycm9yLXRyYWlsaW5nQnJlYWtcIjtcbiAgICAgICAgICAgIGxldCBoYWNrID0gbmV3IFRyYWlsaW5nSGFja1ZpZXdEZXNjKHRoaXMudG9wLCBbXSwgZG9tLCBudWxsKTtcbiAgICAgICAgICAgIGlmIChwYXJlbnQgIT0gdGhpcy50b3ApXG4gICAgICAgICAgICAgICAgcGFyZW50LmNoaWxkcmVuLnB1c2goaGFjayk7XG4gICAgICAgICAgICBlbHNlXG4gICAgICAgICAgICAgICAgcGFyZW50LmNoaWxkcmVuLnNwbGljZSh0aGlzLmluZGV4KyssIDAsIGhhY2spO1xuICAgICAgICAgICAgdGhpcy5jaGFuZ2VkID0gdHJ1ZTtcbiAgICAgICAgfVxuICAgIH1cbiAgICBpc0xvY2tlZChub2RlKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmxvY2sgJiYgKG5vZGUgPT0gdGhpcy5sb2NrIHx8IG5vZGUubm9kZVR5cGUgPT0gMSAmJiBub2RlLmNvbnRhaW5zKHRoaXMubG9jay5wYXJlbnROb2RlKSk7XG4gICAgfVxufVxuLy8gSXRlcmF0ZSBmcm9tIHRoZSBlbmQgb2YgdGhlIGZyYWdtZW50IGFuZCBhcnJheSBvZiBkZXNjcyB0byBmaW5kXG4vLyBkaXJlY3RseSBtYXRjaGluZyBvbmVzLCBpbiBvcmRlciB0byBhdm9pZCBvdmVyZWFnZXJseSByZXVzaW5nIHRob3NlXG4vLyBmb3Igb3RoZXIgbm9kZXMuXG5mdW5jdGlvbiBwcmVNYXRjaChmcmFnLCBwYXJlbnREZXNjKSB7XG4gICAgbGV0IGN1ckRlc2MgPSBwYXJlbnREZXNjLCBkZXNjSSA9IGN1ckRlc2MuY2hpbGRyZW4ubGVuZ3RoO1xuICAgIGxldCBmSSA9IGZyYWcuY2hpbGRDb3VudCwgbWF0Y2hlZCA9IG5ldyBNYXAsIG1hdGNoZXMgPSBbXTtcbiAgICBvdXRlcjogd2hpbGUgKGZJID4gMCkge1xuICAgICAgICBsZXQgZGVzYztcbiAgICAgICAgZm9yICg7Oykge1xuICAgICAgICAgICAgaWYgKGRlc2NJKSB7XG4gICAgICAgICAgICAgICAgbGV0IG5leHQgPSBjdXJEZXNjLmNoaWxkcmVuW2Rlc2NJIC0gMV07XG4gICAgICAgICAgICAgICAgaWYgKG5leHQgaW5zdGFuY2VvZiBNYXJrVmlld0Rlc2MpIHtcbiAgICAgICAgICAgICAgICAgICAgY3VyRGVzYyA9IG5leHQ7XG4gICAgICAgICAgICAgICAgICAgIGRlc2NJID0gbmV4dC5jaGlsZHJlbi5sZW5ndGg7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICBkZXNjID0gbmV4dDtcbiAgICAgICAgICAgICAgICAgICAgZGVzY0ktLTtcbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSBpZiAoY3VyRGVzYyA9PSBwYXJlbnREZXNjKSB7XG4gICAgICAgICAgICAgICAgYnJlYWsgb3V0ZXI7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICBkZXNjSSA9IGN1ckRlc2MucGFyZW50LmNoaWxkcmVuLmluZGV4T2YoY3VyRGVzYyk7XG4gICAgICAgICAgICAgICAgY3VyRGVzYyA9IGN1ckRlc2MucGFyZW50O1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGxldCBub2RlID0gZGVzYy5ub2RlO1xuICAgICAgICBpZiAoIW5vZGUpXG4gICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgaWYgKG5vZGUgIT0gZnJhZy5jaGlsZChmSSAtIDEpKVxuICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgIC0tZkk7XG4gICAgICAgIG1hdGNoZWQuc2V0KGRlc2MsIGZJKTtcbiAgICAgICAgbWF0Y2hlcy5wdXNoKGRlc2MpO1xuICAgIH1cbiAgICByZXR1cm4geyBpbmRleDogZkksIG1hdGNoZWQsIG1hdGNoZXM6IG1hdGNoZXMucmV2ZXJzZSgpIH07XG59XG5mdW5jdGlvbiBjb21wYXJlU2lkZShhLCBiKSB7XG4gICAgcmV0dXJuIGEudHlwZS5zaWRlIC0gYi50eXBlLnNpZGU7XG59XG4vLyBUaGlzIGZ1bmN0aW9uIGFic3RyYWN0cyBpdGVyYXRpbmcgb3ZlciB0aGUgbm9kZXMgYW5kIGRlY29yYXRpb25zIGluXG4vLyBhIGZyYWdtZW50LiBDYWxscyBgb25Ob2RlYCBmb3IgZWFjaCBub2RlLCB3aXRoIGl0cyBsb2NhbCBhbmQgY2hpbGRcbi8vIGRlY29yYXRpb25zLiBTcGxpdHMgdGV4dCBub2RlcyB3aGVuIHRoZXJlIGlzIGEgZGVjb3JhdGlvbiBzdGFydGluZ1xuLy8gb3IgZW5kaW5nIGluc2lkZSBvZiB0aGVtLiBDYWxscyBgb25XaWRnZXRgIGZvciBlYWNoIHdpZGdldC5cbmZ1bmN0aW9uIGl0ZXJEZWNvKHBhcmVudCwgZGVjbywgb25XaWRnZXQsIG9uTm9kZSkge1xuICAgIGxldCBsb2NhbHMgPSBkZWNvLmxvY2FscyhwYXJlbnQpLCBvZmZzZXQgPSAwO1xuICAgIC8vIFNpbXBsZSwgY2hlYXAgdmFyaWFudCBmb3Igd2hlbiB0aGVyZSBhcmUgbm8gbG9jYWwgZGVjb3JhdGlvbnNcbiAgICBpZiAobG9jYWxzLmxlbmd0aCA9PSAwKSB7XG4gICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgcGFyZW50LmNoaWxkQ291bnQ7IGkrKykge1xuICAgICAgICAgICAgbGV0IGNoaWxkID0gcGFyZW50LmNoaWxkKGkpO1xuICAgICAgICAgICAgb25Ob2RlKGNoaWxkLCBsb2NhbHMsIGRlY28uZm9yQ2hpbGQob2Zmc2V0LCBjaGlsZCksIGkpO1xuICAgICAgICAgICAgb2Zmc2V0ICs9IGNoaWxkLm5vZGVTaXplO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybjtcbiAgICB9XG4gICAgbGV0IGRlY29JbmRleCA9IDAsIGFjdGl2ZSA9IFtdLCByZXN0Tm9kZSA9IG51bGw7XG4gICAgZm9yIChsZXQgcGFyZW50SW5kZXggPSAwOzspIHtcbiAgICAgICAgbGV0IHdpZGdldCwgd2lkZ2V0cztcbiAgICAgICAgd2hpbGUgKGRlY29JbmRleCA8IGxvY2Fscy5sZW5ndGggJiYgbG9jYWxzW2RlY29JbmRleF0udG8gPT0gb2Zmc2V0KSB7XG4gICAgICAgICAgICBsZXQgbmV4dCA9IGxvY2Fsc1tkZWNvSW5kZXgrK107XG4gICAgICAgICAgICBpZiAobmV4dC53aWRnZXQpIHtcbiAgICAgICAgICAgICAgICBpZiAoIXdpZGdldClcbiAgICAgICAgICAgICAgICAgICAgd2lkZ2V0ID0gbmV4dDtcbiAgICAgICAgICAgICAgICBlbHNlXG4gICAgICAgICAgICAgICAgICAgICh3aWRnZXRzIHx8ICh3aWRnZXRzID0gW3dpZGdldF0pKS5wdXNoKG5leHQpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGlmICh3aWRnZXQpIHtcbiAgICAgICAgICAgIGlmICh3aWRnZXRzKSB7XG4gICAgICAgICAgICAgICAgd2lkZ2V0cy5zb3J0KGNvbXBhcmVTaWRlKTtcbiAgICAgICAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHdpZGdldHMubGVuZ3RoOyBpKyspXG4gICAgICAgICAgICAgICAgICAgIG9uV2lkZ2V0KHdpZGdldHNbaV0sIHBhcmVudEluZGV4LCAhIXJlc3ROb2RlKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgIG9uV2lkZ2V0KHdpZGdldCwgcGFyZW50SW5kZXgsICEhcmVzdE5vZGUpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGxldCBjaGlsZCwgaW5kZXg7XG4gICAgICAgIGlmIChyZXN0Tm9kZSkge1xuICAgICAgICAgICAgaW5kZXggPSAtMTtcbiAgICAgICAgICAgIGNoaWxkID0gcmVzdE5vZGU7XG4gICAgICAgICAgICByZXN0Tm9kZSA9IG51bGw7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAocGFyZW50SW5kZXggPCBwYXJlbnQuY2hpbGRDb3VudCkge1xuICAgICAgICAgICAgaW5kZXggPSBwYXJlbnRJbmRleDtcbiAgICAgICAgICAgIGNoaWxkID0gcGFyZW50LmNoaWxkKHBhcmVudEluZGV4KyspO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgIH1cbiAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBhY3RpdmUubGVuZ3RoOyBpKyspXG4gICAgICAgICAgICBpZiAoYWN0aXZlW2ldLnRvIDw9IG9mZnNldClcbiAgICAgICAgICAgICAgICBhY3RpdmUuc3BsaWNlKGktLSwgMSk7XG4gICAgICAgIHdoaWxlIChkZWNvSW5kZXggPCBsb2NhbHMubGVuZ3RoICYmIGxvY2Fsc1tkZWNvSW5kZXhdLmZyb20gPD0gb2Zmc2V0ICYmIGxvY2Fsc1tkZWNvSW5kZXhdLnRvID4gb2Zmc2V0KVxuICAgICAgICAgICAgYWN0aXZlLnB1c2gobG9jYWxzW2RlY29JbmRleCsrXSk7XG4gICAgICAgIGxldCBlbmQgPSBvZmZzZXQgKyBjaGlsZC5ub2RlU2l6ZTtcbiAgICAgICAgaWYgKGNoaWxkLmlzVGV4dCkge1xuICAgICAgICAgICAgbGV0IGN1dEF0ID0gZW5kO1xuICAgICAgICAgICAgaWYgKGRlY29JbmRleCA8IGxvY2Fscy5sZW5ndGggJiYgbG9jYWxzW2RlY29JbmRleF0uZnJvbSA8IGN1dEF0KVxuICAgICAgICAgICAgICAgIGN1dEF0ID0gbG9jYWxzW2RlY29JbmRleF0uZnJvbTtcbiAgICAgICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgYWN0aXZlLmxlbmd0aDsgaSsrKVxuICAgICAgICAgICAgICAgIGlmIChhY3RpdmVbaV0udG8gPCBjdXRBdClcbiAgICAgICAgICAgICAgICAgICAgY3V0QXQgPSBhY3RpdmVbaV0udG87XG4gICAgICAgICAgICBpZiAoY3V0QXQgPCBlbmQpIHtcbiAgICAgICAgICAgICAgICByZXN0Tm9kZSA9IGNoaWxkLmN1dChjdXRBdCAtIG9mZnNldCk7XG4gICAgICAgICAgICAgICAgY2hpbGQgPSBjaGlsZC5jdXQoMCwgY3V0QXQgLSBvZmZzZXQpO1xuICAgICAgICAgICAgICAgIGVuZCA9IGN1dEF0O1xuICAgICAgICAgICAgICAgIGluZGV4ID0gLTE7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICB3aGlsZSAoZGVjb0luZGV4IDwgbG9jYWxzLmxlbmd0aCAmJiBsb2NhbHNbZGVjb0luZGV4XS50byA8IGVuZClcbiAgICAgICAgICAgICAgICBkZWNvSW5kZXgrKztcbiAgICAgICAgfVxuICAgICAgICBsZXQgb3V0ZXJEZWNvID0gY2hpbGQuaXNJbmxpbmUgJiYgIWNoaWxkLmlzTGVhZiA/IGFjdGl2ZS5maWx0ZXIoZCA9PiAhZC5pbmxpbmUpIDogYWN0aXZlLnNsaWNlKCk7XG4gICAgICAgIG9uTm9kZShjaGlsZCwgb3V0ZXJEZWNvLCBkZWNvLmZvckNoaWxkKG9mZnNldCwgY2hpbGQpLCBpbmRleCk7XG4gICAgICAgIG9mZnNldCA9IGVuZDtcbiAgICB9XG59XG4vLyBMaXN0IG1hcmtlcnMgaW4gTW9iaWxlIFNhZmFyaSB3aWxsIG15c3RlcmlvdXNseSBkaXNhcHBlYXJcbi8vIHNvbWV0aW1lcy4gVGhpcyB3b3JrcyBhcm91bmQgdGhhdC5cbmZ1bmN0aW9uIGlvc0hhY2tzKGRvbSkge1xuICAgIGlmIChkb20ubm9kZU5hbWUgPT0gXCJVTFwiIHx8IGRvbS5ub2RlTmFtZSA9PSBcIk9MXCIpIHtcbiAgICAgICAgbGV0IG9sZENTUyA9IGRvbS5zdHlsZS5jc3NUZXh0O1xuICAgICAgICBkb20uc3R5bGUuY3NzVGV4dCA9IG9sZENTUyArIFwiOyBsaXN0LXN0eWxlOiBzcXVhcmUgIWltcG9ydGFudFwiO1xuICAgICAgICB3aW5kb3cuZ2V0Q29tcHV0ZWRTdHlsZShkb20pLmxpc3RTdHlsZTtcbiAgICAgICAgZG9tLnN0eWxlLmNzc1RleHQgPSBvbGRDU1M7XG4gICAgfVxufVxuLy8gRmluZCBhIHBpZWNlIG9mIHRleHQgaW4gYW4gaW5saW5lIGZyYWdtZW50LCBvdmVybGFwcGluZyBmcm9tLXRvXG5mdW5jdGlvbiBmaW5kVGV4dEluRnJhZ21lbnQoZnJhZywgdGV4dCwgZnJvbSwgdG8pIHtcbiAgICBmb3IgKGxldCBpID0gMCwgcG9zID0gMDsgaSA8IGZyYWcuY2hpbGRDb3VudCAmJiBwb3MgPD0gdG87KSB7XG4gICAgICAgIGxldCBjaGlsZCA9IGZyYWcuY2hpbGQoaSsrKSwgY2hpbGRTdGFydCA9IHBvcztcbiAgICAgICAgcG9zICs9IGNoaWxkLm5vZGVTaXplO1xuICAgICAgICBpZiAoIWNoaWxkLmlzVGV4dClcbiAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICBsZXQgc3RyID0gY2hpbGQudGV4dDtcbiAgICAgICAgd2hpbGUgKGkgPCBmcmFnLmNoaWxkQ291bnQpIHtcbiAgICAgICAgICAgIGxldCBuZXh0ID0gZnJhZy5jaGlsZChpKyspO1xuICAgICAgICAgICAgcG9zICs9IG5leHQubm9kZVNpemU7XG4gICAgICAgICAgICBpZiAoIW5leHQuaXNUZXh0KVxuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgc3RyICs9IG5leHQudGV4dDtcbiAgICAgICAgfVxuICAgICAgICBpZiAocG9zID49IGZyb20pIHtcbiAgICAgICAgICAgIGlmIChwb3MgPj0gdG8gJiYgc3RyLnNsaWNlKHRvIC0gdGV4dC5sZW5ndGggLSBjaGlsZFN0YXJ0LCB0byAtIGNoaWxkU3RhcnQpID09IHRleHQpXG4gICAgICAgICAgICAgICAgcmV0dXJuIHRvIC0gdGV4dC5sZW5ndGg7XG4gICAgICAgICAgICBsZXQgZm91bmQgPSBjaGlsZFN0YXJ0IDwgdG8gPyBzdHIubGFzdEluZGV4T2YodGV4dCwgdG8gLSBjaGlsZFN0YXJ0IC0gMSkgOiAtMTtcbiAgICAgICAgICAgIGlmIChmb3VuZCA+PSAwICYmIGZvdW5kICsgdGV4dC5sZW5ndGggKyBjaGlsZFN0YXJ0ID49IGZyb20pXG4gICAgICAgICAgICAgICAgcmV0dXJuIGNoaWxkU3RhcnQgKyBmb3VuZDtcbiAgICAgICAgICAgIGlmIChmcm9tID09IHRvICYmIHN0ci5sZW5ndGggPj0gKHRvICsgdGV4dC5sZW5ndGgpIC0gY2hpbGRTdGFydCAmJlxuICAgICAgICAgICAgICAgIHN0ci5zbGljZSh0byAtIGNoaWxkU3RhcnQsIHRvIC0gY2hpbGRTdGFydCArIHRleHQubGVuZ3RoKSA9PSB0ZXh0KVxuICAgICAgICAgICAgICAgIHJldHVybiB0bztcbiAgICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gLTE7XG59XG4vLyBSZXBsYWNlIHJhbmdlIGZyb20tdG8gaW4gYW4gYXJyYXkgb2YgdmlldyBkZXNjcyB3aXRoIHJlcGxhY2VtZW50XG4vLyAobWF5IGJlIG51bGwgdG8ganVzdCBkZWxldGUpLiBUaGlzIGdvZXMgdmVyeSBtdWNoIGFnYWluc3QgdGhlIGdyYWluXG4vLyBvZiB0aGUgcmVzdCBvZiB0aGlzIGNvZGUsIHdoaWNoIHRlbmRzIHRvIGNyZWF0ZSBub2RlcyB3aXRoIHRoZVxuLy8gcmlnaHQgc2hhcGUgaW4gb25lIGdvLCByYXRoZXIgdGhhbiBtZXNzaW5nIHdpdGggdGhlbSBhZnRlclxuLy8gY3JlYXRpb24sIGJ1dCBpcyBuZWNlc3NhcnkgaW4gdGhlIGNvbXBvc2l0aW9uIGhhY2suXG5mdW5jdGlvbiByZXBsYWNlTm9kZXMobm9kZXMsIGZyb20sIHRvLCB2aWV3LCByZXBsYWNlbWVudCkge1xuICAgIGxldCByZXN1bHQgPSBbXTtcbiAgICBmb3IgKGxldCBpID0gMCwgb2ZmID0gMDsgaSA8IG5vZGVzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIGxldCBjaGlsZCA9IG5vZGVzW2ldLCBzdGFydCA9IG9mZiwgZW5kID0gb2ZmICs9IGNoaWxkLnNpemU7XG4gICAgICAgIGlmIChzdGFydCA+PSB0byB8fCBlbmQgPD0gZnJvbSkge1xuICAgICAgICAgICAgcmVzdWx0LnB1c2goY2hpbGQpO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgaWYgKHN0YXJ0IDwgZnJvbSlcbiAgICAgICAgICAgICAgICByZXN1bHQucHVzaChjaGlsZC5zbGljZSgwLCBmcm9tIC0gc3RhcnQsIHZpZXcpKTtcbiAgICAgICAgICAgIGlmIChyZXBsYWNlbWVudCkge1xuICAgICAgICAgICAgICAgIHJlc3VsdC5wdXNoKHJlcGxhY2VtZW50KTtcbiAgICAgICAgICAgICAgICByZXBsYWNlbWVudCA9IHVuZGVmaW5lZDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmIChlbmQgPiB0bylcbiAgICAgICAgICAgICAgICByZXN1bHQucHVzaChjaGlsZC5zbGljZSh0byAtIHN0YXJ0LCBjaGlsZC5zaXplLCB2aWV3KSk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIHJlc3VsdDtcbn1cblxuZnVuY3Rpb24gc2VsZWN0aW9uRnJvbURPTSh2aWV3LCBvcmlnaW4gPSBudWxsKSB7XG4gICAgbGV0IGRvbVNlbCA9IHZpZXcuZG9tU2VsZWN0aW9uUmFuZ2UoKSwgZG9jID0gdmlldy5zdGF0ZS5kb2M7XG4gICAgaWYgKCFkb21TZWwuZm9jdXNOb2RlKVxuICAgICAgICByZXR1cm4gbnVsbDtcbiAgICBsZXQgbmVhcmVzdERlc2MgPSB2aWV3LmRvY1ZpZXcubmVhcmVzdERlc2MoZG9tU2VsLmZvY3VzTm9kZSksIGluV2lkZ2V0ID0gbmVhcmVzdERlc2MgJiYgbmVhcmVzdERlc2Muc2l6ZSA9PSAwO1xuICAgIGxldCBoZWFkID0gdmlldy5kb2NWaWV3LnBvc0Zyb21ET00oZG9tU2VsLmZvY3VzTm9kZSwgZG9tU2VsLmZvY3VzT2Zmc2V0LCAxKTtcbiAgICBpZiAoaGVhZCA8IDApXG4gICAgICAgIHJldHVybiBudWxsO1xuICAgIGxldCAkaGVhZCA9IGRvYy5yZXNvbHZlKGhlYWQpLCBhbmNob3IsIHNlbGVjdGlvbjtcbiAgICBpZiAoc2VsZWN0aW9uQ29sbGFwc2VkKGRvbVNlbCkpIHtcbiAgICAgICAgYW5jaG9yID0gaGVhZDtcbiAgICAgICAgd2hpbGUgKG5lYXJlc3REZXNjICYmICFuZWFyZXN0RGVzYy5ub2RlKVxuICAgICAgICAgICAgbmVhcmVzdERlc2MgPSBuZWFyZXN0RGVzYy5wYXJlbnQ7XG4gICAgICAgIGxldCBuZWFyZXN0RGVzY05vZGUgPSBuZWFyZXN0RGVzYy5ub2RlO1xuICAgICAgICBpZiAobmVhcmVzdERlc2MgJiYgbmVhcmVzdERlc2NOb2RlLmlzQXRvbSAmJiBOb2RlU2VsZWN0aW9uLmlzU2VsZWN0YWJsZShuZWFyZXN0RGVzY05vZGUpICYmIG5lYXJlc3REZXNjLnBhcmVudFxuICAgICAgICAgICAgJiYgIShuZWFyZXN0RGVzY05vZGUuaXNJbmxpbmUgJiYgaXNPbkVkZ2UoZG9tU2VsLmZvY3VzTm9kZSwgZG9tU2VsLmZvY3VzT2Zmc2V0LCBuZWFyZXN0RGVzYy5kb20pKSkge1xuICAgICAgICAgICAgbGV0IHBvcyA9IG5lYXJlc3REZXNjLnBvc0JlZm9yZTtcbiAgICAgICAgICAgIHNlbGVjdGlvbiA9IG5ldyBOb2RlU2VsZWN0aW9uKGhlYWQgPT0gcG9zID8gJGhlYWQgOiBkb2MucmVzb2x2ZShwb3MpKTtcbiAgICAgICAgfVxuICAgIH1cbiAgICBlbHNlIHtcbiAgICAgICAgaWYgKGRvbVNlbCBpbnN0YW5jZW9mIHZpZXcuZG9tLm93bmVyRG9jdW1lbnQuZGVmYXVsdFZpZXcuU2VsZWN0aW9uICYmIGRvbVNlbC5yYW5nZUNvdW50ID4gMSkge1xuICAgICAgICAgICAgbGV0IG1pbiA9IGhlYWQsIG1heCA9IGhlYWQ7XG4gICAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IGRvbVNlbC5yYW5nZUNvdW50OyBpKyspIHtcbiAgICAgICAgICAgICAgICBsZXQgcmFuZ2UgPSBkb21TZWwuZ2V0UmFuZ2VBdChpKTtcbiAgICAgICAgICAgICAgICBtaW4gPSBNYXRoLm1pbihtaW4sIHZpZXcuZG9jVmlldy5wb3NGcm9tRE9NKHJhbmdlLnN0YXJ0Q29udGFpbmVyLCByYW5nZS5zdGFydE9mZnNldCwgMSkpO1xuICAgICAgICAgICAgICAgIG1heCA9IE1hdGgubWF4KG1heCwgdmlldy5kb2NWaWV3LnBvc0Zyb21ET00ocmFuZ2UuZW5kQ29udGFpbmVyLCByYW5nZS5lbmRPZmZzZXQsIC0xKSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAobWluIDwgMClcbiAgICAgICAgICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgICAgICAgIFthbmNob3IsIGhlYWRdID0gbWF4ID09IHZpZXcuc3RhdGUuc2VsZWN0aW9uLmFuY2hvciA/IFttYXgsIG1pbl0gOiBbbWluLCBtYXhdO1xuICAgICAgICAgICAgJGhlYWQgPSBkb2MucmVzb2x2ZShoZWFkKTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIGFuY2hvciA9IHZpZXcuZG9jVmlldy5wb3NGcm9tRE9NKGRvbVNlbC5hbmNob3JOb2RlLCBkb21TZWwuYW5jaG9yT2Zmc2V0LCAxKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoYW5jaG9yIDwgMClcbiAgICAgICAgICAgIHJldHVybiBudWxsO1xuICAgIH1cbiAgICBsZXQgJGFuY2hvciA9IGRvYy5yZXNvbHZlKGFuY2hvcik7XG4gICAgaWYgKCFzZWxlY3Rpb24pIHtcbiAgICAgICAgbGV0IGJpYXMgPSBvcmlnaW4gPT0gXCJwb2ludGVyXCIgfHwgKHZpZXcuc3RhdGUuc2VsZWN0aW9uLmhlYWQgPCAkaGVhZC5wb3MgJiYgIWluV2lkZ2V0KSA/IDEgOiAtMTtcbiAgICAgICAgc2VsZWN0aW9uID0gc2VsZWN0aW9uQmV0d2Vlbih2aWV3LCAkYW5jaG9yLCAkaGVhZCwgYmlhcyk7XG4gICAgfVxuICAgIHJldHVybiBzZWxlY3Rpb247XG59XG5mdW5jdGlvbiBlZGl0b3JPd25zU2VsZWN0aW9uKHZpZXcpIHtcbiAgICByZXR1cm4gdmlldy5lZGl0YWJsZSA/IHZpZXcuaGFzRm9jdXMoKSA6XG4gICAgICAgIGhhc1NlbGVjdGlvbih2aWV3KSAmJiBkb2N1bWVudC5hY3RpdmVFbGVtZW50ICYmIGRvY3VtZW50LmFjdGl2ZUVsZW1lbnQuY29udGFpbnModmlldy5kb20pO1xufVxuZnVuY3Rpb24gc2VsZWN0aW9uVG9ET00odmlldywgZm9yY2UgPSBmYWxzZSkge1xuICAgIGxldCBzZWwgPSB2aWV3LnN0YXRlLnNlbGVjdGlvbjtcbiAgICBzeW5jTm9kZVNlbGVjdGlvbih2aWV3LCBzZWwpO1xuICAgIGlmICghZWRpdG9yT3duc1NlbGVjdGlvbih2aWV3KSlcbiAgICAgICAgcmV0dXJuO1xuICAgIC8vIFRoZSBkZWxheWVkIGRyYWcgc2VsZWN0aW9uIGNhdXNlcyBpc3N1ZXMgd2l0aCBDZWxsIFNlbGVjdGlvbnNcbiAgICAvLyBpbiBTYWZhcmkuIEFuZCB0aGUgZHJhZyBzZWxlY3Rpb24gZGVsYXkgaXMgdG8gd29ya2Fyb25kIGlzc3Vlc1xuICAgIC8vIHdoaWNoIG9ubHkgcHJlc2VudCBpbiBDaHJvbWUuXG4gICAgaWYgKCFmb3JjZSAmJiB2aWV3LmlucHV0Lm1vdXNlRG93biAmJiB2aWV3LmlucHV0Lm1vdXNlRG93bi5hbGxvd0RlZmF1bHQgJiYgY2hyb21lKSB7XG4gICAgICAgIGxldCBkb21TZWwgPSB2aWV3LmRvbVNlbGVjdGlvblJhbmdlKCksIGN1clNlbCA9IHZpZXcuZG9tT2JzZXJ2ZXIuY3VycmVudFNlbGVjdGlvbjtcbiAgICAgICAgaWYgKGRvbVNlbC5hbmNob3JOb2RlICYmIGN1clNlbC5hbmNob3JOb2RlICYmXG4gICAgICAgICAgICBpc0VxdWl2YWxlbnRQb3NpdGlvbihkb21TZWwuYW5jaG9yTm9kZSwgZG9tU2VsLmFuY2hvck9mZnNldCwgY3VyU2VsLmFuY2hvck5vZGUsIGN1clNlbC5hbmNob3JPZmZzZXQpKSB7XG4gICAgICAgICAgICB2aWV3LmlucHV0Lm1vdXNlRG93bi5kZWxheWVkU2VsZWN0aW9uU3luYyA9IHRydWU7XG4gICAgICAgICAgICB2aWV3LmRvbU9ic2VydmVyLnNldEN1clNlbGVjdGlvbigpO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgfVxuICAgIHZpZXcuZG9tT2JzZXJ2ZXIuZGlzY29ubmVjdFNlbGVjdGlvbigpO1xuICAgIGlmICh2aWV3LmN1cnNvcldyYXBwZXIpIHtcbiAgICAgICAgc2VsZWN0Q3Vyc29yV3JhcHBlcih2aWV3KTtcbiAgICB9XG4gICAgZWxzZSB7XG4gICAgICAgIGxldCB7IGFuY2hvciwgaGVhZCB9ID0gc2VsLCByZXNldEVkaXRhYmxlRnJvbSwgcmVzZXRFZGl0YWJsZVRvO1xuICAgICAgICBpZiAoYnJva2VuU2VsZWN0QmV0d2VlblVuZWRpdGFibGUgJiYgIShzZWwgaW5zdGFuY2VvZiBUZXh0U2VsZWN0aW9uKSkge1xuICAgICAgICAgICAgaWYgKCFzZWwuJGZyb20ucGFyZW50LmlubGluZUNvbnRlbnQpXG4gICAgICAgICAgICAgICAgcmVzZXRFZGl0YWJsZUZyb20gPSB0ZW1wb3JhcmlseUVkaXRhYmxlTmVhcih2aWV3LCBzZWwuZnJvbSk7XG4gICAgICAgICAgICBpZiAoIXNlbC5lbXB0eSAmJiAhc2VsLiRmcm9tLnBhcmVudC5pbmxpbmVDb250ZW50KVxuICAgICAgICAgICAgICAgIHJlc2V0RWRpdGFibGVUbyA9IHRlbXBvcmFyaWx5RWRpdGFibGVOZWFyKHZpZXcsIHNlbC50byk7XG4gICAgICAgIH1cbiAgICAgICAgdmlldy5kb2NWaWV3LnNldFNlbGVjdGlvbihhbmNob3IsIGhlYWQsIHZpZXcsIGZvcmNlKTtcbiAgICAgICAgaWYgKGJyb2tlblNlbGVjdEJldHdlZW5VbmVkaXRhYmxlKSB7XG4gICAgICAgICAgICBpZiAocmVzZXRFZGl0YWJsZUZyb20pXG4gICAgICAgICAgICAgICAgcmVzZXRFZGl0YWJsZShyZXNldEVkaXRhYmxlRnJvbSk7XG4gICAgICAgICAgICBpZiAocmVzZXRFZGl0YWJsZVRvKVxuICAgICAgICAgICAgICAgIHJlc2V0RWRpdGFibGUocmVzZXRFZGl0YWJsZVRvKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoc2VsLnZpc2libGUpIHtcbiAgICAgICAgICAgIHZpZXcuZG9tLmNsYXNzTGlzdC5yZW1vdmUoXCJQcm9zZU1pcnJvci1oaWRlc2VsZWN0aW9uXCIpO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgdmlldy5kb20uY2xhc3NMaXN0LmFkZChcIlByb3NlTWlycm9yLWhpZGVzZWxlY3Rpb25cIik7XG4gICAgICAgICAgICBpZiAoXCJvbnNlbGVjdGlvbmNoYW5nZVwiIGluIGRvY3VtZW50KVxuICAgICAgICAgICAgICAgIHJlbW92ZUNsYXNzT25TZWxlY3Rpb25DaGFuZ2Uodmlldyk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgdmlldy5kb21PYnNlcnZlci5zZXRDdXJTZWxlY3Rpb24oKTtcbiAgICB2aWV3LmRvbU9ic2VydmVyLmNvbm5lY3RTZWxlY3Rpb24oKTtcbn1cbi8vIEtsdWRnZSB0byB3b3JrIGFyb3VuZCBXZWJraXQgbm90IGFsbG93aW5nIGEgc2VsZWN0aW9uIHRvIHN0YXJ0L2VuZFxuLy8gYmV0d2VlbiBub24tZWRpdGFibGUgYmxvY2sgbm9kZXMuIFdlIGJyaWVmbHkgbWFrZSBzb21ldGhpbmdcbi8vIGVkaXRhYmxlLCBzZXQgdGhlIHNlbGVjdGlvbiwgdGhlbiBzZXQgaXQgdW5lZGl0YWJsZSBhZ2Fpbi5cbmNvbnN0IGJyb2tlblNlbGVjdEJldHdlZW5VbmVkaXRhYmxlID0gc2FmYXJpIHx8IGNocm9tZSAmJiBjaHJvbWVfdmVyc2lvbiA8IDYzO1xuZnVuY3Rpb24gdGVtcG9yYXJpbHlFZGl0YWJsZU5lYXIodmlldywgcG9zKSB7XG4gICAgbGV0IHsgbm9kZSwgb2Zmc2V0IH0gPSB2aWV3LmRvY1ZpZXcuZG9tRnJvbVBvcyhwb3MsIDApO1xuICAgIGxldCBhZnRlciA9IG9mZnNldCA8IG5vZGUuY2hpbGROb2Rlcy5sZW5ndGggPyBub2RlLmNoaWxkTm9kZXNbb2Zmc2V0XSA6IG51bGw7XG4gICAgbGV0IGJlZm9yZSA9IG9mZnNldCA/IG5vZGUuY2hpbGROb2Rlc1tvZmZzZXQgLSAxXSA6IG51bGw7XG4gICAgaWYgKHNhZmFyaSAmJiBhZnRlciAmJiBhZnRlci5jb250ZW50RWRpdGFibGUgPT0gXCJmYWxzZVwiKVxuICAgICAgICByZXR1cm4gc2V0RWRpdGFibGUoYWZ0ZXIpO1xuICAgIGlmICgoIWFmdGVyIHx8IGFmdGVyLmNvbnRlbnRFZGl0YWJsZSA9PSBcImZhbHNlXCIpICYmXG4gICAgICAgICghYmVmb3JlIHx8IGJlZm9yZS5jb250ZW50RWRpdGFibGUgPT0gXCJmYWxzZVwiKSkge1xuICAgICAgICBpZiAoYWZ0ZXIpXG4gICAgICAgICAgICByZXR1cm4gc2V0RWRpdGFibGUoYWZ0ZXIpO1xuICAgICAgICBlbHNlIGlmIChiZWZvcmUpXG4gICAgICAgICAgICByZXR1cm4gc2V0RWRpdGFibGUoYmVmb3JlKTtcbiAgICB9XG59XG5mdW5jdGlvbiBzZXRFZGl0YWJsZShlbGVtZW50KSB7XG4gICAgZWxlbWVudC5jb250ZW50RWRpdGFibGUgPSBcInRydWVcIjtcbiAgICBpZiAoc2FmYXJpICYmIGVsZW1lbnQuZHJhZ2dhYmxlKSB7XG4gICAgICAgIGVsZW1lbnQuZHJhZ2dhYmxlID0gZmFsc2U7XG4gICAgICAgIGVsZW1lbnQud2FzRHJhZ2dhYmxlID0gdHJ1ZTtcbiAgICB9XG4gICAgcmV0dXJuIGVsZW1lbnQ7XG59XG5mdW5jdGlvbiByZXNldEVkaXRhYmxlKGVsZW1lbnQpIHtcbiAgICBlbGVtZW50LmNvbnRlbnRFZGl0YWJsZSA9IFwiZmFsc2VcIjtcbiAgICBpZiAoZWxlbWVudC53YXNEcmFnZ2FibGUpIHtcbiAgICAgICAgZWxlbWVudC5kcmFnZ2FibGUgPSB0cnVlO1xuICAgICAgICBlbGVtZW50Lndhc0RyYWdnYWJsZSA9IG51bGw7XG4gICAgfVxufVxuZnVuY3Rpb24gcmVtb3ZlQ2xhc3NPblNlbGVjdGlvbkNoYW5nZSh2aWV3KSB7XG4gICAgbGV0IGRvYyA9IHZpZXcuZG9tLm93bmVyRG9jdW1lbnQ7XG4gICAgZG9jLnJlbW92ZUV2ZW50TGlzdGVuZXIoXCJzZWxlY3Rpb25jaGFuZ2VcIiwgdmlldy5pbnB1dC5oaWRlU2VsZWN0aW9uR3VhcmQpO1xuICAgIGxldCBkb21TZWwgPSB2aWV3LmRvbVNlbGVjdGlvblJhbmdlKCk7XG4gICAgbGV0IG5vZGUgPSBkb21TZWwuYW5jaG9yTm9kZSwgb2Zmc2V0ID0gZG9tU2VsLmFuY2hvck9mZnNldDtcbiAgICBkb2MuYWRkRXZlbnRMaXN0ZW5lcihcInNlbGVjdGlvbmNoYW5nZVwiLCB2aWV3LmlucHV0LmhpZGVTZWxlY3Rpb25HdWFyZCA9ICgpID0+IHtcbiAgICAgICAgaWYgKGRvbVNlbC5hbmNob3JOb2RlICE9IG5vZGUgfHwgZG9tU2VsLmFuY2hvck9mZnNldCAhPSBvZmZzZXQpIHtcbiAgICAgICAgICAgIGRvYy5yZW1vdmVFdmVudExpc3RlbmVyKFwic2VsZWN0aW9uY2hhbmdlXCIsIHZpZXcuaW5wdXQuaGlkZVNlbGVjdGlvbkd1YXJkKTtcbiAgICAgICAgICAgIHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgICAgICAgICAgIGlmICghZWRpdG9yT3duc1NlbGVjdGlvbih2aWV3KSB8fCB2aWV3LnN0YXRlLnNlbGVjdGlvbi52aXNpYmxlKVxuICAgICAgICAgICAgICAgICAgICB2aWV3LmRvbS5jbGFzc0xpc3QucmVtb3ZlKFwiUHJvc2VNaXJyb3ItaGlkZXNlbGVjdGlvblwiKTtcbiAgICAgICAgICAgIH0sIDIwKTtcbiAgICAgICAgfVxuICAgIH0pO1xufVxuZnVuY3Rpb24gc2VsZWN0Q3Vyc29yV3JhcHBlcih2aWV3KSB7XG4gICAgbGV0IGRvbVNlbCA9IHZpZXcuZG9tU2VsZWN0aW9uKCk7XG4gICAgaWYgKCFkb21TZWwpXG4gICAgICAgIHJldHVybjtcbiAgICBsZXQgbm9kZSA9IHZpZXcuY3Vyc29yV3JhcHBlci5kb20sIGltZyA9IG5vZGUubm9kZU5hbWUgPT0gXCJJTUdcIjtcbiAgICBpZiAoaW1nKVxuICAgICAgICBkb21TZWwuY29sbGFwc2Uobm9kZS5wYXJlbnROb2RlLCBkb21JbmRleChub2RlKSArIDEpO1xuICAgIGVsc2VcbiAgICAgICAgZG9tU2VsLmNvbGxhcHNlKG5vZGUsIDApO1xuICAgIC8vIEtsdWRnZSB0byBraWxsICdjb250cm9sIHNlbGVjdGlvbicgaW4gSUUxMSB3aGVuIHNlbGVjdGluZyBhblxuICAgIC8vIGludmlzaWJsZSBjdXJzb3Igd3JhcHBlciwgc2luY2UgdGhhdCB3b3VsZCByZXN1bHQgaW4gdGhvc2Ugd2VpcmRcbiAgICAvLyByZXNpemUgaGFuZGxlcyBhbmQgYSBzZWxlY3Rpb24gdGhhdCBjb25zaWRlcnMgdGhlIGFic29sdXRlbHlcbiAgICAvLyBwb3NpdGlvbmVkIHdyYXBwZXIsIHJhdGhlciB0aGFuIHRoZSByb290IGVkaXRhYmxlIG5vZGUsIHRoZVxuICAgIC8vIGZvY3VzZWQgZWxlbWVudC5cbiAgICBpZiAoIWltZyAmJiAhdmlldy5zdGF0ZS5zZWxlY3Rpb24udmlzaWJsZSAmJiBpZSAmJiBpZV92ZXJzaW9uIDw9IDExKSB7XG4gICAgICAgIG5vZGUuZGlzYWJsZWQgPSB0cnVlO1xuICAgICAgICBub2RlLmRpc2FibGVkID0gZmFsc2U7XG4gICAgfVxufVxuZnVuY3Rpb24gc3luY05vZGVTZWxlY3Rpb24odmlldywgc2VsKSB7XG4gICAgaWYgKHNlbCBpbnN0YW5jZW9mIE5vZGVTZWxlY3Rpb24pIHtcbiAgICAgICAgbGV0IGRlc2MgPSB2aWV3LmRvY1ZpZXcuZGVzY0F0KHNlbC5mcm9tKTtcbiAgICAgICAgaWYgKGRlc2MgIT0gdmlldy5sYXN0U2VsZWN0ZWRWaWV3RGVzYykge1xuICAgICAgICAgICAgY2xlYXJOb2RlU2VsZWN0aW9uKHZpZXcpO1xuICAgICAgICAgICAgaWYgKGRlc2MpXG4gICAgICAgICAgICAgICAgZGVzYy5zZWxlY3ROb2RlKCk7XG4gICAgICAgICAgICB2aWV3Lmxhc3RTZWxlY3RlZFZpZXdEZXNjID0gZGVzYztcbiAgICAgICAgfVxuICAgIH1cbiAgICBlbHNlIHtcbiAgICAgICAgY2xlYXJOb2RlU2VsZWN0aW9uKHZpZXcpO1xuICAgIH1cbn1cbi8vIENsZWFyIGFsbCBET00gc3RhdGVmdWxuZXNzIG9mIHRoZSBsYXN0IG5vZGUgc2VsZWN0aW9uLlxuZnVuY3Rpb24gY2xlYXJOb2RlU2VsZWN0aW9uKHZpZXcpIHtcbiAgICBpZiAodmlldy5sYXN0U2VsZWN0ZWRWaWV3RGVzYykge1xuICAgICAgICBpZiAodmlldy5sYXN0U2VsZWN0ZWRWaWV3RGVzYy5wYXJlbnQpXG4gICAgICAgICAgICB2aWV3Lmxhc3RTZWxlY3RlZFZpZXdEZXNjLmRlc2VsZWN0Tm9kZSgpO1xuICAgICAgICB2aWV3Lmxhc3RTZWxlY3RlZFZpZXdEZXNjID0gdW5kZWZpbmVkO1xuICAgIH1cbn1cbmZ1bmN0aW9uIHNlbGVjdGlvbkJldHdlZW4odmlldywgJGFuY2hvciwgJGhlYWQsIGJpYXMpIHtcbiAgICByZXR1cm4gdmlldy5zb21lUHJvcChcImNyZWF0ZVNlbGVjdGlvbkJldHdlZW5cIiwgZiA9PiBmKHZpZXcsICRhbmNob3IsICRoZWFkKSlcbiAgICAgICAgfHwgVGV4dFNlbGVjdGlvbi5iZXR3ZWVuKCRhbmNob3IsICRoZWFkLCBiaWFzKTtcbn1cbmZ1bmN0aW9uIGhhc0ZvY3VzQW5kU2VsZWN0aW9uKHZpZXcpIHtcbiAgICBpZiAodmlldy5lZGl0YWJsZSAmJiAhdmlldy5oYXNGb2N1cygpKVxuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgcmV0dXJuIGhhc1NlbGVjdGlvbih2aWV3KTtcbn1cbmZ1bmN0aW9uIGhhc1NlbGVjdGlvbih2aWV3KSB7XG4gICAgbGV0IHNlbCA9IHZpZXcuZG9tU2VsZWN0aW9uUmFuZ2UoKTtcbiAgICBpZiAoIXNlbC5hbmNob3JOb2RlKVxuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgdHJ5IHtcbiAgICAgICAgLy8gRmlyZWZveCB3aWxsIHJhaXNlICdwZXJtaXNzaW9uIGRlbmllZCcgZXJyb3JzIHdoZW4gYWNjZXNzaW5nXG4gICAgICAgIC8vIHByb3BlcnRpZXMgb2YgYHNlbC5hbmNob3JOb2RlYCB3aGVuIGl0J3MgaW4gYSBnZW5lcmF0ZWQgQ1NTXG4gICAgICAgIC8vIGVsZW1lbnQuXG4gICAgICAgIHJldHVybiB2aWV3LmRvbS5jb250YWlucyhzZWwuYW5jaG9yTm9kZS5ub2RlVHlwZSA9PSAzID8gc2VsLmFuY2hvck5vZGUucGFyZW50Tm9kZSA6IHNlbC5hbmNob3JOb2RlKSAmJlxuICAgICAgICAgICAgKHZpZXcuZWRpdGFibGUgfHwgdmlldy5kb20uY29udGFpbnMoc2VsLmZvY3VzTm9kZS5ub2RlVHlwZSA9PSAzID8gc2VsLmZvY3VzTm9kZS5wYXJlbnROb2RlIDogc2VsLmZvY3VzTm9kZSkpO1xuICAgIH1cbiAgICBjYXRjaCAoXykge1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxufVxuZnVuY3Rpb24gYW5jaG9ySW5SaWdodFBsYWNlKHZpZXcpIHtcbiAgICBsZXQgYW5jaG9yRE9NID0gdmlldy5kb2NWaWV3LmRvbUZyb21Qb3Modmlldy5zdGF0ZS5zZWxlY3Rpb24uYW5jaG9yLCAwKTtcbiAgICBsZXQgZG9tU2VsID0gdmlldy5kb21TZWxlY3Rpb25SYW5nZSgpO1xuICAgIHJldHVybiBpc0VxdWl2YWxlbnRQb3NpdGlvbihhbmNob3JET00ubm9kZSwgYW5jaG9yRE9NLm9mZnNldCwgZG9tU2VsLmFuY2hvck5vZGUsIGRvbVNlbC5hbmNob3JPZmZzZXQpO1xufVxuXG5mdW5jdGlvbiBtb3ZlU2VsZWN0aW9uQmxvY2soc3RhdGUsIGRpcikge1xuICAgIGxldCB7ICRhbmNob3IsICRoZWFkIH0gPSBzdGF0ZS5zZWxlY3Rpb247XG4gICAgbGV0ICRzaWRlID0gZGlyID4gMCA/ICRhbmNob3IubWF4KCRoZWFkKSA6ICRhbmNob3IubWluKCRoZWFkKTtcbiAgICBsZXQgJHN0YXJ0ID0gISRzaWRlLnBhcmVudC5pbmxpbmVDb250ZW50ID8gJHNpZGUgOiAkc2lkZS5kZXB0aCA/IHN0YXRlLmRvYy5yZXNvbHZlKGRpciA+IDAgPyAkc2lkZS5hZnRlcigpIDogJHNpZGUuYmVmb3JlKCkpIDogbnVsbDtcbiAgICByZXR1cm4gJHN0YXJ0ICYmIFNlbGVjdGlvbi5maW5kRnJvbSgkc3RhcnQsIGRpcik7XG59XG5mdW5jdGlvbiBhcHBseSh2aWV3LCBzZWwpIHtcbiAgICB2aWV3LmRpc3BhdGNoKHZpZXcuc3RhdGUudHIuc2V0U2VsZWN0aW9uKHNlbCkuc2Nyb2xsSW50b1ZpZXcoKSk7XG4gICAgcmV0dXJuIHRydWU7XG59XG5mdW5jdGlvbiBzZWxlY3RIb3Jpem9udGFsbHkodmlldywgZGlyLCBtb2RzKSB7XG4gICAgbGV0IHNlbCA9IHZpZXcuc3RhdGUuc2VsZWN0aW9uO1xuICAgIGlmIChzZWwgaW5zdGFuY2VvZiBUZXh0U2VsZWN0aW9uKSB7XG4gICAgICAgIGlmIChtb2RzLmluZGV4T2YoXCJzXCIpID4gLTEpIHtcbiAgICAgICAgICAgIGxldCB7ICRoZWFkIH0gPSBzZWwsIG5vZGUgPSAkaGVhZC50ZXh0T2Zmc2V0ID8gbnVsbCA6IGRpciA8IDAgPyAkaGVhZC5ub2RlQmVmb3JlIDogJGhlYWQubm9kZUFmdGVyO1xuICAgICAgICAgICAgaWYgKCFub2RlIHx8IG5vZGUuaXNUZXh0IHx8ICFub2RlLmlzTGVhZilcbiAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgICAgICBsZXQgJG5ld0hlYWQgPSB2aWV3LnN0YXRlLmRvYy5yZXNvbHZlKCRoZWFkLnBvcyArIG5vZGUubm9kZVNpemUgKiAoZGlyIDwgMCA/IC0xIDogMSkpO1xuICAgICAgICAgICAgcmV0dXJuIGFwcGx5KHZpZXcsIG5ldyBUZXh0U2VsZWN0aW9uKHNlbC4kYW5jaG9yLCAkbmV3SGVhZCkpO1xuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYgKCFzZWwuZW1wdHkpIHtcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIGlmICh2aWV3LmVuZE9mVGV4dGJsb2NrKGRpciA+IDAgPyBcImZvcndhcmRcIiA6IFwiYmFja3dhcmRcIikpIHtcbiAgICAgICAgICAgIGxldCBuZXh0ID0gbW92ZVNlbGVjdGlvbkJsb2NrKHZpZXcuc3RhdGUsIGRpcik7XG4gICAgICAgICAgICBpZiAobmV4dCAmJiAobmV4dCBpbnN0YW5jZW9mIE5vZGVTZWxlY3Rpb24pKVxuICAgICAgICAgICAgICAgIHJldHVybiBhcHBseSh2aWV3LCBuZXh0KTtcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIGlmICghKG1hYyAmJiBtb2RzLmluZGV4T2YoXCJtXCIpID4gLTEpKSB7XG4gICAgICAgICAgICBsZXQgJGhlYWQgPSBzZWwuJGhlYWQsIG5vZGUgPSAkaGVhZC50ZXh0T2Zmc2V0ID8gbnVsbCA6IGRpciA8IDAgPyAkaGVhZC5ub2RlQmVmb3JlIDogJGhlYWQubm9kZUFmdGVyLCBkZXNjO1xuICAgICAgICAgICAgaWYgKCFub2RlIHx8IG5vZGUuaXNUZXh0KVxuICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgIGxldCBub2RlUG9zID0gZGlyIDwgMCA/ICRoZWFkLnBvcyAtIG5vZGUubm9kZVNpemUgOiAkaGVhZC5wb3M7XG4gICAgICAgICAgICBpZiAoIShub2RlLmlzQXRvbSB8fCAoZGVzYyA9IHZpZXcuZG9jVmlldy5kZXNjQXQobm9kZVBvcykpICYmICFkZXNjLmNvbnRlbnRET00pKVxuICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgIGlmIChOb2RlU2VsZWN0aW9uLmlzU2VsZWN0YWJsZShub2RlKSkge1xuICAgICAgICAgICAgICAgIHJldHVybiBhcHBseSh2aWV3LCBuZXcgTm9kZVNlbGVjdGlvbihkaXIgPCAwID8gdmlldy5zdGF0ZS5kb2MucmVzb2x2ZSgkaGVhZC5wb3MgLSBub2RlLm5vZGVTaXplKSA6ICRoZWFkKSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIGlmICh3ZWJraXQpIHtcbiAgICAgICAgICAgICAgICAvLyBDaHJvbWUgYW5kIFNhZmFyaSB3aWxsIGludHJvZHVjZSBleHRyYSBwb2ludGxlc3MgY3Vyc29yXG4gICAgICAgICAgICAgICAgLy8gcG9zaXRpb25zIGFyb3VuZCBpbmxpbmUgdW5lZGl0YWJsZSBub2Rlcywgc28gd2UgaGF2ZSB0b1xuICAgICAgICAgICAgICAgIC8vIHRha2Ugb3ZlciBhbmQgbW92ZSB0aGUgY3Vyc29yIHBhc3QgdGhlbSAoIzkzNylcbiAgICAgICAgICAgICAgICByZXR1cm4gYXBwbHkodmlldywgbmV3IFRleHRTZWxlY3Rpb24odmlldy5zdGF0ZS5kb2MucmVzb2x2ZShkaXIgPCAwID8gbm9kZVBvcyA6IG5vZGVQb3MgKyBub2RlLm5vZGVTaXplKSkpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuICAgIGVsc2UgaWYgKHNlbCBpbnN0YW5jZW9mIE5vZGVTZWxlY3Rpb24gJiYgc2VsLm5vZGUuaXNJbmxpbmUpIHtcbiAgICAgICAgcmV0dXJuIGFwcGx5KHZpZXcsIG5ldyBUZXh0U2VsZWN0aW9uKGRpciA+IDAgPyBzZWwuJHRvIDogc2VsLiRmcm9tKSk7XG4gICAgfVxuICAgIGVsc2Uge1xuICAgICAgICBsZXQgbmV4dCA9IG1vdmVTZWxlY3Rpb25CbG9jayh2aWV3LnN0YXRlLCBkaXIpO1xuICAgICAgICBpZiAobmV4dClcbiAgICAgICAgICAgIHJldHVybiBhcHBseSh2aWV3LCBuZXh0KTtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbn1cbmZ1bmN0aW9uIG5vZGVMZW4obm9kZSkge1xuICAgIHJldHVybiBub2RlLm5vZGVUeXBlID09IDMgPyBub2RlLm5vZGVWYWx1ZS5sZW5ndGggOiBub2RlLmNoaWxkTm9kZXMubGVuZ3RoO1xufVxuZnVuY3Rpb24gaXNJZ25vcmFibGUoZG9tLCBkaXIpIHtcbiAgICBsZXQgZGVzYyA9IGRvbS5wbVZpZXdEZXNjO1xuICAgIHJldHVybiBkZXNjICYmIGRlc2Muc2l6ZSA9PSAwICYmIChkaXIgPCAwIHx8IGRvbS5uZXh0U2libGluZyB8fCBkb20ubm9kZU5hbWUgIT0gXCJCUlwiKTtcbn1cbmZ1bmN0aW9uIHNraXBJZ25vcmVkTm9kZXModmlldywgZGlyKSB7XG4gICAgcmV0dXJuIGRpciA8IDAgPyBza2lwSWdub3JlZE5vZGVzQmVmb3JlKHZpZXcpIDogc2tpcElnbm9yZWROb2Rlc0FmdGVyKHZpZXcpO1xufVxuLy8gTWFrZSBzdXJlIHRoZSBjdXJzb3IgaXNuJ3QgZGlyZWN0bHkgYWZ0ZXIgb25lIG9yIG1vcmUgaWdub3JlZFxuLy8gbm9kZXMsIHdoaWNoIHdpbGwgY29uZnVzZSB0aGUgYnJvd3NlcidzIGN1cnNvciBtb3Rpb24gbG9naWMuXG5mdW5jdGlvbiBza2lwSWdub3JlZE5vZGVzQmVmb3JlKHZpZXcpIHtcbiAgICBsZXQgc2VsID0gdmlldy5kb21TZWxlY3Rpb25SYW5nZSgpO1xuICAgIGxldCBub2RlID0gc2VsLmZvY3VzTm9kZSwgb2Zmc2V0ID0gc2VsLmZvY3VzT2Zmc2V0O1xuICAgIGlmICghbm9kZSlcbiAgICAgICAgcmV0dXJuO1xuICAgIGxldCBtb3ZlTm9kZSwgbW92ZU9mZnNldCwgZm9yY2UgPSBmYWxzZTtcbiAgICAvLyBHZWNrbyB3aWxsIGRvIG9kZCB0aGluZ3Mgd2hlbiB0aGUgc2VsZWN0aW9uIGlzIGRpcmVjdGx5IGluIGZyb250XG4gICAgLy8gb2YgYSBub24tZWRpdGFibGUgbm9kZSwgc28gaW4gdGhhdCBjYXNlLCBtb3ZlIGl0IGludG8gdGhlIG5leHRcbiAgICAvLyBub2RlIGlmIHBvc3NpYmxlLiBJc3N1ZSBwcm9zZW1pcnJvci9wcm9zZW1pcnJvciM4MzIuXG4gICAgaWYgKGdlY2tvICYmIG5vZGUubm9kZVR5cGUgPT0gMSAmJiBvZmZzZXQgPCBub2RlTGVuKG5vZGUpICYmIGlzSWdub3JhYmxlKG5vZGUuY2hpbGROb2Rlc1tvZmZzZXRdLCAtMSkpXG4gICAgICAgIGZvcmNlID0gdHJ1ZTtcbiAgICBmb3IgKDs7KSB7XG4gICAgICAgIGlmIChvZmZzZXQgPiAwKSB7XG4gICAgICAgICAgICBpZiAobm9kZS5ub2RlVHlwZSAhPSAxKSB7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICBsZXQgYmVmb3JlID0gbm9kZS5jaGlsZE5vZGVzW29mZnNldCAtIDFdO1xuICAgICAgICAgICAgICAgIGlmIChpc0lnbm9yYWJsZShiZWZvcmUsIC0xKSkge1xuICAgICAgICAgICAgICAgICAgICBtb3ZlTm9kZSA9IG5vZGU7XG4gICAgICAgICAgICAgICAgICAgIG1vdmVPZmZzZXQgPSAtLW9mZnNldDtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgZWxzZSBpZiAoYmVmb3JlLm5vZGVUeXBlID09IDMpIHtcbiAgICAgICAgICAgICAgICAgICAgbm9kZSA9IGJlZm9yZTtcbiAgICAgICAgICAgICAgICAgICAgb2Zmc2V0ID0gbm9kZS5ub2RlVmFsdWUubGVuZ3RoO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBlbHNlXG4gICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYgKGlzQmxvY2tOb2RlKG5vZGUpKSB7XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIGxldCBwcmV2ID0gbm9kZS5wcmV2aW91c1NpYmxpbmc7XG4gICAgICAgICAgICB3aGlsZSAocHJldiAmJiBpc0lnbm9yYWJsZShwcmV2LCAtMSkpIHtcbiAgICAgICAgICAgICAgICBtb3ZlTm9kZSA9IG5vZGUucGFyZW50Tm9kZTtcbiAgICAgICAgICAgICAgICBtb3ZlT2Zmc2V0ID0gZG9tSW5kZXgocHJldik7XG4gICAgICAgICAgICAgICAgcHJldiA9IHByZXYucHJldmlvdXNTaWJsaW5nO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKCFwcmV2KSB7XG4gICAgICAgICAgICAgICAgbm9kZSA9IG5vZGUucGFyZW50Tm9kZTtcbiAgICAgICAgICAgICAgICBpZiAobm9kZSA9PSB2aWV3LmRvbSlcbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgb2Zmc2V0ID0gMDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgIG5vZGUgPSBwcmV2O1xuICAgICAgICAgICAgICAgIG9mZnNldCA9IG5vZGVMZW4obm9kZSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG4gICAgaWYgKGZvcmNlKVxuICAgICAgICBzZXRTZWxGb2N1cyh2aWV3LCBub2RlLCBvZmZzZXQpO1xuICAgIGVsc2UgaWYgKG1vdmVOb2RlKVxuICAgICAgICBzZXRTZWxGb2N1cyh2aWV3LCBtb3ZlTm9kZSwgbW92ZU9mZnNldCk7XG59XG4vLyBNYWtlIHN1cmUgdGhlIGN1cnNvciBpc24ndCBkaXJlY3RseSBiZWZvcmUgb25lIG9yIG1vcmUgaWdub3JlZFxuLy8gbm9kZXMuXG5mdW5jdGlvbiBza2lwSWdub3JlZE5vZGVzQWZ0ZXIodmlldykge1xuICAgIGxldCBzZWwgPSB2aWV3LmRvbVNlbGVjdGlvblJhbmdlKCk7XG4gICAgbGV0IG5vZGUgPSBzZWwuZm9jdXNOb2RlLCBvZmZzZXQgPSBzZWwuZm9jdXNPZmZzZXQ7XG4gICAgaWYgKCFub2RlKVxuICAgICAgICByZXR1cm47XG4gICAgbGV0IGxlbiA9IG5vZGVMZW4obm9kZSk7XG4gICAgbGV0IG1vdmVOb2RlLCBtb3ZlT2Zmc2V0O1xuICAgIGZvciAoOzspIHtcbiAgICAgICAgaWYgKG9mZnNldCA8IGxlbikge1xuICAgICAgICAgICAgaWYgKG5vZGUubm9kZVR5cGUgIT0gMSlcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIGxldCBhZnRlciA9IG5vZGUuY2hpbGROb2Rlc1tvZmZzZXRdO1xuICAgICAgICAgICAgaWYgKGlzSWdub3JhYmxlKGFmdGVyLCAxKSkge1xuICAgICAgICAgICAgICAgIG1vdmVOb2RlID0gbm9kZTtcbiAgICAgICAgICAgICAgICBtb3ZlT2Zmc2V0ID0gKytvZmZzZXQ7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlXG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAoaXNCbG9ja05vZGUobm9kZSkpIHtcbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgbGV0IG5leHQgPSBub2RlLm5leHRTaWJsaW5nO1xuICAgICAgICAgICAgd2hpbGUgKG5leHQgJiYgaXNJZ25vcmFibGUobmV4dCwgMSkpIHtcbiAgICAgICAgICAgICAgICBtb3ZlTm9kZSA9IG5leHQucGFyZW50Tm9kZTtcbiAgICAgICAgICAgICAgICBtb3ZlT2Zmc2V0ID0gZG9tSW5kZXgobmV4dCkgKyAxO1xuICAgICAgICAgICAgICAgIG5leHQgPSBuZXh0Lm5leHRTaWJsaW5nO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKCFuZXh0KSB7XG4gICAgICAgICAgICAgICAgbm9kZSA9IG5vZGUucGFyZW50Tm9kZTtcbiAgICAgICAgICAgICAgICBpZiAobm9kZSA9PSB2aWV3LmRvbSlcbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgb2Zmc2V0ID0gbGVuID0gMDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgIG5vZGUgPSBuZXh0O1xuICAgICAgICAgICAgICAgIG9mZnNldCA9IDA7XG4gICAgICAgICAgICAgICAgbGVuID0gbm9kZUxlbihub2RlKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cbiAgICBpZiAobW92ZU5vZGUpXG4gICAgICAgIHNldFNlbEZvY3VzKHZpZXcsIG1vdmVOb2RlLCBtb3ZlT2Zmc2V0KTtcbn1cbmZ1bmN0aW9uIGlzQmxvY2tOb2RlKGRvbSkge1xuICAgIGxldCBkZXNjID0gZG9tLnBtVmlld0Rlc2M7XG4gICAgcmV0dXJuIGRlc2MgJiYgZGVzYy5ub2RlICYmIGRlc2Mubm9kZS5pc0Jsb2NrO1xufVxuZnVuY3Rpb24gdGV4dE5vZGVBZnRlcihub2RlLCBvZmZzZXQpIHtcbiAgICB3aGlsZSAobm9kZSAmJiBvZmZzZXQgPT0gbm9kZS5jaGlsZE5vZGVzLmxlbmd0aCAmJiAhaGFzQmxvY2tEZXNjKG5vZGUpKSB7XG4gICAgICAgIG9mZnNldCA9IGRvbUluZGV4KG5vZGUpICsgMTtcbiAgICAgICAgbm9kZSA9IG5vZGUucGFyZW50Tm9kZTtcbiAgICB9XG4gICAgd2hpbGUgKG5vZGUgJiYgb2Zmc2V0IDwgbm9kZS5jaGlsZE5vZGVzLmxlbmd0aCkge1xuICAgICAgICBsZXQgbmV4dCA9IG5vZGUuY2hpbGROb2Rlc1tvZmZzZXRdO1xuICAgICAgICBpZiAobmV4dC5ub2RlVHlwZSA9PSAzKVxuICAgICAgICAgICAgcmV0dXJuIG5leHQ7XG4gICAgICAgIGlmIChuZXh0Lm5vZGVUeXBlID09IDEgJiYgbmV4dC5jb250ZW50RWRpdGFibGUgPT0gXCJmYWxzZVwiKVxuICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgIG5vZGUgPSBuZXh0O1xuICAgICAgICBvZmZzZXQgPSAwO1xuICAgIH1cbn1cbmZ1bmN0aW9uIHRleHROb2RlQmVmb3JlKG5vZGUsIG9mZnNldCkge1xuICAgIHdoaWxlIChub2RlICYmICFvZmZzZXQgJiYgIWhhc0Jsb2NrRGVzYyhub2RlKSkge1xuICAgICAgICBvZmZzZXQgPSBkb21JbmRleChub2RlKTtcbiAgICAgICAgbm9kZSA9IG5vZGUucGFyZW50Tm9kZTtcbiAgICB9XG4gICAgd2hpbGUgKG5vZGUgJiYgb2Zmc2V0KSB7XG4gICAgICAgIGxldCBuZXh0ID0gbm9kZS5jaGlsZE5vZGVzW29mZnNldCAtIDFdO1xuICAgICAgICBpZiAobmV4dC5ub2RlVHlwZSA9PSAzKVxuICAgICAgICAgICAgcmV0dXJuIG5leHQ7XG4gICAgICAgIGlmIChuZXh0Lm5vZGVUeXBlID09IDEgJiYgbmV4dC5jb250ZW50RWRpdGFibGUgPT0gXCJmYWxzZVwiKVxuICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgIG5vZGUgPSBuZXh0O1xuICAgICAgICBvZmZzZXQgPSBub2RlLmNoaWxkTm9kZXMubGVuZ3RoO1xuICAgIH1cbn1cbmZ1bmN0aW9uIHNldFNlbEZvY3VzKHZpZXcsIG5vZGUsIG9mZnNldCkge1xuICAgIGlmIChub2RlLm5vZGVUeXBlICE9IDMpIHtcbiAgICAgICAgbGV0IGJlZm9yZSwgYWZ0ZXI7XG4gICAgICAgIGlmIChhZnRlciA9IHRleHROb2RlQWZ0ZXIobm9kZSwgb2Zmc2V0KSkge1xuICAgICAgICAgICAgbm9kZSA9IGFmdGVyO1xuICAgICAgICAgICAgb2Zmc2V0ID0gMDtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIGlmIChiZWZvcmUgPSB0ZXh0Tm9kZUJlZm9yZShub2RlLCBvZmZzZXQpKSB7XG4gICAgICAgICAgICBub2RlID0gYmVmb3JlO1xuICAgICAgICAgICAgb2Zmc2V0ID0gYmVmb3JlLm5vZGVWYWx1ZS5sZW5ndGg7XG4gICAgICAgIH1cbiAgICB9XG4gICAgbGV0IHNlbCA9IHZpZXcuZG9tU2VsZWN0aW9uKCk7XG4gICAgaWYgKCFzZWwpXG4gICAgICAgIHJldHVybjtcbiAgICBpZiAoc2VsZWN0aW9uQ29sbGFwc2VkKHNlbCkpIHtcbiAgICAgICAgbGV0IHJhbmdlID0gZG9jdW1lbnQuY3JlYXRlUmFuZ2UoKTtcbiAgICAgICAgcmFuZ2Uuc2V0RW5kKG5vZGUsIG9mZnNldCk7XG4gICAgICAgIHJhbmdlLnNldFN0YXJ0KG5vZGUsIG9mZnNldCk7XG4gICAgICAgIHNlbC5yZW1vdmVBbGxSYW5nZXMoKTtcbiAgICAgICAgc2VsLmFkZFJhbmdlKHJhbmdlKTtcbiAgICB9XG4gICAgZWxzZSBpZiAoc2VsLmV4dGVuZCkge1xuICAgICAgICBzZWwuZXh0ZW5kKG5vZGUsIG9mZnNldCk7XG4gICAgfVxuICAgIHZpZXcuZG9tT2JzZXJ2ZXIuc2V0Q3VyU2VsZWN0aW9uKCk7XG4gICAgbGV0IHsgc3RhdGUgfSA9IHZpZXc7XG4gICAgLy8gSWYgbm8gc3RhdGUgdXBkYXRlIGVuZHMgdXAgaGFwcGVuaW5nLCByZXNldCB0aGUgc2VsZWN0aW9uLlxuICAgIHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgICBpZiAodmlldy5zdGF0ZSA9PSBzdGF0ZSlcbiAgICAgICAgICAgIHNlbGVjdGlvblRvRE9NKHZpZXcpO1xuICAgIH0sIDUwKTtcbn1cbmZ1bmN0aW9uIGZpbmREaXJlY3Rpb24odmlldywgcG9zKSB7XG4gICAgbGV0ICRwb3MgPSB2aWV3LnN0YXRlLmRvYy5yZXNvbHZlKHBvcyk7XG4gICAgaWYgKCEoY2hyb21lIHx8IHdpbmRvd3MpICYmICRwb3MucGFyZW50LmlubGluZUNvbnRlbnQpIHtcbiAgICAgICAgbGV0IGNvb3JkcyA9IHZpZXcuY29vcmRzQXRQb3MocG9zKTtcbiAgICAgICAgaWYgKHBvcyA+ICRwb3Muc3RhcnQoKSkge1xuICAgICAgICAgICAgbGV0IGJlZm9yZSA9IHZpZXcuY29vcmRzQXRQb3MocG9zIC0gMSk7XG4gICAgICAgICAgICBsZXQgbWlkID0gKGJlZm9yZS50b3AgKyBiZWZvcmUuYm90dG9tKSAvIDI7XG4gICAgICAgICAgICBpZiAobWlkID4gY29vcmRzLnRvcCAmJiBtaWQgPCBjb29yZHMuYm90dG9tICYmIE1hdGguYWJzKGJlZm9yZS5sZWZ0IC0gY29vcmRzLmxlZnQpID4gMSlcbiAgICAgICAgICAgICAgICByZXR1cm4gYmVmb3JlLmxlZnQgPCBjb29yZHMubGVmdCA/IFwibHRyXCIgOiBcInJ0bFwiO1xuICAgICAgICB9XG4gICAgICAgIGlmIChwb3MgPCAkcG9zLmVuZCgpKSB7XG4gICAgICAgICAgICBsZXQgYWZ0ZXIgPSB2aWV3LmNvb3Jkc0F0UG9zKHBvcyArIDEpO1xuICAgICAgICAgICAgbGV0IG1pZCA9IChhZnRlci50b3AgKyBhZnRlci5ib3R0b20pIC8gMjtcbiAgICAgICAgICAgIGlmIChtaWQgPiBjb29yZHMudG9wICYmIG1pZCA8IGNvb3Jkcy5ib3R0b20gJiYgTWF0aC5hYnMoYWZ0ZXIubGVmdCAtIGNvb3Jkcy5sZWZ0KSA+IDEpXG4gICAgICAgICAgICAgICAgcmV0dXJuIGFmdGVyLmxlZnQgPiBjb29yZHMubGVmdCA/IFwibHRyXCIgOiBcInJ0bFwiO1xuICAgICAgICB9XG4gICAgfVxuICAgIGxldCBjb21wdXRlZCA9IGdldENvbXB1dGVkU3R5bGUodmlldy5kb20pLmRpcmVjdGlvbjtcbiAgICByZXR1cm4gY29tcHV0ZWQgPT0gXCJydGxcIiA/IFwicnRsXCIgOiBcImx0clwiO1xufVxuLy8gQ2hlY2sgd2hldGhlciB2ZXJ0aWNhbCBzZWxlY3Rpb24gbW90aW9uIHdvdWxkIGludm9sdmUgbm9kZVxuLy8gc2VsZWN0aW9ucy4gSWYgc28sIGFwcGx5IGl0IChpZiBub3QsIHRoZSByZXN1bHQgaXMgbGVmdCB0byB0aGVcbi8vIGJyb3dzZXIpXG5mdW5jdGlvbiBzZWxlY3RWZXJ0aWNhbGx5KHZpZXcsIGRpciwgbW9kcykge1xuICAgIGxldCBzZWwgPSB2aWV3LnN0YXRlLnNlbGVjdGlvbjtcbiAgICBpZiAoc2VsIGluc3RhbmNlb2YgVGV4dFNlbGVjdGlvbiAmJiAhc2VsLmVtcHR5IHx8IG1vZHMuaW5kZXhPZihcInNcIikgPiAtMSlcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIGlmIChtYWMgJiYgbW9kcy5pbmRleE9mKFwibVwiKSA+IC0xKVxuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgbGV0IHsgJGZyb20sICR0byB9ID0gc2VsO1xuICAgIGlmICghJGZyb20ucGFyZW50LmlubGluZUNvbnRlbnQgfHwgdmlldy5lbmRPZlRleHRibG9jayhkaXIgPCAwID8gXCJ1cFwiIDogXCJkb3duXCIpKSB7XG4gICAgICAgIGxldCBuZXh0ID0gbW92ZVNlbGVjdGlvbkJsb2NrKHZpZXcuc3RhdGUsIGRpcik7XG4gICAgICAgIGlmIChuZXh0ICYmIChuZXh0IGluc3RhbmNlb2YgTm9kZVNlbGVjdGlvbikpXG4gICAgICAgICAgICByZXR1cm4gYXBwbHkodmlldywgbmV4dCk7XG4gICAgfVxuICAgIGlmICghJGZyb20ucGFyZW50LmlubGluZUNvbnRlbnQpIHtcbiAgICAgICAgbGV0IHNpZGUgPSBkaXIgPCAwID8gJGZyb20gOiAkdG87XG4gICAgICAgIGxldCBiZXlvbmQgPSBzZWwgaW5zdGFuY2VvZiBBbGxTZWxlY3Rpb24gPyBTZWxlY3Rpb24ubmVhcihzaWRlLCBkaXIpIDogU2VsZWN0aW9uLmZpbmRGcm9tKHNpZGUsIGRpcik7XG4gICAgICAgIHJldHVybiBiZXlvbmQgPyBhcHBseSh2aWV3LCBiZXlvbmQpIDogZmFsc2U7XG4gICAgfVxuICAgIHJldHVybiBmYWxzZTtcbn1cbmZ1bmN0aW9uIHN0b3BOYXRpdmVIb3Jpem9udGFsRGVsZXRlKHZpZXcsIGRpcikge1xuICAgIGlmICghKHZpZXcuc3RhdGUuc2VsZWN0aW9uIGluc3RhbmNlb2YgVGV4dFNlbGVjdGlvbikpXG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgIGxldCB7ICRoZWFkLCAkYW5jaG9yLCBlbXB0eSB9ID0gdmlldy5zdGF0ZS5zZWxlY3Rpb247XG4gICAgaWYgKCEkaGVhZC5zYW1lUGFyZW50KCRhbmNob3IpKVxuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICBpZiAoIWVtcHR5KVxuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgaWYgKHZpZXcuZW5kT2ZUZXh0YmxvY2soZGlyID4gMCA/IFwiZm9yd2FyZFwiIDogXCJiYWNrd2FyZFwiKSlcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgbGV0IG5leHROb2RlID0gISRoZWFkLnRleHRPZmZzZXQgJiYgKGRpciA8IDAgPyAkaGVhZC5ub2RlQmVmb3JlIDogJGhlYWQubm9kZUFmdGVyKTtcbiAgICBpZiAobmV4dE5vZGUgJiYgIW5leHROb2RlLmlzVGV4dCkge1xuICAgICAgICBsZXQgdHIgPSB2aWV3LnN0YXRlLnRyO1xuICAgICAgICBpZiAoZGlyIDwgMClcbiAgICAgICAgICAgIHRyLmRlbGV0ZSgkaGVhZC5wb3MgLSBuZXh0Tm9kZS5ub2RlU2l6ZSwgJGhlYWQucG9zKTtcbiAgICAgICAgZWxzZVxuICAgICAgICAgICAgdHIuZGVsZXRlKCRoZWFkLnBvcywgJGhlYWQucG9zICsgbmV4dE5vZGUubm9kZVNpemUpO1xuICAgICAgICB2aWV3LmRpc3BhdGNoKHRyKTtcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuICAgIHJldHVybiBmYWxzZTtcbn1cbmZ1bmN0aW9uIHN3aXRjaEVkaXRhYmxlKHZpZXcsIG5vZGUsIHN0YXRlKSB7XG4gICAgdmlldy5kb21PYnNlcnZlci5zdG9wKCk7XG4gICAgbm9kZS5jb250ZW50RWRpdGFibGUgPSBzdGF0ZTtcbiAgICB2aWV3LmRvbU9ic2VydmVyLnN0YXJ0KCk7XG59XG4vLyBJc3N1ZSAjODY3IC8gIzEwOTAgLyBodHRwczovL2J1Z3MuY2hyb21pdW0ub3JnL3AvY2hyb21pdW0vaXNzdWVzL2RldGFpbD9pZD05MDM4MjFcbi8vIEluIHdoaWNoIFNhZmFyaSAoYW5kIGF0IHNvbWUgcG9pbnQgaW4gdGhlIHBhc3QsIENocm9tZSkgZG9lcyByZWFsbHlcbi8vIHdyb25nIHRoaW5ncyB3aGVuIHRoZSBkb3duIGFycm93IGlzIHByZXNzZWQgd2hlbiB0aGUgY3Vyc29yIGlzXG4vLyBkaXJlY3RseSBhdCB0aGUgc3RhcnQgb2YgYSB0ZXh0YmxvY2sgYW5kIGhhcyBhbiB1bmVkaXRhYmxlIG5vZGVcbi8vIGFmdGVyIGl0XG5mdW5jdGlvbiBzYWZhcmlEb3duQXJyb3dCdWcodmlldykge1xuICAgIGlmICghc2FmYXJpIHx8IHZpZXcuc3RhdGUuc2VsZWN0aW9uLiRoZWFkLnBhcmVudE9mZnNldCA+IDApXG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICBsZXQgeyBmb2N1c05vZGUsIGZvY3VzT2Zmc2V0IH0gPSB2aWV3LmRvbVNlbGVjdGlvblJhbmdlKCk7XG4gICAgaWYgKGZvY3VzTm9kZSAmJiBmb2N1c05vZGUubm9kZVR5cGUgPT0gMSAmJiBmb2N1c09mZnNldCA9PSAwICYmXG4gICAgICAgIGZvY3VzTm9kZS5maXJzdENoaWxkICYmIGZvY3VzTm9kZS5maXJzdENoaWxkLmNvbnRlbnRFZGl0YWJsZSA9PSBcImZhbHNlXCIpIHtcbiAgICAgICAgbGV0IGNoaWxkID0gZm9jdXNOb2RlLmZpcnN0Q2hpbGQ7XG4gICAgICAgIHN3aXRjaEVkaXRhYmxlKHZpZXcsIGNoaWxkLCBcInRydWVcIik7XG4gICAgICAgIHNldFRpbWVvdXQoKCkgPT4gc3dpdGNoRWRpdGFibGUodmlldywgY2hpbGQsIFwiZmFsc2VcIiksIDIwKTtcbiAgICB9XG4gICAgcmV0dXJuIGZhbHNlO1xufVxuLy8gQSBiYWNrZHJvcCBrZXkgbWFwcGluZyB1c2VkIHRvIG1ha2Ugc3VyZSB3ZSBhbHdheXMgc3VwcHJlc3Mga2V5c1xuLy8gdGhhdCBoYXZlIGEgZGFuZ2Vyb3VzIGRlZmF1bHQgZWZmZWN0LCBldmVuIGlmIHRoZSBjb21tYW5kcyB0aGV5IGFyZVxuLy8gYm91bmQgdG8gcmV0dXJuIGZhbHNlLCBhbmQgdG8gbWFrZSBzdXJlIHRoYXQgY3Vyc29yLW1vdGlvbiBrZXlzXG4vLyBmaW5kIGEgY3Vyc29yIChhcyBvcHBvc2VkIHRvIGEgbm9kZSBzZWxlY3Rpb24pIHdoZW4gcHJlc3NlZC4gRm9yXG4vLyBjdXJzb3ItbW90aW9uIGtleXMsIHRoZSBjb2RlIGluIHRoZSBoYW5kbGVycyBhbHNvIHRha2VzIGNhcmUgb2Zcbi8vIGJsb2NrIHNlbGVjdGlvbnMuXG5mdW5jdGlvbiBnZXRNb2RzKGV2ZW50KSB7XG4gICAgbGV0IHJlc3VsdCA9IFwiXCI7XG4gICAgaWYgKGV2ZW50LmN0cmxLZXkpXG4gICAgICAgIHJlc3VsdCArPSBcImNcIjtcbiAgICBpZiAoZXZlbnQubWV0YUtleSlcbiAgICAgICAgcmVzdWx0ICs9IFwibVwiO1xuICAgIGlmIChldmVudC5hbHRLZXkpXG4gICAgICAgIHJlc3VsdCArPSBcImFcIjtcbiAgICBpZiAoZXZlbnQuc2hpZnRLZXkpXG4gICAgICAgIHJlc3VsdCArPSBcInNcIjtcbiAgICByZXR1cm4gcmVzdWx0O1xufVxuZnVuY3Rpb24gY2FwdHVyZUtleURvd24odmlldywgZXZlbnQpIHtcbiAgICBsZXQgY29kZSA9IGV2ZW50LmtleUNvZGUsIG1vZHMgPSBnZXRNb2RzKGV2ZW50KTtcbiAgICBpZiAoY29kZSA9PSA4IHx8IChtYWMgJiYgY29kZSA9PSA3MiAmJiBtb2RzID09IFwiY1wiKSkgeyAvLyBCYWNrc3BhY2UsIEN0cmwtaCBvbiBNYWNcbiAgICAgICAgcmV0dXJuIHN0b3BOYXRpdmVIb3Jpem9udGFsRGVsZXRlKHZpZXcsIC0xKSB8fCBza2lwSWdub3JlZE5vZGVzKHZpZXcsIC0xKTtcbiAgICB9XG4gICAgZWxzZSBpZiAoKGNvZGUgPT0gNDYgJiYgIWV2ZW50LnNoaWZ0S2V5KSB8fCAobWFjICYmIGNvZGUgPT0gNjggJiYgbW9kcyA9PSBcImNcIikpIHsgLy8gRGVsZXRlLCBDdHJsLWQgb24gTWFjXG4gICAgICAgIHJldHVybiBzdG9wTmF0aXZlSG9yaXpvbnRhbERlbGV0ZSh2aWV3LCAxKSB8fCBza2lwSWdub3JlZE5vZGVzKHZpZXcsIDEpO1xuICAgIH1cbiAgICBlbHNlIGlmIChjb2RlID09IDEzIHx8IGNvZGUgPT0gMjcpIHsgLy8gRW50ZXIsIEVzY1xuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG4gICAgZWxzZSBpZiAoY29kZSA9PSAzNyB8fCAobWFjICYmIGNvZGUgPT0gNjYgJiYgbW9kcyA9PSBcImNcIikpIHsgLy8gTGVmdCBhcnJvdywgQ3RybC1iIG9uIE1hY1xuICAgICAgICBsZXQgZGlyID0gY29kZSA9PSAzNyA/IChmaW5kRGlyZWN0aW9uKHZpZXcsIHZpZXcuc3RhdGUuc2VsZWN0aW9uLmZyb20pID09IFwibHRyXCIgPyAtMSA6IDEpIDogLTE7XG4gICAgICAgIHJldHVybiBzZWxlY3RIb3Jpem9udGFsbHkodmlldywgZGlyLCBtb2RzKSB8fCBza2lwSWdub3JlZE5vZGVzKHZpZXcsIGRpcik7XG4gICAgfVxuICAgIGVsc2UgaWYgKGNvZGUgPT0gMzkgfHwgKG1hYyAmJiBjb2RlID09IDcwICYmIG1vZHMgPT0gXCJjXCIpKSB7IC8vIFJpZ2h0IGFycm93LCBDdHJsLWYgb24gTWFjXG4gICAgICAgIGxldCBkaXIgPSBjb2RlID09IDM5ID8gKGZpbmREaXJlY3Rpb24odmlldywgdmlldy5zdGF0ZS5zZWxlY3Rpb24uZnJvbSkgPT0gXCJsdHJcIiA/IDEgOiAtMSkgOiAxO1xuICAgICAgICByZXR1cm4gc2VsZWN0SG9yaXpvbnRhbGx5KHZpZXcsIGRpciwgbW9kcykgfHwgc2tpcElnbm9yZWROb2Rlcyh2aWV3LCBkaXIpO1xuICAgIH1cbiAgICBlbHNlIGlmIChjb2RlID09IDM4IHx8IChtYWMgJiYgY29kZSA9PSA4MCAmJiBtb2RzID09IFwiY1wiKSkgeyAvLyBVcCBhcnJvdywgQ3RybC1wIG9uIE1hY1xuICAgICAgICByZXR1cm4gc2VsZWN0VmVydGljYWxseSh2aWV3LCAtMSwgbW9kcykgfHwgc2tpcElnbm9yZWROb2Rlcyh2aWV3LCAtMSk7XG4gICAgfVxuICAgIGVsc2UgaWYgKGNvZGUgPT0gNDAgfHwgKG1hYyAmJiBjb2RlID09IDc4ICYmIG1vZHMgPT0gXCJjXCIpKSB7IC8vIERvd24gYXJyb3csIEN0cmwtbiBvbiBNYWNcbiAgICAgICAgcmV0dXJuIHNhZmFyaURvd25BcnJvd0J1Zyh2aWV3KSB8fCBzZWxlY3RWZXJ0aWNhbGx5KHZpZXcsIDEsIG1vZHMpIHx8IHNraXBJZ25vcmVkTm9kZXModmlldywgMSk7XG4gICAgfVxuICAgIGVsc2UgaWYgKG1vZHMgPT0gKG1hYyA/IFwibVwiIDogXCJjXCIpICYmXG4gICAgICAgIChjb2RlID09IDY2IHx8IGNvZGUgPT0gNzMgfHwgY29kZSA9PSA4OSB8fCBjb2RlID09IDkwKSkgeyAvLyBNb2QtW2JpeXpdXG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cbiAgICByZXR1cm4gZmFsc2U7XG59XG5cbmZ1bmN0aW9uIHNlcmlhbGl6ZUZvckNsaXBib2FyZCh2aWV3LCBzbGljZSkge1xuICAgIHZpZXcuc29tZVByb3AoXCJ0cmFuc2Zvcm1Db3BpZWRcIiwgZiA9PiB7IHNsaWNlID0gZihzbGljZSwgdmlldyk7IH0pO1xuICAgIGxldCBjb250ZXh0ID0gW10sIHsgY29udGVudCwgb3BlblN0YXJ0LCBvcGVuRW5kIH0gPSBzbGljZTtcbiAgICB3aGlsZSAob3BlblN0YXJ0ID4gMSAmJiBvcGVuRW5kID4gMSAmJiBjb250ZW50LmNoaWxkQ291bnQgPT0gMSAmJiBjb250ZW50LmZpcnN0Q2hpbGQuY2hpbGRDb3VudCA9PSAxKSB7XG4gICAgICAgIG9wZW5TdGFydC0tO1xuICAgICAgICBvcGVuRW5kLS07XG4gICAgICAgIGxldCBub2RlID0gY29udGVudC5maXJzdENoaWxkO1xuICAgICAgICBjb250ZXh0LnB1c2gobm9kZS50eXBlLm5hbWUsIG5vZGUuYXR0cnMgIT0gbm9kZS50eXBlLmRlZmF1bHRBdHRycyA/IG5vZGUuYXR0cnMgOiBudWxsKTtcbiAgICAgICAgY29udGVudCA9IG5vZGUuY29udGVudDtcbiAgICB9XG4gICAgbGV0IHNlcmlhbGl6ZXIgPSB2aWV3LnNvbWVQcm9wKFwiY2xpcGJvYXJkU2VyaWFsaXplclwiKSB8fCBET01TZXJpYWxpemVyLmZyb21TY2hlbWEodmlldy5zdGF0ZS5zY2hlbWEpO1xuICAgIGxldCBkb2MgPSBkZXRhY2hlZERvYygpLCB3cmFwID0gZG9jLmNyZWF0ZUVsZW1lbnQoXCJkaXZcIik7XG4gICAgd3JhcC5hcHBlbmRDaGlsZChzZXJpYWxpemVyLnNlcmlhbGl6ZUZyYWdtZW50KGNvbnRlbnQsIHsgZG9jdW1lbnQ6IGRvYyB9KSk7XG4gICAgbGV0IGZpcnN0Q2hpbGQgPSB3cmFwLmZpcnN0Q2hpbGQsIG5lZWRzV3JhcCwgd3JhcHBlcnMgPSAwO1xuICAgIHdoaWxlIChmaXJzdENoaWxkICYmIGZpcnN0Q2hpbGQubm9kZVR5cGUgPT0gMSAmJiAobmVlZHNXcmFwID0gd3JhcE1hcFtmaXJzdENoaWxkLm5vZGVOYW1lLnRvTG93ZXJDYXNlKCldKSkge1xuICAgICAgICBmb3IgKGxldCBpID0gbmVlZHNXcmFwLmxlbmd0aCAtIDE7IGkgPj0gMDsgaS0tKSB7XG4gICAgICAgICAgICBsZXQgd3JhcHBlciA9IGRvYy5jcmVhdGVFbGVtZW50KG5lZWRzV3JhcFtpXSk7XG4gICAgICAgICAgICB3aGlsZSAod3JhcC5maXJzdENoaWxkKVxuICAgICAgICAgICAgICAgIHdyYXBwZXIuYXBwZW5kQ2hpbGQod3JhcC5maXJzdENoaWxkKTtcbiAgICAgICAgICAgIHdyYXAuYXBwZW5kQ2hpbGQod3JhcHBlcik7XG4gICAgICAgICAgICB3cmFwcGVycysrO1xuICAgICAgICB9XG4gICAgICAgIGZpcnN0Q2hpbGQgPSB3cmFwLmZpcnN0Q2hpbGQ7XG4gICAgfVxuICAgIGlmIChmaXJzdENoaWxkICYmIGZpcnN0Q2hpbGQubm9kZVR5cGUgPT0gMSlcbiAgICAgICAgZmlyc3RDaGlsZC5zZXRBdHRyaWJ1dGUoXCJkYXRhLXBtLXNsaWNlXCIsIGAke29wZW5TdGFydH0gJHtvcGVuRW5kfSR7d3JhcHBlcnMgPyBgIC0ke3dyYXBwZXJzfWAgOiBcIlwifSAke0pTT04uc3RyaW5naWZ5KGNvbnRleHQpfWApO1xuICAgIGxldCB0ZXh0ID0gdmlldy5zb21lUHJvcChcImNsaXBib2FyZFRleHRTZXJpYWxpemVyXCIsIGYgPT4gZihzbGljZSwgdmlldykpIHx8XG4gICAgICAgIHNsaWNlLmNvbnRlbnQudGV4dEJldHdlZW4oMCwgc2xpY2UuY29udGVudC5zaXplLCBcIlxcblxcblwiKTtcbiAgICByZXR1cm4geyBkb206IHdyYXAsIHRleHQsIHNsaWNlIH07XG59XG4vLyBSZWFkIGEgc2xpY2Ugb2YgY29udGVudCBmcm9tIHRoZSBjbGlwYm9hcmQgKG9yIGRyb3AgZGF0YSkuXG5mdW5jdGlvbiBwYXJzZUZyb21DbGlwYm9hcmQodmlldywgdGV4dCwgaHRtbCwgcGxhaW5UZXh0LCAkY29udGV4dCkge1xuICAgIGxldCBpbkNvZGUgPSAkY29udGV4dC5wYXJlbnQudHlwZS5zcGVjLmNvZGU7XG4gICAgbGV0IGRvbSwgc2xpY2U7XG4gICAgaWYgKCFodG1sICYmICF0ZXh0KVxuICAgICAgICByZXR1cm4gbnVsbDtcbiAgICBsZXQgYXNUZXh0ID0gISF0ZXh0ICYmIChwbGFpblRleHQgfHwgaW5Db2RlIHx8ICFodG1sKTtcbiAgICBpZiAoYXNUZXh0KSB7XG4gICAgICAgIHZpZXcuc29tZVByb3AoXCJ0cmFuc2Zvcm1QYXN0ZWRUZXh0XCIsIGYgPT4geyB0ZXh0ID0gZih0ZXh0LCBpbkNvZGUgfHwgcGxhaW5UZXh0LCB2aWV3KTsgfSk7XG4gICAgICAgIGlmIChpbkNvZGUpIHtcbiAgICAgICAgICAgIHNsaWNlID0gbmV3IFNsaWNlKEZyYWdtZW50LmZyb20odmlldy5zdGF0ZS5zY2hlbWEudGV4dCh0ZXh0LnJlcGxhY2UoL1xcclxcbj8vZywgXCJcXG5cIikpKSwgMCwgMCk7XG4gICAgICAgICAgICB2aWV3LnNvbWVQcm9wKFwidHJhbnNmb3JtUGFzdGVkXCIsIGYgPT4geyBzbGljZSA9IGYoc2xpY2UsIHZpZXcsIHRydWUpOyB9KTtcbiAgICAgICAgICAgIHJldHVybiBzbGljZTtcbiAgICAgICAgfVxuICAgICAgICBsZXQgcGFyc2VkID0gdmlldy5zb21lUHJvcChcImNsaXBib2FyZFRleHRQYXJzZXJcIiwgZiA9PiBmKHRleHQsICRjb250ZXh0LCBwbGFpblRleHQsIHZpZXcpKTtcbiAgICAgICAgaWYgKHBhcnNlZCkge1xuICAgICAgICAgICAgc2xpY2UgPSBwYXJzZWQ7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICBsZXQgbWFya3MgPSAkY29udGV4dC5tYXJrcygpO1xuICAgICAgICAgICAgbGV0IHsgc2NoZW1hIH0gPSB2aWV3LnN0YXRlLCBzZXJpYWxpemVyID0gRE9NU2VyaWFsaXplci5mcm9tU2NoZW1hKHNjaGVtYSk7XG4gICAgICAgICAgICBkb20gPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KFwiZGl2XCIpO1xuICAgICAgICAgICAgdGV4dC5zcGxpdCgvKD86XFxyXFxuP3xcXG4pKy8pLmZvckVhY2goYmxvY2sgPT4ge1xuICAgICAgICAgICAgICAgIGxldCBwID0gZG9tLmFwcGVuZENoaWxkKGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoXCJwXCIpKTtcbiAgICAgICAgICAgICAgICBpZiAoYmxvY2spXG4gICAgICAgICAgICAgICAgICAgIHAuYXBwZW5kQ2hpbGQoc2VyaWFsaXplci5zZXJpYWxpemVOb2RlKHNjaGVtYS50ZXh0KGJsb2NrLCBtYXJrcykpKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgfVxuICAgIGVsc2Uge1xuICAgICAgICB2aWV3LnNvbWVQcm9wKFwidHJhbnNmb3JtUGFzdGVkSFRNTFwiLCBmID0+IHsgaHRtbCA9IGYoaHRtbCwgdmlldyk7IH0pO1xuICAgICAgICBkb20gPSByZWFkSFRNTChodG1sKTtcbiAgICAgICAgaWYgKHdlYmtpdClcbiAgICAgICAgICAgIHJlc3RvcmVSZXBsYWNlZFNwYWNlcyhkb20pO1xuICAgIH1cbiAgICBsZXQgY29udGV4dE5vZGUgPSBkb20gJiYgZG9tLnF1ZXJ5U2VsZWN0b3IoXCJbZGF0YS1wbS1zbGljZV1cIik7XG4gICAgbGV0IHNsaWNlRGF0YSA9IGNvbnRleHROb2RlICYmIC9eKFxcZCspIChcXGQrKSg/OiAtKFxcZCspKT8gKC4qKS8uZXhlYyhjb250ZXh0Tm9kZS5nZXRBdHRyaWJ1dGUoXCJkYXRhLXBtLXNsaWNlXCIpIHx8IFwiXCIpO1xuICAgIGlmIChzbGljZURhdGEgJiYgc2xpY2VEYXRhWzNdKVxuICAgICAgICBmb3IgKGxldCBpID0gK3NsaWNlRGF0YVszXTsgaSA+IDA7IGktLSkge1xuICAgICAgICAgICAgbGV0IGNoaWxkID0gZG9tLmZpcnN0Q2hpbGQ7XG4gICAgICAgICAgICB3aGlsZSAoY2hpbGQgJiYgY2hpbGQubm9kZVR5cGUgIT0gMSlcbiAgICAgICAgICAgICAgICBjaGlsZCA9IGNoaWxkLm5leHRTaWJsaW5nO1xuICAgICAgICAgICAgaWYgKCFjaGlsZClcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIGRvbSA9IGNoaWxkO1xuICAgICAgICB9XG4gICAgaWYgKCFzbGljZSkge1xuICAgICAgICBsZXQgcGFyc2VyID0gdmlldy5zb21lUHJvcChcImNsaXBib2FyZFBhcnNlclwiKSB8fCB2aWV3LnNvbWVQcm9wKFwiZG9tUGFyc2VyXCIpIHx8IERPTVBhcnNlci5mcm9tU2NoZW1hKHZpZXcuc3RhdGUuc2NoZW1hKTtcbiAgICAgICAgc2xpY2UgPSBwYXJzZXIucGFyc2VTbGljZShkb20sIHtcbiAgICAgICAgICAgIHByZXNlcnZlV2hpdGVzcGFjZTogISEoYXNUZXh0IHx8IHNsaWNlRGF0YSksXG4gICAgICAgICAgICBjb250ZXh0OiAkY29udGV4dCxcbiAgICAgICAgICAgIHJ1bGVGcm9tTm9kZShkb20pIHtcbiAgICAgICAgICAgICAgICBpZiAoZG9tLm5vZGVOYW1lID09IFwiQlJcIiAmJiAhZG9tLm5leHRTaWJsaW5nICYmXG4gICAgICAgICAgICAgICAgICAgIGRvbS5wYXJlbnROb2RlICYmICFpbmxpbmVQYXJlbnRzLnRlc3QoZG9tLnBhcmVudE5vZGUubm9kZU5hbWUpKVxuICAgICAgICAgICAgICAgICAgICByZXR1cm4geyBpZ25vcmU6IHRydWUgfTtcbiAgICAgICAgICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgfVxuICAgIGlmIChzbGljZURhdGEpIHtcbiAgICAgICAgc2xpY2UgPSBhZGRDb250ZXh0KGNsb3NlU2xpY2Uoc2xpY2UsICtzbGljZURhdGFbMV0sICtzbGljZURhdGFbMl0pLCBzbGljZURhdGFbNF0pO1xuICAgIH1cbiAgICBlbHNlIHsgLy8gSFRNTCB3YXNuJ3QgY3JlYXRlZCBieSBQcm9zZU1pcnJvci4gTWFrZSBzdXJlIHRvcC1sZXZlbCBzaWJsaW5ncyBhcmUgY29oZXJlbnRcbiAgICAgICAgc2xpY2UgPSBTbGljZS5tYXhPcGVuKG5vcm1hbGl6ZVNpYmxpbmdzKHNsaWNlLmNvbnRlbnQsICRjb250ZXh0KSwgdHJ1ZSk7XG4gICAgICAgIGlmIChzbGljZS5vcGVuU3RhcnQgfHwgc2xpY2Uub3BlbkVuZCkge1xuICAgICAgICAgICAgbGV0IG9wZW5TdGFydCA9IDAsIG9wZW5FbmQgPSAwO1xuICAgICAgICAgICAgZm9yIChsZXQgbm9kZSA9IHNsaWNlLmNvbnRlbnQuZmlyc3RDaGlsZDsgb3BlblN0YXJ0IDwgc2xpY2Uub3BlblN0YXJ0ICYmICFub2RlLnR5cGUuc3BlYy5pc29sYXRpbmc7IG9wZW5TdGFydCsrLCBub2RlID0gbm9kZS5maXJzdENoaWxkKSB7IH1cbiAgICAgICAgICAgIGZvciAobGV0IG5vZGUgPSBzbGljZS5jb250ZW50Lmxhc3RDaGlsZDsgb3BlbkVuZCA8IHNsaWNlLm9wZW5FbmQgJiYgIW5vZGUudHlwZS5zcGVjLmlzb2xhdGluZzsgb3BlbkVuZCsrLCBub2RlID0gbm9kZS5sYXN0Q2hpbGQpIHsgfVxuICAgICAgICAgICAgc2xpY2UgPSBjbG9zZVNsaWNlKHNsaWNlLCBvcGVuU3RhcnQsIG9wZW5FbmQpO1xuICAgICAgICB9XG4gICAgfVxuICAgIHZpZXcuc29tZVByb3AoXCJ0cmFuc2Zvcm1QYXN0ZWRcIiwgZiA9PiB7IHNsaWNlID0gZihzbGljZSwgdmlldywgYXNUZXh0KTsgfSk7XG4gICAgcmV0dXJuIHNsaWNlO1xufVxuY29uc3QgaW5saW5lUGFyZW50cyA9IC9eKGF8YWJicnxhY3JvbnltfGJ8Y2l0ZXxjb2RlfGRlbHxlbXxpfGluc3xrYmR8bGFiZWx8b3V0cHV0fHF8cnVieXxzfHNhbXB8c3BhbnxzdHJvbmd8c3VifHN1cHx0aW1lfHV8dHR8dmFyKSQvaTtcbi8vIFRha2VzIGEgc2xpY2UgcGFyc2VkIHdpdGggcGFyc2VTbGljZSwgd2hpY2ggbWVhbnMgdGhlcmUgaGFzbid0IGJlZW5cbi8vIGFueSBjb250ZW50LWV4cHJlc3Npb24gY2hlY2tpbmcgZG9uZSBvbiB0aGUgdG9wIG5vZGVzLCB0cmllcyB0b1xuLy8gZmluZCBhIHBhcmVudCBub2RlIGluIHRoZSBjdXJyZW50IGNvbnRleHQgdGhhdCBtaWdodCBmaXQgdGhlIG5vZGVzLFxuLy8gYW5kIGlmIHN1Y2Nlc3NmdWwsIHJlYnVpbGRzIHRoZSBzbGljZSBzbyB0aGF0IGl0IGZpdHMgaW50byB0aGF0IHBhcmVudC5cbi8vXG4vLyBUaGlzIGFkZHJlc3NlcyB0aGUgcHJvYmxlbSB0aGF0IFRyYW5zZm9ybS5yZXBsYWNlIGV4cGVjdHMgYVxuLy8gY29oZXJlbnQgc2xpY2UsIGFuZCB3aWxsIGZhaWwgdG8gcGxhY2UgYSBzZXQgb2Ygc2libGluZ3MgdGhhdCBkb24ndFxuLy8gZml0IGFueXdoZXJlIGluIHRoZSBzY2hlbWEuXG5mdW5jdGlvbiBub3JtYWxpemVTaWJsaW5ncyhmcmFnbWVudCwgJGNvbnRleHQpIHtcbiAgICBpZiAoZnJhZ21lbnQuY2hpbGRDb3VudCA8IDIpXG4gICAgICAgIHJldHVybiBmcmFnbWVudDtcbiAgICBmb3IgKGxldCBkID0gJGNvbnRleHQuZGVwdGg7IGQgPj0gMDsgZC0tKSB7XG4gICAgICAgIGxldCBwYXJlbnQgPSAkY29udGV4dC5ub2RlKGQpO1xuICAgICAgICBsZXQgbWF0Y2ggPSBwYXJlbnQuY29udGVudE1hdGNoQXQoJGNvbnRleHQuaW5kZXgoZCkpO1xuICAgICAgICBsZXQgbGFzdFdyYXAsIHJlc3VsdCA9IFtdO1xuICAgICAgICBmcmFnbWVudC5mb3JFYWNoKG5vZGUgPT4ge1xuICAgICAgICAgICAgaWYgKCFyZXN1bHQpXG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgbGV0IHdyYXAgPSBtYXRjaC5maW5kV3JhcHBpbmcobm9kZS50eXBlKSwgaW5MYXN0O1xuICAgICAgICAgICAgaWYgKCF3cmFwKVxuICAgICAgICAgICAgICAgIHJldHVybiByZXN1bHQgPSBudWxsO1xuICAgICAgICAgICAgaWYgKGluTGFzdCA9IHJlc3VsdC5sZW5ndGggJiYgbGFzdFdyYXAubGVuZ3RoICYmIGFkZFRvU2libGluZyh3cmFwLCBsYXN0V3JhcCwgbm9kZSwgcmVzdWx0W3Jlc3VsdC5sZW5ndGggLSAxXSwgMCkpIHtcbiAgICAgICAgICAgICAgICByZXN1bHRbcmVzdWx0Lmxlbmd0aCAtIDFdID0gaW5MYXN0O1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgaWYgKHJlc3VsdC5sZW5ndGgpXG4gICAgICAgICAgICAgICAgICAgIHJlc3VsdFtyZXN1bHQubGVuZ3RoIC0gMV0gPSBjbG9zZVJpZ2h0KHJlc3VsdFtyZXN1bHQubGVuZ3RoIC0gMV0sIGxhc3RXcmFwLmxlbmd0aCk7XG4gICAgICAgICAgICAgICAgbGV0IHdyYXBwZWQgPSB3aXRoV3JhcHBlcnMobm9kZSwgd3JhcCk7XG4gICAgICAgICAgICAgICAgcmVzdWx0LnB1c2god3JhcHBlZCk7XG4gICAgICAgICAgICAgICAgbWF0Y2ggPSBtYXRjaC5tYXRjaFR5cGUod3JhcHBlZC50eXBlKTtcbiAgICAgICAgICAgICAgICBsYXN0V3JhcCA9IHdyYXA7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgICAgICBpZiAocmVzdWx0KVxuICAgICAgICAgICAgcmV0dXJuIEZyYWdtZW50LmZyb20ocmVzdWx0KTtcbiAgICB9XG4gICAgcmV0dXJuIGZyYWdtZW50O1xufVxuZnVuY3Rpb24gd2l0aFdyYXBwZXJzKG5vZGUsIHdyYXAsIGZyb20gPSAwKSB7XG4gICAgZm9yIChsZXQgaSA9IHdyYXAubGVuZ3RoIC0gMTsgaSA+PSBmcm9tOyBpLS0pXG4gICAgICAgIG5vZGUgPSB3cmFwW2ldLmNyZWF0ZShudWxsLCBGcmFnbWVudC5mcm9tKG5vZGUpKTtcbiAgICByZXR1cm4gbm9kZTtcbn1cbi8vIFVzZWQgdG8gZ3JvdXAgYWRqYWNlbnQgbm9kZXMgd3JhcHBlZCBpbiBzaW1pbGFyIHBhcmVudHMgYnlcbi8vIG5vcm1hbGl6ZVNpYmxpbmdzIGludG8gdGhlIHNhbWUgcGFyZW50IG5vZGVcbmZ1bmN0aW9uIGFkZFRvU2libGluZyh3cmFwLCBsYXN0V3JhcCwgbm9kZSwgc2libGluZywgZGVwdGgpIHtcbiAgICBpZiAoZGVwdGggPCB3cmFwLmxlbmd0aCAmJiBkZXB0aCA8IGxhc3RXcmFwLmxlbmd0aCAmJiB3cmFwW2RlcHRoXSA9PSBsYXN0V3JhcFtkZXB0aF0pIHtcbiAgICAgICAgbGV0IGlubmVyID0gYWRkVG9TaWJsaW5nKHdyYXAsIGxhc3RXcmFwLCBub2RlLCBzaWJsaW5nLmxhc3RDaGlsZCwgZGVwdGggKyAxKTtcbiAgICAgICAgaWYgKGlubmVyKVxuICAgICAgICAgICAgcmV0dXJuIHNpYmxpbmcuY29weShzaWJsaW5nLmNvbnRlbnQucmVwbGFjZUNoaWxkKHNpYmxpbmcuY2hpbGRDb3VudCAtIDEsIGlubmVyKSk7XG4gICAgICAgIGxldCBtYXRjaCA9IHNpYmxpbmcuY29udGVudE1hdGNoQXQoc2libGluZy5jaGlsZENvdW50KTtcbiAgICAgICAgaWYgKG1hdGNoLm1hdGNoVHlwZShkZXB0aCA9PSB3cmFwLmxlbmd0aCAtIDEgPyBub2RlLnR5cGUgOiB3cmFwW2RlcHRoICsgMV0pKVxuICAgICAgICAgICAgcmV0dXJuIHNpYmxpbmcuY29weShzaWJsaW5nLmNvbnRlbnQuYXBwZW5kKEZyYWdtZW50LmZyb20od2l0aFdyYXBwZXJzKG5vZGUsIHdyYXAsIGRlcHRoICsgMSkpKSk7XG4gICAgfVxufVxuZnVuY3Rpb24gY2xvc2VSaWdodChub2RlLCBkZXB0aCkge1xuICAgIGlmIChkZXB0aCA9PSAwKVxuICAgICAgICByZXR1cm4gbm9kZTtcbiAgICBsZXQgZnJhZ21lbnQgPSBub2RlLmNvbnRlbnQucmVwbGFjZUNoaWxkKG5vZGUuY2hpbGRDb3VudCAtIDEsIGNsb3NlUmlnaHQobm9kZS5sYXN0Q2hpbGQsIGRlcHRoIC0gMSkpO1xuICAgIGxldCBmaWxsID0gbm9kZS5jb250ZW50TWF0Y2hBdChub2RlLmNoaWxkQ291bnQpLmZpbGxCZWZvcmUoRnJhZ21lbnQuZW1wdHksIHRydWUpO1xuICAgIHJldHVybiBub2RlLmNvcHkoZnJhZ21lbnQuYXBwZW5kKGZpbGwpKTtcbn1cbmZ1bmN0aW9uIGNsb3NlUmFuZ2UoZnJhZ21lbnQsIHNpZGUsIGZyb20sIHRvLCBkZXB0aCwgb3BlbkVuZCkge1xuICAgIGxldCBub2RlID0gc2lkZSA8IDAgPyBmcmFnbWVudC5maXJzdENoaWxkIDogZnJhZ21lbnQubGFzdENoaWxkLCBpbm5lciA9IG5vZGUuY29udGVudDtcbiAgICBpZiAoZnJhZ21lbnQuY2hpbGRDb3VudCA+IDEpXG4gICAgICAgIG9wZW5FbmQgPSAwO1xuICAgIGlmIChkZXB0aCA8IHRvIC0gMSlcbiAgICAgICAgaW5uZXIgPSBjbG9zZVJhbmdlKGlubmVyLCBzaWRlLCBmcm9tLCB0bywgZGVwdGggKyAxLCBvcGVuRW5kKTtcbiAgICBpZiAoZGVwdGggPj0gZnJvbSlcbiAgICAgICAgaW5uZXIgPSBzaWRlIDwgMCA/IG5vZGUuY29udGVudE1hdGNoQXQoMCkuZmlsbEJlZm9yZShpbm5lciwgb3BlbkVuZCA8PSBkZXB0aCkuYXBwZW5kKGlubmVyKVxuICAgICAgICAgICAgOiBpbm5lci5hcHBlbmQobm9kZS5jb250ZW50TWF0Y2hBdChub2RlLmNoaWxkQ291bnQpLmZpbGxCZWZvcmUoRnJhZ21lbnQuZW1wdHksIHRydWUpKTtcbiAgICByZXR1cm4gZnJhZ21lbnQucmVwbGFjZUNoaWxkKHNpZGUgPCAwID8gMCA6IGZyYWdtZW50LmNoaWxkQ291bnQgLSAxLCBub2RlLmNvcHkoaW5uZXIpKTtcbn1cbmZ1bmN0aW9uIGNsb3NlU2xpY2Uoc2xpY2UsIG9wZW5TdGFydCwgb3BlbkVuZCkge1xuICAgIGlmIChvcGVuU3RhcnQgPCBzbGljZS5vcGVuU3RhcnQpXG4gICAgICAgIHNsaWNlID0gbmV3IFNsaWNlKGNsb3NlUmFuZ2Uoc2xpY2UuY29udGVudCwgLTEsIG9wZW5TdGFydCwgc2xpY2Uub3BlblN0YXJ0LCAwLCBzbGljZS5vcGVuRW5kKSwgb3BlblN0YXJ0LCBzbGljZS5vcGVuRW5kKTtcbiAgICBpZiAob3BlbkVuZCA8IHNsaWNlLm9wZW5FbmQpXG4gICAgICAgIHNsaWNlID0gbmV3IFNsaWNlKGNsb3NlUmFuZ2Uoc2xpY2UuY29udGVudCwgMSwgb3BlbkVuZCwgc2xpY2Uub3BlbkVuZCwgMCwgMCksIHNsaWNlLm9wZW5TdGFydCwgb3BlbkVuZCk7XG4gICAgcmV0dXJuIHNsaWNlO1xufVxuLy8gVHJpY2sgZnJvbSBqUXVlcnkgLS0gc29tZSBlbGVtZW50cyBtdXN0IGJlIHdyYXBwZWQgaW4gb3RoZXJcbi8vIGVsZW1lbnRzIGZvciBpbm5lckhUTUwgdG8gd29yay4gSS5lLiBpZiB5b3UgZG8gYGRpdi5pbm5lckhUTUwgPVxuLy8gXCI8dGQ+Li48L3RkPlwiYCB0aGUgdGFibGUgY2VsbHMgYXJlIGlnbm9yZWQuXG5jb25zdCB3cmFwTWFwID0ge1xuICAgIHRoZWFkOiBbXCJ0YWJsZVwiXSxcbiAgICB0Ym9keTogW1widGFibGVcIl0sXG4gICAgdGZvb3Q6IFtcInRhYmxlXCJdLFxuICAgIGNhcHRpb246IFtcInRhYmxlXCJdLFxuICAgIGNvbGdyb3VwOiBbXCJ0YWJsZVwiXSxcbiAgICBjb2w6IFtcInRhYmxlXCIsIFwiY29sZ3JvdXBcIl0sXG4gICAgdHI6IFtcInRhYmxlXCIsIFwidGJvZHlcIl0sXG4gICAgdGQ6IFtcInRhYmxlXCIsIFwidGJvZHlcIiwgXCJ0clwiXSxcbiAgICB0aDogW1widGFibGVcIiwgXCJ0Ym9keVwiLCBcInRyXCJdXG59O1xubGV0IF9kZXRhY2hlZERvYyA9IG51bGw7XG5mdW5jdGlvbiBkZXRhY2hlZERvYygpIHtcbiAgICByZXR1cm4gX2RldGFjaGVkRG9jIHx8IChfZGV0YWNoZWREb2MgPSBkb2N1bWVudC5pbXBsZW1lbnRhdGlvbi5jcmVhdGVIVE1MRG9jdW1lbnQoXCJ0aXRsZVwiKSk7XG59XG5sZXQgX3BvbGljeSA9IG51bGw7XG5mdW5jdGlvbiBtYXliZVdyYXBUcnVzdGVkKGh0bWwpIHtcbiAgICBsZXQgdHJ1c3RlZFR5cGVzID0gd2luZG93LnRydXN0ZWRUeXBlcztcbiAgICBpZiAoIXRydXN0ZWRUeXBlcylcbiAgICAgICAgcmV0dXJuIGh0bWw7XG4gICAgLy8gV2l0aCB0aGUgcmVxdWlyZS10cnVzdGVkLXR5cGVzLWZvciBDU1AsIENocm9tZSB3aWxsIGJsb2NrXG4gICAgLy8gaW5uZXJIVE1MLCBldmVuIG9uIGEgZGV0YWNoZWQgZG9jdW1lbnQuIFRoaXMgd3JhcHMgdGhlIHN0cmluZyBpblxuICAgIC8vIGEgd2F5IHRoYXQgbWFrZXMgdGhlIGJyb3dzZXIgYWxsb3cgdXMgdG8gdXNlIGl0cyBwYXJzZXIgYWdhaW4uXG4gICAgaWYgKCFfcG9saWN5KVxuICAgICAgICBfcG9saWN5ID0gdHJ1c3RlZFR5cGVzLmRlZmF1bHRQb2xpY3kgfHwgdHJ1c3RlZFR5cGVzLmNyZWF0ZVBvbGljeShcIlByb3NlTWlycm9yQ2xpcGJvYXJkXCIsIHsgY3JlYXRlSFRNTDogKHMpID0+IHMgfSk7XG4gICAgcmV0dXJuIF9wb2xpY3kuY3JlYXRlSFRNTChodG1sKTtcbn1cbmZ1bmN0aW9uIHJlYWRIVE1MKGh0bWwpIHtcbiAgICBsZXQgbWV0YXMgPSAvXihcXHMqPG1ldGEgW14+XSo+KSovLmV4ZWMoaHRtbCk7XG4gICAgaWYgKG1ldGFzKVxuICAgICAgICBodG1sID0gaHRtbC5zbGljZShtZXRhc1swXS5sZW5ndGgpO1xuICAgIGxldCBlbHQgPSBkZXRhY2hlZERvYygpLmNyZWF0ZUVsZW1lbnQoXCJkaXZcIik7XG4gICAgbGV0IGZpcnN0VGFnID0gLzwoW2Etel1bXj5cXHNdKykvaS5leGVjKGh0bWwpLCB3cmFwO1xuICAgIGlmICh3cmFwID0gZmlyc3RUYWcgJiYgd3JhcE1hcFtmaXJzdFRhZ1sxXS50b0xvd2VyQ2FzZSgpXSlcbiAgICAgICAgaHRtbCA9IHdyYXAubWFwKG4gPT4gXCI8XCIgKyBuICsgXCI+XCIpLmpvaW4oXCJcIikgKyBodG1sICsgd3JhcC5tYXAobiA9PiBcIjwvXCIgKyBuICsgXCI+XCIpLnJldmVyc2UoKS5qb2luKFwiXCIpO1xuICAgIGVsdC5pbm5lckhUTUwgPSBtYXliZVdyYXBUcnVzdGVkKGh0bWwpO1xuICAgIGlmICh3cmFwKVxuICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHdyYXAubGVuZ3RoOyBpKyspXG4gICAgICAgICAgICBlbHQgPSBlbHQucXVlcnlTZWxlY3Rvcih3cmFwW2ldKSB8fCBlbHQ7XG4gICAgcmV0dXJuIGVsdDtcbn1cbi8vIFdlYmtpdCBicm93c2VycyBkbyBzb21lIGhhcmQtdG8tcHJlZGljdCByZXBsYWNlbWVudCBvZiByZWd1bGFyXG4vLyBzcGFjZXMgd2l0aCBub24tYnJlYWtpbmcgc3BhY2VzIHdoZW4gcHV0dGluZyBjb250ZW50IG9uIHRoZVxuLy8gY2xpcGJvYXJkLiBUaGlzIHRyaWVzIHRvIGNvbnZlcnQgc3VjaCBub24tYnJlYWtpbmcgc3BhY2VzICh3aGljaFxuLy8gd2lsbCBiZSB3cmFwcGVkIGluIGEgcGxhaW4gc3BhbiBvbiBDaHJvbWUsIGEgc3BhbiB3aXRoIGNsYXNzXG4vLyBBcHBsZS1jb252ZXJ0ZWQtc3BhY2Ugb24gU2FmYXJpKSBiYWNrIHRvIHJlZ3VsYXIgc3BhY2VzLlxuZnVuY3Rpb24gcmVzdG9yZVJlcGxhY2VkU3BhY2VzKGRvbSkge1xuICAgIGxldCBub2RlcyA9IGRvbS5xdWVyeVNlbGVjdG9yQWxsKGNocm9tZSA/IFwic3Bhbjpub3QoW2NsYXNzXSk6bm90KFtzdHlsZV0pXCIgOiBcInNwYW4uQXBwbGUtY29udmVydGVkLXNwYWNlXCIpO1xuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgbm9kZXMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgbGV0IG5vZGUgPSBub2Rlc1tpXTtcbiAgICAgICAgaWYgKG5vZGUuY2hpbGROb2Rlcy5sZW5ndGggPT0gMSAmJiBub2RlLnRleHRDb250ZW50ID09IFwiXFx1MDBhMFwiICYmIG5vZGUucGFyZW50Tm9kZSlcbiAgICAgICAgICAgIG5vZGUucGFyZW50Tm9kZS5yZXBsYWNlQ2hpbGQoZG9tLm93bmVyRG9jdW1lbnQuY3JlYXRlVGV4dE5vZGUoXCIgXCIpLCBub2RlKTtcbiAgICB9XG59XG5mdW5jdGlvbiBhZGRDb250ZXh0KHNsaWNlLCBjb250ZXh0KSB7XG4gICAgaWYgKCFzbGljZS5zaXplKVxuICAgICAgICByZXR1cm4gc2xpY2U7XG4gICAgbGV0IHNjaGVtYSA9IHNsaWNlLmNvbnRlbnQuZmlyc3RDaGlsZC50eXBlLnNjaGVtYSwgYXJyYXk7XG4gICAgdHJ5IHtcbiAgICAgICAgYXJyYXkgPSBKU09OLnBhcnNlKGNvbnRleHQpO1xuICAgIH1cbiAgICBjYXRjaCAoZSkge1xuICAgICAgICByZXR1cm4gc2xpY2U7XG4gICAgfVxuICAgIGxldCB7IGNvbnRlbnQsIG9wZW5TdGFydCwgb3BlbkVuZCB9ID0gc2xpY2U7XG4gICAgZm9yIChsZXQgaSA9IGFycmF5Lmxlbmd0aCAtIDI7IGkgPj0gMDsgaSAtPSAyKSB7XG4gICAgICAgIGxldCB0eXBlID0gc2NoZW1hLm5vZGVzW2FycmF5W2ldXTtcbiAgICAgICAgaWYgKCF0eXBlIHx8IHR5cGUuaGFzUmVxdWlyZWRBdHRycygpKVxuICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgIGNvbnRlbnQgPSBGcmFnbWVudC5mcm9tKHR5cGUuY3JlYXRlKGFycmF5W2kgKyAxXSwgY29udGVudCkpO1xuICAgICAgICBvcGVuU3RhcnQrKztcbiAgICAgICAgb3BlbkVuZCsrO1xuICAgIH1cbiAgICByZXR1cm4gbmV3IFNsaWNlKGNvbnRlbnQsIG9wZW5TdGFydCwgb3BlbkVuZCk7XG59XG5cbi8vIEEgY29sbGVjdGlvbiBvZiBET00gZXZlbnRzIHRoYXQgb2NjdXIgd2l0aGluIHRoZSBlZGl0b3IsIGFuZCBjYWxsYmFjayBmdW5jdGlvbnNcbi8vIHRvIGludm9rZSB3aGVuIHRoZSBldmVudCBmaXJlcy5cbmNvbnN0IGhhbmRsZXJzID0ge307XG5jb25zdCBlZGl0SGFuZGxlcnMgPSB7fTtcbmNvbnN0IHBhc3NpdmVIYW5kbGVycyA9IHsgdG91Y2hzdGFydDogdHJ1ZSwgdG91Y2htb3ZlOiB0cnVlIH07XG5jbGFzcyBJbnB1dFN0YXRlIHtcbiAgICBjb25zdHJ1Y3RvcigpIHtcbiAgICAgICAgdGhpcy5zaGlmdEtleSA9IGZhbHNlO1xuICAgICAgICB0aGlzLm1vdXNlRG93biA9IG51bGw7XG4gICAgICAgIHRoaXMubGFzdEtleUNvZGUgPSBudWxsO1xuICAgICAgICB0aGlzLmxhc3RLZXlDb2RlVGltZSA9IDA7XG4gICAgICAgIHRoaXMubGFzdENsaWNrID0geyB0aW1lOiAwLCB4OiAwLCB5OiAwLCB0eXBlOiBcIlwiLCBidXR0b246IDAgfTtcbiAgICAgICAgdGhpcy5sYXN0U2VsZWN0aW9uT3JpZ2luID0gbnVsbDtcbiAgICAgICAgdGhpcy5sYXN0U2VsZWN0aW9uVGltZSA9IDA7XG4gICAgICAgIHRoaXMubGFzdElPU0VudGVyID0gMDtcbiAgICAgICAgdGhpcy5sYXN0SU9TRW50ZXJGYWxsYmFja1RpbWVvdXQgPSAtMTtcbiAgICAgICAgdGhpcy5sYXN0Rm9jdXMgPSAwO1xuICAgICAgICB0aGlzLmxhc3RUb3VjaCA9IDA7XG4gICAgICAgIHRoaXMubGFzdENocm9tZURlbGV0ZSA9IDA7XG4gICAgICAgIHRoaXMuY29tcG9zaW5nID0gZmFsc2U7XG4gICAgICAgIHRoaXMuY29tcG9zaXRpb25Ob2RlID0gbnVsbDtcbiAgICAgICAgdGhpcy5jb21wb3NpbmdUaW1lb3V0ID0gLTE7XG4gICAgICAgIHRoaXMuY29tcG9zaXRpb25Ob2RlcyA9IFtdO1xuICAgICAgICB0aGlzLmNvbXBvc2l0aW9uRW5kZWRBdCA9IC0yZTg7XG4gICAgICAgIHRoaXMuY29tcG9zaXRpb25JRCA9IDE7XG4gICAgICAgIHRoaXMuYmFkU2FmYXJpQ29tcG9zaXRpb24gPSBmYWxzZTtcbiAgICAgICAgLy8gU2V0IHRvIGEgY29tcG9zaXRpb24gSUQgd2hlbiB0aGVyZSBhcmUgcGVuZGluZyBjaGFuZ2VzIGF0IGNvbXBvc2l0aW9uZW5kXG4gICAgICAgIHRoaXMuY29tcG9zaXRpb25QZW5kaW5nQ2hhbmdlcyA9IDA7XG4gICAgICAgIHRoaXMuZG9tQ2hhbmdlQ291bnQgPSAwO1xuICAgICAgICB0aGlzLmV2ZW50SGFuZGxlcnMgPSBPYmplY3QuY3JlYXRlKG51bGwpO1xuICAgICAgICB0aGlzLmhpZGVTZWxlY3Rpb25HdWFyZCA9IG51bGw7XG4gICAgfVxufVxuZnVuY3Rpb24gaW5pdElucHV0KHZpZXcpIHtcbiAgICBmb3IgKGxldCBldmVudCBpbiBoYW5kbGVycykge1xuICAgICAgICBsZXQgaGFuZGxlciA9IGhhbmRsZXJzW2V2ZW50XTtcbiAgICAgICAgdmlldy5kb20uYWRkRXZlbnRMaXN0ZW5lcihldmVudCwgdmlldy5pbnB1dC5ldmVudEhhbmRsZXJzW2V2ZW50XSA9IChldmVudCkgPT4ge1xuICAgICAgICAgICAgaWYgKGV2ZW50QmVsb25nc1RvVmlldyh2aWV3LCBldmVudCkgJiYgIXJ1bkN1c3RvbUhhbmRsZXIodmlldywgZXZlbnQpICYmXG4gICAgICAgICAgICAgICAgKHZpZXcuZWRpdGFibGUgfHwgIShldmVudC50eXBlIGluIGVkaXRIYW5kbGVycykpKVxuICAgICAgICAgICAgICAgIGhhbmRsZXIodmlldywgZXZlbnQpO1xuICAgICAgICB9LCBwYXNzaXZlSGFuZGxlcnNbZXZlbnRdID8geyBwYXNzaXZlOiB0cnVlIH0gOiB1bmRlZmluZWQpO1xuICAgIH1cbiAgICAvLyBPbiBTYWZhcmksIGZvciByZWFzb25zIGJleW9uZCBteSB1bmRlcnN0YW5kaW5nLCBhZGRpbmcgYW4gaW5wdXRcbiAgICAvLyBldmVudCBoYW5kbGVyIG1ha2VzIGFuIGlzc3VlIHdoZXJlIHRoZSBjb21wb3NpdGlvbiB2YW5pc2hlcyB3aGVuXG4gICAgLy8geW91IHByZXNzIGVudGVyIGdvIGF3YXkuXG4gICAgaWYgKHNhZmFyaSlcbiAgICAgICAgdmlldy5kb20uYWRkRXZlbnRMaXN0ZW5lcihcImlucHV0XCIsICgpID0+IG51bGwpO1xuICAgIGVuc3VyZUxpc3RlbmVycyh2aWV3KTtcbn1cbmZ1bmN0aW9uIHNldFNlbGVjdGlvbk9yaWdpbih2aWV3LCBvcmlnaW4pIHtcbiAgICB2aWV3LmlucHV0Lmxhc3RTZWxlY3Rpb25PcmlnaW4gPSBvcmlnaW47XG4gICAgdmlldy5pbnB1dC5sYXN0U2VsZWN0aW9uVGltZSA9IERhdGUubm93KCk7XG59XG5mdW5jdGlvbiBkZXN0cm95SW5wdXQodmlldykge1xuICAgIHZpZXcuZG9tT2JzZXJ2ZXIuc3RvcCgpO1xuICAgIGZvciAobGV0IHR5cGUgaW4gdmlldy5pbnB1dC5ldmVudEhhbmRsZXJzKVxuICAgICAgICB2aWV3LmRvbS5yZW1vdmVFdmVudExpc3RlbmVyKHR5cGUsIHZpZXcuaW5wdXQuZXZlbnRIYW5kbGVyc1t0eXBlXSk7XG4gICAgY2xlYXJUaW1lb3V0KHZpZXcuaW5wdXQuY29tcG9zaW5nVGltZW91dCk7XG4gICAgY2xlYXJUaW1lb3V0KHZpZXcuaW5wdXQubGFzdElPU0VudGVyRmFsbGJhY2tUaW1lb3V0KTtcbn1cbmZ1bmN0aW9uIGVuc3VyZUxpc3RlbmVycyh2aWV3KSB7XG4gICAgdmlldy5zb21lUHJvcChcImhhbmRsZURPTUV2ZW50c1wiLCBjdXJyZW50SGFuZGxlcnMgPT4ge1xuICAgICAgICBmb3IgKGxldCB0eXBlIGluIGN1cnJlbnRIYW5kbGVycylcbiAgICAgICAgICAgIGlmICghdmlldy5pbnB1dC5ldmVudEhhbmRsZXJzW3R5cGVdKVxuICAgICAgICAgICAgICAgIHZpZXcuZG9tLmFkZEV2ZW50TGlzdGVuZXIodHlwZSwgdmlldy5pbnB1dC5ldmVudEhhbmRsZXJzW3R5cGVdID0gZXZlbnQgPT4gcnVuQ3VzdG9tSGFuZGxlcih2aWV3LCBldmVudCkpO1xuICAgIH0pO1xufVxuZnVuY3Rpb24gcnVuQ3VzdG9tSGFuZGxlcih2aWV3LCBldmVudCkge1xuICAgIHJldHVybiB2aWV3LnNvbWVQcm9wKFwiaGFuZGxlRE9NRXZlbnRzXCIsIGhhbmRsZXJzID0+IHtcbiAgICAgICAgbGV0IGhhbmRsZXIgPSBoYW5kbGVyc1tldmVudC50eXBlXTtcbiAgICAgICAgcmV0dXJuIGhhbmRsZXIgPyBoYW5kbGVyKHZpZXcsIGV2ZW50KSB8fCBldmVudC5kZWZhdWx0UHJldmVudGVkIDogZmFsc2U7XG4gICAgfSk7XG59XG5mdW5jdGlvbiBldmVudEJlbG9uZ3NUb1ZpZXcodmlldywgZXZlbnQpIHtcbiAgICBpZiAoIWV2ZW50LmJ1YmJsZXMpXG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgIGlmIChldmVudC5kZWZhdWx0UHJldmVudGVkKVxuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgZm9yIChsZXQgbm9kZSA9IGV2ZW50LnRhcmdldDsgbm9kZSAhPSB2aWV3LmRvbTsgbm9kZSA9IG5vZGUucGFyZW50Tm9kZSlcbiAgICAgICAgaWYgKCFub2RlIHx8IG5vZGUubm9kZVR5cGUgPT0gMTEgfHxcbiAgICAgICAgICAgIChub2RlLnBtVmlld0Rlc2MgJiYgbm9kZS5wbVZpZXdEZXNjLnN0b3BFdmVudChldmVudCkpKVxuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIHJldHVybiB0cnVlO1xufVxuZnVuY3Rpb24gZGlzcGF0Y2hFdmVudCh2aWV3LCBldmVudCkge1xuICAgIGlmICghcnVuQ3VzdG9tSGFuZGxlcih2aWV3LCBldmVudCkgJiYgaGFuZGxlcnNbZXZlbnQudHlwZV0gJiZcbiAgICAgICAgKHZpZXcuZWRpdGFibGUgfHwgIShldmVudC50eXBlIGluIGVkaXRIYW5kbGVycykpKVxuICAgICAgICBoYW5kbGVyc1tldmVudC50eXBlXSh2aWV3LCBldmVudCk7XG59XG5lZGl0SGFuZGxlcnMua2V5ZG93biA9ICh2aWV3LCBfZXZlbnQpID0+IHtcbiAgICBsZXQgZXZlbnQgPSBfZXZlbnQ7XG4gICAgdmlldy5pbnB1dC5zaGlmdEtleSA9IGV2ZW50LmtleUNvZGUgPT0gMTYgfHwgZXZlbnQuc2hpZnRLZXk7XG4gICAgaWYgKGluT3JOZWFyQ29tcG9zaXRpb24odmlldywgZXZlbnQpKVxuICAgICAgICByZXR1cm47XG4gICAgdmlldy5pbnB1dC5sYXN0S2V5Q29kZSA9IGV2ZW50LmtleUNvZGU7XG4gICAgdmlldy5pbnB1dC5sYXN0S2V5Q29kZVRpbWUgPSBEYXRlLm5vdygpO1xuICAgIC8vIFN1cHByZXNzIGVudGVyIGtleSBldmVudHMgb24gQ2hyb21lIEFuZHJvaWQsIGJlY2F1c2UgdGhvc2UgdGVuZFxuICAgIC8vIHRvIGJlIHBhcnQgb2YgYSBjb25mdXNlZCBzZXF1ZW5jZSBvZiBjb21wb3NpdGlvbiBldmVudHMgZmlyZWQsXG4gICAgLy8gYW5kIGhhbmRsaW5nIHRoZW0gZWFnZXJseSB0ZW5kcyB0byBjb3JydXB0IHRoZSBpbnB1dC5cbiAgICBpZiAoYW5kcm9pZCAmJiBjaHJvbWUgJiYgZXZlbnQua2V5Q29kZSA9PSAxMylcbiAgICAgICAgcmV0dXJuO1xuICAgIGlmIChldmVudC5rZXlDb2RlICE9IDIyOSlcbiAgICAgICAgdmlldy5kb21PYnNlcnZlci5mb3JjZUZsdXNoKCk7XG4gICAgLy8gT24gaU9TLCBpZiB3ZSBwcmV2ZW50RGVmYXVsdCBlbnRlciBrZXkgcHJlc3NlcywgdGhlIHZpcnR1YWxcbiAgICAvLyBrZXlib2FyZCBnZXRzIGNvbmZ1c2VkLiBTbyB0aGUgaGFjayBoZXJlIGlzIHRvIHNldCBhIGZsYWcgdGhhdFxuICAgIC8vIG1ha2VzIHRoZSBET00gY2hhbmdlIGNvZGUgcmVjb2duaXplIHRoYXQgd2hhdCBqdXN0IGhhcHBlbnMgc2hvdWxkXG4gICAgLy8gYmUgcmVwbGFjZWQgYnkgd2hhdGV2ZXIgdGhlIEVudGVyIGtleSBoYW5kbGVycyBkby5cbiAgICBpZiAoaW9zICYmIGV2ZW50LmtleUNvZGUgPT0gMTMgJiYgIWV2ZW50LmN0cmxLZXkgJiYgIWV2ZW50LmFsdEtleSAmJiAhZXZlbnQubWV0YUtleSkge1xuICAgICAgICBsZXQgbm93ID0gRGF0ZS5ub3coKTtcbiAgICAgICAgdmlldy5pbnB1dC5sYXN0SU9TRW50ZXIgPSBub3c7XG4gICAgICAgIHZpZXcuaW5wdXQubGFzdElPU0VudGVyRmFsbGJhY2tUaW1lb3V0ID0gc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICAgICAgICBpZiAodmlldy5pbnB1dC5sYXN0SU9TRW50ZXIgPT0gbm93KSB7XG4gICAgICAgICAgICAgICAgdmlldy5zb21lUHJvcChcImhhbmRsZUtleURvd25cIiwgZiA9PiBmKHZpZXcsIGtleUV2ZW50KDEzLCBcIkVudGVyXCIpKSk7XG4gICAgICAgICAgICAgICAgdmlldy5pbnB1dC5sYXN0SU9TRW50ZXIgPSAwO1xuICAgICAgICAgICAgfVxuICAgICAgICB9LCAyMDApO1xuICAgIH1cbiAgICBlbHNlIGlmICh2aWV3LnNvbWVQcm9wKFwiaGFuZGxlS2V5RG93blwiLCBmID0+IGYodmlldywgZXZlbnQpKSB8fCBjYXB0dXJlS2V5RG93bih2aWV3LCBldmVudCkpIHtcbiAgICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICB9XG4gICAgZWxzZSB7XG4gICAgICAgIHNldFNlbGVjdGlvbk9yaWdpbih2aWV3LCBcImtleVwiKTtcbiAgICB9XG59O1xuZWRpdEhhbmRsZXJzLmtleXVwID0gKHZpZXcsIGV2ZW50KSA9PiB7XG4gICAgaWYgKGV2ZW50LmtleUNvZGUgPT0gMTYpXG4gICAgICAgIHZpZXcuaW5wdXQuc2hpZnRLZXkgPSBmYWxzZTtcbn07XG5lZGl0SGFuZGxlcnMua2V5cHJlc3MgPSAodmlldywgX2V2ZW50KSA9PiB7XG4gICAgbGV0IGV2ZW50ID0gX2V2ZW50O1xuICAgIGlmIChpbk9yTmVhckNvbXBvc2l0aW9uKHZpZXcsIGV2ZW50KSB8fCAhZXZlbnQuY2hhckNvZGUgfHxcbiAgICAgICAgZXZlbnQuY3RybEtleSAmJiAhZXZlbnQuYWx0S2V5IHx8IG1hYyAmJiBldmVudC5tZXRhS2V5KVxuICAgICAgICByZXR1cm47XG4gICAgaWYgKHZpZXcuc29tZVByb3AoXCJoYW5kbGVLZXlQcmVzc1wiLCBmID0+IGYodmlldywgZXZlbnQpKSkge1xuICAgICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICByZXR1cm47XG4gICAgfVxuICAgIGxldCBzZWwgPSB2aWV3LnN0YXRlLnNlbGVjdGlvbjtcbiAgICBpZiAoIShzZWwgaW5zdGFuY2VvZiBUZXh0U2VsZWN0aW9uKSB8fCAhc2VsLiRmcm9tLnNhbWVQYXJlbnQoc2VsLiR0bykpIHtcbiAgICAgICAgbGV0IHRleHQgPSBTdHJpbmcuZnJvbUNoYXJDb2RlKGV2ZW50LmNoYXJDb2RlKTtcbiAgICAgICAgbGV0IGRlZmx0ID0gKCkgPT4gdmlldy5zdGF0ZS50ci5pbnNlcnRUZXh0KHRleHQpLnNjcm9sbEludG9WaWV3KCk7XG4gICAgICAgIGlmICghL1tcXHJcXG5dLy50ZXN0KHRleHQpICYmICF2aWV3LnNvbWVQcm9wKFwiaGFuZGxlVGV4dElucHV0XCIsIGYgPT4gZih2aWV3LCBzZWwuJGZyb20ucG9zLCBzZWwuJHRvLnBvcywgdGV4dCwgZGVmbHQpKSlcbiAgICAgICAgICAgIHZpZXcuZGlzcGF0Y2goZGVmbHQoKSk7XG4gICAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgfVxufTtcbmZ1bmN0aW9uIGV2ZW50Q29vcmRzKGV2ZW50KSB7IHJldHVybiB7IGxlZnQ6IGV2ZW50LmNsaWVudFgsIHRvcDogZXZlbnQuY2xpZW50WSB9OyB9XG5mdW5jdGlvbiBpc05lYXIoZXZlbnQsIGNsaWNrKSB7XG4gICAgbGV0IGR4ID0gY2xpY2sueCAtIGV2ZW50LmNsaWVudFgsIGR5ID0gY2xpY2sueSAtIGV2ZW50LmNsaWVudFk7XG4gICAgcmV0dXJuIGR4ICogZHggKyBkeSAqIGR5IDwgMTAwO1xufVxuZnVuY3Rpb24gcnVuSGFuZGxlck9uQ29udGV4dCh2aWV3LCBwcm9wTmFtZSwgcG9zLCBpbnNpZGUsIGV2ZW50KSB7XG4gICAgaWYgKGluc2lkZSA9PSAtMSlcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIGxldCAkcG9zID0gdmlldy5zdGF0ZS5kb2MucmVzb2x2ZShpbnNpZGUpO1xuICAgIGZvciAobGV0IGkgPSAkcG9zLmRlcHRoICsgMTsgaSA+IDA7IGktLSkge1xuICAgICAgICBpZiAodmlldy5zb21lUHJvcChwcm9wTmFtZSwgZiA9PiBpID4gJHBvcy5kZXB0aCA/IGYodmlldywgcG9zLCAkcG9zLm5vZGVBZnRlciwgJHBvcy5iZWZvcmUoaSksIGV2ZW50LCB0cnVlKVxuICAgICAgICAgICAgOiBmKHZpZXcsIHBvcywgJHBvcy5ub2RlKGkpLCAkcG9zLmJlZm9yZShpKSwgZXZlbnQsIGZhbHNlKSkpXG4gICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG4gICAgcmV0dXJuIGZhbHNlO1xufVxuZnVuY3Rpb24gdXBkYXRlU2VsZWN0aW9uKHZpZXcsIHNlbGVjdGlvbiwgb3JpZ2luKSB7XG4gICAgaWYgKCF2aWV3LmZvY3VzZWQpXG4gICAgICAgIHZpZXcuZm9jdXMoKTtcbiAgICBpZiAodmlldy5zdGF0ZS5zZWxlY3Rpb24uZXEoc2VsZWN0aW9uKSlcbiAgICAgICAgcmV0dXJuO1xuICAgIGxldCB0ciA9IHZpZXcuc3RhdGUudHIuc2V0U2VsZWN0aW9uKHNlbGVjdGlvbik7XG4gICAgaWYgKG9yaWdpbiA9PSBcInBvaW50ZXJcIilcbiAgICAgICAgdHIuc2V0TWV0YShcInBvaW50ZXJcIiwgdHJ1ZSk7XG4gICAgdmlldy5kaXNwYXRjaCh0cik7XG59XG5mdW5jdGlvbiBzZWxlY3RDbGlja2VkTGVhZih2aWV3LCBpbnNpZGUpIHtcbiAgICBpZiAoaW5zaWRlID09IC0xKVxuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgbGV0ICRwb3MgPSB2aWV3LnN0YXRlLmRvYy5yZXNvbHZlKGluc2lkZSksIG5vZGUgPSAkcG9zLm5vZGVBZnRlcjtcbiAgICBpZiAobm9kZSAmJiBub2RlLmlzQXRvbSAmJiBOb2RlU2VsZWN0aW9uLmlzU2VsZWN0YWJsZShub2RlKSkge1xuICAgICAgICB1cGRhdGVTZWxlY3Rpb24odmlldywgbmV3IE5vZGVTZWxlY3Rpb24oJHBvcyksIFwicG9pbnRlclwiKTtcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuICAgIHJldHVybiBmYWxzZTtcbn1cbmZ1bmN0aW9uIHNlbGVjdENsaWNrZWROb2RlKHZpZXcsIGluc2lkZSkge1xuICAgIGlmIChpbnNpZGUgPT0gLTEpXG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICBsZXQgc2VsID0gdmlldy5zdGF0ZS5zZWxlY3Rpb24sIHNlbGVjdGVkTm9kZSwgc2VsZWN0QXQ7XG4gICAgaWYgKHNlbCBpbnN0YW5jZW9mIE5vZGVTZWxlY3Rpb24pXG4gICAgICAgIHNlbGVjdGVkTm9kZSA9IHNlbC5ub2RlO1xuICAgIGxldCAkcG9zID0gdmlldy5zdGF0ZS5kb2MucmVzb2x2ZShpbnNpZGUpO1xuICAgIGZvciAobGV0IGkgPSAkcG9zLmRlcHRoICsgMTsgaSA+IDA7IGktLSkge1xuICAgICAgICBsZXQgbm9kZSA9IGkgPiAkcG9zLmRlcHRoID8gJHBvcy5ub2RlQWZ0ZXIgOiAkcG9zLm5vZGUoaSk7XG4gICAgICAgIGlmIChOb2RlU2VsZWN0aW9uLmlzU2VsZWN0YWJsZShub2RlKSkge1xuICAgICAgICAgICAgaWYgKHNlbGVjdGVkTm9kZSAmJiBzZWwuJGZyb20uZGVwdGggPiAwICYmXG4gICAgICAgICAgICAgICAgaSA+PSBzZWwuJGZyb20uZGVwdGggJiYgJHBvcy5iZWZvcmUoc2VsLiRmcm9tLmRlcHRoICsgMSkgPT0gc2VsLiRmcm9tLnBvcylcbiAgICAgICAgICAgICAgICBzZWxlY3RBdCA9ICRwb3MuYmVmb3JlKHNlbC4kZnJvbS5kZXB0aCk7XG4gICAgICAgICAgICBlbHNlXG4gICAgICAgICAgICAgICAgc2VsZWN0QXQgPSAkcG9zLmJlZm9yZShpKTtcbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICB9XG4gICAgfVxuICAgIGlmIChzZWxlY3RBdCAhPSBudWxsKSB7XG4gICAgICAgIHVwZGF0ZVNlbGVjdGlvbih2aWV3LCBOb2RlU2VsZWN0aW9uLmNyZWF0ZSh2aWV3LnN0YXRlLmRvYywgc2VsZWN0QXQpLCBcInBvaW50ZXJcIik7XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cbiAgICBlbHNlIHtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbn1cbmZ1bmN0aW9uIGhhbmRsZVNpbmdsZUNsaWNrKHZpZXcsIHBvcywgaW5zaWRlLCBldmVudCwgc2VsZWN0Tm9kZSkge1xuICAgIHJldHVybiBydW5IYW5kbGVyT25Db250ZXh0KHZpZXcsIFwiaGFuZGxlQ2xpY2tPblwiLCBwb3MsIGluc2lkZSwgZXZlbnQpIHx8XG4gICAgICAgIHZpZXcuc29tZVByb3AoXCJoYW5kbGVDbGlja1wiLCBmID0+IGYodmlldywgcG9zLCBldmVudCkpIHx8XG4gICAgICAgIChzZWxlY3ROb2RlID8gc2VsZWN0Q2xpY2tlZE5vZGUodmlldywgaW5zaWRlKSA6IHNlbGVjdENsaWNrZWRMZWFmKHZpZXcsIGluc2lkZSkpO1xufVxuZnVuY3Rpb24gaGFuZGxlRG91YmxlQ2xpY2sodmlldywgcG9zLCBpbnNpZGUsIGV2ZW50KSB7XG4gICAgcmV0dXJuIHJ1bkhhbmRsZXJPbkNvbnRleHQodmlldywgXCJoYW5kbGVEb3VibGVDbGlja09uXCIsIHBvcywgaW5zaWRlLCBldmVudCkgfHxcbiAgICAgICAgdmlldy5zb21lUHJvcChcImhhbmRsZURvdWJsZUNsaWNrXCIsIGYgPT4gZih2aWV3LCBwb3MsIGV2ZW50KSk7XG59XG5mdW5jdGlvbiBoYW5kbGVUcmlwbGVDbGljayh2aWV3LCBwb3MsIGluc2lkZSwgZXZlbnQpIHtcbiAgICByZXR1cm4gcnVuSGFuZGxlck9uQ29udGV4dCh2aWV3LCBcImhhbmRsZVRyaXBsZUNsaWNrT25cIiwgcG9zLCBpbnNpZGUsIGV2ZW50KSB8fFxuICAgICAgICB2aWV3LnNvbWVQcm9wKFwiaGFuZGxlVHJpcGxlQ2xpY2tcIiwgZiA9PiBmKHZpZXcsIHBvcywgZXZlbnQpKSB8fFxuICAgICAgICBkZWZhdWx0VHJpcGxlQ2xpY2sodmlldywgaW5zaWRlLCBldmVudCk7XG59XG5mdW5jdGlvbiBkZWZhdWx0VHJpcGxlQ2xpY2sodmlldywgaW5zaWRlLCBldmVudCkge1xuICAgIGlmIChldmVudC5idXR0b24gIT0gMClcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIGxldCBkb2MgPSB2aWV3LnN0YXRlLmRvYztcbiAgICBpZiAoaW5zaWRlID09IC0xKSB7XG4gICAgICAgIGlmIChkb2MuaW5saW5lQ29udGVudCkge1xuICAgICAgICAgICAgdXBkYXRlU2VsZWN0aW9uKHZpZXcsIFRleHRTZWxlY3Rpb24uY3JlYXRlKGRvYywgMCwgZG9jLmNvbnRlbnQuc2l6ZSksIFwicG9pbnRlclwiKTtcbiAgICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgbGV0ICRwb3MgPSBkb2MucmVzb2x2ZShpbnNpZGUpO1xuICAgIGZvciAobGV0IGkgPSAkcG9zLmRlcHRoICsgMTsgaSA+IDA7IGktLSkge1xuICAgICAgICBsZXQgbm9kZSA9IGkgPiAkcG9zLmRlcHRoID8gJHBvcy5ub2RlQWZ0ZXIgOiAkcG9zLm5vZGUoaSk7XG4gICAgICAgIGxldCBub2RlUG9zID0gJHBvcy5iZWZvcmUoaSk7XG4gICAgICAgIGlmIChub2RlLmlubGluZUNvbnRlbnQpXG4gICAgICAgICAgICB1cGRhdGVTZWxlY3Rpb24odmlldywgVGV4dFNlbGVjdGlvbi5jcmVhdGUoZG9jLCBub2RlUG9zICsgMSwgbm9kZVBvcyArIDEgKyBub2RlLmNvbnRlbnQuc2l6ZSksIFwicG9pbnRlclwiKTtcbiAgICAgICAgZWxzZSBpZiAoTm9kZVNlbGVjdGlvbi5pc1NlbGVjdGFibGUobm9kZSkpXG4gICAgICAgICAgICB1cGRhdGVTZWxlY3Rpb24odmlldywgTm9kZVNlbGVjdGlvbi5jcmVhdGUoZG9jLCBub2RlUG9zKSwgXCJwb2ludGVyXCIpO1xuICAgICAgICBlbHNlXG4gICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxufVxuZnVuY3Rpb24gZm9yY2VET01GbHVzaCh2aWV3KSB7XG4gICAgcmV0dXJuIGVuZENvbXBvc2l0aW9uKHZpZXcpO1xufVxuY29uc3Qgc2VsZWN0Tm9kZU1vZGlmaWVyID0gbWFjID8gXCJtZXRhS2V5XCIgOiBcImN0cmxLZXlcIjtcbmhhbmRsZXJzLm1vdXNlZG93biA9ICh2aWV3LCBfZXZlbnQpID0+IHtcbiAgICBsZXQgZXZlbnQgPSBfZXZlbnQ7XG4gICAgdmlldy5pbnB1dC5zaGlmdEtleSA9IGV2ZW50LnNoaWZ0S2V5O1xuICAgIGxldCBmbHVzaGVkID0gZm9yY2VET01GbHVzaCh2aWV3KTtcbiAgICBsZXQgbm93ID0gRGF0ZS5ub3coKSwgdHlwZSA9IFwic2luZ2xlQ2xpY2tcIjtcbiAgICBpZiAobm93IC0gdmlldy5pbnB1dC5sYXN0Q2xpY2sudGltZSA8IDUwMCAmJiBpc05lYXIoZXZlbnQsIHZpZXcuaW5wdXQubGFzdENsaWNrKSAmJiAhZXZlbnRbc2VsZWN0Tm9kZU1vZGlmaWVyXSAmJlxuICAgICAgICB2aWV3LmlucHV0Lmxhc3RDbGljay5idXR0b24gPT0gZXZlbnQuYnV0dG9uKSB7XG4gICAgICAgIGlmICh2aWV3LmlucHV0Lmxhc3RDbGljay50eXBlID09IFwic2luZ2xlQ2xpY2tcIilcbiAgICAgICAgICAgIHR5cGUgPSBcImRvdWJsZUNsaWNrXCI7XG4gICAgICAgIGVsc2UgaWYgKHZpZXcuaW5wdXQubGFzdENsaWNrLnR5cGUgPT0gXCJkb3VibGVDbGlja1wiKVxuICAgICAgICAgICAgdHlwZSA9IFwidHJpcGxlQ2xpY2tcIjtcbiAgICB9XG4gICAgdmlldy5pbnB1dC5sYXN0Q2xpY2sgPSB7IHRpbWU6IG5vdywgeDogZXZlbnQuY2xpZW50WCwgeTogZXZlbnQuY2xpZW50WSwgdHlwZSwgYnV0dG9uOiBldmVudC5idXR0b24gfTtcbiAgICBsZXQgcG9zID0gdmlldy5wb3NBdENvb3JkcyhldmVudENvb3JkcyhldmVudCkpO1xuICAgIGlmICghcG9zKVxuICAgICAgICByZXR1cm47XG4gICAgaWYgKHR5cGUgPT0gXCJzaW5nbGVDbGlja1wiKSB7XG4gICAgICAgIGlmICh2aWV3LmlucHV0Lm1vdXNlRG93bilcbiAgICAgICAgICAgIHZpZXcuaW5wdXQubW91c2VEb3duLmRvbmUoKTtcbiAgICAgICAgdmlldy5pbnB1dC5tb3VzZURvd24gPSBuZXcgTW91c2VEb3duKHZpZXcsIHBvcywgZXZlbnQsICEhZmx1c2hlZCk7XG4gICAgfVxuICAgIGVsc2UgaWYgKCh0eXBlID09IFwiZG91YmxlQ2xpY2tcIiA/IGhhbmRsZURvdWJsZUNsaWNrIDogaGFuZGxlVHJpcGxlQ2xpY2spKHZpZXcsIHBvcy5wb3MsIHBvcy5pbnNpZGUsIGV2ZW50KSkge1xuICAgICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgIH1cbiAgICBlbHNlIHtcbiAgICAgICAgc2V0U2VsZWN0aW9uT3JpZ2luKHZpZXcsIFwicG9pbnRlclwiKTtcbiAgICB9XG59O1xuY2xhc3MgTW91c2VEb3duIHtcbiAgICBjb25zdHJ1Y3Rvcih2aWV3LCBwb3MsIGV2ZW50LCBmbHVzaGVkKSB7XG4gICAgICAgIHRoaXMudmlldyA9IHZpZXc7XG4gICAgICAgIHRoaXMucG9zID0gcG9zO1xuICAgICAgICB0aGlzLmV2ZW50ID0gZXZlbnQ7XG4gICAgICAgIHRoaXMuZmx1c2hlZCA9IGZsdXNoZWQ7XG4gICAgICAgIHRoaXMuZGVsYXllZFNlbGVjdGlvblN5bmMgPSBmYWxzZTtcbiAgICAgICAgdGhpcy5taWdodERyYWcgPSBudWxsO1xuICAgICAgICB0aGlzLnN0YXJ0RG9jID0gdmlldy5zdGF0ZS5kb2M7XG4gICAgICAgIHRoaXMuc2VsZWN0Tm9kZSA9ICEhZXZlbnRbc2VsZWN0Tm9kZU1vZGlmaWVyXTtcbiAgICAgICAgdGhpcy5hbGxvd0RlZmF1bHQgPSBldmVudC5zaGlmdEtleTtcbiAgICAgICAgbGV0IHRhcmdldE5vZGUsIHRhcmdldFBvcztcbiAgICAgICAgaWYgKHBvcy5pbnNpZGUgPiAtMSkge1xuICAgICAgICAgICAgdGFyZ2V0Tm9kZSA9IHZpZXcuc3RhdGUuZG9jLm5vZGVBdChwb3MuaW5zaWRlKTtcbiAgICAgICAgICAgIHRhcmdldFBvcyA9IHBvcy5pbnNpZGU7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICBsZXQgJHBvcyA9IHZpZXcuc3RhdGUuZG9jLnJlc29sdmUocG9zLnBvcyk7XG4gICAgICAgICAgICB0YXJnZXROb2RlID0gJHBvcy5wYXJlbnQ7XG4gICAgICAgICAgICB0YXJnZXRQb3MgPSAkcG9zLmRlcHRoID8gJHBvcy5iZWZvcmUoKSA6IDA7XG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgdGFyZ2V0ID0gZmx1c2hlZCA/IG51bGwgOiBldmVudC50YXJnZXQ7XG4gICAgICAgIGNvbnN0IHRhcmdldERlc2MgPSB0YXJnZXQgPyB2aWV3LmRvY1ZpZXcubmVhcmVzdERlc2ModGFyZ2V0LCB0cnVlKSA6IG51bGw7XG4gICAgICAgIHRoaXMudGFyZ2V0ID0gdGFyZ2V0RGVzYyAmJiB0YXJnZXREZXNjLm5vZGVET00ubm9kZVR5cGUgPT0gMSA/IHRhcmdldERlc2Mubm9kZURPTSA6IG51bGw7XG4gICAgICAgIGxldCB7IHNlbGVjdGlvbiB9ID0gdmlldy5zdGF0ZTtcbiAgICAgICAgaWYgKGV2ZW50LmJ1dHRvbiA9PSAwICYmXG4gICAgICAgICAgICB0YXJnZXROb2RlLnR5cGUuc3BlYy5kcmFnZ2FibGUgJiYgdGFyZ2V0Tm9kZS50eXBlLnNwZWMuc2VsZWN0YWJsZSAhPT0gZmFsc2UgfHxcbiAgICAgICAgICAgIHNlbGVjdGlvbiBpbnN0YW5jZW9mIE5vZGVTZWxlY3Rpb24gJiYgc2VsZWN0aW9uLmZyb20gPD0gdGFyZ2V0UG9zICYmIHNlbGVjdGlvbi50byA+IHRhcmdldFBvcylcbiAgICAgICAgICAgIHRoaXMubWlnaHREcmFnID0ge1xuICAgICAgICAgICAgICAgIG5vZGU6IHRhcmdldE5vZGUsXG4gICAgICAgICAgICAgICAgcG9zOiB0YXJnZXRQb3MsXG4gICAgICAgICAgICAgICAgYWRkQXR0cjogISEodGhpcy50YXJnZXQgJiYgIXRoaXMudGFyZ2V0LmRyYWdnYWJsZSksXG4gICAgICAgICAgICAgICAgc2V0VW5lZGl0YWJsZTogISEodGhpcy50YXJnZXQgJiYgZ2Vja28gJiYgIXRoaXMudGFyZ2V0Lmhhc0F0dHJpYnV0ZShcImNvbnRlbnRFZGl0YWJsZVwiKSlcbiAgICAgICAgICAgIH07XG4gICAgICAgIGlmICh0aGlzLnRhcmdldCAmJiB0aGlzLm1pZ2h0RHJhZyAmJiAodGhpcy5taWdodERyYWcuYWRkQXR0ciB8fCB0aGlzLm1pZ2h0RHJhZy5zZXRVbmVkaXRhYmxlKSkge1xuICAgICAgICAgICAgdGhpcy52aWV3LmRvbU9ic2VydmVyLnN0b3AoKTtcbiAgICAgICAgICAgIGlmICh0aGlzLm1pZ2h0RHJhZy5hZGRBdHRyKVxuICAgICAgICAgICAgICAgIHRoaXMudGFyZ2V0LmRyYWdnYWJsZSA9IHRydWU7XG4gICAgICAgICAgICBpZiAodGhpcy5taWdodERyYWcuc2V0VW5lZGl0YWJsZSlcbiAgICAgICAgICAgICAgICBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKHRoaXMudmlldy5pbnB1dC5tb3VzZURvd24gPT0gdGhpcylcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMudGFyZ2V0LnNldEF0dHJpYnV0ZShcImNvbnRlbnRFZGl0YWJsZVwiLCBcImZhbHNlXCIpO1xuICAgICAgICAgICAgICAgIH0sIDIwKTtcbiAgICAgICAgICAgIHRoaXMudmlldy5kb21PYnNlcnZlci5zdGFydCgpO1xuICAgICAgICB9XG4gICAgICAgIHZpZXcucm9vdC5hZGRFdmVudExpc3RlbmVyKFwibW91c2V1cFwiLCB0aGlzLnVwID0gdGhpcy51cC5iaW5kKHRoaXMpKTtcbiAgICAgICAgdmlldy5yb290LmFkZEV2ZW50TGlzdGVuZXIoXCJtb3VzZW1vdmVcIiwgdGhpcy5tb3ZlID0gdGhpcy5tb3ZlLmJpbmQodGhpcykpO1xuICAgICAgICBzZXRTZWxlY3Rpb25PcmlnaW4odmlldywgXCJwb2ludGVyXCIpO1xuICAgIH1cbiAgICBkb25lKCkge1xuICAgICAgICB0aGlzLnZpZXcucm9vdC5yZW1vdmVFdmVudExpc3RlbmVyKFwibW91c2V1cFwiLCB0aGlzLnVwKTtcbiAgICAgICAgdGhpcy52aWV3LnJvb3QucmVtb3ZlRXZlbnRMaXN0ZW5lcihcIm1vdXNlbW92ZVwiLCB0aGlzLm1vdmUpO1xuICAgICAgICBpZiAodGhpcy5taWdodERyYWcgJiYgdGhpcy50YXJnZXQpIHtcbiAgICAgICAgICAgIHRoaXMudmlldy5kb21PYnNlcnZlci5zdG9wKCk7XG4gICAgICAgICAgICBpZiAodGhpcy5taWdodERyYWcuYWRkQXR0cilcbiAgICAgICAgICAgICAgICB0aGlzLnRhcmdldC5yZW1vdmVBdHRyaWJ1dGUoXCJkcmFnZ2FibGVcIik7XG4gICAgICAgICAgICBpZiAodGhpcy5taWdodERyYWcuc2V0VW5lZGl0YWJsZSlcbiAgICAgICAgICAgICAgICB0aGlzLnRhcmdldC5yZW1vdmVBdHRyaWJ1dGUoXCJjb250ZW50RWRpdGFibGVcIik7XG4gICAgICAgICAgICB0aGlzLnZpZXcuZG9tT2JzZXJ2ZXIuc3RhcnQoKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAodGhpcy5kZWxheWVkU2VsZWN0aW9uU3luYylcbiAgICAgICAgICAgIHNldFRpbWVvdXQoKCkgPT4gc2VsZWN0aW9uVG9ET00odGhpcy52aWV3KSk7XG4gICAgICAgIHRoaXMudmlldy5pbnB1dC5tb3VzZURvd24gPSBudWxsO1xuICAgIH1cbiAgICB1cChldmVudCkge1xuICAgICAgICB0aGlzLmRvbmUoKTtcbiAgICAgICAgaWYgKCF0aGlzLnZpZXcuZG9tLmNvbnRhaW5zKGV2ZW50LnRhcmdldCkpXG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIGxldCBwb3MgPSB0aGlzLnBvcztcbiAgICAgICAgaWYgKHRoaXMudmlldy5zdGF0ZS5kb2MgIT0gdGhpcy5zdGFydERvYylcbiAgICAgICAgICAgIHBvcyA9IHRoaXMudmlldy5wb3NBdENvb3JkcyhldmVudENvb3JkcyhldmVudCkpO1xuICAgICAgICB0aGlzLnVwZGF0ZUFsbG93RGVmYXVsdChldmVudCk7XG4gICAgICAgIGlmICh0aGlzLmFsbG93RGVmYXVsdCB8fCAhcG9zKSB7XG4gICAgICAgICAgICBzZXRTZWxlY3Rpb25PcmlnaW4odGhpcy52aWV3LCBcInBvaW50ZXJcIik7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAoaGFuZGxlU2luZ2xlQ2xpY2sodGhpcy52aWV3LCBwb3MucG9zLCBwb3MuaW5zaWRlLCBldmVudCwgdGhpcy5zZWxlY3ROb2RlKSkge1xuICAgICAgICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIGlmIChldmVudC5idXR0b24gPT0gMCAmJlxuICAgICAgICAgICAgKHRoaXMuZmx1c2hlZCB8fFxuICAgICAgICAgICAgICAgIC8vIFNhZmFyaSBpZ25vcmVzIGNsaWNrcyBvbiBkcmFnZ2FibGUgZWxlbWVudHNcbiAgICAgICAgICAgICAgICAoc2FmYXJpICYmIHRoaXMubWlnaHREcmFnICYmICF0aGlzLm1pZ2h0RHJhZy5ub2RlLmlzQXRvbSkgfHxcbiAgICAgICAgICAgICAgICAvLyBDaHJvbWUgd2lsbCBzb21ldGltZXMgdHJlYXQgYSBub2RlIHNlbGVjdGlvbiBhcyBhXG4gICAgICAgICAgICAgICAgLy8gY3Vyc29yLCBidXQgc3RpbGwgcmVwb3J0IHRoYXQgdGhlIG5vZGUgaXMgc2VsZWN0ZWRcbiAgICAgICAgICAgICAgICAvLyB3aGVuIGFza2VkIHRocm91Z2ggZ2V0U2VsZWN0aW9uLiBZb3UnbGwgdGhlbiBnZXQgYVxuICAgICAgICAgICAgICAgIC8vIHNpdHVhdGlvbiB3aGVyZSBjbGlja2luZyBhdCB0aGUgcG9pbnQgd2hlcmUgdGhhdFxuICAgICAgICAgICAgICAgIC8vIChoaWRkZW4pIGN1cnNvciBpcyBkb2Vzbid0IGNoYW5nZSB0aGUgc2VsZWN0aW9uLCBhbmRcbiAgICAgICAgICAgICAgICAvLyB0aHVzIGRvZXNuJ3QgZ2V0IGEgcmVhY3Rpb24gZnJvbSBQcm9zZU1pcnJvci4gVGhpc1xuICAgICAgICAgICAgICAgIC8vIHdvcmtzIGFyb3VuZCB0aGF0LlxuICAgICAgICAgICAgICAgIChjaHJvbWUgJiYgIXRoaXMudmlldy5zdGF0ZS5zZWxlY3Rpb24udmlzaWJsZSAmJlxuICAgICAgICAgICAgICAgICAgICBNYXRoLm1pbihNYXRoLmFicyhwb3MucG9zIC0gdGhpcy52aWV3LnN0YXRlLnNlbGVjdGlvbi5mcm9tKSwgTWF0aC5hYnMocG9zLnBvcyAtIHRoaXMudmlldy5zdGF0ZS5zZWxlY3Rpb24udG8pKSA8PSAyKSkpIHtcbiAgICAgICAgICAgIHVwZGF0ZVNlbGVjdGlvbih0aGlzLnZpZXcsIFNlbGVjdGlvbi5uZWFyKHRoaXMudmlldy5zdGF0ZS5kb2MucmVzb2x2ZShwb3MucG9zKSksIFwicG9pbnRlclwiKTtcbiAgICAgICAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICBzZXRTZWxlY3Rpb25PcmlnaW4odGhpcy52aWV3LCBcInBvaW50ZXJcIik7XG4gICAgICAgIH1cbiAgICB9XG4gICAgbW92ZShldmVudCkge1xuICAgICAgICB0aGlzLnVwZGF0ZUFsbG93RGVmYXVsdChldmVudCk7XG4gICAgICAgIHNldFNlbGVjdGlvbk9yaWdpbih0aGlzLnZpZXcsIFwicG9pbnRlclwiKTtcbiAgICAgICAgaWYgKGV2ZW50LmJ1dHRvbnMgPT0gMClcbiAgICAgICAgICAgIHRoaXMuZG9uZSgpO1xuICAgIH1cbiAgICB1cGRhdGVBbGxvd0RlZmF1bHQoZXZlbnQpIHtcbiAgICAgICAgaWYgKCF0aGlzLmFsbG93RGVmYXVsdCAmJiAoTWF0aC5hYnModGhpcy5ldmVudC54IC0gZXZlbnQuY2xpZW50WCkgPiA0IHx8XG4gICAgICAgICAgICBNYXRoLmFicyh0aGlzLmV2ZW50LnkgLSBldmVudC5jbGllbnRZKSA+IDQpKVxuICAgICAgICAgICAgdGhpcy5hbGxvd0RlZmF1bHQgPSB0cnVlO1xuICAgIH1cbn1cbmhhbmRsZXJzLnRvdWNoc3RhcnQgPSB2aWV3ID0+IHtcbiAgICB2aWV3LmlucHV0Lmxhc3RUb3VjaCA9IERhdGUubm93KCk7XG4gICAgZm9yY2VET01GbHVzaCh2aWV3KTtcbiAgICBzZXRTZWxlY3Rpb25PcmlnaW4odmlldywgXCJwb2ludGVyXCIpO1xufTtcbmhhbmRsZXJzLnRvdWNobW92ZSA9IHZpZXcgPT4ge1xuICAgIHZpZXcuaW5wdXQubGFzdFRvdWNoID0gRGF0ZS5ub3coKTtcbiAgICBzZXRTZWxlY3Rpb25PcmlnaW4odmlldywgXCJwb2ludGVyXCIpO1xufTtcbmhhbmRsZXJzLmNvbnRleHRtZW51ID0gdmlldyA9PiBmb3JjZURPTUZsdXNoKHZpZXcpO1xuZnVuY3Rpb24gaW5Pck5lYXJDb21wb3NpdGlvbih2aWV3LCBldmVudCkge1xuICAgIGlmICh2aWV3LmNvbXBvc2luZylcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgLy8gU2VlIGh0dHBzOi8vd3d3LnN0dW0uZGUvMjAxNi8wNi8yNC9oYW5kbGluZy1pbWUtZXZlbnRzLWluLWphdmFzY3JpcHQvLlxuICAgIC8vIE9uIEphcGFuZXNlIGlucHV0IG1ldGhvZCBlZGl0b3JzIChJTUVzKSwgdGhlIEVudGVyIGtleSBpcyB1c2VkIHRvIGNvbmZpcm0gY2hhcmFjdGVyXG4gICAgLy8gc2VsZWN0aW9uLiBPbiBTYWZhcmksIHdoZW4gRW50ZXIgaXMgcHJlc3NlZCwgY29tcG9zaXRpb25lbmQgYW5kIGtleWRvd24gZXZlbnRzIGFyZVxuICAgIC8vIGVtaXR0ZWQuIFRoZSBrZXlkb3duIGV2ZW50IHRyaWdnZXJzIG5ld2xpbmUgaW5zZXJ0aW9uLCB3aGljaCB3ZSBkb24ndCB3YW50LlxuICAgIC8vIFRoaXMgbWV0aG9kIHJldHVybnMgdHJ1ZSBpZiB0aGUga2V5ZG93biBldmVudCBzaG91bGQgYmUgaWdub3JlZC5cbiAgICAvLyBXZSBvbmx5IGlnbm9yZSBpdCBvbmNlLCBhcyBwcmVzc2luZyBFbnRlciBhIHNlY29uZCB0aW1lICpzaG91bGQqIGluc2VydCBhIG5ld2xpbmUuXG4gICAgLy8gRnVydGhlcm1vcmUsIHRoZSBrZXlkb3duIGV2ZW50IHRpbWVzdGFtcCBtdXN0IGJlIGNsb3NlIHRvIHRoZSBjb21wb3NpdGlvbkVuZGVkQXQgdGltZXN0YW1wLlxuICAgIC8vIFRoaXMgZ3VhcmRzIGFnYWluc3QgdGhlIGNhc2Ugd2hlcmUgY29tcG9zaXRpb25lbmQgaXMgdHJpZ2dlcmVkIHdpdGhvdXQgdGhlIGtleWJvYXJkXG4gICAgLy8gKGUuZy4gY2hhcmFjdGVyIGNvbmZpcm1hdGlvbiBtYXkgYmUgZG9uZSB3aXRoIHRoZSBtb3VzZSksIGFuZCBrZXlkb3duIGlzIHRyaWdnZXJlZFxuICAgIC8vIGFmdGVyd2FyZHMtIHdlIHdvdWxkbid0IHdhbnQgdG8gaWdub3JlIHRoZSBrZXlkb3duIGV2ZW50IGluIHRoaXMgY2FzZS5cbiAgICBpZiAoc2FmYXJpICYmIE1hdGguYWJzKGV2ZW50LnRpbWVTdGFtcCAtIHZpZXcuaW5wdXQuY29tcG9zaXRpb25FbmRlZEF0KSA8IDUwMCkge1xuICAgICAgICB2aWV3LmlucHV0LmNvbXBvc2l0aW9uRW5kZWRBdCA9IC0yZTg7XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cbiAgICByZXR1cm4gZmFsc2U7XG59XG4vLyBEcm9wIGFjdGl2ZSBjb21wb3NpdGlvbiBhZnRlciA1IHNlY29uZHMgb2YgaW5hY3Rpdml0eSBvbiBBbmRyb2lkXG5jb25zdCB0aW1lb3V0Q29tcG9zaXRpb24gPSBhbmRyb2lkID8gNTAwMCA6IC0xO1xuZWRpdEhhbmRsZXJzLmNvbXBvc2l0aW9uc3RhcnQgPSBlZGl0SGFuZGxlcnMuY29tcG9zaXRpb251cGRhdGUgPSB2aWV3ID0+IHtcbiAgICBpZiAoIXZpZXcuY29tcG9zaW5nKSB7XG4gICAgICAgIHZpZXcuZG9tT2JzZXJ2ZXIuZmx1c2goKTtcbiAgICAgICAgbGV0IHsgc3RhdGUgfSA9IHZpZXcsICRwb3MgPSBzdGF0ZS5zZWxlY3Rpb24uJHRvO1xuICAgICAgICBpZiAoc3RhdGUuc2VsZWN0aW9uIGluc3RhbmNlb2YgVGV4dFNlbGVjdGlvbiAmJlxuICAgICAgICAgICAgKHN0YXRlLnN0b3JlZE1hcmtzIHx8XG4gICAgICAgICAgICAgICAgKCEkcG9zLnRleHRPZmZzZXQgJiYgJHBvcy5wYXJlbnRPZmZzZXQgJiYgJHBvcy5ub2RlQmVmb3JlLm1hcmtzLnNvbWUobSA9PiBtLnR5cGUuc3BlYy5pbmNsdXNpdmUgPT09IGZhbHNlKSkgfHxcbiAgICAgICAgICAgICAgICBjaHJvbWUgJiYgd2luZG93cyAmJiBzZWxlY3Rpb25CZWZvcmVVbmVkaXRhYmxlKHZpZXcpKSkgeyAvLyBJc3N1ZSAjMTUwMFxuICAgICAgICAgICAgLy8gTmVlZCB0byB3cmFwIHRoZSBjdXJzb3IgaW4gbWFyayBub2RlcyBkaWZmZXJlbnQgZnJvbSB0aGUgb25lcyBpbiB0aGUgRE9NIGNvbnRleHRcbiAgICAgICAgICAgIHZpZXcubWFya0N1cnNvciA9IHZpZXcuc3RhdGUuc3RvcmVkTWFya3MgfHwgJHBvcy5tYXJrcygpO1xuICAgICAgICAgICAgZW5kQ29tcG9zaXRpb24odmlldywgdHJ1ZSk7XG4gICAgICAgICAgICB2aWV3Lm1hcmtDdXJzb3IgPSBudWxsO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgZW5kQ29tcG9zaXRpb24odmlldywgIXN0YXRlLnNlbGVjdGlvbi5lbXB0eSk7XG4gICAgICAgICAgICAvLyBJbiBmaXJlZm94LCBpZiB0aGUgY3Vyc29yIGlzIGFmdGVyIGJ1dCBvdXRzaWRlIGEgbWFya2VkIG5vZGUsXG4gICAgICAgICAgICAvLyB0aGUgaW5zZXJ0ZWQgdGV4dCB3b24ndCBpbmhlcml0IHRoZSBtYXJrcy4gU28gdGhpcyBtb3ZlcyBpdFxuICAgICAgICAgICAgLy8gaW5zaWRlIGlmIG5lY2Vzc2FyeS5cbiAgICAgICAgICAgIGlmIChnZWNrbyAmJiBzdGF0ZS5zZWxlY3Rpb24uZW1wdHkgJiYgJHBvcy5wYXJlbnRPZmZzZXQgJiYgISRwb3MudGV4dE9mZnNldCAmJiAkcG9zLm5vZGVCZWZvcmUubWFya3MubGVuZ3RoKSB7XG4gICAgICAgICAgICAgICAgbGV0IHNlbCA9IHZpZXcuZG9tU2VsZWN0aW9uUmFuZ2UoKTtcbiAgICAgICAgICAgICAgICBmb3IgKGxldCBub2RlID0gc2VsLmZvY3VzTm9kZSwgb2Zmc2V0ID0gc2VsLmZvY3VzT2Zmc2V0OyBub2RlICYmIG5vZGUubm9kZVR5cGUgPT0gMSAmJiBvZmZzZXQgIT0gMDspIHtcbiAgICAgICAgICAgICAgICAgICAgbGV0IGJlZm9yZSA9IG9mZnNldCA8IDAgPyBub2RlLmxhc3RDaGlsZCA6IG5vZGUuY2hpbGROb2Rlc1tvZmZzZXQgLSAxXTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKCFiZWZvcmUpXG4gICAgICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICAgICAgaWYgKGJlZm9yZS5ub2RlVHlwZSA9PSAzKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBsZXQgc2VsID0gdmlldy5kb21TZWxlY3Rpb24oKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChzZWwpXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VsLmNvbGxhcHNlKGJlZm9yZSwgYmVmb3JlLm5vZGVWYWx1ZS5sZW5ndGgpO1xuICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBub2RlID0gYmVmb3JlO1xuICAgICAgICAgICAgICAgICAgICAgICAgb2Zmc2V0ID0gLTE7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgdmlldy5pbnB1dC5jb21wb3NpbmcgPSB0cnVlO1xuICAgIH1cbiAgICBzY2hlZHVsZUNvbXBvc2VFbmQodmlldywgdGltZW91dENvbXBvc2l0aW9uKTtcbn07XG5mdW5jdGlvbiBzZWxlY3Rpb25CZWZvcmVVbmVkaXRhYmxlKHZpZXcpIHtcbiAgICBsZXQgeyBmb2N1c05vZGUsIGZvY3VzT2Zmc2V0IH0gPSB2aWV3LmRvbVNlbGVjdGlvblJhbmdlKCk7XG4gICAgaWYgKCFmb2N1c05vZGUgfHwgZm9jdXNOb2RlLm5vZGVUeXBlICE9IDEgfHwgZm9jdXNPZmZzZXQgPj0gZm9jdXNOb2RlLmNoaWxkTm9kZXMubGVuZ3RoKVxuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgbGV0IG5leHQgPSBmb2N1c05vZGUuY2hpbGROb2Rlc1tmb2N1c09mZnNldF07XG4gICAgcmV0dXJuIG5leHQubm9kZVR5cGUgPT0gMSAmJiBuZXh0LmNvbnRlbnRFZGl0YWJsZSA9PSBcImZhbHNlXCI7XG59XG5lZGl0SGFuZGxlcnMuY29tcG9zaXRpb25lbmQgPSAodmlldywgZXZlbnQpID0+IHtcbiAgICBpZiAodmlldy5jb21wb3NpbmcpIHtcbiAgICAgICAgdmlldy5pbnB1dC5jb21wb3NpbmcgPSBmYWxzZTtcbiAgICAgICAgdmlldy5pbnB1dC5jb21wb3NpdGlvbkVuZGVkQXQgPSBldmVudC50aW1lU3RhbXA7XG4gICAgICAgIHZpZXcuaW5wdXQuY29tcG9zaXRpb25QZW5kaW5nQ2hhbmdlcyA9IHZpZXcuZG9tT2JzZXJ2ZXIucGVuZGluZ1JlY29yZHMoKS5sZW5ndGggPyB2aWV3LmlucHV0LmNvbXBvc2l0aW9uSUQgOiAwO1xuICAgICAgICB2aWV3LmlucHV0LmNvbXBvc2l0aW9uTm9kZSA9IG51bGw7XG4gICAgICAgIGlmICh2aWV3LmlucHV0LmJhZFNhZmFyaUNvbXBvc2l0aW9uKVxuICAgICAgICAgICAgdmlldy5kb21PYnNlcnZlci5mb3JjZUZsdXNoKCk7XG4gICAgICAgIGVsc2UgaWYgKHZpZXcuaW5wdXQuY29tcG9zaXRpb25QZW5kaW5nQ2hhbmdlcylcbiAgICAgICAgICAgIFByb21pc2UucmVzb2x2ZSgpLnRoZW4oKCkgPT4gdmlldy5kb21PYnNlcnZlci5mbHVzaCgpKTtcbiAgICAgICAgdmlldy5pbnB1dC5jb21wb3NpdGlvbklEKys7XG4gICAgICAgIHNjaGVkdWxlQ29tcG9zZUVuZCh2aWV3LCAyMCk7XG4gICAgfVxufTtcbmZ1bmN0aW9uIHNjaGVkdWxlQ29tcG9zZUVuZCh2aWV3LCBkZWxheSkge1xuICAgIGNsZWFyVGltZW91dCh2aWV3LmlucHV0LmNvbXBvc2luZ1RpbWVvdXQpO1xuICAgIGlmIChkZWxheSA+IC0xKVxuICAgICAgICB2aWV3LmlucHV0LmNvbXBvc2luZ1RpbWVvdXQgPSBzZXRUaW1lb3V0KCgpID0+IGVuZENvbXBvc2l0aW9uKHZpZXcpLCBkZWxheSk7XG59XG5mdW5jdGlvbiBjbGVhckNvbXBvc2l0aW9uKHZpZXcpIHtcbiAgICBpZiAodmlldy5jb21wb3NpbmcpIHtcbiAgICAgICAgdmlldy5pbnB1dC5jb21wb3NpbmcgPSBmYWxzZTtcbiAgICAgICAgdmlldy5pbnB1dC5jb21wb3NpdGlvbkVuZGVkQXQgPSB0aW1lc3RhbXBGcm9tQ3VzdG9tRXZlbnQoKTtcbiAgICB9XG4gICAgd2hpbGUgKHZpZXcuaW5wdXQuY29tcG9zaXRpb25Ob2Rlcy5sZW5ndGggPiAwKVxuICAgICAgICB2aWV3LmlucHV0LmNvbXBvc2l0aW9uTm9kZXMucG9wKCkubWFya1BhcmVudHNEaXJ0eSgpO1xufVxuZnVuY3Rpb24gZmluZENvbXBvc2l0aW9uTm9kZSh2aWV3KSB7XG4gICAgbGV0IHNlbCA9IHZpZXcuZG9tU2VsZWN0aW9uUmFuZ2UoKTtcbiAgICBpZiAoIXNlbC5mb2N1c05vZGUpXG4gICAgICAgIHJldHVybiBudWxsO1xuICAgIGxldCB0ZXh0QmVmb3JlID0gdGV4dE5vZGVCZWZvcmUkMShzZWwuZm9jdXNOb2RlLCBzZWwuZm9jdXNPZmZzZXQpO1xuICAgIGxldCB0ZXh0QWZ0ZXIgPSB0ZXh0Tm9kZUFmdGVyJDEoc2VsLmZvY3VzTm9kZSwgc2VsLmZvY3VzT2Zmc2V0KTtcbiAgICBpZiAodGV4dEJlZm9yZSAmJiB0ZXh0QWZ0ZXIgJiYgdGV4dEJlZm9yZSAhPSB0ZXh0QWZ0ZXIpIHtcbiAgICAgICAgbGV0IGRlc2NBZnRlciA9IHRleHRBZnRlci5wbVZpZXdEZXNjLCBsYXN0Q2hhbmdlZCA9IHZpZXcuZG9tT2JzZXJ2ZXIubGFzdENoYW5nZWRUZXh0Tm9kZTtcbiAgICAgICAgaWYgKHRleHRCZWZvcmUgPT0gbGFzdENoYW5nZWQgfHwgdGV4dEFmdGVyID09IGxhc3RDaGFuZ2VkKVxuICAgICAgICAgICAgcmV0dXJuIGxhc3RDaGFuZ2VkO1xuICAgICAgICBpZiAoIWRlc2NBZnRlciB8fCAhZGVzY0FmdGVyLmlzVGV4dCh0ZXh0QWZ0ZXIubm9kZVZhbHVlKSkge1xuICAgICAgICAgICAgcmV0dXJuIHRleHRBZnRlcjtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIGlmICh2aWV3LmlucHV0LmNvbXBvc2l0aW9uTm9kZSA9PSB0ZXh0QWZ0ZXIpIHtcbiAgICAgICAgICAgIGxldCBkZXNjQmVmb3JlID0gdGV4dEJlZm9yZS5wbVZpZXdEZXNjO1xuICAgICAgICAgICAgaWYgKCEoIWRlc2NCZWZvcmUgfHwgIWRlc2NCZWZvcmUuaXNUZXh0KHRleHRCZWZvcmUubm9kZVZhbHVlKSkpXG4gICAgICAgICAgICAgICAgcmV0dXJuIHRleHRBZnRlcjtcbiAgICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gdGV4dEJlZm9yZSB8fCB0ZXh0QWZ0ZXI7XG59XG5mdW5jdGlvbiB0aW1lc3RhbXBGcm9tQ3VzdG9tRXZlbnQoKSB7XG4gICAgbGV0IGV2ZW50ID0gZG9jdW1lbnQuY3JlYXRlRXZlbnQoXCJFdmVudFwiKTtcbiAgICBldmVudC5pbml0RXZlbnQoXCJldmVudFwiLCB0cnVlLCB0cnVlKTtcbiAgICByZXR1cm4gZXZlbnQudGltZVN0YW1wO1xufVxuLyoqXG5AaW50ZXJuYWxcbiovXG5mdW5jdGlvbiBlbmRDb21wb3NpdGlvbih2aWV3LCByZXN0YXJ0aW5nID0gZmFsc2UpIHtcbiAgICBpZiAoYW5kcm9pZCAmJiB2aWV3LmRvbU9ic2VydmVyLmZsdXNoaW5nU29vbiA+PSAwKVxuICAgICAgICByZXR1cm47XG4gICAgdmlldy5kb21PYnNlcnZlci5mb3JjZUZsdXNoKCk7XG4gICAgY2xlYXJDb21wb3NpdGlvbih2aWV3KTtcbiAgICBpZiAocmVzdGFydGluZyB8fCB2aWV3LmRvY1ZpZXcgJiYgdmlldy5kb2NWaWV3LmRpcnR5KSB7XG4gICAgICAgIGxldCBzZWwgPSBzZWxlY3Rpb25Gcm9tRE9NKHZpZXcpLCBjdXIgPSB2aWV3LnN0YXRlLnNlbGVjdGlvbjtcbiAgICAgICAgaWYgKHNlbCAmJiAhc2VsLmVxKGN1cikpXG4gICAgICAgICAgICB2aWV3LmRpc3BhdGNoKHZpZXcuc3RhdGUudHIuc2V0U2VsZWN0aW9uKHNlbCkpO1xuICAgICAgICBlbHNlIGlmICgodmlldy5tYXJrQ3Vyc29yIHx8IHJlc3RhcnRpbmcpICYmICFjdXIuJGZyb20ubm9kZShjdXIuJGZyb20uc2hhcmVkRGVwdGgoY3VyLnRvKSkuaW5saW5lQ29udGVudClcbiAgICAgICAgICAgIHZpZXcuZGlzcGF0Y2godmlldy5zdGF0ZS50ci5kZWxldGVTZWxlY3Rpb24oKSk7XG4gICAgICAgIGVsc2VcbiAgICAgICAgICAgIHZpZXcudXBkYXRlU3RhdGUodmlldy5zdGF0ZSk7XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cbiAgICByZXR1cm4gZmFsc2U7XG59XG5mdW5jdGlvbiBjYXB0dXJlQ29weSh2aWV3LCBkb20pIHtcbiAgICAvLyBUaGUgZXh0cmEgd3JhcHBlciBpcyBzb21laG93IG5lY2Vzc2FyeSBvbiBJRS9FZGdlIHRvIHByZXZlbnQgdGhlXG4gICAgLy8gY29udGVudCBmcm9tIGJlaW5nIG1hbmdsZWQgd2hlbiBpdCBpcyBwdXQgb250byB0aGUgY2xpcGJvYXJkXG4gICAgaWYgKCF2aWV3LmRvbS5wYXJlbnROb2RlKVxuICAgICAgICByZXR1cm47XG4gICAgbGV0IHdyYXAgPSB2aWV3LmRvbS5wYXJlbnROb2RlLmFwcGVuZENoaWxkKGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoXCJkaXZcIikpO1xuICAgIHdyYXAuYXBwZW5kQ2hpbGQoZG9tKTtcbiAgICB3cmFwLnN0eWxlLmNzc1RleHQgPSBcInBvc2l0aW9uOiBmaXhlZDsgbGVmdDogLTEwMDAwcHg7IHRvcDogMTBweFwiO1xuICAgIGxldCBzZWwgPSBnZXRTZWxlY3Rpb24oKSwgcmFuZ2UgPSBkb2N1bWVudC5jcmVhdGVSYW5nZSgpO1xuICAgIHJhbmdlLnNlbGVjdE5vZGVDb250ZW50cyhkb20pO1xuICAgIC8vIERvbmUgYmVjYXVzZSBJRSB3aWxsIGZpcmUgYSBzZWxlY3Rpb25jaGFuZ2UgbW92aW5nIHRoZSBzZWxlY3Rpb25cbiAgICAvLyB0byBpdHMgc3RhcnQgd2hlbiByZW1vdmVBbGxSYW5nZXMgaXMgY2FsbGVkIGFuZCB0aGUgZWRpdG9yIHN0aWxsXG4gICAgLy8gaGFzIGZvY3VzICh3aGljaCB3aWxsIG1lc3MgdXAgdGhlIGVkaXRvcidzIHNlbGVjdGlvbiBzdGF0ZSkuXG4gICAgdmlldy5kb20uYmx1cigpO1xuICAgIHNlbC5yZW1vdmVBbGxSYW5nZXMoKTtcbiAgICBzZWwuYWRkUmFuZ2UocmFuZ2UpO1xuICAgIHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgICBpZiAod3JhcC5wYXJlbnROb2RlKVxuICAgICAgICAgICAgd3JhcC5wYXJlbnROb2RlLnJlbW92ZUNoaWxkKHdyYXApO1xuICAgICAgICB2aWV3LmZvY3VzKCk7XG4gICAgfSwgNTApO1xufVxuLy8gVGhpcyBpcyB2ZXJ5IGNydWRlLCBidXQgdW5mb3J0dW5hdGVseSBib3RoIHRoZXNlIGJyb3dzZXJzIF9wcmV0ZW5kX1xuLy8gdGhhdCB0aGV5IGhhdmUgYSBjbGlwYm9hcmQgQVBJ4oCUYWxsIHRoZSBvYmplY3RzIGFuZCBtZXRob2RzIGFyZVxuLy8gdGhlcmUsIHRoZXkganVzdCBkb24ndCB3b3JrLCBhbmQgdGhleSBhcmUgaGFyZCB0byB0ZXN0LlxuY29uc3QgYnJva2VuQ2xpcGJvYXJkQVBJID0gKGllICYmIGllX3ZlcnNpb24gPCAxNSkgfHxcbiAgICAoaW9zICYmIHdlYmtpdF92ZXJzaW9uIDwgNjA0KTtcbmhhbmRsZXJzLmNvcHkgPSBlZGl0SGFuZGxlcnMuY3V0ID0gKHZpZXcsIF9ldmVudCkgPT4ge1xuICAgIGxldCBldmVudCA9IF9ldmVudDtcbiAgICBsZXQgc2VsID0gdmlldy5zdGF0ZS5zZWxlY3Rpb24sIGN1dCA9IGV2ZW50LnR5cGUgPT0gXCJjdXRcIjtcbiAgICBpZiAoc2VsLmVtcHR5KVxuICAgICAgICByZXR1cm47XG4gICAgLy8gSUUgYW5kIEVkZ2UncyBjbGlwYm9hcmQgaW50ZXJmYWNlIGlzIGNvbXBsZXRlbHkgYnJva2VuXG4gICAgbGV0IGRhdGEgPSBicm9rZW5DbGlwYm9hcmRBUEkgPyBudWxsIDogZXZlbnQuY2xpcGJvYXJkRGF0YTtcbiAgICBsZXQgc2xpY2UgPSBzZWwuY29udGVudCgpLCB7IGRvbSwgdGV4dCB9ID0gc2VyaWFsaXplRm9yQ2xpcGJvYXJkKHZpZXcsIHNsaWNlKTtcbiAgICBpZiAoZGF0YSkge1xuICAgICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICBkYXRhLmNsZWFyRGF0YSgpO1xuICAgICAgICBkYXRhLnNldERhdGEoXCJ0ZXh0L2h0bWxcIiwgZG9tLmlubmVySFRNTCk7XG4gICAgICAgIGRhdGEuc2V0RGF0YShcInRleHQvcGxhaW5cIiwgdGV4dCk7XG4gICAgfVxuICAgIGVsc2Uge1xuICAgICAgICBjYXB0dXJlQ29weSh2aWV3LCBkb20pO1xuICAgIH1cbiAgICBpZiAoY3V0KVxuICAgICAgICB2aWV3LmRpc3BhdGNoKHZpZXcuc3RhdGUudHIuZGVsZXRlU2VsZWN0aW9uKCkuc2Nyb2xsSW50b1ZpZXcoKS5zZXRNZXRhKFwidWlFdmVudFwiLCBcImN1dFwiKSk7XG59O1xuZnVuY3Rpb24gc2xpY2VTaW5nbGVOb2RlKHNsaWNlKSB7XG4gICAgcmV0dXJuIHNsaWNlLm9wZW5TdGFydCA9PSAwICYmIHNsaWNlLm9wZW5FbmQgPT0gMCAmJiBzbGljZS5jb250ZW50LmNoaWxkQ291bnQgPT0gMSA/IHNsaWNlLmNvbnRlbnQuZmlyc3RDaGlsZCA6IG51bGw7XG59XG5mdW5jdGlvbiBjYXB0dXJlUGFzdGUodmlldywgZXZlbnQpIHtcbiAgICBpZiAoIXZpZXcuZG9tLnBhcmVudE5vZGUpXG4gICAgICAgIHJldHVybjtcbiAgICBsZXQgcGxhaW5UZXh0ID0gdmlldy5pbnB1dC5zaGlmdEtleSB8fCB2aWV3LnN0YXRlLnNlbGVjdGlvbi4kZnJvbS5wYXJlbnQudHlwZS5zcGVjLmNvZGU7XG4gICAgbGV0IHRhcmdldCA9IHZpZXcuZG9tLnBhcmVudE5vZGUuYXBwZW5kQ2hpbGQoZG9jdW1lbnQuY3JlYXRlRWxlbWVudChwbGFpblRleHQgPyBcInRleHRhcmVhXCIgOiBcImRpdlwiKSk7XG4gICAgaWYgKCFwbGFpblRleHQpXG4gICAgICAgIHRhcmdldC5jb250ZW50RWRpdGFibGUgPSBcInRydWVcIjtcbiAgICB0YXJnZXQuc3R5bGUuY3NzVGV4dCA9IFwicG9zaXRpb246IGZpeGVkOyBsZWZ0OiAtMTAwMDBweDsgdG9wOiAxMHB4XCI7XG4gICAgdGFyZ2V0LmZvY3VzKCk7XG4gICAgbGV0IHBsYWluID0gdmlldy5pbnB1dC5zaGlmdEtleSAmJiB2aWV3LmlucHV0Lmxhc3RLZXlDb2RlICE9IDQ1O1xuICAgIHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgICB2aWV3LmZvY3VzKCk7XG4gICAgICAgIGlmICh0YXJnZXQucGFyZW50Tm9kZSlcbiAgICAgICAgICAgIHRhcmdldC5wYXJlbnROb2RlLnJlbW92ZUNoaWxkKHRhcmdldCk7XG4gICAgICAgIGlmIChwbGFpblRleHQpXG4gICAgICAgICAgICBkb1Bhc3RlKHZpZXcsIHRhcmdldC52YWx1ZSwgbnVsbCwgcGxhaW4sIGV2ZW50KTtcbiAgICAgICAgZWxzZVxuICAgICAgICAgICAgZG9QYXN0ZSh2aWV3LCB0YXJnZXQudGV4dENvbnRlbnQsIHRhcmdldC5pbm5lckhUTUwsIHBsYWluLCBldmVudCk7XG4gICAgfSwgNTApO1xufVxuZnVuY3Rpb24gZG9QYXN0ZSh2aWV3LCB0ZXh0LCBodG1sLCBwcmVmZXJQbGFpbiwgZXZlbnQpIHtcbiAgICBsZXQgc2xpY2UgPSBwYXJzZUZyb21DbGlwYm9hcmQodmlldywgdGV4dCwgaHRtbCwgcHJlZmVyUGxhaW4sIHZpZXcuc3RhdGUuc2VsZWN0aW9uLiRmcm9tKTtcbiAgICBpZiAodmlldy5zb21lUHJvcChcImhhbmRsZVBhc3RlXCIsIGYgPT4gZih2aWV3LCBldmVudCwgc2xpY2UgfHwgU2xpY2UuZW1wdHkpKSlcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgaWYgKCFzbGljZSlcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIGxldCBzaW5nbGVOb2RlID0gc2xpY2VTaW5nbGVOb2RlKHNsaWNlKTtcbiAgICBsZXQgdHIgPSBzaW5nbGVOb2RlXG4gICAgICAgID8gdmlldy5zdGF0ZS50ci5yZXBsYWNlU2VsZWN0aW9uV2l0aChzaW5nbGVOb2RlLCBwcmVmZXJQbGFpbilcbiAgICAgICAgOiB2aWV3LnN0YXRlLnRyLnJlcGxhY2VTZWxlY3Rpb24oc2xpY2UpO1xuICAgIHZpZXcuZGlzcGF0Y2godHIuc2Nyb2xsSW50b1ZpZXcoKS5zZXRNZXRhKFwicGFzdGVcIiwgdHJ1ZSkuc2V0TWV0YShcInVpRXZlbnRcIiwgXCJwYXN0ZVwiKSk7XG4gICAgcmV0dXJuIHRydWU7XG59XG5mdW5jdGlvbiBnZXRUZXh0KGNsaXBib2FyZERhdGEpIHtcbiAgICBsZXQgdGV4dCA9IGNsaXBib2FyZERhdGEuZ2V0RGF0YShcInRleHQvcGxhaW5cIikgfHwgY2xpcGJvYXJkRGF0YS5nZXREYXRhKFwiVGV4dFwiKTtcbiAgICBpZiAodGV4dClcbiAgICAgICAgcmV0dXJuIHRleHQ7XG4gICAgbGV0IHVyaXMgPSBjbGlwYm9hcmREYXRhLmdldERhdGEoXCJ0ZXh0L3VyaS1saXN0XCIpO1xuICAgIHJldHVybiB1cmlzID8gdXJpcy5yZXBsYWNlKC9cXHI/XFxuL2csIFwiIFwiKSA6IFwiXCI7XG59XG5lZGl0SGFuZGxlcnMucGFzdGUgPSAodmlldywgX2V2ZW50KSA9PiB7XG4gICAgbGV0IGV2ZW50ID0gX2V2ZW50O1xuICAgIC8vIEhhbmRsaW5nIHBhc3RlIGZyb20gSmF2YVNjcmlwdCBkdXJpbmcgY29tcG9zaXRpb24gaXMgdmVyeSBwb29ybHlcbiAgICAvLyBoYW5kbGVkIGJ5IGJyb3dzZXJzLCBzbyBhcyBhIGRvZGd5IGJ1dCBwcmVmZXJhYmxlIGtsdWRnZSwgd2UganVzdFxuICAgIC8vIGxldCB0aGUgYnJvd3NlciBkbyBpdHMgbmF0aXZlIHRoaW5nIHRoZXJlLCBleGNlcHQgb24gQW5kcm9pZCxcbiAgICAvLyB3aGVyZSB0aGUgZWRpdG9yIGlzIGFsbW9zdCBhbHdheXMgY29tcG9zaW5nLlxuICAgIGlmICh2aWV3LmNvbXBvc2luZyAmJiAhYW5kcm9pZClcbiAgICAgICAgcmV0dXJuO1xuICAgIGxldCBkYXRhID0gYnJva2VuQ2xpcGJvYXJkQVBJID8gbnVsbCA6IGV2ZW50LmNsaXBib2FyZERhdGE7XG4gICAgbGV0IHBsYWluID0gdmlldy5pbnB1dC5zaGlmdEtleSAmJiB2aWV3LmlucHV0Lmxhc3RLZXlDb2RlICE9IDQ1O1xuICAgIGlmIChkYXRhICYmIGRvUGFzdGUodmlldywgZ2V0VGV4dChkYXRhKSwgZGF0YS5nZXREYXRhKFwidGV4dC9odG1sXCIpLCBwbGFpbiwgZXZlbnQpKVxuICAgICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgIGVsc2VcbiAgICAgICAgY2FwdHVyZVBhc3RlKHZpZXcsIGV2ZW50KTtcbn07XG5jbGFzcyBEcmFnZ2luZyB7XG4gICAgY29uc3RydWN0b3Ioc2xpY2UsIG1vdmUsIG5vZGUpIHtcbiAgICAgICAgdGhpcy5zbGljZSA9IHNsaWNlO1xuICAgICAgICB0aGlzLm1vdmUgPSBtb3ZlO1xuICAgICAgICB0aGlzLm5vZGUgPSBub2RlO1xuICAgIH1cbn1cbmNvbnN0IGRyYWdDb3B5TW9kaWZpZXIgPSBtYWMgPyBcImFsdEtleVwiIDogXCJjdHJsS2V5XCI7XG5mdW5jdGlvbiBkcmFnTW92ZXModmlldywgZXZlbnQpIHtcbiAgICBsZXQgbW92ZXMgPSB2aWV3LnNvbWVQcm9wKFwiZHJhZ0NvcGllc1wiLCB0ZXN0ID0+ICF0ZXN0KGV2ZW50KSk7XG4gICAgcmV0dXJuIG1vdmVzICE9IG51bGwgPyBtb3ZlcyA6ICFldmVudFtkcmFnQ29weU1vZGlmaWVyXTtcbn1cbmhhbmRsZXJzLmRyYWdzdGFydCA9ICh2aWV3LCBfZXZlbnQpID0+IHtcbiAgICBsZXQgZXZlbnQgPSBfZXZlbnQ7XG4gICAgbGV0IG1vdXNlRG93biA9IHZpZXcuaW5wdXQubW91c2VEb3duO1xuICAgIGlmIChtb3VzZURvd24pXG4gICAgICAgIG1vdXNlRG93bi5kb25lKCk7XG4gICAgaWYgKCFldmVudC5kYXRhVHJhbnNmZXIpXG4gICAgICAgIHJldHVybjtcbiAgICBsZXQgc2VsID0gdmlldy5zdGF0ZS5zZWxlY3Rpb247XG4gICAgbGV0IHBvcyA9IHNlbC5lbXB0eSA/IG51bGwgOiB2aWV3LnBvc0F0Q29vcmRzKGV2ZW50Q29vcmRzKGV2ZW50KSk7XG4gICAgbGV0IG5vZGU7XG4gICAgaWYgKHBvcyAmJiBwb3MucG9zID49IHNlbC5mcm9tICYmIHBvcy5wb3MgPD0gKHNlbCBpbnN0YW5jZW9mIE5vZGVTZWxlY3Rpb24gPyBzZWwudG8gLSAxIDogc2VsLnRvKSkgO1xuICAgIGVsc2UgaWYgKG1vdXNlRG93biAmJiBtb3VzZURvd24ubWlnaHREcmFnKSB7XG4gICAgICAgIG5vZGUgPSBOb2RlU2VsZWN0aW9uLmNyZWF0ZSh2aWV3LnN0YXRlLmRvYywgbW91c2VEb3duLm1pZ2h0RHJhZy5wb3MpO1xuICAgIH1cbiAgICBlbHNlIGlmIChldmVudC50YXJnZXQgJiYgZXZlbnQudGFyZ2V0Lm5vZGVUeXBlID09IDEpIHtcbiAgICAgICAgbGV0IGRlc2MgPSB2aWV3LmRvY1ZpZXcubmVhcmVzdERlc2MoZXZlbnQudGFyZ2V0LCB0cnVlKTtcbiAgICAgICAgaWYgKGRlc2MgJiYgZGVzYy5ub2RlLnR5cGUuc3BlYy5kcmFnZ2FibGUgJiYgZGVzYyAhPSB2aWV3LmRvY1ZpZXcpXG4gICAgICAgICAgICBub2RlID0gTm9kZVNlbGVjdGlvbi5jcmVhdGUodmlldy5zdGF0ZS5kb2MsIGRlc2MucG9zQmVmb3JlKTtcbiAgICB9XG4gICAgbGV0IGRyYWdnZWRTbGljZSA9IChub2RlIHx8IHZpZXcuc3RhdGUuc2VsZWN0aW9uKS5jb250ZW50KCk7XG4gICAgbGV0IHsgZG9tLCB0ZXh0LCBzbGljZSB9ID0gc2VyaWFsaXplRm9yQ2xpcGJvYXJkKHZpZXcsIGRyYWdnZWRTbGljZSk7XG4gICAgLy8gUHJlLTEyMCBDaHJvbWUgdmVyc2lvbnMgY2xlYXIgZmlsZXMgd2hlbiBjYWxsaW5nIGBjbGVhckRhdGFgICgjMTQ3MilcbiAgICBpZiAoIWV2ZW50LmRhdGFUcmFuc2Zlci5maWxlcy5sZW5ndGggfHwgIWNocm9tZSB8fCBjaHJvbWVfdmVyc2lvbiA+IDEyMClcbiAgICAgICAgZXZlbnQuZGF0YVRyYW5zZmVyLmNsZWFyRGF0YSgpO1xuICAgIGV2ZW50LmRhdGFUcmFuc2Zlci5zZXREYXRhKGJyb2tlbkNsaXBib2FyZEFQSSA/IFwiVGV4dFwiIDogXCJ0ZXh0L2h0bWxcIiwgZG9tLmlubmVySFRNTCk7XG4gICAgLy8gU2VlIGh0dHBzOi8vZ2l0aHViLmNvbS9Qcm9zZU1pcnJvci9wcm9zZW1pcnJvci9pc3N1ZXMvMTE1NlxuICAgIGV2ZW50LmRhdGFUcmFuc2Zlci5lZmZlY3RBbGxvd2VkID0gXCJjb3B5TW92ZVwiO1xuICAgIGlmICghYnJva2VuQ2xpcGJvYXJkQVBJKVxuICAgICAgICBldmVudC5kYXRhVHJhbnNmZXIuc2V0RGF0YShcInRleHQvcGxhaW5cIiwgdGV4dCk7XG4gICAgdmlldy5kcmFnZ2luZyA9IG5ldyBEcmFnZ2luZyhzbGljZSwgZHJhZ01vdmVzKHZpZXcsIGV2ZW50KSwgbm9kZSk7XG59O1xuaGFuZGxlcnMuZHJhZ2VuZCA9IHZpZXcgPT4ge1xuICAgIGxldCBkcmFnZ2luZyA9IHZpZXcuZHJhZ2dpbmc7XG4gICAgd2luZG93LnNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgICBpZiAodmlldy5kcmFnZ2luZyA9PSBkcmFnZ2luZylcbiAgICAgICAgICAgIHZpZXcuZHJhZ2dpbmcgPSBudWxsO1xuICAgIH0sIDUwKTtcbn07XG5lZGl0SGFuZGxlcnMuZHJhZ292ZXIgPSBlZGl0SGFuZGxlcnMuZHJhZ2VudGVyID0gKF8sIGUpID0+IGUucHJldmVudERlZmF1bHQoKTtcbmVkaXRIYW5kbGVycy5kcm9wID0gKHZpZXcsIGV2ZW50KSA9PiB7XG4gICAgdHJ5IHtcbiAgICAgICAgaGFuZGxlRHJvcCh2aWV3LCBldmVudCwgdmlldy5kcmFnZ2luZyk7XG4gICAgfVxuICAgIGZpbmFsbHkge1xuICAgICAgICB2aWV3LmRyYWdnaW5nID0gbnVsbDtcbiAgICB9XG59O1xuZnVuY3Rpb24gaGFuZGxlRHJvcCh2aWV3LCBldmVudCwgZHJhZ2dpbmcpIHtcbiAgICBpZiAoIWV2ZW50LmRhdGFUcmFuc2ZlcilcbiAgICAgICAgcmV0dXJuO1xuICAgIGxldCBldmVudFBvcyA9IHZpZXcucG9zQXRDb29yZHMoZXZlbnRDb29yZHMoZXZlbnQpKTtcbiAgICBpZiAoIWV2ZW50UG9zKVxuICAgICAgICByZXR1cm47XG4gICAgbGV0ICRtb3VzZSA9IHZpZXcuc3RhdGUuZG9jLnJlc29sdmUoZXZlbnRQb3MucG9zKTtcbiAgICBsZXQgc2xpY2UgPSBkcmFnZ2luZyAmJiBkcmFnZ2luZy5zbGljZTtcbiAgICBpZiAoc2xpY2UpIHtcbiAgICAgICAgdmlldy5zb21lUHJvcChcInRyYW5zZm9ybVBhc3RlZFwiLCBmID0+IHsgc2xpY2UgPSBmKHNsaWNlLCB2aWV3LCBmYWxzZSk7IH0pO1xuICAgIH1cbiAgICBlbHNlIHtcbiAgICAgICAgc2xpY2UgPSBwYXJzZUZyb21DbGlwYm9hcmQodmlldywgZ2V0VGV4dChldmVudC5kYXRhVHJhbnNmZXIpLCBicm9rZW5DbGlwYm9hcmRBUEkgPyBudWxsIDogZXZlbnQuZGF0YVRyYW5zZmVyLmdldERhdGEoXCJ0ZXh0L2h0bWxcIiksIGZhbHNlLCAkbW91c2UpO1xuICAgIH1cbiAgICBsZXQgbW92ZSA9ICEhKGRyYWdnaW5nICYmIGRyYWdNb3Zlcyh2aWV3LCBldmVudCkpO1xuICAgIGlmICh2aWV3LnNvbWVQcm9wKFwiaGFuZGxlRHJvcFwiLCBmID0+IGYodmlldywgZXZlbnQsIHNsaWNlIHx8IFNsaWNlLmVtcHR5LCBtb3ZlKSkpIHtcbiAgICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBpZiAoIXNsaWNlKVxuICAgICAgICByZXR1cm47XG4gICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICBsZXQgaW5zZXJ0UG9zID0gc2xpY2UgPyBkcm9wUG9pbnQodmlldy5zdGF0ZS5kb2MsICRtb3VzZS5wb3MsIHNsaWNlKSA6ICRtb3VzZS5wb3M7XG4gICAgaWYgKGluc2VydFBvcyA9PSBudWxsKVxuICAgICAgICBpbnNlcnRQb3MgPSAkbW91c2UucG9zO1xuICAgIGxldCB0ciA9IHZpZXcuc3RhdGUudHI7XG4gICAgaWYgKG1vdmUpIHtcbiAgICAgICAgbGV0IHsgbm9kZSB9ID0gZHJhZ2dpbmc7XG4gICAgICAgIGlmIChub2RlKVxuICAgICAgICAgICAgbm9kZS5yZXBsYWNlKHRyKTtcbiAgICAgICAgZWxzZVxuICAgICAgICAgICAgdHIuZGVsZXRlU2VsZWN0aW9uKCk7XG4gICAgfVxuICAgIGxldCBwb3MgPSB0ci5tYXBwaW5nLm1hcChpbnNlcnRQb3MpO1xuICAgIGxldCBpc05vZGUgPSBzbGljZS5vcGVuU3RhcnQgPT0gMCAmJiBzbGljZS5vcGVuRW5kID09IDAgJiYgc2xpY2UuY29udGVudC5jaGlsZENvdW50ID09IDE7XG4gICAgbGV0IGJlZm9yZUluc2VydCA9IHRyLmRvYztcbiAgICBpZiAoaXNOb2RlKVxuICAgICAgICB0ci5yZXBsYWNlUmFuZ2VXaXRoKHBvcywgcG9zLCBzbGljZS5jb250ZW50LmZpcnN0Q2hpbGQpO1xuICAgIGVsc2VcbiAgICAgICAgdHIucmVwbGFjZVJhbmdlKHBvcywgcG9zLCBzbGljZSk7XG4gICAgaWYgKHRyLmRvYy5lcShiZWZvcmVJbnNlcnQpKVxuICAgICAgICByZXR1cm47XG4gICAgbGV0ICRwb3MgPSB0ci5kb2MucmVzb2x2ZShwb3MpO1xuICAgIGlmIChpc05vZGUgJiYgTm9kZVNlbGVjdGlvbi5pc1NlbGVjdGFibGUoc2xpY2UuY29udGVudC5maXJzdENoaWxkKSAmJlxuICAgICAgICAkcG9zLm5vZGVBZnRlciAmJiAkcG9zLm5vZGVBZnRlci5zYW1lTWFya3VwKHNsaWNlLmNvbnRlbnQuZmlyc3RDaGlsZCkpIHtcbiAgICAgICAgdHIuc2V0U2VsZWN0aW9uKG5ldyBOb2RlU2VsZWN0aW9uKCRwb3MpKTtcbiAgICB9XG4gICAgZWxzZSB7XG4gICAgICAgIGxldCBlbmQgPSB0ci5tYXBwaW5nLm1hcChpbnNlcnRQb3MpO1xuICAgICAgICB0ci5tYXBwaW5nLm1hcHNbdHIubWFwcGluZy5tYXBzLmxlbmd0aCAtIDFdLmZvckVhY2goKF9mcm9tLCBfdG8sIF9uZXdGcm9tLCBuZXdUbykgPT4gZW5kID0gbmV3VG8pO1xuICAgICAgICB0ci5zZXRTZWxlY3Rpb24oc2VsZWN0aW9uQmV0d2Vlbih2aWV3LCAkcG9zLCB0ci5kb2MucmVzb2x2ZShlbmQpKSk7XG4gICAgfVxuICAgIHZpZXcuZm9jdXMoKTtcbiAgICB2aWV3LmRpc3BhdGNoKHRyLnNldE1ldGEoXCJ1aUV2ZW50XCIsIFwiZHJvcFwiKSk7XG59XG5oYW5kbGVycy5mb2N1cyA9IHZpZXcgPT4ge1xuICAgIHZpZXcuaW5wdXQubGFzdEZvY3VzID0gRGF0ZS5ub3coKTtcbiAgICBpZiAoIXZpZXcuZm9jdXNlZCkge1xuICAgICAgICB2aWV3LmRvbU9ic2VydmVyLnN0b3AoKTtcbiAgICAgICAgdmlldy5kb20uY2xhc3NMaXN0LmFkZChcIlByb3NlTWlycm9yLWZvY3VzZWRcIik7XG4gICAgICAgIHZpZXcuZG9tT2JzZXJ2ZXIuc3RhcnQoKTtcbiAgICAgICAgdmlldy5mb2N1c2VkID0gdHJ1ZTtcbiAgICAgICAgc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICAgICAgICBpZiAodmlldy5kb2NWaWV3ICYmIHZpZXcuaGFzRm9jdXMoKSAmJiAhdmlldy5kb21PYnNlcnZlci5jdXJyZW50U2VsZWN0aW9uLmVxKHZpZXcuZG9tU2VsZWN0aW9uUmFuZ2UoKSkpXG4gICAgICAgICAgICAgICAgc2VsZWN0aW9uVG9ET00odmlldyk7XG4gICAgICAgIH0sIDIwKTtcbiAgICB9XG59O1xuaGFuZGxlcnMuYmx1ciA9ICh2aWV3LCBfZXZlbnQpID0+IHtcbiAgICBsZXQgZXZlbnQgPSBfZXZlbnQ7XG4gICAgaWYgKHZpZXcuZm9jdXNlZCkge1xuICAgICAgICB2aWV3LmRvbU9ic2VydmVyLnN0b3AoKTtcbiAgICAgICAgdmlldy5kb20uY2xhc3NMaXN0LnJlbW92ZShcIlByb3NlTWlycm9yLWZvY3VzZWRcIik7XG4gICAgICAgIHZpZXcuZG9tT2JzZXJ2ZXIuc3RhcnQoKTtcbiAgICAgICAgaWYgKGV2ZW50LnJlbGF0ZWRUYXJnZXQgJiYgdmlldy5kb20uY29udGFpbnMoZXZlbnQucmVsYXRlZFRhcmdldCkpXG4gICAgICAgICAgICB2aWV3LmRvbU9ic2VydmVyLmN1cnJlbnRTZWxlY3Rpb24uY2xlYXIoKTtcbiAgICAgICAgdmlldy5mb2N1c2VkID0gZmFsc2U7XG4gICAgfVxufTtcbmhhbmRsZXJzLmJlZm9yZWlucHV0ID0gKHZpZXcsIF9ldmVudCkgPT4ge1xuICAgIGxldCBldmVudCA9IF9ldmVudDtcbiAgICAvLyBXZSBzaG91bGQgcHJvYmFibHkgZG8gbW9yZSB3aXRoIGJlZm9yZWlucHV0IGV2ZW50cywgYnV0IHN1cHBvcnRcbiAgICAvLyBpcyBzbyBzcG90dHkgdGhhdCBJJ20gc3RpbGwgd2FpdGluZyB0byBzZWUgd2hlcmUgdGhleSBhcmUgZ29pbmcuXG4gICAgLy8gVmVyeSBzcGVjaWZpYyBoYWNrIHRvIGRlYWwgd2l0aCBiYWNrc3BhY2Ugc29tZXRpbWVzIGZhaWxpbmcgb25cbiAgICAvLyBDaHJvbWUgQW5kcm9pZCB3aGVuIGFmdGVyIGFuIHVuZWRpdGFibGUgbm9kZS5cbiAgICBpZiAoY2hyb21lICYmIGFuZHJvaWQgJiYgZXZlbnQuaW5wdXRUeXBlID09IFwiZGVsZXRlQ29udGVudEJhY2t3YXJkXCIpIHtcbiAgICAgICAgdmlldy5kb21PYnNlcnZlci5mbHVzaFNvb24oKTtcbiAgICAgICAgbGV0IHsgZG9tQ2hhbmdlQ291bnQgfSA9IHZpZXcuaW5wdXQ7XG4gICAgICAgIHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgICAgICAgaWYgKHZpZXcuaW5wdXQuZG9tQ2hhbmdlQ291bnQgIT0gZG9tQ2hhbmdlQ291bnQpXG4gICAgICAgICAgICAgICAgcmV0dXJuOyAvLyBFdmVudCBhbHJlYWR5IGhhZCBzb21lIGVmZmVjdFxuICAgICAgICAgICAgLy8gVGhpcyBidWcgdGVuZHMgdG8gY2xvc2UgdGhlIHZpcnR1YWwga2V5Ym9hcmQsIHNvIHdlIHJlZm9jdXNcbiAgICAgICAgICAgIHZpZXcuZG9tLmJsdXIoKTtcbiAgICAgICAgICAgIHZpZXcuZm9jdXMoKTtcbiAgICAgICAgICAgIGlmICh2aWV3LnNvbWVQcm9wKFwiaGFuZGxlS2V5RG93blwiLCBmID0+IGYodmlldywga2V5RXZlbnQoOCwgXCJCYWNrc3BhY2VcIikpKSlcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICBsZXQgeyAkY3Vyc29yIH0gPSB2aWV3LnN0YXRlLnNlbGVjdGlvbjtcbiAgICAgICAgICAgIC8vIENydWRlIGFwcHJveGltYXRpb24gb2YgYmFja3NwYWNlIGJlaGF2aW9yIHdoZW4gbm8gY29tbWFuZCBoYW5kbGVkIGl0XG4gICAgICAgICAgICBpZiAoJGN1cnNvciAmJiAkY3Vyc29yLnBvcyA+IDApXG4gICAgICAgICAgICAgICAgdmlldy5kaXNwYXRjaCh2aWV3LnN0YXRlLnRyLmRlbGV0ZSgkY3Vyc29yLnBvcyAtIDEsICRjdXJzb3IucG9zKS5zY3JvbGxJbnRvVmlldygpKTtcbiAgICAgICAgfSwgNTApO1xuICAgIH1cbn07XG4vLyBNYWtlIHN1cmUgYWxsIGhhbmRsZXJzIGdldCByZWdpc3RlcmVkXG5mb3IgKGxldCBwcm9wIGluIGVkaXRIYW5kbGVycylcbiAgICBoYW5kbGVyc1twcm9wXSA9IGVkaXRIYW5kbGVyc1twcm9wXTtcblxuZnVuY3Rpb24gY29tcGFyZU9ianMoYSwgYikge1xuICAgIGlmIChhID09IGIpXG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgIGZvciAobGV0IHAgaW4gYSlcbiAgICAgICAgaWYgKGFbcF0gIT09IGJbcF0pXG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgZm9yIChsZXQgcCBpbiBiKVxuICAgICAgICBpZiAoIShwIGluIGEpKVxuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIHJldHVybiB0cnVlO1xufVxuY2xhc3MgV2lkZ2V0VHlwZSB7XG4gICAgY29uc3RydWN0b3IodG9ET00sIHNwZWMpIHtcbiAgICAgICAgdGhpcy50b0RPTSA9IHRvRE9NO1xuICAgICAgICB0aGlzLnNwZWMgPSBzcGVjIHx8IG5vU3BlYztcbiAgICAgICAgdGhpcy5zaWRlID0gdGhpcy5zcGVjLnNpZGUgfHwgMDtcbiAgICB9XG4gICAgbWFwKG1hcHBpbmcsIHNwYW4sIG9mZnNldCwgb2xkT2Zmc2V0KSB7XG4gICAgICAgIGxldCB7IHBvcywgZGVsZXRlZCB9ID0gbWFwcGluZy5tYXBSZXN1bHQoc3Bhbi5mcm9tICsgb2xkT2Zmc2V0LCB0aGlzLnNpZGUgPCAwID8gLTEgOiAxKTtcbiAgICAgICAgcmV0dXJuIGRlbGV0ZWQgPyBudWxsIDogbmV3IERlY29yYXRpb24ocG9zIC0gb2Zmc2V0LCBwb3MgLSBvZmZzZXQsIHRoaXMpO1xuICAgIH1cbiAgICB2YWxpZCgpIHsgcmV0dXJuIHRydWU7IH1cbiAgICBlcShvdGhlcikge1xuICAgICAgICByZXR1cm4gdGhpcyA9PSBvdGhlciB8fFxuICAgICAgICAgICAgKG90aGVyIGluc3RhbmNlb2YgV2lkZ2V0VHlwZSAmJlxuICAgICAgICAgICAgICAgICh0aGlzLnNwZWMua2V5ICYmIHRoaXMuc3BlYy5rZXkgPT0gb3RoZXIuc3BlYy5rZXkgfHxcbiAgICAgICAgICAgICAgICAgICAgdGhpcy50b0RPTSA9PSBvdGhlci50b0RPTSAmJiBjb21wYXJlT2Jqcyh0aGlzLnNwZWMsIG90aGVyLnNwZWMpKSk7XG4gICAgfVxuICAgIGRlc3Ryb3kobm9kZSkge1xuICAgICAgICBpZiAodGhpcy5zcGVjLmRlc3Ryb3kpXG4gICAgICAgICAgICB0aGlzLnNwZWMuZGVzdHJveShub2RlKTtcbiAgICB9XG59XG5jbGFzcyBJbmxpbmVUeXBlIHtcbiAgICBjb25zdHJ1Y3RvcihhdHRycywgc3BlYykge1xuICAgICAgICB0aGlzLmF0dHJzID0gYXR0cnM7XG4gICAgICAgIHRoaXMuc3BlYyA9IHNwZWMgfHwgbm9TcGVjO1xuICAgIH1cbiAgICBtYXAobWFwcGluZywgc3Bhbiwgb2Zmc2V0LCBvbGRPZmZzZXQpIHtcbiAgICAgICAgbGV0IGZyb20gPSBtYXBwaW5nLm1hcChzcGFuLmZyb20gKyBvbGRPZmZzZXQsIHRoaXMuc3BlYy5pbmNsdXNpdmVTdGFydCA/IC0xIDogMSkgLSBvZmZzZXQ7XG4gICAgICAgIGxldCB0byA9IG1hcHBpbmcubWFwKHNwYW4udG8gKyBvbGRPZmZzZXQsIHRoaXMuc3BlYy5pbmNsdXNpdmVFbmQgPyAxIDogLTEpIC0gb2Zmc2V0O1xuICAgICAgICByZXR1cm4gZnJvbSA+PSB0byA/IG51bGwgOiBuZXcgRGVjb3JhdGlvbihmcm9tLCB0bywgdGhpcyk7XG4gICAgfVxuICAgIHZhbGlkKF8sIHNwYW4pIHsgcmV0dXJuIHNwYW4uZnJvbSA8IHNwYW4udG87IH1cbiAgICBlcShvdGhlcikge1xuICAgICAgICByZXR1cm4gdGhpcyA9PSBvdGhlciB8fFxuICAgICAgICAgICAgKG90aGVyIGluc3RhbmNlb2YgSW5saW5lVHlwZSAmJiBjb21wYXJlT2Jqcyh0aGlzLmF0dHJzLCBvdGhlci5hdHRycykgJiZcbiAgICAgICAgICAgICAgICBjb21wYXJlT2Jqcyh0aGlzLnNwZWMsIG90aGVyLnNwZWMpKTtcbiAgICB9XG4gICAgc3RhdGljIGlzKHNwYW4pIHsgcmV0dXJuIHNwYW4udHlwZSBpbnN0YW5jZW9mIElubGluZVR5cGU7IH1cbiAgICBkZXN0cm95KCkgeyB9XG59XG5jbGFzcyBOb2RlVHlwZSB7XG4gICAgY29uc3RydWN0b3IoYXR0cnMsIHNwZWMpIHtcbiAgICAgICAgdGhpcy5hdHRycyA9IGF0dHJzO1xuICAgICAgICB0aGlzLnNwZWMgPSBzcGVjIHx8IG5vU3BlYztcbiAgICB9XG4gICAgbWFwKG1hcHBpbmcsIHNwYW4sIG9mZnNldCwgb2xkT2Zmc2V0KSB7XG4gICAgICAgIGxldCBmcm9tID0gbWFwcGluZy5tYXBSZXN1bHQoc3Bhbi5mcm9tICsgb2xkT2Zmc2V0LCAxKTtcbiAgICAgICAgaWYgKGZyb20uZGVsZXRlZClcbiAgICAgICAgICAgIHJldHVybiBudWxsO1xuICAgICAgICBsZXQgdG8gPSBtYXBwaW5nLm1hcFJlc3VsdChzcGFuLnRvICsgb2xkT2Zmc2V0LCAtMSk7XG4gICAgICAgIGlmICh0by5kZWxldGVkIHx8IHRvLnBvcyA8PSBmcm9tLnBvcylcbiAgICAgICAgICAgIHJldHVybiBudWxsO1xuICAgICAgICByZXR1cm4gbmV3IERlY29yYXRpb24oZnJvbS5wb3MgLSBvZmZzZXQsIHRvLnBvcyAtIG9mZnNldCwgdGhpcyk7XG4gICAgfVxuICAgIHZhbGlkKG5vZGUsIHNwYW4pIHtcbiAgICAgICAgbGV0IHsgaW5kZXgsIG9mZnNldCB9ID0gbm9kZS5jb250ZW50LmZpbmRJbmRleChzcGFuLmZyb20pLCBjaGlsZDtcbiAgICAgICAgcmV0dXJuIG9mZnNldCA9PSBzcGFuLmZyb20gJiYgIShjaGlsZCA9IG5vZGUuY2hpbGQoaW5kZXgpKS5pc1RleHQgJiYgb2Zmc2V0ICsgY2hpbGQubm9kZVNpemUgPT0gc3Bhbi50bztcbiAgICB9XG4gICAgZXEob3RoZXIpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMgPT0gb3RoZXIgfHxcbiAgICAgICAgICAgIChvdGhlciBpbnN0YW5jZW9mIE5vZGVUeXBlICYmIGNvbXBhcmVPYmpzKHRoaXMuYXR0cnMsIG90aGVyLmF0dHJzKSAmJlxuICAgICAgICAgICAgICAgIGNvbXBhcmVPYmpzKHRoaXMuc3BlYywgb3RoZXIuc3BlYykpO1xuICAgIH1cbiAgICBkZXN0cm95KCkgeyB9XG59XG4vKipcbkRlY29yYXRpb24gb2JqZWN0cyBjYW4gYmUgcHJvdmlkZWQgdG8gdGhlIHZpZXcgdGhyb3VnaCB0aGVcbltgZGVjb3JhdGlvbnNgIHByb3BdKGh0dHBzOi8vcHJvc2VtaXJyb3IubmV0L2RvY3MvcmVmLyN2aWV3LkVkaXRvclByb3BzLmRlY29yYXRpb25zKS4gVGhleSBjb21lIGluXG5zZXZlcmFsIHZhcmlhbnRz4oCUc2VlIHRoZSBzdGF0aWMgbWVtYmVycyBvZiB0aGlzIGNsYXNzIGZvciBkZXRhaWxzLlxuKi9cbmNsYXNzIERlY29yYXRpb24ge1xuICAgIC8qKlxuICAgIEBpbnRlcm5hbFxuICAgICovXG4gICAgY29uc3RydWN0b3IoXG4gICAgLyoqXG4gICAgVGhlIHN0YXJ0IHBvc2l0aW9uIG9mIHRoZSBkZWNvcmF0aW9uLlxuICAgICovXG4gICAgZnJvbSwgXG4gICAgLyoqXG4gICAgVGhlIGVuZCBwb3NpdGlvbi4gV2lsbCBiZSB0aGUgc2FtZSBhcyBgZnJvbWAgZm9yIFt3aWRnZXRcbiAgICBkZWNvcmF0aW9uc10oaHR0cHM6Ly9wcm9zZW1pcnJvci5uZXQvZG9jcy9yZWYvI3ZpZXcuRGVjb3JhdGlvbl53aWRnZXQpLlxuICAgICovXG4gICAgdG8sIFxuICAgIC8qKlxuICAgIEBpbnRlcm5hbFxuICAgICovXG4gICAgdHlwZSkge1xuICAgICAgICB0aGlzLmZyb20gPSBmcm9tO1xuICAgICAgICB0aGlzLnRvID0gdG87XG4gICAgICAgIHRoaXMudHlwZSA9IHR5cGU7XG4gICAgfVxuICAgIC8qKlxuICAgIEBpbnRlcm5hbFxuICAgICovXG4gICAgY29weShmcm9tLCB0bykge1xuICAgICAgICByZXR1cm4gbmV3IERlY29yYXRpb24oZnJvbSwgdG8sIHRoaXMudHlwZSk7XG4gICAgfVxuICAgIC8qKlxuICAgIEBpbnRlcm5hbFxuICAgICovXG4gICAgZXEob3RoZXIsIG9mZnNldCA9IDApIHtcbiAgICAgICAgcmV0dXJuIHRoaXMudHlwZS5lcShvdGhlci50eXBlKSAmJiB0aGlzLmZyb20gKyBvZmZzZXQgPT0gb3RoZXIuZnJvbSAmJiB0aGlzLnRvICsgb2Zmc2V0ID09IG90aGVyLnRvO1xuICAgIH1cbiAgICAvKipcbiAgICBAaW50ZXJuYWxcbiAgICAqL1xuICAgIG1hcChtYXBwaW5nLCBvZmZzZXQsIG9sZE9mZnNldCkge1xuICAgICAgICByZXR1cm4gdGhpcy50eXBlLm1hcChtYXBwaW5nLCB0aGlzLCBvZmZzZXQsIG9sZE9mZnNldCk7XG4gICAgfVxuICAgIC8qKlxuICAgIENyZWF0ZXMgYSB3aWRnZXQgZGVjb3JhdGlvbiwgd2hpY2ggaXMgYSBET00gbm9kZSB0aGF0J3Mgc2hvd24gaW5cbiAgICB0aGUgZG9jdW1lbnQgYXQgdGhlIGdpdmVuIHBvc2l0aW9uLiBJdCBpcyByZWNvbW1lbmRlZCB0aGF0IHlvdVxuICAgIGRlbGF5IHJlbmRlcmluZyB0aGUgd2lkZ2V0IGJ5IHBhc3NpbmcgYSBmdW5jdGlvbiB0aGF0IHdpbGwgYmVcbiAgICBjYWxsZWQgd2hlbiB0aGUgd2lkZ2V0IGlzIGFjdHVhbGx5IGRyYXduIGluIGEgdmlldywgYnV0IHlvdSBjYW5cbiAgICBhbHNvIGRpcmVjdGx5IHBhc3MgYSBET00gbm9kZS4gYGdldFBvc2AgY2FuIGJlIHVzZWQgdG8gZmluZCB0aGVcbiAgICB3aWRnZXQncyBjdXJyZW50IGRvY3VtZW50IHBvc2l0aW9uLlxuICAgICovXG4gICAgc3RhdGljIHdpZGdldChwb3MsIHRvRE9NLCBzcGVjKSB7XG4gICAgICAgIHJldHVybiBuZXcgRGVjb3JhdGlvbihwb3MsIHBvcywgbmV3IFdpZGdldFR5cGUodG9ET00sIHNwZWMpKTtcbiAgICB9XG4gICAgLyoqXG4gICAgQ3JlYXRlcyBhbiBpbmxpbmUgZGVjb3JhdGlvbiwgd2hpY2ggYWRkcyB0aGUgZ2l2ZW4gYXR0cmlidXRlcyB0b1xuICAgIGVhY2ggaW5saW5lIG5vZGUgYmV0d2VlbiBgZnJvbWAgYW5kIGB0b2AuXG4gICAgKi9cbiAgICBzdGF0aWMgaW5saW5lKGZyb20sIHRvLCBhdHRycywgc3BlYykge1xuICAgICAgICByZXR1cm4gbmV3IERlY29yYXRpb24oZnJvbSwgdG8sIG5ldyBJbmxpbmVUeXBlKGF0dHJzLCBzcGVjKSk7XG4gICAgfVxuICAgIC8qKlxuICAgIENyZWF0ZXMgYSBub2RlIGRlY29yYXRpb24uIGBmcm9tYCBhbmQgYHRvYCBzaG91bGQgcG9pbnQgcHJlY2lzZWx5XG4gICAgYmVmb3JlIGFuZCBhZnRlciBhIG5vZGUgaW4gdGhlIGRvY3VtZW50LiBUaGF0IG5vZGUsIGFuZCBvbmx5IHRoYXRcbiAgICBub2RlLCB3aWxsIHJlY2VpdmUgdGhlIGdpdmVuIGF0dHJpYnV0ZXMuXG4gICAgKi9cbiAgICBzdGF0aWMgbm9kZShmcm9tLCB0bywgYXR0cnMsIHNwZWMpIHtcbiAgICAgICAgcmV0dXJuIG5ldyBEZWNvcmF0aW9uKGZyb20sIHRvLCBuZXcgTm9kZVR5cGUoYXR0cnMsIHNwZWMpKTtcbiAgICB9XG4gICAgLyoqXG4gICAgVGhlIHNwZWMgcHJvdmlkZWQgd2hlbiBjcmVhdGluZyB0aGlzIGRlY29yYXRpb24uIENhbiBiZSB1c2VmdWxcbiAgICBpZiB5b3UndmUgc3RvcmVkIGV4dHJhIGluZm9ybWF0aW9uIGluIHRoYXQgb2JqZWN0LlxuICAgICovXG4gICAgZ2V0IHNwZWMoKSB7IHJldHVybiB0aGlzLnR5cGUuc3BlYzsgfVxuICAgIC8qKlxuICAgIEBpbnRlcm5hbFxuICAgICovXG4gICAgZ2V0IGlubGluZSgpIHsgcmV0dXJuIHRoaXMudHlwZSBpbnN0YW5jZW9mIElubGluZVR5cGU7IH1cbiAgICAvKipcbiAgICBAaW50ZXJuYWxcbiAgICAqL1xuICAgIGdldCB3aWRnZXQoKSB7IHJldHVybiB0aGlzLnR5cGUgaW5zdGFuY2VvZiBXaWRnZXRUeXBlOyB9XG59XG5jb25zdCBub25lID0gW10sIG5vU3BlYyA9IHt9O1xuLyoqXG5BIGNvbGxlY3Rpb24gb2YgW2RlY29yYXRpb25zXShodHRwczovL3Byb3NlbWlycm9yLm5ldC9kb2NzL3JlZi8jdmlldy5EZWNvcmF0aW9uKSwgb3JnYW5pemVkIGluIHN1Y2hcbmEgd2F5IHRoYXQgdGhlIGRyYXdpbmcgYWxnb3JpdGhtIGNhbiBlZmZpY2llbnRseSB1c2UgYW5kIGNvbXBhcmVcbnRoZW0uIFRoaXMgaXMgYSBwZXJzaXN0ZW50IGRhdGEgc3RydWN0dXJl4oCUaXQgaXMgbm90IG1vZGlmaWVkLFxudXBkYXRlcyBjcmVhdGUgYSBuZXcgdmFsdWUuXG4qL1xuY2xhc3MgRGVjb3JhdGlvblNldCB7XG4gICAgLyoqXG4gICAgQGludGVybmFsXG4gICAgKi9cbiAgICBjb25zdHJ1Y3Rvcihsb2NhbCwgY2hpbGRyZW4pIHtcbiAgICAgICAgdGhpcy5sb2NhbCA9IGxvY2FsLmxlbmd0aCA/IGxvY2FsIDogbm9uZTtcbiAgICAgICAgdGhpcy5jaGlsZHJlbiA9IGNoaWxkcmVuLmxlbmd0aCA/IGNoaWxkcmVuIDogbm9uZTtcbiAgICB9XG4gICAgLyoqXG4gICAgQ3JlYXRlIGEgc2V0IG9mIGRlY29yYXRpb25zLCB1c2luZyB0aGUgc3RydWN0dXJlIG9mIHRoZSBnaXZlblxuICAgIGRvY3VtZW50LiBUaGlzIHdpbGwgY29uc3VtZSAobW9kaWZ5KSB0aGUgYGRlY29yYXRpb25zYCBhcnJheSwgc29cbiAgICB5b3UgbXVzdCBtYWtlIGEgY29weSBpZiB5b3Ugd2FudCBuZWVkIHRvIHByZXNlcnZlIHRoYXQuXG4gICAgKi9cbiAgICBzdGF0aWMgY3JlYXRlKGRvYywgZGVjb3JhdGlvbnMpIHtcbiAgICAgICAgcmV0dXJuIGRlY29yYXRpb25zLmxlbmd0aCA/IGJ1aWxkVHJlZShkZWNvcmF0aW9ucywgZG9jLCAwLCBub1NwZWMpIDogZW1wdHk7XG4gICAgfVxuICAgIC8qKlxuICAgIEZpbmQgYWxsIGRlY29yYXRpb25zIGluIHRoaXMgc2V0IHdoaWNoIHRvdWNoIHRoZSBnaXZlbiByYW5nZVxuICAgIChpbmNsdWRpbmcgZGVjb3JhdGlvbnMgdGhhdCBzdGFydCBvciBlbmQgZGlyZWN0bHkgYXQgdGhlXG4gICAgYm91bmRhcmllcykgYW5kIG1hdGNoIHRoZSBnaXZlbiBwcmVkaWNhdGUgb24gdGhlaXIgc3BlYy4gV2hlblxuICAgIGBzdGFydGAgYW5kIGBlbmRgIGFyZSBvbWl0dGVkLCBhbGwgZGVjb3JhdGlvbnMgaW4gdGhlIHNldCBhcmVcbiAgICBjb25zaWRlcmVkLiBXaGVuIGBwcmVkaWNhdGVgIGlzbid0IGdpdmVuLCBhbGwgZGVjb3JhdGlvbnMgYXJlXG4gICAgYXNzdW1lZCB0byBtYXRjaC5cbiAgICAqL1xuICAgIGZpbmQoc3RhcnQsIGVuZCwgcHJlZGljYXRlKSB7XG4gICAgICAgIGxldCByZXN1bHQgPSBbXTtcbiAgICAgICAgdGhpcy5maW5kSW5uZXIoc3RhcnQgPT0gbnVsbCA/IDAgOiBzdGFydCwgZW5kID09IG51bGwgPyAxZTkgOiBlbmQsIHJlc3VsdCwgMCwgcHJlZGljYXRlKTtcbiAgICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICB9XG4gICAgZmluZElubmVyKHN0YXJ0LCBlbmQsIHJlc3VsdCwgb2Zmc2V0LCBwcmVkaWNhdGUpIHtcbiAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCB0aGlzLmxvY2FsLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICBsZXQgc3BhbiA9IHRoaXMubG9jYWxbaV07XG4gICAgICAgICAgICBpZiAoc3Bhbi5mcm9tIDw9IGVuZCAmJiBzcGFuLnRvID49IHN0YXJ0ICYmICghcHJlZGljYXRlIHx8IHByZWRpY2F0ZShzcGFuLnNwZWMpKSlcbiAgICAgICAgICAgICAgICByZXN1bHQucHVzaChzcGFuLmNvcHkoc3Bhbi5mcm9tICsgb2Zmc2V0LCBzcGFuLnRvICsgb2Zmc2V0KSk7XG4gICAgICAgIH1cbiAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCB0aGlzLmNoaWxkcmVuLmxlbmd0aDsgaSArPSAzKSB7XG4gICAgICAgICAgICBpZiAodGhpcy5jaGlsZHJlbltpXSA8IGVuZCAmJiB0aGlzLmNoaWxkcmVuW2kgKyAxXSA+IHN0YXJ0KSB7XG4gICAgICAgICAgICAgICAgbGV0IGNoaWxkT2ZmID0gdGhpcy5jaGlsZHJlbltpXSArIDE7XG4gICAgICAgICAgICAgICAgdGhpcy5jaGlsZHJlbltpICsgMl0uZmluZElubmVyKHN0YXJ0IC0gY2hpbGRPZmYsIGVuZCAtIGNoaWxkT2ZmLCByZXN1bHQsIG9mZnNldCArIGNoaWxkT2ZmLCBwcmVkaWNhdGUpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuICAgIC8qKlxuICAgIE1hcCB0aGUgc2V0IG9mIGRlY29yYXRpb25zIGluIHJlc3BvbnNlIHRvIGEgY2hhbmdlIGluIHRoZVxuICAgIGRvY3VtZW50LlxuICAgICovXG4gICAgbWFwKG1hcHBpbmcsIGRvYywgb3B0aW9ucykge1xuICAgICAgICBpZiAodGhpcyA9PSBlbXB0eSB8fCBtYXBwaW5nLm1hcHMubGVuZ3RoID09IDApXG4gICAgICAgICAgICByZXR1cm4gdGhpcztcbiAgICAgICAgcmV0dXJuIHRoaXMubWFwSW5uZXIobWFwcGluZywgZG9jLCAwLCAwLCBvcHRpb25zIHx8IG5vU3BlYyk7XG4gICAgfVxuICAgIC8qKlxuICAgIEBpbnRlcm5hbFxuICAgICovXG4gICAgbWFwSW5uZXIobWFwcGluZywgbm9kZSwgb2Zmc2V0LCBvbGRPZmZzZXQsIG9wdGlvbnMpIHtcbiAgICAgICAgbGV0IG5ld0xvY2FsO1xuICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMubG9jYWwubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgIGxldCBtYXBwZWQgPSB0aGlzLmxvY2FsW2ldLm1hcChtYXBwaW5nLCBvZmZzZXQsIG9sZE9mZnNldCk7XG4gICAgICAgICAgICBpZiAobWFwcGVkICYmIG1hcHBlZC50eXBlLnZhbGlkKG5vZGUsIG1hcHBlZCkpXG4gICAgICAgICAgICAgICAgKG5ld0xvY2FsIHx8IChuZXdMb2NhbCA9IFtdKSkucHVzaChtYXBwZWQpO1xuICAgICAgICAgICAgZWxzZSBpZiAob3B0aW9ucy5vblJlbW92ZSlcbiAgICAgICAgICAgICAgICBvcHRpb25zLm9uUmVtb3ZlKHRoaXMubG9jYWxbaV0uc3BlYyk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHRoaXMuY2hpbGRyZW4ubGVuZ3RoKVxuICAgICAgICAgICAgcmV0dXJuIG1hcENoaWxkcmVuKHRoaXMuY2hpbGRyZW4sIG5ld0xvY2FsIHx8IFtdLCBtYXBwaW5nLCBub2RlLCBvZmZzZXQsIG9sZE9mZnNldCwgb3B0aW9ucyk7XG4gICAgICAgIGVsc2VcbiAgICAgICAgICAgIHJldHVybiBuZXdMb2NhbCA/IG5ldyBEZWNvcmF0aW9uU2V0KG5ld0xvY2FsLnNvcnQoYnlQb3MpLCBub25lKSA6IGVtcHR5O1xuICAgIH1cbiAgICAvKipcbiAgICBBZGQgdGhlIGdpdmVuIGFycmF5IG9mIGRlY29yYXRpb25zIHRvIHRoZSBvbmVzIGluIHRoZSBzZXQsXG4gICAgcHJvZHVjaW5nIGEgbmV3IHNldC4gQ29uc3VtZXMgdGhlIGBkZWNvcmF0aW9uc2AgYXJyYXkuIE5lZWRzXG4gICAgYWNjZXNzIHRvIHRoZSBjdXJyZW50IGRvY3VtZW50IHRvIGNyZWF0ZSB0aGUgYXBwcm9wcmlhdGUgdHJlZVxuICAgIHN0cnVjdHVyZS5cbiAgICAqL1xuICAgIGFkZChkb2MsIGRlY29yYXRpb25zKSB7XG4gICAgICAgIGlmICghZGVjb3JhdGlvbnMubGVuZ3RoKVxuICAgICAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgICAgIGlmICh0aGlzID09IGVtcHR5KVxuICAgICAgICAgICAgcmV0dXJuIERlY29yYXRpb25TZXQuY3JlYXRlKGRvYywgZGVjb3JhdGlvbnMpO1xuICAgICAgICByZXR1cm4gdGhpcy5hZGRJbm5lcihkb2MsIGRlY29yYXRpb25zLCAwKTtcbiAgICB9XG4gICAgYWRkSW5uZXIoZG9jLCBkZWNvcmF0aW9ucywgb2Zmc2V0KSB7XG4gICAgICAgIGxldCBjaGlsZHJlbiwgY2hpbGRJbmRleCA9IDA7XG4gICAgICAgIGRvYy5mb3JFYWNoKChjaGlsZE5vZGUsIGNoaWxkT2Zmc2V0KSA9PiB7XG4gICAgICAgICAgICBsZXQgYmFzZU9mZnNldCA9IGNoaWxkT2Zmc2V0ICsgb2Zmc2V0LCBmb3VuZDtcbiAgICAgICAgICAgIGlmICghKGZvdW5kID0gdGFrZVNwYW5zRm9yTm9kZShkZWNvcmF0aW9ucywgY2hpbGROb2RlLCBiYXNlT2Zmc2V0KSkpXG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgaWYgKCFjaGlsZHJlbilcbiAgICAgICAgICAgICAgICBjaGlsZHJlbiA9IHRoaXMuY2hpbGRyZW4uc2xpY2UoKTtcbiAgICAgICAgICAgIHdoaWxlIChjaGlsZEluZGV4IDwgY2hpbGRyZW4ubGVuZ3RoICYmIGNoaWxkcmVuW2NoaWxkSW5kZXhdIDwgY2hpbGRPZmZzZXQpXG4gICAgICAgICAgICAgICAgY2hpbGRJbmRleCArPSAzO1xuICAgICAgICAgICAgaWYgKGNoaWxkcmVuW2NoaWxkSW5kZXhdID09IGNoaWxkT2Zmc2V0KVxuICAgICAgICAgICAgICAgIGNoaWxkcmVuW2NoaWxkSW5kZXggKyAyXSA9IGNoaWxkcmVuW2NoaWxkSW5kZXggKyAyXS5hZGRJbm5lcihjaGlsZE5vZGUsIGZvdW5kLCBiYXNlT2Zmc2V0ICsgMSk7XG4gICAgICAgICAgICBlbHNlXG4gICAgICAgICAgICAgICAgY2hpbGRyZW4uc3BsaWNlKGNoaWxkSW5kZXgsIDAsIGNoaWxkT2Zmc2V0LCBjaGlsZE9mZnNldCArIGNoaWxkTm9kZS5ub2RlU2l6ZSwgYnVpbGRUcmVlKGZvdW5kLCBjaGlsZE5vZGUsIGJhc2VPZmZzZXQgKyAxLCBub1NwZWMpKTtcbiAgICAgICAgICAgIGNoaWxkSW5kZXggKz0gMztcbiAgICAgICAgfSk7XG4gICAgICAgIGxldCBsb2NhbCA9IG1vdmVTcGFucyhjaGlsZEluZGV4ID8gd2l0aG91dE51bGxzKGRlY29yYXRpb25zKSA6IGRlY29yYXRpb25zLCAtb2Zmc2V0KTtcbiAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBsb2NhbC5sZW5ndGg7IGkrKylcbiAgICAgICAgICAgIGlmICghbG9jYWxbaV0udHlwZS52YWxpZChkb2MsIGxvY2FsW2ldKSlcbiAgICAgICAgICAgICAgICBsb2NhbC5zcGxpY2UoaS0tLCAxKTtcbiAgICAgICAgcmV0dXJuIG5ldyBEZWNvcmF0aW9uU2V0KGxvY2FsLmxlbmd0aCA/IHRoaXMubG9jYWwuY29uY2F0KGxvY2FsKS5zb3J0KGJ5UG9zKSA6IHRoaXMubG9jYWwsIGNoaWxkcmVuIHx8IHRoaXMuY2hpbGRyZW4pO1xuICAgIH1cbiAgICAvKipcbiAgICBDcmVhdGUgYSBuZXcgc2V0IHRoYXQgY29udGFpbnMgdGhlIGRlY29yYXRpb25zIGluIHRoaXMgc2V0LCBtaW51c1xuICAgIHRoZSBvbmVzIGluIHRoZSBnaXZlbiBhcnJheS5cbiAgICAqL1xuICAgIHJlbW92ZShkZWNvcmF0aW9ucykge1xuICAgICAgICBpZiAoZGVjb3JhdGlvbnMubGVuZ3RoID09IDAgfHwgdGhpcyA9PSBlbXB0eSlcbiAgICAgICAgICAgIHJldHVybiB0aGlzO1xuICAgICAgICByZXR1cm4gdGhpcy5yZW1vdmVJbm5lcihkZWNvcmF0aW9ucywgMCk7XG4gICAgfVxuICAgIHJlbW92ZUlubmVyKGRlY29yYXRpb25zLCBvZmZzZXQpIHtcbiAgICAgICAgbGV0IGNoaWxkcmVuID0gdGhpcy5jaGlsZHJlbiwgbG9jYWwgPSB0aGlzLmxvY2FsO1xuICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IGNoaWxkcmVuLmxlbmd0aDsgaSArPSAzKSB7XG4gICAgICAgICAgICBsZXQgZm91bmQ7XG4gICAgICAgICAgICBsZXQgZnJvbSA9IGNoaWxkcmVuW2ldICsgb2Zmc2V0LCB0byA9IGNoaWxkcmVuW2kgKyAxXSArIG9mZnNldDtcbiAgICAgICAgICAgIGZvciAobGV0IGogPSAwLCBzcGFuOyBqIDwgZGVjb3JhdGlvbnMubGVuZ3RoOyBqKyspXG4gICAgICAgICAgICAgICAgaWYgKHNwYW4gPSBkZWNvcmF0aW9uc1tqXSkge1xuICAgICAgICAgICAgICAgICAgICBpZiAoc3Bhbi5mcm9tID4gZnJvbSAmJiBzcGFuLnRvIDwgdG8pIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGRlY29yYXRpb25zW2pdID0gbnVsbDtcbiAgICAgICAgICAgICAgICAgICAgICAgIChmb3VuZCB8fCAoZm91bmQgPSBbXSkpLnB1c2goc3Bhbik7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoIWZvdW5kKVxuICAgICAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICAgICAgaWYgKGNoaWxkcmVuID09IHRoaXMuY2hpbGRyZW4pXG4gICAgICAgICAgICAgICAgY2hpbGRyZW4gPSB0aGlzLmNoaWxkcmVuLnNsaWNlKCk7XG4gICAgICAgICAgICBsZXQgcmVtb3ZlZCA9IGNoaWxkcmVuW2kgKyAyXS5yZW1vdmVJbm5lcihmb3VuZCwgZnJvbSArIDEpO1xuICAgICAgICAgICAgaWYgKHJlbW92ZWQgIT0gZW1wdHkpIHtcbiAgICAgICAgICAgICAgICBjaGlsZHJlbltpICsgMl0gPSByZW1vdmVkO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgY2hpbGRyZW4uc3BsaWNlKGksIDMpO1xuICAgICAgICAgICAgICAgIGkgLT0gMztcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBpZiAobG9jYWwubGVuZ3RoKVxuICAgICAgICAgICAgZm9yIChsZXQgaSA9IDAsIHNwYW47IGkgPCBkZWNvcmF0aW9ucy5sZW5ndGg7IGkrKylcbiAgICAgICAgICAgICAgICBpZiAoc3BhbiA9IGRlY29yYXRpb25zW2ldKSB7XG4gICAgICAgICAgICAgICAgICAgIGZvciAobGV0IGogPSAwOyBqIDwgbG9jYWwubGVuZ3RoOyBqKyspXG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAobG9jYWxbal0uZXEoc3Bhbiwgb2Zmc2V0KSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChsb2NhbCA9PSB0aGlzLmxvY2FsKVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb2NhbCA9IHRoaXMubG9jYWwuc2xpY2UoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb2NhbC5zcGxpY2Uoai0tLCAxKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgIGlmIChjaGlsZHJlbiA9PSB0aGlzLmNoaWxkcmVuICYmIGxvY2FsID09IHRoaXMubG9jYWwpXG4gICAgICAgICAgICByZXR1cm4gdGhpcztcbiAgICAgICAgcmV0dXJuIGxvY2FsLmxlbmd0aCB8fCBjaGlsZHJlbi5sZW5ndGggPyBuZXcgRGVjb3JhdGlvblNldChsb2NhbCwgY2hpbGRyZW4pIDogZW1wdHk7XG4gICAgfVxuICAgIGZvckNoaWxkKG9mZnNldCwgbm9kZSkge1xuICAgICAgICBpZiAodGhpcyA9PSBlbXB0eSlcbiAgICAgICAgICAgIHJldHVybiB0aGlzO1xuICAgICAgICBpZiAobm9kZS5pc0xlYWYpXG4gICAgICAgICAgICByZXR1cm4gRGVjb3JhdGlvblNldC5lbXB0eTtcbiAgICAgICAgbGV0IGNoaWxkLCBsb2NhbDtcbiAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCB0aGlzLmNoaWxkcmVuLmxlbmd0aDsgaSArPSAzKVxuICAgICAgICAgICAgaWYgKHRoaXMuY2hpbGRyZW5baV0gPj0gb2Zmc2V0KSB7XG4gICAgICAgICAgICAgICAgaWYgKHRoaXMuY2hpbGRyZW5baV0gPT0gb2Zmc2V0KVxuICAgICAgICAgICAgICAgICAgICBjaGlsZCA9IHRoaXMuY2hpbGRyZW5baSArIDJdO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgfVxuICAgICAgICBsZXQgc3RhcnQgPSBvZmZzZXQgKyAxLCBlbmQgPSBzdGFydCArIG5vZGUuY29udGVudC5zaXplO1xuICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMubG9jYWwubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgIGxldCBkZWMgPSB0aGlzLmxvY2FsW2ldO1xuICAgICAgICAgICAgaWYgKGRlYy5mcm9tIDwgZW5kICYmIGRlYy50byA+IHN0YXJ0ICYmIChkZWMudHlwZSBpbnN0YW5jZW9mIElubGluZVR5cGUpKSB7XG4gICAgICAgICAgICAgICAgbGV0IGZyb20gPSBNYXRoLm1heChzdGFydCwgZGVjLmZyb20pIC0gc3RhcnQsIHRvID0gTWF0aC5taW4oZW5kLCBkZWMudG8pIC0gc3RhcnQ7XG4gICAgICAgICAgICAgICAgaWYgKGZyb20gPCB0bylcbiAgICAgICAgICAgICAgICAgICAgKGxvY2FsIHx8IChsb2NhbCA9IFtdKSkucHVzaChkZWMuY29weShmcm9tLCB0bykpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGlmIChsb2NhbCkge1xuICAgICAgICAgICAgbGV0IGxvY2FsU2V0ID0gbmV3IERlY29yYXRpb25TZXQobG9jYWwuc29ydChieVBvcyksIG5vbmUpO1xuICAgICAgICAgICAgcmV0dXJuIGNoaWxkID8gbmV3IERlY29yYXRpb25Hcm91cChbbG9jYWxTZXQsIGNoaWxkXSkgOiBsb2NhbFNldDtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gY2hpbGQgfHwgZW1wdHk7XG4gICAgfVxuICAgIC8qKlxuICAgIEBpbnRlcm5hbFxuICAgICovXG4gICAgZXEob3RoZXIpIHtcbiAgICAgICAgaWYgKHRoaXMgPT0gb3RoZXIpXG4gICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgaWYgKCEob3RoZXIgaW5zdGFuY2VvZiBEZWNvcmF0aW9uU2V0KSB8fFxuICAgICAgICAgICAgdGhpcy5sb2NhbC5sZW5ndGggIT0gb3RoZXIubG9jYWwubGVuZ3RoIHx8XG4gICAgICAgICAgICB0aGlzLmNoaWxkcmVuLmxlbmd0aCAhPSBvdGhlci5jaGlsZHJlbi5sZW5ndGgpXG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgdGhpcy5sb2NhbC5sZW5ndGg7IGkrKylcbiAgICAgICAgICAgIGlmICghdGhpcy5sb2NhbFtpXS5lcShvdGhlci5sb2NhbFtpXSkpXG4gICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMuY2hpbGRyZW4ubGVuZ3RoOyBpICs9IDMpXG4gICAgICAgICAgICBpZiAodGhpcy5jaGlsZHJlbltpXSAhPSBvdGhlci5jaGlsZHJlbltpXSB8fFxuICAgICAgICAgICAgICAgIHRoaXMuY2hpbGRyZW5baSArIDFdICE9IG90aGVyLmNoaWxkcmVuW2kgKyAxXSB8fFxuICAgICAgICAgICAgICAgICF0aGlzLmNoaWxkcmVuW2kgKyAyXS5lcShvdGhlci5jaGlsZHJlbltpICsgMl0pKVxuICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuICAgIC8qKlxuICAgIEBpbnRlcm5hbFxuICAgICovXG4gICAgbG9jYWxzKG5vZGUpIHtcbiAgICAgICAgcmV0dXJuIHJlbW92ZU92ZXJsYXAodGhpcy5sb2NhbHNJbm5lcihub2RlKSk7XG4gICAgfVxuICAgIC8qKlxuICAgIEBpbnRlcm5hbFxuICAgICovXG4gICAgbG9jYWxzSW5uZXIobm9kZSkge1xuICAgICAgICBpZiAodGhpcyA9PSBlbXB0eSlcbiAgICAgICAgICAgIHJldHVybiBub25lO1xuICAgICAgICBpZiAobm9kZS5pbmxpbmVDb250ZW50IHx8ICF0aGlzLmxvY2FsLnNvbWUoSW5saW5lVHlwZS5pcykpXG4gICAgICAgICAgICByZXR1cm4gdGhpcy5sb2NhbDtcbiAgICAgICAgbGV0IHJlc3VsdCA9IFtdO1xuICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMubG9jYWwubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgIGlmICghKHRoaXMubG9jYWxbaV0udHlwZSBpbnN0YW5jZW9mIElubGluZVR5cGUpKVxuICAgICAgICAgICAgICAgIHJlc3VsdC5wdXNoKHRoaXMubG9jYWxbaV0pO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgfVxuICAgIGZvckVhY2hTZXQoZikgeyBmKHRoaXMpOyB9XG59XG4vKipcblRoZSBlbXB0eSBzZXQgb2YgZGVjb3JhdGlvbnMuXG4qL1xuRGVjb3JhdGlvblNldC5lbXB0eSA9IG5ldyBEZWNvcmF0aW9uU2V0KFtdLCBbXSk7XG4vKipcbkBpbnRlcm5hbFxuKi9cbkRlY29yYXRpb25TZXQucmVtb3ZlT3ZlcmxhcCA9IHJlbW92ZU92ZXJsYXA7XG5jb25zdCBlbXB0eSA9IERlY29yYXRpb25TZXQuZW1wdHk7XG4vLyBBbiBhYnN0cmFjdGlvbiB0aGF0IGFsbG93cyB0aGUgY29kZSBkZWFsaW5nIHdpdGggZGVjb3JhdGlvbnMgdG9cbi8vIHRyZWF0IG11bHRpcGxlIERlY29yYXRpb25TZXQgb2JqZWN0cyBhcyBpZiBpdCB3ZXJlIGEgc2luZ2xlIG9iamVjdFxuLy8gd2l0aCAoYSBzdWJzZXQgb2YpIHRoZSBzYW1lIGludGVyZmFjZS5cbmNsYXNzIERlY29yYXRpb25Hcm91cCB7XG4gICAgY29uc3RydWN0b3IobWVtYmVycykge1xuICAgICAgICB0aGlzLm1lbWJlcnMgPSBtZW1iZXJzO1xuICAgIH1cbiAgICBtYXAobWFwcGluZywgZG9jKSB7XG4gICAgICAgIGNvbnN0IG1hcHBlZERlY29zID0gdGhpcy5tZW1iZXJzLm1hcChtZW1iZXIgPT4gbWVtYmVyLm1hcChtYXBwaW5nLCBkb2MsIG5vU3BlYykpO1xuICAgICAgICByZXR1cm4gRGVjb3JhdGlvbkdyb3VwLmZyb20obWFwcGVkRGVjb3MpO1xuICAgIH1cbiAgICBmb3JDaGlsZChvZmZzZXQsIGNoaWxkKSB7XG4gICAgICAgIGlmIChjaGlsZC5pc0xlYWYpXG4gICAgICAgICAgICByZXR1cm4gRGVjb3JhdGlvblNldC5lbXB0eTtcbiAgICAgICAgbGV0IGZvdW5kID0gW107XG4gICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgdGhpcy5tZW1iZXJzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICBsZXQgcmVzdWx0ID0gdGhpcy5tZW1iZXJzW2ldLmZvckNoaWxkKG9mZnNldCwgY2hpbGQpO1xuICAgICAgICAgICAgaWYgKHJlc3VsdCA9PSBlbXB0eSlcbiAgICAgICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgICAgIGlmIChyZXN1bHQgaW5zdGFuY2VvZiBEZWNvcmF0aW9uR3JvdXApXG4gICAgICAgICAgICAgICAgZm91bmQgPSBmb3VuZC5jb25jYXQocmVzdWx0Lm1lbWJlcnMpO1xuICAgICAgICAgICAgZWxzZVxuICAgICAgICAgICAgICAgIGZvdW5kLnB1c2gocmVzdWx0KTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gRGVjb3JhdGlvbkdyb3VwLmZyb20oZm91bmQpO1xuICAgIH1cbiAgICBlcShvdGhlcikge1xuICAgICAgICBpZiAoIShvdGhlciBpbnN0YW5jZW9mIERlY29yYXRpb25Hcm91cCkgfHxcbiAgICAgICAgICAgIG90aGVyLm1lbWJlcnMubGVuZ3RoICE9IHRoaXMubWVtYmVycy5sZW5ndGgpXG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgdGhpcy5tZW1iZXJzLmxlbmd0aDsgaSsrKVxuICAgICAgICAgICAgaWYgKCF0aGlzLm1lbWJlcnNbaV0uZXEob3RoZXIubWVtYmVyc1tpXSkpXG4gICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG4gICAgbG9jYWxzKG5vZGUpIHtcbiAgICAgICAgbGV0IHJlc3VsdCwgc29ydGVkID0gdHJ1ZTtcbiAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCB0aGlzLm1lbWJlcnMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgIGxldCBsb2NhbHMgPSB0aGlzLm1lbWJlcnNbaV0ubG9jYWxzSW5uZXIobm9kZSk7XG4gICAgICAgICAgICBpZiAoIWxvY2Fscy5sZW5ndGgpXG4gICAgICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgICAgICBpZiAoIXJlc3VsdCkge1xuICAgICAgICAgICAgICAgIHJlc3VsdCA9IGxvY2FscztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgIGlmIChzb3J0ZWQpIHtcbiAgICAgICAgICAgICAgICAgICAgcmVzdWx0ID0gcmVzdWx0LnNsaWNlKCk7XG4gICAgICAgICAgICAgICAgICAgIHNvcnRlZCA9IGZhbHNlO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBmb3IgKGxldCBqID0gMDsgaiA8IGxvY2Fscy5sZW5ndGg7IGorKylcbiAgICAgICAgICAgICAgICAgICAgcmVzdWx0LnB1c2gobG9jYWxzW2pdKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gcmVzdWx0ID8gcmVtb3ZlT3ZlcmxhcChzb3J0ZWQgPyByZXN1bHQgOiByZXN1bHQuc29ydChieVBvcykpIDogbm9uZTtcbiAgICB9XG4gICAgLy8gQ3JlYXRlIGEgZ3JvdXAgZm9yIHRoZSBnaXZlbiBhcnJheSBvZiBkZWNvcmF0aW9uIHNldHMsIG9yIHJldHVyblxuICAgIC8vIGEgc2luZ2xlIHNldCB3aGVuIHBvc3NpYmxlLlxuICAgIHN0YXRpYyBmcm9tKG1lbWJlcnMpIHtcbiAgICAgICAgc3dpdGNoIChtZW1iZXJzLmxlbmd0aCkge1xuICAgICAgICAgICAgY2FzZSAwOiByZXR1cm4gZW1wdHk7XG4gICAgICAgICAgICBjYXNlIDE6IHJldHVybiBtZW1iZXJzWzBdO1xuICAgICAgICAgICAgZGVmYXVsdDogcmV0dXJuIG5ldyBEZWNvcmF0aW9uR3JvdXAobWVtYmVycy5ldmVyeShtID0+IG0gaW5zdGFuY2VvZiBEZWNvcmF0aW9uU2V0KSA/IG1lbWJlcnMgOlxuICAgICAgICAgICAgICAgIG1lbWJlcnMucmVkdWNlKChyLCBtKSA9PiByLmNvbmNhdChtIGluc3RhbmNlb2YgRGVjb3JhdGlvblNldCA/IG0gOiBtLm1lbWJlcnMpLCBbXSkpO1xuICAgICAgICB9XG4gICAgfVxuICAgIGZvckVhY2hTZXQoZikge1xuICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMubWVtYmVycy5sZW5ndGg7IGkrKylcbiAgICAgICAgICAgIHRoaXMubWVtYmVyc1tpXS5mb3JFYWNoU2V0KGYpO1xuICAgIH1cbn1cbmZ1bmN0aW9uIG1hcENoaWxkcmVuKG9sZENoaWxkcmVuLCBuZXdMb2NhbCwgbWFwcGluZywgbm9kZSwgb2Zmc2V0LCBvbGRPZmZzZXQsIG9wdGlvbnMpIHtcbiAgICBsZXQgY2hpbGRyZW4gPSBvbGRDaGlsZHJlbi5zbGljZSgpO1xuICAgIC8vIE1hcmsgdGhlIGNoaWxkcmVuIHRoYXQgYXJlIGRpcmVjdGx5IHRvdWNoZWQgYnkgY2hhbmdlcywgYW5kXG4gICAgLy8gbW92ZSB0aG9zZSB0aGF0IGFyZSBhZnRlciB0aGUgY2hhbmdlcy5cbiAgICBmb3IgKGxldCBpID0gMCwgYmFzZU9mZnNldCA9IG9sZE9mZnNldDsgaSA8IG1hcHBpbmcubWFwcy5sZW5ndGg7IGkrKykge1xuICAgICAgICBsZXQgbW92ZWQgPSAwO1xuICAgICAgICBtYXBwaW5nLm1hcHNbaV0uZm9yRWFjaCgob2xkU3RhcnQsIG9sZEVuZCwgbmV3U3RhcnQsIG5ld0VuZCkgPT4ge1xuICAgICAgICAgICAgbGV0IGRTaXplID0gKG5ld0VuZCAtIG5ld1N0YXJ0KSAtIChvbGRFbmQgLSBvbGRTdGFydCk7XG4gICAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IGNoaWxkcmVuLmxlbmd0aDsgaSArPSAzKSB7XG4gICAgICAgICAgICAgICAgbGV0IGVuZCA9IGNoaWxkcmVuW2kgKyAxXTtcbiAgICAgICAgICAgICAgICBpZiAoZW5kIDwgMCB8fCBvbGRTdGFydCA+IGVuZCArIGJhc2VPZmZzZXQgLSBtb3ZlZClcbiAgICAgICAgICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgICAgICAgICAgbGV0IHN0YXJ0ID0gY2hpbGRyZW5baV0gKyBiYXNlT2Zmc2V0IC0gbW92ZWQ7XG4gICAgICAgICAgICAgICAgaWYgKG9sZEVuZCA+PSBzdGFydCkge1xuICAgICAgICAgICAgICAgICAgICBjaGlsZHJlbltpICsgMV0gPSBvbGRTdGFydCA8PSBzdGFydCA/IC0yIDogLTE7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGVsc2UgaWYgKG9sZFN0YXJ0ID49IGJhc2VPZmZzZXQgJiYgZFNpemUpIHtcbiAgICAgICAgICAgICAgICAgICAgY2hpbGRyZW5baV0gKz0gZFNpemU7XG4gICAgICAgICAgICAgICAgICAgIGNoaWxkcmVuW2kgKyAxXSArPSBkU2l6ZTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBtb3ZlZCArPSBkU2l6ZTtcbiAgICAgICAgfSk7XG4gICAgICAgIGJhc2VPZmZzZXQgPSBtYXBwaW5nLm1hcHNbaV0ubWFwKGJhc2VPZmZzZXQsIC0xKTtcbiAgICB9XG4gICAgLy8gRmluZCB0aGUgY2hpbGQgbm9kZXMgdGhhdCBzdGlsbCBjb3JyZXNwb25kIHRvIGEgc2luZ2xlIG5vZGUsXG4gICAgLy8gcmVjdXJzaXZlbHkgY2FsbCBtYXBJbm5lciBvbiB0aGVtIGFuZCB1cGRhdGUgdGhlaXIgcG9zaXRpb25zLlxuICAgIGxldCBtdXN0UmVidWlsZCA9IGZhbHNlO1xuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgY2hpbGRyZW4ubGVuZ3RoOyBpICs9IDMpXG4gICAgICAgIGlmIChjaGlsZHJlbltpICsgMV0gPCAwKSB7IC8vIFRvdWNoZWQgbm9kZXNcbiAgICAgICAgICAgIGlmIChjaGlsZHJlbltpICsgMV0gPT0gLTIpIHtcbiAgICAgICAgICAgICAgICBtdXN0UmVidWlsZCA9IHRydWU7XG4gICAgICAgICAgICAgICAgY2hpbGRyZW5baSArIDFdID0gLTE7XG4gICAgICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBsZXQgZnJvbSA9IG1hcHBpbmcubWFwKG9sZENoaWxkcmVuW2ldICsgb2xkT2Zmc2V0KSwgZnJvbUxvY2FsID0gZnJvbSAtIG9mZnNldDtcbiAgICAgICAgICAgIGlmIChmcm9tTG9jYWwgPCAwIHx8IGZyb21Mb2NhbCA+PSBub2RlLmNvbnRlbnQuc2l6ZSkge1xuICAgICAgICAgICAgICAgIG11c3RSZWJ1aWxkID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIC8vIE11c3QgcmVhZCBvbGRDaGlsZHJlbiBiZWNhdXNlIGNoaWxkcmVuIHdhcyB0YWdnZWQgd2l0aCAtMVxuICAgICAgICAgICAgbGV0IHRvID0gbWFwcGluZy5tYXAob2xkQ2hpbGRyZW5baSArIDFdICsgb2xkT2Zmc2V0LCAtMSksIHRvTG9jYWwgPSB0byAtIG9mZnNldDtcbiAgICAgICAgICAgIGxldCB7IGluZGV4LCBvZmZzZXQ6IGNoaWxkT2Zmc2V0IH0gPSBub2RlLmNvbnRlbnQuZmluZEluZGV4KGZyb21Mb2NhbCk7XG4gICAgICAgICAgICBsZXQgY2hpbGROb2RlID0gbm9kZS5tYXliZUNoaWxkKGluZGV4KTtcbiAgICAgICAgICAgIGlmIChjaGlsZE5vZGUgJiYgY2hpbGRPZmZzZXQgPT0gZnJvbUxvY2FsICYmIGNoaWxkT2Zmc2V0ICsgY2hpbGROb2RlLm5vZGVTaXplID09IHRvTG9jYWwpIHtcbiAgICAgICAgICAgICAgICBsZXQgbWFwcGVkID0gY2hpbGRyZW5baSArIDJdXG4gICAgICAgICAgICAgICAgICAgIC5tYXBJbm5lcihtYXBwaW5nLCBjaGlsZE5vZGUsIGZyb20gKyAxLCBvbGRDaGlsZHJlbltpXSArIG9sZE9mZnNldCArIDEsIG9wdGlvbnMpO1xuICAgICAgICAgICAgICAgIGlmIChtYXBwZWQgIT0gZW1wdHkpIHtcbiAgICAgICAgICAgICAgICAgICAgY2hpbGRyZW5baV0gPSBmcm9tTG9jYWw7XG4gICAgICAgICAgICAgICAgICAgIGNoaWxkcmVuW2kgKyAxXSA9IHRvTG9jYWw7XG4gICAgICAgICAgICAgICAgICAgIGNoaWxkcmVuW2kgKyAyXSA9IG1hcHBlZDtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIGNoaWxkcmVuW2kgKyAxXSA9IC0yO1xuICAgICAgICAgICAgICAgICAgICBtdXN0UmVidWlsZCA9IHRydWU7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgbXVzdFJlYnVpbGQgPSB0cnVlO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgLy8gUmVtYWluaW5nIGNoaWxkcmVuIG11c3QgYmUgY29sbGVjdGVkIGFuZCByZWJ1aWx0IGludG8gdGhlIGFwcHJvcHJpYXRlIHN0cnVjdHVyZVxuICAgIGlmIChtdXN0UmVidWlsZCkge1xuICAgICAgICBsZXQgZGVjb3JhdGlvbnMgPSBtYXBBbmRHYXRoZXJSZW1haW5pbmdEZWNvcmF0aW9ucyhjaGlsZHJlbiwgb2xkQ2hpbGRyZW4sIG5ld0xvY2FsLCBtYXBwaW5nLCBvZmZzZXQsIG9sZE9mZnNldCwgb3B0aW9ucyk7XG4gICAgICAgIGxldCBidWlsdCA9IGJ1aWxkVHJlZShkZWNvcmF0aW9ucywgbm9kZSwgMCwgb3B0aW9ucyk7XG4gICAgICAgIG5ld0xvY2FsID0gYnVpbHQubG9jYWw7XG4gICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgY2hpbGRyZW4ubGVuZ3RoOyBpICs9IDMpXG4gICAgICAgICAgICBpZiAoY2hpbGRyZW5baSArIDFdIDwgMCkge1xuICAgICAgICAgICAgICAgIGNoaWxkcmVuLnNwbGljZShpLCAzKTtcbiAgICAgICAgICAgICAgICBpIC09IDM7XG4gICAgICAgICAgICB9XG4gICAgICAgIGZvciAobGV0IGkgPSAwLCBqID0gMDsgaSA8IGJ1aWx0LmNoaWxkcmVuLmxlbmd0aDsgaSArPSAzKSB7XG4gICAgICAgICAgICBsZXQgZnJvbSA9IGJ1aWx0LmNoaWxkcmVuW2ldO1xuICAgICAgICAgICAgd2hpbGUgKGogPCBjaGlsZHJlbi5sZW5ndGggJiYgY2hpbGRyZW5bal0gPCBmcm9tKVxuICAgICAgICAgICAgICAgIGogKz0gMztcbiAgICAgICAgICAgIGNoaWxkcmVuLnNwbGljZShqLCAwLCBidWlsdC5jaGlsZHJlbltpXSwgYnVpbHQuY2hpbGRyZW5baSArIDFdLCBidWlsdC5jaGlsZHJlbltpICsgMl0pO1xuICAgICAgICB9XG4gICAgfVxuICAgIHJldHVybiBuZXcgRGVjb3JhdGlvblNldChuZXdMb2NhbC5zb3J0KGJ5UG9zKSwgY2hpbGRyZW4pO1xufVxuZnVuY3Rpb24gbW92ZVNwYW5zKHNwYW5zLCBvZmZzZXQpIHtcbiAgICBpZiAoIW9mZnNldCB8fCAhc3BhbnMubGVuZ3RoKVxuICAgICAgICByZXR1cm4gc3BhbnM7XG4gICAgbGV0IHJlc3VsdCA9IFtdO1xuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgc3BhbnMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgbGV0IHNwYW4gPSBzcGFuc1tpXTtcbiAgICAgICAgcmVzdWx0LnB1c2gobmV3IERlY29yYXRpb24oc3Bhbi5mcm9tICsgb2Zmc2V0LCBzcGFuLnRvICsgb2Zmc2V0LCBzcGFuLnR5cGUpKTtcbiAgICB9XG4gICAgcmV0dXJuIHJlc3VsdDtcbn1cbmZ1bmN0aW9uIG1hcEFuZEdhdGhlclJlbWFpbmluZ0RlY29yYXRpb25zKGNoaWxkcmVuLCBvbGRDaGlsZHJlbiwgZGVjb3JhdGlvbnMsIG1hcHBpbmcsIG9mZnNldCwgb2xkT2Zmc2V0LCBvcHRpb25zKSB7XG4gICAgLy8gR2F0aGVyIGFsbCBkZWNvcmF0aW9ucyBmcm9tIHRoZSByZW1haW5pbmcgbWFya2VkIGNoaWxkcmVuXG4gICAgZnVuY3Rpb24gZ2F0aGVyKHNldCwgb2xkT2Zmc2V0KSB7XG4gICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgc2V0LmxvY2FsLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICBsZXQgbWFwcGVkID0gc2V0LmxvY2FsW2ldLm1hcChtYXBwaW5nLCBvZmZzZXQsIG9sZE9mZnNldCk7XG4gICAgICAgICAgICBpZiAobWFwcGVkKVxuICAgICAgICAgICAgICAgIGRlY29yYXRpb25zLnB1c2gobWFwcGVkKTtcbiAgICAgICAgICAgIGVsc2UgaWYgKG9wdGlvbnMub25SZW1vdmUpXG4gICAgICAgICAgICAgICAgb3B0aW9ucy5vblJlbW92ZShzZXQubG9jYWxbaV0uc3BlYyk7XG4gICAgICAgIH1cbiAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBzZXQuY2hpbGRyZW4ubGVuZ3RoOyBpICs9IDMpXG4gICAgICAgICAgICBnYXRoZXIoc2V0LmNoaWxkcmVuW2kgKyAyXSwgc2V0LmNoaWxkcmVuW2ldICsgb2xkT2Zmc2V0ICsgMSk7XG4gICAgfVxuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgY2hpbGRyZW4ubGVuZ3RoOyBpICs9IDMpXG4gICAgICAgIGlmIChjaGlsZHJlbltpICsgMV0gPT0gLTEpXG4gICAgICAgICAgICBnYXRoZXIoY2hpbGRyZW5baSArIDJdLCBvbGRDaGlsZHJlbltpXSArIG9sZE9mZnNldCArIDEpO1xuICAgIHJldHVybiBkZWNvcmF0aW9ucztcbn1cbmZ1bmN0aW9uIHRha2VTcGFuc0Zvck5vZGUoc3BhbnMsIG5vZGUsIG9mZnNldCkge1xuICAgIGlmIChub2RlLmlzTGVhZilcbiAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgbGV0IGVuZCA9IG9mZnNldCArIG5vZGUubm9kZVNpemUsIGZvdW5kID0gbnVsbDtcbiAgICBmb3IgKGxldCBpID0gMCwgc3BhbjsgaSA8IHNwYW5zLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIGlmICgoc3BhbiA9IHNwYW5zW2ldKSAmJiBzcGFuLmZyb20gPiBvZmZzZXQgJiYgc3Bhbi50byA8IGVuZCkge1xuICAgICAgICAgICAgKGZvdW5kIHx8IChmb3VuZCA9IFtdKSkucHVzaChzcGFuKTtcbiAgICAgICAgICAgIHNwYW5zW2ldID0gbnVsbDtcbiAgICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gZm91bmQ7XG59XG5mdW5jdGlvbiB3aXRob3V0TnVsbHMoYXJyYXkpIHtcbiAgICBsZXQgcmVzdWx0ID0gW107XG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBhcnJheS5sZW5ndGg7IGkrKylcbiAgICAgICAgaWYgKGFycmF5W2ldICE9IG51bGwpXG4gICAgICAgICAgICByZXN1bHQucHVzaChhcnJheVtpXSk7XG4gICAgcmV0dXJuIHJlc3VsdDtcbn1cbi8vIEJ1aWxkIHVwIGEgdHJlZSB0aGF0IGNvcnJlc3BvbmRzIHRvIGEgc2V0IG9mIGRlY29yYXRpb25zLiBgb2Zmc2V0YFxuLy8gaXMgYSBiYXNlIG9mZnNldCB0aGF0IHNob3VsZCBiZSBzdWJ0cmFjdGVkIGZyb20gdGhlIGBmcm9tYCBhbmQgYHRvYFxuLy8gcG9zaXRpb25zIGluIHRoZSBzcGFucyAoc28gdGhhdCB3ZSBkb24ndCBoYXZlIHRvIGFsbG9jYXRlIG5ldyBzcGFuc1xuLy8gZm9yIHJlY3Vyc2l2ZSBjYWxscykuXG5mdW5jdGlvbiBidWlsZFRyZWUoc3BhbnMsIG5vZGUsIG9mZnNldCwgb3B0aW9ucykge1xuICAgIGxldCBjaGlsZHJlbiA9IFtdLCBoYXNOdWxscyA9IGZhbHNlO1xuICAgIG5vZGUuZm9yRWFjaCgoY2hpbGROb2RlLCBsb2NhbFN0YXJ0KSA9PiB7XG4gICAgICAgIGxldCBmb3VuZCA9IHRha2VTcGFuc0Zvck5vZGUoc3BhbnMsIGNoaWxkTm9kZSwgbG9jYWxTdGFydCArIG9mZnNldCk7XG4gICAgICAgIGlmIChmb3VuZCkge1xuICAgICAgICAgICAgaGFzTnVsbHMgPSB0cnVlO1xuICAgICAgICAgICAgbGV0IHN1YnRyZWUgPSBidWlsZFRyZWUoZm91bmQsIGNoaWxkTm9kZSwgb2Zmc2V0ICsgbG9jYWxTdGFydCArIDEsIG9wdGlvbnMpO1xuICAgICAgICAgICAgaWYgKHN1YnRyZWUgIT0gZW1wdHkpXG4gICAgICAgICAgICAgICAgY2hpbGRyZW4ucHVzaChsb2NhbFN0YXJ0LCBsb2NhbFN0YXJ0ICsgY2hpbGROb2RlLm5vZGVTaXplLCBzdWJ0cmVlKTtcbiAgICAgICAgfVxuICAgIH0pO1xuICAgIGxldCBsb2NhbHMgPSBtb3ZlU3BhbnMoaGFzTnVsbHMgPyB3aXRob3V0TnVsbHMoc3BhbnMpIDogc3BhbnMsIC1vZmZzZXQpLnNvcnQoYnlQb3MpO1xuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgbG9jYWxzLmxlbmd0aDsgaSsrKVxuICAgICAgICBpZiAoIWxvY2Fsc1tpXS50eXBlLnZhbGlkKG5vZGUsIGxvY2Fsc1tpXSkpIHtcbiAgICAgICAgICAgIGlmIChvcHRpb25zLm9uUmVtb3ZlKVxuICAgICAgICAgICAgICAgIG9wdGlvbnMub25SZW1vdmUobG9jYWxzW2ldLnNwZWMpO1xuICAgICAgICAgICAgbG9jYWxzLnNwbGljZShpLS0sIDEpO1xuICAgICAgICB9XG4gICAgcmV0dXJuIGxvY2Fscy5sZW5ndGggfHwgY2hpbGRyZW4ubGVuZ3RoID8gbmV3IERlY29yYXRpb25TZXQobG9jYWxzLCBjaGlsZHJlbikgOiBlbXB0eTtcbn1cbi8vIFVzZWQgdG8gc29ydCBkZWNvcmF0aW9ucyBzbyB0aGF0IG9uZXMgd2l0aCBhIGxvdyBzdGFydCBwb3NpdGlvblxuLy8gY29tZSBmaXJzdCwgYW5kIHdpdGhpbiBhIHNldCB3aXRoIHRoZSBzYW1lIHN0YXJ0IHBvc2l0aW9uLCB0aG9zZVxuLy8gd2l0aCBhbiBzbWFsbGVyIGVuZCBwb3NpdGlvbiBjb21lIGZpcnN0LlxuZnVuY3Rpb24gYnlQb3MoYSwgYikge1xuICAgIHJldHVybiBhLmZyb20gLSBiLmZyb20gfHwgYS50byAtIGIudG87XG59XG4vLyBTY2FuIGEgc29ydGVkIGFycmF5IG9mIGRlY29yYXRpb25zIGZvciBwYXJ0aWFsbHkgb3ZlcmxhcHBpbmcgc3BhbnMsXG4vLyBhbmQgc3BsaXQgdGhvc2Ugc28gdGhhdCBvbmx5IGZ1bGx5IG92ZXJsYXBwaW5nIHNwYW5zIGFyZSBsZWZ0ICh0b1xuLy8gbWFrZSBzdWJzZXF1ZW50IHJlbmRlcmluZyBlYXNpZXIpLiBXaWxsIHJldHVybiB0aGUgaW5wdXQgYXJyYXkgaWZcbi8vIG5vIHBhcnRpYWxseSBvdmVybGFwcGluZyBzcGFucyBhcmUgZm91bmQgKHRoZSBjb21tb24gY2FzZSkuXG5mdW5jdGlvbiByZW1vdmVPdmVybGFwKHNwYW5zKSB7XG4gICAgbGV0IHdvcmtpbmcgPSBzcGFucztcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IHdvcmtpbmcubGVuZ3RoIC0gMTsgaSsrKSB7XG4gICAgICAgIGxldCBzcGFuID0gd29ya2luZ1tpXTtcbiAgICAgICAgaWYgKHNwYW4uZnJvbSAhPSBzcGFuLnRvKVxuICAgICAgICAgICAgZm9yIChsZXQgaiA9IGkgKyAxOyBqIDwgd29ya2luZy5sZW5ndGg7IGorKykge1xuICAgICAgICAgICAgICAgIGxldCBuZXh0ID0gd29ya2luZ1tqXTtcbiAgICAgICAgICAgICAgICBpZiAobmV4dC5mcm9tID09IHNwYW4uZnJvbSkge1xuICAgICAgICAgICAgICAgICAgICBpZiAobmV4dC50byAhPSBzcGFuLnRvKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAod29ya2luZyA9PSBzcGFucylcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB3b3JraW5nID0gc3BhbnMuc2xpY2UoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIEZvbGxvd2VkIGJ5IGEgcGFydGlhbGx5IG92ZXJsYXBwaW5nIGxhcmdlciBzcGFuLiBTcGxpdCB0aGF0XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBzcGFuLlxuICAgICAgICAgICAgICAgICAgICAgICAgd29ya2luZ1tqXSA9IG5leHQuY29weShuZXh0LmZyb20sIHNwYW4udG8pO1xuICAgICAgICAgICAgICAgICAgICAgICAgaW5zZXJ0QWhlYWQod29ya2luZywgaiArIDEsIG5leHQuY29weShzcGFuLnRvLCBuZXh0LnRvKSk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICBpZiAobmV4dC5mcm9tIDwgc3Bhbi50bykge1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHdvcmtpbmcgPT0gc3BhbnMpXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgd29ya2luZyA9IHNwYW5zLnNsaWNlKCk7XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBUaGUgZW5kIG9mIHRoaXMgb25lIG92ZXJsYXBzIHdpdGggYSBzdWJzZXF1ZW50IHNwYW4uIFNwbGl0XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyB0aGlzIG9uZS5cbiAgICAgICAgICAgICAgICAgICAgICAgIHdvcmtpbmdbaV0gPSBzcGFuLmNvcHkoc3Bhbi5mcm9tLCBuZXh0LmZyb20pO1xuICAgICAgICAgICAgICAgICAgICAgICAgaW5zZXJ0QWhlYWQod29ya2luZywgaiwgc3Bhbi5jb3B5KG5leHQuZnJvbSwgc3Bhbi50bykpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIHdvcmtpbmc7XG59XG5mdW5jdGlvbiBpbnNlcnRBaGVhZChhcnJheSwgaSwgZGVjbykge1xuICAgIHdoaWxlIChpIDwgYXJyYXkubGVuZ3RoICYmIGJ5UG9zKGRlY28sIGFycmF5W2ldKSA+IDApXG4gICAgICAgIGkrKztcbiAgICBhcnJheS5zcGxpY2UoaSwgMCwgZGVjbyk7XG59XG4vLyBHZXQgdGhlIGRlY29yYXRpb25zIGFzc29jaWF0ZWQgd2l0aCB0aGUgY3VycmVudCBwcm9wcyBvZiBhIHZpZXcuXG5mdW5jdGlvbiB2aWV3RGVjb3JhdGlvbnModmlldykge1xuICAgIGxldCBmb3VuZCA9IFtdO1xuICAgIHZpZXcuc29tZVByb3AoXCJkZWNvcmF0aW9uc1wiLCBmID0+IHtcbiAgICAgICAgbGV0IHJlc3VsdCA9IGYodmlldy5zdGF0ZSk7XG4gICAgICAgIGlmIChyZXN1bHQgJiYgcmVzdWx0ICE9IGVtcHR5KVxuICAgICAgICAgICAgZm91bmQucHVzaChyZXN1bHQpO1xuICAgIH0pO1xuICAgIGlmICh2aWV3LmN1cnNvcldyYXBwZXIpXG4gICAgICAgIGZvdW5kLnB1c2goRGVjb3JhdGlvblNldC5jcmVhdGUodmlldy5zdGF0ZS5kb2MsIFt2aWV3LmN1cnNvcldyYXBwZXIuZGVjb10pKTtcbiAgICByZXR1cm4gRGVjb3JhdGlvbkdyb3VwLmZyb20oZm91bmQpO1xufVxuXG5jb25zdCBvYnNlcnZlT3B0aW9ucyA9IHtcbiAgICBjaGlsZExpc3Q6IHRydWUsXG4gICAgY2hhcmFjdGVyRGF0YTogdHJ1ZSxcbiAgICBjaGFyYWN0ZXJEYXRhT2xkVmFsdWU6IHRydWUsXG4gICAgYXR0cmlidXRlczogdHJ1ZSxcbiAgICBhdHRyaWJ1dGVPbGRWYWx1ZTogdHJ1ZSxcbiAgICBzdWJ0cmVlOiB0cnVlXG59O1xuLy8gSUUxMSBoYXMgdmVyeSBicm9rZW4gbXV0YXRpb24gb2JzZXJ2ZXJzLCBzbyB3ZSBhbHNvIGxpc3RlbiB0byBET01DaGFyYWN0ZXJEYXRhTW9kaWZpZWRcbmNvbnN0IHVzZUNoYXJEYXRhID0gaWUgJiYgaWVfdmVyc2lvbiA8PSAxMTtcbmNsYXNzIFNlbGVjdGlvblN0YXRlIHtcbiAgICBjb25zdHJ1Y3RvcigpIHtcbiAgICAgICAgdGhpcy5hbmNob3JOb2RlID0gbnVsbDtcbiAgICAgICAgdGhpcy5hbmNob3JPZmZzZXQgPSAwO1xuICAgICAgICB0aGlzLmZvY3VzTm9kZSA9IG51bGw7XG4gICAgICAgIHRoaXMuZm9jdXNPZmZzZXQgPSAwO1xuICAgIH1cbiAgICBzZXQoc2VsKSB7XG4gICAgICAgIHRoaXMuYW5jaG9yTm9kZSA9IHNlbC5hbmNob3JOb2RlO1xuICAgICAgICB0aGlzLmFuY2hvck9mZnNldCA9IHNlbC5hbmNob3JPZmZzZXQ7XG4gICAgICAgIHRoaXMuZm9jdXNOb2RlID0gc2VsLmZvY3VzTm9kZTtcbiAgICAgICAgdGhpcy5mb2N1c09mZnNldCA9IHNlbC5mb2N1c09mZnNldDtcbiAgICB9XG4gICAgY2xlYXIoKSB7XG4gICAgICAgIHRoaXMuYW5jaG9yTm9kZSA9IHRoaXMuZm9jdXNOb2RlID0gbnVsbDtcbiAgICB9XG4gICAgZXEoc2VsKSB7XG4gICAgICAgIHJldHVybiBzZWwuYW5jaG9yTm9kZSA9PSB0aGlzLmFuY2hvck5vZGUgJiYgc2VsLmFuY2hvck9mZnNldCA9PSB0aGlzLmFuY2hvck9mZnNldCAmJlxuICAgICAgICAgICAgc2VsLmZvY3VzTm9kZSA9PSB0aGlzLmZvY3VzTm9kZSAmJiBzZWwuZm9jdXNPZmZzZXQgPT0gdGhpcy5mb2N1c09mZnNldDtcbiAgICB9XG59XG5jbGFzcyBET01PYnNlcnZlciB7XG4gICAgY29uc3RydWN0b3IodmlldywgaGFuZGxlRE9NQ2hhbmdlKSB7XG4gICAgICAgIHRoaXMudmlldyA9IHZpZXc7XG4gICAgICAgIHRoaXMuaGFuZGxlRE9NQ2hhbmdlID0gaGFuZGxlRE9NQ2hhbmdlO1xuICAgICAgICB0aGlzLnF1ZXVlID0gW107XG4gICAgICAgIHRoaXMuZmx1c2hpbmdTb29uID0gLTE7XG4gICAgICAgIHRoaXMub2JzZXJ2ZXIgPSBudWxsO1xuICAgICAgICB0aGlzLmN1cnJlbnRTZWxlY3Rpb24gPSBuZXcgU2VsZWN0aW9uU3RhdGU7XG4gICAgICAgIHRoaXMub25DaGFyRGF0YSA9IG51bGw7XG4gICAgICAgIHRoaXMuc3VwcHJlc3NpbmdTZWxlY3Rpb25VcGRhdGVzID0gZmFsc2U7XG4gICAgICAgIHRoaXMubGFzdENoYW5nZWRUZXh0Tm9kZSA9IG51bGw7XG4gICAgICAgIHRoaXMub2JzZXJ2ZXIgPSB3aW5kb3cuTXV0YXRpb25PYnNlcnZlciAmJlxuICAgICAgICAgICAgbmV3IHdpbmRvdy5NdXRhdGlvbk9ic2VydmVyKG11dGF0aW9ucyA9PiB7XG4gICAgICAgICAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBtdXRhdGlvbnMubGVuZ3RoOyBpKyspXG4gICAgICAgICAgICAgICAgICAgIHRoaXMucXVldWUucHVzaChtdXRhdGlvbnNbaV0pO1xuICAgICAgICAgICAgICAgIGlmIChpZSAmJiBpZV92ZXJzaW9uIDw9IDExICYmIG11dGF0aW9ucy5zb21lKG0gPT4gbS50eXBlID09IFwiY2hpbGRMaXN0XCIgJiYgbS5yZW1vdmVkTm9kZXMubGVuZ3RoIHx8XG4gICAgICAgICAgICAgICAgICAgIG0udHlwZSA9PSBcImNoYXJhY3RlckRhdGFcIiAmJiBtLm9sZFZhbHVlLmxlbmd0aCA+IG0udGFyZ2V0Lm5vZGVWYWx1ZS5sZW5ndGgpKSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIElFMTEgd2lsbCBzb21ldGltZXMgKG9uIGJhY2tzcGFjaW5nIG91dCBhIHNpbmdsZSBjaGFyYWN0ZXJcbiAgICAgICAgICAgICAgICAgICAgLy8gdGV4dCBub2RlIGFmdGVyIGEgQlIgbm9kZSkgY2FsbCB0aGUgb2JzZXJ2ZXIgY2FsbGJhY2tcbiAgICAgICAgICAgICAgICAgICAgLy8gYmVmb3JlIGFjdHVhbGx5IHVwZGF0aW5nIHRoZSBET00sIHdoaWNoIHdpbGwgY2F1c2VcbiAgICAgICAgICAgICAgICAgICAgLy8gUHJvc2VNaXJyb3IgdG8gbWlzcyB0aGUgY2hhbmdlIChzZWUgIzkzMClcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5mbHVzaFNvb24oKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgZWxzZSBpZiAoc2FmYXJpICYmIHZpZXcuY29tcG9zaW5nICYmIG11dGF0aW9ucy5zb21lKG0gPT4gbS50eXBlID09IFwiY2hpbGRMaXN0XCIgJiYgbS50YXJnZXQubm9kZU5hbWUgPT0gXCJUUlwiKSkge1xuICAgICAgICAgICAgICAgICAgICAvLyBTYWZhcmkgZG9lcyB3ZWlyZCBzdHVmZiB3aGVuIGZpbmlzaGluZyBhIGNvbXBvc2l0aW9uIGluIGFcbiAgICAgICAgICAgICAgICAgICAgLy8gdGFibGUgY2VsbCwgd2hpY2ggdGVuZHMgdG8gaW52b2x2ZSBpbnNlcnRpbmcgaW5hcHByb3ByaWF0ZVxuICAgICAgICAgICAgICAgICAgICAvLyBub2RlcyBpbiB0aGUgdGFibGUgcm93LlxuICAgICAgICAgICAgICAgICAgICB2aWV3LmlucHV0LmJhZFNhZmFyaUNvbXBvc2l0aW9uID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5mbHVzaFNvb24oKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuZmx1c2goKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgaWYgKHVzZUNoYXJEYXRhKSB7XG4gICAgICAgICAgICB0aGlzLm9uQ2hhckRhdGEgPSBlID0+IHtcbiAgICAgICAgICAgICAgICB0aGlzLnF1ZXVlLnB1c2goeyB0YXJnZXQ6IGUudGFyZ2V0LCB0eXBlOiBcImNoYXJhY3RlckRhdGFcIiwgb2xkVmFsdWU6IGUucHJldlZhbHVlIH0pO1xuICAgICAgICAgICAgICAgIHRoaXMuZmx1c2hTb29uKCk7XG4gICAgICAgICAgICB9O1xuICAgICAgICB9XG4gICAgICAgIHRoaXMub25TZWxlY3Rpb25DaGFuZ2UgPSB0aGlzLm9uU2VsZWN0aW9uQ2hhbmdlLmJpbmQodGhpcyk7XG4gICAgfVxuICAgIGZsdXNoU29vbigpIHtcbiAgICAgICAgaWYgKHRoaXMuZmx1c2hpbmdTb29uIDwgMClcbiAgICAgICAgICAgIHRoaXMuZmx1c2hpbmdTb29uID0gd2luZG93LnNldFRpbWVvdXQoKCkgPT4geyB0aGlzLmZsdXNoaW5nU29vbiA9IC0xOyB0aGlzLmZsdXNoKCk7IH0sIDIwKTtcbiAgICB9XG4gICAgZm9yY2VGbHVzaCgpIHtcbiAgICAgICAgaWYgKHRoaXMuZmx1c2hpbmdTb29uID4gLTEpIHtcbiAgICAgICAgICAgIHdpbmRvdy5jbGVhclRpbWVvdXQodGhpcy5mbHVzaGluZ1Nvb24pO1xuICAgICAgICAgICAgdGhpcy5mbHVzaGluZ1Nvb24gPSAtMTtcbiAgICAgICAgICAgIHRoaXMuZmx1c2goKTtcbiAgICAgICAgfVxuICAgIH1cbiAgICBzdGFydCgpIHtcbiAgICAgICAgaWYgKHRoaXMub2JzZXJ2ZXIpIHtcbiAgICAgICAgICAgIHRoaXMub2JzZXJ2ZXIudGFrZVJlY29yZHMoKTtcbiAgICAgICAgICAgIHRoaXMub2JzZXJ2ZXIub2JzZXJ2ZSh0aGlzLnZpZXcuZG9tLCBvYnNlcnZlT3B0aW9ucyk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHRoaXMub25DaGFyRGF0YSlcbiAgICAgICAgICAgIHRoaXMudmlldy5kb20uYWRkRXZlbnRMaXN0ZW5lcihcIkRPTUNoYXJhY3RlckRhdGFNb2RpZmllZFwiLCB0aGlzLm9uQ2hhckRhdGEpO1xuICAgICAgICB0aGlzLmNvbm5lY3RTZWxlY3Rpb24oKTtcbiAgICB9XG4gICAgc3RvcCgpIHtcbiAgICAgICAgaWYgKHRoaXMub2JzZXJ2ZXIpIHtcbiAgICAgICAgICAgIGxldCB0YWtlID0gdGhpcy5vYnNlcnZlci50YWtlUmVjb3JkcygpO1xuICAgICAgICAgICAgaWYgKHRha2UubGVuZ3RoKSB7XG4gICAgICAgICAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCB0YWtlLmxlbmd0aDsgaSsrKVxuICAgICAgICAgICAgICAgICAgICB0aGlzLnF1ZXVlLnB1c2godGFrZVtpXSk7XG4gICAgICAgICAgICAgICAgd2luZG93LnNldFRpbWVvdXQoKCkgPT4gdGhpcy5mbHVzaCgpLCAyMCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB0aGlzLm9ic2VydmVyLmRpc2Nvbm5lY3QoKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAodGhpcy5vbkNoYXJEYXRhKVxuICAgICAgICAgICAgdGhpcy52aWV3LmRvbS5yZW1vdmVFdmVudExpc3RlbmVyKFwiRE9NQ2hhcmFjdGVyRGF0YU1vZGlmaWVkXCIsIHRoaXMub25DaGFyRGF0YSk7XG4gICAgICAgIHRoaXMuZGlzY29ubmVjdFNlbGVjdGlvbigpO1xuICAgIH1cbiAgICBjb25uZWN0U2VsZWN0aW9uKCkge1xuICAgICAgICB0aGlzLnZpZXcuZG9tLm93bmVyRG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcihcInNlbGVjdGlvbmNoYW5nZVwiLCB0aGlzLm9uU2VsZWN0aW9uQ2hhbmdlKTtcbiAgICB9XG4gICAgZGlzY29ubmVjdFNlbGVjdGlvbigpIHtcbiAgICAgICAgdGhpcy52aWV3LmRvbS5vd25lckRvY3VtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoXCJzZWxlY3Rpb25jaGFuZ2VcIiwgdGhpcy5vblNlbGVjdGlvbkNoYW5nZSk7XG4gICAgfVxuICAgIHN1cHByZXNzU2VsZWN0aW9uVXBkYXRlcygpIHtcbiAgICAgICAgdGhpcy5zdXBwcmVzc2luZ1NlbGVjdGlvblVwZGF0ZXMgPSB0cnVlO1xuICAgICAgICBzZXRUaW1lb3V0KCgpID0+IHRoaXMuc3VwcHJlc3NpbmdTZWxlY3Rpb25VcGRhdGVzID0gZmFsc2UsIDUwKTtcbiAgICB9XG4gICAgb25TZWxlY3Rpb25DaGFuZ2UoKSB7XG4gICAgICAgIGlmICghaGFzRm9jdXNBbmRTZWxlY3Rpb24odGhpcy52aWV3KSlcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgaWYgKHRoaXMuc3VwcHJlc3NpbmdTZWxlY3Rpb25VcGRhdGVzKVxuICAgICAgICAgICAgcmV0dXJuIHNlbGVjdGlvblRvRE9NKHRoaXMudmlldyk7XG4gICAgICAgIC8vIERlbGV0aW9ucyBvbiBJRTExIGZpcmUgdGhlaXIgZXZlbnRzIGluIHRoZSB3cm9uZyBvcmRlciwgZ2l2aW5nXG4gICAgICAgIC8vIHVzIGEgc2VsZWN0aW9uIGNoYW5nZSBldmVudCBiZWZvcmUgdGhlIERPTSBjaGFuZ2VzIGFyZVxuICAgICAgICAvLyByZXBvcnRlZC5cbiAgICAgICAgaWYgKGllICYmIGllX3ZlcnNpb24gPD0gMTEgJiYgIXRoaXMudmlldy5zdGF0ZS5zZWxlY3Rpb24uZW1wdHkpIHtcbiAgICAgICAgICAgIGxldCBzZWwgPSB0aGlzLnZpZXcuZG9tU2VsZWN0aW9uUmFuZ2UoKTtcbiAgICAgICAgICAgIC8vIFNlbGVjdGlvbi5pc0NvbGxhcHNlZCBpc24ndCByZWxpYWJsZSBvbiBJRVxuICAgICAgICAgICAgaWYgKHNlbC5mb2N1c05vZGUgJiYgaXNFcXVpdmFsZW50UG9zaXRpb24oc2VsLmZvY3VzTm9kZSwgc2VsLmZvY3VzT2Zmc2V0LCBzZWwuYW5jaG9yTm9kZSwgc2VsLmFuY2hvck9mZnNldCkpXG4gICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMuZmx1c2hTb29uKCk7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5mbHVzaCgpO1xuICAgIH1cbiAgICBzZXRDdXJTZWxlY3Rpb24oKSB7XG4gICAgICAgIHRoaXMuY3VycmVudFNlbGVjdGlvbi5zZXQodGhpcy52aWV3LmRvbVNlbGVjdGlvblJhbmdlKCkpO1xuICAgIH1cbiAgICBpZ25vcmVTZWxlY3Rpb25DaGFuZ2Uoc2VsKSB7XG4gICAgICAgIGlmICghc2VsLmZvY3VzTm9kZSlcbiAgICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICBsZXQgYW5jZXN0b3JzID0gbmV3IFNldCwgY29udGFpbmVyO1xuICAgICAgICBmb3IgKGxldCBzY2FuID0gc2VsLmZvY3VzTm9kZTsgc2Nhbjsgc2NhbiA9IHBhcmVudE5vZGUoc2NhbikpXG4gICAgICAgICAgICBhbmNlc3RvcnMuYWRkKHNjYW4pO1xuICAgICAgICBmb3IgKGxldCBzY2FuID0gc2VsLmFuY2hvck5vZGU7IHNjYW47IHNjYW4gPSBwYXJlbnROb2RlKHNjYW4pKVxuICAgICAgICAgICAgaWYgKGFuY2VzdG9ycy5oYXMoc2NhbikpIHtcbiAgICAgICAgICAgICAgICBjb250YWluZXIgPSBzY2FuO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgfVxuICAgICAgICBsZXQgZGVzYyA9IGNvbnRhaW5lciAmJiB0aGlzLnZpZXcuZG9jVmlldy5uZWFyZXN0RGVzYyhjb250YWluZXIpO1xuICAgICAgICBpZiAoZGVzYyAmJiBkZXNjLmlnbm9yZU11dGF0aW9uKHtcbiAgICAgICAgICAgIHR5cGU6IFwic2VsZWN0aW9uXCIsXG4gICAgICAgICAgICB0YXJnZXQ6IGNvbnRhaW5lci5ub2RlVHlwZSA9PSAzID8gY29udGFpbmVyLnBhcmVudE5vZGUgOiBjb250YWluZXJcbiAgICAgICAgfSkpIHtcbiAgICAgICAgICAgIHRoaXMuc2V0Q3VyU2VsZWN0aW9uKCk7XG4gICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgfVxuICAgIH1cbiAgICBwZW5kaW5nUmVjb3JkcygpIHtcbiAgICAgICAgaWYgKHRoaXMub2JzZXJ2ZXIpXG4gICAgICAgICAgICBmb3IgKGxldCBtdXQgb2YgdGhpcy5vYnNlcnZlci50YWtlUmVjb3JkcygpKVxuICAgICAgICAgICAgICAgIHRoaXMucXVldWUucHVzaChtdXQpO1xuICAgICAgICByZXR1cm4gdGhpcy5xdWV1ZTtcbiAgICB9XG4gICAgZmx1c2goKSB7XG4gICAgICAgIGxldCB7IHZpZXcgfSA9IHRoaXM7XG4gICAgICAgIGlmICghdmlldy5kb2NWaWV3IHx8IHRoaXMuZmx1c2hpbmdTb29uID4gLTEpXG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIGxldCBtdXRhdGlvbnMgPSB0aGlzLnBlbmRpbmdSZWNvcmRzKCk7XG4gICAgICAgIGlmIChtdXRhdGlvbnMubGVuZ3RoKVxuICAgICAgICAgICAgdGhpcy5xdWV1ZSA9IFtdO1xuICAgICAgICBsZXQgc2VsID0gdmlldy5kb21TZWxlY3Rpb25SYW5nZSgpO1xuICAgICAgICBsZXQgbmV3U2VsID0gIXRoaXMuc3VwcHJlc3NpbmdTZWxlY3Rpb25VcGRhdGVzICYmICF0aGlzLmN1cnJlbnRTZWxlY3Rpb24uZXEoc2VsKSAmJiBoYXNGb2N1c0FuZFNlbGVjdGlvbih2aWV3KSAmJiAhdGhpcy5pZ25vcmVTZWxlY3Rpb25DaGFuZ2Uoc2VsKTtcbiAgICAgICAgbGV0IGZyb20gPSAtMSwgdG8gPSAtMSwgdHlwZU92ZXIgPSBmYWxzZSwgYWRkZWQgPSBbXTtcbiAgICAgICAgaWYgKHZpZXcuZWRpdGFibGUpIHtcbiAgICAgICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgbXV0YXRpb25zLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICAgICAgbGV0IHJlc3VsdCA9IHRoaXMucmVnaXN0ZXJNdXRhdGlvbihtdXRhdGlvbnNbaV0sIGFkZGVkKTtcbiAgICAgICAgICAgICAgICBpZiAocmVzdWx0KSB7XG4gICAgICAgICAgICAgICAgICAgIGZyb20gPSBmcm9tIDwgMCA/IHJlc3VsdC5mcm9tIDogTWF0aC5taW4ocmVzdWx0LmZyb20sIGZyb20pO1xuICAgICAgICAgICAgICAgICAgICB0byA9IHRvIDwgMCA/IHJlc3VsdC50byA6IE1hdGgubWF4KHJlc3VsdC50bywgdG8pO1xuICAgICAgICAgICAgICAgICAgICBpZiAocmVzdWx0LnR5cGVPdmVyKVxuICAgICAgICAgICAgICAgICAgICAgICAgdHlwZU92ZXIgPSB0cnVlO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBpZiAoYWRkZWQuc29tZShuID0+IG4ubm9kZU5hbWUgPT0gXCJCUlwiKSAmJiAodmlldy5pbnB1dC5sYXN0S2V5Q29kZSA9PSA4IHx8IHZpZXcuaW5wdXQubGFzdEtleUNvZGUgPT0gNDYpKSB7XG4gICAgICAgICAgICAvLyBCcm93c2VycyBzb21ldGltZXMgaW5zZXJ0IGEgYm9ndXMgYnJlYWsgbm9kZSBpZiB5b3VcbiAgICAgICAgICAgIC8vIGJhY2tzcGFjZSBvdXQgdGhlIGxhc3QgYml0IG9mIHRleHQgYmVmb3JlIGFuIGlubGluZS1mbGV4IG5vZGUgKCMxNTUyKVxuICAgICAgICAgICAgZm9yIChsZXQgbm9kZSBvZiBhZGRlZClcbiAgICAgICAgICAgICAgICBpZiAobm9kZS5ub2RlTmFtZSA9PSBcIkJSXCIgJiYgbm9kZS5wYXJlbnROb2RlKSB7XG4gICAgICAgICAgICAgICAgICAgIGxldCBhZnRlciA9IG5vZGUubmV4dFNpYmxpbmc7XG4gICAgICAgICAgICAgICAgICAgIGlmIChhZnRlciAmJiBhZnRlci5ub2RlVHlwZSA9PSAxICYmIGFmdGVyLmNvbnRlbnRFZGl0YWJsZSA9PSBcImZhbHNlXCIpXG4gICAgICAgICAgICAgICAgICAgICAgICBub2RlLnBhcmVudE5vZGUucmVtb3ZlQ2hpbGQobm9kZSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYgKGdlY2tvICYmIGFkZGVkLmxlbmd0aCkge1xuICAgICAgICAgICAgbGV0IGJycyA9IGFkZGVkLmZpbHRlcihuID0+IG4ubm9kZU5hbWUgPT0gXCJCUlwiKTtcbiAgICAgICAgICAgIGlmIChicnMubGVuZ3RoID09IDIpIHtcbiAgICAgICAgICAgICAgICBsZXQgW2EsIGJdID0gYnJzO1xuICAgICAgICAgICAgICAgIGlmIChhLnBhcmVudE5vZGUgJiYgYS5wYXJlbnROb2RlLnBhcmVudE5vZGUgPT0gYi5wYXJlbnROb2RlKVxuICAgICAgICAgICAgICAgICAgICBiLnJlbW92ZSgpO1xuICAgICAgICAgICAgICAgIGVsc2VcbiAgICAgICAgICAgICAgICAgICAgYS5yZW1vdmUoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgIGxldCB7IGZvY3VzTm9kZSB9ID0gdGhpcy5jdXJyZW50U2VsZWN0aW9uO1xuICAgICAgICAgICAgICAgIGZvciAobGV0IGJyIG9mIGJycykge1xuICAgICAgICAgICAgICAgICAgICBsZXQgcGFyZW50ID0gYnIucGFyZW50Tm9kZTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKHBhcmVudCAmJiBwYXJlbnQubm9kZU5hbWUgPT0gXCJMSVwiICYmICghZm9jdXNOb2RlIHx8IGJsb2NrUGFyZW50KHZpZXcsIGZvY3VzTm9kZSkgIT0gcGFyZW50KSlcbiAgICAgICAgICAgICAgICAgICAgICAgIGJyLnJlbW92ZSgpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBsZXQgcmVhZFNlbCA9IG51bGw7XG4gICAgICAgIC8vIElmIGl0IGxvb2tzIGxpa2UgdGhlIGJyb3dzZXIgaGFzIHJlc2V0IHRoZSBzZWxlY3Rpb24gdG8gdGhlXG4gICAgICAgIC8vIHN0YXJ0IG9mIHRoZSBkb2N1bWVudCBhZnRlciBmb2N1cywgcmVzdG9yZSB0aGUgc2VsZWN0aW9uIGZyb21cbiAgICAgICAgLy8gdGhlIHN0YXRlXG4gICAgICAgIGlmIChmcm9tIDwgMCAmJiBuZXdTZWwgJiYgdmlldy5pbnB1dC5sYXN0Rm9jdXMgPiBEYXRlLm5vdygpIC0gMjAwICYmXG4gICAgICAgICAgICBNYXRoLm1heCh2aWV3LmlucHV0Lmxhc3RUb3VjaCwgdmlldy5pbnB1dC5sYXN0Q2xpY2sudGltZSkgPCBEYXRlLm5vdygpIC0gMzAwICYmXG4gICAgICAgICAgICBzZWxlY3Rpb25Db2xsYXBzZWQoc2VsKSAmJiAocmVhZFNlbCA9IHNlbGVjdGlvbkZyb21ET00odmlldykpICYmXG4gICAgICAgICAgICByZWFkU2VsLmVxKFNlbGVjdGlvbi5uZWFyKHZpZXcuc3RhdGUuZG9jLnJlc29sdmUoMCksIDEpKSkge1xuICAgICAgICAgICAgdmlldy5pbnB1dC5sYXN0Rm9jdXMgPSAwO1xuICAgICAgICAgICAgc2VsZWN0aW9uVG9ET00odmlldyk7XG4gICAgICAgICAgICB0aGlzLmN1cnJlbnRTZWxlY3Rpb24uc2V0KHNlbCk7XG4gICAgICAgICAgICB2aWV3LnNjcm9sbFRvU2VsZWN0aW9uKCk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAoZnJvbSA+IC0xIHx8IG5ld1NlbCkge1xuICAgICAgICAgICAgaWYgKGZyb20gPiAtMSkge1xuICAgICAgICAgICAgICAgIHZpZXcuZG9jVmlldy5tYXJrRGlydHkoZnJvbSwgdG8pO1xuICAgICAgICAgICAgICAgIGNoZWNrQ1NTKHZpZXcpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKHZpZXcuaW5wdXQuYmFkU2FmYXJpQ29tcG9zaXRpb24pIHtcbiAgICAgICAgICAgICAgICB2aWV3LmlucHV0LmJhZFNhZmFyaUNvbXBvc2l0aW9uID0gZmFsc2U7XG4gICAgICAgICAgICAgICAgZml4VXBCYWRTYWZhcmlDb21wb3NpdGlvbih2aWV3LCBhZGRlZCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB0aGlzLmhhbmRsZURPTUNoYW5nZShmcm9tLCB0bywgdHlwZU92ZXIsIGFkZGVkKTtcbiAgICAgICAgICAgIGlmICh2aWV3LmRvY1ZpZXcgJiYgdmlldy5kb2NWaWV3LmRpcnR5KVxuICAgICAgICAgICAgICAgIHZpZXcudXBkYXRlU3RhdGUodmlldy5zdGF0ZSk7XG4gICAgICAgICAgICBlbHNlIGlmICghdGhpcy5jdXJyZW50U2VsZWN0aW9uLmVxKHNlbCkpXG4gICAgICAgICAgICAgICAgc2VsZWN0aW9uVG9ET00odmlldyk7XG4gICAgICAgICAgICB0aGlzLmN1cnJlbnRTZWxlY3Rpb24uc2V0KHNlbCk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgcmVnaXN0ZXJNdXRhdGlvbihtdXQsIGFkZGVkKSB7XG4gICAgICAgIC8vIElnbm9yZSBtdXRhdGlvbnMgaW5zaWRlIG5vZGVzIHRoYXQgd2VyZSBhbHJlYWR5IG5vdGVkIGFzIGluc2VydGVkXG4gICAgICAgIGlmIChhZGRlZC5pbmRleE9mKG11dC50YXJnZXQpID4gLTEpXG4gICAgICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgICAgbGV0IGRlc2MgPSB0aGlzLnZpZXcuZG9jVmlldy5uZWFyZXN0RGVzYyhtdXQudGFyZ2V0KTtcbiAgICAgICAgaWYgKG11dC50eXBlID09IFwiYXR0cmlidXRlc1wiICYmXG4gICAgICAgICAgICAoZGVzYyA9PSB0aGlzLnZpZXcuZG9jVmlldyB8fCBtdXQuYXR0cmlidXRlTmFtZSA9PSBcImNvbnRlbnRlZGl0YWJsZVwiIHx8XG4gICAgICAgICAgICAgICAgLy8gRmlyZWZveCBzb21ldGltZXMgZmlyZXMgc3B1cmlvdXMgZXZlbnRzIGZvciBudWxsL2VtcHR5IHN0eWxlc1xuICAgICAgICAgICAgICAgIChtdXQuYXR0cmlidXRlTmFtZSA9PSBcInN0eWxlXCIgJiYgIW11dC5vbGRWYWx1ZSAmJiAhbXV0LnRhcmdldC5nZXRBdHRyaWJ1dGUoXCJzdHlsZVwiKSkpKVxuICAgICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgIGlmICghZGVzYyB8fCBkZXNjLmlnbm9yZU11dGF0aW9uKG11dCkpXG4gICAgICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgICAgaWYgKG11dC50eXBlID09IFwiY2hpbGRMaXN0XCIpIHtcbiAgICAgICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgbXV0LmFkZGVkTm9kZXMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgICAgICBsZXQgbm9kZSA9IG11dC5hZGRlZE5vZGVzW2ldO1xuICAgICAgICAgICAgICAgIGFkZGVkLnB1c2gobm9kZSk7XG4gICAgICAgICAgICAgICAgaWYgKG5vZGUubm9kZVR5cGUgPT0gMylcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5sYXN0Q2hhbmdlZFRleHROb2RlID0gbm9kZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmIChkZXNjLmNvbnRlbnRET00gJiYgZGVzYy5jb250ZW50RE9NICE9IGRlc2MuZG9tICYmICFkZXNjLmNvbnRlbnRET00uY29udGFpbnMobXV0LnRhcmdldCkpXG4gICAgICAgICAgICAgICAgcmV0dXJuIHsgZnJvbTogZGVzYy5wb3NCZWZvcmUsIHRvOiBkZXNjLnBvc0FmdGVyIH07XG4gICAgICAgICAgICBsZXQgcHJldiA9IG11dC5wcmV2aW91c1NpYmxpbmcsIG5leHQgPSBtdXQubmV4dFNpYmxpbmc7XG4gICAgICAgICAgICBpZiAoaWUgJiYgaWVfdmVyc2lvbiA8PSAxMSAmJiBtdXQuYWRkZWROb2Rlcy5sZW5ndGgpIHtcbiAgICAgICAgICAgICAgICAvLyBJRTExIGdpdmVzIHVzIGluY29ycmVjdCBuZXh0L3ByZXYgc2libGluZ3MgZm9yIHNvbWVcbiAgICAgICAgICAgICAgICAvLyBpbnNlcnRpb25zLCBzbyBpZiB0aGVyZSBhcmUgYWRkZWQgbm9kZXMsIHJlY29tcHV0ZSB0aG9zZVxuICAgICAgICAgICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgbXV0LmFkZGVkTm9kZXMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgICAgICAgICAgbGV0IHsgcHJldmlvdXNTaWJsaW5nLCBuZXh0U2libGluZyB9ID0gbXV0LmFkZGVkTm9kZXNbaV07XG4gICAgICAgICAgICAgICAgICAgIGlmICghcHJldmlvdXNTaWJsaW5nIHx8IEFycmF5LnByb3RvdHlwZS5pbmRleE9mLmNhbGwobXV0LmFkZGVkTm9kZXMsIHByZXZpb3VzU2libGluZykgPCAwKVxuICAgICAgICAgICAgICAgICAgICAgICAgcHJldiA9IHByZXZpb3VzU2libGluZztcbiAgICAgICAgICAgICAgICAgICAgaWYgKCFuZXh0U2libGluZyB8fCBBcnJheS5wcm90b3R5cGUuaW5kZXhPZi5jYWxsKG11dC5hZGRlZE5vZGVzLCBuZXh0U2libGluZykgPCAwKVxuICAgICAgICAgICAgICAgICAgICAgICAgbmV4dCA9IG5leHRTaWJsaW5nO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGxldCBmcm9tT2Zmc2V0ID0gcHJldiAmJiBwcmV2LnBhcmVudE5vZGUgPT0gbXV0LnRhcmdldFxuICAgICAgICAgICAgICAgID8gZG9tSW5kZXgocHJldikgKyAxIDogMDtcbiAgICAgICAgICAgIGxldCBmcm9tID0gZGVzYy5sb2NhbFBvc0Zyb21ET00obXV0LnRhcmdldCwgZnJvbU9mZnNldCwgLTEpO1xuICAgICAgICAgICAgbGV0IHRvT2Zmc2V0ID0gbmV4dCAmJiBuZXh0LnBhcmVudE5vZGUgPT0gbXV0LnRhcmdldFxuICAgICAgICAgICAgICAgID8gZG9tSW5kZXgobmV4dCkgOiBtdXQudGFyZ2V0LmNoaWxkTm9kZXMubGVuZ3RoO1xuICAgICAgICAgICAgbGV0IHRvID0gZGVzYy5sb2NhbFBvc0Zyb21ET00obXV0LnRhcmdldCwgdG9PZmZzZXQsIDEpO1xuICAgICAgICAgICAgcmV0dXJuIHsgZnJvbSwgdG8gfTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIGlmIChtdXQudHlwZSA9PSBcImF0dHJpYnV0ZXNcIikge1xuICAgICAgICAgICAgcmV0dXJuIHsgZnJvbTogZGVzYy5wb3NBdFN0YXJ0IC0gZGVzYy5ib3JkZXIsIHRvOiBkZXNjLnBvc0F0RW5kICsgZGVzYy5ib3JkZXIgfTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHsgLy8gXCJjaGFyYWN0ZXJEYXRhXCJcbiAgICAgICAgICAgIHRoaXMubGFzdENoYW5nZWRUZXh0Tm9kZSA9IG11dC50YXJnZXQ7XG4gICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICAgIGZyb206IGRlc2MucG9zQXRTdGFydCxcbiAgICAgICAgICAgICAgICB0bzogZGVzYy5wb3NBdEVuZCxcbiAgICAgICAgICAgICAgICAvLyBBbiBldmVudCB3YXMgZ2VuZXJhdGVkIGZvciBhIHRleHQgY2hhbmdlIHRoYXQgZGlkbid0IGNoYW5nZVxuICAgICAgICAgICAgICAgIC8vIGFueSB0ZXh0LiBNYXJrIHRoZSBkb20gY2hhbmdlIHRvIGZhbGwgYmFjayB0byBhc3N1bWluZyB0aGVcbiAgICAgICAgICAgICAgICAvLyBzZWxlY3Rpb24gd2FzIHR5cGVkIG92ZXIgd2l0aCBhbiBpZGVudGljYWwgdmFsdWUgaWYgaXQgY2FuJ3RcbiAgICAgICAgICAgICAgICAvLyBmaW5kIGFub3RoZXIgY2hhbmdlLlxuICAgICAgICAgICAgICAgIHR5cGVPdmVyOiBtdXQudGFyZ2V0Lm5vZGVWYWx1ZSA9PSBtdXQub2xkVmFsdWVcbiAgICAgICAgICAgIH07XG4gICAgICAgIH1cbiAgICB9XG59XG5sZXQgY3NzQ2hlY2tlZCA9IG5ldyBXZWFrTWFwKCk7XG5sZXQgY3NzQ2hlY2tXYXJuZWQgPSBmYWxzZTtcbmZ1bmN0aW9uIGNoZWNrQ1NTKHZpZXcpIHtcbiAgICBpZiAoY3NzQ2hlY2tlZC5oYXModmlldykpXG4gICAgICAgIHJldHVybjtcbiAgICBjc3NDaGVja2VkLnNldCh2aWV3LCBudWxsKTtcbiAgICBpZiAoWydub3JtYWwnLCAnbm93cmFwJywgJ3ByZS1saW5lJ10uaW5kZXhPZihnZXRDb21wdXRlZFN0eWxlKHZpZXcuZG9tKS53aGl0ZVNwYWNlKSAhPT0gLTEpIHtcbiAgICAgICAgdmlldy5yZXF1aXJlc0dlY2tvSGFja05vZGUgPSBnZWNrbztcbiAgICAgICAgaWYgKGNzc0NoZWNrV2FybmVkKVxuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICBjb25zb2xlW1wid2FyblwiXShcIlByb3NlTWlycm9yIGV4cGVjdHMgdGhlIENTUyB3aGl0ZS1zcGFjZSBwcm9wZXJ0eSB0byBiZSBzZXQsIHByZWZlcmFibHkgdG8gJ3ByZS13cmFwJy4gSXQgaXMgcmVjb21tZW5kZWQgdG8gbG9hZCBzdHlsZS9wcm9zZW1pcnJvci5jc3MgZnJvbSB0aGUgcHJvc2VtaXJyb3ItdmlldyBwYWNrYWdlLlwiKTtcbiAgICAgICAgY3NzQ2hlY2tXYXJuZWQgPSB0cnVlO1xuICAgIH1cbn1cbmZ1bmN0aW9uIHJhbmdlVG9TZWxlY3Rpb25SYW5nZSh2aWV3LCByYW5nZSkge1xuICAgIGxldCBhbmNob3JOb2RlID0gcmFuZ2Uuc3RhcnRDb250YWluZXIsIGFuY2hvck9mZnNldCA9IHJhbmdlLnN0YXJ0T2Zmc2V0O1xuICAgIGxldCBmb2N1c05vZGUgPSByYW5nZS5lbmRDb250YWluZXIsIGZvY3VzT2Zmc2V0ID0gcmFuZ2UuZW5kT2Zmc2V0O1xuICAgIGxldCBjdXJyZW50QW5jaG9yID0gdmlldy5kb21BdFBvcyh2aWV3LnN0YXRlLnNlbGVjdGlvbi5hbmNob3IpO1xuICAgIC8vIFNpbmNlIHN1Y2ggYSByYW5nZSBkb2Vzbid0IGRpc3Rpbmd1aXNoIGJldHdlZW4gYW5jaG9yIGFuZCBoZWFkLFxuICAgIC8vIHVzZSBhIGhldXJpc3RpYyB0aGF0IGZsaXBzIGl0IGFyb3VuZCBpZiBpdHMgZW5kIG1hdGNoZXMgdGhlXG4gICAgLy8gY3VycmVudCBhbmNob3IuXG4gICAgaWYgKGlzRXF1aXZhbGVudFBvc2l0aW9uKGN1cnJlbnRBbmNob3Iubm9kZSwgY3VycmVudEFuY2hvci5vZmZzZXQsIGZvY3VzTm9kZSwgZm9jdXNPZmZzZXQpKVxuICAgICAgICBbYW5jaG9yTm9kZSwgYW5jaG9yT2Zmc2V0LCBmb2N1c05vZGUsIGZvY3VzT2Zmc2V0XSA9IFtmb2N1c05vZGUsIGZvY3VzT2Zmc2V0LCBhbmNob3JOb2RlLCBhbmNob3JPZmZzZXRdO1xuICAgIHJldHVybiB7IGFuY2hvck5vZGUsIGFuY2hvck9mZnNldCwgZm9jdXNOb2RlLCBmb2N1c09mZnNldCB9O1xufVxuLy8gVXNlZCB0byB3b3JrIGFyb3VuZCBhIFNhZmFyaSBTZWxlY3Rpb24vc2hhZG93IERPTSBidWdcbi8vIEJhc2VkIG9uIGh0dHBzOi8vZ2l0aHViLmNvbS9jb2RlbWlycm9yL2Rldi9pc3N1ZXMvNDE0IGZpeFxuZnVuY3Rpb24gc2FmYXJpU2hhZG93U2VsZWN0aW9uUmFuZ2Uodmlldywgc2VsZWN0aW9uKSB7XG4gICAgaWYgKHNlbGVjdGlvbi5nZXRDb21wb3NlZFJhbmdlcykge1xuICAgICAgICBsZXQgcmFuZ2UgPSBzZWxlY3Rpb24uZ2V0Q29tcG9zZWRSYW5nZXModmlldy5yb290KVswXTtcbiAgICAgICAgaWYgKHJhbmdlKVxuICAgICAgICAgICAgcmV0dXJuIHJhbmdlVG9TZWxlY3Rpb25SYW5nZSh2aWV3LCByYW5nZSk7XG4gICAgfVxuICAgIGxldCBmb3VuZDtcbiAgICBmdW5jdGlvbiByZWFkKGV2ZW50KSB7XG4gICAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgIGV2ZW50LnN0b3BJbW1lZGlhdGVQcm9wYWdhdGlvbigpO1xuICAgICAgICBmb3VuZCA9IGV2ZW50LmdldFRhcmdldFJhbmdlcygpWzBdO1xuICAgIH1cbiAgICAvLyBCZWNhdXNlIFNhZmFyaSAoYXQgbGVhc3QgaW4gMjAxOC0yMDIyKSBkb2Vzbid0IHByb3ZpZGUgcmVndWxhclxuICAgIC8vIGFjY2VzcyB0byB0aGUgc2VsZWN0aW9uIGluc2lkZSBhIHNoYWRvd1Jvb3QsIHdlIGhhdmUgdG8gcGVyZm9ybSBhXG4gICAgLy8gcmlkaWN1bG91cyBoYWNrIHRvIGdldCBhdCBpdOKAlHVzaW5nIGBleGVjQ29tbWFuZGAgdG8gdHJpZ2dlciBhXG4gICAgLy8gYGJlZm9yZUlucHV0YCBldmVudCBzbyB0aGF0IHdlIGNhbiByZWFkIHRoZSB0YXJnZXQgcmFuZ2UgZnJvbSB0aGVcbiAgICAvLyBldmVudC5cbiAgICB2aWV3LmRvbS5hZGRFdmVudExpc3RlbmVyKFwiYmVmb3JlaW5wdXRcIiwgcmVhZCwgdHJ1ZSk7XG4gICAgZG9jdW1lbnQuZXhlY0NvbW1hbmQoXCJpbmRlbnRcIik7XG4gICAgdmlldy5kb20ucmVtb3ZlRXZlbnRMaXN0ZW5lcihcImJlZm9yZWlucHV0XCIsIHJlYWQsIHRydWUpO1xuICAgIHJldHVybiBmb3VuZCA/IHJhbmdlVG9TZWxlY3Rpb25SYW5nZSh2aWV3LCBmb3VuZCkgOiBudWxsO1xufVxuZnVuY3Rpb24gYmxvY2tQYXJlbnQodmlldywgbm9kZSkge1xuICAgIGZvciAobGV0IHAgPSBub2RlLnBhcmVudE5vZGU7IHAgJiYgcCAhPSB2aWV3LmRvbTsgcCA9IHAucGFyZW50Tm9kZSkge1xuICAgICAgICBsZXQgZGVzYyA9IHZpZXcuZG9jVmlldy5uZWFyZXN0RGVzYyhwLCB0cnVlKTtcbiAgICAgICAgaWYgKGRlc2MgJiYgZGVzYy5ub2RlLmlzQmxvY2spXG4gICAgICAgICAgICByZXR1cm4gcDtcbiAgICB9XG4gICAgcmV0dXJuIG51bGw7XG59XG4vLyBLbHVkZ2UgZm9yIGEgU2FmYXJpIGJ1ZyB3aGVyZSwgb24gZW5kaW5nIGEgY29tcG9zaXRpb24gaW4gYW5cbi8vIG90aGVyd2lzZSBlbXB0eSB0YWJsZSBjZWxsLCBpdCByYW5kb21seSBtb3ZlcyB0aGUgY29tcG9zZWQgdGV4dFxuLy8gaW50byB0aGUgdGFibGUgcm93IGFyb3VuZCB0aGF0IGNlbGwsIGdyZWF0bHkgY29uZnVzaW5nIGV2ZXJ5dGhpbmdcbi8vICgjMTg4KS5cbmZ1bmN0aW9uIGZpeFVwQmFkU2FmYXJpQ29tcG9zaXRpb24odmlldywgYWRkZWROb2Rlcykge1xuICAgIHZhciBfYTtcbiAgICBsZXQgeyBmb2N1c05vZGUsIGZvY3VzT2Zmc2V0IH0gPSB2aWV3LmRvbVNlbGVjdGlvblJhbmdlKCk7XG4gICAgZm9yIChsZXQgbm9kZSBvZiBhZGRlZE5vZGVzKSB7XG4gICAgICAgIGlmICgoKF9hID0gbm9kZS5wYXJlbnROb2RlKSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2Eubm9kZU5hbWUpID09IFwiVFJcIikge1xuICAgICAgICAgICAgbGV0IG5leHRDZWxsID0gbm9kZS5uZXh0U2libGluZztcbiAgICAgICAgICAgIHdoaWxlIChuZXh0Q2VsbCAmJiAobmV4dENlbGwubm9kZU5hbWUgIT0gXCJURFwiICYmIG5leHRDZWxsLm5vZGVOYW1lICE9IFwiVEhcIikpXG4gICAgICAgICAgICAgICAgbmV4dENlbGwgPSBuZXh0Q2VsbC5uZXh0U2libGluZztcbiAgICAgICAgICAgIGlmIChuZXh0Q2VsbCkge1xuICAgICAgICAgICAgICAgIGxldCBwYXJlbnQgPSBuZXh0Q2VsbDtcbiAgICAgICAgICAgICAgICBmb3IgKDs7KSB7XG4gICAgICAgICAgICAgICAgICAgIGxldCBmaXJzdCA9IHBhcmVudC5maXJzdENoaWxkO1xuICAgICAgICAgICAgICAgICAgICBpZiAoIWZpcnN0IHx8IGZpcnN0Lm5vZGVUeXBlICE9IDEgfHwgZmlyc3QuY29udGVudEVkaXRhYmxlID09IFwiZmFsc2VcIiB8fFxuICAgICAgICAgICAgICAgICAgICAgICAgL14oQlJ8SU1HKSQvLnRlc3QoZmlyc3Qubm9kZU5hbWUpKVxuICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgICAgIHBhcmVudCA9IGZpcnN0O1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBwYXJlbnQuaW5zZXJ0QmVmb3JlKG5vZGUsIHBhcmVudC5maXJzdENoaWxkKTtcbiAgICAgICAgICAgICAgICBpZiAoZm9jdXNOb2RlID09IG5vZGUpXG4gICAgICAgICAgICAgICAgICAgIHZpZXcuZG9tU2VsZWN0aW9uKCkuY29sbGFwc2Uobm9kZSwgZm9jdXNPZmZzZXQpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgbm9kZS5wYXJlbnROb2RlLnJlbW92ZUNoaWxkKG5vZGUpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxufVxuXG4vLyBOb3RlIHRoYXQgYWxsIHJlZmVyZW5jaW5nIGFuZCBwYXJzaW5nIGlzIGRvbmUgd2l0aCB0aGVcbi8vIHN0YXJ0LW9mLW9wZXJhdGlvbiBzZWxlY3Rpb24gYW5kIGRvY3VtZW50LCBzaW5jZSB0aGF0J3MgdGhlIG9uZVxuLy8gdGhhdCB0aGUgRE9NIHJlcHJlc2VudHMuIElmIGFueSBjaGFuZ2VzIGNhbWUgaW4gaW4gdGhlIG1lYW50aW1lLFxuLy8gdGhlIG1vZGlmaWNhdGlvbiBpcyBtYXBwZWQgb3ZlciB0aG9zZSBiZWZvcmUgaXQgaXMgYXBwbGllZCwgaW5cbi8vIHJlYWRET01DaGFuZ2UuXG5mdW5jdGlvbiBwYXJzZUJldHdlZW4odmlldywgZnJvbV8sIHRvXykge1xuICAgIGxldCB7IG5vZGU6IHBhcmVudCwgZnJvbU9mZnNldCwgdG9PZmZzZXQsIGZyb20sIHRvIH0gPSB2aWV3LmRvY1ZpZXcucGFyc2VSYW5nZShmcm9tXywgdG9fKTtcbiAgICBsZXQgZG9tU2VsID0gdmlldy5kb21TZWxlY3Rpb25SYW5nZSgpO1xuICAgIGxldCBmaW5kO1xuICAgIGxldCBhbmNob3IgPSBkb21TZWwuYW5jaG9yTm9kZTtcbiAgICBpZiAoYW5jaG9yICYmIHZpZXcuZG9tLmNvbnRhaW5zKGFuY2hvci5ub2RlVHlwZSA9PSAxID8gYW5jaG9yIDogYW5jaG9yLnBhcmVudE5vZGUpKSB7XG4gICAgICAgIGZpbmQgPSBbeyBub2RlOiBhbmNob3IsIG9mZnNldDogZG9tU2VsLmFuY2hvck9mZnNldCB9XTtcbiAgICAgICAgaWYgKCFzZWxlY3Rpb25Db2xsYXBzZWQoZG9tU2VsKSlcbiAgICAgICAgICAgIGZpbmQucHVzaCh7IG5vZGU6IGRvbVNlbC5mb2N1c05vZGUsIG9mZnNldDogZG9tU2VsLmZvY3VzT2Zmc2V0IH0pO1xuICAgIH1cbiAgICAvLyBXb3JrIGFyb3VuZCBpc3N1ZSBpbiBDaHJvbWUgd2hlcmUgYmFja3NwYWNpbmcgc29tZXRpbWVzIHJlcGxhY2VzXG4gICAgLy8gdGhlIGRlbGV0ZWQgY29udGVudCB3aXRoIGEgcmFuZG9tIEJSIG5vZGUgKGlzc3VlcyAjNzk5LCAjODMxKVxuICAgIGlmIChjaHJvbWUgJiYgdmlldy5pbnB1dC5sYXN0S2V5Q29kZSA9PT0gOCkge1xuICAgICAgICBmb3IgKGxldCBvZmYgPSB0b09mZnNldDsgb2ZmID4gZnJvbU9mZnNldDsgb2ZmLS0pIHtcbiAgICAgICAgICAgIGxldCBub2RlID0gcGFyZW50LmNoaWxkTm9kZXNbb2ZmIC0gMV0sIGRlc2MgPSBub2RlLnBtVmlld0Rlc2M7XG4gICAgICAgICAgICBpZiAobm9kZS5ub2RlTmFtZSA9PSBcIkJSXCIgJiYgIWRlc2MpIHtcbiAgICAgICAgICAgICAgICB0b09mZnNldCA9IG9mZjtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmICghZGVzYyB8fCBkZXNjLnNpemUpXG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgIH1cbiAgICB9XG4gICAgbGV0IHN0YXJ0RG9jID0gdmlldy5zdGF0ZS5kb2M7XG4gICAgbGV0IHBhcnNlciA9IHZpZXcuc29tZVByb3AoXCJkb21QYXJzZXJcIikgfHwgRE9NUGFyc2VyLmZyb21TY2hlbWEodmlldy5zdGF0ZS5zY2hlbWEpO1xuICAgIGxldCAkZnJvbSA9IHN0YXJ0RG9jLnJlc29sdmUoZnJvbSk7XG4gICAgbGV0IHNlbCA9IG51bGwsIGRvYyA9IHBhcnNlci5wYXJzZShwYXJlbnQsIHtcbiAgICAgICAgdG9wTm9kZTogJGZyb20ucGFyZW50LFxuICAgICAgICB0b3BNYXRjaDogJGZyb20ucGFyZW50LmNvbnRlbnRNYXRjaEF0KCRmcm9tLmluZGV4KCkpLFxuICAgICAgICB0b3BPcGVuOiB0cnVlLFxuICAgICAgICBmcm9tOiBmcm9tT2Zmc2V0LFxuICAgICAgICB0bzogdG9PZmZzZXQsXG4gICAgICAgIHByZXNlcnZlV2hpdGVzcGFjZTogJGZyb20ucGFyZW50LnR5cGUud2hpdGVzcGFjZSA9PSBcInByZVwiID8gXCJmdWxsXCIgOiB0cnVlLFxuICAgICAgICBmaW5kUG9zaXRpb25zOiBmaW5kLFxuICAgICAgICBydWxlRnJvbU5vZGUsXG4gICAgICAgIGNvbnRleHQ6ICRmcm9tXG4gICAgfSk7XG4gICAgaWYgKGZpbmQgJiYgZmluZFswXS5wb3MgIT0gbnVsbCkge1xuICAgICAgICBsZXQgYW5jaG9yID0gZmluZFswXS5wb3MsIGhlYWQgPSBmaW5kWzFdICYmIGZpbmRbMV0ucG9zO1xuICAgICAgICBpZiAoaGVhZCA9PSBudWxsKVxuICAgICAgICAgICAgaGVhZCA9IGFuY2hvcjtcbiAgICAgICAgc2VsID0geyBhbmNob3I6IGFuY2hvciArIGZyb20sIGhlYWQ6IGhlYWQgKyBmcm9tIH07XG4gICAgfVxuICAgIHJldHVybiB7IGRvYywgc2VsLCBmcm9tLCB0byB9O1xufVxuZnVuY3Rpb24gcnVsZUZyb21Ob2RlKGRvbSkge1xuICAgIGxldCBkZXNjID0gZG9tLnBtVmlld0Rlc2M7XG4gICAgaWYgKGRlc2MpIHtcbiAgICAgICAgcmV0dXJuIGRlc2MucGFyc2VSdWxlKCk7XG4gICAgfVxuICAgIGVsc2UgaWYgKGRvbS5ub2RlTmFtZSA9PSBcIkJSXCIgJiYgZG9tLnBhcmVudE5vZGUpIHtcbiAgICAgICAgLy8gU2FmYXJpIHJlcGxhY2VzIHRoZSBsaXN0IGl0ZW0gb3IgdGFibGUgY2VsbCB3aXRoIGEgQlJcbiAgICAgICAgLy8gZGlyZWN0bHkgaW4gdGhlIGxpc3Qgbm9kZSAoPyEpIGlmIHlvdSBkZWxldGUgdGhlIGxhc3RcbiAgICAgICAgLy8gY2hhcmFjdGVyIGluIGEgbGlzdCBpdGVtIG9yIHRhYmxlIGNlbGwgKCM3MDgsICM4NjIpXG4gICAgICAgIGlmIChzYWZhcmkgJiYgL14odWx8b2wpJC9pLnRlc3QoZG9tLnBhcmVudE5vZGUubm9kZU5hbWUpKSB7XG4gICAgICAgICAgICBsZXQgc2tpcCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoXCJkaXZcIik7XG4gICAgICAgICAgICBza2lwLmFwcGVuZENoaWxkKGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoXCJsaVwiKSk7XG4gICAgICAgICAgICByZXR1cm4geyBza2lwIH07XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAoZG9tLnBhcmVudE5vZGUubGFzdENoaWxkID09IGRvbSB8fCBzYWZhcmkgJiYgL14odHJ8dGFibGUpJC9pLnRlc3QoZG9tLnBhcmVudE5vZGUubm9kZU5hbWUpKSB7XG4gICAgICAgICAgICByZXR1cm4geyBpZ25vcmU6IHRydWUgfTtcbiAgICAgICAgfVxuICAgIH1cbiAgICBlbHNlIGlmIChkb20ubm9kZU5hbWUgPT0gXCJJTUdcIiAmJiBkb20uZ2V0QXR0cmlidXRlKFwibWFyay1wbGFjZWhvbGRlclwiKSkge1xuICAgICAgICByZXR1cm4geyBpZ25vcmU6IHRydWUgfTtcbiAgICB9XG4gICAgcmV0dXJuIG51bGw7XG59XG5jb25zdCBpc0lubGluZSA9IC9eKGF8YWJicnxhY3JvbnltfGJ8YmRbaW9dfGJpZ3xicnxidXR0b258Y2l0ZXxjb2RlfGRhdGEobGlzdCk/fGRlbHxkZm58ZW18aXxpbWd8aW5zfGtiZHxsYWJlbHxtYXB8bWFya3xtZXRlcnxvdXRwdXR8cXxydWJ5fHN8c2FtcHxzbWFsbHxzcGFufHN0cm9uZ3xzdVticF18dGltZXx1fHR0fHZhcikkL2k7XG5mdW5jdGlvbiByZWFkRE9NQ2hhbmdlKHZpZXcsIGZyb20sIHRvLCB0eXBlT3ZlciwgYWRkZWROb2Rlcykge1xuICAgIGxldCBjb21wb3NpdGlvbklEID0gdmlldy5pbnB1dC5jb21wb3NpdGlvblBlbmRpbmdDaGFuZ2VzIHx8ICh2aWV3LmNvbXBvc2luZyA/IHZpZXcuaW5wdXQuY29tcG9zaXRpb25JRCA6IDApO1xuICAgIHZpZXcuaW5wdXQuY29tcG9zaXRpb25QZW5kaW5nQ2hhbmdlcyA9IDA7XG4gICAgaWYgKGZyb20gPCAwKSB7XG4gICAgICAgIGxldCBvcmlnaW4gPSB2aWV3LmlucHV0Lmxhc3RTZWxlY3Rpb25UaW1lID4gRGF0ZS5ub3coKSAtIDUwID8gdmlldy5pbnB1dC5sYXN0U2VsZWN0aW9uT3JpZ2luIDogbnVsbDtcbiAgICAgICAgbGV0IG5ld1NlbCA9IHNlbGVjdGlvbkZyb21ET00odmlldywgb3JpZ2luKTtcbiAgICAgICAgaWYgKG5ld1NlbCAmJiAhdmlldy5zdGF0ZS5zZWxlY3Rpb24uZXEobmV3U2VsKSkge1xuICAgICAgICAgICAgaWYgKGNocm9tZSAmJiBhbmRyb2lkICYmXG4gICAgICAgICAgICAgICAgdmlldy5pbnB1dC5sYXN0S2V5Q29kZSA9PT0gMTMgJiYgRGF0ZS5ub3coKSAtIDEwMCA8IHZpZXcuaW5wdXQubGFzdEtleUNvZGVUaW1lICYmXG4gICAgICAgICAgICAgICAgdmlldy5zb21lUHJvcChcImhhbmRsZUtleURvd25cIiwgZiA9PiBmKHZpZXcsIGtleUV2ZW50KDEzLCBcIkVudGVyXCIpKSkpXG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgbGV0IHRyID0gdmlldy5zdGF0ZS50ci5zZXRTZWxlY3Rpb24obmV3U2VsKTtcbiAgICAgICAgICAgIGlmIChvcmlnaW4gPT0gXCJwb2ludGVyXCIpXG4gICAgICAgICAgICAgICAgdHIuc2V0TWV0YShcInBvaW50ZXJcIiwgdHJ1ZSk7XG4gICAgICAgICAgICBlbHNlIGlmIChvcmlnaW4gPT0gXCJrZXlcIilcbiAgICAgICAgICAgICAgICB0ci5zY3JvbGxJbnRvVmlldygpO1xuICAgICAgICAgICAgaWYgKGNvbXBvc2l0aW9uSUQpXG4gICAgICAgICAgICAgICAgdHIuc2V0TWV0YShcImNvbXBvc2l0aW9uXCIsIGNvbXBvc2l0aW9uSUQpO1xuICAgICAgICAgICAgdmlldy5kaXNwYXRjaCh0cik7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBsZXQgJGJlZm9yZSA9IHZpZXcuc3RhdGUuZG9jLnJlc29sdmUoZnJvbSk7XG4gICAgbGV0IHNoYXJlZCA9ICRiZWZvcmUuc2hhcmVkRGVwdGgodG8pO1xuICAgIGZyb20gPSAkYmVmb3JlLmJlZm9yZShzaGFyZWQgKyAxKTtcbiAgICB0byA9IHZpZXcuc3RhdGUuZG9jLnJlc29sdmUodG8pLmFmdGVyKHNoYXJlZCArIDEpO1xuICAgIGxldCBzZWwgPSB2aWV3LnN0YXRlLnNlbGVjdGlvbjtcbiAgICBsZXQgcGFyc2UgPSBwYXJzZUJldHdlZW4odmlldywgZnJvbSwgdG8pO1xuICAgIGxldCBkb2MgPSB2aWV3LnN0YXRlLmRvYywgY29tcGFyZSA9IGRvYy5zbGljZShwYXJzZS5mcm9tLCBwYXJzZS50byk7XG4gICAgbGV0IHByZWZlcnJlZFBvcywgcHJlZmVycmVkU2lkZTtcbiAgICAvLyBQcmVmZXIgYW5jaG9yaW5nIHRvIGVuZCB3aGVuIEJhY2tzcGFjZSBpcyBwcmVzc2VkXG4gICAgaWYgKHZpZXcuaW5wdXQubGFzdEtleUNvZGUgPT09IDggJiYgRGF0ZS5ub3coKSAtIDEwMCA8IHZpZXcuaW5wdXQubGFzdEtleUNvZGVUaW1lKSB7XG4gICAgICAgIHByZWZlcnJlZFBvcyA9IHZpZXcuc3RhdGUuc2VsZWN0aW9uLnRvO1xuICAgICAgICBwcmVmZXJyZWRTaWRlID0gXCJlbmRcIjtcbiAgICB9XG4gICAgZWxzZSB7XG4gICAgICAgIHByZWZlcnJlZFBvcyA9IHZpZXcuc3RhdGUuc2VsZWN0aW9uLmZyb207XG4gICAgICAgIHByZWZlcnJlZFNpZGUgPSBcInN0YXJ0XCI7XG4gICAgfVxuICAgIHZpZXcuaW5wdXQubGFzdEtleUNvZGUgPSBudWxsO1xuICAgIGxldCBjaGFuZ2UgPSBmaW5kRGlmZihjb21wYXJlLmNvbnRlbnQsIHBhcnNlLmRvYy5jb250ZW50LCBwYXJzZS5mcm9tLCBwcmVmZXJyZWRQb3MsIHByZWZlcnJlZFNpZGUpO1xuICAgIGlmIChjaGFuZ2UpXG4gICAgICAgIHZpZXcuaW5wdXQuZG9tQ2hhbmdlQ291bnQrKztcbiAgICBpZiAoKGlvcyAmJiB2aWV3LmlucHV0Lmxhc3RJT1NFbnRlciA+IERhdGUubm93KCkgLSAyMjUgfHwgYW5kcm9pZCkgJiZcbiAgICAgICAgYWRkZWROb2Rlcy5zb21lKG4gPT4gbi5ub2RlVHlwZSA9PSAxICYmICFpc0lubGluZS50ZXN0KG4ubm9kZU5hbWUpKSAmJlxuICAgICAgICAoIWNoYW5nZSB8fCBjaGFuZ2UuZW5kQSA+PSBjaGFuZ2UuZW5kQikgJiZcbiAgICAgICAgdmlldy5zb21lUHJvcChcImhhbmRsZUtleURvd25cIiwgZiA9PiBmKHZpZXcsIGtleUV2ZW50KDEzLCBcIkVudGVyXCIpKSkpIHtcbiAgICAgICAgdmlldy5pbnB1dC5sYXN0SU9TRW50ZXIgPSAwO1xuICAgICAgICByZXR1cm47XG4gICAgfVxuICAgIGlmICghY2hhbmdlKSB7XG4gICAgICAgIGlmICh0eXBlT3ZlciAmJiBzZWwgaW5zdGFuY2VvZiBUZXh0U2VsZWN0aW9uICYmICFzZWwuZW1wdHkgJiYgc2VsLiRoZWFkLnNhbWVQYXJlbnQoc2VsLiRhbmNob3IpICYmXG4gICAgICAgICAgICAhdmlldy5jb21wb3NpbmcgJiYgIShwYXJzZS5zZWwgJiYgcGFyc2Uuc2VsLmFuY2hvciAhPSBwYXJzZS5zZWwuaGVhZCkpIHtcbiAgICAgICAgICAgIGNoYW5nZSA9IHsgc3RhcnQ6IHNlbC5mcm9tLCBlbmRBOiBzZWwudG8sIGVuZEI6IHNlbC50byB9O1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgaWYgKHBhcnNlLnNlbCkge1xuICAgICAgICAgICAgICAgIGxldCBzZWwgPSByZXNvbHZlU2VsZWN0aW9uKHZpZXcsIHZpZXcuc3RhdGUuZG9jLCBwYXJzZS5zZWwpO1xuICAgICAgICAgICAgICAgIGlmIChzZWwgJiYgIXNlbC5lcSh2aWV3LnN0YXRlLnNlbGVjdGlvbikpIHtcbiAgICAgICAgICAgICAgICAgICAgbGV0IHRyID0gdmlldy5zdGF0ZS50ci5zZXRTZWxlY3Rpb24oc2VsKTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKGNvbXBvc2l0aW9uSUQpXG4gICAgICAgICAgICAgICAgICAgICAgICB0ci5zZXRNZXRhKFwiY29tcG9zaXRpb25cIiwgY29tcG9zaXRpb25JRCk7XG4gICAgICAgICAgICAgICAgICAgIHZpZXcuZGlzcGF0Y2godHIpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgIH1cbiAgICAvLyBIYW5kbGUgdGhlIGNhc2Ugd2hlcmUgb3ZlcndyaXRpbmcgYSBzZWxlY3Rpb24gYnkgdHlwaW5nIG1hdGNoZXNcbiAgICAvLyB0aGUgc3RhcnQgb3IgZW5kIG9mIHRoZSBzZWxlY3RlZCBjb250ZW50LCBjcmVhdGluZyBhIGNoYW5nZVxuICAgIC8vIHRoYXQncyBzbWFsbGVyIHRoYW4gd2hhdCB3YXMgYWN0dWFsbHkgb3ZlcndyaXR0ZW4uXG4gICAgaWYgKHZpZXcuc3RhdGUuc2VsZWN0aW9uLmZyb20gPCB2aWV3LnN0YXRlLnNlbGVjdGlvbi50byAmJlxuICAgICAgICBjaGFuZ2Uuc3RhcnQgPT0gY2hhbmdlLmVuZEIgJiZcbiAgICAgICAgdmlldy5zdGF0ZS5zZWxlY3Rpb24gaW5zdGFuY2VvZiBUZXh0U2VsZWN0aW9uKSB7XG4gICAgICAgIGlmIChjaGFuZ2Uuc3RhcnQgPiB2aWV3LnN0YXRlLnNlbGVjdGlvbi5mcm9tICYmIGNoYW5nZS5zdGFydCA8PSB2aWV3LnN0YXRlLnNlbGVjdGlvbi5mcm9tICsgMiAmJlxuICAgICAgICAgICAgdmlldy5zdGF0ZS5zZWxlY3Rpb24uZnJvbSA+PSBwYXJzZS5mcm9tKSB7XG4gICAgICAgICAgICBjaGFuZ2Uuc3RhcnQgPSB2aWV3LnN0YXRlLnNlbGVjdGlvbi5mcm9tO1xuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYgKGNoYW5nZS5lbmRBIDwgdmlldy5zdGF0ZS5zZWxlY3Rpb24udG8gJiYgY2hhbmdlLmVuZEEgPj0gdmlldy5zdGF0ZS5zZWxlY3Rpb24udG8gLSAyICYmXG4gICAgICAgICAgICB2aWV3LnN0YXRlLnNlbGVjdGlvbi50byA8PSBwYXJzZS50bykge1xuICAgICAgICAgICAgY2hhbmdlLmVuZEIgKz0gKHZpZXcuc3RhdGUuc2VsZWN0aW9uLnRvIC0gY2hhbmdlLmVuZEEpO1xuICAgICAgICAgICAgY2hhbmdlLmVuZEEgPSB2aWV3LnN0YXRlLnNlbGVjdGlvbi50bztcbiAgICAgICAgfVxuICAgIH1cbiAgICAvLyBJRTExIHdpbGwgaW5zZXJ0IGEgbm9uLWJyZWFraW5nIHNwYWNlIF9haGVhZF8gb2YgdGhlIHNwYWNlIGFmdGVyXG4gICAgLy8gdGhlIGN1cnNvciBzcGFjZSB3aGVuIGFkZGluZyBhIHNwYWNlIGJlZm9yZSBhbm90aGVyIHNwYWNlLiBXaGVuXG4gICAgLy8gdGhhdCBoYXBwZW5lZCwgYWRqdXN0IHRoZSBjaGFuZ2UgdG8gY292ZXIgdGhlIHNwYWNlIGluc3RlYWQuXG4gICAgaWYgKGllICYmIGllX3ZlcnNpb24gPD0gMTEgJiYgY2hhbmdlLmVuZEIgPT0gY2hhbmdlLnN0YXJ0ICsgMSAmJlxuICAgICAgICBjaGFuZ2UuZW5kQSA9PSBjaGFuZ2Uuc3RhcnQgJiYgY2hhbmdlLnN0YXJ0ID4gcGFyc2UuZnJvbSAmJlxuICAgICAgICBwYXJzZS5kb2MudGV4dEJldHdlZW4oY2hhbmdlLnN0YXJ0IC0gcGFyc2UuZnJvbSAtIDEsIGNoYW5nZS5zdGFydCAtIHBhcnNlLmZyb20gKyAxKSA9PSBcIiBcXHUwMGEwXCIpIHtcbiAgICAgICAgY2hhbmdlLnN0YXJ0LS07XG4gICAgICAgIGNoYW5nZS5lbmRBLS07XG4gICAgICAgIGNoYW5nZS5lbmRCLS07XG4gICAgfVxuICAgIGxldCAkZnJvbSA9IHBhcnNlLmRvYy5yZXNvbHZlTm9DYWNoZShjaGFuZ2Uuc3RhcnQgLSBwYXJzZS5mcm9tKTtcbiAgICBsZXQgJHRvID0gcGFyc2UuZG9jLnJlc29sdmVOb0NhY2hlKGNoYW5nZS5lbmRCIC0gcGFyc2UuZnJvbSk7XG4gICAgbGV0ICRmcm9tQSA9IGRvYy5yZXNvbHZlKGNoYW5nZS5zdGFydCk7XG4gICAgbGV0IGlubGluZUNoYW5nZSA9ICRmcm9tLnNhbWVQYXJlbnQoJHRvKSAmJiAkZnJvbS5wYXJlbnQuaW5saW5lQ29udGVudCAmJiAkZnJvbUEuZW5kKCkgPj0gY2hhbmdlLmVuZEE7XG4gICAgLy8gSWYgdGhpcyBsb29rcyBsaWtlIHRoZSBlZmZlY3Qgb2YgcHJlc3NpbmcgRW50ZXIgKG9yIHdhcyByZWNvcmRlZFxuICAgIC8vIGFzIGJlaW5nIGFuIGlPUyBlbnRlciBwcmVzcyksIGp1c3QgZGlzcGF0Y2ggYW4gRW50ZXIga2V5IGluc3RlYWQuXG4gICAgaWYgKCgoaW9zICYmIHZpZXcuaW5wdXQubGFzdElPU0VudGVyID4gRGF0ZS5ub3coKSAtIDIyNSAmJlxuICAgICAgICAoIWlubGluZUNoYW5nZSB8fCBhZGRlZE5vZGVzLnNvbWUobiA9PiBuLm5vZGVOYW1lID09IFwiRElWXCIgfHwgbi5ub2RlTmFtZSA9PSBcIlBcIikpKSB8fFxuICAgICAgICAoIWlubGluZUNoYW5nZSAmJiAkZnJvbS5wb3MgPCBwYXJzZS5kb2MuY29udGVudC5zaXplICYmXG4gICAgICAgICAgICAoISRmcm9tLnNhbWVQYXJlbnQoJHRvKSB8fCAhJGZyb20ucGFyZW50LmlubGluZUNvbnRlbnQpICYmXG4gICAgICAgICAgICAkZnJvbS5wb3MgPCAkdG8ucG9zICYmICEvXFxTLy50ZXN0KHBhcnNlLmRvYy50ZXh0QmV0d2VlbigkZnJvbS5wb3MsICR0by5wb3MsIFwiXCIsIFwiXCIpKSkpICYmXG4gICAgICAgIHZpZXcuc29tZVByb3AoXCJoYW5kbGVLZXlEb3duXCIsIGYgPT4gZih2aWV3LCBrZXlFdmVudCgxMywgXCJFbnRlclwiKSkpKSB7XG4gICAgICAgIHZpZXcuaW5wdXQubGFzdElPU0VudGVyID0gMDtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICAvLyBTYW1lIGZvciBiYWNrc3BhY2VcbiAgICBpZiAodmlldy5zdGF0ZS5zZWxlY3Rpb24uYW5jaG9yID4gY2hhbmdlLnN0YXJ0ICYmXG4gICAgICAgIGxvb2tzTGlrZUJhY2tzcGFjZShkb2MsIGNoYW5nZS5zdGFydCwgY2hhbmdlLmVuZEEsICRmcm9tLCAkdG8pICYmXG4gICAgICAgIHZpZXcuc29tZVByb3AoXCJoYW5kbGVLZXlEb3duXCIsIGYgPT4gZih2aWV3LCBrZXlFdmVudCg4LCBcIkJhY2tzcGFjZVwiKSkpKSB7XG4gICAgICAgIGlmIChhbmRyb2lkICYmIGNocm9tZSlcbiAgICAgICAgICAgIHZpZXcuZG9tT2JzZXJ2ZXIuc3VwcHJlc3NTZWxlY3Rpb25VcGRhdGVzKCk7IC8vICM4MjBcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICAvLyBDaHJvbWUgd2lsbCBvY2Nhc2lvbmFsbHksIGR1cmluZyBjb21wb3NpdGlvbiwgZGVsZXRlIHRoZVxuICAgIC8vIGVudGlyZSBjb21wb3NpdGlvbiBhbmQgdGhlbiBpbW1lZGlhdGVseSBpbnNlcnQgaXQgYWdhaW4uIFRoaXMgaXNcbiAgICAvLyB1c2VkIHRvIGRldGVjdCB0aGF0IHNpdHVhdGlvbi5cbiAgICBpZiAoY2hyb21lICYmIGNoYW5nZS5lbmRCID09IGNoYW5nZS5zdGFydClcbiAgICAgICAgdmlldy5pbnB1dC5sYXN0Q2hyb21lRGVsZXRlID0gRGF0ZS5ub3coKTtcbiAgICAvLyBUaGlzIHRyaWVzIHRvIGRldGVjdCBBbmRyb2lkIHZpcnR1YWwga2V5Ym9hcmRcbiAgICAvLyBlbnRlci1hbmQtcGljay1zdWdnZXN0aW9uIGFjdGlvbi4gVGhhdCBzb21ldGltZXMgKHNlZSBpc3N1ZVxuICAgIC8vICMxMDU5KSBmaXJzdCBmaXJlcyBhIERPTSBtdXRhdGlvbiwgYmVmb3JlIG1vdmluZyB0aGUgc2VsZWN0aW9uIHRvXG4gICAgLy8gdGhlIG5ld2x5IGNyZWF0ZWQgYmxvY2suIEFuZCB0aGVuLCBiZWNhdXNlIFByb3NlTWlycm9yIGNsZWFucyB1cFxuICAgIC8vIHRoZSBET00gc2VsZWN0aW9uLCBpdCBnaXZlcyB1cCBtb3ZpbmcgdGhlIHNlbGVjdGlvbiBlbnRpcmVseSxcbiAgICAvLyBsZWF2aW5nIHRoZSBjdXJzb3IgaW4gdGhlIHdyb25nIHBsYWNlLiBXaGVuIHRoYXQgaGFwcGVucywgd2UgZHJvcFxuICAgIC8vIHRoZSBuZXcgcGFyYWdyYXBoIGZyb20gdGhlIGluaXRpYWwgY2hhbmdlLCBhbmQgZmlyZSBhIHNpbXVsYXRlZFxuICAgIC8vIGVudGVyIGtleSBhZnRlcndhcmRzLlxuICAgIGlmIChhbmRyb2lkICYmICFpbmxpbmVDaGFuZ2UgJiYgJGZyb20uc3RhcnQoKSAhPSAkdG8uc3RhcnQoKSAmJiAkdG8ucGFyZW50T2Zmc2V0ID09IDAgJiYgJGZyb20uZGVwdGggPT0gJHRvLmRlcHRoICYmXG4gICAgICAgIHBhcnNlLnNlbCAmJiBwYXJzZS5zZWwuYW5jaG9yID09IHBhcnNlLnNlbC5oZWFkICYmIHBhcnNlLnNlbC5oZWFkID09IGNoYW5nZS5lbmRBKSB7XG4gICAgICAgIGNoYW5nZS5lbmRCIC09IDI7XG4gICAgICAgICR0byA9IHBhcnNlLmRvYy5yZXNvbHZlTm9DYWNoZShjaGFuZ2UuZW5kQiAtIHBhcnNlLmZyb20pO1xuICAgICAgICBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgICAgICAgIHZpZXcuc29tZVByb3AoXCJoYW5kbGVLZXlEb3duXCIsIGZ1bmN0aW9uIChmKSB7IHJldHVybiBmKHZpZXcsIGtleUV2ZW50KDEzLCBcIkVudGVyXCIpKTsgfSk7XG4gICAgICAgIH0sIDIwKTtcbiAgICB9XG4gICAgbGV0IGNoRnJvbSA9IGNoYW5nZS5zdGFydCwgY2hUbyA9IGNoYW5nZS5lbmRBO1xuICAgIGxldCBta1RyID0gKGJhc2UpID0+IHtcbiAgICAgICAgbGV0IHRyID0gYmFzZSB8fCB2aWV3LnN0YXRlLnRyLnJlcGxhY2UoY2hGcm9tLCBjaFRvLCBwYXJzZS5kb2Muc2xpY2UoY2hhbmdlLnN0YXJ0IC0gcGFyc2UuZnJvbSwgY2hhbmdlLmVuZEIgLSBwYXJzZS5mcm9tKSk7XG4gICAgICAgIGlmIChwYXJzZS5zZWwpIHtcbiAgICAgICAgICAgIGxldCBzZWwgPSByZXNvbHZlU2VsZWN0aW9uKHZpZXcsIHRyLmRvYywgcGFyc2Uuc2VsKTtcbiAgICAgICAgICAgIC8vIENocm9tZSB3aWxsIHNvbWV0aW1lcywgZHVyaW5nIGNvbXBvc2l0aW9uLCByZXBvcnQgdGhlXG4gICAgICAgICAgICAvLyBzZWxlY3Rpb24gaW4gdGhlIHdyb25nIHBsYWNlLiBJZiBpdCBsb29rcyBsaWtlIHRoYXQgaXNcbiAgICAgICAgICAgIC8vIGhhcHBlbmluZywgZG9uJ3QgdXBkYXRlIHRoZSBzZWxlY3Rpb24uXG4gICAgICAgICAgICAvLyBFZGdlIGp1c3QgZG9lc24ndCBtb3ZlIHRoZSBjdXJzb3IgZm9yd2FyZCB3aGVuIHlvdSBzdGFydCB0eXBpbmdcbiAgICAgICAgICAgIC8vIGluIGFuIGVtcHR5IGJsb2NrIG9yIGJldHdlZW4gYnIgbm9kZXMuXG4gICAgICAgICAgICBpZiAoc2VsICYmICEoY2hyb21lICYmIHZpZXcuY29tcG9zaW5nICYmIHNlbC5lbXB0eSAmJlxuICAgICAgICAgICAgICAgIChjaGFuZ2Uuc3RhcnQgIT0gY2hhbmdlLmVuZEIgfHwgdmlldy5pbnB1dC5sYXN0Q2hyb21lRGVsZXRlIDwgRGF0ZS5ub3coKSAtIDEwMCkgJiZcbiAgICAgICAgICAgICAgICAoc2VsLmhlYWQgPT0gY2hGcm9tIHx8IHNlbC5oZWFkID09IHRyLm1hcHBpbmcubWFwKGNoVG8pIC0gMSkgfHxcbiAgICAgICAgICAgICAgICBpZSAmJiBzZWwuZW1wdHkgJiYgc2VsLmhlYWQgPT0gY2hGcm9tKSlcbiAgICAgICAgICAgICAgICB0ci5zZXRTZWxlY3Rpb24oc2VsKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoY29tcG9zaXRpb25JRClcbiAgICAgICAgICAgIHRyLnNldE1ldGEoXCJjb21wb3NpdGlvblwiLCBjb21wb3NpdGlvbklEKTtcbiAgICAgICAgcmV0dXJuIHRyLnNjcm9sbEludG9WaWV3KCk7XG4gICAgfTtcbiAgICBsZXQgbWFya0NoYW5nZTtcbiAgICBpZiAoaW5saW5lQ2hhbmdlKSB7XG4gICAgICAgIGlmICgkZnJvbS5wb3MgPT0gJHRvLnBvcykgeyAvLyBEZWxldGlvblxuICAgICAgICAgICAgLy8gSUUxMSBzb21ldGltZXMgd2VpcmRseSBtb3ZlcyB0aGUgRE9NIHNlbGVjdGlvbiBhcm91bmQgYWZ0ZXJcbiAgICAgICAgICAgIC8vIGJhY2tzcGFjaW5nIG91dCB0aGUgZmlyc3QgZWxlbWVudCBpbiBhIHRleHRibG9ja1xuICAgICAgICAgICAgaWYgKGllICYmIGllX3ZlcnNpb24gPD0gMTEgJiYgJGZyb20ucGFyZW50T2Zmc2V0ID09IDApIHtcbiAgICAgICAgICAgICAgICB2aWV3LmRvbU9ic2VydmVyLnN1cHByZXNzU2VsZWN0aW9uVXBkYXRlcygpO1xuICAgICAgICAgICAgICAgIHNldFRpbWVvdXQoKCkgPT4gc2VsZWN0aW9uVG9ET00odmlldyksIDIwKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGxldCB0ciA9IG1rVHIodmlldy5zdGF0ZS50ci5kZWxldGUoY2hGcm9tLCBjaFRvKSk7XG4gICAgICAgICAgICBsZXQgbWFya3MgPSBkb2MucmVzb2x2ZShjaGFuZ2Uuc3RhcnQpLm1hcmtzQWNyb3NzKGRvYy5yZXNvbHZlKGNoYW5nZS5lbmRBKSk7XG4gICAgICAgICAgICBpZiAobWFya3MpXG4gICAgICAgICAgICAgICAgdHIuZW5zdXJlTWFya3MobWFya3MpO1xuICAgICAgICAgICAgdmlldy5kaXNwYXRjaCh0cik7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAoIC8vIEFkZGluZyBvciByZW1vdmluZyBhIG1hcmtcbiAgICAgICAgY2hhbmdlLmVuZEEgPT0gY2hhbmdlLmVuZEIgJiZcbiAgICAgICAgICAgIChtYXJrQ2hhbmdlID0gaXNNYXJrQ2hhbmdlKCRmcm9tLnBhcmVudC5jb250ZW50LmN1dCgkZnJvbS5wYXJlbnRPZmZzZXQsICR0by5wYXJlbnRPZmZzZXQpLCAkZnJvbUEucGFyZW50LmNvbnRlbnQuY3V0KCRmcm9tQS5wYXJlbnRPZmZzZXQsIGNoYW5nZS5lbmRBIC0gJGZyb21BLnN0YXJ0KCkpKSkpIHtcbiAgICAgICAgICAgIGxldCB0ciA9IG1rVHIodmlldy5zdGF0ZS50cik7XG4gICAgICAgICAgICBpZiAobWFya0NoYW5nZS50eXBlID09IFwiYWRkXCIpXG4gICAgICAgICAgICAgICAgdHIuYWRkTWFyayhjaEZyb20sIGNoVG8sIG1hcmtDaGFuZ2UubWFyayk7XG4gICAgICAgICAgICBlbHNlXG4gICAgICAgICAgICAgICAgdHIucmVtb3ZlTWFyayhjaEZyb20sIGNoVG8sIG1hcmtDaGFuZ2UubWFyayk7XG4gICAgICAgICAgICB2aWV3LmRpc3BhdGNoKHRyKTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIGlmICgkZnJvbS5wYXJlbnQuY2hpbGQoJGZyb20uaW5kZXgoKSkuaXNUZXh0ICYmICRmcm9tLmluZGV4KCkgPT0gJHRvLmluZGV4KCkgLSAoJHRvLnRleHRPZmZzZXQgPyAwIDogMSkpIHtcbiAgICAgICAgICAgIC8vIEJvdGggcG9zaXRpb25zIGluIHRoZSBzYW1lIHRleHQgbm9kZSAtLSBzaW1wbHkgaW5zZXJ0IHRleHRcbiAgICAgICAgICAgIGxldCB0ZXh0ID0gJGZyb20ucGFyZW50LnRleHRCZXR3ZWVuKCRmcm9tLnBhcmVudE9mZnNldCwgJHRvLnBhcmVudE9mZnNldCk7XG4gICAgICAgICAgICBsZXQgZGVmbHQgPSAoKSA9PiBta1RyKHZpZXcuc3RhdGUudHIuaW5zZXJ0VGV4dCh0ZXh0LCBjaEZyb20sIGNoVG8pKTtcbiAgICAgICAgICAgIGlmICghdmlldy5zb21lUHJvcChcImhhbmRsZVRleHRJbnB1dFwiLCBmID0+IGYodmlldywgY2hGcm9tLCBjaFRvLCB0ZXh0LCBkZWZsdCkpKVxuICAgICAgICAgICAgICAgIHZpZXcuZGlzcGF0Y2goZGVmbHQoKSk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICB2aWV3LmRpc3BhdGNoKG1rVHIoKSk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgZWxzZSB7XG4gICAgICAgIHZpZXcuZGlzcGF0Y2gobWtUcigpKTtcbiAgICB9XG59XG5mdW5jdGlvbiByZXNvbHZlU2VsZWN0aW9uKHZpZXcsIGRvYywgcGFyc2VkU2VsKSB7XG4gICAgaWYgKE1hdGgubWF4KHBhcnNlZFNlbC5hbmNob3IsIHBhcnNlZFNlbC5oZWFkKSA+IGRvYy5jb250ZW50LnNpemUpXG4gICAgICAgIHJldHVybiBudWxsO1xuICAgIHJldHVybiBzZWxlY3Rpb25CZXR3ZWVuKHZpZXcsIGRvYy5yZXNvbHZlKHBhcnNlZFNlbC5hbmNob3IpLCBkb2MucmVzb2x2ZShwYXJzZWRTZWwuaGVhZCkpO1xufVxuLy8gR2l2ZW4gdHdvIHNhbWUtbGVuZ3RoLCBub24tZW1wdHkgZnJhZ21lbnRzIG9mIGlubGluZSBjb250ZW50LFxuLy8gZGV0ZXJtaW5lIHdoZXRoZXIgdGhlIGZpcnN0IGNvdWxkIGJlIGNyZWF0ZWQgZnJvbSB0aGUgc2Vjb25kIGJ5XG4vLyByZW1vdmluZyBvciBhZGRpbmcgYSBzaW5nbGUgbWFyayB0eXBlLlxuZnVuY3Rpb24gaXNNYXJrQ2hhbmdlKGN1ciwgcHJldikge1xuICAgIGxldCBjdXJNYXJrcyA9IGN1ci5maXJzdENoaWxkLm1hcmtzLCBwcmV2TWFya3MgPSBwcmV2LmZpcnN0Q2hpbGQubWFya3M7XG4gICAgbGV0IGFkZGVkID0gY3VyTWFya3MsIHJlbW92ZWQgPSBwcmV2TWFya3MsIHR5cGUsIG1hcmssIHVwZGF0ZTtcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IHByZXZNYXJrcy5sZW5ndGg7IGkrKylcbiAgICAgICAgYWRkZWQgPSBwcmV2TWFya3NbaV0ucmVtb3ZlRnJvbVNldChhZGRlZCk7XG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBjdXJNYXJrcy5sZW5ndGg7IGkrKylcbiAgICAgICAgcmVtb3ZlZCA9IGN1ck1hcmtzW2ldLnJlbW92ZUZyb21TZXQocmVtb3ZlZCk7XG4gICAgaWYgKGFkZGVkLmxlbmd0aCA9PSAxICYmIHJlbW92ZWQubGVuZ3RoID09IDApIHtcbiAgICAgICAgbWFyayA9IGFkZGVkWzBdO1xuICAgICAgICB0eXBlID0gXCJhZGRcIjtcbiAgICAgICAgdXBkYXRlID0gKG5vZGUpID0+IG5vZGUubWFyayhtYXJrLmFkZFRvU2V0KG5vZGUubWFya3MpKTtcbiAgICB9XG4gICAgZWxzZSBpZiAoYWRkZWQubGVuZ3RoID09IDAgJiYgcmVtb3ZlZC5sZW5ndGggPT0gMSkge1xuICAgICAgICBtYXJrID0gcmVtb3ZlZFswXTtcbiAgICAgICAgdHlwZSA9IFwicmVtb3ZlXCI7XG4gICAgICAgIHVwZGF0ZSA9IChub2RlKSA9PiBub2RlLm1hcmsobWFyay5yZW1vdmVGcm9tU2V0KG5vZGUubWFya3MpKTtcbiAgICB9XG4gICAgZWxzZSB7XG4gICAgICAgIHJldHVybiBudWxsO1xuICAgIH1cbiAgICBsZXQgdXBkYXRlZCA9IFtdO1xuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgcHJldi5jaGlsZENvdW50OyBpKyspXG4gICAgICAgIHVwZGF0ZWQucHVzaCh1cGRhdGUocHJldi5jaGlsZChpKSkpO1xuICAgIGlmIChGcmFnbWVudC5mcm9tKHVwZGF0ZWQpLmVxKGN1cikpXG4gICAgICAgIHJldHVybiB7IG1hcmssIHR5cGUgfTtcbn1cbmZ1bmN0aW9uIGxvb2tzTGlrZUJhY2tzcGFjZShvbGQsIHN0YXJ0LCBlbmQsICRuZXdTdGFydCwgJG5ld0VuZCkge1xuICAgIGlmICggLy8gVGhlIGNvbnRlbnQgbXVzdCBoYXZlIHNocnVua1xuICAgIGVuZCAtIHN0YXJ0IDw9ICRuZXdFbmQucG9zIC0gJG5ld1N0YXJ0LnBvcyB8fFxuICAgICAgICAvLyBuZXdFbmQgbXVzdCBwb2ludCBkaXJlY3RseSBhdCBvciBhZnRlciB0aGUgZW5kIG9mIHRoZSBibG9jayB0aGF0IG5ld1N0YXJ0IHBvaW50cyBpbnRvXG4gICAgICAgIHNraXBDbG9zaW5nQW5kT3BlbmluZygkbmV3U3RhcnQsIHRydWUsIGZhbHNlKSA8ICRuZXdFbmQucG9zKVxuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgbGV0ICRzdGFydCA9IG9sZC5yZXNvbHZlKHN0YXJ0KTtcbiAgICAvLyBIYW5kbGUgdGhlIGNhc2Ugd2hlcmUsIHJhdGhlciB0aGFuIGpvaW5pbmcgYmxvY2tzLCB0aGUgY2hhbmdlIGp1c3QgcmVtb3ZlZCBhbiBlbnRpcmUgYmxvY2tcbiAgICBpZiAoISRuZXdTdGFydC5wYXJlbnQuaXNUZXh0YmxvY2spIHtcbiAgICAgICAgbGV0IGFmdGVyID0gJHN0YXJ0Lm5vZGVBZnRlcjtcbiAgICAgICAgcmV0dXJuIGFmdGVyICE9IG51bGwgJiYgZW5kID09IHN0YXJ0ICsgYWZ0ZXIubm9kZVNpemU7XG4gICAgfVxuICAgIC8vIFN0YXJ0IG11c3QgYmUgYXQgdGhlIGVuZCBvZiBhIGJsb2NrXG4gICAgaWYgKCRzdGFydC5wYXJlbnRPZmZzZXQgPCAkc3RhcnQucGFyZW50LmNvbnRlbnQuc2l6ZSB8fCAhJHN0YXJ0LnBhcmVudC5pc1RleHRibG9jaylcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIGxldCAkbmV4dCA9IG9sZC5yZXNvbHZlKHNraXBDbG9zaW5nQW5kT3BlbmluZygkc3RhcnQsIHRydWUsIHRydWUpKTtcbiAgICAvLyBUaGUgbmV4dCB0ZXh0YmxvY2sgbXVzdCBzdGFydCBiZWZvcmUgZW5kIGFuZCBlbmQgbmVhciBpdFxuICAgIGlmICghJG5leHQucGFyZW50LmlzVGV4dGJsb2NrIHx8ICRuZXh0LnBvcyA+IGVuZCB8fFxuICAgICAgICBza2lwQ2xvc2luZ0FuZE9wZW5pbmcoJG5leHQsIHRydWUsIGZhbHNlKSA8IGVuZClcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIC8vIFRoZSBmcmFnbWVudHMgYWZ0ZXIgdGhlIGpvaW4gcG9pbnQgbXVzdCBtYXRjaFxuICAgIHJldHVybiAkbmV3U3RhcnQucGFyZW50LmNvbnRlbnQuY3V0KCRuZXdTdGFydC5wYXJlbnRPZmZzZXQpLmVxKCRuZXh0LnBhcmVudC5jb250ZW50KTtcbn1cbmZ1bmN0aW9uIHNraXBDbG9zaW5nQW5kT3BlbmluZygkcG9zLCBmcm9tRW5kLCBtYXlPcGVuKSB7XG4gICAgbGV0IGRlcHRoID0gJHBvcy5kZXB0aCwgZW5kID0gZnJvbUVuZCA/ICRwb3MuZW5kKCkgOiAkcG9zLnBvcztcbiAgICB3aGlsZSAoZGVwdGggPiAwICYmIChmcm9tRW5kIHx8ICRwb3MuaW5kZXhBZnRlcihkZXB0aCkgPT0gJHBvcy5ub2RlKGRlcHRoKS5jaGlsZENvdW50KSkge1xuICAgICAgICBkZXB0aC0tO1xuICAgICAgICBlbmQrKztcbiAgICAgICAgZnJvbUVuZCA9IGZhbHNlO1xuICAgIH1cbiAgICBpZiAobWF5T3Blbikge1xuICAgICAgICBsZXQgbmV4dCA9ICRwb3Mubm9kZShkZXB0aCkubWF5YmVDaGlsZCgkcG9zLmluZGV4QWZ0ZXIoZGVwdGgpKTtcbiAgICAgICAgd2hpbGUgKG5leHQgJiYgIW5leHQuaXNMZWFmKSB7XG4gICAgICAgICAgICBuZXh0ID0gbmV4dC5maXJzdENoaWxkO1xuICAgICAgICAgICAgZW5kKys7XG4gICAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIGVuZDtcbn1cbmZ1bmN0aW9uIGZpbmREaWZmKGEsIGIsIHBvcywgcHJlZmVycmVkUG9zLCBwcmVmZXJyZWRTaWRlKSB7XG4gICAgbGV0IHN0YXJ0ID0gYS5maW5kRGlmZlN0YXJ0KGIsIHBvcyk7XG4gICAgaWYgKHN0YXJ0ID09IG51bGwpXG4gICAgICAgIHJldHVybiBudWxsO1xuICAgIGxldCB7IGE6IGVuZEEsIGI6IGVuZEIgfSA9IGEuZmluZERpZmZFbmQoYiwgcG9zICsgYS5zaXplLCBwb3MgKyBiLnNpemUpO1xuICAgIGlmIChwcmVmZXJyZWRTaWRlID09IFwiZW5kXCIpIHtcbiAgICAgICAgbGV0IGFkanVzdCA9IE1hdGgubWF4KDAsIHN0YXJ0IC0gTWF0aC5taW4oZW5kQSwgZW5kQikpO1xuICAgICAgICBwcmVmZXJyZWRQb3MgLT0gZW5kQSArIGFkanVzdCAtIHN0YXJ0O1xuICAgIH1cbiAgICBpZiAoZW5kQSA8IHN0YXJ0ICYmIGEuc2l6ZSA8IGIuc2l6ZSkge1xuICAgICAgICBsZXQgbW92ZSA9IHByZWZlcnJlZFBvcyA8PSBzdGFydCAmJiBwcmVmZXJyZWRQb3MgPj0gZW5kQSA/IHN0YXJ0IC0gcHJlZmVycmVkUG9zIDogMDtcbiAgICAgICAgc3RhcnQgLT0gbW92ZTtcbiAgICAgICAgaWYgKHN0YXJ0ICYmIHN0YXJ0IDwgYi5zaXplICYmIGlzU3Vycm9nYXRlUGFpcihiLnRleHRCZXR3ZWVuKHN0YXJ0IC0gMSwgc3RhcnQgKyAxKSkpXG4gICAgICAgICAgICBzdGFydCArPSBtb3ZlID8gMSA6IC0xO1xuICAgICAgICBlbmRCID0gc3RhcnQgKyAoZW5kQiAtIGVuZEEpO1xuICAgICAgICBlbmRBID0gc3RhcnQ7XG4gICAgfVxuICAgIGVsc2UgaWYgKGVuZEIgPCBzdGFydCkge1xuICAgICAgICBsZXQgbW92ZSA9IHByZWZlcnJlZFBvcyA8PSBzdGFydCAmJiBwcmVmZXJyZWRQb3MgPj0gZW5kQiA/IHN0YXJ0IC0gcHJlZmVycmVkUG9zIDogMDtcbiAgICAgICAgc3RhcnQgLT0gbW92ZTtcbiAgICAgICAgaWYgKHN0YXJ0ICYmIHN0YXJ0IDwgYS5zaXplICYmIGlzU3Vycm9nYXRlUGFpcihhLnRleHRCZXR3ZWVuKHN0YXJ0IC0gMSwgc3RhcnQgKyAxKSkpXG4gICAgICAgICAgICBzdGFydCArPSBtb3ZlID8gMSA6IC0xO1xuICAgICAgICBlbmRBID0gc3RhcnQgKyAoZW5kQSAtIGVuZEIpO1xuICAgICAgICBlbmRCID0gc3RhcnQ7XG4gICAgfVxuICAgIHJldHVybiB7IHN0YXJ0LCBlbmRBLCBlbmRCIH07XG59XG5mdW5jdGlvbiBpc1N1cnJvZ2F0ZVBhaXIoc3RyKSB7XG4gICAgaWYgKHN0ci5sZW5ndGggIT0gMilcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIGxldCBhID0gc3RyLmNoYXJDb2RlQXQoMCksIGIgPSBzdHIuY2hhckNvZGVBdCgxKTtcbiAgICByZXR1cm4gYSA+PSAweERDMDAgJiYgYSA8PSAweERGRkYgJiYgYiA+PSAweEQ4MDAgJiYgYiA8PSAweERCRkY7XG59XG5cbi8qKlxuQGludGVybmFsXG4qL1xuY29uc3QgX19wYXJzZUZyb21DbGlwYm9hcmQgPSBwYXJzZUZyb21DbGlwYm9hcmQ7XG4vKipcbkBpbnRlcm5hbFxuKi9cbmNvbnN0IF9fZW5kQ29tcG9zaXRpb24gPSBlbmRDb21wb3NpdGlvbjtcbi8qKlxuQW4gZWRpdG9yIHZpZXcgbWFuYWdlcyB0aGUgRE9NIHN0cnVjdHVyZSB0aGF0IHJlcHJlc2VudHMgYW5cbmVkaXRhYmxlIGRvY3VtZW50LiBJdHMgc3RhdGUgYW5kIGJlaGF2aW9yIGFyZSBkZXRlcm1pbmVkIGJ5IGl0c1xuW3Byb3BzXShodHRwczovL3Byb3NlbWlycm9yLm5ldC9kb2NzL3JlZi8jdmlldy5EaXJlY3RFZGl0b3JQcm9wcykuXG4qL1xuY2xhc3MgRWRpdG9yVmlldyB7XG4gICAgLyoqXG4gICAgQ3JlYXRlIGEgdmlldy4gYHBsYWNlYCBtYXkgYmUgYSBET00gbm9kZSB0aGF0IHRoZSBlZGl0b3Igc2hvdWxkXG4gICAgYmUgYXBwZW5kZWQgdG8sIGEgZnVuY3Rpb24gdGhhdCB3aWxsIHBsYWNlIGl0IGludG8gdGhlIGRvY3VtZW50LFxuICAgIG9yIGFuIG9iamVjdCB3aG9zZSBgbW91bnRgIHByb3BlcnR5IGhvbGRzIHRoZSBub2RlIHRvIHVzZSBhcyB0aGVcbiAgICBkb2N1bWVudCBjb250YWluZXIuIElmIGl0IGlzIGBudWxsYCwgdGhlIGVkaXRvciB3aWxsIG5vdCBiZVxuICAgIGFkZGVkIHRvIHRoZSBkb2N1bWVudC5cbiAgICAqL1xuICAgIGNvbnN0cnVjdG9yKHBsYWNlLCBwcm9wcykge1xuICAgICAgICB0aGlzLl9yb290ID0gbnVsbDtcbiAgICAgICAgLyoqXG4gICAgICAgIEBpbnRlcm5hbFxuICAgICAgICAqL1xuICAgICAgICB0aGlzLmZvY3VzZWQgPSBmYWxzZTtcbiAgICAgICAgLyoqXG4gICAgICAgIEtsdWRnZSB1c2VkIHRvIHdvcmsgYXJvdW5kIGEgQ2hyb21lIGJ1ZyBAaW50ZXJuYWxcbiAgICAgICAgKi9cbiAgICAgICAgdGhpcy50cmFja1dyaXRlcyA9IG51bGw7XG4gICAgICAgIHRoaXMubW91bnRlZCA9IGZhbHNlO1xuICAgICAgICAvKipcbiAgICAgICAgQGludGVybmFsXG4gICAgICAgICovXG4gICAgICAgIHRoaXMubWFya0N1cnNvciA9IG51bGw7XG4gICAgICAgIC8qKlxuICAgICAgICBAaW50ZXJuYWxcbiAgICAgICAgKi9cbiAgICAgICAgdGhpcy5jdXJzb3JXcmFwcGVyID0gbnVsbDtcbiAgICAgICAgLyoqXG4gICAgICAgIEBpbnRlcm5hbFxuICAgICAgICAqL1xuICAgICAgICB0aGlzLmxhc3RTZWxlY3RlZFZpZXdEZXNjID0gdW5kZWZpbmVkO1xuICAgICAgICAvKipcbiAgICAgICAgQGludGVybmFsXG4gICAgICAgICovXG4gICAgICAgIHRoaXMuaW5wdXQgPSBuZXcgSW5wdXRTdGF0ZTtcbiAgICAgICAgdGhpcy5wcmV2RGlyZWN0UGx1Z2lucyA9IFtdO1xuICAgICAgICB0aGlzLnBsdWdpblZpZXdzID0gW107XG4gICAgICAgIC8qKlxuICAgICAgICBIb2xkcyBgdHJ1ZWAgd2hlbiBhIGhhY2sgbm9kZSBpcyBuZWVkZWQgaW4gRmlyZWZveCB0byBwcmV2ZW50IHRoZVxuICAgICAgICBbc3BhY2UgaXMgZWF0ZW4gaXNzdWVdKGh0dHBzOi8vZ2l0aHViLmNvbS9Qcm9zZU1pcnJvci9wcm9zZW1pcnJvci9pc3N1ZXMvNjUxKVxuICAgICAgICBAaW50ZXJuYWxcbiAgICAgICAgKi9cbiAgICAgICAgdGhpcy5yZXF1aXJlc0dlY2tvSGFja05vZGUgPSBmYWxzZTtcbiAgICAgICAgLyoqXG4gICAgICAgIFdoZW4gZWRpdG9yIGNvbnRlbnQgaXMgYmVpbmcgZHJhZ2dlZCwgdGhpcyBvYmplY3QgY29udGFpbnNcbiAgICAgICAgaW5mb3JtYXRpb24gYWJvdXQgdGhlIGRyYWdnZWQgc2xpY2UgYW5kIHdoZXRoZXIgaXQgaXMgYmVpbmdcbiAgICAgICAgY29waWVkIG9yIG1vdmVkLiBBdCBhbnkgb3RoZXIgdGltZSwgaXQgaXMgbnVsbC5cbiAgICAgICAgKi9cbiAgICAgICAgdGhpcy5kcmFnZ2luZyA9IG51bGw7XG4gICAgICAgIHRoaXMuX3Byb3BzID0gcHJvcHM7XG4gICAgICAgIHRoaXMuc3RhdGUgPSBwcm9wcy5zdGF0ZTtcbiAgICAgICAgdGhpcy5kaXJlY3RQbHVnaW5zID0gcHJvcHMucGx1Z2lucyB8fCBbXTtcbiAgICAgICAgdGhpcy5kaXJlY3RQbHVnaW5zLmZvckVhY2goY2hlY2tTdGF0ZUNvbXBvbmVudCk7XG4gICAgICAgIHRoaXMuZGlzcGF0Y2ggPSB0aGlzLmRpc3BhdGNoLmJpbmQodGhpcyk7XG4gICAgICAgIHRoaXMuZG9tID0gKHBsYWNlICYmIHBsYWNlLm1vdW50KSB8fCBkb2N1bWVudC5jcmVhdGVFbGVtZW50KFwiZGl2XCIpO1xuICAgICAgICBpZiAocGxhY2UpIHtcbiAgICAgICAgICAgIGlmIChwbGFjZS5hcHBlbmRDaGlsZClcbiAgICAgICAgICAgICAgICBwbGFjZS5hcHBlbmRDaGlsZCh0aGlzLmRvbSk7XG4gICAgICAgICAgICBlbHNlIGlmICh0eXBlb2YgcGxhY2UgPT0gXCJmdW5jdGlvblwiKVxuICAgICAgICAgICAgICAgIHBsYWNlKHRoaXMuZG9tKTtcbiAgICAgICAgICAgIGVsc2UgaWYgKHBsYWNlLm1vdW50KVxuICAgICAgICAgICAgICAgIHRoaXMubW91bnRlZCA9IHRydWU7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5lZGl0YWJsZSA9IGdldEVkaXRhYmxlKHRoaXMpO1xuICAgICAgICB1cGRhdGVDdXJzb3JXcmFwcGVyKHRoaXMpO1xuICAgICAgICB0aGlzLm5vZGVWaWV3cyA9IGJ1aWxkTm9kZVZpZXdzKHRoaXMpO1xuICAgICAgICB0aGlzLmRvY1ZpZXcgPSBkb2NWaWV3RGVzYyh0aGlzLnN0YXRlLmRvYywgY29tcHV0ZURvY0RlY28odGhpcyksIHZpZXdEZWNvcmF0aW9ucyh0aGlzKSwgdGhpcy5kb20sIHRoaXMpO1xuICAgICAgICB0aGlzLmRvbU9ic2VydmVyID0gbmV3IERPTU9ic2VydmVyKHRoaXMsIChmcm9tLCB0bywgdHlwZU92ZXIsIGFkZGVkKSA9PiByZWFkRE9NQ2hhbmdlKHRoaXMsIGZyb20sIHRvLCB0eXBlT3ZlciwgYWRkZWQpKTtcbiAgICAgICAgdGhpcy5kb21PYnNlcnZlci5zdGFydCgpO1xuICAgICAgICBpbml0SW5wdXQodGhpcyk7XG4gICAgICAgIHRoaXMudXBkYXRlUGx1Z2luVmlld3MoKTtcbiAgICB9XG4gICAgLyoqXG4gICAgSG9sZHMgYHRydWVgIHdoZW4gYVxuICAgIFtjb21wb3NpdGlvbl0oaHR0cHM6Ly93M2MuZ2l0aHViLmlvL3VpZXZlbnRzLyNldmVudHMtY29tcG9zaXRpb25ldmVudHMpXG4gICAgaXMgYWN0aXZlLlxuICAgICovXG4gICAgZ2V0IGNvbXBvc2luZygpIHsgcmV0dXJuIHRoaXMuaW5wdXQuY29tcG9zaW5nOyB9XG4gICAgLyoqXG4gICAgVGhlIHZpZXcncyBjdXJyZW50IFtwcm9wc10oaHR0cHM6Ly9wcm9zZW1pcnJvci5uZXQvZG9jcy9yZWYvI3ZpZXcuRWRpdG9yUHJvcHMpLlxuICAgICovXG4gICAgZ2V0IHByb3BzKCkge1xuICAgICAgICBpZiAodGhpcy5fcHJvcHMuc3RhdGUgIT0gdGhpcy5zdGF0ZSkge1xuICAgICAgICAgICAgbGV0IHByZXYgPSB0aGlzLl9wcm9wcztcbiAgICAgICAgICAgIHRoaXMuX3Byb3BzID0ge307XG4gICAgICAgICAgICBmb3IgKGxldCBuYW1lIGluIHByZXYpXG4gICAgICAgICAgICAgICAgdGhpcy5fcHJvcHNbbmFtZV0gPSBwcmV2W25hbWVdO1xuICAgICAgICAgICAgdGhpcy5fcHJvcHMuc3RhdGUgPSB0aGlzLnN0YXRlO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB0aGlzLl9wcm9wcztcbiAgICB9XG4gICAgLyoqXG4gICAgVXBkYXRlIHRoZSB2aWV3J3MgcHJvcHMuIFdpbGwgaW1tZWRpYXRlbHkgY2F1c2UgYW4gdXBkYXRlIHRvXG4gICAgdGhlIERPTS5cbiAgICAqL1xuICAgIHVwZGF0ZShwcm9wcykge1xuICAgICAgICBpZiAocHJvcHMuaGFuZGxlRE9NRXZlbnRzICE9IHRoaXMuX3Byb3BzLmhhbmRsZURPTUV2ZW50cylcbiAgICAgICAgICAgIGVuc3VyZUxpc3RlbmVycyh0aGlzKTtcbiAgICAgICAgbGV0IHByZXZQcm9wcyA9IHRoaXMuX3Byb3BzO1xuICAgICAgICB0aGlzLl9wcm9wcyA9IHByb3BzO1xuICAgICAgICBpZiAocHJvcHMucGx1Z2lucykge1xuICAgICAgICAgICAgcHJvcHMucGx1Z2lucy5mb3JFYWNoKGNoZWNrU3RhdGVDb21wb25lbnQpO1xuICAgICAgICAgICAgdGhpcy5kaXJlY3RQbHVnaW5zID0gcHJvcHMucGx1Z2lucztcbiAgICAgICAgfVxuICAgICAgICB0aGlzLnVwZGF0ZVN0YXRlSW5uZXIocHJvcHMuc3RhdGUsIHByZXZQcm9wcyk7XG4gICAgfVxuICAgIC8qKlxuICAgIFVwZGF0ZSB0aGUgdmlldyBieSB1cGRhdGluZyBleGlzdGluZyBwcm9wcyBvYmplY3Qgd2l0aCB0aGUgb2JqZWN0XG4gICAgZ2l2ZW4gYXMgYXJndW1lbnQuIEVxdWl2YWxlbnQgdG8gYHZpZXcudXBkYXRlKE9iamVjdC5hc3NpZ24oe30sXG4gICAgdmlldy5wcm9wcywgcHJvcHMpKWAuXG4gICAgKi9cbiAgICBzZXRQcm9wcyhwcm9wcykge1xuICAgICAgICBsZXQgdXBkYXRlZCA9IHt9O1xuICAgICAgICBmb3IgKGxldCBuYW1lIGluIHRoaXMuX3Byb3BzKVxuICAgICAgICAgICAgdXBkYXRlZFtuYW1lXSA9IHRoaXMuX3Byb3BzW25hbWVdO1xuICAgICAgICB1cGRhdGVkLnN0YXRlID0gdGhpcy5zdGF0ZTtcbiAgICAgICAgZm9yIChsZXQgbmFtZSBpbiBwcm9wcylcbiAgICAgICAgICAgIHVwZGF0ZWRbbmFtZV0gPSBwcm9wc1tuYW1lXTtcbiAgICAgICAgdGhpcy51cGRhdGUodXBkYXRlZCk7XG4gICAgfVxuICAgIC8qKlxuICAgIFVwZGF0ZSB0aGUgZWRpdG9yJ3MgYHN0YXRlYCBwcm9wLCB3aXRob3V0IHRvdWNoaW5nIGFueSBvZiB0aGVcbiAgICBvdGhlciBwcm9wcy5cbiAgICAqL1xuICAgIHVwZGF0ZVN0YXRlKHN0YXRlKSB7XG4gICAgICAgIHRoaXMudXBkYXRlU3RhdGVJbm5lcihzdGF0ZSwgdGhpcy5fcHJvcHMpO1xuICAgIH1cbiAgICB1cGRhdGVTdGF0ZUlubmVyKHN0YXRlLCBwcmV2UHJvcHMpIHtcbiAgICAgICAgdmFyIF9hO1xuICAgICAgICBsZXQgcHJldiA9IHRoaXMuc3RhdGUsIHJlZHJhdyA9IGZhbHNlLCB1cGRhdGVTZWwgPSBmYWxzZTtcbiAgICAgICAgLy8gV2hlbiBzdG9yZWQgbWFya3MgYXJlIGFkZGVkLCBzdG9wIGNvbXBvc2l0aW9uLCBzbyB0aGF0IHRoZXkgY2FuXG4gICAgICAgIC8vIGJlIGRpc3BsYXllZC5cbiAgICAgICAgaWYgKHN0YXRlLnN0b3JlZE1hcmtzICYmIHRoaXMuY29tcG9zaW5nKSB7XG4gICAgICAgICAgICBjbGVhckNvbXBvc2l0aW9uKHRoaXMpO1xuICAgICAgICAgICAgdXBkYXRlU2VsID0gdHJ1ZTtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLnN0YXRlID0gc3RhdGU7XG4gICAgICAgIGxldCBwbHVnaW5zQ2hhbmdlZCA9IHByZXYucGx1Z2lucyAhPSBzdGF0ZS5wbHVnaW5zIHx8IHRoaXMuX3Byb3BzLnBsdWdpbnMgIT0gcHJldlByb3BzLnBsdWdpbnM7XG4gICAgICAgIGlmIChwbHVnaW5zQ2hhbmdlZCB8fCB0aGlzLl9wcm9wcy5wbHVnaW5zICE9IHByZXZQcm9wcy5wbHVnaW5zIHx8IHRoaXMuX3Byb3BzLm5vZGVWaWV3cyAhPSBwcmV2UHJvcHMubm9kZVZpZXdzKSB7XG4gICAgICAgICAgICBsZXQgbm9kZVZpZXdzID0gYnVpbGROb2RlVmlld3ModGhpcyk7XG4gICAgICAgICAgICBpZiAoY2hhbmdlZE5vZGVWaWV3cyhub2RlVmlld3MsIHRoaXMubm9kZVZpZXdzKSkge1xuICAgICAgICAgICAgICAgIHRoaXMubm9kZVZpZXdzID0gbm9kZVZpZXdzO1xuICAgICAgICAgICAgICAgIHJlZHJhdyA9IHRydWU7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHBsdWdpbnNDaGFuZ2VkIHx8IHByZXZQcm9wcy5oYW5kbGVET01FdmVudHMgIT0gdGhpcy5fcHJvcHMuaGFuZGxlRE9NRXZlbnRzKSB7XG4gICAgICAgICAgICBlbnN1cmVMaXN0ZW5lcnModGhpcyk7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5lZGl0YWJsZSA9IGdldEVkaXRhYmxlKHRoaXMpO1xuICAgICAgICB1cGRhdGVDdXJzb3JXcmFwcGVyKHRoaXMpO1xuICAgICAgICBsZXQgaW5uZXJEZWNvID0gdmlld0RlY29yYXRpb25zKHRoaXMpLCBvdXRlckRlY28gPSBjb21wdXRlRG9jRGVjbyh0aGlzKTtcbiAgICAgICAgbGV0IHNjcm9sbCA9IHByZXYucGx1Z2lucyAhPSBzdGF0ZS5wbHVnaW5zICYmICFwcmV2LmRvYy5lcShzdGF0ZS5kb2MpID8gXCJyZXNldFwiXG4gICAgICAgICAgICA6IHN0YXRlLnNjcm9sbFRvU2VsZWN0aW9uID4gcHJldi5zY3JvbGxUb1NlbGVjdGlvbiA/IFwidG8gc2VsZWN0aW9uXCIgOiBcInByZXNlcnZlXCI7XG4gICAgICAgIGxldCB1cGRhdGVEb2MgPSByZWRyYXcgfHwgIXRoaXMuZG9jVmlldy5tYXRjaGVzTm9kZShzdGF0ZS5kb2MsIG91dGVyRGVjbywgaW5uZXJEZWNvKTtcbiAgICAgICAgaWYgKHVwZGF0ZURvYyB8fCAhc3RhdGUuc2VsZWN0aW9uLmVxKHByZXYuc2VsZWN0aW9uKSlcbiAgICAgICAgICAgIHVwZGF0ZVNlbCA9IHRydWU7XG4gICAgICAgIGxldCBvbGRTY3JvbGxQb3MgPSBzY3JvbGwgPT0gXCJwcmVzZXJ2ZVwiICYmIHVwZGF0ZVNlbCAmJiB0aGlzLmRvbS5zdHlsZS5vdmVyZmxvd0FuY2hvciA9PSBudWxsICYmIHN0b3JlU2Nyb2xsUG9zKHRoaXMpO1xuICAgICAgICBpZiAodXBkYXRlU2VsKSB7XG4gICAgICAgICAgICB0aGlzLmRvbU9ic2VydmVyLnN0b3AoKTtcbiAgICAgICAgICAgIC8vIFdvcmsgYXJvdW5kIGFuIGlzc3VlIGluIENocm9tZSwgSUUsIGFuZCBFZGdlIHdoZXJlIGNoYW5naW5nXG4gICAgICAgICAgICAvLyB0aGUgRE9NIGFyb3VuZCBhbiBhY3RpdmUgc2VsZWN0aW9uIHB1dHMgaXQgaW50byBhIGJyb2tlblxuICAgICAgICAgICAgLy8gc3RhdGUgd2hlcmUgdGhlIHRoaW5nIHRoZSB1c2VyIHNlZXMgZGlmZmVycyBmcm9tIHRoZVxuICAgICAgICAgICAgLy8gc2VsZWN0aW9uIHJlcG9ydGVkIGJ5IHRoZSBTZWxlY3Rpb24gb2JqZWN0ICgjNzEwLCAjOTczLFxuICAgICAgICAgICAgLy8gIzEwMTEsICMxMDEzLCAjMTAzNSkuXG4gICAgICAgICAgICBsZXQgZm9yY2VTZWxVcGRhdGUgPSB1cGRhdGVEb2MgJiYgKGllIHx8IGNocm9tZSkgJiYgIXRoaXMuY29tcG9zaW5nICYmXG4gICAgICAgICAgICAgICAgIXByZXYuc2VsZWN0aW9uLmVtcHR5ICYmICFzdGF0ZS5zZWxlY3Rpb24uZW1wdHkgJiYgc2VsZWN0aW9uQ29udGV4dENoYW5nZWQocHJldi5zZWxlY3Rpb24sIHN0YXRlLnNlbGVjdGlvbik7XG4gICAgICAgICAgICBpZiAodXBkYXRlRG9jKSB7XG4gICAgICAgICAgICAgICAgLy8gSWYgdGhlIG5vZGUgdGhhdCB0aGUgc2VsZWN0aW9uIHBvaW50cyBpbnRvIGlzIHdyaXR0ZW4gdG8sXG4gICAgICAgICAgICAgICAgLy8gQ2hyb21lIHNvbWV0aW1lcyBzdGFydHMgbWlzcmVwb3J0aW5nIHRoZSBzZWxlY3Rpb24sIHNvIHRoaXNcbiAgICAgICAgICAgICAgICAvLyB0cmFja3MgdGhhdCBhbmQgZm9yY2VzIGEgc2VsZWN0aW9uIHJlc2V0IHdoZW4gb3VyIHVwZGF0ZVxuICAgICAgICAgICAgICAgIC8vIGRpZCB3cml0ZSB0byB0aGUgbm9kZS5cbiAgICAgICAgICAgICAgICBsZXQgY2hyb21lS2x1ZGdlID0gY2hyb21lID8gKHRoaXMudHJhY2tXcml0ZXMgPSB0aGlzLmRvbVNlbGVjdGlvblJhbmdlKCkuZm9jdXNOb2RlKSA6IG51bGw7XG4gICAgICAgICAgICAgICAgaWYgKHRoaXMuY29tcG9zaW5nKVxuICAgICAgICAgICAgICAgICAgICB0aGlzLmlucHV0LmNvbXBvc2l0aW9uTm9kZSA9IGZpbmRDb21wb3NpdGlvbk5vZGUodGhpcyk7XG4gICAgICAgICAgICAgICAgaWYgKHJlZHJhdyB8fCAhdGhpcy5kb2NWaWV3LnVwZGF0ZShzdGF0ZS5kb2MsIG91dGVyRGVjbywgaW5uZXJEZWNvLCB0aGlzKSkge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmRvY1ZpZXcudXBkYXRlT3V0ZXJEZWNvKG91dGVyRGVjbyk7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuZG9jVmlldy5kZXN0cm95KCk7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuZG9jVmlldyA9IGRvY1ZpZXdEZXNjKHN0YXRlLmRvYywgb3V0ZXJEZWNvLCBpbm5lckRlY28sIHRoaXMuZG9tLCB0aGlzKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgaWYgKGNocm9tZUtsdWRnZSAmJiAoIXRoaXMudHJhY2tXcml0ZXMgfHwgIXRoaXMuZG9tLmNvbnRhaW5zKHRoaXMudHJhY2tXcml0ZXMpKSlcbiAgICAgICAgICAgICAgICAgICAgZm9yY2VTZWxVcGRhdGUgPSB0cnVlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgLy8gV29yayBhcm91bmQgZm9yIGFuIGlzc3VlIHdoZXJlIGFuIHVwZGF0ZSBhcnJpdmluZyByaWdodCBiZXR3ZWVuXG4gICAgICAgICAgICAvLyBhIERPTSBzZWxlY3Rpb24gY2hhbmdlIGFuZCB0aGUgXCJzZWxlY3Rpb25jaGFuZ2VcIiBldmVudCBmb3IgaXRcbiAgICAgICAgICAgIC8vIGNhbiBjYXVzZSBhIHNwdXJpb3VzIERPTSBzZWxlY3Rpb24gdXBkYXRlLCBkaXNydXB0aW5nIG1vdXNlXG4gICAgICAgICAgICAvLyBkcmFnIHNlbGVjdGlvbi5cbiAgICAgICAgICAgIGlmIChmb3JjZVNlbFVwZGF0ZSB8fFxuICAgICAgICAgICAgICAgICEodGhpcy5pbnB1dC5tb3VzZURvd24gJiYgdGhpcy5kb21PYnNlcnZlci5jdXJyZW50U2VsZWN0aW9uLmVxKHRoaXMuZG9tU2VsZWN0aW9uUmFuZ2UoKSkgJiZcbiAgICAgICAgICAgICAgICAgICAgYW5jaG9ySW5SaWdodFBsYWNlKHRoaXMpKSkge1xuICAgICAgICAgICAgICAgIHNlbGVjdGlvblRvRE9NKHRoaXMsIGZvcmNlU2VsVXBkYXRlKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgIHN5bmNOb2RlU2VsZWN0aW9uKHRoaXMsIHN0YXRlLnNlbGVjdGlvbik7XG4gICAgICAgICAgICAgICAgdGhpcy5kb21PYnNlcnZlci5zZXRDdXJTZWxlY3Rpb24oKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHRoaXMuZG9tT2JzZXJ2ZXIuc3RhcnQoKTtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLnVwZGF0ZVBsdWdpblZpZXdzKHByZXYpO1xuICAgICAgICBpZiAoKChfYSA9IHRoaXMuZHJhZ2dpbmcpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS5ub2RlKSAmJiAhcHJldi5kb2MuZXEoc3RhdGUuZG9jKSlcbiAgICAgICAgICAgIHRoaXMudXBkYXRlRHJhZ2dlZE5vZGUodGhpcy5kcmFnZ2luZywgcHJldik7XG4gICAgICAgIGlmIChzY3JvbGwgPT0gXCJyZXNldFwiKSB7XG4gICAgICAgICAgICB0aGlzLmRvbS5zY3JvbGxUb3AgPSAwO1xuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYgKHNjcm9sbCA9PSBcInRvIHNlbGVjdGlvblwiKSB7XG4gICAgICAgICAgICB0aGlzLnNjcm9sbFRvU2VsZWN0aW9uKCk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAob2xkU2Nyb2xsUG9zKSB7XG4gICAgICAgICAgICByZXNldFNjcm9sbFBvcyhvbGRTY3JvbGxQb3MpO1xuICAgICAgICB9XG4gICAgfVxuICAgIC8qKlxuICAgIEBpbnRlcm5hbFxuICAgICovXG4gICAgc2Nyb2xsVG9TZWxlY3Rpb24oKSB7XG4gICAgICAgIGxldCBzdGFydERPTSA9IHRoaXMuZG9tU2VsZWN0aW9uUmFuZ2UoKS5mb2N1c05vZGU7XG4gICAgICAgIGlmICghc3RhcnRET00gfHwgIXRoaXMuZG9tLmNvbnRhaW5zKHN0YXJ0RE9NLm5vZGVUeXBlID09IDEgPyBzdGFydERPTSA6IHN0YXJ0RE9NLnBhcmVudE5vZGUpKSA7XG4gICAgICAgIGVsc2UgaWYgKHRoaXMuc29tZVByb3AoXCJoYW5kbGVTY3JvbGxUb1NlbGVjdGlvblwiLCBmID0+IGYodGhpcykpKSA7XG4gICAgICAgIGVsc2UgaWYgKHRoaXMuc3RhdGUuc2VsZWN0aW9uIGluc3RhbmNlb2YgTm9kZVNlbGVjdGlvbikge1xuICAgICAgICAgICAgbGV0IHRhcmdldCA9IHRoaXMuZG9jVmlldy5kb21BZnRlclBvcyh0aGlzLnN0YXRlLnNlbGVjdGlvbi5mcm9tKTtcbiAgICAgICAgICAgIGlmICh0YXJnZXQubm9kZVR5cGUgPT0gMSlcbiAgICAgICAgICAgICAgICBzY3JvbGxSZWN0SW50b1ZpZXcodGhpcywgdGFyZ2V0LmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpLCBzdGFydERPTSk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICBzY3JvbGxSZWN0SW50b1ZpZXcodGhpcywgdGhpcy5jb29yZHNBdFBvcyh0aGlzLnN0YXRlLnNlbGVjdGlvbi5oZWFkLCAxKSwgc3RhcnRET00pO1xuICAgICAgICB9XG4gICAgfVxuICAgIGRlc3Ryb3lQbHVnaW5WaWV3cygpIHtcbiAgICAgICAgbGV0IHZpZXc7XG4gICAgICAgIHdoaWxlICh2aWV3ID0gdGhpcy5wbHVnaW5WaWV3cy5wb3AoKSlcbiAgICAgICAgICAgIGlmICh2aWV3LmRlc3Ryb3kpXG4gICAgICAgICAgICAgICAgdmlldy5kZXN0cm95KCk7XG4gICAgfVxuICAgIHVwZGF0ZVBsdWdpblZpZXdzKHByZXZTdGF0ZSkge1xuICAgICAgICBpZiAoIXByZXZTdGF0ZSB8fCBwcmV2U3RhdGUucGx1Z2lucyAhPSB0aGlzLnN0YXRlLnBsdWdpbnMgfHwgdGhpcy5kaXJlY3RQbHVnaW5zICE9IHRoaXMucHJldkRpcmVjdFBsdWdpbnMpIHtcbiAgICAgICAgICAgIHRoaXMucHJldkRpcmVjdFBsdWdpbnMgPSB0aGlzLmRpcmVjdFBsdWdpbnM7XG4gICAgICAgICAgICB0aGlzLmRlc3Ryb3lQbHVnaW5WaWV3cygpO1xuICAgICAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCB0aGlzLmRpcmVjdFBsdWdpbnMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgICAgICBsZXQgcGx1Z2luID0gdGhpcy5kaXJlY3RQbHVnaW5zW2ldO1xuICAgICAgICAgICAgICAgIGlmIChwbHVnaW4uc3BlYy52aWV3KVxuICAgICAgICAgICAgICAgICAgICB0aGlzLnBsdWdpblZpZXdzLnB1c2gocGx1Z2luLnNwZWMudmlldyh0aGlzKSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMuc3RhdGUucGx1Z2lucy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgICAgIGxldCBwbHVnaW4gPSB0aGlzLnN0YXRlLnBsdWdpbnNbaV07XG4gICAgICAgICAgICAgICAgaWYgKHBsdWdpbi5zcGVjLnZpZXcpXG4gICAgICAgICAgICAgICAgICAgIHRoaXMucGx1Z2luVmlld3MucHVzaChwbHVnaW4uc3BlYy52aWV3KHRoaXMpKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgdGhpcy5wbHVnaW5WaWV3cy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgICAgIGxldCBwbHVnaW5WaWV3ID0gdGhpcy5wbHVnaW5WaWV3c1tpXTtcbiAgICAgICAgICAgICAgICBpZiAocGx1Z2luVmlldy51cGRhdGUpXG4gICAgICAgICAgICAgICAgICAgIHBsdWdpblZpZXcudXBkYXRlKHRoaXMsIHByZXZTdGF0ZSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG4gICAgdXBkYXRlRHJhZ2dlZE5vZGUoZHJhZ2dpbmcsIHByZXYpIHtcbiAgICAgICAgbGV0IHNlbCA9IGRyYWdnaW5nLm5vZGUsIGZvdW5kID0gLTE7XG4gICAgICAgIGlmICh0aGlzLnN0YXRlLmRvYy5ub2RlQXQoc2VsLmZyb20pID09IHNlbC5ub2RlKSB7XG4gICAgICAgICAgICBmb3VuZCA9IHNlbC5mcm9tO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgbGV0IG1vdmVkUG9zID0gc2VsLmZyb20gKyAodGhpcy5zdGF0ZS5kb2MuY29udGVudC5zaXplIC0gcHJldi5kb2MuY29udGVudC5zaXplKTtcbiAgICAgICAgICAgIGxldCBtb3ZlZCA9IG1vdmVkUG9zID4gMCAmJiB0aGlzLnN0YXRlLmRvYy5ub2RlQXQobW92ZWRQb3MpO1xuICAgICAgICAgICAgaWYgKG1vdmVkID09IHNlbC5ub2RlKVxuICAgICAgICAgICAgICAgIGZvdW5kID0gbW92ZWRQb3M7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5kcmFnZ2luZyA9IG5ldyBEcmFnZ2luZyhkcmFnZ2luZy5zbGljZSwgZHJhZ2dpbmcubW92ZSwgZm91bmQgPCAwID8gdW5kZWZpbmVkIDogTm9kZVNlbGVjdGlvbi5jcmVhdGUodGhpcy5zdGF0ZS5kb2MsIGZvdW5kKSk7XG4gICAgfVxuICAgIHNvbWVQcm9wKHByb3BOYW1lLCBmKSB7XG4gICAgICAgIGxldCBwcm9wID0gdGhpcy5fcHJvcHMgJiYgdGhpcy5fcHJvcHNbcHJvcE5hbWVdLCB2YWx1ZTtcbiAgICAgICAgaWYgKHByb3AgIT0gbnVsbCAmJiAodmFsdWUgPSBmID8gZihwcm9wKSA6IHByb3ApKVxuICAgICAgICAgICAgcmV0dXJuIHZhbHVlO1xuICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMuZGlyZWN0UGx1Z2lucy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgbGV0IHByb3AgPSB0aGlzLmRpcmVjdFBsdWdpbnNbaV0ucHJvcHNbcHJvcE5hbWVdO1xuICAgICAgICAgICAgaWYgKHByb3AgIT0gbnVsbCAmJiAodmFsdWUgPSBmID8gZihwcm9wKSA6IHByb3ApKVxuICAgICAgICAgICAgICAgIHJldHVybiB2YWx1ZTtcbiAgICAgICAgfVxuICAgICAgICBsZXQgcGx1Z2lucyA9IHRoaXMuc3RhdGUucGx1Z2lucztcbiAgICAgICAgaWYgKHBsdWdpbnMpXG4gICAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHBsdWdpbnMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgICAgICBsZXQgcHJvcCA9IHBsdWdpbnNbaV0ucHJvcHNbcHJvcE5hbWVdO1xuICAgICAgICAgICAgICAgIGlmIChwcm9wICE9IG51bGwgJiYgKHZhbHVlID0gZiA/IGYocHJvcCkgOiBwcm9wKSlcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHZhbHVlO1xuICAgICAgICAgICAgfVxuICAgIH1cbiAgICAvKipcbiAgICBRdWVyeSB3aGV0aGVyIHRoZSB2aWV3IGhhcyBmb2N1cy5cbiAgICAqL1xuICAgIGhhc0ZvY3VzKCkge1xuICAgICAgICAvLyBXb3JrIGFyb3VuZCBJRSBub3QgaGFuZGxpbmcgZm9jdXMgY29ycmVjdGx5IGlmIHJlc2l6ZSBoYW5kbGVzIGFyZSBzaG93bi5cbiAgICAgICAgLy8gSWYgdGhlIGN1cnNvciBpcyBpbnNpZGUgYW4gZWxlbWVudCB3aXRoIHJlc2l6ZSBoYW5kbGVzLCBhY3RpdmVFbGVtZW50XG4gICAgICAgIC8vIHdpbGwgYmUgdGhhdCBlbGVtZW50IGluc3RlYWQgb2YgdGhpcy5kb20uXG4gICAgICAgIGlmIChpZSkge1xuICAgICAgICAgICAgLy8gSWYgYWN0aXZlRWxlbWVudCBpcyB3aXRoaW4gdGhpcy5kb20sIGFuZCB0aGVyZSBhcmUgbm8gb3RoZXIgZWxlbWVudHNcbiAgICAgICAgICAgIC8vIHNldHRpbmcgYGNvbnRlbnRlZGl0YWJsZWAgdG8gZmFsc2UgaW4gYmV0d2VlbiwgdHJlYXQgaXQgYXMgZm9jdXNlZC5cbiAgICAgICAgICAgIGxldCBub2RlID0gdGhpcy5yb290LmFjdGl2ZUVsZW1lbnQ7XG4gICAgICAgICAgICBpZiAobm9kZSA9PSB0aGlzLmRvbSlcbiAgICAgICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgICAgIGlmICghbm9kZSB8fCAhdGhpcy5kb20uY29udGFpbnMobm9kZSkpXG4gICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgICAgd2hpbGUgKG5vZGUgJiYgdGhpcy5kb20gIT0gbm9kZSAmJiB0aGlzLmRvbS5jb250YWlucyhub2RlKSkge1xuICAgICAgICAgICAgICAgIGlmIChub2RlLmNvbnRlbnRFZGl0YWJsZSA9PSAnZmFsc2UnKVxuICAgICAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgICAgICAgICAgbm9kZSA9IG5vZGUucGFyZW50RWxlbWVudDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB0aGlzLnJvb3QuYWN0aXZlRWxlbWVudCA9PSB0aGlzLmRvbTtcbiAgICB9XG4gICAgLyoqXG4gICAgRm9jdXMgdGhlIGVkaXRvci5cbiAgICAqL1xuICAgIGZvY3VzKCkge1xuICAgICAgICB0aGlzLmRvbU9ic2VydmVyLnN0b3AoKTtcbiAgICAgICAgaWYgKHRoaXMuZWRpdGFibGUpXG4gICAgICAgICAgICBmb2N1c1ByZXZlbnRTY3JvbGwodGhpcy5kb20pO1xuICAgICAgICBzZWxlY3Rpb25Ub0RPTSh0aGlzKTtcbiAgICAgICAgdGhpcy5kb21PYnNlcnZlci5zdGFydCgpO1xuICAgIH1cbiAgICAvKipcbiAgICBHZXQgdGhlIGRvY3VtZW50IHJvb3QgaW4gd2hpY2ggdGhlIGVkaXRvciBleGlzdHMuIFRoaXMgd2lsbFxuICAgIHVzdWFsbHkgYmUgdGhlIHRvcC1sZXZlbCBgZG9jdW1lbnRgLCBidXQgbWlnaHQgYmUgYSBbc2hhZG93XG4gICAgRE9NXShodHRwczovL2RldmVsb3Blci5tb3ppbGxhLm9yZy9lbi1VUy9kb2NzL1dlYi9XZWJfQ29tcG9uZW50cy9TaGFkb3dfRE9NKVxuICAgIHJvb3QgaWYgdGhlIGVkaXRvciBpcyBpbnNpZGUgb25lLlxuICAgICovXG4gICAgZ2V0IHJvb3QoKSB7XG4gICAgICAgIGxldCBjYWNoZWQgPSB0aGlzLl9yb290O1xuICAgICAgICBpZiAoY2FjaGVkID09IG51bGwpXG4gICAgICAgICAgICBmb3IgKGxldCBzZWFyY2ggPSB0aGlzLmRvbS5wYXJlbnROb2RlOyBzZWFyY2g7IHNlYXJjaCA9IHNlYXJjaC5wYXJlbnROb2RlKSB7XG4gICAgICAgICAgICAgICAgaWYgKHNlYXJjaC5ub2RlVHlwZSA9PSA5IHx8IChzZWFyY2gubm9kZVR5cGUgPT0gMTEgJiYgc2VhcmNoLmhvc3QpKSB7XG4gICAgICAgICAgICAgICAgICAgIGlmICghc2VhcmNoLmdldFNlbGVjdGlvbilcbiAgICAgICAgICAgICAgICAgICAgICAgIE9iamVjdC5nZXRQcm90b3R5cGVPZihzZWFyY2gpLmdldFNlbGVjdGlvbiA9ICgpID0+IHNlYXJjaC5vd25lckRvY3VtZW50LmdldFNlbGVjdGlvbigpO1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5fcm9vdCA9IHNlYXJjaDtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIHJldHVybiBjYWNoZWQgfHwgZG9jdW1lbnQ7XG4gICAgfVxuICAgIC8qKlxuICAgIFdoZW4gYW4gZXhpc3RpbmcgZWRpdG9yIHZpZXcgaXMgbW92ZWQgdG8gYSBuZXcgZG9jdW1lbnQgb3JcbiAgICBzaGFkb3cgdHJlZSwgY2FsbCB0aGlzIHRvIG1ha2UgaXQgcmVjb21wdXRlIGl0cyByb290LlxuICAgICovXG4gICAgdXBkYXRlUm9vdCgpIHtcbiAgICAgICAgdGhpcy5fcm9vdCA9IG51bGw7XG4gICAgfVxuICAgIC8qKlxuICAgIEdpdmVuIGEgcGFpciBvZiB2aWV3cG9ydCBjb29yZGluYXRlcywgcmV0dXJuIHRoZSBkb2N1bWVudFxuICAgIHBvc2l0aW9uIHRoYXQgY29ycmVzcG9uZHMgdG8gdGhlbS4gTWF5IHJldHVybiBudWxsIGlmIHRoZSBnaXZlblxuICAgIGNvb3JkaW5hdGVzIGFyZW4ndCBpbnNpZGUgb2YgdGhlIGVkaXRvci4gV2hlbiBhbiBvYmplY3QgaXNcbiAgICByZXR1cm5lZCwgaXRzIGBwb3NgIHByb3BlcnR5IGlzIHRoZSBwb3NpdGlvbiBuZWFyZXN0IHRvIHRoZVxuICAgIGNvb3JkaW5hdGVzLCBhbmQgaXRzIGBpbnNpZGVgIHByb3BlcnR5IGhvbGRzIHRoZSBwb3NpdGlvbiBvZiB0aGVcbiAgICBpbm5lciBub2RlIHRoYXQgdGhlIHBvc2l0aW9uIGZhbGxzIGluc2lkZSBvZiwgb3IgLTEgaWYgaXQgaXMgYXRcbiAgICB0aGUgdG9wIGxldmVsLCBub3QgaW4gYW55IG5vZGUuXG4gICAgKi9cbiAgICBwb3NBdENvb3Jkcyhjb29yZHMpIHtcbiAgICAgICAgcmV0dXJuIHBvc0F0Q29vcmRzKHRoaXMsIGNvb3Jkcyk7XG4gICAgfVxuICAgIC8qKlxuICAgIFJldHVybnMgdGhlIHZpZXdwb3J0IHJlY3RhbmdsZSBhdCBhIGdpdmVuIGRvY3VtZW50IHBvc2l0aW9uLlxuICAgIGBsZWZ0YCBhbmQgYHJpZ2h0YCB3aWxsIGJlIHRoZSBzYW1lIG51bWJlciwgYXMgdGhpcyByZXR1cm5zIGFcbiAgICBmbGF0IGN1cnNvci1pc2ggcmVjdGFuZ2xlLiBJZiB0aGUgcG9zaXRpb24gaXMgYmV0d2VlbiB0d28gdGhpbmdzXG4gICAgdGhhdCBhcmVuJ3QgZGlyZWN0bHkgYWRqYWNlbnQsIGBzaWRlYCBkZXRlcm1pbmVzIHdoaWNoIGVsZW1lbnRcbiAgICBpcyB1c2VkLiBXaGVuIDwgMCwgdGhlIGVsZW1lbnQgYmVmb3JlIHRoZSBwb3NpdGlvbiBpcyB1c2VkLFxuICAgIG90aGVyd2lzZSB0aGUgZWxlbWVudCBhZnRlci5cbiAgICAqL1xuICAgIGNvb3Jkc0F0UG9zKHBvcywgc2lkZSA9IDEpIHtcbiAgICAgICAgcmV0dXJuIGNvb3Jkc0F0UG9zKHRoaXMsIHBvcywgc2lkZSk7XG4gICAgfVxuICAgIC8qKlxuICAgIEZpbmQgdGhlIERPTSBwb3NpdGlvbiB0aGF0IGNvcnJlc3BvbmRzIHRvIHRoZSBnaXZlbiBkb2N1bWVudFxuICAgIHBvc2l0aW9uLiBXaGVuIGBzaWRlYCBpcyBuZWdhdGl2ZSwgZmluZCB0aGUgcG9zaXRpb24gYXMgY2xvc2UgYXNcbiAgICBwb3NzaWJsZSB0byB0aGUgY29udGVudCBiZWZvcmUgdGhlIHBvc2l0aW9uLiBXaGVuIHBvc2l0aXZlLFxuICAgIHByZWZlciBwb3NpdGlvbnMgY2xvc2UgdG8gdGhlIGNvbnRlbnQgYWZ0ZXIgdGhlIHBvc2l0aW9uLiBXaGVuXG4gICAgemVybywgcHJlZmVyIGFzIHNoYWxsb3cgYSBwb3NpdGlvbiBhcyBwb3NzaWJsZS5cbiAgICBcbiAgICBOb3RlIHRoYXQgeW91IHNob3VsZCAqKm5vdCoqIG11dGF0ZSB0aGUgZWRpdG9yJ3MgaW50ZXJuYWwgRE9NLFxuICAgIG9ubHkgaW5zcGVjdCBpdCAoYW5kIGV2ZW4gdGhhdCBpcyB1c3VhbGx5IG5vdCBuZWNlc3NhcnkpLlxuICAgICovXG4gICAgZG9tQXRQb3MocG9zLCBzaWRlID0gMCkge1xuICAgICAgICByZXR1cm4gdGhpcy5kb2NWaWV3LmRvbUZyb21Qb3MocG9zLCBzaWRlKTtcbiAgICB9XG4gICAgLyoqXG4gICAgRmluZCB0aGUgRE9NIG5vZGUgdGhhdCByZXByZXNlbnRzIHRoZSBkb2N1bWVudCBub2RlIGFmdGVyIHRoZVxuICAgIGdpdmVuIHBvc2l0aW9uLiBNYXkgcmV0dXJuIGBudWxsYCB3aGVuIHRoZSBwb3NpdGlvbiBkb2Vzbid0IHBvaW50XG4gICAgaW4gZnJvbnQgb2YgYSBub2RlIG9yIGlmIHRoZSBub2RlIGlzIGluc2lkZSBhbiBvcGFxdWUgbm9kZSB2aWV3LlxuICAgIFxuICAgIFRoaXMgaXMgaW50ZW5kZWQgdG8gYmUgYWJsZSB0byBjYWxsIHRoaW5ncyBsaWtlXG4gICAgYGdldEJvdW5kaW5nQ2xpZW50UmVjdGAgb24gdGhhdCBET00gbm9kZS4gRG8gKipub3QqKiBtdXRhdGUgdGhlXG4gICAgZWRpdG9yIERPTSBkaXJlY3RseSwgb3IgYWRkIHN0eWxpbmcgdGhpcyB3YXksIHNpbmNlIHRoYXQgd2lsbCBiZVxuICAgIGltbWVkaWF0ZWx5IG92ZXJyaWRlbiBieSB0aGUgZWRpdG9yIGFzIGl0IHJlZHJhd3MgdGhlIG5vZGUuXG4gICAgKi9cbiAgICBub2RlRE9NKHBvcykge1xuICAgICAgICBsZXQgZGVzYyA9IHRoaXMuZG9jVmlldy5kZXNjQXQocG9zKTtcbiAgICAgICAgcmV0dXJuIGRlc2MgPyBkZXNjLm5vZGVET00gOiBudWxsO1xuICAgIH1cbiAgICAvKipcbiAgICBGaW5kIHRoZSBkb2N1bWVudCBwb3NpdGlvbiB0aGF0IGNvcnJlc3BvbmRzIHRvIGEgZ2l2ZW4gRE9NXG4gICAgcG9zaXRpb24uIChXaGVuZXZlciBwb3NzaWJsZSwgaXQgaXMgcHJlZmVyYWJsZSB0byBpbnNwZWN0IHRoZVxuICAgIGRvY3VtZW50IHN0cnVjdHVyZSBkaXJlY3RseSwgcmF0aGVyIHRoYW4gcG9raW5nIGFyb3VuZCBpbiB0aGVcbiAgICBET00sIGJ1dCBzb21ldGltZXPigJRmb3IgZXhhbXBsZSB3aGVuIGludGVycHJldGluZyBhbiBldmVudFxuICAgIHRhcmdldOKAlHlvdSBkb24ndCBoYXZlIGEgY2hvaWNlLilcbiAgICBcbiAgICBUaGUgYGJpYXNgIHBhcmFtZXRlciBjYW4gYmUgdXNlZCB0byBpbmZsdWVuY2Ugd2hpY2ggc2lkZSBvZiBhIERPTVxuICAgIG5vZGUgdG8gdXNlIHdoZW4gdGhlIHBvc2l0aW9uIGlzIGluc2lkZSBhIGxlYWYgbm9kZS5cbiAgICAqL1xuICAgIHBvc0F0RE9NKG5vZGUsIG9mZnNldCwgYmlhcyA9IC0xKSB7XG4gICAgICAgIGxldCBwb3MgPSB0aGlzLmRvY1ZpZXcucG9zRnJvbURPTShub2RlLCBvZmZzZXQsIGJpYXMpO1xuICAgICAgICBpZiAocG9zID09IG51bGwpXG4gICAgICAgICAgICB0aHJvdyBuZXcgUmFuZ2VFcnJvcihcIkRPTSBwb3NpdGlvbiBub3QgaW5zaWRlIHRoZSBlZGl0b3JcIik7XG4gICAgICAgIHJldHVybiBwb3M7XG4gICAgfVxuICAgIC8qKlxuICAgIEZpbmQgb3V0IHdoZXRoZXIgdGhlIHNlbGVjdGlvbiBpcyBhdCB0aGUgZW5kIG9mIGEgdGV4dGJsb2NrIHdoZW5cbiAgICBtb3ZpbmcgaW4gYSBnaXZlbiBkaXJlY3Rpb24uIFdoZW4sIGZvciBleGFtcGxlLCBnaXZlbiBgXCJsZWZ0XCJgLFxuICAgIGl0IHdpbGwgcmV0dXJuIHRydWUgaWYgbW92aW5nIGxlZnQgZnJvbSB0aGUgY3VycmVudCBjdXJzb3JcbiAgICBwb3NpdGlvbiB3b3VsZCBsZWF2ZSB0aGF0IHBvc2l0aW9uJ3MgcGFyZW50IHRleHRibG9jay4gV2lsbCBhcHBseVxuICAgIHRvIHRoZSB2aWV3J3MgY3VycmVudCBzdGF0ZSBieSBkZWZhdWx0LCBidXQgaXQgaXMgcG9zc2libGUgdG9cbiAgICBwYXNzIGEgZGlmZmVyZW50IHN0YXRlLlxuICAgICovXG4gICAgZW5kT2ZUZXh0YmxvY2soZGlyLCBzdGF0ZSkge1xuICAgICAgICByZXR1cm4gZW5kT2ZUZXh0YmxvY2sodGhpcywgc3RhdGUgfHwgdGhpcy5zdGF0ZSwgZGlyKTtcbiAgICB9XG4gICAgLyoqXG4gICAgUnVuIHRoZSBlZGl0b3IncyBwYXN0ZSBsb2dpYyB3aXRoIHRoZSBnaXZlbiBIVE1MIHN0cmluZy4gVGhlXG4gICAgYGV2ZW50YCwgaWYgZ2l2ZW4sIHdpbGwgYmUgcGFzc2VkIHRvIHRoZVxuICAgIFtgaGFuZGxlUGFzdGVgXShodHRwczovL3Byb3NlbWlycm9yLm5ldC9kb2NzL3JlZi8jdmlldy5FZGl0b3JQcm9wcy5oYW5kbGVQYXN0ZSkgaG9vay5cbiAgICAqL1xuICAgIHBhc3RlSFRNTChodG1sLCBldmVudCkge1xuICAgICAgICByZXR1cm4gZG9QYXN0ZSh0aGlzLCBcIlwiLCBodG1sLCBmYWxzZSwgZXZlbnQgfHwgbmV3IENsaXBib2FyZEV2ZW50KFwicGFzdGVcIikpO1xuICAgIH1cbiAgICAvKipcbiAgICBSdW4gdGhlIGVkaXRvcidzIHBhc3RlIGxvZ2ljIHdpdGggdGhlIGdpdmVuIHBsYWluLXRleHQgaW5wdXQuXG4gICAgKi9cbiAgICBwYXN0ZVRleHQodGV4dCwgZXZlbnQpIHtcbiAgICAgICAgcmV0dXJuIGRvUGFzdGUodGhpcywgdGV4dCwgbnVsbCwgdHJ1ZSwgZXZlbnQgfHwgbmV3IENsaXBib2FyZEV2ZW50KFwicGFzdGVcIikpO1xuICAgIH1cbiAgICAvKipcbiAgICBTZXJpYWxpemUgdGhlIGdpdmVuIHNsaWNlIGFzIGl0IHdvdWxkIGJlIGlmIGl0IHdhcyBjb3BpZWQgZnJvbVxuICAgIHRoaXMgZWRpdG9yLiBSZXR1cm5zIGEgRE9NIGVsZW1lbnQgdGhhdCBjb250YWlucyBhXG4gICAgcmVwcmVzZW50YXRpb24gb2YgdGhlIHNsaWNlIGFzIGl0cyBjaGlsZHJlbiwgYSB0ZXh0dWFsXG4gICAgcmVwcmVzZW50YXRpb24sIGFuZCB0aGUgdHJhbnNmb3JtZWQgc2xpY2UgKHdoaWNoIGNhbiBiZVxuICAgIGRpZmZlcmVudCBmcm9tIHRoZSBnaXZlbiBpbnB1dCBkdWUgdG8gaG9va3MgbGlrZVxuICAgIFtgdHJhbnNmb3JtQ29waWVkYF0oaHR0cHM6Ly9wcm9zZW1pcnJvci5uZXQvZG9jcy9yZWYvI3ZpZXcuRWRpdG9yUHJvcHMudHJhbnNmb3JtQ29waWVkKSkuXG4gICAgKi9cbiAgICBzZXJpYWxpemVGb3JDbGlwYm9hcmQoc2xpY2UpIHtcbiAgICAgICAgcmV0dXJuIHNlcmlhbGl6ZUZvckNsaXBib2FyZCh0aGlzLCBzbGljZSk7XG4gICAgfVxuICAgIC8qKlxuICAgIFJlbW92ZXMgdGhlIGVkaXRvciBmcm9tIHRoZSBET00gYW5kIGRlc3Ryb3lzIGFsbCBbbm9kZVxuICAgIHZpZXdzXShodHRwczovL3Byb3NlbWlycm9yLm5ldC9kb2NzL3JlZi8jdmlldy5Ob2RlVmlldykuXG4gICAgKi9cbiAgICBkZXN0cm95KCkge1xuICAgICAgICBpZiAoIXRoaXMuZG9jVmlldylcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgZGVzdHJveUlucHV0KHRoaXMpO1xuICAgICAgICB0aGlzLmRlc3Ryb3lQbHVnaW5WaWV3cygpO1xuICAgICAgICBpZiAodGhpcy5tb3VudGVkKSB7XG4gICAgICAgICAgICB0aGlzLmRvY1ZpZXcudXBkYXRlKHRoaXMuc3RhdGUuZG9jLCBbXSwgdmlld0RlY29yYXRpb25zKHRoaXMpLCB0aGlzKTtcbiAgICAgICAgICAgIHRoaXMuZG9tLnRleHRDb250ZW50ID0gXCJcIjtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIGlmICh0aGlzLmRvbS5wYXJlbnROb2RlKSB7XG4gICAgICAgICAgICB0aGlzLmRvbS5wYXJlbnROb2RlLnJlbW92ZUNoaWxkKHRoaXMuZG9tKTtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLmRvY1ZpZXcuZGVzdHJveSgpO1xuICAgICAgICB0aGlzLmRvY1ZpZXcgPSBudWxsO1xuICAgICAgICBjbGVhclJldXNlZFJhbmdlKCk7XG4gICAgfVxuICAgIC8qKlxuICAgIFRoaXMgaXMgdHJ1ZSB3aGVuIHRoZSB2aWV3IGhhcyBiZWVuXG4gICAgW2Rlc3Ryb3llZF0oaHR0cHM6Ly9wcm9zZW1pcnJvci5uZXQvZG9jcy9yZWYvI3ZpZXcuRWRpdG9yVmlldy5kZXN0cm95KSAoYW5kIHRodXMgc2hvdWxkIG5vdCBiZVxuICAgIHVzZWQgYW55bW9yZSkuXG4gICAgKi9cbiAgICBnZXQgaXNEZXN0cm95ZWQoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmRvY1ZpZXcgPT0gbnVsbDtcbiAgICB9XG4gICAgLyoqXG4gICAgVXNlZCBmb3IgdGVzdGluZy5cbiAgICAqL1xuICAgIGRpc3BhdGNoRXZlbnQoZXZlbnQpIHtcbiAgICAgICAgcmV0dXJuIGRpc3BhdGNoRXZlbnQodGhpcywgZXZlbnQpO1xuICAgIH1cbiAgICAvKipcbiAgICBAaW50ZXJuYWxcbiAgICAqL1xuICAgIGRvbVNlbGVjdGlvblJhbmdlKCkge1xuICAgICAgICBsZXQgc2VsID0gdGhpcy5kb21TZWxlY3Rpb24oKTtcbiAgICAgICAgaWYgKCFzZWwpXG4gICAgICAgICAgICByZXR1cm4geyBmb2N1c05vZGU6IG51bGwsIGZvY3VzT2Zmc2V0OiAwLCBhbmNob3JOb2RlOiBudWxsLCBhbmNob3JPZmZzZXQ6IDAgfTtcbiAgICAgICAgcmV0dXJuIHNhZmFyaSAmJiB0aGlzLnJvb3Qubm9kZVR5cGUgPT09IDExICYmXG4gICAgICAgICAgICBkZWVwQWN0aXZlRWxlbWVudCh0aGlzLmRvbS5vd25lckRvY3VtZW50KSA9PSB0aGlzLmRvbSAmJiBzYWZhcmlTaGFkb3dTZWxlY3Rpb25SYW5nZSh0aGlzLCBzZWwpIHx8IHNlbDtcbiAgICB9XG4gICAgLyoqXG4gICAgQGludGVybmFsXG4gICAgKi9cbiAgICBkb21TZWxlY3Rpb24oKSB7XG4gICAgICAgIHJldHVybiB0aGlzLnJvb3QuZ2V0U2VsZWN0aW9uKCk7XG4gICAgfVxufVxuRWRpdG9yVmlldy5wcm90b3R5cGUuZGlzcGF0Y2ggPSBmdW5jdGlvbiAodHIpIHtcbiAgICBsZXQgZGlzcGF0Y2hUcmFuc2FjdGlvbiA9IHRoaXMuX3Byb3BzLmRpc3BhdGNoVHJhbnNhY3Rpb247XG4gICAgaWYgKGRpc3BhdGNoVHJhbnNhY3Rpb24pXG4gICAgICAgIGRpc3BhdGNoVHJhbnNhY3Rpb24uY2FsbCh0aGlzLCB0cik7XG4gICAgZWxzZVxuICAgICAgICB0aGlzLnVwZGF0ZVN0YXRlKHRoaXMuc3RhdGUuYXBwbHkodHIpKTtcbn07XG5mdW5jdGlvbiBjb21wdXRlRG9jRGVjbyh2aWV3KSB7XG4gICAgbGV0IGF0dHJzID0gT2JqZWN0LmNyZWF0ZShudWxsKTtcbiAgICBhdHRycy5jbGFzcyA9IFwiUHJvc2VNaXJyb3JcIjtcbiAgICBhdHRycy5jb250ZW50ZWRpdGFibGUgPSBTdHJpbmcodmlldy5lZGl0YWJsZSk7XG4gICAgdmlldy5zb21lUHJvcChcImF0dHJpYnV0ZXNcIiwgdmFsdWUgPT4ge1xuICAgICAgICBpZiAodHlwZW9mIHZhbHVlID09IFwiZnVuY3Rpb25cIilcbiAgICAgICAgICAgIHZhbHVlID0gdmFsdWUodmlldy5zdGF0ZSk7XG4gICAgICAgIGlmICh2YWx1ZSlcbiAgICAgICAgICAgIGZvciAobGV0IGF0dHIgaW4gdmFsdWUpIHtcbiAgICAgICAgICAgICAgICBpZiAoYXR0ciA9PSBcImNsYXNzXCIpXG4gICAgICAgICAgICAgICAgICAgIGF0dHJzLmNsYXNzICs9IFwiIFwiICsgdmFsdWVbYXR0cl07XG4gICAgICAgICAgICAgICAgZWxzZSBpZiAoYXR0ciA9PSBcInN0eWxlXCIpXG4gICAgICAgICAgICAgICAgICAgIGF0dHJzLnN0eWxlID0gKGF0dHJzLnN0eWxlID8gYXR0cnMuc3R5bGUgKyBcIjtcIiA6IFwiXCIpICsgdmFsdWVbYXR0cl07XG4gICAgICAgICAgICAgICAgZWxzZSBpZiAoIWF0dHJzW2F0dHJdICYmIGF0dHIgIT0gXCJjb250ZW50ZWRpdGFibGVcIiAmJiBhdHRyICE9IFwibm9kZU5hbWVcIilcbiAgICAgICAgICAgICAgICAgICAgYXR0cnNbYXR0cl0gPSBTdHJpbmcodmFsdWVbYXR0cl0pO1xuICAgICAgICAgICAgfVxuICAgIH0pO1xuICAgIGlmICghYXR0cnMudHJhbnNsYXRlKVxuICAgICAgICBhdHRycy50cmFuc2xhdGUgPSBcIm5vXCI7XG4gICAgcmV0dXJuIFtEZWNvcmF0aW9uLm5vZGUoMCwgdmlldy5zdGF0ZS5kb2MuY29udGVudC5zaXplLCBhdHRycyldO1xufVxuZnVuY3Rpb24gdXBkYXRlQ3Vyc29yV3JhcHBlcih2aWV3KSB7XG4gICAgaWYgKHZpZXcubWFya0N1cnNvcikge1xuICAgICAgICBsZXQgZG9tID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudChcImltZ1wiKTtcbiAgICAgICAgZG9tLmNsYXNzTmFtZSA9IFwiUHJvc2VNaXJyb3Itc2VwYXJhdG9yXCI7XG4gICAgICAgIGRvbS5zZXRBdHRyaWJ1dGUoXCJtYXJrLXBsYWNlaG9sZGVyXCIsIFwidHJ1ZVwiKTtcbiAgICAgICAgZG9tLnNldEF0dHJpYnV0ZShcImFsdFwiLCBcIlwiKTtcbiAgICAgICAgdmlldy5jdXJzb3JXcmFwcGVyID0geyBkb20sIGRlY286IERlY29yYXRpb24ud2lkZ2V0KHZpZXcuc3RhdGUuc2VsZWN0aW9uLmZyb20sIGRvbSwgeyByYXc6IHRydWUsIG1hcmtzOiB2aWV3Lm1hcmtDdXJzb3IgfSkgfTtcbiAgICB9XG4gICAgZWxzZSB7XG4gICAgICAgIHZpZXcuY3Vyc29yV3JhcHBlciA9IG51bGw7XG4gICAgfVxufVxuZnVuY3Rpb24gZ2V0RWRpdGFibGUodmlldykge1xuICAgIHJldHVybiAhdmlldy5zb21lUHJvcChcImVkaXRhYmxlXCIsIHZhbHVlID0+IHZhbHVlKHZpZXcuc3RhdGUpID09PSBmYWxzZSk7XG59XG5mdW5jdGlvbiBzZWxlY3Rpb25Db250ZXh0Q2hhbmdlZChzZWwxLCBzZWwyKSB7XG4gICAgbGV0IGRlcHRoID0gTWF0aC5taW4oc2VsMS4kYW5jaG9yLnNoYXJlZERlcHRoKHNlbDEuaGVhZCksIHNlbDIuJGFuY2hvci5zaGFyZWREZXB0aChzZWwyLmhlYWQpKTtcbiAgICByZXR1cm4gc2VsMS4kYW5jaG9yLnN0YXJ0KGRlcHRoKSAhPSBzZWwyLiRhbmNob3Iuc3RhcnQoZGVwdGgpO1xufVxuZnVuY3Rpb24gYnVpbGROb2RlVmlld3Modmlldykge1xuICAgIGxldCByZXN1bHQgPSBPYmplY3QuY3JlYXRlKG51bGwpO1xuICAgIGZ1bmN0aW9uIGFkZChvYmopIHtcbiAgICAgICAgZm9yIChsZXQgcHJvcCBpbiBvYmopXG4gICAgICAgICAgICBpZiAoIU9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChyZXN1bHQsIHByb3ApKVxuICAgICAgICAgICAgICAgIHJlc3VsdFtwcm9wXSA9IG9ialtwcm9wXTtcbiAgICB9XG4gICAgdmlldy5zb21lUHJvcChcIm5vZGVWaWV3c1wiLCBhZGQpO1xuICAgIHZpZXcuc29tZVByb3AoXCJtYXJrVmlld3NcIiwgYWRkKTtcbiAgICByZXR1cm4gcmVzdWx0O1xufVxuZnVuY3Rpb24gY2hhbmdlZE5vZGVWaWV3cyhhLCBiKSB7XG4gICAgbGV0IG5BID0gMCwgbkIgPSAwO1xuICAgIGZvciAobGV0IHByb3AgaW4gYSkge1xuICAgICAgICBpZiAoYVtwcm9wXSAhPSBiW3Byb3BdKVxuICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgIG5BKys7XG4gICAgfVxuICAgIGZvciAobGV0IF8gaW4gYilcbiAgICAgICAgbkIrKztcbiAgICByZXR1cm4gbkEgIT0gbkI7XG59XG5mdW5jdGlvbiBjaGVja1N0YXRlQ29tcG9uZW50KHBsdWdpbikge1xuICAgIGlmIChwbHVnaW4uc3BlYy5zdGF0ZSB8fCBwbHVnaW4uc3BlYy5maWx0ZXJUcmFuc2FjdGlvbiB8fCBwbHVnaW4uc3BlYy5hcHBlbmRUcmFuc2FjdGlvbilcbiAgICAgICAgdGhyb3cgbmV3IFJhbmdlRXJyb3IoXCJQbHVnaW5zIHBhc3NlZCBkaXJlY3RseSB0byB0aGUgdmlldyBtdXN0IG5vdCBoYXZlIGEgc3RhdGUgY29tcG9uZW50XCIpO1xufVxuXG5leHBvcnQgeyBEZWNvcmF0aW9uLCBEZWNvcmF0aW9uU2V0LCBFZGl0b3JWaWV3LCBfX2VuZENvbXBvc2l0aW9uLCBfX3BhcnNlRnJvbUNsaXBib2FyZCB9O1xuIl0sIm5hbWVzIjpbXSwiaWdub3JlTGlzdCI6WzBdLCJzb3VyY2VSb290IjoiIn0=\n//# sourceURL=webpack-internal:///(ssr)/./node_modules/prosemirror-view/dist/index.js\n");
|
|
|
|
/***/ })
|
|
|
|
};
|
|
; |